Monday, July 1, 2013

Spring security @PreAuthorize example and generic exception

Hi,

In my recent project I have working on securing spring methods exposed by controllers via @RequestMappings. 

PROBLEM TAKEN
I have to cross check the permissions/authorities assigned to the user who has logged-in to the system.  If the authority mentioned above the method matches then execution goes successfully else exception is throws.

TECHNOLOGY STACK
·         Spring
·         Hibernate
·         Tomcat
·         Maven
·         jQuery

SOLUTION APPROACH
I made the class that checks the user who is logged-in at present (I made the UserInfo object to be flowed in each request object after successful authentication.  For details please refer my blog http://sv-technical.blogspot.in/2013/07/spring-how-to-make-bean-object.html).

Ingredients to cook above code are:
Firstly I made my custom class extending org.springframework.security.access.PermissionEvaluator as BasePermissionEvaluator.  This class stores the object of UserInfo (refer blog mentioned above for details) and has below structure.


            BasePermissionEvaluator.java
public class BasePermissionEvaluator implements PermissionEvaluator
{
    @Autowired
    private UserInfo userInfo;
   
    /**
     * @return the userInfo
     */
    public UserInfo getUserInfo()
    {
        return userInfo;
    }

    /**
     * @param userInfo the userInfo to set
     */
    public void setUserInfo(UserInfo userInfo)
    {
        this.userInfo = userInfo;
    }

    @Override
    public boolean hasPermission(Authentication authentication, Object targetDomainObject, Object permission)
    {
        boolean hasPermission = false;

        if (authentication != null && permission instanceof String)
        {
            hasPermission = userInfo.hasPermission((String)permission);
        } else
        {
            hasPermission = false;
        }
        return hasPermission;
    }

    @Override
    public boolean hasPermission(Authentication authentication, Serializable targetId, String targetType, Object permission)
    {
        throw new RuntimeException("Id and Class permissions are not supperted by this application");
    }
}

Corresponding applicationContext.xml entries
<security:global-method-security pre-post-annotations="enabled">
    <security:expression-handler ref="expressionHandler" />
</security:global-method-security>
<bean id="webExpressionHandler" class="org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler" />

    <bean id="expressionHandler"
        class="org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler">
        <property name="permissionEvaluator" ref="permissionEvaluator" />
    </bean>

    <bean id="permissionEvaluator"
        class=" BasePermissionEvaluator" />


If the exception is thrown by any of the method then handles it using below entries
<bean
        class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
        <property name="exceptionMappings">
            <props>
                <prop key="java.lang.Exception">/pages/common/error</prop>
            </props>
        </property>
    </bean>
Here you are supposed to create on error.jsp inside pages/common folder of you context root folder.


Below is one of the Controller’s methods secured via @PreAuthorize annotation.
    @RequestMapping(value = "service/user/list.do", method = RequestMethod.GET)
    @PreAuthorize("hasPermission('null','can-view-users')")
    public @ResponseBody
    List<User> list()
    {
        return userService.list();
    }


Error.jsp
<%@ page isErrorPage="true" %>
<!doctype html>
<html>
<head>
     <meta charset="utf-8">
     <title>vCare - for you</title>
     <link rel="stylesheet" type="text/css" href="<%=ctx%>/content/css/bootstrap.css" />
     <link rel="stylesheet" type="text/css" href="<%=ctx%>/content/css/bootstrap-responsive.css" />
     <link rel="stylesheet" type="text/css" href="<%=ctx%>/content/css/default.css" />
     <script type="text/javascript" src="<%=ctx%>/content/scripts/jquery-1.8.2.js"></script>
     <script type="text/javascript" src="<%=ctx%>/content/scripts/bootstrap.min.js"></script>
</head>
<body>
     <div class="header">
           <div class="wrapper row-fluid">
                <div class="span12">
                     <div class="logo">
                           <a href="#">
                                <img src="<%=ctx%>/content/images/logo-150-60.png" border="0" />
                           </a>
                     </div>
                </div>
           </div>
     </div>
     <div class="main-content">
           <div class="wrapper">
                <div class="error-wrap">
                     <h1>Error</h1>
                     <h3>Sorry, an error occurred.</h3>
                     <hr />
                     <p>Below are the details: </p>
                     <div class="alert alert-error">
                           <%=exception.getMessage()%>
                     </div>
                     <hr />
                     <a class="btn btn-success" href="<%=request.getContextPath ()%>/">Go Back</a>
                </div>
           </div>
     </div>
</body>
</html>

Please let me know if you need any other help or more information.

Thanks
Shailendra