Skip to content
Draft
Show file tree
Hide file tree
Changes from all 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
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions src/auth/integration-tests/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ tempfile.workspace = true
serde_json.workspace = true
httptest.workspace = true
test-case.workspace = true
base64.workspace = true
reqwest.workspace = true
# Local dependencies
auth = { path = "../../../src/auth", package = "google-cloud-auth" }
gax = { path = "../../../src/gax", package = "google-cloud-gax" }
Expand Down
41 changes: 41 additions & 0 deletions src/auth/integration-tests/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,12 @@ use auth::credentials::{
ProgrammaticBuilder as ExternalAccountProgrammaticBuilder,
},
impersonated::Builder as ImpersonatedCredentialsBuilder,
mds::idtoken::Builder as IDTokenMDSBuilder,
service_account::Builder as ServiceAccountCredentialsBuilder,
subject_token::{Builder as SubjectTokenBuilder, SubjectToken, SubjectTokenProvider},
};
use auth::errors::SubjectTokenProviderError;
use base64::{Engine as _, engine::general_purpose::URL_SAFE_NO_PAD};
use bigquery::client::DatasetService;
use gax::error::rpc::Code;
use httptest::{Expectation, Server, matchers::*, responders::*};
Expand All @@ -32,6 +34,7 @@ use language::client::LanguageService;
use language::model::Document;
use scoped_env::ScopedEnv;
use secretmanager::{client::SecretManagerService, model::SecretPayload};
use serde_json::Value;
use std::sync::Arc;

pub async fn service_account() -> anyhow::Result<()> {
Expand Down Expand Up @@ -196,6 +199,44 @@ pub async fn api_key() -> anyhow::Result<()> {
Ok(())
}

pub async fn mds_id_token() -> anyhow::Result<()> {
let audience = "https://example.com";

// Get the service account email from the metadata server directly
let client = reqwest::Client::new();
let expected_email = client
.get("http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/email")
.header("Metadata-Flavor", "Google")
.send()
.await
.expect("failed to get service account email from metadata server")
.text()
.await
.expect("failed to read service account email from metadata server response");

// Only works when running on an env that has MDS.
let id_token_creds = IDTokenMDSBuilder::new(audience)
.with_format("full")
.build()
.expect("failed to create id token credentials");
let token = id_token_creds
.id_token()
.await
.expect("failed to get id token");

// Decode the JWT and verify its claims
let parts: Vec<&str> = token.split('.').collect();
anyhow::ensure!(parts.len() == 3, "ID token is not a valid JWT");
let payload = URL_SAFE_NO_PAD.decode(parts[1])?;
let claims: Value = serde_json::from_slice(&payload)?;

assert_eq!(claims["aud"], audience);
assert_eq!(claims["email"], expected_email);
assert_eq!(claims["email_verified"], true);

Ok(())
}

pub async fn workload_identity_provider_url_sourced(
with_impersonation: bool,
) -> anyhow::Result<()> {
Expand Down
5 changes: 5 additions & 0 deletions src/auth/integration-tests/tests/driver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ mod driver {
auth_integration_tests::api_key().await
}

#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
async fn run_mds_id_token() -> anyhow::Result<()> {
auth_integration_tests::mds_id_token().await
}

#[cfg(all(test, feature = "run-byoid-integration-tests"))]
#[test_case(false; "without impersonation")]
#[test_case(true; "with impersonation")]
Expand Down
3 changes: 1 addition & 2 deletions src/auth/src/credentials.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,7 @@ pub mod anonymous;
pub mod api_key_credentials;
pub mod external_account;
pub(crate) mod external_account_sources;
#[allow(dead_code)]
pub(crate) mod idtoken;
pub mod idtoken;
pub mod impersonated;
pub(crate) mod internal;
pub mod mds;
Expand Down
3 changes: 1 addition & 2 deletions src/auth/src/credentials/mds.rs
Original file line number Diff line number Diff line change
Expand Up @@ -397,8 +397,7 @@ impl TokenProvider for MDSAccessTokenProvider {
}
}

#[allow(dead_code)]
pub(crate) mod idtoken {
pub mod idtoken {
//! Types for fetching ID tokens from the metadata service.
use super::{
GCE_METADATA_HOST_ENV_VAR, MDS_DEFAULT_URI, METADATA_FLAVOR, METADATA_FLAVOR_VALUE,
Expand Down
Loading