Spring Security pre-authentication - gives me a new session even though principal is unchanged - session

I have implemented a spring security preathentication filter in my Grails application in order to integrate with Tivoli Access Manager.
The filter getting called for every request in my web application - yet even though the filter returns the same principal as a previous request, it seems to create a new session. I have created a ApplicationListener to listen for authentication events and I can see a new AuthenticationSuccessEvent, with a new session id for each request.
This means all my session variables get cleared each request- which wouldn't be a big deal but it breaks the uploadr plugin.
When I turn debug logging on for my preauthentication filter I see that it thinks the principal has changed, even though it has not:
2015-03-04 11:34:57.769 foobar.TamAuthenticationFilter Checking secure context token: org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken#f0666480: Principal: grails.plugin.springsecurity.userdetails.GrailsUser#3125618: Username: 66734; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: ROLE_ADMIN,ROLE_APPROVER; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails#fffde5d4: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: 87928D9E25D98DD3CCFAC5D67689E609; Granted Authorities: ROLE_ADMIN, ROLE_APPROVER
2015-03-04 11:34:57.770 foobar.TamAuthenticationFilter Pre-authenticated principal has changed to 66734 and will be reauthenticated
2015-03-04 11:34:57.770 foobar.TamAuthenticationFilter Invalidating existing session
2015-03-04 11:34:57.771 foobar.TamAuthenticationFilter preAuthenticatedPrincipal = 66734, trying to authenticate
How can I make spring security use the same session for each principal returned by the pre authentication filter, rather than create a new one for every request?
here is my filter:
package foobar
import org.springframework.security.web.authentication.preauth.AbstractPreAuthenticatedProcessingFilter
import grails.util.Environment
import grails.util.Holders
import groovy.util.logging.Log4j
#Log4j
class TamAuthenticationFilter extends AbstractPreAuthenticatedProcessingFilter {
java.lang.Object getPreAuthenticatedCredentials(javax.servlet.http.HttpServletRequest request)
{
"N/A"
}
java.lang.Object getPreAuthenticatedPrincipal(javax.servlet.http.HttpServletRequest request)
{
Long staffId = getStaffIdFromTamHeader(request)
if(!staffId)
log.error "iv-user header not found"
return staffId
}
/**
* Get Staff ID from the ivUser Tamheader.
* #param request
* #return
*/
static public Long getStaffIdFromTamHeader(request) {
return request.getHeader("iv-user")
}
}
LoggingSecurityEventListener:
package foobar
import groovy.util.logging.Log4j
import org.springframework.context.ApplicationListener
import org.springframework.security.authentication.event.AbstractAuthenticationEvent
#Log4j
class LoggingSecurityEventListener implements
ApplicationListener<AbstractAuthenticationEvent> {
void onApplicationEvent(AbstractAuthenticationEvent event) {
def username = event.authentication.principal
def address = event.authentication.details.remoteAddress
def sessionId = event.authentication.details.sessionId
log.info "event=${event.class.simpleName} username=${username} remoteAddress=${address} sessionId=${sessionId}"
}
}
resources.groovy:
beans = {
//
// grabs the user id from the tam headers
//
tamAuthenticationFilter(TamAuthenticationFilter) {
authenticationManager = ref('authenticationManager')
checkForPrincipalChanges = true
}
tamAuthenticationProvider(PreAuthenticatedAuthenticationProvider) {
preAuthenticatedUserDetailsService = ref('authenticationUserDetailsService')
}
//
// we do not want to redirect to the auth/login page since we are using tam
//
authenticationEntryPoint(Http403ForbiddenEntryPoint)
securityEventListener(LoggingSecurityEventListener)
}
config.groovy:
grails.plugin.springsecurity.useSecurityEventListener = true
grails.plugin.springsecurity.providerNames = ['tamAuthenticationProvider']
grails.plugin.springsecurity.userLookup.userDomainClassName = 'strobe.auth.User'
grails.plugin.springsecurity.userLookup.authorityJoinClassName = 'strobe.auth.UserRole'
grails.plugin.springsecurity.authority.className = 'strobe.auth.Role'
grails.plugin.springsecurity.securityConfigType="InterceptUrlMap"
grails.plugin.springsecurity.interceptUrlMap = [
'/foobar/**': ['ROLE_USER']]
bootstrap.groovy:
def init = { servletContext -> SpringSecurityUtils.clientRegisterFilter('tamAuthenticationFilter',
SecurityFilterPosition.PRE_AUTH_FILTER.order + 10)
}

I have found the solution to my problem- I was returning a Long from getPreauthenticatedPrincipal() which confuses spring security, as the method requiresAuthentication() in AbstractPreauthenticatedProcessingFilter has this line of code:
if ((principal instanceof String) && currentUser.getName().equals(principal)) {
return false;
}
It expects the principal to be a String. Every time I returned a long it would reauthenticate and give me a new session.
I can't believe the solution was that simple and it took me 2 days to figure out!!!
Part of the problem I think is the scant documentation on preauthentication in spring and also the method signature of:
java.lang.Object getPreAuthenticatedPrincipal(javax.servlet.http.HttpServletRequest request)
which doesn't clearly suggest a return type.

Related

Spring Boot with Spring Security - Authorization with Method Level Security with #PreAuthorize, #RolledAllowed or #Secured Not Working

I have a Spring Boot application that users Spring Security. My Authentication and Authorization filters are working as expected.
In my Authentication filter, I generate JWT token with list of user authorities set as claim, and send the generated JWT together with claims back to client as part of "Auth" header. That is all working great.
In Authorization filter, I also got it all working fine, my doFilterInternals() override does proper chaining and it also calls my getAuthenticationToken() method:
private UsernamePasswordAuthenticationToken getAuthenticationToken(HttpServletRequest request) {
String token = request.getHeader("Auth");
if (token != null) {
token = token.replace("Bearer", "");
String username = Jwts.parser()
.setSigningKey(SecurityConstants.getTokenSecret())
.parseClaimsJws(token)
.getBody()
.getSubject();
String authoritiesString = Jwts.parser()
.setSigningKey(SecurityConstants.getTokenSecret())
.parseClaimsJws(token)
.getBody()
.get("user-authorities").toString(); //authority1, authority2, ...
if (username != null) {
List<GrantedAuthority> authorities = AuthorityUtils.commaSeparatedStringToAuthorityList(authoritiesString);
return new UsernamePasswordAuthenticationToken(username, null, authorities);
}
}
return null;
}
Above, I extract authorities (these are user groups coming from Active Directory) from claim I named"user-authorities" and I generate new UsernamePasswordAuthenticationToken with the authorities and return it.
This is all working great and I have been using for a while now.
Now, I am trying to use these authorities to add method level security to my controllers.
In order to do so, I have a #Configuration class which I annotated with #EnableGlobalMethodSecurity:
#Configuration
#EnableGlobalMethodSecurity(
prePostEnabled = true,
securedEnabled = true,
jsr250Enabled = true
)
public class AppConfig {
...
}
Then on my controller I am using #Secured("authority1") to secure my controller:
#PostMapping(consumes = {MediaType.APPLICATION_JSON_VALUE}, produces = {MediaType.APPLICATION_JSON_VALUE})
#Secured("authority1")
public CarResponse saveCar(#Valid #RequestBody CarRequest carRequest, #RequestHeader HttpHeaders httpHeaders) {
System.out.println("Received :" + carRequest.toString());
return null;
}
I know JWT token contains claims with "authority1,authority2,authority3" comma-delimited string of authorities. So, my expectation would be that the controller below will execute for a user who authenticates and has these 3 authorities.
However, what I get back is 500 error. If I comment out the #Secured annotation, my controller will execute just fine but then it is not secured. I have also tried using #PreAuthorized("hasRole('authority1')") and also #RolesAllowed("authority1") but none are workng.
I dont know what I am missing.

Spring Security 5 with multiple searchbase groups fails while singel group base with same credentials does not. What do i miss here?

This question is about how to use multiple group search bases instead of the one.
I used an example provided by samaddico (simple spring security + LDAP example), modified it for single group search base with provided server / user / LDAP configuration text. It uses a service account to connect to ldap and a user which then tries to authenticate for certain simple web pages.
This approach works but lacks ability to collect membership / roles from different groups in the search tree.
Spring Security provides classes LdapContextSource and MultipleLdapAuthoritiesPopulator to allow for searching for roles in different locations.
Now here is the code which will result in the error shown below:
LDAP Configuration:
* Create an implementation of org.springframework.security.ldap.userdetails.LdapAuthoritiesPopulator which can call
multiple instances of LdapAuthoritiesPopulator.
* Then create one LdapAuthoritiesPopulatorfor each 'groupSearchBase' that I wanted to query.
#Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
LdapContextSource contextSource = contextSource();
MultipleLdapAuthoritiesPopulator multipleLdapAuthoritiesPopulator = new MultipleLdapAuthoritiesPopulator(
new DefaultLdapAuthoritiesPopulator(contextSource, ldapGroupSearchBaseA),
new DefaultLdapAuthoritiesPopulator(contextSource, ldapGroupSearchBaseB),
new DefaultLdapAuthoritiesPopulator(contextSource, ldapGroupSearchBaseC));
auth
.ldapAuthentication()
.contextSource(contextSource)
.ldapAuthoritiesPopulator(multipleLdapAuthoritiesPopulator)
.userSearchFilter(ldapUserSearchFilter)
.userSearchBase(ldapUserSearchBase);
}
class MultipleLdapAuthoritiesPopulator implements LdapAuthoritiesPopulator {
private List<LdapAuthoritiesPopulator> authoritiesPopulators;
public MultipleLdapAuthoritiesPopulator(LdapAuthoritiesPopulator...authoritiesPopulators) {
this.authoritiesPopulators = Arrays.asList(authoritiesPopulators);
}
#Override
public Collection<? extends GrantedAuthority> getGrantedAuthorities(DirContextOperations userData, String username) {
List<GrantedAuthority> grantedAuthorities = authoritiesPopulators.stream()
.map(authPopulator -> authPopulator.getGrantedAuthorities(userData, username))
.flatMap(Collection::stream)
.collect(Collectors.toList());
return grantedAuthorities;
}
}
/**
* Creates context source object instead of configuring it with AuthenticationBuilder
* #return Context source object used for accessing ldap server
*/
#Bean
public LdapContextSource contextSource() {
LdapContextSource contextSource= new LdapContextSource();
contextSource.setUrl(ldapUrl);
contextSource.setUserDn(ldapManagerDn);
contextSource.setPassword(ldapManagerPassword);
contextSource.afterPropertiesSet();
return contextSource;
}
Session Configuration:
/**
* This is essential to make sure that the Spring Security session registry is notified when the session is destroyed.
* #return
*/
#Bean
public HttpSessionEventPublisher httpSessionEventPublisher() {
return new HttpSessionEventPublisher();
}
The Spring Application tells me that my service account got successful connected to LDAP server.
DEBUG 17220 --- [nio-8080-exec-5] o.s.s.w.a.i.FilterSecurityInterceptor : Previously Authenticated: org.springframework.security.authentication.AnonymousAuthenticationToken#c1e15be1: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails#380f4: RemoteIpAddress: 127.0.0.1; SessionId: 0A82CE8FA4FB9EB248D756EEE8134CAE; Granted Authorities: ROLE_ANONYMOUS
The error then is thrown when the found user is beeing tried to bind:
DEBUG 17220 --- [nio-8080-exec-8] o.s.s.l.a.BindAuthenticator : Failed to bind as CN=familyName\, name,OU=Group: org.springframework.ldap.AuthenticationException: [LDAP: error code 49 - 80090308: LdapErr: DSID-0C090453, comment: AcceptSecurityContext error, data 52e, v3839 ]; nested exception is javax.naming.AuthenticationException: [LDAP: error code 49 - 80090308: LdapErr: DSID-0C090453, comment: AcceptSecurityContext error, data 52e, v3839 ]
DEBUG 17220 --- [nio-8080-exec-8] w.a.UsernamePasswordAuthenticationFilter : Authentication request failed: org.springframework.security.authentication.BadCredentialsException: Bad credentials
To sum this up: my credentials are correct for a single group base without using LdapContextSource and MultipleLdapAuthoritiesPopulator. But the authentication process seems not to provide the enteret password for my user with multiple group bases.
After spending some time in figuring out a solution i had to admit that there was no efficient way to create a solution i.e. with overwriting methods or classes.
But i stumbled on a change request for spring security, precicely for this use case when multiple group search bases need to be checked.
It is implemented since Spring Security version 5.4.1 (i believe) or included when using Spring Starter parent version 2.4.2.
Simply add the option to your authentification method:
.groupSearchSubtree(true)
The complete updated method example for authentication looks like this then:
#Override
#Autowired
protected void configure(AuthenticationManagerBuilder auth) throws Exception
{
auth
.ldapAuthentication()
.contextSource()
.url(ldapUrl)
.managerDn(ldapManagerDn)
.managerPassword(ldapManagerPassword)
.and()
.userSearchFilter(ldapUserSearchFilter)
.userSearchBase(ldapUserSearchBase)
.groupSearchFilter(ldapGroupSearchFilter)
.groupSearchBase(ldapGroupSearchBase)
.groupSearchSubtree(true)
;
You see that there is no need for three different nodes and no more custom context object to be forwarded any more, simply add the parent node for the group search base and let the subtree search do the rest.
It might have been nice to figure out a way by myself, but using an incorporated solution of the framework is surely the better way to go.

How can I validate OAuth 2.0 token user details in #PreAuthorize annotation in Spring Boot REST service

I need to make a check in #PreAuthorize annotation. Something like:
#PreAuthorize("hasRole('ROLE_VIEWER') or hasRole('ROLE_EDITOR')")
That is OK but I also need to validate some user details stored in the OAuth 2.0 token with those in the request path so I would need to do something like (oauthToken.userDetails is just an example:
#PreAuthorize("#pathProfileId.equals(oauthToken.userDetails.profileId)")
(profileId is not userId or userName, it is a user details that we add in the OAuth token when we create it)
What is the simplest way to make OAuth token properties visible in the preauthorized annotation security expression language?
You have two options:
1-
Setting UserDetailsService instance into DefaultUserAuthenticationConverter
and set converter to JwtAccessTokenConverter so when spring calls extractAuthentication method from DefaultUserAuthenticationConverter it found (userDetailsService != null) so it get the whole UserDetails object by calling implementation of loadUserByUsername when calling this line:
userDetailsService.loadUserByUsername((String) map.get(USERNAME))
implemented in next method inside spring class org.springframework.security.oauth2.provider.token.DefaultUserAuthenticationConverter.java but just adding it to clarify how spring get principal object from map (first getting it by username, and if userDetailsService not null so it get the whole object):
//Note: This method implemented by spring but just putting it to show where spring exctract principal object and how extracting it
public Authentication extractAuthentication(Map<String, ?> map) {
if (map.containsKey(USERNAME)) {
Object principal = map.get(USERNAME);
Collection<? extends GrantedAuthority> authorities = getAuthorities(map);
if (userDetailsService != null) {
UserDetails user = userDetailsService.loadUserByUsername((String) map.get(USERNAME));
authorities = user.getAuthorities();
principal = user;
}
return new UsernamePasswordAuthenticationToken(principal, "N/A", authorities);
}
return null;
}
So what you need to implement in your microservice is:
#Bean//this method just used with token store bean example: new JwtTokenStore(tokenEnhancer());
public JwtAccessTokenConverter tokenEnhancer() {
/**
* CustomTokenConverter is a class extends JwtAccessTokenConverter
* which override "enhance" to add extra information to OAuth2AccessToken after
* authenticate the user and get it by loadUserByUsername implementation
* like profileId in your case
**/
JwtAccessTokenConverter converter = new CustomTokenConverter();
DefaultAccessTokenConverter datc = new DefaultAccessTokenConverter();
datc.setUserTokenConverter(userAuthenticationConverter());
converter.setAccessTokenConverter(datc);
//Other method code implementation....
}
#Autowired
private UserDetailsService userDetailsService;
#Bean
public UserAuthenticationConverter userAuthenticationConverter() {
DefaultUserAuthenticationConverter duac = new DefaultUserAuthenticationConverter();
duac.setUserDetailsService(userDetailsService);
return duac;
}
Note: this first way will hit database in every request so it load user by username and get UserDetails object so it assign it to principal object inside authentication.
2-
If for any reason you see it's better to not hit database in each request and no problem about executing data needed like profileId from token passed in request.
Assuming you know that old authorities assigned to user when generating oauth2 token will always be in token till it goes invalid even after you change it in database for user who passes the token in request so user could call a method not allowed to him/her anymore after extracting token and it was allowed before extracting the token.
So this means if user authorities changed after generating the token, new authorities will not be checked by #PreAuthorize as it's not removed or added to token and you have to wait till old token goes invalid or expired so user forced to execute the service again to get new oauth token.
Anyway, in this second option you only need to override extractAuthentication method inside CustomTokenConverter class extends JwtAccessTokenConverter and forget about setting access token converter converter.setAccessTokenConverter from tokenEnhancer() method in first option, and here are the whole CustomTokenConverter you can use it for reading data from token and return principal object not just string username:
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
public class CustomTokenConverter extends JwtAccessTokenConverter {
// This is the method you need to override to read data direct from token passed in request
#Override
public OAuth2Authentication extractAuthentication(Map<String, ?> map) {
OAuth2Authentication authentication = super.extractAuthentication(map);
Object userIdObj = map.get(AuthenticationUtils.USER_ID);
UUID userId = userIdObj != null ? UUID.fromString(userIdObj.toString()) : null;
Object profileIdObj = map.get(AuthenticationUtils.PROFILE_ID);
UUID profileId = profileIdObj != null ? UUID.fromString(profileIdObj.toString()) : null;
Object firstNameObj = map.get(AuthenticationUtils.FIRST_NAME);
String firstName = firstNameObj != null ? String.valueOf(firstNameObj) : null;
Object lastNameObj = map.get(AuthenticationUtils.LAST_NAME);
String lastName = lastNameObj != null ? String.valueOf(lastNameObj) : null;
JwtUser principal = new JwtUser(userId, profileId, authentication.getUserAuthentication().getName(), "N/A", authentication.getUserAuthentication().getAuthorities(), firstName, lastName);
authentication = new OAuth2Authentication(authentication.getOAuth2Request(),
new UsernamePasswordAuthenticationToken(principal, "N/A", authentication.getUserAuthentication().getAuthorities()));
return authentication;
}
#Override
public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
JwtUser user = (JwtUser) authentication.getPrincipal();
Map<String, Object> info = new LinkedHashMap<>(accessToken.getAdditionalInformation());
if (user.getId() != null)
info.put(AuthenticationUtils.USER_ID, user.getId());
if (user.getProfileId() != null)
info.put(AuthenticationUtils.PROFILE_ID, user.getProfileId());
if (isNotNullNotEmpty(user.getFirstName()))
info.put(AuthenticationUtils.FIRST_NAME, user.getFirstName());
if (isNotNullNotEmpty(user.getLastName()))
info.put(AuthenticationUtils.LAST_NAME, user.getLastName());
DefaultOAuth2AccessToken customAccessToken = new DefaultOAuth2AccessToken(accessToken);
customAccessToken.setAdditionalInformation(info);
return super.enhance(customAccessToken, authentication);
}
private boolean isNotNullNotEmpty(String str) {
return Optional.ofNullable(str).map(String::trim).map(string -> !str.isEmpty()).orElse(false);
}
}
Finally: Guess how i know you are asking about JWT used with OAuth2?
Because i am a part of your company :P and you know that :P

Different principals in spring security context when 'in-bean' login method used

For couple of days I have been working on integrating Facebook with our application. I have successfully made the connection working and now after Facebook Login I copy the user to our database and later on I want to use our internal principal within context.
For the Spring security login we overloaded our authentication-manager with our class implemeting UserDetailsService.
When someone logs in with facebook, he has abstract credentials he can not know.
I used this method in my Facebook login controller to log him in:
Authentication auth = new UsernamePasswordAuthenticationToken(
profile.getId(), new Md5PasswordEncoder().encodePassword(
profile.getEmail() + profile.getId(), null),
(Collection<? extends GrantedAuthority>) getAuthorities(profile.getId()));
PROBLEM:
Within some controllers I use
public String profile(Locale locale, Model model, HttpSession session, Principal principal)and then principal actually contains different Objects.
For regular spring security login its:
org.springframework.security.authentication.UsernamePasswordAuthenticationToken#4527d081: Principal: org.springframework.security.core.userdetails.User#586034f: Username: admin; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: ROLE_ADMIN; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails#21a2c: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: A5E9AB9E4AEE7486EC4B4F6133F77320; Granted Authorities: ROLE_ADMIN
But after login with the method in the controller its:
org.springframework.security.authentication.UsernamePasswordAuthenticationToken#cd4699c5: Principal: 1405308431; Credentials: [PROTECTED]; Authenticated: true; Details: null; Granted Authorities: ROLE_CLIENT
QUESTION:
I really don't want to distinguish between these types in all my controllers. Why it differs?! It obviously is a User (my type) object when we login with normal credentials and its just a String for facebook. How can I change it so facebook login would give me User object in my security context too?
You need to set up SignInAdapter as described at the end of this chapiter. In the SignInAdapter.signIn(...) method you can load your user object from DB then prepare authentication object and inject it in security context holder.
I didn't really get the 'prepare authentication object' at first but it was really easy;
I post this example for future clarification maybe one will need it :)
public class FacebookAuthenticationToken extends AbstractAuthenticationToken
{
private final org.springframework.security.core.userdetails.UserDetails principal;
private String credentials;
public FacebookAuthenticationToken(org.springframework.security.core.userdetails.UserDetails details,FacebookProfile profile, Collection<? extends GrantedAuthority> authorities){
super(authorities);
this.principal = details;
this.credentials = new Md5PasswordEncoder().encodePassword(profile.getEmail()+profile.getId(), null);
super.setAuthenticated(true); // must use super, as we override
}
private static final long serialVersionUID = -7545290433068513777L;
public Object getCredentials() {
return this.credentials;
}
public Object getPrincipal() {
return this.principal;
}
}
And now i understood I could have even used the UsernamePasswordAuthenticationToken,
just provide the Object principal with correct class. Silly me.

How can I get the current user roles from Spring security 3.1

I have loaded the roles from the database for the current user. And I can access the user role with spring security expression in JSP, and can hide the options and URLs which are not authorized with hasRole. Now I wanted to have it in the servlet and display it in the logs (or store in the user object session). How can we achieve it?
You can try something like this:
Collection<SimpleGrantedAuthority> authorities = (Collection<SimpleGrantedAuthority>) SecurityContextHolder.getContext().getAuthentication().getAuthorities();
You have the collection of roles in the authorities variable.
If you develop on Java 8, it's getting easier.
To get all user roles:
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
Set<String> roles = authentication.getAuthorities().stream()
.map(r -> r.getAuthority()).collect(Collectors.toSet());
To check if the user has a particular role, for example, ROLE_USER:
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
boolean hasUserRole = authentication.getAuthorities().stream()
.anyMatch(r -> r.getAuthority().equals("ROLE_USER"));
Try to call getUserPrincipal() from HttpServletRequest.
I've created a custom hasRole function for my project.
public static boolean hasRole (String roleName)
{
return SecurityContextHolder.getContext().getAuthentication().getAuthorities().stream()
.anyMatch(grantedAuthority -> grantedAuthority.getAuthority().equals(roleName));
}
To complete both answers...
Here is a Spring security implementation of getUserPrincipal, so you can see that the getUserPrincipal actually is SecurityContextHolder
public Principal getUserPrincipal() {
Authentication auth = getAuthentication();
if ((auth == null) || (auth.getPrincipal() == null)) {
return null;
}
return auth;
}
// And the getAuthentication
private Authentication getAuthentication() {
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if (!trustResolver.isAnonymous(auth)) {
return auth;
}
return null;
}
This may help someone.
import org.springframework.security.core.Authentication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.ui.Model;
import org.springframework.security.core.userdetails.User;
#GetMapping("/home")
public String getHomePage(Authentication authentication, Model model) {
User u = (User) authentication.getPrincipal();
model.addAttribute("cu", u);
return "sb/homePage";
}
And in template Thymeleaf:
Current user:</br>
<div th:if="${cu}">
Username: [[${cu.username}]]</br>
Password: [[${cu.password}]]</br>
Role: [[${cu.authorities[0]}]]</br>
Enabled: [[${cu.enabled}]]</br>
Full: [[${cu}]]</br>
</div>
<div th:unless="${cu}">
Not logged-in!
</div>

Resources