Skip to content

Commit 7d99436

Browse files
committed
SEC-2358: Add RequestHeaderRequestMatcher
1 parent 0ac1176 commit 7d99436

File tree

2 files changed

+183
-0
lines changed

2 files changed

+183
-0
lines changed
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
/*
2+
* Copyright 2002-2013 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.security.web.util;
17+
18+
import javax.servlet.http.HttpServletRequest;
19+
20+
import org.springframework.util.Assert;
21+
22+
/**
23+
* A {@link RequestMatcher} that can be used to match request that contain a
24+
* header with an expected header name and an expected value.
25+
*
26+
* <p>
27+
* For example, the following will match an request that contains a header with
28+
* the name X-Requested-With no matter what the value is.
29+
* </p>
30+
*
31+
* <pre>
32+
* RequestMatcher matcher = new RequestHeaderRequestMatcher(&quot;X-Requested-With&quot;);
33+
* </pre>
34+
*
35+
* Alternatively, the RequestHeaderRequestMatcher can be more precise and
36+
* require a specific value. For example the following will match on requests
37+
* with the header name of X-Requested-With with the value of "XMLHttpRequest",
38+
* but will not match on header name of "X-Requested-With" with the value of
39+
* "Other".
40+
*
41+
* <pre>
42+
* RequestMatcher matcher = new RequestHeaderRequestMatcher(&quot;X-Requested-With&quot;,
43+
* &quot;XMLHttpRequest&quot;);
44+
* </pre>
45+
*
46+
* The value used to compare is the first header value, so in the previous
47+
* example if the header "X-Requested-With" contains the values "Other" and
48+
* "XMLHttpRequest", then it will not match.
49+
*
50+
* @author Rob Winch
51+
* @since 3.2
52+
*/
53+
public final class RequestHeaderRequestMatcher implements RequestMatcher {
54+
private final String expectedHeaderName;
55+
private final String expectedHeaderValue;
56+
57+
/**
58+
* Creates a new instance that will match if a header by the name of
59+
* {@link #expectedHeaderName} is present. In this instance, the value does
60+
* not matter.
61+
*
62+
* @param expectedHeaderName
63+
* the name of the expected header that if present the request
64+
* will match. Cannot be null.
65+
*/
66+
public RequestHeaderRequestMatcher(String expectedHeaderName) {
67+
this(expectedHeaderName, null);
68+
}
69+
70+
/**
71+
* Creates a new instance that will match if a header by the name of
72+
* {@link #expectedHeaderName} is present and if the
73+
* {@link #expectedHeaderValue} is non-null the first value is the same.
74+
*
75+
* @param expectedHeaderName
76+
* the name of the expected header. Cannot be null
77+
* @param expectedHeaderName
78+
* the expected header value or null if the value does not matter
79+
*/
80+
public RequestHeaderRequestMatcher(String expectedHeaderName,
81+
String exepctedHeaderName) {
82+
Assert.notNull(expectedHeaderName, "headerName cannot be null");
83+
this.expectedHeaderName = expectedHeaderName;
84+
this.expectedHeaderValue = exepctedHeaderName;
85+
}
86+
87+
public boolean matches(HttpServletRequest request) {
88+
String actualHeaderValue = request.getHeader(expectedHeaderName);
89+
if (expectedHeaderValue == null) {
90+
return actualHeaderValue != null;
91+
}
92+
93+
return expectedHeaderValue.equals(actualHeaderValue);
94+
}
95+
}
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
/*
2+
* Copyright 2002-2013 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.security.web.util;
17+
18+
import static org.fest.assertions.Assertions.assertThat;
19+
20+
import org.junit.Before;
21+
import org.junit.Test;
22+
import org.springframework.mock.web.MockHttpServletRequest;
23+
24+
/**
25+
*
26+
* @author Rob Winch
27+
*
28+
*/
29+
public class RequestHeaderRequestMatcherTests {
30+
31+
private final String headerName = "headerName";
32+
33+
private final String headerValue = "headerValue";
34+
35+
private MockHttpServletRequest request;
36+
37+
@Before
38+
public void setup() {
39+
request = new MockHttpServletRequest();
40+
}
41+
42+
@Test(expected = IllegalArgumentException.class)
43+
public void constructorNullHeaderName() {
44+
new RequestHeaderRequestMatcher(null);
45+
}
46+
47+
@Test(expected = IllegalArgumentException.class)
48+
public void constructorNullHeaderNameNonNullHeaderValue() {
49+
new RequestHeaderRequestMatcher(null,"v");
50+
}
51+
52+
@Test
53+
public void matchesHeaderNameMatches() {
54+
request.addHeader(headerName, headerValue);
55+
assertThat(new RequestHeaderRequestMatcher(headerName).matches(request)).isTrue();
56+
}
57+
58+
@Test
59+
public void matchesHeaderNameDoesNotMatch() {
60+
request.addHeader(headerName+"notMatch", headerValue);
61+
assertThat(new RequestHeaderRequestMatcher(headerName).matches(request)).isFalse();
62+
}
63+
64+
@Test
65+
public void matchesHeaderNameValueMatches() {
66+
request.addHeader(headerName, headerValue);
67+
assertThat(new RequestHeaderRequestMatcher(headerName, headerValue).matches(request)).isTrue();
68+
}
69+
70+
@Test
71+
public void matchesHeaderNameValueHeaderNameNotMatch() {
72+
request.addHeader(headerName+"notMatch", headerValue);
73+
assertThat(new RequestHeaderRequestMatcher(headerName, headerValue).matches(request)).isFalse();
74+
}
75+
76+
@Test
77+
public void matchesHeaderNameValueHeaderValueNotMatch() {
78+
request.addHeader(headerName, headerValue+"notMatch");
79+
assertThat(new RequestHeaderRequestMatcher(headerName, headerValue).matches(request)).isFalse();
80+
}
81+
82+
@Test
83+
public void matchesHeaderNameValueHeaderValueMultiNotMatch() {
84+
request.addHeader(headerName, headerValue+"notMatch");
85+
request.addHeader(headerName, headerValue);
86+
assertThat(new RequestHeaderRequestMatcher(headerName, headerValue).matches(request)).isFalse();
87+
}
88+
}

0 commit comments

Comments
 (0)