Beware Your Spring Security Principal's Authorities Format

This can beat you up pretty badly when putting a Spring Security configuration in place. Everything is going great until you test your Intercept-Url filterings with user roles and see Not Authorized pages flying all over the place. The problem may lie in the format of your Principal's Granted Authorities, particularly if you're using a custom User object to extend the Spring Security UserDetails.User object.

In our example we're retrieving user data from an H2Database. We have our User, Authorities and User_Authorities tables populated accordingly, with a user (ROLE_USER) and admin account (ROLE_USER, ROLE_ADMIN). We have a Contacts page viewable to all, but to see the Contact Details page you have to be authorized. And to use the H2 Console I blogged about before, you have to be ROLE_ADMIN.

Here are our Security Expressions. Pages not in the PERMITALL_ list like the Contact Details page will throw up a login page. A User account will see the Contact Details page but will be redirected to a Not Authorized/403 page if attempting to view the H2 Console at /console.

.antMatchers(PERMITALL_RESOURCE_LIST).permitAll()
.antMatchers("/console/**").hasAuthority("ROLE_ADMIN")
.anyRequest().authenticated()

Now to the Granted Authorities List Format. After being beaten-up a while by Not Authorized pages I changed by Spring AuthenticationManager from H2Database to InMemoryAuthentication.

Everything worked perfectly with InMemory Authentication. Let's look at the DEBUG Principal info. See those beautiful Granted Authorities for admin? Nice and clean, ready to rock.

Now let's look at the same output for our CurrentUser Principal which gave us fits earlier. What's with those brackets???

Let's look at the defective CurrentUser Principal another way, in the IntelliJ Debugger.

Holy crap! So our CurrentUser Granted Authorities consist of a single role named [ROLE_USER, ROLE_ADMIN]? Well hell, no wonder we were seeing Not Authorized pages!

How did this happen? It happened in the CurrentUser Constructor. We already have a collection of Roles from our Application's User Model which we convert to a List<>. Really dumb, and really obvious when looking back at it.

public CurrentUser(User user) {
super(user.getUsername(), user.getPassword(),
AuthorityUtils.createAuthorityList(user.getAuthorities().toString()));
this.user = user;
}

Using a simple user.getAuthorities() and an Authority.toString() output of public String toString() { return authority; } returned order and happiness to my Spring Security World.

Posted August 07, 2015 10:54 AM EDT

More Like This Post