Skip to content
Merged
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: 1 addition & 1 deletion sdk/identity/examples/environment_credentials.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use url::Url;
#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
let sub_id = std::env::var("AZURE_SUBSCRIPTION_ID")?;
let creds = EnvironmentCredential;
let creds = EnvironmentCredential::default();
let res = creds
.get_token("https://management.azure.com/")
.await
Expand Down
71 changes: 67 additions & 4 deletions sdk/identity/src/token_credentials/client_secret_credentials.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,59 @@ use oauth2::{
use std::{str, time::Duration};
use url::Url;

/// Provides options to configure how the Identity library makes authentication
/// requests to Azure Active Directory.
#[derive(Clone, Debug, PartialEq)]
pub struct TokenCredentialOptions {
authority_host: String,
}

impl Default for TokenCredentialOptions {
fn default() -> Self {
Self {
authority_host: authority_hosts::AZURE_PUBLIC_CLOUD.to_owned(),
}
}
}

impl TokenCredentialOptions {
/// Create a new TokenCredentialsOptions. `default()` may also be used.
pub fn new(authority_host: String) -> Self {
Self { authority_host }
}

pub fn set_authority_host(&mut self, authority_host: String) {
self.authority_host = authority_host
}

/// The authority host to use for authentication requests. The default is
/// "https://login.microsoftonline.com".
pub fn authority_host(&self) -> &str {
&self.authority_host
}
}

/// A list of known Azure authority hosts
pub mod authority_hosts {
/// China-based Azure Authority Host
pub const AZURE_CHINA: &str = "https://login.chinacloudapi.cn";
/// Germany-based Azure Authority Host
pub const AZURE_GERMANY: &str = "https://login.microsoftonline.de";
/// US Government Azure Authority Host
pub const AZURE_GOVERNMENT: &str = "https://login.microsoftonline.us";
/// Public Cloud Azure Authority Host
pub const AZURE_PUBLIC_CLOUD: &str = "https://login.microsoftonline.com";
}

pub mod tenant_ids {
/// The tenant ID for multi-tenant apps
///
/// https://docs.microsoft.com/en-us/azure/active-directory/develop/howto-convert-app-to-be-multi-tenant
pub const TENANT_ID_COMMON: &str = "common";
/// The tenant ID for Active Directory Federated Services
pub const TENANT_ID_ADFS: &str = "adfs";
}

/// Enables authentication to Azure Active Directory using a client secret that was generated for an App Registration.
///
/// More information on how to configure a client secret can be found here:
Expand All @@ -15,29 +68,39 @@ pub struct ClientSecretCredential {
tenant_id: String,
client_id: oauth2::ClientId,
client_secret: Option<oauth2::ClientSecret>,
options: TokenCredentialOptions,
}

impl ClientSecretCredential {
pub fn new(
tenant_id: String,
client_id: String,
client_secret: String,
options: TokenCredentialOptions,
) -> ClientSecretCredential {
ClientSecretCredential {
tenant_id,
client_id: oauth2::ClientId::new(client_id),
client_secret: Some(oauth2::ClientSecret::new(client_secret)),
options,
}
}

fn options(&self) -> &TokenCredentialOptions {
&self.options
}
}

#[async_trait::async_trait]
impl TokenCredential for ClientSecretCredential {
async fn get_token(&self, resource: &str) -> Result<TokenResponse, AzureError> {
let options = self.options();
let authority_host = options.authority_host();

let token_url = TokenUrl::from_url(
Url::parse(&format!(
"https://login.microsoftonline.com/{}/oauth2/v2.0/token",
self.tenant_id
"{}/{}/oauth2/v2.0/token",
authority_host, self.tenant_id
))
.map_err(|_| {
AzureError::GenericErrorWithText(format!(
Expand All @@ -49,8 +112,8 @@ impl TokenCredential for ClientSecretCredential {

let auth_url = AuthUrl::from_url(
Url::parse(&format!(
"https://login.microsoftonline.com/{}/oauth2/v2.0/authorize",
self.tenant_id
"{}/{}/oauth2/v2.0/authorize",
authority_host, self.tenant_id
))
.map_err(|_| {
AzureError::GenericErrorWithText(format!(
Expand Down
4 changes: 2 additions & 2 deletions sdk/identity/src/token_credentials/default_credentials.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ impl DefaultCredentialBuilder {
let mut sources =
Vec::<Box<dyn TokenCredential + Send + Sync>>::with_capacity(source_count);
if self.include_environment_credential {
sources.push(Box::new(EnvironmentCredential {}));
sources.push(Box::new(EnvironmentCredential::default()));
}
if self.include_managed_identity_credential {
sources.push(Box::new(ManagedIdentityCredential {}))
Expand Down Expand Up @@ -78,7 +78,7 @@ impl Default for DefaultCredential {
fn default() -> Self {
DefaultCredential {
sources: vec![
Box::new(EnvironmentCredential {}),
Box::new(EnvironmentCredential::default()),
Box::new(ManagedIdentityCredential {}),
Box::new(AzureCliCredential {}),
],
Expand Down
27 changes: 24 additions & 3 deletions sdk/identity/src/token_credentials/environment_credentials.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use super::ClientSecretCredential;
use super::{ClientSecretCredential, TokenCredentialOptions};
use azure_core::errors::AzureError;
use azure_core::{TokenCredential, TokenResponse};

Expand All @@ -22,7 +22,23 @@ const AZURE_CLIENT_CERTIFICATE_PATH_ENV_KEY: &str = "AZURE_CLIENT_CERTIFICATE_PA
/// This credential ultimately uses a `ClientSecretCredential` to perform the authentication using
/// these details.
/// Please consult the documentation of that class for more details.
pub struct EnvironmentCredential;
pub struct EnvironmentCredential {
options: TokenCredentialOptions,
}

impl EnvironmentCredential {
pub fn new(options: TokenCredentialOptions) -> Self {
Self { options }
}
}

impl Default for EnvironmentCredential {
fn default() -> Self {
Self {
options: TokenCredentialOptions::default(),
}
}
}

#[async_trait::async_trait]
impl TokenCredential for EnvironmentCredential {
Expand All @@ -46,7 +62,12 @@ impl TokenCredential for EnvironmentCredential {
let client_certificate_path = std::env::var(AZURE_CLIENT_CERTIFICATE_PATH_ENV_KEY);

if let Ok(client_secret) = client_secret {
let credential = ClientSecretCredential::new(tenant_id, client_id, client_secret);
let credential = ClientSecretCredential::new(
tenant_id,
client_id,
client_secret,
self.options.clone(),
);
return credential.get_token(resource).await;
} else if username.is_ok() && password.is_ok() {
// Could use multiple if-let with #![feature(let_chains)] once stabilised - see https://github.com/rust-lang/rust/issues/53667
Expand Down
9 changes: 7 additions & 2 deletions sdk/key_vault/examples/backup_secret.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use azure_identity::token_credentials::ClientSecretCredential;
use azure_identity::token_credentials::{ClientSecretCredential, TokenCredentialOptions};
use azure_key_vault::KeyVaultClient;
use std::env;

Expand All @@ -12,7 +12,12 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
env::var("KEYVAULT_NAME").expect("Missing KEYVAULT_NAME environment variable.");
let secret_name = env::var("SECRET_NAME").expect("Missing SECRET_NAME environment variable.");

let creds = ClientSecretCredential::new(tenant_id, client_id, client_secret);
let creds = ClientSecretCredential::new(
tenant_id,
client_id,
client_secret,
TokenCredentialOptions::default(),
);
let mut client = KeyVaultClient::new(&creds, &keyvault_name);

let backup_response = client.backup_secret(&secret_name).await?;
Expand Down
9 changes: 7 additions & 2 deletions sdk/key_vault/examples/delete_secret.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use azure_identity::token_credentials::ClientSecretCredential;
use azure_identity::token_credentials::{ClientSecretCredential, TokenCredentialOptions};
use azure_key_vault::KeyVaultClient;
use std::env;

Expand All @@ -12,7 +12,12 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
env::var("KEYVAULT_NAME").expect("Missing KEYVAULT_NAME environment variable.");
let secret_name = env::var("SECRET_NAME").expect("Missing SECRET_NAME environment variable.");

let creds = ClientSecretCredential::new(tenant_id, client_id, client_secret);
let creds = ClientSecretCredential::new(
tenant_id,
client_id,
client_secret,
TokenCredentialOptions::default(),
);
let mut client = KeyVaultClient::new(&creds, &keyvault_name);
client.delete_secret(&secret_name).await?;

Expand Down
9 changes: 7 additions & 2 deletions sdk/key_vault/examples/get_secret.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use azure_identity::token_credentials::ClientSecretCredential;
use azure_identity::token_credentials::{ClientSecretCredential, TokenCredentialOptions};
use azure_key_vault::KeyVaultClient;
use std::env;

Expand All @@ -12,7 +12,12 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
env::var("KEYVAULT_NAME").expect("Missing KEYVAULT_NAME environment variable.");
let secret_name = env::var("SECRET_NAME").expect("Missing SECRET_NAME environment variable.");

let creds = ClientSecretCredential::new(tenant_id, client_id, client_secret);
let creds = ClientSecretCredential::new(
tenant_id,
client_id,
client_secret,
TokenCredentialOptions::default(),
);
let mut client = KeyVaultClient::new(&creds, &keyvault_name);

let secret = client.get_secret(&secret_name).await?;
Expand Down
9 changes: 7 additions & 2 deletions sdk/key_vault/examples/get_secret_versions.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use azure_identity::token_credentials::ClientSecretCredential;
use azure_identity::token_credentials::{ClientSecretCredential, TokenCredentialOptions};
use azure_key_vault::KeyVaultClient;
use std::env;

Expand All @@ -12,7 +12,12 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
env::var("KEYVAULT_NAME").expect("Missing KEYVAULT_NAME environment variable.");
let secret_name = env::var("SECRET_NAME").expect("Missing SECRET_NAME environment variable.");

let creds = ClientSecretCredential::new(tenant_id, client_id, client_secret);
let creds = ClientSecretCredential::new(
tenant_id,
client_id,
client_secret,
TokenCredentialOptions::default(),
);
let mut client = KeyVaultClient::new(&creds, &keyvault_name);

let secrets = client.get_secret_versions(&secret_name).await?;
Expand Down
9 changes: 7 additions & 2 deletions sdk/key_vault/examples/list_secrets.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use azure_identity::token_credentials::ClientSecretCredential;
use azure_identity::token_credentials::{ClientSecretCredential, TokenCredentialOptions};
use azure_key_vault::KeyVaultClient;
use std::env;

Expand All @@ -11,7 +11,12 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
let keyvault_name =
env::var("KEYVAULT_NAME").expect("Missing KEYVAULT_NAME environment variable.");

let creds = ClientSecretCredential::new(tenant_id, client_id, client_secret);
let creds = ClientSecretCredential::new(
tenant_id,
client_id,
client_secret,
TokenCredentialOptions::default(),
);
let mut client = KeyVaultClient::new(&creds, &keyvault_name);

let secrets = client.list_secrets().await?;
Expand Down
9 changes: 7 additions & 2 deletions sdk/key_vault/examples/restore_secret.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use azure_identity::token_credentials::ClientSecretCredential;
use azure_identity::token_credentials::{ClientSecretCredential, TokenCredentialOptions};
use azure_key_vault::KeyVaultClient;
use std::env;

Expand All @@ -12,7 +12,12 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
env::var("KEYVAULT_NAME").expect("Missing KEYVAULT_NAME environment variable.");
let backup_blob = env::var("BACKUP_BLOB").expect("Missing BACKUP_BLOB environment variable.");

let creds = ClientSecretCredential::new(tenant_id, client_id, client_secret);
let creds = ClientSecretCredential::new(
tenant_id,
client_id,
client_secret,
TokenCredentialOptions::default(),
);
let mut client = KeyVaultClient::new(&creds, &keyvault_name);

client.restore_secret(&backup_blob).await?;
Expand Down
9 changes: 7 additions & 2 deletions sdk/key_vault/examples/set_secret.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use azure_identity::token_credentials::ClientSecretCredential;
use azure_identity::token_credentials::{ClientSecretCredential, TokenCredentialOptions};
use azure_key_vault::KeyVaultClient;
use std::env;

Expand All @@ -14,7 +14,12 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
let secret_value =
env::var("SECRET_VALUE").expect("Missing SECRET_VALUE environment variable.");

let creds = ClientSecretCredential::new(tenant_id, client_id, client_secret);
let creds = ClientSecretCredential::new(
tenant_id,
client_id,
client_secret,
TokenCredentialOptions::default(),
);
let mut client = KeyVaultClient::new(&creds, &keyvault_name);

client.set_secret(&secret_name, &secret_value).await?;
Expand Down
9 changes: 7 additions & 2 deletions sdk/key_vault/examples/update_secret.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use azure_identity::token_credentials::ClientSecretCredential;
use azure_identity::token_credentials::{ClientSecretCredential, TokenCredentialOptions};
use azure_key_vault::{KeyVaultClient, RecoveryLevel};
use chrono::prelude::*;
use chrono::Duration;
Expand All @@ -16,7 +16,12 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
let secret_version =
env::var("SECRET_VERSION").expect("Missing SECRET_VERSION environment variable.");

let creds = ClientSecretCredential::new(tenant_id, client_id, client_secret);
let creds = ClientSecretCredential::new(
tenant_id,
client_id,
client_secret,
TokenCredentialOptions::default(),
);
let mut client = KeyVaultClient::new(&creds, &keyvault_name);

// Disable secret.
Expand Down