Showing posts with label grails. Show all posts
Showing posts with label grails. Show all posts

Monday, December 22, 2008

Grails + JSecurity

I have been using the Grails JSecurity Plugin for authentication/authorization in my proto-type Grails app.

While there are many good things about the JSecurity Grails Plugin, "thorough documentation" is not one of them. I had some difficulty figuring out how to tie it all togethr, so I am posting here my basic set up.

For apps where authorization is, to some degree, external to the core object model, the WildcardPermission is the flexible, powerful way to go.

In my app, however, authorization rules are deeply embedded within the domain model -- whether or not User X can edit object Y is a function of some of Y's member values. I do not see how that can be accomplished via WildcardPermission.

My first cut of a solution involves defining an enum and an interface


public enum PermissionActionEnum {
VIEW, EDIT, EXECUTE, DELETE, CREATE, ...
}

public interface AuthProvider<E> {
public boolean isPermitted(User u, PermissionActionEnum a, E on);
public Class<E> getClazz();
}


Each of these AuthProviders knows how to determine authorization by examining the target object. I have a class "GlobalAuthProvider" which contains references to all the known AuthProviders and its own isPermitted method which delegates appropriately.

I defined a JSecurity Permission to link resource/target with a PermissionAction.


public class ResourcePermission implements org.jsecurity.authz.Permission {
Object resource
PermissionActionEnum action
...
//So that action can be set with either an Enum or String
public void setAction(String name) {
action = PermissionActionEnum.valueOf(name.toUpperCase());
}
}


Next, I defined a groovy authService which wraps the GlobalAuthProvider


public class AuthService {
...
public boolean isPermitted(User user, ResourcePermission resourcePermission) {
GlobalAuthProvider gap = ...
Object on = resourcePermission.resource
PermissionActionEnum action = resourcePermission.action
return gap.isPermitted(user, action, on);
}
...


My Realm then delegates to the authService

class MyRealm {
def authService
...
//Assumes ResourcePermision
def isPermitted(principal, requiredPermission) {
def user = User.findByName( principal )
return authService.isPermitted(user, requiredPermission)
}
...


Now the JSecurity tag can be used in the gsp. This is a little tricky because the GSP jsec:hasPermission tag, appears to be slightly different from the general JSP one


<jsec:hasPermission
permission="${ new ResourcePermission(resource:obj,action:'VIEW') }">
...
</jsec:hasPermission>

Monday, December 8, 2008

Grails GUI

For my nascent grails app I am using YUI + Grails GUI.

Ran into the problem described here, where one autocomplete options containers renders under another autocomplete text input.

The best fix I (described in jira) found was adding a zIndex property to the gui:autoComplete tag and setting the parent container div with it.

Monday, December 1, 2008

Grails Many To Many

Grails doesn't yet handle many-to-many relationships in the scaffolding.

Most of the stuff available online recommends using relationship domain class to fudge the many-to-many relationship. If I have a many to many relationship of User to Role, I could have a UserRoleRelation that has a one-to-many relationship with both a User and Role, which Grails should handle cleanly.

It is also pretty easy to set up a simple direct ManyToMany relationship manually, as follows:

In my Role.java class I have

@ManyToMany(targetEntity=User.class, mappedBy="roleCollection")
private Set userCollection;

In my User.java class I have

@ManyToMany(targetEntity=Role.class, cascade = {CascadeType.MERGE})
@JoinTable(name="USER_ROLE_XREF",
joinColumns=@JoinColumn(name="User_Name", referencedColumnName = "User_Name"),
inverseJoinColumns=@JoinColumn(name="Role_Name", referencedColumnName = "Role_Name")
)
private Set roleCollection;

I cross-refrence by name instead of id to make the table more human readable. This may have the unfortunate side effect of breaking the generate-views command.

In the user/edit.gsp, I add a select box with the list of roles available

<tr class="prop">
<td valign="top" class="name">
<label for="roleCollection">Roles:
</td>
<td valign="top" class="value ${hasErrors(bean:user,field:'roleCollection','errors')}">
<g:select name="newRoleCollection" from="${Role.list()}"
value="${user?.roleCollection?.id}" optionKey="id" multiple="multiple" />
</td>
</tr>

If you only want to present a subset of the Roles (which happens to be the case in my prototype app), you can use Role.findAllByXXX instead of Role.list()

Finally, in my controllers/UserController.groovy, I add the code to put humpty dumpty back together again.

user.roleCollection.clear()

//probably a groovier way to do this, but it works...
//if newRoleCollection is a string instead of a string[], each iterates over each character
boolean newRoleCollectionIsStringArray = params.newRoleCollection.class.name != 'java.lang.String'

if (newRoleCollectionIsStringArray) {
params.newRoleCollection.each{
user.roleCollection.add( Role.findById( Integer.valueOf( it ) ) )
}
} else {
user.roleCollection.add( Role.findById( Integer.valueOf( params.newRoleCollection ) ) )
}

It isn't pretty but it does the trick.

Grails

Been playing with Grails (http://grails.org/).

Positive first impressions: Conceptually, what is not to like about the possibility of defining your domain model and having a functioning GUI up in a few clicks? The Grails generated web-app code and structure appears much neater then, for example, what JBoss SEAM produced. I am also, for the moment, loving writing web-app controllers in Groovy. It feels so much more natural, for that purpose, then Java.

On the negative side: Conceptually, I don't see any non-trivial benefit to defining domain classes in Groovy instead of Java. On the contrary, it seems to me, that in any real enterprise context, you are going to want to define your domain (and perhaps a service layer) in Java. Additionally, if you use Java domain objects, you can reverse engineer them from the database using a tool like hbm2ddl. The development focus on POGOs makes me a little nervous that maybe the Grails development team is more focused on replicating Rails then really thinking about how Grails can most naturally fit into an Enterprise Java environment. The purchase by SpringSource does offset this fear.


Finally, grails seems to enjoy failing without useful error messages. For example: I ran into http://jira.codehaus.org/browse/GRAILS-2096 and http://jira.codehaus.org/browse/GRAILS-3658