1
0
mirror of synced 2026-08-04 17:27:13 +00:00

SEC-1132: Moved remaining preauth code from core to web

This commit is contained in:
Luke Taylor
2009-05-12 00:11:06 +00:00
parent 76561813e9
commit 4bad213b19
31 changed files with 83 additions and 250 deletions
@@ -13,7 +13,6 @@ import org.springframework.security.web.authentication.WebAuthenticationDetailsS
import org.springframework.security.authentication.AuthenticationDetailsSource;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.event.InteractiveAuthenticationSuccessEvent;
import org.springframework.security.authentication.preauth.PreAuthenticatedAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
@@ -0,0 +1,134 @@
package org.springframework.security.web.authentication.preauth;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.core.Ordered;
import org.springframework.security.authentication.AccountStatusUserDetailsChecker;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.AuthenticationUserDetailsService;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsChecker;
import org.springframework.util.Assert;
/**
* <p>
* Processes a pre-authenticated authentication request. The request will
* typically originate from a {@link org.springframework.security.web.authentication.preauth.AbstractPreAuthenticatedProcessingFilter}
* subclass.
*
* <p>
* This authentication provider will not perform any checks on authentication
* requests, as they should already be pre-authenticated. However, the
* AuthenticationUserDetailsService implementation may still throw a UsernameNotFoundException, for example.
*
* @author Ruud Senden
* @version $Id$
* @since 2.0
*/
public class PreAuthenticatedAuthenticationProvider implements AuthenticationProvider, InitializingBean, Ordered {
private static final Log logger = LogFactory.getLog(PreAuthenticatedAuthenticationProvider.class);
private AuthenticationUserDetailsService preAuthenticatedUserDetailsService = null;
private UserDetailsChecker userDetailsChecker = new AccountStatusUserDetailsChecker();
private boolean throwExceptionWhenTokenRejected = false;
private int order = -1; // default: same as non-ordered
/**
* Check whether all required properties have been set.
*/
public void afterPropertiesSet() {
Assert.notNull(preAuthenticatedUserDetailsService, "An AuthenticationUserDetailsService must be set");
}
/**
* Authenticate the given PreAuthenticatedAuthenticationToken.
* <p>
* If the principal contained in the authentication object is null, the request will be ignored to allow other
* providers to authenticate it.
*/
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
if (!supports(authentication.getClass())) {
return null;
}
if (logger.isDebugEnabled()) {
logger.debug("PreAuthenticated authentication request: " + authentication);
}
if (authentication.getPrincipal() == null) {
logger.debug("No pre-authenticated principal found in request.");
if (throwExceptionWhenTokenRejected) {
throw new BadCredentialsException("No pre-authenticated principal found in request.");
}
return null;
}
if (authentication.getCredentials() == null) {
logger.debug("No pre-authenticated credentials found in request.");
if (throwExceptionWhenTokenRejected) {
throw new BadCredentialsException("No pre-authenticated credentials found in request.");
}
return null;
}
UserDetails ud = preAuthenticatedUserDetailsService.loadUserDetails(authentication);
userDetailsChecker.check(ud);
PreAuthenticatedAuthenticationToken result =
new PreAuthenticatedAuthenticationToken(ud, authentication.getCredentials(), ud.getAuthorities());
result.setDetails(authentication.getDetails());
return result;
}
/**
* Indicate that this provider only supports PreAuthenticatedAuthenticationToken (sub)classes.
*/
public boolean supports(Class<? extends Object> authentication) {
return PreAuthenticatedAuthenticationToken.class.isAssignableFrom(authentication);
}
/**
* Set the AuthenticatedUserDetailsServices to be used.
*
* @param aPreAuthenticatedUserDetailsService
*/
public void setPreAuthenticatedUserDetailsService(AuthenticationUserDetailsService aPreAuthenticatedUserDetailsService) {
this.preAuthenticatedUserDetailsService = aPreAuthenticatedUserDetailsService;
}
public int getOrder() {
return order;
}
public void setOrder(int i) {
order = i;
}
/**
* If true, causes the provider to throw a BadCredentialsException if the presented authentication
* request is invalid (contains a null principal or credentials). Otherwise it will just return
* null. Defaults to false.
*/
public void setThrowExceptionWhenTokenRejected(boolean throwExceptionWhenTokenRejected) {
this.throwExceptionWhenTokenRejected = throwExceptionWhenTokenRejected;
}
/**
* Sets the strategy which will be used to validate the loaded <tt>UserDetails</tt> object
* for the user. Defaults to an {@link AccountStatusUserDetailsChecker}.
* @param userDetailsChecker
*/
public void setUserDetailsChecker(UserDetailsChecker userDetailsChecker) {
Assert.notNull(userDetailsChecker, "userDetailsChacker cannot be null");
this.userDetailsChecker = userDetailsChecker;
}
}
@@ -0,0 +1,81 @@
package org.springframework.security.web.authentication.preauth;
import java.util.Arrays;
import java.util.List;
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
/**
* {@link org.springframework.security.core.Authentication} implementation for pre-authenticated
* authentication.
*
* @author Ruud Senden
* @since 2.0
*/
public class PreAuthenticatedAuthenticationToken extends AbstractAuthenticationToken {
private final Object principal;
private final Object credentials;
/**
* Constructor used for an authentication request. The {@link
* org.springframework.security.core.Authentication#isAuthenticated()} will return
* <code>false</code>.
*
* @TODO Should we have only a single credentials parameter here? For
* example for X509 the certificate is used as credentials, while
* currently a J2EE username is specified as a principal but could as
* well be set as credentials.
*
* @param aPrincipal
* The pre-authenticated principal
* @param aCredentials
* The pre-authenticated credentials
*/
public PreAuthenticatedAuthenticationToken(Object aPrincipal, Object aCredentials) {
super(null);
this.principal = aPrincipal;
this.credentials = aCredentials;
}
/**
*
* @deprecated
*/
public PreAuthenticatedAuthenticationToken(Object aPrincipal, Object aCredentials, GrantedAuthority[] anAuthorities) {
this(aPrincipal, aCredentials, Arrays.asList(anAuthorities));
}
/**
* Constructor used for an authentication response. The {@link
* org.springframework.security.core.Authentication#isAuthenticated()} will return
* <code>true</code>.
*
* @param aPrincipal
* The authenticated principal
* @param anAuthorities
* The granted authorities
*/
public PreAuthenticatedAuthenticationToken(Object aPrincipal, Object aCredentials, List<GrantedAuthority> anAuthorities) {
super(anAuthorities);
this.principal = aPrincipal;
this.credentials = aCredentials;
setAuthenticated(true);
}
/**
* Get the credentials
*/
public Object getCredentials() {
return this.credentials;
}
/**
* Get the principal
*/
public Object getPrincipal() {
return this.principal;
}
}
@@ -0,0 +1,57 @@
package org.springframework.security.web.authentication.preauth;
import java.util.List;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.GrantedAuthoritiesContainer;
import org.springframework.security.core.userdetails.AuthenticationUserDetailsService;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.util.Assert;
/**
* <p>
* This AuthenticationUserDetailsService implementation creates a UserDetails
* object based solely on the information contained in the given
* PreAuthenticatedAuthenticationToken. The user name is set to the name as
* returned by PreAuthenticatedAuthenticationToken.getName(), the password is
* set to a fixed dummy value (it will not be used by the
* PreAuthenticatedAuthenticationProvider anyway), and the Granted Authorities
* are retrieved from the details object as returned by
* PreAuthenticatedAuthenticationToken.getDetails().
*
* <p>
* The details object as returned by PreAuthenticatedAuthenticationToken.getDetails() must implement the
* {@link GrantedAuthoritiesContainer} interface for this implementation to work.
*
* @author Ruud Senden
* @since 2.0
*/
public class PreAuthenticatedGrantedAuthoritiesUserDetailsService implements AuthenticationUserDetailsService {
/**
* Get a UserDetails object based on the user name contained in the given
* token, and the GrantedAuthorities as returned by the
* GrantedAuthoritiesContainer implementation as returned by
* the token.getDetails() method.
*/
public final UserDetails loadUserDetails(Authentication token) throws AuthenticationException {
Assert.notNull(token.getDetails());
Assert.isInstanceOf(GrantedAuthoritiesContainer.class, token.getDetails());
List<GrantedAuthority> authorities = ((GrantedAuthoritiesContainer) token.getDetails()).getGrantedAuthorities();
UserDetails ud = createuserDetails(token, authorities);
return ud;
}
/**
* Creates the final <tt>UserDetails</tt> object. Can be overridden to customize the contents.
*
* @param token the authentication request token
* @param authorities the pre-authenticated authorities.
*/
protected UserDetails createuserDetails(Authentication token, List<GrantedAuthority> authorities) {
return new User(token.getName(), "N/A", true, true, true, true, authorities);
}
}
@@ -6,9 +6,9 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.security.authentication.AuthenticationDetailsSource;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.preauth.PreAuthenticatedAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken;
import org.springframework.util.Assert;
/**
@@ -0,0 +1,119 @@
package org.springframework.security.web.authentication.preauth;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import org.junit.Test;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.AuthenticationUserDetailsService;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider;
import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken;
/**
*
* @author TSARDD
* @since 18-okt-2007
*/
public class PreAuthenticatedAuthenticationProviderTests {
@Test(expected = IllegalArgumentException.class)
public final void afterPropertiesSet() {
PreAuthenticatedAuthenticationProvider provider = new PreAuthenticatedAuthenticationProvider();
provider.afterPropertiesSet();
}
@Test
public final void authenticateInvalidToken() throws Exception {
UserDetails ud = new User("dummyUser", "dummyPwd", true, true, true, true, AuthorityUtils.NO_AUTHORITIES );
PreAuthenticatedAuthenticationProvider provider = getProvider(ud);
Authentication request = new UsernamePasswordAuthenticationToken("dummyUser", "dummyPwd");
Authentication result = provider.authenticate(request);
assertNull(result);
}
@Test
public final void nullPrincipalReturnsNullAuthentication() throws Exception {
PreAuthenticatedAuthenticationProvider provider = new PreAuthenticatedAuthenticationProvider();
Authentication request = new PreAuthenticatedAuthenticationToken(null, "dummyPwd");
Authentication result = provider.authenticate(request);
assertNull(result);
}
@Test
public final void authenticateKnownUser() throws Exception {
UserDetails ud = new User("dummyUser", "dummyPwd", true, true, true, true, AuthorityUtils.NO_AUTHORITIES );
PreAuthenticatedAuthenticationProvider provider = getProvider(ud);
Authentication request = new PreAuthenticatedAuthenticationToken("dummyUser", "dummyPwd");
Authentication result = provider.authenticate(request);
assertNotNull(result);
assertEquals(result.getPrincipal(), ud);
// @TODO: Add more asserts?
}
@Test
public final void authenticateIgnoreCredentials() throws Exception {
UserDetails ud = new User("dummyUser1", "dummyPwd1", true, true, true, true, AuthorityUtils.NO_AUTHORITIES );
PreAuthenticatedAuthenticationProvider provider = getProvider(ud);
Authentication request = new PreAuthenticatedAuthenticationToken("dummyUser1", "dummyPwd2");
Authentication result = provider.authenticate(request);
assertNotNull(result);
assertEquals(result.getPrincipal(), ud);
// @TODO: Add more asserts?
}
@Test(expected=UsernameNotFoundException.class)
public final void authenticateUnknownUserThrowsException() throws Exception {
UserDetails ud = new User("dummyUser1", "dummyPwd", true, true, true, true, AuthorityUtils.NO_AUTHORITIES );
PreAuthenticatedAuthenticationProvider provider = getProvider(ud);
Authentication request = new PreAuthenticatedAuthenticationToken("dummyUser2", "dummyPwd");
provider.authenticate(request);
}
@Test
public final void supportsArbitraryObject() throws Exception {
PreAuthenticatedAuthenticationProvider provider = getProvider(null);
assertFalse(provider.supports(Authentication.class));
}
@Test
public final void supportsPreAuthenticatedAuthenticationToken() throws Exception {
PreAuthenticatedAuthenticationProvider provider = getProvider(null);
assertTrue(provider.supports(PreAuthenticatedAuthenticationToken.class));
}
@Test
public void getSetOrder() throws Exception {
PreAuthenticatedAuthenticationProvider provider = getProvider(null);
provider.setOrder(333);
assertEquals(provider.getOrder(), 333);
}
private PreAuthenticatedAuthenticationProvider getProvider(UserDetails aUserDetails) throws Exception {
PreAuthenticatedAuthenticationProvider result = new PreAuthenticatedAuthenticationProvider();
result.setPreAuthenticatedUserDetailsService(getPreAuthenticatedUserDetailsService(aUserDetails));
result.afterPropertiesSet();
return result;
}
private AuthenticationUserDetailsService getPreAuthenticatedUserDetailsService(final UserDetails aUserDetails) {
return new AuthenticationUserDetailsService() {
public UserDetails loadUserDetails(Authentication token) throws UsernameNotFoundException {
if (aUserDetails != null && aUserDetails.getUsername().equals(token.getName())) {
return aUserDetails;
}
throw new UsernameNotFoundException("notfound");
}
};
}
}
@@ -0,0 +1,56 @@
package org.springframework.security.web.authentication.preauth;
import java.util.List;
import junit.framework.TestCase;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken;
/**
*
* @author TSARDD
* @since 18-okt-2007
*/
public class PreAuthenticatedAuthenticationTokenTests extends TestCase {
public void testPreAuthenticatedAuthenticationTokenRequestWithDetails() {
Object principal = "dummyUser";
Object credentials = "dummyCredentials";
Object details = "dummyDetails";
PreAuthenticatedAuthenticationToken token = new PreAuthenticatedAuthenticationToken(principal, credentials);
token.setDetails(details);
assertEquals(principal, token.getPrincipal());
assertEquals(credentials, token.getCredentials());
assertEquals(details, token.getDetails());
assertNull(token.getAuthorities());
}
public void testPreAuthenticatedAuthenticationTokenRequestWithoutDetails() {
Object principal = "dummyUser";
Object credentials = "dummyCredentials";
PreAuthenticatedAuthenticationToken token = new PreAuthenticatedAuthenticationToken(principal, credentials);
assertEquals(principal, token.getPrincipal());
assertEquals(credentials, token.getCredentials());
assertNull(token.getDetails());
assertNull(token.getAuthorities());
}
public void testPreAuthenticatedAuthenticationTokenResponse() {
Object principal = "dummyUser";
Object credentials = "dummyCredentials";
List<GrantedAuthority> gas = AuthorityUtils.createAuthorityList("Role1");
PreAuthenticatedAuthenticationToken token =
new PreAuthenticatedAuthenticationToken(principal, credentials, gas);
assertEquals(principal, token.getPrincipal());
assertEquals(credentials, token.getCredentials());
assertNull(token.getDetails());
assertNotNull(token.getAuthorities());
List<GrantedAuthority> resultColl = token.getAuthorities();
assertTrue("GrantedAuthority collections do not match; result: " + resultColl + ", expected: " + gas,
gas.containsAll(resultColl) && resultColl.containsAll(gas));
}
}
@@ -0,0 +1,73 @@
package org.springframework.security.web.authentication.preauth;
import static org.junit.Assert.*;
import java.util.List;
import org.junit.Test;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.authority.GrantedAuthoritiesContainer;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken;
import org.springframework.security.web.authentication.preauth.PreAuthenticatedGrantedAuthoritiesUserDetailsService;
/**
*
* @author TSARDD
* @since 18-okt-2007
*/
public class PreAuthenticatedGrantedAuthoritiesUserDetailsServiceTests {
@Test(expected=IllegalArgumentException.class)
public void testGetUserDetailsInvalidType() {
PreAuthenticatedGrantedAuthoritiesUserDetailsService svc = new PreAuthenticatedGrantedAuthoritiesUserDetailsService();
PreAuthenticatedAuthenticationToken token = new PreAuthenticatedAuthenticationToken("dummy", "dummy");
token.setDetails(new Object());
svc.loadUserDetails(token);
}
@Test(expected=IllegalArgumentException.class)
public void testGetUserDetailsNoDetails() {
PreAuthenticatedGrantedAuthoritiesUserDetailsService svc = new PreAuthenticatedGrantedAuthoritiesUserDetailsService();
PreAuthenticatedAuthenticationToken token = new PreAuthenticatedAuthenticationToken("dummy", "dummy");
token.setDetails(null);
svc.loadUserDetails(token);
}
@Test
public void testGetUserDetailsEmptyAuthorities() {
final String userName = "dummyUser";
testGetUserDetails(userName, AuthorityUtils.NO_AUTHORITIES);
}
@Test
public void testGetUserDetailsWithAuthorities() {
final String userName = "dummyUser";
testGetUserDetails(userName, AuthorityUtils.createAuthorityList("Role1", "Role2"));
}
private void testGetUserDetails(final String userName, final List<GrantedAuthority> gas) {
PreAuthenticatedGrantedAuthoritiesUserDetailsService svc = new PreAuthenticatedGrantedAuthoritiesUserDetailsService();
PreAuthenticatedAuthenticationToken token = new PreAuthenticatedAuthenticationToken(userName, "dummy");
token.setDetails(new GrantedAuthoritiesContainer() {
public List<GrantedAuthority> getGrantedAuthorities() {
return gas;
}
});
UserDetails ud = svc.loadUserDetails(token);
assertTrue(ud.isAccountNonExpired());
assertTrue(ud.isAccountNonLocked());
assertTrue(ud.isCredentialsNonExpired());
assertTrue(ud.isEnabled());
assertEquals(ud.getUsername(), userName);
//Password is not saved by
// PreAuthenticatedGrantedAuthoritiesUserDetailsService
//assertEquals(ud.getPassword(),password);
assertTrue("GrantedAuthority collections do not match; result: " + ud.getAuthorities() + ", expected: " + gas,
gas.containsAll(ud.getAuthorities()) && ud.getAuthorities().containsAll(gas));
}
}
@@ -8,7 +8,6 @@ import org.junit.After;
import org.junit.Test;
import org.springframework.security.authentication.AuthenticationDetailsSource;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.preauth.PreAuthenticatedAuthenticationProvider;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.context.SecurityContext;
@@ -17,6 +16,7 @@ import org.springframework.security.core.context.SecurityContextImpl;
import org.springframework.security.core.userdetails.AuthenticationUserDetailsService;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsChecker;
import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider;
/**
*