diff --git a/docs/src/main/asciidoc/spring-cloud-openfeign.adoc b/docs/src/main/asciidoc/spring-cloud-openfeign.adoc
index 26cbe520..3dd8e88e 100644
--- a/docs/src/main/asciidoc/spring-cloud-openfeign.adoc
+++ b/docs/src/main/asciidoc/spring-cloud-openfeign.adoc
@@ -811,6 +811,19 @@ When the flag is set to true, and the oauth2 client context resource details are
Sometimes, when load balancing is enabled for Feign clients, you may want to use load balancing for fetching access tokens, too. To do so, you should ensure that the load balancer is on the classpath (spring-cloud-starter-loadbalancer) and explicitly enable load balancing for OAuth2FeignRequestInterceptor by setting the following flag:
----
feign.oauth2.load-balanced=true
+
+When the flag is set to true, and the oauth2 client context resource details are present, a bean of class `OAuth2AccessTokenInterceptor` is created. Before each request, the interceptor resolves the required access token and includes it as a header.
+`OAuth2AccessTokenInterceptor` uses the `AuthorizedClientServiceOAuth2AuthorizedClientManager` to get `OAuth2AuthorizedClient` that holds an `OAuth2AccessToken`. If the user has specified an OAuth2 `clientId` using the `spring.cloud.openfeign.oauth2.clientId` property, it will be used to retrieve the token. If the token is not retrieved or the `clientId` has not been specified, the `serviceId` retrieved from the `url` host segment will be used.
+
+TIP:: Using the `serviceId` as OAuth2 client id is convenient for load-balanced Feign clients. For non-load-balanced ones, the property-based `clientId` is a suitable approach.
+
+=== Transform the load-balanced HTTP request
+
+You can use the selected `ServiceInstance` to transform the load-balanced HTTP Request.
+
+For `Request`, you need to implement and define `LoadBalancerFeignRequestTransformer`, as follows:
+
+[source,java,indent=0]
----
== Configuration properties
diff --git a/spring-cloud-openfeign-core/pom.xml b/spring-cloud-openfeign-core/pom.xml
index b441393d..306c4474 100644
--- a/spring-cloud-openfeign-core/pom.xml
+++ b/spring-cloud-openfeign-core/pom.xml
@@ -228,6 +228,7 @@
org.springframework.security
spring-security-oauth2-client
+ true
diff --git a/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/FeignAutoConfiguration.java b/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/FeignAutoConfiguration.java
index ec97c25d..a182c0d9 100644
--- a/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/FeignAutoConfiguration.java
+++ b/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/FeignAutoConfiguration.java
@@ -51,7 +51,6 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
-import org.springframework.boot.autoconfigure.security.oauth2.client.OAuth2ClientProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cache.interceptor.CacheInterceptor;
import org.springframework.cloud.client.actuator.HasFeatures;
@@ -383,13 +382,11 @@ public class FeignAutoConfiguration {
@Bean
@ConditionalOnBean({OAuth2AuthorizedClientService.class, ClientRegistrationRepository.class})
public OAuth2AccessTokenInterceptor defaultOAuth2AccessTokenInterceptor(
- @Value("${spring.cloud.openfeign.oauth2.specifiedClientIds:}") List specifiedClientIds,
- OAuth2ClientProperties oAuth2ClientProperties,
+ @Value("${spring.cloud.openfeign.oauth2.clientId:}") String clientId,
OAuth2AuthorizedClientService oAuth2AuthorizedClientService,
ClientRegistrationRepository clientRegistrationRepository) {
-
- return new OAuth2AccessTokenInterceptor(specifiedClientIds, oAuth2ClientProperties,
- oAuth2AuthorizedClientService, clientRegistrationRepository);
+ return new OAuth2AccessTokenInterceptor(clientId, oAuth2AuthorizedClientService,
+ clientRegistrationRepository);
}
}
diff --git a/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/security/OAuth2AccessTokenInterceptor.java b/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/security/OAuth2AccessTokenInterceptor.java
index cc017006..b421d0ae 100644
--- a/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/security/OAuth2AccessTokenInterceptor.java
+++ b/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/security/OAuth2AccessTokenInterceptor.java
@@ -16,17 +16,14 @@
package org.springframework.cloud.openfeign.security;
+import java.net.URI;
import java.time.Instant;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
import java.util.Optional;
import feign.RequestInterceptor;
import feign.RequestTemplate;
+import feign.Target;
-import org.springframework.boot.autoconfigure.security.oauth2.client.OAuth2ClientProperties;
import org.springframework.security.authentication.AnonymousAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.authority.AuthorityUtils;
@@ -38,16 +35,22 @@ import org.springframework.security.oauth2.client.OAuth2AuthorizedClientManager;
import org.springframework.security.oauth2.client.OAuth2AuthorizedClientService;
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
import org.springframework.security.oauth2.core.OAuth2AccessToken;
+import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
- * RequestInterceptor for OAuth2 Feign Requests. By default, It uses the
+ * A {@link RequestInterceptor} for OAuth2 Feign Requests. By default, it uses the
* {@link AuthorizedClientServiceOAuth2AuthorizedClientManager } to get
- * {@link OAuth2AuthorizedClient } that hold an {@link OAuth2AccessToken }. Use the
- * Client(s) from properties if not specific the field
- * {@link OAuth2AccessTokenInterceptor#specifiedClientIds}
+ * {@link OAuth2AuthorizedClient } that holds an {@link OAuth2AccessToken }. If the user
+ * has specified an OAuth2 {@code clientId} using the
+ * {@code spring.cloud.openfeign.oauth2.clientId} property, it will be used to retrieve
+ * the token. If the token is not retrieved or the {@code clientId} has not been
+ * specified, the {@code serviceId} retrieved from the {@code url} host segment will be
+ * used. This approach is convenient for load-balanced Feign clients. For
+ * non-load-balanced ones, the property-based {@code clientId} is a suitable approach.
*
* @author Dangzhicairang(小水牛)
+ * @author Olga Maciaszek-Sharma
* @since 4.0.0
*/
public class OAuth2AccessTokenInterceptor implements RequestInterceptor {
@@ -66,9 +69,7 @@ public class OAuth2AccessTokenInterceptor implements RequestInterceptor {
private final String header;
- private final List specifiedClientIds;
-
- private final OAuth2ClientProperties oAuth2ClientProperties;
+ private final String clientId;
private final OAuth2AuthorizedClientService oAuth2AuthorizedClientService;
@@ -79,69 +80,56 @@ public class OAuth2AccessTokenInterceptor implements RequestInterceptor {
}
private static final Authentication ANONYMOUS_AUTHENTICATION = new AnonymousAuthenticationToken("anonymous",
- "anonymousUser", AuthorityUtils.createAuthorityList("ROLE_ANONYMOUS"));
+ "anonymousUser", AuthorityUtils.createAuthorityList("ROLE_ANONYMOUS"));
- public OAuth2AccessTokenInterceptor(OAuth2ClientProperties oAuth2ClientProperties,
- OAuth2AuthorizedClientService oAuth2AuthorizedClientService,
- ClientRegistrationRepository clientRegistrationRepository) {
- this(new ArrayList<>(), oAuth2ClientProperties, oAuth2AuthorizedClientService, clientRegistrationRepository);
+ public OAuth2AccessTokenInterceptor(OAuth2AuthorizedClientService oAuth2AuthorizedClientService,
+ ClientRegistrationRepository clientRegistrationRepository) {
+ this(null, oAuth2AuthorizedClientService, clientRegistrationRepository);
}
- public OAuth2AccessTokenInterceptor(List specifiedClientIds, OAuth2ClientProperties oAuth2ClientProperties,
- OAuth2AuthorizedClientService oAuth2AuthorizedClientService,
- ClientRegistrationRepository clientRegistrationRepository) {
- this(BEARER, AUTHORIZATION, specifiedClientIds, oAuth2ClientProperties, oAuth2AuthorizedClientService,
- clientRegistrationRepository);
+ public OAuth2AccessTokenInterceptor(String clientId, OAuth2AuthorizedClientService oAuth2AuthorizedClientService,
+ ClientRegistrationRepository clientRegistrationRepository) {
+ this(BEARER, AUTHORIZATION, clientId, oAuth2AuthorizedClientService, clientRegistrationRepository);
}
- public OAuth2AccessTokenInterceptor(String tokenType, String header, List specifiedClientIds,
- OAuth2ClientProperties oAuth2ClientProperties, OAuth2AuthorizedClientService oAuth2AuthorizedClientService,
- ClientRegistrationRepository clientRegistrationRepository) {
+ public OAuth2AccessTokenInterceptor(String tokenType, String header, String clientId,
+ OAuth2AuthorizedClientService oAuth2AuthorizedClientService,
+ ClientRegistrationRepository clientRegistrationRepository) {
this.tokenType = tokenType;
this.header = header;
- this.specifiedClientIds = specifiedClientIds;
- this.oAuth2ClientProperties = oAuth2ClientProperties;
+ this.clientId = clientId;
this.oAuth2AuthorizedClientService = oAuth2AuthorizedClientService;
this.authorizedClientManager = new AuthorizedClientServiceOAuth2AuthorizedClientManager(
- clientRegistrationRepository, this.oAuth2AuthorizedClientService);
+ clientRegistrationRepository, this.oAuth2AuthorizedClientService);
}
@Override
public void apply(RequestTemplate template) {
+ OAuth2AccessToken token = getToken(template);
+ String extractedToken = String.format("%s %s", tokenType, token.getTokenValue());
template.header(header);
- template.header(header, extract(tokenType));
+ template.header(header, extractedToken);
}
- protected String extract(String tokenType) {
- OAuth2AccessToken accessToken = getToken();
- return String.format("%s %s", tokenType, accessToken.getTokenValue());
- }
-
- public OAuth2AccessToken getToken() {
-
- // if specific, try to use them to get token.
- for (String clientId : this.specifiedClientIds) {
- OAuth2AccessToken token = this.getToken(clientId);
+ public OAuth2AccessToken getToken(RequestTemplate template) {
+ // If specified, try to use them to get token.
+ if (StringUtils.hasText(clientId)) {
+ OAuth2AccessToken token = getToken(clientId);
if (token != null) {
return token;
}
}
- // use clients from properties by default
- for (String clientId : Optional.ofNullable(this.oAuth2ClientProperties)
- .map(OAuth2ClientProperties::getRegistration).map(Map::keySet)
- .orElse(new HashSet<>())) {
- OAuth2AccessToken token = this.getToken(clientId);
- if (token != null) {
- return token;
- }
+ // If not specified use host (synonymous with serviceId for load-balanced
+ // requests; non-load-balanced requests should use the method above).
+ OAuth2AccessToken token = getToken(getServiceId(template));
+ if (token != null) {
+ return token;
}
-
- throw new IllegalStateException("No token acquired, which is illegal according to the contract.");
+ throw new IllegalStateException("OAuth2 token has not been successfully acquired.");
}
protected OAuth2AccessToken getToken(String clientId) {
-
if (!StringUtils.hasText(clientId)) {
return null;
}
@@ -151,27 +139,35 @@ public class OAuth2AccessTokenInterceptor implements RequestInterceptor {
principal = ANONYMOUS_AUTHENTICATION;
}
- // already exist
+ // Already exist
OAuth2AuthorizedClient oAuth2AuthorizedClient = oAuth2AuthorizedClientService.loadAuthorizedClient(clientId,
- principal.getName());
+ principal.getName());
if (oAuth2AuthorizedClient != null) {
OAuth2AccessToken accessToken = oAuth2AuthorizedClient.getAccessToken();
- if (accessToken != null && this.noExpire(accessToken)) {
+ if (accessToken != null && notExpired(accessToken)) {
return accessToken;
}
}
OAuth2AuthorizeRequest authorizeRequest = OAuth2AuthorizeRequest.withClientRegistrationId(clientId)
- .principal(principal).build();
- OAuth2AuthorizedClient authorize = this.authorizedClientManager.authorize(authorizeRequest);
- return Optional.ofNullable(authorize).map(OAuth2AuthorizedClient::getAccessToken)
- .filter(this::noExpire)
- .orElse(null);
+ .principal(principal).build();
+ OAuth2AuthorizedClient authorizedClient = authorizedClientManager.authorize(authorizeRequest);
+ return Optional.ofNullable(authorizedClient).map(OAuth2AuthorizedClient::getAccessToken)
+ .filter(this::notExpired).orElse(null);
}
- protected boolean noExpire(OAuth2AccessToken token) {
+ protected boolean notExpired(OAuth2AccessToken token) {
return Optional.ofNullable(token).map(OAuth2AccessToken::getExpiresAt)
- .map(expire -> expire.isAfter(Instant.now())).orElse(false);
+ .map(expire -> expire.isAfter(Instant.now())).orElse(false);
+ }
+
+ private static String getServiceId(RequestTemplate template) {
+ Target> feignTarget = template.feignTarget();
+ Assert.notNull(feignTarget, "feignTarget may not be null");
+ String url = feignTarget.url();
+ Assert.hasLength(url, "url may not be empty");
+ final URI originalUri = URI.create(url);
+ return originalUri.getHost();
}
}
diff --git a/spring-cloud-openfeign-core/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/spring-cloud-openfeign-core/src/main/resources/META-INF/additional-spring-configuration-metadata.json
index 73ff218b..88c42c56 100644
--- a/spring-cloud-openfeign-core/src/main/resources/META-INF/additional-spring-configuration-metadata.json
+++ b/spring-cloud-openfeign-core/src/main/resources/META-INF/additional-spring-configuration-metadata.json
@@ -79,6 +79,12 @@
"type": "java.lang.Boolean",
"description": "Enables load balancing for oauth2 access token provider.",
"defaultValue": "false"
+ },
+ {
+ "name": "feign.oauth2.registrationClientId",
+ "type": "java.lang.String",
+ "description": "Provides a clientId to be used with OAuth2.",
+ "defaultValue": ""
}
]
}
diff --git a/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/FeignAutoConfigurationTests.java b/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/FeignAutoConfigurationTests.java
index 4997f29e..a8f1c919 100644
--- a/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/FeignAutoConfigurationTests.java
+++ b/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/FeignAutoConfigurationTests.java
@@ -17,8 +17,6 @@
package org.springframework.cloud.openfeign;
import java.lang.reflect.Method;
-import java.util.ArrayList;
-import java.util.List;
import feign.Target;
import org.assertj.core.api.Condition;
@@ -141,17 +139,12 @@ class FeignAutoConfigurationTests {
@Test
void shouldInstantiateFeignOAuth2FeignRequestInterceptor() {
runner.withPropertyValues("spring.cloud.openfeign.oauth2.enabled=true",
- "spring.cloud.openfeign.oauth2.specifiedClientIds=feign-client")
+ "spring.cloud.openfeign.oauth2.clientId=feign-client")
.withBean(OAuth2AuthorizedClientService.class, () -> mock(OAuth2AuthorizedClientService.class))
.withBean(ClientRegistrationRepository.class, () -> mock(ClientRegistrationRepository.class))
.run(ctx -> {
assertOauth2AccessTokenInterceptorExists(ctx);
- assertThatOauth2AccessTokenInterceptorHasSpecifiedIdsPropertyWithValue(ctx,
- new ArrayList() {
- {
- add("feign-client");
- }
- });
+ assertThatOauth2AccessTokenInterceptorHasSpecifiedIdsPropertyWithValue(ctx, "feign-client");
});
}
@@ -184,9 +177,9 @@ class FeignAutoConfigurationTests {
}
private void assertThatOauth2AccessTokenInterceptorHasSpecifiedIdsPropertyWithValue(
- ConfigurableApplicationContext ctx, List expectedValue) {
+ ConfigurableApplicationContext ctx, String expectedValue) {
final OAuth2AccessTokenInterceptor bean = ctx.getBean(OAuth2AccessTokenInterceptor.class);
- assertThat(bean).hasFieldOrPropertyWithValue("specifiedClientIds", expectedValue);
+ assertThat(bean).hasFieldOrPropertyWithValue("clientId", expectedValue);
}
private void assertOnlyOneTargeterPresent(ConfigurableApplicationContext ctx, Class> beanClass) {
diff --git a/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/security/OAuth2AccessTokenInterceptorTests.java b/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/security/OAuth2AccessTokenInterceptorTests.java
index 4242609b..9a825e57 100644
--- a/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/security/OAuth2AccessTokenInterceptorTests.java
+++ b/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/security/OAuth2AccessTokenInterceptorTests.java
@@ -17,15 +17,14 @@
package org.springframework.cloud.openfeign.security;
import java.time.Instant;
-import java.util.HashMap;
import feign.Request.HttpMethod;
import feign.RequestTemplate;
-import org.assertj.core.api.Assertions;
+import feign.Target;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
-import org.springframework.boot.autoconfigure.security.oauth2.client.OAuth2ClientProperties;
+import org.springframework.security.oauth2.client.OAuth2AuthorizeRequest;
import org.springframework.security.oauth2.client.OAuth2AuthorizedClient;
import org.springframework.security.oauth2.client.OAuth2AuthorizedClientManager;
import org.springframework.security.oauth2.client.OAuth2AuthorizedClientService;
@@ -35,121 +34,117 @@ import org.springframework.security.oauth2.core.AuthorizationGrantType;
import org.springframework.security.oauth2.core.OAuth2AccessToken;
import org.springframework.util.AlternativeJdkIdGenerator;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.BDDMockito.given;
+import static org.mockito.ArgumentMatchers.argThat;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
/**
+ * Tests for {@link OAuth2AccessTokenInterceptor}.
+ *
* @author Dangzhicairang(小水牛)
+ * @author Olga Maciaszek-Sharma
+ *
*/
class OAuth2AccessTokenInterceptorTests {
+ private final OAuth2AuthorizedClientService mockOAuth2AuthorizedClientService = mock(
+ OAuth2AuthorizedClientService.class);
+
+ private final OAuth2AuthorizedClientManager mockOAuth2AuthorizedClientManager = mock(
+ OAuth2AuthorizedClientManager.class);
+
private OAuth2AccessTokenInterceptor oAuth2AccessTokenInterceptor;
private RequestTemplate requestTemplate;
- private OAuth2ClientProperties mockOAuth2ClientProperties;
-
private static final String DEFAULT_CLIENT_ID = "feign-client";
@BeforeEach
void setUp() {
-
requestTemplate = new RequestTemplate().method(HttpMethod.GET);
-
- mockOAuth2ClientProperties = mock(OAuth2ClientProperties.class);
- given(mockOAuth2ClientProperties.getRegistration())
- .willReturn(new HashMap() {
- {
- put(DEFAULT_CLIENT_ID, mock(OAuth2ClientProperties.Registration.class));
- }
- });
-
+ Target> feignTarget = mock(Target.class);
+ when(feignTarget.url()).thenReturn("http://test");
+ requestTemplate.feignTarget(feignTarget);
}
@Test
- void noTokenAcquired() {
-
- OAuth2AuthorizedClientService mockOAuth2AuthorizedClientService = mock(OAuth2AuthorizedClientService.class);
- given(mockOAuth2AuthorizedClientService.loadAuthorizedClient(anyString(), anyString())).willReturn(null);
-
- oAuth2AccessTokenInterceptor = new OAuth2AccessTokenInterceptor(mockOAuth2ClientProperties,
- mockOAuth2AuthorizedClientService, mock(ClientRegistrationRepository.class));
-
- OAuth2AuthorizedClientManager mockOAuth2AuthorizedClientManager = mock(OAuth2AuthorizedClientManager.class);
- given(mockOAuth2AuthorizedClientManager.authorize(any())).willReturn(null);
-
+ void shouldThrowExceptionWhenNoTokenAcquired() {
+ when(mockOAuth2AuthorizedClientService.loadAuthorizedClient(anyString(), anyString())).thenReturn(null);
+ oAuth2AccessTokenInterceptor = new OAuth2AccessTokenInterceptor(mockOAuth2AuthorizedClientService,
+ mock(ClientRegistrationRepository.class));
+ when(mockOAuth2AuthorizedClientManager.authorize(any())).thenReturn(null);
oAuth2AccessTokenInterceptor.setAuthorizedClientManager(mockOAuth2AuthorizedClientManager);
- Assertions.assertThatExceptionOfType(IllegalStateException.class)
- .isThrownBy(() -> oAuth2AccessTokenInterceptor.apply(requestTemplate))
- .withMessage("No token acquired, which is illegal according to the contract.");
-
+ assertThatExceptionOfType(IllegalStateException.class)
+ .isThrownBy(() -> oAuth2AccessTokenInterceptor.apply(requestTemplate))
+ .withMessage("OAuth2 token has not been successfully acquired.");
}
@Test
- void validTokenAcquired() {
-
- OAuth2AuthorizedClientService mockOAuth2AuthorizedClientService = mock(OAuth2AuthorizedClientService.class);
- given(mockOAuth2AuthorizedClientService.loadAuthorizedClient(anyString(), anyString())).willReturn(null);
-
- oAuth2AccessTokenInterceptor = new OAuth2AccessTokenInterceptor(mockOAuth2ClientProperties,
- mockOAuth2AuthorizedClientService, mock(ClientRegistrationRepository.class));
-
- OAuth2AuthorizedClientManager mockOAuth2AuthorizedClientManager = mock(OAuth2AuthorizedClientManager.class);
- given(mockOAuth2AuthorizedClientManager.authorize(any())).willReturn(validTokenOAuth2AuthorizedClient());
-
+ void shouldAcquireValidToken() {
+ when(mockOAuth2AuthorizedClientService.loadAuthorizedClient(anyString(), anyString())).thenReturn(null);
+ oAuth2AccessTokenInterceptor = new OAuth2AccessTokenInterceptor(mockOAuth2AuthorizedClientService,
+ mock(ClientRegistrationRepository.class));
+ when(mockOAuth2AuthorizedClientManager.authorize(
+ argThat((OAuth2AuthorizeRequest request) -> ("test").equals(request.getClientRegistrationId()))))
+ .thenReturn(validTokenOAuth2AuthorizedClient());
oAuth2AccessTokenInterceptor.setAuthorizedClientManager(mockOAuth2AuthorizedClientManager);
oAuth2AccessTokenInterceptor.apply(requestTemplate);
- Assertions.assertThat(requestTemplate.headers().get("Authorization"))
- .contains("Bearer Valid Token");
+ assertThat(requestTemplate.headers().get("Authorization")).contains("Bearer Valid Token");
}
@Test
- void expireTokenAcquired() {
-
- OAuth2AuthorizedClientService mockOAuth2AuthorizedClientService = mock(OAuth2AuthorizedClientService.class);
- given(mockOAuth2AuthorizedClientService.loadAuthorizedClient(anyString(), anyString())).willReturn(null);
-
- oAuth2AccessTokenInterceptor = new OAuth2AccessTokenInterceptor(mockOAuth2ClientProperties,
- mockOAuth2AuthorizedClientService, mock(ClientRegistrationRepository.class));
-
- OAuth2AuthorizedClientManager mockOAuth2AuthorizedClientManager = mock(OAuth2AuthorizedClientManager.class);
- given(mockOAuth2AuthorizedClientManager.authorize(any())).willReturn(expiredTokenOAuth2AuthorizedClient());
-
+ void shouldThrowExceptionWhenExpiredTokenAcquired() {
+ when(mockOAuth2AuthorizedClientService.loadAuthorizedClient(anyString(), anyString())).thenReturn(null);
+ oAuth2AccessTokenInterceptor = new OAuth2AccessTokenInterceptor(mockOAuth2AuthorizedClientService,
+ mock(ClientRegistrationRepository.class));
+ when(mockOAuth2AuthorizedClientManager.authorize(any())).thenReturn(expiredTokenOAuth2AuthorizedClient());
oAuth2AccessTokenInterceptor.setAuthorizedClientManager(mockOAuth2AuthorizedClientManager);
- Assertions.assertThatExceptionOfType(IllegalStateException.class)
- .isThrownBy(() -> oAuth2AccessTokenInterceptor.apply(requestTemplate))
- .withMessage("No token acquired, which is illegal according to the contract.");
+ assertThatExceptionOfType(IllegalStateException.class)
+ .isThrownBy(() -> oAuth2AccessTokenInterceptor.apply(requestTemplate))
+ .withMessage("OAuth2 token has not been successfully acquired.");
}
@Test
- void acquireTokenFromAuthorizedClient() {
- OAuth2AuthorizedClientService mockOAuth2AuthorizedClientService = mock(OAuth2AuthorizedClientService.class);
- given(mockOAuth2AuthorizedClientService.loadAuthorizedClient(anyString(), anyString()))
- .willReturn(validTokenOAuth2AuthorizedClient());
-
- oAuth2AccessTokenInterceptor = new OAuth2AccessTokenInterceptor(mockOAuth2ClientProperties,
- mockOAuth2AuthorizedClientService, mock(ClientRegistrationRepository.class));
+ void shouldAcquireTokenFromAuthorizedClient() {
+ when(mockOAuth2AuthorizedClientService.loadAuthorizedClient(eq("test"), anyString()))
+ .thenReturn(validTokenOAuth2AuthorizedClient());
+ oAuth2AccessTokenInterceptor = new OAuth2AccessTokenInterceptor(mockOAuth2AuthorizedClientService,
+ mock(ClientRegistrationRepository.class));
oAuth2AccessTokenInterceptor.apply(requestTemplate);
- Assertions.assertThat(requestTemplate.headers().get("Authorization"))
- .contains("Bearer Valid Token");
+ assertThat(requestTemplate.headers().get("Authorization")).contains("Bearer Valid Token");
+ }
+
+ @Test
+ void shouldAcquireValidTokenFromSpecifiedClientId() {
+ when(mockOAuth2AuthorizedClientService.loadAuthorizedClient(eq("testId"), anyString()))
+ .thenReturn(validTokenOAuth2AuthorizedClient());
+ oAuth2AccessTokenInterceptor = new OAuth2AccessTokenInterceptor("testId", mockOAuth2AuthorizedClientService,
+ mock(ClientRegistrationRepository.class));
+
+ oAuth2AccessTokenInterceptor.apply(requestTemplate);
+
+ assertThat(requestTemplate.headers().get("Authorization")).contains("Bearer Valid Token");
}
private OAuth2AccessToken validToken() {
return new OAuth2AccessToken(OAuth2AccessToken.TokenType.BEARER, "Valid Token", Instant.now(),
- Instant.now().plusSeconds(60L));
+ Instant.now().plusSeconds(60L));
}
private OAuth2AccessToken expiredToken() {
return new OAuth2AccessToken(OAuth2AccessToken.TokenType.BEARER, "Expired Token",
- Instant.now().minusSeconds(61L), Instant.now().minusSeconds(60L));
+ Instant.now().minusSeconds(61L), Instant.now().minusSeconds(60L));
}
private OAuth2AuthorizedClient validTokenOAuth2AuthorizedClient() {
@@ -161,10 +156,9 @@ class OAuth2AccessTokenInterceptorTests {
}
private ClientRegistration defaultClientRegistration() {
- return ClientRegistration.withRegistrationId(new AlternativeJdkIdGenerator().generateId()
- .toString())
- .clientId(DEFAULT_CLIENT_ID).tokenUri("mock token uri")
- .authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS).build();
+ return ClientRegistration.withRegistrationId(new AlternativeJdkIdGenerator().generateId().toString())
+ .clientId(DEFAULT_CLIENT_ID).tokenUri("mock token uri")
+ .authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS).build();
}
}
diff --git a/spring-cloud-openfeign-dependencies/pom.xml b/spring-cloud-openfeign-dependencies/pom.xml
index a46020b6..70929ac7 100644
--- a/spring-cloud-openfeign-dependencies/pom.xml
+++ b/spring-cloud-openfeign-dependencies/pom.xml
@@ -19,7 +19,6 @@
3.8.0
2.5.2
- 6.0.0-SNAPSHOT
@@ -31,7 +30,6 @@
org.springframework.security
spring-security-oauth2-client
- ${spring-security-oauth2-client.version}
org.springframework.cloud