Reputation: 145
How you would do an expression to permit access to all roles unless one, without declaring them all in spring-security.xml?
We have four roles: private
, user1
, user2
and user3
. private
is the only role that can execute certain services. The other are allowed only to user1
, user2
and user3
.
<http pattern="/priv/**">
<intercept-url pattern="/**" access="hasRole('private')"/>
<http-basic/>
</http>
<http pattern="/pub/**">
<intercept-url pattern="/**" access="!hasRole('private')"/>
<http-basic/>
</http>
I know that with this, the problem would be solved, but in the case of an user having private
and user2
for example, this user should can execute the /priv/
and the /pub/
operation. How could the xml be configured?
If the user has two roles (private
and one more of the others), both operations would be allowed.
Upvotes: 1
Views: 247
Reputation: 120831
You can implement an extension of WebSecurityExpressionRoot
with a method boolean hasAnyRoleExcept(String... ignoredRoles)
sketch (written without IDE support):
import org.springframework.security.core.authority.AuthorityUtils;
public class MyWebSecurityExpressionRoot extends WebSecurityExpressionRoot {
public MyWebSecurityExpressionRoot(final Authentication a, final FilterInvocation fi) {
super(a, fi);
}
public boolean hasAnyRoleExcept(String... ignoredRoles) {
//see SecurityExpressionRoot.hasAnyRole
Set<String> roles =
AuthorityUtils.authorityListToSet(
getAuthentication().getAuthorities());
//find a not ignored role
for (String role : roles) {
if (!ignoredRoles.contains(role)) {
return true;
}
}
return false;
}
}
To register it:
public class MyWebSecurityExpressionHandler extends DefaultWebSecurityExpressionHandler {
//Attention: override setTrustResolver too.
private AuthenticationTrustResolver trustResolver = new AuthenticationTrustResolverImpl();
@Override
protected SecurityExpressionOperations createSecurityExpressionRoot(Authentication authentication, FilterInvocation fi) {
MyWebSecurityExpressionRoot root = new MyWebSecurityExpressionRoot(authentication, fi);
root.setPermissionEvaluator(getPermissionEvaluator());
root.setTrustResolver(trustResolver);
root.setRoleHierarchy(getRoleHierarchy());
return root;
}
}
<security:http use-expressions="true" ...>
...
<security:expression-handler ref="myWebSecurityExpressionHandler"/>
<security:intercept-url pattern="/**" access="hasAnyRoleExcept('private')"/>
</security:http>
<bean id="myWebSecurityExpressionHandler" class="MyWebSecurityExpressionHandler"/>
Upvotes: 0
Reputation: 6308
You can make use of RoleHierarchy
to simplify your security configuration.
<bean id="roleVoter" class="org.springframework.security.access.vote.RoleHierarchyVoter">
<constructor-arg ref="roleHierarchy" />
</bean>
<bean id="roleHierarchy"
class="org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl">
<property name="hierarchy">
<value>
ROLE_PRIVATE > ROLE_USER
ROLE_USER > ROLE_USER1 > ROLE_USER2 > ROLE_USER3
</value>
</property>
</bean>
And then in your http
configuration:
<http pattern="/priv/**">
<intercept-url pattern="/**" access="hasRole('PRIVATE')"/>
<http-basic/>
</http>
<http pattern="/pub/**">
<intercept-url pattern="/**" access="hasRole('USER')"/>
<http-basic/>
</http>
This way your ROLE_USER
will "embed" all other ROLE_USERX
rules, and ROLE_PRIVATE
will embed all from ROLE_USER
.
You should also refer to the Spring Security Reference.
Upvotes: 0