feat: Speedbump when logging in with OIDC with no next target

This commit is contained in:
Ginger committed 2026-07-02 16:34:38 -04:00
1 parent 4ee0bb7533
commit e2fe166d63
5 files changed
+113 -63

No files matched your search

+38 -25
View File
@@ -7,12 +7,14 @@ use axum::{
routing::{get, on},
};
use conduwuit_api::client::handle_login;
use openidconnect::core::CoreAuthPrompt;
use ruma::{
OwnedUserId,
api::client::uiaa::{EmailUserIdentifier, MatrixUserIdentifier, UserIdentifier},
};
use serde::Deserialize;
use tower_sessions::Session;
use url::Url;
use crate::{
ROUTE_PREFIX, WebError,
@@ -37,6 +39,7 @@ pub(crate) fn build() -> Router<crate::State> {
template! {
struct Login use "login.html.j2" {
body: LoginBody,
login_type: LoginType,
login_error: Option<String>
}
}
@@ -45,7 +48,6 @@ template! {
enum LoginBody {
Unauthenticated {
server_name: String,
registration_available: bool,
next: Option<LoginTarget>,
},
Authenticated {
@@ -53,6 +55,16 @@ enum LoginBody {
},
}
#[derive(Debug)]
enum LoginType {
Interactive {
registration_available: bool,
},
Oidc {
redirect_url: Url,
},
}
#[derive(Deserialize)]
struct LoginForm {
identifier: Option<String>,
@@ -69,38 +81,39 @@ async fn route_login(
) -> Result {
let user_id = user.into_session().map(|session| session.user_id);
if services.oidc.enabled() {
if user_id.is_some() && !reauthenticate {
return response!(Redirect::to(&next.unwrap_or_default().target_path()));
}
let (session, redirect_url) = services.oidc.begin_session().await;
let login_type = if services.oidc.enabled() {
let (session, redirect_url) = services
.oidc
.begin_session(reauthenticate.then(|| CoreAuthPrompt::Consent))
.await;
session_store
.insert(OIDC_SESSION_ID_KEY, OidcSession {
next: next.unwrap_or_default(),
state: OidcSessionState::CodeExchange { expected_user: user_id, session },
next: next.clone().unwrap_or_default(),
state: OidcSessionState::CodeExchange { expected_user: user_id.clone(), session },
})
.await
.expect("should be able to serialize OIDC session");
return response!(Redirect::to(redirect_url.as_str()));
}
if next.is_some() {
return response!(Redirect::to(redirect_url.as_str()));
}
LoginType::Oidc { redirect_url }
} else {
let (trusted_flow_status, untrusted_flow_status) =
registration_flow_status(&services).await;
let registration_available = matches!(trusted_flow_status, TrustedFlowStatus::Available)
|| matches!(untrusted_flow_status, UntrustedFlowStatus::Available { .. });
LoginType::Interactive { registration_available }
};
let body = match &user_id {
| None => {
let (trusted_flow_status, untrusted_flow_status) =
registration_flow_status(&services).await;
let registration_available =
matches!(trusted_flow_status, TrustedFlowStatus::Available)
|| matches!(untrusted_flow_status, UntrustedFlowStatus::Available { .. });
LoginBody::Unauthenticated {
server_name: services.globals.server_name().to_string(),
registration_available,
next: next.clone(),
}
| None => LoginBody::Unauthenticated {
server_name: services.globals.server_name().to_string(),
next: next.clone(),
},
| Some(user_id) => {
if !reauthenticate {
@@ -113,7 +126,7 @@ async fn route_login(
},
};
let mut template = Login::new(context, body, None);
let mut template = Login::new(context, body, login_type, None);
if let Some(form) = form {
let login_result = match (user_id, form.identifier) {
+7
View File
@@ -4,6 +4,7 @@ use ruma::UserId;
use validator::{Validate, ValidationError, ValidationErrors};
use crate::{
WebError,
extract::PostForm,
form,
pages::{
@@ -65,6 +66,12 @@ async fn route_change_password(
user: User,
PostForm(form): PostForm<ChangePasswordForm>,
) -> Result {
if services.oidc.enabled() {
return Err(WebError::BadRequest(
"Password changing is not available on this server".to_owned(),
));
}
let user_id = user.expect(LoginTarget::ChangePassword)?;
let user_card = UserCard::for_local_user(&services, user_id.clone()).await;
+7
View File
@@ -65,6 +65,13 @@ async fn route_reset_password(
return response!(ResetPassword::new(context, ResetPasswordBody::Unavailable));
}
// Check if OIDC is enabled
if services.oidc.enabled() {
return Err(WebError::BadRequest(
"Password resets are not available on this server".to_owned(),
));
}
let Some(form) = form else {
// For GET requests return the reset request form
return response!(ResetPassword::new(