Raging Goblin

6 April 2013

Spring Roo 5: Role based views

Filed under: Java,Spring Roo — raginggoblin @ 20:18
Tags: , ,

The user management functionality introduced in the previous post is not meant to be accessed by all users. This is the reason why we introduced the LogUserRole. Only members of the group ADMINSTRATOR should be able to add, update or delete users. To accomplish this we need 2 things:

  1. Check for the role the logged in user has when executing a method in the LogUserController.
  2. Remove the links to user management from the menus.

The first can be done by using the @PreAuthorize annotation. To enrich our application with this we first add this to webmvc-config.xml. Add the schema definition and enable the annotation by setting the head of this configuration file to:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:mvc="http://www.springframework.org/schema/mvc" 
	xmlns:p="http://www.springframework.org/schema/p"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:security="http://www.springframework.org/schema/security"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd">
<security:global-method-security pre-post-annotations="enabled "/>

Note that I added two things, the schema definition and the enabling of the pre-post-annotations.

Now, in the LogUserController we can add the @PreAuthorize annotation. E.g. the head of the method create will look like this:

@PreAuthorize("hasRole('ADMINISTRATOR')")
@RequestMapping(method = RequestMethod.POST, produces = "text/html")
public String create(@Valid LogUser logUser, BindingResult bindingResult, Model uiModel,
	HttpServletRequest httpServletRequest) {

You should do this for all the other methods as well.

We also add a AccessDeniedException configuration to the webmvc-config.xml to let the one who tries to access these methods know what went wrong:

<props>
  <prop key=".DataAccessException">dataAccessFailure</prop>
  <prop key=".NoSuchRequestHandlingMethodException">resourceNotFound</prop>
  <prop key=".TypeMismatchException">resourceNotFound</prop>
  <prop key=".MissingServletRequestParameterException">resourceNotFound</prop>
  <prop key="org.springframework.security.access.AccessDeniedException">accessDenied</prop>
</props>

Add a view definition in src/main/webapp/WEB-INF/views/views.xml:

<definition extends="public" name="accessDenied">
  <put-attribute name="body" value="/WEB-INF/views/accessDeniedException.jspx"/>
</definition>

Create this view with a proper message in src/main/webapp/WEB-INF/views/accessDeniedException.jspx.

The second thing we need to do is change the menus so that a normal user will not access these methods accidentally. This can be done by adding a security tag to menu.jspx and surrounding the user management menu items with a role based security tag:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<div xmlns:jsp="http://java.sun.com/JSP/Page"
	xmlns:menu="urn:jsptagdir:/WEB-INF/tags/menu"
	xmlns:security="http://www.springframework.org/security/tags" id="menu"
	version="2.0">

	<jsp:directive.page contentType="text/html;charset=UTF-8" />
	<jsp:output omit-xml-declaration="yes" />
	<menu:menu id="_menu" z="nZaf43BjUg1iM0v70HJVEsXDopc=">
		<menu:category id="c_logitem" z="SqQ1OSujMWnswClBZ0yGRL10ER0=">
			<menu:item id="i_logitem_new" messageCode="global_menu_new"
				url="/logitems?form" z="/iSFuRAPFJM3+CEo2pV5jdJJVfU=" />
			<menu:item id="i_logitem_list" messageCode="global_menu_list"
				url="/logitems?page=1&amp;size=${empty param.size ? 10 : param.size}"
				z="+VS0ebBCcdnV89xtkN9/QZZFFOw=" />
		</menu:category>
		<security:authorize ifAllGranted="ADMINISTRATOR">
		<menu:category id="c_loguser" z="Ya37W2Dk3lcEcn0gGjq3sCqfdxc=">
			<menu:item id="i_loguser_new" messageCode="global_menu_new"
				url="/logusers?form" z="YxH3QphXpDJh34UhJibtVutDlQw=" />
			<menu:item id="i_loguser_list" messageCode="global_menu_list"
				url="/logusers?page=1&amp;size=${empty param.size ? 10 : param.size}"
				z="De/VBRYqUuix4e1/Lcmen2eTqFY=" />
		</menu:category>
		</security:authorize>
	</menu:menu>
</div>

This will result in different views for different roles:

Admin menu

Admin menu


Menu user

User menu

About these ads

5 Comments »

  1. Nice post ! In enterprise application many tables are user specific. Simple example. user->projects->tasks. Now if we want to show only tasks for the user, roo’s finder methods are not enough because currently roo does not support finders by user if the the entity is at 2nd level or more. For example, findTasksByUser in this example. IT would be great if you have any recommended approach. Because of this problem, we have to override almost roo generated methods and it looses advantage of rapid application development.

    Comment by sudhir — 11 April 2013 @ 19:40 | Reply

    • You can do 2 things in my opinion, but maybe there are more solutions:
      1) Make the relationships the other way around by using field set on the user and the project. That way you can get the projects directly from the user and tasks directly from the projects.
      2) Make tasks dependent on project and user.

      Comment by raginggoblin — 12 April 2013 @ 13:47 | Reply

      • Thanks. In first approach we can not take advantages of roo’s finder method. Can we ? I dont think roo can generate finder methods something like user.getTasks(). I am finding ways to reduce custom code when using roo.
        2nd Approach can work. But kind of extra column in all user related tables.

        Comment by sudhir — 12 April 2013 @ 18:14 | Reply

    • 2nd approach does indeed add extra columns which is probably not what
      you want. For the 1st approach you don’t need finders. You can call
      user.getProjects() and getTasks() on all projects.

      Comment by raginggoblin — 12 April 2013 @ 21:43 | Reply

      • Yes, in the first approach, one has to write finder code by hand, roo can not help to generate the code. Also, it can not also generated related jspx for the finder and one has to write that too !
        Thanks, please keep on writing on roo.

        Comment by sudhirkd — 12 April 2013 @ 22:30 | Reply


RSS feed for comments on this post. TrackBack URI

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

The Rubric Theme Blog at WordPress.com.

%d bloggers like this: