Page 1 of 2 12 LastLast
Results 1 to 10 of 12

Thread: using authentication token during authorisation

  1. #1
    Join Date
    Sep 2010
    Posts
    12

    Default using authentication token during authorisation

    I implemented my own AuthenticationProcessingFilter in which I set the authentication token to an instance of DomainSecurityAuthenticationToken, which is a class derived from UsernamePasswordAuthenticationToken.

    DomainSecurityAuthenticationToken has an extra property "domain".

    Using the custom filter with the new token class works fine.

    Now I want to use the same token class (and the extra property "domain") during authorisation.

    In my own Voter (I'm using spring security 2.x) I added the following lines in the vote() method:

    DomainSecurityAuthenticationToken token = (DomainSecurityAuthenticationToken) authentication;

    At run-time I get the following error on this line:

    java.lang.ClassCastException: org.springframework.security.providers.UsernamePas swordAuthenticationToken cannot be cast to be.vlaamsbrabant.domainsecuritytest.security.Domai nSecurityAuthenticationToken
    be.vlaamsbrabant.domainsecuritytest.security.UrlVo ter.vote(UrlVoter.java:18)


    How can I use the same token for authorisation that I used for authentication?
    Do I again have to replace a filter? Which one?

  2. #2
    Luke Taylor is offline Senior Member Acegi Security System TeamSpring Team
    Join Date
    Aug 2004
    Location
    Glasgow, Scotland
    Posts
    3,449

    Default

    If you are returning a DomainSecurityAuthenticationToken from the AuthenticationProvider and/or setting it in the SecurityContext then that should be what is presented to your voter.

    Are you actually setting the security context contents?
    Spring - by Pivotal
    twitter @tekul

  3. #3
    Join Date
    Jan 2008
    Posts
    1,834

    Default

    Are you certain that your filter is being used to authenticate? Did you verify using the debugger or logging that your Authentication is being used? It sounds like this might be an issue with your configuration and/or custom implementation. Can you post your Spring Security configuration and custom code (please use the code tags)?
    Rob Winch
    Twitter @rob_winch
    Spring Security Lead
    Spring by Pivotal

  4. #4
    Join Date
    Sep 2010
    Posts
    12

    Default using authentication token during authorisation

    I posted what I did for the custom authentication process in a long post on Feb 11th of this year in post with the title "extra login fields".

    What happens with the custom authentication token is the following:

    In the custom Authentication Processing Filter:

    Code:
    public Authentication attemptAuthentication (HttpServletRequest request) throws AuthenticationException
    {
    ...
    String domain = request.getParameter (DOMAIN_PARAM_KEY);
    DomainSecurityAuthenticationToken domsecToken = new DomainSecurityAuthenticationToken (username, password, domain);
    ...
    Authentication auth = this.getAuthenticationManager ().authenticate (domsecToken);
    ...
    }
    The auth object is not passed or returned to anything. Do I have to put it in the SecurityContext, so that I can retrieve later on?

    How can I retrieve the SecurityContext in a Voter?

  5. #5
    Join Date
    Jan 2008
    Posts
    1,834

    Default

    Quote Originally Posted by guythomas View Post
    The auth object is not passed or returned to anything. Do I have to put it in the SecurityContext, so that I can retrieve later on?
    You should be returning the custom authentication in the filter. AbstractProcessingFilter will add this to the SecurityContextHolder.

    Quote Originally Posted by guythomas View Post
    How can I retrieve the SecurityContext in a Voter?
    You get the authentication passed into the Voter. That Authentication object should be the one that you returned in your custom Filter and was set in the SecurityContextHolder.

    If you still have problems I would recommend turning on debug logging for Spring Security. You will likely see logs that contain something like:

    Code:
    Updated SecurityContextHolder to contain the following Authentication:
    Rob Winch
    Twitter @rob_winch
    Spring Security Lead
    Spring by Pivotal

  6. #6
    Join Date
    Sep 2010
    Posts
    12

    Default using authentication token during authorisation

    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);

  7. #7
    Luke Taylor is offline Senior Member Acegi Security System TeamSpring Team
    Join Date
    Aug 2004
    Location
    Glasgow, Scotland
    Posts
    3,449

    Default

    The AuthenticationProvider calls createSuccessAuthentication() and returns the instance provided by that method.

    So that is the value that is returned by the AuthenticationManager and ultimately stored in the security context. If you don't customize the returned object, you will get a basic UsernamePasswordAuthenticationToken, as provided by the default implementation of createSuccessAuthentication().
    Spring - by Pivotal
    twitter @tekul

  8. #8
    Join Date
    Sep 2010
    Posts
    12

    Default using authentication token during authorisation

    Hallo Luke, if I understand you correctly, implementing my own version of createSuccessAuthentication() was the right thing to do?

    But I'm still wondering why the authentication object in the retrieveUser() implementation of AbstractUserDetailsAuthenticationProvider is cast to UsernamePasswordAuthenticationToken.

    If this weren't the case, couldn't we do without providing our own version of createSuccessAuthentication()?

    In the attemptAuthentication method of the AuthenticationProcessingFilter I already initialized UsernamePasswordAuthenticationToken as a reference to a DomainSecurityAuthenticationToken:

    Code:
    UsernamePasswordAuthenticationToken authRequest = new DomainSecurityAuthenticationToken (username, password, domain);
    which is then passed to the authentication manager:

    Code:
    return this.getAuthenticationManager ().authenticate (authRequest);
    It looks to me as if this reference is lost when we do not provide our own implementation of createSuccessAuthentication().

    Or am I talking complete nonsense?

  9. #9
    Join Date
    Sep 2010
    Posts
    12

    Default

    Sorry, the second sentence in my previous mail should be:

    But I'm still wondering why the authentication object in the autheticate() method of AbstractUserDetailsAuthenticationProvider is cast to UsernamePasswordAuthenticationToken.

    Code:
    user = retrieveUser(username, (UsernamePasswordAuthenticationToken) authentication);

  10. #10
    Luke Taylor is offline Senior Member Acegi Security System TeamSpring Team
    Join Date
    Aug 2004
    Location
    Glasgow, Scotland
    Posts
    3,449

    Default

    Quote Originally Posted by guythomas View Post
    Sorry, the second sentence in my previous mail should be:

    But I'm still wondering why the authentication object in the autheticate() method of AbstractUserDetailsAuthenticationProvider is cast to UsernamePasswordAuthenticationToken.
    It's cast because DaoAuthenticationProvider is for authentication using a username/password and the retrieveUser signature requires a UsernamePasswordAuthenticationToken. It shouldn't make any difference - casting doesn't affect the type of the object.

    It seems like you are getting confused by the type of the authentication request. Even though the signature of AuthenticationProvider is

    Code:
    Authentication authenticate(Authentication authRequest)
    the returned object which is the result of the authentication process is a new instance and is not connected with the request object (other than indirectly). The request object is discarded.

    It might be more obvious if you just try implementing AuthenticationProvider directly rather than trying to understand the process as it is implemented in DaoAuthenticationProvider. Inheritance tends to confuse the picture.
    Spring - by Pivotal
    twitter @tekul

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •