diff --git a/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/introspection/NimbusOpaqueTokenIntrospector.java b/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/introspection/NimbusOpaqueTokenIntrospector.java
index 1f0821cff7..440ba8b9c4 100644
--- a/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/introspection/NimbusOpaqueTokenIntrospector.java
+++ b/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/introspection/NimbusOpaqueTokenIntrospector.java
@@ -39,7 +39,6 @@ import org.springframework.http.ResponseEntity;
import org.springframework.http.client.support.BasicAuthenticationInterceptor;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
-import org.springframework.security.oauth2.core.DefaultOAuth2AuthenticatedPrincipal;
import org.springframework.security.oauth2.core.OAuth2AuthenticatedPrincipal;
import org.springframework.util.Assert;
import org.springframework.util.LinkedMultiValueMap;
@@ -232,7 +231,7 @@ public class NimbusOpaqueTokenIntrospector implements OpaqueTokenIntrospector {
}
}
- return new DefaultOAuth2AuthenticatedPrincipal(claims, authorities);
+ return new OAuth2IntrospectionAuthenticatedPrincipal(claims, authorities);
}
private URL issuer(String uri) {
diff --git a/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/introspection/NimbusReactiveOpaqueTokenIntrospector.java b/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/introspection/NimbusReactiveOpaqueTokenIntrospector.java
index 2aa31b792c..05c1e9c4c3 100644
--- a/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/introspection/NimbusReactiveOpaqueTokenIntrospector.java
+++ b/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/introspection/NimbusReactiveOpaqueTokenIntrospector.java
@@ -37,7 +37,6 @@ import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
-import org.springframework.security.oauth2.core.DefaultOAuth2AuthenticatedPrincipal;
import org.springframework.security.oauth2.core.OAuth2AuthenticatedPrincipal;
import org.springframework.util.Assert;
import org.springframework.web.reactive.function.BodyInserters;
@@ -193,7 +192,7 @@ public class NimbusReactiveOpaqueTokenIntrospector implements ReactiveOpaqueToke
}
}
- return new DefaultOAuth2AuthenticatedPrincipal(claims, authorities);
+ return new OAuth2IntrospectionAuthenticatedPrincipal(claims, authorities);
}
private URL issuer(String uri) {
diff --git a/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/introspection/OAuth2IntrospectionAuthenticatedPrincipal.java b/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/introspection/OAuth2IntrospectionAuthenticatedPrincipal.java
new file mode 100644
index 0000000000..0f4f925440
--- /dev/null
+++ b/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/introspection/OAuth2IntrospectionAuthenticatedPrincipal.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2002-2020 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.oauth2.server.resource.introspection;
+
+import static org.springframework.security.core.authority.AuthorityUtils.NO_AUTHORITIES;
+
+import java.io.Serializable;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Map;
+
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.oauth2.core.OAuth2AuthenticatedPrincipal;
+import org.springframework.util.Assert;
+
+/**
+ * A domain object that wraps the attributes of OAuth 2.0 Token Introspection.
+ *
+ * @author David Kovac
+ * @since 5.4
+ * @see Introspection Response
+ */
+public final class OAuth2IntrospectionAuthenticatedPrincipal implements OAuth2AuthenticatedPrincipal,
+ OAuth2IntrospectionClaimAccessor, Serializable {
+ private final Map attributes;
+ private final Collection authorities;
+ private final String name;
+
+ /**
+ * Constructs an {@code OAuth2IntrospectionAuthenticatedPrincipal} using the provided parameters.
+ *
+ * @param attributes the attributes of the OAuth 2.0 Token Introspection
+ * @param authorities the authorities of the OAuth 2.0 Token Introspection
+ */
+ public OAuth2IntrospectionAuthenticatedPrincipal(Map attributes,
+ Collection authorities) {
+
+ this(null, attributes, authorities);
+ }
+
+ /**
+ * Constructs an {@code OAuth2IntrospectionAuthenticatedPrincipal} using the provided parameters.
+ *
+ * @param name the name attached to the OAuth 2.0 Token Introspection
+ * @param attributes the attributes of the OAuth 2.0 Token Introspection
+ * @param authorities the authorities of the OAuth 2.0 Token Introspection
+ */
+ public OAuth2IntrospectionAuthenticatedPrincipal(String name, Map attributes,
+ Collection authorities) {
+
+ Assert.notEmpty(attributes, "attributes cannot be empty");
+ this.attributes = Collections.unmodifiableMap(attributes);
+ this.authorities = authorities == null ?
+ NO_AUTHORITIES : Collections.unmodifiableCollection(authorities);
+ this.name = name == null ? getSubject() : name;
+ }
+
+ /**
+ * Gets the attributes of the OAuth 2.0 Token Introspection in map form.
+ *
+ * @return a {@link Map} of the attribute's objects keyed by the attribute's names
+ */
+ @Override
+ public Map getAttributes() {
+ return this.attributes;
+ }
+
+ /**
+ * Get the {@link Collection} of {@link GrantedAuthority}s associated
+ * with this OAuth 2.0 Token Introspection
+ *
+ * @return the OAuth 2.0 Token Introspection authorities
+ */
+ @Override
+ public Collection extends GrantedAuthority> getAuthorities() {
+ return this.authorities;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String getName() {
+ return this.name;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Map getClaims() {
+ return getAttributes();
+ }
+}
diff --git a/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/introspection/OAuth2IntrospectionClaimAccessor.java b/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/introspection/OAuth2IntrospectionClaimAccessor.java
new file mode 100644
index 0000000000..18c3c30e78
--- /dev/null
+++ b/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/introspection/OAuth2IntrospectionClaimAccessor.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright 2002-2020 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.oauth2.server.resource.introspection;
+
+import java.net.URL;
+import java.time.Instant;
+import java.util.List;
+
+import org.springframework.security.oauth2.core.ClaimAccessor;
+
+/**
+ * A {@link ClaimAccessor} for the "claims" that may be contained
+ * in the Introspection Response.
+ *
+ * @author David Kovac
+ * @since 5.4
+ * @see ClaimAccessor
+ * @see OAuth2IntrospectionClaimNames
+ * @see OAuth2IntrospectionAuthenticatedPrincipal
+ * @see Introspection Response
+ */
+public interface OAuth2IntrospectionClaimAccessor extends ClaimAccessor {
+ /**
+ * Returns the indicator {@code (active)} whether or not the token is currently active
+ *
+ * @return the indicator whether or not the token is currently active
+ */
+ default boolean isActive() {
+ return Boolean.TRUE.equals(this.getClaimAsBoolean(OAuth2IntrospectionClaimNames.ACTIVE));
+ }
+
+ /**
+ * Returns the scopes {@code (scope)} associated with the token
+ *
+ * @return the scopes associated with the token
+ */
+ default String getScope() {
+ return this.getClaimAsString(OAuth2IntrospectionClaimNames.SCOPE);
+ }
+
+ /**
+ * Returns the client identifier {@code (client_id)} for the token
+ *
+ * @return the client identifier for the token
+ */
+ default String getClientId() {
+ return this.getClaimAsString(OAuth2IntrospectionClaimNames.CLIENT_ID);
+ }
+
+ /**
+ * Returns a human-readable identifier {@code (username)} for the resource owner that authorized the token
+ *
+ * @return a human-readable identifier for the resource owner that authorized the token
+ */
+ default String getUsername() {
+ return this.getClaimAsString(OAuth2IntrospectionClaimNames.USERNAME);
+ }
+
+ /**
+ * Returns the type of the token {@code (token_type)}, for example {@code bearer}.
+ *
+ * @return the type of the token, for example {@code bearer}.
+ */
+ default String getTokenType() {
+ return this.getClaimAsString(OAuth2IntrospectionClaimNames.TOKEN_TYPE);
+ }
+
+ /**
+ * Returns a timestamp {@code (exp)} indicating when the token expires
+ *
+ * @return a timestamp indicating when the token expires
+ */
+ default Instant getExpiresAt() {
+ return this.getClaimAsInstant(OAuth2IntrospectionClaimNames.EXPIRES_AT);
+ }
+
+ /**
+ * Returns a timestamp {@code (iat)} indicating when the token was issued
+ *
+ * @return a timestamp indicating when the token was issued
+ */
+ default Instant getIssuedAt() {
+ return this.getClaimAsInstant(OAuth2IntrospectionClaimNames.ISSUED_AT);
+ }
+
+ /**
+ * Returns a timestamp {@code (nbf)} indicating when the token is not to be used before
+ *
+ * @return a timestamp indicating when the token is not to be used before
+ */
+ default Instant getNotBefore() {
+ return this.getClaimAsInstant(OAuth2IntrospectionClaimNames.NOT_BEFORE);
+ }
+
+ /**
+ * Returns usually a machine-readable identifier {@code (sub)} of the resource owner who authorized the token
+ *
+ * @return usually a machine-readable identifier of the resource owner who authorized the token
+ */
+ default String getSubject() {
+ return this.getClaimAsString(OAuth2IntrospectionClaimNames.SUBJECT);
+ }
+
+ /**
+ * Returns the intended audience {@code (aud)} for the token
+ *
+ * @return the intended audience for the token
+ */
+ default List getAudience() {
+ return this.getClaimAsStringList(OAuth2IntrospectionClaimNames.AUDIENCE);
+ }
+
+ /**
+ * Returns the issuer {@code (iss)} of the token
+ *
+ * @return the issuer of the token
+ */
+ default URL getIssuer() {
+ return this.getClaimAsURL(OAuth2IntrospectionClaimNames.ISSUER);
+ }
+
+ /**
+ * Returns the identifier {@code (jti)} for the token
+ *
+ * @return the identifier for the token
+ */
+ default String getId() {
+ return this.getClaimAsString(OAuth2IntrospectionClaimNames.JTI);
+ }
+}
diff --git a/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/core/TestOAuth2AuthenticatedPrincipals.java b/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/core/TestOAuth2AuthenticatedPrincipals.java
index c1b593d800..92c9437a34 100644
--- a/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/core/TestOAuth2AuthenticatedPrincipals.java
+++ b/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/core/TestOAuth2AuthenticatedPrincipals.java
@@ -28,6 +28,7 @@ import java.util.function.Consumer;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
+import org.springframework.security.oauth2.server.resource.introspection.OAuth2IntrospectionAuthenticatedPrincipal;
import org.springframework.security.oauth2.server.resource.introspection.OAuth2IntrospectionClaimNames;
/**
@@ -56,7 +57,7 @@ public class TestOAuth2AuthenticatedPrincipals {
Collection authorities =
Arrays.asList(new SimpleGrantedAuthority("SCOPE_read"),
new SimpleGrantedAuthority("SCOPE_write"), new SimpleGrantedAuthority("SCOPE_dolphin"));
- return new DefaultOAuth2AuthenticatedPrincipal(attributes, authorities);
+ return new OAuth2IntrospectionAuthenticatedPrincipal(attributes, authorities);
}
private static URL url(String url) {
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 c91fbd8903..61496ff77d 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
@@ -25,9 +25,9 @@ import org.junit.Test;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.core.Authentication;
-import org.springframework.security.oauth2.core.DefaultOAuth2AuthenticatedPrincipal;
import org.springframework.security.oauth2.core.OAuth2AuthenticatedPrincipal;
import org.springframework.security.oauth2.server.resource.BearerTokenAuthenticationToken;
+import org.springframework.security.oauth2.server.resource.introspection.OAuth2IntrospectionAuthenticatedPrincipal;
import org.springframework.security.oauth2.server.resource.introspection.OAuth2IntrospectionClaimNames;
import org.springframework.security.oauth2.server.resource.introspection.OAuth2IntrospectionException;
import org.springframework.security.oauth2.server.resource.introspection.OpaqueTokenIntrospector;
@@ -63,9 +63,9 @@ public class OpaqueTokenAuthenticationProviderTests {
Authentication result =
provider.authenticate(new BearerTokenAuthenticationToken("token"));
- assertThat(result.getPrincipal()).isInstanceOf(DefaultOAuth2AuthenticatedPrincipal.class);
+ assertThat(result.getPrincipal()).isInstanceOf(OAuth2IntrospectionAuthenticatedPrincipal.class);
- Map attributes = ((DefaultOAuth2AuthenticatedPrincipal) result.getPrincipal()).getAttributes();
+ Map attributes = ((OAuth2AuthenticatedPrincipal) result.getPrincipal()).getAttributes();
assertThat(attributes)
.isNotNull()
.containsEntry(ACTIVE, true)
@@ -85,7 +85,7 @@ public class OpaqueTokenAuthenticationProviderTests {
@Test
public void authenticateWhenMissingScopeAttributeThenNoAuthorities() {
- OAuth2AuthenticatedPrincipal principal = new DefaultOAuth2AuthenticatedPrincipal(Collections.singletonMap("claim", "value"), null);
+ OAuth2AuthenticatedPrincipal principal = new OAuth2IntrospectionAuthenticatedPrincipal(Collections.singletonMap("claim", "value"), null);
OpaqueTokenIntrospector introspector = mock(OpaqueTokenIntrospector.class);
when(introspector.introspect(any())).thenReturn(principal);
OpaqueTokenAuthenticationProvider provider = new OpaqueTokenAuthenticationProvider(introspector);
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 03411ede4e..e7b92f8a45 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
@@ -27,9 +27,9 @@ import reactor.core.publisher.Mono;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.core.Authentication;
-import org.springframework.security.oauth2.core.DefaultOAuth2AuthenticatedPrincipal;
import org.springframework.security.oauth2.core.OAuth2AuthenticatedPrincipal;
import org.springframework.security.oauth2.server.resource.BearerTokenAuthenticationToken;
+import org.springframework.security.oauth2.server.resource.introspection.OAuth2IntrospectionAuthenticatedPrincipal;
import org.springframework.security.oauth2.server.resource.introspection.OAuth2IntrospectionClaimNames;
import org.springframework.security.oauth2.server.resource.introspection.OAuth2IntrospectionException;
import org.springframework.security.oauth2.server.resource.introspection.ReactiveOpaqueTokenIntrospector;
@@ -66,9 +66,9 @@ public class OpaqueTokenReactiveAuthenticationManagerTests {
Authentication result =
provider.authenticate(new BearerTokenAuthenticationToken("token")).block();
- assertThat(result.getPrincipal()).isInstanceOf(DefaultOAuth2AuthenticatedPrincipal.class);
+ assertThat(result.getPrincipal()).isInstanceOf(OAuth2IntrospectionAuthenticatedPrincipal.class);
- Map attributes = ((DefaultOAuth2AuthenticatedPrincipal) result.getPrincipal()).getAttributes();
+ Map attributes = ((OAuth2AuthenticatedPrincipal) result.getPrincipal()).getAttributes();
assertThat(attributes)
.isNotNull()
.containsEntry(ACTIVE, true)
@@ -88,7 +88,7 @@ public class OpaqueTokenReactiveAuthenticationManagerTests {
@Test
public void authenticateWhenMissingScopeAttributeThenNoAuthorities() {
- OAuth2AuthenticatedPrincipal authority = new DefaultOAuth2AuthenticatedPrincipal(Collections.singletonMap("claim", "value"), null);
+ OAuth2AuthenticatedPrincipal authority = new OAuth2IntrospectionAuthenticatedPrincipal(Collections.singletonMap("claim", "value"), null);
ReactiveOpaqueTokenIntrospector introspector = mock(ReactiveOpaqueTokenIntrospector.class);
when(introspector.introspect(any())).thenReturn(Mono.just(authority));
OpaqueTokenReactiveAuthenticationManager provider =
@@ -96,9 +96,9 @@ public class OpaqueTokenReactiveAuthenticationManagerTests {
Authentication result =
provider.authenticate(new BearerTokenAuthenticationToken("token")).block();
- assertThat(result.getPrincipal()).isInstanceOf(DefaultOAuth2AuthenticatedPrincipal.class);
+ assertThat(result.getPrincipal()).isInstanceOf(OAuth2IntrospectionAuthenticatedPrincipal.class);
- Map attributes = ((DefaultOAuth2AuthenticatedPrincipal) result.getPrincipal()).getAttributes();
+ Map attributes = ((OAuth2AuthenticatedPrincipal) result.getPrincipal()).getAttributes();
assertThat(attributes)
.isNotNull()
.doesNotContainKey(SCOPE);
diff --git a/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/introspection/OAuth2IntrospectionAuthenticatedPrincipalTests.java b/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/introspection/OAuth2IntrospectionAuthenticatedPrincipalTests.java
new file mode 100644
index 0000000000..83b6f318f4
--- /dev/null
+++ b/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/introspection/OAuth2IntrospectionAuthenticatedPrincipalTests.java
@@ -0,0 +1,184 @@
+/*
+ * Copyright 2002-2020 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.oauth2.server.resource.introspection;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatCode;
+
+import java.time.Instant;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.junit.Test;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.authority.AuthorityUtils;
+import org.springframework.security.oauth2.core.OAuth2AuthenticatedPrincipal;
+
+/**
+ * Tests for {@link OAuth2IntrospectionAuthenticatedPrincipal}
+ *
+ * @author David Kovac
+ */
+public class OAuth2IntrospectionAuthenticatedPrincipalTests {
+ private static final String AUTHORITY = "SCOPE_read";
+ private static final Collection AUTHORITIES = AuthorityUtils.createAuthorityList(AUTHORITY);
+
+ private static final String SUBJECT = "test-subject";
+
+ private static final String ACTIVE_CLAIM = "active";
+ private static final String CLIENT_ID_CLAIM = "client_id";
+ private static final String USERNAME_CLAIM = "username";
+ private static final String TOKEN_TYPE_CLAIM = "token_type";
+ private static final String EXP_CLAIM = "exp";
+ private static final String IAT_CLAIM = "iat";
+ private static final String NBF_CLAIM = "nbf";
+ private static final String SUB_CLAIM = "sub";
+ private static final String AUD_CLAIM = "aud";
+ private static final String ISS_CLAIM = "iss";
+ private static final String JTI_CLAIM = "jti";
+
+ private static final boolean ACTIVE_VALUE = true;
+ private static final String CLIENT_ID_VALUE = "client-id-1";
+ private static final String USERNAME_VALUE = "username-1";
+ private static final String TOKEN_TYPE_VALUE = "token-type-1";
+ private static final long EXP_VALUE = Instant.now().plusSeconds(60).getEpochSecond();
+ private static final long IAT_VALUE = Instant.now().getEpochSecond();
+ private static final long NBF_VALUE = Instant.now().plusSeconds(5).getEpochSecond();
+ private static final String SUB_VALUE = "subject1";
+ private static final List AUD_VALUE = Arrays.asList("aud1", "aud2");
+ private static final String ISS_VALUE = "https://provider.com";
+ private static final String JTI_VALUE = "jwt-id-1";
+
+ private static final Map CLAIMS;
+
+ static {
+ CLAIMS = new HashMap<>();
+ CLAIMS.put(ACTIVE_CLAIM, ACTIVE_VALUE);
+ CLAIMS.put(CLIENT_ID_CLAIM, CLIENT_ID_VALUE);
+ CLAIMS.put(USERNAME_CLAIM, USERNAME_VALUE);
+ CLAIMS.put(TOKEN_TYPE_CLAIM, TOKEN_TYPE_VALUE);
+ CLAIMS.put(EXP_CLAIM, EXP_VALUE);
+ CLAIMS.put(IAT_CLAIM, IAT_VALUE);
+ CLAIMS.put(NBF_CLAIM, NBF_VALUE);
+ CLAIMS.put(SUB_CLAIM, SUB_VALUE);
+ CLAIMS.put(AUD_CLAIM, AUD_VALUE);
+ CLAIMS.put(ISS_CLAIM, ISS_VALUE);
+ CLAIMS.put(JTI_CLAIM, JTI_VALUE);
+ }
+
+ @Test
+ public void constructorWhenAttributesIsNullOrEmptyThenIllegalArgumentException() {
+ assertThatCode(() -> new OAuth2IntrospectionAuthenticatedPrincipal(null, AUTHORITIES))
+ .isInstanceOf(IllegalArgumentException.class);
+
+ assertThatCode(() -> new OAuth2IntrospectionAuthenticatedPrincipal(Collections.emptyMap(), AUTHORITIES))
+ .isInstanceOf(IllegalArgumentException.class);
+ }
+
+ @Test
+ public void constructorWhenAuthoritiesIsNullOrEmptyThenNoAuthorities() {
+ Collection extends GrantedAuthority> authorities =
+ new OAuth2IntrospectionAuthenticatedPrincipal(CLAIMS, null).getAuthorities();
+ assertThat(authorities).isEmpty();
+
+ authorities = new OAuth2IntrospectionAuthenticatedPrincipal(CLAIMS,
+ Collections.emptyList()).getAuthorities();
+ assertThat(authorities).isEmpty();
+ }
+
+ @Test
+ public void constructorWhenNameIsNullThenFallsbackToSubAttribute() {
+ OAuth2AuthenticatedPrincipal principal =
+ new OAuth2IntrospectionAuthenticatedPrincipal(null, CLAIMS, AUTHORITIES);
+ assertThat(principal.getName()).isEqualTo(CLAIMS.get(SUB_CLAIM));
+ }
+
+ @Test
+ public void constructorWhenAttributesAuthoritiesProvidedThenCreated() {
+ OAuth2IntrospectionAuthenticatedPrincipal principal =
+ new OAuth2IntrospectionAuthenticatedPrincipal(CLAIMS, AUTHORITIES);
+
+ assertThat(principal.getName()).isEqualTo(CLAIMS.get(SUB_CLAIM));
+ assertThat(principal.getAttributes()).isEqualTo(CLAIMS);
+ assertThat(principal.getClaims()).isEqualTo(CLAIMS);
+ assertThat(principal.isActive()).isEqualTo(ACTIVE_VALUE);
+ assertThat(principal.getClientId()).isEqualTo(CLIENT_ID_VALUE);
+ assertThat(principal.getUsername()).isEqualTo(USERNAME_VALUE);
+ assertThat(principal.getTokenType()).isEqualTo(TOKEN_TYPE_VALUE);
+ assertThat(principal.getExpiresAt().getEpochSecond()).isEqualTo(EXP_VALUE);
+ assertThat(principal.getIssuedAt().getEpochSecond()).isEqualTo(IAT_VALUE);
+ assertThat(principal.getNotBefore().getEpochSecond()).isEqualTo(NBF_VALUE);
+ assertThat(principal.getSubject()).isEqualTo(SUB_VALUE);
+ assertThat(principal.getAudience()).isEqualTo(AUD_VALUE);
+ assertThat(principal.getIssuer().toString()).isEqualTo(ISS_VALUE);
+ assertThat(principal.getId()).isEqualTo(JTI_VALUE);
+ assertThat(principal.getAuthorities()).hasSize(1);
+ assertThat(principal.getAuthorities().iterator().next().getAuthority()).isEqualTo(AUTHORITY);
+ }
+
+ @Test
+ public void constructorWhenAllParametersProvidedAndValidThenCreated() {
+ OAuth2IntrospectionAuthenticatedPrincipal principal =
+ new OAuth2IntrospectionAuthenticatedPrincipal(SUBJECT, CLAIMS, AUTHORITIES);
+
+ assertThat(principal.getName()).isEqualTo(SUBJECT);
+ assertThat(principal.getAttributes()).isEqualTo(CLAIMS);
+ assertThat(principal.getClaims()).isEqualTo(CLAIMS);
+ assertThat(principal.isActive()).isEqualTo(ACTIVE_VALUE);
+ assertThat(principal.getClientId()).isEqualTo(CLIENT_ID_VALUE);
+ assertThat(principal.getUsername()).isEqualTo(USERNAME_VALUE);
+ assertThat(principal.getTokenType()).isEqualTo(TOKEN_TYPE_VALUE);
+ assertThat(principal.getExpiresAt().getEpochSecond()).isEqualTo(EXP_VALUE);
+ assertThat(principal.getIssuedAt().getEpochSecond()).isEqualTo(IAT_VALUE);
+ assertThat(principal.getNotBefore().getEpochSecond()).isEqualTo(NBF_VALUE);
+ assertThat(principal.getSubject()).isEqualTo(SUB_VALUE);
+ assertThat(principal.getAudience()).isEqualTo(AUD_VALUE);
+ assertThat(principal.getIssuer().toString()).isEqualTo(ISS_VALUE);
+ assertThat(principal.getId()).isEqualTo(JTI_VALUE);
+ assertThat(principal.getAuthorities()).hasSize(1);
+ assertThat(principal.getAuthorities().iterator().next().getAuthority()).isEqualTo(AUTHORITY);
+ }
+
+ @Test
+ public void getNameWhenInConstructorThenReturns() {
+ OAuth2AuthenticatedPrincipal principal =
+ new OAuth2IntrospectionAuthenticatedPrincipal(SUB_VALUE, CLAIMS, AUTHORITIES);
+ assertThat(principal.getName()).isEqualTo(SUB_VALUE);
+ }
+
+ @Test
+ public void getAttributeWhenGivenKeyThenReturnsValue() {
+ OAuth2AuthenticatedPrincipal principal =
+ new OAuth2IntrospectionAuthenticatedPrincipal(CLAIMS, AUTHORITIES);
+
+ assertThat((Object) principal.getAttribute(ACTIVE_CLAIM)).isEqualTo(ACTIVE_VALUE);
+ assertThat((Object) principal.getAttribute(CLIENT_ID_CLAIM)).isEqualTo(CLIENT_ID_VALUE);
+ assertThat((Object) principal.getAttribute(USERNAME_CLAIM)).isEqualTo(USERNAME_VALUE);
+ assertThat((Object) principal.getAttribute(TOKEN_TYPE_CLAIM)).isEqualTo(TOKEN_TYPE_VALUE);
+ assertThat((Object) principal.getAttribute(EXP_CLAIM)).isEqualTo(EXP_VALUE);
+ assertThat((Object) principal.getAttribute(IAT_CLAIM)).isEqualTo(IAT_VALUE);
+ assertThat((Object) principal.getAttribute(NBF_CLAIM)).isEqualTo(NBF_VALUE);
+ assertThat((Object) principal.getAttribute(SUB_CLAIM)).isEqualTo(SUB_VALUE);
+ assertThat((Object) principal.getAttribute(AUD_CLAIM)).isEqualTo(AUD_VALUE);
+ assertThat((Object) principal.getAttribute(ISS_CLAIM)).isEqualTo(ISS_VALUE);
+ assertThat((Object) principal.getAttribute(JTI_CLAIM)).isEqualTo(JTI_VALUE);
+ }
+}
diff --git a/test/src/main/java/org/springframework/security/test/web/reactive/server/SecurityMockServerConfigurers.java b/test/src/main/java/org/springframework/security/test/web/reactive/server/SecurityMockServerConfigurers.java
index a144b42c1d..997f41eb23 100644
--- a/test/src/main/java/org/springframework/security/test/web/reactive/server/SecurityMockServerConfigurers.java
+++ b/test/src/main/java/org/springframework/security/test/web/reactive/server/SecurityMockServerConfigurers.java
@@ -55,7 +55,6 @@ import org.springframework.security.oauth2.client.web.reactive.result.method.ann
import org.springframework.security.oauth2.client.web.server.ServerOAuth2AuthorizedClientRepository;
import org.springframework.security.oauth2.client.web.server.WebSessionServerOAuth2AuthorizedClientRepository;
import org.springframework.security.oauth2.core.AuthorizationGrantType;
-import org.springframework.security.oauth2.core.DefaultOAuth2AuthenticatedPrincipal;
import org.springframework.security.oauth2.core.OAuth2AccessToken;
import org.springframework.security.oauth2.core.OAuth2AuthenticatedPrincipal;
import org.springframework.security.oauth2.core.oidc.IdTokenClaimNames;
@@ -71,6 +70,7 @@ import org.springframework.security.oauth2.jwt.Jwt;
import org.springframework.security.oauth2.server.resource.authentication.BearerTokenAuthentication;
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken;
import org.springframework.security.oauth2.server.resource.authentication.JwtGrantedAuthoritiesConverter;
+import org.springframework.security.oauth2.server.resource.introspection.OAuth2IntrospectionAuthenticatedPrincipal;
import org.springframework.security.oauth2.server.resource.introspection.OAuth2IntrospectionClaimNames;
import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors;
import org.springframework.security.web.server.csrf.CsrfWebFilter;
@@ -666,7 +666,7 @@ public class SecurityMockServerConfigurers {
}
private OAuth2AuthenticatedPrincipal defaultPrincipal() {
- return new DefaultOAuth2AuthenticatedPrincipal
+ return new OAuth2IntrospectionAuthenticatedPrincipal
(this.attributes.get(), this.authorities.get());
}
diff --git a/test/src/main/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestPostProcessors.java b/test/src/main/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestPostProcessors.java
index 92450c408d..866396e754 100644
--- a/test/src/main/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestPostProcessors.java
+++ b/test/src/main/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestPostProcessors.java
@@ -66,7 +66,6 @@ import org.springframework.security.oauth2.client.web.HttpSessionOAuth2Authorize
import org.springframework.security.oauth2.client.web.OAuth2AuthorizedClientRepository;
import org.springframework.security.oauth2.client.web.method.annotation.OAuth2AuthorizedClientArgumentResolver;
import org.springframework.security.oauth2.core.AuthorizationGrantType;
-import org.springframework.security.oauth2.core.DefaultOAuth2AuthenticatedPrincipal;
import org.springframework.security.oauth2.core.OAuth2AccessToken;
import org.springframework.security.oauth2.core.OAuth2AuthenticatedPrincipal;
import org.springframework.security.oauth2.core.oidc.IdTokenClaimNames;
@@ -82,6 +81,7 @@ import org.springframework.security.oauth2.jwt.Jwt;
import org.springframework.security.oauth2.server.resource.authentication.BearerTokenAuthentication;
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken;
import org.springframework.security.oauth2.server.resource.authentication.JwtGrantedAuthoritiesConverter;
+import org.springframework.security.oauth2.server.resource.introspection.OAuth2IntrospectionAuthenticatedPrincipal;
import org.springframework.security.oauth2.server.resource.introspection.OAuth2IntrospectionClaimNames;
import org.springframework.security.test.context.TestSecurityContextHolder;
import org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers;
@@ -1283,7 +1283,7 @@ public final class SecurityMockMvcRequestPostProcessors {
}
private OAuth2AuthenticatedPrincipal defaultPrincipal() {
- return new DefaultOAuth2AuthenticatedPrincipal
+ return new OAuth2IntrospectionAuthenticatedPrincipal
(this.attributes.get(), this.authorities.get());
}