graph-oauth 3.0.0

Rust SDK Client for Microsoft Identity Platform
use std::env::VarError;
use std::fmt::{Debug, Formatter};

use crate::identity::{
    ClientSecretCredential, ConfidentialClientApplication, PublicClientApplication,
    ResourceOwnerPasswordCredential,
};

const AZURE_TENANT_ID: &str = "AZURE_TENANT_ID";
const AZURE_CLIENT_ID: &str = "AZURE_CLIENT_ID";
const AZURE_CLIENT_SECRET: &str = "AZURE_CLIENT_SECRET";
const AZURE_USERNAME: &str = "AZURE_USERNAME";
const AZURE_PASSWORD: &str = "AZURE_PASSWORD";

#[derive(Clone)]
pub struct EnvironmentCredential;

impl Debug for EnvironmentCredential {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("EnvironmentCredential").finish()
    }
}

impl EnvironmentCredential {
    pub fn resource_owner_password_credential(
    ) -> Result<PublicClientApplication<ResourceOwnerPasswordCredential>, VarError> {
        match EnvironmentCredential::try_username_password_compile_time_env() {
            Ok(credential) => Ok(credential),
            Err(_) => EnvironmentCredential::try_username_password_runtime_env(),
        }
    }

    pub fn client_secret_credential(
    ) -> Result<ConfidentialClientApplication<ClientSecretCredential>, VarError> {
        match EnvironmentCredential::try_azure_client_secret_compile_time_env() {
            Ok(credential) => Ok(credential),
            Err(_) => EnvironmentCredential::try_azure_client_secret_runtime_env(),
        }
    }

    fn try_azure_client_secret_compile_time_env(
    ) -> Result<ConfidentialClientApplication<ClientSecretCredential>, VarError> {
        let tenant_id = option_env!("AZURE_TENANT_ID");
        let azure_client_id = option_env!("AZURE_CLIENT_ID").ok_or(VarError::NotPresent)?;
        let azure_client_secret = option_env!("AZURE_CLIENT_SECRET").ok_or(VarError::NotPresent)?;
        EnvironmentCredential::client_secret_env(
            tenant_id.map(|s| s.to_owned()),
            azure_client_id.to_owned(),
            azure_client_secret.to_owned(),
        )
    }

    fn try_azure_client_secret_runtime_env(
    ) -> Result<ConfidentialClientApplication<ClientSecretCredential>, VarError> {
        let tenant_id = std::env::var(AZURE_TENANT_ID).ok();
        let azure_client_id = std::env::var(AZURE_CLIENT_ID)?;
        let azure_client_secret = std::env::var(AZURE_CLIENT_SECRET)?;
        EnvironmentCredential::client_secret_env(tenant_id, azure_client_id, azure_client_secret)
    }

    fn client_secret_env(
        tenant_id: Option<String>,
        azure_client_id: String,
        azure_client_secret: String,
    ) -> Result<ConfidentialClientApplication<ClientSecretCredential>, VarError> {
        match tenant_id {
            Some(tenant_id) => Ok(ConfidentialClientApplication::credential(
                ClientSecretCredential::new_with_tenant(
                    tenant_id,
                    azure_client_id,
                    azure_client_secret,
                ),
            )),
            None => Ok(ConfidentialClientApplication::credential(
                ClientSecretCredential::new(azure_client_id, azure_client_secret),
            )),
        }
    }

    fn try_username_password_compile_time_env(
    ) -> Result<PublicClientApplication<ResourceOwnerPasswordCredential>, VarError> {
        let tenant_id = option_env!("AZURE_TENANT_ID");
        let azure_client_id = option_env!("AZURE_CLIENT_ID").ok_or(VarError::NotPresent)?;
        let azure_username = option_env!("AZURE_USERNAME").ok_or(VarError::NotPresent)?;
        let azure_password = option_env!("AZURE_PASSWORD").ok_or(VarError::NotPresent)?;
        Ok(EnvironmentCredential::username_password_env(
            tenant_id.map(|s| s.to_owned()),
            azure_client_id.to_owned(),
            azure_username.to_owned(),
            azure_password.to_owned(),
        ))
    }

    fn try_username_password_runtime_env(
    ) -> Result<PublicClientApplication<ResourceOwnerPasswordCredential>, VarError> {
        let tenant_id = std::env::var(AZURE_TENANT_ID).ok();
        let azure_client_id = std::env::var(AZURE_CLIENT_ID)?;
        let azure_username = std::env::var(AZURE_USERNAME)?;
        let azure_password = std::env::var(AZURE_PASSWORD)?;
        Ok(EnvironmentCredential::username_password_env(
            tenant_id,
            azure_client_id,
            azure_username,
            azure_password,
        ))
    }

    fn username_password_env(
        tenant_id: Option<String>,
        azure_client_id: String,
        azure_username: String,
        azure_password: String,
    ) -> PublicClientApplication<ResourceOwnerPasswordCredential> {
        match tenant_id {
            Some(tenant_id) => {
                PublicClientApplication::new(ResourceOwnerPasswordCredential::new_with_tenant(
                    tenant_id,
                    azure_client_id,
                    azure_username,
                    azure_password,
                ))
            }
            None => PublicClientApplication::new(ResourceOwnerPasswordCredential::new(
                azure_client_id,
                azure_username,
                azure_password,
            )),
        }
    }
}