Skip to content

Commit

Permalink
Add fromStream to ServiceAccount(JwtAccess)Credentials and UserCreden…
Browse files Browse the repository at this point in the history
…tials (googleapis#80)
  • Loading branch information
mziccard committed Nov 4, 2016
1 parent a4abf28 commit 0d27d88
Show file tree
Hide file tree
Showing 8 changed files with 392 additions and 18 deletions.
Expand Up @@ -38,6 +38,7 @@
import com.google.api.client.http.HttpRequestFactory;
import com.google.api.client.http.HttpResponse;
import com.google.api.client.http.UrlEncodedContent;
import com.google.api.client.json.GenericJson;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.JsonObjectParser;
import com.google.api.client.json.webtoken.JsonWebSignature;
Expand All @@ -54,6 +55,7 @@
import com.google.common.collect.ImmutableSet;

import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.Reader;
import java.io.StringReader;
Expand Down Expand Up @@ -222,6 +224,51 @@ static PrivateKey privateKeyFromPkcs8(String privateKeyPkcs8) throws IOException
throw new IOException("Unexpected exception reading PKCS#8 data", unexpectedException);
}

/**
* Returns credentials defined by a Service Account key file in JSON format from the Google
* Developers Console.
*
* @param credentialsStream the stream with the credential definition.
* @return the credential defined by the credentialsStream.
* @throws IOException if the credential cannot be created from the stream.
**/
public static ServiceAccountCredentials fromStream(InputStream credentialsStream)
throws IOException {
return fromStream(credentialsStream, OAuth2Utils.HTTP_TRANSPORT_FACTORY);
}

/**
* Returns credentials defined by a Service Account key file in JSON format from the Google
* Developers Console.
*
* @param credentialsStream the stream with the credential definition.
* @param transportFactory HTTP transport factory, creates the transport used to get access
* tokens.
* @return the credential defined by the credentialsStream.
* @throws IOException if the credential cannot be created from the stream.
**/
public static ServiceAccountCredentials fromStream(InputStream credentialsStream,
HttpTransportFactory transportFactory) throws IOException {
Preconditions.checkNotNull(credentialsStream);
Preconditions.checkNotNull(transportFactory);

JsonFactory jsonFactory = OAuth2Utils.JSON_FACTORY;
JsonObjectParser parser = new JsonObjectParser(jsonFactory);
GenericJson fileContents = parser.parseAndClose(
credentialsStream, OAuth2Utils.UTF_8, GenericJson.class);

String fileType = (String) fileContents.get("type");
if (fileType == null) {
throw new IOException("Error reading credentials from stream, 'type' field not specified.");
}
if (SERVICE_ACCOUNT_FILE_TYPE.equals(fileType)) {
return fromJson(fileContents, transportFactory);
}
throw new IOException(String.format(
"Error reading credentials from stream, 'type' value '%s' not recognized."
+ " Expecting '%s'.", fileType, SERVICE_ACCOUNT_FILE_TYPE));
}

/**
* Refreshes the OAuth2 access token by getting a new access token using a JSON Web Token (JWT).
*/
Expand Down
Expand Up @@ -31,7 +31,11 @@

package com.google.auth.oauth2;

import static com.google.auth.oauth2.GoogleCredentials.SERVICE_ACCOUNT_FILE_TYPE;

import com.google.api.client.json.GenericJson;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.JsonObjectParser;
import com.google.api.client.json.webtoken.JsonWebSignature;
import com.google.api.client.json.webtoken.JsonWebToken;
import com.google.api.client.util.Clock;
Expand All @@ -44,6 +48,7 @@
import com.google.common.base.MoreObjects;

import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.net.URI;
import java.security.GeneralSecurityException;
Expand Down Expand Up @@ -123,7 +128,7 @@ static ServiceAccountJwtAccessCredentials fromJson(Map<String, Object> json) thr
}

/**
* Returns service account crentials defined by JSON using the format supported by the Google
* Returns service account credentials defined by JSON using the format supported by the Google
* Developers Console.
*
* @param json a map from the JSON representing the credentials.
Expand Down Expand Up @@ -174,6 +179,49 @@ public static ServiceAccountJwtAccessCredentials fromPkcs8(String clientId, Stri
clientId, clientEmail, privateKey, privateKeyId, defaultAudience);
}

/**
* Returns credentials defined by a Service Account key file in JSON format from the Google
* Developers Console.
*
* @param credentialsStream the stream with the credential definition.
* @return the credential defined by the credentialsStream.
* @throws IOException if the credential cannot be created from the stream.
**/
public static ServiceAccountJwtAccessCredentials fromStream(InputStream credentialsStream)
throws IOException {
return fromStream(credentialsStream, null);
}

/**
* Returns credentials defined by a Service Account key file in JSON format from the Google
* Developers Console.
*
* @param credentialsStream the stream with the credential definition.
* @param defaultAudience Audience to use if not provided by transport. May be null.
* @return the credential defined by the credentialsStream.
* @throws IOException if the credential cannot be created from the stream.
**/
public static ServiceAccountJwtAccessCredentials fromStream(InputStream credentialsStream,
URI defaultAudience) throws IOException {
Preconditions.checkNotNull(credentialsStream);

JsonFactory jsonFactory = OAuth2Utils.JSON_FACTORY;
JsonObjectParser parser = new JsonObjectParser(jsonFactory);
GenericJson fileContents = parser.parseAndClose(
credentialsStream, OAuth2Utils.UTF_8, GenericJson.class);

String fileType = (String) fileContents.get("type");
if (fileType == null) {
throw new IOException("Error reading credentials from stream, 'type' field not specified.");
}
if (SERVICE_ACCOUNT_FILE_TYPE.equals(fileType)) {
return fromJson(fileContents, defaultAudience);
}
throw new IOException(String.format(
"Error reading credentials from stream, 'type' value '%s' not recognized."
+ " Expecting '%s'.", fileType, SERVICE_ACCOUNT_FILE_TYPE));
}

@Override
public String getAuthenticationType() {
return "JWTAccess";
Expand Down
48 changes: 47 additions & 1 deletion oauth2_http/java/com/google/auth/oauth2/UserCredentials.java
Expand Up @@ -38,12 +38,15 @@
import com.google.api.client.http.HttpRequestFactory;
import com.google.api.client.http.HttpResponse;
import com.google.api.client.http.UrlEncodedContent;
import com.google.api.client.json.GenericJson;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.JsonObjectParser;
import com.google.api.client.util.GenericData;
import com.google.api.client.util.Preconditions;
import com.google.auth.http.HttpTransportFactory;

import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.net.URI;
import java.util.Date;
Expand Down Expand Up @@ -118,7 +121,7 @@ public UserCredentials(String clientId, String clientSecret, String refreshToken
}

/**
* Returns user crentials defined by JSON contents using the format supported by the Cloud SDK.
* Returns user credentials defined by JSON contents using the format supported by the Cloud SDK.
*
* @param json a map from the JSON representing the credentials.
* @param transportFactory HTTP transport factory, creates the transport used to get access
Expand All @@ -138,6 +141,49 @@ static UserCredentials fromJson(Map<String, Object> json, HttpTransportFactory t
return new UserCredentials(clientId, clientSecret, refreshToken, null, transportFactory, null);
}

/**
* Returns credentials defined by a JSON file stream using the format supported by the Cloud SDK.
*
* @param credentialsStream the stream with the credential definition.
* @return the credential defined by the credentialsStream.
* @throws IOException if the credential cannot be created from the stream.
**/
public static UserCredentials fromStream(InputStream credentialsStream)
throws IOException {
return fromStream(credentialsStream, OAuth2Utils.HTTP_TRANSPORT_FACTORY);
}

/**
* Returns credentials defined by a JSON file stream using the format supported by the Cloud SDK.
*
* @param credentialsStream the stream with the credential definition.
* @param transportFactory HTTP transport factory, creates the transport used to get access
* tokens.
* @return the credential defined by the credentialsStream.
* @throws IOException if the credential cannot be created from the stream.
**/
public static UserCredentials fromStream(InputStream credentialsStream,
HttpTransportFactory transportFactory) throws IOException {
Preconditions.checkNotNull(credentialsStream);
Preconditions.checkNotNull(transportFactory);

JsonFactory jsonFactory = OAuth2Utils.JSON_FACTORY;
JsonObjectParser parser = new JsonObjectParser(jsonFactory);
GenericJson fileContents = parser.parseAndClose(
credentialsStream, OAuth2Utils.UTF_8, GenericJson.class);

String fileType = (String) fileContents.get("type");
if (fileType == null) {
throw new IOException("Error reading credentials from stream, 'type' field not specified.");
}
if (USER_FILE_TYPE.equals(fileType)) {
return fromJson(fileContents, transportFactory);
}
throw new IOException(String.format(
"Error reading credentials from stream, 'type' value '%s' not recognized."
+ " Expecting '%s'.", fileType, USER_FILE_TYPE));
}

/**
* Refreshes the OAuth2 access token by getting a new access token from the refresh token
*/
Expand Down
Expand Up @@ -272,7 +272,7 @@ public void getDefaultCredentials_envServiceAccount_providesToken() throws IOExc
MockTokenServerTransportFactory transportFactory = new MockTokenServerTransportFactory();
transportFactory.transport.addServiceAccount(SA_CLIENT_EMAIL, ACCESS_TOKEN);
InputStream serviceAccountStream = ServiceAccountCredentialsTest
.writeServiceAccountAccountStream(
.writeServiceAccountStream(
SA_CLIENT_ID, SA_CLIENT_EMAIL, SA_PRIVATE_KEY_PKCS8, SA_PRIVATE_KEY_ID);
TestDefaultCredentialsProvider testProvider = new TestDefaultCredentialsProvider();
String serviceAccountPath = "/service_account.json";
Expand Down
Expand Up @@ -114,18 +114,18 @@ public void fromStream_nullTransport_throws() throws IOException {
InputStream stream = new ByteArrayInputStream("foo".getBytes());
try {
GoogleCredentials.fromStream(stream, null);
fail();
fail("Should throw if HttpTransportFactory is null");
} catch (NullPointerException expected) {
// Expected
}
}

@Test
public void fromStream_nullStreamThrows() throws IOException {
public void fromStream_nullStream_throws() throws IOException {
MockHttpTransportFactory transportFactory = new MockHttpTransportFactory();
try {
GoogleCredentials.fromStream(null, transportFactory);
fail();
fail("Should throw if InputStream is null");
} catch (NullPointerException expected) {
// Expected
}
Expand All @@ -136,7 +136,7 @@ public void fromStream_serviceAccount_providesToken() throws IOException {
MockTokenServerTransportFactory transportFactory = new MockTokenServerTransportFactory();
transportFactory.transport.addServiceAccount(SA_CLIENT_EMAIL, ACCESS_TOKEN);
InputStream serviceAccountStream = ServiceAccountCredentialsTest
.writeServiceAccountAccountStream(
.writeServiceAccountStream(
SA_CLIENT_ID, SA_CLIENT_EMAIL, SA_PRIVATE_KEY_PKCS8, SA_PRIVATE_KEY_ID);

GoogleCredentials credentials =
Expand All @@ -151,35 +151,31 @@ public void fromStream_serviceAccount_providesToken() throws IOException {
@Test
public void fromStream_serviceAccountNoClientId_throws() throws IOException {
InputStream serviceAccountStream = ServiceAccountCredentialsTest
.writeServiceAccountAccountStream(
null, SA_CLIENT_EMAIL, SA_PRIVATE_KEY_PKCS8, SA_PRIVATE_KEY_ID);
.writeServiceAccountStream(null, SA_CLIENT_EMAIL, SA_PRIVATE_KEY_PKCS8, SA_PRIVATE_KEY_ID);

testFromStreamException(serviceAccountStream, "client_id");
}

@Test
public void fromStream_serviceAccountNoClientEmail_throws() throws IOException {
InputStream serviceAccountStream = ServiceAccountCredentialsTest
.writeServiceAccountAccountStream(
SA_CLIENT_ID, null, SA_PRIVATE_KEY_PKCS8, SA_PRIVATE_KEY_ID);
.writeServiceAccountStream(SA_CLIENT_ID, null, SA_PRIVATE_KEY_PKCS8, SA_PRIVATE_KEY_ID);

testFromStreamException(serviceAccountStream, "client_email");
}

@Test
public void fromStream_serviceAccountNoPrivateKey_throws() throws IOException {
InputStream serviceAccountStream = ServiceAccountCredentialsTest
.writeServiceAccountAccountStream(
SA_CLIENT_ID, SA_CLIENT_EMAIL, null, SA_PRIVATE_KEY_ID);
.writeServiceAccountStream(SA_CLIENT_ID, SA_CLIENT_EMAIL, null, SA_PRIVATE_KEY_ID);

testFromStreamException(serviceAccountStream, "private_key");
}

@Test
public void fromStream_serviceAccountNoPrivateKeyId_throws() throws IOException {
InputStream serviceAccountStream = ServiceAccountCredentialsTest
.writeServiceAccountAccountStream(
SA_CLIENT_ID, SA_CLIENT_EMAIL, SA_PRIVATE_KEY_PKCS8, null);
.writeServiceAccountStream(SA_CLIENT_ID, SA_CLIENT_EMAIL, SA_PRIVATE_KEY_PKCS8, null);

testFromStreamException(serviceAccountStream, "private_key_id");
}
Expand Down Expand Up @@ -223,10 +219,11 @@ public void fromStream_userNoRefreshToken_throws() throws IOException {
testFromStreamException(userStream, "refresh_token");
}

private void testFromStreamException(InputStream stream, String expectedMessageContent) {
private static void testFromStreamException(InputStream stream, String expectedMessageContent) {
try {
GoogleCredentials.fromStream(stream, DUMMY_TRANSPORT_FACTORY);
fail();
fail(String.format("Should throw exception with message containing '%s'",
expectedMessageContent));
} catch (IOException expected) {
assertTrue(expected.getMessage().contains(expectedMessageContent));
}
Expand Down

0 comments on commit 0d27d88

Please sign in to comment.