3
votes

I’m new to Grails and I’m trying to build a simple help desk application. I want to be able to register a new user, log in, post a request/incident, save it to a database and from administrator side I want to be able to see all requests/incidents in a table, and change permissions of users. For the security part (and security management) I was thinking of using Spring security & Spring security UI plugins. For now I’ve created application, installed both spring security and its UI extension, added the realname, email and company properties. When I run the application, I manage to successfully register and when I confirm registration from email i’m automatically logged in, but when I try to log in with different browser I get the following error :

“Sorry, we were not able to find a user with that username and password”

But there is one in the database.

Also, I want to have, lets say Incident domain class where I will persist all incidents/request data. The relationship between the User and Incident domain classes will be one to many. Do I just implement that like any other relationship or do I have to do something special because User is implemented by Spring Security? I’m open for any suggestions.

3

3 Answers

3
votes

There's an incompatibility between the latest spring-security-core and spring-security-ui 0.1.2. In particular, spring-security-core moved password encoding into beforeInsert/beforeUpdate event handlers in the User class. RegisterController.register controller in spring-security-ui doesn't know about this yet, and tries to encode it again, resulting in a doubly encoded password. To fix, override the RegisterController and change the register action to:

def register = { RegisterCommand command ->

    if (command.hasErrors()) {
        render view: 'index', model: [command: command]
        return
    }

    def user = lookupUserClass().newInstance(email: command.email, username: command.username,
                                             password: command.password, accountLocked: true, enabled: true)
    if (!user.validate() || !user.save()) {
        // TODO
    }

    def registrationCode = new RegistrationCode(username: user.username).save()
    String url = generateLink('verifyRegistration', [t: registrationCode.token])

    def conf = SpringSecurityUtils.securityConfig
    def body = conf.ui.register.emailBody
    if (body.contains('$')) {
        body = evaluate(body, [user: user, url: url])
    }
    mailService.sendMail {
        to command.email
        from conf.ui.register.emailFrom
        subject conf.ui.register.emailSubject
        html body.toString()
    }

    render view: 'index', model: [emailSent: true]
}

This issue is being tracked in http://jira.grails.org/browse/GPSPRINGSECURITYUI-27.

Regarding your second question, you can treat your User class just like any other domain object.

2
votes

When you add Spring Security to your grails project with s2-quickstart script, domain classes for user and role are automatically created. Those are normal domain classes, so you can add anything you want (like a list of Incidents) to user class.

To get the currently logged user domain object at runtime, use

springSecurityService.currentUser

0
votes

This issue is already fixed in "org.grails.plugins:spring-security-ui:1.0-RC3". spring-security-ui does not encode the password by default.

Here's the description and their solution to the problem from the grails spring Security UI documentation. Search for the section entitled "Password Hashing"

http://grails-plugins.github.io/grails-spring-security-ui/v1/guide/customization.html

"In recent versions of the Spring Security Core plugin, the "User" domain class is geneThis option defaults to falserated by the s2-quickstart script with code to automatically hash the password. This makes the code simpler (for example in controllers where you create users or update user passwords) but older generated classes don't have this generated code. This presents a problem for plugins like this one since it's not possible to reliably determine if the domain class hashes the password or if you use the older approach of explicitly calling springSecurityService.encodePassword().

The unfortunate consequence of mixing a newer domain class that does password hashing with controllers that call springSecurityService.encodePassword() is the the passwords get double-hashed, and users aren't able to login. So to get around this there's a configuration option you can set to tell this plugin's controllers whether to hash or not: grails.plugin.springsecurity.ui.encodePassword.

This option defaults to false, so if you have an older domain class that doesn't handle hashing just enable this plugin's hashing:

grails.plugin.springsecurity.ui.encodePassword = true"