1
0
mirror of synced 2026-08-05 01:36:56 +00:00

Add SecurityAssertions

This commit introduces a simple, internal test API for
verifying aspects of an Authentication, like its name
and authorities.

Closes gh-17844
This commit is contained in:
Josh Cummings
2025-09-03 16:33:16 -06:00
parent de10e08348
commit c64b086878
15 changed files with 180 additions and 108 deletions
@@ -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());
@@ -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'
}
@@ -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<GrantedAuthority> 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<GrantedAuthority> authorities = authentication.getAuthorities();
assertThat(authorities).containsExactly(new SimpleGrantedAuthority("blah"));
SecurityAssertions.assertThat(authentication).hasAuthority("blah");
}
@Test
@@ -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<GrantedAuthority> isScope() {
return (a) -> a.getAuthority().startsWith("SCOPE_");
}
}
@@ -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");
}
}
@@ -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<GrantedAuthority> isScope() {
return (a) -> a.getAuthority().startsWith("SCOPE_");
}
}
@@ -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<String, Object> 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<GrantedAuthority> isScope() {
return (a) -> a.getAuthority().startsWith("SCOPE_");
}
}
@@ -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<GrantedAuthority> 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<GrantedAuthority> 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<GrantedAuthority> 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<GrantedAuthority> 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<GrantedAuthority> 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<GrantedAuthority> authorities = authentication.getAuthorities();
assertThat(authorities).containsExactly();
SecurityAssertions.assertThat(authentication).authorities().noneMatch(isScope());
}
static Predicate<GrantedAuthority> isScope() {
return (a) -> a.getAuthority().startsWith("SCOPE_");
}
}