Skip to content

Commit

Permalink
ENG-6645: GCP Extend overthere hosts to allow authentication using IA…
Browse files Browse the repository at this point in the history
…M Token (#273)

* ENG-6645: OVerthere GCP Token based authentication and Authorization

* ENG-6645: GCP Extend overthere hosts to allow authentication using IAM tokens

* ENG-6645: GCP Code Refractoring

* ENG-6645: GCP Code Refractoring Next

* Update Jenkinsfile

* ENG-6645: GCP Overthere token Test Case

* ENG-6645: GCP Overthere token Test Case Correction

* ENG-6645: GCP Overthere Token based authentication Review comments

* Update Jenkinsfile

* Update GcpMetadataKeyManager.java

Co-authored-by: Karthik Sonti <sonti.karthik2008@gmail.com>
  • Loading branch information
nitheshrayuduv and karthiksonti24 committed Aug 20, 2021
1 parent 295d292 commit d32214a
Show file tree
Hide file tree
Showing 8 changed files with 131 additions and 9 deletions.
1 change: 0 additions & 1 deletion Jenkinsfile
Expand Up @@ -14,7 +14,6 @@ pipeline {
description: 'Configuration to run server on an environment with designated jdk version')
string(name: 'slaveNode', defaultValue: 'xlr||xld', description: 'Node label where steps would be executed.')
}

environment {
REPOSITORY_NAME = 'overthere'
GRADLE_OPTS = "-XX:MaxPermSize=256m -Xmx1024m -Djsse.enableSNIExtension=true"
Expand Down
19 changes: 19 additions & 0 deletions README.md
Expand Up @@ -1294,6 +1294,9 @@ To be able to use GCP API's credentials needs to be supplied via Overthere optio
<li>
`ServiceAccountPkcs8` - defined by a Service Account PKCS#8 private key and other required options.
</li>
<li>
`ServiceAccountToken` - defined by an Access Token.
</li>
</ul>
</td>
</tr>
Expand Down Expand Up @@ -1374,6 +1377,22 @@ For `ServiceAccountPkcs8` following options are required:
</tr>
</table>

For `ServiceAccountToken` following option is required:
<table>
<tr>
<th align="left" valign="top"><a name="gcp_projectId"></a>projectId</th>
<td>
Project ID
</td>
</tr>
<tr>
<th align="left" valign="top"><a name="gcp_apiToken"></a>ApiToken</th>
<td>
Access Token Which can be used for Authentication.Generated by using the Token URL.
</td>
</tr>
</table>

<a name="release_history"></a>
# Release History
* Overthere 5.3.2 (30-Mar-2021)
Expand Down
Expand Up @@ -20,7 +20,6 @@
import com.google.api.services.compute.model.Operation;
import com.google.api.services.compute.model.Project;
import com.google.auth.http.HttpCredentialsAdapter;

import com.xebialabs.overthere.gcp.credentials.GcpCredentialFactory;
import com.xebialabs.overthere.gcp.credentials.ProjectCredentials;

Expand Down Expand Up @@ -211,11 +210,19 @@ private void checkForOperationErrors(final Operation operation) {
}

private Compute createComputeService() {
return new Compute.Builder(
httpTransport,
jsonFactory,
new HttpCredentialsAdapter(projectCredentials.getCredentials())
).setApplicationName(applicationName).build();
if(projectCredentials.getOauth2Credential() != null) {
return new Compute.Builder(
httpTransport, jsonFactory, null)
.setApplicationName(applicationName)
.setHttpRequestInitializer(projectCredentials.getOauth2Credential())
.build();
} else {
return new Compute.Builder(
httpTransport,
jsonFactory,
new HttpCredentialsAdapter(projectCredentials.getCredentials())
).setApplicationName(applicationName).build();
}
}

private static String getISO8601StringForDate(long date) {
Expand Down
Expand Up @@ -48,6 +48,11 @@ public class GcpSshConnectionBuilder extends SshConnectionBuilder {
*/
public static final String PROJECT_ID = "projectId";

/**
* See <a href="https://github.com/xebialabs/overthere/blob/master/README.md#gcp_apiToken">the online documentation</a>
*/
public static final String API_TOKEN = "apiToken";

/**
* See <a href="https://github.com/xebialabs/overthere/blob/master/README.md#gcp_zoneName">the online documentation</a>
*/
Expand Down
Expand Up @@ -21,6 +21,7 @@
import static com.xebialabs.overthere.gcp.GcpSshConnectionBuilder.SCOPES;
import static com.xebialabs.overthere.gcp.GcpSshConnectionBuilder.SERVICE_ACCOUNT_USER;
import static com.xebialabs.overthere.gcp.GcpSshConnectionBuilder.TOKEN_SERVER_URI;
import static com.xebialabs.overthere.gcp.GcpSshConnectionBuilder.API_TOKEN;

/**
* Enums that are used under option `gcpCredentialsType`.
Expand All @@ -41,6 +42,19 @@ public String createKey(final ConnectionOptions options) {
return composeKey(options.<String>get(CLIENT_EMAIL), options);
}
},
ServiceAccountToken(Sets.newHashSet(PROJECT_ID, API_TOKEN)) {
@Override
protected GcpCredentialFactory doCreate(final ConnectionOptions options) {
return new ServiceAccountTokenGcpCredentialFactory(
options.<String>get(PROJECT_ID),
options.<String>get(API_TOKEN)
);
}
@Override
public String createKey(final ConnectionOptions options) {
return composeKey(options.<String>get(API_TOKEN), options);
}
},
ServiceAccountJsonFile(Sets.newHashSet(CREDENTIALS_FILE)) {
@Override
protected GcpCredentialFactory doCreate(final ConnectionOptions options) {
Expand Down
@@ -1,9 +1,10 @@
package com.xebialabs.overthere.gcp.credentials;

import com.google.auth.Credentials;

import com.google.api.client.auth.oauth2.Credential;
public final class ProjectCredentials {
private final Credentials credentials;
private Credentials credentials;
private Credential oauth2Credential;
private final String projectId;
private final String clientEmail;

Expand All @@ -13,10 +14,20 @@ public final class ProjectCredentials {
this.clientEmail = clientEmail;
}

ProjectCredentials(final Credential credential, final String projectId, final String clientEmail) {
this.oauth2Credential = credential;
this.projectId = projectId;
this.clientEmail = clientEmail;
}

public Credentials getCredentials() {
return credentials;
}

public Credential getOauth2Credential() {
return oauth2Credential;
}

public String getProjectId() {
return projectId;
}
Expand Down
@@ -0,0 +1,51 @@
package com.xebialabs.overthere.gcp.credentials;

import com.google.api.client.auth.oauth2.BearerToken;
import com.google.api.client.auth.oauth2.Credential;
import com.google.api.client.auth.oauth2.TokenResponse;
import com.google.api.client.http.GenericUrl;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.jackson2.JacksonFactory;
import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport;

import java.io.IOException;
import java.security.GeneralSecurityException;
/**
* Returns credentials defined by a Service Account key in JSON format from the Google Developers Console.
*/
class ServiceAccountTokenGcpCredentialFactory extends GcpCredentialFactory {

private final String projectId;
private final String apiToken;
private static final JsonFactory JSON_FACTORY = JacksonFactory.getDefaultInstance();
private HttpTransport httpTransport;

ServiceAccountTokenGcpCredentialFactory(final String projectId, final String apiToken) {
this.projectId = projectId;
this.apiToken = apiToken;
}

@Override
protected ProjectCredentials doCreate() {
try {
this.httpTransport = GoogleNetHttpTransport.newTrustedTransport();
TokenResponse tokenResponse = new TokenResponse();
tokenResponse.setAccessToken(apiToken);
return new ProjectCredentials(new Credential.Builder(BearerToken.authorizationHeaderAccessMethod()).setTransport(
httpTransport)
.setJsonFactory(JSON_FACTORY)
.setTokenServerUrl(
new GenericUrl("https://www.googleapis.com/auth/cloud-platform"))
.build()
.setFromTokenResponse(tokenResponse), projectId, "");
} catch (IOException | GeneralSecurityException e) {
throw new IllegalArgumentException(String.format("Cannot use credentials from Token : %s", apiToken), e);
}
}

@Override
public String info() {
return String.format("credentials Api Token : %s", apiToken);
}
}
Expand Up @@ -22,6 +22,7 @@
import static com.xebialabs.overthere.gcp.GcpSshConnectionBuilder.SCOPES;
import static com.xebialabs.overthere.gcp.GcpSshConnectionBuilder.SERVICE_ACCOUNT_USER;
import static com.xebialabs.overthere.gcp.GcpSshConnectionBuilder.TOKEN_SERVER_URI;
import static com.xebialabs.overthere.gcp.GcpSshConnectionBuilder.API_TOKEN;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.startsWith;
import static org.hamcrest.MatcherAssert.assertThat;
Expand All @@ -45,6 +46,21 @@ public void canSetupDefaultGcpCredentialsType() {
assertThat(gcpCredentialFactory instanceof DefaultCredentialsGcpCredentialFactory, equalTo(true));
}

@Test
public void canSetupServiceAccountTokenGcpCredentialsType() {
options.set(GCP_CREDENTIALS_TYPE, GcpCredentialsType.ServiceAccountToken.name());
options.set(PROJECT_ID, "project_id");
options.set(API_TOKEN, "ya29.c.Kp8BCQjd8meb5Z2MuKkzVUzqPbIveWIgI7NVuQVxZBpeSGmVbS4gaUY4Cbq6UUVzi8zr-hTTEwHANedcbT5godVD6-740kLc9C7JeB2_HilgaYqv7kR-oi_mz8Apgbh-HJhugFRRp8zMh07sMA98_shojHg3ljORcStFCTcEKNNJ5cIbiuSDVClhZc48KE4OBumf_9rag5OhAyAczdW_uXG9");

GcpCredentialsType resolved = GcpCredentialsType.resolve(options);
String key = resolved.createKey(options);
GcpCredentialFactory gcpCredentialFactory = resolved.createGcpCredentialFactory(options);

assertThat(resolved, equalTo(GcpCredentialsType.ServiceAccountToken));
assertThat(key, startsWith(GcpCredentialsType.ServiceAccountToken.name()));
assertThat(gcpCredentialFactory instanceof ServiceAccountTokenGcpCredentialFactory, equalTo(true));
}

@Test
public void canSetupServiceAccountJsonFileGcpCredentialsType() throws Exception {
options.set(GCP_CREDENTIALS_TYPE, GcpCredentialsType.ServiceAccountJsonFile.name());
Expand Down

0 comments on commit d32214a

Please sign in to comment.