Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: adds support for 3PI credentials #464

Merged
merged 6 commits into from
Aug 26, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,9 @@
import com.google.api.client.json.JsonObjectParser;
import com.google.auth.http.HttpTransportFactory;
import com.google.common.annotations.VisibleForTesting;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.LinkOption;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collection;
Expand Down Expand Up @@ -72,6 +72,17 @@ enum IdentityPoolCredentialSourceType {

@Nullable private Map<String, String> headers;

/**
* The source of the 3P credential.
*
* <p>If the this a file based 3P credential, the credentials file can be retrieved using the
* `file` key.
*
* <p>If this is url-based 3p credential, the metadata server URL can be retrieved using the
lsirac marked this conversation as resolved.
Show resolved Hide resolved
* `url` key.
*
* <p>Optional headers can be present, and should be keyed by `headers`.
*/
public IdentityPoolCredentialSource(Map<String, Object> credentialSourceMap) {
super(credentialSourceMap);

Expand Down Expand Up @@ -155,14 +166,14 @@ private String retrieveSubjectTokenFromCredentialFile() throws IOException {
IdentityPoolCredentialSource identityPoolCredentialSource =
(IdentityPoolCredentialSource) credentialSource;
String credentialFilePath = identityPoolCredentialSource.credentialLocation;
if (!new File(credentialFilePath).isFile()) {
if (!Files.exists(Paths.get(credentialFilePath), LinkOption.NOFOLLOW_LINKS)) {
throw new IOException("Invalid credential location. The file does not exist.");
lsirac marked this conversation as resolved.
Show resolved Hide resolved
}
try {
return new String(Files.readAllBytes(Paths.get(credentialFilePath)));
} catch (IOException e) {
throw new IOException(
"Error when attempting to read the subject token from the credential file. " + e);
"Error when attempting to read the subject token from the credential file.", e);
}
}

Expand Down
7 changes: 2 additions & 5 deletions oauth2_http/javatests/com/google/auth/TestUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,6 @@
/** Utilities for test code under com.google.auth. */
public class TestUtils {

private static final String RFC3339 = "yyyy-MM-dd'T'HH:mm:ss'Z'";
private static final int VALID_LIFETIME = 300;
chingor13 marked this conversation as resolved.
Show resolved Hide resolved

private static final JsonFactory JSON_FACTORY = JacksonFactory.getDefaultInstance();

public static final String UTF_8 = "UTF-8";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please see comments on original PR

Expand Down Expand Up @@ -150,8 +147,8 @@ public static String getDefaultExpireTime() {
Date currentDate = new Date();
Calendar c = Calendar.getInstance();
c.setTime(currentDate);
c.add(Calendar.SECOND, VALID_LIFETIME);
return new SimpleDateFormat(RFC3339).format(c.getTime());
c.add(Calendar.SECOND, 300);
return new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'").format(c.getTime());
}

private TestUtils() {}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2015, Google Inc. All rights reserved.
* Copyright 2020, Google LLC
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
Expand Down Expand Up @@ -31,7 +31,6 @@

package com.google.auth.oauth2;

import static com.google.auth.TestUtils.buildHttpResponseException;
import static com.google.auth.TestUtils.getDefaultExpireTime;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertThrows;
Expand Down Expand Up @@ -59,43 +58,30 @@
@RunWith(JUnit4.class)
public class ExternalAccountCredentialsTest {

private static final String FILE = "file";
private static final String AUDIENCE = "audience";
private static final String SUBJECT_TOKEN_TYPE = "subjectTokenType";
private static final String TOKEN_INFO_URL = "tokenInfoUrl";
private static final String STS_URL = "https://www.sts.google.com";
private static final String CREDENTIAL = "credential";
private static final String ACCESS_TOKEN = "eya23tfgdfga2123as";
private static final String CONTENT_TYPE_KEY = "content-type";
private static final String CONTENT_TYPE = "application/x-www-form-urlencoded";
private static final String CLOUD_PLATFORM_SCOPE =
"https://www.googleapis.com/auth/cloud-platform";

static class MockExternalAccountCredentialsTransportFactory implements HttpTransportFactory {

MockExternalAccountCredentialsTransport transport =
new MockExternalAccountCredentialsTransport();

private static final Map<String, Object> FILE_CREDENTIAL_SOURCE_MAP =
new HashMap<String, Object>() {
{
put(FILE, FILE);
put("file", "file");
}
};

private static final IdentityPoolCredentialSource FILE_CREDENTIAL_SOURCE =
new IdentityPoolCredentialSource(FILE_CREDENTIAL_SOURCE_MAP);

private static final IdentityPoolCredentials EXTERNAL_ACCOUNT_CREDENTIALS =
(IdentityPoolCredentials)
IdentityPoolCredentials.newBuilder()
.setHttpTransportFactory(OAuth2Utils.HTTP_TRANSPORT_FACTORY)
.setAudience(AUDIENCE)
.setSubjectTokenType(SUBJECT_TOKEN_TYPE)
.setTokenUrl(STS_URL)
.setTokenInfoUrl(TOKEN_INFO_URL)
.setCredentialSource(FILE_CREDENTIAL_SOURCE)
.build();

@Override
public HttpTransport create() {
return transport;
Expand Down Expand Up @@ -201,8 +187,8 @@ public void exchange3PICredentialForAccessToken() throws IOException {

Map<String, List<String>> headers = transportFactory.transport.getRequest().getHeaders();

assertThat(headers.containsKey(CONTENT_TYPE_KEY)).isTrue();
assertThat(headers.get(CONTENT_TYPE_KEY).get(0)).isEqualTo(CONTENT_TYPE);
assertThat(headers.containsKey("content-type")).isTrue();
assertThat(headers.get("content-type").get(0)).isEqualTo("application/x-www-form-urlencoded");
}

@Test
Expand All @@ -214,7 +200,7 @@ public void exchange3PICredentialForAccessToken_throws() throws IOException {
String errorDescription = "errorDescription";
String errorUri = "errorUri";
transportFactory.transport.addResponseErrorSequence(
buildHttpResponseException(errorCode, errorDescription, errorUri));
TestUtils.buildHttpResponseException(errorCode, errorDescription, errorUri));

final StsTokenExchangeRequest stsTokenExchangeRequest =
StsTokenExchangeRequest.newBuilder(CREDENTIAL, SUBJECT_TOKEN_TYPE).build();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2015, Google Inc. All rights reserved.
* Copyright 2020, Google LLC
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,16 +57,17 @@
*/
public class MockExternalAccountCredentialsTransport extends MockHttpTransport {

private static final String EXPECTED_GRANT_TYPE =
"urn:ietf:params:oauth:grant-type:token-exchange";
private static final String CLOUD_PLATFORM_SCOPE =
"https://www.googleapis.com/auth/cloud-platform";

private static final String METADATA_SERVER_URL = "https://www.metadata.google.com";
private static final String STS_URL = "https://www.sts.google.com";
private static final String SERVICE_ACCOUNT_IMPERSONATION_URL =
"https://iamcredentials.googleapis.com";
private static final String CLOUD_PLATFORM_SCOPE =
"https://www.googleapis.com/auth/cloud-platform";

private static final String SUBJECT_TOKEN = "subjectToken";
private static final String CONTENT_TYPE_TEXT = "text/html";
private static final String EXPECTED_GRANT_TYPE =
"urn:ietf:params:oauth:grant-type:token-exchange";
private static final String ISSUED_TOKEN_TYPE = "urn:ietf:params:oauth:token-type:access_token";
private static final String TOKEN_TYPE = "Bearer";
private static final String ACCESS_TOKEN = "accessToken";
Expand Down Expand Up @@ -108,7 +109,7 @@ public LowLevelHttpResponse execute() throws IOException {
throw new IOException("Metadata request header not found.");
}
return new MockLowLevelHttpResponse()
.setContentType(CONTENT_TYPE_TEXT)
.setContentType("text/html")
.setContent(SUBJECT_TOKEN);
}
if (STS_URL.equals(url)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@

package com.google.auth.oauth2;

import static com.google.auth.TestUtils.buildHttpResponseException;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertThrows;

Expand Down Expand Up @@ -203,7 +202,7 @@ public void exchangeToken_throwsException() throws IOException {
.build();

transport.addResponseErrorSequence(
buildHttpResponseException(
TestUtils.buildHttpResponseException(
INVALID_REQUEST, /* errorDescription= */ null, /* errorUri= */ null));

OAuthException e =
Expand Down Expand Up @@ -232,7 +231,7 @@ public void exchangeToken_withOptionalParams_throwsException() throws IOExceptio
.build();

transport.addResponseErrorSequence(
buildHttpResponseException(INVALID_REQUEST, ERROR_DESCRIPTION, ERROR_URI));
TestUtils.buildHttpResponseException(INVALID_REQUEST, ERROR_DESCRIPTION, ERROR_URI));

OAuthException e =
assertThrows(
Expand Down