feat(dpop): wire audit event on dpop bound to session
This commit is contained in:
@@ -1113,6 +1113,21 @@ impl AuthApplicationService {
|
|||||||
origin,
|
origin,
|
||||||
);
|
);
|
||||||
if let Some(jkt) = validated_jkt {
|
if let Some(jkt) = validated_jkt {
|
||||||
|
// Success-path audit — records the bind so operators can
|
||||||
|
// correlate a session_id in the panel with the exact moment
|
||||||
|
// it acquired its DPoP thumbprint. Emitted BEFORE the move
|
||||||
|
// (`with_dpop_jkt` consumes `jkt`) so the prefix is safe.
|
||||||
|
// See `docs/plan/dpop.md` §Gate 10.
|
||||||
|
let jkt_prefix: String = jkt.chars().take(8).collect();
|
||||||
|
tracing::info!(
|
||||||
|
target: "audit",
|
||||||
|
event = "dpop.bound_at_login",
|
||||||
|
session_id = %session.id(),
|
||||||
|
user_id = %session.user_id(),
|
||||||
|
origin = origin.as_str(),
|
||||||
|
jkt_prefix = %jkt_prefix,
|
||||||
|
"🔒 DPoP session bound at login"
|
||||||
|
);
|
||||||
session = session.with_dpop_jkt(jkt);
|
session = session.with_dpop_jkt(jkt);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2324,8 +2339,11 @@ impl AuthApplicationService {
|
|||||||
///
|
///
|
||||||
/// Emits `auth.dpop_bind_rejected` on validation failure or when
|
/// Emits `auth.dpop_bind_rejected` on validation failure or when
|
||||||
/// the caller tries to re-bind an already-bound session (anti-
|
/// the caller tries to re-bind an already-bound session (anti-
|
||||||
/// downgrade guard). Emits `auth.dpop_bound` on the accept path
|
/// downgrade guard). Emits `dpop.bound_at_login` (with
|
||||||
/// so operators can correlate binding events with sessions.
|
/// `method = "post_redirect_bind"`) on the accept path so operators
|
||||||
|
/// can correlate binding events with sessions — same event name as
|
||||||
|
/// the POST-flow bind at `mint_session_for_authenticated_user`, per
|
||||||
|
/// `docs/plan/dpop.md` §Gate 10.
|
||||||
pub async fn bind_dpop_jkt_to_session(
|
pub async fn bind_dpop_jkt_to_session(
|
||||||
&self,
|
&self,
|
||||||
session_id: Uuid,
|
session_id: Uuid,
|
||||||
@@ -2351,11 +2369,22 @@ impl AuthApplicationService {
|
|||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
Ok(()) => {
|
Ok(()) => {
|
||||||
|
// Same event as the POST-flow bind at
|
||||||
|
// `mint_session_for_authenticated_user`; `method` is the
|
||||||
|
// constant `"post_redirect_bind"` because this path is
|
||||||
|
// exclusively OIDC-callback + magic-link redemption (both
|
||||||
|
// create the session unbound and hand off to this
|
||||||
|
// endpoint post-redirect — see `docs/plan/dpop.md`
|
||||||
|
// Gate 3). Consumers can `origin`-join with the session
|
||||||
|
// row to disambiguate if they need finer granularity.
|
||||||
|
let jkt_prefix: String = validated.chars().take(8).collect();
|
||||||
tracing::info!(
|
tracing::info!(
|
||||||
target: "audit",
|
target: "audit",
|
||||||
event = "auth.dpop_bound",
|
event = "dpop.bound_at_login",
|
||||||
session_id = %session_id,
|
session_id = %session_id,
|
||||||
"🔐 DPoP thumbprint bound to session",
|
method = "post_redirect_bind",
|
||||||
|
jkt_prefix = %jkt_prefix,
|
||||||
|
"🔒 DPoP session bound at login (post-redirect)"
|
||||||
);
|
);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user