Skip to content

Commit 02d2988

Browse files
committed
Associate Refresh Token to OAuth2AuthorizedClient
Fixes gh-5416
1 parent 1137f3b commit 02d2988

23 files changed

+245
-27
lines changed

oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/OAuth2AuthorizedClient.java

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2017 the original author or authors.
2+
* Copyright 2002-2018 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.
@@ -15,8 +15,10 @@
1515
*/
1616
package org.springframework.security.oauth2.client;
1717

18+
import org.springframework.lang.Nullable;
1819
import org.springframework.security.oauth2.client.registration.ClientRegistration;
1920
import org.springframework.security.oauth2.core.OAuth2AccessToken;
21+
import org.springframework.security.oauth2.core.OAuth2RefreshToken;
2022
import org.springframework.util.Assert;
2123

2224
/**
@@ -33,11 +35,13 @@
3335
* @since 5.0
3436
* @see ClientRegistration
3537
* @see OAuth2AccessToken
38+
* @see OAuth2RefreshToken
3639
*/
3740
public class OAuth2AuthorizedClient {
3841
private final ClientRegistration clientRegistration;
3942
private final String principalName;
4043
private final OAuth2AccessToken accessToken;
44+
private final OAuth2RefreshToken refreshToken;
4145

4246
/**
4347
* Constructs an {@code OAuth2AuthorizedClient} using the provided parameters.
@@ -47,12 +51,26 @@ public class OAuth2AuthorizedClient {
4751
* @param accessToken the access token credential granted
4852
*/
4953
public OAuth2AuthorizedClient(ClientRegistration clientRegistration, String principalName, OAuth2AccessToken accessToken) {
54+
this(clientRegistration, principalName, accessToken, null);
55+
}
56+
57+
/**
58+
* Constructs an {@code OAuth2AuthorizedClient} using the provided parameters.
59+
*
60+
* @param clientRegistration the authorized client's registration
61+
* @param principalName the name of the End-User {@code Principal} (Resource Owner)
62+
* @param accessToken the access token credential granted
63+
* @param refreshToken the refresh token credential granted
64+
*/
65+
public OAuth2AuthorizedClient(ClientRegistration clientRegistration, String principalName,
66+
OAuth2AccessToken accessToken, @Nullable OAuth2RefreshToken refreshToken) {
5067
Assert.notNull(clientRegistration, "clientRegistration cannot be null");
5168
Assert.hasText(principalName, "principalName cannot be empty");
5269
Assert.notNull(accessToken, "accessToken cannot be null");
5370
this.clientRegistration = clientRegistration;
5471
this.principalName = principalName;
5572
this.accessToken = accessToken;
73+
this.refreshToken = refreshToken;
5674
}
5775

5876
/**
@@ -81,4 +99,14 @@ public String getPrincipalName() {
8199
public OAuth2AccessToken getAccessToken() {
82100
return this.accessToken;
83101
}
102+
103+
/**
104+
* Returns the {@link OAuth2RefreshToken refresh token} credential granted.
105+
*
106+
* @since 5.1
107+
* @return the {@link OAuth2RefreshToken}
108+
*/
109+
public @Nullable OAuth2RefreshToken getRefreshToken() {
110+
return this.refreshToken;
111+
}
84112
}

oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/authentication/OAuth2AuthorizationCodeAuthenticationProvider.java

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020
import org.springframework.security.core.AuthenticationException;
2121
import org.springframework.security.oauth2.client.endpoint.OAuth2AccessTokenResponseClient;
2222
import org.springframework.security.oauth2.client.endpoint.OAuth2AuthorizationCodeGrantRequest;
23-
import org.springframework.security.oauth2.core.OAuth2AccessToken;
2423
import org.springframework.security.oauth2.core.endpoint.OAuth2AccessTokenResponse;
2524
import org.springframework.util.Assert;
2625

@@ -69,13 +68,12 @@ public Authentication authenticate(Authentication authentication) throws Authent
6968
authorizationCodeAuthentication.getClientRegistration(),
7069
authorizationCodeAuthentication.getAuthorizationExchange()));
7170

72-
OAuth2AccessToken accessToken = accessTokenResponse.getAccessToken();
73-
7471
OAuth2AuthorizationCodeAuthenticationToken authenticationResult =
7572
new OAuth2AuthorizationCodeAuthenticationToken(
7673
authorizationCodeAuthentication.getClientRegistration(),
7774
authorizationCodeAuthentication.getAuthorizationExchange(),
78-
accessToken);
75+
accessTokenResponse.getAccessToken(),
76+
accessTokenResponse.getRefreshToken());
7977
authenticationResult.setDetails(authorizationCodeAuthentication.getDetails());
8078

8179
return authenticationResult;

oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/authentication/OAuth2AuthorizationCodeAuthenticationToken.java

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,12 @@
1515
*/
1616
package org.springframework.security.oauth2.client.authentication;
1717

18+
import org.springframework.lang.Nullable;
1819
import org.springframework.security.authentication.AbstractAuthenticationToken;
1920
import org.springframework.security.core.SpringSecurityCoreVersion;
2021
import org.springframework.security.oauth2.client.registration.ClientRegistration;
2122
import org.springframework.security.oauth2.core.OAuth2AccessToken;
23+
import org.springframework.security.oauth2.core.OAuth2RefreshToken;
2224
import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationExchange;
2325
import org.springframework.util.Assert;
2426

@@ -40,6 +42,7 @@ public class OAuth2AuthorizationCodeAuthenticationToken extends AbstractAuthenti
4042
private ClientRegistration clientRegistration;
4143
private OAuth2AuthorizationExchange authorizationExchange;
4244
private OAuth2AccessToken accessToken;
45+
private OAuth2RefreshToken refreshToken;
4346

4447
/**
4548
* This constructor should be used when the Authorization Request/Response is complete.
@@ -67,9 +70,26 @@ public OAuth2AuthorizationCodeAuthenticationToken(ClientRegistration clientRegis
6770
public OAuth2AuthorizationCodeAuthenticationToken(ClientRegistration clientRegistration,
6871
OAuth2AuthorizationExchange authorizationExchange,
6972
OAuth2AccessToken accessToken) {
73+
this(clientRegistration, authorizationExchange, accessToken, null);
74+
}
75+
76+
/**
77+
* This constructor should be used when the Access Token Request/Response is complete,
78+
* which indicates that the Authorization Code Grant flow has fully completed.
79+
*
80+
* @param clientRegistration the client registration
81+
* @param authorizationExchange the authorization exchange
82+
* @param accessToken the access token credential
83+
* @param refreshToken the refresh token credential
84+
*/
85+
public OAuth2AuthorizationCodeAuthenticationToken(ClientRegistration clientRegistration,
86+
OAuth2AuthorizationExchange authorizationExchange,
87+
OAuth2AccessToken accessToken,
88+
@Nullable OAuth2RefreshToken refreshToken) {
7089
this(clientRegistration, authorizationExchange);
7190
Assert.notNull(accessToken, "accessToken cannot be null");
7291
this.accessToken = accessToken;
92+
this.refreshToken = refreshToken;
7393
this.setAuthenticated(true);
7494
}
7595

@@ -111,4 +131,13 @@ public OAuth2AuthorizationExchange getAuthorizationExchange() {
111131
public OAuth2AccessToken getAccessToken() {
112132
return this.accessToken;
113133
}
134+
135+
/**
136+
* Returns the {@link OAuth2RefreshToken refresh token}.
137+
*
138+
* @return the {@link OAuth2RefreshToken}
139+
*/
140+
public @Nullable OAuth2RefreshToken getRefreshToken() {
141+
return this.refreshToken;
142+
}
114143
}

oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/authentication/OAuth2LoginAuthenticationProvider.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2017 the original author or authors.
2+
* Copyright 2002-2018 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.
@@ -113,7 +113,8 @@ public Authentication authenticate(Authentication authentication) throws Authent
113113
authorizationCodeAuthentication.getAuthorizationExchange(),
114114
oauth2User,
115115
mappedAuthorities,
116-
accessToken);
116+
accessToken,
117+
accessTokenResponse.getRefreshToken());
117118
authenticationResult.setDetails(authorizationCodeAuthentication.getDetails());
118119

119120
return authenticationResult;

oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/authentication/OAuth2LoginAuthenticationToken.java

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2017 the original author or authors.
2+
* Copyright 2002-2018 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.
@@ -15,11 +15,13 @@
1515
*/
1616
package org.springframework.security.oauth2.client.authentication;
1717

18+
import org.springframework.lang.Nullable;
1819
import org.springframework.security.authentication.AbstractAuthenticationToken;
1920
import org.springframework.security.core.GrantedAuthority;
2021
import org.springframework.security.core.SpringSecurityCoreVersion;
2122
import org.springframework.security.oauth2.client.registration.ClientRegistration;
2223
import org.springframework.security.oauth2.core.OAuth2AccessToken;
24+
import org.springframework.security.oauth2.core.OAuth2RefreshToken;
2325
import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationExchange;
2426
import org.springframework.security.oauth2.core.user.OAuth2User;
2527
import org.springframework.util.Assert;
@@ -46,6 +48,7 @@ public class OAuth2LoginAuthenticationToken extends AbstractAuthenticationToken
4648
private ClientRegistration clientRegistration;
4749
private OAuth2AuthorizationExchange authorizationExchange;
4850
private OAuth2AccessToken accessToken;
51+
private OAuth2RefreshToken refreshToken;
4952

5053
/**
5154
* This constructor should be used when the Authorization Request/Response is complete.
@@ -80,6 +83,27 @@ public OAuth2LoginAuthenticationToken(ClientRegistration clientRegistration,
8083
OAuth2User principal,
8184
Collection<? extends GrantedAuthority> authorities,
8285
OAuth2AccessToken accessToken) {
86+
this(clientRegistration, authorizationExchange, principal, authorities, accessToken, null);
87+
}
88+
89+
/**
90+
* This constructor should be used when the Access Token Request/Response is complete,
91+
* which indicates that the Authorization Code Grant flow has fully completed
92+
* and OAuth 2.0 Login has been achieved.
93+
*
94+
* @param clientRegistration the client registration
95+
* @param authorizationExchange the authorization exchange
96+
* @param principal the user {@code Principal} registered with the OAuth 2.0 Provider
97+
* @param authorities the authorities granted to the user
98+
* @param accessToken the access token credential
99+
* @param refreshToken the refresh token credential
100+
*/
101+
public OAuth2LoginAuthenticationToken(ClientRegistration clientRegistration,
102+
OAuth2AuthorizationExchange authorizationExchange,
103+
OAuth2User principal,
104+
Collection<? extends GrantedAuthority> authorities,
105+
OAuth2AccessToken accessToken,
106+
@Nullable OAuth2RefreshToken refreshToken) {
83107
super(authorities);
84108
Assert.notNull(clientRegistration, "clientRegistration cannot be null");
85109
Assert.notNull(authorizationExchange, "authorizationExchange cannot be null");
@@ -89,6 +113,7 @@ public OAuth2LoginAuthenticationToken(ClientRegistration clientRegistration,
89113
this.authorizationExchange = authorizationExchange;
90114
this.principal = principal;
91115
this.accessToken = accessToken;
116+
this.refreshToken = refreshToken;
92117
this.setAuthenticated(true);
93118
}
94119

@@ -128,4 +153,14 @@ public OAuth2AuthorizationExchange getAuthorizationExchange() {
128153
public OAuth2AccessToken getAccessToken() {
129154
return this.accessToken;
130155
}
156+
157+
/**
158+
* Returns the {@link OAuth2RefreshToken refresh token}.
159+
*
160+
* @since 5.1
161+
* @return the {@link OAuth2RefreshToken}
162+
*/
163+
public @Nullable OAuth2RefreshToken getRefreshToken() {
164+
return this.refreshToken;
165+
}
131166
}

oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/authentication/OAuth2LoginReactiveAuthenticationManager.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -120,11 +120,13 @@ private Mono<OAuth2AuthenticationToken> authenticationResult(OAuth2LoginAuthenti
120120
authorizationCodeAuthentication.getAuthorizationExchange(),
121121
oauth2User,
122122
mappedAuthorities,
123-
accessToken);
123+
accessToken,
124+
accessTokenResponse.getRefreshToken());
124125
OAuth2AuthorizedClient authorizedClient = new OAuth2AuthorizedClient(
125126
authenticationResult.getClientRegistration(),
126127
authenticationResult.getName(),
127-
authenticationResult.getAccessToken());
128+
authenticationResult.getAccessToken(),
129+
authenticationResult.getRefreshToken());
128130
OAuth2AuthenticationToken result = new OAuth2AuthenticationToken(
129131
authenticationResult.getPrincipal(),
130132
authenticationResult.getAuthorities(),

oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/endpoint/NimbusAuthorizationCodeTokenResponseClient.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2017 the original author or authors.
2+
* Copyright 2002-2018 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.
@@ -138,12 +138,18 @@ public OAuth2AccessTokenResponse getTokenResponse(OAuth2AuthorizationCodeGrantRe
138138
accessTokenResponse.getTokens().getAccessToken().getScope().toStringList());
139139
}
140140

141+
String refreshToken = null;
142+
if (accessTokenResponse.getTokens().getRefreshToken() != null) {
143+
refreshToken = accessTokenResponse.getTokens().getRefreshToken().getValue();
144+
}
145+
141146
Map<String, Object> additionalParameters = new LinkedHashMap<>(accessTokenResponse.getCustomParameters());
142147

143148
return OAuth2AccessTokenResponse.withToken(accessToken)
144149
.tokenType(accessTokenType)
145150
.expiresIn(expiresIn)
146151
.scopes(scopes)
152+
.refreshToken(refreshToken)
147153
.additionalParameters(additionalParameters)
148154
.build();
149155
}

oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/endpoint/NimbusReactiveAuthorizationCodeTokenResponseClient.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,13 +118,19 @@ public Mono<OAuth2AccessTokenResponse> getTokenResponse(OAuth2AuthorizationCodeG
118118
accessToken.getScope().toStringList());
119119
}
120120

121+
String refreshToken = null;
122+
if (accessTokenResponse.getTokens().getRefreshToken() != null) {
123+
refreshToken = accessTokenResponse.getTokens().getRefreshToken().getValue();
124+
}
125+
121126
Map<String, Object> additionalParameters = new LinkedHashMap<>(
122127
accessTokenResponse.getCustomParameters());
123128

124129
return OAuth2AccessTokenResponse.withToken(accessToken.getValue())
125130
.tokenType(accessTokenType)
126131
.expiresIn(expiresIn)
127132
.scopes(scopes)
133+
.refreshToken(refreshToken)
128134
.additionalParameters(additionalParameters)
129135
.build();
130136
});

oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/oidc/authentication/OidcAuthorizationCodeAuthenticationProvider.java

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2017 the original author or authors.
2+
* Copyright 2002-2018 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.
@@ -27,7 +27,6 @@
2727
import org.springframework.security.oauth2.client.oidc.userinfo.OidcUserService;
2828
import org.springframework.security.oauth2.client.registration.ClientRegistration;
2929
import org.springframework.security.oauth2.client.userinfo.OAuth2UserService;
30-
import org.springframework.security.oauth2.core.OAuth2AccessToken;
3130
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
3231
import org.springframework.security.oauth2.core.OAuth2Error;
3332
import org.springframework.security.oauth2.core.endpoint.OAuth2AccessTokenResponse;
@@ -142,8 +141,6 @@ public Authentication authenticate(Authentication authentication) throws Authent
142141
authorizationCodeAuthentication.getClientRegistration(),
143142
authorizationCodeAuthentication.getAuthorizationExchange()));
144143

145-
OAuth2AccessToken accessToken = accessTokenResponse.getAccessToken();
146-
147144
ClientRegistration clientRegistration = authorizationCodeAuthentication.getClientRegistration();
148145

149146
if (!accessTokenResponse.getAdditionalParameters().containsKey(OidcParameterNames.ID_TOKEN)) {
@@ -161,7 +158,7 @@ public Authentication authenticate(Authentication authentication) throws Authent
161158
this.validateIdToken(idToken, clientRegistration);
162159

163160
OidcUser oidcUser = this.userService.loadUser(
164-
new OidcUserRequest(clientRegistration, accessToken, idToken));
161+
new OidcUserRequest(clientRegistration, accessTokenResponse.getAccessToken(), idToken));
165162

166163
Collection<? extends GrantedAuthority> mappedAuthorities =
167164
this.authoritiesMapper.mapAuthorities(oidcUser.getAuthorities());
@@ -171,7 +168,8 @@ public Authentication authenticate(Authentication authentication) throws Authent
171168
authorizationCodeAuthentication.getAuthorizationExchange(),
172169
oidcUser,
173170
mappedAuthorities,
174-
accessToken);
171+
accessTokenResponse.getAccessToken(),
172+
accessTokenResponse.getRefreshToken());
175173
authenticationResult.setDetails(authorizationCodeAuthentication.getDetails());
176174

177175
return authenticationResult;

oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/OAuth2AuthorizationCodeGrantFilter.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,8 @@ private void processAuthorizationResponse(HttpServletRequest request, HttpServle
198198
OAuth2AuthorizedClient authorizedClient = new OAuth2AuthorizedClient(
199199
authenticationResult.getClientRegistration(),
200200
currentAuthentication.getName(),
201-
authenticationResult.getAccessToken());
201+
authenticationResult.getAccessToken(),
202+
authenticationResult.getRefreshToken());
202203

203204
this.authorizedClientService.saveAuthorizedClient(authorizedClient, currentAuthentication);
204205

oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/OAuth2LoginAuthenticationFilter.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,8 @@ public Authentication attemptAuthentication(HttpServletRequest request, HttpServ
173173
OAuth2AuthorizedClient authorizedClient = new OAuth2AuthorizedClient(
174174
authenticationResult.getClientRegistration(),
175175
oauth2Authentication.getName(),
176-
authenticationResult.getAccessToken());
176+
authenticationResult.getAccessToken(),
177+
authenticationResult.getRefreshToken());
177178

178179
this.authorizedClientService.saveAuthorizedClient(authorizedClient, oauth2Authentication);
179180

0 commit comments

Comments
 (0)