diff --git a/docs/manual/src/asciidoc/index.adoc b/docs/manual/src/asciidoc/index.adoc index a801a07c7e..495e7ee353 100644 --- a/docs/manual/src/asciidoc/index.adoc +++ b/docs/manual/src/asciidoc/index.adoc @@ -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. ---- +When used in conjuction with Spring Security's PermissionEvaluator, the tag can also be used to check permissions. For example: + +[source,xml] +---- + + + This content will only be visible to users who have read or write permission to the Object found as a request attribute named "domain". + + +---- + 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 <>. [source,xml] ---- - 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. ---- -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. diff --git a/taglibs/src/main/java/org/springframework/security/taglibs/authz/AccessControlListTag.java b/taglibs/src/main/java/org/springframework/security/taglibs/authz/AccessControlListTag.java index c16aa1535c..b515f5451b 100644 --- a/taglibs/src/main/java/org/springframework/security/taglibs/authz/AccessControlListTag.java +++ b/taglibs/src/main/java/org/springframework/security/taglibs/authz/AccessControlListTag.java @@ -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. *

* One or more comma separate numeric are specified via the {@code hasPermission} attribute. The tag delegates diff --git a/taglibs/src/test/java/org/springframework/security/taglibs/authz/AuthorizeTagTests.java b/taglibs/src/test/java/org/springframework/security/taglibs/authz/AuthorizeTagTests.java index f390abd411..3c1bbcca59 100644 --- a/taglibs/src/test/java/org/springframework/security/taglibs/authz/AuthorizeTagTests.java +++ b/taglibs/src/test/java/org/springframework/security/taglibs/authz/AuthorizeTagTests.java @@ -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();