SEC-1420: Add htmlEscape attribute to authentication JSP tag.
This allows HTML escaping to be disabled if required.
This commit is contained in:
parent
43f3568b16
commit
0551dd89ac
|
@ -15,8 +15,10 @@
|
|||
|
||||
package org.springframework.security.core.userdetails.memory;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.security.core.authority.AuthorityUtils;
|
||||
import org.springframework.security.core.userdetails.User;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
|
@ -29,9 +31,9 @@ import org.springframework.security.core.userdetails.memory.UserMap;
|
|||
*
|
||||
* @author Ben Alex
|
||||
*/
|
||||
public class UserMapTests extends TestCase {
|
||||
public class UserMapTests {
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
@Test
|
||||
public void testAddAndRetrieveUser() {
|
||||
UserDetails rod = new User("rod", "koala", true, true, true, true,
|
||||
AuthorityUtils.createAuthorityList("ROLE_ONE","ROLE_TWO"));
|
||||
|
@ -50,7 +52,8 @@ public class UserMapTests extends TestCase {
|
|||
assertEquals(peter, map.getUser("peter"));
|
||||
}
|
||||
|
||||
public void testNullUserCannotBeAdded() {
|
||||
@Test
|
||||
public void nullUserCannotBeAdded() {
|
||||
UserMap map = new UserMap();
|
||||
assertEquals(0, map.getUserCount());
|
||||
|
||||
|
@ -62,7 +65,8 @@ public class UserMapTests extends TestCase {
|
|||
}
|
||||
}
|
||||
|
||||
public void testUnknownUserIsNotRetrieved() {
|
||||
@Test
|
||||
public void unknownUserIsNotRetrieved() {
|
||||
UserDetails rod = new User("rod", "koala", true, true, true, true,
|
||||
AuthorityUtils.createAuthorityList("ROLE_ONE","ROLE_TWO"));
|
||||
UserMap map = new UserMap();
|
||||
|
|
|
@ -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="theescapist<>&." password="theescapistspassword" authorities="ROLE_USER"/>
|
||||
</user-service>
|
||||
</authentication-provider>
|
||||
</authentication-manager>
|
||||
|
|
|
@ -0,0 +1,158 @@
|
|||
<?xml version="1.0" encoding="ISO-8859-1" ?>
|
||||
<!DOCTYPE taglib
|
||||
PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN"
|
||||
"http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">
|
||||
<taglib>
|
||||
<tlib-version>1.0</tlib-version>
|
||||
<jsp-version>1.2</jsp-version>
|
||||
<short-name>security</short-name>
|
||||
<uri>http://www.springframework.org/security/tags</uri>
|
||||
<description>
|
||||
Spring Security Authorization Tag Library
|
||||
$Id$
|
||||
</description>
|
||||
|
||||
<tag>
|
||||
<name>authorize</name>
|
||||
<tag-class>org.springframework.security.taglibs.authz.AuthorizeTag</tag-class>
|
||||
<description>
|
||||
A tag which outputs the body of the tag if the configured access expression
|
||||
evaluates to true for the currently authenticated principal.
|
||||
</description>
|
||||
|
||||
<attribute>
|
||||
<name>access</name>
|
||||
<required>false</required>
|
||||
<rtexprvalue>false</rtexprvalue>
|
||||
<description>
|
||||
A Spring-EL expression which is supported by the WebSecurityExpressionHandler
|
||||
in the application context. The latter will be used to evaluate the expression.
|
||||
</description>
|
||||
</attribute>
|
||||
|
||||
<attribute>
|
||||
<name>url</name>
|
||||
<required>false</required>
|
||||
<rtexprvalue>false</rtexprvalue>
|
||||
<description>
|
||||
A URL within the application. If the user has access to this URL (as determined by
|
||||
the AccessDecisionManager), the tag body will be evaluated. If not, it will
|
||||
be skipped.
|
||||
</description>
|
||||
</attribute>
|
||||
|
||||
<attribute>
|
||||
<name>method</name>
|
||||
<required>false</required>
|
||||
<rtexprvalue>false</rtexprvalue>
|
||||
<description>
|
||||
Can optionally be used to narrow down the HTTP method (typically GET or POST) to which the URL
|
||||
applies to. Only has any meaning when used in combination with the "url" attribute.
|
||||
</description>
|
||||
</attribute>
|
||||
|
||||
|
||||
<attribute>
|
||||
<name>ifNotGranted</name>
|
||||
<required>false</required>
|
||||
<rtexprvalue>true</rtexprvalue>
|
||||
<description>
|
||||
A comma separated list of roles which the user must not have
|
||||
for the body to be output. Deprecated in favour of the access expression.
|
||||
</description>
|
||||
</attribute>
|
||||
|
||||
<attribute>
|
||||
<name>ifAllGranted</name>
|
||||
<required>false</required>
|
||||
<rtexprvalue>true</rtexprvalue>
|
||||
<description>
|
||||
A comma separated list of roles which the user must all
|
||||
possess for the body to be output. Deprecated in favour of the access expression.
|
||||
</description>
|
||||
</attribute>
|
||||
|
||||
<attribute>
|
||||
<name>ifAnyGranted</name>
|
||||
<required>false</required>
|
||||
<rtexprvalue>true</rtexprvalue>
|
||||
<description>
|
||||
A comma separated list of roles, one of which the user must
|
||||
possess for the body to be output. Deprecated in favour of the access expression.
|
||||
</description>
|
||||
</attribute>
|
||||
</tag>
|
||||
|
||||
<tag>
|
||||
<name>authentication</name>
|
||||
<tag-class>org.springframework.security.taglibs.authz.AuthenticationTag</tag-class>
|
||||
<description>
|
||||
Allows access to the current Authentication object.
|
||||
</description>
|
||||
|
||||
<attribute>
|
||||
<name>property</name>
|
||||
<required>true</required>
|
||||
<rtexprvalue>true</rtexprvalue>
|
||||
<description>
|
||||
Property of the Authentication object which should be output. Supports nested
|
||||
properties. For example if the principal object is an instance of UserDetails,
|
||||
the property "principal.username" will return the username. Alternatively, using
|
||||
"name" will call getName method on the Authentication object directly.
|
||||
</description>
|
||||
</attribute>
|
||||
<attribute>
|
||||
<name>var</name>
|
||||
<required>false</required>
|
||||
<rtexprvalue>false</rtexprvalue>
|
||||
<description>
|
||||
Name of the exported scoped variable which will contain the
|
||||
evaluated property of the Authentication object.
|
||||
</description>
|
||||
</attribute>
|
||||
<attribute>
|
||||
<description>Set HTML escaping for this tag, as a boolean value.</description>
|
||||
<name>htmlEscape</name>
|
||||
<required>false</required>
|
||||
<rtexprvalue>true</rtexprvalue>
|
||||
</attribute>
|
||||
<attribute>
|
||||
<name>scope</name>
|
||||
<required>false</required>
|
||||
<rtexprvalue>false</rtexprvalue>
|
||||
<description>
|
||||
Scope for var.
|
||||
</description>
|
||||
</attribute>
|
||||
</tag>
|
||||
|
||||
<tag>
|
||||
<name>accesscontrollist</name>
|
||||
<tag-class>org.springframework.security.taglibs.authz.AccessControlListTag</tag-class>
|
||||
<description>
|
||||
Allows inclusion of a tag body if the current Authentication
|
||||
has one of the specified permissions to the presented
|
||||
domain object instance.
|
||||
</description>
|
||||
|
||||
<attribute>
|
||||
<name>hasPermission</name>
|
||||
<required>true</required>
|
||||
<rtexprvalue>true</rtexprvalue>
|
||||
<description>
|
||||
A comma separated list of permissions, which will be converted to
|
||||
Permission instances by the configured PermissionFactory.
|
||||
</description>
|
||||
</attribute>
|
||||
<attribute>
|
||||
<name>domainObject</name>
|
||||
<required>true</required>
|
||||
<rtexprvalue>true</rtexprvalue>
|
||||
<description>
|
||||
The actual domain object instance for which permissions
|
||||
are being evaluated.
|
||||
</description>
|
||||
</attribute>
|
||||
</tag>
|
||||
|
||||
</taglib>
|
|
@ -95,4 +95,16 @@ public class InMemoryProviderWebAppTests extends AbstractWebServerIntegrationTes
|
|||
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<>&."));
|
||||
assertTrue(response.contains("This is the principal.username: theescapist<>&."));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ import org.springframework.security.web.util.TextEscapeUtils;
|
|||
|
||||
import org.springframework.beans.BeanWrapperImpl;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.web.util.ExpressionEvaluationUtils;
|
||||
import org.springframework.web.util.TagUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
|
@ -48,6 +49,7 @@ public class AuthenticationTag extends TagSupport {
|
|||
private String property;
|
||||
private int scope;
|
||||
private boolean scopeSpecified;
|
||||
private boolean htmlEscape = true;
|
||||
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
@ -120,7 +122,11 @@ public class AuthenticationTag extends TagSupport {
|
|||
}
|
||||
}
|
||||
} else {
|
||||
writeMessage(TextEscapeUtils.escapeEntities(String.valueOf(result)));
|
||||
if (htmlEscape) {
|
||||
writeMessage(TextEscapeUtils.escapeEntities(String.valueOf(result)));
|
||||
} else {
|
||||
writeMessage(String.valueOf(result));
|
||||
}
|
||||
}
|
||||
return EVAL_PAGE;
|
||||
}
|
||||
|
@ -132,4 +138,21 @@ public class AuthenticationTag extends TagSupport {
|
|||
throw new JspException(ioe);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set HTML escaping for this tag, as boolean value.
|
||||
*/
|
||||
public void setHtmlEscape(String htmlEscape) throws JspException {
|
||||
this.htmlEscape = ExpressionEvaluationUtils.evaluateBoolean("htmlEscape", htmlEscape, pageContext);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the HTML escaping setting for this tag,
|
||||
* or the default setting if not overridden.
|
||||
* @see #isDefaultHtmlEscape()
|
||||
*/
|
||||
protected boolean isHtmlEscape() {
|
||||
return htmlEscape;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -110,6 +110,12 @@
|
|||
evaluated property of the Authentication object.
|
||||
</description>
|
||||
</attribute>
|
||||
<attribute>
|
||||
<description>Set HTML escaping for this tag, as a boolean value.</description>
|
||||
<name>htmlEscape</name>
|
||||
<required>false</required>
|
||||
<rtexprvalue>true</rtexprvalue>
|
||||
</attribute>
|
||||
<attribute>
|
||||
<name>scope</name>
|
||||
<required>false</required>
|
||||
|
|
|
@ -15,11 +15,13 @@
|
|||
|
||||
package org.springframework.security.taglibs.authz;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import javax.servlet.jsp.JspException;
|
||||
import javax.servlet.jsp.tagext.Tag;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Test;
|
||||
import org.springframework.security.authentication.TestingAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.authority.AuthorityUtils;
|
||||
|
@ -32,7 +34,7 @@ import org.springframework.security.core.userdetails.User;
|
|||
*
|
||||
* @author Ben Alex
|
||||
*/
|
||||
public class AuthenticationTagTests extends TestCase {
|
||||
public class AuthenticationTagTests {
|
||||
//~ Instance fields ================================================================================================
|
||||
|
||||
private final MyAuthenticationTag authenticationTag = new MyAuthenticationTag();
|
||||
|
@ -41,10 +43,12 @@ public class AuthenticationTagTests extends TestCase {
|
|||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
protected void tearDown() throws Exception {
|
||||
@After
|
||||
public void tearDown() {
|
||||
SecurityContextHolder.clearContext();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOperationWhenPrincipalIsAUserDetailsInstance()throws JspException {
|
||||
SecurityContextHolder.getContext().setAuthentication(auth);
|
||||
|
||||
|
@ -54,6 +58,7 @@ public class AuthenticationTagTests extends TestCase {
|
|||
assertEquals("rodUserDetails", authenticationTag.getLastMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOperationWhenPrincipalIsAString() throws JspException {
|
||||
SecurityContextHolder.getContext().setAuthentication(
|
||||
new TestingAuthenticationToken("rodAsString", "koala", AuthorityUtils.NO_AUTHORITIES ));
|
||||
|
@ -64,6 +69,7 @@ public class AuthenticationTagTests extends TestCase {
|
|||
assertEquals("rodAsString", authenticationTag.getLastMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNestedPropertyIsReadCorrectly() throws JspException {
|
||||
SecurityContextHolder.getContext().setAuthentication(auth);
|
||||
|
||||
|
@ -73,6 +79,7 @@ public class AuthenticationTagTests extends TestCase {
|
|||
assertEquals("rodUserDetails", authenticationTag.getLastMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOperationWhenPrincipalIsNull() throws JspException {
|
||||
SecurityContextHolder.getContext().setAuthentication(
|
||||
new TestingAuthenticationToken(null, "koala", AuthorityUtils.NO_AUTHORITIES ));
|
||||
|
@ -82,6 +89,7 @@ public class AuthenticationTagTests extends TestCase {
|
|||
assertEquals(Tag.EVAL_PAGE, authenticationTag.doEndTag());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOperationWhenSecurityContextIsNull() throws Exception {
|
||||
SecurityContextHolder.getContext().setAuthentication(null);
|
||||
|
||||
|
@ -91,12 +99,14 @@ public class AuthenticationTagTests extends TestCase {
|
|||
assertEquals(null, authenticationTag.getLastMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSkipsBodyIfNullOrEmptyOperation() throws Exception {
|
||||
authenticationTag.setProperty("");
|
||||
assertEquals(Tag.SKIP_BODY, authenticationTag.doStartTag());
|
||||
assertEquals(Tag.EVAL_PAGE, authenticationTag.doEndTag());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testThrowsExceptionForUnrecognisedProperty() {
|
||||
SecurityContextHolder.getContext().setAuthentication(auth);
|
||||
authenticationTag.setProperty("qsq");
|
||||
|
@ -109,6 +119,25 @@ public class AuthenticationTagTests extends TestCase {
|
|||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void htmlEscapingIsUsedByDefault() throws Exception {
|
||||
SecurityContextHolder.getContext().setAuthentication(new TestingAuthenticationToken("<>& ", ""));
|
||||
authenticationTag.setProperty("name");
|
||||
authenticationTag.doStartTag();
|
||||
authenticationTag.doEndTag();
|
||||
assertEquals("<>& ", authenticationTag.getLastMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void settingHtmlEscapeToFalsePreventsEscaping() throws Exception {
|
||||
SecurityContextHolder.getContext().setAuthentication(new TestingAuthenticationToken("<>& ", ""));
|
||||
authenticationTag.setProperty("name");
|
||||
authenticationTag.setHtmlEscape("false");
|
||||
authenticationTag.doStartTag();
|
||||
authenticationTag.doEndTag();
|
||||
assertEquals("<>& ", authenticationTag.getLastMessage());
|
||||
}
|
||||
|
||||
//~ Inner Classes ==================================================================================================
|
||||
|
||||
private class MyAuthenticationTag extends AuthenticationTag {
|
||||
|
|
Loading…
Reference in New Issue