use std::fmt::Display;
use url::{ParseError, Url};
lazy_static! {
pub static ref AZURE_PUBLIC_CLOUD_INSTANCE: Url = {
Url::parse(AzureCloudInstance::AzurePublic.as_ref())
.expect("Unable to create Azure Public Cloud Instance Url")
};
pub static ref AZURE_CHINA_CLOUD_INSTANCE: Url = {
Url::parse(AzureCloudInstance::AzureChina.as_ref())
.expect("Unable to create Azure China Cloud Instance Url")
};
pub static ref AZURE_GERMANY_CLOUD_INSTANCE: Url = {
Url::parse(AzureCloudInstance::AzureGermany.as_ref())
.expect("Unable to create Azure Germany Cloud Instance Url")
};
pub static ref AZURE_US_GOVERNMENT: Url = {
Url::parse(AzureCloudInstance::AzureUsGovernment.as_ref())
.expect("Unable to create Azure Us Government Cloud Instance Url")
};
}
#[derive(
Copy, Clone, Debug, Default, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize,
)]
pub enum AzureCloudInstance {
#[default]
AzurePublic,
AzureChina,
AzureGermany,
AzureUsGovernment,
}
impl AzureCloudInstance {
pub fn get_open_id_configuration_url(&self, authority: Authority) -> String {
format!("{}/v2.0/{}", self.as_ref(), authority.as_ref())
}
}
impl AsRef<str> for AzureCloudInstance {
fn as_ref(&self) -> &str {
match self {
AzureCloudInstance::AzurePublic => "https://login.microsoftonline.com",
AzureCloudInstance::AzureChina => "https://login.chinacloudapi.cn",
AzureCloudInstance::AzureGermany => "https://login.microsoftonline.de",
AzureCloudInstance::AzureUsGovernment => "https://login.microsoftonline.us",
}
}
}
impl From<&AzureCloudInstance> for Url {
fn from(value: &AzureCloudInstance) -> Self {
match value {
AzureCloudInstance::AzurePublic => AZURE_PUBLIC_CLOUD_INSTANCE.clone(),
AzureCloudInstance::AzureChina => AZURE_CHINA_CLOUD_INSTANCE.clone(),
AzureCloudInstance::AzureGermany => AZURE_GERMANY_CLOUD_INSTANCE.clone(),
AzureCloudInstance::AzureUsGovernment => AZURE_US_GOVERNMENT.clone(),
}
}
}
impl From<AzureCloudInstance> for Url {
fn from(value: AzureCloudInstance) -> Self {
match value {
AzureCloudInstance::AzurePublic => AZURE_PUBLIC_CLOUD_INSTANCE.clone(),
AzureCloudInstance::AzureChina => AZURE_CHINA_CLOUD_INSTANCE.clone(),
AzureCloudInstance::AzureGermany => AZURE_GERMANY_CLOUD_INSTANCE.clone(),
AzureCloudInstance::AzureUsGovernment => AZURE_US_GOVERNMENT.clone(),
}
}
}
impl AzureCloudInstance {
pub fn auth_uri(&self, authority: &Authority) -> Result<Url, ParseError> {
Url::parse(&format!(
"{}/{}/oauth2/v2.0/authorize",
self.as_ref(),
authority.as_ref()
))
}
pub fn token_uri(&self, authority: &Authority) -> Result<Url, ParseError> {
Url::parse(&format!(
"{}/{}/oauth2/v2.0/token",
self.as_ref(),
authority.as_ref()
))
}
pub fn admin_consent_uri(&self, authority: &Authority) -> Result<Url, ParseError> {
Url::parse(&format!(
"{}/{}/adminconsent",
self.as_ref(),
authority.as_ref()
))
}
pub fn device_code_uri(&self, authority: &Authority) -> Result<Url, ParseError> {
Url::parse(&format!(
"{}/{}/oauth2/v2.0/devicecode",
self.as_ref(),
authority.as_ref()
))
}
pub fn openid_configuration_uri(&self, authority: &Authority) -> Result<Url, ParseError> {
Url::parse(&format!(
"{}/{}/v2.0/.well-known/openid-configuration",
self.as_ref(),
authority.as_ref()
))
}
pub fn issuer(&self, authority: &Authority) -> Result<Url, ParseError> {
Url::parse(&format!("{}/{}/v2.0", self.as_ref(), authority.as_ref()))
}
}
#[derive(Clone, Debug, Default, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)]
pub enum AadAuthorityAudience {
AzureAdMyOrg(String),
#[default]
AzureAdAndPersonalMicrosoftAccount,
AzureAdMultipleOrgs,
PersonalMicrosoftAccount,
}
impl AadAuthorityAudience {
pub fn as_str(&self) -> &str {
match self {
AadAuthorityAudience::AzureAdMyOrg(tenant) => tenant.as_str(),
AadAuthorityAudience::AzureAdAndPersonalMicrosoftAccount => "common",
AadAuthorityAudience::AzureAdMultipleOrgs => "organizations",
AadAuthorityAudience::PersonalMicrosoftAccount => "consumers",
}
}
}
impl AsRef<str> for AadAuthorityAudience {
fn as_ref(&self) -> &str {
self.as_str()
}
}
impl Display for AadAuthorityAudience {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.as_str())
}
}
impl From<&str> for AadAuthorityAudience {
fn from(value: &str) -> Self {
match value.as_bytes() {
b"common" => AadAuthorityAudience::AzureAdAndPersonalMicrosoftAccount,
b"organizations" => AadAuthorityAudience::AzureAdMultipleOrgs,
b"consumers" => AadAuthorityAudience::PersonalMicrosoftAccount,
_ => AadAuthorityAudience::AzureAdMyOrg(value.to_string()),
}
}
}
#[derive(Clone, Debug, Default, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub enum Authority {
#[default]
AzureActiveDirectory,
AzureDirectoryFederatedServices,
Common,
Organizations,
Consumers,
TenantId(String),
}
impl Authority {
pub fn tenant_id(&self) -> Option<&String> {
match self {
Authority::TenantId(tenant_id) => Some(tenant_id),
_ => None,
}
}
pub fn as_str(&self) -> &str {
match self {
Authority::AzureActiveDirectory | Authority::Common => "common",
Authority::AzureDirectoryFederatedServices => "adfs",
Authority::Organizations => "organizations",
Authority::Consumers => "consumers",
Authority::TenantId(tenant_id) => tenant_id.as_str(),
}
}
}
impl From<&AadAuthorityAudience> for Authority {
fn from(value: &AadAuthorityAudience) -> Self {
match value {
AadAuthorityAudience::AzureAdAndPersonalMicrosoftAccount => Authority::Common,
AadAuthorityAudience::AzureAdMyOrg(tenant_id) => Authority::TenantId(tenant_id.clone()),
AadAuthorityAudience::AzureAdMultipleOrgs => Authority::Organizations,
AadAuthorityAudience::PersonalMicrosoftAccount => Authority::Consumers,
}
}
}
impl From<AadAuthorityAudience> for Authority {
fn from(value: AadAuthorityAudience) -> Self {
match value {
AadAuthorityAudience::AzureAdAndPersonalMicrosoftAccount => Authority::Common,
AadAuthorityAudience::AzureAdMyOrg(tenant_id) => Authority::TenantId(tenant_id),
AadAuthorityAudience::AzureAdMultipleOrgs => Authority::Organizations,
AadAuthorityAudience::PersonalMicrosoftAccount => Authority::Consumers,
}
}
}
impl AsRef<str> for Authority {
fn as_ref(&self) -> &str {
self.as_str()
}
}
impl Display for Authority {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.as_str())
}
}
impl From<&str> for Authority {
fn from(value: &str) -> Self {
match value.as_bytes() {
b"aad" => Authority::AzureActiveDirectory,
b"common" => Authority::Common,
b"adfs" => Authority::AzureDirectoryFederatedServices,
b"organizations" => Authority::Organizations,
b"consumers" => Authority::Consumers,
_ => Authority::TenantId(value.to_owned()),
}
}
}