Skip to main content

manta_server/server/audit/
auth.rs

1//! The `/v2/auth/token` attempt event.
2//!
3//! `/v2/auth/*` is outside the [`super::audit_requests`] middleware —
4//! there is no bearer token yet (the caller is asking for one) — so
5//! the auth handler emits its own event, with the identity taken from
6//! the submitted username. The password never reaches this module.
7
8use axum::http::StatusCode;
9
10use super::{
11  AuditLog,
12  event::{Actor, Client, EventKind, Outcome, Request, Verdict},
13};
14
15/// Emit an [`EventKind::AuthAttempt`] event for a `/v2/auth/token` call.
16pub fn send_auth_audit(
17  audit: &AuditLog,
18  success: bool,
19  username: &str,
20  source_ip: &str,
21  site: &str,
22) {
23  let mut event = audit.event(EventKind::AuthAttempt, "auth.token".into());
24  event.actor = Actor {
25    username: Some(username.to_string()),
26    ..Actor::default()
27  };
28  event.client = Client {
29    ip: Some(source_ip.to_string()),
30    forwarded_for: None,
31  };
32  event.site = Some(site.to_string());
33  event.request = Request {
34    method: "POST".into(),
35    route: "/v2/auth/token".into(),
36    path: "/v2/auth/token".into(),
37    query: None,
38  };
39  let status = if success {
40    StatusCode::OK
41  } else {
42    StatusCode::UNAUTHORIZED
43  };
44  event.outcome = Outcome {
45    result: Verdict::from_status(status),
46    status: status.as_u16(),
47    duration_ms: 0,
48  };
49  audit.emit(event);
50}
51
52#[cfg(test)]
53mod tests {
54  use std::sync::Arc;
55
56  use super::*;
57  use crate::server::audit::CaptureSink;
58
59  #[test]
60  fn records_username_site_and_outcome() {
61    let sink = Arc::new(CaptureSink::default());
62    let log = AuditLog::with_sinks(vec![sink.clone()]);
63    send_auth_audit(&log, false, "alice", "10.0.0.1", "alps");
64    let events = sink.0.lock().unwrap();
65    let e = &events[0];
66    assert_eq!(e.kind, EventKind::AuthAttempt);
67    assert_eq!(e.actor.username.as_deref(), Some("alice"));
68    assert_eq!(e.client.ip.as_deref(), Some("10.0.0.1"));
69    assert_eq!(e.site.as_deref(), Some("alps"));
70    assert_eq!(e.outcome.result, Verdict::Denied);
71  }
72}