Skip to content

Commit

Permalink
Implemented in-memory TokenStore and added opportunity to save user c…
Browse files Browse the repository at this point in the history
…redentials into file (#129)
  • Loading branch information
YuryBandarchuk16 authored and garrettjonesgoogle committed Nov 2, 2017
1 parent ab21104 commit 5e699a0
Show file tree
Hide file tree
Showing 7 changed files with 180 additions and 47 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@

import java.io.IOException;
import java.io.InputStream;

import java.util.Collection;

/**
Expand Down
59 changes: 59 additions & 0 deletions oauth2_http/java/com/google/auth/oauth2/MemoryTokensStorage.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/*
* Copyright 2017, Google Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

package com.google.auth.oauth2;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
* Represents an in-memory storage of tokens.
*/
public class MemoryTokensStorage implements TokenStore {
private final Map<String, String> tokensStorage = new HashMap<>();

@Override
public String load(String id) throws IOException {
return tokensStorage.get(id);
}

@Override
public void store(String id, String tokens) throws IOException {
tokensStorage.put(id, tokens);
}

@Override
public void delete(String id) throws IOException {
tokensStorage.remove(id);
}

}
20 changes: 20 additions & 0 deletions oauth2_http/java/com/google/auth/oauth2/OAuth2Utils.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,14 @@
import com.google.api.client.json.jackson2.JacksonFactory;
import com.google.auth.http.AuthHttpConstants;
import com.google.auth.http.HttpTransportFactory;
import com.google.common.io.ByteStreams;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.math.BigDecimal;
import java.net.URI;
import java.nio.charset.Charset;
Expand Down Expand Up @@ -122,6 +126,22 @@ static String validateString(Map<String, Object> map, String key, String errorPr
return (String) value;
}

/**
* Saves the end user credentials into the given file path.
*
* @param credentials InputStream containing user credentials in JSON format
* @param filePath Path to file where to store the credentials
* @throws IOException An error saving the credentials.
*/
static void writeInputStreamToFile(InputStream credentials, String filePath) throws IOException {
final OutputStream outputStream = new FileOutputStream(new File(filePath));
try {
ByteStreams.copy(credentials, outputStream);
} finally {
outputStream.close();
}
}

/**
* Return the specified optional string from JSON or throw a helpful error message.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ public UserAuthorizer(ClientId clientId, Collection<String> scopes, TokenStore t
(transportFactory == null) ? OAuth2Utils.HTTP_TRANSPORT_FACTORY : transportFactory;
this.tokenServerUri = (tokenServerUri == null) ? OAuth2Utils.TOKEN_SERVER_URI : tokenServerUri;
this.userAuthUri = (userAuthUri == null) ? OAuth2Utils.USER_AUTH_URI : userAuthUri;
this.tokenStore = tokenStore;
this.tokenStore = (tokenStore == null) ? new MemoryTokensStorage() : tokenStore;
}


Expand Down
48 changes: 46 additions & 2 deletions oauth2_http/java/com/google/auth/oauth2/UserCredentials.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@

package com.google.auth.oauth2;

import static com.google.auth.oauth2.OAuth2Utils.JSON_FACTORY;
import static com.google.auth.oauth2.OAuth2Utils.UTF_8;
import static com.google.common.base.MoreObjects.firstNonNull;

import com.google.api.client.http.GenericUrl;
Expand All @@ -45,6 +47,7 @@
import com.google.api.client.util.Preconditions;
import com.google.auth.http.HttpTransportFactory;

import java.io.ByteArrayInputStream;
import com.google.common.base.MoreObjects;
import java.io.IOException;
import java.io.InputStream;
Expand Down Expand Up @@ -184,7 +187,7 @@ public static UserCredentials fromStream(InputStream credentialsStream,
Preconditions.checkNotNull(credentialsStream);
Preconditions.checkNotNull(transportFactory);

JsonFactory jsonFactory = OAuth2Utils.JSON_FACTORY;
JsonFactory jsonFactory = JSON_FACTORY;
JsonObjectParser parser = new JsonObjectParser(jsonFactory);
GenericJson fileContents = parser.parseAndClose(
credentialsStream, OAuth2Utils.UTF_8, GenericJson.class);
Expand Down Expand Up @@ -220,7 +223,7 @@ public AccessToken refreshAccessToken() throws IOException {
HttpRequestFactory requestFactory = transportFactory.create().createRequestFactory();
HttpRequest request =
requestFactory.buildPostRequest(new GenericUrl(tokenServerUri), content);
request.setParser(new JsonObjectParser(OAuth2Utils.JSON_FACTORY));
request.setParser(new JsonObjectParser(JSON_FACTORY));
HttpResponse response = request.execute();
GenericData responseData = response.parseAs(GenericData.class);
String accessToken =
Expand Down Expand Up @@ -258,6 +261,47 @@ public final String getRefreshToken() {
return refreshToken;
}


/**
* Returns the instance of InputStream containing the following user credentials in JSON format:
* - RefreshToken
* - ClientId
* - ClientSecret
* - ServerTokenUri
*
* @return user credentials stream
*/
private InputStream getUserCredentialsStream() throws IOException {
GenericJson json = new GenericJson();
json.put("type", GoogleCredentials.USER_FILE_TYPE);
if (refreshToken != null) {
json.put("refresh_token", refreshToken);
}
if (tokenServerUri != null) {
json.put("token_server_uri", tokenServerUri);
}
if (clientId != null) {
json.put("client_id", clientId);
}
if (clientSecret != null) {
json.put("client_secret", clientSecret);
}
json.setFactory(JSON_FACTORY);
String text = json.toPrettyString();
return new ByteArrayInputStream(text.getBytes(UTF_8));
}

/**
* Saves the end user credentials into the given file path.
*
* @param filePath Path to file where to store the credentials
*
* @throws IOException An error storing the credentials.
*/
public void save(String filePath) throws IOException {
OAuth2Utils.writeInputStreamToFile(getUserCredentialsStream(), filePath);
}

@Override
public int hashCode() {
return Objects.hash(super.hashCode(), clientId, clientSecret, refreshToken, tokenServerUri,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
Expand All @@ -75,7 +74,7 @@ public class UserAuthorizerTest {

@Test
public void constructorMinimum() {
TestTokenStore store = new TestTokenStore();
TokenStore store = new MemoryTokensStorage();

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

@Test
public void constructorCommon() {
TestTokenStore store = new TestTokenStore();
TokenStore store = new MemoryTokensStorage();

UserAuthorizer authorizer = UserAuthorizer.newBuilder()
.setClientId(CLIENT_ID)
Expand Down Expand Up @@ -172,7 +171,7 @@ public void getCredentials_noCredentials_returnsNull() throws IOException {
UserAuthorizer authorizer = UserAuthorizer.newBuilder()
.setClientId(CLIENT_ID)
.setScopes(SCOPES)
.setTokenStore(new TestTokenStore())
.setTokenStore(new MemoryTokensStorage())
.build();

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

@Test
public void getCredentials_storedCredentials_returnsStored() throws IOException {
TestTokenStore tokenStore = new TestTokenStore();
TokenStore tokenStore = new MemoryTokensStorage();

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

@Test(expected = NullPointerException.class)
public void getCredentials_nullUserId_throws() throws IOException {
TestTokenStore tokenStore = new TestTokenStore();
TokenStore tokenStore = new MemoryTokensStorage();
UserAuthorizer authorizer = UserAuthorizer.newBuilder()
.setClientId(CLIENT_ID)
.setScopes(SCOPES)
Expand All @@ -217,16 +216,6 @@ public void getCredentials_nullUserId_throws() throws IOException {
authorizer.getCredentials(null);
}

@Test(expected = IllegalStateException.class)
public void getCredentials_nullTokenStore_throws() throws IOException {
UserAuthorizer authorizer = UserAuthorizer.newBuilder()
.setClientId(CLIENT_ID)
.setScopes(SCOPES)
.build();

authorizer.getCredentials(USER_ID);
}

@Test
public void getCredentials_refreshedToken_stored() throws IOException {
final String accessTokenValue1 = "1/MkSJoj1xsli0AccessToken_NKPY2";
Expand All @@ -236,7 +225,7 @@ public void getCredentials_refreshedToken_stored() throws IOException {
MockTokenServerTransportFactory transportFactory = new MockTokenServerTransportFactory();
transportFactory.transport.addClient(CLIENT_ID_VALUE, CLIENT_SECRET);
transportFactory.transport.addRefreshToken(REFRESH_TOKEN, accessTokenValue2);
TestTokenStore tokenStore = new TestTokenStore();
TokenStore tokenStore = new MemoryTokensStorage();
UserAuthorizer authorizer = UserAuthorizer.newBuilder()
.setClientId(CLIENT_ID)
.setScopes(SCOPES)
Expand Down Expand Up @@ -277,7 +266,7 @@ public void getCredentialsFromCode_conevertsCodeToTokens() throws IOException {
MockTokenServerTransportFactory transportFactory = new MockTokenServerTransportFactory();
transportFactory.transport.addClient(CLIENT_ID_VALUE, CLIENT_SECRET);
transportFactory.transport.addAuthorizationCode(CODE, REFRESH_TOKEN, ACCESS_TOKEN_VALUE);
TestTokenStore tokenStore = new TestTokenStore();
TokenStore tokenStore = new MemoryTokensStorage();
UserAuthorizer authorizer = UserAuthorizer.newBuilder()
.setClientId(CLIENT_ID)
.setScopes(SCOPES)
Expand All @@ -296,7 +285,7 @@ public void getCredentialsFromCode_nullCode_throws() throws IOException {
UserAuthorizer authorizer = UserAuthorizer.newBuilder()
.setClientId(CLIENT_ID)
.setScopes(SCOPES)
.setTokenStore(new TestTokenStore())
.setTokenStore(new MemoryTokensStorage())
.build();

authorizer.getCredentialsFromCode(null, BASE_URI);
Expand All @@ -309,7 +298,7 @@ public void getAndStoreCredentialsFromCode_getAndStoresCredentials() throws IOEx
MockTokenServerTransportFactory transportFactory = new MockTokenServerTransportFactory();
transportFactory.transport.addClient(CLIENT_ID_VALUE, CLIENT_SECRET);
transportFactory.transport.addAuthorizationCode(CODE, REFRESH_TOKEN, accessTokenValue1);
TestTokenStore tokenStore = new TestTokenStore();
TokenStore tokenStore = new MemoryTokensStorage();
UserAuthorizer authorizer = UserAuthorizer.newBuilder()
.setClientId(CLIENT_ID)
.setScopes(SCOPES)
Expand Down Expand Up @@ -342,7 +331,7 @@ public void getAndStoreCredentialsFromCode_nullCode_throws() throws IOException
UserAuthorizer authorizer = UserAuthorizer.newBuilder()
.setClientId(CLIENT_ID)
.setScopes(SCOPES)
.setTokenStore(new TestTokenStore())
.setTokenStore(new MemoryTokensStorage())
.build();

authorizer.getAndStoreCredentialsFromCode(USER_ID, null, BASE_URI);
Expand All @@ -353,15 +342,15 @@ public void getAndStoreCredentialsFromCode_nullUserId_throws() throws IOExceptio
UserAuthorizer authorizer = UserAuthorizer.newBuilder()
.setClientId(CLIENT_ID)
.setScopes(SCOPES)
.setTokenStore(new TestTokenStore())
.setTokenStore(new MemoryTokensStorage())
.build();

authorizer.getAndStoreCredentialsFromCode(null, CODE, BASE_URI);
}

@Test
public void revokeAuthorization_revokesAndClears() throws IOException {
TestTokenStore tokenStore = new TestTokenStore();
TokenStore tokenStore = new MemoryTokensStorage();
MockTokenServerTransportFactory transportFactory = new MockTokenServerTransportFactory();
transportFactory.transport.addClient(CLIENT_ID_VALUE, CLIENT_SECRET);
transportFactory.transport.addRefreshToken(REFRESH_TOKEN, ACCESS_TOKEN_VALUE);
Expand Down Expand Up @@ -398,24 +387,4 @@ public void revokeAuthorization_revokesAndClears() throws IOException {
UserCredentials credentials2 = authorizer.getCredentials(USER_ID);
assertNull(credentials2);
}

private static class TestTokenStore implements TokenStore {

private final Map<String, String> map = new HashMap<>();

@Override
public String load(String id) throws IOException {
return map.get(id);
}

@Override
public void store(String id, String tokens) throws IOException {
map.put(id, tokens);
}

@Override
public void delete(String id) throws IOException {
map.remove(id);
}
}
}
Loading

0 comments on commit 5e699a0

Please sign in to comment.