alexgorbatchev

Friday, March 6, 2015

Grails 3 App with Security (Part 1)

The great Spring Security Plugin is now available for Grails 3!

I will leave these blog posts up as a reference, but I would strongly suggest (as if you needed the suggestion) to use the Spring-Security plugin for Grails 3

Since Spring Security Core Plugin is not was not working for Grails 3, and I could not find any other resources for the spring-boot-starter-security related to Grails 3 I decided to share what I did to get up and going. I created a github project at https://github.com/dspies/grails-3-with-security and tagged each step if you want to follow along.
Uses:
  • Grails Version: 3.0.0.M2
  • Groovy Version: 2.4.1
  • JVM Version: 1.7.0_51

Setting up Security:

Simply add the following to build.gradle in the dependencies:
compile "org.springframework.boot:spring-boot-starter-security"
This will cause ALL HTTP endpoints to require authorization and a random password to be generated each time you start up your app. Also, because Spring-Boot-Security-Starter logs the randomly generated password at level INFO, you need to add the following to your logback.groovy file.
 //see http://logback.qos.ch/manual/groovy.html for more info
 logger('org.springframework.boot.autoconfigure.security', INFO)
This is not sufficient for anything but a demo, so let's customize it a bit. Let's start with the easiest part, creating a fixed password. There are a few methods of setting a static password, but we'll concentrate on two 1) in the application.yml or 2) in a WebSecurityConfigurerAdapter Class.

In the Application.yml file

    security:
        user:
            password: password

In a WebSecurityConfigurerAdapter Class

Using a WebSecurityConfigurerAdapter class, we can override the default implementation(s) used in spring-boot-starter-security.

grails-app/init/simpleappwithsecurity/SecurityConfiguration.groovy
package simpleappwithsecurity

import org.springframework.beans.factory.annotation.Autowired
import org.springframework.context.annotation.Configuration
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@Configuration
@EnableWebSecurity
class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth
                .inMemoryAuthentication()
                .withUser("user").password("pwd").roles("USER");
    }
}
One important note, Grails does NOT know anything about the SecurityConfiguration class unless you do something to tell your Grails' app about the new class. The two easiest methods are to specify a bean in resources.groovy
grails-app/conf/spring/resources.groovy
import simpleappwithsecurity.SecurityConfiguration

beans = {
    webSecurityConfiguration(SecurityConfiguration)
}
If you use this, you do not need the class annotations @Configuration and @EnableWebSecurity on the SecurityConfiguration class. Another method is to enable Spring's Component Scan on the Grails application in the Application.groovy file by adding @ComponentScan to the Application class, such as
grails-app/init/Application.groovy

...
import org.springframework.context.annotation.ComponentScan;

@ComponentScan
class Application extends GrailsAutoConfiguration {
...
I think this depends on how you view your application. If it is a Grails Application, using primarily Grails Plugins with Spring sprinkled in, then use the first method. If it is a Spring Boot application with Grails sprinkled in, use the latter method. For now, our app is a Grails app, so we'll use the bean definition in resources.groovy.

Securing specific URIs (or request maps)

Let's extend our example by adding pattern matches to our SecurityConfiguration class.
grails-app/init/simpleappwithsecurity/SecurityConfiguration.groovy
...
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
                .antMatchers('/admin/**').hasAnyRole('ADMIN')
                .antMatchers('/home/**').hasAnyRole('USER', 'ADMIN')
                .antMatchers('/').permitAll()
            .and()
                .formLogin().permitAll()
            .and()
                .logout().permitAll()
    }

    //<-- --="" .inmemoryauthentication="" .withuser="" auth="" code="" configureglobal="" end="" exception="" in="" of="" password="" previous="" public="" roles="" snippet="" throws="" user="" uthenticationmanagerbuilder="" utowired="" void="">
                .and()
                .withUser('admin').password('admin').roles('ADMIN');
    }

...
Restarting the application now will allow you to see the index page, but require authentication when attempting to access /home or /admin controllers.

Resources:

10 comments:

  1. Thanks. Clean an simple. Just what i was looking for. Next step is security with OAuth2 ;)

    ReplyDelete
    Replies
    1. I'll see what I can do ;), but Spring has a blog post https://spring.io/blog/2015/02/03/sso-with-oauth2-angular-js-and-spring-security-part-v

      Delete
  2. Thanks for the article. Could you please hint how to display username in the gsp after successful login? Which tag should I use?

    ReplyDelete
    Replies
    1. Unfortunately, I have been working in Angular on the front end so I am not sure what tag library to use, however, I am guessing that the traditional Spring Security JSP tag libs would still work. I would have a look at http://docs.spring.io/spring-security/site/docs/4.0.1.RELEASE/reference/htmlsingle/#the-authentication-tag.

      Delete
  3. Hi David
    We will be waiting for second part of the post! Hope you will be covering JDBC configuration with it.

    ReplyDelete
  4. A taglib can do that... in the GSP, put:
    <g:username />

    Then create a file in the taglib folder such as:

    UserTagLib.groovy
    class CommonTagLib {
       def username = {
          def user = session.SPRING_SECURITY_CONTEXT?.getAuthentication()?.getPrincipal()
       out << user?.getUsername()
       }
    }

    ReplyDelete
    Replies
    1. Oops, this was meant to be posted as a reply to the April 21 question above. Anyway, a better formatted version of the code at is at: stackoverflow.com/a/30448442

      Delete
  5. Hi! Great post. Do you know if it's possible to change the default login form, and how to do it ?

    ReplyDelete
  6. Good stuff, but way too much work :) The spring-security-core plugin has been updated to work with Grails 3 - see the docs at https://grails-plugins.github.io/grails-spring-security-core/

    ReplyDelete
  7. How could i change the spring login view??

    ReplyDelete