Make User available from Authentication via DaoAuthenticationProvider.

This commit is contained in:
Ben Alex
2004-06-21 06:10:14 +00:00
parent 36ad7f3963
commit 1a0bec5bf1
15 changed files with 164 additions and 39 deletions

View File

@@ -51,12 +51,26 @@ import org.springframework.dao.DataAccessException;
* <p>
* Upon successful validation, a
* <code>UsernamePasswordAuthenticationToken</code> will be created and
* returned to the caller. In addition, the {@link User} will be placed in the
* {@link UserCache} so that subsequent requests with the same username can be
* validated without needing to query the {@link AuthenticationDao}. It should
* be noted that if a user appears to present an incorrect password, the
* {@link AuthenticationDao} will be queried to confirm the most up-to-date
* password was used for comparison.
* returned to the caller. The token will include as its principal either a
* <code>String</code> representation of the username, or the {@link User}
* that was returned from the authentication repository. Using
* <code>String</code> is appropriate if a container adapter is being used, as
* it expects <code>String</code> representations of the username. Using
* <code>User</code> is appropriate if you require access to additional
* properties of the authenticated user, such as email addresses,
* human-friendly names etc. As container adapters are not recommended to be
* used, and <code>User</code> provides additional flexibility, by default a
* <code>User</code> is returned. To override this default, set the {@link
* #setForcePrincipalAsString} to <code>true</code>.
* </p>
*
* <P>
* Caching is handled via the <code>User</code> object being placed in the
* {@link UserCache}. This ensures that subsequent requests with the same
* username can be validated without needing to query the {@link
* AuthenticationDao}. It should be noted that if a user appears to present an
* incorrect password, the {@link AuthenticationDao} will be queried to
* confirm the most up-to-date password was used for comparison.
* </p>
*
* <P>
@@ -79,6 +93,7 @@ public class DaoAuthenticationProvider implements AuthenticationProvider,
private PasswordEncoder passwordEncoder = new PlaintextPasswordEncoder();
private SaltSource saltSource;
private UserCache userCache = new NullUserCache();
private boolean forcePrincipalAsString = false;
//~ Methods ================================================================
@@ -95,6 +110,14 @@ public class DaoAuthenticationProvider implements AuthenticationProvider,
return authenticationDao;
}
public void setForcePrincipalAsString(boolean forcePrincipalAsString) {
this.forcePrincipalAsString = forcePrincipalAsString;
}
public boolean isForcePrincipalAsString() {
return forcePrincipalAsString;
}
/**
* Sets the PasswordEncoder instance to be used to encode and validate
* passwords. If not set, {@link PlaintextPasswordEncoder} will be used by
@@ -148,13 +171,19 @@ public class DaoAuthenticationProvider implements AuthenticationProvider,
public Authentication authenticate(Authentication authentication)
throws AuthenticationException {
// Determine username
String username = authentication.getPrincipal().toString();
if (authentication.getPrincipal() instanceof User) {
username = ((User) authentication.getPrincipal()).getUsername();
}
boolean cacheWasUsed = true;
User user = this.userCache.getUserFromCache(authentication.getPrincipal()
.toString());
User user = this.userCache.getUserFromCache(username);
if (user == null) {
cacheWasUsed = false;
user = getUserFromBackend(authentication);
user = getUserFromBackend(username);
}
if (!user.isEnabled()) {
@@ -170,7 +199,7 @@ public class DaoAuthenticationProvider implements AuthenticationProvider,
// Password incorrect, so ensure we're using most current password
if (cacheWasUsed) {
cacheWasUsed = false;
user = getUserFromBackend(authentication);
user = getUserFromBackend(username);
}
if (!isPasswordCorrect(authentication, user)) {
@@ -194,9 +223,15 @@ public class DaoAuthenticationProvider implements AuthenticationProvider,
}
}
Object principalToReturn = user;
if (forcePrincipalAsString) {
principalToReturn = user.getUsername();
}
// Ensure we return the original credentials the user supplied,
// so subsequent attempts are successful even with encoded passwords
return new UsernamePasswordAuthenticationToken(user.getUsername(),
return new UsernamePasswordAuthenticationToken(principalToReturn,
authentication.getCredentials(), user.getAuthorities());
}
@@ -220,10 +255,9 @@ public class DaoAuthenticationProvider implements AuthenticationProvider,
authentication.getCredentials().toString(), salt);
}
private User getUserFromBackend(Authentication authentication) {
private User getUserFromBackend(String username) {
try {
return this.authenticationDao.loadUserByUsername(authentication.getPrincipal()
.toString());
return this.authenticationDao.loadUserByUsername(username);
} catch (UsernameNotFoundException notFound) {
throw new BadCredentialsException("Bad credentials presented");
} catch (DataAccessException repositoryProblem) {

View File

@@ -36,6 +36,7 @@
<!-- Authentication provider that queries our data access object -->
<bean id="daoAuthenticationProvider" class="net.sf.acegisecurity.providers.dao.DaoAuthenticationProvider">
<property name="authenticationDao"><ref bean="inMemoryDaoImpl"/></property>
<property name="forcePrincipalAsString"><value>true</value></property>
</bean>
<!-- The authentication manager that iterates through our only authentication provider -->

View File

@@ -36,6 +36,7 @@
<!-- Authentication provider that queries our data access object -->
<bean id="daoAuthenticationProvider" class="net.sf.acegisecurity.providers.dao.DaoAuthenticationProvider">
<property name="authenticationDao"><ref bean="inMemoryDaoImpl"/></property>
<property name="forcePrincipalAsString"><value>true</value></property>
</bean>
<!-- The authentication manager that iterates through our only authentication provider -->

View File

@@ -166,7 +166,7 @@ public class DaoAuthenticationProviderTests extends TestCase {
}
UsernamePasswordAuthenticationToken castResult = (UsernamePasswordAuthenticationToken) result;
assertEquals("marissa", castResult.getPrincipal());
assertEquals(User.class, castResult.getPrincipal().getClass());
assertEquals("koala", castResult.getCredentials());
assertEquals("ROLE_ONE", castResult.getAuthorities()[0].getAuthority());
assertEquals("ROLE_TWO", castResult.getAuthorities()[1].getAuthority());
@@ -192,7 +192,7 @@ public class DaoAuthenticationProviderTests extends TestCase {
}
UsernamePasswordAuthenticationToken castResult = (UsernamePasswordAuthenticationToken) result;
assertEquals("marissa", castResult.getPrincipal());
assertEquals(User.class, castResult.getPrincipal().getClass());
// We expect original credentials user submitted to be returned
assertEquals("koala", castResult.getCredentials());

View File

@@ -24,6 +24,7 @@ import net.sf.acegisecurity.MockFilterConfig;
import net.sf.acegisecurity.MockHttpServletRequest;
import net.sf.acegisecurity.MockHttpServletResponse;
import net.sf.acegisecurity.MockHttpSession;
import net.sf.acegisecurity.providers.dao.User;
import net.sf.acegisecurity.ui.webapp.HttpSessionIntegrationFilter;
import org.apache.commons.codec.binary.Base64;
@@ -199,8 +200,8 @@ public class BasicProcessingFilterTests extends TestCase {
assertTrue(request.getSession().getAttribute(HttpSessionIntegrationFilter.ACEGI_SECURITY_AUTHENTICATION_KEY) != null);
assertEquals("marissa",
((Authentication) request.getSession().getAttribute(HttpSessionIntegrationFilter.ACEGI_SECURITY_AUTHENTICATION_KEY)).getPrincipal()
.toString());
((User) ((Authentication) request.getSession().getAttribute(HttpSessionIntegrationFilter.ACEGI_SECURITY_AUTHENTICATION_KEY)).getPrincipal())
.getUsername());
}
public void testOtherAuthorizationSchemeIsIgnored()
@@ -291,8 +292,8 @@ public class BasicProcessingFilterTests extends TestCase {
assertTrue(request.getSession().getAttribute(HttpSessionIntegrationFilter.ACEGI_SECURITY_AUTHENTICATION_KEY) != null);
assertEquals("marissa",
((Authentication) request.getSession().getAttribute(HttpSessionIntegrationFilter.ACEGI_SECURITY_AUTHENTICATION_KEY)).getPrincipal()
.toString());
((User) ((Authentication) request.getSession().getAttribute(HttpSessionIntegrationFilter.ACEGI_SECURITY_AUTHENTICATION_KEY)).getPrincipal())
.getUsername());
// NOW PERFORM FAILED AUTHENTICATION
// Setup our HTTP request

View File

@@ -20,6 +20,8 @@ import junit.framework.TestCase;
import net.sf.acegisecurity.MockHttpServletRequest;
import net.sf.acegisecurity.MockHttpServletResponse;
import java.net.URLEncoder;
/**
* Tests {@link CasProcessingFilterEntryPoint}.
@@ -99,8 +101,11 @@ public class CasProcessingFilterEntryPointTests extends TestCase {
ep.afterPropertiesSet();
ep.commence(request, response);
assertEquals("https://cas/login?service=https://mycompany.com/bigWebApp/j_acegi_cas_security_check",
response.getRedirect());
assertEquals("https://cas/login?service="
+ URLEncoder.encode(
"https://mycompany.com/bigWebApp/j_acegi_cas_security_check",
"UTF-8"), response.getRedirect());
}
public void testNormalOperationWithRenewTrue() throws Exception {