Actually I´m working in a forum project built with Spring boot, Mongodb and Vue.js.
When I´m trying to post a new comment and get the user datails with the SecurityContextHolder and cast it to my UsersDetailImpl who implements from the UserDetails class provided by Spring boot, it throw the following error: org.springframework.security.web.authentication.webauthenticationdetails cannot be cast to .... UserDetailsImpl
I don´t really know the reason of this error becasuse if I test it from Postman does not report an error.
UserDetailsImpl.java
public class UserDetailsImpl implements UserDetails {
private static final long serialVersionUID = 1L;
private String id;
private String username;
private String email;
#JsonIgnore
private String password;
private Collection<? extends GrantedAuthority> authorities;
public UserDetailsImpl(String id, String username, String email, String password,
Collection<? extends GrantedAuthority> authorities) {
this.id = id;
this.username = username;
this.email = email;
this.password = password;
this.authorities = authorities;
}
public static UserDetailsImpl build(User user) {
List<GrantedAuthority> authorities = user.getRoles().stream()
.map(role -> new SimpleGrantedAuthority(role.getName().name()))
.collect(Collectors.toList());
return new UserDetailsImpl(
user.getId(),
user.getUsername(),
user.getEmail(),
user.getPassword(),
authorities);
}
#Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return authorities;
}
public String getId() {
return id;
}
public String getEmail() {
return email;
}
#Override
public String getPassword() {
return password;
}
#Override
public String getUsername() {
return username;
}
#Override
public boolean isAccountNonExpired() {
return true;
}
#Override
public boolean isAccountNonLocked() {
return true;
}
#Override
public boolean isCredentialsNonExpired() {
return true;
}
#Override
public boolean isEnabled() {
return true;
}
#Override
public boolean equals(Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
UserDetailsImpl user = (UserDetailsImpl) o;
return Objects.equals(id, user.id);
}
}
CommentController.java
#CrossOrigin(origins = "*", maxAge = 3600)
#RestController
#RequestMapping("/comments")
public class CommentController {
#Autowired
CommentRepository commentRepository;
#Autowired
RoleRepository roleRepository;
#PostMapping("/ask")
public ResponseEntity<?> ask (#Valid #RequestBody AskRequest askRequest) {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
UserDetailsImpl userDetails = (UserDetailsImpl) authentication.getPrincipal();
HashSet<String> strRoles = userDetails.getAuthorities().stream()
.map(GrantedAuthority::getAuthority)
.collect(Collectors.toCollection(HashSet::new));
Set<Role> roles = new HashSet<>();
strRoles.forEach(role -> {
int cutPoint = role.indexOf("_");
role = role.substring(cutPoint + 1).toLowerCase();
findRole(roles, role, roleRepository);
});
User user = new User(userDetails.getUsername(), userDetails.getEmail(), roles);
ObjectId discussion_id = ObjectId.get();
String slug = new Slugify().slugify(askRequest.getTitle());
Comment comment = new Comment(discussion_id, askRequest.getTitle(),
askRequest.getText(),slug, "full_slug_test", Instant.now(),user);
String info = comment.getDiscussion_id().toString() + comment.getPosted() + comment.getTitle()
+ comment.getText() + comment.getAuthor().getUsername() + comment.getAuthor().getEmail()
+ comment.getAuthor().getId() + comment.getAuthor().getRoles();
commentRepository.save(comment);
return ResponseEntity.ok(new MessageResponse(info));
}
}
I´m new in all this technologies there may be serious errors. All the advices will be a great help to me because the project is academic.
If someone need more information just ask for it.
Thank you all :)
Change authentication.getDetails() to getAuthentication().getPrincipal()
You will have:
UserDetailsImpl userDetails = (UserDetailsImpl) authentication.getPrincipal();
Finally I found the error and it was in the front-end side. I was sending de headers with the JWT in this way.
import axios from 'axios';
import authHeader from './auth-header';
const API_URL = 'http://localhost:8080/comments/';
class CommentsService {
ask(post){
return axios.post(API_URL + 'ask', {
title: post.title,
text: post.text,
headers: authHeader()
});
}
}
export default new CommentsService();
and it is totally wrong so I found the manner to do it.
import axios from 'axios';
import authHeader from './auth-header';
const API_URL = 'http://localhost:8080/comments/';
class CommentsService {
ask(post){
return axios.post(API_URL + 'ask', {
title: post.title,
text: post.text
},{headers: authHeader()});
}
}
export default new CommentsService();
I also add the code to mount the headers.
export default function authHeader() {
let user = JSON.parse(localStorage.getItem('user'));
if (user && user.accessToken) {
return { Authorization: 'Bearer ' + user.accessToken };
} else {
return {};
}
}
Related
Basically, I am trying to establish a relationship between my two tables using spring boots.
And the relationship which I had used was the #onetoone and #onetomany relationship.
But after building the relationship and creating the table in MySQL whenever I run the program my foreign key is not updating.
The relationship is one user can have many contacts. I have tried unidirectional as well as bidirectional mapping but it is not working.
I want in contact table there will be a separate column for the foreign key. Based on that key I will show all contacts for that particular user.
This is my contact entity...
package com.example.jpa.contactEntities;
#Entity
#Table(name = "Contact")
public class ContactEntities {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long c_id;
private String c_name;
private String second_c_name;
private String c_work;
private String c_emali;
private String c_phone;
private String c_image;
#Column(length = 5000)
private String c_description;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "contact_id")
private UserEntities userEntities;
public ContactEntities() {
super();
}
public ContactEntities(long c_id, String c_name, String second_c_name, String c_work, String c_emali,
String c_phone, String c_image, String c_description, UserEntities userEntities) {
super();
this.c_id = c_id;
this.c_name = c_name;
this.second_c_name = second_c_name;
this.c_work = c_work;
this.c_emali = c_emali;
this.c_phone = c_phone;
this.c_image = c_image;
this.c_description = c_description;
this.userEntities = userEntities;
}
public long getC_id() {
return c_id;
}
public void setC_id(int c_id) {
this.c_id = c_id;
}
public String getC_name() {
return c_name;
}
public void setC_name(String c_name) {
this.c_name = c_name;
}
public String getSecond_c_name() {
return second_c_name;
}
public void setSecond_c_name(String second_c_name) {
this.second_c_name = second_c_name;
}
public String getC_work() {
return c_work;
}
public void setC_work(String c_work) {
this.c_work = c_work;
}
public String getC_emali() {
return c_emali;
}
public void setC_emali(String c_emali) {
this.c_emali = c_emali;
}
public String getC_phone() {
return c_phone;
}
public void setC_phone(String c_phone) {
this.c_phone = c_phone;
}
public String getC_image() {
return c_image;
}
public void setC_image(String c_image) {
this.c_image = c_image;
}
public String getC_description() {
return c_description;
}
public void setC_description(String c_description) {
this.c_description = c_description;
}
public UserEntities getUserEntities() {
return userEntities;
}
public void setUserEntities(UserEntities userEntities) {
this.userEntities = userEntities;
}
#Override
public String toString() {
return "ContactEntities [c_id=" + c_id + ", c_name=" + c_name + ", second_c_name=" + second_c_name + ", c_work="
+ c_work + ", c_emali=" + c_emali + ", c_phone=" + c_phone + ", c_image=" + c_image + ", c_description="
+ c_description + ", userEntities=" + userEntities + "]";
}
}
this is my user entity...
package com.example.jpa.userEntities;
#Entity
#Table(name = "UserEntities")
public class UserEntities {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long userId;
#NotBlank
#Size(min = 2, max = 20)
private String userName;
#NotBlank
#Column(unique = true)
#Email(regexp = "^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+#[a-zA-Z0-9-]+(?:\\.[a-zA-Z0-9-]+)*$")
private String userEmail;
#NotNull(message = "password should not be blank")
private String userPass;
private boolean enable;
private String role;
#Column(length = 500)
private String userAbout;
#OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "userEntities", orphanRemoval = true)
private List<ContactEntities> contactList = new ArrayList<>();
public UserEntities() {
}
public String getRole() {
return role;
}
public void setRole(String role) {
this.role = role;
}
public long getUserId() {
return userId;
}
public void setUserId(long userId) {
this.userId = userId;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getUserEmail() {
return userEmail;
}
public void setUserEmail(String userEmail) {
this.userEmail = userEmail;
}
public String getUserPass() {
return userPass;
}
public void setUserPass(String userPass) {
this.userPass = userPass;
}
public boolean isEnable() {
return enable;
}
public void setEnable(boolean enable) {
this.enable = enable;
}
public String getRoll() {
return role;
}
public void setRoll(String role) {
this.role = role;
}
public String getUserAbout() {
return userAbout;
}
public void setUserAbout(String userAbout) {
this.userAbout = userAbout;
}
public List<ContactEntities> getContactList() {
return contactList;
}
public void setContactList(List<ContactEntities> contactList) {
this.contactList = contactList;
}
#Override
public String toString() {
return "UserEntities [userId=" + userId + ", userName=" + userName + ", userEmail=" + userEmail + ", userPass="
+ userPass + ", enable=" + enable + ", role=" + role + ", userAbout=" + userAbout + ", contactList="
+ contactList + "]";
}
}
Repository of Contact
package com.example.jpa.repo;
import java.util.List;
import com.example.jpa.contactEntities.ContactEntities;
public interface ContactRepo extends JpaRepository<ContactEntities, Integer> {
#Query("from ContactEntities as c where c.userEntities.userId=:u_Id")
public List<ContactEntities> findContactsByUser(#Param("u_Id") long l);
}
Repository of User
package com.example.jpa.repo;
import com.example.jpa.userEntities.UserEntities;
#EnableJpaRepositories
public interface UserRepository extends JpaRepository<UserEntities, Integer> {
#Query("select u from UserEntities u where u.userEmail=:userEmail")
public UserEntities getUserByUserName(#Param("userEmail") String userEmail);
}
User controller
package com.example.jpa.controller;
#Controller
#RequestMapping("/user")
public class UserController {
#Autowired
private UserRepository userRepository;
#Autowired
private ContactRepo contactRepo;
#ModelAttribute
public void addCommonData(Model model, Principal principal) {
String username = principal.getName();
System.out.println("UserName:-" + username);
UserEntities userEntities = this.userRepository.getUserByUserName(username);
System.out.println("User:- " + userEntities);
model.addAttribute("userEntities", userEntities);
}
//dash board home
#RequestMapping("/index")
public String dashboard(Model model, Principal principal) {
return "normal/user_dashboard";
}
// open add form handler
#GetMapping("/add-contact")
public String openAddContactForm(Model model) {
model.addAttribute("title", "Add contact");
model.addAttribute("contactEntitie", new ContactEntities());
return "normal/add_contact";
}
// processing and contact form
#PostMapping("/upload")
public String processContact(#ModelAttribute ContactEntities contactEntitie,
#RequestParam("userImage") MultipartFile multipartFile, Principal principal, Model model,
HttpSession session) {
try {
model.addAttribute("contactEntitie", new ContactEntities());
String name = principal.getName();
UserEntities userEntities = userRepository.getUserByUserName(name);
userEntities.getContactList().add(contactEntitie);
// processing and uploading file....
if (multipartFile.isEmpty()) {
System.out.println("File is empty");
} else {
// upload the the file and update
contactEntitie.setC_image(multipartFile.getOriginalFilename());
File saveFile = new ClassPathResource("static/img").getFile();
// bring the folder path...
Path path = Paths
.get(saveFile.getAbsolutePath() + File.separator + multipartFile.getOriginalFilename());
Files.copy(multipartFile.getInputStream(), path, StandardCopyOption.REPLACE_EXISTING);
System.out.println("Image is uploaded");
}
userRepository.save(userEntities);
System.out.println("Datas are :" + contactEntitie);
// message success
session.setAttribute("message", new Messages("Your Contact is added !!! Add more...", "success"));
} catch (Exception e) {
System.out.println("Error: " + e.getMessage());
e.printStackTrace();
// error message
session.setAttribute("message", new Messages("Something went wrong !!! Try Again", "danger"));
}
return "normal/add_contact";
}
// show Contact handler
#GetMapping("/show-contacts")
public String showContact(Model model, Principal principal) {
model.addAttribute("title", "Show Contacts");
String userName = principal.getName();
UserEntities userEntities = userRepository.getUserByUserName(userName);
List<ContactEntities> contactList = contactRepo.findContactsByUser(userEntities.getUserId());
model.addAttribute("contactList", contactList);
return "normal/show_contacts";
}
}
All configuration class
User Details configuration
package com.example.jpa.Myconfiguration;
public class UserDetailsServiceImple implements UserDetailsService {
#Autowired
private UserRepository userRepository;
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
// fetching data from DB
UserEntities userEntities = userRepository.getUserByUserName(username);
if (userEntities == null) {
throw new UsernameNotFoundException("Could not found user !!!");
}
CustomUserDetails customUserDetails = new CustomUserDetails(userEntities);
return customUserDetails;
}
}
package com.example.jpa.Myconfiguration;
public class CustomUserDetails implements UserDetails {
private UserEntities userEntities;
public CustomUserDetails(UserEntities userEntities) {
super();
this.userEntities = userEntities;
}
#Override
public Collection<? extends GrantedAuthority> getAuthorities() {
SimpleGrantedAuthority simpleGrantedAuthority = new SimpleGrantedAuthority(userEntities.getRoll());
return List.of(simpleGrantedAuthority);
}
#Override
public String getPassword() {
return userEntities.getUserPass();
}
#Override
public String getUsername() {
return userEntities.getUserEmail();
}
#Override
public boolean isAccountNonExpired() {
return true;
}
#Override
public boolean isAccountNonLocked() {
return true;
}
#Override
public boolean isCredentialsNonExpired() {
return true;
}
#Override
public boolean isEnabled() {
return true;
}
}
Application property:-
#Database configuration
spring.datasource.url=jdbc:mysql://localhost:3306/smartcontact
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.cj.jdbc.NonRegisteringDriver
spring.jpa.properties.hibernate.dilact=org.hibernate.dialect.Mysql8Dialect
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=false
spring.jpa.properties.hibernate.globally_quoted_identifiers=true
spring.servlet.multipart.enabled=true
spring.servlet.multipart.file-size-threshold=2KB
spring.servlet.multipart.max-file-size=10MB
spring.servlet.multipart.max-request-size=10MB
I am updating user's information like first name and last name and I am getting first name and last name in all the pages for welcome message.
I have two controllers one for ajax request mapping and the other for normal request mapping.
Normal request mapping controller have this method. In this controller all page navigation is present and some request mapping which are not ajax calls
private String getPrincipalDisplay() {
GreenBusUser user = null;
String userName = "";
Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
if (principal instanceof UserDetails) {
user = (GreenBusUser) principal;
userName = user.getFirstName() + " " + user.getLastName();
} else {
userName = "";
}
return userName;
}
This is how I am getting the username on every page by return string of this function I am adding it in ModelMap object.
When I update user's information I am doing in ajax request mapping.
#RequestMapping(value = "/restify/updateUserData", method = RequestMethod.PUT, headers = "Accept=application/json")
public ServiceResponse forgotPassword(#RequestBody Object user)
{
//logger.debug("getting response");
return setDataPut("http://localhost:7020/forgotPassword",user);
}
user is an Object type which has json data. Now how do I retrieve data from object and update my first name and last name in principal.
This is my GreenBusUser class
public class GreenBusUser implements UserDetails
{
private static final long serialVersionUID = 1L;
private String username;
private String password;
private Collection<? extends GrantedAuthority> grantedAuthorities;
private String firstName;
private String lastName;
public GreenBusUser(String username,String password,Collection<? extends GrantedAuthority> authorities,String firstName, String lastName)
{
this.username = username;
this.password = password;
this.grantedAuthorities = authorities;
this.firstName=firstName;
this.lastName=lastName;
this.grantedAuthorities.stream().forEach(System.out::println);
}
public Collection<? extends GrantedAuthority> getAuthorities()
{
return grantedAuthorities;
}
public String getFirstName() {
return firstName;
}
public String getLastName() {
return lastName;
}
public String getPassword()
{
return password;
}
public String getUsername()
{
return username;
}
public boolean isAccountNonExpired()
{
return true;
}
public boolean isAccountNonLocked()
{
return true;
}
public boolean isCredentialsNonExpired()
{
return true;
}
public boolean isEnabled()
{
return true;
}
}
UPDATE:::::
I have updated your code and applied some part of your answer into mine but still I ran into a problem
#RequestMapping(value="/updateUser",method=RequestMethod.GET)
public String updateUser(ModelMap model) {
UserInfo user = getUserObject();
GreenBusUser newGreenBususer = null;
List<User> list = new ArrayList<User>();
list = FetchDataService.fetchDataUser("http://localhost:8060/GetuserbyUserName?username=" + getPrincipal(), user.getUsername(), user.getPassword());
logger.debug("new user list ----->>>"+list.size());
User newuser=(User)list.get(0);
UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(
SecurityContextHolder.getContext().getAuthentication().getPrincipal(), SecurityContextHolder.getContext().getAuthentication().getCredentials());
Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
newGreenBususer=(GreenBusUser)principal;
logger.debug("newGreenBususerDetails---->>>"+newGreenBususer.toString());
newGreenBususer.setFirstName(newuser.getFirstName());
newGreenBususer.setLastName(newuser.getLastName());
if(newGreenBususer.getFirstName()!=null) {
logger.debug("got my first name");
}
if(newGreenBususer.getLastName()!=null) {
logger.debug("got my last name");
}
auth.setDetails(newGreenBususer);
SecurityContext context = SecurityContextHolder.getContext();
context.setAuthentication(auth);
SecurityContextHolder.setContext(context);
model.addAttribute("user", getPrincipalDisplay());
model.addAttribute("userData", list);
model.addAttribute("check", true);
return "GreenBus_updateProfile_User";
}
At first it sets the firstname and lastname to GreenBusUser and then there is setDetails method when I reload the page it says No user found when I am calling getUserObject() method at the top of this method.
private X2CUser getUserObject() {
X2CUser userName = null;
Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
if (principal instanceof UserDetails) {
userName = ((X2CUser) principal);
} else {
logger.info("No user found");
}
return userName;
}
If you are updating the password, then it will be good to logout the user and tell him to relogin.
Try this code .. It might help you.
UsernamePasswordAuthenticationToken authReq = new UsernamePasswordAuthenticationToken(user, pass);
Authentication auth = authManager.authenticate(authReq);
SecurityContext sc = SecurityContextHolder.getContext();
securityContext.setAuthentication(auth);
I have finally resolved my problem though I have later added some code in my question part in UPDATE section.
Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
newGreenBususer=(GreenBusUser)principal;
newGreenBususer.setFirstName(newuser.getFirstName());
newGreenBususer.setLastName(newuser.getLastName());
Yes that's all need to be done.
This part--->>
auth.setDetails(newGreenBususer);
SecurityContext context = SecurityContextHolder.getContext();
context.setAuthentication(auth);
SecurityContextHolder.setContext(context);
set new context making security pointing to null when I reload still not clear because I am setting the details before reload so its like I get new context but I have set the new user details.
Though I have finally resolved my problem but if anyone could shed some light why it was happening then I will accept his/her answer.
Thanks alot for your support. Keep Learning!
given a scenario , there is a HTML contents OR some method in a controller, which only allow to be access by "a" role.
from above, we achieve by using #hasRole("a")
However, in my case, the role is dynamic:
Example, admin add a new role "b", and able to be access these content.
So how to do it?
I tried ACL, but that's only protect the domain object with an id.
there is an annotation called hasAuthority, but i cant search
anythings from internet.
there is an ObjectIdentityImpl, not really
how to implement.
EDIT: my solution
After study, ACL is more on secure list of object.
Example: u want to secure staff table, some staff record(like CEO,manager) are only accessible by higher management. the rest of staff record are view-able by all. This is what ACL to do.
However, when we need to protect some method,controller,url,static content.... the ACL is not suitable for this. we need to use hasAuthority or hasPermission or hasRole or ......
In some web systems, there are only few roles, admin and user. For this case, hasAuthority or hasRole is quite enough for this. u just annotate #hasRole('admin') for the resources u want to protect.
However,in some systems, there are dynamic role, for example: admin create a new role "temporary_user", but the contoller or method is annotate by #hasRole('user'), which not accessible by "temporary_user".
in this case, based on my understanding, there are few ways to do.
create many roles based on how many resources u want to protect. for example: assign 'role_getRecord' to getRecords(),assign 'role_writeRecord' to writeRecord(). this is a way to do without changing spring security mechanism, but will have a lot of roles on your database table, and more complex system, will have more.
#hasPermission - this is what i use right now. i create a CustomGrantedAuthority, in order to have more flexible implementation. and i do have a CustomUserDetailsService and CustomSpringSecurityUser, when user login will create CustomSpringSecurityUser with collection of CustomGrantedAuthority then return CustomSpringSecurityUser to CustomUserDetailsService. and also i do have a CustomPermission to verify the permission.
Please vote UP, if your think is useful, and please comment if i wrong or does havea better way to do it.
here is my code
CustomSpringSecurityUser
public class CustomSpringSecurityUser implements UserDetails, CredentialsContainer {
private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID;
private String password;
private final String username;
private final Set<GrantedAuthority> authorities;
private final boolean accountNonExpired;
private final boolean accountNonLocked;
private final boolean credentialsNonExpired;
private final boolean enabled;
public CustomSpringSecurityUser(String username, String password, Collection<? extends GrantedAuthority> authorities) {
this(username, password, true, true, true, true, authorities);
}
public CustomSpringSecurityUser(String username, String password, boolean enabled, boolean accountNonExpired,
boolean credentialsNonExpired, boolean accountNonLocked, Collection<? extends GrantedAuthority> authorities) {
if (((username == null) || "".equals(username)) || (password == null)) {
throw new IllegalArgumentException("Cannot pass null or empty values to constructor");
}
this.username = username;
this.password = password;
this.enabled = enabled;
this.accountNonExpired = accountNonExpired;
this.credentialsNonExpired = credentialsNonExpired;
this.accountNonLocked = accountNonLocked;
// this.authorities = Collections.unmodifiableSet(sortAuthorities(authorities));
this.authorities = new HashSet<GrantedAuthority>(authorities);
}
public Collection<GrantedAuthority> getAuthorities() {
return authorities;
}
public String getPassword() {
return password;
}
public String getUsername() {
return username;
}
public boolean isEnabled() {
return enabled;
}
public boolean isAccountNonExpired() {
return accountNonExpired;
}
public boolean isAccountNonLocked() {
return accountNonLocked;
}
public boolean isCredentialsNonExpired() {
return credentialsNonExpired;
}
public void eraseCredentials() {
password = null;
}
private static SortedSet<GrantedAuthority> sortAuthorities(Collection<? extends GrantedAuthority> authorities) {
Assert.notNull(authorities, "Cannot pass a null GrantedAuthority collection");
SortedSet<GrantedAuthority> sortedAuthorities =
new TreeSet<GrantedAuthority>(new AuthorityComparator());
for (GrantedAuthority grantedAuthority : authorities) {
Assert.notNull(grantedAuthority, "GrantedAuthority list cannot contain any null elements");
sortedAuthorities.add(grantedAuthority);
}
return sortedAuthorities;
}
private static class AuthorityComparator implements Comparator<GrantedAuthority>, Serializable {
private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID;
public int compare(GrantedAuthority g1, GrantedAuthority g2) {
if (g2.getAuthority() == null) {
return -1;
}
if (g1.getAuthority() == null) {
return 1;
}
return g1.getAuthority().compareTo(g2.getAuthority());
}
}
#Override
public boolean equals(Object rhs) {
if (rhs instanceof CustomSpringSecurityUser) {
return username.equals(((CustomSpringSecurityUser) rhs).username);
}
return false;
}
#Override
public int hashCode() {
return username.hashCode();
}
#Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(super.toString()).append(": ");
sb.append("Username: ").append(this.username).append("; ");
sb.append("Password: [PROTECTED]; ");
sb.append("Enabled: ").append(this.enabled).append("; ");
sb.append("AccountNonExpired: ").append(this.accountNonExpired).append("; ");
sb.append("credentialsNonExpired: ").append(this.credentialsNonExpired).append("; ");
sb.append("AccountNonLocked: ").append(this.accountNonLocked).append("; ");
if (!authorities.isEmpty()) {
sb.append("Granted Authorities: ");
boolean first = true;
for (GrantedAuthority auth : authorities) {
if (!first) {
sb.append(",");
}
first = false;
sb.append(auth);
}
} else {
sb.append("Not granted any authorities");
}
return sb.toString();
}
}
CustomGrantedAuthority
public class CustomGrantedAuthority implements GrantedAuthority{
private String role;
private String permission,action;
public String getPermission() {
return permission;
}
public void setPermission(String permission) {
this.permission = permission;
}
public String getAction() {
return action;
}
public void setAction(String action) {
this.action = action;
}
public String getRole() {
return role;
}
public void setRole(String role) {
this.role = role;
}
#Override
public String getAuthority() {
return role;
}
}
CustomeUserDetailsService
#Service
#Transactional(readOnly = true)
public class CustomUserDetailsService implements UserDetailsService {
#Autowired
private OcUserService userService;
private static final Logger logger = LoggerFactory.getLogger(CustomUserDetailsService.class);
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
try {
sg.com.xx.xx.table.OcUser u = userService.findByLoginname(username);
String pass = sg.com.xx.xx.table.OcUser.byteToHex(u.getPassword());
Collection<? extends GrantedAuthority> permissionList = userService.getPermissionByUserId(u.getId());
boolean enabled = true;
boolean accountNonExpired = true;
boolean credentialsNonExpired = true;
boolean accountNonLocked = true;
CustomSpringSecurityUser user = new CustomSpringSecurityUser(u.getLoginname(),
pass,
enabled,
accountNonExpired,
credentialsNonExpired,
accountNonLocked,
permissionList);
return user;
} catch (Exception e) {
logger.error("==============================================");
logger.error(e.toString());
return null;
}
}
}
CustomPermission
public class CustomPermission implements PermissionEvaluator {
#Override
public boolean hasPermission(Authentication authentication, Object targetDomainObject, Object permission) {
Collection<? extends GrantedAuthority> x = authentication.getAuthorities();
for(Object o : x)
{
CustomGrantedAuthority y = (CustomGrantedAuthority) o ;
if(y.getPermission().equals(targetDomainObject) )
if( y.getAction().equals(permission) )
return true;
}
return false;
}
#Override
public boolean hasPermission(Authentication authentication, Serializable targetId, String targetType, Object permission) {
int a = 5;
return true;
}
}
I don't know what you mean under resources, but I found that the best way to work with it in spring, is to grant users permissions (authorities) instead of roles, you still have roles, but they are there just to bundle up the permissions. After this is set up, you assign actual permissions for your views and methods. I found a data model here:
http://springinpractice.com/2010/10/27/quick-tip-spring-security-role-based-authorization-and-permissions/
What if you use Java Reflection to get every controller method, then you asign any of these methods to role relation to build a "dynamic role"? This way you could add or remove any action to any role at any moment. Maybe Spring Security is not required this way.
I cannot generate an appropriate GUI via roo for a one-to-many relationship. In particular, I would need a multiple choice element to select among the authorities (spring security) to associate to the user.
I created my RegisteredUser class:
#RooJavaBean
#RooToString
#RooJpaActiveRecord
public class RegisteredUser extends MyUser implements UserDetails,
CredentialsContainer {
private String password;
private String username;
private Boolean enabled = true;
private Boolean accountNonExpired = true;
private Boolean credentialsNonExpired = true;
private Boolean accountNonLocked = true;
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private Set<MyBaseAuthority> authorities = new HashSet<MyBaseAuthority>();
#Override
public void eraseCredentials() {
password = null;
}
#Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return authorities;
}
#Override
public String getPassword() {
return password;
}
#Override
public String getUsername() {
return username;
}
#Override
public boolean isAccountNonExpired() {
return accountNonExpired;
}
#Override
public boolean isAccountNonLocked() {
return accountNonLocked;
}
#Override
public boolean isCredentialsNonExpired() {
return credentialsNonExpired;
}
#Override
public boolean isEnabled() {
return enabled;
}
}
Then MyBaseAuthority class:
#RooJavaBean
#RooToString
#RooJpaActiveRecord
public class MyBaseAuthority extends ObjectWithId implements
GrantedAuthority {
private String authority;
#Override
public String getAuthority() {
return authority;
}
}
Then I had to manually create the controller for MyBaseAuthority, but not for RegisteredUser (generated by webmvc command):
#RequestMapping("/registeredusers")
#Controller
#RooWebScaffold(path = "registeredusers", formBackingObject = RegisteredUser.class)
public class RegisteredUserController {
}
#RequestMapping("/authorities")
#Controller
#RooWebScaffold(path = "authorities", formBackingObject = MyBaseAuthority.class)
public class MyBaseAuthorityController {
}
On the GUI, I can create and list all authorities and registered users. However, when creating a registered user, I can only set string fields and boolean fields, but not the one-to-many relationship. How can I fix that?
If I were trying to acomplish this task I would print out all of my checkboxes with the available options as array keys with a name like so:
<input type="checkbox" name="role[]" value="ROLE_ONE">
<input type="checkbox" name="role[]" value="ROLE_TWO">
Then, I would map these parameters to a String[] array like in this post
#RequestParam(value="myParam[]" String roles)
I would then loop over the strings and add create the MyBaseAuthority objects, attach your user and persist() them.
User enters Username, password and system generates unique field. Each username password combination along with an auto generated unique field is stored in a List as an object.
I want to find out if the username-password combination is repeated or not in the list (without considering the unique key).
I wanted to avoid using for loops to figure this out. Using hashmap to find out if there are repeated combinations-
//hm is the hashmap...
//up is the list....
for(int i=0; i<up.length(); i++){
if(hm.contains(up[i])){
System.out.println("Repeated combination");
break;
}
else{
hm.put(up[i],i);
}
}
However the object has a unique auto generated field and the above logic wouldn't work. Any suggestions to achieve this in the fastest possible way.
I assume that up[i] is some class(User) which has username, password and unique_id as three fields.
If that's true you can create wrapper around this class(UserWrapper) and override equals/hashCode methods to rely only on username/password attributes of User class.
That should be really quick to code/test
EDIT: Sample classes are below. You could you LinkedHashMap (so you'll have map functionality and still have users ordered in the same way as you put them in)
class User {
private final String id = UUID.randomUUID().toString();
private final String username;
private final String password;
public User(String username, String password) {
this.username = username;
this.password = password;
}
#Override
public boolean equals(Object obj) {
if (obj instanceof User) {
User user = (User) obj;
return id.equals(user.getId()) &&
username.equals(user.getUsername()) &&
password.equals(user.getPassword());
}
return false;
}
public int hashCode() {
return id.hashCode() + username.hashCode() * 31 + password.hashCode() * 31 * 31;
}
public String getId() {
return id;
}
public String getUsername() {
return username;
}
public String getPassword() {
return password;
}
}
Wrapper:
class UserWrapper {
private final User user;
public UserWrapper(User user) {
this.user = user;
}
#Override
public boolean equals(Object obj) {
if (obj instanceof UserWrapper) {
UserWrapper userWrapper = (UserWrapper) obj;
return user.getUsername().equals(userWrapper.getUser().getUsername()) &&
user.getPassword().equals(userWrapper.getUser().getPassword());
}
return false;
}
public int hashCode() {
return user.getUsername().hashCode() + user.getPassword().hashCode() * 31;
}
public User getUser() {
return user;
}
}
Finder:
class DuplicateUserFinder {
public List<UserWrapper> findDuplicates(List<UserWrapper> allUsers) {
final List<UserWrapper> duplicateList = new ArrayList<UserWrapper>();
final Set<UserWrapper> duplicateSet = new HashSet<UserWrapper>();
for (UserWrapper wrapper : allUsers) {
if (duplicateSet.contains(wrapper)) {
duplicateList.add(wrapper);
} else {
duplicateSet.add(wrapper);
}
}
return duplicateList;
}
}
Unit Test:
public class DuplicateUserFinderTest {
private final DuplicateUserFinder finder = new DuplicateUserFinder();
#Test
public void shouldReturnEmptyIfNoDuplicates() {
User user1 = new User("user1", "pass1");
User user2 = new User("user2", "pass2");
UserWrapper userWrapper1 = new UserWrapper(user1);
UserWrapper userWrapper2 = new UserWrapper(user2);
Assert.assertTrue(finder.findDuplicates(Arrays.asList(userWrapper1, userWrapper2)).isEmpty());
}
#Test
public void shouldReturnDuplicates() {
User user1 = new User("user", "pass");
User user2 = new User("user", "pass");
UserWrapper userWrapper1 = new UserWrapper(user1);
UserWrapper userWrapper2 = new UserWrapper(user2);
Assert.assertTrue(finder.findDuplicates(Arrays.asList(userWrapper1, userWrapper2)).contains(userWrapper2));
Assert.assertThat(finder.findDuplicates(Arrays.asList(userWrapper1, userWrapper2)).size(), CoreMatchers.equalTo(1));
}
}