Securing Vaadin applications isn’t as straightforward as it looks. There are a few options already available: The AppFoundation add-on provides an authentication module, but it uses statics to access its functions, which I don’t like and it uses EclipseLink, a technology I have no experience with (and I don’t think it works with the Google AppEngine). A second option is to use the Vaadin Spring integration example that shows how to integrate Spring Security. Yet that one only has very course authentication (you’re either have access to everything or nothing).
So I rolled my own solution.
What I’d like to have in a security solution:
- Build as much as possible on top of existing technology (I choose Spring Security)
- Let a user access the application, even if he’s not logged in.
- Provide a popup login window inside the application (no ugly redirects)
- Only show items that are available for the user’s authorization level.
- If possible configure this in one central location.
This blog post only goes into how to set up Spring Security and log in a user inside the application (numbers 1 to 3 above). I’ll do a follow up post in the future with details on point 4 and 5 (but I’m still struggling with a few bugs between Google AppEngine and Spring Security, see point 4).
Here’s what you need to do to get started. Some Spring Security knowledge will be necessary to implement this.
1. Set up anonymous access to the application servlet
Although this might seem a bit superfluous, the reason I’m doing this is to make sure I’m enjoying all the benefit of the default filter chain that Spring Security offers for HTTP integration. Most importantly, the HttpSessionContextIntegrationFilter will manage the SecurityContext for me. This means I don’t have to worry about clearing it at the end of the request and (possibly) storing it for “remember me”-like functionality.
Also, using the “standard” way of doing HTTP integration will make sure I can keep up with new Spring Security releases. For instance, I first wanted to roll my own security context invalidation filter, but I noticed the HttpSessionContextIntegrationFilter has been deprecated in favor of the SecurityContextPersistenceFilter. So I ended up going through the slightly more complicated way of setting up anonymous access.
Anonymous access is as easy as setting up an auth-config HTTP security with an intercept URL “/**” set to access “IS_AUTHENTICATED_ANONYMOUSLY”. See the Spring Security documentation for all the dirty details.
2. Authentication in code
It’s fairly easy to do the authentication by yourself. I created a nice Vaadin form for username and password input and used this post to authenticate the user. I used the Spring annotation based injection to get to my authentication provider. I’ve detailed this method in a previous post.
This worked like a charm, until I combined it with the anonymous access mentioned above.
3. Don’t use an authentication provider directly, use the manager
Adding anonymous access will cause 2 security providers to be available: one you have defined which connects to whatever you want, and an anonymous one. This meant the dependency injection stopped working, because there were now 2 available implementations and, obviously, the program couldn’t decide which one to use.
I was glad to encounter this problem, because it actually showed a fault in my logic: in every Spring Security application, there is one authentication manager which will manage the different providers for you, so you really should authenticate via the manager.
Implementing this change was as easy as replacing one variable. The dependency injection did the rest (the authentication manager takes the same arguments as the authentication provider)
4. Spring Security & AppEngine
This is not related to Vaadin at all, but you might also be reading my Vaadin posts because I want to deploy everything to Google AppEngine. If you are using AppEngine and Spring Security, don’t use the latest 3.0.2 release, there is a show stopping issue. For now, version 3.0.1 works almost perfectly (you can’t use @Secured for now).
Example code will be forthcoming once I get all those kinks sorted out. In the meantime, feel free to share any additional tips you might have.