SEC-2325 Added JSP tags for CSRF meta tags and form fields
This commit is contained in:
@@ -1,3 +1,19 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.taglibs;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
@@ -6,7 +22,7 @@ import org.apache.commons.logging.LogFactory;
|
||||
import javax.servlet.jsp.tagext.Tag;
|
||||
|
||||
/**
|
||||
* internal cconfiguration class for taglibs.
|
||||
* internal configuration class for taglibs.
|
||||
*
|
||||
* Not for public use.
|
||||
*
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.taglibs.csrf;
|
||||
|
||||
import org.springframework.security.web.csrf.CsrfToken;
|
||||
|
||||
import javax.servlet.jsp.JspException;
|
||||
import javax.servlet.jsp.tagext.TagSupport;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* An abstract tag for handling CSRF operations.
|
||||
*
|
||||
* @since 3.2.1
|
||||
* @author Nick Williams
|
||||
*/
|
||||
public abstract class AbstractCsrfTag extends TagSupport {
|
||||
|
||||
@Override
|
||||
public int doEndTag() throws JspException {
|
||||
|
||||
CsrfToken token = (CsrfToken)this.pageContext.getRequest().getAttribute(CsrfToken.class.getName());
|
||||
if (token != null) {
|
||||
try {
|
||||
this.pageContext.getOut().write(this.handleToken(token));
|
||||
} catch (IOException e) {
|
||||
throw new JspException(e);
|
||||
}
|
||||
}
|
||||
|
||||
return EVAL_PAGE;
|
||||
}
|
||||
|
||||
protected abstract String handleToken(CsrfToken token);
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.taglibs.csrf;
|
||||
|
||||
import org.springframework.security.web.csrf.CsrfToken;
|
||||
|
||||
/**
|
||||
* A JSP tag that prints out a hidden form field for the CSRF token. See the JSP Tab Library documentation for more
|
||||
* information.
|
||||
*
|
||||
* @since 3.2.1
|
||||
* @author Nick Williams
|
||||
*/
|
||||
public class FormFieldTag extends AbstractCsrfTag {
|
||||
|
||||
@Override
|
||||
public String handleToken(CsrfToken token) {
|
||||
return "<input type=\"hidden\" name=\"" + token.getParameterName() + "\" value=\"" + token.getToken() +
|
||||
"\" />\n";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.taglibs.csrf;
|
||||
|
||||
import org.springframework.security.web.csrf.CsrfToken;
|
||||
|
||||
/**
|
||||
* A JSP tag that prints out a meta tags holding the CSRF form field name and token value for use in JavaScrip code.
|
||||
* See the JSP Tab Library documentation for more information.
|
||||
*
|
||||
* @since 3.2.1
|
||||
* @author Nick Williams
|
||||
*/
|
||||
public class MetaTagsTag extends AbstractCsrfTag {
|
||||
|
||||
@Override
|
||||
public String handleToken(CsrfToken token) {
|
||||
return "<meta name=\"_csrf_parameter\" content=\"" + token.getParameterName() + "\" />\n" +
|
||||
" <meta name=\"_csrf_header\" content=\"" + token.getHeaderName() + "\" />\n" +
|
||||
" <meta name=\"_csrf\" content=\"" + token.getToken() + "\" />\n";
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,19 @@
|
||||
<?xml version="1.0" encoding="ISO-8859-1" ?>
|
||||
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!--
|
||||
~ Copyright 2002-2014 the original author or authors.
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
<taglib xmlns="http://java.sun.com/xml/ns/j2ee"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd"
|
||||
@@ -177,4 +191,35 @@
|
||||
</attribute>
|
||||
</tag>
|
||||
|
||||
<tag>
|
||||
<description><![CDATA[
|
||||
If CSRF protection is enabled, this tag inserts a hidden form field with the correct name and value for the
|
||||
CSRF protection token. If CSRF protection is not enabled, this tag outputs nothing. Normally Spring Security
|
||||
automatically inserts this form field for any <form:form> tags, but if for some reason you cannot use
|
||||
<form:form> this tag is a handy replacement. You should place this tag within an HTML <form></form> block,
|
||||
where you would normally place other <input>s. Do NOT place this tag within a Spring <form:form></form:form>
|
||||
block—Spring Security handles Spring forms automatically.
|
||||
]]></description>
|
||||
<name>csrfField</name>
|
||||
<tag-class>org.springframework.security.taglibs.csrf.FormFieldTag</tag-class>
|
||||
<body-content>empty</body-content>
|
||||
</tag>
|
||||
|
||||
<tag>
|
||||
<description><![CDATA[
|
||||
If CSRF protection is enabled, this tag inserts meta tags containing the CSRF protection token form
|
||||
field and header names and CSRF protection token value. These tags are useful for employing CSRF protection
|
||||
within JavaScript in your applications. You should place this tag within an HTML <head></head> block, where
|
||||
you would normally place other meta tags. Once you use this tag, you can access the form field name using
|
||||
the JQuery $("meta[name='_csrf_parameter']").attr("content") and the header name using
|
||||
$("meta[name='_csrf_header']").attr("content"). Likewise, you can access the token value with
|
||||
$("meta[name='_csrf']").attr("content"). You should use a form field when creating and submitting forms from
|
||||
JavaScript, and you should use a header when sending AJAX requests. If CSRF protection is not enabled, this
|
||||
tag outputs nothing.
|
||||
]]></description>
|
||||
<name>csrfMetaTags</name>
|
||||
<tag-class>org.springframework.security.taglibs.csrf.MetaTagsTag</tag-class>
|
||||
<body-content>empty</body-content>
|
||||
</tag>
|
||||
|
||||
</taglib>
|
||||
|
||||
+91
@@ -0,0 +1,91 @@
|
||||
package org.springframework.security.taglibs.csrf;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
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.web.csrf.CsrfToken;
|
||||
import org.springframework.security.web.csrf.DefaultCsrfToken;
|
||||
|
||||
import javax.servlet.jsp.JspException;
|
||||
import javax.servlet.jsp.tagext.TagSupport;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* @author Nick Williams
|
||||
*/
|
||||
public class AbstractCsrfTagTests {
|
||||
|
||||
public MockTag tag;
|
||||
private MockHttpServletRequest request;
|
||||
private MockHttpServletResponse response;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockServletContext servletContext = new MockServletContext();
|
||||
this.request = new MockHttpServletRequest(servletContext);
|
||||
this.response = new MockHttpServletResponse();
|
||||
MockPageContext pageContext = new MockPageContext(servletContext, this.request, this.response);
|
||||
this.tag = new MockTag();
|
||||
this.tag.setPageContext(pageContext);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDoEndTag01() throws JspException, UnsupportedEncodingException {
|
||||
|
||||
this.tag.handleReturn = "fooBarBazQux";
|
||||
|
||||
int returned = this.tag.doEndTag();
|
||||
|
||||
assertEquals("The returned value is not correct.", TagSupport.EVAL_PAGE, returned);
|
||||
assertEquals("The output value is not correct.", "", this.response.getContentAsString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDoEndTag02() throws JspException, UnsupportedEncodingException {
|
||||
|
||||
CsrfToken token = new DefaultCsrfToken("X-Csrf-Token", "_csrf", "abc123def456ghi789");
|
||||
this.request.setAttribute(CsrfToken.class.getName(), token);
|
||||
|
||||
this.tag.handleReturn = "fooBarBazQux";
|
||||
|
||||
int returned = this.tag.doEndTag();
|
||||
|
||||
assertEquals("The returned value is not correct.", TagSupport.EVAL_PAGE, returned);
|
||||
assertEquals("The output value is not correct.", "fooBarBazQux", this.response.getContentAsString());
|
||||
assertSame("The token is not correct.", token, this.tag.token);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDoEndTag03() throws JspException, UnsupportedEncodingException {
|
||||
|
||||
CsrfToken token = new DefaultCsrfToken("X-Csrf-Token", "_csrf", "abc123def456ghi789");
|
||||
this.request.setAttribute(CsrfToken.class.getName(), token);
|
||||
|
||||
this.tag.handleReturn = "<input type=\"hidden\" />";
|
||||
|
||||
int returned = this.tag.doEndTag();
|
||||
|
||||
assertEquals("The returned value is not correct.", TagSupport.EVAL_PAGE, returned);
|
||||
assertEquals("The output value is not correct.", "<input type=\"hidden\" />",
|
||||
this.response.getContentAsString());
|
||||
assertSame("The token is not correct.", token, this.tag.token);
|
||||
}
|
||||
|
||||
private static class MockTag extends AbstractCsrfTag {
|
||||
|
||||
private CsrfToken token;
|
||||
private String handleReturn;
|
||||
|
||||
@Override
|
||||
protected String handleToken(CsrfToken token) {
|
||||
this.token = token;
|
||||
return this.handleReturn;
|
||||
}
|
||||
}
|
||||
}
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
package org.springframework.security.taglibs.csrf;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.security.web.csrf.CsrfToken;
|
||||
import org.springframework.security.web.csrf.DefaultCsrfToken;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* @author Nick Williams
|
||||
*/
|
||||
public class FormFieldTagTests {
|
||||
|
||||
public FormFieldTag tag;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
this.tag = new FormFieldTag();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHandleToken01() {
|
||||
CsrfToken token = new DefaultCsrfToken("X-Csrf-Token", "_csrf", "abc123def456ghi789");
|
||||
|
||||
String value = this.tag.handleToken(token);
|
||||
|
||||
assertNotNull("The returned value should not be null.", value);
|
||||
assertEquals("The output is not correct.",
|
||||
"<input type=\"hidden\" name=\"_csrf\" value=\"abc123def456ghi789\" />\n",
|
||||
value);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHandleToken() {
|
||||
CsrfToken token = new DefaultCsrfToken("X-Csrf-Token", "csrfParameter", "fooBarBazQux");
|
||||
|
||||
String value = this.tag.handleToken(token);
|
||||
|
||||
assertNotNull("The returned value should not be null.", value);
|
||||
assertEquals("The output is not correct.",
|
||||
"<input type=\"hidden\" name=\"csrfParameter\" value=\"fooBarBazQux\" />\n",
|
||||
value);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package org.springframework.security.taglibs.csrf;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.security.web.csrf.CsrfToken;
|
||||
import org.springframework.security.web.csrf.DefaultCsrfToken;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* @author Nick Williams
|
||||
*/
|
||||
public class MetaTagsTagTests {
|
||||
|
||||
public MetaTagsTag tag;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
this.tag = new MetaTagsTag();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHandleToken01() {
|
||||
CsrfToken token = new DefaultCsrfToken("X-Csrf-Token", "_csrf", "abc123def456ghi789");
|
||||
|
||||
String value = this.tag.handleToken(token);
|
||||
|
||||
assertNotNull("The returned value should not be null.", value);
|
||||
assertEquals("The output is not correct.",
|
||||
"<meta name=\"_csrf_parameter\" content=\"_csrf\" />\n" +
|
||||
" <meta name=\"_csrf_header\" content=\"X-Csrf-Token\" />\n" +
|
||||
" <meta name=\"_csrf\" content=\"abc123def456ghi789\" />\n",
|
||||
value);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHandleToken02() {
|
||||
CsrfToken token = new DefaultCsrfToken("csrfHeader", "csrfParameter", "fooBarBazQux");
|
||||
|
||||
String value = this.tag.handleToken(token);
|
||||
|
||||
assertNotNull("The returned value should not be null.", value);
|
||||
assertEquals("The output is not correct.",
|
||||
"<meta name=\"_csrf_parameter\" content=\"csrfParameter\" />\n" +
|
||||
" <meta name=\"_csrf_header\" content=\"csrfHeader\" />\n" +
|
||||
" <meta name=\"_csrf\" content=\"fooBarBazQux\" />\n",
|
||||
value);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user