This is a follow-up post to Flex on Grails, Take 2.
Task creation
Now that we have a basic working application, let’s improve it by adding some security in there. If your Grails application is still running, you can leave it that way as you won’t need to restart your backend every time you modify it. That’s the whole beauty and productivity of Grails and this plugin.
First thing we’re going to do is that we’re going to create a TaskDetail DTO that will be useful for our task creation method:
package org.epseelon.todolist.dto class TaskDetail { Long id String title }
Yes, I know, the fields are the same as for TaskListItem and you lazy ranters are already complaining about the fact that we create 2 identical classes. But remember that they serve completely different purposes, that we’re only starting, and that those 2 classes are very likely to evolve in very different ways. Having TaskDetail extend TaskListItem is also a bad idea because you would be assuming that all the fields in TaskListItem will always be needed in TaskDetail, which is not sure. For example, in a list, you might want to display a few summary fields that won’t be needed in a task edition form.
Notice that we created our TaskDetail class in the same package as TaskListItem, under src/groovy.
Now that we have our DTO, let’s add a new service operation below getAllTasks():
@RemotingInclude @Secured(["ROLE_ADMIN"]) TaskDetail createNewTask(TaskDetail newTask) { Task task = new Task(title:newTask.title) if(task.validate()){ task.save() return new TaskDetail( id: task.id, title: task.title ) } else { throw new Exception(task.errors.allErrors.defaultMessage.join("n")) } }
Notice that in addition to RemotingInclude, we added a Secured annotation to our createNewTask operation. You should have two such annotations in your classpath. grails.plugins.springsecurity.Secured is used for securing Grails controller methods. Here we will be using org.springframework.security.access.annotation.Secured. The String array parameter of this annotation specifies a list of roles which means that whoever walls this method must be authenticated and have at least one of the roles listed in the annotation (at least that’s what the default security configuration does).
Now let’s go back to Flash Builder and improve our todolist frontend a little bit. First, let’s create a new TaskForm component to serve as a dialog box to create a new task. To do that, right click the default package and choose New>MXML Component:
Let’s call our new component TaskForm and let’s make it based on spark.components.TitleWindow:
Here is the code of the TaskForm component:
[sourcecode language=”xml”]
[Event(name=”taskSaved”,type=”flash.events.Event”)]
[Event(name=”taskCancelled”,type=”flash.events.Event”)]
The next dialog allows you to select the files that will be deleted. Click OK to simply delete regenerated files:
Click “Connect to Data/Service…” again, select todoListService and click OK. You should get the following service:
Then, modify the code of Main.xml like the following:
[sourcecode language=”xml”]
[/sourcecode]
With this new code, when you click the “+” button, a dialog box opens, lets you specify the title of your task, and when you click Save, it calls the createNewTask() method of our service. And that’s where security jumps in, because you get an error dialog saying “Access is denied”.
And that’s alright, because we are not even authenticated, let alone authorized.
Spring Security
First off, we need to create security-related domain class. In the Grails application, run the following command: “grails s2-quickstart org.epseelon.todolist.domain User Role”. To run this command in IntelliJ, you have to bring up the groovy command dialog by using the Tools menu and then choose Grails>Target:
Authentication UI
Now, let’s move back to Flash Builder to add some authentication UI. First, let’s create 2 states for our main UI, a “loggedIn” and a “loggedOut” state. In Main.mxml, add the following code between the fx:Script and the fx:Declarations sections: [sourcecode language=”xml”] [/sourcecode] In Flex, authentication is handled via the channelSet associated to a RemoteObject, so we have to update our TodoListService instantiation code like the following: [sourcecode language=”xml”] [/sourcecode] Yes, I know, the URL is now hard-coded inside the application but we’ll improve that in a future episode by integrating some dependency injection logic. Then add the currentState attribute to the Application element: [sourcecode language=”xml”] … [/sourcecode] Now add a String variable to Main.mxml that will contain the name of the user currently logged in: [sourcecode language=”actionscript”] [Bindable] private var loggedInUser:String; [/sourcecode] And add some authentication UI to the control bar of our main panel: [sourcecode language=”xml”] [/sourcecode] Before implementing login and logout logic, let’s add 2 CallResponder’s to handle responses to login and logout: [sourcecode language=”xml”] [/sourcecode] Now let’s implement the click handlers for our login and logout buttons: [sourcecode language=”javascript”] protected function loginButton_clickHandler(event:MouseEvent):void { loginResult.token = channelSet.login(usernameInput.text, passwordInput.text); } protected function logoutButton_clickHandler(event:MouseEvent):void { logoutResult.token = channelSet.logout(); } protected function loginResult_resultHandler(event:ResultEvent):void { loggedInUser = event.result.name; usernameInput.text = “”; passwordInput.text = “”; } protected function logoutResult_resultHandler(event:ResultEvent):void { loggedInUser = “”; } [/sourcecode] Here is the entire code of our Main.mxml at this stage: [sourcecode language=”xml”] [/sourcecode]Running the application
Now when you run your application (and provided that you restarted the backend after adding security initialization code), you should get the following results:- If you don’t log in and try to create a new task, you’ll get an “Access is denied” message like before
- If you log in as user/user and try to create a new task, you’ll get an “Access is denied message because authorization is kicking in and you don’t have the ROLE_ADMIN role
- If you log in as admin/admin and try to create a new task, it works!
15 responses to “Flex on Grails: Take 2, Part 2”
Have you managed to solve any lazy load exceptions with this approach that you get with the underlying GORM/Hibernate? – You don’t have a complicated enough domain model here yet to warrant knowing if this approach solves anything new. (Or am I missing something?)
Spice Factory Pimento/Parsley still looks like best approach.
Possibly Robotlegs/dpHibernate – Michael Labriola recently mentioned they’ve got an improved version of dpHibernate that circumvents need for having domain class inherit from a base class. I also think something Yakov Fain did in Clear Toolkit could be adapted (he was using some XDoclet style approach with SQL- but the underlying concept of sending the delta changes over the wire I reckon could be applied to Hibernate
As far as I’m concerned, I’ve never faced any issue with lazy loading because I’ve always been a firm opponent of using lazy loading over the wire, which is why I always work with DTO’s. I think that the Flex plugin adds something to that but I’m not using it so you might want to wait for Burt Beckwith to publish his screencast showing his blazeds+flex plugin setup.
[…] This post was mentioned on Twitter by Sebastien Arbogast, Daniel Soriano Gil. Daniel Soriano Gil said: http://sebastien-arbogast.com/2010/11/15/flex-on-grails-take-2/ http://sebastien-arbogast.com/2010/11/16/flex-on-grails-take-2-part-2/ […]
Jeremy – I looked at dpHibernate but didn’t like having to use subclasses, but I’m glad to know they’re working on that. Spring Flex has converters that handle lazy loading and send null for uninitialized references or collections. I made those configurable and added an OpenSessionInView-style wrapper (which can be disabled) so you can use lazy loading if you want, or not use it and send nothing, or explicitly initialize lazy-loaded references.
DTOs are a good solution, but they have the one disadvantage of not being very DRY.
See “Data serialization” in section 3 in the docs for more info: http://grails-plugins.github.com/grails-blazeds/docs/manual/
DTO’s are DRY! Because transferring data and storing it are 2 different beasts. DTO’s are more secure (you transfer only the data that is needed), take less bandwidth (for the same reason) and make your UI less tightly-coupled to your domain model. For me that’s worth a few copy/pastes. Don’t you think?
¡DTOs are not DRY!, they are very much RY (or perhaps wet). Change domain => change DTO + rewrite code where you populate your DTO. Ouch.
If the main arguments for DTOs are what you have stated above then I’m definitely not convinced. Well, each to their own maybe one day I’ll be converted, in the meantime I’m looking forward to the mentioned screencast from Burt. This new BlazeDS/Grails integration is all great to read about.
A change in your DTO does not always imply a change in your user interface, hence it does not always require a change in your DTO’s. And when it does, well, you are simply changing a feature in your app, which certainly implies changes in all the layers of your application, so I don’t see where is the RY. And even if there is some RY, I personnally think that loose coupling is much more important for maintainability and evolutivity than lazin… huuuh… sorry… DRY. ;o)
This plugin appears to eliminate the work I fear so maybe we can all live happily together after all: http://www.grails.org/plugin/dto
And how could we trace flex service blazeds requests in a similar way as this example http://mrhaki.blogspot.com/2010/01/grails-goodness-logging-service-method.html?
What is the problem with doing just that? Behind the scenes, BlazeDS is invoking your service methods exactly like a controller would so you should have no problem overriding invokemethod.
Ok, thanks!!
Hi, I was just wondering how secure a flex application would be if you wrap the SWF in a gsp, and configure Spring Security in the usual way you would do for a html based grails app. Once the html wrapped SWF is loaded onto the browser, you are redirected to the spring security login page. Upon login you’re redirected to the home page of your app which contains the swf with the bulk of the functionality.
You’re services are anyway secured and enabled for remote access and spring would throw an exception if you’re not logged in. This gives you a cookie and session id based authentication mechanism with all the easy to do parts of spring security without you worrying about any of the intricate detail involved.
I tried this out and it seems to work. But I was just wondering if I’m over looking some obvious but important security concern. Does anyone see problems with this approach?
Thanks
First of all: Great series of articles! Thanks for sharing.
But I keep getting Bad Credentials error when trying to login with user/user or admin/admin.
I’ve deleted the project and started over and it’s the same.
I’m using latest versions.
Grails 1.3.7
Flex 4.5.1
and STS IDE
I’m a Flex/PHP developer, and this is the first time I’m trying to work with Java, so I’m really lost here.
Any idea of what is wrong?
Found the problem.
My version of Spring Security automaticaly created:
def beforeInsert() { encodePassword() }
So it always encode the password property when set.
And in the Bootstrap example it has:
def user = new User(username: “user”, password: springSecurityService.encodePassword(“user”), enabled: true).save()
So it was encoding the password twice.
I found a bug. The password must be encrypted with SHA256.
So you should write as follows.
import mx.utils.SHA256;
import flash.utils.ByteArray;
protected function loginButton_clickHandler(event:MouseEvent):void
{
var bytes:ByteArray = new ByteArray();
bytes.writeUTFBytes(passwordInput.text);
loginResult.token = channelSet.login(usernameInput.text, SHA256.computeDigest(bytes));
}