Using Spring Security 3 with Wicket 6-AuthRoles and JavaConfig and a little Servlet 3

Spring Security is a great framework. It unifies a lot of different authentication mechanisms into a pretty decent package. The only part that wasn’t really up to current Spring-standards was the lack of full java config support. In July they finally released the first fully java config enabled version.

In this blog post I’d like to show how to integrate this new version with Wicket 6-AuthRoles.

The project

I put all the code up on GitHub, clone it and you are ready to go. It shouldn’t be a big surprise that you have to use a Servlet 3 container. I tested the application on Tomcat 7 and Jetty 9, worked without a hitch.

How Spring and Servlet 3 Interact

Servlet 3 provides one of the most fundamental changes. It made web.xml optional. To achieve this the container will scan each war for an implementation of javax.servlet.ServletContainerInitializer to get everything going. Spring provides such a implementation with the SpringServletContainerInitializer. When it is discovered by the container it will then scan the class path for implementations of WebApplicationInitializer. And that’s where we do our stuff.

Servlet 3 Bootstrap

The class AppInitializer contains the whole code required to bootstrap the application. The only really interesting part is how to actually register the Wicket-filter. That cost me some time to figure out but the following snipped does the trick:


        WicketFilter wicketFilter = new WicketFilter(new WicketApplication()) {
            @Override
            public void init(boolean isServlet, FilterConfig filterConfig) throws ServletException {
                setFilterPath("");
                super.init(isServlet, filterConfig);
            }
        };
        FilterRegistration.Dynamic wicketFilterReg = servletContext.addFilter("wicketFilter", wicketFilter);

Auth Roles

Wicket-AuthRoles provide a complete set of annotations to cover all scenarios of authorization. In my demo application I only use @AuthorizeInstantiation.

One important thing to note is that Spring Security prepends ROLE_ to all role names. So instead of writing @AuthorizeInstantiation(Roles.USER) you will have to use @AuthorizeInstantiation(“ROLE_USER”).

Getting AuthRoles to work you need to provide a custom WebSession-implementation:


public class UserAuthenticatedWebSession extends AuthenticatedWebSession {    
    public UserAuthenticatedWebSession(Request request) {
        super(request);
    }

    @Override
    public boolean authenticate(String username, String password) {
        throw new UnsupportedOperationException("You are supposed to use Spring-Security!!");
    }

    @Override
    public Roles getRoles() {
        Roles roles = new Roles();
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        for (GrantedAuthority authority : authentication.getAuthorities()) {
            roles.add(authority.getAuthority());
        }
        return roles;
    }

}

The authenticate method is not required as Spring Security is going to take care of that. The only thing we have to do in here is to provide a getRoles-implementation which uses the SecurityContextHolder

Now we have to change the WebApplication to extend AuthenticatedWebApplication and override init, getWebSessionClass and getSignInPageClass:


@Override
public void init() {
    super.init();
    getComponentInstantiationListeners().add(new SpringComponentInjector(this));
    getSecuritySettings().setAuthorizationStrategy(new AnnotationsRoleAuthorizationStrategy(this));
    mountPage("/home", HomePage.class);
    mountPage("/login", SignInPage.class);
}

We also have to specify the /login-mountpoint this should point to a Wicket-page with the following content:


<form method="POST">
    <input type="text" id="username" name="username"/>
    <input type="password" id="password" name="password"/>
    <input type="submit" value="submit"/>
</form>

The form-submit will NOT be handled by Wicket but by the Spring Security filter!

Spring Security

The final piece of the puzzle is the Spring Security configuration.

In AppInitializer I added the following code to bootstrap the Spring context and the security filter:


    AnnotationConfigWebApplicationContext root = new AnnotationConfigWebApplicationContext();
    root.register(SpringSecurityConfiguration.class);
    FilterRegistration.Dynamic springSecurityFilterChainReg = servletContext.addFilter("springSecurityFilterChain", DelegatingFilterProxy.class);
    springSecurityFilterChainReg.addMappingForUrlPatterns(EnumSet.of(DispatcherType.ERROR, DispatcherType.REQUEST), false, "/*");
    servletContext.addListener(new ContextLoaderListener(root));

The actual configuration happens in SpringSecurityConfiguration:


@Configuration
@EnableWebSecurity
public class SpringSecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeUrls()
                .antMatchers("/favicon.ico")
                    .permitAll()
                .antMatchers("/**")
                    .hasRole("USER")
                    .and()
                    .formLogin()
                        .loginPage("/login")
                        .permitAll();
    }

    @Override
    protected void registerAuthentication(AuthenticationManagerBuilder auth) throws Exception {
        auth
            .inMemoryAuthentication()
                .withUser("testuser")
                    .password("password")
                    .roles("USER");
    }
}

I use configure to tell spring security to allow unrestricted access to favicon.ico. Then I tell it ti restrict access to all other URLs to users with the role USER (reminder: this translates to ROLE_USER when used in AuthRoles-annotations). The last step is to add a custom formLogin to use the mount point from before.

In registerAuthentication I add a simple in-memory-authentication. Here you can now add all the other fancy stuff.

Get it while it’s hot: https://github.com/codepitbull/wicket-servlet3-springsecurity

Have fun.

Advertisements

About codepitbull
A nerd, a geek, a software developer. Oh, and married ;)

2 Responses to Using Spring Security 3 with Wicket 6-AuthRoles and JavaConfig and a little Servlet 3

  1. ozeray says:

    Thank you very much. I appreciate your effort. Best wishes.

  2. codepitbull says:

    You are welcome 😉

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: