Protecting Parameters in Groovy/Grails

Section 11.2 of the Grails Framework Reference Docs talks about how to protect parameters in a Groovy/Grails app. On my current project, on public facing pages, we’ve been obscuring ids using the base64 codec that comes with grails. Here is a quick example:


def encodedString = "test".encodeAsBase64()

println encodedString

//build your decoded string from the byte array returned from the decode method.
def decodedString = new String(encodedString.decodeBase64())

println decodedString

Obscure ids and keep those urls hard to guess!

Advertisements

Shiro/Grails Tips

The Shiro plugin page in the Grails plugin repository has great information. Here are a couple of additional items I picked up during an implementation on my current project:

1. Filter every action except ‘x’ on a given controller

	    myFilter(uri: '/myController/**') {
	      before = {
	        if (!controllerName || actionName == "anOpenAction" || actionName == "anotherOpenAction") return true

	        // Access control by convention.
	        if (!isErrorPage(controllerName, actionName)) {
	          accessControl()
	        }
	      }
	    }

In this case, we’re taking advantage of common properties in grails. Basically, we’re filtering actions on myController. The first ‘if’ clause (!controllerName) filters for direct/default controller views, ignoring direct views. The other clauses are saying ‘if we’ve hit this filter, but the actionName is ‘anOpenAction’ or ‘anotherOpenAction’, let the request through.

2. Simple landing pages – enhancing the ‘free’ Shiro AuthController

If there is no target URI on the user’s original request to login, meaning, if they weren’t challenged and instead clicked on a ‘login’ link, a simple way to control where they are directed (assuming the goal is not to direct them to ‘/’) is as simple as this (with source from the AuthController):

	// If the user came to the login page via redirect (security filter caught an attempt to
	            // go to a restricted area of the site), then send them back from whence they came.
		        def savedRequest = WebUtils.getSavedRequest(request)
		        if (savedRequest) {
		            targetUri = savedRequest.requestURI - request.contextPath
		            if (savedRequest.queryString) targetUri = targetUri + '?' + savedRequest.queryString
		            println "Target URI, from saved request: ${targetUri}"
		        }
		        else {
		            // If a controller redirected to this page, redirect back
			        // to it. Otherwise redirect to an appropriate URI depending on the
		            // role of the user who just logged in.
		        	if(params.targetUri) {
		        		targetUri = params.targetUri
		        	}
		        	else {
		        		targetUri = //some bit of code that determine the URI from the current user, etc.
		        	}
		        }

Where that last reference of ‘targetUri’ is somehow set to where you want your newly-authenticated user to land.

Strange Days, Indeed

On my current project, I was adding a closure to a taglib that displayed a link conditionally, based on the current logged-in user’s role. The taglib is referenced on every page of the application, as it is included in the main Sitemesh layout. For the purpose of this example, a user cannot have both of the roles mentioned below.

Originally, the code looked something like this:

	def user = User.findByUsername(SecurityUtils?.getSubject()?.getPrincipal())
	def roles = user?.roles
	roles.each { role->
		if(role.name == RoleNames.CUSTOMER) {
			out << " | ${link(controller:'customer', action:'showProfile'){'View Profile'}}"
			return
		}
		else if (role.name == RoleNames.SALES){
			out << " | ${link(controller:'agent', action:'showProfile'){'View Profile'}}"
			return
		}
	}

The first issue I ran into was a LazyInitializationException while attempting to use the each closure on my list of roles. Apparently, there was a JIRA opened about this.

Since the taglib is part of the Sitemesh layout, it doesn’t keep the hibernate session alive long enough to provide support for lazy fetching of child objects. This is easily overcome with some eager fetching of the child objects – this case, roles.

Now, the code has turned into something like this:

	def user = User.createCriteria().list() {
		and {
			eq('username',SecurityUtils?.getSubject()?.getPrincipal())
		}
		fetchMode('roles', FM.EAGER)
	}

Obvious problem here – I’m expected a single result, but I’m using ‘list()’ instead of ‘get()’. Sorry. It took a minute to figure out. I’m using ‘list()’, I’ve learned my lesson, I’m getting back a result set, and it’s going to be some sort of a list. In other instances I’ve done the same thing, and since the result is not statically typed, I’m expecting I’ll just get whatever the first result is.

Simple enough.

But, something else happened here. In the each closure on roles, ‘role’ was also being interpreted as a list. The code above was failing.

It seems that when you’re eager fetching using ‘list()’, the parent object and all the children (even the singular instances accessed in the each closure) are treated as lists. To function correctly, the code had to be changed to this:

	roles.each { role->
		if(role[0].name == RoleNames.CUSTOMER) {
			out << " | ${link(controller:'customer', action:'showProfile'){'View Profile'}}"
			return
		}
		else if (role[0].name == RoleNames.SALES){
			out << " | ${link(controller:'agent', action:'showProfile'){'View Profile'}}"
			return
		}
	}

That doesn’t seem as clear to me as it could be. A brief conversation with some co-workers, and changing:

		def user = User.createCriteria().list() {

to:

		def user = User.createCriteria().get() {

got things back to normal for us. The comparisons then became:

	if(role.name == ... 

If anyone else has had a similar experience to the one above or an explanation of this behavior, I’d like to hear about it!

Simple Grails Zip Code Custom Validator

My next post was going to be as verbose as the last, and on an equally obscure topic. Instead of two boring posts in a row, I give you this. It’s simple, but it’s useful:


	zip(nullable:false, blank:false,validator:{zip, address ->
		if(zip ==~ /^(\d{5}-\d{4})|(\d{5})$/) {
			return true
		}
		else {
			return "invalidZipFormat" 
		}
	})
		

For the Regex-challenged (which I am), it’s basically saying 5 digits, a dash, followed by 4 digits OR 5 digits and nothing else. Take care of the rest of the formatting on the client side.

Simple, but a good trick for the bag.

Pdf Generation Using Jasper In A Grails App

The jasper reporting engine provides a free, open source tool for report generation in java. It can produce reports in a variety of formats, including pdf, which makes it very handy in creating all types of data filled documents. Suppose you had a report you just finished constructing and wanted to integrate with your latest Groovy/Grails application. There is a grails plugin that provides tools for displaying your report within a page and also nice looking links to download your report in various formats. Depending on the size of your report, this may be the best option. If your report is small, you may also choose to stream the contents of your report back to the browser window. This is particularly nice if you’d like the pdf to display in the browser’s window as if it were a direct link to the file, using the browser’s pdf plugin. If your goal is the latter, here’s how, utilizing the jasper reporting engine, and some of the conveniences of groovy and grails.

1. Get your report ready to be integrated into your application.

A few things to note here – the most important of which is getting your .jasper files onto the classpath of your application after it is built. For this, place your files under ‘%APPLICATION_DIR%/src/java’, where APPLICATION_DIR refers to the root of your grails project. I would recommend creating a ‘resources’ folder in that location, and possibly sub-directors based on your application’s needs. I had a fun time with this particular detail – that’s for another post…

2. Get your data into your report

These small reports are sometimes easiest generated using the XML datasource feature of jasper. This provides the ability to easily test your code and layout offline, as well as flexibility, if your domain model is significantly different than what you’d like to include in your report.

I’ll skip the XML generation. The code below assumes your XML has been provided as a String.

		import org.apache.commons.io.IOUtils 
		import net.sf.jasperreports.engine.JasperFillManager 
		import net.sf.jasperreports.engine.JasperPrint 
		import net.sf.jasperreports.engine.data.JRXmlDataSource 
		import net.sf.jasperreports.engine.JRException 
		import net.sf.jasperreports.engine.JasperExportManager
		
		private byte[] getJasperReport(String xml, String reportName) throws JRException {
			//add any properties you need passed to your report here.
			HashMap hm = new HashMap();
			
			//convert your xml and .jasper file to input streams.  Commons IO provides a nice way to do this.
			InputStream xmlStream = IOUtils.toInputStream(xml)
			InputStream reportStream = this.getClass().getClassLoader().getResourceAsStream(reportName)
			
			byte[] byteArray = null
			JRXmlDataSource jrxmlds = new JRXmlDataSource(xmlStream);
			JasperPrint jasperPrint = JasperFillManager.fillReport(reportStream, hm, jrxmlds);
			byteArray = JasperExportManager.exportReportToPdf(jasperPrint); 
			
			//this is your report, available as a byte array.  
			return byteArray		
		}

3. Get those bytes back to the browser.

Here, we’ll stream the bytes back to the browser. Since this report is ‘small’, we’ll configure the cache settings accordingly. This code belongs in a controller, as we’ll be dealing directly with the servlet response. pre-check & post-check sets how often (in seconds) the cached object should be checked for freshness before and after it is shown to the user. must-revalidate specifies that the cached object requires revalidation before access. Given the settings below, basically, we’re never going to get this object from the cache. You may choose to configure your caching differently.

	def generatePdf = {
		try {
			//generate or retrieve your XML
			String xml = thisMethodShouldReturnXml()
		
			byte[] bytes = getJasperReport(xml, 'thePath/andNameOfYourReport.jasper')
		
			//get the output stream from the common property 'response'
			ServletOutputStream servletOutputStream = response.outputStream

			//set the byte content on the response. This determines what is shown in your browser window.		
			response.setContentType('application/pdf')
			response.setContentLength(bytes.length)
		
			response.setHeader('Content-disposition', 'inline; filename=quote.pdf')
			response.setHeader('Expires', '0');
			response.setHeader('Cache-Control', 'must-revalidate, post-check=0, pre-check=0');
			servletOutputStream << bytes
		}
		catch(Exception e) {
			//deal with your exception here
			e.printStackTrace()
			//redirect, etc
		}
	}

The servlet response is available as a common property to any controller – a convenience feature of grails. Note groovy’s handling of pushing the report bytes onto the output stream. Also note the lack of calls to ‘flush’ and ‘close’ on the stream. Both conveniences added by groovy.

Depending on your browser, and whether or not that browser has pdf-handling features (via a plugin
or otherwise), you may see different results. A browser with pdf-handling features will render the pdf directly in the browser. If no pdf-handling capability is present, the user is prompted to download or open the rendered pdf, and is provided with the filename specified in the response header. If the user is prompted to download, the page from which the request for the pdf was issued will remain in the browser window.