Skip to content
Grails Spring Security SAML2.0 Plugin for Grails 3
Branch: master
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
example-files
gradle/wrapper
grails-app
src
.gitignore
CONTRIBUTING.md
README.md
_config.yml
build.gradle
gitflow-init.sh
gradle.properties
gradlew
gradlew.bat
grails-wrapper.jar
grailsw
grailsw.bat
settings.gradle

README.md

SAML 2.0 Plugin for Grails 3

This plugin provides SAML 2.0 support for Grails 3 applications. It was originally built from the Plugin that supported Grails 2 applications. It enables SAML configuration directly from your application.yml or application.groovy without having to manually configure the Spring SAML Plugin and Grails Spring Security Plugin

Plugin Compatibility with Grails

Grails 3.0.x - Use Version 3.0.x of the plugin Grails 3.1.x - Use Version 3.1.x of the plugin Grails 3.3.x - Use Version 3.3.x of the plugin

Installation

Maven

<dependency>
  <groupId>org.grails.plugins</groupId>
  <artifactId>spring-security-saml</artifactId>
  <version>3.3.0</version>
  <type>pom</type>
</dependency>

Gradle

compile 'org.grails.plugins:spring-security-saml:3.3.0'

NOTE: you may have to add the following repositories

 maven { url "http://central.maven.org/maven2/"}
    maven { url "https://build.shibboleth.net/nexus/content/repositories/releases"}
    maven { url "https://build.shibboleth.net/nexus/content/groups/public/"}
    maven { url "https://code.lds.org/nexus/content/groups/main-repo"}
    maven { url "http://repository.jboss.org/maven2/"}

Configuration

The Plugin basically creates a bridge from your application configuration to both the Spring Security SAML Plugin and the Grails Spring Security Plugin. Instead of having to map all of the beans in your application, the plugin wires the SAML Plugin beans from your application configuration.

All configuration items are preceeded with grails >> plugin >> springsecurity >> saml. The following is a list of all of the configuration options available.

Spring Security Starter

The spring security starter must be added to your build.gradle

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

Spring Security Classes

The plugin requires that the Spring Security Classes that are created with the s2-quickstart, are present in your application. To run s2-quickstart, see s2-quickstart

Command Line Example

$> grails s2-quickstart com.jeffwils User Role

This will create the Spring Security Domain Classes and it will create/modify the application.groovy file. You can convert the generated configuration to yaml format and use in application.yml as well.

Authentication Provider

The plugin sets up a SAML Authentication provider samlAuthenticationProvider which can be referenced in the Grails Spring Security Plugin configuration

grails:
   plugins:
      springsecurity:
         providerNames: ['samlAuthenticationProvider', ......]

Property Table

All of these properties can be put in either application.yml or application.groovy and they are all prefixed with: grails.plugins.springsecurity.saml

Property Syntax Example Value Description
active boolean true States whether or not SAML is active
afterLoginUrl url string '/' Redirection Url in your application upon successful login from the IDP
afterLogoutUrl url string '/' Redirection Url in your application upon successful logout from the IDP
responseSkew numeric 60 Time in seconds to account for differences in clock time between SP and IDP if their times should differ when attempting to compare request and assertion time index values
signatureAlgorithm String Value 'rsa-sha256' Accepted Values are From org.opensaml.xml.signature.SignatureConstants
digestAlgorithm String Value 'sha256' Accepted Values are From org.opensaml.xml.encryption.EncryptionConstants
userAttributeMappings Map [username:'funkyUserNameFromIDP'] Allows Custom Mapping if both Application and IDP Attribute Names cannot be changed.
userGroupAttribute String Value 'memberOf' Corresponds to the Role Designator in the SAML Assertion from the IDP
userGroupToRoleMapping Map [Spring Security Role: Saml Assertion Role] [ROLE_MY_APP_ROLE: 'CN=MYSAMLGROUP, OU=MyAppGroups, DC=myldap, DC=example, DC=com'] This maps the Spring Security Roles in your application to the roles from the SAML Assertion. Only roles in this Map will be resolved.
autoCreate.active boolean false If you want the plugin to generate users in the DB as they are authenticated via SAML
autoCreate.key domain class unique identifier 'id' if autoCreate active is true then this is the unique id field of the db table
autoCreate.assignAuthorities boolean false If you want the plugin to insert the authorities that come from the SAML message into the UserRole Table.
metadata.providers Map [idp alias: idp file reference] [ping:"/pathtoIdpFile/myIdp.xml"] Map of idp providers. Contain an alias and reference to the idp xml file
metadata.defaultIdp String 'ping' the default Idp from the ones listed in the metadata.provider map
metadata.url relative url '/saml/metadata' url used to retrieve the SP metadata for your app to send to the IDP
metadata.sp.file file reference as string "/mySpFilePath/myspfile.xml" Reference to your SP XML File. This can be on the classpath or in your file system.
metadata.sp.defaults.local boolean true True for metadata of a local service provider. False for remote identity providers.
metadata.sp.defaults.entityId String Value 'http://myapp.example.com' Identifier for the Service Provider
metadata.sp.defaults.alias url alias 'myalias' Unique alias used to identify the selected local service provider based on used URL. Will be postpended to the url in the SP File generated and given to the IDP
metadata.sp.defaults.securityProfile String Value 'pkix' Security profile for verification of message signatures metaiop, pkix
metadata.sp.defaults.signingKey keystore alias 'mykey' For local entities alias of private key used to create signatures. The default private key is used when no value is provided. For remote identity providers defines an additional public key used to verify signatures.
metadata.sp.defaults.encryptionKey keystore alias 'mykey' For local entities alias of private key used to encrypt data. The default private key is used when no value is provided. For remote identity providers defines an additional public key used to decrypt data.
metadata.sp.defaults.tlsKey keystore alias 'mykey' For local entities alias of private key used for SSL/TLS client authentication. No client authentication is used when value is not specified. For remote identity providers defines an additional public key used for trust resolution.
metadata.sp.defaults.requireArtifactResolveSigned boolean false Enables signing of artifact resolution requests sent to the remote identity providers.
metadata.sp.defaults.requireLogoutRequestSigned boolean false For local entities enables requirement of signed logout requests. For remote entities enables signing of requests sent to the IDP.
metadata.sp.defaults.requireLogoutResponseSigned boolean false For local entities enables requirement of signed logout responses. For remote entities enables signing of responses sent to the IDP.
keyManager.storeFile file reference string "/mypath/mykeystore.jks"
keyManager.storePass password string 'changeit' Keypass to keystore referenced in storeFile
keyManager.passwords password map [private key alias:password] [mykey:'changeit'] Map of aliases and passwords if private key in storeFile is password protected
keyManager.defaultKey keystore alias 'mykey' Default Key Alias in keystore referenced in storeFile

Example Configuration

The following are example configurations that will allow the application to start up correctly out of the box and have all the required beans mapped. There are two build.gradle files (3.0.9 which should cover all 3.0.x and 3.2.8 which should work with 3.1+). The example configurations (application.groovy & application.yml) utilize some of the defaults in the plugin and will need to be changed in your application (The SP and IDP specific) settings so that it will work with your service provider/identity provider configuration.

build.gradle grails 3.0.9

buildscript {
    ext {
        grailsVersion = project.grailsVersion
    }
    repositories {
        mavenLocal()
        maven { url "https://repo.grails.org/grails/core" }
    }
    dependencies {        
        classpath "org.grails:grails-gradle-plugin:$grailsVersion"
        classpath 'com.bertramlabs.plugins:asset-pipeline-gradle:2.5.0'
        classpath "org.grails.plugins:hibernate:4.3.10.5"
    }
}

plugins {
    id "io.spring.dependency-management" version "0.5.2.RELEASE"
}

version "0.1"
group "ss.test"

apply plugin: "spring-boot"
apply plugin: "war"
apply plugin: "asset-pipeline"
apply plugin: 'eclipse'
apply plugin: 'idea'
apply plugin: "org.grails.grails-web"
apply plugin: "org.grails.grails-gsp"

ext {
    grailsVersion = project.grailsVersion
    gradleWrapperVersion = project.gradleWrapperVersion
}

assets {
    minifyJs = true
    minifyCss = true
}

repositories {
    mavenLocal()
    mavenCentral()
    maven { url "https://repo.grails.org/grails/core" }
    maven { url "http://central.maven.org/maven2/"}
    maven { url "https://build.shibboleth.net/nexus/content/repositories/releases"}
    maven { url "https://build.shibboleth.net/nexus/content/groups/public/"}
    maven { url "https://code.lds.org/nexus/content/groups/main-repo"}
    maven { url "http://repository.jboss.org/maven2/"}
}

dependencyManagement {
    imports {
        mavenBom "org.grails:grails-bom:$grailsVersion"
    }
    applyMavenExclusions false
}

dependencies {
    compile "org.springframework.boot:spring-boot-starter-logging"
    compile "org.springframework.boot:spring-boot-starter-actuator"
    compile "org.springframework.boot:spring-boot-autoconfigure"
    compile "org.springframework.boot:spring-boot-starter-tomcat"
    compile "org.springframework.boot:spring-boot-starter-security"
    compile "org.grails:grails-dependencies"
    compile "org.grails:grails-web-boot"

    compile "org.grails.plugins:hibernate"
    compile "org.grails.plugins:cache"
    compile "org.hibernate:hibernate-ehcache"
    compile "org.grails.plugins:scaffolding"
    compile 'org.grails.plugins:spring-security-core:3.1.1'
    compile "org.grails.plugins:spring-security-saml:3.0.0"

    runtime "org.grails.plugins:asset-pipeline"

    testCompile "org.grails:grails-plugin-testing"
    testCompile "org.grails.plugins:geb"

    // Note: It is recommended to update to a more robust driver (Chrome, Firefox etc.)
    testRuntime 'org.seleniumhq.selenium:selenium-htmlunit-driver:2.44.0'

    console "org.grails:grails-console"
}

task wrapper(type: Wrapper) {
    gradleVersion = gradleWrapperVersion
}

build.gradle 3.2.8

buildscript {
    repositories {
        mavenLocal()
        maven { url "https://repo.grails.org/grails/core" }
    }
    dependencies {
        classpath "org.grails:grails-gradle-plugin:$grailsVersion"
        classpath "com.bertramlabs.plugins:asset-pipeline-gradle:2.14.1"
        classpath "org.grails.plugins:hibernate5:${gormVersion-".RELEASE"}"
    }
}

version "0.1"
group "ss.test.latest"

apply plugin:"eclipse"
apply plugin:"idea"
apply plugin:"war"
apply plugin:"org.grails.grails-web"
apply plugin:"org.grails.grails-gsp"
apply plugin:"asset-pipeline"

repositories {
    mavenLocal()
    maven { url "https://repo.grails.org/grails/core" }
    maven { url "http://central.maven.org/maven2/"}
    maven { url "https://build.shibboleth.net/nexus/content/repositories/releases"}
    maven { url "https://build.shibboleth.net/nexus/content/groups/public/"}
    maven { url "https://code.lds.org/nexus/content/groups/main-repo"}
    maven { url "http://repository.jboss.org/maven2/"}
}

dependencies {
    compile "org.springframework.boot:spring-boot-starter-logging"
    compile "org.springframework.boot:spring-boot-autoconfigure"
    compile "org.grails:grails-core"
    compile "org.springframework.boot:spring-boot-starter-actuator"
    compile "org.springframework.boot:spring-boot-starter-tomcat"
    compile "org.springframework.boot:spring-boot-starter-security"
    compile "org.grails:grails-dependencies"
    compile "org.grails:grails-web-boot"
    compile "org.grails.plugins:cache"
    compile "org.grails.plugins:scaffolding"
    compile "org.grails.plugins:hibernate5"
    compile "org.hibernate:hibernate-core:5.1.3.Final"
    compile "org.hibernate:hibernate-ehcache:5.1.3.Final"
    compile 'org.grails.plugins:spring-security-core:3.1.1'
    compile "org.grails.plugins:spring-security-saml:3.0.0"
    console "org.grails:grails-console"
    profile "org.grails.profiles:web"
    runtime "com.bertramlabs.plugins:asset-pipeline-grails:2.14.1"
    runtime "com.h2database:h2"
    testCompile "org.grails:grails-plugin-testing"
    testCompile "org.grails.plugins:geb"
    testRuntime "org.seleniumhq.selenium:selenium-htmlunit-driver:2.47.1"
    testRuntime "net.sourceforge.htmlunit:htmlunit:2.18"
}

bootRun {
    jvmArgs('-Dspring.output.ansi.enabled=always')
    addResources = true
}


assets {
    minifyJs = true
    minifyCss = true
}

application.groovy

// Added by the Spring Security Core plugin:
grails.plugin.springsecurity.userLookup.userDomainClassName = 'com.jeffwils.User'
grails.plugin.springsecurity.userLookup.authorityJoinClassName = 'com.jeffwils.UserRole'
grails.plugin.springsecurity.authority.className = 'com.jeffwils.Role'
grails.plugin.springsecurity.requestMap.className = 'com.jeffwils.UserRole'
grails.plugin.springsecurity.securityConfigType = 'Requestmap'
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']]
]

grails.plugin.springsecurity.filterChain.chainMap = [
	[pattern: '/assets/**',      filters: 'none'],
	[pattern: '/**/js/**',       filters: 'none'],
	[pattern: '/**/css/**',      filters: 'none'],
	[pattern: '/**/images/**',   filters: 'none'],
	[pattern: '/**/favicon.ico', filters: 'none'],
	[pattern: '/**',             filters: 'JOINED_FILTERS']
]

grails.plugin.springsecurity.providerNames = ['samlAuthenticationProvider', 'daoAuthenticationProvider', 'anonymousAuthenticationProvider']

grails.plugin.springsecurity.saml.active = true
grails.plugin.springsecurity.saml.afterLoginUrl = '/'
grails.plugin.springsecurity.saml.afterLogoutUrl = '/'
grails.plugin.springsecurity.saml.responseSkew = 300
grails.plugin.springsecurity.saml.signatureAlgorithm = 'rsa-sha256'
grails.plugin.springsecurity.saml.digestAlgorithm = 'sha256'
grails.plugin.springsecurity.saml.userGroupAttribute = 'roles'
grails.plugin.springsecurity.saml.autoCreate.active = false  //If you want the plugin to generate users in the DB as they are authenticated via SAML
grails.plugin.springsecurity.saml.autoCreate.key = 'id'
grails.plugin.springsecurity.saml.autoCreate.assignAuthorities=false  //If you want the plugin to assign the authorities that come from the SAML message.
grails.plugin.springsecurity.saml.metadata.defaultldp = 'ping'
grails.plugin.springsecurity.saml.metadata.url = '/saml/metadata'
grails.plugin.springsecurity.saml.metadata.providers = [ping:'security/idp-local.xml']
grails.plugin.springsecurity.saml.metadata.sp.file = "security/sp.xml"
grails.plugin.springsecurity.saml.metadata.sp.defaults.local = true;
grails.plugin.springsecurity.saml.metadata.sp.defaults.entityId = 'test'
grails.plugin.springsecurity.saml.metadata.sp.defaults.alias = 'test';
grails.plugin.springsecurity.saml.metadata.sp.defaults.securityProfile = 'pkix';
grails.plugin.springsecurity.saml.metadata.sp.defaults.signingKey = 'ping';
grails.plugin.springsecurity.saml.metadata.sp.defaults.encryptionKey = 'ping';
grails.plugin.springsecurity.saml.metadata.sp.defaults.tlsKey = 'ping';
grails.plugin.springsecurity.saml.metadata.sp.defaults.requireArtifactResolveSigned = false;
grails.plugin.springsecurity.saml.metadata.sp.defaults.requireLogoutRequestSigned = false;
grails.plugin.springsecurity.saml.metadata.sp.defaults.requireLogoutResponseSigned = false;
grails.plugin.springsecurity.saml.keyManager.storeFile = "classpath:security/keystore.jks"
grails.plugin.springsecurity.saml.keyManager.storePass = 'nalle123'
grails.plugin.springsecurity.saml.keyManager.passwords = ping:'ping123'
grails.plugin.springsecurity.saml.keyManager.defaultKey = 'ping'

application.yml

grails:
   plugin:
      springsecurity:
         userLookup:
            userDomainClassName: 'com.jeffwils.User'
            authorityJoinClassName: 'com.jeffwils.UserRole'
         authority:
            className: 'com.jeffwils.Role'
         requestMap:
            className: 'com.jeffwils.UserRole'
         securityConfigType: 'Requestmap'
         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']]
                          ]
         filterChain:
            chainMap: [
                        	[pattern: '/assets/**',      filters: 'none'],
                        	[pattern: '/**/js/**',       filters: 'none'],
                        	[pattern: '/**/css/**',      filters: 'none'],
                        	[pattern: '/**/images/**',   filters: 'none'],
                        	[pattern: '/**/favicon.ico', filters: 'none'],
                        	[pattern: '/**',             filters: 'JOINED_FILTERS']
                      ]
         providerNames: ['samlAuthenticationProvider', 'daoAuthenticationProvider', 'anonymousAuthenticationProvider']

         saml:
            active: true
            afterLoginUrl: '/'
            afterLogoutUrl: '/'
            responseSkew: 300
            signatureAlgorithm = 'rsa-sha256'
            digestAlgorithm = 'sha256'
            userGroupAttribute = 'roles'
            autoCreate:
               active: false  //If you want the plugin to generate users in the DB as they are authenticated via SAML
               key: 'id'
               assignAuthorities: false  //If you want the plugin to assign the authorities that come from the SAML message.
            metadata:
               defaultldp: 'ping'
               url: '/saml/metadata'
               providers: [ping:'security/idp-local.xml']
               sp:
                  file: "security/sp.xml"
                  defaults:
                     local: true
                     entityId: 'test'
                     alias: 'test'
                     securityProfile: 'pkix';
                     signingKey: 'ping'
                     encryptionKey: 'ping'
                     tlsKey: 'ping'
                     requireArtifactResolveSigned: false
                     requireLogoutRequestSigned: false
                     requireLogoutResponseSigned: false
            keyManager:
               storeFile: "classpath:security/keystore.jks"
               storePass: 'nalle123'
               passwords: ping:'ping123'
               defaultKey: 'ping'
You can’t perform that action at this time.