Photo by Lesly B. Juarez on Unsplash

Spring Security and Spring Data REST

Spring Security and Spring Data REST are discussed in this post. It builds on the previous post “Introduction to Spring Data REST” and my series of posts on Spring Security –

Spring Security and Spring Data REST

Spring Security is split into two components –

  • Authentication – Defined by AuthenticationManager, or the source of the authentication credentials
  • Authorisation – what we want to protect – URL’s, Roles, method

This tutorial is only considering BasicAuthentication with an memory realm. I will probably return to this subject to show how to properly harden a RESTful API.

Source Code

Code available on github –

https://github.com/farrelmr/introtospringdatarest/tree/2.0.0

https://github.com/farrelmr/introtospringdatarest/releases/tag/2.0.0

Run the code by typing –

mvnw spring-boot:run

Maven

You can secure spring boot by simply including this dependency –

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>

You can then get the password when you startup spring boot, but that is not very practical for most usages.

SecurityConfig

Ive moved the Spring Data REST API URL to /rest in application.properties –

spring.data.rest.basePath=/rest

SecurityConfig has –

  • Two users – user(Role – USER), admin(Role – admin)
  • Restrictions –
    • Only “ADMIN” or “USER” roles can access “/rest”,
    • Only “ADMIN” users can POST to the web service –
package com.javabullets.springdata.jparest;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.http.HttpMethod;

@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth)
            throws Exception {
        auth.
            inMemoryAuthentication()
                .withUser("user").password("user").roles("USER").and()
                .withUser("admin").password("admin").roles("USER","ADMIN");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
          .authorizeRequests()
            .antMatchers(HttpMethod.POST, "/rest/parkrunCourses/**").hasRole("ADMIN")
            .antMatchers("/rest/**").hasAnyRole("ADMIN","USER").and()
          .httpBasic()
            .and()
           .csrf().disable();
    }
}

Putting It Together

mvnw spring-boot:run

Ive switched to curl for calling the API’s as its clearer for tutorials –

No credentials – Doesnt Authenticate

curl  -X GET -H "Content-Type:application/json" http://localhost:8080/rest/parkrunCourses/1
{"timestamp":1496069649024,"status":401,"error":"Unauthorized","message":"Full authentication is required to access this resource","path":"/rest/parkrunCourses/1"}

user/user credentials – Authenticates

curl -u user:user -X GET -H "Content-Type:application/json" http://localhost:8080/rest/parkrunCourses/1
{
  "courseName" : "Inverness",
  "url" : "http://www.parkrun.org.uk/inverness/",
  "averageTime" : 1582,
  "_links" : {
    "self" : {
      "href" : "http://localhost:8080/rest/parkrunCourses/1"
    },
    "parkrunCourse" : {
      "href" : "http://localhost:8080/rest/parkrunCourses/1"
    }
  }
}

POST methods – Access Forbidden

curl -u user:user -X POST -H "Content-Type:application/json" -d "{  \"courseName\" : \"adminOnly\",  \"url\" : \"url\",  \"averageTime\" : \"10000\" }" http://localhost:8080/rest/parkrunCourses
{"timestamp":1496069812087,"status":403,"error":"Forbidden","message":"Access is denied","path":"/rest/parkrunCourses"}

POST methods – Access Allowed

curl -u admin:admin -X POST -H "Content-Type:application/json" -d "{  \"courseName\" : \"adminOnly\",  \"url\" : \"url\",  \"averageTime\" : \"10000\" }" http://localhost:8080/rest/parkrunCourses
{
  "courseName" : "adminOnly",
  "url" : "url",
  "averageTime" : 10000,
  "_links" : {
    "self" : {
      "href" : "http://localhost:8080/rest/parkrunCourses/13"
    },
    "parkrunCourse" : {
      "href" : "http://localhost:8080/rest/parkrunCourses/13"
    }
  }
}

Conclusions

This post shows how Spring Security and Spring Data REST can be combined to secure REST API URL’s and HTTP methods. It used a basic form of Spring authentication, combining a MemoryRealm with the security configuration. We have also demonstrated how to restrict access to REST methods based on user group.

About the Author Martin Farrell