Using MongoDB With Version 2.x of the Grails Spring Security Core Plugin

With a few customization steps it’s easy to use MongoDB to store user and role information for the spring-security-core plugin instead of using Hibernate, and after seeing this Stack Overflow question I thought I’d write up some notes on how to do this with the current plugins. Note that much of this is based on this blog post.

I created a demo application using Grails 2.3.3; it’s available on GitHub. The general steps were:

  • $ grails create-app mongoSpringSecurity
  • add the plugins to BuildConfig.groovy
  • $ grails s2-quickstart auth User Role
  • update DataSource.groovy to use MongoDB
  • create a custom UserDetailsService and register it in resources.groovy
  • create a test role and a user in BootStrap.groovy
  • customize the domain classes to use MongoDB
  • add tags to index.gsp to add a login link if you’re not logged in, and show that you’re logged in if you are

One difference between what I do here and what was done in the original blog post is that the custom UserDetailsService is not a Grails service – it’s in src/groovy and not in grails-app/services. It wasn’t necessary to be a real service then and isn’t now; it’s a coincidence that the Spring Security interface name ends in “Service”. See the plugin documentation for general information about customizing this bean.

You can see the source for the custom bean here. By embedding the authorities in the user domain class, the many-to-many relationship is not needed and the model is a lot simpler, so the class implementation is also – for example there’s no need for a withTransaction block to avoid lazy loading exceptions.

The changes for the User class are fairly minor. You need static mapWith = 'mongo' if you have both the Hibernate and MongoDB plugins; in this case it’s unnecessary but harmless to leave it in. The id field should be an ObjectId, and I retained the other customizations from the earlier blog post (the embedded roles, the addition of the email field, extra constraints, etc.). The Role class changes are similar.

Since we’re using a custom UserDetailsService, we can delete the userLookup.userDomainClassName, userLookup.authorityJoinClassName, and authority.className properties from Config.groovy, and since the roles are embedded in the user class we can delete the generated UserRole class.

You should be able to clone the repo and start the application (assuming you have MongoDB and Grails 2.3.3 already). Click the login link on the start page and after you successfully authenticate, the link should be replaced by a message.

14 Responses to “Using MongoDB With Version 2.x of the Grails Spring Security Core Plugin”

  1. Pawel says:

    It’s great to see a new post here! Is there any chance for weekly updates for This Week in Grails?

  2. Pawel says:

    In that case thanks for all your work on “This Week in Grails”! It has been very valuable source of information about Grails/Groovy ecosystem. I used to visit your blog quite often just to catch up with latest news.

    Maybe you could write a short post here so more people are informed about Grails Diary? Not everyone is reading these comments.

    One more thought – I’m afraid that Grails is loosing its traction. I see some important people like you or Marc Palmer being less and less involved in the community lately…

  3. Raj says:

    How can we use UserDetailsService to support a custom login where additional Group/Organization must be specified in addition to username/password.

  4. Hi Burt,
    I haven’t been able to get the cas spring security plugin to work after upgrading to Grails 2.3.3. It appears that the default authentication handler is being called and redirecting to /login/auth rather than the CAS handler defined in the Config.

    Have you seen any issues? Im using the mongo 1.3.3 plugin and have hibernate disabled.

    • Burt says:

      Try the User list – I tested CAS with Hibernate before releasing the plugin and it worked fine, but another user might be able to shed some light.

  5. Hi Burt,

    Thanks for writing this post. I also enjoy how you explained different parts of the Grails framework in your book. In the post Above you said “By embedding the authorities in the user domain class, the many-to-many relationship is not needed and the model is a lot simpler, so the class implementation is also”, So do you think in future you might apply that to the actual plugin so that become the default or is it tricky since people’s code might break due to that change ? I was just curious :)

    • Burt says:

      That would be a breaking change and would likely affect other plugins that use and/or extend the core plugin. Plus it is a fairly natural many-to-many relationship. Given how Mongo works and how it’s typically used embedding makes a lot of sense there, but in a relational database the current three-table approach works well. You also get the consistency check from the foreign key relationships – if you try to assign a non-existent role it will fail. But in Mongo you can easily add a bad role, e.g. ROLE_ADMN instead of ROLE_ADMIN, and there’s no check for that.

      • Thanks for explaining. So if I’m not using mangoDB, using the current model of 3 tables (User, Role, UserRole) shouldn’t cause performance issues for a website with thousands of users. What I mean is, a typical Blog website that only has 1 admin, and the rest are just users. Correct ? (I know it depends on the web application, just asking generally)

        • Burt says:

          I did a talk a while back on performance issues with 1-many and many-many collections in Grails; it’s online here: http://www.infoq.com/presentations/GORM-Performance

          The implementation of the many-many in the plugin explicitly maps the join table in addition to the user and role tables, that’s why the UserRole domain class that’s generated by the s2-quickstart has so much code in it. This approach is very fast and doesn’t have the unexpected problems with standard many-to-many mappings in Grails that use collections.

          • Great Job Burt! I watched the video, it was very helpful and I re-coded my country, state, city domain classes using that approach afterward. My model is now very simple comparing to the hasMany and belogTo model.

  6. I don’t know if you have a post related to rememberMe portion of Spring Security Core Plugin that you can redirect me to. Because I’m having a problem with that and seems like it’s not working. I think when the remember me isn’t checked, when we close the browser and open it again, it should show the login page rather than log the user in automatically, am I correct ? In either case, whether it’s checked or not, the user gets logged in. I appreciate it if you can elaborate on that. You can remove this reply message if you can answer the question here : http://stackoverflow.com/questions/21977692/grails-spring-security-remember-me-feature-doesnt-work

    Thanks!

Creative Commons License
This work is licensed under a Creative Commons Attribution 3.0 License.