From fe5e6f2f442ce39784e4a6f843586c496e0da19a Mon Sep 17 00:00:00 2001 From: Pranav Iyer Date: Sun, 16 Nov 2025 17:53:58 -0800 Subject: [PATCH 1/4] Added initial changes for customCredentialSuppliers in AWS and Okta with tests and readme --- auth/README.md | 73 +++++++- auth/customCredentialSupplierAws.js | 150 +++++++++++++++ auth/customCredentialSupplierOkta.js | 176 ++++++++++++++++++ .../customCredentialSupplierAwsTest.js | 48 +++++ .../customCredentialSupplierOktaTest.js | 51 +++++ 5 files changed, 497 insertions(+), 1 deletion(-) create mode 100644 auth/customCredentialSupplierAws.js create mode 100644 auth/customCredentialSupplierOkta.js create mode 100644 auth/system-test/customCredentialSupplierAwsTest.js create mode 100644 auth/system-test/customCredentialSupplierOktaTest.js diff --git a/auth/README.md b/auth/README.md index 636015860f..a08eb49384 100644 --- a/auth/README.md +++ b/auth/README.md @@ -60,8 +60,79 @@ information](https://developers.google.com/identity/protocols/application-defaul $ npm run test:downscoping +## Custom Credential Suppliers + +If you want to use external credentials (like AWS or Okta) that require custom retrieval logic not supported natively by the library, you can provide a custom supplier implementation. + +### Custom AWS Credential Supplier + +This sample demonstrates how to use the AWS SDK for Node.js as a custom `AwsSecurityCredentialsSupplier` to bridge AWS credentials—from sources like EKS IRSA, ECS, or local profiles—to Google Cloud Workload Identity. + +#### 1. Set Environment Variables + +```bash +# AWS Credentials (or use ~/.aws/credentials) +export AWS_ACCESS_KEY_ID="YOUR_AWS_ACCESS_KEY_ID" +export AWS_SECRET_ACCESS_KEY="YOUR_AWS_SECRET_ACCESS_KEY" +export AWS_REGION="us-east-1" + +# Google Cloud Config +# Format: //iam.googleapis.com/projects//locations/global/workloadIdentityPools//providers/ +export GCP_WORKLOAD_AUDIENCE="//iam.googleapis.com/projects/123456/locations/global/workloadIdentityPools/my-pool/providers/my-aws-provider" +export GCS_BUCKET_NAME="your-bucket-name" + +# Optional: Service Account Impersonation +# export GCP_SERVICE_ACCOUNT_IMPERSONATION_URL="https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/my-sa@my-project.iam.gserviceaccount.com:generateAccessToken" +``` + +#### 2. Run the Sample + +```bash +node custom-credential-supplier-aws.js +``` + +#### Running in Kubernetes (EKS) + +To run this in an EKS cluster using IAM Roles for Service Accounts (IRSA): + +1. **Configure IRSA:** Associate an AWS IAM Role with your Kubernetes Service Account. +2. **Configure GCP:** Allow the AWS IAM Role ARN to impersonate your Workload Identity Pool. +3. **Deploy:** When deploying your Node.js application, ensure the Pod uses the annotated Service Account. The AWS SDK in the sample will automatically detect the credentials injected by the EKS OIDC webhook. + +--- + +### Custom Okta Credential Supplier + +This sample demonstrates how to use a custom `SubjectTokenSupplier` to fetch an OIDC token from **Okta** using the Client Credentials flow and exchange it for Google Cloud credentials via Workload Identity Federation. + +#### 1. Okta Configuration + +Ensure you have an Okta Machine-to-Machine (M2M) application set up with "Client Credentials" grant type enabled. You will need the Domain, Client ID, and Client Secret. + +#### 2. Set Environment Variables + +```bash +# Okta Configuration +export OKTA_DOMAIN="https://your-okta-domain.okta.com" +export OKTA_CLIENT_ID="your-okta-client-id" +export OKTA_CLIENT_SECRET="your-okta-client-secret" + +# Google Cloud Config +export GCP_WORKLOAD_AUDIENCE="//iam.googleapis.com/projects/123456/locations/global/workloadIdentityPools/my-pool/providers/my-oidc-provider" +export GCS_BUCKET_NAME="your-bucket-name" + +# Optional: Service Account Impersonation +# export GCP_SERVICE_ACCOUNT_IMPERSONATION_URL="https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/my-sa@my-project.iam.gserviceaccount.com:generateAccessToken" +``` + +#### 3. Run the Sample + +```bash +node custom-credential-supplier-okta.js +``` + ### Additional resources For more information on downscoped credentials you can visit: -> https://github.com/googleapis/google-auth-library-nodejs \ No newline at end of file +> https://github.com/googleapis/google-auth-library-nodejs diff --git a/auth/customCredentialSupplierAws.js b/auth/customCredentialSupplierAws.js new file mode 100644 index 0000000000..8662f16708 --- /dev/null +++ b/auth/customCredentialSupplierAws.js @@ -0,0 +1,150 @@ +// Copyright 2025 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// [START auth_custom_credential_supplier_aws] +const {AwsClient} = require('google-auth-library'); +const {fromNodeProviderChain} = require('@aws-sdk/credential-providers'); +const {STSClient} = require('@aws-sdk/client-sts'); + +/** + * Custom AWS Security Credentials Supplier. + * + * This implementation resolves AWS credentials using the default Node provider + * chain from the AWS SDK. This allows fetching credentials from environment + * variables, shared credential files (~/.aws/credentials), or IAM roles + * for service accounts (IRSA) in EKS, etc. + */ +class CustomAwsSupplier { + constructor() { + // Will be cached upon first resolution. + this.region = null; + + // Initialize the AWS credential provider. + // The AWS SDK handles memoization (caching) and proactive refreshing internally. + this.awsCredentialsProvider = fromNodeProviderChain(); + } + + /** + * Returns the AWS region. This is required for signing the AWS request. + * It resolves the region automatically by using the default AWS region + * provider chain, which searches for the region in the standard locations + * (environment variables, AWS config file, etc.). + */ + async getAwsRegion(_context) { + if (this.region) { + return this.region; + } + + const client = new STSClient({}); + this.region = await client.config.region(); + + if (!this.region) { + throw new Error( + 'CustomAwsSupplier: Unable to resolve AWS region. Please set the AWS_REGION environment variable or configure it in your ~/.aws/config file.' + ); + } + + return this.region; + } + + /** + * Retrieves AWS security credentials using the AWS SDK's default provider chain. + */ + async getAwsSecurityCredentials(_context) { + // Call the initialized provider. It will return cached creds or refresh if needed. + const awsCredentials = await this.awsCredentialsProvider(); + + if (!awsCredentials.accessKeyId || !awsCredentials.secretAccessKey) { + throw new Error( + 'Unable to resolve AWS credentials from the node provider chain. ' + + 'Ensure your AWS CLI is configured, or AWS environment variables (like AWS_ACCESS_KEY_ID) are set.' + ); + } + + // Map the AWS SDK format to the google-auth-library format. + return { + accessKeyId: awsCredentials.accessKeyId, + secretAccessKey: awsCredentials.secretAccessKey, + token: awsCredentials.sessionToken, + }; + } +} + +/** + * Authenticates with Google Cloud using AWS credentials and retrieves bucket metadata. + * + * @param {string} bucketName The name of the bucket to retrieve. + * @param {string} audience The Workload Identity Pool audience. + * @param {string} [impersonationUrl] Optional Service Account impersonation URL. + */ +async function authenticateWithAwsCredentials( + bucketName, + audience, + impersonationUrl +) { + // 1. Instantiate the custom supplier. + const customSupplier = new CustomAwsSupplier(); + + // 2. Configure the AwsClient options. + const clientOptions = { + audience: audience, + subject_token_type: 'urn:ietf:params:aws:token-type:aws4_request', + service_account_impersonation_url: impersonationUrl, + aws_security_credentials_supplier: customSupplier, + }; + + // 3. Create the auth client + const client = new AwsClient(clientOptions); + + // 4. Make an authenticated request to GCS. + const bucketUrl = `https://storage.googleapis.com/storage/v1/b/${bucketName}`; + const res = await client.request({url: bucketUrl}); + return res.data; +} +// [END auth_custom_credential_supplier_aws] + +async function main() { + require('dotenv').config(); + const gcpAudience = process.env.GCP_WORKLOAD_AUDIENCE; + const saImpersonationUrl = process.env.GCP_SERVICE_ACCOUNT_IMPERSONATION_URL; + const gcsBucketName = process.env.GCS_BUCKET_NAME; + + if (!gcpAudience || !gcsBucketName) { + throw new Error( + 'Missing required environment variables: GCP_WORKLOAD_AUDIENCE, GCS_BUCKET_NAME' + ); + } + + try { + console.log(`Retrieving metadata for bucket: ${gcsBucketName}...`); + const bucketMetadata = await authenticateWithAwsCredentials( + gcsBucketName, + gcpAudience, + saImpersonationUrl + ); + console.log('\n--- SUCCESS! ---'); + console.log('Bucket Name:', bucketMetadata.name); + console.log('Bucket Location:', bucketMetadata.location); + } catch (error) { + console.error('\n--- FAILED ---'); + console.error(error.response?.data || error); + process.exitCode = 1; + } +} + +if (require.main === module) { + main(); +} + +exports.authenticateWithAwsCredentials = authenticateWithAwsCredentials; diff --git a/auth/customCredentialSupplierOkta.js b/auth/customCredentialSupplierOkta.js new file mode 100644 index 0000000000..17d4609b96 --- /dev/null +++ b/auth/customCredentialSupplierOkta.js @@ -0,0 +1,176 @@ +// Copyright 2025 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// [START auth_custom_credential_supplier_okta] +const {IdentityPoolClient} = require('google-auth-library'); +const {Gaxios} = require('gaxios'); + +/** + * A custom SubjectTokenSupplier that authenticates with Okta using the + * Client Credentials grant flow. + */ +class OktaClientCredentialsSupplier { + constructor(domain, clientId, clientSecret) { + this.oktaTokenUrl = `${domain}/oauth2/default/v1/token`; + this.clientId = clientId; + this.clientSecret = clientSecret; + this.accessToken = null; + this.expiryTime = 0; + this.gaxios = new Gaxios(); + } + + /** + * Main method called by the auth library. It will fetch a new token if one + * is not already cached. + * @returns {Promise} A promise that resolves with the Okta Access token. + */ + async getSubjectToken() { + // Check if the current token is still valid (with a 60-second buffer). + const isTokenValid = + this.accessToken && Date.now() < this.expiryTime - 60 * 1000; + + if (isTokenValid) { + return this.accessToken; + } + + const {accessToken, expiresIn} = await this.fetchOktaAccessToken(); + this.accessToken = accessToken; + this.expiryTime = Date.now() + expiresIn * 1000; + return this.accessToken; + } + + /** + * Performs the Client Credentials grant flow with Okta. + */ + async fetchOktaAccessToken() { + const params = new URLSearchParams(); + params.append('grant_type', 'client_credentials'); + params.append('scope', 'gcp.test.read'); + + const authHeader = + 'Basic ' + + Buffer.from(`${this.clientId}:${this.clientSecret}`).toString('base64'); + + try { + const response = await this.gaxios.request({ + url: this.oktaTokenUrl, + method: 'POST', + headers: { + Authorization: authHeader, + 'Content-Type': 'application/x-www-form-urlencoded', + }, + data: params.toString(), + }); + + const {access_token, expires_in} = response.data; + if (access_token && expires_in) { + return {accessToken: access_token, expiresIn: expires_in}; + } else { + throw new Error( + 'Access token or expires_in not found in Okta response.' + ); + } + } catch (error) { + throw new Error( + `Failed to authenticate with Okta: ${error.response?.data || error.message}` + ); + } + } +} + +/** + * Authenticates with Google Cloud using Okta credentials and retrieves bucket metadata. + * + * @param {string} bucketName The name of the bucket to retrieve. + * @param {string} audience The Workload Identity Pool audience. + * @param {string} domain The Okta domain. + * @param {string} clientId The Okta client ID. + * @param {string} clientSecret The Okta client secret. + * @param {string} [impersonationUrl] Optional Service Account impersonation URL. + */ +async function authenticateWithOktaCredentials( + bucketName, + audience, + domain, + clientId, + clientSecret, + impersonationUrl +) { + // 1. Instantiate the custom supplier. + const oktaSupplier = new OktaClientCredentialsSupplier( + domain, + clientId, + clientSecret + ); + + // 2. Instantiate an IdentityPoolClient with the required configuration. + const client = new IdentityPoolClient({ + audience: audience, + subject_token_type: 'urn:ietf:params:oauth:token-type:jwt', + token_url: 'https://sts.googleapis.com/v1/token', + subject_token_supplier: oktaSupplier, + service_account_impersonation_url: impersonationUrl, + }); + + // 3. Make an authenticated request. + const bucketUrl = `https://storage.googleapis.com/storage/v1/b/${bucketName}`; + const res = await client.request({url: bucketUrl}); + return res.data; +} +// [END auth_custom_credential_supplier_okta] + +async function main() { + require('dotenv').config(); + const gcpAudience = process.env.GCP_WORKLOAD_AUDIENCE; + const saImpersonationUrl = process.env.GCP_SERVICE_ACCOUNT_IMPERSONATION_URL; + const gcsBucketName = process.env.GCS_BUCKET_NAME; + const oktaDomain = process.env.OKTA_DOMAIN; + const oktaClientId = process.env.OKTA_CLIENT_ID; + const oktaClientSecret = process.env.OKTA_CLIENT_SECRET; + + if ( + !gcpAudience || + !gcsBucketName || + !oktaDomain || + !oktaClientId || + !oktaClientSecret + ) { + throw new Error('Missing required environment variables for Okta/GCP.'); + } + + try { + console.log(`Retrieving metadata for bucket: ${gcsBucketName}...`); + const bucketMetadata = await authenticateWithOktaCredentials( + gcsBucketName, + gcpAudience, + oktaDomain, + oktaClientId, + oktaClientSecret, + saImpersonationUrl + ); + console.log('\n--- SUCCESS! ---'); + console.log('Bucket Name:', bucketMetadata.name); + console.log('Bucket Location:', bucketMetadata.location); + } catch (error) { + console.error('\n--- FAILED ---'); + console.error(error.response?.data || error); + process.exitCode = 1; + } +} + +if (require.main === module) { + main(); +} + +exports.authenticateWithOktaCredentials = authenticateWithOktaCredentials; diff --git a/auth/system-test/customCredentialSupplierAwsTest.js b/auth/system-test/customCredentialSupplierAwsTest.js new file mode 100644 index 0000000000..f26117b515 --- /dev/null +++ b/auth/system-test/customCredentialSupplierAwsTest.js @@ -0,0 +1,48 @@ +// Copyright 2025 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +const assert = require('assert'); +const { + authenticateWithAwsCredentials, +} = require('../custom-credential-supplier-aws'); + +describe('Custom Credential Supplier AWS', () => { + const audience = process.env.GCP_WORKLOAD_AUDIENCE; + const bucketName = process.env.GCS_BUCKET_NAME; + const impersonationUrl = process.env.GCP_SERVICE_ACCOUNT_IMPERSONATION_URL; + + it('should authenticate using AWS credentials', async function () { + // Skip system tests if required environment variables are missing + if ( + !process.env.AWS_ACCESS_KEY_ID || + !process.env.AWS_SECRET_ACCESS_KEY || + !process.env.AWS_REGION || + !audience || + !bucketName + ) { + this.skip(); + } + + const metadata = await authenticateWithAwsCredentials( + bucketName, + audience, + impersonationUrl, + ); + + assert.strictEqual(metadata.name, bucketName); + assert.ok(metadata.location); + }); +}); diff --git a/auth/system-test/customCredentialSupplierOktaTest.js b/auth/system-test/customCredentialSupplierOktaTest.js new file mode 100644 index 0000000000..a314aa5573 --- /dev/null +++ b/auth/system-test/customCredentialSupplierOktaTest.js @@ -0,0 +1,51 @@ +// Copyright 2025 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +const assert = require('assert'); +const { + authenticateWithOktaCredentials, +} = require('../custom-credential-supplier-okta'); + +describe('Custom Credential Supplier Okta', () => { + const audience = process.env.GCP_WORKLOAD_AUDIENCE; + const bucketName = process.env.GCS_BUCKET_NAME; + const impersonationUrl = process.env.GCP_SERVICE_ACCOUNT_IMPERSONATION_URL; + + it('should authenticate using Okta credentials', async function () { + // Skip system tests if required environment variables are missing + if ( + !process.env.OKTA_DOMAIN || + !process.env.OKTA_CLIENT_ID || + !process.env.OKTA_CLIENT_SECRET || + !audience || + !bucketName + ) { + this.skip(); + } + + const metadata = await authenticateWithOktaCredentials( + bucketName, + audience, + process.env.OKTA_DOMAIN, + process.env.OKTA_CLIENT_ID, + process.env.OKTA_CLIENT_SECRET, + impersonationUrl, + ); + + assert.strictEqual(metadata.name, bucketName); + assert.ok(metadata.location); + }); +}); From 65200e020913f33c890d71639640f41103267b39 Mon Sep 17 00:00:00 2001 From: Pranav Iyer Date: Mon, 17 Nov 2025 16:22:25 -0800 Subject: [PATCH 2/4] Fixed tests and added some lint corrections. --- .eslintrc.json | 1 + auth/.eslintrc.json | 6 ++++++ auth/package.json | 4 ++++ auth/system-test/customCredentialSupplierAwsTest.js | 4 ++-- auth/system-test/customCredentialSupplierOktaTest.js | 4 ++-- 5 files changed, 15 insertions(+), 4 deletions(-) create mode 100644 auth/.eslintrc.json diff --git a/.eslintrc.json b/.eslintrc.json index 7e5a1dd078..44510807ab 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -12,6 +12,7 @@ "node/no-unsupported-features/es-syntax": ["off"] }, "parserOptions": { + "ecmaVersion": 2020, "sourceType": "module" } } diff --git a/auth/.eslintrc.json b/auth/.eslintrc.json new file mode 100644 index 0000000000..95f214a816 --- /dev/null +++ b/auth/.eslintrc.json @@ -0,0 +1,6 @@ +{ + "extends": "../.eslintrc.json", + "rules": { + "no-unused-vars": "off" + } +} diff --git a/auth/package.json b/auth/package.json index 71988b2b5f..3826539aa9 100644 --- a/auth/package.json +++ b/auth/package.json @@ -19,6 +19,10 @@ "system-test": "c8 mocha -p -j 2 system-test/*.test.js --timeout=30000" }, "dependencies": { + "@aws-sdk/client-sts": "^3.58.0", + "@aws-sdk/credential-providers": "^3.0.0", + "dotenv": "^17.0.0", + "gaxios": "^6.0.0", "@google-cloud/storage": "^7.0.0", "fix": "0.0.6", "google-auth-library": "^9.0.0", diff --git a/auth/system-test/customCredentialSupplierAwsTest.js b/auth/system-test/customCredentialSupplierAwsTest.js index f26117b515..cba05aff03 100644 --- a/auth/system-test/customCredentialSupplierAwsTest.js +++ b/auth/system-test/customCredentialSupplierAwsTest.js @@ -17,7 +17,7 @@ const assert = require('assert'); const { authenticateWithAwsCredentials, -} = require('../custom-credential-supplier-aws'); +} = require('../customCredentialSupplierAws'); describe('Custom Credential Supplier AWS', () => { const audience = process.env.GCP_WORKLOAD_AUDIENCE; @@ -39,7 +39,7 @@ describe('Custom Credential Supplier AWS', () => { const metadata = await authenticateWithAwsCredentials( bucketName, audience, - impersonationUrl, + impersonationUrl ); assert.strictEqual(metadata.name, bucketName); diff --git a/auth/system-test/customCredentialSupplierOktaTest.js b/auth/system-test/customCredentialSupplierOktaTest.js index a314aa5573..244f5a87a5 100644 --- a/auth/system-test/customCredentialSupplierOktaTest.js +++ b/auth/system-test/customCredentialSupplierOktaTest.js @@ -17,7 +17,7 @@ const assert = require('assert'); const { authenticateWithOktaCredentials, -} = require('../custom-credential-supplier-okta'); +} = require('../customCredentialSupplierOkta'); describe('Custom Credential Supplier Okta', () => { const audience = process.env.GCP_WORKLOAD_AUDIENCE; @@ -42,7 +42,7 @@ describe('Custom Credential Supplier Okta', () => { process.env.OKTA_DOMAIN, process.env.OKTA_CLIENT_ID, process.env.OKTA_CLIENT_SECRET, - impersonationUrl, + impersonationUrl ); assert.strictEqual(metadata.name, bucketName); From aa306360a8bf902c3dd2cbc841f6f9814d16d773 Mon Sep 17 00:00:00 2001 From: Pranav Iyer Date: Mon, 17 Nov 2025 23:37:27 -0800 Subject: [PATCH 3/4] Changed tests formatting. --- .../customCredentialSupplierAws.test.js | 48 +++++++++++++++++ .../customCredentialSupplierOkta.test.js | 51 +++++++++++++++++++ 2 files changed, 99 insertions(+) create mode 100644 auth/system-test/customCredentialSupplierAws.test.js create mode 100644 auth/system-test/customCredentialSupplierOkta.test.js diff --git a/auth/system-test/customCredentialSupplierAws.test.js b/auth/system-test/customCredentialSupplierAws.test.js new file mode 100644 index 0000000000..cba05aff03 --- /dev/null +++ b/auth/system-test/customCredentialSupplierAws.test.js @@ -0,0 +1,48 @@ +// Copyright 2025 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +const assert = require('assert'); +const { + authenticateWithAwsCredentials, +} = require('../customCredentialSupplierAws'); + +describe('Custom Credential Supplier AWS', () => { + const audience = process.env.GCP_WORKLOAD_AUDIENCE; + const bucketName = process.env.GCS_BUCKET_NAME; + const impersonationUrl = process.env.GCP_SERVICE_ACCOUNT_IMPERSONATION_URL; + + it('should authenticate using AWS credentials', async function () { + // Skip system tests if required environment variables are missing + if ( + !process.env.AWS_ACCESS_KEY_ID || + !process.env.AWS_SECRET_ACCESS_KEY || + !process.env.AWS_REGION || + !audience || + !bucketName + ) { + this.skip(); + } + + const metadata = await authenticateWithAwsCredentials( + bucketName, + audience, + impersonationUrl + ); + + assert.strictEqual(metadata.name, bucketName); + assert.ok(metadata.location); + }); +}); diff --git a/auth/system-test/customCredentialSupplierOkta.test.js b/auth/system-test/customCredentialSupplierOkta.test.js new file mode 100644 index 0000000000..244f5a87a5 --- /dev/null +++ b/auth/system-test/customCredentialSupplierOkta.test.js @@ -0,0 +1,51 @@ +// Copyright 2025 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +const assert = require('assert'); +const { + authenticateWithOktaCredentials, +} = require('../customCredentialSupplierOkta'); + +describe('Custom Credential Supplier Okta', () => { + const audience = process.env.GCP_WORKLOAD_AUDIENCE; + const bucketName = process.env.GCS_BUCKET_NAME; + const impersonationUrl = process.env.GCP_SERVICE_ACCOUNT_IMPERSONATION_URL; + + it('should authenticate using Okta credentials', async function () { + // Skip system tests if required environment variables are missing + if ( + !process.env.OKTA_DOMAIN || + !process.env.OKTA_CLIENT_ID || + !process.env.OKTA_CLIENT_SECRET || + !audience || + !bucketName + ) { + this.skip(); + } + + const metadata = await authenticateWithOktaCredentials( + bucketName, + audience, + process.env.OKTA_DOMAIN, + process.env.OKTA_CLIENT_ID, + process.env.OKTA_CLIENT_SECRET, + impersonationUrl + ); + + assert.strictEqual(metadata.name, bucketName); + assert.ok(metadata.location); + }); +}); From a2759769eef3ed9b968c587f4f4ac06b36522b49 Mon Sep 17 00:00:00 2001 From: Pranav Iyer Date: Mon, 17 Nov 2025 23:38:25 -0800 Subject: [PATCH 4/4] Deleted old test files. --- .../customCredentialSupplierAwsTest.js | 48 ----------------- .../customCredentialSupplierOktaTest.js | 51 ------------------- 2 files changed, 99 deletions(-) delete mode 100644 auth/system-test/customCredentialSupplierAwsTest.js delete mode 100644 auth/system-test/customCredentialSupplierOktaTest.js diff --git a/auth/system-test/customCredentialSupplierAwsTest.js b/auth/system-test/customCredentialSupplierAwsTest.js deleted file mode 100644 index cba05aff03..0000000000 --- a/auth/system-test/customCredentialSupplierAwsTest.js +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2025 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -'use strict'; - -const assert = require('assert'); -const { - authenticateWithAwsCredentials, -} = require('../customCredentialSupplierAws'); - -describe('Custom Credential Supplier AWS', () => { - const audience = process.env.GCP_WORKLOAD_AUDIENCE; - const bucketName = process.env.GCS_BUCKET_NAME; - const impersonationUrl = process.env.GCP_SERVICE_ACCOUNT_IMPERSONATION_URL; - - it('should authenticate using AWS credentials', async function () { - // Skip system tests if required environment variables are missing - if ( - !process.env.AWS_ACCESS_KEY_ID || - !process.env.AWS_SECRET_ACCESS_KEY || - !process.env.AWS_REGION || - !audience || - !bucketName - ) { - this.skip(); - } - - const metadata = await authenticateWithAwsCredentials( - bucketName, - audience, - impersonationUrl - ); - - assert.strictEqual(metadata.name, bucketName); - assert.ok(metadata.location); - }); -}); diff --git a/auth/system-test/customCredentialSupplierOktaTest.js b/auth/system-test/customCredentialSupplierOktaTest.js deleted file mode 100644 index 244f5a87a5..0000000000 --- a/auth/system-test/customCredentialSupplierOktaTest.js +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright 2025 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -'use strict'; - -const assert = require('assert'); -const { - authenticateWithOktaCredentials, -} = require('../customCredentialSupplierOkta'); - -describe('Custom Credential Supplier Okta', () => { - const audience = process.env.GCP_WORKLOAD_AUDIENCE; - const bucketName = process.env.GCS_BUCKET_NAME; - const impersonationUrl = process.env.GCP_SERVICE_ACCOUNT_IMPERSONATION_URL; - - it('should authenticate using Okta credentials', async function () { - // Skip system tests if required environment variables are missing - if ( - !process.env.OKTA_DOMAIN || - !process.env.OKTA_CLIENT_ID || - !process.env.OKTA_CLIENT_SECRET || - !audience || - !bucketName - ) { - this.skip(); - } - - const metadata = await authenticateWithOktaCredentials( - bucketName, - audience, - process.env.OKTA_DOMAIN, - process.env.OKTA_CLIENT_ID, - process.env.OKTA_CLIENT_SECRET, - impersonationUrl - ); - - assert.strictEqual(metadata.name, bucketName); - assert.ok(metadata.location); - }); -});