Polish gh-11665
This commit is contained in:
+18
-19
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
* Copyright 2002-2022 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.
|
||||
@@ -17,6 +17,7 @@
|
||||
package org.springframework.security.oauth2.server.resource.authentication;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
@@ -24,7 +25,6 @@ import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.security.authentication.AbstractAuthenticationToken;
|
||||
import org.springframework.security.authentication.AuthenticationProvider;
|
||||
import org.springframework.security.authentication.AuthenticationServiceException;
|
||||
import org.springframework.security.authentication.ReactiveAuthenticationManager;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
@@ -50,18 +50,21 @@ import org.springframework.util.Assert;
|
||||
* opaque access token, returning its attributes set as part of the {@link Authentication}
|
||||
* statement.
|
||||
* <p>
|
||||
* This {@link ReactiveAuthenticationManager} is responsible for introspecting and
|
||||
* verifying an opaque access token, returning its attributes set as part of the
|
||||
* {@link Authentication} statement.
|
||||
* Scopes are translated into {@link GrantedAuthority}s according to the following
|
||||
* algorithm:
|
||||
* <ol>
|
||||
* <li>If there is a "scope" attribute, then convert to a {@link Collection} of
|
||||
* {@link String}s.
|
||||
* <li>Take the resulting {@link Collection} and prepend the "SCOPE_" keyword to each
|
||||
* element, adding as {@link GrantedAuthority}s.
|
||||
* </ol>
|
||||
* <p>
|
||||
* An {@link OpaqueTokenIntrospector} is responsible for retrieving token attributes from
|
||||
* an authorization server.
|
||||
* <p>
|
||||
* {@link org.springframework.security.oauth2.server.resource.introspection.ReactiveOpaqueTokenIntrospector}
|
||||
* is responsible for retrieving token attributes from authorization-server.
|
||||
* </p>
|
||||
* <p>
|
||||
* authenticationConverter is responsible for turning successful introspection into
|
||||
* {@link Authentication} (which includes {@link GrantedAuthority}s mapping from token
|
||||
* attributes or retrieving from an other source)
|
||||
* An {@link OpaqueTokenAuthenticationConverter} is responsible for turning a successful
|
||||
* introspection result into an {@link Authentication} instance (which may include mapping
|
||||
* {@link GrantedAuthority}s from token attributes or retrieving from another source).
|
||||
*
|
||||
* @author Josh Cummings
|
||||
* @author Jerome Wacongne <ch4mp@c4-soft.com>
|
||||
@@ -74,7 +77,7 @@ public final class OpaqueTokenAuthenticationProvider implements AuthenticationPr
|
||||
|
||||
private final OpaqueTokenIntrospector introspector;
|
||||
|
||||
private OpaqueTokenAuthenticationConverter authenticationConverter;
|
||||
private OpaqueTokenAuthenticationConverter authenticationConverter = OpaqueTokenAuthenticationProvider::convert;
|
||||
|
||||
/**
|
||||
* Creates a {@code OpaqueTokenAuthenticationProvider} with the provided parameters
|
||||
@@ -83,20 +86,16 @@ public final class OpaqueTokenAuthenticationProvider implements AuthenticationPr
|
||||
public OpaqueTokenAuthenticationProvider(OpaqueTokenIntrospector introspector) {
|
||||
Assert.notNull(introspector, "introspector cannot be null");
|
||||
this.introspector = introspector;
|
||||
this.setAuthenticationConverter(OpaqueTokenAuthenticationProvider::convert);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Introspect and validate the opaque
|
||||
* <a href="https://tools.ietf.org/html/rfc6750#section-1.2" target="_blank">Bearer
|
||||
* Token</a> and then delegates {@link Authentication} instantiation to
|
||||
* {@link OpaqueTokenAuthenticationConverter}.
|
||||
* </p>
|
||||
* <p>
|
||||
* If created Authentication is instance of {@link AbstractAuthenticationToken} and
|
||||
* details are null, then introspection result details are used.
|
||||
* </p>
|
||||
* @param authentication the authentication request object.
|
||||
* @return A successful authentication
|
||||
* @throws AuthenticationException if authentication failed for some reason
|
||||
@@ -142,9 +141,9 @@ public final class OpaqueTokenAuthenticationProvider implements AuthenticationPr
|
||||
|
||||
/**
|
||||
* Default {@link OpaqueTokenAuthenticationConverter}.
|
||||
* @param introspectedToken the bearer sring that was successfuly introspected
|
||||
* @param introspectedToken the bearer string that was successfully introspected
|
||||
* @param authenticatedPrincipal the successful introspection output
|
||||
* @returna {@link BearerTokenAuthentication}
|
||||
* @return a {@link BearerTokenAuthentication}
|
||||
*/
|
||||
static BearerTokenAuthentication convert(String introspectedToken,
|
||||
OAuth2AuthenticatedPrincipal authenticatedPrincipal) {
|
||||
|
||||
+13
-18
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
* Copyright 2002-2022 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.
|
||||
@@ -36,7 +36,7 @@ import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* An {@link ReactiveAuthenticationManager} implementation for opaque
|
||||
* <a href="https://tools.ietf.org/html/rfc6750#section-1.2" target= "_blank">Bearer
|
||||
* <a href="https://tools.ietf.org/html/rfc6750#section-1.2" target="_blank">Bearer
|
||||
* Token</a>s, using an
|
||||
* <a href="https://tools.ietf.org/html/rfc7662" target="_blank">OAuth 2.0 Introspection
|
||||
* Endpoint</a> to check the token's validity and reveal its attributes.
|
||||
@@ -45,14 +45,13 @@ import org.springframework.util.Assert;
|
||||
* verifying an opaque access token, returning its attributes set as part of the
|
||||
* {@link Authentication} statement.
|
||||
* <p>
|
||||
* A {@link ReactiveOpaqueTokenIntrospector} is responsible for retrieving token
|
||||
* attributes from an authorization server.
|
||||
* <p>
|
||||
* {@link ReactiveOpaqueTokenIntrospector} is responsible for retrieving token attributes
|
||||
* from authorization-server.
|
||||
* </p>
|
||||
* <p>
|
||||
* authenticationConverter is responsible for turning successful introspection into
|
||||
* {@link Authentication} (which includes {@link GrantedAuthority}s mapping from token
|
||||
* attributes or retrieving from another source)
|
||||
* A {@link ReactiveOpaqueTokenAuthenticationConverter} is responsible for turning a
|
||||
* successful introspection result into an {@link Authentication} instance (which may
|
||||
* include mapping {@link GrantedAuthority}s from token attributes or retrieving from
|
||||
* another source).
|
||||
*
|
||||
* @author Josh Cummings
|
||||
* @author Jerome Wacongne <ch4mp@c4-soft.com>
|
||||
@@ -63,7 +62,7 @@ public class OpaqueTokenReactiveAuthenticationManager implements ReactiveAuthent
|
||||
|
||||
private final ReactiveOpaqueTokenIntrospector introspector;
|
||||
|
||||
private ReactiveOpaqueTokenAuthenticationConverter authenticationConverter;
|
||||
private ReactiveOpaqueTokenAuthenticationConverter authenticationConverter = OpaqueTokenReactiveAuthenticationManager::convert;
|
||||
|
||||
/**
|
||||
* Creates a {@code OpaqueTokenReactiveAuthenticationManager} with the provided
|
||||
@@ -73,20 +72,16 @@ public class OpaqueTokenReactiveAuthenticationManager implements ReactiveAuthent
|
||||
public OpaqueTokenReactiveAuthenticationManager(ReactiveOpaqueTokenIntrospector introspector) {
|
||||
Assert.notNull(introspector, "introspector cannot be null");
|
||||
this.introspector = introspector;
|
||||
this.setAuthenticationConverter(OpaqueTokenReactiveAuthenticationManager::convert);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Introspect and validate the opaque
|
||||
* <a href="https://tools.ietf.org/html/rfc6750#section-1.2" target="_blank">Bearer
|
||||
* Token</a> and then delegates {@link Authentication} instantiation to
|
||||
* {@link OpaqueTokenAuthenticationConverter}.
|
||||
* </p>
|
||||
* {@link ReactiveOpaqueTokenAuthenticationConverter}.
|
||||
* <p>
|
||||
* If created Authentication is instance of {@link AbstractAuthenticationToken} and
|
||||
* details are null, then introspection result details are used.
|
||||
* </p>
|
||||
* @param authentication the authentication request object.
|
||||
* @return A successful authentication
|
||||
*/
|
||||
@@ -117,10 +112,10 @@ public class OpaqueTokenReactiveAuthenticationManager implements ReactiveAuthent
|
||||
}
|
||||
|
||||
/**
|
||||
* Default reactive {@link OpaqueTokenAuthenticationConverter}.
|
||||
* @param introspectedToken the bearer sring that was successfuly introspected
|
||||
* Default {@link ReactiveOpaqueTokenAuthenticationConverter}.
|
||||
* @param introspectedToken the bearer string that was successfully introspected
|
||||
* @param authenticatedPrincipal the successful introspection output
|
||||
* @returna an async wrapper of default {@link OpaqueTokenAuthenticationConverter}
|
||||
* @return an async wrapper of default {@link OpaqueTokenAuthenticationConverter}
|
||||
* result
|
||||
*/
|
||||
static Mono<Authentication> convert(String introspectedToken, OAuth2AuthenticatedPrincipal authenticatedPrincipal) {
|
||||
|
||||
+7
-1
@@ -20,7 +20,7 @@ import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.oauth2.core.OAuth2AuthenticatedPrincipal;
|
||||
|
||||
/**
|
||||
* Turn successful introspection result into an Authentication instance
|
||||
* Convert a successful introspection result into an authentication result.
|
||||
*
|
||||
* @author Jerome Wacongne <ch4mp@c4-soft.com>
|
||||
* @since 5.8
|
||||
@@ -28,6 +28,12 @@ import org.springframework.security.oauth2.core.OAuth2AuthenticatedPrincipal;
|
||||
@FunctionalInterface
|
||||
public interface OpaqueTokenAuthenticationConverter {
|
||||
|
||||
/**
|
||||
* Converts a successful introspection result into an authentication result.
|
||||
* @param introspectedToken the bearer token used to perform token introspection
|
||||
* @param authenticatedPrincipal the result of token introspection
|
||||
* @return an {@link Authentication} instance
|
||||
*/
|
||||
Authentication convert(String introspectedToken, OAuth2AuthenticatedPrincipal authenticatedPrincipal);
|
||||
|
||||
}
|
||||
|
||||
+7
-1
@@ -22,7 +22,7 @@ import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.oauth2.core.OAuth2AuthenticatedPrincipal;
|
||||
|
||||
/**
|
||||
* Turn successful introspection result into an Authentication instance
|
||||
* Convert a successful introspection result into an authentication result.
|
||||
*
|
||||
* @author Jerome Wacongne <ch4mp@c4-soft.com>
|
||||
* @since 5.8
|
||||
@@ -30,6 +30,12 @@ import org.springframework.security.oauth2.core.OAuth2AuthenticatedPrincipal;
|
||||
@FunctionalInterface
|
||||
public interface ReactiveOpaqueTokenAuthenticationConverter {
|
||||
|
||||
/**
|
||||
* Converts a successful introspection result into an authentication result.
|
||||
* @param introspectedToken the bearer token used to perform token introspection
|
||||
* @param authenticatedPrincipal the result of token introspection
|
||||
* @return an {@link Authentication} instance
|
||||
*/
|
||||
Mono<Authentication> convert(String introspectedToken, OAuth2AuthenticatedPrincipal authenticatedPrincipal);
|
||||
|
||||
}
|
||||
|
||||
+33
@@ -25,6 +25,7 @@ import java.util.Map;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.security.authentication.AuthenticationServiceException;
|
||||
import org.springframework.security.authentication.TestingAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.oauth2.core.OAuth2AuthenticatedPrincipal;
|
||||
import org.springframework.security.oauth2.core.OAuth2TokenIntrospectionClaimNames;
|
||||
@@ -32,6 +33,7 @@ import org.springframework.security.oauth2.core.TestOAuth2AuthenticatedPrincipal
|
||||
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.OAuth2IntrospectionException;
|
||||
import org.springframework.security.oauth2.server.resource.introspection.OpaqueTokenAuthenticationConverter;
|
||||
import org.springframework.security.oauth2.server.resource.introspection.OpaqueTokenIntrospector;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
@@ -40,6 +42,8 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||
|
||||
/**
|
||||
* Tests for {@link OpaqueTokenAuthenticationProvider}
|
||||
@@ -114,4 +118,33 @@ public class OpaqueTokenAuthenticationProviderTests {
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setAuthenticationConverterWhenNullThenThrowsIllegalArgumentException() {
|
||||
OpaqueTokenIntrospector introspector = mock(OpaqueTokenIntrospector.class);
|
||||
OpaqueTokenAuthenticationProvider provider = new OpaqueTokenAuthenticationProvider(introspector);
|
||||
// @formatter:off
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> provider.setAuthenticationConverter(null))
|
||||
.withMessage("authenticationConverter cannot be null");
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void authenticateWhenCustomAuthenticationConverterThenUses() {
|
||||
OpaqueTokenIntrospector introspector = mock(OpaqueTokenIntrospector.class);
|
||||
OAuth2AuthenticatedPrincipal principal = TestOAuth2AuthenticatedPrincipals.active();
|
||||
given(introspector.introspect(any())).willReturn(principal);
|
||||
OpaqueTokenAuthenticationProvider provider = new OpaqueTokenAuthenticationProvider(introspector);
|
||||
OpaqueTokenAuthenticationConverter authenticationConverter = mock(OpaqueTokenAuthenticationConverter.class);
|
||||
given(authenticationConverter.convert(any(), any(OAuth2AuthenticatedPrincipal.class)))
|
||||
.willReturn(new TestingAuthenticationToken(principal, null, Collections.emptyList()));
|
||||
provider.setAuthenticationConverter(authenticationConverter);
|
||||
|
||||
Authentication result = provider.authenticate(new BearerTokenAuthenticationToken("token"));
|
||||
assertThat(result).isNotNull();
|
||||
verify(introspector).introspect("token");
|
||||
verify(authenticationConverter).convert("token", principal);
|
||||
verifyNoMoreInteractions(introspector, authenticationConverter);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+35
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
* Copyright 2002-2022 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.
|
||||
@@ -26,6 +26,7 @@ import org.junit.jupiter.api.Test;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.security.authentication.AuthenticationServiceException;
|
||||
import org.springframework.security.authentication.TestingAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.oauth2.core.OAuth2AuthenticatedPrincipal;
|
||||
import org.springframework.security.oauth2.core.OAuth2TokenIntrospectionClaimNames;
|
||||
@@ -33,6 +34,7 @@ import org.springframework.security.oauth2.core.TestOAuth2AuthenticatedPrincipal
|
||||
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.OAuth2IntrospectionException;
|
||||
import org.springframework.security.oauth2.server.resource.introspection.ReactiveOpaqueTokenAuthenticationConverter;
|
||||
import org.springframework.security.oauth2.server.resource.introspection.ReactiveOpaqueTokenIntrospector;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
@@ -41,6 +43,8 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||
|
||||
/**
|
||||
* Tests for {@link OpaqueTokenReactiveAuthenticationManager}
|
||||
@@ -112,4 +116,34 @@ public class OpaqueTokenReactiveAuthenticationManagerTests {
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setAuthenticationConverterWhenNullThenThrowsIllegalArgumentException() {
|
||||
ReactiveOpaqueTokenIntrospector introspector = mock(ReactiveOpaqueTokenIntrospector.class);
|
||||
OpaqueTokenReactiveAuthenticationManager provider = new OpaqueTokenReactiveAuthenticationManager(introspector);
|
||||
// @formatter:off
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> provider.setAuthenticationConverter(null))
|
||||
.withMessage("authenticationConverter cannot be null");
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void authenticateWhenCustomAuthenticationConverterThenUses() {
|
||||
ReactiveOpaqueTokenIntrospector introspector = mock(ReactiveOpaqueTokenIntrospector.class);
|
||||
OAuth2AuthenticatedPrincipal principal = TestOAuth2AuthenticatedPrincipals.active();
|
||||
given(introspector.introspect(any())).willReturn(Mono.just(principal));
|
||||
OpaqueTokenReactiveAuthenticationManager provider = new OpaqueTokenReactiveAuthenticationManager(introspector);
|
||||
ReactiveOpaqueTokenAuthenticationConverter authenticationConverter = mock(
|
||||
ReactiveOpaqueTokenAuthenticationConverter.class);
|
||||
given(authenticationConverter.convert(any(), any(OAuth2AuthenticatedPrincipal.class)))
|
||||
.willReturn(Mono.just(new TestingAuthenticationToken(principal, null, Collections.emptyList())));
|
||||
provider.setAuthenticationConverter(authenticationConverter);
|
||||
|
||||
Authentication result = provider.authenticate(new BearerTokenAuthenticationToken("token")).block();
|
||||
assertThat(result).isNotNull();
|
||||
verify(introspector).introspect("token");
|
||||
verify(authenticationConverter).convert("token", principal);
|
||||
verifyNoMoreInteractions(introspector, authenticationConverter);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user