Skip to content
This repository was archived by the owner on May 12, 2026. It is now read-only.

Commit 5e699a0

Browse files
Implemented in-memory TokenStore and added opportunity to save user credentials into file (#129)
1 parent ab21104 commit 5e699a0

7 files changed

Lines changed: 180 additions & 47 deletions

File tree

oauth2_http/java/com/google/auth/oauth2/GoogleCredentials.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939

4040
import java.io.IOException;
4141
import java.io.InputStream;
42+
4243
import java.util.Collection;
4344

4445
/**
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/*
2+
* Copyright 2017, Google Inc. All rights reserved.
3+
*
4+
* Redistribution and use in source and binary forms, with or without
5+
* modification, are permitted provided that the following conditions are
6+
* met:
7+
*
8+
* * Redistributions of source code must retain the above copyright
9+
* notice, this list of conditions and the following disclaimer.
10+
* * Redistributions in binary form must reproduce the above
11+
* copyright notice, this list of conditions and the following disclaimer
12+
* in the documentation and/or other materials provided with the
13+
* distribution.
14+
*
15+
* * Neither the name of Google Inc. nor the names of its
16+
* contributors may be used to endorse or promote products derived from
17+
* this software without specific prior written permission.
18+
*
19+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20+
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21+
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22+
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23+
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24+
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25+
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26+
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27+
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28+
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29+
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30+
*/
31+
32+
package com.google.auth.oauth2;
33+
34+
import java.io.IOException;
35+
import java.util.HashMap;
36+
import java.util.Map;
37+
38+
/**
39+
* Represents an in-memory storage of tokens.
40+
*/
41+
public class MemoryTokensStorage implements TokenStore {
42+
private final Map<String, String> tokensStorage = new HashMap<>();
43+
44+
@Override
45+
public String load(String id) throws IOException {
46+
return tokensStorage.get(id);
47+
}
48+
49+
@Override
50+
public void store(String id, String tokens) throws IOException {
51+
tokensStorage.put(id, tokens);
52+
}
53+
54+
@Override
55+
public void delete(String id) throws IOException {
56+
tokensStorage.remove(id);
57+
}
58+
59+
}

oauth2_http/java/com/google/auth/oauth2/OAuth2Utils.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,14 @@
4040
import com.google.api.client.json.jackson2.JacksonFactory;
4141
import com.google.auth.http.AuthHttpConstants;
4242
import com.google.auth.http.HttpTransportFactory;
43+
import com.google.common.io.ByteStreams;
4344

4445
import java.io.ByteArrayInputStream;
46+
import java.io.File;
47+
import java.io.FileOutputStream;
4548
import java.io.IOException;
4649
import java.io.InputStream;
50+
import java.io.OutputStream;
4751
import java.math.BigDecimal;
4852
import java.net.URI;
4953
import java.nio.charset.Charset;
@@ -122,6 +126,22 @@ static String validateString(Map<String, Object> map, String key, String errorPr
122126
return (String) value;
123127
}
124128

129+
/**
130+
* Saves the end user credentials into the given file path.
131+
*
132+
* @param credentials InputStream containing user credentials in JSON format
133+
* @param filePath Path to file where to store the credentials
134+
* @throws IOException An error saving the credentials.
135+
*/
136+
static void writeInputStreamToFile(InputStream credentials, String filePath) throws IOException {
137+
final OutputStream outputStream = new FileOutputStream(new File(filePath));
138+
try {
139+
ByteStreams.copy(credentials, outputStream);
140+
} finally {
141+
outputStream.close();
142+
}
143+
}
144+
125145
/**
126146
* Return the specified optional string from JSON or throw a helpful error message.
127147
*/

oauth2_http/java/com/google/auth/oauth2/UserAuthorizer.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ public UserAuthorizer(ClientId clientId, Collection<String> scopes, TokenStore t
122122
(transportFactory == null) ? OAuth2Utils.HTTP_TRANSPORT_FACTORY : transportFactory;
123123
this.tokenServerUri = (tokenServerUri == null) ? OAuth2Utils.TOKEN_SERVER_URI : tokenServerUri;
124124
this.userAuthUri = (userAuthUri == null) ? OAuth2Utils.USER_AUTH_URI : userAuthUri;
125-
this.tokenStore = tokenStore;
125+
this.tokenStore = (tokenStore == null) ? new MemoryTokensStorage() : tokenStore;
126126
}
127127

128128

oauth2_http/java/com/google/auth/oauth2/UserCredentials.java

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@
3131

3232
package com.google.auth.oauth2;
3333

34+
import static com.google.auth.oauth2.OAuth2Utils.JSON_FACTORY;
35+
import static com.google.auth.oauth2.OAuth2Utils.UTF_8;
3436
import static com.google.common.base.MoreObjects.firstNonNull;
3537

3638
import com.google.api.client.http.GenericUrl;
@@ -45,6 +47,7 @@
4547
import com.google.api.client.util.Preconditions;
4648
import com.google.auth.http.HttpTransportFactory;
4749

50+
import java.io.ByteArrayInputStream;
4851
import com.google.common.base.MoreObjects;
4952
import java.io.IOException;
5053
import java.io.InputStream;
@@ -184,7 +187,7 @@ public static UserCredentials fromStream(InputStream credentialsStream,
184187
Preconditions.checkNotNull(credentialsStream);
185188
Preconditions.checkNotNull(transportFactory);
186189

187-
JsonFactory jsonFactory = OAuth2Utils.JSON_FACTORY;
190+
JsonFactory jsonFactory = JSON_FACTORY;
188191
JsonObjectParser parser = new JsonObjectParser(jsonFactory);
189192
GenericJson fileContents = parser.parseAndClose(
190193
credentialsStream, OAuth2Utils.UTF_8, GenericJson.class);
@@ -220,7 +223,7 @@ public AccessToken refreshAccessToken() throws IOException {
220223
HttpRequestFactory requestFactory = transportFactory.create().createRequestFactory();
221224
HttpRequest request =
222225
requestFactory.buildPostRequest(new GenericUrl(tokenServerUri), content);
223-
request.setParser(new JsonObjectParser(OAuth2Utils.JSON_FACTORY));
226+
request.setParser(new JsonObjectParser(JSON_FACTORY));
224227
HttpResponse response = request.execute();
225228
GenericData responseData = response.parseAs(GenericData.class);
226229
String accessToken =
@@ -258,6 +261,47 @@ public final String getRefreshToken() {
258261
return refreshToken;
259262
}
260263

264+
265+
/**
266+
* Returns the instance of InputStream containing the following user credentials in JSON format:
267+
* - RefreshToken
268+
* - ClientId
269+
* - ClientSecret
270+
* - ServerTokenUri
271+
*
272+
* @return user credentials stream
273+
*/
274+
private InputStream getUserCredentialsStream() throws IOException {
275+
GenericJson json = new GenericJson();
276+
json.put("type", GoogleCredentials.USER_FILE_TYPE);
277+
if (refreshToken != null) {
278+
json.put("refresh_token", refreshToken);
279+
}
280+
if (tokenServerUri != null) {
281+
json.put("token_server_uri", tokenServerUri);
282+
}
283+
if (clientId != null) {
284+
json.put("client_id", clientId);
285+
}
286+
if (clientSecret != null) {
287+
json.put("client_secret", clientSecret);
288+
}
289+
json.setFactory(JSON_FACTORY);
290+
String text = json.toPrettyString();
291+
return new ByteArrayInputStream(text.getBytes(UTF_8));
292+
}
293+
294+
/**
295+
* Saves the end user credentials into the given file path.
296+
*
297+
* @param filePath Path to file where to store the credentials
298+
*
299+
* @throws IOException An error storing the credentials.
300+
*/
301+
public void save(String filePath) throws IOException {
302+
OAuth2Utils.writeInputStreamToFile(getUserCredentialsStream(), filePath);
303+
}
304+
261305
@Override
262306
public int hashCode() {
263307
return Objects.hash(super.hashCode(), clientId, clientSecret, refreshToken, tokenServerUri,

oauth2_http/javatests/com/google/auth/oauth2/UserAuthorizerTest.java

Lines changed: 12 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,6 @@
5050
import java.util.Collection;
5151
import java.util.Collections;
5252
import java.util.Date;
53-
import java.util.HashMap;
5453
import java.util.Map;
5554

5655
/**
@@ -75,7 +74,7 @@ public class UserAuthorizerTest {
7574

7675
@Test
7776
public void constructorMinimum() {
78-
TestTokenStore store = new TestTokenStore();
77+
TokenStore store = new MemoryTokensStorage();
7978

8079
UserAuthorizer authorizer = UserAuthorizer.newBuilder()
8180
.setClientId(CLIENT_ID)
@@ -91,7 +90,7 @@ public void constructorMinimum() {
9190

9291
@Test
9392
public void constructorCommon() {
94-
TestTokenStore store = new TestTokenStore();
93+
TokenStore store = new MemoryTokensStorage();
9594

9695
UserAuthorizer authorizer = UserAuthorizer.newBuilder()
9796
.setClientId(CLIENT_ID)
@@ -172,7 +171,7 @@ public void getCredentials_noCredentials_returnsNull() throws IOException {
172171
UserAuthorizer authorizer = UserAuthorizer.newBuilder()
173172
.setClientId(CLIENT_ID)
174173
.setScopes(SCOPES)
175-
.setTokenStore(new TestTokenStore())
174+
.setTokenStore(new MemoryTokensStorage())
176175
.build();
177176

178177
UserCredentials credentials = authorizer.getCredentials(USER_ID);
@@ -182,7 +181,7 @@ public void getCredentials_noCredentials_returnsNull() throws IOException {
182181

183182
@Test
184183
public void getCredentials_storedCredentials_returnsStored() throws IOException {
185-
TestTokenStore tokenStore = new TestTokenStore();
184+
TokenStore tokenStore = new MemoryTokensStorage();
186185

187186
UserCredentials initialCredentials = UserCredentials.newBuilder()
188187
.setClientId(CLIENT_ID_VALUE)
@@ -207,7 +206,7 @@ public void getCredentials_storedCredentials_returnsStored() throws IOException
207206

208207
@Test(expected = NullPointerException.class)
209208
public void getCredentials_nullUserId_throws() throws IOException {
210-
TestTokenStore tokenStore = new TestTokenStore();
209+
TokenStore tokenStore = new MemoryTokensStorage();
211210
UserAuthorizer authorizer = UserAuthorizer.newBuilder()
212211
.setClientId(CLIENT_ID)
213212
.setScopes(SCOPES)
@@ -217,16 +216,6 @@ public void getCredentials_nullUserId_throws() throws IOException {
217216
authorizer.getCredentials(null);
218217
}
219218

220-
@Test(expected = IllegalStateException.class)
221-
public void getCredentials_nullTokenStore_throws() throws IOException {
222-
UserAuthorizer authorizer = UserAuthorizer.newBuilder()
223-
.setClientId(CLIENT_ID)
224-
.setScopes(SCOPES)
225-
.build();
226-
227-
authorizer.getCredentials(USER_ID);
228-
}
229-
230219
@Test
231220
public void getCredentials_refreshedToken_stored() throws IOException {
232221
final String accessTokenValue1 = "1/MkSJoj1xsli0AccessToken_NKPY2";
@@ -236,7 +225,7 @@ public void getCredentials_refreshedToken_stored() throws IOException {
236225
MockTokenServerTransportFactory transportFactory = new MockTokenServerTransportFactory();
237226
transportFactory.transport.addClient(CLIENT_ID_VALUE, CLIENT_SECRET);
238227
transportFactory.transport.addRefreshToken(REFRESH_TOKEN, accessTokenValue2);
239-
TestTokenStore tokenStore = new TestTokenStore();
228+
TokenStore tokenStore = new MemoryTokensStorage();
240229
UserAuthorizer authorizer = UserAuthorizer.newBuilder()
241230
.setClientId(CLIENT_ID)
242231
.setScopes(SCOPES)
@@ -277,7 +266,7 @@ public void getCredentialsFromCode_conevertsCodeToTokens() throws IOException {
277266
MockTokenServerTransportFactory transportFactory = new MockTokenServerTransportFactory();
278267
transportFactory.transport.addClient(CLIENT_ID_VALUE, CLIENT_SECRET);
279268
transportFactory.transport.addAuthorizationCode(CODE, REFRESH_TOKEN, ACCESS_TOKEN_VALUE);
280-
TestTokenStore tokenStore = new TestTokenStore();
269+
TokenStore tokenStore = new MemoryTokensStorage();
281270
UserAuthorizer authorizer = UserAuthorizer.newBuilder()
282271
.setClientId(CLIENT_ID)
283272
.setScopes(SCOPES)
@@ -296,7 +285,7 @@ public void getCredentialsFromCode_nullCode_throws() throws IOException {
296285
UserAuthorizer authorizer = UserAuthorizer.newBuilder()
297286
.setClientId(CLIENT_ID)
298287
.setScopes(SCOPES)
299-
.setTokenStore(new TestTokenStore())
288+
.setTokenStore(new MemoryTokensStorage())
300289
.build();
301290

302291
authorizer.getCredentialsFromCode(null, BASE_URI);
@@ -309,7 +298,7 @@ public void getAndStoreCredentialsFromCode_getAndStoresCredentials() throws IOEx
309298
MockTokenServerTransportFactory transportFactory = new MockTokenServerTransportFactory();
310299
transportFactory.transport.addClient(CLIENT_ID_VALUE, CLIENT_SECRET);
311300
transportFactory.transport.addAuthorizationCode(CODE, REFRESH_TOKEN, accessTokenValue1);
312-
TestTokenStore tokenStore = new TestTokenStore();
301+
TokenStore tokenStore = new MemoryTokensStorage();
313302
UserAuthorizer authorizer = UserAuthorizer.newBuilder()
314303
.setClientId(CLIENT_ID)
315304
.setScopes(SCOPES)
@@ -342,7 +331,7 @@ public void getAndStoreCredentialsFromCode_nullCode_throws() throws IOException
342331
UserAuthorizer authorizer = UserAuthorizer.newBuilder()
343332
.setClientId(CLIENT_ID)
344333
.setScopes(SCOPES)
345-
.setTokenStore(new TestTokenStore())
334+
.setTokenStore(new MemoryTokensStorage())
346335
.build();
347336

348337
authorizer.getAndStoreCredentialsFromCode(USER_ID, null, BASE_URI);
@@ -353,15 +342,15 @@ public void getAndStoreCredentialsFromCode_nullUserId_throws() throws IOExceptio
353342
UserAuthorizer authorizer = UserAuthorizer.newBuilder()
354343
.setClientId(CLIENT_ID)
355344
.setScopes(SCOPES)
356-
.setTokenStore(new TestTokenStore())
345+
.setTokenStore(new MemoryTokensStorage())
357346
.build();
358347

359348
authorizer.getAndStoreCredentialsFromCode(null, CODE, BASE_URI);
360349
}
361350

362351
@Test
363352
public void revokeAuthorization_revokesAndClears() throws IOException {
364-
TestTokenStore tokenStore = new TestTokenStore();
353+
TokenStore tokenStore = new MemoryTokensStorage();
365354
MockTokenServerTransportFactory transportFactory = new MockTokenServerTransportFactory();
366355
transportFactory.transport.addClient(CLIENT_ID_VALUE, CLIENT_SECRET);
367356
transportFactory.transport.addRefreshToken(REFRESH_TOKEN, ACCESS_TOKEN_VALUE);
@@ -398,24 +387,4 @@ public void revokeAuthorization_revokesAndClears() throws IOException {
398387
UserCredentials credentials2 = authorizer.getCredentials(USER_ID);
399388
assertNull(credentials2);
400389
}
401-
402-
private static class TestTokenStore implements TokenStore {
403-
404-
private final Map<String, String> map = new HashMap<>();
405-
406-
@Override
407-
public String load(String id) throws IOException {
408-
return map.get(id);
409-
}
410-
411-
@Override
412-
public void store(String id, String tokens) throws IOException {
413-
map.put(id, tokens);
414-
}
415-
416-
@Override
417-
public void delete(String id) throws IOException {
418-
map.remove(id);
419-
}
420-
}
421390
}

0 commit comments

Comments
 (0)