Skip to content

Commit b9f7954

Browse files
committed
Add RequestAttributeSecurityContextRepository
Closes gh-10918
1 parent ff87cfc commit b9f7954

File tree

2 files changed

+155
-0
lines changed

2 files changed

+155
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
/*
2+
* Copyright 2002-2022 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+
* https://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+
17+
package org.springframework.security.web.context;
18+
19+
import javax.servlet.http.HttpServletRequest;
20+
import javax.servlet.http.HttpServletResponse;
21+
22+
import org.springframework.security.core.context.SecurityContext;
23+
import org.springframework.security.core.context.SecurityContextHolder;
24+
25+
/**
26+
* Stores the {@link SecurityContext} on a
27+
* {@link javax.servlet.ServletRequest#setAttribute(String, Object)} so that it can be
28+
* restored when different dispatch types occur. It will not be available on subsequent
29+
* requests.
30+
*
31+
* Unlike {@link HttpSessionSecurityContextRepository} this filter has no need to persist
32+
* the {@link SecurityContext} on the response being committed because the
33+
* {@link SecurityContext} will not be available for subsequent requests for
34+
* {@link RequestAttributeSecurityContextRepository}.
35+
*
36+
* @author Rob Winch
37+
* @since 5.7
38+
*/
39+
public final class RequestAttributeSecurityContextRepository implements SecurityContextRepository {
40+
41+
/**
42+
* The default request attribute name to use.
43+
*/
44+
public static final String DEFAULT_REQUEST_ATTR_NAME = RequestAttributeSecurityContextRepository.class.getName()
45+
.concat(".SPRING_SECURITY_CONTEXT");
46+
47+
private final String requestAttributeName;
48+
49+
/**
50+
* Creates a new instance using {@link #DEFAULT_REQUEST_ATTR_NAME}.
51+
*/
52+
public RequestAttributeSecurityContextRepository() {
53+
this(DEFAULT_REQUEST_ATTR_NAME);
54+
}
55+
56+
/**
57+
* Creates a new instance with the specified request attribute name.
58+
* @param requestAttributeName the request attribute name to set to the
59+
* {@link SecurityContext}.
60+
*/
61+
public RequestAttributeSecurityContextRepository(String requestAttributeName) {
62+
this.requestAttributeName = requestAttributeName;
63+
}
64+
65+
@Override
66+
public boolean containsContext(HttpServletRequest request) {
67+
return loadContext(request) != null;
68+
}
69+
70+
@Override
71+
public SecurityContext loadContext(HttpRequestResponseHolder requestResponseHolder) {
72+
SecurityContext context = loadContext(requestResponseHolder.getRequest());
73+
return (context != null) ? context : SecurityContextHolder.createEmptyContext();
74+
}
75+
76+
private SecurityContext loadContext(HttpServletRequest request) {
77+
return (SecurityContext) request.getAttribute(this.requestAttributeName);
78+
}
79+
80+
@Override
81+
public void saveContext(SecurityContext context, HttpServletRequest request, HttpServletResponse response) {
82+
request.setAttribute(this.requestAttributeName, context);
83+
}
84+
85+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
/*
2+
* Copyright 2002-2022 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+
* https://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+
17+
package org.springframework.security.web.context;
18+
19+
import org.junit.jupiter.api.Test;
20+
21+
import org.springframework.mock.web.MockHttpServletRequest;
22+
import org.springframework.mock.web.MockHttpServletResponse;
23+
import org.springframework.security.authentication.TestAuthentication;
24+
import org.springframework.security.core.context.SecurityContext;
25+
import org.springframework.security.core.context.SecurityContextHolder;
26+
import org.springframework.security.core.context.SecurityContextImpl;
27+
28+
import static org.assertj.core.api.Assertions.assertThat;
29+
30+
/**
31+
* @author Rob Winch
32+
*/
33+
class RequestAttributeSecurityContextRepositoryTests {
34+
35+
private MockHttpServletRequest request = new MockHttpServletRequest();
36+
37+
private MockHttpServletResponse response = new MockHttpServletResponse();
38+
39+
private RequestAttributeSecurityContextRepository repository = new RequestAttributeSecurityContextRepository();
40+
41+
private SecurityContext expectedSecurityContext = new SecurityContextImpl(TestAuthentication.authenticatedUser());
42+
43+
@Test
44+
void saveContextAndLoadContextThenFound() {
45+
this.repository.saveContext(this.expectedSecurityContext, this.request, this.response);
46+
SecurityContext securityContext = this.repository
47+
.loadContext(new HttpRequestResponseHolder(this.request, this.response));
48+
assertThat(securityContext).isEqualTo(this.expectedSecurityContext);
49+
}
50+
51+
@Test
52+
void saveContextWhenLoadContextAndNewRequestThenNotFound() {
53+
this.repository.saveContext(this.expectedSecurityContext, this.request, this.response);
54+
SecurityContext securityContext = this.repository.loadContext(
55+
new HttpRequestResponseHolder(new MockHttpServletRequest(), new MockHttpServletResponse()));
56+
assertThat(securityContext).isEqualTo(SecurityContextHolder.createEmptyContext());
57+
}
58+
59+
@Test
60+
void containsContextWhenNotSavedThenFalse() {
61+
assertThat(this.repository.containsContext(this.request)).isFalse();
62+
}
63+
64+
@Test
65+
void containsContextWhenSavedThenTrue() {
66+
this.repository.saveContext(this.expectedSecurityContext, this.request, this.response);
67+
assertThat(this.repository.containsContext(this.request)).isTrue();
68+
}
69+
70+
}

0 commit comments

Comments
 (0)