/*
* Copyright 2002-2017 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.test.web.servlet.request;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Base64;
import java.util.Collection;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.security.authentication.AnonymousAuthenticationToken;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
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;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.RequestPostProcessor;
import org.springframework.util.Assert;
import org.springframework.util.DigestUtils;
/**
* Contains {@link MockMvc} {@link RequestPostProcessor} implementations for Spring
* Security.
*
* @author Rob Winch
* @since 4.0
*/
public final class SecurityMockMvcRequestPostProcessors {
/**
* Creates a DigestRequestPostProcessor that enables easily adding digest based
* authentication to a request.
*
* @return the DigestRequestPostProcessor to use
*/
public static DigestRequestPostProcessor digest() {
return new DigestRequestPostProcessor();
}
/**
* Creates a DigestRequestPostProcessor that enables easily adding digest based
* authentication to a request.
*
* @param username the username to use
* @return the DigestRequestPostProcessor to use
*/
public static DigestRequestPostProcessor digest(String username) {
return digest().username(username);
}
/**
* Populates the provided X509Certificate instances on the request.
* @param certificates the X509Certificate instances to pouplate
* @return the
* {@link org.springframework.test.web.servlet.request.RequestPostProcessor} to use.
*/
public static RequestPostProcessor x509(X509Certificate... certificates) {
return new X509RequestPostProcessor(certificates);
}
/**
* Finds an X509Cetificate using a resoureName and populates it on the request.
*
* @param resourceName the name of the X509Certificate resource
* @return the
* {@link org.springframework.test.web.servlet.request.RequestPostProcessor} to use.
* @throws IOException
* @throws CertificateException
*/
public static RequestPostProcessor x509(String resourceName)
throws IOException, CertificateException {
ResourceLoader loader = new DefaultResourceLoader();
Resource resource = loader.getResource(resourceName);
InputStream inputStream = resource.getInputStream();
CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
X509Certificate certificate = (X509Certificate) certFactory
.generateCertificate(inputStream);
return x509(certificate);
}
/**
* Creates a {@link RequestPostProcessor} that will automatically populate a valid
* {@link CsrfToken} in the request.
*
* @return the {@link CsrfRequestPostProcessor} for further customizations.
*/
public static CsrfRequestPostProcessor csrf() {
return new CsrfRequestPostProcessor();
}
/**
* Creates a {@link RequestPostProcessor} that can be used to ensure that the
* resulting request is ran with the user in the {@link TestSecurityContextHolder}.
*
* @return the {@link RequestPostProcessor} to sue
*/
public static RequestPostProcessor testSecurityContext() {
return new TestSecurityContextHolderPostProcessor();
}
/**
* Establish a {@link SecurityContext} that has a
* {@link UsernamePasswordAuthenticationToken} for the
* {@link Authentication#getPrincipal()} and a {@link User} for the
* {@link UsernamePasswordAuthenticationToken#getPrincipal()}. All details are
* declarative and do not require that the user actually exists.
*
* <p>
* The support works by associating the user to the HttpServletRequest. To associate
* the request to the SecurityContextHolder you need to ensure that the
* SecurityContextPersistenceFilter is associated with the MockMvc instance. A few
* ways to do this are:
* </p>
*
* <ul>
* <li>Invoking apply {@link SecurityMockMvcConfigurers#springSecurity()}</li>
* <li>Adding Spring Security's FilterChainProxy to MockMvc</li>
* <li>Manually adding {@link SecurityContextPersistenceFilter} to the MockMvc
* instance may make sense when using MockMvcBuilders standaloneSetup</li>
* </ul>
*
* @param username the username to populate
* @return the {@link UserRequestPostProcessor} for additional customization
*/
public static UserRequestPostProcessor user(String username) {
return new UserRequestPostProcessor(username);
}
/**
* Establish a {@link SecurityContext} that has a
* {@link UsernamePasswordAuthenticationToken} for the
* {@link Authentication#getPrincipal()} and a custom {@link UserDetails} for the
* {@link UsernamePasswordAuthenticationToken#getPrincipal()}. All details are
* declarative and do not require that the user actually exists.
*
* <p>
* The support works by associating the user to the HttpServletRequest. To associate
* the request to the SecurityContextHolder you need to ensure that the
* SecurityContextPersistenceFilter is associated with the MockMvc instance. A few
* ways to do this are:
* </p>
*
* <ul>
* <li>Invoking apply {@link SecurityMockMvcConfigurers#springSecurity()}</li>
* <li>Adding Spring Security's FilterChainProxy to MockMvc</li>
* <li>Manually adding {@link SecurityContextPersistenceFilter} to the MockMvc
* instance may make sense when using MockMvcBuilders standaloneSetup</li>
* </ul>
*
* @param user the UserDetails to populate
* @return the {@link RequestPostProcessor} to use
*/
public static RequestPostProcessor user(UserDetails user) {
return new UserDetailsRequestPostProcessor(user);
}
/**
* Establish a {@link SecurityContext} that uses the specified {@link Authentication}
* for the {@link Authentication#getPrincipal()} and a custom {@link UserDetails}. All
* details are declarative and do not require that the user actually exists.
*
* <p>
* The support works by associating the user to the HttpServletRequest. To associate
* the request to the SecurityContextHolder you need to ensure that the
* SecurityContextPersistenceFilter is associated with the MockMvc instance. A few
* ways to do this are:
* </p>
*
* <ul>
* <li>Invoking apply {@link SecurityMockMvcConfigurers#springSecurity()}</li>
* <li>Adding Spring Security's FilterChainProxy to MockMvc</li>
* <li>Manually adding {@link SecurityContextPersistenceFilter} to the MockMvc
* instance may make sense when using MockMvcBuilders standaloneSetup</li>
* </ul>
*
* @param authentication the Authentication to populate
* @return the {@link RequestPostProcessor} to use
*/
public static RequestPostProcessor authentication(Authentication authentication) {
return new AuthenticationRequestPostProcessor(authentication);
}
/**
* Establish a {@link SecurityContext} that uses an
* {@link AnonymousAuthenticationToken}. This is useful when a user wants to run a
* majority of tests as a specific user and wishes to override a few methods to be
* anonymous. For example:
*
* <pre>
* <code>
* public class SecurityTests {
* @Before
* public void setup() {
* mockMvc = MockMvcBuilders
* .webAppContextSetup(context)
* .defaultRequest(get("/").with(user("user")))
* .build();
* }
*
* @Test
* public void anonymous() {
* mockMvc.perform(get("anonymous").with(anonymous()));
* }
* // ... lots of tests ran with a default user ...
* }
* </code> </pre>
*
* @return the {@link RequestPostProcessor} to use
*/
public static RequestPostProcessor anonymous() {
return new AnonymousRequestPostProcessor();
}
/**
* Establish the specified {@link SecurityContext} to be used.
*
* <p>
* This works by associating the user to the {@link HttpServletRequest}. To associate
* the request to the {@link SecurityContextHolder} you need to ensure that the
* {@link SecurityContextPersistenceFilter} (i.e. Spring Security's FilterChainProxy
* will typically do this) is associated with the {@link MockMvc} instance.
* </p>
*/
public static RequestPostProcessor securityContext(SecurityContext securityContext) {
return new SecurityContextRequestPostProcessor(securityContext);
}
/**
* Convenience mechanism for setting the Authorization header to use HTTP Basic with
* the given username and password. This method will automatically perform the
* necessary Base64 encoding.
*
* @param username the username to include in the Authorization header.
* @param password the password to include in the Authorization header.
* @return the {@link RequestPostProcessor} to use
*/
public static RequestPostProcessor httpBasic(String username, String password) {
return new HttpBasicRequestPostProcessor(username, password);
}
/**
* Populates the X509Certificate instances onto the request
*/
private static class X509RequestPostProcessor implements RequestPostProcessor {
private final X509Certificate[] certificates;
private X509RequestPostProcessor(X509Certificate... certificates) {
Assert.notNull(certificates, "X509Certificate cannot be null");
this.certificates = certificates;
}
@Override
public MockHttpServletRequest postProcessRequest(MockHttpServletRequest request) {
request.setAttribute("javax.servlet.request.X509Certificate",
this.certificates);
return request;
}
}
/**
* Populates a valid {@link CsrfToken} into the request.
*
* @author Rob Winch
* @since 4.0
*/
public static class CsrfRequestPostProcessor implements RequestPostProcessor {
private boolean asHeader;
private boolean useInvalidToken;
/*
* (non-Javadoc)
*
* @see org.springframework.test.web.servlet.request.RequestPostProcessor
* #postProcessRequest (org.springframework.mock.web.MockHttpServletRequest)
*/
@Override
public MockHttpServletRequest postProcessRequest(MockHttpServletRequest request) {
CsrfTokenRepository repository = WebTestUtils.getCsrfTokenRepository(request);
if (!(repository instanceof TestCsrfTokenRepository)) {
repository = new TestCsrfTokenRepository(
new HttpSessionCsrfTokenRepository());
WebTestUtils.setCsrfTokenRepository(request, repository);
}
TestCsrfTokenRepository.enable(request);
CsrfToken token = repository.generateToken(request);
repository.saveToken(token, request, new MockHttpServletResponse());
String tokenValue = this.useInvalidToken ? "invalid" + token.getToken()
: token.getToken();
if (this.asHeader) {
request.addHeader(token.getHeaderName(), tokenValue);
}
else {
request.setParameter(token.getParameterName(), tokenValue);
}
return request;
}
/**
* Instead of using the {@link CsrfToken} as a request parameter (default) will
* populate the {@link CsrfToken} as a header.
*
* @return the {@link CsrfRequestPostProcessor} for additional customizations
*/
public CsrfRequestPostProcessor asHeader() {
this.asHeader = true;
return this;
}
/**
* Populates an invalid token value on the request.
*
* @return the {@link CsrfRequestPostProcessor} for additional customizations
*/
public CsrfRequestPostProcessor useInvalidToken() {
this.useInvalidToken = true;
return this;
}
private CsrfRequestPostProcessor() {
}
/**
* Used to wrap the CsrfTokenRepository to provide support for testing when the
* request is wrapped (i.e. Spring Session is in use).
*/
static class TestCsrfTokenRepository implements CsrfTokenRepository {
final static String TOKEN_ATTR_NAME = TestCsrfTokenRepository.class.getName()
.concat(".TOKEN");
final static String ENABLED_ATTR_NAME = TestCsrfTokenRepository.class
.getName().concat(".ENABLED");
private final CsrfTokenRepository delegate;
private TestCsrfTokenRepository(CsrfTokenRepository delegate) {
this.delegate = delegate;
}
@Override
public CsrfToken generateToken(HttpServletRequest request) {
return this.delegate.generateToken(request);
}
@Override
public void saveToken(CsrfToken token, HttpServletRequest request,
HttpServletResponse response) {
if (isEnabled(request)) {
request.setAttribute(TOKEN_ATTR_NAME, token);
}
else {
this.delegate.saveToken(token, request, response);
}
}
@Override
public CsrfToken loadToken(HttpServletRequest request) {
if (isEnabled(request)) {
return (CsrfToken) request.getAttribute(TOKEN_ATTR_NAME);
}
else {
return this.delegate.loadToken(request);
}
}
public static void enable(HttpServletRequest request) {
request.setAttribute(ENABLED_ATTR_NAME, Boolean.TRUE);
}
public boolean isEnabled(HttpServletRequest request) {
return Boolean.TRUE.equals(request.getAttribute(ENABLED_ATTR_NAME));
}
}
}
public static class DigestRequestPostProcessor implements RequestPostProcessor {
private String username = "user";
private String password = "password";
private String realm = "Spring Security";
private String nonce = generateNonce(60);
private String qop = "auth";
private String nc = "00000001";
private String cnonce = "c822c727a648aba7";
/**
* Configures the username to use
* @param username the username to use
* @return the DigestRequestPostProcessor for further customization
*/
private DigestRequestPostProcessor username(String username) {
Assert.notNull(username, "username cannot be null");
this.username = username;
return this;
}
/**
* Configures the password to use
* @param password the password to use
* @return the DigestRequestPostProcessor for further customization
*/
public DigestRequestPostProcessor password(String password) {
Assert.notNull(password, "password cannot be null");
this.password = password;
return this;
}
/**
* Configures the realm to use
* @param realm the realm to use
* @return the DigestRequestPostProcessor for further customization
*/
public DigestRequestPostProcessor realm(String realm) {
Assert.notNull(realm, "realm cannot be null");
this.realm = realm;
return this;
}
private static String generateNonce(int validitySeconds) {
long expiryTime = System.currentTimeMillis() + (validitySeconds * 1000);
String toDigest = expiryTime + ":" + "key";
String signatureValue = md5Hex(toDigest);
String nonceValue = expiryTime + ":" + signatureValue;
return new String(Base64.getEncoder().encode(nonceValue.getBytes()));
}
private String createAuthorizationHeader(MockHttpServletRequest request) {
String uri = request.getRequestURI();
String responseDigest = generateDigest(this.username, this.realm,
this.password, request.getMethod(), uri, this.qop, this.nonce,
this.nc, this.cnonce);
return "Digest username=\"" + this.username + "\", realm=\"" + this.realm
+ "\", nonce=\"" + this.nonce + "\", uri=\"" + uri + "\", response=\""
+ responseDigest + "\", qop=" + this.qop + ", nc=" + this.nc
+ ", cnonce=\"" + this.cnonce + "\"";
}
@Override
public MockHttpServletRequest postProcessRequest(MockHttpServletRequest request) {
request.addHeader("Authorization", createAuthorizationHeader(request));
return request;
}
/**
* Computes the <code>response</code> portion of a Digest authentication header.
* Both the server and user agent should compute the <code>response</code>
* independently. Provided as a static method to simplify the coding of user
* agents.
*
* @param username the user's login name.
* @param realm the name of the realm.
* @param password the user's password in plaintext or ready-encoded.
* @param httpMethod the HTTP request method (GET, POST etc.)
* @param uri the request URI.
* @param qop the qop directive, or null if not set.
* @param nonce the nonce supplied by the server
* @param nc the "nonce-count" as defined in RFC 2617.
* @param cnonce opaque string supplied by the client when qop is set.
* @return the MD5 of the digest authentication response, encoded in hex
* @throws IllegalArgumentException if the supplied qop value is unsupported.
*/
private static String generateDigest(String username, String realm,
String password, String httpMethod, String uri, String qop, String nonce,
String nc, String cnonce) throws IllegalArgumentException {
String a1Md5 = encodePasswordInA1Format(username, realm, password);
String a2 = httpMethod + ":" + uri;
String a2Md5 = md5Hex(a2);
String digest;
if (qop == null) {
// as per RFC 2069 compliant clients (also reaffirmed by RFC 2617)
digest = a1Md5 + ":" + nonce + ":" + a2Md5;
}
else if ("auth".equals(qop)) {
// As per RFC 2617 compliant clients
digest = a1Md5 + ":" + nonce + ":" + nc + ":" + cnonce + ":" + qop + ":"
+ a2Md5;
}
else {
throw new IllegalArgumentException(
"This method does not support a qop: '" + qop + "'");
}
return md5Hex(digest);
}
static String encodePasswordInA1Format(String username, String realm,
String password) {
String a1 = username + ":" + realm + ":" + password;
return md5Hex(a1);
}
private static String md5Hex(String a2) {
try {
return DigestUtils.md5DigestAsHex(a2.getBytes("UTF-8"));
}
catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
}
}
/**
* 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
* {@link MockHttpServletRequest}.
*
* @author Rob Winch
* @since 4.0
*/
private final static class TestSecurityContextHolderPostProcessor extends
SecurityContextRequestPostProcessorSupport implements RequestPostProcessor {
private SecurityContext EMPTY = SecurityContextHolder.createEmptyContext();
@Override
public MockHttpServletRequest postProcessRequest(MockHttpServletRequest request) {
// TestSecurityContextHolder is only a default value
SecurityContext existingContext = TestSecurityContextRepository
.getContext(request);
if (existingContext != null) {
return request;
}
SecurityContext context = TestSecurityContextHolder.getContext();
if (!this.EMPTY.equals(context)) {
save(context, request);
}
return request;
}
}
/**
* Associates the specified {@link SecurityContext} with the
* {@link MockHttpServletRequest}.
*
* @author Rob Winch
* @since 4.0
*/
private final static class SecurityContextRequestPostProcessor extends
SecurityContextRequestPostProcessorSupport implements RequestPostProcessor {
private final SecurityContext securityContext;
private SecurityContextRequestPostProcessor(SecurityContext securityContext) {
this.securityContext = securityContext;
}
@Override
public MockHttpServletRequest postProcessRequest(MockHttpServletRequest request) {
save(this.securityContext, request);
return request;
}
}
/**
* Sets the specified {@link Authentication} on an empty {@link SecurityContext} and
* associates it to the {@link MockHttpServletRequest}
*
* @author Rob Winch
* @since 4.0
*
*/
private final static class AuthenticationRequestPostProcessor extends
SecurityContextRequestPostProcessorSupport implements RequestPostProcessor {
private final Authentication authentication;
private AuthenticationRequestPostProcessor(Authentication authentication) {
this.authentication = authentication;
}
@Override
public MockHttpServletRequest postProcessRequest(MockHttpServletRequest request) {
SecurityContext context = SecurityContextHolder.createEmptyContext();
context.setAuthentication(this.authentication);
save(this.authentication, request);
return request;
}
}
/**
* Creates a {@link UsernamePasswordAuthenticationToken} and sets the
* {@link UserDetails} as the principal and associates it to the
* {@link MockHttpServletRequest}.
*
* @author Rob Winch
* @since 4.0
*/
private final static class UserDetailsRequestPostProcessor
implements RequestPostProcessor {
private final RequestPostProcessor delegate;
public UserDetailsRequestPostProcessor(UserDetails user) {
Authentication token = new UsernamePasswordAuthenticationToken(user,
user.getPassword(), user.getAuthorities());
this.delegate = new AuthenticationRequestPostProcessor(token);
}
@Override
public MockHttpServletRequest postProcessRequest(MockHttpServletRequest request) {
return this.delegate.postProcessRequest(request);
}
}
/**
* Creates a {@link UsernamePasswordAuthenticationToken} and sets the principal to be
* a {@link User} and associates it to the {@link MockHttpServletRequest}.
*
* @author Rob Winch
* @since 4.0
*/
public final static class UserRequestPostProcessor extends
SecurityContextRequestPostProcessorSupport implements RequestPostProcessor {
private String username;
private String password = "password";
private static final String ROLE_PREFIX = "ROLE_";
private Collection<? extends GrantedAuthority> authorities = AuthorityUtils
.createAuthorityList("ROLE_USER");
private boolean enabled = true;
private boolean accountNonExpired = true;
private boolean credentialsNonExpired = true;
private boolean accountNonLocked = true;
/**
* Creates a new instance with the given username
* @param username the username to use
*/
private UserRequestPostProcessor(String username) {
Assert.notNull(username, "username cannot be null");
this.username = username;
}
/**
* Specify the roles of the user to authenticate as. This method is similar to
* {@link #authorities(GrantedAuthority...)}, but just not as flexible.
*
* @param roles The roles to populate. Note that if the role does not start with
* {@link #ROLE_PREFIX} it will automatically be prepended. This means by default
* {@code roles("ROLE_USER")} and {@code roles("USER")} are equivalent.
* @see #authorities(GrantedAuthority...)
* @see #ROLE_PREFIX
* @return the UserRequestPostProcessor for further customizations
*/
public UserRequestPostProcessor roles(String... roles) {
List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>(
roles.length);
for (String role : roles) {
if (role.startsWith(ROLE_PREFIX)) {
throw new IllegalArgumentException(
"Role should not start with " + ROLE_PREFIX
+ " since this method automatically prefixes with this value. Got "
+ role);
}
else {
authorities.add(new SimpleGrantedAuthority(ROLE_PREFIX + role));
}
}
this.authorities = authorities;
return this;
}
/**
* Populates the user's {@link GrantedAuthority}'s. The default is ROLE_USER.
*
* @param authorities
* @see #roles(String...)
* @return the UserRequestPostProcessor for further customizations
*/
public UserRequestPostProcessor authorities(GrantedAuthority... authorities) {
return authorities(Arrays.asList(authorities));
}
/**
* Populates the user's {@link GrantedAuthority}'s. The default is ROLE_USER.
*
* @param authorities
* @see #roles(String...)
* @return the UserRequestPostProcessor for further customizations
*/
public UserRequestPostProcessor authorities(
Collection<? extends GrantedAuthority> authorities) {
this.authorities = authorities;
return this;
}
/**
* Populates the user's password. The default is "password"
*
* @param password the user's password
* @return the UserRequestPostProcessor for further customizations
*/
public UserRequestPostProcessor password(String password) {
this.password = password;
return this;
}
@Override
public MockHttpServletRequest postProcessRequest(MockHttpServletRequest request) {
UserDetailsRequestPostProcessor delegate = new UserDetailsRequestPostProcessor(
createUser());
return delegate.postProcessRequest(request);
}
/**
* Creates a new {@link User}
* @return the {@link User} for the principal
*/
private User createUser() {
return new User(this.username, this.password, this.enabled,
this.accountNonExpired, this.credentialsNonExpired,
this.accountNonLocked, this.authorities);
}
}
private static class AnonymousRequestPostProcessor extends
SecurityContextRequestPostProcessorSupport implements RequestPostProcessor {
private AuthenticationRequestPostProcessor delegate = new AuthenticationRequestPostProcessor(
new AnonymousAuthenticationToken("key", "anonymous",
AuthorityUtils.createAuthorityList("ROLE_ANONYMOUS")));
/*
* (non-Javadoc)
*
* @see org.springframework.test.web.servlet.request.RequestPostProcessor#
* postProcessRequest(org.springframework.mock.web.MockHttpServletRequest)
*/
@Override
public MockHttpServletRequest postProcessRequest(MockHttpServletRequest request) {
return this.delegate.postProcessRequest(request);
}
}
private static class HttpBasicRequestPostProcessor implements RequestPostProcessor {
private String headerValue;
private HttpBasicRequestPostProcessor(String username, String password) {
byte[] toEncode;
try {
toEncode = (username + ":" + password).getBytes("UTF-8");
}
catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
this.headerValue = "Basic " + new String(Base64.getEncoder().encode(toEncode));
}
@Override
public MockHttpServletRequest postProcessRequest(MockHttpServletRequest request) {
request.addHeader("Authorization", this.headerValue);
return request;
}
}
private SecurityMockMvcRequestPostProcessors() {
}
}