diff --git a/web/src/main/java/org/springframework/security/web/util/RequestHeaderRequestMatcher.java b/web/src/main/java/org/springframework/security/web/util/RequestHeaderRequestMatcher.java new file mode 100644 index 0000000000..ea5e1aaf06 --- /dev/null +++ b/web/src/main/java/org/springframework/security/web/util/RequestHeaderRequestMatcher.java @@ -0,0 +1,95 @@ +/* + * 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.util; + +import javax.servlet.http.HttpServletRequest; + +import org.springframework.util.Assert; + +/** + * A {@link RequestMatcher} that can be used to match request that contain a + * header with an expected header name and an expected value. + * + *

+ * For example, the following will match an request that contains a header with + * the name X-Requested-With no matter what the value is. + *

+ * + *
+ * RequestMatcher matcher = new RequestHeaderRequestMatcher("X-Requested-With");
+ * 
+ * + * Alternatively, the RequestHeaderRequestMatcher can be more precise and + * require a specific value. For example the following will match on requests + * with the header name of X-Requested-With with the value of "XMLHttpRequest", + * but will not match on header name of "X-Requested-With" with the value of + * "Other". + * + *
+ * RequestMatcher matcher = new RequestHeaderRequestMatcher("X-Requested-With",
+ * 		"XMLHttpRequest");
+ * 
+ * + * The value used to compare is the first header value, so in the previous + * example if the header "X-Requested-With" contains the values "Other" and + * "XMLHttpRequest", then it will not match. + * + * @author Rob Winch + * @since 3.2 + */ +public final class RequestHeaderRequestMatcher implements RequestMatcher { + private final String expectedHeaderName; + private final String expectedHeaderValue; + + /** + * Creates a new instance that will match if a header by the name of + * {@link #expectedHeaderName} is present. In this instance, the value does + * not matter. + * + * @param expectedHeaderName + * the name of the expected header that if present the request + * will match. Cannot be null. + */ + public RequestHeaderRequestMatcher(String expectedHeaderName) { + this(expectedHeaderName, null); + } + + /** + * Creates a new instance that will match if a header by the name of + * {@link #expectedHeaderName} is present and if the + * {@link #expectedHeaderValue} is non-null the first value is the same. + * + * @param expectedHeaderName + * the name of the expected header. Cannot be null + * @param expectedHeaderName + * the expected header value or null if the value does not matter + */ + public RequestHeaderRequestMatcher(String expectedHeaderName, + String exepctedHeaderName) { + Assert.notNull(expectedHeaderName, "headerName cannot be null"); + this.expectedHeaderName = expectedHeaderName; + this.expectedHeaderValue = exepctedHeaderName; + } + + public boolean matches(HttpServletRequest request) { + String actualHeaderValue = request.getHeader(expectedHeaderName); + if (expectedHeaderValue == null) { + return actualHeaderValue != null; + } + + return expectedHeaderValue.equals(actualHeaderValue); + } +} \ No newline at end of file diff --git a/web/src/test/java/org/springframework/security/web/util/RequestHeaderRequestMatcherTests.java b/web/src/test/java/org/springframework/security/web/util/RequestHeaderRequestMatcherTests.java new file mode 100644 index 0000000000..f231a163d9 --- /dev/null +++ b/web/src/test/java/org/springframework/security/web/util/RequestHeaderRequestMatcherTests.java @@ -0,0 +1,88 @@ +/* + * 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.util; + +import static org.fest.assertions.Assertions.assertThat; + +import org.junit.Before; +import org.junit.Test; +import org.springframework.mock.web.MockHttpServletRequest; + +/** + * + * @author Rob Winch + * + */ +public class RequestHeaderRequestMatcherTests { + + private final String headerName = "headerName"; + + private final String headerValue = "headerValue"; + + private MockHttpServletRequest request; + + @Before + public void setup() { + request = new MockHttpServletRequest(); + } + + @Test(expected = IllegalArgumentException.class) + public void constructorNullHeaderName() { + new RequestHeaderRequestMatcher(null); + } + + @Test(expected = IllegalArgumentException.class) + public void constructorNullHeaderNameNonNullHeaderValue() { + new RequestHeaderRequestMatcher(null,"v"); + } + + @Test + public void matchesHeaderNameMatches() { + request.addHeader(headerName, headerValue); + assertThat(new RequestHeaderRequestMatcher(headerName).matches(request)).isTrue(); + } + + @Test + public void matchesHeaderNameDoesNotMatch() { + request.addHeader(headerName+"notMatch", headerValue); + assertThat(new RequestHeaderRequestMatcher(headerName).matches(request)).isFalse(); + } + + @Test + public void matchesHeaderNameValueMatches() { + request.addHeader(headerName, headerValue); + assertThat(new RequestHeaderRequestMatcher(headerName, headerValue).matches(request)).isTrue(); + } + + @Test + public void matchesHeaderNameValueHeaderNameNotMatch() { + request.addHeader(headerName+"notMatch", headerValue); + assertThat(new RequestHeaderRequestMatcher(headerName, headerValue).matches(request)).isFalse(); + } + + @Test + public void matchesHeaderNameValueHeaderValueNotMatch() { + request.addHeader(headerName, headerValue+"notMatch"); + assertThat(new RequestHeaderRequestMatcher(headerName, headerValue).matches(request)).isFalse(); + } + + @Test + public void matchesHeaderNameValueHeaderValueMultiNotMatch() { + request.addHeader(headerName, headerValue+"notMatch"); + request.addHeader(headerName, headerValue); + assertThat(new RequestHeaderRequestMatcher(headerName, headerValue).matches(request)).isFalse(); + } +}