Tải bản đầy đủ (.pdf) (58 trang)

The definitive guide to grails second edition - phần 7 docx

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (772.78 KB, 58 trang )

CHAPTER 13 ■ PLUGINS
391
can then provide additional named URLs of SVN repositories used for discovery and distribu-
tion. Listing 13-32 presents an example of configuring an additional plugin repository.
Listing 13-32. Configuring Additional Plugin Repositories
grails.plugin.repos.discovery.myRepository=""
grails.plugin.repos.distrubtion.myRepository=""
Notice in Listing 13-28 how Grails groups repositories under discovery and distribution.
The URLs under discovery are used by the list-plugins, install-plugin, and plug-info
commands discussed in the section on “Plugin Installation” to produce the plugin list that
is presented to the user. The URLs under distribution are used by the release-plugin com-
mand, as discussed in the previous section.
By default, the release-plugin command will always try to publish to the Grails central
repository. To tell the release-plugin command to publish to one of the repositories config-
ured as in Listing 13-32, you need to add the name of the repository as an argument to the
release-plugin command. For example:
$ grails release-plugin -repository=myRepository
And with that, we’ve reached the end of this tour of the plugin system. As you can imagine,
you can take advantage of the plugin system in many different ways. In this section, we’ve
touched on some ideas for plugins such as the simple-cache plugin and the Quartz plugin,
but we think the plugin system is such a critical part of the Grails ecosystem that the lessons
learned in this chapter should be put to further use. In the next section, you’ll be applying what
you’ve learned so far to create two new plugins for the gTunes application. Along the way,
you’ll discover how Grails’ plugins can be used as both a way to extend the functionality of an
existing application and as a way to effectively modularize your codebase.
Plugins in Action
So, you’ve learned what plugins are and the basics of creating plugins. It is now time to put that
knowledge to work by developing a couple of plugins for the gTunes application. The first one
you’re going to create is a plugin that makes the album art service and tag library you devel-
oped in Chapter 8 into a reusable plugin. This is a perfect example of developing a plugin to
add functionality and enhance behavior.


Plugins to Add Behavior
To start with, run the create-plugin command to create the basis of an album-art plugin:
$ grails create-plugin album-art
392
CHAPTER 13
■ PLUGINS
The next step is to move the AlbumArtService.groovy file and the AlbumArtTagLib.groovy
file into the newly created plugin project. Once this is done, your plugin should be structured
like Figure 13-3.
Figure 13-3. The structure of the album-art plugin
Of course, the AlbumArtService relies heavily on the Amazon web services library, so you
should move those from the application into the plugin too. Figure 13-4 shows the lib direc-
tory with the necessary JAR files in place.
Also, don’t forget to move the two tests that provide coverage for the AlbumArtService and
AlbumArtTagLib from the application into the plugin. As mentioned previously, the great thing
about plugins is that they can be developed and tested separately, which makes them useful for
larger projects with multiple developers. With the AlbumArtServiceTests and AlbumArtTagLibTests
test cases included in the album-art plugin, you can now immediately test whether your plugin is
working by running the test-app command:
$ grails test-app
CHAPTER 13 ■ PLUGINS
393
Figure 13-4. The album-art plugin’s dependencies
With the tests passing, you can add the plugin metadata to the plugin descriptor that
describes what this plugin is all about. Listing 13-33 shows the updated plugin descriptor with
the metadata provided.
Listing 13-33. Providing Metadata to the album-art Plugin
class AlbumArtGrailsPlugin {
def version = 0.1
def author = "Graeme Rocher"

def authorEmail = ""
def title = "Album art look-up plugin"
def description = 'A plug-in that provides facilities to look-up album art'

}
One thing to consider is that when you developed the AlbumArtService in Chapter 8, it was
designed to work in conjunction with an albumArtCache that used Ehcache provided by the
application’s grails-app/conf/spring/resources.groovy file. One solution to this would be to
update the doWithSpring of the AlbumArtGrailsPlugin descriptor, as shown in Listing 13-34.
394
CHAPTER 13
■ PLUGINS
Listing 13-34. Providing the albumArtCache with doWithSpring
class AlbumArtGrailsPlugin {
def version = 0.1

def doWithSpring = {
albumArtCache(org.springframework.cache.ehcache.EhCacheFactoryBean) {
timeToLive = 300
}
}
}
However, since you previously developed a simple-cache plugin earlier in the chapter, it
makes a lot more sense to take advantage of it. To do so, let’s modify the dependsOn property on
the album-art plugin descriptor, as shown in Listing 13-35.
Listing 13-35. Using dependsOn to Depend on the simple-cache Plugin
class AlbumArtGrailsPlugin {
def dependsOn = [simpleCache:'0.1 > *']

}

■Tip When specifying dependencies, you need to use bean conventions instead of the hyphen-separated,
lowercase name
simple-cache. The reason for this Grails design decision is that a hyphen isn’t valid in a
variable name or map key in Groovy unless you put quotes around it.
To enable the ability to continue to test the album-art plugin in isolation, you can install
the simple-cache plugin into the album-art plugin using the install-plugin command from
the root of the album-art plugin directory:
$ grails install-plugin /path/to/simple-cache/grails-simple-cache-0.1.zip
When you package the album-art plugin, Grails will not include the simple-cache plugin
within the album-art zip. It is your responsibility to ensure that when you install the album-art
plugin into the target application, you install the simple-cache plugin first. If you don’t, you will
get an error because Grails will be unable to resolve the album-art plugins’ dependency on
the simple-cache plugin, unless the simple-cache plugin is available in one of the configured
repositories.
Moving on, you now need to update the album-art plugin to use the CacheService provided
by the simple-cache plugin. Listing 13-36 shows the changes made to the AlbumArtService high-
lighted in bold.
CHAPTER 13 ■ PLUGINS
395
Listing 13-36. Updating the AlbumArtService to Use the simple-cache Plugin
class AlbumArtService {

def cacheService
String getAlbumArt(String artist, String album) {

def key = new AlbumArtKey(album:album, artist:artist)
return cacheService.cacheOrReturn(key) {
try {
def request = new ItemSearchRequest()


def response = client.itemSearch(request)
// get the URL to the amazon image (if one was returned).
return response.items[0].item[0].largeImage.URL
}
catch(Exception e) {
log.error "Problem calling Amazon: ${e.message}", e
return DEFAULT_ALBUM_ART_IMAGE
}
}

}
}
The changes in Listing 13-36 will cause the tests for the AlbumArtService to fail with a
NullPointerException because the cacheService is null within the context of the test. Instead
of using a real implementation in the unit test, you can use duck typing to specify a mock
implementation using Groovy’s Map literal syntax, as shown in Listing 13-37.
Listing 13-37. Mocking the cacheService
albumArtService.cacheService = [cacheOrReturn:{key, callable-> callable() }]
Groovy allows maps, where the value of a given key is a closure, to act as if they are callable
methods. In the example in Listing 13-37, by providing a cacheOrReturn key, you are able to
mock the methods of the CacheService.
To spice things up even further, you’re going to do a bit of metaprogramming, first by add-
ing a getAlbumArt method to all controllers and second by allowing instances of the Album class
from the gTunes application to retrieve their art simply by calling a getArt() method. The first
case, in Listing 13-38, shows the necessary code, which just gets the AlbumArtService instance
and adds a method to all controllers that delegates to the AlbumArtService.
396
CHAPTER 13
■ PLUGINS
Listing 13-38. Adding a getAlbumArt Method to All Controllers

class AlbumArtGrailsPlugin {

def doWithDynamicMethods = { ctx ->
def albumArtService = ctx.getBean("albumArtService")
application.controllerClasses
*.metaClass
*.getAlbumArt = { String artist, String album ->
return albumArtService.getAlbumArt(artist, album)
}
}
}
Adding a getArt() method to the Album class is a little trickier, because the plugin doesn’t
know anything about the Album class. So to implement this enhancement, you’ll search the
GrailsApplication instance for a domain class called Album and, if it exists, add the getArt()
method to it. Listing 13-39 shows the modifications to the doWithDynamicMethods plugin hook.
Listing 13-39. Adding a getAlbumArt Method to All Controllers
class AlbumArtGrailsPlugin {

def doWithDynamicMethods = { ctx ->

def albumClass = application.domainClasses.find { it.shortName == 'Album' }
if(albumClass) {
albumClass.metaClass.getArt ={->
albumArtService.getAlbumArt( delegate.artist?.name,
delegate.title)
}
}
}
}
Notice how within the body of the new getArt method you can use the closure delegate to

obtain the artist and title. The delegate property of a closure, when used in this context, is
equivalent to referring to this in a regular method. With the code in Listing 13-39 in place, you
can now obtain the URL to an Album instance’s album art with the code shown in Listing 13-40.
Listing 13-40. Using the getArt() Method to Obtain Album Art
def album = Album.get(10)
println "The art for this album is at ${album.art}"
Note that, in Groovy, methods that follow bean conventions are accessible via the prop-
erty access notation, so the expression album.art is equivalent to album.getArt(). And with
that, you have completed the album-art plugin that can now be installed into any application
CHAPTER 13 ■ PLUGINS
397
that has a requirement to look up album art. The gTunes application is one such application.
However, before you can install the album-art plugin, you need to install the simple-cache plu-
gin that the album-art plugin is dependent on into the gTunes application:
$ grails install-plugin /simple-cache/grails-simple-cache-0.1.zip
With that done, install the album-art plugin next:
$ grails install-plugin /simple-cache/grails-album-art-0.1.zip
Now you can start up the gTunes application, and it will behave exactly as before, except it
is utilizing the album-art plugin’s functionality instead! One thing to note about the album-art
plugin is that although it provides new functionality in the form of services, tag libraries, and
new methods, it does not comprise an entire self-contained application. We’ll be looking at
how you can achieve this in the next section.
Plugins for Application Modularity
As well as making it possible to extend the available APIs within a Grails application, plugins
can also provide entire modules of application functionality. Many newcomers dismiss plugins
as purely for plugin developers who are willing to jump into the core Grails APIs, but in fact,
plugins are an extremely effective way to modularize your application. In this section, we’ll
explain how you can create an entire application as a plugin that can be installed into the
gTunes application.
To keep things simple, you’ll tackle a very commonly demonstrated application in screen-

casts and presentations around Grails: the blog. Yes, as with any self-respecting modern Web
2.0 application, the gTunes application needs a blog where the proprietors of the gTunes store
can make big announcements about new music, events, and so on. Luckily, a simple blog takes
about five minutes to implement in Grails, so it shouldn’t be too complicated.
The first step is to run the create-plugin command to create the blog plugin:
$ grails create-plugin blog
This will create the blog plugin and associated BlogGrailsPlugin descriptor. You can
populate the descriptor with some plugin metadata; Listing 13-41 shows a sample blog plugin
descriptor.
Listing 13-41. Adding Metadata to the blog Plugin
class BlogGrailsPlugin {
def version = 0.1
def author = "Graeme Rocher"
def authorEmail = ""
def title = "A blogging plugin"
def description = 'A plugin that provides a blog facility'
}
Now it’s time to create a domain class that models a blog post:
$ grails create-domain-class com.g2one.blog.Post
398
CHAPTER 13
■ PLUGINS
After these two commands are complete, you should have a directory structure similar to
that pictured in Figure 13-5.
Figure 13-5. The Post domain class
Thinking about the Post domain class for a moment, it’s going to have the obvious things
like a title and a body, as well as a date posted. Putting this into practice, Listing 13-42 shows
the Post domain class containing the necessary properties.
Listing 13-42. The Post Domain Class
package com.g2one.blog

class Post {
String title
String body
Date dateCreated
Date lastUpdated
static constraints = {
title blank:false
body type:"text", blank:false
}
}
CHAPTER 13 ■ PLUGINS
399
Note that the Post domain class is using the property names dateCreated and lastUpdated to
take advantage of Grails’ auto time stamping capabilities that were first discussed in Chapter 10.
With an appropriate domain class in place, to help you get started, you can use scaffolding to
quickly generate a controller and views for the Post domain class:
$ grails generate-all com.g2one.blog.Post
For this first revision of the blog plugin, you’re going to support the creation of new entries
only; hence, you can remove the generated edit, update, and delete actions. In addition, you
need to show only the first five posts; therefore, you can use the max parameter to the static list
method of the Post class to specify that. Listing 13-43 shows the full code for the PostController.
Listing 13-43. The PostController for the blog Plugin
package com.g2one.blog
class PostController {
def index = { redirect(action:list,params:params) }
def allowedMethods = [save:'POST']
def list = {
[ postList: Post.list( max:5) ]
}
def create = {

[post: new Post(params) ]
}
def save = {
def post = new Post(params)
if(!post.hasErrors() && post.save()) {
flash.message = "Post ${post.id} created"
redirect(action:list)
}
else {
render(view:'create',model:[post:post])
}
}
}
Now let’s move onto the views. In the case of the blog plugin, the list.gsp view is the most
important because it will be responsible for showing each blog entry. However, Grails’ default
scaffolding displays the list view as a table, which is not very useful in this case. You can correct
that by modifying the list.gsp view to render a _post.gsp template instead. Listing 13-44
shows the updated list.gsp code.
400
CHAPTER 13
■ PLUGINS
Listing 13-44. The blog Plugin’s list.gsp View
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<meta name="layout" content="${params.layout ?: 'main'}" />
<title>Post List</title>
</head>
<body>
<div class="nav">

<span class="menuButton">
<g:link class="create" action="create">New Post</g:link>
</span>
</div>
<div class="blog">
<h1>${grailsApplication.config.blog.title ?: 'No Title'}</h1>
<g:render plugin="blog"
template="post"
var="post"
collection="${postList?.reverse()}" />
</div>
</body>
</html>
There are a few key things to mention about the list.gsp view in Listing 13-44. First,
note that when using the <g:render> tag to render a template in a plugin view, you must
specify the plugin that this template belongs to; otherwise, Grails will attempt to resolve
the template within the application it is installed into. Second, take note of the usage of the
grailsApplication variable to specify the blog title:
<h1>${grailsApplication.config.blog.title ?: 'No Title'}</h1>
Here the implicit grailsApplication object is used to read a configuration setting
from the grails-app/conf/Config.groovy file. If the setting called blog.title is specified
in Config.groovy, then the view will use that. Hence, users of this plugin are able to configure
the blog to their needs. An alternative approach to doing this would be to use the <g:message>
tag, in which case the plugin user has to specify the message in the grails-app/i18n/
messages.properties file. The choice is up to you.
Finally, take note of the HTML <meta> tag that dictates what layout the list.gsp uses:
<meta name="layout" content="${params.layout ?: 'main'}" />
CHAPTER 13 ■ PLUGINS
401
What this does is if there is a layout parameter within the params object, it will use

that for the layout; otherwise, use the main layout. The main layout will, of course, resolve
to grails-app/views/layouts/main.gsp, but why the decision to allow customization via a
parameter? The idea here is that the user of the plugin can very easily customize the layout of
the blog through URL mappings. For example, consider the URL mapping in Listing 13-45.
Listing 13-45. Using a URL Mapping to Customize the blog Plugin’s Layout
"/blog"(controller:"post", action:"list") {
layout = "funky"
}
If you add the URL mapping in Listing 13-45 to your grails-app/conf/UrlMappings.groovy
file, users can go to the /blog URL and have the list action of the PostController execute, which
in turn renders the list.gsp view. However, notice how a property called layout is set inside the
body of the closure passed to the URL mapping definition. As you learned in Chapter 6, it is
possible to pass parameters in this way. The result is that for the /blog mapping, a layout called
grails-app/views/layouts/funky.gsp will be used instead! This is a pretty powerful pattern
because it allows you to apply a different layout simply by applying a new URL mapping to the
same controller and action.
As for the _post.gsp template used in the <g:render> method of Listing 13-44, it is
pretty simple and just formats each Post instance appropriately. You can see the code for
the _post.gsp template in Listing 13-46.
Listing 13-46. The _post.gsp Template
<div id="post${post.id}" class="blogPost">
<h2>${post.title}</h2>
<div class="body">
${post.body}
</div>
<div class="desc">
Posted on <g:formatDate date="${post.dateCreated}"
format="dd MMMMMM yy" />
</div>
</div>

And with that, you have pretty much completed the list.gsp view. Figure 13-6 shows
what the list.gsp view looks like when you run the blog plugin and head off to the list action
of the PostController.
402
CHAPTER 13
■ PLUGINS
Figure 13-6. The list view of the blog plugin
Since the view renders each Post directly in the list.gsp view, the show.gsp view has been
made redundant and can be deleted. Also, for the first revision, you’re interesting in creating
new posts only, so edit.gsp can be deleted too—you can always add editing later!
Moving on to the create.gsp view, it too could use a little cleaning up. Also, it would be
nice to provide a rich text–editing capability for authoring the post. One of the plugins available
for Grails is the fckeditor plugin, which adds support for FCKeditor (editor.
net/), a rich text–editing component. To install the fckeditor plugin into the blog plugin, run
the following command:
$ grails install-plugin fckeditor
In addition to this, you need to update the BlogGrailsPlugin descriptor and add a
dependsOn setting to ensure that when others install the blog plugin, FCKeditor is resolved
too. Listing 13-47 shows the dependsOn set appropriately.
Listing 13-47. Making the blog Plugin Depend on the fckeditor Plugin
class BlogGrailsPlugin {
def dependsOn = [fckeditor:'0.8 > *']

}
With that done, let’s enable FCKeditor in create-gsp by using the <fck:editor> tag pro-
vided by the fckeditor plugin. Listing 13-48 shows the updated create.gsp file with the usage
of the <fck:editor> tag highlighted in bold. You will notice the logical name printed when you
ran the blog plugin with grails run-app. Grails prints out a message such as this:
Loading with installed plug-ins: ["fckeditor", "blog"]
CHAPTER 13 ■ PLUGINS

403
Listing 13-48. Using the fckeditor to Enable Rich Text Editing
<html>

<body>
<h1>Create Post</h1>
<g:if test="${flash.message}">
<div class="message">${flash.message}</div>
</g:if>
<g:hasErrors bean="${post}">
<div class="errors">
<g:renderErrors bean="${post}" as="list" />
</div>
</g:hasErrors>
<g:form action="save" method="post" >
<div class="dialog">
<div id="titleField">
<label for="title">Title:</label>
<g:textField name="title"
value="${fieldValue(bean:post,field:'title')}"/>
</div>
<div id="bodyField">
<fck:editor name="body"
width="500"
height="300"
toolbar="Basic">
${fieldValue(bean:post,field:'body')}
</fck:editor>
</div>
</div>

<div class="buttons">
<span class="button">
<input class="save" type="submit" value="Post" />
</span>
</div>
</g:form>
</body>
</html>
Using the toolbar attribute of the <fck:editor> tag, you can specify that you want only a
simple toolbar with basic formatting options; otherwise, you’ll get a toolbar with almost as
many options as a word processor like Microsoft Word. Figure 13-7 shows the create.gsp view
with the <fck:editor> tag doing the job of rendering a rich text–editing component.
404
CHAPTER 13
■ PLUGINS
Figure 13-7. Creating a post with FCKeditor
Of course, both the list.gsp and create.gsp pages currently look rather uninspiring, but
it is up to the application you install the blog plugin into to provide useful style information via
CSS. Speaking of installing the blog plugin into an application, it is time to do exactly that! First
package up the blog plugin by running the package-plugin command:
$ grails package-plugin
Then navigate to the gTunes application, and use install-plugin to install the blog
plugin:
$ grails install-plugin /blog/grails-blog-0.1.zip
Note how, in this case, since the FCKeditor plugin exists in the Grails central repository,
the install-plugin command will automatically resolve the dependency. Now it would be
useful to configure the blog’s title using the grails-app/conf/Config.groovy file. Remember,
the blog.title setting allows you to customize the blog title; simply adding the following set-
ting to Config.groovy will do the trick:
// configuration for the blog

blog.title="The gTunes Weblog"
Run the gTunes application using the run-app command, and then navigate to the URL
http://localhost:8080/gTunes/post/list. Like magic, you have the blog plugin running
inside the gTunes application exactly as it was before—except that it is now taking advantage
of the gTunes application’s main layout. Clicking the “New Post” button will take you to the
create.gsp view you developed earlier. Figure 13-8 shows the FCKeditor component running
within the gTunes application.
CHAPTER 13 ■ PLUGINS
405
Figure 13-8. Creating blog posts in the gTunes application
If you type some content, including a title and body, and then hit the “Post” button, you’re
able to create new posts on the gTunes application blog, as shown in Figure 13-9.
Figure 13-9. A blog post in the gTunes application
406
CHAPTER 13
■ PLUGINS
Clearly, this is a very basic blog plugin at the moment with no support for RSS, comments,
calendars, archives, and all that jazz. However, as a demonstration of the concept of using plu-
gins to separate your application in reusable modules, it’s a perfect example. A separate team
of developers could happily work on the blog plugin and gradually integrate its functionality
into the primary application over time. You could even create an automated build, as you
learned in Chapter 12, to build and test all your plugins and install them into your main appli-
cation for integrating testing. So, plugins are definitely worth a look, even if you don’t intend to
become an expert on Grails internals.
Summary
In this chapter, we hope you have learned the power of the Grails plugin system not just for
plugins that provide API enhancements but equally for use cases that provide fully functional
application modules like you saw in the previous section. Plugin development is a very broad
topic, and this chapter only brushed the surface of what is possible; however, this chapter has
given you enough knowledge to investigate developing your own plugins.

From the basics of creating and populating plugin metadata to the intricacies of develop-
ing the plugin itself and finally to the packaging and distribution of your plugins, this chapter
has covered a lot of ground. As you have seen, Grails provides a broad set of functionality out
of the box that can be extended without limits through its plugin system.
One thing you will have noticed during the development of the blog plugin in the previous
section is that at the moment it allows pretty much anyone to post. Clearly, this is not desirable
in the long term, so in the next chapter, we’ll cover how you can refactor the simple security
implementation in the gTunes application into one of the more fully featured security plugins
that are available. Role-based security, here we come!
407
■ ■ ■
CHAPTER 14
Security
Security is a broad topic that is applicable across multiple layers of your application. From
the view layer to the database, making your application immune to the various forms of attack
is a nontrivial task. Scary things like cross-site scripting (XSS) and SQL injection attacks require
careful attention when building your application. As well as covering techniques that help
avoid such attacks, in this chapter we’ll cover how you can secure your application through
authentication and authorization.
Authentication refers to the act of establishing a client’s identity. The ubiquitous login
form is typically used to establish identity in web applications. Authorization, on the other
hand, is about granting a client specific rights (often referred to as privileges or permissions).
Of course, there is no point in reinventing the wheel, so we’ll cover how you can use one of
the security frameworks already available to implement a more generic solution for authenti-
cation and authorization.
Securing Against Attacks
Hacking Internet sites has become a challenge for not just malicious individuals but also for
security firms that research potential holes in an application’s makeup. The more media cov-
erage an application has, the more likely it is subject to such attacks. Banks and large Internet
sites are at particular risk.

When developing an application, you should pay careful attention to the security
requirements. Is it exposed to the outside world, or is it an intranet application? What are
the implications of a breach? An application with heightened security requirements will take
longer to develop and require more user acceptance testing and probing.
As for Grails, some vulnerabilities are completely beyond its control. No matter how
cautious you are, Grails won’t save you if there is a vulnerability at the operating system or
web server level. Having said that, Grails does provide you with the tools to implement appli-
cation-layer security, but ultimately it is up to you to keep security at the forefront of your
mind. Unit and functional testing can help you spot problems in this area. Your application
can be breached in many ways. In the next few sections, we’ll cover some of those ways and
how you can help avoid any issues occurring in the first place.
SQL or HQL Injection
One way to launch a Denial of Service (DoS) attack is to use SQL or HQL injection. Essentially,
if you use HQL that is built up from values obtained from request parameters, it is possible for
408
CHAPTER 14
■ SECURITY
an attacker to modify the incoming parameters to give the HQL a different meaning. This may
cause invalid data to be returned from the HQL query or, worse still, data held in the database
to be removed or changed! To illustrate the problem, consider the code in Listing 14-1.
Listing 14-1. An Action Vulnerable to HQL Injection
def search = {
Album.findAll("from Album as a where a.title='"+ params.title +"'")
}
With the code in Listing 14-1, an attacker could pass a value as the title parameter that
could compromise the query and lead to a DoS attack. For example, say the attacker decided to
send a request parameter with the following value:
' or a.title not null
This would result in the following HQL query:
from Album as a where a.title='' or a.title not null

The result is that instead of returning only a few records, the query could return thou-
sands or millions of records, causing a potential OutOfMemoryError. Worse still, if the attacker
initiates 10,000 requests using the same parameters, you could get threads blocking while
these long-running queries execute. With no threads left in the pool, your server will become
unresponsive, and the hacker will have successfully completed a DoS attack.
Of course, this phenomenon is not specific to Grails; any application that builds HQL or
SQL up dynamically comes up against it. So, how do you prevent such an attack? The secret
is never, ever to build up queries from String values, as you saw in Listing 14-1. Instead, use
either named or ordinal parameters for the query or, even better, criteria queries. Listing 14-2
shows four possible alternatives to the query from Listing 14-1.
Listing 14-2. Alternatives That Avoid HQL Injection
// using ordinal parameters
Album.findAll("from Album as a where a.title = ?", [params.title])
// using named parameters
Album.findAll("from Album as a where a.title = :title", [title:params.title])
// using criteria
Album.withCriteria {
eq('title', params.title)
}
// using a dynamic finder
Album.findAllByTitle(params.title)
CHAPTER 14 ■ SECURITY
409
In all the examples from Listing 14-2, Hibernate will automatically deal with escaping the
values passed into the query, making it impossible to execute an HQL injection attack. In the next
section, we’ll show another potential avenue for attack that is specific to Groovy and Grails—
Groovy injection.
Groovy Injection
HQL injection vulnerabilities are dangerous for sure, but the unguarded parsing of Groovy
scripts from user input could be even more harmful. Called Groovy injection, this involves

accepting input from a user that is then executed as a Groovy script. Listing 14-3 shows an
example of this technique.
Listing 14-3. Groovy Injection
def execute = {
new GroovyShell().evaluate(params.script)
}
Writing code like that shown in Listing 14-3 is, to be blunt, not the smartest thing to do.
Bringing the whole container down is a simple matter of sending a parameter with the follow-
ing value:
System.exit(1)
Or worse, the user could send code that modifies key system files, corrupting the operating
system. The GroovyShell class places no restrictions on what code the user is able to run.
Generally, as is the case with other dynamic languages such as Ruby and JavaScript, it is not
advisable to dynamically evaluate user input in this manner. If you really must have this func-
tionality, then you need to make sure the GroovyShell instance is set up with the appropriate
Java security permissions. The Groovy website has good documentation on how to achieve this
at />Cross-Site Scripting (XSS)
XSS attacks are probably the most well known but least understood security exploit. The tech-
nique involves injecting JavaScript written by the attacker into the page. An attacker able to
control the JavaScript on your site is an incredibly dangerous scenario. She could do all man-
ner of things, from stealing a user’s cookie to changing a login form so that it sends requests to
another server that captures usernames and passwords.
XSS attacks are amazingly common; the site xssed.com even keeps an up-to-date list of
the latest known vulnerabilities in major public sites. You’ll notice many prominent industry
names there; as you can see, even some of the most well-known companies in the software
industry make mistakes. The main reason XSS attacks are so common is that they are very hard
to test for. Automated testing in most cases is insufficient to trace every potential XSS problem.
410
CHAPTER 14
■ SECURITY

In fact, the current implementation of the gTunes application already has an XSS vulnerability
that we left in there on purpose (honest!). To reproduce it, try the following:
1. Click the “Signup now” link to load the register form.
2. Enter a valid login, password, email, and last name.
3. For the “First Name” field, enter the text <script type="text/javascript">alert
('hello')</script>.
4. Click the “Register” button.
Figure 14-1 shows the form populated with the data from these steps.
Figure 14-1. Entering malicious data into the registration form
When you click the “Register” button, you’ll see an alert box pop up with the message
“hello.” The JavaScript you entered into the “First Name” field has been executed! The gTunes
application is currently vulnerable to an XSS attack. Figure 14-2 shows an example of the mes-
sage box appearing in Firefox.
Figure 14-2. An XSS vulnerability in action
CHAPTER 14 ■ SECURITY
411
But why? The reason for the vulnerability lies in the grails-app/views/user/
_welcomeMessage.gsp template. If you look at the code for the template, it has the
following snippet of HTML:
Welcome back <span id="userFirstName">${session?.user?.firstName}!</span><br><br>
Using the GSP expression syntax ${ } on the first name simply dumps out the value;
there is no HTML escaping happening here. So, what is the solution? A robust and future-
proof solution would be to make all ${ } expressions HTML escaped by default using the
grails.views.default.codec setting in grails-app/conf/Config.groovy:
grails.views.default.codec="html"
By setting the default codec Grails uses to encode data in GSP views to HTML, you can
ensure all GSP expressions are HTML escaped by default. The downside of this approach is that
if you’re using GSPs to produce any format other than HTML, such as JSON or raw text, then
this may be problematic since the setting is global. An alternative is to use the defaultCodec
page directive to enable HTML escaping on a page-by-page basis:

<%@ defaultCodec="html" %>
By inserting the previous line of code at the top of a GSP, you can enable escaping all
expressions for only the current page. Finally, you can also use the encodeAsHTML() method
provided by Grails to explicitly encode the data, as shown in Listing 14-4.
Listing 14-4. Using encodeAsHTML to HTML Escape a Value
Welcome back
<span id="userFirstName">${session?.user?.firstName?.encodeAsHTML()}!</span><br><br>
Another important thing to note is that Grails’ built-in form tags, such as <g:textField>,
automatically use the encodeAsHTML() method for you. So, you need to be concerned only when
the data is being used outside of Grails’ built-in tags.
XSS and URL Escaping
In the previous section, you saw how a user can launch an XSS exploit if you don’t correctly
encode data as HTML by calling the encodeAsHTML() method. However, when creating URLs pro-
grammatically from user input, it is equally important to URL encode the data used to make up a
link. If you’re using Grails’ built-in <g:link> tag and all the other built-in tags that use URLs, then
you don’t have to worry. Grails will ensure all the data is appropriately URL encoded.
However, if you decide to bypass the built-in tags and do your own link creation, maybe
through a tag library, then it is critical you URL escape the programmatically created links.
Listing 14-5 shows an example of a potentially vulnerable link.
Listing 14-5. A Vulnerable Link
<a href="/gTunes/albums?title=${params.title}">Show Album</a>
412
CHAPTER 14
■ SECURITY
Simply by fiddling with the title parameter in a GET request an attacker could perform an
XSS attack. To avoid this problem, you can call the encodeAsURL() method on any data to be
included in the URL. Listing 14-6 shows an example of this.
Listing 14-6. Escaping URLs
<a href="/gTunes/albums?title=${params.title?.encodeAsURL()}">Show Album</a>
You’ll be learning more about the encodeAsHTML() and encodeAsURL() methods in the sec-

tion “Using Dynamic Codecs.” For now, let’s stay on the topic of vulnerabilities with a further
look into DoS attacks.
Denial of Service (DoS)
You’ve already seen how HQL injection can be used to cause a DoS attack and bring your sys-
tem down. However, there are other ways you can be vulnerable to a DoS attack even if you
avoid using String concatenation to build queries. One of the most common ways is through
pagination. As you’ll recall, GORM methods like list and the dynamic finders accept parame-
ters such as offset and max that allow you to paginate through the records available in the
database. Listing 14-7 presents an example of a simple list action that does this.
Listing 14-7. Listing All Albums
def list = {
if(!params.max) params.max = 10
[albumList: Album.list(params)]
}
As innocent as it may seem, the code in Listing 14-7 is vulnerable to a DoS attack. The
reason is that the code doesn’t set the maximum value of the max argument. An attacker could
pass a max value of 1000000, and you could end up with a million records loading and the same
OutOfMemoryError and thread blocking issues we mentioned earlier. Ouch!
A better solution is to ensure that you constrain the value of the max parameter passed to
a query to not exceed a specific value. Listing 14-8 shows an example implementation that
ensures the max parameter can only ever reach 100.
Listing 14-8. Constraining the Maximum Value for Pagination
def list = {
params.max = Math.min( params.max?.toInteger() ?: 0, 100)
[albumList: Album.list(params)]
}
As you can see from the code in Listing 14-8, you can use the Math.min method to get a safe
maximum value to use when paginating data. We’re not done with potential vulnerabilities
just yet, though. In the next section, you’ll look at one that affects data binding.
CHAPTER 14 ■ SECURITY

413
Batch Data Binding Vulnerability
Many web frameworks, including Grails, allow you to bind the data of incoming request
parameters to objects. In the case of Grails, these are typically domain instances. Data binding
was covered in depth in Chapter 4, but just as a reminder, with Grails it can be done with the
following constructor:
def album = new Album(params)
or alternatively using the properties property of an existing domain instance:
def album = Album.get(params.id)
album.properties = params
In many scenarios, this is not a problem, because a trusted source may be performing the
update. However, in some cases, using this technique can be undesirable. Consider, for exam-
ple, a scenario where you used a simple flag on a User domain class to signify whether the User
is an administrator:
class User {

boolean administrator
}
Administrators have far-reaching powers over the system that only a select few are allowed
to have. To set the scene further, say you had a profile page where a user can change her pass-
word, phone number, and various personal details. Listing 14-9 shows the server-side code to
update the User instance.
Listing 14-9. Vulnerable Controller Action
def update = {
def user = User.get(params.id)
user.properties = params
if(user.save()) {
redirect(action:"profile", id:user.id)
}


}
The form that sends the request to the update action in Listing 14-9 has fields that only the
User is allowed to edit. However, a particularly malicious individual could spoof a request so
that it sent a parameter called administrator with a value of true. The result would be the User
gaining newfound powers and, potentially, compromising your system.
In this scenario, you should make sure you are explicit about what properties can be
updated. Listing 14-10 shows a corrected version of the code in Listing 14-9 that uses the sub-
script operator on the properties property to specify which properties are subject to data
binding.
414
CHAPTER 14
■ SECURITY
Listing 14-10. Correcting the Data Binding Vulnerability
def update = {
def user = User.get(params.id)
user.properties['firstName', 'lastName', 'phoneNumber','password'] = params
if(user.save()) {
redirect(action:"profile", id:user.id)
}

}
The key message with all these attacks is to make sure that when you accept input from the
user, you are aware of the risks of doing so. Grails provides you with all the tools necessary to
avoid attacks but will not magically save you from writing vulnerable code. So far in this chap-
ter, you’ve seen the use of encodeAsURL() and encodeAsHTML(); in the next section, we’ll cover
how these methods came about and how you can add your own custom versions.
Using Dynamic Codecs
Throughout the course of the chapter so far, you’ve seen examples of the encodeAsHTML() and
encodeAsURL() methods. These methods didn’t magically appear out of nowhere; codec classes
that ship with Grails provide them. For example, the encodeAsHTML() method is implemented

in Grails as shown in Listing 14-11.
Listing 14-11. An Example Codec Class
import org.springframework.web.util.HtmlUtils
class HTMLCodec {
static encode( theTarget ) {
HtmlUtils.htmlEscape(theTarget?.toString())
}
static decode( theTarget ) {
HtmlUtils.htmlUnescape(theTarget?.toString())
}
}
Essentially, a codec class is one that ends with the convention Codec and includes encode
and/or decode methods. Grails will automatically create encodeAsHTML() and decodeHTML() meth-
ods that delegate to the HTMLCodec class in Listing 14-11 at runtime. The interesting thing is that
you can provide your own custom codecs. For example, say you wanted to provide the ability
to encrypt data using the Blowfish encryption algorithm that is part of the Java Cryptography
Extension (JCE) provided by Sun at
Thanks to custom codecs, this is pretty easy: all you need to do is create a new codec class in
the grails-app/utils directory called BlowfishCodec.groovy and populate it with the code
in Listing 14-12.
CHAPTER 14 ■ SECURITY
415
Listing 14-12. A Blowfish Encryption Codec Class
import org.codehaus.groovy.grails.commons.ConfigurationHolder as CH
import java.security.*;
import javax.crypto.*;
import javax.crypto.spec.*;
class BlowfishCodec {
static encode(target) {
def cipher = getCipher(Cipher.ENCRYPT_MODE)

return cipher.doFinal(target.bytes).encodeBase64()
}
static decode(target) {
def cipher = getCipher(Cipher.DECRYPT_MODE)
return new String(cipher.doFinal(target.decodeBase64()))
}
private static getCipher(mode) {
def keySpec = new PBEKeySpec(getPassword())
def cipher = Cipher.getInstance("Blowfish")
def keyFactory = SecretKeyFactory.getInstance("Blowfish")
cipher.init(mode, keyFactory.generateSecret(keySpec))
}
private static getPassword() { CH.config.secret.key.toCharArray() }
}
The BlowfishCodec implementation shown in Listing 14-12 uses the Java cryptography
APIs to construct a Cipher using a password set in grails-app/conf/Config.groovy. The
method getPassword() inspects the config object provided by importing the org.codehaus.
groovy.grails.commons.ConfigurationHolder class:
private static getPassword() { CH.config.secret.key.toCharArray() }
The getCipher(mode) then uses the getPassword() method to construct an instance of the
javax.crypto.spec.PBEKeySpec class that is used for password-based encryption. A javax.
crypto.Cipher instance is then obtained using the Blowfish algorithm and initialized using the
appropriate mode:
private static getCipher(mode) {
def keySpec = new PBEKeySpec(getPassword())
def cipher = Cipher.getInstance("Blowfish")
def keyFactory = SecretKeyFactory.getInstance("Blowfish")
cipher.init(mode, keyFactory.generateSecret(keySpec))
}
Finally, the encode and decode closures then use the cipher to encrypt and decrypt the

necessary bytes. Notice how this codec is actually using the Base64Codec built into Grails to

×