user995009
user995009

Reputation:

Spring + Spring Security + hasPermission Not working

I am trying to use Spring Security 3 with Struts 2 and Spring DI. I put hasRole() annotation in my code and it is working fine but hasPermission() annotation is not working. I have made expression handler, custom permission evaluator etc.

Here is the code

applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans> 
 <import resource="mySecurity.xml"/>
<bean id="myAction" name="myAction" class="code.action.MyAction" autowire="byName">
</bean>
<bean id="permission" name="permission" class="code.permission.Permission" autowire="byName">
</bean>
<bean id="myEntity" name="myEntity" class="code.entities.MyEntity" autowire="byName">
</bean>
<bean id="expressionHandler" class="org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler" 
    name="expressionHandler" autowire="byName">
</bean>
<bean class="code.permission.MyCustomPermissionEvaluator" id="customPermissionEvaluator" name="customPermissionEvaluator" autowire="byName" />
</beans>

Here is my acl-context.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xmlns:p="http://www.springframework.org/schema/p"
 xmlns:util="http://www.springframework.org/schema/util"
 xsi:schemaLocation="http://www.springframework.org/schema/beans
      http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
   http://www.springframework.org/schema/util
   http://www.springframework.org/schema/util/spring-util-3.0.xsd">

    <!-- Declare a simple map containing all our roles -->
    <util:map id="permissionsMap">
         <entry key="ROLE_USER" value-ref="user"/>
     </util:map>

 <!-- Declare permissions for Admin
  Contains a map of objects and their associated allowed actions -->
 <bean id="user" class="code.permission.Permission" >
  <property name="objects">
   <map>
    <entry key="code.entities.MyEntity">
     <list>
      <value>READ</value>
     </list>
    </entry>
   </map>
  </property>
 </bean>

</beans>

this is mySecurity.xml

 <?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
  xmlns:beans="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
           http://www.springframework.org/schema/security
           http://www.springframework.org/schema/security/spring-security-3.1.xsd">

  <!-- To enable Method Security Expressions and custom PermissionEvaluator
   we need to add the following -->
         <global-method-security pre-post-annotations="enabled">
                <expression-handler ref="expressionHandler" />
         </global-method-security>

 <!-- To use hasPermission() expressions, we have to configure a PermissionEvaluator -->
 <!-- See 15.3.2 Built-In Expression
   @http://static.springsource.org/spring-security/site/docs/3.0.x/reference/el-access.html#el-permission-evaluator -->
        <beans:bean id="expressionHandler"
            class="org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler" name="expressionHandler" autowire="byName">
        <beans:property name="permissionEvaluator" ref="customPermissionEvaluator" />
        <beans:property name = "roleHierarchy" ref="roleHierarchy"/>
     </beans:bean>

 <!-- Declare a custom PermissionEvaluator interface -->
 <beans:bean class="code.permission.MyCustomPermissionEvaluator" id="customPermissionEvaluator" name="customPermissionEvaluator" autowire="byName" />

    <http auto-config="true" use-expressions="true">
    <intercept-url pattern="/index.jsp" access="permitAll" />
    <intercept-url pattern="/firstPage" access="hasRole('ROLE_USER')" />
    </http>

    <authentication-manager>
        <authentication-provider>
            <user-service>
                <user name="user" password="user" authorities="ROLE_USER" />
            </user-service>
        </authentication-provider>
    </authentication-manager>

    <!-- http://static.springsource.org/spring-security/site/docs/3.0.x/apidocs/org/springframework/security/access/hierarchicalroles/RoleHierarchyImpl.html -->
    <beans:bean id="roleHierarchy"  class="org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl" name="roleHierarchy" autowire="byName">
      <beans:property name="hierarchy">
         <beans:value>
             ROLE_USER
         </beans:value>
     </beans:property>
    </beans:bean>
 </beans:beans>

This is my Permission.java package code.permission;

import java.util.List;
import java.util.Map;

/**
 * Contains a map of objects and their associated allowed actions
 */
public class Permission {

 /**
  *  A Map containing a list of objects and their corresponding actions
  *  <p>
  *  String: key name of the object
  *  List<String>: a list of permissions
  */
  private Map<String, List<String>> objects;

 public Map<String, List<String>> getObjects() {
  return objects;
 }
 public void setObjects(Map<String, List<String>> objects) {
  this.objects = objects;
 }

}

This is myCustomPermissionEvaluator.java

package code.permission;

import java.io.Serializable;
import java.util.Collection;
import java.util.Map;

import org.springframework.security.access.PermissionEvaluator;
import org.springframework.security.access.hierarchicalroles.RoleHierarchy;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;

import javax.annotation.Resource;

public class MyCustomPermissionEvaluator implements PermissionEvaluator {

  @Resource(name="permissionsMap")
   private Map permissionsMap;

 @Resource(name="roleHierarchy")
 private RoleHierarchy roleHierarchy;

 public boolean hasPermission(Authentication authentication,
   Object targetDomainObject, Object permission) {
     System.out.println("First hasPermission");

  String role = getRole(authentication);

  return hasPermission(role, permission, targetDomainObject);
 }

 /**
  * Another hasPermission signature. We will not implement this.
  */
 public boolean hasPermission(Authentication authentication,
    Serializable targetId, String targetType, Object permission) {

  return false;
 }

 /**
  * Retrieves the user's highest role
  */
 private String getRole(Authentication authentication) {
  String highestRole = null;

  try {
    Collection<GrantedAuthority> auths = (Collection<GrantedAuthority>)   roleHierarchy.getReachableGrantedAuthorities(authentication.getAuthorities());
   for (GrantedAuthority auth: auths) {
    highestRole = auth.getAuthority();
    break;
   }

  } catch (Exception e) {

  }

  return highestRole;
 }

 private Boolean hasPermission(String role, Object permission, Object domain) {
     System.out.println("Second hasPermission");
  if ( permissionsMap.containsKey(role) ) {
        Permission userPermission = (Permission) permissionsMap.get(role);

  if ( userPermission.getObjects().containsKey(domain.getClass().getName())){

    for (String action: userPermission.getObjects().get(domain.getClass().getName()) ) {
      if (action.equals(permission)) {

       return true;
     }
    }
   }
  }

  return false;
 }
}

this is MyAction.java

package code.action;

import org.springframework.security.access.prepost.PreAuthorize;
import code.entities.MyEntity;

public class MyAction {
    @PreAuthorize("hasRole('ROLE_USER')")
    public String showPage(){
        System.out.println("in MyAction : showPage");
        MyEntity entity = new MyEntity();
        if(isAccessible(entity))
            return "success";
        else
            return "input";
    }
     @PreAuthorize("hasPermission(#entity,'WRITE')")
    public boolean isAccessible(MyEntity entity){
        System.out.println("in MyAction : isAccessible");
        return true;
    }
}

Any expert here to tell me why this hasPermission() not working ?

Upvotes: 2

Views: 7574

Answers (1)

Ralph
Ralph

Reputation: 120771

It does not work, because Spring AOP can only incercept calls between beans, but not if you invoke a method of the same bean.

So either you move the isAccessible Method to an other bean, or use use AspectJ instead of Spring Proxy AOP.

An other idea would be using the permission evaluation directly, instead of having the annotated method. (But I do not know exactly how this can be done.)

Upvotes: 6

Related Questions