Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

rename AccessToken to Secret and expand it's usage #1472

Merged
merged 5 commits into from
Nov 29, 2023
Merged
Show file tree
Hide file tree
Changes from 3 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
32 changes: 25 additions & 7 deletions sdk/core/src/auth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ use serde::{Deserialize, Serialize};
use std::{borrow::Cow, fmt::Debug};
use time::OffsetDateTime;

#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct AccessToken(Cow<'static, str>);
#[derive(Clone, Deserialize, Serialize)]
pub struct Secret(Cow<'static, str>);

impl AccessToken {
impl Secret {
pub fn new<T>(access_token: T) -> Self
where
T: Into<Cow<'static, str>>,
Expand All @@ -20,26 +20,44 @@ impl AccessToken {
}
}

impl From<String> for Secret {
fn from(access_token: String) -> Self {
Self::new(access_token)
}
}

impl Debug for Secret {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_tuple("Secret").field(&"<REDACTED>").finish()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice

}
}

/// Represents an Azure service bearer access token with expiry information.
#[derive(Debug, Clone)]
pub struct TokenResponse {
/// Get the access token value.
pub token: AccessToken,
pub token: Secret,
/// Gets the time when the provided token expires.
pub expires_on: OffsetDateTime,
}

impl TokenResponse {
/// Create a new `TokenResponse`.
pub fn new(token: AccessToken, expires_on: OffsetDateTime) -> Self {
Self { token, expires_on }
pub fn new<T>(token: T, expires_on: OffsetDateTime) -> Self
where
T: Into<Secret>,
{
Self {
token: token.into(),
expires_on,
}
}
}

/// Represents a credential capable of providing an OAuth token.
#[cfg_attr(target_arch = "wasm32", async_trait::async_trait(?Send))]
#[cfg_attr(not(target_arch = "wasm32"), async_trait::async_trait)]
pub trait TokenCredential: Send + Sync {
pub trait TokenCredential: Send + Sync + Debug {
/// Gets a `TokenResponse` for the specified resource
async fn get_token(&self, resource: &str) -> crate::Result<TokenResponse>;
}
8 changes: 4 additions & 4 deletions sdk/identity/src/client_credentials_flow/login_response.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use azure_core::auth::AccessToken;
use azure_core::auth::Secret;
use serde::{Deserialize, Deserializer};
use time::OffsetDateTime;

Expand All @@ -21,7 +21,7 @@ pub struct LoginResponse {
pub expires_on: Option<OffsetDateTime>,
pub not_before: Option<OffsetDateTime>,
pub resource: Option<String>,
pub access_token: AccessToken,
pub access_token: Secret,
}

impl<'de> Deserialize<'de> for LoginResponse {
Expand All @@ -35,7 +35,7 @@ impl<'de> Deserialize<'de> for LoginResponse {
}

impl LoginResponse {
pub fn access_token(&self) -> &AccessToken {
pub fn access_token(&self) -> &Secret {
&self.access_token
}

Expand All @@ -56,7 +56,7 @@ impl LoginResponse {
expires_on,
not_before,
resource: r.resource,
access_token: AccessToken::new(r.access_token),
access_token: r.access_token.into(),
}
}
}
14 changes: 7 additions & 7 deletions sdk/identity/src/device_code_flow/device_code_responses.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use azure_core::auth::AccessToken;
use azure_core::auth::Secret;
use serde::Deserialize;
use std::fmt;

Expand Down Expand Up @@ -34,26 +34,26 @@ pub struct DeviceCodeAuthorization {
pub expires_in: u64,
/// Issued for the scopes that were requested.
/// Format: Opaque string
access_token: AccessToken,
access_token: Secret,
/// Issued if the original scope parameter included offline_access.
/// Format: JWT
refresh_token: Option<AccessToken>,
refresh_token: Option<Secret>,
/// Issued if the original scope parameter included the openid scope.
/// Format: Opaque string
id_token: Option<AccessToken>,
id_token: Option<Secret>,
}

impl DeviceCodeAuthorization {
/// Get the access token
pub fn access_token(&self) -> &AccessToken {
pub fn access_token(&self) -> &Secret {
&self.access_token
}
/// Get the refresh token
pub fn refresh_token(&self) -> Option<&AccessToken> {
pub fn refresh_token(&self) -> Option<&Secret> {
self.refresh_token.as_ref()
}
/// Get the id token
pub fn id_token(&self) -> Option<&AccessToken> {
pub fn id_token(&self) -> Option<&Secret> {
self.id_token.as_ref()
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use azure_core::auth::AccessToken;
use azure_core::auth::Secret;
use serde::{Deserialize, Deserializer};
use time::OffsetDateTime;

Expand All @@ -21,7 +21,7 @@ pub struct LoginResponse {
pub expires_on: Option<OffsetDateTime>,
pub not_before: Option<OffsetDateTime>,
pub resource: Option<String>,
pub access_token: AccessToken,
pub access_token: Secret,
}

impl<'de> Deserialize<'de> for LoginResponse {
Expand All @@ -35,7 +35,7 @@ impl<'de> Deserialize<'de> for LoginResponse {
}

impl LoginResponse {
pub fn access_token(&self) -> &AccessToken {
pub fn access_token(&self) -> &Secret {
&self.access_token
}

Expand All @@ -56,7 +56,7 @@ impl LoginResponse {
expires_on,
not_before,
resource: r.resource,
access_token: AccessToken::new(r.access_token),
access_token: r.access_token.into(),
}
}
}
14 changes: 7 additions & 7 deletions sdk/identity/src/refresh_token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

use azure_core::Method;
use azure_core::{
auth::AccessToken,
auth::Secret,
content_type,
error::{Error, ErrorKind, ResultExt},
headers, HttpClient, Request,
Expand All @@ -18,7 +18,7 @@ pub async fn exchange(
tenant_id: &str,
client_id: &str,
client_secret: Option<&str>,
refresh_token: &AccessToken,
refresh_token: &Secret,
) -> azure_core::Result<RefreshTokenResponse> {
let encoded = {
let mut encoded = &mut form_urlencoded::Serializer::new(String::new());
Expand Down Expand Up @@ -66,8 +66,8 @@ pub struct RefreshTokenResponse {
scopes: Vec<String>,
expires_in: u64,
ext_expires_in: u64,
access_token: AccessToken,
refresh_token: AccessToken,
access_token: Secret,
refresh_token: Secret,
}

impl RefreshTokenResponse {
Expand All @@ -84,11 +84,11 @@ impl RefreshTokenResponse {
self.expires_in
}
/// Issued for the scopes that were requested.
pub fn access_token(&self) -> &AccessToken {
pub fn access_token(&self) -> &Secret {
&self.access_token
}
/// The new refresh token and should replace old refresh token.
pub fn refresh_token(&self) -> &AccessToken {
pub fn refresh_token(&self) -> &Secret {
&self.refresh_token
}
/// Indicates the extended lifetime of an `access_token`.
Expand Down Expand Up @@ -147,7 +147,7 @@ mod tests {
"UNUSED",
"UNUSED",
None,
&AccessToken::new("UNUSED"),
&Secret::new("UNUSED"),
));
}
}
24 changes: 12 additions & 12 deletions sdk/identity/src/token_credentials/auto_refreshing_credentials.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ pub struct AutoRefreshingTokenCredential {
impl std::fmt::Debug for AutoRefreshingTokenCredential {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
f.debug_struct("AutoRefreshingTokenCredential")
.field("credential", &"TokenCredential")
.field("credential", &self.credential)
.field("token_cache", &"<REDACTED>")
.finish()
}
}
Expand Down Expand Up @@ -73,10 +74,11 @@ impl TokenCredential for AutoRefreshingTokenCredential {
#[cfg(test)]
mod tests {
use super::*;
use azure_core::auth::AccessToken;
use azure_core::auth::Secret;
use azure_core::auth::TokenCredential;
use std::sync::Mutex;

#[derive(Debug)]
struct MockCredential {
token: TokenResponse,
get_token_call_count: Mutex<usize>,
Expand All @@ -99,7 +101,7 @@ mod tests {
let mut call_count = self.get_token_call_count.lock().unwrap();
*call_count += 1;
Ok(TokenResponse {
token: AccessToken::new(format!(
token: Secret::new(format!(
"{}-{}:{}",
resource,
self.token.token.secret(),
Expand All @@ -117,10 +119,9 @@ mod tests {
async fn test_get_token_different_resources() -> azure_core::Result<()> {
let resource1 = STORAGE_TOKEN_SCOPE;
let resource2 = IOTHUB_TOKEN_SCOPE;
let token_value = "test-token";
let access_token = AccessToken::new(token_value);
let access_token = "test-token";
let expires_on = OffsetDateTime::now_utc() + Duration::from_secs(300);
let token_response = TokenResponse::new(access_token, expires_on);
let token_response = TokenResponse::new(Secret::new(access_token), expires_on);

let mock_credential = MockCredential::new(token_response);
let auto_refreshing_credential =
Expand All @@ -129,15 +130,15 @@ mod tests {
// Test that querying a token for the same resource twice returns the same (cached) token on the second call
let token1 = auto_refreshing_credential.get_token(resource1).await?;
let token2 = auto_refreshing_credential.get_token(resource1).await?;
let expected_token = format!("{}-{}:1", resource1, token_value);
let expected_token = format!("{}-{}:1", resource1, access_token);
assert_eq!(token1.token.secret(), expected_token);
assert_eq!(token2.token.secret(), expected_token);

// Test that querying a token for a second resource returns a different token, as the cache is per-resource.
// Also test that the same token is the returned (cached) on a second call.
let token3 = auto_refreshing_credential.get_token(resource2).await?;
let token4 = auto_refreshing_credential.get_token(resource2).await?;
let expected_token = format!("{}-{}:2", resource2, token_value);
let expected_token = format!("{}-{}:2", resource2, access_token);
assert_eq!(token3.token.secret(), expected_token);
assert_eq!(token4.token.secret(), expected_token);

Expand All @@ -147,10 +148,9 @@ mod tests {
#[tokio::test]
async fn test_refresh_expired_token() -> azure_core::Result<()> {
let resource = STORAGE_TOKEN_SCOPE;
let token_value = "test-token";
let access_token = AccessToken::new(token_value);
let access_token = "test-token";
let expires_on = OffsetDateTime::now_utc();
let token_response = TokenResponse::new(access_token, expires_on);
let token_response = TokenResponse::new(Secret::new(access_token), expires_on);

let mock_credential = MockCredential::new(token_response);
let auto_refreshing_credential =
Expand All @@ -161,7 +161,7 @@ mod tests {
let token = auto_refreshing_credential.get_token(resource).await?;
assert_eq!(
token.token.secret(),
format!("{}-{}:{}", resource, token_value, i)
format!("{}-{}:{}", resource, access_token, i)
);
}

Expand Down
6 changes: 3 additions & 3 deletions sdk/identity/src/token_credentials/azure_cli_credentials.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use azure_core::auth::{AccessToken, TokenCredential, TokenResponse};
use azure_core::auth::{Secret, TokenCredential, TokenResponse};
use azure_core::error::{Error, ErrorKind, ResultExt};
use serde::Deserialize;
use std::process::Command;
Expand Down Expand Up @@ -94,7 +94,7 @@ mod az_cli_date_format {
#[derive(Debug, Clone, Deserialize)]
#[serde(rename_all = "camelCase")]
struct CliTokenResponse {
pub access_token: AccessToken,
pub access_token: Secret,
#[serde(with = "az_cli_date_format")]
pub expires_on: OffsetDateTime,
pub subscription: String,
Expand All @@ -104,7 +104,7 @@ struct CliTokenResponse {
}

/// Enables authentication to Azure Active Directory using Azure CLI to obtain an access token.
#[derive(Default)]
#[derive(Debug, Default)]
pub struct AzureCliCredential {
_private: (),
}
Expand Down
Loading