From 972e13ae80c586543b901c788bdee4d4db00c8c8 Mon Sep 17 00:00:00 2001 From: threema-donat <129288638+threema-donat@users.noreply.github.com> Date: Wed, 12 Jun 2024 11:27:10 +0200 Subject: [PATCH 1/5] Make crypto provider configurable --- .github/workflows/test.yml | 5 ++++- Cargo.toml | 14 ++++++++------ src/authenticator.rs | 8 ++++++-- src/service_account.rs | 10 +++++++--- tests/tests.rs | 12 ------------ 5 files changed, 25 insertions(+), 24 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 506e4c6e..c62175ae 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -9,7 +9,10 @@ jobs: strategy: fail-fast: false matrix: - features: ["service_account,hyper-rustls", "service_account,hyper-tls", "service_account", "hyper-rustls"] + features: ["service_account,hyper-rustls,ring", + "service_account,hyper-rustls,aws-lc-rs", + "service_account,hyper-tls,ring", "service_account,hyper-tls,aws-lc-rs" + "service_account,ring", "hyper-rustls,ring"] steps: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@stable diff --git a/Cargo.toml b/Cargo.toml index cd430271..b361b075 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,24 +12,26 @@ edition = "2018" [[example]] name = "custom_flow" -required-features = ["hyper-rustls"] +required-features = ["hyper-rustls", "ring"] [[example]] name = "custom_client" -required-features = ["hyper-rustls", "service_account"] +required-features = ["hyper-rustls", "service_account", "ring"] [[example]] name = "custom_storage" -required-features = ["hyper-rustls"] +required-features = ["hyper-rustls", "ring"] [[test]] name = "tests" required-features = ["hyper-rustls", "service_account"] [features] -default = ["hyper-rustls", "rustls", "service_account"] +default = ["hyper-rustls", "rustls", "service_account", "ring"] service_account = ["hyper-rustls", "rustls", "rustls-pemfile"] hyper-rustls = ["dep:hyper-rustls", "rustls"] +ring = ["rustls/ring", "hyper-rustls?/ring"] +aws-lc-rs = ["rustls/aws_lc_rs", "hyper-rustls?/aws-lc-rs"] [dependencies] anyhow = "1.0.38" @@ -40,11 +42,11 @@ http = "1" http-body-util = "0.1" hyper = "1" hyper-util = { version = "0.1.5", features = ["client-legacy", "server-auto", "http1", "http2", "server-graceful"] } -hyper-rustls = { version = "0.27", optional = true, default-features = false, features = ["http1", "http2", "rustls-native-certs", "ring", "native-tokio"] } +hyper-rustls = { version = "0.27", optional = true, default-features = false, features = ["http1", "http2", "rustls-native-certs", "native-tokio"] } hyper-tls = { version = "0.6.0", optional = true } log = "0.4" percent-encoding = "2" -rustls = { version = "^0.23", optional = true, default-features = false, features = ["ring", "std"] } +rustls = { version = "^0.23", optional = true, default-features = false, features = ["std"] } rustls-pemfile = { version = "2.0.0", optional = true } seahash = "4" serde = { version = "1.0", features = ["derive"] } diff --git a/src/authenticator.rs b/src/authenticator.rs index b1dcd4c7..80e60ad5 100644 --- a/src/authenticator.rs +++ b/src/authenticator.rs @@ -16,6 +16,10 @@ use crate::service_account::{self, ServiceAccountFlow, ServiceAccountFlowOpts, S use crate::storage::{self, Storage, TokenStorage}; use crate::types::{AccessToken, ApplicationSecret, TokenInfo}; use private::AuthFlow; +#[cfg(all(feature = "aws-lc-rs", feature = "hyper-rustls", not(feature = "ring")))] +use rustls::crypto::aws_lc_rs::default_provider as default_crypto_provider; +#[cfg(all(feature = "ring", feature = "hyper-rustls"))] +use rustls::crypto::ring::default_provider as default_crypto_provider; use crate::access_token::AccessTokenFlow; @@ -1003,7 +1007,7 @@ impl HyperClientBuilder for DefaultHyperClient { ) -> Result, Error> { #[cfg(feature = "hyper-rustls")] let connector = hyper_rustls::HttpsConnectorBuilder::new() - .with_provider_and_native_roots(rustls::crypto::ring::default_provider())? + .with_provider_and_native_roots(default_crypto_provider())? .https_or_http() .enable_http1() .enable_http2() @@ -1023,7 +1027,7 @@ impl HyperClientBuilder for DefaultHyperClient { ) -> hyper_util::client::legacy::Client { #[cfg(feature = "hyper-rustls")] let connector = hyper_rustls::HttpsConnectorBuilder::new() - .with_provider_and_native_roots(rustls::crypto::ring::default_provider()) + .with_provider_and_native_roots(default_crypto_provider()) .unwrap() .https_or_http() .enable_http1() diff --git a/src/service_account.rs b/src/service_account.rs index 46044ad2..6dc9d83b 100644 --- a/src/service_account.rs +++ b/src/service_account.rs @@ -23,7 +23,11 @@ use base64::Engine as _; use http::header; use http_body_util::BodyExt; use hyper_util::client::legacy::connect::Connect; -use rustls::{self, crypto::ring::sign, pki_types::PrivateKeyDer, sign::SigningKey}; +#[cfg(all(feature = "aws-lc-rs", not(feature = "ring")))] +use rustls::crypto::aws_lc_rs as crypto_provider; +#[cfg(feature = "ring")] +use rustls::crypto::ring as crypto_provider; +use rustls::{self, pki_types::PrivateKeyDer, sign::SigningKey}; use serde::{Deserialize, Serialize}; use time::OffsetDateTime; use url::form_urlencoded; @@ -125,7 +129,7 @@ pub(crate) struct JWTSigner { impl JWTSigner { fn new(private_key: &str) -> Result { let key = decode_rsa_key(private_key)?; - let signing_key = sign::RsaSigningKey::new(&key) + let signing_key = crypto_provider::sign::RsaSigningKey::new(&key) .map_err(|_| io::Error::new(io::ErrorKind::Other, "Couldn't initialize signer"))?; let signer = signing_key .choose_scheme(&[rustls::SignatureScheme::RSA_PKCS1_SHA256]) @@ -243,7 +247,7 @@ mod tests { hyper_util::client::legacy::Client::builder(hyper_util::rt::TokioExecutor::new()) .build( hyper_rustls::HttpsConnectorBuilder::new() - .with_provider_and_native_roots(rustls::crypto::ring::default_provider()) + .with_provider_and_native_roots(crypto_provider::default_provider()) .unwrap() .https_only() .enable_http1() diff --git a/tests/tests.rs b/tests/tests.rs index 40a8901c..845cd2a8 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -55,7 +55,6 @@ async fn create_device_flow_auth(server: &Server) -> DefaultAuthenticator { #[tokio::test] async fn test_device_success() { let _ = env_logger::try_init(); - let _ = rustls::crypto::ring::default_provider().install_default(); let server = Server::run(); server.expect( Expectation::matching(all_of![ @@ -103,7 +102,6 @@ async fn test_device_success() { #[tokio::test] async fn test_device_no_code() { let _ = env_logger::try_init(); - let _ = rustls::crypto::ring::default_provider().install_default(); let server = Server::run(); server.expect( Expectation::matching(all_of![ @@ -128,7 +126,6 @@ async fn test_device_no_code() { #[tokio::test] async fn test_device_no_token() { let _ = env_logger::try_init(); - let _ = rustls::crypto::ring::default_provider().install_default(); let server = Server::run(); server.expect( Expectation::matching(all_of![ @@ -242,7 +239,6 @@ async fn create_installed_flow_auth( #[tokio::test] async fn test_installed_interactive_success() { let _ = env_logger::try_init(); - let _ = rustls::crypto::ring::default_provider().install_default(); let server = Server::run(); let auth = create_installed_flow_auth(&server, InstalledFlowReturnMethod::Interactive, None).await; @@ -275,7 +271,6 @@ async fn test_installed_interactive_success() { #[tokio::test] async fn test_installed_redirect_success() { let _ = env_logger::try_init(); - let _ = rustls::crypto::ring::default_provider().install_default(); let server = Server::run(); let auth = create_installed_flow_auth(&server, InstalledFlowReturnMethod::HTTPRedirect, None).await; @@ -308,7 +303,6 @@ async fn test_installed_redirect_success() { #[tokio::test] async fn test_installed_error() { let _ = env_logger::try_init(); - let _ = rustls::crypto::ring::default_provider().install_default(); let server = Server::run(); let auth = create_installed_flow_auth(&server, InstalledFlowReturnMethod::Interactive, None).await; @@ -357,7 +351,6 @@ async fn create_service_account_auth(server: &Server) -> DefaultAuthenticator { async fn test_service_account_success() { use time::OffsetDateTime; let _ = env_logger::try_init(); - let _ = rustls::crypto::ring::default_provider().install_default(); let server = Server::run(); let auth = create_service_account_auth(&server).await; @@ -385,7 +378,6 @@ async fn test_service_account_success() { #[tokio::test] async fn test_service_account_error() { let _ = env_logger::try_init(); - let _ = rustls::crypto::ring::default_provider().install_default(); let server = Server::run(); let auth = create_service_account_auth(&server).await; server.expect( @@ -405,7 +397,6 @@ async fn test_service_account_error() { #[tokio::test] async fn test_refresh() { let _ = env_logger::try_init(); - let _ = rustls::crypto::ring::default_provider().install_default(); let server = Server::run(); let auth = create_installed_flow_auth(&server, InstalledFlowReturnMethod::Interactive, None).await; @@ -521,7 +512,6 @@ async fn test_refresh() { #[tokio::test] async fn test_memory_storage() { let _ = env_logger::try_init(); - let _ = rustls::crypto::ring::default_provider().install_default(); let server = Server::run(); let auth = create_installed_flow_auth(&server, InstalledFlowReturnMethod::Interactive, None).await; @@ -589,7 +579,6 @@ async fn test_memory_storage() { #[tokio::test] async fn test_disk_storage() { let _ = env_logger::try_init(); - let _ = rustls::crypto::ring::default_provider().install_default(); let server = Server::run(); let tempdir = tempfile::tempdir().unwrap(); let storage_path = tempdir.path().join("tokenstorage.json"); @@ -662,7 +651,6 @@ async fn test_disk_storage() { async fn test_default_application_credentials_from_metadata_server() { use yup_oauth2::authenticator::ApplicationDefaultCredentialsTypes; let _ = env_logger::try_init(); - let _ = rustls::crypto::ring::default_provider().install_default(); let server = Server::run(); server.expect( Expectation::matching(all_of![ From 05484d6c09dac8be36111dbf54034854c41ab0e5 Mon Sep 17 00:00:00 2001 From: threema-donat <129288638+threema-donat@users.noreply.github.com> Date: Wed, 12 Jun 2024 12:00:10 +0200 Subject: [PATCH 2/5] Rename feature service_account to service-account --- Cargo.toml | 9 +++++---- src/authenticator.rs | 26 +++++++++++++------------- src/helper.rs | 6 +++--- src/lib.rs | 6 +++--- src/service_account.rs | 2 +- 5 files changed, 25 insertions(+), 24 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index b361b075..2da7374b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,7 +16,7 @@ required-features = ["hyper-rustls", "ring"] [[example]] name = "custom_client" -required-features = ["hyper-rustls", "service_account", "ring"] +required-features = ["hyper-rustls", "service-account", "ring"] [[example]] name = "custom_storage" @@ -24,11 +24,12 @@ required-features = ["hyper-rustls", "ring"] [[test]] name = "tests" -required-features = ["hyper-rustls", "service_account"] +required-features = ["hyper-rustls", "service-account"] [features] -default = ["hyper-rustls", "rustls", "service_account", "ring"] -service_account = ["hyper-rustls", "rustls", "rustls-pemfile"] +default = ["hyper-rustls", "rustls", "service-account", "ring"] +service_account = ["service-account"] +service-account = ["hyper-rustls", "rustls", "rustls-pemfile"] hyper-rustls = ["dep:hyper-rustls", "rustls"] ring = ["rustls/ring", "hyper-rustls?/ring"] aws-lc-rs = ["rustls/aws_lc_rs", "hyper-rustls?/aws-lc-rs"] diff --git a/src/authenticator.rs b/src/authenticator.rs index 80e60ad5..7edf2ebd 100644 --- a/src/authenticator.rs +++ b/src/authenticator.rs @@ -11,7 +11,7 @@ use crate::installed::{InstalledFlow, InstalledFlowReturnMethod}; use crate::refresh::RefreshFlow; use crate::service_account_impersonator::ServiceAccountImpersonationFlow; -#[cfg(feature = "service_account")] +#[cfg(feature = "service-account")] use crate::service_account::{self, ServiceAccountFlow, ServiceAccountFlowOpts, ServiceAccountKey}; use crate::storage::{self, Storage, TokenStorage}; use crate::types::{AccessToken, ApplicationSecret, TokenInfo}; @@ -263,10 +263,10 @@ impl DeviceFlowAuthenticator { /// .expect("failed to create authenticator"); /// # } /// ``` -#[cfg(feature = "service_account")] +#[cfg(feature = "service-account")] pub struct ServiceAccountAuthenticator; -#[cfg(feature = "service_account")] +#[cfg(feature = "service-account")] impl ServiceAccountAuthenticator { /// Use the builder pattern to create an Authenticator that uses a service account. #[cfg(any(feature = "hyper-rustls", feature = "hyper-tls"))] @@ -297,7 +297,7 @@ impl ServiceAccountAuthenticator { /// Create an authenticator that uses a application default credentials. /// ``` -/// # #[cfg(all(any(feature = "hyper-rustls", feature = "hyper-tls"), feature = "service_account"))] +/// # #[cfg(all(any(feature = "hyper-rustls", feature = "hyper-tls"), feature = "service-account"))] /// # async fn foo() { /// # use yup_oauth2::ApplicationDefaultCredentialsAuthenticator; /// # use yup_oauth2::ApplicationDefaultCredentialsFlowOpts; @@ -319,7 +319,7 @@ impl ServiceAccountAuthenticator { pub struct ApplicationDefaultCredentialsAuthenticator; impl ApplicationDefaultCredentialsAuthenticator { /// Try to build ServiceAccountFlowOpts from the environment - #[cfg(feature = "service_account")] + #[cfg(feature = "service-account")] pub async fn from_environment() -> Result { let key_path = std::env::var("GOOGLE_APPLICATION_CREDENTIALS")?; @@ -331,7 +331,7 @@ impl ApplicationDefaultCredentialsAuthenticator { /// Use the builder pattern to deduce which model of authenticator should be used: /// Service account one or GCE instance metadata kind - #[cfg(feature = "service_account")] + #[cfg(feature = "service-account")] #[cfg(any(feature = "hyper-rustls", feature = "hyper-tls"))] #[cfg_attr( yup_oauth2_docsrs, @@ -344,7 +344,7 @@ impl ApplicationDefaultCredentialsAuthenticator { } /// Use the builder pattern to deduce which model of authenticator should be used and allow providing a hyper client - #[cfg(feature = "service_account")] + #[cfg(feature = "service-account")] pub async fn with_client( opts: ApplicationDefaultCredentialsFlowOpts, client: C, @@ -370,7 +370,7 @@ where C: HyperClientBuilder, { /// Service account based authenticator signature - #[cfg(feature = "service_account")] + #[cfg(feature = "service-account")] ServiceAccount(AuthenticatorBuilder), /// GCE Instance Metadata based authenticator signature InstanceMetadata(AuthenticatorBuilder), @@ -749,7 +749,7 @@ impl AuthenticatorBuilder { /// .expect("failed to create authenticator"); /// # } /// ``` -#[cfg(feature = "service_account")] +#[cfg(feature = "service-account")] impl AuthenticatorBuilder { /// Use the provided subject. pub fn subject(self, subject: impl Into) -> Self { @@ -875,7 +875,7 @@ mod private { use crate::error::Error; use crate::external_account::ExternalAccountFlow; use crate::installed::InstalledFlow; - #[cfg(feature = "service_account")] + #[cfg(feature = "service-account")] use crate::service_account::ServiceAccountFlow; use crate::service_account_impersonator::ServiceAccountImpersonationFlow; use crate::types::{ApplicationSecret, TokenInfo}; @@ -884,7 +884,7 @@ mod private { pub enum AuthFlow { DeviceFlow(DeviceFlow), InstalledFlow(InstalledFlow), - #[cfg(feature = "service_account")] + #[cfg(feature = "service-account")] ServiceAccountFlow(ServiceAccountFlow), ServiceAccountImpersonationFlow(ServiceAccountImpersonationFlow), ApplicationDefaultCredentialsFlow(ApplicationDefaultCredentialsFlow), @@ -898,7 +898,7 @@ mod private { match self { AuthFlow::DeviceFlow(device_flow) => Some(&device_flow.app_secret), AuthFlow::InstalledFlow(installed_flow) => Some(&installed_flow.app_secret), - #[cfg(feature = "service_account")] + #[cfg(feature = "service-account")] AuthFlow::ServiceAccountFlow(_) => None, AuthFlow::ServiceAccountImpersonationFlow(_) => None, AuthFlow::ApplicationDefaultCredentialsFlow(_) => None, @@ -922,7 +922,7 @@ mod private { AuthFlow::InstalledFlow(installed_flow) => { installed_flow.token(hyper_client, scopes).await } - #[cfg(feature = "service_account")] + #[cfg(feature = "service-account")] AuthFlow::ServiceAccountFlow(service_account_flow) => { service_account_flow.token(hyper_client, scopes).await } diff --git a/src/helper.rs b/src/helper.rs index 8a2970e7..8d4dc966 100644 --- a/src/helper.rs +++ b/src/helper.rs @@ -8,7 +8,7 @@ use crate::authorized_user::AuthorizedUserSecret; use crate::external_account::ExternalAccountSecret; use crate::types::{ApplicationSecret, ConsoleApplicationSecret}; -#[cfg(feature = "service_account")] +#[cfg(feature = "service-account")] use crate::service_account::ServiceAccountKey; use std::io; @@ -43,13 +43,13 @@ pub fn parse_application_secret>(secret: S) -> io::Result>(path: P) -> io::Result { let key = tokio::fs::read(path).await?; parse_service_account_key(key) } -#[cfg(feature = "service_account")] +#[cfg(feature = "service-account")] /// Read a service account key from a JSON string. pub fn parse_service_account_key>(key: S) -> io::Result { serde_json::from_slice(key.as_ref()).map_err(|e| { diff --git a/src/lib.rs b/src/lib.rs index 2e1f38ae..082aa1ad 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -85,7 +85,7 @@ mod installed; mod refresh; pub mod service_account_impersonator; -#[cfg(feature = "service_account")] +#[cfg(feature = "service-account")] mod service_account; /// Interface for storing tokens so that they can be re-used. There are built-in memory and @@ -99,7 +99,7 @@ pub use hyper; #[cfg(feature = "hyper-rustls")] pub use hyper_rustls; -#[cfg(feature = "service_account")] +#[cfg(feature = "service-account")] #[doc(inline)] pub use crate::authenticator::ServiceAccountAuthenticator; @@ -117,7 +117,7 @@ pub use crate::helper::*; pub use crate::installed::InstalledFlowReturnMethod; pub use crate::application_default_credentials::ApplicationDefaultCredentialsFlowOpts; -#[cfg(feature = "service_account")] +#[cfg(feature = "service-account")] pub use crate::service_account::ServiceAccountKey; #[doc(inline)] diff --git a/src/service_account.rs b/src/service_account.rs index 6dc9d83b..35493616 100644 --- a/src/service_account.rs +++ b/src/service_account.rs @@ -1,4 +1,4 @@ -#![cfg(feature = "service_account")] +#![cfg(feature = "service-account")] //! This module provides a flow that obtains tokens for service accounts. //! From 28813d8fdc2ede81a0e57ba16c7d5a460138236b Mon Sep 17 00:00:00 2001 From: threema-donat <129288638+threema-donat@users.noreply.github.com> Date: Wed, 12 Jun 2024 12:02:19 +0200 Subject: [PATCH 3/5] List feature hyper-tls in available features --- Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/Cargo.toml b/Cargo.toml index 2da7374b..6bac639a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,6 +33,7 @@ service-account = ["hyper-rustls", "rustls", "rustls-pemfile"] hyper-rustls = ["dep:hyper-rustls", "rustls"] ring = ["rustls/ring", "hyper-rustls?/ring"] aws-lc-rs = ["rustls/aws_lc_rs", "hyper-rustls?/aws-lc-rs"] +hyper-tls = ["dep:hyper-tls"] [dependencies] anyhow = "1.0.38" From a0c24b56c163293e8dca876e08cc05a9b10e9462 Mon Sep 17 00:00:00 2001 From: threema-donat <129288638+threema-donat@users.noreply.github.com> Date: Mon, 17 Jun 2024 16:31:00 +0200 Subject: [PATCH 4/5] Allow service account feature without hyper-rustls --- .github/workflows/test.yml | 4 ++-- Cargo.toml | 10 ++++++---- src/service_account.rs | 1 + 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index c62175ae..7bae34d3 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -11,8 +11,8 @@ jobs: matrix: features: ["service_account,hyper-rustls,ring", "service_account,hyper-rustls,aws-lc-rs", - "service_account,hyper-tls,ring", "service_account,hyper-tls,aws-lc-rs" - "service_account,ring", "hyper-rustls,ring"] + "service_account,hyper-tls,ring", "service_account,hyper-tls,aws-lc-rs", + "hyper-rustls,ring"] steps: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@stable diff --git a/Cargo.toml b/Cargo.toml index 6bac639a..aeafc9ff 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,13 +27,15 @@ name = "tests" required-features = ["hyper-rustls", "service-account"] [features] -default = ["hyper-rustls", "rustls", "service-account", "ring"] +default = ["hyper-rustls", "service-account", "ring"] service_account = ["service-account"] -service-account = ["hyper-rustls", "rustls", "rustls-pemfile"] -hyper-rustls = ["dep:hyper-rustls", "rustls"] +service-account = ["rustls-pemfile"] +hyper-rustls = ["dep:hyper-rustls", "__rustls"] ring = ["rustls/ring", "hyper-rustls?/ring"] aws-lc-rs = ["rustls/aws_lc_rs", "hyper-rustls?/aws-lc-rs"] -hyper-tls = ["dep:hyper-tls"] +hyper-tls = ["dep:hyper-tls", "__rustls"] +# hidden features +__rustls = ["dep:rustls"] [dependencies] anyhow = "1.0.38" diff --git a/src/service_account.rs b/src/service_account.rs index 35493616..3b66f4ff 100644 --- a/src/service_account.rs +++ b/src/service_account.rs @@ -234,6 +234,7 @@ mod tests { const TEST_PRIVATE_KEY_PATH: &str = "examples/Sanguine-69411a0c0eea.json"; // Uncomment this test to verify that we can successfully obtain tokens. + #[cfg(feature = "hyper-rustls")] // #[tokio::test] #[allow(dead_code)] async fn test_service_account_e2e() { From 310ea83a28a0e904415f64180f1c7c1763bb36f9 Mon Sep 17 00:00:00 2001 From: threema-donat <129288638+threema-donat@users.noreply.github.com> Date: Wed, 26 Jun 2024 10:18:14 +0200 Subject: [PATCH 5/5] Fix storage test --- src/storage.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/storage.rs b/src/storage.rs index e820cc2c..c3fc0067 100644 --- a/src/storage.rs +++ b/src/storage.rs @@ -445,7 +445,13 @@ mod tests { id_token: None, }; let scope_set = ScopeSet::from(&["myscope"]); - let tempdir = tempfile::tempdir().unwrap(); + + let tempdir = tempfile::Builder::new() + .prefix("yup-oauth2-tests_") + .rand_bytes(15) + .tempdir() + .unwrap(); + { let storage = DiskStorage::new(tempdir.path().join("tokenstorage.json")) .await