Spring Storage Loading Users into a Database with Grails 3.0

How do you store users in a database with a new simple Vanilla Grails 3.0 application?

Background:

  • Shiro and Spring security plugins are not yet available for Grails 3.0 (and it looks like Spring Boot is the future for Grails security).
  • There are various examples to show how to use it inMemoryAuthentication()

    , but they seem completely pointless because ultimately passwords are stored in plain text (and it only takes 30 seconds to create a domain model in Grails).
  • Almost all Grails applications require this feature.
  • I am using MongoDB, but it probably doesn't matter.
  • Related: Graphics 3 and Spring Security Plugin

I inMemoryAuthentication()

currently have the following working:

build.gradle

compile "org.springframework.boot:spring-boot-starter-security"

      


Grails app / conf / spring / resources.groovy

import com.tincanworks.AppSecurityConfig
beans = {
   webSecurityConfiguration(AppSecurityConfig)
   }

      


AppSecurityConfig.groovy

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.WebSecurityConfigurerAdapter

class AppSecurityConfig extends WebSecurityConfigurerAdapter {

   @Override
   protected void configure(HttpSecurity http) throws Exception {
      http
         .authorizeRequests()
            .antMatchers("/").permitAll()
            .antMatchers("/assets/**").permitAll()
            .antMatchers("/admin/**").hasAnyRole("admin")
            .anyRequest().authenticated()
         .and()
            .formLogin().permitAll()
         .and()
            .logout().permitAll()
      }

   @Autowired
   public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
      auth
         .inMemoryAuthentication()
            .withUser("user").password("123456").roles("user")
            .and()
            .withUser("admin").password("1qaz2wsx").roles("user", "admin")
      }

}

      

The answer seems to be related to JdbcDaoImpl , but I have no idea how to hook this up in Grails.

+3


source to share


2 answers


Gorm based

I wrote two blog posts ( Part 1 - In Memory Auth and Part 2 - Gorm Based Authentication on how to use spring-starter-security and GORM in a Grails 3 application. I also created a github repo with a working Grails 3 application using spring-starter-security.

JDBC-unverified

Alternatively, if you want to use standard JDBC based authentication, you can simply create the database tables using the following SQL script

HSQLDB

From http://docs.spring.io/spring-security/site/docs/3.0.x/reference/appendix-schema.html



create table users(
      username varchar_ignorecase(50) not null primary key,
      password varchar_ignorecase(50) not null,
      enabled boolean not null);

  create table authorities (
      username varchar_ignorecase(50) not null,
      authority varchar_ignorecase(50) not null,
      constraint fk_authorities_users foreign key(username) references users(username));
      create unique index ix_auth_username on authorities (username,authority);

      

MySQL

This comes from http://justinrodenbostel.com/2014/05/30/part-5-integrating-spring-security-with-spring-boot-web/

create table users (
    username varchar(50) not null primary key,
    password varchar(255) not null,
    enabled boolean not null) engine = InnoDb;

create table authorities (
    username varchar(50) not null,
    authority varchar(50) not null,
    foreign key (username) references users (username),
    unique index authorities_idx_1 (username, authority)) engine = InnoDb;

      

and then change the method configureGlobal

to

@Autowired  //not sure if this is needed as you have the AppSecurityConfig bean referenced in resources.groovy
def datasource  //bean injected by Grails

@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
  auth
     .jdbcAuthentication()
     .dataSource(datasource)
}

      

+2


source


If you want to avoid creating an entire user management layer from scratch with a DB, you might want to consider Stormpath .

Among other things, they provide a Spring security plugin that uses Stormpath as its authentication and authorization provider. They also have a sample Spring Security Application that shows how the plugin is used. Since you are using Java Annotations (not xml config) take a look at this thread .

So, in a nutshell, the key snippets you need to identify are as follows:



  • Stormpath Bean client that provides fast and secure communication with Stormpath using the Stormpath Java SDK :

    //Let create the Stormpath client using the apiKey.properties file from the User home folder.
    @Bean
    ClientFactory stormpathClient(CacheManager cacheManager) {
        ClientFactory clientFactory = new ClientFactory();
        clientFactory.setApiKeyFileLocation(System.getProperty("user.home") + File.separator + ".stormpath" + File.separator + "apiKey.properties");
        clientFactory.setCacheManager(cacheManager);
        return clientFactory;
    }
    
          

  • You will need to define a Stormpath authentication provider so that Spring Security can transparently interact with the Stormpath to authenticate and authorize users:

    @Bean
    @Autowired
    public StormpathAuthenticationProvider stormpathAuthenticationProvider(Client client, String applicationRestUrl) throws Exception {
        StormpathAuthenticationProvider stormpathAuthenticationProvider = new StormpathAuthenticationProvider();
        stormpathAuthenticationProvider.setClient(client);
        stormpathAuthenticationProvider.setApplicationRestUrl(applicationRestUrl);
        return stormpathAuthenticationProvider;
    }
    
          

  • applicationRestUrl

    should point to the Stormpath application where all users / groups will exist:

    @Bean
    public String getApplicationRestUrl() {
        return "https://api.stormpath.com/v1/applications/9TqbyZ2po73eDP4gYo2H92";
    }
    
          

  • Spring security configuration must be configured to use the Stormpath authentication provider:

    //Let add the StormpathAuthenticationProvider to the `AuthenticationProvider`
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(stormpathAuthenticationProvider);
    }
    
          

  • Finally, to restrict access to resources to roles, you will need to define roles. For example:

    //The access control settings are defined here
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .formLogin()
                .and()
            .authorizeRequests()
                .accessDecisionManager(accessDecisionManager())
                .antMatchers("/account/*").hasAuthority("https://api.stormpath.com/v1/groups/36O9eBTN2oLtjoMSWLdnwL") //you are giving access to "/account/*" to users' that belong to the group univocally identified by this href value
                .and()
            .logout()
                .logoutUrl("/logout")
                .logoutSuccessUrl("/index.jsp")
                .and()
            .httpBasic()
            .and()
            .csrf().disable();
    }
    
          

Disclaimer, I am an active member of Stormpath.

0


source







All Articles