1use corium_protocol::authz::{Access, Principal};
11
12use crate::model::action_name;
13
14#[derive(Clone, Debug)]
16pub struct AuditEvent {
17 pub subject: String,
19 pub provider: String,
21 pub action: &'static str,
23 pub database: Option<String>,
25 pub object: String,
27 pub allowed: bool,
29 pub reason: Option<String>,
31 pub path: Option<String>,
33 pub views: Vec<String>,
35 pub authz_t: u64,
37 pub source: String,
39}
40
41impl AuditEvent {
42 #[must_use]
44 pub fn new(
45 principal: &Principal,
46 access: &Access,
47 decision: &crate::AuthzDecision,
48 source: &str,
49 ) -> Self {
50 Self {
51 subject: principal.subject.clone(),
52 provider: principal.provider.clone(),
53 action: action_name(access.action),
54 database: access.database.clone(),
55 object: decision.object.clone(),
56 allowed: decision.is_allowed(),
57 reason: decision.reason.clone(),
58 path: decision.path.clone(),
59 views: decision.views.clone(),
60 authz_t: decision.authz_t,
61 source: source.to_owned(),
62 }
63 }
64}
65
66pub trait AuditSink: Send + Sync + 'static {
68 fn record(&self, event: &AuditEvent);
70}
71
72#[derive(Clone, Copy, Debug, Default)]
75pub struct TracingAudit;
76
77impl AuditSink for TracingAudit {
78 fn record(&self, event: &AuditEvent) {
79 if event.allowed {
80 tracing::debug!(
81 target: "corium_authz::audit",
82 subject = %event.subject,
83 provider = %event.provider,
84 action = event.action,
85 object = %event.object,
86 path = event.path.as_deref().unwrap_or(""),
87 views = ?event.views,
88 authz_t = event.authz_t,
89 source = %event.source,
90 "authorization allowed"
91 );
92 } else {
93 tracing::info!(
94 target: "corium_authz::audit",
95 subject = %event.subject,
96 provider = %event.provider,
97 action = event.action,
98 object = %event.object,
99 reason = event.reason.as_deref().unwrap_or(""),
100 authz_t = event.authz_t,
101 source = %event.source,
102 "authorization denied"
103 );
104 }
105 }
106}
107
108#[derive(Clone, Copy, Debug, Default)]
110pub struct NullAudit;
111
112impl AuditSink for NullAudit {
113 fn record(&self, _event: &AuditEvent) {}
114}