How to Secure Grails Application with Spring Security Rest in Grails 3
Table of Contents
In this tutorial, we are going to secure our grails application with spring security simply refer to spring security rest login. Here we are using grails version 3.3.0 and Java 8. This tutorial describes the configuration of Spring Security Core, Spring Security Rest with Grails 3 to secure the application.
Pre-requisites:
- Running Java
- Running Grails
1. Create App
grails create-app spring-security-rest --profile rest-api
// Application created at (path of app)
Open your favorite text editor or IDE and open the project that we recently created.Go to a created project folder.
cd spring-security-rest
Run grails interactive mode.grails
In order to run and stop an application simply type "run-app" and "stop-app"2. Create Domain Class
Let's create a dummy class to test security called "Product". You can use either terminal or your IDE.
create-domain-class Product
Add some properties in the domain class.class Product {
String name
Double price
String companyName
String description
Date dateCreated = new Date()
static constraints = {
}
}
Add some data using BootStrap.groovyclass BootStrap {
def init = { servletContext ->
if (Product.count() == 0){
new Product(name: "product1", price: 10, companyName: "company1", description:"description1").save(flush:true)
new Product(name: "product2", price: 100, companyName: "company2", description:"description2").save(flush:true)
new Product(name: "product3", price: 1000, companyName: "company3", description:"description3").save(flush:true)
new Product(name: "product4", price: 10000, companyName: "company4", description:"description4").save(flush:true)
}
}
def destroy = {
}
}
Create Controller for product domain.create-restful-controller Product
It will create controller like this:class ProductController extends RestfulController {
static responseFormats = ['json', 'xml']
ProductController() {
super(Product)
}
}
Run application. And simply make get request, as following endpoint will results "product" data in Json format that we created in BootStrap.groovy.http://localhost:8080/product
Spring Security Core Plugin Configuration:
Under build.gradle file within dependencies add the following configuration and run command "compile"
dependencies {
compile 'org.grails.plugins:spring-security-core:3.2.0'
}
Now its time to create user related tables, for this exit from the interactive console.exit
grails s2-quickstart spring.security.rest User Role
You can see:CONFIGURE SUCCESSFUL
Total time: 2.965 secs
| Creating User class 'User' and Role class 'Role' in package 'spring.security.rest'
| Rendered template PersonWithoutInjection.groovy.template to destination grails-app/domain/spring/security/rest/User.groovy
| Rendered template PersonPasswordEncoderListener.groovy.template to destination src/main/groovy/spring/security/rest/UserPasswordEncoderListener.groovy
| Rendered template Authority.groovy.template to destination grails-app/domain/spring/security/rest/Role.groovy
| Rendered template PersonAuthority.groovy.template to destination grails-app/domain/spring/security/rest/UserRole.groovy
|
************************************************************
* Created security-related domain classes. Your *
* grails-app/conf/application.groovy has been updated with *
* the class names of the configured domain classes; *
* please verify that the values are correct. *
************************************************************
Which will create User.groovy, Role.groovy, and UserRole.groovy Domain classes.Now let's create a user data for testing purpose using BootStrap.groovy.
def role1 = new Role(authority:"ROLE_USER").save flush:true
def user1 = new User(username:"user@gmail.com",password:"pwd@123").save flush:true
UserRole.create(user1,role1)
Spring Security Rest Plugin Configuration:Under build.gradle file within dependencies add the following configuration and run command "compile"
dependencies {
compile "org.grails.plugins:spring-security-rest:2.0.0.M2"
}
Go to application.groovy and add chainMap configuration:grails.plugin.springsecurity.filterChain. chainMap = [
[pattern: '/**',filters: 'JOINED_FILTERS,-anonymousAuthenticationFilter,-exceptionTranslationFilter,-authenticationProcessingFilter,-securityContextPersistenceFilter'],
[pattern: '/**', filters: 'JOINED_FILTERS,-restTokenValidationFilter,-restExceptionTranslationFilter']
]
Note: If your endpoint start with https://address.com/api or /othername then your chainMap look likegrails.plugin.springsecurity.filterChain. chainMap = [
[pattern: '/api**',filters: 'JOINED_FILTERS,-anonymousAuthenticationFilter,-exceptionTranslationFilter,-authenticationProcessingFilter,-securityContextPersistenceFilter'],
[pattern: '/**', filters: 'JOINED_FILTERS,-restTokenValidationFilter,-restExceptionTranslationFilter']
]
The final configuration looks like
// Added by the Spring Security Core plugin:
grails.plugin.springsecurity.userLookup.userDomainClassName = 'spring.security.rest.User'
grails.plugin.springsecurity.userLookup.authorityJoinClassName = 'spring.security.rest.UserRole'
grails.plugin.springsecurity.authority.className = 'spring.security.rest.Role'
grails.plugin.springsecurity.controllerAnnotations.staticRules = [
[pattern: '/', access: ['permitAll']],
[pattern: '/error', access: ['permitAll']],
[pattern: '/index', access: ['permitAll']],
[pattern: '/index.gsp', access: ['permitAll']],
[pattern: '/shutdown', access: ['permitAll']],
[pattern: '/assets/**', access: ['permitAll']],
[pattern: '/**/js/**', access: ['permitAll']],
[pattern: '/**/css/**', access: ['permitAll']],
[pattern: '/**/images/**', access: ['permitAll']],
[pattern: '/**/favicon.ico', access: ['permitAll']],
[pattern: '/**', access: ['isFullyAuthenticated()']]
]
grails.plugin.springsecurity.filterChain. chainMap = [
[pattern: '/**',filters: 'JOINED_FILTERS,-anonymousAuthenticationFilter,-exceptionTranslationFilter,-authenticationProcessingFilter,-securityContextPersistenceFilter'],
[pattern: '/**', filters: 'JOINED_FILTERS,-restTokenValidationFilter,-restExceptionTranslationFilter']
]
Testing Secured REST API:Now re-run the application and request the endpoint "http://localhost:8080/product"
which is our application is secured. I will make a tutorial for customizing this message format.
Next test the login endpoint with our existing user created in BootStrap.groovy. Here I am using Post-man.
Now access data via authorization.
[pattern: '/**', access: ['isFullyAuthenticated()']]
In the next tutorial I am going to create different customization for configuration and describe about different annotations.
OMG! THis is a pain in the ass. There must be an easier way to do this. Didn't anyone build a plugin to auto-configure Spring security with the api's?? Oh wait, they did... https://github.com/orubel/Beapi-API-Framework
ReplyDelete