1
0
mirror of synced 2026-05-22 13:23:17 +00:00

Fix ProviderManager.copyDetails Changes Authentication Type

Closes gh-18027
This commit is contained in:
Rob Winch
2025-10-10 10:51:04 -05:00
parent 1213dbe76f
commit 864a9b2fb3
2 changed files with 63 additions and 8 deletions
@@ -182,7 +182,7 @@ public class ProviderManager implements AuthenticationManager, MessageSourceAwar
try {
result = provider.authenticate(authentication);
if (result != null) {
result = copyDetails(authentication, result);
copyDetails(authentication, result);
break;
}
}
@@ -277,14 +277,10 @@ public class ProviderManager implements AuthenticationManager, MessageSourceAwar
* @param source source authentication
* @param dest the destination authentication object
*/
private Authentication copyDetails(Authentication source, Authentication dest) {
if (source.getDetails() == null) {
return dest;
private void copyDetails(Authentication source, Authentication dest) {
if ((dest instanceof AbstractAuthenticationToken token) && (dest.getDetails() == null)) {
token.setDetails(source.getDetails());
}
if (dest.getDetails() != null) {
return dest;
}
return dest.toBuilder().details(source.getDetails()).build();
}
public List<AuthenticationProvider> getProviders() {
@@ -21,6 +21,7 @@ import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import org.jspecify.annotations.Nullable;
import org.junit.jupiter.api.Test;
import org.springframework.context.MessageSource;
@@ -162,6 +163,20 @@ public class ProviderManagerTests {
assertThat(result.getDetails()).isSameAs(details);
}
// gh-18027
@Test
void authenticationIsSameWhenDetailsSetAndAuthenticationToBuilderIsDefault() {
Authentication customAuthentication = new DefaultToBuilderAuthentication();
AuthenticationProvider provider = mock(AuthenticationProvider.class);
given(provider.supports(any())).willReturn(true);
given(provider.authenticate(any())).willReturn(customAuthentication);
TestingAuthenticationToken request = createAuthenticationToken();
request.setDetails(new Object());
ProviderManager authMgr = new ProviderManager(provider);
Authentication result = authMgr.authenticate(request);
assertThat(result).isSameAs(customAuthentication);
}
@Test
void authenticationExceptionIsIgnoredIfLaterProviderAuthenticates() {
Authentication result = new TestingAuthenticationToken("user", "pass", "FACTOR");
@@ -356,4 +371,48 @@ public class ProviderManagerTests {
}
/**
* Represents a custom {@link Authentication} that does not override
* {@link #toBuilder()}. We should remain passive to previous versions of Spring
* Security and not change the {@link Authentication} type.
*/
private static final class DefaultToBuilderAuthentication implements Authentication {
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return List.of();
}
@Override
public @Nullable Object getCredentials() {
return null;
}
@Override
public @Nullable Object getDetails() {
return null;
}
@Override
public @Nullable Object getPrincipal() {
return null;
}
@Override
public boolean isAuthenticated() {
return false;
}
@Override
public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException {
}
@Override
public String getName() {
return "";
}
}
}