I'm creating a simple prototype to use as a model for changing how an existing Grails application that uses Spring Security Core authenticates the end user.
Grails version - 2.3.11 Spring Security Core version - 1.2.7.3
I created my own CA, issued my own server certificate, issued a client certificate, and configured my Tomcat 7 instance and browser to use said certification.
I modified the Tomcat server.xml as follows:
<Connector port="8443" protocol="org.apache.coyote.http11.Http11Protocol"
maxThreads="150" SSLEnabled="true" scheme="https" secure="true"
truststoreFile="/Users/mybox/Documents/apache-tomcat-7.0.64/conf/cacerts.jks" truststorePass="password"
keystoreFile="/Users/mybox/Documents/apache-tomcat-7.0.64/conf/keystore.jks" keystorePass="password"
clientAuth="true" sslProtocol="TLS" />
In the Grails project itself, I've modified several files:
In Config.groovy I added:
// Added by the Spring Security Core plugin:
grails.plugins.springsecurity.userLookup.userDomainClassName = 'com.pkiprototype.User'
grails.plugins.springsecurity.userLookup.authorityJoinClassName = 'com.pkiprototype.UserRole'
grails.plugins.springsecurity.authority.className = 'com.pkiprototype.Role'
grails.plugin.springsecurity.useX509 = true
grails.plugin.springsecurityx509.continueFilterChainOnUnsuccessfulAuthentication = true
grails.plugin.springsecurity.controllerAnnotations.staticRules = [
'/': ['permitAll'],
'/sample': ['permitAll'],
'/index': ['permitAll'],
'/index.gsp': ['permitAll'],
'/assets/**': ['permitAll'],
'/**/js/**': ['permitAll'],
'/**/css/**': ['permitAll'],
'/**/images/**': ['permitAll'],
'/**/favicon.ico': ['permitAll'],
'/dbconsole/**': ['permitAll']
]
In BuildConfig.groovy I added:
grails.tomcat.keystorePath = "${basedir}/grails-app/conf/keystore.jks"
grails.tomcat.keyStorePassword = "password"
I've got the keystore.jks at that location, too.
I've got a super simple Controller:
package com.pkiprototype
class SampleController {
def springSecurityService
def User = {
def currentUser = springSecurityService. getCurrentUser ()
render "Welcome user:" + currentUser. username + "\n Your role is:" + currentUser. getAuthorities ()
}
def index() { }
}
I've got a user in my bootstrap.groovy whose username matches the CN of the user in my client certificate, that I've loaded into my browser.
When I hit the page https://localhost:8443/pkiprototype-0.1/sample/User, I am prompted to use my certificate. But then the page throws an error "An error has occurred", and when I check the Tomcat's stacktrace.log I get the following:
2015-09-15 15:27:25,420 [http-bio-8443-exec-7] ERROR StackTrace - Full Stack Trace:
java.lang.NullPointerException: Cannot get property 'username' on null object
at com.pkiprototype.SampleController$_closure1.doCall(SampleController.groovy:9)
at grails.plugin.cache.web.filter.PageFragmentCachingFilter.doFilter(PageFragmentCachingFilter.java:189)
at grails.plugin.cache.web.filter.AbstractFilter.doFilter(AbstractFilter.java:63)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
What am I missing? Shouldn't the certificate I supplied to the browser be read and used by Spring Security Core, to find the user and thus and pass it along to the controller action, and the rendered page?
I figured it out!
The issue was this line:
grails.plugin.springsecurity.useX509 = true
The correct syntax for VERSION 1 of Spring Security Core plugin references in Config.groovy is grails.plugins
I changed the line to
grails.plugins.springsecurity.useX509 = true
And voila! It works.
Please note, that a VERY valuable resource for help (which was super helpful to me with this issue), is the Grails Community SLACK, http://slack-signup.grails.org/