SEC-1492: Added GrantedAuthoritiesMapper to provide mapping of loaded authorities to those which are eventually stored in the user Authentication object.
This commit is contained in:
parent
89f80659a1
commit
d64efe9747
|
@ -31,6 +31,8 @@ import org.springframework.security.cas.web.CasAuthenticationFilter;
|
|||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.core.SpringSecurityMessageSource;
|
||||
import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper;
|
||||
import org.springframework.security.core.authority.mapping.NullAuthoritiesMapper;
|
||||
import org.springframework.security.core.userdetails.*;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
|
@ -59,6 +61,8 @@ public class CasAuthenticationProvider implements AuthenticationProvider, Initia
|
|||
private String key;
|
||||
private TicketValidator ticketValidator;
|
||||
private ServiceProperties serviceProperties;
|
||||
private GrantedAuthoritiesMapper authoritiesMapper = new NullAuthoritiesMapper();
|
||||
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
|
@ -131,7 +135,8 @@ public class CasAuthenticationProvider implements AuthenticationProvider, Initia
|
|||
final Assertion assertion = this.ticketValidator.validate(authentication.getCredentials().toString(), serviceProperties.getService());
|
||||
final UserDetails userDetails = loadUserByAssertion(assertion);
|
||||
userDetailsChecker.check(userDetails);
|
||||
return new CasAuthenticationToken(this.key, userDetails, authentication.getCredentials(), userDetails.getAuthorities(), userDetails, assertion);
|
||||
return new CasAuthenticationToken(this.key, userDetails, authentication.getCredentials(),
|
||||
authoritiesMapper.mapAuthorities(userDetails.getAuthorities()), userDetails, assertion);
|
||||
} catch (final TicketValidationException e) {
|
||||
throw new BadCredentialsException(e.getMessage(), e);
|
||||
}
|
||||
|
@ -194,6 +199,10 @@ public class CasAuthenticationProvider implements AuthenticationProvider, Initia
|
|||
this.ticketValidator = ticketValidator;
|
||||
}
|
||||
|
||||
public void setAuthoritiesMapper(GrantedAuthoritiesMapper authoritiesMapper) {
|
||||
this.authoritiesMapper = authoritiesMapper;
|
||||
}
|
||||
|
||||
public boolean supports(final Class<?> authentication) {
|
||||
return (UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication)) ||
|
||||
(CasAuthenticationToken.class.isAssignableFrom(authentication)) ||
|
||||
|
|
|
@ -28,6 +28,8 @@ import org.springframework.security.authentication.UsernamePasswordAuthenticatio
|
|||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.core.SpringSecurityMessageSource;
|
||||
import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper;
|
||||
import org.springframework.security.core.authority.mapping.NullAuthoritiesMapper;
|
||||
import org.springframework.security.core.userdetails.UserCache;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.core.userdetails.UserDetailsChecker;
|
||||
|
@ -84,6 +86,7 @@ public abstract class AbstractUserDetailsAuthenticationProvider implements Authe
|
|||
protected boolean hideUserNotFoundExceptions = true;
|
||||
private UserDetailsChecker preAuthenticationChecks = new DefaultPreAuthenticationChecks();
|
||||
private UserDetailsChecker postAuthenticationChecks = new DefaultPostAuthenticationChecks();
|
||||
private GrantedAuthoritiesMapper authoritiesMapper = new NullAuthoritiesMapper();
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
|
@ -191,7 +194,7 @@ public abstract class AbstractUserDetailsAuthenticationProvider implements Authe
|
|||
// Also ensure we return the original getDetails(), so that future
|
||||
// authentication events after cache expiry contain the details
|
||||
UsernamePasswordAuthenticationToken result = new UsernamePasswordAuthenticationToken(principal,
|
||||
authentication.getCredentials(), user.getAuthorities());
|
||||
authentication.getCredentials(), authoritiesMapper.mapAuthorities(user.getAuthorities()));
|
||||
result.setDetails(authentication.getDetails());
|
||||
|
||||
return result;
|
||||
|
@ -295,6 +298,10 @@ public abstract class AbstractUserDetailsAuthenticationProvider implements Authe
|
|||
this.postAuthenticationChecks = postAuthenticationChecks;
|
||||
}
|
||||
|
||||
public void setAuthoritiesMapper(GrantedAuthoritiesMapper authoritiesMapper) {
|
||||
this.authoritiesMapper = authoritiesMapper;
|
||||
}
|
||||
|
||||
private class DefaultPreAuthenticationChecks implements UserDetailsChecker {
|
||||
public void check(UserDetails user) {
|
||||
if (!user.isAccountNonLocked()) {
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
package org.springframework.security.core.authority.mapping;
|
||||
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Mapping interface which can be injected into the authentication layer to convert the
|
||||
* authorities loaded from storage into those which will be used in the {@code Authentication} object.
|
||||
*
|
||||
* @author Luke Taylor
|
||||
*/
|
||||
public interface GrantedAuthoritiesMapper {
|
||||
Collection<? extends GrantedAuthority> mapAuthorities(Collection<? extends GrantedAuthority> authorities);
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package org.springframework.security.core.authority.mapping;
|
||||
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @author Luke Taylor
|
||||
*/
|
||||
public class NullAuthoritiesMapper implements GrantedAuthoritiesMapper {
|
||||
public Collection<? extends GrantedAuthority> mapAuthorities(Collection<? extends GrantedAuthority> authorities) {
|
||||
return authorities;
|
||||
}
|
||||
}
|
|
@ -33,6 +33,8 @@ import org.springframework.security.core.Authentication;
|
|||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.SpringSecurityMessageSource;
|
||||
import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper;
|
||||
import org.springframework.security.core.authority.mapping.NullAuthoritiesMapper;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||
import org.springframework.security.ldap.ppolicy.PasswordPolicyException;
|
||||
|
@ -140,6 +142,7 @@ public class LdapAuthenticationProvider implements AuthenticationProvider, Messa
|
|||
private UserDetailsContextMapper userDetailsContextMapper = new LdapUserDetailsMapper();
|
||||
private boolean useAuthenticationRequestCredentials = true;
|
||||
private boolean hideUserNotFoundExceptions = true;
|
||||
private GrantedAuthoritiesMapper authoritiesMapper = new NullAuthoritiesMapper();
|
||||
|
||||
//~ Constructors ===================================================================================================
|
||||
|
||||
|
@ -201,7 +204,7 @@ public class LdapAuthenticationProvider implements AuthenticationProvider, Messa
|
|||
}
|
||||
|
||||
/**
|
||||
* Provides access to the injected <tt>UserDetailsContextMapper</tt> strategy for use by subclasses.
|
||||
* Provides access to the injected {@code UserDetailsContextMapper} strategy for use by subclasses.
|
||||
*/
|
||||
protected UserDetailsContextMapper getUserDetailsContextMapper() {
|
||||
return userDetailsContextMapper;
|
||||
|
@ -214,7 +217,7 @@ public class LdapAuthenticationProvider implements AuthenticationProvider, Messa
|
|||
/**
|
||||
* Determines whether the supplied password will be used as the credentials in the successful authentication
|
||||
* token. If set to false, then the password will be obtained from the UserDetails object
|
||||
* created by the configured <tt>UserDetailsContextMapper</tt>.
|
||||
* created by the configured {@code UserDetailsContextMapper}.
|
||||
* Often it will not be possible to read the password from the directory, so defaults to true.
|
||||
*
|
||||
* @param useAuthenticationRequestCredentials
|
||||
|
@ -227,6 +230,10 @@ public class LdapAuthenticationProvider implements AuthenticationProvider, Messa
|
|||
this.messages = new MessageSourceAccessor(messageSource);
|
||||
}
|
||||
|
||||
public void setAuthoritiesMapper(GrantedAuthoritiesMapper authoritiesMapper) {
|
||||
this.authoritiesMapper = authoritiesMapper;
|
||||
}
|
||||
|
||||
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
|
||||
Assert.isInstanceOf(UsernamePasswordAuthenticationToken.class, authentication,
|
||||
messages.getMessage("AbstractUserDetailsAuthenticationProvider.onlySupports",
|
||||
|
@ -251,9 +258,8 @@ public class LdapAuthenticationProvider implements AuthenticationProvider, Messa
|
|||
try {
|
||||
DirContextOperations userData = getAuthenticator().authenticate(authentication);
|
||||
|
||||
Collection<? extends GrantedAuthority> extraAuthorities = loadUserAuthorities(userData, username, password);
|
||||
|
||||
UserDetails user = userDetailsContextMapper.mapUserFromContext(userData, username, extraAuthorities);
|
||||
UserDetails user = userDetailsContextMapper.mapUserFromContext(userData, username,
|
||||
loadUserAuthorities(userData, username, password));
|
||||
|
||||
return createSuccessfulAuthentication(userToken, user);
|
||||
} catch (PasswordPolicyException ppe) {
|
||||
|
@ -277,7 +283,7 @@ public class LdapAuthenticationProvider implements AuthenticationProvider, Messa
|
|||
}
|
||||
|
||||
/**
|
||||
* Creates the final <tt>Authentication</tt> object which will be returned from the <tt>authenticate</tt> method.
|
||||
* Creates the final {@code Authentication} object which will be returned from the {@code authenticate} method.
|
||||
*
|
||||
* @param authentication the original authentication request token
|
||||
* @param user the <tt>UserDetails</tt> instance returned by the configured <tt>UserDetailsContextMapper</tt>.
|
||||
|
@ -287,7 +293,8 @@ public class LdapAuthenticationProvider implements AuthenticationProvider, Messa
|
|||
UserDetails user) {
|
||||
Object password = useAuthenticationRequestCredentials ? authentication.getCredentials() : user.getPassword();
|
||||
|
||||
UsernamePasswordAuthenticationToken result = new UsernamePasswordAuthenticationToken(user, password, user.getAuthorities());
|
||||
UsernamePasswordAuthenticationToken result = new UsernamePasswordAuthenticationToken(user, password,
|
||||
authoritiesMapper.mapAuthorities(user.getAuthorities()));
|
||||
result.setDetails(authentication.getDetails());
|
||||
|
||||
return result;
|
||||
|
|
|
@ -20,6 +20,8 @@ import org.springframework.security.authentication.AuthenticationServiceExceptio
|
|||
import org.springframework.security.authentication.BadCredentialsException;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper;
|
||||
import org.springframework.security.core.authority.mapping.NullAuthoritiesMapper;
|
||||
import org.springframework.security.core.userdetails.AuthenticationUserDetailsService;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper;
|
||||
|
@ -30,21 +32,23 @@ import org.springframework.util.Assert;
|
|||
/**
|
||||
* Finalises the OpenID authentication by obtaining local authorities for the authenticated user.
|
||||
* <p>
|
||||
* The authorities are obtained by calling the configured <tt>UserDetailsService</tt>.
|
||||
* The <code>UserDetails</code> it returns must, at minimum, contain the username and <code>GrantedAuthority</code>
|
||||
* The authorities are obtained by calling the configured {@code UserDetailsService}.
|
||||
* The {@code UserDetails} it returns must, at minimum, contain the username and {@code GrantedAuthority}
|
||||
* objects applicable to the authenticated user. Note that by default, Spring Security ignores the password and
|
||||
* enabled/disabled status of the <code>UserDetails</code> because this is
|
||||
* authentication-related and should have been enforced by another provider server.
|
||||
* enabled/disabled status of the {@code UserDetails} because this is authentication-related and should have been
|
||||
* enforced by another provider server.
|
||||
* <p>
|
||||
* The <code>UserDetails</code> returned by implementations is stored in the generated <code>AuthenticationToken</code>,
|
||||
* The {@code UserDetails} returned by implementations is stored in the generated {@code Authentication} token,
|
||||
* so additional properties such as email addresses, telephone numbers etc can easily be stored.
|
||||
*
|
||||
* @author Robin Bramley, Opsera Ltd.
|
||||
* @author Luke Taylor
|
||||
*/
|
||||
public class OpenIDAuthenticationProvider implements AuthenticationProvider, InitializingBean {
|
||||
//~ Instance fields ================================================================================================
|
||||
|
||||
private AuthenticationUserDetailsService<OpenIDAuthenticationToken> userDetailsService;
|
||||
private GrantedAuthoritiesMapper authoritiesMapper = new NullAuthoritiesMapper();
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
|
@ -100,7 +104,7 @@ public class OpenIDAuthenticationProvider implements AuthenticationProvider, Ini
|
|||
* @return the token which will represent the authenticated user.
|
||||
*/
|
||||
protected Authentication createSuccessfulAuthentication(UserDetails userDetails, OpenIDAuthenticationToken auth) {
|
||||
return new OpenIDAuthenticationToken(userDetails, userDetails.getAuthorities(),
|
||||
return new OpenIDAuthenticationToken(userDetails, authoritiesMapper.mapAuthorities(userDetails.getAuthorities()),
|
||||
auth.getIdentityUrl(), auth.getAttributes());
|
||||
}
|
||||
|
||||
|
@ -124,4 +128,8 @@ public class OpenIDAuthenticationProvider implements AuthenticationProvider, Ini
|
|||
public boolean supports(Class<?> authentication) {
|
||||
return OpenIDAuthenticationToken.class.isAssignableFrom(authentication);
|
||||
}
|
||||
|
||||
public void setAuthoritiesMapper(GrantedAuthoritiesMapper authoritiesMapper) {
|
||||
this.authoritiesMapper = authoritiesMapper;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,6 +14,8 @@ import org.springframework.security.authentication.AuthenticationDetailsSource;
|
|||
import org.springframework.security.authentication.RememberMeAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.SpringSecurityMessageSource;
|
||||
import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper;
|
||||
import org.springframework.security.core.authority.mapping.NullAuthoritiesMapper;
|
||||
import org.springframework.security.core.codec.Base64;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.core.userdetails.UserDetailsChecker;
|
||||
|
@ -55,6 +57,7 @@ public abstract class AbstractRememberMeServices implements RememberMeServices,
|
|||
private String key;
|
||||
private int tokenValiditySeconds = TWO_WEEKS_S;
|
||||
private boolean useSecureCookie = false;
|
||||
private GrantedAuthoritiesMapper authoritiesMapper = new NullAuthoritiesMapper();
|
||||
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
Assert.hasLength(key);
|
||||
|
@ -147,7 +150,8 @@ public abstract class AbstractRememberMeServices implements RememberMeServices,
|
|||
* @return the <tt>Authentication</tt> for the remember-me authenticated user
|
||||
*/
|
||||
protected Authentication createSuccessfulAuthentication(HttpServletRequest request, UserDetails user) {
|
||||
RememberMeAuthenticationToken auth = new RememberMeAuthenticationToken(key, user, user.getAuthorities());
|
||||
RememberMeAuthenticationToken auth = new RememberMeAuthenticationToken(key, user,
|
||||
authoritiesMapper.mapAuthorities(user.getAuthorities()));
|
||||
auth.setDetails(authenticationDetailsSource.buildDetails(request));
|
||||
return auth;
|
||||
}
|
||||
|
@ -417,4 +421,8 @@ public abstract class AbstractRememberMeServices implements RememberMeServices,
|
|||
public void setUserDetailsChecker(UserDetailsChecker userDetailsChecker) {
|
||||
this.userDetailsChecker = userDetailsChecker;
|
||||
}
|
||||
|
||||
public void setAuthoritiesMapper(GrantedAuthoritiesMapper authoritiesMapper) {
|
||||
this.authoritiesMapper = authoritiesMapper;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue