Grails, Vaadin and Spring Security Core

I got kind of bored with Flex and all the complexity it introduces by forcing you to switch between ActionScript and whatever you are using for the backend (Groovy in my case). I also got bored with having to regenerate my data service stubs on each server-side change, and having to handle the asynchronous remoting. So I started to have a look at Vaadin.

Vaadin offers the same richness of components as Flex, but I can code my UI with Groovy and it completely removes the need to bother about remoting and all that stuff. It’s really like my old Swing days and I love it.

Last week-end, I tried their AddressBook tutorial, and I adapted it to Grails using the Grails-Vaadin plugin. Then I modified the sample so that it uses GORM to store contacts. And finally I installed spring-security-core plugin to secure my business services with @Secured annotations. And it worked absolutely great.

I just released a new version of the Grails-Vaadin plugin with Vaadin upgraded to 6.5.1 (the latest version at this point), and I uploaded my version of addressbook to GitHub.

For me, the most interesting part is how I got security to work. All I had to do was to install spring-security-core plugin into grails and then define a simple SecurityService like the following:

package org.epseelon.addressbook.business

import org.springframework.security.core.context.SecurityContextHolder as SCH
import org.springframework.security.authentication.BadCredentialsException
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken

class SecurityService {

    static transactional = true

    def springSecurityService
    def authenticationManager

    void signIn(String username, String password) {
        try {
            def authentication = new UsernamePasswordAuthenticationToken(username, password)
            SCH.context.authentication = authenticationManager.authenticate(authentication)
        } catch (BadCredentialsException e) {
            throw new SecurityException("Invalid username/password")
        }
    }

    void signOut(){
        SCH.context.authentication = null
    }

    boolean isSignedIn(){
        return springSecurityService.isLoggedIn()
    }
}

Then I injected this SecurityService into my AddressBookApplication and used it:

class AddressBookApplication extends Application {
    private SecurityService security = (SecurityService)getBean(SecurityService)

    [...]

    boolean login(String username, String password) {
        try {
            security.signIn(username, password)
            refreshToolbar()
            return true
        } catch (SecurityServiceException e) {
            getMainWindow().showNotification(e.message, Notification.TYPE_ERROR_MESSAGE);
            return false
        }
    }
}

Then whenever I try to call a @Secured method:

package org.epseelon.addressbook.business

import org.epseelon.addressbook.dto.PersonListItem
import org.epseelon.addressbook.domain.Person
import grails.plugins.springsecurity.Secured

class PersonService {

    static transactional = true

    [...]

    @Secured(["ROLE_USER"])
    PersonListItem updatePerson(PersonListItem item) {
        Person p = Person.get(item.id)
        if(p){
            p.firstName = item.firstName
            p.lastName = item.lastName
            p.email = item.email
            p.phoneNumber = item.phoneNumber
            p.streetAddress = item.streetAddress
            p.postalCode = item.postalCode
            p.city = item.city
            p.save()

            return new PersonListItem(
                firstName: p.firstName,
                lastName: p.lastName,
                email: p.email,
                phoneNumber: p.phoneNumber,
                streetAddress: p.streetAddress,
                postalCode: p.postalCode,
                city: p.city
            )
        }
        return null
    }
}

If I’m not logged in as a user, I get an “access denied” exception:

package org.epseelon.addressbook.presentation.data

import com.vaadin.data.util.BeanItemContainer
import org.epseelon.addressbook.dto.PersonListItem
import org.epseelon.addressbook.business.PersonService
import com.vaadin.data.util.BeanItem
import com.vaadin.ui.Window.Notification
import org.epseelon.addressbook.presentation.AddressBookApplication

/**
 *
 * @author sarbogast
 * @version 19/02/11, 11:12
 */
class PersonContainer extends BeanItemContainer<PersonListItem> implements Serializable {
    [...]
    boolean updateItem(Object itemId) {
        try {
            personService.updatePerson((PersonListItem) itemId)
            return true
        } catch (Exception e) {
            AddressBookApplication.application.getMainWindow().showNotification(
                    e.message,
                    Notification.TYPE_ERROR_MESSAGE
            );
            return false
        }
    }
}

To see what it looks like, all you have to do is to download the code from GitHub, and run “grails run-app” at the root of it.
If you try to create a new contact of edit an existing one and save it without being logged in, you get an “access denied” message. But if you login as ramon/password, it works.

Note that this project uses Grails 1.3.6 but the plugin supports any version of Grails above 3.2 included. As always, your feedback is more than welcome.

21 comments

  1. I have to say that I’m disappointed at hearing that from you: “I got kind of bored with Flex and all the complexity it introduces by forcing you to switch between ActionScript and whatever you are using for the backend”. I’m a big fan of your full-stacks projectsa and a big fan of what Flash platform offers.

    I find it hard to believe that you can obtain the same results with Vaadin than you get from Flash technologies. Yesterday I just found a great sample of waht Flash platform is getting to:

    http://gregsramblings.com/2011/02/23/imagine-this-new-3d-flash-technology-applied-to-enterprise/

    Maybe it is that you’r not getting the most of these technologies, but in my company we have a great creative and we’re getting fascinating and cool projects. Attitudes like that and a lot of Apple fanboys are hurting a lot to a great technology, not perfect, but great.

    Just another example of the importance of the Flash pltaform in the next era of multiple and so different devices:

    Greetings

    1. Talking about fanboys… If You read some other posts on this blog you can see that I’ve been a great Flash supporter along the years and I still believe it is much more adapted for apps than doc-based techs like HTML. But it’s precisely because I’m not the integrist you accuse me of being that I can also recognize the weaknesses of technologies I love. I’m a pragmatic guy and right now my main focus is to produce usable apps quickly. And until I can write groovy code for the Flash player, or use Actionscript for my backend, I’m exploring alternative solutions.

  2. Well, I didn’t pretend to be neither rude nor integrist. I admire your work a lot. I use Flex because I think it is the best technology for UIs at the moment. If tomorrow appears anything better, I will change without any doubt. But you can’t pretend that waht is a good technology for backend will be a perfect technology for UI’s too. That could be a little integrist. You want to marry one technology for everything. I use Flex, yeah, but I use to work with Java for the backend. Now I’m trying Grails too.

    Greetings!

  3. Interesting, but It fails whnen itry tu run it.

    Configuring Spring Security …
    Configuring Spring Security ACL …
    2011-02-25 11:13:35,896 [main] ERROR [localhost].[/addressbook] – Servlet /addr
    essbook threw load() exception
    java.lang.ClassNotFoundException: com.mycompany.MyVaadinApplication

    1. When you install the Vaadin plugin, it overwrites grails-app/conf/VaadinConfig.groovy. You need to edit this file and configure the qualified name of your application class there: applicationClass = “org.epseelon.addressbook.presentation.AddressBookApplication”

  4. Is there a way to catch ‘AccessDeniedException’ globally?
    So I wouldn’t have to write
    try {
    myService.securedAction
    } catch (Exception e) { AddressBookApplication.application.getMainWindow().showNotification(
    e.message,
    Notification.TYPE_ERROR_MESSAGE
    );

    every time I invoke the securedAction method?

  5. Nice snippet!

    DTO code can be tersed exploiting auto-binding (fortunately field names match).

    This:

    return new PersonListItem(
    firstName: p.firstName,
    lastName: p.lastName,
    email: p.email,
    phoneNumber: p.phoneNumber,
    streetAddress: p.streetAddress,
    postalCode: p.postalCode,
    city: p.city
    )

    can be done like that:

    return new PersonListItem(p)

    Is there a way to carry Grails domain class constraints over to Vaadin?

  6. Mea culpa!

    return new PersonListItem(p) is just faulty, i.e. plain nonsense, as Grails data binding only applies to domain classes. The code can still be made less verbose using Groovy meta class access:

    return new PersonListItem(p.properties.findAll { pi -> (PersonListItem.metaClass.properties*.name – [“class”,”metaClass”]).contains(pi.key) })

    In real life, the property name list should be changed to a Set and assigned to a static field in order to maintain acceptable performance:

    private static final Set PERSON_LIST_ITEM_PROPERTY_NAMES = (PersonListItem.metaClass.properties*.name – [“class”,”metaClass”]) as Set

    return new PersonListItem(p.properties.findAll { pi -> PERSON_LIST_ITEM_PROPERTY_NAMES.contains(pi.key) })

    Regards,
    Reiner

  7. Hy all of you,

    Thanks to the author I stopped loosing my hairs and nerves, so big thanks to you sebastien.

    I have a question relatively to the cast problem explained by Reiner Saddey.
    My questions :
    – Do you do this cast/binding in the PersonService?
    – It seems that you bind in one way only. What about creating a person directly from a personListItem?

    Thanks for your help

Leave a Reply to Florent THOMAS Cancel reply