diff --git a/core/src/main/java/org/springframework/security/access/expression/SecurityExpressionRoot.java b/core/src/main/java/org/springframework/security/access/expression/SecurityExpressionRoot.java index 87ead1ff89..4adb363acc 100644 --- a/core/src/main/java/org/springframework/security/access/expression/SecurityExpressionRoot.java +++ b/core/src/main/java/org/springframework/security/access/expression/SecurityExpressionRoot.java @@ -1,7 +1,10 @@ package org.springframework.security.access.expression; +import java.util.HashSet; +import java.util.List; import java.util.Set; +import org.springframework.security.access.hierarchicalroles.RoleHierarchy; import org.springframework.security.authentication.AuthenticationTrustResolver; import org.springframework.security.core.Authentication; import org.springframework.security.core.GrantedAuthority; @@ -18,6 +21,9 @@ import org.springframework.security.core.authority.AuthorityUtils; public abstract class SecurityExpressionRoot { protected final Authentication authentication; private AuthenticationTrustResolver trustResolver; + private RoleHierarchy roleHierarchy; + private Set roles; + /** Allows "permitAll" expression */ public final boolean permitAll = true; @@ -32,17 +38,11 @@ public abstract class SecurityExpressionRoot { } public final boolean hasRole(String role) { - for (GrantedAuthority authority : authentication.getAuthorities()) { - if (role.equals(authority.getAuthority())) { - return true; - } - } - - return false; + return getAuthoritySet().contains(role); } public final boolean hasAnyRole(String... roles) { - Set roleSet = AuthorityUtils.authorityListToSet(authentication.getAuthorities()); + Set roleSet = getAuthoritySet(); for (String role : roles) { if (roleSet.contains(role)) { @@ -88,4 +88,23 @@ public abstract class SecurityExpressionRoot { public void setTrustResolver(AuthenticationTrustResolver trustResolver) { this.trustResolver = trustResolver; } + + public void setRoleHierarchy(RoleHierarchy roleHierarchy) { + this.roleHierarchy = roleHierarchy; + } + + private Set getAuthoritySet() { + if (roles == null) { + roles = new HashSet(); + List userAuthorities = authentication.getAuthorities(); + + if (roleHierarchy != null) { + userAuthorities = roleHierarchy.getReachableGrantedAuthorities(userAuthorities); + } + + roles = AuthorityUtils.authorityListToSet(userAuthorities); + } + + return roles; + } } diff --git a/core/src/main/java/org/springframework/security/access/expression/method/DefaultMethodSecurityExpressionHandler.java b/core/src/main/java/org/springframework/security/access/expression/method/DefaultMethodSecurityExpressionHandler.java index 33c4025e5d..fb1fbdf7b1 100644 --- a/core/src/main/java/org/springframework/security/access/expression/method/DefaultMethodSecurityExpressionHandler.java +++ b/core/src/main/java/org/springframework/security/access/expression/method/DefaultMethodSecurityExpressionHandler.java @@ -16,6 +16,7 @@ import org.springframework.expression.ExpressionParser; import org.springframework.expression.spel.standard.SpelExpressionParser; import org.springframework.security.access.PermissionEvaluator; import org.springframework.security.access.expression.ExpressionUtils; +import org.springframework.security.access.hierarchicalroles.RoleHierarchy; import org.springframework.security.authentication.AuthenticationTrustResolver; import org.springframework.security.authentication.AuthenticationTrustResolverImpl; import org.springframework.security.core.Authentication; @@ -37,6 +38,7 @@ public class DefaultMethodSecurityExpressionHandler implements MethodSecurityExp private PermissionEvaluator permissionEvaluator = new DenyAllPermissionEvaluator(); private AuthenticationTrustResolver trustResolver = new AuthenticationTrustResolverImpl(); private ExpressionParser expressionParser = new SpelExpressionParser(); + private RoleHierarchy roleHierarchy; public DefaultMethodSecurityExpressionHandler() { } @@ -50,6 +52,7 @@ public class DefaultMethodSecurityExpressionHandler implements MethodSecurityExp MethodSecurityExpressionRoot root = new MethodSecurityExpressionRoot(auth); root.setTrustResolver(trustResolver); root.setPermissionEvaluator(permissionEvaluator); + root.setRoleHierarchy(roleHierarchy); ctx.setRootObject(root); return ctx; @@ -141,4 +144,7 @@ public class DefaultMethodSecurityExpressionHandler implements MethodSecurityExp ((MethodSecurityExpressionRoot)ctx.getRootObject().getValue()).setReturnObject(returnObject); } + public void setRoleHierarchy(RoleHierarchy roleHierarchy) { + this.roleHierarchy = roleHierarchy; + } } diff --git a/core/src/test/java/org/springframework/security/access/expression/SecurityExpressionRootTests.java b/core/src/test/java/org/springframework/security/access/expression/SecurityExpressionRootTests.java new file mode 100644 index 0000000000..0b4d1aa900 --- /dev/null +++ b/core/src/test/java/org/springframework/security/access/expression/SecurityExpressionRootTests.java @@ -0,0 +1,38 @@ +package org.springframework.security.access.expression; + +import static org.junit.Assert.*; + +import java.util.List; + +import org.junit.Test; +import org.springframework.security.access.hierarchicalroles.RoleHierarchy; +import org.springframework.security.authentication.TestingAuthenticationToken; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.AuthorityUtils; + +/** + * + * @author Luke Taylor + * @version $Id$ + * @since 3.0 + */ +public class SecurityExpressionRootTests { + + @Test + public void roleHierarchySupportIsCorrectlyUsedInEvaluatingRoles() throws Exception { + SecurityExpressionRoot root = + new SecurityExpressionRoot(new TestingAuthenticationToken("joe", "pass", "A", "B")) {}; + + root.setRoleHierarchy(new RoleHierarchy() { + public List getReachableGrantedAuthorities(List authorities) { + return AuthorityUtils.createAuthorityList("C"); + } + }); + + assertTrue(root.hasRole("C")); + assertFalse(root.hasRole("A")); + assertFalse(root.hasRole("B")); + assertTrue(root.hasAnyRole("C", "A", "B")); + assertFalse(root.hasAnyRole("A", "B")); + } +} diff --git a/web/src/main/java/org/springframework/security/web/access/expression/DefaultWebSecurityExpressionHandler.java b/web/src/main/java/org/springframework/security/web/access/expression/DefaultWebSecurityExpressionHandler.java index 110fe4d682..2fea10df66 100644 --- a/web/src/main/java/org/springframework/security/web/access/expression/DefaultWebSecurityExpressionHandler.java +++ b/web/src/main/java/org/springframework/security/web/access/expression/DefaultWebSecurityExpressionHandler.java @@ -5,6 +5,7 @@ import org.springframework.expression.ExpressionParser; import org.springframework.expression.spel.standard.SpelExpressionParser; import org.springframework.expression.spel.support.StandardEvaluationContext; import org.springframework.security.access.expression.SecurityExpressionRoot; +import org.springframework.security.access.hierarchicalroles.RoleHierarchy; import org.springframework.security.authentication.AuthenticationTrustResolver; import org.springframework.security.authentication.AuthenticationTrustResolverImpl; import org.springframework.security.core.Authentication; @@ -22,6 +23,7 @@ public class DefaultWebSecurityExpressionHandler implements WebSecurityExpressio private AuthenticationTrustResolver trustResolver = new AuthenticationTrustResolverImpl(); private ExpressionParser expressionParser = new SpelExpressionParser(); + private RoleHierarchy roleHierarchy; public ExpressionParser getExpressionParser() { return expressionParser; @@ -31,8 +33,13 @@ public class DefaultWebSecurityExpressionHandler implements WebSecurityExpressio StandardEvaluationContext ctx = new StandardEvaluationContext(); SecurityExpressionRoot root = new WebSecurityExpressionRoot(authentication, fi); root.setTrustResolver(trustResolver); + root.setRoleHierarchy(roleHierarchy); ctx.setRootObject(root); return ctx; } + + public void setRoleHierarchy(RoleHierarchy roleHierarchy) { + this.roleHierarchy = roleHierarchy; + } }