parent
d067aca43d
commit
dd5edeb255
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2023 the original author or authors.
|
* Copyright 2002-2024 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -183,7 +183,7 @@ public class SpringOpaqueTokenIntrospector implements OpaqueTokenIntrospector {
|
||||||
return claims;
|
return claims;
|
||||||
}
|
}
|
||||||
|
|
||||||
private OAuth2TokenIntrospectionClaimAccessor convertClaimsSet(Map<String, Object> claims) {
|
private ArrayListFromStringClaimAccessor convertClaimsSet(Map<String, Object> claims) {
|
||||||
Map<String, Object> converted = new LinkedHashMap<>(claims);
|
Map<String, Object> converted = new LinkedHashMap<>(claims);
|
||||||
converted.computeIfPresent(OAuth2TokenIntrospectionClaimNames.AUD, (k, v) -> {
|
converted.computeIfPresent(OAuth2TokenIntrospectionClaimNames.AUD, (k, v) -> {
|
||||||
if (v instanceof String) {
|
if (v instanceof String) {
|
||||||
|
@ -277,4 +277,18 @@ public class SpringOpaqueTokenIntrospector implements OpaqueTokenIntrospector {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// gh-15165
|
||||||
|
private interface ArrayListFromStringClaimAccessor extends OAuth2TokenIntrospectionClaimAccessor {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
default List<String> getScopes() {
|
||||||
|
Object value = getClaims().get(OAuth2TokenIntrospectionClaimNames.SCOPE);
|
||||||
|
if (value instanceof ArrayListFromString list) {
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
return OAuth2TokenIntrospectionClaimAccessor.super.getScopes();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2023 the original author or authors.
|
* Copyright 2002-2024 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -143,7 +143,7 @@ public class SpringReactiveOpaqueTokenIntrospector implements ReactiveOpaqueToke
|
||||||
.switchIfEmpty(Mono.error(() -> new BadOpaqueTokenException("Provided token isn't active")));
|
.switchIfEmpty(Mono.error(() -> new BadOpaqueTokenException("Provided token isn't active")));
|
||||||
}
|
}
|
||||||
|
|
||||||
private OAuth2TokenIntrospectionClaimAccessor convertClaimsSet(Map<String, Object> claims) {
|
private ArrayListFromStringClaimAccessor convertClaimsSet(Map<String, Object> claims) {
|
||||||
Map<String, Object> converted = new LinkedHashMap<>(claims);
|
Map<String, Object> converted = new LinkedHashMap<>(claims);
|
||||||
converted.computeIfPresent(OAuth2TokenIntrospectionClaimNames.AUD, (k, v) -> {
|
converted.computeIfPresent(OAuth2TokenIntrospectionClaimNames.AUD, (k, v) -> {
|
||||||
if (v instanceof String) {
|
if (v instanceof String) {
|
||||||
|
@ -231,4 +231,18 @@ public class SpringReactiveOpaqueTokenIntrospector implements ReactiveOpaqueToke
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// gh-15165
|
||||||
|
private interface ArrayListFromStringClaimAccessor extends OAuth2TokenIntrospectionClaimAccessor {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
default List<String> getScopes() {
|
||||||
|
Object value = getClaims().get(OAuth2TokenIntrospectionClaimNames.SCOPE);
|
||||||
|
if (value instanceof ArrayListFromString list) {
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
return OAuth2TokenIntrospectionClaimAccessor.super.getScopes();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2023 the original author or authors.
|
* Copyright 2002-2024 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -39,6 +39,7 @@ import org.springframework.http.HttpStatus;
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.http.RequestEntity;
|
import org.springframework.http.RequestEntity;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.security.core.authority.AuthorityUtils;
|
||||||
import org.springframework.security.oauth2.core.OAuth2AuthenticatedPrincipal;
|
import org.springframework.security.oauth2.core.OAuth2AuthenticatedPrincipal;
|
||||||
import org.springframework.security.oauth2.core.OAuth2TokenIntrospectionClaimAccessor;
|
import org.springframework.security.oauth2.core.OAuth2TokenIntrospectionClaimAccessor;
|
||||||
import org.springframework.security.oauth2.core.OAuth2TokenIntrospectionClaimNames;
|
import org.springframework.security.oauth2.core.OAuth2TokenIntrospectionClaimNames;
|
||||||
|
@ -245,6 +246,21 @@ public class SpringOpaqueTokenIntrospectorTests {
|
||||||
assertThat(scope).containsExactly("read", "write", "dolphin");
|
assertThat(scope).containsExactly("read", "write", "dolphin");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// gh-15165
|
||||||
|
@Test
|
||||||
|
public void introspectWhenActiveThenMapsAuthorities() {
|
||||||
|
RestOperations restOperations = mock(RestOperations.class);
|
||||||
|
OpaqueTokenIntrospector introspectionClient = new SpringOpaqueTokenIntrospector(INTROSPECTION_URL,
|
||||||
|
restOperations);
|
||||||
|
given(restOperations.exchange(any(RequestEntity.class), eq(STRING_OBJECT_MAP))).willReturn(ACTIVE);
|
||||||
|
OAuth2AuthenticatedPrincipal principal = introspectionClient.introspect("token");
|
||||||
|
assertThat(principal.getAuthorities()).isNotEmpty();
|
||||||
|
Collection<String> scope = principal.getAttribute("scope");
|
||||||
|
assertThat(scope).containsExactly("read", "write", "dolphin");
|
||||||
|
Collection<String> authorities = AuthorityUtils.authorityListToSet(principal.getAuthorities());
|
||||||
|
assertThat(authorities).containsExactly("SCOPE_read", "SCOPE_write", "SCOPE_dolphin");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void constructorWhenIntrospectionUriIsNullThenIllegalArgumentException() {
|
public void constructorWhenIntrospectionUriIsNullThenIllegalArgumentException() {
|
||||||
assertThatIllegalArgumentException()
|
assertThatIllegalArgumentException()
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2023 the original author or authors.
|
* Copyright 2002-2024 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -20,6 +20,7 @@ import java.io.IOException;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Base64;
|
import java.util.Base64;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
@ -37,6 +38,7 @@ import org.springframework.core.convert.converter.Converter;
|
||||||
import org.springframework.http.HttpHeaders;
|
import org.springframework.http.HttpHeaders;
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.security.core.authority.AuthorityUtils;
|
||||||
import org.springframework.security.oauth2.core.OAuth2AuthenticatedPrincipal;
|
import org.springframework.security.oauth2.core.OAuth2AuthenticatedPrincipal;
|
||||||
import org.springframework.security.oauth2.core.OAuth2TokenIntrospectionClaimAccessor;
|
import org.springframework.security.oauth2.core.OAuth2TokenIntrospectionClaimAccessor;
|
||||||
import org.springframework.security.oauth2.core.OAuth2TokenIntrospectionClaimNames;
|
import org.springframework.security.oauth2.core.OAuth2TokenIntrospectionClaimNames;
|
||||||
|
@ -197,6 +199,20 @@ public class SpringReactiveOpaqueTokenIntrospectorTests {
|
||||||
// @formatter:on
|
// @formatter:on
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// gh-15165
|
||||||
|
@Test
|
||||||
|
public void introspectWhenActiveThenMapsAuthorities() {
|
||||||
|
WebClient webClient = mockResponse(ACTIVE_RESPONSE);
|
||||||
|
SpringReactiveOpaqueTokenIntrospector introspectionClient = new SpringReactiveOpaqueTokenIntrospector(
|
||||||
|
INTROSPECTION_URL, webClient);
|
||||||
|
OAuth2AuthenticatedPrincipal principal = introspectionClient.introspect("token").block();
|
||||||
|
assertThat(principal.getAuthorities()).isNotEmpty();
|
||||||
|
Collection<String> scope = principal.getAttribute("scope");
|
||||||
|
assertThat(scope).containsExactly("read", "write", "dolphin");
|
||||||
|
Collection<String> authorities = AuthorityUtils.authorityListToSet(principal.getAuthorities());
|
||||||
|
assertThat(authorities).containsExactly("SCOPE_read", "SCOPE_write", "SCOPE_dolphin");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void setAuthenticationConverterWhenConverterIsNullThenExceptionIsThrown() {
|
public void setAuthenticationConverterWhenConverterIsNullThenExceptionIsThrown() {
|
||||||
WebClient web = mock(WebClient.class);
|
WebClient web = mock(WebClient.class);
|
||||||
|
|
Loading…
Reference in New Issue