From 989e464dd014a78c067bedd08687b011ded60c61 Mon Sep 17 00:00:00 2001 From: Quentin Gliech Date: Fri, 2 Dec 2022 15:52:49 +0100 Subject: [PATCH] WIP: Provider list on the login page --- crates/handlers/src/views/login.rs | 8 ++- crates/storage/sqlx-data.json | 60 +++++++++++++++++++ crates/storage/src/upstream_oauth2/mod.rs | 4 +- .../storage/src/upstream_oauth2/provider.rs | 26 ++++++++ crates/templates/src/context.rs | 8 +++ templates/pages/login.html | 12 ++++ 6 files changed, 115 insertions(+), 3 deletions(-) diff --git a/crates/handlers/src/views/login.rs b/crates/handlers/src/views/login.rs index 71a043ef..f1a43317 100644 --- a/crates/handlers/src/views/login.rs +++ b/crates/handlers/src/views/login.rs @@ -60,8 +60,9 @@ pub(crate) async fn get( let reply = query.go_next(); Ok((cookie_jar, reply).into_response()) } else { + let providers = mas_storage::upstream_oauth2::get_providers(&mut conn).await?; let content = render( - LoginContext::default(), + LoginContext::default().with_upstrem_providers(providers), query, csrf_token, &mut conn, @@ -103,8 +104,11 @@ pub(crate) async fn post( }; if !state.is_valid() { + let providers = mas_storage::upstream_oauth2::get_providers(&mut conn).await?; let content = render( - LoginContext::default().with_form_state(state), + LoginContext::default() + .with_form_state(state) + .with_upstrem_providers(providers), query, csrf_token, &mut conn, diff --git a/crates/storage/sqlx-data.json b/crates/storage/sqlx-data.json index e980858f..83132760 100644 --- a/crates/storage/sqlx-data.json +++ b/crates/storage/sqlx-data.json @@ -2559,6 +2559,66 @@ }, "query": "\n INSERT INTO oauth2_clients\n (oauth2_client_id,\n encrypted_client_secret,\n grant_type_authorization_code,\n grant_type_refresh_token,\n client_name,\n logo_uri,\n client_uri,\n policy_uri,\n tos_uri,\n jwks_uri,\n jwks,\n id_token_signed_response_alg,\n userinfo_signed_response_alg,\n token_endpoint_auth_method,\n token_endpoint_auth_signing_alg,\n initiate_login_uri)\n VALUES\n ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16)\n " }, + "cf00e0ad529bcb5c0640adcfe0880a3560d9739f355b90ca3ba88dd1eaf26565": { + "describe": { + "columns": [ + { + "name": "upstream_oauth_provider_id", + "ordinal": 0, + "type_info": "Uuid" + }, + { + "name": "issuer", + "ordinal": 1, + "type_info": "Text" + }, + { + "name": "scope", + "ordinal": 2, + "type_info": "Text" + }, + { + "name": "client_id", + "ordinal": 3, + "type_info": "Text" + }, + { + "name": "encrypted_client_secret", + "ordinal": 4, + "type_info": "Text" + }, + { + "name": "token_endpoint_signing_alg", + "ordinal": 5, + "type_info": "Text" + }, + { + "name": "token_endpoint_auth_method", + "ordinal": 6, + "type_info": "Text" + }, + { + "name": "created_at", + "ordinal": 7, + "type_info": "Timestamptz" + } + ], + "nullable": [ + false, + false, + false, + false, + true, + true, + false, + false + ], + "parameters": { + "Left": [] + } + }, + "query": "\n SELECT\n upstream_oauth_provider_id,\n issuer,\n scope,\n client_id,\n encrypted_client_secret,\n token_endpoint_signing_alg,\n token_endpoint_auth_method,\n created_at\n FROM upstream_oauth_providers\n " + }, "d1738c27339b81f0844da4bd9b040b9b07a91aa4d9b199b98f24c9cee5709b2b": { "describe": { "columns": [], diff --git a/crates/storage/src/upstream_oauth2/mod.rs b/crates/storage/src/upstream_oauth2/mod.rs index 6376a16e..165251d9 100644 --- a/crates/storage/src/upstream_oauth2/mod.rs +++ b/crates/storage/src/upstream_oauth2/mod.rs @@ -18,7 +18,9 @@ mod session; pub use self::{ link::{add_link, associate_link_to_user, lookup_link, lookup_link_by_subject}, - provider::{add_provider, get_paginated_providers, lookup_provider, ProviderLookupError}, + provider::{ + add_provider, get_paginated_providers, get_providers, lookup_provider, ProviderLookupError, + }, session::{ add_session, complete_session, consume_session, lookup_session, lookup_session_on_link, SessionLookupError, diff --git a/crates/storage/src/upstream_oauth2/provider.rs b/crates/storage/src/upstream_oauth2/provider.rs index 931f7870..7fcb526e 100644 --- a/crates/storage/src/upstream_oauth2/provider.rs +++ b/crates/storage/src/upstream_oauth2/provider.rs @@ -219,3 +219,29 @@ pub async fn get_paginated_providers( let page: Result, _> = page.into_iter().map(TryInto::try_into).collect(); Ok((has_previous_page, has_next_page, page?)) } + +#[tracing::instrument(skip_all, err)] +pub async fn get_providers( + executor: impl PgExecutor<'_>, +) -> Result, anyhow::Error> { + let res = sqlx::query_as!( + ProviderLookup, + r#" + SELECT + upstream_oauth_provider_id, + issuer, + scope, + client_id, + encrypted_client_secret, + token_endpoint_signing_alg, + token_endpoint_auth_method, + created_at + FROM upstream_oauth_providers + "#, + ) + .fetch_all(executor) + .await?; + + let res: Result, _> = res.into_iter().map(TryInto::try_into).collect(); + Ok(res?) +} diff --git a/crates/templates/src/context.rs b/crates/templates/src/context.rs index 198b3c96..3c690d48 100644 --- a/crates/templates/src/context.rs +++ b/crates/templates/src/context.rs @@ -279,6 +279,7 @@ pub enum PostAuthContext { pub struct LoginContext { form: FormState, next: Option, + providers: Vec, register_link: String, } @@ -291,6 +292,7 @@ impl TemplateContext for LoginContext { vec![LoginContext { form: FormState::default(), next: None, + providers: Vec::new(), register_link: "/register".to_owned(), }] } @@ -303,6 +305,12 @@ impl LoginContext { Self { form, ..self } } + /// Set the upstream OAuth 2.0 providers + #[must_use] + pub fn with_upstrem_providers(self, providers: Vec) -> Self { + Self { providers, ..self } + } + /// Add a post authentication action to the context #[must_use] pub fn with_post_action(self, next: PostAuthContext) -> Self { diff --git a/templates/pages/login.html b/templates/pages/login.html index 2018fc0e..7ab75ca2 100644 --- a/templates/pages/login.html +++ b/templates/pages/login.html @@ -65,6 +65,18 @@ limitations under the License. {{ button::link_text(text="Create an account", href=register_link) }} {% endif %} + + {% if providers %} +
+
+
Or
+
+
+ + {% for provider in providers %} + {{ button::link(text="Continue with " ~ provider.issuer, href="/upstream/authorize/" ~ provider.id) }} + {% endfor %} + {% endif %} {% endblock content %}