Add Factor Tests for Authentication Providers

Issue gh-17933
This commit is contained in:
Josh Cummings 2025-09-18 15:38:39 -06:00
parent 39e2bb67fc
commit 758b35df9c
No known key found for this signature in database
GPG Key ID: 869B37A20E876129
9 changed files with 158 additions and 0 deletions

View File

@ -31,6 +31,7 @@ import org.springframework.security.authentication.CredentialsExpiredException;
import org.springframework.security.authentication.DisabledException;
import org.springframework.security.authentication.InternalAuthenticationServiceException;
import org.springframework.security.authentication.LockedException;
import org.springframework.security.authentication.SecurityAssertions;
import org.springframework.security.authentication.TestingAuthenticationToken;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.authentication.password.CompromisedPasswordChecker;
@ -504,6 +505,15 @@ public class DaoAuthenticationProviderTests {
assertThat(authentication).isNotNull();
}
@Test
void authenticateWhenSuccessThenIssuesFactor() {
UserDetails user = PasswordEncodedUser.user();
DaoAuthenticationProvider provider = new DaoAuthenticationProvider(withUsers(user));
Authentication request = new UsernamePasswordAuthenticationToken("user", "password");
Authentication result = provider.authenticate(request);
SecurityAssertions.assertThat(result).hasAuthority("FACTOR_PASSWORD");
}
private UserDetailsService withUsers(UserDetails... users) {
return new InMemoryUserDetailsManager(users);
}

View File

@ -26,6 +26,7 @@ import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.SecurityAssertions;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetailsService;
@ -98,6 +99,18 @@ public class OneTimeTokenAuthenticationProviderTests {
assertThatExceptionOfType(BadCredentialsException.class).isThrownBy(() -> this.provider.authenticate(token));
}
@Test
void authenticateWhenSuccessThenIssuesFactor() {
given(this.oneTimeTokenService.consume(any()))
.willReturn(new DefaultOneTimeToken(TOKEN, USERNAME, Instant.now().plusSeconds(120)));
given(this.userDetailsService.loadUserByUsername(anyString()))
.willReturn(new User(USERNAME, PASSWORD, List.of()));
OneTimeTokenAuthenticationToken token = new OneTimeTokenAuthenticationToken(TOKEN);
Authentication authentication = this.provider.authenticate(token);
SecurityAssertions.assertThat(authentication).hasAuthority("FACTOR_OTT");
}
@Test
void constructorWhenOneTimeTokenServiceIsNullThenThrowIllegalArgumentException() {
// @formatter:off

View File

@ -26,6 +26,7 @@ import org.springframework.ldap.core.DirContextOperations;
import org.springframework.ldap.support.LdapNameBuilder;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.InternalAuthenticationServiceException;
import org.springframework.security.authentication.SecurityAssertions;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
@ -156,6 +157,16 @@ public class LdapAuthenticationProviderTests {
.isSameAs(expectedCause);
}
@Test
void authenticateWhenSuccessThenIssuesFactor() {
MockAuthenticator authenticator = new MockAuthenticator();
MockAuthoritiesPopulator populator = new MockAuthoritiesPopulator();
LdapAuthenticationProvider ldapProvider = new LdapAuthenticationProvider(authenticator, populator);
UsernamePasswordAuthenticationToken request = new UsernamePasswordAuthenticationToken("ben", "benspassword");
Authentication result = ldapProvider.authenticate(request);
SecurityAssertions.assertThat(result).hasAuthority("FACTOR_PASSWORD");
}
class MockAuthenticator implements LdapAuthenticator {
@Override

View File

@ -29,6 +29,8 @@ import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.stubbing.Answer;
import org.springframework.security.authentication.SecurityAssertions;
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.mapping.GrantedAuthoritiesMapper;
@ -48,6 +50,7 @@ import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationResp
import org.springframework.security.oauth2.core.endpoint.TestOAuth2AuthorizationRequests;
import org.springframework.security.oauth2.core.endpoint.TestOAuth2AuthorizationResponses;
import org.springframework.security.oauth2.core.user.OAuth2User;
import org.springframework.security.oauth2.core.user.TestOAuth2Users;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
@ -206,6 +209,17 @@ public class OAuth2LoginAuthenticationProviderTests {
.containsAllEntriesOf(accessTokenResponse.getAdditionalParameters());
}
@Test
public void authenticateWhenLoginSuccessThenIssuesFactor() {
OAuth2AccessTokenResponse accessTokenResponse = accessTokenSuccessResponse();
given(this.accessTokenResponseClient.getTokenResponse(any())).willReturn(accessTokenResponse);
given(this.userService.loadUser(any())).willReturn(TestOAuth2Users.create());
Authentication request = new OAuth2LoginAuthenticationToken(this.clientRegistration,
this.authorizationExchange);
Authentication result = this.authenticationProvider.authenticate(request);
SecurityAssertions.assertThat(result).hasAuthority("FACTOR_AUTHORIZATION_CODE");
}
private OAuth2AccessTokenResponse accessTokenSuccessResponse() {
Instant expiresAt = Instant.now().plusSeconds(5);
Set<String> scopes = new LinkedHashSet<>(Arrays.asList("scope1", "scope2"));

View File

@ -24,6 +24,7 @@ import org.junit.jupiter.api.Test;
import org.springframework.core.convert.converter.Converter;
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.authentication.SecurityAssertions;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.oauth2.jwt.Jwt;
@ -110,4 +111,11 @@ public class JwtAuthenticationConverterTests {
assertThat(authentication.getName()).isEqualTo("100");
}
@Test
public void convertWhenDefaultsThenIssuesFactor() {
Jwt jwt = TestJwts.jwt().build();
Authentication result = this.jwtAuthenticationConverter.convert(jwt);
SecurityAssertions.assertThat(result).hasAuthority("FACTOR_BEARER");
}
}

View File

@ -146,6 +146,17 @@ public class OpaqueTokenAuthenticationProviderTests {
verifyNoMoreInteractions(introspector, authenticationConverter);
}
@Test
void authenticateWhenSuccessThenIssuesFactor() {
OAuth2AuthenticatedPrincipal principal = TestOAuth2AuthenticatedPrincipals.active();
OpaqueTokenIntrospector introspector = mock(OpaqueTokenIntrospector.class);
given(introspector.introspect(any())).willReturn(principal);
OpaqueTokenAuthenticationProvider provider = new OpaqueTokenAuthenticationProvider(introspector);
Authentication request = new BearerTokenAuthenticationToken("token");
Authentication result = provider.authenticate(request);
SecurityAssertions.assertThat(result).hasAuthority("FACTOR_BEARER");
}
static Predicate<GrantedAuthority> isScope() {
return (a) -> a.getAuthority().startsWith("SCOPE_");
}

View File

@ -985,6 +985,14 @@ public class OpenSaml5AuthenticationProviderTests {
assertThatExceptionOfType(Saml2AuthenticationException.class).isThrownBy(() -> provider.authenticate(token));
}
@Test
public void authenticateWhenSuccessThenIssuesFactor() {
Response response = TestOpenSamlObjects.signedResponseWithOneAssertion();
Authentication request = token(response, verifying(registration()));
Authentication result = this.provider.authenticate(request);
SecurityAssertions.assertThat(result).hasAuthority("FACTOR_SAML_RESPONSE");
}
private <T extends XMLObject> T build(QName qName) {
return (T) XMLObjectProviderRegistrySupport.getBuilderFactory().getBuilder(qName).buildObject(qName);
}

View File

@ -16,12 +16,18 @@
package org.springframework.security.web.authentication.preauth;
import java.util.Collection;
import java.util.function.Supplier;
import org.junit.jupiter.api.Test;
import org.springframework.security.authentication.SecurityAssertions;
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.userdetails.AuthenticationUserDetailsService;
import org.springframework.security.core.userdetails.PasswordEncodedUser;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
@ -29,6 +35,9 @@ import org.springframework.security.core.userdetails.UsernameNotFoundException;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
/**
* @author TSARDD
@ -89,6 +98,19 @@ public class PreAuthenticatedAuthenticationProviderTests {
assertThatExceptionOfType(UsernameNotFoundException.class).isThrownBy(() -> provider.authenticate(request));
}
@Test
void authenticateWhenSuccessThenIssuesFactor() {
UserDetails ud = PasswordEncodedUser.user();
PreAuthenticatedAuthenticationProvider provider = getProvider(ud);
Supplier<Collection<GrantedAuthority>> authorities = mock(Supplier.class);
given(authorities.get()).willReturn(AuthorityUtils.createAuthorityList("FACTOR"));
provider.setGrantedAuthoritySupplier(authorities);
Authentication request = new PreAuthenticatedAuthenticationToken(ud.getUsername(), ud.getPassword());
Authentication result = provider.authenticate(request);
SecurityAssertions.assertThat(result).hasAuthority("FACTOR");
verify(authorities).get();
}
@Test
public final void supportsArbitraryObject() throws Exception {
PreAuthenticatedAuthenticationProvider provider = getProvider(null);

View File

@ -0,0 +1,61 @@
/*
* 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.web.webauthn.authentication;
import org.junit.jupiter.api.Test;
import org.springframework.security.authentication.SecurityAssertions;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.PasswordEncodedUser;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.webauthn.api.AuthenticatorAssertionResponse;
import org.springframework.security.web.webauthn.api.PublicKeyCredential;
import org.springframework.security.web.webauthn.api.PublicKeyCredentialRequestOptions;
import org.springframework.security.web.webauthn.api.TestAuthenticationAssertionResponses;
import org.springframework.security.web.webauthn.api.TestPublicKeyCredentialRequestOptions;
import org.springframework.security.web.webauthn.api.TestPublicKeyCredentialUserEntities;
import org.springframework.security.web.webauthn.api.TestPublicKeyCredentials;
import org.springframework.security.web.webauthn.management.RelyingPartyAuthenticationRequest;
import org.springframework.security.web.webauthn.management.WebAuthnRelyingPartyOperations;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
class WebAuthnAuthenticationProviderTests {
@Test
void authenticateWhenSuccessThenIssuesFactor() {
WebAuthnRelyingPartyOperations operations = mock(WebAuthnRelyingPartyOperations.class);
UserDetailsService users = mock(UserDetailsService.class);
PublicKeyCredentialRequestOptions options = TestPublicKeyCredentialRequestOptions.create().build();
AuthenticatorAssertionResponse response = TestAuthenticationAssertionResponses
.createAuthenticatorAssertionResponse()
.build();
PublicKeyCredential<AuthenticatorAssertionResponse> credentials = TestPublicKeyCredentials
.createPublicKeyCredential(response)
.build();
Authentication request = new WebAuthnAuthenticationRequestToken(
new RelyingPartyAuthenticationRequest(options, credentials));
WebAuthnAuthenticationProvider provider = new WebAuthnAuthenticationProvider(operations, users);
given(users.loadUserByUsername(any())).willReturn(PasswordEncodedUser.user());
given(operations.authenticate(any())).willReturn(TestPublicKeyCredentialUserEntities.userEntity().build());
Authentication result = provider.authenticate(request);
SecurityAssertions.assertThat(result).hasAuthority("FACTOR_WEBAUTHN");
}
}