fix: verify authenticated user in passkey add finish
Add AuthenticatedUser extractor to passkey_add_finish and verify the session user matches the challenge owner, preventing one user from completing another user's passkey registration.
This commit is contained in:
parent
55f2de1e92
commit
0bf30d3475
1 changed files with 13 additions and 4 deletions
|
|
@ -8,7 +8,7 @@ use tracing::{error, info, warn};
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
use webauthn_rs::prelude::*;
|
use webauthn_rs::prelude::*;
|
||||||
|
|
||||||
use crate::application::auth::AuthenticatedUser;
|
use crate::application::auth::{AuthenticatedUser, SESSION_COOKIE_NAME};
|
||||||
use crate::application::state::AppState;
|
use crate::application::state::AppState;
|
||||||
use crate::domain::passkey_credentials::NewPasskeyCredential;
|
use crate::domain::passkey_credentials::NewPasskeyCredential;
|
||||||
use crate::domain::sessions::NewSession;
|
use crate::domain::sessions::NewSession;
|
||||||
|
|
@ -17,8 +17,6 @@ use crate::domain::users::NewUser;
|
||||||
use crate::infrastructure::auth::{generate_session_token, generate_token, hash_token};
|
use crate::infrastructure::auth::{generate_session_token, generate_token, hash_token};
|
||||||
use crate::infrastructure::webauthn::CliCallbackInfo;
|
use crate::infrastructure::webauthn::CliCallbackInfo;
|
||||||
|
|
||||||
const SESSION_COOKIE_NAME: &str = "brewlog_session";
|
|
||||||
|
|
||||||
// --- Request/Response types ---
|
// --- Request/Response types ---
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
|
|
@ -432,9 +430,10 @@ pub(crate) async fn passkey_add_start(
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(skip(state, payload))]
|
#[tracing::instrument(skip(state, auth_user, payload))]
|
||||||
pub(crate) async fn passkey_add_finish(
|
pub(crate) async fn passkey_add_finish(
|
||||||
State(state): State<AppState>,
|
State(state): State<AppState>,
|
||||||
|
auth_user: AuthenticatedUser,
|
||||||
Json(payload): Json<PasskeyAddFinishRequest>,
|
Json(payload): Json<PasskeyAddFinishRequest>,
|
||||||
) -> Result<StatusCode, StatusCode> {
|
) -> Result<StatusCode, StatusCode> {
|
||||||
let (user_id, reg_state) = state
|
let (user_id, reg_state) = state
|
||||||
|
|
@ -443,6 +442,16 @@ pub(crate) async fn passkey_add_finish(
|
||||||
.await
|
.await
|
||||||
.ok_or(StatusCode::BAD_REQUEST)?;
|
.ok_or(StatusCode::BAD_REQUEST)?;
|
||||||
|
|
||||||
|
// Verify the authenticated user matches the challenge owner
|
||||||
|
if auth_user.0.id != user_id {
|
||||||
|
warn!(
|
||||||
|
auth_user_id = %auth_user.0.id,
|
||||||
|
challenge_user_id = %user_id,
|
||||||
|
"passkey add finish: user mismatch"
|
||||||
|
);
|
||||||
|
return Err(StatusCode::FORBIDDEN);
|
||||||
|
}
|
||||||
|
|
||||||
let passkey = state
|
let passkey = state
|
||||||
.webauthn
|
.webauthn
|
||||||
.finish_passkey_registration(&payload.credential, ®_state)
|
.finish_passkey_registration(&payload.credential, ®_state)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue