diff --git a/core/src/test/java/org/springframework/security/authentication/dao/DaoAuthenticationProviderTests.java b/core/src/test/java/org/springframework/security/authentication/dao/DaoAuthenticationProviderTests.java index 1212e5b313..e80e4e6a85 100644 --- a/core/src/test/java/org/springframework/security/authentication/dao/DaoAuthenticationProviderTests.java +++ b/core/src/test/java/org/springframework/security/authentication/dao/DaoAuthenticationProviderTests.java @@ -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); } diff --git a/core/src/test/java/org/springframework/security/authentication/ott/OneTimeTokenAuthenticationProviderTests.java b/core/src/test/java/org/springframework/security/authentication/ott/OneTimeTokenAuthenticationProviderTests.java index a59ca4803a..c2456562e9 100644 --- a/core/src/test/java/org/springframework/security/authentication/ott/OneTimeTokenAuthenticationProviderTests.java +++ b/core/src/test/java/org/springframework/security/authentication/ott/OneTimeTokenAuthenticationProviderTests.java @@ -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 diff --git a/ldap/src/test/java/org/springframework/security/ldap/authentication/LdapAuthenticationProviderTests.java b/ldap/src/test/java/org/springframework/security/ldap/authentication/LdapAuthenticationProviderTests.java index 0381d0b5c4..af5781cd42 100644 --- a/ldap/src/test/java/org/springframework/security/ldap/authentication/LdapAuthenticationProviderTests.java +++ b/ldap/src/test/java/org/springframework/security/ldap/authentication/LdapAuthenticationProviderTests.java @@ -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 diff --git a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/authentication/OAuth2LoginAuthenticationProviderTests.java b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/authentication/OAuth2LoginAuthenticationProviderTests.java index 511cb50af2..ccf1ae997f 100644 --- a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/authentication/OAuth2LoginAuthenticationProviderTests.java +++ b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/authentication/OAuth2LoginAuthenticationProviderTests.java @@ -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 scopes = new LinkedHashSet<>(Arrays.asList("scope1", "scope2")); diff --git a/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/authentication/JwtAuthenticationConverterTests.java b/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/authentication/JwtAuthenticationConverterTests.java index 6cfa9676f2..439484e562 100644 --- a/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/authentication/JwtAuthenticationConverterTests.java +++ b/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/authentication/JwtAuthenticationConverterTests.java @@ -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"); + } + } diff --git a/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/authentication/OpaqueTokenAuthenticationProviderTests.java b/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/authentication/OpaqueTokenAuthenticationProviderTests.java index 586294d581..2d9d4507fb 100644 --- a/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/authentication/OpaqueTokenAuthenticationProviderTests.java +++ b/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/authentication/OpaqueTokenAuthenticationProviderTests.java @@ -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 isScope() { return (a) -> a.getAuthority().startsWith("SCOPE_"); } diff --git a/saml2/saml2-service-provider/src/opensaml5Test/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml5AuthenticationProviderTests.java b/saml2/saml2-service-provider/src/opensaml5Test/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml5AuthenticationProviderTests.java index e44ddef43c..a5770c728e 100644 --- a/saml2/saml2-service-provider/src/opensaml5Test/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml5AuthenticationProviderTests.java +++ b/saml2/saml2-service-provider/src/opensaml5Test/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml5AuthenticationProviderTests.java @@ -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 build(QName qName) { return (T) XMLObjectProviderRegistrySupport.getBuilderFactory().getBuilder(qName).buildObject(qName); } diff --git a/web/src/test/java/org/springframework/security/web/authentication/preauth/PreAuthenticatedAuthenticationProviderTests.java b/web/src/test/java/org/springframework/security/web/authentication/preauth/PreAuthenticatedAuthenticationProviderTests.java index 35543f2633..998ee79108 100644 --- a/web/src/test/java/org/springframework/security/web/authentication/preauth/PreAuthenticatedAuthenticationProviderTests.java +++ b/web/src/test/java/org/springframework/security/web/authentication/preauth/PreAuthenticatedAuthenticationProviderTests.java @@ -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> 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); diff --git a/webauthn/src/test/java/org/springframework/security/web/webauthn/authentication/WebAuthnAuthenticationProviderTests.java b/webauthn/src/test/java/org/springframework/security/web/webauthn/authentication/WebAuthnAuthenticationProviderTests.java new file mode 100644 index 0000000000..f7f18b0851 --- /dev/null +++ b/webauthn/src/test/java/org/springframework/security/web/webauthn/authentication/WebAuthnAuthenticationProviderTests.java @@ -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 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"); + } + +}