1
0
mirror of https://github.com/matrix-org/matrix-authentication-service.git synced 2025-07-31 09:24:31 +03:00

Skip the "continue" screens on upstream IDP logins for new accounts

This commit is contained in:
Quentin Gliech
2023-08-24 18:18:36 +02:00
parent c7311eea79
commit ca3460b49e
4 changed files with 29 additions and 112 deletions

View File

@ -33,8 +33,7 @@ use mas_storage::{
BoxClock, BoxRepository, BoxRng, RepositoryAccess, BoxClock, BoxRepository, BoxRng, RepositoryAccess,
}; };
use mas_templates::{ use mas_templates::{
EmptyContext, TemplateContext, Templates, UpstreamExistingLinkContext, UpstreamRegister, TemplateContext, Templates, UpstreamExistingLinkContext, UpstreamRegister, UpstreamSuggestLink,
UpstreamSuggestLink,
}; };
use serde::Deserialize; use serde::Deserialize;
use thiserror::Error; use thiserror::Error;
@ -158,7 +157,6 @@ pub(crate) enum FormData {
import_display_name: Option<String>, import_display_name: Option<String>,
}, },
Link, Link,
Login,
} }
#[tracing::instrument( #[tracing::instrument(
@ -176,10 +174,14 @@ pub(crate) async fn get(
Path(link_id): Path<Ulid>, Path(link_id): Path<Ulid>,
) -> Result<impl IntoResponse, RouteError> { ) -> Result<impl IntoResponse, RouteError> {
let sessions_cookie = UpstreamSessionsCookie::load(&cookie_jar); let sessions_cookie = UpstreamSessionsCookie::load(&cookie_jar);
let (session_id, _post_auth_action) = sessions_cookie let (session_id, post_auth_action) = sessions_cookie
.lookup_link(link_id) .lookup_link(link_id)
.map_err(|_| RouteError::MissingCookie)?; .map_err(|_| RouteError::MissingCookie)?;
let post_auth_action = OptionalPostAuthAction {
post_auth_action: post_auth_action.cloned(),
};
let link = repo let link = repo
.upstream_oauth_link() .upstream_oauth_link()
.lookup(link_id) .lookup(link_id)
@ -206,7 +208,7 @@ pub(crate) async fn get(
let (csrf_token, mut cookie_jar) = cookie_jar.csrf_token(&clock, &mut rng); let (csrf_token, mut cookie_jar) = cookie_jar.csrf_token(&clock, &mut rng);
let maybe_user_session = user_session_info.load_session(&mut repo).await?; let maybe_user_session = user_session_info.load_session(&mut repo).await?;
let render = match (maybe_user_session, link.user_id) { let response = match (maybe_user_session, link.user_id) {
(Some(session), Some(user_id)) if session.user.id == user_id => { (Some(session), Some(user_id)) if session.user.id == user_id => {
// Session already linked, and link matches the currently logged // Session already linked, and link matches the currently logged
// user. Mark the session as consumed and renew the authentication. // user. Mark the session as consumed and renew the authentication.
@ -222,13 +224,7 @@ pub(crate) async fn get(
repo.save().await?; repo.save().await?;
let ctx = EmptyContext post_auth_action.go_next().into_response()
.with_session(session)
.with_csrf(csrf_token.form_value());
templates
.render_upstream_oauth2_already_linked(&ctx)
.await?
} }
(Some(user_session), Some(user_id)) => { (Some(user_session), Some(user_id)) => {
@ -247,7 +243,7 @@ pub(crate) async fn get(
.with_session(user_session) .with_session(user_session)
.with_csrf(csrf_token.form_value()); .with_csrf(csrf_token.form_value());
templates.render_upstream_oauth2_link_mismatch(&ctx).await? Html(templates.render_upstream_oauth2_link_mismatch(&ctx).await?).into_response()
} }
(Some(user_session), None) => { (Some(user_session), None) => {
@ -256,7 +252,7 @@ pub(crate) async fn get(
.with_session(user_session) .with_session(user_session)
.with_csrf(csrf_token.form_value()); .with_csrf(csrf_token.form_value());
templates.render_upstream_oauth2_suggest_link(&ctx).await? Html(templates.render_upstream_oauth2_suggest_link(&ctx).await?).into_response()
} }
(None, Some(user_id)) => { (None, Some(user_id)) => {
@ -268,9 +264,24 @@ pub(crate) async fn get(
.filter(mas_data_model::User::is_valid) .filter(mas_data_model::User::is_valid)
.ok_or(RouteError::UserNotFound)?; .ok_or(RouteError::UserNotFound)?;
let ctx = UpstreamExistingLinkContext::new(user).with_csrf(csrf_token.form_value()); let session = repo.browser_session().add(&mut rng, &clock, &user).await?;
templates.render_upstream_oauth2_do_login(&ctx).await? repo.upstream_oauth_session()
.consume(&clock, upstream_session)
.await?;
repo.browser_session()
.authenticate_with_upstream(&mut rng, &clock, &session, &link)
.await?;
cookie_jar = sessions_cookie
.consume_link(link_id)?
.save(cookie_jar, &clock);
cookie_jar = cookie_jar.set_session(&session);
repo.save().await?;
post_auth_action.go_next().into_response()
} }
(None, None) => { (None, None) => {
@ -322,11 +333,11 @@ pub(crate) async fn get(
let ctx = ctx.with_csrf(csrf_token.form_value()); let ctx = ctx.with_csrf(csrf_token.form_value());
templates.render_upstream_oauth2_do_register(&ctx).await? Html(templates.render_upstream_oauth2_do_register(&ctx).await?).into_response()
} }
}; };
Ok((cookie_jar, Html(render))) Ok((cookie_jar, response))
} }
#[tracing::instrument( #[tracing::instrument(
@ -388,17 +399,6 @@ pub(crate) async fn post(
session session
} }
(None, Some(user_id), FormData::Login) => {
let user = repo
.user()
.lookup(user_id)
.await?
.filter(mas_data_model::User::is_valid)
.ok_or(RouteError::UserNotFound)?;
repo.browser_session().add(&mut rng, &clock, &user).await?
}
( (
None, None,
None, None,

View File

@ -267,18 +267,12 @@ register_templates! {
/// Render the email verification subject /// Render the email verification subject
pub fn render_email_verification_subject(EmailVerificationContext) { "emails/verification.subject" } pub fn render_email_verification_subject(EmailVerificationContext) { "emails/verification.subject" }
/// Render the upstream already linked message
pub fn render_upstream_oauth2_already_linked(WithCsrf<WithSession<EmptyContext>>) { "pages/upstream_oauth2/already_linked.html" }
/// Render the upstream link mismatch message /// Render the upstream link mismatch message
pub fn render_upstream_oauth2_link_mismatch(WithCsrf<WithSession<UpstreamExistingLinkContext>>) { "pages/upstream_oauth2/link_mismatch.html" } pub fn render_upstream_oauth2_link_mismatch(WithCsrf<WithSession<UpstreamExistingLinkContext>>) { "pages/upstream_oauth2/link_mismatch.html" }
/// Render the upstream suggest link message /// Render the upstream suggest link message
pub fn render_upstream_oauth2_suggest_link(WithCsrf<WithSession<UpstreamSuggestLink>>) { "pages/upstream_oauth2/suggest_link.html" } pub fn render_upstream_oauth2_suggest_link(WithCsrf<WithSession<UpstreamSuggestLink>>) { "pages/upstream_oauth2/suggest_link.html" }
/// Render the upstream login screen
pub fn render_upstream_oauth2_do_login(WithCsrf<UpstreamExistingLinkContext>) { "pages/upstream_oauth2/do_login.html" }
/// Render the upstream register screen /// Render the upstream register screen
pub fn render_upstream_oauth2_do_register(WithCsrf<UpstreamRegister>) { "pages/upstream_oauth2/do_register.html" } pub fn render_upstream_oauth2_do_register(WithCsrf<UpstreamRegister>) { "pages/upstream_oauth2/do_register.html" }
} }
@ -308,10 +302,8 @@ impl Templates {
check::render_email_verification_txt(self, now, rng).await?; check::render_email_verification_txt(self, now, rng).await?;
check::render_email_verification_html(self, now, rng).await?; check::render_email_verification_html(self, now, rng).await?;
check::render_email_verification_subject(self, now, rng).await?; check::render_email_verification_subject(self, now, rng).await?;
check::render_upstream_oauth2_already_linked(self, now, rng).await?;
check::render_upstream_oauth2_link_mismatch(self, now, rng).await?; check::render_upstream_oauth2_link_mismatch(self, now, rng).await?;
check::render_upstream_oauth2_suggest_link(self, now, rng).await?; check::render_upstream_oauth2_suggest_link(self, now, rng).await?;
check::render_upstream_oauth2_do_login(self, now, rng).await?;
check::render_upstream_oauth2_do_register(self, now, rng).await?; check::render_upstream_oauth2_do_register(self, now, rng).await?;
Ok(()) Ok(())
} }

View File

@ -1,26 +0,0 @@
{#
Copyright 2022 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
#}
{% extends "base.html" %}
{% block content %}
{{ navbar::top() }}
<section class="flex items-center justify-center flex-1">
<h1 class="rounded-lg bg-grey-25 dark:bg-grey-450 p-2 flex flex-col font-medium text-lg text-center">
Your upstream account is already linked.
</h1>
</section>
{% endblock content %}

View File

@ -1,49 +0,0 @@
{#
Copyright 2022 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
#}
{% extends "base.html" %}
{% block content %}
<section class="flex items-center justify-center flex-1">
<form method="POST" class="grid grid-cols-1 gap-6 w-96">
<h1 class="rounded-lg bg-grey-25 dark:bg-grey-450 p-2 font-medium text-lg text-center">
Continue login
</h1>
<div class="rounded-lg bg-grey-25 dark:bg-grey-450 p-4 flex flex-col">
<div>
Username: <span class="font-medium">{{ linked_user.username }}</span>
</div>
<div class="text-sm">
Identifier: <span class="font-mono font-medium">{{ linked_user.sub }}</span>
</div>
<div class="text-sm">
Primary email:
{% if linked_user.primary_email %}
<span class="font-medium">{{ linked_user.primary_email.email }}</span>
{% else %}
<span class="italic">none</span>
{% endif %}
</div>
</div>
<input type="hidden" name="csrf" value="{{ csrf_token }}" />
<input type="hidden" name="action" value="login" />
{{ button::button(text="Continue") }}
</form>
</section>
{% endblock content %}