From 71a45f059ed0a71ea0d5f4b5df989f287a0a6ae7 Mon Sep 17 00:00:00 2001 From: Lewin Bormann Date: Wed, 12 Jun 2019 21:16:28 +0200 Subject: [PATCH] refactor(delegate): Split AuthenticatorDelegate to have FlowDelegate --- src/authenticator_delegate.rs | 3 ++- src/device.rs | 29 +++++++++++++++-------------- src/installed.rs | 28 ++++++++++++++-------------- 3 files changed, 31 insertions(+), 29 deletions(-) diff --git a/src/authenticator_delegate.rs b/src/authenticator_delegate.rs index e918fd1..1dd37e1 100644 --- a/src/authenticator_delegate.rs +++ b/src/authenticator_delegate.rs @@ -134,7 +134,9 @@ pub trait AuthenticatorDelegate: Clone { let _ = error_description; } } +} +pub trait FlowDelegate: Clone { /// Called as long as we are waiting for the user to authorize us. /// Can be used to print progress information, or decide to time-out. /// @@ -150,7 +152,6 @@ pub trait AuthenticatorDelegate: Clone { fn redirect_uri(&self) -> Option { None } - /// The server has returned a `user_code` which must be shown to the user, /// along with the `verification_url`. /// # Notes diff --git a/src/device.rs b/src/device.rs index 535055a..f35dcd2 100644 --- a/src/device.rs +++ b/src/device.rs @@ -13,7 +13,7 @@ use serde_json as json; use tokio_timer; use url::form_urlencoded; -use crate::authenticator_delegate::{AuthenticatorDelegate, PollError, PollInformation}; +use crate::authenticator_delegate::{FlowDelegate, PollError, PollInformation}; use crate::types::{ApplicationSecret, Flow, FlowType, GetToken, JsonError, RequestError, Token}; pub const GOOGLE_DEVICE_CODE_URL: &'static str = "https://accounts.google.com/o/oauth2/device/code"; @@ -22,25 +22,25 @@ pub const GOOGLE_DEVICE_CODE_URL: &'static str = "https://accounts.google.com/o/ /// It operates in two steps: /// * obtain a code to show to the user /// * (repeatedly) poll for the user to authenticate your application -pub struct DeviceFlow { +pub struct DeviceFlow { client: hyper::Client, application_secret: ApplicationSecret, /// Usually GOOGLE_DEVICE_CODE_URL device_code_url: String, - ad: AD, + fd: FD, wait: Duration, } -impl Flow for DeviceFlow { +impl Flow for DeviceFlow { fn type_id() -> FlowType { FlowType::Device(String::new()) } } impl< - AD: AuthenticatorDelegate + Clone + Send + 'static, + FD: FlowDelegate + Clone + Send + 'static, C: hyper::client::connect::Connect + Sync + 'static, - > GetToken for DeviceFlow + > GetToken for DeviceFlow { fn token<'b, I, T>( &mut self, @@ -57,19 +57,19 @@ impl< } } -impl DeviceFlow +impl DeviceFlow where C: hyper::client::connect::Connect + Sync + 'static, C::Transport: 'static, C::Future: 'static, - AD: AuthenticatorDelegate + Clone + Send + 'static, + FD: FlowDelegate + Clone + Send + 'static, { pub fn new>( client: hyper::Client, secret: ApplicationSecret, - ad: AD, + fd: FD, device_code_url: Option, - ) -> DeviceFlow { + ) -> DeviceFlow { DeviceFlow { client: client, application_secret: secret, @@ -77,7 +77,7 @@ where .as_ref() .map(|s| s.as_ref().to_string()) .unwrap_or(GOOGLE_DEVICE_CODE_URL.to_string()), - ad: ad, + fd: fd, wait: Duration::from_secs(120), } } @@ -87,11 +87,13 @@ where self.wait = wait; } + /// Essentially what `GetToken::token` does: Retrieve a token for the given scopes without + /// caching. pub fn retrieve_device_token<'a>( &mut self, scopes: Vec, ) -> Box> + Send> { - let mut ad = self.ad.clone(); + let mut fd = self.fd.clone(); let application_secret = self.application_secret.clone(); let client = self.client.clone(); let wait = self.wait; @@ -102,14 +104,13 @@ where scopes, ) .and_then(move |(pollinf, device_code)| { - ad.present_user_code(&pollinf); + fd.present_user_code(&pollinf); Ok((pollinf, device_code)) }); Box::new(request_code.and_then(move |(pollinf, device_code)| { future::loop_fn(0, move |i| { // Make a copy of everything every time, because the loop function needs to be // repeatable, i.e. we can't move anything out. - // let pt = Self::poll_token( application_secret.clone(), client.clone(), diff --git a/src/installed.rs b/src/installed.rs index 7e32c5c..1a5a0d1 100644 --- a/src/installed.rs +++ b/src/installed.rs @@ -16,7 +16,7 @@ use serde_json::error; use url::form_urlencoded; use url::percent_encoding::{percent_encode, QUERY_ENCODE_SET}; -use crate::authenticator_delegate::AuthenticatorDelegate; +use crate::authenticator_delegate::FlowDelegate; use crate::types::{ApplicationSecret, GetToken, Token}; const OOB_REDIRECT_URI: &'static str = "urn:ietf:wg:oauth:2.0:oob"; @@ -62,9 +62,9 @@ where } impl< - AD: AuthenticatorDelegate + 'static + Send + Clone, + FD: FlowDelegate + 'static + Send + Clone, C: hyper::client::connect::Connect + 'static, - > GetToken for InstalledFlow + > GetToken for InstalledFlow { fn token<'b, I, T>( &mut self, @@ -81,10 +81,10 @@ impl< } } -pub struct InstalledFlow { +pub struct InstalledFlow { method: InstalledFlowReturnMethod, client: hyper::client::Client, - ad: AD, + fd: FD, appsecret: ApplicationSecret, } @@ -101,22 +101,22 @@ pub enum InstalledFlowReturnMethod { impl< 'c, - AD: 'static + AuthenticatorDelegate + Clone + Send, + FD: 'static + FlowDelegate + Clone + Send, C: 'c + hyper::client::connect::Connect, - > InstalledFlow + > InstalledFlow { /// Starts a new Installed App auth flow. /// If HTTPRedirect is chosen as method and the server can't be started, the flow falls /// back to Interactive. pub fn new( client: hyper::client::Client, - ad: AD, + fd: FD, secret: ApplicationSecret, method: InstalledFlowReturnMethod, - ) -> InstalledFlow { + ) -> InstalledFlow { InstalledFlow { method: method, - ad: ad, + fd: fd, appsecret: secret, client: client, } @@ -127,12 +127,12 @@ impl< /// . Obtain a token and refresh token using that code. /// . Return that token /// - /// It's recommended not to use the DefaultAuthenticatorDelegate, but a specialized one. + /// It's recommended not to use the DefaultFlowDelegate, but a specialized one. pub fn obtain_token<'a>( &mut self, scopes: Vec, // Note: I haven't found a better way to give a list of strings here, due to ownership issues with futures. ) -> impl 'a + Future> + Send { - let rduri = self.ad.redirect_uri(); + let rduri = self.fd.redirect_uri(); // Start server on localhost to accept auth code. let server = if let InstalledFlowReturnMethod::HTTPRedirect(port) = self.method { match InstalledFlowServer::new(port) { @@ -149,7 +149,7 @@ impl< }; let client = self.client.clone(); let (appsecclone, appsecclone2) = (self.appsecret.clone(), self.appsecret.clone()); - let auth_delegate = self.ad.clone(); + let auth_delegate = self.fd.clone(); server .into_future() // First: Obtain authorization code from user. @@ -218,7 +218,7 @@ impl< fn ask_authorization_code<'a, S, T>( server: Option, - mut auth_delegate: AD, + mut auth_delegate: FD, appsecret: &ApplicationSecret, scopes: S, ) -> Box> + Send>