SEC-2615: accesscontrollist tag hasPermission performs OR not AND
In 3.1 the accesscontrollist tag began performing an and on the permissions. This may have been accidental, but I think that it is more intuitive & secure for it to behave this way. When compared to hasAnyRole and hasRoles the hasPermission tag implies it is an and. If users end up needing OR support, then the authorize tag can be used along with the hasPermission expression. For example: <sec:authorize access="hasPermission(#domain, 'read') or hasPermission(#domain, 'write') "> In general, the authorize tag should be preferred as it is the more powerful way of performing authorization checks.
This commit is contained in:
parent
f20219d541
commit
55d6d5a86a
|
@ -4978,6 +4978,7 @@ To use any of the tags, you must have the security taglib declared in your JSP:
|
|||
<%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags" %>
|
||||
----
|
||||
|
||||
[[taglibs-authorize]]
|
||||
=== The authorize Tag
|
||||
This tag is used to determine whether its contents should be evaluated or not. In Spring Security 3.0, it can be used in two ways footnote:[
|
||||
The legacy options from Spring Security 2.0 are also supported, but discouraged.
|
||||
|
@ -4992,6 +4993,17 @@ The legacy options from Spring Security 2.0 are also supported, but discouraged.
|
|||
</sec:authorize>
|
||||
----
|
||||
|
||||
When used in conjuction with Spring Security's PermissionEvaluator, the tag can also be used to check permissions. For example:
|
||||
|
||||
[source,xml]
|
||||
----
|
||||
<sec:authorize access="hasPermission(#domain,'read') or hasPermission(#domain,'write')">
|
||||
|
||||
This content will only be visible to users who have read or write permission to the Object found as a request attribute named "domain".
|
||||
|
||||
</sec:authorize>
|
||||
----
|
||||
|
||||
A common requirement is to only show a particular link, if the user is actually allowed to click it. How can we determine in advance whether something will be allowed? This tag can also operate in an alternative mode which allows you to define a particular URL as an attribute. If the user is allowed to invoke that URL, then the tag body will be evaluated, otherwise it will be skipped. So you might have something like
|
||||
|
||||
[source,xml]
|
||||
|
@ -5021,18 +5033,20 @@ Of course, it isn't necessary to use JSP tags for this kind of thing and some pe
|
|||
|
||||
|
||||
=== The accesscontrollist Tag
|
||||
This tag is only valid when used with Spring Security's ACL module. It checks a comma-separated list of required permissions for a specified domain object. If the current user has any of those permissions, then the tag body will be evaluated. If they don't, it will be skipped. An example might be
|
||||
This tag is only valid when used with Spring Security's ACL module. It checks a comma-separated list of required permissions for a specified domain object. If the current user has all of those permissions, then the tag body will be evaluated. If they don't, it will be skipped. An example might be
|
||||
|
||||
CAUTION: In general this tag should be considered deprecated. Instead use the <<taglibs-authorize>>.
|
||||
|
||||
[source,xml]
|
||||
----
|
||||
<sec:accesscontrollist hasPermission="1,2" domainObject="${someObject}">
|
||||
|
||||
This will be shown if the user has either of the permissions represented by the values "1" or "2" on the given object.
|
||||
This will be shown if the user has all of the permissions represented by the values "1" or "2" on the given object.
|
||||
|
||||
</sec:accesscontrollist>
|
||||
----
|
||||
|
||||
The permissions are passed to the `PermissionFactory` defined in the application context, converting them to ACL `Permission` instances, so they may be any format which is supported by the factory - they don't have to be integers, they could be strings like `READ` or `WRITE`. If no `PermissionFactory` is found, an instance of `DefaultPermissionFactory` will be used. The `AclService` from the application context will be used to load the `Acl` instance for the supplied object. The `Acl` will be invoked with the required permissions to check if any of them are granted.
|
||||
The permissions are passed to the `PermissionFactory` defined in the application context, converting them to ACL `Permission` instances, so they may be any format which is supported by the factory - they don't have to be integers, they could be strings like `READ` or `WRITE`. If no `PermissionFactory` is found, an instance of `DefaultPermissionFactory` will be used. The `AclService` from the application context will be used to load the `Acl` instance for the supplied object. The `Acl` will be invoked with the required permissions to check if all of them are granted.
|
||||
|
||||
This tag also supports the `var` attribute, in the same way as the `authorize` tag.
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@ import java.util.*;
|
|||
|
||||
|
||||
/**
|
||||
* An implementation of {@link Tag} that allows its body through if some authorizations are granted to the request's
|
||||
* An implementation of {@link Tag} that allows its body through if all authorizations are granted to the request's
|
||||
* principal.
|
||||
* <p>
|
||||
* One or more comma separate numeric are specified via the {@code hasPermission} attribute. The tag delegates
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
|
||||
package org.springframework.security.taglibs.authz;
|
||||
|
||||
import static org.mockito.Mockito.*;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import javax.servlet.jsp.JspException;
|
||||
|
@ -23,10 +24,15 @@ import javax.servlet.jsp.tagext.Tag;
|
|||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
import org.springframework.mock.web.MockPageContext;
|
||||
import org.springframework.mock.web.MockServletContext;
|
||||
import org.springframework.security.access.PermissionEvaluator;
|
||||
import org.springframework.security.authentication.TestingAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
|
@ -40,9 +46,12 @@ import org.springframework.web.context.support.StaticWebApplicationContext;
|
|||
* @author Francois Beausoleil
|
||||
* @author Luke Taylor
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class AuthorizeTagTests {
|
||||
//~ Instance fields ================================================================================================
|
||||
|
||||
@Mock
|
||||
private PermissionEvaluator permissionEvaluator;
|
||||
private JspAuthorizeTag authorizeTag;
|
||||
private MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
private final TestingAuthenticationToken currentUser = new TestingAuthenticationToken("abc", "123", "ROLE SUPERVISOR", "ROLE_TELLER");
|
||||
|
@ -53,7 +62,11 @@ public class AuthorizeTagTests {
|
|||
public void setUp() throws Exception {
|
||||
SecurityContextHolder.getContext().setAuthentication(currentUser);
|
||||
StaticWebApplicationContext ctx = new StaticWebApplicationContext();
|
||||
ctx.registerSingleton("expressionHandler", DefaultWebSecurityExpressionHandler.class);
|
||||
|
||||
BeanDefinitionBuilder webExpressionHandler = BeanDefinitionBuilder.rootBeanDefinition(DefaultWebSecurityExpressionHandler.class);
|
||||
webExpressionHandler.addPropertyValue("permissionEvaluator", permissionEvaluator);
|
||||
|
||||
ctx.registerBeanDefinition("expressionHandler", webExpressionHandler.getBeanDefinition());
|
||||
ctx.registerSingleton("wipe", MockWebInvocationPrivilegeEvaluator.class);
|
||||
MockServletContext servletCtx = new MockServletContext();
|
||||
servletCtx.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, ctx);
|
||||
|
@ -68,6 +81,16 @@ public class AuthorizeTagTests {
|
|||
|
||||
// access attribute tests
|
||||
|
||||
@Test
|
||||
public void taglibsDocumentationHasPermissionOr() throws Exception {
|
||||
Object domain = new Object();
|
||||
request.setAttribute("domain", domain);
|
||||
authorizeTag.setAccess("hasPermission(#domain,'read') or hasPermission(#domain,'write')");
|
||||
when(permissionEvaluator.hasPermission(eq(currentUser), eq(domain), anyString())).thenReturn(true);
|
||||
|
||||
assertEquals(Tag.EVAL_BODY_INCLUDE, authorizeTag.doStartTag());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void skipsBodyIfNoAuthenticationPresent() throws Exception {
|
||||
SecurityContextHolder.clearContext();
|
||||
|
|
Loading…
Reference in New Issue