My implementation of the attemptAuthentication() method of the AuthenticationProcessingFilter:
Code:
public class CustomAuthenticationProcessingFilter extends AuthenticationProcessingFilter
{
@Override
public Authentication attemptAuthentication (HttpServletRequest request) throws AuthenticationException
{
logger.debug ("CustomAuthenticationProcessingFilter::attemptAuthentication()");
try
{
...
logger.debug ("username : " + username);
logger.debug ("password : " + password);
logger.debug ("domain : " + domain);
UsernamePasswordAuthenticationToken authRequest = new DomainSecurityAuthenticationToken (username, password, domain);
// Place the last username attempted into HttpSession for views
HttpSession session = request.getSession (false);
if (session != null || getAllowSessionCreation ()) request.getSession ().setAttribute (SPRING_SECURITY_LAST_USERNAME_KEY, ...);
// Allow subclasses to set the "details" property
setDetails (request, authRequest);
// set default target url based on domain in request
setDefaultTargetUrl ("/domain/secure/" + domain + "/hoofdpagina");
return this.getAuthenticationManager ().authenticate (authRequest);
}
catch (AuthenticationException ae)
{
logger.error (ae);
throw ae;
}
}
}
A couple of questions about this implementation:
- Do I need the code related to setting the session attribute?
- Do I need the setDetails() call?
I want to keep my implementation as lean as possible.
In the logging I see that this implementation is called. These are all the lines related to what I'm trying to implement:
Code:
CustomAuthenticationProcessingFilter:251 - Request is to process authentication
CustomAuthenticationProcessingFilter:35 - CustomAuthenticationProcessingFilter::attemptAuthentication()
CustomAuthenticationProcessingFilter:42 - username : aaa
CustomAuthenticationProcessingFilter:44 - domain : provraad
CustomUserDetailsAuthenticationProvider:34 - CustomUserDetailsAuthenticationProvider::supports()
CustomUserDetailsAuthenticationProvider:35 - auth.class : be.vlaamsbrabant.domainsecuritytest.security.DomainSecurityAuthenticationToken
CustomUserDetailsAuthenticationProvider:38 - supports : true
CustomUserDetailsAuthenticationProvider:52 - Retrieving the logged in user details ...
CustomUserDetailsAuthenticationProvider:60 - USERNAME: aaa
CustomUserDetailsAuthenticationProvider:72 - Retrieve user:
CustomUserDetailsAuthenticationProvider:73 - - Naam : aaa
CustomUserDetailsAuthenticationProvider:79 - DOMAIN: provraad
DomainSecurityDAOImpl:50 - DomainSecurityDAOImpl::DomainSecurityDAOImpl()
DomainSecurityDAOImpl:318 - wsdlLocationURL : http://localhost:8084/domainsecurity-ws/DomainSecurityService?wsdl
CustomUserDetailsAuthenticationProvider:116 - additionalAuthenticationChecks()
CustomUserDetailsAuthenticationProvider:119 - secuserDomain : provraad
CustomUserDetailsAuthenticationProvider:121 - tokenDomain : provraad
CustomUserDetailsAuthenticationProvider:139 - createSuccessAuthentication()
CustomAuthenticationProcessingFilter:363 - Updated SecurityContextHolder to contain the following Authentication: 'be.vlaamsbrabant.domainsecuritytest.security.DomainSecurityAuthenticationToken@4b47bf7b: Principal: be.vlaamsbrabant.domainsecuritytest.security.SecurityUserDetails@16a7c99; Password: [PROTECTED]; Authenticated: true; Details: org.springframework.security.ui.WebAuthenticationDetails@1c07a: RemoteIpAddress: 127.0.0.1; SessionId: 6322CADEFA5EBC7164638F5F5B76A21D; Granted Authorities: ROLE_DOMAIN_USER'
UrlVoter:17 - UrlVoter::vote()
UrlVoter:20 - auth.class : be.vlaamsbrabant.domainsecuritytest.security.DomainSecurityAuthenticationToken
UrlVoter:24 - domain : provraad
Next, as shown in the logging my own implementation of the AbstractUserDetailsAuthenticationProvider is called (CustomUserDetailsAuthenticationProvider)
I implemented the supports() method and in the logging you can see that the implementation class logged in that method is my own class (DomainSecurityAuthenticationToken, derived from UsernamePasswordAuthenticationToken).
Next my own implementation of retrieveUser() of the CustomUserDetailsAuthenticationProvider is called:
Code:
@Override
protected UserDetails retrieveUser (String username, UsernamePasswordAuthenticationToken token) throws AuthenticationException
{
if (logger.isInfoEnabled ()) logger.info ("Retrieving the logged in user details ...");
username = token.getPrincipal ().toString ();
logger.debug ("USERNAME: " + username);
String paswoord = token.getCredentials ().toString ();
if (logger.isDebugEnabled ()) logger.debug ("Retrieve user:");
if (logger.isDebugEnabled ()) logger.debug ("- Naam : " + username);
String domain = ((DomainSecurityAuthenticationToken) token).getDomain ();
logger.debug ("DOMAIN: " + domain);
// getting the DomainUser object for specified username, (encoded) password and domain
DomainSecurityClient domsecClient = DomainSecurityClientFactory.getInstance ();
DomainUser domainUser = null;
UserDetails secUserDetails = null;
try
{
secUserDetails = ...
}
catch (DomainSecurityException dse)
{
logger.error (dse);
}
catch (AuthenticationException ae)
{
logger.error (ae);
throw ae;
}
return secUserDetails;
}
Next my own implementations of additionalAuthenticationChecks() and createSuccessAuthentication() in the AuthenticationProvider are called.
This is my implementation of createSuccessAuthentication():
Code:
protected Authentication createSuccessAuthentication (Object principal, Authentication authentication, UserDetails user)
{
logger.debug ("createSuccessAuthentication()");
DomainSecurityAuthenticationToken result = new DomainSecurityAuthenticationToken (principal,
authentication.getCredentials (), user.getAuthorities (), ((DomainSecurityAuthenticationToken) authentication)
.getDomain ());
result.setDetails (authentication.getDetails ());
return result;
}
After adding this implementation I got the lines in my logging showing that the DomainSecurityAuthenticationToken was stored in the SecurityContextHolder and my additional Voter works.
WHEN I LEAVE OUT THE IMPLEMENTATION OF createSuccessAuthentication () I get the following log lines. Now UsernamePasswordAuthenticationToken is stored in the SecurityContextHolder and I get the ClassCastException in the UrlVoter.
Code:
CustomAuthenticationProcessingFilter:363 - Updated SecurityContextHolder to contain the following Authentication: 'org.springframework.security.providers.UsernamePasswordAuthenticationToken@b5a59201: Principal: be.vlaamsbrabant.domainsecuritytest.security.SecurityUserDetails@76fb1b; Password: [PROTECTED]; Authenticated: true; Details: org.springframework.security.ui.WebAuthenticationDetails@ffff6a82: RemoteIpAddress: 127.0.0.1; SessionId: BD2C174501CDE769E206CD51B7B5D7F0; Granted Authorities: ROLE_DOMAIN_USER'
UrlVoter:17 - UrlVoter::vote()
UrlVoter:20 - auth.class : org.springframework.security.providers.UsernamePasswordAuthenticationToken
[default]:260 - Servlet.service() for servlet default threw exception
java.lang.ClassCastException: org.springframework.security.providers.UsernamePasswordAuthenticationToken cannot be cast to be.vlaamsbrabant.domainsecuritytest.security.DomainSecurityAuthenticationToken
I downloaded the source code and what happens according to me is this (correct me if I'm wrong):
At a certain point the authenticate() method of AbstractUserDetailsAuthenticationProvider is called. In this method retrieveUser of my own implementation is called:
Code:
try {
user = retrieveUser(username, (UsernamePasswordAuthenticationToken) authentication);
} catch (UsernameNotFoundException notFound) { ...
}
authenticate() returns the result of createSuccessAuthentication(). In this method an instance of UsernamePasswordAuthenticationToken is created:
Code:
protected Authentication createSuccessAuthentication(Object principal, Authentication authentication, UserDetails user) {
UsernamePasswordAuthenticationToken result = new UsernamePasswordAuthenticationToken(principal,
authentication.getCredentials(), user.getAuthorities());
result.setDetails(authentication.getDetails());
return result;
}
Apparently this instance is stored in the SecurityContextHolder and not my own implementation of this token, even when I end my implementation of AuthenticationProcessingFilter attempAuthentication() with the following line:
Code:
return this.getAuthenticationManager ().authenticate (authRequest);
authRequest has been instantiated in the same method as follows:
Code:
UsernamePasswordAuthenticationToken authRequest = new DomainSecurityAuthenticationToken (username, password, domain);