diff --git a/pom.xml b/pom.xml index 26697e2..b599ce3 100644 --- a/pom.xml +++ b/pom.xml @@ -82,7 +82,7 @@ ch.qos.logback logback-core - 1.5.13 + 1.5.19 @@ -95,7 +95,7 @@ ch.qos.logback logback-classic - 1.5.6 + 1.5.19 @@ -130,6 +130,15 @@ 2.34.8 true + + + + com.google.auth + google-auth-library-oauth2-http + 1.40.0 + true + + org.junit.jupiter diff --git a/src/main/java/com/infisical/sdk/auth/GCPAuthProvider.java b/src/main/java/com/infisical/sdk/auth/GCPAuthProvider.java new file mode 100644 index 0000000..7ac3e2c --- /dev/null +++ b/src/main/java/com/infisical/sdk/auth/GCPAuthProvider.java @@ -0,0 +1,51 @@ +package com.infisical.sdk.auth; + +import java.net.UnknownHostException; +import java.util.Arrays; +import java.util.HashMap; + +import com.google.auth.oauth2.GoogleCredentials; +import com.google.auth.oauth2.IdTokenCredentials; +import com.google.auth.oauth2.IdTokenProvider; +import com.google.auth.oauth2.IdTokenProvider.Option; +import com.infisical.sdk.util.InfisicalException; + +public class GCPAuthProvider { + + public static HashMap getGCPAuthInput(String identityId) throws InfisicalException{ + + if ( identityId == null || identityId.isEmpty() ) + + throw new InfisicalException( "Infisical Identity ID is required"); + + try{ + + // This will fetch credentials from environment variable named GOOGLE_APPLICATION_CREDENTIALS or + // or if it's running in a GCP instance it will get them from the instance itself (GCP service account attached) + GoogleCredentials googleCredentials = GoogleCredentials.getApplicationDefault(); + + IdTokenCredentials idTokenCredentials = + IdTokenCredentials.newBuilder() + .setIdTokenProvider((IdTokenProvider) googleCredentials) + .setTargetAudience(identityId) + .build(); + + // Get the ID token. + String idToken = idTokenCredentials.refreshAccessToken().getTokenValue(); + + // Body cannot be a string so used a HashMap, you can use builder, POJO etc + HashMap body = new HashMap<>(); + body.put("identityId", identityId); + body.put("jwt", idToken); + + return body; + + } catch (Exception e){ + if (e.getCause() instanceof UnknownHostException) { + throw new InfisicalException("Unknown Host, may be check network connection ?"); + } + throw new InfisicalException("Failed to fetch Google credentials: " + e.getMessage()); + } + + } +} diff --git a/src/main/java/com/infisical/sdk/resources/AuthClient.java b/src/main/java/com/infisical/sdk/resources/AuthClient.java index bf334df..c56d637 100644 --- a/src/main/java/com/infisical/sdk/resources/AuthClient.java +++ b/src/main/java/com/infisical/sdk/resources/AuthClient.java @@ -2,6 +2,7 @@ import com.infisical.sdk.api.ApiClient; import com.infisical.sdk.auth.AwsAuthProvider; +import com.infisical.sdk.auth.GCPAuthProvider; import com.infisical.sdk.models.AwsAuthLoginInput; import com.infisical.sdk.models.LdapAuthLoginInput; import com.infisical.sdk.models.MachineIdentityCredential; @@ -56,6 +57,19 @@ public void AwsAuthLogin(AwsAuthLoginInput input) throws InfisicalException { this.onAuthenticate.accept(credential.getAccessToken()); } + public void GCPAuthLogin(String identityId) throws InfisicalException { + + if (identityId == null||identityId.isEmpty()) + + throw new InfisicalException("Infisical Identity ID is required"); + + var url = String.format("%s%s", this.apiClient.GetBaseUrl(), "/api/v1/auth/gcp-auth/login"); + + var input = GCPAuthProvider.getGCPAuthInput(identityId); + var credential = this.apiClient.post(url, input, MachineIdentityCredential.class); + this.onAuthenticate.accept(credential.getAccessToken()); + } + public void SetAccessToken(String accessToken) { this.onAuthenticate.accept(accessToken); } diff --git a/src/test/java/com/infisical/sdk/auth/GCPAuthIntegrationTest.java b/src/test/java/com/infisical/sdk/auth/GCPAuthIntegrationTest.java new file mode 100644 index 0000000..ec13f32 --- /dev/null +++ b/src/test/java/com/infisical/sdk/auth/GCPAuthIntegrationTest.java @@ -0,0 +1,59 @@ +package com.infisical.sdk.auth; + +import com.infisical.sdk.InfisicalSdk; +import com.infisical.sdk.config.SdkConfig; +import com.infisical.sdk.util.EnvironmentVariables; +import org.junit.jupiter.api.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import static org.junit.jupiter.api.Assertions.*; + +public class GCPAuthIntegrationTest { + + private static final Logger logger = LoggerFactory.getLogger(GCPAuthIntegrationTest.class); + @Test + public void testGCPAuthAndFetchSecrets() { + + try { + + // Load env variables + var envVars = new EnvironmentVariables(); + + // Get Machine Identity Id + String machineIdentityId = System.getenv("INFISICAL_MACHINE_IDENTITY_ID"); + + + // Check if env variable machine identity is set, others are already tested via env tests + assertNotNull(machineIdentityId, "INFISICAL_MACHINE_IDENTITY_ID env variable must be set"); +assertFalse(machineIdentityId.isEmpty(), "INFISICAL_MACHINE_IDENTITY_ID env variable must not be empty"); + + + // Create SDK instance + var sdk = new InfisicalSdk(new SdkConfig.Builder() + .withSiteUrl(envVars.getSiteUrl()) + .build() + ); + + // Authenticate using GCP Auth + assertDoesNotThrow(() -> { + sdk.Auth().GCPAuthLogin(machineIdentityId); + }); + + // Test if we have correctly logged in and we can list the secrets + var secrets = sdk.Secrets().ListSecrets( + envVars.getProjectId(), + "dev", + "/", + null, + null, + null); + + logger.info("TestGCPAuth Successful"); + logger.info("Secrets length : {}", secrets.size()); + + } catch (Exception e) { + throw new AssertionError(e); + } + } +}