Autocomplete password during reauth with TOTP (#3290)

During a re-auth flow, the password was not autocompleted once
totp was autocompleted. This is because in a normal login flow
the autocomplete is performed on the first login.html page,
but in a re-auth we skip that page.

This adds the proper handling to allow the pw to autofill
in the background once the TOTP is completed.
This commit is contained in:
Firstyear 2024-12-16 09:43:29 +10:00 committed by GitHub
parent 6db0cdc345
commit 5d75c9b247
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 40 additions and 2 deletions

View file

@ -552,6 +552,8 @@ pub async fn view_login_mech_choose_post(
#[derive(Debug, Clone, Deserialize)] #[derive(Debug, Clone, Deserialize)]
pub struct LoginTotpForm { pub struct LoginTotpForm {
#[serde(default, deserialize_with = "empty_string_as_none")]
password: Option<String>,
totp: String, totp: String,
} }
@ -560,7 +562,7 @@ pub async fn view_login_totp_post(
Extension(kopid): Extension<KOpId>, Extension(kopid): Extension<KOpId>,
VerifiedClientInformation(client_auth_info): VerifiedClientInformation, VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
DomainInfo(domain_info): DomainInfo, DomainInfo(domain_info): DomainInfo,
jar: CookieJar, mut jar: CookieJar,
Form(login_totp_form): Form<LoginTotpForm>, Form(login_totp_form): Form<LoginTotpForm>,
) -> Response { ) -> Response {
// trim leading and trailing white space. // trim leading and trailing white space.
@ -583,6 +585,31 @@ pub async fn view_login_totp_post(
} }
}; };
// In some flows the PW manager may not have autocompleted the pw until
// this point. This could be due to a re-auth flow which skips the username
// prompt, the use of remember-me+return which then skips the autocomplete.
//
// In the case the pw *is* bg filled, we need to add it to the session context
// here.
//
// It's probably not "optimal" to be getting the context out and signing it
// here to re-add it, but it also helps keep the flow neater in general.
if let Some(password_autofill) = login_totp_form.password {
let mut session_context =
cookies::get_signed::<SessionContext>(&state, &jar, COOKIE_AUTH_SESSION_ID)
.unwrap_or_default();
session_context.password = Some(password_autofill);
// If we can't write this back to the jar, we warn and move on.
if let Ok(update_jar) = add_session_cookie(&state, jar.clone(), &session_context) {
jar = update_jar;
} else {
warn!("Unable to update session_context, ignoring...");
}
}
let auth_cred = AuthCredential::Totp(totp); let auth_cred = AuthCredential::Totp(totp);
credential_step(state, kopid, jar, client_auth_info, auth_cred, domain_info).await credential_step(state, kopid, jar, client_auth_info, auth_cred, domain_info).await
} }

View file

@ -23,7 +23,7 @@
/> />
</div> </div>
<!-- BEGIN: to work better with password managers --> <!-- BEGIN: allows a password manager to autocomplete these fields in the BG. -->
<input <input
class="d-none" class="d-none"
id="password" id="password"

View file

@ -10,6 +10,17 @@
(% endmatch %) (% endmatch %)
<form id="login" action="/ui/login/totp" method="post"> <form id="login" action="/ui/login/totp" method="post">
<div class="input-group mb-3"> <div class="input-group mb-3">
<!-- BEGIN: allows a password manager to autocomplete these fields in the BG. -->
<input
class="d-none"
id="password"
name="password"
type="password"
autocomplete="current-password"
value=""
/>
<!-- END -->
<input <input
autofocus=true autofocus=true
class="autofocus form-control" class="autofocus form-control"