I recently upgraded one of our Grails 2.2.1 with Spring Security core plugin 1.2.7.3 on Java 1.6 application to Grails 3.2.1 with Spring Security core plugin 3.1.1 on Java 1.8. By following the recommended path detailed out well enough in Grails 3 documentation, I got the following done before I got to the point of successfully running the application:
The error was bit puzzling and made me to comment out the following Spring security core plugin's configuration property set in application.groovy:
//grails.plugin.springsecurity.dao.reflectionSaltSourceProperty = 'username’
Commenting out that property revealed the issue with the following error:
After quickly reading through documents of both Grails-2 Spring Security Core Plugin and Grails-3 Spring Security Core Plugin, there was a special mention of Bcrypt algorithm in version 3 documentation. Also, it was specified up front in the Configuration Settings section of the doc that the plugin's default security settings are maintained in DefaultSecurityConfig.groovy file. I checked both plugin 2, plugin 3 and found the following differences:
Grails-3 plugin
Grails-2 plugin
Differences are highlighted. The hash.iterations property is set to 10000 in Grails-3 plugin, but is not set explicitly in Grail-2 plugin. I had to add algorithm and hash.iterations explicitly to match Grails-2 plugin and retain the reflectionSaltSourceProperty in application.groovy.The following are the changes:
Grails Spring Security 2 documentation
Grails Spring Security 3 documentation
- Upgraded one of our in-house plugins: ZipCityState
- Reorganized Grails artifacts and other files as per Grails-3 app directory structure
- Rewrote build and other configurations
- Fixed several code compilation errors and issues resulted due to changed package names of several Grails frame-work classes and some classes that are deprecated and removed
- Upgraded static resources like images, javascript and stylesheets from resources plugin to asset-pipeline plugin by re-organizing those files and creating appropriate asset-pipeline directives to mimic resource plugin's modules defined in AppResources.groovy
Static Rules
Static rules are now List of Maps and not just a Map. I covered this in my previous post. Check it out.
Authentication
Change username and password form fields in login page (auth.gsp) from j_username and j_password to username and password.
If you have used UsernamePasswordAuthenticationFilter.SPRING_SECURITY_LAST_USERNAME_KEY somewhere in your code, you need to change that to SpringSecurityUtils.SPRING_SECURITY_LAST_USERNAME_KEY
If you have any pre authentication checks written by extending DefaultPreAuthenticationChecks, the hibernate session seems not created and attached to the current thread at this point.
If you run into any exception like the following, you may need to use either withTransaction or withSession method on the domain object to come over this.
If you run into any exception like the following, you may need to use either withTransaction or withSession method on the domain object to come over this.
org.springframework.dao.DataAccessResourceFailureException: Could not obtain current Hibernate Session; nested exception is org.hibernate.HibernateException: No Session found for current thread.
Password encryption algorithm differences
The application has an admin account created in the database only once with exists check from the Bootstrap. The login failed for admin user that was created by Grails 2.2.1 app and after upgrading to Grails 3.2.1 with the following exception:
ERROR org.apache.catalina.core.ContainerBase.[Tomcat].[localhost].[/].[grailsDispatcherServlet] - Servlet.service() for servlet [grailsDispatcherServlet] in context with path [] threw exception [Filter execution threw an exception] with root cause
java.lang.AssertionError: Salt value must be null when used with crypto module PasswordEncoder. Expression: salt. Values: salt = admin
at org.codehaus.groovy.runtime.InvokerHelper.assertFailed(InvokerHelper.java:404)
at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.assertFailed(ScriptBytecodeAdapter.java:650)
at grails.plugin.springsecurity.authentication.encoding.BCryptPasswordEncoder.checkSalt(BCryptPasswordEncoder.groovy:49)
The error was bit puzzling and made me to comment out the following Spring security core plugin's configuration property set in application.groovy:
//grails.plugin.springsecurity.dao.reflectionSaltSourceProperty = 'username’
Commenting out that property revealed the issue with the following error:
WARN org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder - Encoded password does not look like BCrypt
After quickly reading through documents of both Grails-2 Spring Security Core Plugin and Grails-3 Spring Security Core Plugin, there was a special mention of Bcrypt algorithm in version 3 documentation. Also, it was specified up front in the Configuration Settings section of the doc that the plugin's default security settings are maintained in DefaultSecurityConfig.groovy file. I checked both plugin 2, plugin 3 and found the following differences:
Grails-3 plugin
password {
algorithm = ‘bcrypt’
encodeHashAsBase64 = false
bcrypt {
logrounds = 10
}
hash {
iterations = 10000
}
}
Grails-2 plugin
password.algorithm = 'SHA-256'
password.encodeHashAsBase64 = false
password.bcrypt.logrounds = 10
Differences are highlighted. The hash.iterations property is set to 10000 in Grails-3 plugin, but is not set explicitly in Grail-2 plugin. I had to add algorithm and hash.iterations explicitly to match Grails-2 plugin and retain the reflectionSaltSourceProperty in application.groovy.The following are the changes:
grails.plugin.springsecurity.password.algorithm = 'SHA-256'
grails.plugin.springsecurity.password.hash.iterations = 1
grails.plugin.springsecurity.dao.reflectionSaltSourceProperty = 'username'
Summary
With static rule configuration changes, password encryption properties changes and code changes to auth.gsp and some security related classes, I was able to get the application successfully migrated from Grails 2.2.1 to Grails 3.2.1 along with upgraded Spring Security core plugin.References
Grails 3.2.1 documentationGrails Spring Security 2 documentation
Grails Spring Security 3 documentation
THank you soo much. This was really helpful, had to change the username and password fields on the login page from j_username & j_password, to username & password. Thanks again
ReplyDelete@Dominic Fui Dodzi-Nusenu Thank you. I am glad to know that it was helpful.
ReplyDelete