diff --git a/examples/test-adc/src/main.rs b/examples/test-adc/src/main.rs index 01137ef..cac39c9 100644 --- a/examples/test-adc/src/main.rs +++ b/examples/test-adc/src/main.rs @@ -1,12 +1,18 @@ +use yup_oauth2::authenticator::ApplicationDefaultCredentialsTypes; use yup_oauth2::ApplicationDefaultCredentialsAuthenticator; #[tokio::main] async fn main() { - let auth = ApplicationDefaultCredentialsAuthenticator::builder() - .await - .build() - .await - .unwrap(); + let auth = match ApplicationDefaultCredentialsAuthenticator::builder().await { + ApplicationDefaultCredentialsTypes::InstanceMetadata(auth) => auth + .build() + .await + .expect("Unable to create instance metadata authenticator"), + ApplicationDefaultCredentialsTypes::ServiceAccount(auth) => auth + .build() + .await + .expect("Unable to create service account authenticator"), + }; let scopes = &["https://www.googleapis.com/auth/pubsub"]; let tok = auth.token(scopes).await.unwrap(); diff --git a/src/authenticator.rs b/src/authenticator.rs index 7b0970a..101709c 100644 --- a/src/authenticator.rs +++ b/src/authenticator.rs @@ -260,36 +260,66 @@ impl ServiceAccountAuthenticator { /// Create an authenticator that uses a application default credentials. /// ``` /// # async fn foo() { -/// let authenticator = yup_oauth2::ApplicationDefaultCredentialsAuthenticator::builder() -/// .await -/// .build() -/// .await -/// .expect("failed to create authenticator"); +/// let authenticator = match ApplicationDefaultCredentialsAuthenticator::builder().await { +/// ApplicationDefaultCredentialsTypes::InstanceMetadata(auth) => auth +/// .build() +/// .await +/// .expect("Unable to create instance metadata authenticator"), +/// ApplicationDefaultCredentialsTypes::ServiceAccount(auth) => auth +/// .build() +/// .await +/// .expect("Unable to create service account authenticator"), +/// }; /// # } /// ``` pub struct ApplicationDefaultCredentialsAuthenticator; impl ApplicationDefaultCredentialsAuthenticator { - /// Use the builder pattern to create an Authenticator that uses a service account. - pub async fn builder( + /// Use modified builder pattern to create an Authenticator that uses GCE instance metadata server + /// to provide tokens. + pub fn from_instance_metadata( ) -> AuthenticatorBuilder { - match std::env::var("GOOGLE_APPLICATION_CREDENTIALS") { - Ok(_path) => { - todo!() - // # here we would need to do something like this: - // let service_account_key = crate::read_service_account_key(path).await.unwrap(); - // AuthenticatorBuilder::::with_auth_flow( - // ServiceAccountFlowOpts { - // key: service_account_key, - // subject: None, - // }, - // ) - } - Err(_e) => AuthenticatorBuilder::::with_auth_flow( - ApplicationDefaultCredentialsFlowOpts {}, + AuthenticatorBuilder::::with_auth_flow( + ApplicationDefaultCredentialsFlowOpts {}, + ) + } + + /// Use modified builder pattern to create an Authenticator that pulls default application credentials + /// service account file name from os environment variable. + pub async fn from_environment( + ) -> Result, std::env::VarError> + { + let service_account_key = + crate::read_service_account_key(std::env::var("GOOGLE_APPLICATION_CREDENTIALS")?) + .await + .unwrap(); + Ok( + AuthenticatorBuilder::::with_auth_flow(ServiceAccountFlowOpts { + key: service_account_key, + subject: None, + }), + ) + } + + /// Use the builder pattern to deduce which model of authenticator should be used: + /// Service account one or GCE instance metadata kind + pub async fn builder() -> ApplicationDefaultCredentialsTypes { + match ApplicationDefaultCredentialsAuthenticator::from_environment().await { + Ok(builder) => ApplicationDefaultCredentialsTypes::ServiceAccount(builder), + Err(_) => ApplicationDefaultCredentialsTypes::InstanceMetadata( + ApplicationDefaultCredentialsAuthenticator::from_instance_metadata(), ), } } } +/// Types of authenticators provided by ApplicationDefaultCredentialsAuthenticator +pub enum ApplicationDefaultCredentialsTypes { + /// Service account based authenticator signature + ServiceAccount(AuthenticatorBuilder), + /// GCE Instance Metadata based authenticator signature + InstanceMetadata( + AuthenticatorBuilder, + ), +} /// ## Methods available when building any Authenticator. /// ``` diff --git a/tests/tests.rs b/tests/tests.rs index 3b10967..fab7e6e 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -599,7 +599,8 @@ async fn test_disk_storage() { } #[tokio::test] -async fn test_default_application_credentials() { +async fn test_default_application_credentials_from_metadata_server() { + use yup_oauth2::authenticator::ApplicationDefaultCredentialsTypes; let _ = env_logger::try_init(); let server = Server::run(); server.expect( @@ -618,11 +619,10 @@ async fn test_default_application_credentials() { "expires_in": 12345678, }))), ); - let authenticator = ApplicationDefaultCredentialsAuthenticator::builder() - .await - .build() - .await - .unwrap(); + let authenticator = match ApplicationDefaultCredentialsAuthenticator::builder().await { + ApplicationDefaultCredentialsTypes::InstanceMetadata(auth) => auth.build().await.unwrap(), + _ => panic!("We are not testing service account adc model"), + }; let token = authenticator .token(&["https://googleapis.com/some/scope"]) .await