I created a user with a fake username and a password. I tried to log in this user with java code. I can obtain username correctly by
SecurityContextHolder.getContext().getAuthentication().getName()
However, the jsp tag
<sec:authorize access="!isAuthenticated()">
is still false. And <sec:authentication property="name" /> is anonymousUser. How can I fix it? Thanks
Collection<GrantedAuthority> grantedAuthorities = new ArrayList<GrantedAuthority>();
GrantedAuthority grantedAuthority = new GrantedAuthority() {
//anonymous inner type
public String getAuthority() {
return "ROLE_USER";
}
};
grantedAuthorities.add(grantedAuthority);
User tempUser = new User(username, passwd, true, true, true, true, grantedAuthorities);
Authentication authentication = new UsernamePasswordAuthenticationToken(tempUser, "", grantedAuthorities);
SecurityContextHolder.getContext().setAuthentication(authentication);
HttpSession session = httpServletRequest.getSession();
User authUser = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
session.setAttribute("username", authUser.getUsername());
session.setAttribute("authorities", authentication.getAuthorities());
Related
Spring Security 4.2.4. Java 8
I need to change the permissions of users without re-logging them. It's my service:
#Component
public class AuthoritiesUpdater {
private final UserRoleService userRoleService;
#Autowired
public AuthoritiesUpdater(UserRoleService userRoleService) {
this.userRoleService = userRoleService;
}
public void update(User user) {
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
List<UserRole> userRoles = userRoleService.findByUser(user);
List<GrantedAuthority> actualAuthorities = userRoles.stream().map(userRole -> new
SimpleGrantedAuthority(userRole.getRole())).collect(Collectors.toList());
Authentication newAuth = new
UsernamePasswordAuthenticationToken(auth.getPrincipal(), auth.getCredentials(), actualAuthorities);
SecurityContextHolder.getContext().setAuthentication(newAuth);
}
}
But there is a trouble. I need to change roles for any user. Let's say I'm manager and I want to change roles for test user. I need to reload the permissions after saving configuration and test user will have new roles when he press F5 button and reload the page without re-login.
But SecurityContextHolder.getContext().getAuthentication(); returns authentication object only for current user (manager). I need to get authentication object for changed user to call new
UsernamePasswordAuthenticationToken(auth.getPrincipal(), auth.getCredentials(), actualAuthorities);.
Can I get authentication object for any user or can I solve this problem in another way? Maybe I can get authentication object uses session registry?
P.S.: Doing an expired session for user isn't a good option.
Excellent answer, thanks #virkom!
For newer users, the steps are as follow:
Create a list of authorities you want the user to have (including the previous one(s) they had). In this case (below) I created a set so they would be unique.
Create an authentication object which matches the user you want to authenticate with their new authorities. In this case, I used a user who was in memory to simplify the example, but database authentication is preferred!
Update the security context with the new authentication information. This will have the effect of a refresh of the user's credentials.
A code snippet is shown below:
Set<GrantedAuthority> authorities = new HashSet<>();
authorities.add(new SimpleGrantedAuthority("USER"));
authorities.add(new SimpleGrantedAuthority("ADMIN"));
Authentication reAuth = new UsernamePasswordAuthenticationToken("user",new
BCryptPasswordEncoder().encode("password"),authorities);
SecurityContextHolder.getContext().setAuthentication(reAuth);
Sample code is available on github: https://github.com/aoa4eva/ContextDemo
The solution is a bit easier than I thought. I have a user.
And I can call UsernamePasswordAuthenticationToken(user.getUserName(), user.getPassword(), actualAuthorities); instead of UsernamePasswordAuthenticationToken(auth.getPrincipal(), auth.getCredentials(), actualAuthorities);.
I don't need to get authentication object. Final version of service:
#Component
public class AuthoritiesUpdater {
private final UserRoleService userRoleService;
#Autowired
public AuthoritiesUpdater(UserRoleService userRoleService) {
this.userRoleService = userRoleService;
}
public void update(User user) {
List<UserRole> userRoles = userRoleService.findByUser(user);
List<GrantedAuthority> actualAuthorities = userRoles.stream().map(userRole -> new SimpleGrantedAuthority(userRole.getRole())).collect(Collectors.toList());
Authentication newAuth = new UsernamePasswordAuthenticationToken(user.getUsername(), user.getPassword(), actualAuthorities);
SecurityContextHolder.getContext().setAuthentication(newAuth);
}
}
i'm trying to update the roles associated with the current logged user without log out, but it's not working as i wish.
Here is my code :
PreAuthenticatedAuthenticationToken authtoken_orig = (PreAuthenticatedAuthenticationToken) SecurityContextHolder
.getContext().getAuthentication();
Collection<? extends GrantedAuthority> Authorities_orig = authtoken_orig.getAuthorities();
ArrayList<SimpleGrantedAuthority> Authorities_new = new ArrayList<SimpleGrantedAuthority>();
for (GrantedAuthority sga : Authorities_orig) {
SimpleGrantedAuthority tmpsga = (SimpleGrantedAuthority) sga;
if (tmpsga.getAuthority().compareTo("ROLE_UNKNOWN") != 0
&& tmpsga.getAuthority().compareTo("ROLE_SIGNER") != 0) {
Authorities_new.add(tmpsga);
}
}
SimpleGrantedAuthority role_signer_auth = new SimpleGrantedAuthority("ROLE_SIGNER");
Authorities_new.add(role_signer_auth);
PreAuthenticatedAuthenticationToken authtoken_new = new PreAuthenticatedAuthenticationToken(
authtoken_orig.getPrincipal(), authtoken_orig.getCredentials(), Authorities_new);
SecurityContextHolder.clearContext();
SecurityContextHolder.createEmptyContext().setAuthentication(authtoken_new);
Please could you advice ?
Thanks in advance
David L.
First eval Granted Authority for the logged-in user like:
GrantedAuthority grantedAuthority = getNextRoleToAssign(context.getUserDetails());
Now, then initialiaze UsernamePasswordAuthenticationToken by using below code:
Authentication auth = new UsernamePasswordAuthenticationToken(authorisedUser, passowrd,Collections<GrantedAuthorities>);
Finally, set this Authentication into the Security context for the current User as mentioned below:
SecurityContextHolder.getContext().setAuthentication(auth);
Your method works, my roles assumption was erroneously based on the principal authorities and not on the authentication authorities. The result of
sc.getAuthentication().getAuthorities()
is not the same as
((UserDetails)sc.getAuthentication().getPrincipal()).getAuthorities()
(Where sc is the securitycontext)
How do I change my the current user that is currently login in the application?
Here's the code that I use to switch the current user to it's another account/relative account.
User user = userService.getUser(dependentId);
String access_token = authorizationToken.replace("Bearer","").trim();
if(SecurityContextHolder.getContext().getAuthentication() != null) {
User relative = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
for(Role role: relative.getRoles()) {
if(role.getName().equals("PATIENT")) {
OAuth2Authentication oauth2 = defaultTokenServices.loadAuthentication(access_token);
User o3 =(User)SecurityContextHolder.getContext()
.getAuthentication()
.getPrincipal();
Authentication authentication = new UsernamePasswordAuthenticationToken(user,
user.getPassword()
,user.getAuthorities());
OAuth2Authentication oAuth2Authentication = new OAuth2Authentication(oauth2.getOAuth2Request(),authentication);
SecurityContextHolder.getContext().setAuthentication(oAuth2Authentication);
User o5 = (User)SecurityContextHolder.getContext().getAuthentication().getPrincipal();
break;
}
}
I ran the code on my debugger, I am expecting o5 to be a different object from o3 but they are still the same
I have a User table and a UserInfo table which keeps the personal information of the user. What I am trying to do is adding personel information after log in. There is OneToOne relationship between tables with userId column so I defined it like this :
UserInfo class :
public class UserInfo {
//...
#OneToOne
#JoinColumn(name="user_id")
private User user;
// ...
}
User class :
public class User implements UserDetails {
// ...
#OneToOne(mappedBy="user", cascade = CascadeType.ALL, fetch=FetchType.LAZY,optional=true)
private UserInfo userInfo;
...
}
After I log in, I want to add some user information to the db for current user. But I don't know how can i save user information in controller? Should I save User object like below? I've searched about it and there is a way to get current user's information:
(User)SecurityContextHolder.getContext().getAuthentication().getPrincipal();
But when I try to use it in the controller it just returns null. How can I do such operations (adding pers. info) for logged in user?
#RequestMapping(value = "/show", method = RequestMethod.POST)
public ModelAndView newUser(ModelMap model, Principal principal) {
ModelAndView result = new ModelAndView("home");
User user = (User)SecurityContextHolder.getContext().getAuthentication().getPrincipal();
UserInfo userinfo = new UserInfo();
userinfo.setPlacesVisit(userinfo.getPlacesVisit());
user.setUserInfo(userinfo);
userService.save(user);
String message = "Userinfo was successfully added.";
result.addObject("message", message);
return result;
}
instead of saving current object update current object. First get current user object in controller after that set UserInfo then update user object in database.
#RequestMapping(value = "/show", method = RequestMethod.POST)
public ModelAndView newUser(ModelMap model, Principal principal) {
String userName=principal.getName(); // username or email using user login
User user=userService.getUserByName(userName); // retrieve current user information
UserInfo userinfo = new UserInfo(); // create userinfor object
userinfo.setPlacesVisit(userinfo.getPlacesVisit());
user.setUserInfo(userinfo); // set userinfo to user
userService.update(user); // update user
String message = "Userinfo was successfully added.";
result.addObject("message", message);
return result;
}
You can retrieve to user with the Principal parameter :
public ModelAndView newUser(ModelMap model, Principal principal) {
User activeUser = (User) ((Authentication) principal).getPrincipal();
}
SecurityContextHolder is a part of Spring Security. If you want to use this component, you have to set up Spring Security for the log in of your application to be able to retrieve, in your REST controller, the current user (javax.security.Principal)
Spring Security Documentation
You can use session to save session attributes. In spring, you can access session using
ServletRequestAttributes attr = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
HttpSession session = attr.getRequest().getSession();
You can save your logged user in session:
FacesContext facesContext = FacesContext.getCurrentInstance();
ExternalContext externalContext = facesContext.getExternalContext();
HttpServletRequest request = (HttpServletRequest) externalContext.getRequest();
request.getSession().setAttribute("key", user);
and if you want get currently logged user, just:
(User) user = ((HttpServletRequest) request).getSession().getAttribute("key")
This example is in JSF, but I am sure that is also possible without JSF
I'm using the following method in a Spring Controller to allow authentication via Ajax. It works, but it doesn't seem to create a cookie or anything that makes the authentication persistent.
#RequestMapping(method = RequestMethod.POST)
#ResponseBody
public LoginStatus login(#RequestParam("j_username") String username,
#RequestParam("j_password") String password) {
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(username, password);
try {
Authentication auth = authenticationManager.authenticate(token);
SecurityContextHolder.getContext().setAuthentication(auth);
return new LoginStatus(auth.isAuthenticated(), auth.getName());
} catch (BadCredentialsException e) {
return new LoginStatus(false, null);
}
}
What do I need to do to make the authentication persistent?
Make sure
you have SecurityContextPersistenceFilter configured
you are not setting create-session attribute of <security:http> tag to none.