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 is split into two components –
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.
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
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.
Ive moved the Spring Data REST API URL to /rest in application.properties –
spring.data.rest.basePath=/rest
SecurityConfig has –
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(); } }
mvnw spring-boot:run
Ive switched to curl for calling the API’s as its clearer for tutorials –
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"}
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" } } }
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"}
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" } } }
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.