How to Secure Grails Application with Spring Security Rest in Grails 3
Introduction:
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
Create Grails Application:
1. Create App
In order to create grails application, open your terminal or cmd and type following command to create an 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.groovy
class 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 like
grails.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.
Here, for authorization key use "Bearer access_token". You can see data as shown above. Because in our application.groovy we configure in such a way that all the login users can access data.
[pattern: '/**', access: ['isFullyAuthenticated()']]
In the next tutorial I am going to create different customization for configuration and describe about different annotations.