This site uses cookies. Continue to use the site as normal if you are happy with this, or read more about cookies and how to manage them.

×

This site uses cookies. Continue to use the site as normal if you are happy with this, or read more about cookies and how to manage them.

×

Saddling Blaze (Adventures with BlazeDS - Part 2: Spring Security)

As you may gather from other entries in this blog, we've been working on a customer project which uses Flex for the client and Java for the server, with SOAP over HTTP in between. It worked well for us as a combination, because it minimised the number of new things to be learned - helpful when you're dealing with, er, aggressive delivery timescale aspirations. I've been having a few doubts about its long-term viability, though. SOAP's pretty verbose, and I'm not sure how quick the marshalling to/from XML is in ActionScript. Anyway, I was lucky enough to have a bit of spare time to investigate BlazeDS as an alternative, and thought I'd share some of the experience.

I downloaded BlazeDS and the sample applications to use as a guide in converting my existing web application. I'm not going to go into all the details here since that's not really the focus of this article - the Adobe BlazeDS Developer's Guide is well worth reading. Our server side code is a Spring application, so some extra work was required to make Blaze and Spring work together. Fortunately, Christophe Conraets has written an excellent article on the subject, along with some very handy sample code, which I have made use of.

Our server-side code is a Spring application, but there are a few minor peculiarities in the way it uses Spring 2 Security. The server is completely stateless, so the Flex client has to authenticate each request. For the SOAP version, we pass an authentication token in a custom HTTP header (Flex prevents you from accessing certain HTTP headers, the Authorization header included). In the BlazeDS version, I had to find another way of authenticating, since I couldn't see a way of getting access to the HTTP request that it uses to send the request to the server, so no way of adding my custom header.

I came across Cliff Meyers' very useful blog on the subject. Blaze allows you to specify a custom login command, and provides a number of examples which integrate with different app servers' security models. All these implement the LoginCommand interface. You tell Blaze that you want to use a custom login command by specifying it in the services-config.xml file:

Custom

You do need to specify a value for the server attribute of the login-command tag, or BlazeDS won't call your LoginCommand at all. There are examples in the developer's guide for specific servers.

As Cliff did, I wrote my own custom implementation of LoginCommand which looks up the pluggable authentication provider from the Spring application context (which we had already gone to the trouble of writing for our previous version of the application) and uses it to validate the incoming user credentials. If the credentials are valid, the resulting Authentication object is placed in the application's SecurityContext in exactly the same way as it was before.

public class BlazeSpringLoginCommand implements LoginCommand {

    public Principal doAuthentication(String username, Object credentials) {
        UsernamePasswordAuthenticationToken authentication =
            new UsernamePasswordAuthenticationToken(username, credentials);

        AuthenticationProvider provider = (AuthenticationProvider) getBean("authenticationProvider");

        authentication = (UsernamePasswordAuthenticationToken) provider.authenticate(authentication);

        SecurityContextImpl securityContextImpl = new SecurityContextImpl();
        securityContextImpl.setAuthentication(authentication);
        SecurityContextHolder.setContext(securityContextImpl);

        return authentication;
    }

    private Object getBean(String beanName) {
        ApplicationContext appContext = 
            WebApplicationContextUtils.getWebApplicationContext(flex.messaging.FlexContext.getServletConfig().getServletContext());

        try
        {
            return appContext.getBean(beanName);
        }
        catch (NoSuchBeanDefinitionException nexc)
        {
            ServiceException e = new ServiceException();
            String msg = "Spring service named '" + beanName + "' does not exist.";
            e.setMessage(msg);
            e.setRootCause(nexc);
            e.setDetails(msg);
            e.setCode("Server.Authentication");
            throw e;
        }
        catch (BeansException bexc)
        {
            ServiceException e = new ServiceException();
            String msg = "Unable to create Spring service named '" + beanName + "' ";
            e.setMessage(msg);
            e.setRootCause(bexc);
            e.setDetails(msg);
            e.setCode("Server.Authentication");
            throw e;
        }
    }
    [... there are a few other trivial methods you need to implement ...]
}

It all worked. Sort of. I discovered that I needed to have per-client authentication turned on to avoid two applications that might be sharing a session (as they might in two tabs of the same browser) from also sharing their authentication information, so I included that within services-config.xml too:

true

That was all OK, but I kept getting exceptions telling me that I couldn't do something with the session after the response had been committed, and the session had been invalidated.

[BlazeDS] FlexSession with id '19423D12B4CB9513CE49304B26FCB504' for an Http-based client connection has been invalidated.
[BlazeDS] Cannot create a session after the response has been committed
java.lang.IllegalStateException: Cannot create a session after the response has been committed
[.....]

Authentication would work most of the time but not all. It was pretty weird. On googling the exception there were a few articles that talked about Session Fixation, and then this one. Aha...

As the Spring configuration docs say, "Session fixation attacks are a potential risk where it is possible for a malicious attacker to create a session by accessing a site, then persuade another user to log in with the same session (by sending them a link containing the session identifier as a parameter, for example)." Spring protects against this by automatically creating a new session when a user logs in. From the Spring bug report, it looks like there are two options: upgrade Spring or turn session fixation protection off. To turn it off, add this attribute to your Spring config:

[...]

and bingo! no more exceptions. As it happens, I realised I needed to upgrade Spring to solve a completely unrelated problem. I upgraded to Spring 2.5, and the problem disappeared, even when I removed the session-fixation-protection attribute from my Spring config again..

In fact, after going through all this, I realised that if I was going to pursue using BlazeDS then it would involve redesigning my application. As I said before, the server is stateless, and requires the client to authenticate on every request, which just doesn't fit with the BlazeDS model of the world. BlazeDS is stateful: it uses the session, and knows if you've already authenticated, so doesn't bother calling the LoginCommand every time. The shift from a stateless to a stateful application isn't one to be taken lightly. So, while Blaze may give me advantages, they come at a cost that has to be considered in relation to the project as a whole.