Saturday, November 7, 2009

Google App Engine with Grails

After I recently got a grails app to work with spring-security, REST, and cache I wanted to try my luck and create a Google App Engine application using grails. Unfortunately, I think it's still pretty early as I ran into several issues early on. However, I see enormous potential once these issues get resolved.

I am using grails v1.1.1, app-engine plugin v0.8.5, with gorm-jpa v0.5. The first issue I ran into was deploying when using grails app-engine deploy. It failed to work subsequent times after I got the WAR initially deployed using /app-sdk/bin/appcfg.sh. It complained about not supplying an email address. Turns out there is a bug related to ant that should get fixed soon. The work around was simple enough; just hit Enter before typing in your email address.

Secondly, I was disappointed to find out that the spring-security (acegi) plugin wasn't compatible in GAE. Based on the compile errors I received locally, it appears spring-security depends on hibernate which is not an option in GAE (you either get JDO or JPA). I chose JPA because according to the documentation, JDO doesn't support any of the GORM dynamic finders methods where as JPA supports most of them. I guess now that I think about it, I'm not suprised acegi didn't work in GAE; just disappointed.

I found a minor issue I submitted concerning the default delete action in generated controllers. Seems the gorm-jpa plugin doesn't wrap the delete method around a [Domain].withTransaction closure which apparently is required (see the save action).

Finally, I was unable to get content negotiation working using the withFormat concept I described here. It worked locally running grails app-engine run, but threw an exception in GAE:

Caused by: java.security.AccessControlException: access denied java.lang.RuntimePermission getClassLoader

My guess is it's related to the Security issues they report on the FAQ:

"The current preview release of the Google AppEngine SDK has a bug that doesn't allow it to run Groovy code when the full permissions restrictions are used. This will be fixed in the next release, but in the meantime the development environment runs without emulating the permissions restrictions of the actual AppEngine environment."
Overall, I enjoyed the easy commands it provides to build, run, and deploy to GAE. The deploy was suprisingly pretty quick. I was able to view the exceptions in GAE easily. I was just prevented from making any real progress. If you want to see what I did get done, which was not much, check it out here http://james-lorenzen.appspot.com

Tuesday, November 3, 2009

Learning with Grails: Security, Extjs, REST, Spring Insight

Unfortunately, security and performance are often postponed early in the development process and are surpassed for new functionality. Reasonable justification usually includes cost and time. A few of the real issues I think are difficulty and lack of experience. I have to admit I am no security or performance expert, and implementing both early on would be time consuming and difficult. I've always heard security done after the fact is never as good if it's done in the beginning. So I wanted to share my experience using the spring-security (acegi) plugin in grails. Not only did I learn a lot about security, but also how to add support for REST Services and integrate Ajax clients using Extjs, how to enable caching, and inspect the performance of my app using Spring Insight that comes with the Springsource tc server developer edition.

Table of Contents


Spring-Security (Acegi)


Building authentication and authorization into your app in the beginning can be difficult, but with the spring-security plugin and grails it's super easy. There are other security plugins for grails, but I decided on spring-security/acegi since our team has contemplated using it on our project several times and it seems to have a pretty good history. This isn't a how to guide on using the security plugin, the documentation is pretty good. However, I do want to share some unexpected things I ran into and how I arrived at some of my conclusions.

When applying the security capabilities, I applied Test-Driven Development (TDD) to test my assumptions and changes. After I installed the plugin, I got started right away creating Users, Roles, and Requestmaps in Bootstrap. Requestmap is the domain model mapping roles to URIs. I prefered this method initially because I wanted to persist this information to the database. First I wanted to lock down the ability to delete a model I called Event. Here is a sample Bootstrap to accomplish it:

In this first test I created an admin role, mapped the admin role to /event/delete, and then added a new user to the admin role. This worked as expected but had a pretty big security hole (see Unexpected observations using spring-security plugin). The issue was unauthorized users were still able to delete events using the edit form. Underneath, grails submits to the index action and the controller handles directing the request to the delete action in the controller bypassing the security created by my Requestmap. I could hide the Delete button on the edit page, but malicous users could still expliot this hole.

So instead of using Requestmap, I annotated my controller actions. This method can properly handle the use case above and deny unauthorized access to the delete action.
I also learned that users have to be associated with a Role, otherwise they are unable to log in (see post). This seemed rather annoying since I was expecting to use the predefined roles: IS_AUTHENTICATED_FULLY, IS_AUTHENTICATED_REMEMBERED, and IS_AUTHENTICATED_ANONYMOUSLY without having to associate all my users with roles. Two suggestions by Burt where to extend a Base model class that supported a default Role for all Users, or extend the GrailsDaoImpl class to remove the role requirement for users.

In summary, it seems best to annotation your controllers instead of using Requestmap and keep in mind that by default all users need to be associated with a role to login into your application.

REST Support for Extjs Ajax clients


Now that I have portions of my app locked down, I wanted to see how this effected Rich Internet Applications (RIAs) such as those that use Extjs. I wanted to answer 2 basic questions:
  1. How can javascript clients remove admin functions like Delete buttons?
  2. How could I modify my controller to support multiple clients that need HTML, JSON, or XML?
To test these questions, I downloaded and installed extjs into my grails app and created a simple grid based on the array-grid example in extjs. As part of this test I wanted to add a Delete button to the bottom toolbar, so that I could later enable or disable based on the users role.

I'm not super proud of how I contrived the roles and used them in javascript, but below is how I did it (If you were doing this for real, I'd make this a point of focus to come up with a better solution like creating a service that returned this information as JSON that could be called by an Ajax client).

Since there is no real easy way to get access to the users roles in a gsp, I set a bean in the controller that is used in the gsp. So in EventController I added the following grid action:
Then in a new grid.gsp I added the following:

Ext.onReady(function() {
var roles = new Ext.util.MixedCollection();
<% authorities?.each { %>
roles.add("<%=it.authority%>");
<% } %>
});
Then when I build the grid, I could eanble or disable the Delete button by doing:

roles.contains("ROLE_ADMIN")
That's pretty much how I disabled certain gui items that are restricted based on role. Again not very pretty, but effective.

Next, I wanted to populate my grid with real data from my controller. Fortunately for developers, grails excels in this area using convention over configuration using the withFormat content negiotation with URI Extensions. All I had to do was modify the controllers list action to support more than HTML responses:

def list = {
params.max = Math.min( params.max ? params.max.toInteger() : 10, 100)
def events = Event.list(params)
withFormat {
html { [eventInstanceList: events, eventInstanceTotal: Event.count()] }
xml { render events as XML }
json { render( [list: events] as JSON ) }
}
}
Here I easily add support for XML and JSON clients while also continuing to support clients who want HTML. One thing to note, is I like naming arrays in JSON; that is why you see the render([list: events]) syntax. Without that, the JSON response looks like this
{[{"class":"Event".....
instead of my preferred way
{"list":[{"class":"Event".....
Now all the client needs to do is request the URI /event/list.json or /event/list.xml.

Here is my complete javascript that includes the example JsonStore and Grid definitions.

Spring Insight and Caching


Next, I really wanted to try out the Spring Insight capability that is now included in the Springsource tc server developers edition. This would let you see into how grails and hibernate are operating on your behalf per request. For many web applications, there are typically 2 bottlenecks that degrade performance: 1) number of trips from the client to server 2) number of trips to the database. Using the Spring Insight tool, developers can see what SQL is being executed and how long it took.

To get started with Spring Insight I followed their Getting Started Guide. Once I had Insight running (http://localhost:8080/insight), I next ran 'grails war' to create a WAR that I could deploy to tomcat (Note: if you do this multiple times, redeploy, you have to be careful with what you do in your apps Bootstrap class. I was doing a lot of inserts that caused my WAR to fail deployment because by default when running 'grails war', grails defaults to the production environment which uses an update file database. So my Bootstrap was trying to add roles and users that already existed and that caused deployment to fail).

The WAR deployed fine and I was up and running watching my apps performance metrics in the Insight dashboard as I moved around in my app. What I noticed first was unexpected multiple JDBC calls when I thought caching was enabled by default in grails.


What I learned was you have to enable caching on a per domain or query basis. So I added the following to my Event domain model

static mapping = {
cache true
}
rebuilt and redeployed the war and was able to see fewer JDBC calls proving that my cached domain was working. I then added a new Event, viewed all events, and saw the extra select call since the cache was purged. Pretty impressive!

Next I wondered if spring-security was caching all the user and role information by default like it advertised. If not that could be a huge performance issue. Spring Insight was also able to prove that it was caching its results.

Overall, I learned a lot about grails, security, REST, extjs, caching, and spring insight and grails was the perfect platform to prototype these concepts in preparation for real production use.

Tuesday, August 4, 2009

Blank screen when installing Ubuntu


Several co-workers and I run encrypted Ubuntu Desktop on our work laptops. Specifically I have an HP Compaq 6710b and they have all had monitor issues when installing Ubuntu. If you run the default "Install Ubuntu" option, the next screen will just be a blank screen. I need to get this documented because I always forget how to fix it.

While at the Ubuntu Splash screen do the following:

  • Press the F1 key for "Help"
  • Press the F6 key for "Special boot parameters for special machines"
There you will see an option in the middle described as:
Laptops with screen display problems vga=771. We need to append this to the Boot Options.
  • Press the ESC key to get back to the Splash page
  • Press F6 for "Other Options" and then Press ESC
Now the Boot Options should be visible. It should look something like this:

Boot Options file=/cdrom/preseed/ubuntu.see initrd=/install/initrd.gz quiest --

Delete the trailing -- and add in vga=771. You should have the following:

Boot Options file=/cdrom/preseed/ubuntu.see initrd=/install/initrd.gz quiest vga-771

Press the enter key and you should now be able to successfully install Ubuntu.