Archive for the ‘grails real life development’ Category

Groovy XML back and forth

February 8, 2010

Groovy has convenient classes for working with XML. You can use the XmlParser (or XmlSlurper) if you want to parse existing XML into a tree structure. You can use the XmlBuilder, if you want to build XML from scratch. But what if you want to read existing XML, change it, and write it back again? It’s easy. You can use the XmlNodePrinter object for that:

def xmltree = new XmlParser.parseText("<node text='hello'>")
xmltree.@text = 'goodbye'
StringWriter writer = new StringWriter()
new XmlNodePrinter(new PrintWriter(writer)).print(xmltree)
writer.toString()
Advertisements

Security leak with grails acegi plugin annotations

January 26, 2010

The Spring Security Plugin offers a very easy way to secure URLs in your grails application. It works with users, roles and url patterns. Each user can be assigned a number of roles. Based on the roles a user has, access to URL patterns is granted or rejected by the Spring Security Plugin.

The documentation for the plugin describes three ways to specify the URL patterns that must be secured: by storing security mappings in the database, by storing them in a text file, or by defining annotations on controllers and actions.

Annotations seem to offer an attractive way to define security. But be warned. On grails 1.1.2 and the grails-acegi-plugin-0.5.2, I found a security leak using annotations. The security leak is caused by the way grails handles extensions on a URL.

Look at the following controller:

class TestController {
@Secured(['ROLE_ADMIN'])
    def index = { render text: "this page should be secured" }
}

If you surf to http://myserver:8080/myapp/test/index, you are presented a login screen, because the index controller is secured with @Secured([‘ROLE_ADMIN’]). This is the intended behaviour of the plugin. However, if I add “.html” to the URL, the whole login screen is bypassed. The content of the controller is shown without ever having to login. This is a major security issue, I would say.

The solution I chose, was to use text-based security. This way, you can prevent the above from happening, BUT YOU STILL HAVE TO BE CAREFUL. Do not forget to follow the instructions HERE, or otherwise you will still have the same problem.

Another way of solving the problem, is to disable content negotiation (which is enabled by default!). In Config.groovy, change

grails.mime.file.extensions = true

to

grails.mime.file.extensions = false

This is not a solution if you need to use content negotiation of course.

Struggling with REST in Grails

December 19, 2009

I’ve been trying to implement RESTful web services with Grails. Grails turned out to have some nifty features. But I also struggled a lot, and got frustrated too. I’ll tell you what I found out about content negotiation and mapping different HTTP methods. But first, a short recapitulation of RESTful services.

REST, a short recapitulation

REST is a lightweight way of implementing web services. It basically assumes that there are two important concepts for a web service:

  • Resources (data, documents, content)
  • Operations (reading, writing, deleting)

REST conveniently maps those two concepts on the corresponding concepts in the http protocol. Each resource is mapped on a URL.

http://mynaughtydomain.xxx/myapp/people/myself
would refer to a document (e.g. an html page, or a snippet of xml, or both) about “myself”.
http://mynaughtydomain.xxx/myapp/people
would refer to a list of all people known in myapp
http://mynaughtydomain.xxx/myapp/people/johnmccain/photographs
would refer to a list of all photographs of a certain person
http://mynaughtydomain.xxx/myapp/people/johnmccain/photographs/inatigersuit.jpg
would refer to a photograph you don’t really want to see.

Nothing special so far. The URLs have a tree structure. And a GET-request to a URL returns a web page. But there’s more.

A PUT-request to a URL sends information to the web application. The information is not just stored on a web server, but actually read and processed by the application. So, if I PUT an XML-document on http://mynaughtydomain.xxx/myapp/people/sarahpalin, not only mrs Palin will be astronged to mynaughtydomain. She will also receive a confirmation mail. And her credit card will be charged for $10000 too.

Luckily for her, she can also send a DELETE request. But that won’t give her her money back.

Content negotiation

URL mappings in Grails are defined in grails-app/conf/UrlMappings.groovy. The following pattern will provide a mapping for viewing photographs.

"/people/${person}/photographs/${photo}.jpg" {
    controller = "photo"
    action = "show"
}

Requests that match the pattern will be sent to the show action of the PhotoController class. ${person} and ${photo} can be received just as if they were normal http request parameters. Within PhotoController.action, we can refer to them with params.person and params.photo.

Now suppose that for some reason, I do not want to return a JPG-file, but an XML-file with information about the photograph. It would be easy to change the above code into

"/people/${person}/photographs/${photo}.xml" { // don't do this, it doesn't work!
    controller = "photo"
    action = "show"
}

The first URL pattern works. The second does not. Why?

Grails uses a technique called content negotiation, to return a resource in the format that is required by the client. Each http request has an accept header. The request header tells the server, what document formats it is allowed to send back. A browser request includes text/html and application/xml in the accept header. A client that only understands json, would only include the accept header application/json. This way, the server can send the same resource in different document formats. The same URL http://mynaughtysite.xxx/myapp/people will either send html or xml, based on the accept header. Or it will send an error, that it doesn’t know what the heck json is.

Unfortunately, browsers accept headers are fixed. Browsers will always prefer to receive xhtml or html. And there are a number of fixed second choices. So, in a browser, if I ask for http://mynaughtysite.xxx/myapp/people, I will always get the html version of the list and never the xml version. But Spring made a nifty feature to solve this. If you cannot use accept headers, you can append the URL with a format extension. So

http://mynaughtysite.xxx/myapp/people.html
will have the same effect as GETting http://mynaughtysite.xxx/myapp/people with text/html as the accept header
http://mynaughtysite.xxx/myapp/people.xml
will have the same effect as GETting http://mynaughtysite.xxx/myapp/people with application/xml as the accept header

grails-app/conf/Config.groovy contains the following list

grails.mime.types = [ html: ['text/html','application/xhtml+xml'],
                      xml: ['text/xml', 'application/xml'],
                      text: 'text/plain',
                      js: 'text/javascript',
                      rss: 'application/rss+xml',
                      atom: 'application/atom+xml',
                      css: 'text/css',
                      csv: 'text/csv',
                      all: '*/*',
                      json: ['application/json','text/json'],
                      form: 'application/x-www-form-urlencoded',
                      multipartForm: 'multipart/form-data'
]

html and xml are in there as mime types. That is why in the second mapping, we must NOT explicitly specify .xml. Spring’s content negotation will make sure that .xml and .html are mapped correctly. jpg is not in the list of mime types. That’s why the first mapping works as is.

To implement different formats in your controller action, you can inspect the value of request.format. Or, even nicer, you can use withFormat. The first format specified within withFormat is the default format. Note that instead of “html”, request.format may also have the value “form”, which means more or less the same.

HTTP methods

The two specified mappings, map ALL http requests to a single controller action. GET, POST, PUT and DELETE are all mapped to the same method. We can do a switch/case statement within the method. But that is evil. Instead, we can also change the mapping to this:

"/people" {
    controller = "person"
    action = [GET: "list"]
}

"/people/${person}" {
    controller = "person"
    action = [GET: "show", DELETE: "delete", PUT: "chargethebitch"]
}

Requests sent to the application will work as expected. However, the links generated by grails in your scaffolded pages WILL NOT!!!

Grails provides <g:link>, <g:actionSubmit> and <g:form> tags that reverse map names of controllers and actions to URLs. In the tags, you specify the controller and action you want to link to. At runtime, Grails replaces the controller/action-specification by the URL you specified in UrlMappings. Or at least that is what it should do.

If you use request method specifications in your mappings, forward mapping URLs to controller methods works just fine. But reverse mapping controller and action names back to a URL does not! Luckily, according to Graeme Rocher, it’s not a bug, it’s a feature!.

There are at least two ways you can work around this:

  • Use the request method mappings, but do not use the <g:link>, <g:actionSubmit> and <g:form> tags. Instead, use normal html <a> and <form> tags, and explicitly specify the URLs. Since you have thoughtfully considered your RESTful API, the URLs are logical, and are unlikely to change.
  • Do not use the request method mapping, but use a switch/case in the corresponding controller methods. This leads to ugly code.

Or of course, you can implement your own version of the three tags. Grails puts a spring bean grailsUrlMappingsHolder in the application context that might be useful.

Summary

Grails has some nifty features for implementing RESTful services, but it definitely has its rough edges too. Be aware of this, when you’re implementing REST.

Why belongsTo is important for validation

October 15, 2009

Grails domain classes often work together. Various one-to-one relations and one-to-many-relations may exist. On validate and save, you want to cascade as much as possible. In this article, we’ll show you how you can do that. As you’ll see, the most important thing is that you always add a belongsTo statement in the referenced class.

Validating one-to-many

Suppose you have a person, and a person can have one or more addresses. This is implemented in the following two domain classes:

class Person {
    static hasMany = [addresses: Address]
}
class Address {
    String street
    static constraints = {
        street nullable:false
    }
}

Cascading save

Now let’s create a person and give him an address. If we save the person, we want the address to be saved too, without explicitly having to specify that. This is expressed by the following integration test:

import grails.test.*

class PersonTests extends GrailsUnitTestCase {
    void testCascadingSave() {
        def personCount = Person.count()
        def addressCount = Address.count()
        def person = new Person()
        def address = new Address(street:"Weena")
        person.addToAddresses(address)
        assert person.validate()
        assert person.save()
        assert 1 == Person.count() - personCount
        assert 1 == Address.count() - addressCount
    }
}

Cascading validation

If you run the test, you’ll see that one-to-many relations are automatically cascaded on save. But what happens with validation? The street property of Address is not nullable. If I validate a person, does grails also automatically validate his or her addresses? Let’s test.

    void testCascadingValidate() {
        def personCount = Person.count()
        def addressCount = Address.count()
        def person = new Person()
        def address = new Address() // WRONG, empty street!
        person.addToAddresses(address)
        assert !person.validate()
    }

The test fails. Grails does not check if the address is valid. There is one important rule we have to remember:

The referenced class must have a belongsTo statement.

Add the following to the address class, and it works:

    static belongsTo = [person: Person]

This extra line adds a property person to the Address class. If you call person.addToAddresses(address), the person property of address is automatically set. However, the reverse is not true. If you set the person property of an address, the address is not automatically added to the person instance. Therefore, you must always use the addTo-method to add one-to-many-relations.

Validating one-to-one

Now, suppose a person can only have zero or one address. This is expressed in the domain class:

class Person {
    Address address
}

In the above tests, change

person.addToAddresses(address)

to

person.address = address

The two tests will still succeed. But, if we remove the belongsTo statement from the address class, both tests will fail. The belongsTo statement arranges two things:

  1. The address instance is saved automatically if the person object it
    belongs to is saved.
  2. The address instance is validated automatically if the person object it
    belongs to is validated.

So, we need the belongsTo statement for both one-to-many and many-to-many relations.

There is however one difference. With one-to-many relations, the person property of the address class was automatically set when calling addToAddresses. With a one-to-one-relation, the person property is NOT automatically set. Since this is very confusing, we’ll get rid of the property. Simply change the belongsTo statement to:

    static belongsTo = Person

The address instance is still saved and validated automatically, whenever its corresponding person is saved or validated. However, the address won’t have a person property anymore. In the one-to-one case, this is a good thing, since it didn’t have the proper value anyway. With one-to-many relations, you may choose yourself which variant of the belongsTo statement you use, depending if you need the extra person property.

Note that we wrote the above tests as integration tests. If we use mockDomain to mock the Person and Address classes, and run the tests as unit tests, they will both fail. The mockDomain method is quite useless if you want to mock collaberating classes.

Easier i18n of Spring error messages

August 4, 2009

When validating fields, Grails provides an easy way to validate complete error messages like “The property Last Name of User cannot be blank”. However, using a default message “The property {0} of {1} cannot be blank”, and providing translations for {0} = Last Name and {1} = User only, is not possible. In this post, we will show you how you can tweak Grails to give you this feature.

Grails i18n introduction

  • With Grails, you can easily put localisable messages in your view. Within a GSP, simply use the <g:message> tag:
    <g:message code="user.create" default="Create User" />

    When Grails encounters this tag, it looks for a code “user.create” in your grails-app/i18n/messages.properties. If Grails cannot find the code, it uses the value of the default argument.

  • By default, there are message.properties files for many languages. If you want to see a page in your application in another language, simply add “?lang=es” to the url. Replace “es” by any ISO language code for which you have provided a translation.
  • The standard scaffolded (and generated) templates of your application are not internationalised. You can replace the standard scaffolding (and generating) templates by your own versions, by simply putting them into src/templates/scaffolding. Writing templates is almost as much fun as writing Lisp macros! But wait, others have already done the work. Simply use the I18n Templates Plugin and you’re done.

Validation messages

  • Grails uses Spring validation for rendering error messages. The messages are looked up in the messages.properties file. There are default messages for all kinds of validation errors. For example:
    default.blank.message=Property [{0}] of class [{1}] cannot be blank
  • Spring automatically substitutes {0} by the property name and {1} by the class name. For example, the user would see the friendly message:
    Property [lastName] of class [com.acme.myfirstgrailsapp.security.User] cannot be blank.
  • It becomes even more user friendly when you translate it. Let’s say in Dutch:
    Attribuut [lastName] van entiteit [com.acme.myfirstgrailsapp.security.User] mag niet leeg zijn.

Translating lastName and com.acme.myfirstgrailsapp.security.User

  • Of course we do not want the user to see texts like “lastName” and “com.acme.myfirstgrailsapp.security.User”. “Last name” and “User” would be better options. Or in Dutch: “Achternaam” and “Gebruiker”.
  • Spring has a mechanism to overwrite the default message for specific classes and properties. If we add
    user.lastName.blank.error=Property last name of user cannot be blank

    Spring will render the above message if the last name of a user is blank. For all other properties that are left blank, Spring will fall back to the default message above.

  • If our application has 20 domain classes with 20 properties, we only have to supply 400 variants of the default message “Property [{0}] of class [{1}] cannot be blank”.
  • But wait, Spring does not only check for blank fields, but also for null fields, minimum values, maximum values, minimum size, maximum size, regex patterns… Each check has its own message. So, we do not only get 400 variants of the “blank” message, but also 400 variants of a null message, 400 variants of a minimum value message, 400 variants of a maximum value message, …

Making it easier

  • Spring enables us to modify and translate the message “Property [{0}] of class [{1} cannot be blank”, but it does not enable us to modify and translate the filled in values for {0} and {1}. Let’s tell Grails to do so.
  • Grails uses the <g:renderErrors> tag to render the above messages. This tag is implemented in the Grails class ValidationTagLib.
  • Filling in the values for {0} and {1} is done in the “message” closure in the ValidationTagLib class. We will provide an alternative implementation of this closure, in our own TagLib. First, generate the tag lib:
    grails create-tag-lib i18n-errors
  • We start by inheriting all default functionality from the ValidationTagLib class, by simply extending it. Also, we will provide a namespace i18m (short for I18n Messages) for the tag lib, so we can type <i18m:renderErrors>. The code of our newly created tag lib is now:
    import org.springframework.web.servlet.support.RequestContextUtils as RCU
    import org.codehaus.groovy.grails.plugins.web.taglib.ValidationTagLib
    import org.springframework.context.NoSuchMessageException
    
    class I18nErrorsTagLib extends ValidationTagLib {
    
      static namespace = "i18m"
      
    }
  • Now insert an adjusted version of the “message” closure. The closure is a copy from the original ValidationTagLib, with a few lines added.
      private String tryResolveMessage(messageSource, String code, locale) {
        try {
            messageSource.getMessage(code, new Object[0], locale) ?: null
        }
        catch (NoSuchMessageException e) {
          null
        }
      }
    
      private String abbreviateFullClassName(String classname) {
        def index = classname.lastIndexOf('.') + 1
        classname.substring(index, index + 1).toLowerCase() + classname.substring(index + 1)
      }
    
      def message = {attrs ->
        def messageSource = grailsAttributes.getApplicationContext().getBean("messageSource")
    
        def locale = RCU.getLocale(request)
        def text
    
        if (attrs['error']) {
          def error = attrs['error']
    
          // We adjusted the original "message" closure here.
          // Instead of just passing the error arguments, we try to resolve the
          // arguments in message.properties.
          def propname = error.arguments[0]
          def classname = abbreviateFullClassName(error.arguments[1].toString())
          error.arguments[0] = tryResolveMessage(messageSource, "${classname}.${propname}", locale) ?: error.arguments[0]
          error.arguments[1] = tryResolveMessage(messageSource, "${classname}", locale) ?: error.arguments[1]
    
          def message = messageSource.getMessage(error, locale)
          if (message) {
            text = message
          }
          else {
            text = error.code
          }
        }
        if (attrs['code']) {
          def code = attrs['code']
          def args = attrs['args']
          def defaultMessage = (attrs['default'] != null ? attrs['default'] : code)
    
          def message = messageSource.getMessage(code,
                  args == null ? null : args.toArray(),
                  defaultMessage,
                  locale)
          if (message != null) {
            text = message
          }
          else {
            text = defaultMessage
          }
        }
        if (text) {
          out << (attrs.encodeAs ? text."encodeAs${attrs.encodeAs}"() : text)
        }
      }

Making it work

  • Replace <g:renderErrors> by <i18m:renderErrors> wherever you wish to use the alternative error rendering.
  • If you placed your own scaffolding templates in src/templates/scaffolding (for example because you’re using the I18n Templates Plugin), you can do the replacement here.
  • Put names for the com.acme.myfirstgrailsapp.security.User class and its lastName property, in messages.properties:
    user=User
    user.lastName=Last Name
  • If you do not put a user.lastName.blank.error in your messages.properties, Grails will use the default message “Property [{0}] of class [{1}] cannot be blank”, with {0} = User and {1} = Last Name.
  • If you do not specify user and user.lastName in messages.properties, Grails will fall back to default behaviour (fully qualified class name and exact property name).
  • Optionally, you can still override specific messages for specific properties of specific classes. But you don’t have to.
    user.lastName.blank.error = Property Last Name of class User cannot be blank,
    unlike the First Name which you can leave out