Reputation:
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
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