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

Use Application Default Credentials to get App/Compute Engine credentials #337

Merged
merged 8 commits into from
Nov 25, 2015
Merged
Show file tree
Hide file tree
Changes from 6 commits
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
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,8 @@ Most `gcloud-java` libraries require a project ID. There are multiple ways to s
1. Project ID supplied when building the service options
2. Project ID specified by the environment variable `GCLOUD_PROJECT`
3. App Engine project ID
4. Compute Engine project ID
5. Google Cloud SDK project ID
4. Google Cloud SDK project ID
5. Compute Engine project ID

Authentication
--------------
Expand Down
10 changes: 8 additions & 2 deletions gcloud-java-core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,18 @@
<dependency>
<groupId>com.google.auth</groupId>
<artifactId>google-auth-library-credentials</artifactId>
<version>0.1.0</version>
<version>0.3.1</version>
</dependency>
<dependency>
<groupId>com.google.auth</groupId>
<artifactId>google-auth-library-oauth2-http</artifactId>
<version>0.1.0</version>
<version>0.3.1</version>
<exclusions>
<exclusion>
<groupId>com.google.guava</groupId>
<artifactId>guava-jdk5</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.google.http-client</groupId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,9 @@
import static com.google.common.base.Preconditions.checkNotNull;

import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
import com.google.api.client.googleapis.compute.ComputeCredential;
import com.google.api.client.googleapis.extensions.appengine.auth.oauth2.AppIdentityCredential;
import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport;
import com.google.api.client.http.HttpRequestInitializer;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.jackson.JacksonFactory;
import com.google.auth.http.HttpCredentialsAdapter;
import com.google.auth.oauth2.GoogleCredentials;
Expand All @@ -33,7 +30,6 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import java.security.GeneralSecurityException;
import java.security.PrivateKey;
import java.util.Objects;
import java.util.Set;
Expand Down Expand Up @@ -164,55 +160,6 @@ public RestorableState<AuthCredentials> capture() {
}
}

private static class ComputeEngineAuthCredentials extends AuthCredentials {

private ComputeCredential computeCredential;

private static final ComputeEngineAuthCredentialsState STATE =
new ComputeEngineAuthCredentialsState();

private static class ComputeEngineAuthCredentialsState
implements RestorableState<AuthCredentials>, Serializable {

private static final long serialVersionUID = -6168594072854417404L;

@Override
public AuthCredentials restore() {
try {
return new ComputeEngineAuthCredentials();
} catch (IOException | GeneralSecurityException e) {
throw new IllegalStateException(
"Could not restore " + ComputeEngineAuthCredentials.class.getSimpleName(), e);
}
}

@Override
public int hashCode() {
return getClass().getName().hashCode();
}

@Override
public boolean equals(Object obj) {
return obj instanceof ComputeEngineAuthCredentialsState;
}
}

ComputeEngineAuthCredentials() throws IOException, GeneralSecurityException {
computeCredential = getComputeCredential();
}

@Override
protected HttpRequestInitializer httpRequestInitializer(HttpTransport transport,
Set<String> scopes) {
return computeCredential;
}

@Override
public RestorableState<AuthCredentials> capture() {
return STATE;
}
}

public static class ApplicationDefaultAuthCredentials extends AuthCredentials {

private GoogleCredentials googleCredentials;
Expand Down Expand Up @@ -278,11 +225,6 @@ public static AuthCredentials createForAppEngine() {
return AppEngineAuthCredentials.INSTANCE;
}

public static AuthCredentials createForComputeEngine()
throws IOException, GeneralSecurityException {
return new ComputeEngineAuthCredentials();
}

/**
* Returns the Application Default Credentials.
*
Expand Down Expand Up @@ -337,13 +279,4 @@ public static ServiceAccountAuthCredentials createForJson(InputStream jsonCreden
public static AuthCredentials noCredentials() {
return ServiceAccountAuthCredentials.NO_CREDENTIALS;
}

static ComputeCredential getComputeCredential() throws IOException, GeneralSecurityException {
NetHttpTransport transport = GoogleNetHttpTransport.newTrustedTransport();
// Try to connect using Google Compute Engine service account credentials.
ComputeCredential credential = new ComputeCredential(transport, new JacksonFactory());
// Force token refresh to detect if we are running on Google Compute Engine.
credential.refreshToken();
return credential;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,13 @@
import static java.nio.charset.StandardCharsets.UTF_8;

import com.google.api.client.extensions.appengine.http.UrlFetchTransport;
import com.google.api.client.googleapis.compute.ComputeCredential;
import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport;
import com.google.api.client.http.HttpRequest;
import com.google.api.client.http.HttpRequestInitializer;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.jackson.JacksonFactory;
import com.google.common.collect.Iterables;
import com.google.gcloud.spi.ServiceRpcFactory;

Expand All @@ -41,6 +44,7 @@
import java.lang.reflect.Method;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.GeneralSecurityException;
import java.util.Enumeration;
import java.util.Locale;
import java.util.Objects;
Expand Down Expand Up @@ -111,12 +115,22 @@ public HttpTransport create() {
}
// Consider Compute
try {
return AuthCredentials.getComputeCredential().getTransport();
return getComputeHttpTransport();

This comment was marked as spam.

} catch (Exception e) {
// Maybe not on GCE
}
return new NetHttpTransport();
}

private static HttpTransport getComputeHttpTransport()
throws IOException, GeneralSecurityException {
NetHttpTransport transport = GoogleNetHttpTransport.newTrustedTransport();
// Try to connect using Google Compute Engine service account credentials.
ComputeCredential credential = new ComputeCredential(transport, new JacksonFactory());
// Force token refresh to detect if we are running on Google Compute Engine.
credential.refreshToken();
return transport;
}
}

/**
Expand Down Expand Up @@ -342,7 +356,7 @@ protected boolean projectIdRequired() {
}

private static AuthCredentials defaultAuthCredentials() {
// Consider App Engine. This will not be needed once issue #21 is fixed.
// Consider App Engine.
if (appEngineAppId() != null) {
try {
return AuthCredentials.createForAppEngine();
Expand All @@ -354,16 +368,8 @@ private static AuthCredentials defaultAuthCredentials() {
try {
return AuthCredentials.createApplicationDefaults();
} catch (Exception ex) {
// fallback to old-style
return AuthCredentials.noCredentials();
}

// Consider old-style Compute. This will not be needed once issue #21 is fixed.
try {
return AuthCredentials.createForComputeEngine();
} catch (Exception ignore) {
// Maybe not on GCE
}
return AuthCredentials.noCredentials();
}

protected static String appEngineAppId() {
Expand All @@ -383,19 +389,6 @@ protected String defaultProject() {
}

protected static String googleCloudProjectId() {
try {
URL url = new URL("http://metadata/computeMetadata/v1/project/project-id");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestProperty("X-Google-Metadata-Request", "True");
InputStream input = connection.getInputStream();
if (connection.getResponseCode() == 200) {
try (BufferedReader reader = new BufferedReader(new InputStreamReader(input, UTF_8))) {
return reader.readLine();
}
}
} catch (IOException ignore) {
// ignore
}
File configDir;
if (System.getenv().containsKey("CLOUDSDK_CONFIG")) {
configDir = new File(System.getenv("CLOUDSDK_CONFIG"));
Expand All @@ -404,38 +397,52 @@ protected static String googleCloudProjectId() {
} else {
configDir = new File(System.getProperty("user.home"), ".config/gcloud");
}
FileReader fileReader;
FileReader fileReader = null;
try {
fileReader = new FileReader(new File(configDir, "configurations/config_default"));
} catch (FileNotFoundException newConfigFileNotFoundEx) {
try {
fileReader = new FileReader(new File(configDir, "properties"));
} catch (FileNotFoundException oldConfigFileNotFoundEx) {
// return null if we can't find config file
return null;
// ignore
}
}
try (BufferedReader reader = new BufferedReader(fileReader)) {
String line;
String section = null;
Pattern projectPattern = Pattern.compile("^project\\s*=\\s*(.*)$");
Pattern sectionPattern = Pattern.compile("^\\[(.*)\\]$");
while ((line = reader.readLine()) != null) {
if (line.isEmpty() || line.startsWith(";")) {
continue;
}
line = line.trim();
Matcher matcher = sectionPattern.matcher(line);
if (matcher.matches()) {
section = matcher.group(1);
} else if (section == null || section.equals("core")) {
matcher = projectPattern.matcher(line);
if (fileReader != null) {
try (BufferedReader reader = new BufferedReader(fileReader)) {
String line;
String section = null;
Pattern projectPattern = Pattern.compile("^project\\s*=\\s*(.*)$");
Pattern sectionPattern = Pattern.compile("^\\[(.*)\\]$");
while ((line = reader.readLine()) != null) {
if (line.isEmpty() || line.startsWith(";")) {
continue;
}
line = line.trim();
Matcher matcher = sectionPattern.matcher(line);
if (matcher.matches()) {
return matcher.group(1);
section = matcher.group(1);
} else if (section == null || section.equals("core")) {
matcher = projectPattern.matcher(line);
if (matcher.matches()) {
return matcher.group(1);
}
}
}
} catch (IOException ex) {
// ignore
}
}
try {
URL url = new URL("http://metadata/computeMetadata/v1/project/project-id");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestProperty("X-Google-Metadata-Request", "True");
InputStream input = connection.getInputStream();
if (connection.getResponseCode() == 200) {
try (BufferedReader reader = new BufferedReader(new InputStreamReader(input, UTF_8))) {
return reader.readLine();
}
}
} catch (IOException ex) {
} catch (IOException ignore) {
// ignore
}
// return null if can't determine
Expand Down