Spring Security: Set GrantedAuthorities - spring

Is there anyway to set the List<GrantedAuthority> in the Authentication/UserDetailsImpl object? In my application, I have two layers of security, one for logging in (which uses my custom login authenticator, in the class I set the Authentication object using the UsernamePasswordAuthenticationToken) and one for a "challenge question" where the user is prompted to answer a particular question.
What I want to do is add a GrantedAuthority to the current List<GrantedAuthority>, which was created during the login process, after the user answers the challenge question.
Is this possible?

you can do it with following code:
Collection<SimpleGrantedAuthority> oldAuthorities = (Collection<SimpleGrantedAuthority>)SecurityContextHolder.getContext().getAuthentication().getAuthorities();
SimpleGrantedAuthority authority = new SimpleGrantedAuthority("ROLE_ANOTHER");
List<SimpleGrantedAuthority> updatedAuthorities = new ArrayList<SimpleGrantedAuthority>();
updatedAuthorities.add(authority);
updatedAuthorities.addAll(oldAuthorities);
SecurityContextHolder.getContext().setAuthentication(
new UsernamePasswordAuthenticationToken(
SecurityContextHolder.getContext().getAuthentication().getPrincipal(),
SecurityContextHolder.getContext().getAuthentication().getCredentials(),
updatedAuthorities)
);

The UserDetails.getAuthorities() method just returns a Collection<GrantedAuthority> object. You can use the appropriate Collection method to add your new authority to that collection.
Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
if (principal instanceof UserDetails) {
((UserDetails) principal).getAuthorities().add(New GrantedAuthorityImpl("ROLE_FOO"));
}
Selah.

Related

authorities Collection from Collection<GrantedAuthority> authorities = jwtGrantedAuthoritiesConverter.convert(jwt) is empty

I am testing a method that override some parameter in jwtGrantedAuthoritiesConverter but always when i debug get that this collection (Collection authorities = jwtGrantedAuthoritiesConverter.convert(jwt);) is empty did not know the reason !! here is my code
can some one help me please .. Thank you!
class SecurityConfigTest {
#Test
void convertWithOverriddenGrantedAuthoritiesConverter() {
Jwt jwt = this.jwt(Collections.singletonMap("scope", "message:read message:write"));
JwtGrantedAuthoritiesConverter jwtGrantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter();
jwtGrantedAuthoritiesConverter.setAuthorityPrefix("");
jwtGrantedAuthoritiesConverter.setAuthoritiesClaimName("roles");
Collection<GrantedAuthority> authorities = jwtGrantedAuthoritiesConverter.convert(jwt);
assertThat(authorities).containsExactly(
new SimpleGrantedAuthority("message:read"),
new SimpleGrantedAuthority("message:write"));
Assert.assertTrue(authorities.contains("roles"));
}
private Jwt jwt(Map<String, Object> claims) {
Map<String, Object> headers = new HashMap<>();
headers.put("alg", JwsAlgorithms.RS256);
return new Jwt("token", Instant.now(), Instant.now().plusSeconds(3600), headers, claims);
}
}
according to the docs the default claim that spring will use when trying to find Authorities to mapping scopes to roles is the scope claim in the JWT.
You can override this behavior by supplying a custom JwtGrantedAuthoritiesConverter and use the setAuthoritiesClaimName to set a different claim.
the above code has this line
jwtGrantedAuthoritiesConverter.setAuthoritiesClaimName("roles");
so spring tries to find a claim called roles in the JWT, that it can map to authorities and it can't find it, so it returns empty.
Removing that line will fix the problem.

Extending a Jhipster JWT (Spring) monolith application to support impersonation

I have generated a jhipster angular/java application that is using JWT authentication.
I now want to extend the application to support impersonation.
I am interested in achieving the following:
Impersonation by admin: Allowing the admin user to login as any other user
Impersonation granted to user: Allowing another user that has been granted the right to impersonate a user (granted by the user itself) to login as that other user.
Audit - recording changes (audit function) - the audit trail must be able to distinguish between the actual user and an impersonated user and record this in the audit trail.
I see that Spring supports impersonation but it is unclear to me how I can implement it properly in my Jhipster application given that JWT is used. I am not sure if the Spring route is appropriate for JHipster-JWT-Monolith application - I am of the opinion that it not the right approach.
While there are some incomplete information on various other posts, after an extensive search I have been unable to find a post that can provide clear step by step guide on this. If somebody can do that for me it would be greatly appreciated. I expect others would also find such an answer very useful.
Thanks in advance.
Fergal
You just need to add below method in UserJwtController.java
#PostMapping("/authenticate-externalnodes")
public ResponseEntity<JWTToken> authenticateExternalnodes(#Valid #RequestBody LoginVM loginVM) {
// Get Roles for user via username
Set<Authority> authorities = userService.getUserWithAuthoritiesByLogin(loginVM.getUsername()).get()
.getAuthorities();
// Create Granted Authority Rules
Set<GrantedAuthority> grantedAuthorities = new HashSet<>();
for (Authority authority : authorities) {
grantedAuthorities.add(new SimpleGrantedAuthority(authority.getName()));
}
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(
loginVM.getUsername(), "", grantedAuthorities);
Authentication authentication = authenticationToken;
SecurityContextHolder.getContext().setAuthentication(authentication);
boolean rememberMe = (loginVM.isRememberMe() == null) ? false : loginVM.isRememberMe();
String jwt = tokenProvider.createToken(authentication, rememberMe);
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.add(JWTFilter.AUTHORIZATION_HEADER, "Bearer " + jwt);
return new ResponseEntity<>(new JWTToken(jwt), httpHeaders, HttpStatus.OK);
}

How to customize the behavior of session scoped bean by current user is Spring MVC

Consider following scenario: Spring Security authenticates login data against custom UserDetailsServiceimplementation as follows
#Override
public UserDetails loadUserByUsername(String name) throws UsernameNotFoundException {
List<GrantedAuthority> authorities = new ArrayList<>();
authorities.add(new SimpleGrantedAuthority("ROLE_USER"));
UserProfile profile = users.find(name);
if (profile.getUsername().equals("admin"))
authorities.add(new SimpleGrantedAuthority("ROLE_ADMIN"));
return new User(profile.getUsername(), profile.getPassword(), authorities);
}
If authentication succeeds, I want to create unique session scoped service in controller, with customized behavior by valid UserProfile object state. I guess best way to do that is to declare the session bean manually in configuration file and somehow autowire UserProfile or session owner to it's constructor, but how that's possible, when UserProfile is not even an managed object?
In this case, I want server to create service for authenticated user, which maintains SSH connection to remote host with credentials stored in UserProfile
Also, how to restrict a creation of such service just to post login? Is there way to achieve this kind of behavior, or is it actually bad architecture?
You can use the SecurityContextHolder to access the authenticated user for the current request. I think the best approach is to create a singleton Service with a method like this:
public UserDetails getCurrentUser() {
Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
if (principal instanceof UserDetails) {
return (UserDetails) principal;
} else {
//handle not authenticated users
return null;
}
}
Now you can autowire and use the service in your controllers.

Spring security : auto login issue

i am trying to auto login user after signup. Here is code for auto login
private boolean autoLogin(HttpServletRequest request, User user) {
SimpleGrantedAuthority auth = new SimpleGrantedAuthority("ADMIN");
Collection<SimpleGrantedAuthority> authorities = new HashSet<SimpleGrantedAuthority>();
authorities.add(auth);
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(
user.getEmail(), user.getPassword(), authorities);
token.setDetails(new WebAuthenticationDetails(request));
authenticationManager.authenticate(token);
SecurityContextHolder.getContext().setAuthentication(token);
return true;
}
and inside an interceptor that check logged in user code is
Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
Problem is when i debug the code (after auto login) the principal object has logged in user's email address instead of UserDetails object.
Things working fine when i log in useing spring security login form.
You're missing re-assigning the return from AuthenticationManager.authenticate().
This line:
authenticationManager.authenticate(token);
should be:
token = authenticationManager.authenticate(token);
That should fix things.

Howto integrate spring-social authentication with spring-security?

I've got a little webapp secured by spring-security using a username/password combo on a sql-db as credentials.
I now want to add facebook/twitter authentication with spring-social. Using the examples I am able to store the users credentials in my db. I'm now working on authenticating the user against his current session on my app using the following piece of code:
public String signIn(String userId, Connection<?> connection, NativeWebRequest request) {
User user = userService.getUserById(Long.parseLong(userId));
user.setPassword(this.passwordEncoder.encodePassword(user.getAccessToken(), this.salt));
this.userService.store(user);
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(user.getDisplayName(), user.getAccessToken());
HttpServletRequest req = request.getNativeRequest(HttpServletRequest.class); // generate session if one doesn't exist
token.setDetails(new WebAuthenticationDetails(req));
Authentication authenticatedUser = this.authenticationManager.authenticate(token);
SecurityContextHolder.getContext().setAuthentication(authenticatedUser);
return "/user/dashboard";
}
The authentication works, I am not getting any BadCredential-exceptions. But after being redirected to /user/dashboard I am thrown back to the login.
I am out of ideas, a similar piece of code for authenticating the session is working after a classical signup.
Does anyone have any ideas why this happens or how to debug this?
Thanks very much in advance!
Hendrik
I have similar code that works for me, and also adds "remember me" support:
// lookup by id, which in my case is the login
User user = userService.findByLogin(userId);
// code to populate the user's roles
List<GrantedAuthority> authorities = ...;
// create new instance of my UserDetails implementation
UserDetailsImpl springSecurityUser = new UserDetailsImpl(user, authorities);
// create new Authentication using UserDetails instance, password, and roles
Authentication authentication = new UsernamePasswordAuthenticationToken(springSecurityUser, user.getPassword(), authorities);
// set the Authentication in the SecurityContext
SecurityContextHolder.getContext().setAuthentication(authentication);
// optional: remember-me support (must #Autowire in TokenBasedRememberMeServices)
tokenBasedRememberMeServices.onLoginSuccess(
(HttpServletRequest) request.getNativeRequest(),
(HttpServletResponse) request.getNativeResponse(),
authentication);

Resources