From ff4ed4c72e9a841971563b98cd89839f59bc790c Mon Sep 17 00:00:00 2001 From: Jesse Luehrs Date: Tue, 26 Nov 2019 05:06:02 -0500 Subject: pass oauth login urls along to the browser --- teleterm/src/cmd/web.rs | 14 ++++++++++++ teleterm/src/protocol.rs | 20 ++++++++++++++++++ teleterm/src/server.rs | 11 +++++----- teleterm/src/web.rs | 55 +++++++++++++++++++++++++++++++++++++++++++----- 4 files changed, 89 insertions(+), 11 deletions(-) diff --git a/teleterm/src/cmd/web.rs b/teleterm/src/cmd/web.rs index e292288..637d1ff 100644 --- a/teleterm/src/cmd/web.rs +++ b/teleterm/src/cmd/web.rs @@ -4,6 +4,19 @@ use crate::prelude::*; pub struct Config { #[serde(default)] web: crate::config::Web, + + #[serde( + rename = "oauth", + deserialize_with = "crate::config::oauth_configs", + default + )] + oauth_configs: std::collections::HashMap< + crate::protocol::AuthType, + std::collections::HashMap< + crate::protocol::AuthClient, + crate::oauth::Config, + >, + >, } impl crate::config::Config for Config { @@ -22,6 +35,7 @@ impl crate::config::Config for Config { self.web.public_address.clone(), self.web.server_address.clone(), self.web.allowed_login_methods.clone(), + self.oauth_configs.clone(), )) } } diff --git a/teleterm/src/protocol.rs b/teleterm/src/protocol.rs index 130e52d..5633b8e 100644 --- a/teleterm/src/protocol.rs +++ b/teleterm/src/protocol.rs @@ -139,6 +139,26 @@ impl AuthType { .take_while(std::result::Result::is_ok) .map(std::result::Result::unwrap) } + + pub fn oauth_client( + self, + config: &crate::oauth::Config, + id: Option<&str>, + ) -> Option> { + match self { + Self::RecurseCenter => { + Some(Box::new(crate::oauth::RecurseCenter::new( + config.clone(), + &id.map_or_else( + || format!("{}", uuid::Uuid::new_v4()), + std::string::ToString::to_string, + ), + ))) + } + ty if !ty.is_oauth() => None, + _ => unreachable!(), + } + } } impl std::convert::TryFrom for AuthType { diff --git a/teleterm/src/server.rs b/teleterm/src/server.rs index e36f3fc..5c846ed 100644 --- a/teleterm/src/server.rs +++ b/teleterm/src/server.rs @@ -399,12 +399,11 @@ impl )?; ( id.is_some(), - Box::new(crate::oauth::RecurseCenter::new( - config.clone(), - &id.clone().unwrap_or_else(|| { - format!("{}", uuid::Uuid::new_v4()) - }), - )), + ty.oauth_client( + config, + id.as_ref().map(std::string::String::as_str), + ) + .unwrap(), ) } _ => unreachable!(), diff --git a/teleterm/src/web.rs b/teleterm/src/web.rs index ed887a5..690d8a3 100644 --- a/teleterm/src/web.rs +++ b/teleterm/src/web.rs @@ -11,12 +11,19 @@ use crate::prelude::*; use gotham::router::builder::{DefineSingleRoute as _, DrawRoutes as _}; use gotham::state::FromState as _; -#[derive(Clone, serde::Serialize, gotham_derive::StateData)] +#[derive(Clone, gotham_derive::StateData)] struct Config { server_address: (String, std::net::SocketAddr), public_address: String, allowed_login_methods: std::collections::HashSet, + oauth_configs: std::collections::HashMap< + crate::protocol::AuthType, + std::collections::HashMap< + crate::protocol::AuthClient, + crate::oauth::Config, + >, + >, } #[derive(Default, serde::Deserialize, serde::Serialize)] @@ -30,18 +37,35 @@ struct WebConfig<'a> { public_address: &'a str, allowed_login_methods: &'a std::collections::HashSet, + oauth_login_urls: + std::collections::HashMap, } impl<'a> WebConfig<'a> { - fn new(config: &'a Config, session: &'a SessionData) -> Self { - Self { + fn new(config: &'a Config, session: &'a SessionData) -> Result { + let mut oauth_login_urls = std::collections::HashMap::new(); + for ty in crate::protocol::AuthType::iter().filter(|ty| { + ty.is_oauth() && config.allowed_login_methods.contains(ty) + }) { + let oauth_config = config + .oauth_configs + .get(&ty) + .and_then(|configs| { + configs.get(&crate::protocol::AuthClient::Web) + }) + .context(crate::error::AuthTypeMissingOauthConfig { ty })?; + let client = ty.oauth_client(oauth_config, None).unwrap(); + oauth_login_urls.insert(ty, client.generate_authorize_url()); + } + Ok(Self { username: session .username .as_ref() .map(std::string::String::as_str), public_address: &config.public_address, allowed_login_methods: &config.allowed_login_methods, - } + oauth_login_urls, + }) } } @@ -57,11 +81,19 @@ impl Server { allowed_login_methods: std::collections::HashSet< crate::protocol::AuthType, >, + oauth_configs: std::collections::HashMap< + crate::protocol::AuthType, + std::collections::HashMap< + crate::protocol::AuthClient, + crate::oauth::Config, + >, + >, ) -> Self { let data = Config { server_address, public_address, allowed_login_methods, + oauth_configs, }; Self { server: Box::new(gotham::init_server( @@ -146,7 +178,20 @@ fn serve_template( let session = gotham::middleware::session::SessionData::< crate::web::SessionData, >::borrow_from(&state); - let web_config = WebConfig::new(config, session); + let web_config = match WebConfig::new(config, session) { + Ok(config) => config, + Err(e) => { + // this means that the server configuration is incorrect, and + // there's nothing the client can do about it + return ( + state, + hyper::Response::builder() + .status(hyper::StatusCode::INTERNAL_SERVER_ERROR) + .body(hyper::Body::from(format!("{}", e))) + .unwrap(), + ); + } + }; let rendered = view::HANDLEBARS.render(name, &web_config).unwrap(); let response = hyper::Response::builder() .header("Content-Type", content_type) -- cgit v1.2.3