azure_identity/token_credentials/
environment_credentials.rs

1#[cfg(feature = "client_certificate")]
2pub use crate::token_credentials::ClientCertificateCredential;
3use crate::token_credentials::{
4    ClientSecretCredential, TokenCredentialOptions, WorkloadIdentityCredential,
5};
6use azure_core::{
7    auth::{AccessToken, TokenCredential},
8    error::{Error, ErrorKind},
9};
10
11#[derive(Debug)]
12pub(crate) enum EnvironmentCredentialKind {
13    ClientSecret(ClientSecretCredential),
14    WorkloadIdentity(WorkloadIdentityCredential),
15    #[cfg(feature = "client_certificate")]
16    ClientCertificate(ClientCertificateCredential),
17}
18
19/// Enables authentication with Workflows Identity if either `AZURE_FEDERATED_TOKEN` or `AZURE_FEDERATED_TOKEN_FILE` is set,
20/// otherwise enables authentication to Azure Active Directory using client secret, or a username and password.
21///
22///
23/// Details configured in the following environment variables:
24///
25/// | Variable                            | Description                                      |
26/// |-------------------------------------|--------------------------------------------------|
27/// | `AZURE_TENANT_ID`                   | The Azure Active Directory tenant(directory) ID. |
28/// | `AZURE_CLIENT_ID`                   | The client(application) ID of an App Registration in the tenant. |
29/// | `AZURE_CLIENT_SECRET`               | A client secret that was generated for the App Registration. |
30/// | `AZURE_FEDERATED_TOKEN_FILE`        | Path to an federated token file. Variable is present in pods with aks workload identities. |
31///
32/// This credential ultimately uses a `WorkloadIdentityCredential` or a`ClientSecretCredential` to perform the authentication using
33/// these details.
34/// Please consult the documentation of that class for more details.
35#[derive(Debug)]
36pub struct EnvironmentCredential {
37    source: EnvironmentCredentialKind,
38}
39
40impl EnvironmentCredential {
41    pub fn create(
42        options: impl Into<TokenCredentialOptions>,
43    ) -> azure_core::Result<EnvironmentCredential> {
44        let options = options.into();
45        if let Ok(credential) = WorkloadIdentityCredential::create(options.clone()) {
46            return Ok(Self {
47                source: EnvironmentCredentialKind::WorkloadIdentity(credential),
48            });
49        }
50        if let Ok(credential) = ClientSecretCredential::create(options.clone()) {
51            return Ok(Self {
52                source: EnvironmentCredentialKind::ClientSecret(credential),
53            });
54        }
55        #[cfg(feature = "client_certificate")]
56        if let Ok(credential) = ClientCertificateCredential::create(options.clone()) {
57            return Ok(Self {
58                source: EnvironmentCredentialKind::ClientCertificate(credential),
59            });
60        }
61        Err(Error::message(
62            ErrorKind::Credential,
63            "no valid environment credential providers",
64        ))
65    }
66
67    #[cfg(test)]
68    pub(crate) fn source(&self) -> &EnvironmentCredentialKind {
69        &self.source
70    }
71}
72
73#[cfg_attr(target_arch = "wasm32", async_trait::async_trait(?Send))]
74#[cfg_attr(not(target_arch = "wasm32"), async_trait::async_trait)]
75impl TokenCredential for EnvironmentCredential {
76    async fn get_token(&self, scopes: &[&str]) -> azure_core::Result<AccessToken> {
77        match &self.source {
78            EnvironmentCredentialKind::ClientSecret(credential) => {
79                credential.get_token(scopes).await
80            }
81            EnvironmentCredentialKind::WorkloadIdentity(credential) => {
82                credential.get_token(scopes).await
83            }
84            #[cfg(feature = "client_certificate")]
85            EnvironmentCredentialKind::ClientCertificate(credential) => {
86                credential.get_token(scopes).await
87            }
88        }
89    }
90
91    async fn clear_cache(&self) -> azure_core::Result<()> {
92        match &self.source {
93            EnvironmentCredentialKind::ClientSecret(credential) => credential.clear_cache().await,
94            EnvironmentCredentialKind::WorkloadIdentity(credential) => {
95                credential.clear_cache().await
96            }
97            #[cfg(feature = "client_certificate")]
98            EnvironmentCredentialKind::ClientCertificate(credential) => {
99                credential.clear_cache().await
100            }
101        }
102    }
103}