diff --git a/config/src/test/java/org/springframework/security/config/annotation/authentication/AuthenticationManagerBuilderTests.java b/config/src/test/java/org/springframework/security/config/annotation/authentication/AuthenticationManagerBuilderTests.java index 7065838491..0934e71f03 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/authentication/AuthenticationManagerBuilderTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/authentication/AuthenticationManagerBuilderTests.java @@ -32,6 +32,7 @@ import org.springframework.security.authentication.AuthenticationEventPublisher; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.AuthenticationProvider; import org.springframework.security.authentication.ProviderManager; +import org.springframework.security.authentication.SecurityAssertions; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.authentication.dao.DaoAuthenticationProvider; import org.springframework.security.config.ObjectPostProcessor; @@ -44,7 +45,6 @@ import org.springframework.security.config.test.SpringTestContext; import org.springframework.security.config.test.SpringTestContextExtension; import org.springframework.security.core.Authentication; import org.springframework.security.core.AuthenticationException; -import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.userdetails.PasswordEncodedUser; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.crypto.password.NoOpPasswordEncoder; @@ -107,8 +107,7 @@ public class AuthenticationManagerBuilderTests { .getAuthenticationManager(); Authentication auth = manager .authenticate(UsernamePasswordAuthenticationToken.unauthenticated("user", "password")); - assertThat(auth.getName()).isEqualTo("user"); - assertThat(auth.getAuthorities()).extracting(GrantedAuthority::getAuthority).containsOnly("ROLE_USER"); + SecurityAssertions.assertThat(auth).name("user").hasAuthority("ROLE_USER"); } @Test @@ -119,8 +118,7 @@ public class AuthenticationManagerBuilderTests { .getAuthenticationManager(); Authentication auth = manager .authenticate(UsernamePasswordAuthenticationToken.unauthenticated("user", "password")); - assertThat(auth.getName()).isEqualTo("user"); - assertThat(auth.getAuthorities()).extracting(GrantedAuthority::getAuthority).containsOnly("ROLE_USER"); + SecurityAssertions.assertThat(auth).name("user").hasAuthority("ROLE_USER"); } @Test diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2LoginConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2LoginConfigurerTests.java index bb53b37dcd..d2f5574a67 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2LoginConfigurerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2LoginConfigurerTests.java @@ -45,6 +45,7 @@ import org.springframework.mock.web.MockFilterChain; import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockHttpServletResponse; import org.springframework.security.authentication.AuthenticationProvider; +import org.springframework.security.authentication.SecurityAssertions; import org.springframework.security.authentication.event.AuthenticationSuccessEvent; import org.springframework.security.config.Customizer; import org.springframework.security.config.ObjectPostProcessor; @@ -217,10 +218,9 @@ public class OAuth2LoginConfigurerTests { Authentication authentication = this.securityContextRepository .loadContext(new HttpRequestResponseHolder(this.request, this.response)) .getAuthentication(); - assertThat(authentication.getAuthorities()).hasSize(1); - assertThat(authentication.getAuthorities()).first() - .isInstanceOf(OAuth2UserAuthority.class) - .hasToString("OAUTH2_USER"); + SecurityAssertions.assertThat(authentication) + .hasAuthority("OAUTH2_USER") + .isInstanceOf(OAuth2UserAuthority.class); } @Test @@ -234,10 +234,9 @@ public class OAuth2LoginConfigurerTests { Authentication authentication = this.securityContextRepository .loadContext(new HttpRequestResponseHolder(this.request, this.response)) .getAuthentication(); - assertThat(authentication.getAuthorities()).hasSize(1); - assertThat(authentication.getAuthorities()).first() - .isInstanceOf(OAuth2UserAuthority.class) - .hasToString("OAUTH2_USER"); + SecurityAssertions.assertThat(authentication) + .hasAuthority("OAUTH2_USER") + .isInstanceOf(OAuth2UserAuthority.class); SecurityContextHolderStrategy strategy = this.context.getBean(SecurityContextHolderStrategy.class); verify(strategy, atLeastOnce()).getDeferredContext(); SecurityContextChangedListener listener = this.context.getBean(SecurityContextChangedListener.class); @@ -255,10 +254,9 @@ public class OAuth2LoginConfigurerTests { Authentication authentication = this.securityContextRepository .loadContext(new HttpRequestResponseHolder(this.request, this.response)) .getAuthentication(); - assertThat(authentication.getAuthorities()).hasSize(1); - assertThat(authentication.getAuthorities()).first() - .isInstanceOf(OAuth2UserAuthority.class) - .hasToString("OAUTH2_USER"); + SecurityAssertions.assertThat(authentication) + .hasAuthority("OAUTH2_USER") + .isInstanceOf(OAuth2UserAuthority.class); } // gh-6009 @@ -296,9 +294,7 @@ public class OAuth2LoginConfigurerTests { Authentication authentication = this.securityContextRepository .loadContext(new HttpRequestResponseHolder(this.request, this.response)) .getAuthentication(); - assertThat(authentication.getAuthorities()).hasSize(2); - assertThat(authentication.getAuthorities()).first().hasToString("OAUTH2_USER"); - assertThat(authentication.getAuthorities()).last().hasToString("ROLE_OAUTH2_USER"); + SecurityAssertions.assertThat(authentication).hasAuthorities("OAUTH2_USER", "ROLE_OAUTH2_USER"); } @Test @@ -317,9 +313,7 @@ public class OAuth2LoginConfigurerTests { Authentication authentication = this.securityContextRepository .loadContext(new HttpRequestResponseHolder(this.request, this.response)) .getAuthentication(); - assertThat(authentication.getAuthorities()).hasSize(2); - assertThat(authentication.getAuthorities()).first().hasToString("OAUTH2_USER"); - assertThat(authentication.getAuthorities()).last().hasToString("ROLE_OAUTH2_USER"); + SecurityAssertions.assertThat(authentication).hasAuthorities("OAUTH2_USER", "ROLE_OAUTH2_USER"); } @Test @@ -338,9 +332,7 @@ public class OAuth2LoginConfigurerTests { Authentication authentication = this.securityContextRepository .loadContext(new HttpRequestResponseHolder(this.request, this.response)) .getAuthentication(); - assertThat(authentication.getAuthorities()).hasSize(2); - assertThat(authentication.getAuthorities()).first().hasToString("OAUTH2_USER"); - assertThat(authentication.getAuthorities()).last().hasToString("ROLE_OAUTH2_USER"); + SecurityAssertions.assertThat(authentication).hasAuthorities("OAUTH2_USER", "ROLE_OAUTH2_USER"); } // gh-5488 @@ -361,10 +353,9 @@ public class OAuth2LoginConfigurerTests { Authentication authentication = this.securityContextRepository .loadContext(new HttpRequestResponseHolder(this.request, this.response)) .getAuthentication(); - assertThat(authentication.getAuthorities()).hasSize(1); - assertThat(authentication.getAuthorities()).first() - .isInstanceOf(OAuth2UserAuthority.class) - .hasToString("OAUTH2_USER"); + SecurityAssertions.assertThat(authentication) + .hasAuthority("OAUTH2_USER") + .isInstanceOf(OAuth2UserAuthority.class); } // gh-5521 @@ -570,10 +561,7 @@ public class OAuth2LoginConfigurerTests { Authentication authentication = this.securityContextRepository .loadContext(new HttpRequestResponseHolder(this.request, this.response)) .getAuthentication(); - assertThat(authentication.getAuthorities()).hasSize(1); - assertThat(authentication.getAuthorities()).first() - .isInstanceOf(OidcUserAuthority.class) - .hasToString("OIDC_USER"); + SecurityAssertions.assertThat(authentication).hasAuthority("OIDC_USER").isInstanceOf(OidcUserAuthority.class); } @Test @@ -593,9 +581,7 @@ public class OAuth2LoginConfigurerTests { .loadContext(new HttpRequestResponseHolder(this.request, this.response)) .getAuthentication(); assertThat(authentication.getAuthorities()).hasSize(1); - assertThat(authentication.getAuthorities()).first() - .isInstanceOf(OidcUserAuthority.class) - .hasToString("OIDC_USER"); + SecurityAssertions.assertThat(authentication).hasAuthority("OIDC_USER").isInstanceOf(OidcUserAuthority.class); } @Test @@ -614,9 +600,7 @@ public class OAuth2LoginConfigurerTests { Authentication authentication = this.securityContextRepository .loadContext(new HttpRequestResponseHolder(this.request, this.response)) .getAuthentication(); - assertThat(authentication.getAuthorities()).hasSize(2); - assertThat(authentication.getAuthorities()).first().hasToString("OIDC_USER"); - assertThat(authentication.getAuthorities()).last().hasToString("ROLE_OIDC_USER"); + SecurityAssertions.assertThat(authentication).hasAuthorities("OIDC_USER", "ROLE_OIDC_USER"); } @Test @@ -635,9 +619,7 @@ public class OAuth2LoginConfigurerTests { Authentication authentication = this.securityContextRepository .loadContext(new HttpRequestResponseHolder(this.request, this.response)) .getAuthentication(); - assertThat(authentication.getAuthorities()).hasSize(2); - assertThat(authentication.getAuthorities()).first().hasToString("OIDC_USER"); - assertThat(authentication.getAuthorities()).last().hasToString("ROLE_OIDC_USER"); + SecurityAssertions.assertThat(authentication).hasAuthorities("OIDC_USER", "ROLE_OIDC_USER"); } @Test @@ -690,11 +672,7 @@ public class OAuth2LoginConfigurerTests { Authentication authentication = this.securityContextRepository .loadContext(new HttpRequestResponseHolder(this.request, this.response)) .getAuthentication(); - assertThat(authentication.getAuthorities()).hasSize(1); - assertThat(authentication.getAuthorities()).first() - .isInstanceOf(OidcUserAuthority.class) - .hasToString("OIDC_USER"); - + SecurityAssertions.assertThat(authentication).hasAuthority("OIDC_USER").isInstanceOf(OidcUserAuthority.class); // Ensure shared objects set for OAuth2 Client are not used ClientRegistrationRepository clientRegistrationRepository = this.spring.getContext() .getBean(ClientRegistrationRepository.class); diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/OAuth2ResourceServerConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/OAuth2ResourceServerConfigurerTests.java index d9915d0152..b380474810 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/OAuth2ResourceServerConfigurerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/OAuth2ResourceServerConfigurerTests.java @@ -2674,6 +2674,7 @@ public class OAuth2ResourceServerConfigurerTests { String requiresReadScope(JwtAuthenticationToken token) { return token.getAuthorities() .stream() + .filter((ga) -> ga.getAuthority().startsWith("SCOPE_")) .map(GrantedAuthority::getAuthority) .collect(Collectors.toList()) .toString(); diff --git a/core/src/test/java/org/springframework/security/authentication/SecurityAssertions.java b/core/src/test/java/org/springframework/security/authentication/SecurityAssertions.java new file mode 100644 index 0000000000..000c51e55c --- /dev/null +++ b/core/src/test/java/org/springframework/security/authentication/SecurityAssertions.java @@ -0,0 +1,100 @@ +/* + * 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; + +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.Set; +import java.util.function.Predicate; + +import org.assertj.core.api.AbstractObjectAssert; +import org.assertj.core.api.Assertions; +import org.assertj.core.api.CollectionAssert; +import org.assertj.core.api.Condition; +import org.assertj.core.api.ObjectAssert; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; + +import org.springframework.security.core.Authentication; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.AuthorityUtils; + +@NullMarked +public final class SecurityAssertions { + + private SecurityAssertions() { + + } + + public static AuthenticationAssert assertThat(@Nullable Authentication authentication) { + Assertions.assertThat(authentication).isNotNull(); + return new AuthenticationAssert(authentication); + } + + public static final class AuthenticationAssert extends AbstractObjectAssert { + + private final Authentication authentication; + + private AuthenticationAssert(Authentication authentication) { + super(authentication, AuthenticationAssert.class); + this.authentication = authentication; + } + + public AuthenticationAssert name(String name) { + Assertions.assertThat(this.authentication.getName()).isEqualTo(name); + return this; + } + + public ObjectAssert hasAuthority(String authority) { + Collection actual = this.authentication.getAuthorities(); + for (GrantedAuthority element : actual) { + if (element.getAuthority().equals(authority)) { + return new ObjectAssert<>(element); + } + } + throw new AssertionError(actual + " does not contain " + authority + " as expected"); + } + + public CollectionAssert hasAuthorities(String... authorities) { + HasAuthoritiesPredicate test = new HasAuthoritiesPredicate(authorities); + return authorities().has(new Condition<>(test, "contains %s", Arrays.toString(authorities))); + } + + public CollectionAssert authorities() { + return new CollectionAssert<>(this.authentication.getAuthorities()); + } + + } + + private static final class HasAuthoritiesPredicate implements Predicate> { + + private final Collection expected; + + private HasAuthoritiesPredicate(String... expected) { + this.expected = List.of(expected); + } + + @Override + public boolean test(Collection actual) { + Set asString = AuthorityUtils.authorityListToSet(actual); + return asString.containsAll(this.expected); + } + + } + +} diff --git a/ldap/spring-security-ldap.gradle b/ldap/spring-security-ldap.gradle index 826932ef2d..f4d6abfb32 100644 --- a/ldap/spring-security-ldap.gradle +++ b/ldap/spring-security-ldap.gradle @@ -19,7 +19,8 @@ dependencies { exclude(group: 'org.springframework.data', module: 'spring-data-commons') } - testImplementation project(':spring-security-test') + testImplementation project(path : ':spring-security-core', configuration : 'tests') + testImplementation project(":spring-security-test") testImplementation 'org.slf4j:slf4j-api' testImplementation "org.assertj:assertj-core" testImplementation "org.junit.jupiter:junit-jupiter-api" diff --git a/ldap/src/test/java/org/springframework/security/ldap/authentication/ad/ActiveDirectoryLdapAuthenticationProviderTests.java b/ldap/src/test/java/org/springframework/security/ldap/authentication/ad/ActiveDirectoryLdapAuthenticationProviderTests.java index 09304ca2f5..45f76f2aea 100644 --- a/ldap/src/test/java/org/springframework/security/ldap/authentication/ad/ActiveDirectoryLdapAuthenticationProviderTests.java +++ b/ldap/src/test/java/org/springframework/security/ldap/authentication/ad/ActiveDirectoryLdapAuthenticationProviderTests.java @@ -42,6 +42,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.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; import org.springframework.security.ldap.authentication.ad.ActiveDirectoryLdapAuthenticationProvider.ContextFactory; @@ -357,10 +358,10 @@ public class ActiveDirectoryLdapAuthenticationProviderTests { .willReturn(new MockNamingEnumeration(sr)); provider.contextFactory = createContextFactoryReturning(this.ctx); Authentication result = provider.authenticate(this.joe); - assertThat(result.getAuthorities()).isEmpty(); + SecurityAssertions.assertThat(result).authorities().doesNotHaveToString("Admin"); dca.addAttributeValue("memberOf", "CN=Admin,CN=Users,DC=mydomain,DC=eu"); result = provider.authenticate(this.joe); - assertThat(result.getAuthorities()).hasSize(1); + SecurityAssertions.assertThat(result).hasAuthority("Admin"); } static class MockNamingEnumeration implements NamingEnumeration { 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 e8b51ee9cb..511cb50af2 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 @@ -165,7 +165,7 @@ public class OAuth2LoginAuthenticationProviderTests { assertThat(authentication.isAuthenticated()).isTrue(); assertThat(authentication.getPrincipal()).isEqualTo(principal); assertThat(authentication.getCredentials()).isEqualTo(""); - assertThat(authentication.getAuthorities()).isEqualTo(authorities); + assertThat(authentication.getAuthorities()).containsAll(authorities); assertThat(authentication.getClientRegistration()).isEqualTo(this.clientRegistration); assertThat(authentication.getAuthorizationExchange()).isEqualTo(this.authorizationExchange); assertThat(authentication.getAccessToken()).isEqualTo(accessTokenResponse.getAccessToken()); diff --git a/oauth2/oauth2-resource-server/spring-security-oauth2-resource-server.gradle b/oauth2/oauth2-resource-server/spring-security-oauth2-resource-server.gradle index ddcd1318fa..fbed03dcb3 100644 --- a/oauth2/oauth2-resource-server/spring-security-oauth2-resource-server.gradle +++ b/oauth2/oauth2-resource-server/spring-security-oauth2-resource-server.gradle @@ -14,6 +14,7 @@ dependencies { provided 'jakarta.servlet:jakarta.servlet-api' + testImplementation project(path : ':spring-security-core', configuration : 'tests') testImplementation project(path: ':spring-security-oauth2-jose', configuration: 'tests') testImplementation 'com.squareup.okhttp3:mockwebserver' testImplementation 'com.fasterxml.jackson.core:jackson-databind' @@ -27,5 +28,6 @@ dependencies { testImplementation "org.mockito:mockito-junit-jupiter" testImplementation "org.springframework:spring-test" + testRuntimeOnly 'org.junit.platform:junit-platform-launcher' } 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 bda6657437..6cfa9676f2 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 @@ -23,6 +23,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.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.oauth2.jwt.Jwt; @@ -46,9 +47,7 @@ public class JwtAuthenticationConverterTests { public void convertWhenDefaultGrantedAuthoritiesConverterSet() { Jwt jwt = TestJwts.jwt().claim("scope", "message:read message:write").build(); AbstractAuthenticationToken authentication = this.jwtAuthenticationConverter.convert(jwt); - Collection authorities = authentication.getAuthorities(); - assertThat(authorities).containsExactly(new SimpleGrantedAuthority("SCOPE_message:read"), - new SimpleGrantedAuthority("SCOPE_message:write")); + SecurityAssertions.assertThat(authentication).hasAuthorities("SCOPE_message:read", "SCOPE_message:write"); } @Test @@ -65,8 +64,7 @@ public class JwtAuthenticationConverterTests { .asList(new SimpleGrantedAuthority("blah")); this.jwtAuthenticationConverter.setJwtGrantedAuthoritiesConverter(grantedAuthoritiesConverter); AbstractAuthenticationToken authentication = this.jwtAuthenticationConverter.convert(jwt); - Collection authorities = authentication.getAuthorities(); - assertThat(authorities).containsExactly(new SimpleGrantedAuthority("blah")); + SecurityAssertions.assertThat(authentication).hasAuthority("blah"); } @Test diff --git a/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/authentication/JwtBearerTokenAuthenticationConverterTests.java b/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/authentication/JwtBearerTokenAuthenticationConverterTests.java index 7bcf98a18d..2edbf0f754 100644 --- a/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/authentication/JwtBearerTokenAuthenticationConverterTests.java +++ b/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/authentication/JwtBearerTokenAuthenticationConverterTests.java @@ -17,11 +17,13 @@ package org.springframework.security.oauth2.server.resource.authentication; import java.util.Arrays; +import java.util.function.Predicate; import org.junit.jupiter.api.Test; import org.springframework.security.authentication.AbstractAuthenticationToken; -import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.authentication.SecurityAssertions; +import org.springframework.security.core.GrantedAuthority; import org.springframework.security.oauth2.jwt.Jwt; import static org.assertj.core.api.Assertions.assertThat; @@ -48,7 +50,7 @@ public class JwtBearerTokenAuthenticationConverterTests { BearerTokenAuthentication bearerToken = (BearerTokenAuthentication) token; assertThat(bearerToken.getToken().getTokenValue()).isEqualTo("token-value"); assertThat(bearerToken.getTokenAttributes()).containsOnlyKeys("claim"); - assertThat(bearerToken.getAuthorities()).isEmpty(); + assertThat(bearerToken.getAuthorities()).noneMatch(isScope()); } @Test @@ -62,8 +64,7 @@ public class JwtBearerTokenAuthenticationConverterTests { AbstractAuthenticationToken token = this.converter.convert(jwt); assertThat(token).isInstanceOf(BearerTokenAuthentication.class); BearerTokenAuthentication bearerToken = (BearerTokenAuthentication) token; - assertThat(bearerToken.getAuthorities()).containsExactly(new SimpleGrantedAuthority("SCOPE_message:read"), - new SimpleGrantedAuthority("SCOPE_message:write")); + SecurityAssertions.assertThat(bearerToken).hasAuthorities("SCOPE_message:read", "SCOPE_message:write"); } @Test @@ -77,8 +78,11 @@ public class JwtBearerTokenAuthenticationConverterTests { AbstractAuthenticationToken token = this.converter.convert(jwt); assertThat(token).isInstanceOf(BearerTokenAuthentication.class); BearerTokenAuthentication bearerToken = (BearerTokenAuthentication) token; - assertThat(bearerToken.getAuthorities()).containsExactly(new SimpleGrantedAuthority("SCOPE_message:read"), - new SimpleGrantedAuthority("SCOPE_message:write")); + SecurityAssertions.assertThat(bearerToken).hasAuthorities("SCOPE_message:read", "SCOPE_message:write"); + } + + static Predicate isScope() { + return (a) -> a.getAuthority().startsWith("SCOPE_"); } } diff --git a/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/authentication/JwtReactiveAuthenticationManagerTests.java b/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/authentication/JwtReactiveAuthenticationManagerTests.java index 5579825aaf..03b345a813 100644 --- a/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/authentication/JwtReactiveAuthenticationManagerTests.java +++ b/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/authentication/JwtReactiveAuthenticationManagerTests.java @@ -23,10 +23,10 @@ import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import reactor.core.publisher.Mono; +import org.springframework.security.authentication.SecurityAssertions; import org.springframework.security.authentication.TestingAuthenticationToken; import org.springframework.security.core.Authentication; import org.springframework.security.core.AuthenticationException; -import org.springframework.security.core.GrantedAuthority; import org.springframework.security.oauth2.core.OAuth2AuthenticationException; import org.springframework.security.oauth2.jwt.BadJwtException; import org.springframework.security.oauth2.jwt.Jwt; @@ -137,11 +137,7 @@ public class JwtReactiveAuthenticationManagerTests { Authentication authentication = this.manager.authenticate(token).block(); assertThat(authentication).isNotNull(); assertThat(authentication.isAuthenticated()).isTrue(); - // @formatter:off - assertThat(authentication.getAuthorities()) - .extracting(GrantedAuthority::getAuthority) - .containsOnly("SCOPE_message:read", "SCOPE_message:write"); - // @formatter:on + SecurityAssertions.assertThat(authentication).hasAuthorities("SCOPE_message:read", "SCOPE_message:write"); } } 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 1429434441..586294d581 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 @@ -21,12 +21,15 @@ import java.time.Instant; import java.util.Arrays; import java.util.Collections; import java.util.Map; +import java.util.function.Predicate; import org.junit.jupiter.api.Test; import org.springframework.security.authentication.AuthenticationServiceException; +import org.springframework.security.authentication.SecurityAssertions; import org.springframework.security.authentication.TestingAuthenticationToken; import org.springframework.security.core.Authentication; +import org.springframework.security.core.GrantedAuthority; import org.springframework.security.oauth2.core.OAuth2AuthenticatedPrincipal; import org.springframework.security.oauth2.core.OAuth2TokenIntrospectionClaimNames; import org.springframework.security.oauth2.core.TestOAuth2AuthenticatedPrincipals; @@ -75,10 +78,7 @@ public class OpaqueTokenAuthenticationProviderTests { .containsEntry(OAuth2TokenIntrospectionClaimNames.SUB, "Z5O3upPC88QrAjx00dis") .containsEntry(OAuth2TokenIntrospectionClaimNames.USERNAME, "jdoe") .containsEntry("extension_field", "twenty-seven"); - assertThat(result.getAuthorities()) - .extracting("authority") - .containsExactly("SCOPE_read", "SCOPE_write", - "SCOPE_dolphin"); + SecurityAssertions.assertThat(result).hasAuthorities("SCOPE_read", "SCOPE_write", "SCOPE_dolphin"); // @formatter:on } @@ -97,7 +97,7 @@ public class OpaqueTokenAuthenticationProviderTests { .isNotNull() .doesNotContainKey(OAuth2TokenIntrospectionClaimNames.SCOPE); // @formatter:on - assertThat(result.getAuthorities()).isEmpty(); + SecurityAssertions.assertThat(result).authorities().noneMatch(isScope()); } @Test @@ -146,4 +146,8 @@ public class OpaqueTokenAuthenticationProviderTests { verifyNoMoreInteractions(introspector, authenticationConverter); } + static Predicate isScope() { + return (a) -> a.getAuthority().startsWith("SCOPE_"); + } + } diff --git a/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/authentication/OpaqueTokenReactiveAuthenticationManagerTests.java b/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/authentication/OpaqueTokenReactiveAuthenticationManagerTests.java index a0b5c236a7..f5f6fbc085 100644 --- a/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/authentication/OpaqueTokenReactiveAuthenticationManagerTests.java +++ b/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/authentication/OpaqueTokenReactiveAuthenticationManagerTests.java @@ -21,13 +21,16 @@ import java.time.Instant; import java.util.Arrays; import java.util.Collections; import java.util.Map; +import java.util.function.Predicate; import org.junit.jupiter.api.Test; import reactor.core.publisher.Mono; import org.springframework.security.authentication.AuthenticationServiceException; +import org.springframework.security.authentication.SecurityAssertions; import org.springframework.security.authentication.TestingAuthenticationToken; import org.springframework.security.core.Authentication; +import org.springframework.security.core.GrantedAuthority; import org.springframework.security.oauth2.core.OAuth2AuthenticatedPrincipal; import org.springframework.security.oauth2.core.OAuth2TokenIntrospectionClaimNames; import org.springframework.security.oauth2.core.TestOAuth2AuthenticatedPrincipals; @@ -76,10 +79,7 @@ public class OpaqueTokenReactiveAuthenticationManagerTests { .containsEntry(OAuth2TokenIntrospectionClaimNames.SUB, "Z5O3upPC88QrAjx00dis") .containsEntry(OAuth2TokenIntrospectionClaimNames.USERNAME, "jdoe") .containsEntry("extension_field", "twenty-seven"); - assertThat(result.getAuthorities()) - .extracting("authority") - .containsExactly("SCOPE_read", "SCOPE_write", - "SCOPE_dolphin"); + SecurityAssertions.assertThat(result).hasAuthorities("SCOPE_read", "SCOPE_write", "SCOPE_dolphin"); // @formatter:on } @@ -94,7 +94,7 @@ public class OpaqueTokenReactiveAuthenticationManagerTests { assertThat(result.getPrincipal()).isInstanceOf(OAuth2IntrospectionAuthenticatedPrincipal.class); Map attributes = ((OAuth2AuthenticatedPrincipal) result.getPrincipal()).getAttributes(); assertThat(attributes).isNotNull().doesNotContainKey(OAuth2TokenIntrospectionClaimNames.SCOPE); - assertThat(result.getAuthorities()).isEmpty(); + SecurityAssertions.assertThat(result).authorities().noneMatch(isScope()); } @Test @@ -145,4 +145,8 @@ public class OpaqueTokenReactiveAuthenticationManagerTests { verifyNoMoreInteractions(introspector, authenticationConverter); } + static Predicate isScope() { + return (a) -> a.getAuthority().startsWith("SCOPE_"); + } + } diff --git a/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/authentication/ReactiveJwtAuthenticationConverterAdapterTests.java b/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/authentication/ReactiveJwtAuthenticationConverterAdapterTests.java index c52ff5b495..6ec965b77c 100644 --- a/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/authentication/ReactiveJwtAuthenticationConverterAdapterTests.java +++ b/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/authentication/ReactiveJwtAuthenticationConverterAdapterTests.java @@ -17,19 +17,17 @@ package org.springframework.security.oauth2.server.resource.authentication; import java.util.Arrays; -import java.util.Collection; +import java.util.function.Predicate; 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.GrantedAuthority; -import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.oauth2.jwt.Jwt; import org.springframework.security.oauth2.jwt.TestJwts; -import static org.assertj.core.api.Assertions.assertThat; - /** * Tests for {@link ReactiveJwtAuthenticationConverterAdapter} * @@ -46,40 +44,28 @@ public class ReactiveJwtAuthenticationConverterAdapterTests { public void convertWhenTokenHasScopeAttributeThenTranslatedToAuthorities() { Jwt jwt = TestJwts.jwt().claim("scope", "message:read message:write").build(); AbstractAuthenticationToken authentication = this.jwtAuthenticationConverter.convert(jwt).block(); - Collection authorities = authentication.getAuthorities(); - // @formatter:off - assertThat(authorities) - .containsExactly(new SimpleGrantedAuthority("SCOPE_message:read"), - new SimpleGrantedAuthority("SCOPE_message:write")); - // @formatter:on + SecurityAssertions.assertThat(authentication).hasAuthorities("SCOPE_message:read", "SCOPE_message:write"); } @Test public void convertWhenTokenHasEmptyScopeAttributeThenTranslatedToNoAuthorities() { Jwt jwt = TestJwts.jwt().claim("scope", "").build(); AbstractAuthenticationToken authentication = this.jwtAuthenticationConverter.convert(jwt).block(); - Collection authorities = authentication.getAuthorities(); - assertThat(authorities).containsExactly(); + SecurityAssertions.assertThat(authentication).authorities().noneMatch(isScope()); } @Test public void convertWhenTokenHasScpAttributeThenTranslatedToAuthorities() { Jwt jwt = TestJwts.jwt().claim("scp", Arrays.asList("message:read", "message:write")).build(); AbstractAuthenticationToken authentication = this.jwtAuthenticationConverter.convert(jwt).block(); - Collection authorities = authentication.getAuthorities(); - // @formatter:off - assertThat(authorities) - .containsExactly(new SimpleGrantedAuthority("SCOPE_message:read"), - new SimpleGrantedAuthority("SCOPE_message:write")); - // @formatter:on + SecurityAssertions.assertThat(authentication).hasAuthorities("SCOPE_message:read", "SCOPE_message:write"); } @Test public void convertWhenTokenHasEmptyScpAttributeThenTranslatedToNoAuthorities() { Jwt jwt = TestJwts.jwt().claim("scp", Arrays.asList()).build(); AbstractAuthenticationToken authentication = this.jwtAuthenticationConverter.convert(jwt).block(); - Collection authorities = authentication.getAuthorities(); - assertThat(authorities).containsExactly(); + SecurityAssertions.assertThat(authentication).authorities().noneMatch(isScope()); } @Test @@ -89,12 +75,7 @@ public class ReactiveJwtAuthenticationConverterAdapterTests { .claim("scope", "missive:read missive:write") .build(); AbstractAuthenticationToken authentication = this.jwtAuthenticationConverter.convert(jwt).block(); - Collection authorities = authentication.getAuthorities(); - // @formatter:off - assertThat(authorities) - .containsExactly(new SimpleGrantedAuthority("SCOPE_missive:read"), - new SimpleGrantedAuthority("SCOPE_missive:write")); - // @formatter:on + SecurityAssertions.assertThat(authentication).hasAuthorities("SCOPE_missive:read", "SCOPE_missive:write"); } @Test @@ -106,8 +87,11 @@ public class ReactiveJwtAuthenticationConverterAdapterTests { .build(); // @formatter:on AbstractAuthenticationToken authentication = this.jwtAuthenticationConverter.convert(jwt).block(); - Collection authorities = authentication.getAuthorities(); - assertThat(authorities).containsExactly(); + SecurityAssertions.assertThat(authentication).authorities().noneMatch(isScope()); + } + + 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 e3ebe437cf..e44ddef43c 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 @@ -71,6 +71,7 @@ import org.opensaml.xmlsec.encryption.impl.EncryptedDataBuilder; import org.opensaml.xmlsec.signature.support.SignatureConstants; import org.springframework.core.convert.converter.Converter; +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; @@ -734,7 +735,7 @@ public class OpenSaml5AuthenticationProviderTests { Response response = TestOpenSamlObjects.signedResponseWithOneAssertion(); Saml2AuthenticationToken token = token(response, verifying(registration())); Authentication authentication = provider.authenticate(token); - assertThat(AuthorityUtils.authorityListToSet(authentication.getAuthorities())).containsExactly("CUSTOM"); + SecurityAssertions.assertThat(authentication).hasAuthority("CUSTOM"); verify(grantedAuthoritiesConverter).convert(any()); }