Results 1 to 2 of 2

Thread: Axis and SecurityContext strategy

  1. #1
    Join Date
    Jul 2005
    Posts
    14

    Default Axis and SecurityContext strategy

    I am attempting to interface an Axis web service with Acegi. My method of doing so is to add a method to the webservice called authenticate( username, password ), and in that method create a proper SecurityContext (from a user/password token authenticated using my authentication manager) and store that in the SecurityContextHolder. The actual authentication works great, i.e. a proper Authentication object is returned and it has the right GrantedAuthorities, etc. I then hook up an AOP method interceptor, and this seems to be working well too.

    What's hanging me up is that when I use MODE_THREADLOCAL or MODE_INHERITABLETHREADLOCAL, on subsquent calls (after the authenticate() call), I am told there is no valid authentication object in the context. If I use MODE_GLOBAL, then it works. However, I am running an acegi enabled web application in the same JVM, so global isn't really an option for me.

    I am guessing that the two separate webservice calls are being handled by separate threads in Axis, and thus the security context is not available on the second call because it's a different thread.

    Does anyone know of some configuration magic to make this work?

    Barring that, would creating my own strategy, say one that stores the security context on the session (returned by MessageContext.getCurrentContext().getSession()) be a viable solution?

    Any other solutions?

    Thanks much,
    Ron

  2. #2
    Join Date
    Jul 2005
    Posts
    14

    Default (fixed)

    You guys must have known that if you just stayed quiet, eventually, I'd figure it out...

    Again, the basic problem: Tomcat spawns different threads for different web service calls, so thread local storage of the security context doesn't really work across multiple calls during what amounts to the same (from the client standpoint) session.

    In case anyone else ever runs up against this, here is the solution I came up with:

    1) Add the HttpSessionContextIngrationFilter to the web.xml and cover your /services/* url with it.

    2) Before making calls on the web service stub, call setMaintainSession(true) so it will use sessions (if anyone knows how to make this permanently true for a given web service, please let me know).

    That's pretty much it. For those who haven't poured over the source for this filter, it basically looks on the current http session for an acegi security context. If it finds one, it sets it on the SecurityContextHolder, which has the effect of setting it on thread local storage for the current request. Exactly what we need here. If it doesn't find one, it creates a new one and sets it on the session.

    So in my authenticate() method, I do the normal authentication and set that on the current security context, then I stick the context on the current session using the ACEGI_SECURITY_CONTEXT_KEY where the filter sees it.

    The login method looks like this:

    Code:
        public void login( final String username, final String password ) throws AxisFault
        {
            // Create an authentication token from the credentials, and attempt to authenticate
            //
            final UsernamePasswordAuthenticationToken token = 
                    new UsernamePasswordAuthenticationToken( username, password );
            final Authentication auth = m_authenticationManager.authenticate( token );
    
            // If we make it here, no authentication errors occurred, so we set the
            // authentication object on the security context, and then set that context
            // as the current one for this thread. Note that we don't set the context on
            // the holder, because below we stick it on the session, and the filter
            // mentioned below will take care of sticking it in the holder on a per
            // request basis.
            //
            final SecurityContext ctx = SecurityContextHolder.getContext();
            ctx.setAuthentication( auth );
            
            // Finally, we need to set this context on our http session, as 
            // the HttpSessionContextIntegrationFilter will be looking for it there,
            // so it can maintain it on whatever thread is handling a request for 
            // this session
            //
            final AxisHttpSession session = ( AxisHttpSession ) 
                    MessageContext.getCurrentContext().getSession();
            final HttpSession httpSession = session.getRep();
            httpSession.setAttribute( HttpSessionContextIntegrationFilter.ACEGI_SECURITY_CONTEXT_KEY, 
                    SecurityContextHolder.getContext() );
    
        }
    Once you have this working, just stick your web service code in a delegate bean, and cover that bean with a MethodSecurityInterceptor, and delegate all calls in your Axis service class to the delegate, and you're in business.

    Hope this helps someone...

    Cheers,
    rjf&

Posting Permissions

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