Add authentication converter for introspected tokens
Adds configurable authentication converter for resource-servers with token introspection (something very similar to what JwtAuthenticationConverter does for resource-servers with JWT decoder). The new (Reactive)OpaqueTokenAuthenticationConverter is given responsibility for converting successful token introspection result into an Authentication instance (which is currently done by a private methods of OpaqueTokenAuthenticationProvider and OpaqueTokenReactiveAuthenticationManager). The default (Reactive)OpaqueTokenAuthenticationConverter, behave the same as current private convert(OAuth2AuthenticatedPrincipal principal, String token) methods: map authorities from scope attribute and build a BearerTokenAuthentication. Closes gh-11661
This commit is contained in:
@@ -23,6 +23,7 @@ import java.security.interfaces.RSAPublicKey;
|
||||
import java.time.Clock;
|
||||
import java.time.Instant;
|
||||
import java.time.ZoneId;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
@@ -68,13 +69,17 @@ import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.RequestEntity;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.security.authentication.AbstractAuthenticationToken;
|
||||
import org.springframework.security.authentication.AuthenticationManagerResolver;
|
||||
import org.springframework.security.authentication.AuthenticationServiceException;
|
||||
import org.springframework.security.config.http.OAuth2ResourceServerBeanDefinitionParser.JwtBeanDefinitionParser;
|
||||
import org.springframework.security.config.http.OAuth2ResourceServerBeanDefinitionParser.OpaqueTokenBeanDefinitionParser;
|
||||
import org.springframework.security.config.test.SpringTestContext;
|
||||
import org.springframework.security.config.test.SpringTestContextExtension;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.context.SecurityContextHolderStrategy;
|
||||
import org.springframework.security.oauth2.core.OAuth2AuthenticatedPrincipal;
|
||||
import org.springframework.security.oauth2.core.OAuth2Error;
|
||||
import org.springframework.security.oauth2.core.OAuth2TokenValidator;
|
||||
import org.springframework.security.oauth2.core.OAuth2TokenValidatorResult;
|
||||
@@ -87,6 +92,7 @@ import org.springframework.security.oauth2.jwt.NimbusJwtDecoder;
|
||||
import org.springframework.security.oauth2.jwt.TestJwts;
|
||||
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken;
|
||||
import org.springframework.security.oauth2.server.resource.introspection.NimbusOpaqueTokenIntrospector;
|
||||
import org.springframework.security.oauth2.server.resource.introspection.OpaqueTokenAuthenticationConverter;
|
||||
import org.springframework.security.oauth2.server.resource.introspection.OpaqueTokenIntrospector;
|
||||
import org.springframework.security.oauth2.server.resource.web.BearerTokenResolver;
|
||||
import org.springframework.security.test.context.annotation.SecurityTestExecutionListeners;
|
||||
@@ -662,6 +668,20 @@ public class OAuth2ResourceServerBeanDefinitionParserTests {
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void configureWhenIntrospectingWithAuthenticationConverterThenUses() throws Exception {
|
||||
this.spring.configLocations(xml("OpaqueTokenRestOperations"), xml("OpaqueTokenAndAuthenticationConverter"))
|
||||
.autowire();
|
||||
mockRestOperations(json("Active"));
|
||||
// @formatter:off
|
||||
this.mvc.perform(get("/authenticated").header("Authorization", "Bearer token"))
|
||||
.andExpect(status().isNotFound());
|
||||
|
||||
this.mvc.perform(get("/authenticated").header("Authorization", "Bearer invalidToken"))
|
||||
.andExpect(status().isUnauthorized());
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getWhenIntrospectionFailsThenUnauthorized() throws Exception {
|
||||
this.spring.configLocations(xml("OpaqueTokenRestOperations"), xml("OpaqueToken")).autowire();
|
||||
@@ -1096,4 +1116,39 @@ public class OAuth2ResourceServerBeanDefinitionParserTests {
|
||||
|
||||
}
|
||||
|
||||
public static class TestAuthentication extends AbstractAuthenticationToken {
|
||||
|
||||
private final String introspectedToken;
|
||||
|
||||
public TestAuthentication(String introspectedToken, Collection<? extends GrantedAuthority> authorities) {
|
||||
super(authorities);
|
||||
this.introspectedToken = introspectedToken;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getCredentials() {
|
||||
return this.introspectedToken;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getPrincipal() {
|
||||
return this.introspectedToken;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAuthenticated() {
|
||||
return "token".equals(this.introspectedToken);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class TestOpaqueTokenAuthenticationConverter implements OpaqueTokenAuthenticationConverter {
|
||||
|
||||
@Override
|
||||
public Authentication convert(String introspectedToken, OAuth2AuthenticatedPrincipal authenticatedPrincipal) {
|
||||
return new TestAuthentication(introspectedToken, Collections.emptyList());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
~ Copyright 2002-2020 the original author or authors.
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ https://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
|
||||
<b:beans xmlns:b="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns="http://www.springframework.org/schema/security"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/security https://www.springframework.org/schema/security/spring-security.xsd
|
||||
http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd">
|
||||
|
||||
<b:bean name="authentication-converter"
|
||||
class="org.springframework.security.config.http.OAuth2ResourceServerBeanDefinitionParserTests$TestOpaqueTokenAuthenticationConverter">
|
||||
</b:bean>
|
||||
|
||||
<http>
|
||||
<intercept-url pattern="/requires-read-scope" access="hasAuthority('SCOPE_message:read')"/>
|
||||
<intercept-url pattern="/**" access="authenticated"/>
|
||||
<oauth2-resource-server>
|
||||
<opaque-token introspector-ref="introspector" authentication-converter-ref="authentication-converter"/>
|
||||
</oauth2-resource-server>
|
||||
</http>
|
||||
|
||||
<b:import resource="userservice.xml"/>
|
||||
</b:beans>
|
||||
Reference in New Issue
Block a user