From 82e5b3165cb2d098aca88e8b99406d77fce05604 Mon Sep 17 00:00:00 2001 From: bodymindarts Date: Thu, 22 Aug 2024 09:36:58 +0200 Subject: [PATCH] Expose feature to use webpki certs --- Cargo.toml | 5 ++-- src/authenticator.rs | 64 +++++++++++++++++++++--------------------- src/client.rs | 27 +++++++++++------- src/error.rs | 3 ++ src/lib.rs | 8 +++--- src/service_account.rs | 2 +- 6 files changed, 60 insertions(+), 49 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 6347800a..0789c62e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,7 +30,8 @@ required-features = ["hyper-rustls", "service-account"] default = ["hyper-rustls", "service-account", "ring"] service_account = ["service-account"] service-account = ["rustls-pemfile"] -hyper-rustls = ["dep:hyper-rustls", "__rustls"] +hyper-rustls = ["dep:hyper-rustls", "hyper-rustls?/native-tokio", "__rustls"] +hyper-rustls-webpki = ["dep:hyper-rustls", "hyper-rustls?/webpki-tokio", "__rustls"] ring = ["rustls/ring", "hyper-rustls?/ring"] aws-lc-rs = ["rustls/aws_lc_rs", "hyper-rustls?/aws-lc-rs"] hyper-tls = ["dep:hyper-tls", "__rustls"] @@ -45,7 +46,7 @@ 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", "native-tokio"] } +hyper-rustls = { version = "0.27", optional = true, default-features = false, features = ["http1", "http2"] } hyper-tls = { version = "0.6.0", optional = true } log = "0.4" percent-encoding = "2" diff --git a/src/authenticator.rs b/src/authenticator.rs index 4e153b4c..b992a787 100644 --- a/src/authenticator.rs +++ b/src/authenticator.rs @@ -4,7 +4,7 @@ use crate::application_default_credentials::{ }; use crate::authenticator_delegate::{DeviceFlowDelegate, InstalledFlowDelegate}; use crate::authorized_user::{AuthorizedUserFlow, AuthorizedUserSecret}; -#[cfg(any(feature = "hyper-rustls", feature = "hyper-tls"))] +#[cfg(any(feature = "hyper-rustls", feature = "hyper-rustls-webpki", feature = "hyper-tls"))] use crate::client::DefaultHyperClientBuilder; use crate::client::{HttpClient, HyperClientBuilder}; use crate::device::DeviceFlow; @@ -185,7 +185,7 @@ pub struct AuthenticatorBuilder { /// Create an authenticator that uses the installed flow. /// ``` -/// # #[cfg(any(feature = "hyper-rustls", feature = "hyper-tls"))] +/// # #[cfg(any(feature = "hyper-rustls", feature = "hyper-rustls-webpki", feature = "hyper-tls"))] /// # async fn foo() { /// # use yup_oauth2::InstalledFlowReturnMethod; /// # let custom_flow_delegate = yup_oauth2::authenticator_delegate::DefaultInstalledFlowDelegate; @@ -202,8 +202,8 @@ pub struct AuthenticatorBuilder { pub struct InstalledFlowAuthenticator; impl InstalledFlowAuthenticator { /// Use the builder pattern to create an Authenticator that uses the installed flow. - #[cfg(any(feature = "hyper-rustls", feature = "hyper-tls"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "hyper-rustls", feature = "hyper-tls"))))] + #[cfg(any(feature = "hyper-rustls", feature = "hyper-rustls-webpki", feature = "hyper-tls"))] + #[cfg_attr(docsrs, doc(cfg(any(feature = "hyper-rustls", feature = "hyper-rustls-webpki", feature = "hyper-tls"))))] pub fn builder( app_secret: ApplicationSecret, method: InstalledFlowReturnMethod, @@ -223,7 +223,7 @@ impl InstalledFlowAuthenticator { /// Create an authenticator that uses the device flow. /// ``` -/// # #[cfg(any(feature = "hyper-rustls", feature = "hyper-tls"))] +/// # #[cfg(any(feature = "hyper-rustls", feature = "hyper-tls", feature = "hyper-rustls-webpki" ))] /// # async fn foo() { /// # let app_secret = yup_oauth2::read_application_secret("/tmp/foo").await.unwrap(); /// let authenticator = yup_oauth2::DeviceFlowAuthenticator::builder(app_secret) @@ -235,8 +235,8 @@ impl InstalledFlowAuthenticator { pub struct DeviceFlowAuthenticator; impl DeviceFlowAuthenticator { /// Use the builder pattern to create an Authenticator that uses the device flow. - #[cfg(any(feature = "hyper-rustls", feature = "hyper-tls"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "hyper-rustls", feature = "hyper-tls"))))] + #[cfg(any(feature = "hyper-rustls", feature = "hyper-tls", feature = "hyper-rustls-webpki"))] + #[cfg_attr(docsrs, doc(cfg(any(feature = "hyper-rustls", feature = "hyper-tls", feature = "hyper-rustls-webpki"))))] pub fn builder( app_secret: ApplicationSecret, ) -> AuthenticatorBuilder { @@ -254,7 +254,7 @@ impl DeviceFlowAuthenticator { /// Create an authenticator that uses a service account. /// ``` -/// # #[cfg(any(feature = "hyper-rustls", feature = "hyper-tls"))] +/// # #[cfg(any(feature = "hyper-rustls", feature = "hyper-tls", feature = "hyper-rustls-webpki"))] /// # async fn foo() { /// # let service_account_key = yup_oauth2::read_service_account_key("/tmp/foo").await.unwrap(); /// let authenticator = yup_oauth2::ServiceAccountAuthenticator::builder(service_account_key) @@ -269,8 +269,8 @@ pub struct ServiceAccountAuthenticator; #[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"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "hyper-rustls", feature = "hyper-tls"))))] + #[cfg(any(feature = "hyper-rustls", feature = "hyper-tls", feature = "hyper-rustls-webpki"))] + #[cfg_attr(docsrs, doc(cfg(any(feature = "hyper-rustls", feature = "hyper-tls", feature = "hyper-rustls-webpki"))))] pub fn builder( service_account_key: ServiceAccountKey, ) -> AuthenticatorBuilder { @@ -294,7 +294,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 = "hyper-rustls-webpki"), feature = "service-account"))] /// # async fn foo() { /// # use yup_oauth2::ApplicationDefaultCredentialsAuthenticator; /// # use yup_oauth2::ApplicationDefaultCredentialsFlowOpts; @@ -329,8 +329,8 @@ 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(any(feature = "hyper-rustls", feature = "hyper-tls"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "hyper-rustls", feature = "hyper-tls"))))] + #[cfg(any(feature = "hyper-rustls", feature = "hyper-tls", feature = "hyper-rustls-webpki"))] + #[cfg_attr(docsrs, doc(cfg(any(feature = "hyper-rustls", feature = "hyper-tls", feature = "hyper-rustls-webpki"))))] pub async fn builder( opts: ApplicationDefaultCredentialsFlowOpts, ) -> ApplicationDefaultCredentialsTypes { @@ -372,7 +372,7 @@ where /// Create an authenticator that uses an authorized user credentials. /// ``` -/// # #[cfg(any(feature = "hyper-rustls", feature = "hyper-tls"))] +/// # #[cfg(any(feature = "hyper-rustls", feature = "hyper-tls", feature = "hyper-rustls-webpki"))] /// # async fn foo() { /// # use yup_oauth2::authenticator::AuthorizedUserAuthenticator; /// # let secret = yup_oauth2::read_authorized_user_secret("/tmp/foo").await.unwrap(); @@ -385,8 +385,8 @@ where pub struct AuthorizedUserAuthenticator; impl AuthorizedUserAuthenticator { /// Use the builder pattern to create an Authenticator that uses an authorized user. - #[cfg(any(feature = "hyper-rustls", feature = "hyper-tls"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "hyper-rustls", feature = "hyper-tls"))))] + #[cfg(any(feature = "hyper-rustls", feature = "hyper-tls", feature = "hyper-rustls-webpki"))] + #[cfg_attr(docsrs, doc(cfg(any(feature = "hyper-rustls", feature = "hyper-tls", feature = "hyper-rustls-webpki"))))] pub fn builder( authorized_user_secret: AuthorizedUserSecret, ) -> AuthenticatorBuilder { @@ -409,7 +409,7 @@ impl AuthorizedUserAuthenticator { /// Create an authenticator that uses an external account credentials. /// ``` -/// # #[cfg(any(feature = "hyper-rustls", feature = "hyper-tls"))] +/// # #[cfg(any(feature = "hyper-rustls", feature = "hyper-tls", feature = "hyper-rustls-webpki"))] /// # async fn foo() { /// # use yup_oauth2::authenticator::ExternalAccountAuthenticator; /// # let secret = yup_oauth2::read_external_account_secret("/tmp/foo").await.unwrap(); @@ -422,8 +422,8 @@ impl AuthorizedUserAuthenticator { pub struct ExternalAccountAuthenticator; impl ExternalAccountAuthenticator { /// Use the builder pattern to create an Authenticator that uses an external account. - #[cfg(any(feature = "hyper-rustls", feature = "hyper-tls"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "hyper-rustls", feature = "hyper-tls"))))] + #[cfg(any(feature = "hyper-rustls", feature = "hyper-tls", feature = "hyper-rustls-webpki"))] + #[cfg_attr(docsrs, doc(cfg(any(feature = "hyper-rustls", feature = "hyper-tls", feature = "hyper-rustls-webpki"))))] pub fn builder( external_account_secret: ExternalAccountSecret, ) -> AuthenticatorBuilder { @@ -458,10 +458,10 @@ impl ExternalAccountAuthenticator { /// # .expect("failed to create authenticator"); /// # } /// ``` -#[cfg(any(feature = "hyper-rustls", feature = "hyper-tls"))] +#[cfg(any(feature = "hyper-rustls", feature = "hyper-tls", feature = "hyper-rustls-webpki"))] pub struct AccessTokenAuthenticator; -#[cfg(any(feature = "hyper-rustls", feature = "hyper-tls"))] +#[cfg(any(feature = "hyper-rustls", feature = "hyper-tls", feature = "hyper-rustls-webpki"))] impl AccessTokenAuthenticator { /// the builder pattern for the authenticator pub fn builder( @@ -483,7 +483,7 @@ impl AccessTokenAuthenticator { /// a service account. /// /// ``` -/// # #[cfg(any(feature = "hyper-rustls", feature = "hyper-tls"))] +/// # #[cfg(any(feature = "hyper-rustls", feature = "hyper-tls", feature = "hyper-rustls-webpki"))] /// # async fn foo() { /// # use yup_oauth2::authenticator::AuthorizedUserAuthenticator; /// # let secret = yup_oauth2::read_authorized_user_secret("/tmp/foo").await.unwrap(); @@ -497,8 +497,8 @@ impl AccessTokenAuthenticator { pub struct ServiceAccountImpersonationAuthenticator; impl ServiceAccountImpersonationAuthenticator { /// Use the builder pattern to create an Authenticator that uses the device flow. - #[cfg(any(feature = "hyper-rustls", feature = "hyper-tls"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "hyper-rustls", feature = "hyper-tls"))))] + #[cfg(any(feature = "hyper-rustls", feature = "hyper-tls", feature = "hyper-rustls-webpki"))] + #[cfg_attr(docsrs, doc(cfg(any(feature = "hyper-rustls", feature = "hyper-tls", feature = "hyper-rustls-webpki"))))] pub fn builder( authorized_user_secret: AuthorizedUserSecret, service_account_email: &str, @@ -608,7 +608,7 @@ where /// ## Methods available when building a device flow Authenticator. /// ``` -/// # #[cfg(any(feature = "hyper-rustls", feature = "hyper-tls"))] +/// # #[cfg(any(feature = "hyper-rustls", feature = "hyper-tls", feature = "hyper-rustls-webpki"))] /// # async fn foo() { /// # let custom_flow_delegate = yup_oauth2::authenticator_delegate::DefaultDeviceFlowDelegate; /// # let app_secret = yup_oauth2::read_application_secret("/tmp/foo").await.unwrap(); @@ -671,7 +671,7 @@ impl AuthenticatorBuilder { /// ## Methods available when building an installed flow Authenticator. /// ``` -/// # #[cfg(any(feature = "hyper-rustls", feature = "hyper-tls"))] +/// # #[cfg(any(feature = "hyper-rustls", feature = "hyper-tls", feature = "hyper-rustls-webpki"))] /// # async fn foo() { /// # use yup_oauth2::InstalledFlowReturnMethod; /// # let custom_flow_delegate = yup_oauth2::authenticator_delegate::DefaultInstalledFlowDelegate; @@ -724,7 +724,7 @@ impl AuthenticatorBuilder { /// ## Methods available when building a service account authenticator. /// ``` -/// # #[cfg(any(feature = "hyper-rustls", feature = "hyper-tls"))] +/// # #[cfg(any(feature = "hyper-rustls", feature = "hyper-tls", feature = "hyper-rustls-webpki"))] /// # async fn foo() { /// # let service_account_key = yup_oauth2::read_service_account_key("/tmp/foo").await.unwrap(); /// let authenticator = yup_oauth2::ServiceAccountAuthenticator::builder( @@ -934,14 +934,14 @@ mod private { } } -#[cfg(feature = "hyper-rustls")] -#[cfg_attr(docsrs, doc(cfg(any(feature = "hyper-rustls", feature = "hyper-tls"))))] +#[cfg(any(feature = "hyper-rustls", feature = "hyper-rustls-webpki"))] +#[cfg_attr(docsrs, doc(cfg(any(feature = "hyper-rustls", feature = "hyper-tls", feature = "hyper-rustls-webpki"))))] /// Default authenticator type pub type DefaultAuthenticator = Authenticator>; -#[cfg(all(not(feature = "hyper-rustls"), feature = "hyper-tls"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "hyper-rustls", feature = "hyper-tls"))))] +#[cfg(all(not(feature = "hyper-rustls"), not(feature = "hyper-rustls-webpki"), feature = "hyper-tls"))] +#[cfg_attr(docsrs, doc(cfg(any(feature = "hyper-rustls", feature = "hyper-tls", feature = "hyper-rustls-webpki" ))))] /// Default authenticator type pub type DefaultAuthenticator = Authenticator>; @@ -959,7 +959,7 @@ enum StorageType { #[cfg(test)] mod tests { #[test] - #[cfg(any(feature = "hyper-rustls", feature = "hyper-tls"))] + #[cfg(any(feature = "hyper-rustls", feature = "hyper-tls", feature = "hyper-rustls-webpki"))] fn ensure_send_sync() { use super::*; fn is_send_sync() {} diff --git a/src/client.rs b/src/client.rs index 5f76544c..4deae551 100644 --- a/src/client.rs +++ b/src/client.rs @@ -4,9 +4,9 @@ use std::time::Duration; use futures::TryFutureExt; use http::Uri; use hyper_util::client::legacy::{connect::Connect, Error as LegacyHyperError}; -#[cfg(all(feature = "aws-lc-rs", feature = "hyper-rustls", not(feature = "ring")))] +#[cfg(all(feature = "aws-lc-rs", any(feature = "hyper-rustls", feature = "hyper-rustls-webpki"), not(feature = "ring")))] use rustls::crypto::aws_lc_rs::default_provider as default_crypto_provider; -#[cfg(all(feature = "ring", feature = "hyper-rustls"))] +#[cfg(all(feature = "ring", any(feature = "hyper-rustls", feature = "hyper-rustls-webpki")))] use rustls::crypto::ring::default_provider as default_crypto_provider; use thiserror::Error as ThisError; @@ -110,14 +110,14 @@ pub(crate) trait SendRequest { } /// The builder value used when the default hyper client should be used. -#[cfg(any(feature = "hyper-rustls", feature = "hyper-tls"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "hyper-rustls", feature = "hyper-tls"))))] +#[cfg(any(feature = "hyper-rustls", feature = "hyper-tls", feature = "hyper-rustls-webpki"))] +#[cfg_attr(docsrs, doc(cfg(any(feature = "hyper-rustls", feature = "hyper-tls", feature = "hyper-rustls-webpki"))))] #[derive(Default)] pub struct DefaultHyperClientBuilder { timeout: Option, } -#[cfg(any(feature = "hyper-rustls", feature = "hyper-tls"))] +#[cfg(any(feature = "hyper-rustls", feature = "hyper-tls", feature = "hyper-rustls-webpki"))] impl DefaultHyperClientBuilder { /// Set the duration after which a request times out pub fn with_timeout(mut self, timeout: Duration) -> Self { @@ -126,13 +126,13 @@ impl DefaultHyperClientBuilder { } } -#[cfg(any(feature = "hyper-rustls", feature = "hyper-tls"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "hyper-rustls", feature = "hyper-tls"))))] +#[cfg(any(feature = "hyper-rustls", feature = "hyper-tls", feature = "hyper-rustls-webpki"))] +#[cfg_attr(docsrs, doc(cfg(any(feature = "hyper-rustls", feature = "hyper-tls", feature = "hyper-rustls-webpki"))))] impl HyperClientBuilder for DefaultHyperClientBuilder { - #[cfg(feature = "hyper-rustls")] + #[cfg(any(feature = "hyper-rustls", feature = "hyper-rustls-webpki"))] type Connector = hyper_rustls::HttpsConnector; - #[cfg(all(not(feature = "hyper-rustls"), feature = "hyper-tls"))] + #[cfg(all(not(feature = "hyper-rustls"), not(feature = "hyper-rustls-webpki"), feature = "hyper-tls"))] type Connector = hyper_tls::HttpsConnector; fn with_timeout(mut self, timeout: Duration) -> Self { @@ -148,7 +148,14 @@ impl HyperClientBuilder for DefaultHyperClientBuilder { .enable_http1() .enable_http2() .build(); - #[cfg(all(not(feature = "hyper-rustls"), feature = "hyper-tls"))] + #[cfg(feature = "hyper-rustls-webpki")] + let connector = hyper_rustls::HttpsConnectorBuilder::new() + .with_provider_and_webpki_roots(default_crypto_provider())? + .https_or_http() + .enable_http1() + .enable_http2() + .build(); + #[cfg(all(not(feature = "hyper-rustls"), not(feature = "hyper-rustls-webpki"), feature = "hyper-tls"))] let connector = hyper_tls::HttpsConnector::new(); Ok(HttpClient::new( diff --git a/src/error.rs b/src/error.rs index f3961c97..d77df1ef 100644 --- a/src/error.rs +++ b/src/error.rs @@ -168,6 +168,9 @@ pub enum Error { /// A lower level IO error. #[error("Low level error: {0}")] LowLevelError(#[from] io::Error), + /// A lower level IO error. + #[error("Rustls error: {0}")] + RustlsError(#[from] rustls::Error), /// We required an access token, but received a response that didn't contain one. #[error("Expected an access token, but received a response without one")] MissingAccessToken, diff --git a/src/lib.rs b/src/lib.rs index 46b940b4..b6534cb5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -39,7 +39,7 @@ //! ```test_harness,no_run //! use yup_oauth2::{InstalledFlowAuthenticator, InstalledFlowReturnMethod}; //! -//! # #[cfg(any(feature = "hyper-rustls", feature = "hyper-tls"))] +//! # #[cfg(any(feature = "hyper-rustls", feature = "hyper-tls", feature = "hyper-rustls-webpki"))] //! #[tokio::main] //! async fn main() { //! // Read application secret from a file. Sometimes it's easier to compile it directly into @@ -97,17 +97,17 @@ mod types; pub use hyper; -#[cfg(feature = "hyper-rustls")] +#[cfg(any(feature = "hyper-rustls", feature = "hyper-rustls-webpki"))] pub use hyper_rustls; #[cfg(feature = "service-account")] #[doc(inline)] pub use crate::authenticator::ServiceAccountAuthenticator; -#[cfg(any(feature = "hyper-rustls", feature = "hyper-tls"))] +#[cfg(any(feature = "hyper-rustls", feature = "hyper-rustls-webpki", feature = "hyper-tls"))] pub use crate::authenticator::AccessTokenAuthenticator; -#[cfg(any(feature = "hyper-rustls", feature = "hyper-tls"))] +#[cfg(any(feature = "hyper-rustls", feature = "hyper-rustls-webpki", feature = "hyper-tls"))] pub use crate::client::DefaultHyperClientBuilder; pub use crate::client::{CustomHyperClientBuilder, HttpClient, HyperClientBuilder}; diff --git a/src/service_account.rs b/src/service_account.rs index 02b047df..b2d1507f 100644 --- a/src/service_account.rs +++ b/src/service_account.rs @@ -231,7 +231,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")] + #[cfg(any(feature = "hyper-rustls", feature = "hyper-rustls-webpki"))] // #[tokio::test] #[allow(dead_code)] async fn test_service_account_e2e() {