Polish Opaque Token
Use OAuth2AuthenticatedPrincipal Use BearerTokenAuthentication Update names to reflect more generic approach. Fixes gh-7344 Fixes gh-7345
This commit is contained in:
parent
c019507770
commit
068f4f0147
|
@ -37,7 +37,7 @@ import org.springframework.security.oauth2.jwt.JwtDecoder;
|
|||
import org.springframework.security.oauth2.jwt.NimbusJwtDecoder;
|
||||
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationConverter;
|
||||
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationProvider;
|
||||
import org.springframework.security.oauth2.server.resource.authentication.OAuth2IntrospectionAuthenticationProvider;
|
||||
import org.springframework.security.oauth2.server.resource.authentication.OpaqueTokenAuthenticationProvider;
|
||||
import org.springframework.security.oauth2.server.resource.introspection.NimbusOpaqueTokenIntrospector;
|
||||
import org.springframework.security.oauth2.server.resource.introspection.OpaqueTokenIntrospector;
|
||||
import org.springframework.security.oauth2.server.resource.web.BearerTokenAuthenticationEntryPoint;
|
||||
|
@ -388,8 +388,8 @@ public final class OAuth2ResourceServerConfigurer<H extends HttpSecurityBuilder<
|
|||
}
|
||||
|
||||
OpaqueTokenIntrospector introspector = getIntrospector();
|
||||
OAuth2IntrospectionAuthenticationProvider provider =
|
||||
new OAuth2IntrospectionAuthenticationProvider(introspector);
|
||||
OpaqueTokenAuthenticationProvider provider =
|
||||
new OpaqueTokenAuthenticationProvider(introspector);
|
||||
http.authenticationProvider(provider);
|
||||
|
||||
return http.getSharedObject(AuthenticationManager.class);
|
||||
|
|
|
@ -87,7 +87,7 @@ import org.springframework.security.oauth2.jwt.ReactiveJwtDecoder;
|
|||
import org.springframework.security.oauth2.jwt.ReactiveJwtDecoderFactory;
|
||||
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationConverter;
|
||||
import org.springframework.security.oauth2.server.resource.authentication.JwtReactiveAuthenticationManager;
|
||||
import org.springframework.security.oauth2.server.resource.authentication.OAuth2IntrospectionReactiveAuthenticationManager;
|
||||
import org.springframework.security.oauth2.server.resource.authentication.OpaqueTokenReactiveAuthenticationManager;
|
||||
import org.springframework.security.oauth2.server.resource.authentication.ReactiveJwtAuthenticationConverterAdapter;
|
||||
import org.springframework.security.oauth2.server.resource.introspection.NimbusReactiveOpaqueTokenIntrospector;
|
||||
import org.springframework.security.oauth2.server.resource.introspection.ReactiveOpaqueTokenIntrospector;
|
||||
|
@ -1867,7 +1867,7 @@ public class ServerHttpSecurity {
|
|||
}
|
||||
|
||||
protected ReactiveAuthenticationManager getAuthenticationManager() {
|
||||
return new OAuth2IntrospectionReactiveAuthenticationManager(getIntrospector());
|
||||
return new OpaqueTokenReactiveAuthenticationManager(getIntrospector());
|
||||
}
|
||||
|
||||
protected ReactiveOpaqueTokenIntrospector getIntrospector() {
|
||||
|
|
|
@ -78,8 +78,8 @@ import org.springframework.security.core.GrantedAuthority;
|
|||
import org.springframework.security.core.annotation.AuthenticationPrincipal;
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.oauth2.core.DefaultOAuth2AuthenticatedPrincipal;
|
||||
import org.springframework.security.oauth2.core.OAuth2Error;
|
||||
import org.springframework.security.oauth2.core.OAuth2TokenAttributes;
|
||||
import org.springframework.security.oauth2.core.OAuth2TokenValidator;
|
||||
import org.springframework.security.oauth2.core.OAuth2TokenValidatorResult;
|
||||
import org.springframework.security.oauth2.jose.jws.JwsAlgorithms;
|
||||
|
@ -91,7 +91,7 @@ import org.springframework.security.oauth2.jwt.JwtTimestampValidator;
|
|||
import org.springframework.security.oauth2.jwt.NimbusJwtDecoder;
|
||||
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationConverter;
|
||||
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken;
|
||||
import org.springframework.security.oauth2.server.resource.authentication.OAuth2IntrospectionAuthenticationToken;
|
||||
import org.springframework.security.oauth2.server.resource.authentication.BearerTokenAuthentication;
|
||||
import org.springframework.security.oauth2.server.resource.introspection.NimbusOpaqueTokenIntrospector;
|
||||
import org.springframework.security.oauth2.server.resource.introspection.OpaqueTokenIntrospector;
|
||||
import org.springframework.security.oauth2.server.resource.web.BearerTokenAuthenticationEntryPoint;
|
||||
|
@ -159,8 +159,9 @@ public class OAuth2ResourceServerConfigurerTests {
|
|||
private static final String INTROSPECTION_URI = "https://idp.example.com";
|
||||
private static final String CLIENT_ID = "client-id";
|
||||
private static final String CLIENT_SECRET = "client-secret";
|
||||
private static final OAuth2IntrospectionAuthenticationToken INTROSPECTION_AUTHENTICATION_TOKEN =
|
||||
new OAuth2IntrospectionAuthenticationToken(noScopes(), new OAuth2TokenAttributes(JWT_CLAIMS), Collections.emptyList());
|
||||
private static final BearerTokenAuthentication INTROSPECTION_AUTHENTICATION_TOKEN =
|
||||
new BearerTokenAuthentication(new DefaultOAuth2AuthenticatedPrincipal(JWT_CLAIMS, Collections.emptyList()),
|
||||
noScopes(), Collections.emptyList());
|
||||
|
||||
@Autowired(required = false)
|
||||
MockMvc mvc;
|
||||
|
|
|
@ -1,58 +0,0 @@
|
|||
/*
|
||||
* Copyright 2002-2019 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.core;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* A domain object that wraps the attributes of an OAuth 2.0 token.
|
||||
*
|
||||
* @author Clement Ng
|
||||
* @since 5.2
|
||||
*/
|
||||
public final class OAuth2TokenAttributes {
|
||||
private final Map<String, Object> attributes;
|
||||
|
||||
/**
|
||||
* Constructs an {@code OAuth2TokenAttributes} using the provided parameters.
|
||||
*
|
||||
* @param attributes the attributes of the OAuth 2.0 token
|
||||
*/
|
||||
public OAuth2TokenAttributes(Map<String, Object> attributes) {
|
||||
this.attributes = Collections.unmodifiableMap(attributes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the attributes of the OAuth 2.0 token in map form.
|
||||
*
|
||||
* @return a {@link Map} of the attribute's objects keyed by the attribute's names
|
||||
*/
|
||||
public Map<String, Object> getAttributes() {
|
||||
return attributes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the attribute of the OAuth 2.0 token corresponding to the name.
|
||||
*
|
||||
* @param name the name to lookup in the attributes
|
||||
* @return the object corresponding to the name in the attributes
|
||||
*/
|
||||
public <A> A getAttribute(String name) {
|
||||
return (A) this.attributes.get(name);
|
||||
}
|
||||
}
|
|
@ -1,100 +0,0 @@
|
|||
/*
|
||||
* Copyright 2002-2019 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.authentication;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.SpringSecurityCoreVersion;
|
||||
import org.springframework.security.core.Transient;
|
||||
import org.springframework.security.oauth2.core.OAuth2AccessToken;
|
||||
import org.springframework.security.oauth2.core.OAuth2TokenAttributes;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import static org.springframework.security.oauth2.server.resource.introspection.OAuth2IntrospectionClaimNames.SUBJECT;
|
||||
|
||||
/**
|
||||
* An {@link org.springframework.security.core.Authentication} token that represents a successful authentication as
|
||||
* obtained through an opaque token
|
||||
* <a target="_blank" href="https://tools.ietf.org/html/rfc7662">introspection</a>
|
||||
* process.
|
||||
*
|
||||
* @author Josh Cummings
|
||||
* @since 5.2
|
||||
*/
|
||||
@Transient
|
||||
public class OAuth2IntrospectionAuthenticationToken
|
||||
extends AbstractOAuth2TokenAuthenticationToken<OAuth2AccessToken> {
|
||||
|
||||
private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID;
|
||||
|
||||
private Map<String, Object> attributes;
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* Constructs a {@link OAuth2IntrospectionAuthenticationToken} with the provided arguments
|
||||
*
|
||||
* @param token The verified token
|
||||
* @param authorities The authorities associated with the given token
|
||||
*/
|
||||
public OAuth2IntrospectionAuthenticationToken(OAuth2AccessToken token,
|
||||
OAuth2TokenAttributes attributes, Collection<? extends GrantedAuthority> authorities) {
|
||||
|
||||
this(token, attributes, authorities, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a {@link OAuth2IntrospectionAuthenticationToken} with the provided arguments
|
||||
*
|
||||
* @param token The verified token
|
||||
* @param authorities The authorities associated with the given token
|
||||
* @param name The name associated with this token
|
||||
*/
|
||||
public OAuth2IntrospectionAuthenticationToken(OAuth2AccessToken token, OAuth2TokenAttributes attributes,
|
||||
Collection<? extends GrantedAuthority> authorities, String name) {
|
||||
|
||||
super(token, attributes, token, authorities);
|
||||
this.attributes = attributes(attributes);
|
||||
this.name = name == null ? (String) this.attributes.get(SUBJECT) : name;
|
||||
setAuthenticated(true);
|
||||
}
|
||||
|
||||
private static Map<String, Object> attributes(OAuth2TokenAttributes attributes) {
|
||||
Assert.notNull(attributes, "attributes cannot be empty");
|
||||
Map<String, Object> attr = attributes.getAttributes();
|
||||
Assert.notEmpty(attr, "attributes cannot be empty");
|
||||
return Collections.unmodifiableMap(new LinkedHashMap<>(attr));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public Map<String, Object> getTokenAttributes() {
|
||||
return this.attributes;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
}
|
|
@ -16,11 +16,7 @@
|
|||
package org.springframework.security.oauth2.server.resource.authentication;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.security.authentication.AbstractAuthenticationToken;
|
||||
|
@ -28,20 +24,18 @@ import org.springframework.security.authentication.AuthenticationProvider;
|
|||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
import org.springframework.security.oauth2.core.OAuth2AccessToken;
|
||||
import org.springframework.security.oauth2.core.OAuth2AuthenticatedPrincipal;
|
||||
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
|
||||
import org.springframework.security.oauth2.core.OAuth2Error;
|
||||
import org.springframework.security.oauth2.core.OAuth2TokenAttributes;
|
||||
import org.springframework.security.oauth2.server.resource.introspection.OAuth2IntrospectionException;
|
||||
import org.springframework.security.oauth2.server.resource.introspection.OpaqueTokenIntrospector;
|
||||
import org.springframework.security.oauth2.server.resource.BearerTokenAuthenticationToken;
|
||||
import org.springframework.security.oauth2.server.resource.BearerTokenError;
|
||||
import org.springframework.security.oauth2.server.resource.introspection.OAuth2IntrospectionException;
|
||||
import org.springframework.security.oauth2.server.resource.introspection.OpaqueTokenIntrospector;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import static org.springframework.security.oauth2.server.resource.introspection.OAuth2IntrospectionClaimNames.EXPIRES_AT;
|
||||
import static org.springframework.security.oauth2.server.resource.introspection.OAuth2IntrospectionClaimNames.ISSUED_AT;
|
||||
import static org.springframework.security.oauth2.server.resource.introspection.OAuth2IntrospectionClaimNames.SCOPE;
|
||||
|
||||
/**
|
||||
* An {@link AuthenticationProvider} implementation for opaque
|
||||
|
@ -65,20 +59,20 @@ import static org.springframework.security.oauth2.server.resource.introspection.
|
|||
* @since 5.2
|
||||
* @see AuthenticationProvider
|
||||
*/
|
||||
public final class OAuth2IntrospectionAuthenticationProvider implements AuthenticationProvider {
|
||||
public final class OpaqueTokenAuthenticationProvider implements AuthenticationProvider {
|
||||
private static final BearerTokenError DEFAULT_INVALID_TOKEN =
|
||||
invalidToken("An error occurred while attempting to introspect the token: Invalid token");
|
||||
|
||||
private OpaqueTokenIntrospector introspectionClient;
|
||||
private OpaqueTokenIntrospector introspector;
|
||||
|
||||
/**
|
||||
* Creates a {@code OAuth2IntrospectionAuthenticationProvider} with the provided parameters
|
||||
* Creates a {@code OpaqueTokenAuthenticationProvider} with the provided parameters
|
||||
*
|
||||
* @param introspectionClient The {@link OpaqueTokenIntrospector} to use
|
||||
* @param introspector The {@link OpaqueTokenIntrospector} to use
|
||||
*/
|
||||
public OAuth2IntrospectionAuthenticationProvider(OpaqueTokenIntrospector introspectionClient) {
|
||||
Assert.notNull(introspectionClient, "introspectionClient cannot be null");
|
||||
this.introspectionClient = introspectionClient;
|
||||
public OpaqueTokenAuthenticationProvider(OpaqueTokenIntrospector introspector) {
|
||||
Assert.notNull(introspector, "introspector cannot be null");
|
||||
this.introspector = introspector;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -97,15 +91,15 @@ public final class OAuth2IntrospectionAuthenticationProvider implements Authenti
|
|||
}
|
||||
BearerTokenAuthenticationToken bearer = (BearerTokenAuthenticationToken) authentication;
|
||||
|
||||
Map<String, Object> claims;
|
||||
OAuth2AuthenticatedPrincipal principal;
|
||||
try {
|
||||
claims = this.introspectionClient.introspect(bearer.getToken());
|
||||
principal = this.introspector.introspect(bearer.getToken());
|
||||
} catch (OAuth2IntrospectionException failed) {
|
||||
OAuth2Error invalidToken = invalidToken(failed.getMessage());
|
||||
throw new OAuth2AuthenticationException(invalidToken);
|
||||
}
|
||||
|
||||
AbstractAuthenticationToken result = convert(bearer.getToken(), claims);
|
||||
AbstractAuthenticationToken result = convert(principal, bearer.getToken());
|
||||
result.setDetails(bearer.getDetails());
|
||||
return result;
|
||||
}
|
||||
|
@ -118,22 +112,12 @@ public final class OAuth2IntrospectionAuthenticationProvider implements Authenti
|
|||
return BearerTokenAuthenticationToken.class.isAssignableFrom(authentication);
|
||||
}
|
||||
|
||||
private AbstractAuthenticationToken convert(String token, Map<String, Object> claims) {
|
||||
Instant iat = (Instant) claims.get(ISSUED_AT);
|
||||
Instant exp = (Instant) claims.get(EXPIRES_AT);
|
||||
OAuth2AccessToken accessToken = new OAuth2AccessToken(OAuth2AccessToken.TokenType.BEARER,
|
||||
private AbstractAuthenticationToken convert(OAuth2AuthenticatedPrincipal principal, String token) {
|
||||
Instant iat = principal.getAttribute(ISSUED_AT);
|
||||
Instant exp = principal.getAttribute(EXPIRES_AT);
|
||||
OAuth2AccessToken accessToken = new OAuth2AccessToken(OAuth2AccessToken.TokenType.BEARER,
|
||||
token, iat, exp);
|
||||
Collection<GrantedAuthority> authorities = extractAuthorities(claims);
|
||||
return new OAuth2IntrospectionAuthenticationToken(accessToken, new OAuth2TokenAttributes(claims), authorities);
|
||||
}
|
||||
|
||||
private Collection<GrantedAuthority> extractAuthorities(Map<String, Object> claims) {
|
||||
Collection<String> scopes = (Collection<String>) claims.getOrDefault(SCOPE, Collections.emptyList());
|
||||
List<GrantedAuthority> authorities = new ArrayList<>();
|
||||
for (String scope : scopes) {
|
||||
authorities.add(new SimpleGrantedAuthority("SCOPE_" + scope));
|
||||
}
|
||||
return authorities;
|
||||
return new BearerTokenAuthentication(principal, accessToken, principal.getAuthorities());
|
||||
}
|
||||
|
||||
private static BearerTokenError invalidToken(String message) {
|
|
@ -17,32 +17,25 @@
|
|||
package org.springframework.security.oauth2.server.resource.authentication;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.security.oauth2.core.OAuth2TokenAttributes;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.security.authentication.ReactiveAuthenticationManager;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
import org.springframework.security.oauth2.core.OAuth2AccessToken;
|
||||
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
|
||||
import org.springframework.security.oauth2.core.OAuth2Error;
|
||||
import org.springframework.security.oauth2.server.resource.introspection.OAuth2IntrospectionException;
|
||||
import org.springframework.security.oauth2.server.resource.introspection.ReactiveOpaqueTokenIntrospector;
|
||||
import org.springframework.security.oauth2.server.resource.BearerTokenAuthenticationToken;
|
||||
import org.springframework.security.oauth2.server.resource.BearerTokenError;
|
||||
import org.springframework.security.oauth2.server.resource.introspection.OAuth2IntrospectionException;
|
||||
import org.springframework.security.oauth2.server.resource.introspection.ReactiveOpaqueTokenIntrospector;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import static org.springframework.security.oauth2.server.resource.introspection.OAuth2IntrospectionClaimNames.EXPIRES_AT;
|
||||
import static org.springframework.security.oauth2.server.resource.introspection.OAuth2IntrospectionClaimNames.ISSUED_AT;
|
||||
import static org.springframework.security.oauth2.server.resource.introspection.OAuth2IntrospectionClaimNames.SCOPE;
|
||||
|
||||
/**
|
||||
* An {@link ReactiveAuthenticationManager} implementation for opaque
|
||||
|
@ -66,20 +59,20 @@ import static org.springframework.security.oauth2.server.resource.introspection.
|
|||
* @since 5.2
|
||||
* @see ReactiveAuthenticationManager
|
||||
*/
|
||||
public class OAuth2IntrospectionReactiveAuthenticationManager implements ReactiveAuthenticationManager {
|
||||
public class OpaqueTokenReactiveAuthenticationManager implements ReactiveAuthenticationManager {
|
||||
private static final BearerTokenError DEFAULT_INVALID_TOKEN =
|
||||
invalidToken("An error occurred while attempting to introspect the token: Invalid token");
|
||||
|
||||
private ReactiveOpaqueTokenIntrospector introspectionClient;
|
||||
private ReactiveOpaqueTokenIntrospector introspector;
|
||||
|
||||
/**
|
||||
* Creates a {@code OAuth2IntrospectionReactiveAuthenticationManager} with the provided parameters
|
||||
* Creates a {@code OpaqueTokenReactiveAuthenticationManager} with the provided parameters
|
||||
*
|
||||
* @param introspectionClient The {@link ReactiveOpaqueTokenIntrospector} to use
|
||||
* @param introspector The {@link ReactiveOpaqueTokenIntrospector} to use
|
||||
*/
|
||||
public OAuth2IntrospectionReactiveAuthenticationManager(ReactiveOpaqueTokenIntrospector introspectionClient) {
|
||||
Assert.notNull(introspectionClient, "introspectionClient cannot be null");
|
||||
this.introspectionClient = introspectionClient;
|
||||
public OpaqueTokenReactiveAuthenticationManager(ReactiveOpaqueTokenIntrospector introspector) {
|
||||
Assert.notNull(introspector, "introspector cannot be null");
|
||||
this.introspector = introspector;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -92,30 +85,20 @@ public class OAuth2IntrospectionReactiveAuthenticationManager implements Reactiv
|
|||
.cast(Authentication.class);
|
||||
}
|
||||
|
||||
private Mono<OAuth2IntrospectionAuthenticationToken> authenticate(String token) {
|
||||
return this.introspectionClient.introspect(token)
|
||||
.map(claims -> {
|
||||
Instant iat = (Instant) claims.get(ISSUED_AT);
|
||||
Instant exp = (Instant) claims.get(EXPIRES_AT);
|
||||
private Mono<BearerTokenAuthentication> authenticate(String token) {
|
||||
return this.introspector.introspect(token)
|
||||
.map(principal -> {
|
||||
Instant iat = principal.getAttribute(ISSUED_AT);
|
||||
Instant exp = principal.getAttribute(EXPIRES_AT);
|
||||
|
||||
// construct token
|
||||
OAuth2AccessToken accessToken =
|
||||
new OAuth2AccessToken(OAuth2AccessToken.TokenType.BEARER, token, iat, exp);
|
||||
Collection<GrantedAuthority> authorities = extractAuthorities(claims);
|
||||
return new OAuth2IntrospectionAuthenticationToken(accessToken, new OAuth2TokenAttributes(claims), authorities);
|
||||
return new BearerTokenAuthentication(principal, accessToken, principal.getAuthorities());
|
||||
})
|
||||
.onErrorMap(OAuth2IntrospectionException.class, this::onError);
|
||||
}
|
||||
|
||||
private Collection<GrantedAuthority> extractAuthorities(Map<String, Object> claims) {
|
||||
Collection<String> scopes = (Collection<String>) claims.getOrDefault(SCOPE, Collections.emptyList());
|
||||
List<GrantedAuthority> authorities = new ArrayList<>();
|
||||
for (String scope : scopes) {
|
||||
authorities.add(new SimpleGrantedAuthority("SCOPE_" + scope));
|
||||
}
|
||||
return authorities;
|
||||
}
|
||||
|
||||
private static BearerTokenError invalidToken(String message) {
|
||||
try {
|
||||
return new BearerTokenError("invalid_token",
|
|
@ -19,6 +19,8 @@ package org.springframework.security.oauth2.server.resource.introspection;
|
|||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
import java.time.Instant;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
@ -36,6 +38,10 @@ import org.springframework.http.MediaType;
|
|||
import org.springframework.http.RequestEntity;
|
||||
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;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
|
@ -63,8 +69,10 @@ public class NimbusOpaqueTokenIntrospector implements OpaqueTokenIntrospector {
|
|||
private Converter<String, RequestEntity<?>> requestEntityConverter;
|
||||
private RestOperations restOperations;
|
||||
|
||||
private final String authorityPrefix = "SCOPE_";
|
||||
|
||||
/**
|
||||
* Creates a {@code OAuth2IntrospectionAuthenticationProvider} with the provided parameters
|
||||
* Creates a {@code OpaqueTokenAuthenticationProvider} with the provided parameters
|
||||
*
|
||||
* @param introspectionUri The introspection endpoint uri
|
||||
* @param clientId The client id authorized to introspect
|
||||
|
@ -82,7 +90,7 @@ public class NimbusOpaqueTokenIntrospector implements OpaqueTokenIntrospector {
|
|||
}
|
||||
|
||||
/**
|
||||
* Creates a {@code OAuth2IntrospectionAuthenticationProvider} with the provided parameters
|
||||
* Creates a {@code OpaqueTokenAuthenticationProvider} with the provided parameters
|
||||
*
|
||||
* The given {@link RestOperations} should perform its own client authentication against the
|
||||
* introspection endpoint.
|
||||
|
@ -122,7 +130,7 @@ public class NimbusOpaqueTokenIntrospector implements OpaqueTokenIntrospector {
|
|||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public Map<String, Object> introspect(String token) {
|
||||
public OAuth2AuthenticatedPrincipal introspect(String token) {
|
||||
RequestEntity<?> requestEntity = this.requestEntityConverter.convert(token);
|
||||
if (requestEntity == null) {
|
||||
throw new OAuth2IntrospectionException("Provided token [" + token + "] isn't active");
|
||||
|
@ -189,7 +197,8 @@ public class NimbusOpaqueTokenIntrospector implements OpaqueTokenIntrospector {
|
|||
return (TokenIntrospectionSuccessResponse) introspectionResponse;
|
||||
}
|
||||
|
||||
private Map<String, Object> convertClaimsSet(TokenIntrospectionSuccessResponse response) {
|
||||
private OAuth2AuthenticatedPrincipal convertClaimsSet(TokenIntrospectionSuccessResponse response) {
|
||||
Collection<GrantedAuthority> authorities = new ArrayList<>();
|
||||
Map<String, Object> claims = response.toJSONObject();
|
||||
if (response.getAudience() != null) {
|
||||
List<String> audiences = new ArrayList<>();
|
||||
|
@ -216,10 +225,15 @@ public class NimbusOpaqueTokenIntrospector implements OpaqueTokenIntrospector {
|
|||
claims.put(NOT_BEFORE, response.getNotBeforeTime().toInstant());
|
||||
}
|
||||
if (response.getScope() != null) {
|
||||
claims.put(SCOPE, Collections.unmodifiableList(response.getScope().toStringList()));
|
||||
List<String> scopes = Collections.unmodifiableList(response.getScope().toStringList());
|
||||
claims.put(SCOPE, scopes);
|
||||
|
||||
for (String scope : scopes) {
|
||||
authorities.add(new SimpleGrantedAuthority(this.authorityPrefix + scope));
|
||||
}
|
||||
}
|
||||
|
||||
return claims;
|
||||
return new DefaultOAuth2AuthenticatedPrincipal(claims, authorities);
|
||||
}
|
||||
|
||||
private URL issuer(String uri) {
|
||||
|
|
|
@ -19,6 +19,8 @@ package org.springframework.security.oauth2.server.resource.introspection;
|
|||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
import java.time.Instant;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
@ -34,6 +36,10 @@ import reactor.core.publisher.Mono;
|
|||
|
||||
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;
|
||||
import org.springframework.web.reactive.function.client.ClientResponse;
|
||||
|
@ -59,8 +65,10 @@ public class NimbusReactiveOpaqueTokenIntrospector implements ReactiveOpaqueToke
|
|||
private URI introspectionUri;
|
||||
private WebClient webClient;
|
||||
|
||||
private String authorityPrefix = "SCOPE_";
|
||||
|
||||
/**
|
||||
* Creates a {@code OAuth2IntrospectionReactiveAuthenticationManager} with the provided parameters
|
||||
* Creates a {@code OpaqueTokenReactiveAuthenticationManager} with the provided parameters
|
||||
*
|
||||
* @param introspectionUri The introspection endpoint uri
|
||||
* @param clientId The client id authorized to introspect
|
||||
|
@ -78,7 +86,7 @@ public class NimbusReactiveOpaqueTokenIntrospector implements ReactiveOpaqueToke
|
|||
}
|
||||
|
||||
/**
|
||||
* Creates a {@code OAuth2IntrospectionReactiveAuthenticationManager} with the provided parameters
|
||||
* Creates a {@code OpaqueTokenReactiveAuthenticationManager} with the provided parameters
|
||||
*
|
||||
* @param introspectionUri The introspection endpoint uri
|
||||
* @param webClient The client for performing the introspection request
|
||||
|
@ -95,7 +103,7 @@ public class NimbusReactiveOpaqueTokenIntrospector implements ReactiveOpaqueToke
|
|||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public Mono<Map<String, Object>> introspect(String token) {
|
||||
public Mono<OAuth2AuthenticatedPrincipal> introspect(String token) {
|
||||
return Mono.just(token)
|
||||
.flatMap(this::makeRequest)
|
||||
.flatMap(this::adaptToNimbusResponse)
|
||||
|
@ -150,8 +158,9 @@ public class NimbusReactiveOpaqueTokenIntrospector implements ReactiveOpaqueToke
|
|||
}
|
||||
}
|
||||
|
||||
private Map<String, Object> convertClaimsSet(TokenIntrospectionSuccessResponse response) {
|
||||
private OAuth2AuthenticatedPrincipal convertClaimsSet(TokenIntrospectionSuccessResponse response) {
|
||||
Map<String, Object> claims = response.toJSONObject();
|
||||
Collection<GrantedAuthority> authorities = new ArrayList<>();
|
||||
if (response.getAudience() != null) {
|
||||
List<String> audiences = new ArrayList<>();
|
||||
for (Audience audience : response.getAudience()) {
|
||||
|
@ -177,10 +186,15 @@ public class NimbusReactiveOpaqueTokenIntrospector implements ReactiveOpaqueToke
|
|||
claims.put(NOT_BEFORE, response.getNotBeforeTime().toInstant());
|
||||
}
|
||||
if (response.getScope() != null) {
|
||||
claims.put(SCOPE, Collections.unmodifiableList(response.getScope().toStringList()));
|
||||
List<String> scopes = Collections.unmodifiableList(response.getScope().toStringList());
|
||||
claims.put(SCOPE, scopes);
|
||||
|
||||
for (String scope : scopes) {
|
||||
authorities.add(new SimpleGrantedAuthority(this.authorityPrefix + scope));
|
||||
}
|
||||
}
|
||||
|
||||
return claims;
|
||||
return new DefaultOAuth2AuthenticatedPrincipal(claims, authorities);
|
||||
}
|
||||
|
||||
private URL issuer(String uri) {
|
||||
|
|
|
@ -18,6 +18,8 @@ package org.springframework.security.oauth2.server.resource.introspection;
|
|||
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.security.oauth2.core.OAuth2AuthenticatedPrincipal;
|
||||
|
||||
/**
|
||||
* A contract for introspecting and verifying an OAuth 2.0 token.
|
||||
*
|
||||
|
@ -41,5 +43,5 @@ public interface OpaqueTokenIntrospector {
|
|||
* @param token the token to introspect
|
||||
* @return the token's attributes
|
||||
*/
|
||||
Map<String, Object> introspect(String token);
|
||||
OAuth2AuthenticatedPrincipal introspect(String token);
|
||||
}
|
||||
|
|
|
@ -20,6 +20,8 @@ import java.util.Map;
|
|||
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.security.oauth2.core.OAuth2AuthenticatedPrincipal;
|
||||
|
||||
/**
|
||||
* A contract for introspecting and verifying an OAuth 2.0 token.
|
||||
*
|
||||
|
@ -43,5 +45,5 @@ public interface ReactiveOpaqueTokenIntrospector {
|
|||
* @param token the token to introspect
|
||||
* @return the token's attributes
|
||||
*/
|
||||
Mono<Map<String, Object>> introspect(String token);
|
||||
Mono<OAuth2AuthenticatedPrincipal> introspect(String token);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* Copyright 2002-2019 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.core;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.net.URL;
|
||||
import java.time.Instant;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
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.OAuth2IntrospectionClaimNames;
|
||||
|
||||
/**
|
||||
* Test values of {@link OAuth2AuthenticatedPrincipal}s
|
||||
*
|
||||
* @author Josh Cummings
|
||||
*/
|
||||
public class TestOAuth2AuthenticatedPrincipals {
|
||||
public static OAuth2AuthenticatedPrincipal active() {
|
||||
return active(attributes -> {});
|
||||
}
|
||||
|
||||
public static OAuth2AuthenticatedPrincipal active(Consumer<Map<String, Object>> attributesConsumer) {
|
||||
Map<String, Object> attributes = new HashMap<>();
|
||||
attributes.put(OAuth2IntrospectionClaimNames.ACTIVE, true);
|
||||
attributes.put(OAuth2IntrospectionClaimNames.AUDIENCE, Arrays.asList("https://protected.example.net/resource"));
|
||||
attributes.put(OAuth2IntrospectionClaimNames.CLIENT_ID, "l238j323ds-23ij4");
|
||||
attributes.put(OAuth2IntrospectionClaimNames.EXPIRES_AT, Instant.ofEpochSecond(1419356238));
|
||||
attributes.put(OAuth2IntrospectionClaimNames.NOT_BEFORE, Instant.ofEpochSecond(29348723984L));
|
||||
attributes.put(OAuth2IntrospectionClaimNames.ISSUER, url("https://server.example.com/"));
|
||||
attributes.put(OAuth2IntrospectionClaimNames.SCOPE, Arrays.asList("read", "write", "dolphin"));
|
||||
attributes.put(OAuth2IntrospectionClaimNames.SUBJECT, "Z5O3upPC88QrAjx00dis");
|
||||
attributes.put(OAuth2IntrospectionClaimNames.USERNAME, "jdoe");
|
||||
attributesConsumer.accept(attributes);
|
||||
|
||||
Collection<GrantedAuthority> authorities =
|
||||
Arrays.asList(new SimpleGrantedAuthority("SCOPE_read"),
|
||||
new SimpleGrantedAuthority("SCOPE_write"), new SimpleGrantedAuthority("SCOPE_dolphin"));
|
||||
return new DefaultOAuth2AuthenticatedPrincipal(attributes, authorities);
|
||||
}
|
||||
|
||||
private static URL url(String url) {
|
||||
try {
|
||||
return new URL(url);
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException(e);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,150 +0,0 @@
|
|||
/*
|
||||
* Copyright 2002-2019 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.authentication;
|
||||
|
||||
import java.net.URL;
|
||||
import java.time.Instant;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import net.minidev.json.JSONObject;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.authority.AuthorityUtils;
|
||||
import org.springframework.security.oauth2.core.OAuth2AccessToken;
|
||||
import org.springframework.security.oauth2.core.OAuth2TokenAttributes;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatCode;
|
||||
import static org.springframework.security.oauth2.server.resource.introspection.OAuth2IntrospectionClaimNames.CLIENT_ID;
|
||||
import static org.springframework.security.oauth2.server.resource.introspection.OAuth2IntrospectionClaimNames.SUBJECT;
|
||||
import static org.springframework.security.oauth2.server.resource.introspection.OAuth2IntrospectionClaimNames.USERNAME;
|
||||
|
||||
/**
|
||||
* Tests for {@link OAuth2IntrospectionAuthenticationToken}
|
||||
*
|
||||
* @author Josh Cummings
|
||||
*/
|
||||
public class OAuth2IntrospectionAuthenticationTokenTests {
|
||||
private final OAuth2AccessToken token =
|
||||
new OAuth2AccessToken(OAuth2AccessToken.TokenType.BEARER,
|
||||
"token", Instant.now(), Instant.now().plusSeconds(3600));
|
||||
private final String name = "sub";
|
||||
private Map<String, Object> attributesMap = new HashMap<>();
|
||||
private final OAuth2TokenAttributes attributes = new OAuth2TokenAttributes(attributesMap);
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
this.attributesMap.put(SUBJECT, this.name);
|
||||
this.attributesMap.put(CLIENT_ID, "client_id");
|
||||
this.attributesMap.put(USERNAME, "username");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getNameWhenConfiguredInConstructorThenReturnsName() {
|
||||
OAuth2IntrospectionAuthenticationToken authenticated =
|
||||
new OAuth2IntrospectionAuthenticationToken(this.token, this.attributes,
|
||||
AuthorityUtils.createAuthorityList("USER"), this.name);
|
||||
assertThat(authenticated.getName()).isEqualTo(this.name);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getNameWhenHasNoSubjectThenReturnsNull() {
|
||||
OAuth2IntrospectionAuthenticationToken authenticated =
|
||||
new OAuth2IntrospectionAuthenticationToken(this.token,
|
||||
new OAuth2TokenAttributes(Collections.singletonMap("claim", "value")),
|
||||
Collections.emptyList());
|
||||
assertThat(authenticated.getName()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getNameWhenTokenHasUsernameThenReturnsUsernameAttribute() {
|
||||
OAuth2IntrospectionAuthenticationToken authenticated =
|
||||
new OAuth2IntrospectionAuthenticationToken(this.token, this.attributes, Collections.emptyList());
|
||||
assertThat(authenticated.getName()).isEqualTo(this.attributes.getAttribute(SUBJECT));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void constructorWhenTokenIsNullThenThrowsException() {
|
||||
assertThatCode(() -> new OAuth2IntrospectionAuthenticationToken(null, this.attributes, null))
|
||||
.isInstanceOf(IllegalArgumentException.class)
|
||||
.hasMessageContaining("token cannot be null");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void constructorWhenAttributesAreNullOrEmptyThenThrowsException() {
|
||||
assertThatCode(() -> new OAuth2IntrospectionAuthenticationToken(this.token, null, null))
|
||||
.isInstanceOf(IllegalArgumentException.class)
|
||||
.hasMessageContaining("principal cannot be null");
|
||||
|
||||
assertThatCode(() -> new OAuth2IntrospectionAuthenticationToken(this.token,
|
||||
new OAuth2TokenAttributes(Collections.emptyMap()), null))
|
||||
.isInstanceOf(IllegalArgumentException.class)
|
||||
.hasMessageContaining("attributes cannot be empty");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void constructorWhenPassingAllAttributesThenTokenIsAuthenticated() {
|
||||
OAuth2IntrospectionAuthenticationToken authenticated =
|
||||
new OAuth2IntrospectionAuthenticationToken(this.token,
|
||||
new OAuth2TokenAttributes(Collections.singletonMap("claim", "value")),
|
||||
Collections.emptyList(), "harris");
|
||||
assertThat(authenticated.isAuthenticated()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getTokenAttributesWhenHasTokenThenReturnsThem() {
|
||||
OAuth2IntrospectionAuthenticationToken authenticated =
|
||||
new OAuth2IntrospectionAuthenticationToken(this.token, this.attributes, Collections.emptyList());
|
||||
assertThat(authenticated.getTokenAttributes()).isEqualTo(this.attributes.getAttributes());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAuthoritiesWhenHasAuthoritiesThenReturnsThem() {
|
||||
List<GrantedAuthority> authorities = AuthorityUtils.createAuthorityList("USER");
|
||||
OAuth2IntrospectionAuthenticationToken authenticated =
|
||||
new OAuth2IntrospectionAuthenticationToken(this.token, this.attributes, authorities);
|
||||
assertThat(authenticated.getAuthorities()).isEqualTo(authorities);
|
||||
}
|
||||
|
||||
// gh-6843
|
||||
@Test
|
||||
public void constructorWhenDefaultParametersThenSetsPrincipalToAttributesCopy() {
|
||||
JSONObject attributes = new JSONObject();
|
||||
attributes.put("active", true);
|
||||
OAuth2IntrospectionAuthenticationToken token =
|
||||
new OAuth2IntrospectionAuthenticationToken(this.token, new OAuth2TokenAttributes(attributes),
|
||||
Collections.emptyList());
|
||||
assertThat(token.getPrincipal()).isNotSameAs(attributes);
|
||||
assertThat(token.getTokenAttributes()).isNotSameAs(attributes);
|
||||
}
|
||||
|
||||
// gh-6843
|
||||
@Test
|
||||
public void toStringWhenAttributesContainsURLThenDoesNotFail() throws Exception {
|
||||
JSONObject attributes = new JSONObject(Collections.singletonMap("iss", new URL("https://idp.example.com")));
|
||||
OAuth2IntrospectionAuthenticationToken token =
|
||||
new OAuth2IntrospectionAuthenticationToken(this.token, new OAuth2TokenAttributes(attributes),
|
||||
Collections.emptyList());
|
||||
assertThatCode(token::toString)
|
||||
.doesNotThrowAnyException();
|
||||
}
|
||||
}
|
|
@ -18,23 +18,26 @@ package org.springframework.security.oauth2.server.resource.authentication;
|
|||
import java.net.URL;
|
||||
import java.time.Instant;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
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.core.OAuth2AuthenticationException;
|
||||
import org.springframework.security.oauth2.core.OAuth2TokenAttributes;
|
||||
import org.springframework.security.oauth2.server.resource.BearerTokenAuthenticationToken;
|
||||
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;
|
||||
import org.springframework.security.oauth2.server.resource.BearerTokenAuthenticationToken;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatCode;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.springframework.security.oauth2.core.TestOAuth2AuthenticatedPrincipals.active;
|
||||
import static org.springframework.security.oauth2.server.resource.introspection.OAuth2IntrospectionClaimNames.ACTIVE;
|
||||
import static org.springframework.security.oauth2.server.resource.introspection.OAuth2IntrospectionClaimNames.AUDIENCE;
|
||||
import static org.springframework.security.oauth2.server.resource.introspection.OAuth2IntrospectionClaimNames.EXPIRES_AT;
|
||||
|
@ -43,30 +46,26 @@ import static org.springframework.security.oauth2.server.resource.introspection.
|
|||
import static org.springframework.security.oauth2.server.resource.introspection.OAuth2IntrospectionClaimNames.SCOPE;
|
||||
import static org.springframework.security.oauth2.server.resource.introspection.OAuth2IntrospectionClaimNames.SUBJECT;
|
||||
import static org.springframework.security.oauth2.server.resource.introspection.OAuth2IntrospectionClaimNames.USERNAME;
|
||||
import static org.springframework.security.oauth2.server.resource.introspection.TestOAuth2TokenIntrospectionClientResponses.active;
|
||||
|
||||
/**
|
||||
* Tests for {@link OAuth2IntrospectionAuthenticationProvider}
|
||||
* Tests for {@link OpaqueTokenAuthenticationProvider}
|
||||
*
|
||||
* @author Josh Cummings
|
||||
* @since 5.2
|
||||
*/
|
||||
public class OAuth2IntrospectionAuthenticationProviderTests {
|
||||
public class OpaqueTokenAuthenticationProviderTests {
|
||||
@Test
|
||||
public void authenticateWhenActiveTokenThenOk() throws Exception {
|
||||
Map<String, Object> claims = active();
|
||||
claims.put("extension_field", "twenty-seven");
|
||||
OpaqueTokenIntrospector introspectionClient = mock(OpaqueTokenIntrospector.class);
|
||||
when(introspectionClient.introspect(any())).thenReturn(claims);
|
||||
OAuth2IntrospectionAuthenticationProvider provider =
|
||||
new OAuth2IntrospectionAuthenticationProvider(introspectionClient);
|
||||
OAuth2AuthenticatedPrincipal principal = active(attributes -> attributes.put("extension_field", "twenty-seven"));
|
||||
OpaqueTokenIntrospector introspector = mock(OpaqueTokenIntrospector.class);
|
||||
when(introspector.introspect(any())).thenReturn(principal);
|
||||
OpaqueTokenAuthenticationProvider provider = new OpaqueTokenAuthenticationProvider(introspector);
|
||||
|
||||
Authentication result =
|
||||
provider.authenticate(new BearerTokenAuthenticationToken("token"));
|
||||
|
||||
assertThat(result.getPrincipal()).isInstanceOf(OAuth2TokenAttributes.class);
|
||||
assertThat(result.getPrincipal()).isInstanceOf(DefaultOAuth2AuthenticatedPrincipal.class);
|
||||
|
||||
Map<String, Object> attributes = ((OAuth2TokenAttributes) result.getPrincipal()).getAttributes();
|
||||
Map<String, Object> attributes = ((DefaultOAuth2AuthenticatedPrincipal) result.getPrincipal()).getAttributes();
|
||||
assertThat(attributes)
|
||||
.isNotNull()
|
||||
.containsEntry(ACTIVE, true)
|
||||
|
@ -86,18 +85,16 @@ public class OAuth2IntrospectionAuthenticationProviderTests {
|
|||
|
||||
@Test
|
||||
public void authenticateWhenMissingScopeAttributeThenNoAuthorities() {
|
||||
Map<String, Object> claims = active();
|
||||
claims.remove(SCOPE);
|
||||
OpaqueTokenIntrospector introspectionClient = mock(OpaqueTokenIntrospector.class);
|
||||
when(introspectionClient.introspect(any())).thenReturn(claims);
|
||||
OAuth2IntrospectionAuthenticationProvider provider =
|
||||
new OAuth2IntrospectionAuthenticationProvider(introspectionClient);
|
||||
OAuth2AuthenticatedPrincipal principal = new DefaultOAuth2AuthenticatedPrincipal(Collections.singletonMap("claim", "value"), null);
|
||||
OpaqueTokenIntrospector introspector = mock(OpaqueTokenIntrospector.class);
|
||||
when(introspector.introspect(any())).thenReturn(principal);
|
||||
OpaqueTokenAuthenticationProvider provider = new OpaqueTokenAuthenticationProvider(introspector);
|
||||
|
||||
Authentication result =
|
||||
provider.authenticate(new BearerTokenAuthenticationToken("token"));
|
||||
assertThat(result.getPrincipal()).isInstanceOf(OAuth2TokenAttributes.class);
|
||||
assertThat(result.getPrincipal()).isInstanceOf(OAuth2AuthenticatedPrincipal.class);
|
||||
|
||||
Map<String, Object> attributes = ((OAuth2TokenAttributes) result.getPrincipal()).getAttributes();
|
||||
Map<String, Object> attributes = ((OAuth2AuthenticatedPrincipal) result.getPrincipal()).getAttributes();
|
||||
assertThat(attributes)
|
||||
.isNotNull()
|
||||
.doesNotContainKey(SCOPE);
|
||||
|
@ -107,10 +104,9 @@ public class OAuth2IntrospectionAuthenticationProviderTests {
|
|||
|
||||
@Test
|
||||
public void authenticateWhenIntrospectionEndpointThrowsExceptionThenInvalidToken() {
|
||||
OpaqueTokenIntrospector introspectionClient = mock(OpaqueTokenIntrospector.class);
|
||||
when(introspectionClient.introspect(any())).thenThrow(new OAuth2IntrospectionException("with \"invalid\" chars"));
|
||||
OAuth2IntrospectionAuthenticationProvider provider =
|
||||
new OAuth2IntrospectionAuthenticationProvider(introspectionClient);
|
||||
OpaqueTokenIntrospector introspector = mock(OpaqueTokenIntrospector.class);
|
||||
when(introspector.introspect(any())).thenThrow(new OAuth2IntrospectionException("with \"invalid\" chars"));
|
||||
OpaqueTokenAuthenticationProvider provider = new OpaqueTokenAuthenticationProvider(introspector);
|
||||
|
||||
assertThatCode(() -> provider.authenticate(new BearerTokenAuthenticationToken("token")))
|
||||
.isInstanceOf(OAuth2AuthenticationException.class)
|
||||
|
@ -120,7 +116,7 @@ public class OAuth2IntrospectionAuthenticationProviderTests {
|
|||
|
||||
@Test
|
||||
public void constructorWhenIntrospectionClientIsNullThenIllegalArgumentException() {
|
||||
assertThatCode(() -> new OAuth2IntrospectionAuthenticationProvider(null))
|
||||
assertThatCode(() -> new OpaqueTokenAuthenticationProvider(null))
|
||||
.isInstanceOf(IllegalArgumentException.class);
|
||||
}
|
||||
}
|
|
@ -19,24 +19,27 @@ package org.springframework.security.oauth2.server.resource.authentication;
|
|||
import java.net.URL;
|
||||
import java.time.Instant;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.security.oauth2.core.OAuth2TokenAttributes;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
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.core.OAuth2AuthenticationException;
|
||||
import org.springframework.security.oauth2.server.resource.BearerTokenAuthenticationToken;
|
||||
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;
|
||||
import org.springframework.security.oauth2.server.resource.BearerTokenAuthenticationToken;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatCode;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.springframework.security.oauth2.core.TestOAuth2AuthenticatedPrincipals.active;
|
||||
import static org.springframework.security.oauth2.server.resource.introspection.OAuth2IntrospectionClaimNames.ACTIVE;
|
||||
import static org.springframework.security.oauth2.server.resource.introspection.OAuth2IntrospectionClaimNames.AUDIENCE;
|
||||
import static org.springframework.security.oauth2.server.resource.introspection.OAuth2IntrospectionClaimNames.EXPIRES_AT;
|
||||
|
@ -45,27 +48,27 @@ import static org.springframework.security.oauth2.server.resource.introspection.
|
|||
import static org.springframework.security.oauth2.server.resource.introspection.OAuth2IntrospectionClaimNames.SCOPE;
|
||||
import static org.springframework.security.oauth2.server.resource.introspection.OAuth2IntrospectionClaimNames.SUBJECT;
|
||||
import static org.springframework.security.oauth2.server.resource.introspection.OAuth2IntrospectionClaimNames.USERNAME;
|
||||
import static org.springframework.security.oauth2.server.resource.introspection.TestOAuth2TokenIntrospectionClientResponses.active;
|
||||
|
||||
/**
|
||||
* Tests for {@link OAuth2IntrospectionReactiveAuthenticationManager}
|
||||
* Tests for {@link OpaqueTokenReactiveAuthenticationManager}
|
||||
*
|
||||
* @author Josh Cummings
|
||||
*/
|
||||
public class OAuth2IntrospectionReactiveAuthenticationManagerTests {
|
||||
public class OpaqueTokenReactiveAuthenticationManagerTests {
|
||||
@Test
|
||||
public void authenticateWhenActiveTokenThenOk() throws Exception {
|
||||
Map<String, Object> claims = active();
|
||||
claims.put("extension_field", "twenty-seven");
|
||||
ReactiveOpaqueTokenIntrospector introspectionClient = mock(ReactiveOpaqueTokenIntrospector.class);
|
||||
when(introspectionClient.introspect(any())).thenReturn(Mono.just(claims));
|
||||
OAuth2IntrospectionReactiveAuthenticationManager provider =
|
||||
new OAuth2IntrospectionReactiveAuthenticationManager(introspectionClient);
|
||||
OAuth2AuthenticatedPrincipal authority = active(attributes -> attributes.put("extension_field", "twenty-seven"));
|
||||
ReactiveOpaqueTokenIntrospector introspector = mock(ReactiveOpaqueTokenIntrospector.class);
|
||||
when(introspector.introspect(any())).thenReturn(Mono.just(authority));
|
||||
OpaqueTokenReactiveAuthenticationManager provider =
|
||||
new OpaqueTokenReactiveAuthenticationManager(introspector);
|
||||
|
||||
Authentication result =
|
||||
provider.authenticate(new BearerTokenAuthenticationToken("token")).block();
|
||||
|
||||
assertThat(result.getPrincipal()).isInstanceOf(OAuth2TokenAttributes.class);
|
||||
assertThat(result.getPrincipal()).isInstanceOf(DefaultOAuth2AuthenticatedPrincipal.class);
|
||||
|
||||
Map<String, Object> attributes = ((OAuth2TokenAttributes) result.getPrincipal()).getAttributes();
|
||||
Map<String, Object> attributes = ((DefaultOAuth2AuthenticatedPrincipal) result.getPrincipal()).getAttributes();
|
||||
assertThat(attributes)
|
||||
.isNotNull()
|
||||
.containsEntry(ACTIVE, true)
|
||||
|
@ -85,18 +88,17 @@ public class OAuth2IntrospectionReactiveAuthenticationManagerTests {
|
|||
|
||||
@Test
|
||||
public void authenticateWhenMissingScopeAttributeThenNoAuthorities() {
|
||||
Map<String, Object> claims = active();
|
||||
claims.remove(SCOPE);
|
||||
ReactiveOpaqueTokenIntrospector introspectionClient = mock(ReactiveOpaqueTokenIntrospector.class);
|
||||
when(introspectionClient.introspect(any())).thenReturn(Mono.just(claims));
|
||||
OAuth2IntrospectionReactiveAuthenticationManager provider =
|
||||
new OAuth2IntrospectionReactiveAuthenticationManager(introspectionClient);
|
||||
OAuth2AuthenticatedPrincipal authority = new DefaultOAuth2AuthenticatedPrincipal(Collections.singletonMap("claim", "value"), null);
|
||||
ReactiveOpaqueTokenIntrospector introspector = mock(ReactiveOpaqueTokenIntrospector.class);
|
||||
when(introspector.introspect(any())).thenReturn(Mono.just(authority));
|
||||
OpaqueTokenReactiveAuthenticationManager provider =
|
||||
new OpaqueTokenReactiveAuthenticationManager(introspector);
|
||||
|
||||
Authentication result =
|
||||
provider.authenticate(new BearerTokenAuthenticationToken("token")).block();
|
||||
assertThat(result.getPrincipal()).isInstanceOf(OAuth2TokenAttributes.class);
|
||||
assertThat(result.getPrincipal()).isInstanceOf(DefaultOAuth2AuthenticatedPrincipal.class);
|
||||
|
||||
Map<String, Object> attributes = ((OAuth2TokenAttributes) result.getPrincipal()).getAttributes();
|
||||
Map<String, Object> attributes = ((DefaultOAuth2AuthenticatedPrincipal) result.getPrincipal()).getAttributes();
|
||||
assertThat(attributes)
|
||||
.isNotNull()
|
||||
.doesNotContainKey(SCOPE);
|
||||
|
@ -106,11 +108,11 @@ public class OAuth2IntrospectionReactiveAuthenticationManagerTests {
|
|||
|
||||
@Test
|
||||
public void authenticateWhenIntrospectionEndpointThrowsExceptionThenInvalidToken() {
|
||||
ReactiveOpaqueTokenIntrospector introspectionClient = mock(ReactiveOpaqueTokenIntrospector.class);
|
||||
when(introspectionClient.introspect(any()))
|
||||
ReactiveOpaqueTokenIntrospector introspector = mock(ReactiveOpaqueTokenIntrospector.class);
|
||||
when(introspector.introspect(any()))
|
||||
.thenReturn(Mono.error(new OAuth2IntrospectionException("with \"invalid\" chars")));
|
||||
OAuth2IntrospectionReactiveAuthenticationManager provider =
|
||||
new OAuth2IntrospectionReactiveAuthenticationManager(introspectionClient);
|
||||
OpaqueTokenReactiveAuthenticationManager provider =
|
||||
new OpaqueTokenReactiveAuthenticationManager(introspector);
|
||||
|
||||
assertThatCode(() -> provider.authenticate(new BearerTokenAuthenticationToken("token")).block())
|
||||
.isInstanceOf(OAuth2AuthenticationException.class)
|
||||
|
@ -120,7 +122,7 @@ public class OAuth2IntrospectionReactiveAuthenticationManagerTests {
|
|||
|
||||
@Test
|
||||
public void constructorWhenIntrospectionClientIsNullThenIllegalArgumentException() {
|
||||
assertThatCode(() -> new OAuth2IntrospectionReactiveAuthenticationManager(null))
|
||||
assertThatCode(() -> new OpaqueTokenReactiveAuthenticationManager(null))
|
||||
.isInstanceOf(IllegalArgumentException.class);
|
||||
}
|
||||
}
|
|
@ -38,6 +38,7 @@ import org.springframework.http.HttpStatus;
|
|||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.RequestEntity;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.security.oauth2.core.OAuth2AuthenticatedPrincipal;
|
||||
import org.springframework.web.client.RestOperations;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
@ -113,8 +114,8 @@ public class NimbusOpaqueTokenIntrospectorTests {
|
|||
OpaqueTokenIntrospector introspectionClient =
|
||||
new NimbusOpaqueTokenIntrospector(introspectUri, CLIENT_ID, CLIENT_SECRET);
|
||||
|
||||
Map<String, Object> attributes = introspectionClient.introspect("token");
|
||||
assertThat(attributes)
|
||||
OAuth2AuthenticatedPrincipal authority = introspectionClient.introspect("token");
|
||||
assertThat(authority.getAttributes())
|
||||
.isNotNull()
|
||||
.containsEntry(OAuth2IntrospectionClaimNames.ACTIVE, true)
|
||||
.containsEntry(AUDIENCE, Arrays.asList("https://protected.example.net/resource"))
|
||||
|
@ -168,8 +169,8 @@ public class NimbusOpaqueTokenIntrospectorTests {
|
|||
when(restOperations.exchange(any(RequestEntity.class), eq(String.class)))
|
||||
.thenReturn(response(new JSONObject(introspectedValues).toJSONString()));
|
||||
|
||||
Map<String, Object> attributes = introspectionClient.introspect("token");
|
||||
assertThat(attributes)
|
||||
OAuth2AuthenticatedPrincipal authority = introspectionClient.introspect("token");
|
||||
assertThat(authority.getAttributes())
|
||||
.isNotNull()
|
||||
.containsEntry(OAuth2IntrospectionClaimNames.ACTIVE, true)
|
||||
.containsEntry(AUDIENCE, Arrays.asList("aud"))
|
||||
|
|
|
@ -36,6 +36,7 @@ import reactor.core.publisher.Mono;
|
|||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.security.oauth2.core.OAuth2AuthenticatedPrincipal;
|
||||
import org.springframework.web.reactive.function.client.ClientResponse;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
|
||||
|
@ -103,8 +104,8 @@ public class NimbusReactiveOpaqueTokenIntrospectorTests {
|
|||
NimbusReactiveOpaqueTokenIntrospector introspectionClient =
|
||||
new NimbusReactiveOpaqueTokenIntrospector(introspectUri, CLIENT_ID, CLIENT_SECRET);
|
||||
|
||||
Map<String, Object> attributes = introspectionClient.introspect("token").block();
|
||||
assertThat(attributes)
|
||||
OAuth2AuthenticatedPrincipal authority = introspectionClient.introspect("token").block();
|
||||
assertThat(authority.getAttributes())
|
||||
.isNotNull()
|
||||
.containsEntry(OAuth2IntrospectionClaimNames.ACTIVE, true)
|
||||
.containsEntry(AUDIENCE, Arrays.asList("https://protected.example.net/resource"))
|
||||
|
@ -155,8 +156,8 @@ public class NimbusReactiveOpaqueTokenIntrospectorTests {
|
|||
NimbusReactiveOpaqueTokenIntrospector introspectionClient =
|
||||
new NimbusReactiveOpaqueTokenIntrospector(INTROSPECTION_URL, webClient);
|
||||
|
||||
Map<String, Object> attributes = introspectionClient.introspect("token").block();
|
||||
assertThat(attributes)
|
||||
OAuth2AuthenticatedPrincipal authority = introspectionClient.introspect("token").block();
|
||||
assertThat(authority.getAttributes())
|
||||
.isNotNull()
|
||||
.containsEntry(OAuth2IntrospectionClaimNames.ACTIVE, true)
|
||||
.containsEntry(AUDIENCE, Arrays.asList("aud"))
|
||||
|
|
|
@ -1,59 +0,0 @@
|
|||
/*
|
||||
* Copyright 2002-2019 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.io.IOException;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.net.URL;
|
||||
import java.time.Instant;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.springframework.security.oauth2.server.resource.introspection.OAuth2IntrospectionClaimNames.ACTIVE;
|
||||
import static org.springframework.security.oauth2.server.resource.introspection.OAuth2IntrospectionClaimNames.AUDIENCE;
|
||||
import static org.springframework.security.oauth2.server.resource.introspection.OAuth2IntrospectionClaimNames.CLIENT_ID;
|
||||
import static org.springframework.security.oauth2.server.resource.introspection.OAuth2IntrospectionClaimNames.EXPIRES_AT;
|
||||
import static org.springframework.security.oauth2.server.resource.introspection.OAuth2IntrospectionClaimNames.ISSUER;
|
||||
import static org.springframework.security.oauth2.server.resource.introspection.OAuth2IntrospectionClaimNames.NOT_BEFORE;
|
||||
import static org.springframework.security.oauth2.server.resource.introspection.OAuth2IntrospectionClaimNames.SCOPE;
|
||||
import static org.springframework.security.oauth2.server.resource.introspection.OAuth2IntrospectionClaimNames.SUBJECT;
|
||||
import static org.springframework.security.oauth2.server.resource.introspection.OAuth2IntrospectionClaimNames.USERNAME;
|
||||
|
||||
public class TestOAuth2TokenIntrospectionClientResponses {
|
||||
public static Map<String, Object> active() {
|
||||
Map<String, Object> attributes = new HashMap<>();
|
||||
attributes.put(ACTIVE, true);
|
||||
attributes.put(AUDIENCE, Arrays.asList("https://protected.example.net/resource"));
|
||||
attributes.put(CLIENT_ID, "l238j323ds-23ij4");
|
||||
attributes.put(EXPIRES_AT, Instant.ofEpochSecond(1419356238));
|
||||
attributes.put(NOT_BEFORE, Instant.ofEpochSecond(29348723984L));
|
||||
attributes.put(ISSUER, url("https://server.example.com/"));
|
||||
attributes.put(SCOPE, Arrays.asList("read", "write", "dolphin"));
|
||||
attributes.put(SUBJECT, "Z5O3upPC88QrAjx00dis");
|
||||
attributes.put(USERNAME, "jdoe");
|
||||
return attributes;
|
||||
}
|
||||
|
||||
private static URL url(String url) {
|
||||
try {
|
||||
return new URL(url);
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException(e);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -16,7 +16,7 @@
|
|||
package sample;
|
||||
|
||||
import org.springframework.security.core.annotation.AuthenticationPrincipal;
|
||||
import org.springframework.security.oauth2.core.OAuth2TokenAttributes;
|
||||
import org.springframework.security.oauth2.core.OAuth2AuthenticatedPrincipal;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
|
@ -27,8 +27,8 @@ import org.springframework.web.bind.annotation.RestController;
|
|||
public class OAuth2ResourceServerController {
|
||||
|
||||
@GetMapping("/")
|
||||
public String index(@AuthenticationPrincipal OAuth2TokenAttributes attributes) {
|
||||
return String.format("Hello, %s!", (String) attributes.getAttribute("sub"));
|
||||
public String index(@AuthenticationPrincipal OAuth2AuthenticatedPrincipal principal) {
|
||||
return String.format("Hello, %s!", (String) principal.getAttribute("sub"));
|
||||
}
|
||||
|
||||
@GetMapping("/message")
|
||||
|
|
Loading…
Reference in New Issue