Improve documentation

This commit is contained in:
Glenn Griffin
2019-11-13 15:43:16 -08:00
parent e5aa32b3cf
commit ca453c056c
6 changed files with 156 additions and 49 deletions

View File

@@ -1,3 +1,4 @@
//! Module contianing the core functionality for OAuth2 Authentication.
use crate::authenticator_delegate::{
AuthenticatorDelegate, DefaultAuthenticatorDelegate, FlowDelegate,
};
@@ -15,6 +16,8 @@ use std::path::PathBuf;
use std::sync::Mutex;
use std::time::Duration;
/// Authenticator is responsible for fetching tokens, handling refreshing tokens,
/// and optionally persisting tokens to disk.
pub struct Authenticator<C> {
hyper_client: hyper::Client<C>,
app_secret: ApplicationSecret,
@@ -27,6 +30,7 @@ impl<C> Authenticator<C>
where
C: hyper::client::connect::Connect + 'static,
{
/// Return the current token for the provided scopes.
pub async fn token<'a, T>(&'a self, scopes: &'a [T]) -> Result<Token, Error>
where
T: AsRef<str>,
@@ -77,6 +81,7 @@ where
}
}
/// Configure an Authenticator using the builder pattern.
pub struct AuthenticatorBuilder<C, F> {
hyper_client_builder: C,
app_secret: ApplicationSecret,
@@ -85,8 +90,24 @@ pub struct AuthenticatorBuilder<C, F> {
auth_flow: F,
}
/// Create an authenticator that uses the installed flow.
/// ```
/// # async fn foo() {
/// # use yup_oauth2::InstalledFlowReturnMethod;
/// # let custom_flow_delegate = yup_oauth2::authenticator_delegate::DefaultFlowDelegate;
/// # let app_secret = yup_oauth2::read_application_secret("/tmp/foo").unwrap();
/// let authenticator = yup_oauth2::InstalledFlowAuthenticator::builder(
/// app_secret,
/// InstalledFlowReturnMethod::HTTPRedirect,
/// )
/// .build()
/// .await
/// .expect("failed to create authenticator");
/// # }
/// ```
pub struct InstalledFlowAuthenticator;
impl InstalledFlowAuthenticator {
/// Use the builder pattern to create an Authenticator that uses the installed flow.
pub fn builder(
app_secret: ApplicationSecret,
method: InstalledFlowReturnMethod,
@@ -98,8 +119,19 @@ impl InstalledFlowAuthenticator {
}
}
/// Create an authenticator that uses the device flow.
/// ```
/// # async fn foo() {
/// # let app_secret = yup_oauth2::read_application_secret("/tmp/foo").unwrap();
/// let authenticator = yup_oauth2::DeviceFlowAuthenticator::builder(app_secret)
/// .build()
/// .await
/// .expect("failed to create authenticator");
/// # }
/// ```
pub struct DeviceFlowAuthenticator;
impl DeviceFlowAuthenticator {
/// Use the builder pattern to create an Authenticator that uses the device flow.
pub fn builder(
app_secret: ApplicationSecret,
) -> AuthenticatorBuilder<DefaultHyperClient, DeviceFlow> {
@@ -107,7 +139,45 @@ impl DeviceFlowAuthenticator {
}
}
/// Methods available when building any Authenticator.
/// ```
/// # async fn foo() {
/// # let custom_hyper_client = hyper::Client::new();
/// # let custom_auth_delegate = yup_oauth2::authenticator_delegate::DefaultAuthenticatorDelegate;
/// # let app_secret = yup_oauth2::read_application_secret("/tmp/foo").unwrap();
/// let authenticator = yup_oauth2::DeviceFlowAuthenticator::builder(app_secret)
/// .hyper_client(custom_hyper_client)
/// .persist_tokens_to_disk("/tmp/tokenfile.json")
/// .auth_delegate(Box::new(custom_auth_delegate))
/// .build()
/// .await
/// .expect("failed to create authenticator");
/// # }
/// ```
impl<C, F> AuthenticatorBuilder<C, F> {
/// Create the authenticator.
pub async fn build(self) -> io::Result<Authenticator<C::Connector>>
where
C: HyperClientBuilder,
F: Into<AuthFlow>,
{
let hyper_client = self.hyper_client_builder.build_hyper_client();
let storage = match self.storage_type {
StorageType::Memory => Storage::Memory {
tokens: Mutex::new(storage::JSONTokens::new()),
},
StorageType::Disk(path) => Storage::Disk(storage::DiskStorage::new(path).await?),
};
Ok(Authenticator {
hyper_client,
app_secret: self.app_secret,
storage,
auth_delegate: self.auth_delegate,
auth_flow: self.auth_flow.into(),
})
}
fn with_auth_flow(
app_secret: ApplicationSecret,
auth_flow: F,
@@ -153,31 +223,23 @@ impl<C, F> AuthenticatorBuilder<C, F> {
..self
}
}
/// Create the authenticator.
pub async fn build(self) -> io::Result<Authenticator<C::Connector>>
where
C: HyperClientBuilder,
F: Into<AuthFlow>,
{
let hyper_client = self.hyper_client_builder.build_hyper_client();
let storage = match self.storage_type {
StorageType::Memory => Storage::Memory {
tokens: Mutex::new(storage::JSONTokens::new()),
},
StorageType::Disk(path) => Storage::Disk(storage::DiskStorage::new(path).await?),
};
Ok(Authenticator {
hyper_client,
app_secret: self.app_secret,
storage,
auth_delegate: self.auth_delegate,
auth_flow: self.auth_flow.into(),
})
}
}
/// Methods available when building a device flow Authenticator.
/// ```
/// # async fn foo() {
/// # let custom_flow_delegate = yup_oauth2::authenticator_delegate::DefaultFlowDelegate;
/// # let app_secret = yup_oauth2::read_application_secret("/tmp/foo").unwrap();
/// let authenticator = yup_oauth2::DeviceFlowAuthenticator::builder(app_secret)
/// .device_code_url("foo")
/// .flow_delegate(Box::new(custom_flow_delegate))
/// .wait_duration(std::time::Duration::from_secs(120))
/// .grant_type("foo")
/// .build()
/// .await
/// .expect("failed to create authenticator");
/// # }
/// ```
impl<C> AuthenticatorBuilder<C, DeviceFlow> {
/// Use the provided device code url.
pub fn device_code_url(self, url: impl Into<Cow<'static, str>>) -> Self {
@@ -224,6 +286,22 @@ impl<C> AuthenticatorBuilder<C, DeviceFlow> {
}
}
/// Methods available when building an installed flow Authenticator.
/// ```
/// # async fn foo() {
/// # use yup_oauth2::InstalledFlowReturnMethod;
/// # let custom_flow_delegate = yup_oauth2::authenticator_delegate::DefaultFlowDelegate;
/// # let app_secret = yup_oauth2::read_application_secret("/tmp/foo").unwrap();
/// let authenticator = yup_oauth2::InstalledFlowAuthenticator::builder(
/// app_secret,
/// InstalledFlowReturnMethod::HTTPRedirect,
/// )
/// .flow_delegate(Box::new(custom_flow_delegate))
/// .build()
/// .await
/// .expect("failed to create authenticator");
/// # }
/// ```
impl<C> AuthenticatorBuilder<C, InstalledFlow> {
/// Use the provided FlowDelegate.
pub fn flow_delegate(self, flow_delegate: Box<dyn FlowDelegate>) -> Self {
@@ -285,8 +363,10 @@ mod private {
/// A trait implemented for any hyper::Client as well as teh DefaultHyperClient.
pub trait HyperClientBuilder {
/// The hyper connector that the resulting hyper client will use.
type Connector: hyper::client::connect::Connect + 'static;
/// Create a hyper::Client
fn build_hyper_client(self) -> hyper::Client<Self::Connector>;
}

View File

@@ -1,3 +1,5 @@
//! Module containing types related to delegates.
use crate::error::{Error, PollError, RefreshError};
use std::error::Error as StdError;

View File

@@ -1,3 +1,5 @@
//! Module containing various error types.
use std::error::Error as StdError;
use std::fmt;
use std::io;

View File

@@ -20,19 +20,19 @@
//! based on the Google APIs; it may or may not work with other providers.
//!
//! # Installed Flow Usage
//! The `InstalledFlow` involves showing a URL to the user (or opening it in a browser)
//! The installed flow involves showing a URL to the user (or opening it in a browser)
//! and then either prompting the user to enter a displayed code, or make the authorizing
//! website redirect to a web server spun up by this library and running on localhost.
//!
//! In order to use the interactive method, use the `InstalledInteractive` `FlowType`;
//! for the redirect method, use `InstalledRedirect`, with the port number to let the
//! server listen on.
//! In order to use the interactive method, use the `Interactive` `InstalledFlowReturnMethod`;
//! for the redirect method, use `HTTPRedirect`.
//!
//! You can implement your own `AuthenticatorDelegate` in order to customize the flow;
//! the `InstalledFlow` uses the `present_user_url` method.
//! the installed flow uses the `present_user_url` method.
//!
//! The returned `Token` is stored permanently in the given token storage in order to
//! authorize future API requests to the same scopes.
//! The returned `Token` will be stored in memory in order to authorize future
//! API requests to the same scopes. The tokens can optionally be persisted to
//! disk by using `persist_tokens_to_disk` when creating the authenticator.
//!
//! The following example, which is derived from the (actual and runnable) example in
//! `examples/test-installed/`, shows the basics of using this crate:
@@ -68,6 +68,7 @@
//! }
//! ```
//!
#![deny(missing_docs)]
pub mod authenticator;
pub mod authenticator_delegate;
mod device;

View File

@@ -69,15 +69,25 @@ fn decode_rsa_key(pem_pkcs8: &str) -> Result<PrivateKey, io::Error> {
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct ServiceAccountKey {
#[serde(rename = "type")]
/// key_type
pub key_type: Option<String>,
/// project_id
pub project_id: Option<String>,
/// private_key_id
pub private_key_id: Option<String>,
/// private_key
pub private_key: String,
/// client_email
pub client_email: String,
/// client_id
pub client_id: Option<String>,
/// auth_uri
pub auth_uri: Option<String>,
/// token_uri
pub token_uri: String,
/// auth_provider_x509_cert_url
pub auth_provider_x509_cert_url: Option<String>,
/// client_x509_cert_url
pub client_x509_cert_url: Option<String>,
}
@@ -150,8 +160,19 @@ impl JWTSigner {
}
}
/// Create an authenticator that uses a service account.
/// ```
/// # async fn foo() {
/// # let service_key = yup_oauth2::service_account_key_from_file("/tmp/foo").unwrap();
/// let authenticator = yup_oauth2::ServiceAccountAuthenticator::builder(service_key)
/// .build()
/// .expect("failed to create authenticator");
/// # }
/// ```
pub struct ServiceAccountAuthenticator;
impl ServiceAccountAuthenticator {
/// Use the builder pattern to create an authenticator that uses a service
/// account.
pub fn builder(key: ServiceAccountKey) -> Builder<DefaultHyperClient> {
Builder {
client: DefaultHyperClient,
@@ -161,12 +182,25 @@ impl ServiceAccountAuthenticator {
}
}
/// Configure a service account authenticator using the builder pattern.
pub struct Builder<C> {
client: C,
key: ServiceAccountKey,
subject: Option<String>,
}
/// Methods available when building a service account authenticator.
/// ```
/// # async fn foo() {
/// # let custom_hyper_client = hyper::Client::new();
/// # let service_key = yup_oauth2::service_account_key_from_file("/tmp/foo").unwrap();
/// let authenticator = yup_oauth2::ServiceAccountAuthenticator::builder(service_key)
/// .hyper_client(custom_hyper_client)
/// .subject("foo")
/// .build()
/// .expect("failed to create authenticator");
/// # }
/// ```
impl<C> Builder<C> {
/// Use the provided hyper client.
pub fn hyper_client<NewC: HyperClientBuilder>(self, hyper_client: NewC) -> Builder<NewC> {
@@ -178,9 +212,9 @@ impl<C> Builder<C> {
}
/// Use the provided subject.
pub fn subject(self, subject: String) -> Self {
pub fn subject(self, subject: impl Into<String>) -> Self {
Builder {
subject: Some(subject),
subject: Some(subject.into()),
..self
}
}
@@ -194,6 +228,7 @@ impl<C> Builder<C> {
}
}
/// ServiceAccountAccess can fetch oauth tokens using a service account.
pub struct ServiceAccountAccess<C> {
client: hyper::Client<C>,
key: ServiceAccountKey,
@@ -223,6 +258,7 @@ where
})
}
/// Return the current token for the provided scopes.
pub async fn token<T>(&self, scopes: &[T]) -> Result<Token, Error>
where
T: AsRef<str>,

View File

@@ -80,8 +80,8 @@ pub struct ApplicationSecret {
pub token_uri: String,
/// The authorization server endpoint URI.
pub auth_uri: String,
/// The redirect uris.
pub redirect_uris: Vec<String>,
/// Name of the google project the credentials are associated with
pub project_id: Option<String>,
/// The service account email associated with the client.
@@ -93,27 +93,13 @@ pub struct ApplicationSecret {
pub client_x509_cert_url: Option<String>,
}
impl ApplicationSecret {
pub const fn empty() -> Self {
ApplicationSecret {
client_id: String::new(),
client_secret: String::new(),
token_uri: String::new(),
auth_uri: String::new(),
redirect_uris: Vec::new(),
project_id: None,
client_email: None,
auth_provider_x509_cert_url: None,
client_x509_cert_url: None,
}
}
}
/// A type to facilitate reading and writing the json secret file
/// as returned by the [google developer console](https://code.google.com/apis/console)
#[derive(Deserialize, Serialize, Default)]
pub struct ConsoleApplicationSecret {
/// web app secret
pub web: Option<ApplicationSecret>,
/// installed app secret
pub installed: Option<ApplicationSecret>,
}