Skip to content

Commit

Permalink
Merge pull request #152 from nagisa/nagisa/features
Browse files Browse the repository at this point in the history
--all-features and --no-default-features
  • Loading branch information
dermesser authored Jun 30, 2021
2 parents e63aa4b + 469f045 commit ac0e5f6
Show file tree
Hide file tree
Showing 9 changed files with 196 additions and 62 deletions.
26 changes: 23 additions & 3 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,37 @@ name: Actions CI

jobs:
build_and_test:
name: yup-oauth2
name: yup-oauth2
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
features: ["hyper-rustls", "hyper-tls", "hyper-rustls,hyper-tls", ""]
steps:
- uses: actions/checkout@v2
- uses: actions-rs/toolchain@v1
with:
toolchain: stable
profile: minimal
default: true
- uses: actions-rs/cargo@v1
with:
command: test
args: --no-default-features --features=${{ matrix.features }}

doc:
name: yup-oauth2
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions-rs/toolchain@v1
with:
toolchain: nightly
profile: minimal
default: true
- uses: actions-rs/cargo@v1
with:
command: build
args: --examples
command: doc
args: --all-features
env:
RUSTDOCFLAGS: --cfg yup_oauth2_docsrs
17 changes: 17 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,18 @@ keywords = ["google", "oauth", "v2"]
license = "MIT OR Apache-2.0"
edition = "2018"

[[example]]
name = "custom_flow"
required-features = ["hyper-rustls"]

[[example]]
name = "custom_storage"
required-features = ["hyper-rustls"]

[[test]]
name = "tests"
required-features = ["hyper-rustls"]

[features]
default = ["hyper-rustls"]

Expand Down Expand Up @@ -38,6 +50,11 @@ httptest = "0.14"
env_logger = "0.7"
tempfile = "3.1"
webbrowser = "0.5"
hyper-rustls = "0.22.1"

[workspace]
members = ["examples/test-installed/", "examples/test-svc-acct/", "examples/test-device/", "examples/service_account", "examples/drive_example"]

[package.metadata.docs.rs]
all-features = true
rustdoc-args = ["--cfg", "yup_oauth2_docsrs"]
43 changes: 43 additions & 0 deletions examples/custom_client.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
//! This example demonstrates how to use the same connection pool for both obtaining the tokens and
//! using the API that these tokens authorize. In most cases e.g. obtaining the service account key
//! will already establish a keep-alive http connection, so the succeeding API call should be much
//! faster.
//!
//! It is also a better use of resources (memory, sockets, etc.)
async fn r#use<C>(
client: hyper::Client<C>,
authenticator: yup_oauth2::authenticator::Authenticator<C>,
) -> Result<(), Box<dyn std::error::Error + Send + Sync>>
where
C: Clone + Send + Sync + hyper::client::connect::Connect + 'static,
{
let token = authenticator.token(&["email"]).await?;
let request = http::Request::get("https://example.com")
.header(
http::header::AUTHORIZATION,
format!("Bearer {}", token.as_str()),
)
.body(hyper::body::Body::empty())?;
let response = client.request(request).await?;
drop(response); // Implementing handling of the response is left as an exercise for the reader.
Ok(())
}

#[tokio::main]
async fn main() {
let google_credentials = std::env::var("GOOGLE_APPLICATION_CREDENTIALS")
.expect("env var GOOGLE_APPLICATION_CREDENTIALS is required");
let secret = yup_oauth2::read_service_account_key(google_credentials)
.await
.expect("$GOOGLE_APPLICATION_CREDENTIALS is not a valid service account key");
let client = hyper::Client::builder().build(hyper_rustls::HttpsConnector::with_native_roots());
let authenticator =
yup_oauth2::ServiceAccountAuthenticator::with_client(secret, client.clone())
.build()
.await
.expect("could not create an authenticator");
r#use(client, authenticator)
.await
.expect("use is successful!");
}
104 changes: 86 additions & 18 deletions src/authenticator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ pub struct AuthenticatorBuilder<C, F> {

/// Create an authenticator that uses the installed flow.
/// ```
/// # #[cfg(any(feature = "hyper-rustls", feature = "hyper-tls"))]
/// # async fn foo() {
/// # use yup_oauth2::InstalledFlowReturnMethod;
/// # let custom_flow_delegate = yup_oauth2::authenticator_delegate::DefaultInstalledFlowDelegate;
Expand All @@ -157,18 +158,31 @@ pub struct AuthenticatorBuilder<C, F> {
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(
yup_oauth2_docsrs,
doc(cfg(any(feature = "hyper-rustls", feature = "hyper-tls")))
)]
pub fn builder(
app_secret: ApplicationSecret,
method: InstalledFlowReturnMethod,
) -> AuthenticatorBuilder<DefaultHyperClient, InstalledFlow> {
AuthenticatorBuilder::<DefaultHyperClient, _>::with_auth_flow(InstalledFlow::new(
app_secret, method,
))
Self::with_client(app_secret, method, DefaultHyperClient)
}

/// Construct a new Authenticator that uses the installed flow and the provided http client.
pub fn with_client<C>(
app_secret: ApplicationSecret,
method: InstalledFlowReturnMethod,
client: C,
) -> AuthenticatorBuilder<C, InstalledFlow> {
AuthenticatorBuilder::new(InstalledFlow::new(app_secret, method), client)
}
}

/// Create an authenticator that uses the device flow.
/// ```
/// # #[cfg(any(feature = "hyper-rustls", feature = "hyper-tls"))]
/// # async fn foo() {
/// # let app_secret = yup_oauth2::read_application_secret("/tmp/foo").await.unwrap();
/// let authenticator = yup_oauth2::DeviceFlowAuthenticator::builder(app_secret)
Expand All @@ -180,15 +194,29 @@ 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(
yup_oauth2_docsrs,
doc(cfg(any(feature = "hyper-rustls", feature = "hyper-tls")))
)]
pub fn builder(
app_secret: ApplicationSecret,
) -> AuthenticatorBuilder<DefaultHyperClient, DeviceFlow> {
AuthenticatorBuilder::<DefaultHyperClient, _>::with_auth_flow(DeviceFlow::new(app_secret))
Self::with_client(app_secret, DefaultHyperClient)
}

/// Construct a new Authenticator that uses the installed flow and the provided http client.
pub fn with_client<C>(
app_secret: ApplicationSecret,
client: C,
) -> AuthenticatorBuilder<C, DeviceFlow> {
AuthenticatorBuilder::new(DeviceFlow::new(app_secret), client)
}
}

/// Create an authenticator that uses a service account.
/// ```
/// # #[cfg(any(feature = "hyper-rustls", feature = "hyper-tls"))]
/// # 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)
Expand All @@ -200,18 +228,35 @@ impl DeviceFlowAuthenticator {
pub struct ServiceAccountAuthenticator;
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(
yup_oauth2_docsrs,
doc(cfg(any(feature = "hyper-rustls", feature = "hyper-tls")))
)]
pub fn builder(
service_account_key: ServiceAccountKey,
) -> AuthenticatorBuilder<DefaultHyperClient, ServiceAccountFlowOpts> {
AuthenticatorBuilder::<DefaultHyperClient, _>::with_auth_flow(ServiceAccountFlowOpts {
key: service_account_key,
subject: None,
})
Self::with_client(service_account_key, DefaultHyperClient)
}

/// Construct a new Authenticator that uses the installed flow and the provided http client.
pub fn with_client<C>(
service_account_key: ServiceAccountKey,
client: C,
) -> AuthenticatorBuilder<C, ServiceAccountFlowOpts> {
AuthenticatorBuilder::new(
ServiceAccountFlowOpts {
key: service_account_key,
subject: None,
},
client,
)
}
}

/// ## Methods available when building any Authenticator.
/// ```
/// # #[cfg(any(feature = "hyper-rustls", feature = "hyper-tls"))]
/// # async fn foo() {
/// # let custom_hyper_client = hyper::Client::new();
/// # let app_secret = yup_oauth2::read_application_secret("/tmp/foo").await.unwrap();
Expand Down Expand Up @@ -250,9 +295,9 @@ impl<C, F> AuthenticatorBuilder<C, F> {
})
}

fn with_auth_flow(auth_flow: F) -> AuthenticatorBuilder<DefaultHyperClient, F> {
fn new(auth_flow: F, hyper_client_builder: C) -> AuthenticatorBuilder<C, F> {
AuthenticatorBuilder {
hyper_client_builder: DefaultHyperClient,
hyper_client_builder,
storage_type: StorageType::Memory,
auth_flow,
}
Expand Down Expand Up @@ -289,6 +334,7 @@ impl<C, F> AuthenticatorBuilder<C, F> {

/// ## Methods available when building a device flow Authenticator.
/// ```
/// # #[cfg(any(feature = "hyper-rustls", feature = "hyper-tls"))]
/// # async fn foo() {
/// # let custom_flow_delegate = yup_oauth2::authenticator_delegate::DefaultDeviceFlowDelegate;
/// # let app_secret = yup_oauth2::read_application_secret("/tmp/foo").await.unwrap();
Expand Down Expand Up @@ -351,6 +397,7 @@ impl<C> AuthenticatorBuilder<C, DeviceFlow> {

/// ## Methods available when building an installed flow Authenticator.
/// ```
/// # #[cfg(any(feature = "hyper-rustls", feature = "hyper-tls"))]
/// # async fn foo() {
/// # use yup_oauth2::InstalledFlowReturnMethod;
/// # let custom_flow_delegate = yup_oauth2::authenticator_delegate::DefaultInstalledFlowDelegate;
Expand Down Expand Up @@ -393,6 +440,7 @@ impl<C> AuthenticatorBuilder<C, InstalledFlow> {

/// ## Methods available when building a service account authenticator.
/// ```
/// # #[cfg(any(feature = "hyper-rustls", feature = "hyper-tls"))]
/// # async fn foo() {
/// # let service_account_key = yup_oauth2::read_service_account_key("/tmp/foo").await.unwrap();
/// let authenticator = yup_oauth2::ServiceAccountAuthenticator::builder(
Expand Down Expand Up @@ -484,27 +532,47 @@ pub trait HyperClientBuilder {
fn build_hyper_client(self) -> hyper::Client<Self::Connector>;
}

#[cfg(not(feature = "hyper-tls"))]
#[cfg(feature = "hyper-rustls")]
#[cfg_attr(
yup_oauth2_docsrs,
doc(cfg(any(feature = "hyper-rustls", feature = "hyper-tls")))
)]
/// Default authenticator type
pub type DefaultAuthenticator =
Authenticator<hyper_rustls::HttpsConnector<hyper::client::HttpConnector>>;
#[cfg(feature = "hyper-tls")]

#[cfg(all(not(feature = "hyper-rustls"), feature = "hyper-tls"))]
#[cfg_attr(
yup_oauth2_docsrs,
doc(cfg(any(feature = "hyper-rustls", feature = "hyper-tls")))
)]
/// Default authenticator type
pub type DefaultAuthenticator =
Authenticator<hyper_tls::HttpsConnector<hyper::client::HttpConnector>>;

/// The builder value used when the default hyper client should be used.
#[cfg(any(feature = "hyper-rustls", feature = "hyper-tls"))]
#[cfg_attr(
yup_oauth2_docsrs,
doc(cfg(any(feature = "hyper-rustls", feature = "hyper-tls")))
)]
pub struct DefaultHyperClient;

#[cfg(any(feature = "hyper-rustls", feature = "hyper-tls"))]
#[cfg_attr(
yup_oauth2_docsrs,
doc(cfg(any(feature = "hyper-rustls", feature = "hyper-tls")))
)]
impl HyperClientBuilder for DefaultHyperClient {
#[cfg(not(feature = "hyper-tls"))]
#[cfg(feature = "hyper-rustls")]
type Connector = hyper_rustls::HttpsConnector<hyper::client::connect::HttpConnector>;
#[cfg(feature = "hyper-tls")]
#[cfg(all(not(feature = "hyper-rustls"), feature = "hyper-tls"))]
type Connector = hyper_tls::HttpsConnector<hyper::client::connect::HttpConnector>;

fn build_hyper_client(self) -> hyper::Client<Self::Connector> {
#[cfg(not(feature = "hyper-tls"))]
#[cfg(feature = "hyper-rustls")]
let connector = hyper_rustls::HttpsConnector::with_native_roots();
#[cfg(feature = "hyper-tls")]
#[cfg(all(not(feature = "hyper-rustls"), feature = "hyper-tls"))]
let connector = hyper_tls::HttpsConnector::new();

hyper::Client::builder()
Expand Down Expand Up @@ -536,10 +604,10 @@ enum StorageType {

#[cfg(test)]
mod tests {
use super::*;

#[test]
#[cfg(any(feature = "hyper-rustls", feature = "hyper-tls"))]
fn ensure_send_sync() {
use super::*;
fn is_send_sync<T: Send + Sync>() {}
is_send_sync::<Authenticator<<DefaultHyperClient as HyperClientBuilder>::Connector>>()
}
Expand Down
5 changes: 3 additions & 2 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@ use std::io;
use serde::Deserialize;

/// Error returned by the authorization server.
/// https://tools.ietf.org/html/rfc6749#section-5.2
/// https://tools.ietf.org/html/rfc8628#section-3.5
///
/// <https://tools.ietf.org/html/rfc6749#section-5.2>
/// <https://tools.ietf.org/html/rfc8628#section-3.5>
#[derive(Deserialize, Debug, PartialEq, Eq)]
pub struct AuthError {
/// Error code from the server.
Expand Down
8 changes: 5 additions & 3 deletions src/installed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,9 @@ where
})
}

/// cf. https://developers.google.com/identity/protocols/OAuth2InstalledApp#choosingredirecturi
/// Method by which the user agent return token to this application.
///
/// cf. <https://developers.google.com/identity/protocols/OAuth2InstalledApp#choosingredirecturi>
pub enum InstalledFlowReturnMethod {
/// Involves showing a URL to the user and asking to copy a code from their browser
/// (default)
Expand All @@ -71,8 +73,8 @@ pub enum InstalledFlowReturnMethod {
}

/// InstalledFlowImpl provides tokens for services that follow the "Installed" OAuth flow. (See
/// https://www.oauth.com/oauth2-servers/authorization/,
/// https://developers.google.com/identity/protocols/OAuth2InstalledApp).
/// <https://www.oauth.com/oauth2-servers/authorization/>,
/// <https://developers.google.com/identity/protocols/OAuth2InstalledApp>).
pub struct InstalledFlow {
pub(crate) app_secret: ApplicationSecret,
pub(crate) method: InstalledFlowReturnMethod,
Expand Down
3 changes: 3 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
//! ```test_harness,no_run
//! use yup_oauth2::{InstalledFlowAuthenticator, InstalledFlowReturnMethod};
//!
//! # #[cfg(any(feature = "hyper-rustls", feature = "hyper-tls"))]
//! #[tokio::main]
//! async fn main() {
//! // Read application secret from a file. Sometimes it's easier to compile it directly into
Expand Down Expand Up @@ -69,6 +70,8 @@
//! ```
//!
#![deny(missing_docs)]
#![cfg_attr(yup_oauth2_docsrs, feature(doc_cfg))]

pub mod authenticator;
pub mod authenticator_delegate;
mod device;
Expand Down
Loading

0 comments on commit ac0e5f6

Please sign in to comment.