|
@@ -22,6 +22,7 @@ import java.util.ArrayList;
|
|
import java.util.Arrays;
|
|
import java.util.Arrays;
|
|
import java.util.Collection;
|
|
import java.util.Collection;
|
|
import java.util.Collections;
|
|
import java.util.Collections;
|
|
|
|
+import java.util.List;
|
|
import java.util.Map;
|
|
import java.util.Map;
|
|
|
|
|
|
import org.apache.commons.logging.Log;
|
|
import org.apache.commons.logging.Log;
|
|
@@ -69,7 +70,7 @@ public class SpringOpaqueTokenIntrospector implements OpaqueTokenIntrospector {
|
|
|
|
|
|
private Converter<String, RequestEntity<?>> requestEntityConverter;
|
|
private Converter<String, RequestEntity<?>> requestEntityConverter;
|
|
|
|
|
|
- private Converter<OAuth2TokenIntrospectionClaimAccessor, OAuth2AuthenticatedPrincipal> authenticationConverter;
|
|
|
|
|
|
+ private Converter<OAuth2TokenIntrospectionClaimAccessor, ? extends OAuth2AuthenticatedPrincipal> authenticationConverter = this::defaultAuthenticationConverter;
|
|
|
|
|
|
/**
|
|
/**
|
|
* Creates a {@code OpaqueTokenAuthenticationProvider} with the provided parameters
|
|
* Creates a {@code OpaqueTokenAuthenticationProvider} with the provided parameters
|
|
@@ -85,7 +86,6 @@ public class SpringOpaqueTokenIntrospector implements OpaqueTokenIntrospector {
|
|
RestTemplate restTemplate = new RestTemplate();
|
|
RestTemplate restTemplate = new RestTemplate();
|
|
restTemplate.getInterceptors().add(new BasicAuthenticationInterceptor(clientId, clientSecret));
|
|
restTemplate.getInterceptors().add(new BasicAuthenticationInterceptor(clientId, clientSecret));
|
|
this.restOperations = restTemplate;
|
|
this.restOperations = restTemplate;
|
|
- this.authenticationConverter = this.defaultAuthenticationConverter();
|
|
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
/**
|
|
@@ -100,7 +100,6 @@ public class SpringOpaqueTokenIntrospector implements OpaqueTokenIntrospector {
|
|
Assert.notNull(restOperations, "restOperations cannot be null");
|
|
Assert.notNull(restOperations, "restOperations cannot be null");
|
|
this.requestEntityConverter = this.defaultRequestEntityConverter(URI.create(introspectionUri));
|
|
this.requestEntityConverter = this.defaultRequestEntityConverter(URI.create(introspectionUri));
|
|
this.restOperations = restOperations;
|
|
this.restOperations = restOperations;
|
|
- this.authenticationConverter = this.defaultAuthenticationConverter();
|
|
|
|
}
|
|
}
|
|
|
|
|
|
private Converter<String, RequestEntity<?>> defaultRequestEntityConverter(URI introspectionUri) {
|
|
private Converter<String, RequestEntity<?>> defaultRequestEntityConverter(URI introspectionUri) {
|
|
@@ -131,8 +130,8 @@ public class SpringOpaqueTokenIntrospector implements OpaqueTokenIntrospector {
|
|
}
|
|
}
|
|
ResponseEntity<Map<String, Object>> responseEntity = makeRequest(requestEntity);
|
|
ResponseEntity<Map<String, Object>> responseEntity = makeRequest(requestEntity);
|
|
Map<String, Object> claims = adaptToNimbusResponse(responseEntity);
|
|
Map<String, Object> claims = adaptToNimbusResponse(responseEntity);
|
|
- convertClaimsSet(claims);
|
|
|
|
- return this.authenticationConverter.convert(() -> claims);
|
|
|
|
|
|
+ OAuth2TokenIntrospectionClaimAccessor accessor = convertClaimsSet(claims);
|
|
|
|
+ return this.authenticationConverter.convert(accessor);
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
/**
|
|
@@ -183,7 +182,7 @@ public class SpringOpaqueTokenIntrospector implements OpaqueTokenIntrospector {
|
|
return claims;
|
|
return claims;
|
|
}
|
|
}
|
|
|
|
|
|
- private Map<String, Object> convertClaimsSet(Map<String, Object> claims) {
|
|
|
|
|
|
+ private OAuth2TokenIntrospectionClaimAccessor convertClaimsSet(Map<String, Object> claims) {
|
|
claims.computeIfPresent(OAuth2TokenIntrospectionClaimNames.AUD, (k, v) -> {
|
|
claims.computeIfPresent(OAuth2TokenIntrospectionClaimNames.AUD, (k, v) -> {
|
|
if (v instanceof String) {
|
|
if (v instanceof String) {
|
|
return Collections.singletonList(v);
|
|
return Collections.singletonList(v);
|
|
@@ -216,44 +215,16 @@ public class SpringOpaqueTokenIntrospector implements OpaqueTokenIntrospector {
|
|
claims.computeIfPresent(OAuth2TokenIntrospectionClaimNames.ISS, (k, v) -> v.toString());
|
|
claims.computeIfPresent(OAuth2TokenIntrospectionClaimNames.ISS, (k, v) -> v.toString());
|
|
claims.computeIfPresent(OAuth2TokenIntrospectionClaimNames.NBF,
|
|
claims.computeIfPresent(OAuth2TokenIntrospectionClaimNames.NBF,
|
|
(k, v) -> Instant.ofEpochSecond(((Number) v).longValue()));
|
|
(k, v) -> Instant.ofEpochSecond(((Number) v).longValue()));
|
|
- return claims;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /**
|
|
|
|
- * If {@link SpringOpaqueTokenIntrospector#authenticationConverter} is not explicitly
|
|
|
|
- * set, this default converter will be used. transforms an
|
|
|
|
- * {@link OAuth2TokenIntrospectionClaimAccessor} into an
|
|
|
|
- * {@link OAuth2AuthenticatedPrincipal} by extracting claims, mapping scopes to
|
|
|
|
- * authorities, and creating a principal.
|
|
|
|
- * @return {@link Converter Converter<OAuth2TokenIntrospectionClaimAccessor,
|
|
|
|
- * OAuth2AuthenticatedPrincipal>}
|
|
|
|
- * @since 6.3
|
|
|
|
- */
|
|
|
|
- private Converter<OAuth2TokenIntrospectionClaimAccessor, OAuth2AuthenticatedPrincipal> defaultAuthenticationConverter() {
|
|
|
|
- return (accessor) -> {
|
|
|
|
- Map<String, Object> claims = accessor.getClaims();
|
|
|
|
- Collection<GrantedAuthority> authorities = new ArrayList<>();
|
|
|
|
-
|
|
|
|
- claims.computeIfPresent(OAuth2TokenIntrospectionClaimNames.SCOPE, (k, v) -> {
|
|
|
|
- if (v instanceof String) {
|
|
|
|
- Collection<String> scopes = Arrays.asList(((String) v).split(" "));
|
|
|
|
- for (String scope : scopes) {
|
|
|
|
- authorities.add(new SimpleGrantedAuthority(AUTHORITY_PREFIX + scope));
|
|
|
|
- }
|
|
|
|
- return scopes;
|
|
|
|
- }
|
|
|
|
- return v;
|
|
|
|
- });
|
|
|
|
-
|
|
|
|
- return new OAuth2IntrospectionAuthenticatedPrincipal(claims, authorities);
|
|
|
|
- };
|
|
|
|
|
|
+ claims.computeIfPresent(OAuth2TokenIntrospectionClaimNames.SCOPE,
|
|
|
|
+ (k, v) -> (v instanceof String s) ? new ArrayListFromString(s.split(" ")) : v);
|
|
|
|
+ return () -> claims;
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
/**
|
|
* <p>
|
|
* <p>
|
|
* Sets the {@link Converter Converter<OAuth2TokenIntrospectionClaimAccessor,
|
|
* Sets the {@link Converter Converter<OAuth2TokenIntrospectionClaimAccessor,
|
|
* OAuth2AuthenticatedPrincipal>} to use. Defaults to
|
|
* OAuth2AuthenticatedPrincipal>} to use. Defaults to
|
|
- * {@link SpringOpaqueTokenIntrospector#defaultAuthenticationConverter()}.
|
|
|
|
|
|
+ * {@link SpringOpaqueTokenIntrospector#defaultAuthenticationConverter}.
|
|
* </p>
|
|
* </p>
|
|
* <p>
|
|
* <p>
|
|
* Use if you need a custom mapping of OAuth 2.0 token claims to the authenticated
|
|
* Use if you need a custom mapping of OAuth 2.0 token claims to the authenticated
|
|
@@ -263,9 +234,45 @@ public class SpringOpaqueTokenIntrospector implements OpaqueTokenIntrospector {
|
|
* @since 6.3
|
|
* @since 6.3
|
|
*/
|
|
*/
|
|
public void setAuthenticationConverter(
|
|
public void setAuthenticationConverter(
|
|
- Converter<OAuth2TokenIntrospectionClaimAccessor, OAuth2AuthenticatedPrincipal> authenticationConverter) {
|
|
|
|
|
|
+ Converter<OAuth2TokenIntrospectionClaimAccessor, ? extends OAuth2AuthenticatedPrincipal> authenticationConverter) {
|
|
Assert.notNull(authenticationConverter, "converter cannot be null");
|
|
Assert.notNull(authenticationConverter, "converter cannot be null");
|
|
this.authenticationConverter = authenticationConverter;
|
|
this.authenticationConverter = authenticationConverter;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /**
|
|
|
|
+ * If {@link SpringOpaqueTokenIntrospector#authenticationConverter} is not explicitly
|
|
|
|
+ * set, this default converter will be used. transforms an
|
|
|
|
+ * {@link OAuth2TokenIntrospectionClaimAccessor} into an
|
|
|
|
+ * {@link OAuth2AuthenticatedPrincipal} by extracting claims, mapping scopes to
|
|
|
|
+ * authorities, and creating a principal.
|
|
|
|
+ * @return {@link Converter Converter<OAuth2TokenIntrospectionClaimAccessor,
|
|
|
|
+ * OAuth2AuthenticatedPrincipal>}
|
|
|
|
+ * @since 6.3
|
|
|
|
+ */
|
|
|
|
+ private OAuth2IntrospectionAuthenticatedPrincipal defaultAuthenticationConverter(
|
|
|
|
+ OAuth2TokenIntrospectionClaimAccessor accessor) {
|
|
|
|
+ Collection<GrantedAuthority> authorities = authorities(accessor.getScopes());
|
|
|
|
+ return new OAuth2IntrospectionAuthenticatedPrincipal(accessor.getClaims(), authorities);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private Collection<GrantedAuthority> authorities(List<String> scopes) {
|
|
|
|
+ if (!(scopes instanceof ArrayListFromString)) {
|
|
|
|
+ return Collections.emptyList();
|
|
|
|
+ }
|
|
|
|
+ Collection<GrantedAuthority> authorities = new ArrayList<>();
|
|
|
|
+ for (String scope : scopes) {
|
|
|
|
+ authorities.add(new SimpleGrantedAuthority(AUTHORITY_PREFIX + scope));
|
|
|
|
+ }
|
|
|
|
+ return authorities;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // gh-7563
|
|
|
|
+ private static final class ArrayListFromString extends ArrayList<String> {
|
|
|
|
+
|
|
|
|
+ ArrayListFromString(String... elements) {
|
|
|
|
+ super(Arrays.asList(elements));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
}
|
|
}
|