Check If toBuilder Is Implemented
Since RC1 is right around the corner, let's change the API footprint as little as possible by using reflection to check if a class has declared toBuilder themselves. If they have, we can assume that that class's builder will produce that class. Issue gh-18052
This commit is contained in:
+25
@@ -0,0 +1,25 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2004-present 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.authentication;
|
||||||
|
|
||||||
|
public class NonBuildableAuthenticationToken extends TestingAuthenticationToken {
|
||||||
|
|
||||||
|
public NonBuildableAuthenticationToken(String user, String password, String... authorities) {
|
||||||
|
super(user, password, authorities);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+7
-2
@@ -17,6 +17,7 @@
|
|||||||
package org.springframework.security.oauth2.server.resource.web.authentication;
|
package org.springframework.security.oauth2.server.resource.web.authentication;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
@@ -56,7 +57,6 @@ import org.springframework.security.web.context.RequestAttributeSecurityContextR
|
|||||||
import org.springframework.security.web.context.SecurityContextRepository;
|
import org.springframework.security.web.context.SecurityContextRepository;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
import org.springframework.util.CollectionUtils;
|
import org.springframework.util.CollectionUtils;
|
||||||
import org.springframework.util.ReflectionUtils;
|
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
import org.springframework.web.filter.OncePerRequestFilter;
|
import org.springframework.web.filter.OncePerRequestFilter;
|
||||||
|
|
||||||
@@ -214,7 +214,12 @@ public class BearerTokenAuthenticationFilter extends OncePerRequestFilter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static boolean declaresToBuilder(Authentication authentication) {
|
private static boolean declaresToBuilder(Authentication authentication) {
|
||||||
return ReflectionUtils.findMethod(authentication.getClass(), "toBuilder") != null;
|
for (Method method : authentication.getClass().getDeclaredMethods()) {
|
||||||
|
if (method.getName().equals("toBuilder") && method.getParameterTypes().length == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+19
@@ -38,6 +38,7 @@ import org.springframework.security.authentication.AuthenticationDetailsSource;
|
|||||||
import org.springframework.security.authentication.AuthenticationManager;
|
import org.springframework.security.authentication.AuthenticationManager;
|
||||||
import org.springframework.security.authentication.AuthenticationManagerResolver;
|
import org.springframework.security.authentication.AuthenticationManagerResolver;
|
||||||
import org.springframework.security.authentication.AuthenticationServiceException;
|
import org.springframework.security.authentication.AuthenticationServiceException;
|
||||||
|
import org.springframework.security.authentication.NonBuildableAuthenticationToken;
|
||||||
import org.springframework.security.authentication.SecurityAssertions;
|
import org.springframework.security.authentication.SecurityAssertions;
|
||||||
import org.springframework.security.authentication.TestingAuthenticationToken;
|
import org.springframework.security.authentication.TestingAuthenticationToken;
|
||||||
import org.springframework.security.core.Authentication;
|
import org.springframework.security.core.Authentication;
|
||||||
@@ -316,6 +317,24 @@ public class BearerTokenAuthenticationFilterTests {
|
|||||||
// @formatter:on
|
// @formatter:on
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void doFilterWhenNonBuildableAuthenticationSubclassThenSkipsToBuilder() throws Exception {
|
||||||
|
TestingAuthenticationToken existingAuthn = new TestingAuthenticationToken("username", "password", "FACTORONE");
|
||||||
|
SecurityContextHolder.setContext(new SecurityContextImpl(existingAuthn));
|
||||||
|
given(this.authenticationManager.authenticate(any()))
|
||||||
|
.willReturn(new NonBuildableAuthenticationToken("username", "password", "FACTORTWO"));
|
||||||
|
given(this.bearerTokenResolver.resolve(any())).willReturn("token");
|
||||||
|
BearerTokenAuthenticationFilter filter = addMocks(
|
||||||
|
new BearerTokenAuthenticationFilter(this.authenticationManager));
|
||||||
|
filter.doFilter(this.request, this.response, this.filterChain);
|
||||||
|
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
|
||||||
|
// @formatter:off
|
||||||
|
SecurityAssertions.assertThat(authentication).authorities()
|
||||||
|
.extracting(GrantedAuthority::getAuthority)
|
||||||
|
.containsExactly("FACTORTWO");
|
||||||
|
// @formatter:on
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void setAuthenticationEntryPointWhenNullThenThrowsException() {
|
public void setAuthenticationEntryPointWhenNullThenThrowsException() {
|
||||||
BearerTokenAuthenticationFilter filter = new BearerTokenAuthenticationFilter(this.authenticationManager);
|
BearerTokenAuthenticationFilter filter = new BearerTokenAuthenticationFilter(this.authenticationManager);
|
||||||
|
|||||||
+11
-1
@@ -17,6 +17,7 @@
|
|||||||
package org.springframework.security.web.authentication;
|
package org.springframework.security.web.authentication;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@@ -252,7 +253,7 @@ public abstract class AbstractAuthenticationProcessingFilter extends GenericFilt
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Authentication current = this.securityContextHolderStrategy.getContext().getAuthentication();
|
Authentication current = this.securityContextHolderStrategy.getContext().getAuthentication();
|
||||||
if (current != null && current.isAuthenticated()) {
|
if (current != null && current.isAuthenticated() && declaresToBuilder(authenticationResult)) {
|
||||||
authenticationResult = authenticationResult.toBuilder()
|
authenticationResult = authenticationResult.toBuilder()
|
||||||
// @formatter:off
|
// @formatter:off
|
||||||
.authorities((a) -> {
|
.authorities((a) -> {
|
||||||
@@ -285,6 +286,15 @@ public abstract class AbstractAuthenticationProcessingFilter extends GenericFilt
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static boolean declaresToBuilder(Authentication authentication) {
|
||||||
|
for (Method method : authentication.getClass().getDeclaredMethods()) {
|
||||||
|
if (method.getName().equals("toBuilder") && method.getParameterTypes().length == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Indicates whether this filter should attempt to process a login request for the
|
* Indicates whether this filter should attempt to process a login request for the
|
||||||
* current invocation.
|
* current invocation.
|
||||||
|
|||||||
+11
-1
@@ -17,6 +17,7 @@
|
|||||||
package org.springframework.security.web.authentication;
|
package org.springframework.security.web.authentication;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@@ -188,7 +189,7 @@ public class AuthenticationFilter extends OncePerRequestFilter {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Authentication current = this.securityContextHolderStrategy.getContext().getAuthentication();
|
Authentication current = this.securityContextHolderStrategy.getContext().getAuthentication();
|
||||||
if (current != null && current.isAuthenticated()) {
|
if (current != null && current.isAuthenticated() && declaresToBuilder(authenticationResult)) {
|
||||||
authenticationResult = authenticationResult.toBuilder()
|
authenticationResult = authenticationResult.toBuilder()
|
||||||
// @formatter:off
|
// @formatter:off
|
||||||
.authorities((a) -> {
|
.authorities((a) -> {
|
||||||
@@ -215,6 +216,15 @@ public class AuthenticationFilter extends OncePerRequestFilter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static boolean declaresToBuilder(Authentication authentication) {
|
||||||
|
for (Method method : authentication.getClass().getDeclaredMethods()) {
|
||||||
|
if (method.getName().equals("toBuilder") && method.getParameterTypes().length == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected String getAlreadyFilteredAttributeName() {
|
protected String getAlreadyFilteredAttributeName() {
|
||||||
String name = getFilterName();
|
String name = getFilterName();
|
||||||
|
|||||||
+11
-1
@@ -17,6 +17,7 @@
|
|||||||
package org.springframework.security.web.authentication.preauth;
|
package org.springframework.security.web.authentication.preauth;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@@ -208,7 +209,7 @@ public abstract class AbstractPreAuthenticatedProcessingFilter extends GenericFi
|
|||||||
authenticationRequest.setDetails(this.authenticationDetailsSource.buildDetails(request));
|
authenticationRequest.setDetails(this.authenticationDetailsSource.buildDetails(request));
|
||||||
Authentication authenticationResult = this.authenticationManager.authenticate(authenticationRequest);
|
Authentication authenticationResult = this.authenticationManager.authenticate(authenticationRequest);
|
||||||
Authentication current = this.securityContextHolderStrategy.getContext().getAuthentication();
|
Authentication current = this.securityContextHolderStrategy.getContext().getAuthentication();
|
||||||
if (current != null && current.isAuthenticated()) {
|
if (current != null && current.isAuthenticated() && declaresToBuilder(authenticationResult)) {
|
||||||
authenticationResult = authenticationResult.toBuilder()
|
authenticationResult = authenticationResult.toBuilder()
|
||||||
// @formatter:off
|
// @formatter:off
|
||||||
.authorities((a) -> {
|
.authorities((a) -> {
|
||||||
@@ -234,6 +235,15 @@ public abstract class AbstractPreAuthenticatedProcessingFilter extends GenericFi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static boolean declaresToBuilder(Authentication authentication) {
|
||||||
|
for (Method method : authentication.getClass().getDeclaredMethods()) {
|
||||||
|
if (method.getName().equals("toBuilder") && method.getParameterTypes().length == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Puts the <code>Authentication</code> instance returned by the authentication
|
* Puts the <code>Authentication</code> instance returned by the authentication
|
||||||
* manager into the secure context.
|
* manager into the secure context.
|
||||||
|
|||||||
+11
-1
@@ -17,6 +17,7 @@
|
|||||||
package org.springframework.security.web.authentication.www;
|
package org.springframework.security.web.authentication.www;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
@@ -190,7 +191,7 @@ public class BasicAuthenticationFilter extends OncePerRequestFilter {
|
|||||||
if (authenticationIsRequired(username)) {
|
if (authenticationIsRequired(username)) {
|
||||||
Authentication authResult = this.authenticationManager.authenticate(authRequest);
|
Authentication authResult = this.authenticationManager.authenticate(authRequest);
|
||||||
Authentication current = this.securityContextHolderStrategy.getContext().getAuthentication();
|
Authentication current = this.securityContextHolderStrategy.getContext().getAuthentication();
|
||||||
if (current != null && current.isAuthenticated()) {
|
if (current != null && current.isAuthenticated() && declaresToBuilder(authResult)) {
|
||||||
authResult = authResult.toBuilder()
|
authResult = authResult.toBuilder()
|
||||||
// @formatter:off
|
// @formatter:off
|
||||||
.authorities((a) -> {
|
.authorities((a) -> {
|
||||||
@@ -234,6 +235,15 @@ public class BasicAuthenticationFilter extends OncePerRequestFilter {
|
|||||||
chain.doFilter(request, response);
|
chain.doFilter(request, response);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static boolean declaresToBuilder(Authentication authentication) {
|
||||||
|
for (Method method : authentication.getClass().getDeclaredMethods()) {
|
||||||
|
if (method.getName().equals("toBuilder") && method.getParameterTypes().length == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
protected boolean authenticationIsRequired(String username) {
|
protected boolean authenticationIsRequired(String username) {
|
||||||
// Only reauthenticate if username doesn't match SecurityContextHolder and user
|
// Only reauthenticate if username doesn't match SecurityContextHolder and user
|
||||||
// isn't authenticated (see SEC-53)
|
// isn't authenticated (see SEC-53)
|
||||||
|
|||||||
+13
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package org.springframework.security.web.server.authentication;
|
package org.springframework.security.web.server.authentication;
|
||||||
|
|
||||||
|
import java.lang.reflect.Method;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
@@ -141,6 +142,9 @@ public class AuthenticationWebFilter implements WebFilter {
|
|||||||
if (!current.isAuthenticated()) {
|
if (!current.isAuthenticated()) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
if (!declaresToBuilder(result)) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
return result.toBuilder()
|
return result.toBuilder()
|
||||||
// @formatter:off
|
// @formatter:off
|
||||||
.authorities((a) -> {
|
.authorities((a) -> {
|
||||||
@@ -158,6 +162,15 @@ public class AuthenticationWebFilter implements WebFilter {
|
|||||||
}).switchIfEmpty(Mono.just(result));
|
}).switchIfEmpty(Mono.just(result));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static boolean declaresToBuilder(Authentication authentication) {
|
||||||
|
for (Method method : authentication.getClass().getDeclaredMethods()) {
|
||||||
|
if (method.getName().equals("toBuilder") && method.getParameterTypes().length == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
protected Mono<Void> onAuthenticationSuccess(Authentication authentication, WebFilterExchange webFilterExchange) {
|
protected Mono<Void> onAuthenticationSuccess(Authentication authentication, WebFilterExchange webFilterExchange) {
|
||||||
ServerWebExchange exchange = webFilterExchange.getExchange();
|
ServerWebExchange exchange = webFilterExchange.getExchange();
|
||||||
SecurityContextImpl securityContext = new SecurityContextImpl();
|
SecurityContextImpl securityContext = new SecurityContextImpl();
|
||||||
|
|||||||
+18
@@ -37,6 +37,8 @@ import org.springframework.mock.web.MockHttpServletResponse;
|
|||||||
import org.springframework.security.authentication.AuthenticationManager;
|
import org.springframework.security.authentication.AuthenticationManager;
|
||||||
import org.springframework.security.authentication.BadCredentialsException;
|
import org.springframework.security.authentication.BadCredentialsException;
|
||||||
import org.springframework.security.authentication.InternalAuthenticationServiceException;
|
import org.springframework.security.authentication.InternalAuthenticationServiceException;
|
||||||
|
import org.springframework.security.authentication.NonBuildableAuthenticationToken;
|
||||||
|
import org.springframework.security.authentication.SecurityAssertions;
|
||||||
import org.springframework.security.authentication.TestAuthentication;
|
import org.springframework.security.authentication.TestAuthentication;
|
||||||
import org.springframework.security.authentication.TestingAuthenticationToken;
|
import org.springframework.security.authentication.TestingAuthenticationToken;
|
||||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||||
@@ -480,6 +482,22 @@ public class AbstractAuthenticationProcessingFilterTests {
|
|||||||
.containsExactly(DefaultEqualsGrantedAuthority.AUTHORITY);
|
.containsExactly(DefaultEqualsGrantedAuthority.AUTHORITY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void doFilterWhenNotOverridingToBuilderThenDoesNotMergeAuthorities() throws Exception {
|
||||||
|
TestingAuthenticationToken existingAuthn = new TestingAuthenticationToken("username", "password", "FACTORONE");
|
||||||
|
SecurityContextHolder.setContext(new SecurityContextImpl(existingAuthn));
|
||||||
|
MockHttpServletRequest request = createMockAuthenticationRequest();
|
||||||
|
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||||
|
MockAuthenticationFilter filter = new MockAuthenticationFilter(
|
||||||
|
new NonBuildableAuthenticationToken("username", "password", "FACTORTWO"));
|
||||||
|
filter.doFilter(request, response, new MockFilterChain(false));
|
||||||
|
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
|
||||||
|
SecurityAssertions.assertThat(authentication)
|
||||||
|
.authorities()
|
||||||
|
.extracting(GrantedAuthority::getAuthority)
|
||||||
|
.containsExactly("FACTORTWO");
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* https://github.com/spring-projects/spring-security/pull/3905
|
* https://github.com/spring-projects/spring-security/pull/3905
|
||||||
*/
|
*/
|
||||||
|
|||||||
+22
@@ -37,6 +37,8 @@ import org.springframework.mock.web.MockHttpSession;
|
|||||||
import org.springframework.security.authentication.AuthenticationManager;
|
import org.springframework.security.authentication.AuthenticationManager;
|
||||||
import org.springframework.security.authentication.AuthenticationManagerResolver;
|
import org.springframework.security.authentication.AuthenticationManagerResolver;
|
||||||
import org.springframework.security.authentication.BadCredentialsException;
|
import org.springframework.security.authentication.BadCredentialsException;
|
||||||
|
import org.springframework.security.authentication.NonBuildableAuthenticationToken;
|
||||||
|
import org.springframework.security.authentication.SecurityAssertions;
|
||||||
import org.springframework.security.authentication.TestingAuthenticationToken;
|
import org.springframework.security.authentication.TestingAuthenticationToken;
|
||||||
import org.springframework.security.core.Authentication;
|
import org.springframework.security.core.Authentication;
|
||||||
import org.springframework.security.core.GrantedAuthority;
|
import org.springframework.security.core.GrantedAuthority;
|
||||||
@@ -348,6 +350,26 @@ public class AuthenticationFilterTests {
|
|||||||
.containsExactlyInAnyOrder(DefaultEqualsGrantedAuthority.AUTHORITY);
|
.containsExactlyInAnyOrder(DefaultEqualsGrantedAuthority.AUTHORITY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void doFilterWhenNotOverridingToBuilderThenDoesNotMergeAuthorities() throws Exception {
|
||||||
|
TestingAuthenticationToken existingAuthn = new TestingAuthenticationToken("username", "password", "FACTORONE");
|
||||||
|
SecurityContextHolder.setContext(new SecurityContextImpl(existingAuthn));
|
||||||
|
given(this.authenticationConverter.convert(any())).willReturn(existingAuthn);
|
||||||
|
given(this.authenticationManager.authenticate(any()))
|
||||||
|
.willReturn(new NonBuildableAuthenticationToken("user", "password", "FACTORTWO"));
|
||||||
|
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/");
|
||||||
|
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||||
|
FilterChain chain = new MockFilterChain();
|
||||||
|
AuthenticationFilter filter = new AuthenticationFilter(this.authenticationManager,
|
||||||
|
this.authenticationConverter);
|
||||||
|
filter.doFilter(request, response, chain);
|
||||||
|
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
|
||||||
|
SecurityAssertions.assertThat(authentication)
|
||||||
|
.authorities()
|
||||||
|
.extracting(GrantedAuthority::getAuthority)
|
||||||
|
.containsExactly("FACTORTWO");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void filterWhenCustomSecurityContextRepositoryAndSuccessfulAuthenticationRepositoryUsed() throws Exception {
|
public void filterWhenCustomSecurityContextRepositoryAndSuccessfulAuthenticationRepositoryUsed() throws Exception {
|
||||||
SecurityContextRepository securityContextRepository = mock(SecurityContextRepository.class);
|
SecurityContextRepository securityContextRepository = mock(SecurityContextRepository.class);
|
||||||
|
|||||||
+18
@@ -32,6 +32,8 @@ import org.springframework.mock.web.MockHttpServletRequest;
|
|||||||
import org.springframework.mock.web.MockHttpServletResponse;
|
import org.springframework.mock.web.MockHttpServletResponse;
|
||||||
import org.springframework.security.authentication.AuthenticationManager;
|
import org.springframework.security.authentication.AuthenticationManager;
|
||||||
import org.springframework.security.authentication.BadCredentialsException;
|
import org.springframework.security.authentication.BadCredentialsException;
|
||||||
|
import org.springframework.security.authentication.NonBuildableAuthenticationToken;
|
||||||
|
import org.springframework.security.authentication.SecurityAssertions;
|
||||||
import org.springframework.security.authentication.TestingAuthenticationToken;
|
import org.springframework.security.authentication.TestingAuthenticationToken;
|
||||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||||
import org.springframework.security.core.Authentication;
|
import org.springframework.security.core.Authentication;
|
||||||
@@ -436,6 +438,22 @@ public class AbstractPreAuthenticatedProcessingFilterTests {
|
|||||||
// @formatter:on
|
// @formatter:on
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void doFilterWhenNotOverridingToBuilderThenDoesNotMergeAuthorities() throws Exception {
|
||||||
|
TestingAuthenticationToken existingAuthn = new TestingAuthenticationToken("username", "password", "FACTORONE");
|
||||||
|
SecurityContextHolder.setContext(new SecurityContextImpl(existingAuthn));
|
||||||
|
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||||
|
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||||
|
this.filter = createFilterAuthenticatesWith(
|
||||||
|
new NonBuildableAuthenticationToken("username", "password", "FACTORTWO"));
|
||||||
|
this.filter.doFilter(request, response, new MockFilterChain());
|
||||||
|
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
|
||||||
|
SecurityAssertions.assertThat(authentication)
|
||||||
|
.authorities()
|
||||||
|
.extracting(GrantedAuthority::getAuthority)
|
||||||
|
.containsExactly("FACTORTWO");
|
||||||
|
}
|
||||||
|
|
||||||
private AbstractPreAuthenticatedProcessingFilter createFilterAuthenticatesWith(Authentication authentication) {
|
private AbstractPreAuthenticatedProcessingFilter createFilterAuthenticatesWith(Authentication authentication) {
|
||||||
ConcretePreAuthenticatedProcessingFilter filter = new ConcretePreAuthenticatedProcessingFilter();
|
ConcretePreAuthenticatedProcessingFilter filter = new ConcretePreAuthenticatedProcessingFilter();
|
||||||
filter.setRequiresAuthenticationRequestMatcher(AnyRequestMatcher.INSTANCE);
|
filter.setRequiresAuthenticationRequestMatcher(AnyRequestMatcher.INSTANCE);
|
||||||
|
|||||||
+21
@@ -36,6 +36,8 @@ import org.springframework.mock.web.MockHttpServletResponse;
|
|||||||
import org.springframework.mock.web.MockHttpSession;
|
import org.springframework.mock.web.MockHttpSession;
|
||||||
import org.springframework.security.authentication.AuthenticationManager;
|
import org.springframework.security.authentication.AuthenticationManager;
|
||||||
import org.springframework.security.authentication.BadCredentialsException;
|
import org.springframework.security.authentication.BadCredentialsException;
|
||||||
|
import org.springframework.security.authentication.NonBuildableAuthenticationToken;
|
||||||
|
import org.springframework.security.authentication.SecurityAssertions;
|
||||||
import org.springframework.security.authentication.TestingAuthenticationToken;
|
import org.springframework.security.authentication.TestingAuthenticationToken;
|
||||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||||
import org.springframework.security.core.Authentication;
|
import org.springframework.security.core.Authentication;
|
||||||
@@ -539,6 +541,25 @@ public class BasicAuthenticationFilterTests {
|
|||||||
.containsExactly(DefaultEqualsGrantedAuthority.AUTHORITY);
|
.containsExactly(DefaultEqualsGrantedAuthority.AUTHORITY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void doFilterWhenNotOverridingToBuilderThenDoesNotMergeAuthorities() throws Exception {
|
||||||
|
TestingAuthenticationToken existingAuthn = new TestingAuthenticationToken("username", "password", "FACTORONE");
|
||||||
|
SecurityContextHolder.setContext(new SecurityContextImpl(existingAuthn));
|
||||||
|
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||||
|
request.addHeader(HttpHeaders.AUTHORIZATION, "Basic " + CodecTestUtils.encodeBase64("a:b"));
|
||||||
|
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||||
|
AuthenticationManager manager = mock(AuthenticationManager.class);
|
||||||
|
given(manager.authenticate(any()))
|
||||||
|
.willReturn(new NonBuildableAuthenticationToken("username", "password", "FACTORTWO"));
|
||||||
|
BasicAuthenticationFilter filter = new BasicAuthenticationFilter(manager);
|
||||||
|
filter.doFilter(request, response, new MockFilterChain());
|
||||||
|
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
|
||||||
|
SecurityAssertions.assertThat(authentication)
|
||||||
|
.authorities()
|
||||||
|
.extracting(GrantedAuthority::getAuthority)
|
||||||
|
.containsExactly("FACTORTWO");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void doFilterWhenCustomAuthenticationConverterRequestThenAuthenticate() throws Exception {
|
public void doFilterWhenCustomAuthenticationConverterRequestThenAuthenticate() throws Exception {
|
||||||
this.filter.setAuthenticationConverter(new TestAuthenticationConverter());
|
this.filter.setAuthenticationConverter(new TestAuthenticationConverter());
|
||||||
|
|||||||
+27
@@ -25,8 +25,10 @@ import org.mockito.junit.jupiter.MockitoExtension;
|
|||||||
import reactor.core.publisher.Mono;
|
import reactor.core.publisher.Mono;
|
||||||
|
|
||||||
import org.springframework.security.authentication.BadCredentialsException;
|
import org.springframework.security.authentication.BadCredentialsException;
|
||||||
|
import org.springframework.security.authentication.NonBuildableAuthenticationToken;
|
||||||
import org.springframework.security.authentication.ReactiveAuthenticationManager;
|
import org.springframework.security.authentication.ReactiveAuthenticationManager;
|
||||||
import org.springframework.security.authentication.ReactiveAuthenticationManagerResolver;
|
import org.springframework.security.authentication.ReactiveAuthenticationManagerResolver;
|
||||||
|
import org.springframework.security.authentication.SecurityAssertions;
|
||||||
import org.springframework.security.authentication.TestingAuthenticationToken;
|
import org.springframework.security.authentication.TestingAuthenticationToken;
|
||||||
import org.springframework.security.core.Authentication;
|
import org.springframework.security.core.Authentication;
|
||||||
import org.springframework.security.core.GrantedAuthority;
|
import org.springframework.security.core.GrantedAuthority;
|
||||||
@@ -230,6 +232,31 @@ public class AuthenticationWebFilterTests {
|
|||||||
.containsExactly(DefaultEqualsGrantedAuthority.AUTHORITY);
|
.containsExactly(DefaultEqualsGrantedAuthority.AUTHORITY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void doFilterWhenNotOverridingToBuilderThenDoesNotMergeAuthorities() throws Exception {
|
||||||
|
TestingAuthenticationToken existingAuthn = new TestingAuthenticationToken("username", "password", "FACTORONE");
|
||||||
|
given(this.authenticationManager.authenticate(any()))
|
||||||
|
.willReturn(Mono.just(new NonBuildableAuthenticationToken("user", "password", "FACTORTWO")));
|
||||||
|
given(this.securityContextRepository.save(any(), any())).willReturn(Mono.empty());
|
||||||
|
this.filter = new AuthenticationWebFilter(this.authenticationManager);
|
||||||
|
this.filter.setSecurityContextRepository(this.securityContextRepository);
|
||||||
|
WebTestClient client = WebTestClientBuilder.bindToWebFilters(new RunAsWebFilter(existingAuthn), this.filter)
|
||||||
|
.build();
|
||||||
|
client.get()
|
||||||
|
.uri("/")
|
||||||
|
.headers((headers) -> headers.setBasicAuth("test", "this"))
|
||||||
|
.exchange()
|
||||||
|
.expectStatus()
|
||||||
|
.isOk();
|
||||||
|
ArgumentCaptor<SecurityContext> context = ArgumentCaptor.forClass(SecurityContext.class);
|
||||||
|
verify(this.securityContextRepository).save(any(), context.capture());
|
||||||
|
Authentication authentication = context.getValue().getAuthentication();
|
||||||
|
SecurityAssertions.assertThat(authentication)
|
||||||
|
.authorities()
|
||||||
|
.extracting(GrantedAuthority::getAuthority)
|
||||||
|
.containsExactly("FACTORTWO");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void filterWhenAuthenticationManagerResolverDefaultsAndAuthenticationFailThenUnauthorized() {
|
public void filterWhenAuthenticationManagerResolverDefaultsAndAuthenticationFailThenUnauthorized() {
|
||||||
given(this.authenticationManager.authenticate(any()))
|
given(this.authenticationManager.authenticate(any()))
|
||||||
|
|||||||
Reference in New Issue
Block a user