Adding Security to Spring Guide’s Rest Service

Recently we looked at creating containerless web applications with Spring Boot. Let’s take a spring boot application and do some experimentation to see how easy it is to build a real web application from the starter projects. Is it easy or are the starter guides exaggerating their own ease of use?

Well, For Starters…

Starter projects are nice, but they are typically trivial. This is for good reason: project authors don’t want to confuse users with details not relevant to the specific technology being taught. But it is difficult to see how a large scale application would actually pull all the pieces together, or even if the pieces will fit together at all.

We are going to take a spring boot guide and see how easy it is to pull two of the guides together by adding security to a web service project. The complete code is available on github (my version requires Java 8).

The Starter Project

The rest service guide is one of the most popular guides available from spring.io. This project is very easy to run, you can just download the project, run “gradle runJar”, and the service immediately runs. The service responds to requests (say, curl localhost:8080/greeting) with {“id”:1,”content”:”Hello, World!”}

The Security Project

Next is the security project. The most obvious place to look is the securing web project, which does in fact do a nice job of securing a web site. But does this work if we want to secure a rest service? Do the security concepts carry over??

The answer is: sort of. If you try to add security from the security web project to the web service project by adding the security dependency and copying WebSecurityConfig.java to the rest project, you will find that it is more oriented around securing web pages, and does not immediately work for securing rest endpoints. The WebSecurityConfig requires some additional changes for it to work with basic auth (as you might want for a rest service). You have to modify the configuration code to use basic auth like so:

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
            // this replaces the web security http configuration
            http.authorizeRequests()
                 .antMatchers("/**")
                 .authenticated()
                 .and().httpBasic();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder authManagerBuilder) throws Exception {
        authManagerBuilder.inMemoryAuthentication()
                .withUser("user").password("password").roles("USER");
    }
}

REST, Actually

A more appropriate approach, in my opinion, is to apply spring actuator to the rest project.

Start by adding the security dependency and actuator dependency (here, to the gradle build file)

compile("org.springframework.boot:spring-boot-actuator:0.5.0.M6")
compile("org.springframework.boot:spring-boot-starter-security:0.5.0.M6")

Then add a Configuration class to provide an AuthorizationManager bean, per security directions in the actuator project. As of this writing, the actuator directions are a little out of date, so and the latest code does not line up with the latest directions. The code here works, however.

@Configuration
public class WebSecurityConfig {
    
    @Bean
    public AuthenticationManager authenticationManager() throws Exception {
        return new AuthenticationManagerBuilder(new NopPostProcessor())
                       .inMemoryAuthentication().withUser("user").password("password").roles("USER")
                       .and().and().build();
    }
    
    private static class NopPostProcessor implements ObjectPostProcessor {
        @Override
        @SuppressWarnings("unchecked")
        public Object postProcess(Object object) {
            return object;
        }
    };
}

With these simple changes to the popular rest project, the endpoints are now all protected by http basic auth. And of course basic auth should be done over HTTPS, but adding HTTPS is a topic for another day. We can test the endpoints like so:

curl localhost:8080/greeting

and get the response

{"timestamp":1385921426457,"error":"Unauthorized","status":401,"message":"An Authentication object was not found in the SecurityContext"}

Then try with basic auth:

curl user:password@localhost:8080/greeting

And get the response:

{"id":2,"content":"Hello, World!"}

Our endpoint is protected!

Conclusion

The authors of spring boot made every effort to make the guides easy to understand and use, and I think overall they succeeded. However, these are new (incubator) projects, and there are still some kinks being worked out, such as documentation not lining up with the code. And we must keep in mind that usually specific technologies cannot be applied directly from one project to another, because applying a concept from one context to another requires understanding how the technology actually works in the new context. That’s why the guides are so focused and small – to reduce the context needed to explain how it works.

I still think these are great projects to bring Spring technologies into even wider use, and am looking forward to spring boot and the guides becoming the go-to place for new projects.

Advertisements

1 Comment

Filed under Software Engineering

One response to “Adding Security to Spring Guide’s Rest Service

  1. Thank you!!! Worked for me. I was trying to do that.

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