1
0
mirror of synced 2026-08-04 17:27:13 +00:00

SEC-1574: Add CSRF Support

This commit is contained in:
Rob Winch
2013-08-15 14:49:21 -05:00
parent 5f35d9e3ec
commit e9bb9e766e
93 changed files with 2895 additions and 348 deletions
@@ -28,6 +28,7 @@ import javax.servlet.http.HttpServletResponse;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.util.RequestMatcher;
import org.springframework.security.web.util.UrlUtils;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
@@ -49,7 +50,9 @@ public class LogoutFilter extends GenericFilterBean {
//~ Instance fields ================================================================================================
private String filterProcessesUrl = "/j_spring_security_logout";
private String filterProcessesUrl;
private RequestMatcher logoutRequestMatcher;
private final List<LogoutHandler> handlers;
private final LogoutSuccessHandler logoutSuccessHandler;
@@ -65,6 +68,7 @@ public class LogoutFilter extends GenericFilterBean {
this.handlers = Arrays.asList(handlers);
Assert.notNull(logoutSuccessHandler, "logoutSuccessHandler cannot be null");
this.logoutSuccessHandler = logoutSuccessHandler;
setFilterProcessesUrl("/j_spring_security_logout");
}
public LogoutFilter(String logoutSuccessUrl, LogoutHandler... handlers) {
@@ -77,6 +81,7 @@ public class LogoutFilter extends GenericFilterBean {
urlLogoutSuccessHandler.setDefaultTargetUrl(logoutSuccessUrl);
}
logoutSuccessHandler = urlLogoutSuccessHandler;
setFilterProcessesUrl("/j_spring_security_logout");
}
//~ Methods ========================================================================================================
@@ -114,35 +119,55 @@ public class LogoutFilter extends GenericFilterBean {
* @return <code>true</code> if logout should occur, <code>false</code> otherwise
*/
protected boolean requiresLogout(HttpServletRequest request, HttpServletResponse response) {
String uri = request.getRequestURI();
int pathParamIndex = uri.indexOf(';');
if (pathParamIndex > 0) {
// strip everything from the first semi-colon
uri = uri.substring(0, pathParamIndex);
}
int queryParamIndex = uri.indexOf('?');
if (queryParamIndex > 0) {
// strip everything from the first question mark
uri = uri.substring(0, queryParamIndex);
}
if ("".equals(request.getContextPath())) {
return uri.endsWith(filterProcessesUrl);
}
return uri.endsWith(request.getContextPath() + filterProcessesUrl);
return logoutRequestMatcher.matches(request);
}
public void setLogoutRequestMatcher(RequestMatcher logoutRequestMatcher) {
Assert.notNull(logoutRequestMatcher, "logoutRequestMatcher cannot be null");
this.logoutRequestMatcher = logoutRequestMatcher;
}
@Deprecated
public void setFilterProcessesUrl(String filterProcessesUrl) {
Assert.isTrue(UrlUtils.isValidRedirectUrl(filterProcessesUrl), filterProcessesUrl + " isn't a valid value for" +
" 'filterProcessesUrl'");
this.logoutRequestMatcher = new FilterProcessUrlRequestMatcher(filterProcessesUrl);
this.filterProcessesUrl = filterProcessesUrl;
}
@Deprecated
protected String getFilterProcessesUrl() {
return filterProcessesUrl;
}
private static final class FilterProcessUrlRequestMatcher implements RequestMatcher {
private final String filterProcessesUrl;
private FilterProcessUrlRequestMatcher(String filterProcessesUrl) {
Assert.hasLength(filterProcessesUrl, "filterProcessesUrl must be specified");
Assert.isTrue(UrlUtils.isValidRedirectUrl(filterProcessesUrl), filterProcessesUrl + " isn't a valid redirect URL");
this.filterProcessesUrl = filterProcessesUrl;
}
public boolean matches(HttpServletRequest request) {
String uri = request.getRequestURI();
int pathParamIndex = uri.indexOf(';');
if (pathParamIndex > 0) {
// strip everything from the first semi-colon
uri = uri.substring(0, pathParamIndex);
}
int queryParamIndex = uri.indexOf('?');
if (queryParamIndex > 0) {
// strip everything from the first question mark
uri = uri.substring(0, queryParamIndex);
}
if ("".equals(request.getContextPath())) {
return uri.endsWith(filterProcessesUrl);
}
return uri.endsWith(request.getContextPath() + filterProcessesUrl);
}
}
}
@@ -67,7 +67,7 @@ public class CompositeSessionAuthenticationStrategy implements SessionAuthentica
throw new IllegalArgumentException("delegateStrategies cannot contain null entires. Got " + delegateStrategies);
}
}
this.delegateStrategies = new ArrayList<SessionAuthenticationStrategy>(delegateStrategies);
this.delegateStrategies = delegateStrategies;
}
/* (non-Javadoc)
@@ -27,6 +27,7 @@ import javax.servlet.http.HttpSession;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.WebAttributes;
import org.springframework.security.web.csrf.CsrfToken;
import org.springframework.web.filter.GenericFilterBean;
/**
@@ -164,6 +165,7 @@ public class DefaultLoginPageViewFilter extends GenericFilterBean {
}
sb.append(" <tr><td colspan='2'><input name=\"submit\" type=\"submit\" value=\"Login\"/></td></tr>\n");
renderHiddenInputs(sb, request);
sb.append(" </table>\n");
sb.append("</form>");
}
@@ -181,6 +183,7 @@ public class DefaultLoginPageViewFilter extends GenericFilterBean {
sb.append(" <tr><td colspan='2'><input name=\"submit\" type=\"submit\" value=\"Login\"/></td></tr>\n");
sb.append(" </table>\n");
renderHiddenInputs(sb, request);
sb.append("</form>");
}
@@ -189,6 +192,14 @@ public class DefaultLoginPageViewFilter extends GenericFilterBean {
return sb.toString();
}
private void renderHiddenInputs(StringBuilder sb, HttpServletRequest request) {
CsrfToken token = (CsrfToken) request.getAttribute(CsrfToken.class.getName());
if(token != null) {
sb.append(" <input name=\""+ token.getParameterName() +"\" type=\"hidden\" value=\""+ token.getToken() +"\" />\n");
}
}
private boolean isLogoutSuccess(HttpServletRequest request) {
return logoutSuccessUrl != null && matches(request, logoutSuccessUrl);
}
@@ -0,0 +1,56 @@
/*
* Copyright 2002-2013 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.web.csrf;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.session.SessionAuthenticationException;
import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy;
import org.springframework.util.Assert;
/**
* {@link CsrfAuthenticationStrategy} is in charge of removing the {@link CsrfToken} upon
* authenticating. A new {@link CsrfToken} will then be generated by the framework upon
* the next request.
*
* @author Rob Winch
* @since 3.2
*/
public final class CsrfAuthenticationStrategy implements
SessionAuthenticationStrategy {
private final CsrfTokenRepository csrfTokenRepository;
/**
* Creates a new instance
* @param csrfTokenRepository the {@link CsrfTokenRepository} to use
*/
public CsrfAuthenticationStrategy(CsrfTokenRepository csrfTokenRepository) {
Assert.notNull(csrfTokenRepository,"csrfTokenRepository cannot be null");
this.csrfTokenRepository = csrfTokenRepository;
}
/* (non-Javadoc)
* @see org.springframework.security.web.authentication.session.SessionAuthenticationStrategy#onAuthentication(org.springframework.security.core.Authentication, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
*/
public void onAuthentication(Authentication authentication,
HttpServletRequest request, HttpServletResponse response)
throws SessionAuthenticationException {
this.csrfTokenRepository.saveToken(null, request, response);
}
}
@@ -0,0 +1,141 @@
/*
* Copyright 2002-2013 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.web.csrf;
import java.io.IOException;
import java.util.regex.Pattern;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.access.AccessDeniedHandlerImpl;
import org.springframework.security.web.util.RequestMatcher;
import org.springframework.util.Assert;
import org.springframework.web.filter.OncePerRequestFilter;
/**
* <p>
* Applies <a
* href="https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)"
* >CSRF</a> protection using a synchronizer token pattern. Developers are
* required to ensure that {@link CsrfFilter} is invoked for any request that
* allows state to change. Typically this just means that they should ensure
* their web application follows proper REST semantics (i.e. do not change state
* with the HTTP methods GET, HEAD, TRACE, OPTIONS).
* </p>
*
* <p>
* Typically the {@link CsrfTokenRepository} implementation chooses to store the
* {@link CsrfToken} in {@link HttpSession} with
* {@link HttpSessionCsrfTokenRepository}. This is preferred to storing the
* token in a cookie which.
* </p>
*
* @author Rob Winch
* @since 3.2
*/
public final class CsrfFilter extends OncePerRequestFilter {
private final CsrfTokenRepository tokenRepository;
private RequestMatcher requireCsrfProtectionMatcher = new DefaultRequiresCsrfMatcher();
private AccessDeniedHandler accessDeniedHandler = new AccessDeniedHandlerImpl();
public CsrfFilter(CsrfTokenRepository csrfTokenRepository) {
Assert.notNull(csrfTokenRepository, "csrfTokenRepository cannot be null");
this.tokenRepository = csrfTokenRepository;
}
/* (non-Javadoc)
* @see org.springframework.web.filter.OncePerRequestFilter#doFilterInternal(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, javax.servlet.FilterChain)
*/
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
CsrfToken csrfToken = tokenRepository.loadToken(request);
if(csrfToken == null) {
csrfToken = tokenRepository.generateAndSaveToken(request, response);
}
request.setAttribute(CsrfToken.class.getName(), csrfToken);
request.setAttribute(csrfToken.getParameterName(), csrfToken);
response.addHeader(csrfToken.getHeaderName(), csrfToken.getToken());
if(!requireCsrfProtectionMatcher.matches(request)) {
filterChain.doFilter(request, response);
return;
}
String actualToken = request.getHeader(csrfToken.getHeaderName());
if(actualToken == null) {
actualToken = request.getParameter(csrfToken.getParameterName());
}
if(!csrfToken.getToken().equals(actualToken)) {
accessDeniedHandler.handle(request, response, new InvalidCsrfTokenException(csrfToken, actualToken));
return;
}
filterChain.doFilter(request, response);
}
/**
* Specifies a {@link RequestMatcher} that is used to determine if CSRF
* protection should be applied. If the {@link RequestMatcher} returns true
* for a given request, then CSRF protection is applied.
*
* <p>
* The default is to apply CSRF protection for any HTTP method other than
* GET, HEAD, TRACE, OPTIONS.
* </p>
*
* @param requireCsrfProtectionMatcher
* the {@link RequestMatcher} used to determine if CSRF
* protection should be applied.
*/
public void setRequireCsrfProtectionMatcher(RequestMatcher requireCsrfProtectionMatcher) {
Assert.notNull(requireCsrfProtectionMatcher, "requireCsrfProtectionMatcher cannot be null");
this.requireCsrfProtectionMatcher = requireCsrfProtectionMatcher;
}
/**
* Specifies a {@link AccessDeniedHandler} that should be used when CSRF protection fails.
*
* <p>
* The default is to use AccessDeniedHandlerImpl with no arguments.
* </p>
*
* @param accessDeniedHandler
* the {@link AccessDeniedHandler} to use
*/
public void setAccessDeniedHandler(AccessDeniedHandler accessDeniedHandler) {
Assert.notNull(accessDeniedHandler, "accessDeniedHandler cannot be null");
this.accessDeniedHandler = accessDeniedHandler;
}
private static class DefaultRequiresCsrfMatcher implements RequestMatcher {
private Pattern allowedMethods = Pattern.compile("^(GET|HEAD|TRACE|OPTIONS)$");
/* (non-Javadoc)
* @see org.springframework.security.web.util.RequestMatcher#matches(javax.servlet.http.HttpServletRequest)
*/
public boolean matches(HttpServletRequest request) {
return !allowedMethods.matcher(request.getMethod()).matches();
}
}
}
@@ -0,0 +1,54 @@
/*
* Copyright 2002-2013 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.web.csrf;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.logout.LogoutHandler;
import org.springframework.util.Assert;
/**
* {@link CsrfLogoutHandler} is in charge of removing the {@link CsrfToken} upon
* logout. A new {@link CsrfToken} will then be generated by the framework upon
* the next request.
*
* @author Rob Winch
* @since 3.2
*/
public final class CsrfLogoutHandler implements LogoutHandler {
private final CsrfTokenRepository csrfTokenRepository;
/**
* Creates a new instance
* @param csrfTokenRepository the {@link CsrfTokenRepository} to use
*/
public CsrfLogoutHandler(CsrfTokenRepository csrfTokenRepository) {
Assert.notNull(csrfTokenRepository,"csrfTokenRepository cannot be null");
this.csrfTokenRepository = csrfTokenRepository;
}
/**
* Clears the {@link CsrfToken}
*
* @see org.springframework.security.web.authentication.logout.LogoutHandler#logout(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, org.springframework.security.core.Authentication)
*/
public void logout(HttpServletRequest request,
HttpServletResponse response, Authentication authentication) {
this.csrfTokenRepository.saveToken(null, request, response);
}
}
@@ -0,0 +1,78 @@
/*
* Copyright 2002-2013 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.web.csrf;
import java.io.Serializable;
import org.springframework.util.Assert;
/**
* A CSRF token that is used to protect against CSRF attacks.
*
* @author Rob Winch
* @since 3.2
*/
@SuppressWarnings("serial")
public final class CsrfToken implements Serializable {
private final String token;
private final String parameterName;
private final String headerName;
/**
* Creates a new instance
* @param headerName the HTTP header name to use
* @param parameterName the HTTP parameter name to use
* @param token the value of the token (i.e. expected value of the HTTP parameter of parametername).
*/
public CsrfToken(String headerName, String parameterName, String token) {
Assert.hasLength(headerName, "headerName cannot be null or empty");
Assert.hasLength(parameterName, "parameterName cannot be null or empty");
Assert.hasLength(token, "token cannot be null or empty");
this.headerName = headerName;
this.parameterName = parameterName;
this.token = token;
}
/**
* Gets the HTTP header that the CSRF is populated on the response and can
* be placed on requests instead of the parameter. Cannot be null.
*
* @return the HTTP header that the CSRF is populated on the response and
* can be placed on requests instead of the parameter
*/
public String getHeaderName() {
return headerName;
}
/**
* Gets the HTTP parameter name that should contain the token. Cannot be null.
* @return the HTTP parameter name that should contain the token.
*/
public String getParameterName() {
return parameterName;
}
/**
* Gets the token value. Cannot be null.
* @return the token value
*/
public String getToken() {
return token;
}
}
@@ -0,0 +1,71 @@
/*
* Copyright 2002-2013 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.web.csrf;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
/**
* An API to allow changing the method in which the expected {@link CsrfToken}
* is associated to the {@link HttpServletRequest}. For example, it may be
* stored in {@link HttpSession}.
*
* @see HttpSessionCsrfTokenRepository
*
* @author Rob Winch
* @since 3.2
*
*/
public interface CsrfTokenRepository {
/**
* Generates and saves the expected {@link CsrfToken}
*
* @param request
* the {@link HttpServletRequest} to use
* @param response
* the {@link HttpServletResponse} to use
* @return the {@link CsrfToken} that was generated and saved. Cannot be
* null.
*/
CsrfToken generateAndSaveToken(HttpServletRequest request,
HttpServletResponse response);
/**
* Saves the {@link CsrfToken} using the {@link HttpServletRequest} and
* {@link HttpServletResponse}. If the {@link CsrfToken} is null, it is the
* same as deleting it.
*
* @param token
* the {@link CsrfToken} to save or null to delete
* @param request
* the {@link HttpServletRequest} to use
* @param response
* the {@link HttpServletResponse} to use
*/
void saveToken(CsrfToken token, HttpServletRequest request,
HttpServletResponse response);
/**
* Loads the expected {@link CsrfToken} from the {@link HttpServletRequest}
*
* @param request
* the {@link HttpServletRequest} to use
* @return the {@link CsrfToken} or null if none exists
*/
CsrfToken loadToken(HttpServletRequest request);
}
@@ -0,0 +1,109 @@
/*
* Copyright 2002-2013 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.web.csrf;
import java.util.UUID;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.springframework.util.Assert;
/**
* A {@link CsrfTokenRepository} that stores the {@link CsrfToken} in the {@link HttpSession}.
*
* @author Rob Winch
* @since 3.2
*/
public final class HttpSessionCsrfTokenRepository implements CsrfTokenRepository {
private static final String DEFAULT_CSRF_PARAMETER_NAME = "_csrf";
private static final String DEFAULT_CSRF_HEADER_NAME = "X-CSRF-TOKEN";
private static final String DEFAULT_CSRF_TOKEN_ATTR_NAME = HttpSessionCsrfTokenRepository.class.getName().concat(".CSRF_TOKEN");
private String parameterName = DEFAULT_CSRF_PARAMETER_NAME;
private String headerName = DEFAULT_CSRF_HEADER_NAME;
private String sessionAttributeName = DEFAULT_CSRF_TOKEN_ATTR_NAME;
/*
* (non-Javadoc)
* @see org.springframework.security.web.csrf.CsrfTokenRepository#saveToken(org.springframework.security.web.csrf.CsrfToken, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
*/
public void saveToken(CsrfToken token, HttpServletRequest request,
HttpServletResponse response) {
HttpSession session = request.getSession();
if(token == null) {
session.removeAttribute(sessionAttributeName);
} else {
session.setAttribute(sessionAttributeName, token);
}
}
/* (non-Javadoc)
* @see org.springframework.security.web.csrf.CsrfTokenRepository#loadToken(javax.servlet.http.HttpServletRequest)
*/
public CsrfToken loadToken(HttpServletRequest request) {
return (CsrfToken) request.getSession().getAttribute(sessionAttributeName);
}
/* (non-Javadoc)
* @see org.springframework.security.web.csrf.CsrfTokenRepository#generateNewToken(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
*/
public CsrfToken generateAndSaveToken(HttpServletRequest request,
HttpServletResponse response) {
CsrfToken token = new CsrfToken(headerName, parameterName, createNewToken());
saveToken(token, request, response);
return token;
}
/**
* Sets the {@link HttpServletRequest} parameter name that the {@link CsrfToken} is expected to appear on
* @param parameterName the new parameter name to use
*/
public void setParameterName(String parameterName) {
Assert.hasLength(parameterName, "parameterName cannot be null or empty");
this.parameterName = parameterName;
}
/**
* Sets the header name that the {@link CsrfToken} is expected to appear on
* and the header that the response will contain the {@link CsrfToken}.
*
* @param parameterName
* the new parameter name to use
*/
public void setHeaderName(String parameterName) {
Assert.hasLength(parameterName, "parameterName cannot be null or empty");
this.parameterName = parameterName;
}
/**
* Sets the {@link HttpSession} attribute name that the {@link CsrfToken} is stored in
* @param sessionAttributeName the new attribute name to use
*/
public void setSessionAttributeName(String sessionAttributeName) {
Assert.hasLength(sessionAttributeName, "sessionAttributename cannot be null or empty");
this.sessionAttributeName = sessionAttributeName;
}
private String createNewToken() {
return UUID.randomUUID().toString();
}
}
@@ -0,0 +1,40 @@
/*
* Copyright 2002-2013 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.web.csrf;
import org.springframework.security.access.AccessDeniedException;
/**
* Thrown when an invalid or missing {@link CsrfToken} is found in the HttpServletRequest
*
* @author Rob Winch
* @since 3.2
*/
@SuppressWarnings("serial")
public class InvalidCsrfTokenException extends AccessDeniedException {
/**
* @param msg
*/
public InvalidCsrfTokenException(CsrfToken expectedAccessToken, String actualAccessToken) {
super("Invalid CSRF Token '" + actualAccessToken
+ "' was found on the request parameter '"
+ expectedAccessToken.getParameterName() + "' or header '"
+ expectedAccessToken.getHeaderName() + "'.");
}
}
@@ -0,0 +1,86 @@
/*
* Copyright 2002-2013 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.web.servlet.support.csrf;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.springframework.security.web.csrf.CsrfToken;
import org.springframework.web.servlet.support.RequestDataValueProcessor;
/**
* Integration with Spring Web MVC that automatically adds the {@link CsrfToken}
* into forms with hidden inputs when using Spring tag libraries.
*
* @author Rob Winch
* @since 3.2
*/
public final class CsrfRequestDataValueProcessor implements
RequestDataValueProcessor {
/*
* (non-Javadoc)
*
* @see org.springframework.web.servlet.support.RequestDataValueProcessor#
* processAction(javax.servlet.http.HttpServletRequest, java.lang.String)
*/
public String processAction(HttpServletRequest request, String action) {
return action;
}
/*
* (non-Javadoc)
*
* @see org.springframework.web.servlet.support.RequestDataValueProcessor#
* processFormFieldValue(javax.servlet.http.HttpServletRequest,
* java.lang.String, java.lang.String, java.lang.String)
*/
public String processFormFieldValue(HttpServletRequest request,
String name, String value, String type) {
return value;
}
/*
* (non-Javadoc)
*
* @see org.springframework.web.servlet.support.RequestDataValueProcessor#
* getExtraHiddenFields(javax.servlet.http.HttpServletRequest)
*/
public Map<String, String> getExtraHiddenFields(HttpServletRequest request) {
CsrfToken token = (CsrfToken) request.getAttribute(CsrfToken.class
.getName());
if (token == null) {
return Collections.emptyMap();
}
Map<String, String> hiddenFields = new HashMap<String, String>(1);
hiddenFields.put(token.getParameterName(), token.getToken());
return hiddenFields;
}
/*
* (non-Javadoc)
*
* @see
* org.springframework.web.servlet.support.RequestDataValueProcessor#processUrl
* (javax.servlet.http.HttpServletRequest, java.lang.String)
*/
public String processUrl(HttpServletRequest request, String url) {
return url;
}
}
@@ -0,0 +1,64 @@
/*
* Copyright 2002-2013 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.web.csrf;
import static org.mockito.Mockito.verify;
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.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.security.authentication.TestingAuthenticationToken;
/**
* @author Rob Winch
*
*/
@RunWith(MockitoJUnitRunner.class)
public class CsrfAuthenticationStrategyTests {
@Mock
private CsrfTokenRepository csrfTokenRepository;
private MockHttpServletRequest request;
private MockHttpServletResponse response;
private CsrfAuthenticationStrategy strategy;
@Before
public void setup() {
request = new MockHttpServletRequest();
response = new MockHttpServletResponse();
strategy = new CsrfAuthenticationStrategy(csrfTokenRepository);
}
@Test(expected = IllegalArgumentException.class)
public void constructorNullCsrfTokenRepository() {
new CsrfAuthenticationStrategy(null);
}
@Test
public void logoutRemovesCsrfToken() {
strategy.onAuthentication(new TestingAuthenticationToken("user", "password", "ROLE_USER"),request, response);
verify(csrfTokenRepository).saveToken(null, request, response);
}
}
@@ -0,0 +1,303 @@
/*
* Copyright 2002-2013 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.web.csrf;
import static org.fest.assertions.Assertions.assertThat;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;
import java.io.IOException;
import java.util.Arrays;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletResponse;
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.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.util.RequestMatcher;
/**
* @author Rob Winch
*
*/
@RunWith(MockitoJUnitRunner.class)
public class CsrfFilterTests {
@Mock
private RequestMatcher requestMatcher;
@Mock
private CsrfTokenRepository tokenRepository;
@Mock
private FilterChain filterChain;
@Mock
private AccessDeniedHandler deniedHandler;
private MockHttpServletRequest request;
private MockHttpServletResponse response;
private CsrfToken token;
private CsrfFilter filter;
@Before
public void setup() {
token = new CsrfToken("headerName","paramName", "csrfTokenValue");
resetRequestResponse();
filter = new CsrfFilter(tokenRepository);
filter.setRequireCsrfProtectionMatcher(requestMatcher);
filter.setAccessDeniedHandler(deniedHandler);
}
private void resetRequestResponse() {
request = new MockHttpServletRequest();
response = new MockHttpServletResponse();
}
@Test(expected = IllegalArgumentException.class)
public void constructorNullRepository() {
new CsrfFilter(null);
}
@Test
public void doFilterAccessDeniedNoTokenPresent() throws ServletException, IOException {
when(requestMatcher.matches(request)).thenReturn(true);
when(tokenRepository.loadToken(request)).thenReturn(token);
filter.doFilter(request, response, filterChain);
assertThat(response.getHeader(token.getHeaderName())).isEqualTo(token.getToken());
assertThat(request.getAttribute(token.getParameterName())).isEqualTo(token);
assertThat(request.getAttribute(CsrfToken.class.getName())).isEqualTo(token);
verify(deniedHandler).handle(eq(request), eq(response), any(InvalidCsrfTokenException.class));
verifyZeroInteractions(filterChain);
}
@Test
public void doFilterAccessDeniedIncorrectTokenPresent() throws ServletException, IOException {
when(requestMatcher.matches(request)).thenReturn(true);
when(tokenRepository.loadToken(request)).thenReturn(token);
request.setParameter(token.getParameterName(), token.getToken()+ " INVALID");
filter.doFilter(request, response, filterChain);
assertThat(response.getHeader(token.getHeaderName())).isEqualTo(token.getToken());
assertThat(request.getAttribute(token.getParameterName())).isEqualTo(token);
assertThat(request.getAttribute(CsrfToken.class.getName())).isEqualTo(token);
verify(deniedHandler).handle(eq(request), eq(response), any(InvalidCsrfTokenException.class));
verifyZeroInteractions(filterChain);
}
@Test
public void doFilterAccessDeniedIncorrectTokenPresentHeader() throws ServletException, IOException {
when(requestMatcher.matches(request)).thenReturn(true);
when(tokenRepository.loadToken(request)).thenReturn(token);
request.addHeader(token.getHeaderName(), token.getToken()+ " INVALID");
filter.doFilter(request, response, filterChain);
assertThat(response.getHeader(token.getHeaderName())).isEqualTo(token.getToken());
assertThat(request.getAttribute(token.getParameterName())).isEqualTo(token);
assertThat(request.getAttribute(CsrfToken.class.getName())).isEqualTo(token);
verify(deniedHandler).handle(eq(request), eq(response), any(InvalidCsrfTokenException.class));
verifyZeroInteractions(filterChain);
}
@Test
public void doFilterAccessDeniedIncorrectTokenPresentHeaderPreferredOverParameter() throws ServletException, IOException {
when(requestMatcher.matches(request)).thenReturn(true);
when(tokenRepository.loadToken(request)).thenReturn(token);
request.setParameter(token.getParameterName(), token.getToken());
request.addHeader(token.getHeaderName(), token.getToken()+ " INVALID");
filter.doFilter(request, response, filterChain);
assertThat(response.getHeader(token.getHeaderName())).isEqualTo(token.getToken());
assertThat(request.getAttribute(token.getParameterName())).isEqualTo(token);
assertThat(request.getAttribute(CsrfToken.class.getName())).isEqualTo(token);
verify(deniedHandler).handle(eq(request), eq(response), any(InvalidCsrfTokenException.class));
verifyZeroInteractions(filterChain);
}
@Test
public void doFilterNotCsrfRequestExistingToken() throws ServletException, IOException {
when(requestMatcher.matches(request)).thenReturn(false);
when(tokenRepository.loadToken(request)).thenReturn(token);
filter.doFilter(request, response, filterChain);
assertThat(response.getHeader(token.getHeaderName())).isEqualTo(token.getToken());
assertThat(request.getAttribute(token.getParameterName())).isEqualTo(token);
assertThat(request.getAttribute(CsrfToken.class.getName())).isEqualTo(token);
verify(filterChain).doFilter(request, response);
verifyZeroInteractions(deniedHandler);
}
@Test
public void doFilterNotCsrfRequestGenerateToken() throws ServletException, IOException {
when(requestMatcher.matches(request)).thenReturn(false);
when(tokenRepository.generateAndSaveToken(request, response)).thenReturn(token);
filter.doFilter(request, response, filterChain);
assertThat(response.getHeader(token.getHeaderName())).isEqualTo(token.getToken());
assertThat(request.getAttribute(token.getParameterName())).isEqualTo(token);
assertThat(request.getAttribute(CsrfToken.class.getName())).isEqualTo(token);
verify(filterChain).doFilter(request, response);
verifyZeroInteractions(deniedHandler);
}
@Test
public void doFilterIsCsrfRequestExistingTokenHeader() throws ServletException, IOException {
when(requestMatcher.matches(request)).thenReturn(true);
when(tokenRepository.loadToken(request)).thenReturn(token);
request.addHeader(token.getHeaderName(), token.getToken());
filter.doFilter(request, response, filterChain);
assertThat(response.getHeader(token.getHeaderName())).isEqualTo(token.getToken());
assertThat(request.getAttribute(token.getParameterName())).isEqualTo(token);
assertThat(request.getAttribute(CsrfToken.class.getName())).isEqualTo(token);
verify(filterChain).doFilter(request, response);
verifyZeroInteractions(deniedHandler);
}
@Test
public void doFilterIsCsrfRequestExistingTokenHeaderPreferredOverInvalidParam() throws ServletException, IOException {
when(requestMatcher.matches(request)).thenReturn(true);
when(tokenRepository.loadToken(request)).thenReturn(token);
request.setParameter(token.getParameterName(), token.getToken()+ " INVALID");
request.addHeader(token.getHeaderName(), token.getToken());
filter.doFilter(request, response, filterChain);
assertThat(response.getHeader(token.getHeaderName())).isEqualTo(token.getToken());
assertThat(request.getAttribute(token.getParameterName())).isEqualTo(token);
assertThat(request.getAttribute(CsrfToken.class.getName())).isEqualTo(token);
verify(filterChain).doFilter(request, response);
verifyZeroInteractions(deniedHandler);
}
@Test
public void doFilterIsCsrfRequestExistingToken() throws ServletException, IOException {
when(requestMatcher.matches(request)).thenReturn(true);
when(tokenRepository.loadToken(request)).thenReturn(token);
request.setParameter(token.getParameterName(), token.getToken());
filter.doFilter(request, response, filterChain);
assertThat(response.getHeader(token.getHeaderName())).isEqualTo(token.getToken());
assertThat(request.getAttribute(token.getParameterName())).isEqualTo(token);
assertThat(request.getAttribute(CsrfToken.class.getName())).isEqualTo(token);
verify(filterChain).doFilter(request, response);
verifyZeroInteractions(deniedHandler);
}
@Test
public void doFilterIsCsrfRequestGenerateToken() throws ServletException, IOException {
when(requestMatcher.matches(request)).thenReturn(true);
when(tokenRepository.generateAndSaveToken(request, response)).thenReturn(token);
request.setParameter(token.getParameterName(), token.getToken());
filter.doFilter(request, response, filterChain);
assertThat(response.getHeader(token.getHeaderName())).isEqualTo(token.getToken());
assertThat(request.getAttribute(token.getParameterName())).isEqualTo(token);
assertThat(request.getAttribute(CsrfToken.class.getName())).isEqualTo(token);
verify(filterChain).doFilter(request, response);
verifyZeroInteractions(deniedHandler);
}
@Test
public void doFilterDefaultRequireCsrfProtectionMatcherAllowedMethods() throws ServletException, IOException {
filter = new CsrfFilter(tokenRepository);
filter.setAccessDeniedHandler(deniedHandler);
for(String method : Arrays.asList("GET","TRACE", "OPTIONS", "HEAD")) {
resetRequestResponse();
when(tokenRepository.loadToken(request)).thenReturn(token);
request.setMethod(method);
filter.doFilter(request, response, filterChain);
verify(filterChain).doFilter(request, response);
verifyZeroInteractions(deniedHandler);
}
}
@Test
public void doFilterDefaultRequireCsrfProtectionMatcherDeniedMethods() throws ServletException, IOException {
filter = new CsrfFilter(tokenRepository);
filter.setAccessDeniedHandler(deniedHandler);
for(String method : Arrays.asList("POST","PUT", "PATCH", "DELETE", "INVALID")) {
resetRequestResponse();
when(tokenRepository.loadToken(request)).thenReturn(token);
request.setMethod(method);
filter.doFilter(request, response, filterChain);
verify(deniedHandler).handle(eq(request), eq(response), any(InvalidCsrfTokenException.class));
verifyZeroInteractions(filterChain);
}
}
@Test
public void doFilterDefaultAccessDenied() throws ServletException, IOException {
filter = new CsrfFilter(tokenRepository);
filter.setRequireCsrfProtectionMatcher(requestMatcher);
when(requestMatcher.matches(request)).thenReturn(true);
when(tokenRepository.loadToken(request)).thenReturn(token);
filter.doFilter(request, response, filterChain);
assertThat(response.getHeader(token.getHeaderName())).isEqualTo(token.getToken());
assertThat(request.getAttribute(token.getParameterName())).isEqualTo(token);
assertThat(request.getAttribute(CsrfToken.class.getName())).isEqualTo(token);
assertThat(response.getStatus()).isEqualTo(HttpServletResponse.SC_FORBIDDEN);
verifyZeroInteractions(filterChain);
}
@Test(expected = IllegalArgumentException.class)
public void setRequireCsrfProtectionMatcherNull() {
filter.setRequireCsrfProtectionMatcher(null);
}
@Test(expected = IllegalArgumentException.class)
public void setAccessDeniedHandlerNull() {
filter.setAccessDeniedHandler(null);
}
}
@@ -0,0 +1,63 @@
/*
* Copyright 2002-2013 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.web.csrf;
import static org.mockito.Mockito.verify;
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.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.security.authentication.TestingAuthenticationToken;
/**
* @author Rob Winch
* @since 3.2
*/
@RunWith(MockitoJUnitRunner.class)
public class CsrfLogoutHandlerTests {
@Mock
private CsrfTokenRepository csrfTokenRepository;
private MockHttpServletRequest request;
private MockHttpServletResponse response;
private CsrfLogoutHandler handler;
@Before
public void setup() {
request = new MockHttpServletRequest();
response = new MockHttpServletResponse();
handler = new CsrfLogoutHandler(csrfTokenRepository);
}
@Test(expected = IllegalArgumentException.class)
public void constructorNullCsrfTokenRepository() {
new CsrfLogoutHandler(null);
}
@Test
public void logoutRemovesCsrfToken() {
handler.logout(request, response, new TestingAuthenticationToken("user", "password", "ROLE_USER"));
verify(csrfTokenRepository).saveToken(null, request, response);
}
}
@@ -0,0 +1,58 @@
/*
* Copyright 2002-2013 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.web.csrf;
import org.junit.Test;
/**
* @author Rob Winch
*
*/
public class CsrfTokenTests {
private final String headerName = "headerName";
private final String parameterName = "parameterName";
private final String tokenValue = "tokenValue";
@Test(expected = IllegalArgumentException.class)
public void constructorNullHeaderName() {
new CsrfToken(null,parameterName, tokenValue);
}
@Test(expected = IllegalArgumentException.class)
public void constructorEmptyHeaderName() {
new CsrfToken("",parameterName, tokenValue);
}
@Test(expected = IllegalArgumentException.class)
public void constructorNullParameterName() {
new CsrfToken(headerName,null, tokenValue);
}
@Test(expected = IllegalArgumentException.class)
public void constructorEmptyParameterName() {
new CsrfToken(headerName,"", tokenValue);
}
@Test(expected = IllegalArgumentException.class)
public void constructorNullTokenValue() {
new CsrfToken(headerName,parameterName, null);
}
@Test(expected = IllegalArgumentException.class)
public void constructorEmptyTokenValue() {
new CsrfToken(headerName,parameterName, "");
}
}
@@ -0,0 +1,127 @@
/*
* Copyright 2002-2013 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.web.csrf;
import static org.fest.assertions.Assertions.assertThat;
import org.junit.Before;
import org.junit.Test;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
/**
* @author Rob Winch
*
*/
public class HttpSessionCsrfTokenRepositoryTests {
private MockHttpServletRequest request;
private MockHttpServletResponse response;
private CsrfToken token;
private HttpSessionCsrfTokenRepository repo;
@Before
public void setup() {
request = new MockHttpServletRequest();
response = new MockHttpServletResponse();
repo = new HttpSessionCsrfTokenRepository();
}
@Test
public void generateAndSaveToken() {
token = repo.generateAndSaveToken(request, response);
assertThat(token.getParameterName()).isEqualTo("_csrf");
assertThat(token.getToken()).isNotEmpty();
CsrfToken loadedToken = repo.loadToken(request);
assertThat(loadedToken).isEqualTo(token);
}
@Test
public void generateAndSaveTokenCustomParameter() {
String paramName = "_csrf";
repo.setParameterName(paramName);
token = repo.generateAndSaveToken(request, response);
assertThat(token.getParameterName()).isEqualTo(paramName);
assertThat(token.getToken()).isNotEmpty();
}
@Test
public void loadTokenNull() {
assertThat(repo.loadToken(request)).isNull();
}
@Test
public void saveToken() {
CsrfToken tokenToSave = new CsrfToken("123", "abc", "def");
repo.saveToken(tokenToSave, request, response);
String attrName = request.getSession().getAttributeNames()
.nextElement();
CsrfToken loadedToken = (CsrfToken) request.getSession().getAttribute(
attrName);
assertThat(loadedToken).isEqualTo(tokenToSave);
}
@Test
public void saveTokenCustomSessionAttribute() {
CsrfToken tokenToSave = new CsrfToken("123", "abc", "def");
String sessionAttributeName = "custom";
repo.setSessionAttributeName(sessionAttributeName);
repo.saveToken(tokenToSave, request, response);
CsrfToken loadedToken = (CsrfToken) request.getSession().getAttribute(
sessionAttributeName);
assertThat(loadedToken).isEqualTo(tokenToSave);
}
@Test
public void saveTokenNullToken() {
saveToken();
repo.saveToken(null, request, response);
assertThat(request.getSession().getAttributeNames().hasMoreElements())
.isFalse();
}
@Test(expected = IllegalArgumentException.class)
public void setSessionAttributeNameEmpty() {
repo.setSessionAttributeName("");
}
@Test(expected = IllegalArgumentException.class)
public void setSessionAttributeNameNull() {
repo.setSessionAttributeName(null);
}
@Test(expected = IllegalArgumentException.class)
public void setParameterNameEmpty() {
repo.setParameterName("");
}
@Test(expected = IllegalArgumentException.class)
public void setParameterNameNull() {
repo.setParameterName(null);
}
}
@@ -0,0 +1,79 @@
/*
* Copyright 2002-2013 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.web.servlet.support.csrf;
import static org.fest.assertions.Assertions.assertThat;
import java.util.HashMap;
import java.util.Map;
import org.junit.Before;
import org.junit.Test;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.security.web.csrf.CsrfToken;
/**
* @author Rob Winch
*
*/
public class CsrfRequestDataValueProcessorTests {
private MockHttpServletRequest request;
private MockHttpServletResponse response;
private CsrfRequestDataValueProcessor processor;
@Before
public void setup() {
request = new MockHttpServletRequest();
response = new MockHttpServletResponse();
processor = new CsrfRequestDataValueProcessor();
}
@Test
public void getExtraHiddenFieldsNoCsrfToken() {
assertThat(processor.getExtraHiddenFields(request)).isEmpty();
}
@Test
public void getExtraHiddenFieldsHasCsrfToken() {
CsrfToken token = new CsrfToken("1", "a", "b");
request.setAttribute(CsrfToken.class.getName(), token);
Map<String,String> expected = new HashMap<String,String>();
expected.put(token.getParameterName(),token.getToken());
assertThat(processor.getExtraHiddenFields(request)).isEqualTo(expected);
}
@Test
public void processAction() {
String action = "action";
assertThat(processor.processAction(request, action)).isEqualTo(action);
}
@Test
public void processFormFieldValue() {
String value = "action";
assertThat(processor.processFormFieldValue(request, "name", value, "hidden")).isEqualTo(value);
}
@Test
public void processUrl() {
String url = "url";
assertThat(processor.processUrl(request, url)).isEqualTo(url);
}
}