Skip to content

Commit 3dbfef9

Browse files
committed
OAuth2AccessTokenResponseHttpMessageConverter handles JSON object parameters
Fixes gh-6463
1 parent 8acdb82 commit 3dbfef9

File tree

2 files changed

+46
-6
lines changed

2 files changed

+46
-6
lines changed

oauth2/oauth2-core/src/main/java/org/springframework/security/oauth2/core/http/converter/OAuth2AccessTokenResponseHttpMessageConverter.java

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2018 the original author or authors.
2+
* Copyright 2002-2020 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -43,6 +43,7 @@
4343
import java.util.Collections;
4444
import java.util.LinkedHashMap;
4545
import java.util.HashMap;
46+
import java.util.stream.Collectors;
4647

4748
/**
4849
* A {@link HttpMessageConverter} for an {@link OAuth2AccessTokenResponse OAuth 2.0 Access Token Response}.
@@ -55,8 +56,8 @@
5556
public class OAuth2AccessTokenResponseHttpMessageConverter extends AbstractHttpMessageConverter<OAuth2AccessTokenResponse> {
5657
private static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8;
5758

58-
private static final ParameterizedTypeReference<Map<String, String>> PARAMETERIZED_RESPONSE_TYPE =
59-
new ParameterizedTypeReference<Map<String, String>>() {};
59+
private static final ParameterizedTypeReference<Map<String, Object>> PARAMETERIZED_RESPONSE_TYPE =
60+
new ParameterizedTypeReference<Map<String, Object>>() {};
6061

6162
private GenericHttpMessageConverter<Object> jsonMessageConverter = HttpMessageConverters.getJsonMessageConverter();
6263

@@ -80,10 +81,16 @@ protected OAuth2AccessTokenResponse readInternal(Class<? extends OAuth2AccessTok
8081
throws HttpMessageNotReadableException {
8182

8283
try {
84+
// gh-6463
85+
// Parse parameter values as Object in order to handle potential JSON Object and then convert values to String
8386
@SuppressWarnings("unchecked")
84-
Map<String, String> tokenResponseParameters = (Map<String, String>) this.jsonMessageConverter.read(
87+
Map<String, Object> tokenResponseParameters = (Map<String, Object>) this.jsonMessageConverter.read(
8588
PARAMETERIZED_RESPONSE_TYPE.getType(), null, inputMessage);
86-
return this.tokenResponseConverter.convert(tokenResponseParameters);
89+
return this.tokenResponseConverter.convert(
90+
tokenResponseParameters.entrySet().stream()
91+
.collect(Collectors.toMap(
92+
Map.Entry::getKey,
93+
entry -> entry.getValue().toString())));
8794
} catch (Exception ex) {
8895
throw new HttpMessageNotReadableException("An error occurred reading the OAuth 2.0 Access Token Response: " +
8996
ex.getMessage(), ex, inputMessage);

oauth2/oauth2-core/src/test/java/org/springframework/security/oauth2/core/http/converter/OAuth2AccessTokenResponseHttpMessageConverterTests.java

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2018 the original author or authors.
2+
* Copyright 2002-2020 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -96,6 +96,39 @@ public void readInternalWhenSuccessfulTokenResponseThenReadOAuth2AccessTokenResp
9696

9797
}
9898

99+
// gh-6463
100+
@Test
101+
public void readInternalWhenSuccessfulTokenResponseWithObjectThenReadOAuth2AccessTokenResponse() {
102+
String tokenResponse = "{\n" +
103+
" \"access_token\": \"access-token-1234\",\n" +
104+
" \"token_type\": \"bearer\",\n" +
105+
" \"expires_in\": 3600,\n" +
106+
" \"scope\": \"read write\",\n" +
107+
" \"refresh_token\": \"refresh-token-1234\",\n" +
108+
" \"custom_object_1\": {\"name1\": \"value1\"},\n" +
109+
" \"custom_object_2\": [\"value1\", \"value2\"],\n" +
110+
" \"custom_parameter_1\": \"custom-value-1\",\n" +
111+
" \"custom_parameter_2\": \"custom-value-2\"\n" +
112+
"}\n";
113+
114+
MockClientHttpResponse response = new MockClientHttpResponse(
115+
tokenResponse.getBytes(), HttpStatus.OK);
116+
117+
OAuth2AccessTokenResponse accessTokenResponse = this.messageConverter.readInternal(
118+
OAuth2AccessTokenResponse.class, response);
119+
120+
assertThat(accessTokenResponse.getAccessToken().getTokenValue()).isEqualTo("access-token-1234");
121+
assertThat(accessTokenResponse.getAccessToken().getTokenType()).isEqualTo(OAuth2AccessToken.TokenType.BEARER);
122+
assertThat(accessTokenResponse.getAccessToken().getExpiresAt()).isBeforeOrEqualTo(Instant.now().plusSeconds(3600));
123+
assertThat(accessTokenResponse.getAccessToken().getScopes()).containsExactly("read", "write");
124+
assertThat(accessTokenResponse.getRefreshToken().getTokenValue()).isEqualTo("refresh-token-1234");
125+
assertThat(accessTokenResponse.getAdditionalParameters()).containsExactly(
126+
entry("custom_object_1", "{name1=value1}"),
127+
entry("custom_object_2", "[value1, value2]"),
128+
entry("custom_parameter_1", "custom-value-1"),
129+
entry("custom_parameter_2", "custom-value-2"));
130+
}
131+
99132
@Test
100133
public void readInternalWhenConversionFailsThenThrowHttpMessageNotReadableException() {
101134
Converter tokenResponseConverter = mock(Converter.class);

0 commit comments

Comments
 (0)