Sunday, November 20, 2016

Upgrading Grails-2 application to Grails-3: Spring Security Core Plugin differences . . .

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:
  • 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
Once all the above are done, I had to make the following changes from the Security aspect for the application to successfully run, display and login:

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.

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 documentation
Grails Spring Security 2 documentation
Grails Spring Security 3 documentation


Sunday, November 13, 2016

Upgrading Grails-2 application to Grails-3 - Make static assets available . . .

Recently, I started upgrading a Grails web-application from Grails-2 to Grails-3, particularly from version 2.2.1 to 3.2.1. The perfect minor.patch(2.1) matching of both versions in this process was just a perfect timing-coincidence as Grails was at 2.2.1 when this app was developed and the latest Grails was at 3.2.1 when I started to upgrade.

The process of upgrading was not bad, but it required quite a bit of careful changes. I simply followed the very well documented Grails3 Documentation and get going this effort after successfully migrating an in-house plugin ZipCityState from Grails-2 to Grails-3. This deserves another blog post.

Static Assets

One of the web aspects that needed bit more effort in this upgrade was: Static Assets.

Grails-3 comes with asset-pipeline plugin. Static assets like images, javascript and stylesheets need an upgrade by moving from Resources plugin to Asset-pipeline plugin. There is a nice blog post on this from Grails Team and according to this, the viable option in Grails-3 is asset-pipeline and resources plugin is not available. I will write a bit more detailed post on this later.

After upgrading the application and taking care of several compilation and startup issues along the way, I was finally able to get the application started and running. The login page showed up but all the static assets like stylesheets, javascripts and images were totally missing. This made me look into all asset pipeline directives and related changes I made in migrating static assets to asset-pipeline. Everything looked good but the issue was just puzzling. After spending sometime finally I realized that static assets upgrade to asset-pipeline from Grails-2 to Grails-2 need some attention from security settings as well.

Grails Spring Security Plugin takes a pessimistic locks down approach and locks down all URLs that do not have an applicable URL mapping. 

Usually, Grails-2 security static rules look like:
grails.plugins.springsecurity.controllerAnnotations.staticRules = [ '/login/**': ['IS_AUTHENTICATED_ANONYMOUSLY'], '/js/**': ['IS_AUTHENTICATED_ANONYMOUSLY'], '/css/**': ['IS_AUTHENTICATED_ANONYMOUSLY'], '/images/**': ['IS_AUTHENTICATED_ANONYMOUSLY'], '/**': ['IS_AUTHENTICATED_FULLY'] ]

In Grails-3, add pattern 'assets/**' for static assets as they are now moved under grails-app/assets and get served by asset pipeline plugin through requests URLs like- http://my-app-url/assets/.  Make the static rules look like the following (highlighted is the change):
grails.plugin.springsecurity.controllerAnnotations.staticRules = [ [pattern: '/login/**', access: ['IS_AUTHENTICATED_ANONYMOUSLY']], [pattern: '/assets/**', access: ['IS_AUTHENTICATED_ANONYMOUSLY']], [pattern:'/**', access: ['IS_AUTHENTICATED_FULLY']] ]

There you go, asset pipeline plugin works and all static assets are available, get served and become visible!

References