Spring security core with groups

In this blog post I will look into assigning roles through groups.

Group assignment becomes more interesting with:

  • increasing user count
  • increasing role count
  • users with similar access needs

Overview

There are three basic domains when configuring spring security for groups.

  • User
  • Role
  • RoleGroup

We also have these many-to-many helper domains:

Each user can be member of any rolegroup.

And each rolegroup can have any role.

This setup means that roles are assigned to rolegroups. No roles are assigned directly to users.

Create the application

grails create-app ssc-groups1 --profile=web

Add spring security to build.gradle:

compile 'org.grails.plugins:spring-security-core:4.0.0'

Initialize spring security:

grails s2-quickstart no.prpr.security User Role --groupClassName=RoleGroup

Initialize user, role, group

BootStrap.groovy:

package ssc.groups1

import no.prpr.security.Role
import no.prpr.security.RoleGroup
import no.prpr.security.RoleGroupRole
import no.prpr.security.User
import no.prpr.security.UserRoleGroup

class BootStrap {

    def init = { servletContext ->
        def adminUser = User.findByUsername('admin')
        if (!adminUser) {
            User.withNewTransaction {
                adminUser = new User(username: 'admin', password: 'password')
                        .save(flush: true)
            }
            log.info("Added user admin: ${adminUser}")
        }

        def adminsRoleGroup = RoleGroup.findByName('Admins')
        if (!adminsRoleGroup) {
            RoleGroup.withNewTransaction {
                adminsRoleGroup = new RoleGroup(name: 'Admins')
                        .save(flush: true)
            }
            log.info("Added role-group Admins: ${adminsRoleGroup}")
        }

        def adminRole = Role.findByAuthority('ROLE_ADMIN')
        if (!adminRole) {
            Role.withNewTransaction {
                adminRole = new Role(authority: 'ROLE_ADMIN')
                adminRole.save(flush: true)
            }
            log.info("Added role ROLE_ADMIN: ${adminRole}")
        }

        def adminsToAdminRoleGroup = RoleGroupRole.get(adminsRoleGroup.id, adminRole.id)
        if (!adminsToAdminRoleGroup) {
            RoleGroupRole.withNewTransaction {
                adminsToAdminRoleGroup = new RoleGroupRole(roleGroup: adminsRoleGroup, role: adminRole)
                        .save(flush: true)
            }
            log.info("Added admin role to admins role-group -> adminsToAdminRoleGroup: ${adminsToAdminRoleGroup}")
        }

        def adminsUserRoleGroup = UserRoleGroup.get(adminUser.id, adminsRoleGroup.id)
        if (!adminsUserRoleGroup) {
            UserRoleGroup.withNewTransaction {
                adminsUserRoleGroup = new UserRoleGroup(user: adminUser, roleGroup: adminsRoleGroup)
                        .save(flush: true)
            }
            log.info("added admin to admins-role-group -> adminsUserRoleGroup: ${adminsUserRoleGroup}")
        }
    }
    def destroy = {
    }
}

Add user UI

grails generate-all no.prpr.security.User

Add @Secured to UserController

@Secured('ROLE_ADMIN')
class UserController {

Modify application.groovy:

grails.plugin.springsecurity.logout.postOnly = false

The complete application is here: https://johnny.prpr.no/wp-content/uploads/2020/04/ssc-groups1.zip

Summary

In 4 blog posts I have covered different sides of configuring spring security plugin.

Parts of our applications can store business critical and privacy information. When starting up with Grails the plan was to enable some kind of two-factor authentication in order to protect data better than password only.

It was only after attending an ObjectComputing webinar I was made aware that they had successfully configured the Spring security domains for multitenancy.

Finally in this post touched groups, so that most users can be configured with one or just a few group memberships.

Play with spring security in more ways than you need.