Skip to content

Commit 2f2fb18

Browse files
authored
Credentials get authority host from CloudConfiguration (#3115)
1 parent 9fbbc1c commit 2f2fb18

File tree

9 files changed

+211
-134
lines changed

9 files changed

+211
-134
lines changed

sdk/core/azure_core/CHANGELOG.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,17 @@
11
# Release History
22

3+
## 0.30.0 (Unreleased)
4+
5+
### Features Added
6+
7+
### Breaking Changes
8+
9+
- Removed `constants` module.
10+
11+
### Bugs Fixed
12+
13+
### Other Changes
14+
315
## 0.29.1 (2025-10-06)
416

517
### Breaking Changes

sdk/core/azure_core/src/constants.rs

Lines changed: 0 additions & 56 deletions
This file was deleted.

sdk/core/azure_core/src/lib.rs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,13 @@
1111
mod macros;
1212

1313
pub mod cloud;
14-
mod constants;
1514
pub mod credentials;
1615
pub mod error;
1716
pub mod hmac;
1817
pub mod http;
1918
#[cfg(feature = "test")]
2019
pub mod test;
2120

22-
pub use constants::*;
23-
2421
// Re-export modules in typespec_client_core such that azure_core-based crates don't need to reference it directly.
2522
pub use typespec_client_core::{
2623
async_runtime, base64, fmt, json, sleep, stream, time, Bytes, Error, Result, Uuid,

sdk/identity/azure_identity/CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,11 @@
66

77
### Breaking Changes
88

9+
- `ClientCertificateCredential::new()` takes `Option<ClientCertificateCredentialOptions>` instead of `impl Into<ClientCertificateCredentialOptions>`.
10+
- Credential constructors return an error when given a non-HTTPS authority host.
11+
- Renamed `ClientCertificateCredential::new()` parameter `client_certificate_pass` to `client_certificate_password`.
12+
- Replaced credential-specific `authority_host` options with `azure_core::cloud::CloudConfiguration` configured via `ClientOptions.cloud`.
13+
914
### Bugs Fixed
1015

1116
### Other Changes

sdk/identity/azure_identity/src/client_assertion_credential.rs

Lines changed: 42 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,6 @@ pub struct ClientAssertionCredentialOptions {
4040
/// Add the wildcard value "*" to allow the credential to acquire tokens for any tenant in which the application is registered.
4141
pub additionally_allowed_tenants: Vec<String>,
4242

43-
/// The base URL for token requests.
44-
///
45-
/// The default is `https://login.microsoftonline.com`.
46-
pub authority_host: Option<String>,
47-
4843
/// Should be set true only by applications authenticating in disconnected clouds, or private clouds such as Azure Stack.
4944
///
5045
/// It determines whether the credential requests Microsoft Entra instance metadata
@@ -89,7 +84,7 @@ impl<C: ClientAssertion> ClientAssertionCredential<C> {
8984
validate_tenant_id(&tenant_id)?;
9085
validate_not_empty(&client_id, "no client ID specified")?;
9186
let options = options.unwrap_or_default();
92-
let authority_host = get_authority_host(None, options.authority_host)?;
87+
let authority_host = get_authority_host(None, options.client_options.cloud.as_deref())?;
9388
let endpoint = authority_host
9489
.join(&format!("/{tenant_id}/oauth2/v2.0/token"))
9590
.with_context_fn(ErrorKind::DataConversion, || {
@@ -98,7 +93,7 @@ impl<C: ClientAssertion> ClientAssertionCredential<C> {
9893
let pipeline = Pipeline::new(
9994
option_env!("CARGO_PKG_NAME"),
10095
option_env!("CARGO_PKG_VERSION"),
101-
options.client_options.clone(),
96+
options.client_options,
10297
Vec::default(),
10398
Vec::default(),
10499
None,
@@ -194,7 +189,6 @@ pub(crate) mod tests {
194189
use super::*;
195190
use crate::tests::*;
196191
use azure_core::{
197-
authority_hosts::AZURE_PUBLIC_CLOUD,
198192
http::{
199193
headers::{self, content_type, Headers},
200194
Body, BufResponse, Method, Request, Transport,
@@ -207,12 +201,10 @@ pub(crate) mod tests {
207201

208202
pub const FAKE_ASSERTION: &str = "fake assertion";
209203

210-
pub fn is_valid_request() -> impl Fn(&Request) -> azure_core::Result<()> {
211-
let expected_url = format!(
212-
"{}{}/oauth2/v2.0/token",
213-
AZURE_PUBLIC_CLOUD.as_str(),
214-
FAKE_TENANT_ID
215-
);
204+
pub fn is_valid_request(
205+
expected_authority: String,
206+
) -> impl Fn(&Request) -> azure_core::Result<()> {
207+
let expected_url = format!("{expected_authority}/oauth2/v2.0/token");
216208
move |req: &Request| {
217209
assert_eq!(Method::Post, req.method());
218210
assert_eq!(expected_url, req.url().to_string());
@@ -269,7 +261,9 @@ pub(crate) mod tests {
269261
expected
270262
)),
271263
)],
272-
Some(Arc::new(is_valid_request())),
264+
Some(Arc::new(is_valid_request(
265+
FAKE_PUBLIC_CLOUD_AUTHORITY.to_string(),
266+
))),
273267
);
274268
let credential = ClientAssertionCredential::new(
275269
FAKE_TENANT_ID.to_string(),
@@ -300,15 +294,10 @@ pub(crate) mod tests {
300294
#[tokio::test]
301295
async fn get_token_success() {
302296
let mock = MockSts::new(
303-
vec![BufResponse::from_bytes(
304-
StatusCode::Ok,
305-
Headers::default(),
306-
Bytes::from(format!(
307-
r#"{{"access_token":"{}","expires_in":3600,"token_type":"Bearer"}}"#,
308-
FAKE_TOKEN
309-
)),
310-
)],
311-
Some(Arc::new(is_valid_request())),
297+
vec![token_response()],
298+
Some(Arc::new(is_valid_request(
299+
FAKE_PUBLIC_CLOUD_AUTHORITY.to_string(),
300+
))),
312301
);
313302
let credential = ClientAssertionCredential::new(
314303
FAKE_TENANT_ID.to_string(),
@@ -340,4 +329,33 @@ pub(crate) mod tests {
340329
assert_eq!(token.token.secret(), cached_token.token.secret());
341330
assert_eq!(token.expires_on, cached_token.expires_on);
342331
}
332+
333+
#[tokio::test]
334+
async fn cloud_configuration() {
335+
for (cloud, expected_authority) in cloud_configuration_cases() {
336+
let mock = MockSts::new(
337+
vec![token_response()],
338+
Some(Arc::new(is_valid_request(expected_authority))),
339+
);
340+
let credential = ClientAssertionCredential::new(
341+
FAKE_TENANT_ID.to_string(),
342+
FAKE_CLIENT_ID.to_string(),
343+
MockAssertion {},
344+
Some(ClientAssertionCredentialOptions {
345+
client_options: ClientOptions {
346+
transport: Some(Transport::new(Arc::new(mock))),
347+
cloud: Some(Arc::new(cloud)),
348+
..Default::default()
349+
},
350+
..Default::default()
351+
}),
352+
)
353+
.expect("valid credential");
354+
355+
credential
356+
.get_token(LIVE_TEST_SCOPES, None)
357+
.await
358+
.expect("token");
359+
}
360+
}
343361
}

sdk/identity/azure_identity/src/client_certificate_credential.rs

Lines changed: 10 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,6 @@ const AZURE_CLIENT_SEND_CERTIFICATE_CHAIN_ENV_KEY: &str = "AZURE_CLIENT_SEND_CER
3636
/// requests to Azure Active Directory.
3737
#[derive(Clone, Debug)]
3838
pub struct ClientCertificateCredentialOptions {
39-
/// The base URL for token requests.
40-
///
41-
/// The default is `https://login.microsoftonline.com`.
42-
pub authority_host: Option<String>,
43-
4439
/// Options for the credential's HTTP pipeline.
4540
pub client_options: ClientOptions,
4641

@@ -54,7 +49,6 @@ impl Default for ClientCertificateCredentialOptions {
5449
.map(|s| s == "1" || s.to_lowercase() == "true")
5550
.unwrap_or(false);
5651
Self {
57-
authority_host: None,
5852
client_options: ClientOptions::default(),
5953
send_certificate_chain,
6054
}
@@ -69,8 +63,8 @@ impl Default for ClientCertificateCredentialOptions {
6963
#[derive(Debug)]
7064
pub struct ClientCertificateCredential {
7165
client_id: String,
72-
client_certificate: Secret,
73-
client_certificate_pass: Secret,
66+
certificate: Secret,
67+
password: Secret,
7468
endpoint: Url,
7569
pipeline: Pipeline,
7670
send_certificate_chain: bool,
@@ -83,16 +77,15 @@ impl ClientCertificateCredential {
8377
tenant_id: String,
8478
client_id: String,
8579
client_certificate: C,
86-
client_certificate_pass: P,
87-
options: impl Into<ClientCertificateCredentialOptions>,
80+
client_certificate_password: P,
81+
options: Option<ClientCertificateCredentialOptions>,
8882
) -> azure_core::Result<Arc<ClientCertificateCredential>>
8983
where
9084
C: Into<Secret>,
9185
P: Into<Secret>,
9286
{
93-
let options = options.into();
94-
95-
let authority_host = get_authority_host(None, options.authority_host)?;
87+
let options = options.unwrap_or_default();
88+
let authority_host = get_authority_host(None, options.client_options.cloud.as_deref())?;
9689
let endpoint = authority_host
9790
.join(&format!("/{tenant_id}/oauth2/v2.0/token"))
9891
.with_context_fn(ErrorKind::DataConversion, || {
@@ -110,8 +103,8 @@ impl ClientCertificateCredential {
110103

111104
Ok(Arc::new(ClientCertificateCredential {
112105
client_id,
113-
client_certificate: client_certificate.into(),
114-
client_certificate_pass: client_certificate_pass.into(),
106+
certificate: client_certificate.into(),
107+
password: client_certificate_password.into(),
115108
endpoint,
116109
pipeline,
117110
send_certificate_chain: options.send_certificate_chain,
@@ -154,12 +147,12 @@ impl ClientCertificateCredential {
154147
));
155148
};
156149

157-
let certificate = base64::decode(self.client_certificate.secret())
150+
let certificate = base64::decode(self.certificate.secret())
158151
.map_err(|_| Error::with_message(ErrorKind::Credential, "Base64 decode failed"))?;
159152

160153
let pkcs12_certificate = Pkcs12::from_der(&certificate)
161154
.map_err(openssl_error)?
162-
.parse2(self.client_certificate_pass.secret())
155+
.parse2(self.password.secret())
163156
.map_err(openssl_error)?;
164157

165158
let Some(cert) = pkcs12_certificate.cert.as_ref() else {

0 commit comments

Comments
 (0)