Browse Source

SEC-524: Added "var" attribute to authorize and accesscontrollist JSP tags.

Allows the result of the boolean condition granting/denying access to be stored in the page context for later use, without having to duplicate the tag.
pull/1/head
Luke Taylor 16 years ago
parent
commit
bf91f2ca67
  1. 1
      itest/web/src/main/resources/log4j.properties
  2. 6
      itest/web/src/main/webapp/WEB-INF/http-security.xml
  3. 1
      itest/web/src/main/webapp/WEB-INF/in-memory-provider.xml
  4. 19
      itest/web/src/main/webapp/WEB-INF/security.tld
  5. 21
      itest/web/src/main/webapp/secure/authorizationTagTestPage.jsp
  6. 13
      itest/web/src/test/java/org/springframework/security/integration/InMemoryProviderWebAppTests.java
  7. 39
      itest/web/src/test/java/org/springframework/security/integration/JspTaglibTests.java
  8. 33
      taglibs/src/main/java/org/springframework/security/taglibs/authz/AccessControlListTag.java
  9. 20
      taglibs/src/main/java/org/springframework/security/taglibs/authz/AuthorizeTag.java
  10. 19
      taglibs/src/main/resources/META-INF/security.tld
  11. 13
      taglibs/src/test/java/org/springframework/security/taglibs/authz/AccessControlListTagTests.java

1
itest/web/src/main/resources/log4j.properties

@ -7,4 +7,5 @@ log4j.appender.stdout.layout.ConversionPattern=%d %p %c - %m%n @@ -7,4 +7,5 @@ log4j.appender.stdout.layout.ConversionPattern=%d %p %c - %m%n
log4j.category.org.apache.jasper=INFO
log4j.category.org.apache.directory=ERROR
log4j.category.org.mortbay.log=INFO
log4j.category.httpclient.wire=INFO
log4j.category.org.springframework.security=TRACE

6
itest/web/src/main/webapp/WEB-INF/http-security.xml

@ -11,10 +11,10 @@ @@ -11,10 +11,10 @@
Needs to be supplemented with authentication provider(s)
-->
<http>
<http use-expressions="true">
<intercept-url pattern="/login.jsp*" filters="none" />
<intercept-url pattern="/secure/**" access="ROLE_DEVELOPER,ROLE_USER" />
<intercept-url pattern="/**" access="ROLE_DEVELOPER,ROLE_USER" />
<intercept-url pattern="/secure/**" access="hasAnyRole('ROLE_DEVELOPER','ROLE_USER')" />
<intercept-url pattern="/**" access="hasAnyRole('ROLE_DEVELOPER','ROLE_USER')" />
<form-login login-page="/login.jsp" authentication-failure-url="/login.jsp?login_error=true"/>
<http-basic/>

1
itest/web/src/main/webapp/WEB-INF/in-memory-provider.xml

@ -12,6 +12,7 @@ @@ -12,6 +12,7 @@
<user name="miles" password="milespassword" authorities="ROLE_USER,ROLE_JAZZ,ROLE_TRUMPETER"/>
<user name="johnc" password="johncspassword" authorities="ROLE_USER,ROLE_JAZZ,ROLE_SAXOPHONIST"/>
<user name="jimi" password="jimispassword" authorities="ROLE_USER,ROLE_ROCK,ROLE_GUITARIST"/>
<user name="bessie" password="bessiespassword" authorities="ROLE_USER,ROLE_JAZZ,ROLE_SINGER"/>
<user name="theescapist&lt;&gt;&amp;." password="theescapistspassword" authorities="ROLE_USER"/>
</user-service>
</authentication-provider>

19
itest/web/src/main/webapp/WEB-INF/security.tld

@ -9,7 +9,6 @@ @@ -9,7 +9,6 @@
<uri>http://www.springframework.org/security/tags</uri>
<description>
Spring Security Authorization Tag Library
$Id$
</description>
<tag>
@ -51,6 +50,15 @@ @@ -51,6 +50,15 @@
</description>
</attribute>
<attribute>
<name>var</name>
<required>false</required>
<rtexprvalue>false</rtexprvalue>
<description>
A page scoped variable into which the boolean result of the tag evaluation will be written, allowing the
same condition to be reused subsequently in the page without re-evaluation.
</description>
</attribute>
<attribute>
<name>ifNotGranted</name>
@ -153,6 +161,15 @@ @@ -153,6 +161,15 @@
are being evaluated.
</description>
</attribute>
<attribute>
<name>var</name>
<required>false</required>
<rtexprvalue>false</rtexprvalue>
<description>
A page scoped variable into which the boolean result of the tag evaluation will be written, allowing the
same condition to be reused subsequently in the page without re-evaluation.
</description>
</attribute>
</tag>
</taglib>

21
itest/web/src/main/webapp/secure/authorizationTagTestPage.jsp

@ -0,0 +1,21 @@ @@ -0,0 +1,21 @@
<%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags" %>
<html>
<body>
<h1>Authorization Tag Test Page</h1>
<sec:authorize access="hasRole('ROLE_USER')" var="allowed">
Users can see this and 'allowed' variable is ${allowed}.
</sec:authorize>
<sec:authorize access="hasRole('ROLE_X')" var="allowed">
Role X users (nobody) can see this.
</sec:authorize>
Role X expression evaluates to ${allowed}.
</body>
</html>

13
itest/web/src/test/java/org/springframework/security/integration/InMemoryProviderWebAppTests.java

@ -94,17 +94,4 @@ public class InMemoryProviderWebAppTests extends AbstractWebServerIntegrationTes @@ -94,17 +94,4 @@ public class InMemoryProviderWebAppTests extends AbstractWebServerIntegrationTes
tester.gotoPage("secure/index.html");
tester.assertTextPresent("This session has been expired");
}
@Test
public void authenticationTagEscapingWorksCorrectly() {
beginAt("secure/authenticationTagTestPage.jsp");
login("theescapist<>&.", "theescapistspassword");
String response = tester.getServerResponse();
assertTrue(response.contains("This is the unescaped authentication name: theescapist<>&."));
assertTrue(response.contains("This is the unescaped principal.username: theescapist<>&."));
assertTrue(response.contains("This is the authentication name: theescapist&lt;&gt;&amp;&#46;"));
assertTrue(response.contains("This is the principal.username: theescapist&lt;&gt;&amp;&#46;"));
}
}

39
itest/web/src/test/java/org/springframework/security/integration/JspTaglibTests.java

@ -0,0 +1,39 @@ @@ -0,0 +1,39 @@
package org.springframework.security.integration;
import static org.testng.Assert.*;
import org.testng.annotations.Test;
/**
*
* @author Luke Taylor
*/
public final class JspTaglibTests extends AbstractWebServerIntegrationTests {
@Override
protected String getContextConfigLocations() {
return "/WEB-INF/http-security.xml /WEB-INF/in-memory-provider.xml";
}
@Test
public void authenticationTagEscapingWorksCorrectly() {
beginAt("secure/authenticationTagTestPage.jsp");
login("theescapist<>&.", "theescapistspassword");
String response = tester.getServerResponse();
assertTrue(response.contains("This is the unescaped authentication name: theescapist<>&."));
assertTrue(response.contains("This is the unescaped principal.username: theescapist<>&."));
assertTrue(response.contains("This is the authentication name: theescapist&lt;&gt;&amp;&#46;"));
assertTrue(response.contains("This is the principal.username: theescapist&lt;&gt;&amp;&#46;"));
}
@Test
public void authorizationTagEvaluatesExpressionCorrectlyAndWritesValueToVariable() {
beginAt("secure/authorizationTagTestPage.jsp");
login("bessie", "bessiespassword");
String response = tester.getServerResponse();
assertTrue(response.contains("Users can see this and 'allowed' variable is true."));
assertFalse(response.contains("Role X users (nobody) can see this."));
assertTrue(response.contains("Role X expression evaluates to false"));
}
}

33
taglibs/src/main/java/org/springframework/security/taglibs/authz/AccessControlListTag.java

@ -66,6 +66,7 @@ import org.springframework.web.util.ExpressionEvaluationUtils; @@ -66,6 +66,7 @@ import org.springframework.web.util.ExpressionEvaluationUtils;
* implementations are found in the application context.
*
* @author Ben Alex
* @author Luke Taylor
*/
public class AccessControlListTag extends TagSupport {
//~ Static fields/initializers =====================================================================================
@ -81,12 +82,13 @@ public class AccessControlListTag extends TagSupport { @@ -81,12 +82,13 @@ public class AccessControlListTag extends TagSupport {
private SidRetrievalStrategy sidRetrievalStrategy;
private PermissionFactory permissionFactory;
private String hasPermission = "";
private String var;
//~ Methods ========================================================================================================
public int doStartTag() throws JspException {
if ((null == hasPermission) || "".equals(hasPermission)) {
return Tag.SKIP_BODY;
return skipBody();
}
initializeIfRequired();
@ -111,7 +113,7 @@ public class AccessControlListTag extends TagSupport { @@ -111,7 +113,7 @@ public class AccessControlListTag extends TagSupport {
}
// Of course they have access to a null object!
return Tag.EVAL_BODY_INCLUDE;
return evalBody();
}
if (SecurityContextHolder.getContext().getAuthentication() == null) {
@ -120,7 +122,7 @@ public class AccessControlListTag extends TagSupport { @@ -120,7 +122,7 @@ public class AccessControlListTag extends TagSupport {
"SecurityContextHolder did not return a non-null Authentication object, so skipping tag body");
}
return Tag.SKIP_BODY;
return skipBody();
}
List<Sid> sids = sidRetrievalStrategy.getSids(SecurityContextHolder.getContext().getAuthentication());
@ -131,15 +133,30 @@ public class AccessControlListTag extends TagSupport { @@ -131,15 +133,30 @@ public class AccessControlListTag extends TagSupport {
Acl acl = aclService.readAclById(oid, sids);
if (acl.isGranted(requiredPermissions, sids, false)) {
return Tag.EVAL_BODY_INCLUDE;
return evalBody();
} else {
return Tag.SKIP_BODY;
return skipBody();
}
} catch (NotFoundException nfe) {
return Tag.SKIP_BODY;
return skipBody();
}
}
private int skipBody() {
if (var != null) {
pageContext.setAttribute(var, Boolean.FALSE, PageContext.PAGE_SCOPE);
}
return SKIP_BODY;
}
private int evalBody() {
if (var != null) {
pageContext.setAttribute(var, Boolean.TRUE, PageContext.PAGE_SCOPE);
}
return EVAL_BODY_INCLUDE;
}
/**
* Allows test cases to override where application context obtained from.
*
@ -233,4 +250,8 @@ public class AccessControlListTag extends TagSupport { @@ -233,4 +250,8 @@ public class AccessControlListTag extends TagSupport {
public void setHasPermission(String hasPermission) {
this.hasPermission = hasPermission;
}
public void setVar(String var) {
this.var = var;
}
}

20
taglibs/src/main/java/org/springframework/security/taglibs/authz/AuthorizeTag.java

@ -10,6 +10,7 @@ import javax.servlet.ServletRequest; @@ -10,6 +10,7 @@ import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.PageContext;
import org.springframework.context.ApplicationContext;
import org.springframework.expression.Expression;
@ -35,6 +36,7 @@ public class AuthorizeTag extends LegacyAuthorizeTag { @@ -35,6 +36,7 @@ public class AuthorizeTag extends LegacyAuthorizeTag {
private String access;
private String url;
private String method;
private String var;
// If access expression evaluates to "true" return
public int doStartTag() throws JspException {
@ -44,13 +46,21 @@ public class AuthorizeTag extends LegacyAuthorizeTag { @@ -44,13 +46,21 @@ public class AuthorizeTag extends LegacyAuthorizeTag {
return SKIP_BODY;
}
int result;
if (access != null && access.length() > 0) {
return authorizeUsingAccessExpression(currentUser);
result = authorizeUsingAccessExpression(currentUser);
} else if (url != null && url.length() > 0) {
return authorizeUsingUrlCheck(currentUser);
result = authorizeUsingUrlCheck(currentUser);
} else {
result = super.doStartTag();
}
if (var != null) {
pageContext.setAttribute(var, Boolean.valueOf(result == EVAL_BODY_INCLUDE), PageContext.PAGE_SCOPE);
}
return super.doStartTag();
return result;
}
private int authorizeUsingAccessExpression(Authentication currentUser) throws JspException {
@ -91,6 +101,10 @@ public class AuthorizeTag extends LegacyAuthorizeTag { @@ -91,6 +101,10 @@ public class AuthorizeTag extends LegacyAuthorizeTag {
this.method = method;
}
public void setVar(String var) {
this.var = var;
}
WebSecurityExpressionHandler getExpressionHandler() throws JspException {
ServletContext servletContext = pageContext.getServletContext();
ApplicationContext ctx = WebApplicationContextUtils.getRequiredWebApplicationContext(servletContext);

19
taglibs/src/main/resources/META-INF/security.tld

@ -9,7 +9,6 @@ @@ -9,7 +9,6 @@
<uri>http://www.springframework.org/security/tags</uri>
<description>
Spring Security Authorization Tag Library
$Id$
</description>
<tag>
@ -51,6 +50,15 @@ @@ -51,6 +50,15 @@
</description>
</attribute>
<attribute>
<name>var</name>
<required>false</required>
<rtexprvalue>false</rtexprvalue>
<description>
A page scoped variable into which the boolean result of the tag evaluation will be written, allowing the
same condition to be reused subsequently in the page without re-evaluation.
</description>
</attribute>
<attribute>
<name>ifNotGranted</name>
@ -153,6 +161,15 @@ @@ -153,6 +161,15 @@
are being evaluated.
</description>
</attribute>
<attribute>
<name>var</name>
<required>false</required>
<rtexprvalue>false</rtexprvalue>
<description>
A page scoped variable into which the boolean result of the tag evaluation will be written, allowing the
same condition to be reused subsequently in the page without re-evaluation.
</description>
</attribute>
</tag>
</taglib>

13
taglibs/src/test/java/org/springframework/security/taglibs/authz/AccessControlListTagTests.java

@ -1,6 +1,6 @@ @@ -1,6 +1,6 @@
package org.springframework.security.taglibs.authz;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.*;
import static org.mockito.Matchers.*;
import static org.mockito.Mockito.*;
@ -33,6 +33,7 @@ import org.springframework.web.context.WebApplicationContext; @@ -33,6 +33,7 @@ import org.springframework.web.context.WebApplicationContext;
public class AccessControlListTagTests {
AccessControlListTag tag;
Acl acl;
MockPageContext pageContext;
@Before
public void setup() {
@ -44,9 +45,6 @@ public class AccessControlListTagTests { @@ -44,9 +45,6 @@ public class AccessControlListTagTests {
ObjectIdentity oid = mock(ObjectIdentity.class);
ObjectIdentityRetrievalStrategy oidStrategy = mock(ObjectIdentityRetrievalStrategy.class);
when(oidStrategy.getObjectIdentity(anyObject())).thenReturn(oid);
// AclPermissionEvaluator pe = new AclPermissionEvaluator(service);
// pe.setObjectIdentityRetrievalStrategy(oidStrategy);
// pe.setSidRetrievalStrategy(mock(SidRetrievalStrategy.class));
acl = mock(Acl.class);
when(service.readAclById(any(ObjectIdentity.class), anyList())).thenReturn(acl);
@ -59,7 +57,8 @@ public class AccessControlListTagTests { @@ -59,7 +57,8 @@ public class AccessControlListTagTests {
MockServletContext servletCtx = new MockServletContext();
servletCtx.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, ctx);
tag.setPageContext(new MockPageContext(servletCtx, new MockHttpServletRequest(), new MockHttpServletResponse()));
pageContext = new MockPageContext(servletCtx, new MockHttpServletRequest(), new MockHttpServletResponse());
tag.setPageContext(pageContext);
}
@After
@ -73,8 +72,10 @@ public class AccessControlListTagTests { @@ -73,8 +72,10 @@ public class AccessControlListTagTests {
tag.setDomainObject(new Object());
tag.setHasPermission("READ");
tag.setVar("allowed");
assertEquals(Tag.EVAL_BODY_INCLUDE, tag.doStartTag());
assertTrue((Boolean)pageContext.getAttribute("allowed"));
}
@Test
@ -83,8 +84,10 @@ public class AccessControlListTagTests { @@ -83,8 +84,10 @@ public class AccessControlListTagTests {
tag.setDomainObject(new Object());
tag.setHasPermission("READ");
tag.setVar("allowed");
assertEquals(Tag.SKIP_BODY, tag.doStartTag());
assertFalse((Boolean)pageContext.getAttribute("allowed"));
}
}

Loading…
Cancel
Save