Safest way to store an authentication token - java

I have my custom AuthenticationProvider which call a third party SSO to authenticate a user. If a user is valid I get an authentication token from the SSO service. I have to keep this token during the session for another services which will require this authentication token to verify the user has a valid session.
public Authentication authenticate(Authentication authentication)
throws AuthenticationException {
String id = authentication.getName();
String password = authentication.getCredentials().toString();
JsonObject response = ssoClient.login(id, password);
JsonObject session = response.getJsonObject("session");
JsonObject user = session.getJsonObject("user");
String email = user.getString("email");
String username = user.getString("username");
String fullname = user.getString("fullname");
String auth_token = session.getString("auth_token");
List<GrantedAuthority> grantedAuths = null;
return new CustomAuthenticationToken(username, auth_token, email,
fullname, grantedAuths);
}
I have extended from AbstractAuthenticationToken to create a custom CustomAuthenticationToken to store this token and another information. Should I sign this token with something like itsdangeous (but in java) or encrypt it? Or should I store the authentication token in any other place? Thanks!

Related

How to get the Roles and Attributes of a Keycloak User

How do I get the roles and attributes of a user using the Java Client of Keycloak? Below is the code that I have written to get the access token of a user, however, I am not able to find the way to get the roles assigned to that user.
Configuration configuration = new Configuration();
configuration.setRealm("foo");
configuration.setResource("foo");
configuration.setBearerOnly(Boolean.TRUE);
configuration.setAuthServerUrl("http://localhost:8080");
configuration.setCredentials(Map.of("secret", "FV3P4ajYHedAUDtOa55EX5nzK8zc6jUA"));
AuthzClient authzClient = AuthzClient.create(configuration);
AuthorizationRequest request = new AuthorizationRequest();
AuthorizationResponse authorize = authzClient.authorization("john.doe", "john.doe").authorize(request);
String token = authorize.getToken();
log.info("Auth bearer token is {}", token);
You have the token as a String, namely:
String token = authorize.getToken();
now you just need to parse it to get the Realm and Client roles, which are encoded in the token. For that you can use the class TokenVerifier from org.keycloak.TokenVerifier.
For example:
try {
AccessToken token = TokenVerifier.create(tokenString, AccessToken.class).getToken();
System.out.printf("Realm 'foo' = Roles %s%n", token.getRealmAccess().getRoles());
token.getResourceAccess().forEach((k, v) -> System.out.printf("Client '%s' = Roles '%s'%n", k, v.getRoles()));
} catch (VerificationException e) {
...
}

Problem getting the userName from jwtToken

I implemented security for my application using JWT tokens. I make a post request to the /auth endpoint (passing userName and password) and get back a token, which I then use for further requests to the other endpoints. Everything works perfectly fine, but I can't get the userName out of this token. Here' my controller method:
#GetMapping(produces = {MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE})
public ResponseEntity<List<SongList>> getSongListsForUser(#RequestParam("userId") String ownerId) {
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
String userId = auth.getName();
return ResponseEntity.ok(userId.equals(ownerId)
? songListDAO.findListsOf(userId)
: songListDAO.findPublicListsOf(ownerId));
}
Found this solution here on stackoverflow.
I put a breakpoint at the line of the return statement to inspect whats inside the userId and got this:
Why this is not working? What do I have to do to get the userName (=userId) from the jwt token?

Does spring security context persist across REST/SOAP calls?

Do Spring security context persist while calling rest/soap services from Client. I have client application which sets authentication using SecurityContextHolder.getContext().setAuthentication(). Client application makes rest/soap calls where I have to get context.
//Setting security context in client application:
User contextUser = new User(username, enc_password, true, true, true, true,grantedAuthorities, null);
authentication = new UsernamePasswordAuthenticationToken(contextUser, username,grantedAuthorities);
SecurityContextHolder.getContext().setAuthentication(authentication);
// on server side
// I want to get following authentication on server side to get logged in user
Authentication auth=SecurityContextHolder.getContext().getAuthentication();
User user= null;
if (auth != null && !(auth instanceof AnonymousAuthenticationToken)) {
// userDetails = auth.getPrincipal()
Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
String username = null;
if (principal instanceof UserDetails) {
username = ((UserDetails) principal).getUsername();
user = (UserDetails) principal;
} else {
username = principal.toString();
}
}
To access username on server side, after REST/SOAP API calls are made, you can do it by adding username in each request's header, before making API call.
Intercept each request on the server-side by using Spring Interceptors, you can create interceptor class by implementing a HandlerInterceptorAdapter interface.
For more information about interceptors.

How to programmatically change current Principal in Spring Security?

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

How I can connect with token URL

how to authenticate a user without typing a name and password, but a URL sent by email with a token ?
I tried with a controller intercepting the url containing the token but my spring setting returns the login page because the user is anonymous.
I would also like to connect with token in the URL such as :
http://myWebSite/guest/18f1ff9a-fd1e-49be-bb31 ...
I have a token for each user in database
I have allowed anonymous access to the controller with token. Then I get the username and password of a user by token Like this :
String queryFindUserByToken = "from UserEntity u where u.token = :token";
Now I want to automatically create a user session with the login and password that I got from the database.
I tried to redirect to redirect to j_spring_security_check with parameters but authentication method not supported: GET
#RequestMapping(value = "guest/{tokenUser}", method = RequestMethod.GET)
public String guest(Map<String, Object> map, #PathVariable String tokenUser) {
UserEntity user = userService.findUserByToken(tokenUser);
return "redirect:j_spring_security_check?j_username=" + user.getUsername() + "&j_password=" + user.getPassword() ;
}
do you have a better solution ?

Categories