Skip to content

SecurityContextRequestPostProcessorSupport small-improvements #6858

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/*
* Copyright 2002-2019 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
*
* https://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.test.web.servlet.request;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.test.web.support.WebTestUtils;
import org.springframework.security.web.context.HttpRequestResponseHolder;
import org.springframework.security.web.context.SecurityContextRepository;
import org.springframework.test.web.servlet.request.RequestPostProcessor;

/**
* Support class for {@link RequestPostProcessor}'s that establish a Spring Security
* context
*/
public class SecurityContextRequestPostProcessorSupport {

/**
* Saves the specified {@link Authentication} into an empty
* {@link SecurityContext} using the {@link SecurityContextRepository}.
*
* @param authentication the {@link Authentication} to save
* @param request the {@link HttpServletRequest} to use
*/
static final void save(Authentication authentication, HttpServletRequest request) {
SecurityContext securityContext = SecurityContextHolder.createEmptyContext();
securityContext.setAuthentication(authentication);
save(securityContext, request);
}

/**
* Saves the {@link SecurityContext} using the {@link SecurityContextRepository}
*
* @param securityContext the {@link SecurityContext} to save
* @param request the {@link HttpServletRequest} to use
*/
static final void save(SecurityContext securityContext, HttpServletRequest request) {
SecurityContextRepository securityContextRepository = WebTestUtils
.getSecurityContextRepository(request);
boolean isTestRepository = securityContextRepository instanceof TestSecurityContextRepository;
if (!isTestRepository) {
securityContextRepository = new TestSecurityContextRepository(
securityContextRepository);
WebTestUtils.setSecurityContextRepository(request,
securityContextRepository);
}

HttpServletResponse response = new MockHttpServletResponse();

HttpRequestResponseHolder requestResponseHolder = new HttpRequestResponseHolder(
request, response);
securityContextRepository.loadContext(requestResponseHolder);

request = requestResponseHolder.getRequest();
response = requestResponseHolder.getResponse();

securityContextRepository.saveContext(securityContext, request, response);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,7 @@
import org.springframework.security.test.context.TestSecurityContextHolder;
import org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers;
import org.springframework.security.test.web.support.WebTestUtils;
import org.springframework.security.web.context.HttpRequestResponseHolder;
import org.springframework.security.web.context.SecurityContextPersistenceFilter;
import org.springframework.security.web.context.SecurityContextRepository;
import org.springframework.security.web.csrf.CsrfToken;
import org.springframework.security.web.csrf.CsrfTokenRepository;
import org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository;
Expand Down Expand Up @@ -551,100 +549,6 @@ private static String md5Hex(String a2) {
}
}

/**
* Support class for {@link RequestPostProcessor}'s that establish a Spring Security
* context
*/
private static abstract class SecurityContextRequestPostProcessorSupport {

/**
* Saves the specified {@link Authentication} into an empty
* {@link SecurityContext} using the {@link SecurityContextRepository}.
*
* @param authentication the {@link Authentication} to save
* @param request the {@link HttpServletRequest} to use
*/
final void save(Authentication authentication, HttpServletRequest request) {
SecurityContext securityContext = SecurityContextHolder.createEmptyContext();
securityContext.setAuthentication(authentication);
save(securityContext, request);
}

/**
* Saves the {@link SecurityContext} using the {@link SecurityContextRepository}
*
* @param securityContext the {@link SecurityContext} to save
* @param request the {@link HttpServletRequest} to use
*/
final void save(SecurityContext securityContext, HttpServletRequest request) {
SecurityContextRepository securityContextRepository = WebTestUtils
.getSecurityContextRepository(request);
boolean isTestRepository = securityContextRepository instanceof TestSecurityContextRepository;
if (!isTestRepository) {
securityContextRepository = new TestSecurityContextRepository(
securityContextRepository);
WebTestUtils.setSecurityContextRepository(request,
securityContextRepository);
}

HttpServletResponse response = new MockHttpServletResponse();

HttpRequestResponseHolder requestResponseHolder = new HttpRequestResponseHolder(
request, response);
securityContextRepository.loadContext(requestResponseHolder);

request = requestResponseHolder.getRequest();
response = requestResponseHolder.getResponse();

securityContextRepository.saveContext(securityContext, request, response);
}

/**
* Used to wrap the SecurityContextRepository to provide support for testing in
* stateless mode
*/
static class TestSecurityContextRepository implements SecurityContextRepository {
private final static String ATTR_NAME = TestSecurityContextRepository.class
.getName().concat(".REPO");

private final SecurityContextRepository delegate;

private TestSecurityContextRepository(SecurityContextRepository delegate) {
this.delegate = delegate;
}

@Override
public SecurityContext loadContext(
HttpRequestResponseHolder requestResponseHolder) {
SecurityContext result = getContext(requestResponseHolder.getRequest());
// always load from the delegate to ensure the request/response in the
// holder are updated
// remember the SecurityContextRepository is used in many different
// locations
SecurityContext delegateResult = this.delegate
.loadContext(requestResponseHolder);
return result == null ? delegateResult : result;
}

@Override
public void saveContext(SecurityContext context, HttpServletRequest request,
HttpServletResponse response) {
request.setAttribute(ATTR_NAME, context);
this.delegate.saveContext(context, request, response);
}

@Override
public boolean containsContext(HttpServletRequest request) {
return getContext(request) != null
|| this.delegate.containsContext(request);
}

private static SecurityContext getContext(HttpServletRequest request) {
return (SecurityContext) request.getAttribute(ATTR_NAME);
}
}
}

/**
* Associates the {@link SecurityContext} found in
* {@link TestSecurityContextHolder#getContext()} with the
Expand All @@ -653,22 +557,20 @@ private static SecurityContext getContext(HttpServletRequest request) {
* @author Rob Winch
* @since 4.0
*/
private final static class TestSecurityContextHolderPostProcessor extends
SecurityContextRequestPostProcessorSupport implements RequestPostProcessor {
private final static class TestSecurityContextHolderPostProcessor implements RequestPostProcessor {
private SecurityContext EMPTY = SecurityContextHolder.createEmptyContext();

@Override
public MockHttpServletRequest postProcessRequest(MockHttpServletRequest request) {
// TestSecurityContextHolder is only a default value
SecurityContext existingContext = TestSecurityContextRepository
.getContext(request);
SecurityContext existingContext = TestSecurityContextRepository.getContext(request);
if (existingContext != null) {
return request;
}

SecurityContext context = TestSecurityContextHolder.getContext();
if (!this.EMPTY.equals(context)) {
save(context, request);
SecurityContextRequestPostProcessorSupport.save(context, request);
}

return request;
Expand All @@ -682,8 +584,7 @@ public MockHttpServletRequest postProcessRequest(MockHttpServletRequest request)
* @author Rob Winch
* @since 4.0
*/
private final static class SecurityContextRequestPostProcessor extends
SecurityContextRequestPostProcessorSupport implements RequestPostProcessor {
private final static class SecurityContextRequestPostProcessor implements RequestPostProcessor {

private final SecurityContext securityContext;

Expand All @@ -693,7 +594,7 @@ private SecurityContextRequestPostProcessor(SecurityContext securityContext) {

@Override
public MockHttpServletRequest postProcessRequest(MockHttpServletRequest request) {
save(this.securityContext, request);
SecurityContextRequestPostProcessorSupport.save(this.securityContext, request);
return request;
}
}
Expand All @@ -706,8 +607,7 @@ public MockHttpServletRequest postProcessRequest(MockHttpServletRequest request)
* @since 4.0
*
*/
private final static class AuthenticationRequestPostProcessor extends
SecurityContextRequestPostProcessorSupport implements RequestPostProcessor {
private final static class AuthenticationRequestPostProcessor implements RequestPostProcessor {
private final Authentication authentication;

private AuthenticationRequestPostProcessor(Authentication authentication) {
Expand All @@ -716,9 +616,7 @@ private AuthenticationRequestPostProcessor(Authentication authentication) {

@Override
public MockHttpServletRequest postProcessRequest(MockHttpServletRequest request) {
SecurityContext context = SecurityContextHolder.createEmptyContext();
context.setAuthentication(this.authentication);
save(this.authentication, request);
SecurityContextRequestPostProcessorSupport.save(this.authentication, request);
return request;
}
}
Expand Down Expand Up @@ -755,8 +653,7 @@ public MockHttpServletRequest postProcessRequest(MockHttpServletRequest request)
* @author Rob Winch
* @since 4.0
*/
public final static class UserRequestPostProcessor extends
SecurityContextRequestPostProcessorSupport implements RequestPostProcessor {
public final static class UserRequestPostProcessor implements RequestPostProcessor {

private String username;

Expand Down Expand Up @@ -866,8 +763,7 @@ private User createUser() {
}
}

private static class AnonymousRequestPostProcessor extends
SecurityContextRequestPostProcessorSupport implements RequestPostProcessor {
private static class AnonymousRequestPostProcessor implements RequestPostProcessor {
private AuthenticationRequestPostProcessor delegate = new AuthenticationRequestPostProcessor(
new AnonymousAuthenticationToken("key", "anonymous",
AuthorityUtils.createAuthorityList("ROLE_ANONYMOUS")));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/*
* Copyright 2002-2019 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
*
* https://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.test.web.servlet.request;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.web.context.HttpRequestResponseHolder;
import org.springframework.security.web.context.SecurityContextRepository;

/**
* Used to wrap the SecurityContextRepository to provide support for testing in
* stateless mode
*/
public class TestSecurityContextRepository implements SecurityContextRepository {
private final static String ATTR_NAME = TestSecurityContextRepository.class
.getName().concat(".REPO");

private final SecurityContextRepository delegate;

TestSecurityContextRepository(SecurityContextRepository delegate) {
this.delegate = delegate;
}

@Override
public SecurityContext loadContext(
HttpRequestResponseHolder requestResponseHolder) {
SecurityContext result = getContext(requestResponseHolder.getRequest());
// always load from the delegate to ensure the request/response in the
// holder are updated
// remember the SecurityContextRepository is used in many different
// locations
SecurityContext delegateResult = this.delegate
.loadContext(requestResponseHolder);
return result == null ? delegateResult : result;
}

@Override
public void saveContext(SecurityContext context, HttpServletRequest request,
HttpServletResponse response) {
request.setAttribute(ATTR_NAME, context);
this.delegate.saveContext(context, request, response);
}

@Override
public boolean containsContext(HttpServletRequest request) {
return getContext(request) != null
|| this.delegate.containsContext(request);
}

static SecurityContext getContext(HttpServletRequest request) {
return (SecurityContext) request.getAttribute(ATTR_NAME);
}
}