PACS System 0.1.0
PACS DICOM system library
Loading...
Searching...
No Matches
atna_service_auditor.cpp
Go to the documentation of this file.
1
7
9
10// =============================================================================
11// Construction
12// =============================================================================
13
15 const syslog_transport_config& config,
16 std::string audit_source_id)
17 : audit_source_id_(std::move(audit_source_id)),
18 transport_(config) {}
19
21 atna_service_auditor&& other) noexcept
22 : audit_source_id_(std::move(other.audit_source_id_)),
23 transport_(std::move(other.transport_)),
24 enabled_(other.enabled_.load(std::memory_order_relaxed)),
25 events_sent_(other.events_sent_.load(std::memory_order_relaxed)),
26 events_failed_(other.events_failed_.load(std::memory_order_relaxed)) {}
27
29 atna_service_auditor&& other) noexcept {
30 if (this != &other) {
31 audit_source_id_ = std::move(other.audit_source_id_);
32 transport_ = std::move(other.transport_);
33 enabled_.store(other.enabled_.load(std::memory_order_relaxed),
34 std::memory_order_relaxed);
35 events_sent_.store(other.events_sent_.load(std::memory_order_relaxed),
36 std::memory_order_relaxed);
37 events_failed_.store(
38 other.events_failed_.load(std::memory_order_relaxed),
39 std::memory_order_relaxed);
40 }
41 return *this;
42}
43
44// =============================================================================
45// DICOM Service Audit Methods
46// =============================================================================
47
49 const std::string& source_ae,
50 const std::string& dest_ae,
51 const std::string& study_uid,
52 const std::string& patient_id,
53 bool success) {
54
55 if (!enabled_.load(std::memory_order_relaxed)) {
56 return;
57 }
58
61
64 source_ae, // source AE
65 "", // source IP (not available at service level)
66 dest_ae, // destination AE
67 "", // destination IP (not available at service level)
68 study_uid,
69 patient_id,
70 true, // is_import (SCP receiving)
71 outcome);
72
73 send_audit(msg);
74}
75
77 const std::string& calling_ae,
78 const std::string& called_ae,
79 const std::string& query_level,
80 bool success) {
81
82 if (!enabled_.load(std::memory_order_relaxed)) {
83 return;
84 }
85
88
89 // Use query level as query_data for the audit trail
92 calling_ae,
93 "", // user IP (not available at service level)
94 "QueryLevel=" + query_level + " CalledAE=" + called_ae,
95 "", // patient_id (not available from query keys here)
96 outcome);
97
98 send_audit(msg);
99}
100
102 const std::string& user_id,
103 bool is_login,
104 bool success) {
105
106 if (!enabled_.load(std::memory_order_relaxed)) {
107 return;
108 }
109
110 auto outcome = success ? atna_event_outcome::success
112
115 user_id,
116 "", // user IP (not available at this level)
117 is_login,
118 outcome);
119
120 send_audit(msg);
121}
122
124 const std::string& user_id,
125 const std::string& alert_description) {
126
127 if (!enabled_.load(std::memory_order_relaxed)) {
128 return;
129 }
130
133 user_id,
134 "", // user IP (not available at this level)
135 alert_description);
136
137 send_audit(msg);
138}
139
140// =============================================================================
141// Enable / Disable
142// =============================================================================
143
144void atna_service_auditor::set_enabled(bool enabled) noexcept {
145 enabled_.store(enabled, std::memory_order_relaxed);
146}
147
148bool atna_service_auditor::is_enabled() const noexcept {
149 return enabled_.load(std::memory_order_relaxed);
150}
151
152// =============================================================================
153// Statistics
154// =============================================================================
155
156size_t atna_service_auditor::events_sent() const noexcept {
157 return events_sent_.load(std::memory_order_relaxed);
158}
159
160size_t atna_service_auditor::events_failed() const noexcept {
161 return events_failed_.load(std::memory_order_relaxed);
162}
163
165 events_sent_.store(0, std::memory_order_relaxed);
166 events_failed_.store(0, std::memory_order_relaxed);
167}
168
169// =============================================================================
170// Configuration Access
171// =============================================================================
172
173const std::string& atna_service_auditor::audit_source_id() const noexcept {
174 return audit_source_id_;
175}
176
178 return transport_;
179}
180
181// =============================================================================
182// Private Helpers
183// =============================================================================
184
186 auto xml = atna_audit_logger::to_xml(message);
187 auto result = transport_.send(xml);
188
189 if (result.is_ok()) {
190 events_sent_.fetch_add(1, std::memory_order_relaxed);
191 } else {
192 events_failed_.fetch_add(1, std::memory_order_relaxed);
193 }
194}
195
196} // namespace kcenon::pacs::security
High-level facade for ATNA audit logging in DICOM services.
static atna_audit_message build_dicom_instances_transferred(const std::string &source_id, const std::string &source_ae, const std::string &source_ip, const std::string &dest_ae, const std::string &dest_ip, const std::string &study_uid, const std::string &patient_id="", bool is_import=true, atna_event_outcome outcome=atna_event_outcome::success)
Build DICOM Instances Transferred audit message (C-STORE, C-MOVE)
static std::string to_xml(const atna_audit_message &message)
Serialize an audit message to RFC 3881 XML.
static atna_audit_message build_security_alert(const std::string &source_id, const std::string &user_id, const std::string &user_ip, const std::string &alert_description, atna_event_outcome outcome=atna_event_outcome::serious_failure)
Build Security Alert audit message.
static atna_audit_message build_user_authentication(const std::string &source_id, const std::string &user_id, const std::string &user_ip, bool is_login, atna_event_outcome outcome=atna_event_outcome::success)
Build User Authentication audit message (login/logout)
static atna_audit_message build_query(const std::string &source_id, const std::string &user_id, const std::string &user_ip, const std::string &query_data, const std::string &patient_id="", atna_event_outcome outcome=atna_event_outcome::success)
Build Query audit message (C-FIND, QIDO-RS)
High-level facade for emitting ATNA audit events from DICOM services.
size_t events_failed() const noexcept
Get the number of audit event send failures.
void audit_authentication(const std::string &user_id, bool is_login, bool success)
Audit a User Authentication event.
void set_enabled(bool enabled) noexcept
Enable or disable audit event emission.
size_t events_sent() const noexcept
Get the number of audit events successfully sent.
std::atomic< bool > enabled_
Whether audit is enabled.
bool is_enabled() const noexcept
Check if audit event emission is enabled.
std::string audit_source_id_
Audit source identifier (e.g., "PACS_SYSTEM_01")
void audit_query(const std::string &calling_ae, const std::string &called_ae, const std::string &query_level, bool success)
Audit a C-FIND (Query) event.
void send_audit(const atna_audit_message &message)
Send an audit message via syslog transport.
const atna_syslog_transport & transport() const noexcept
Get the underlying transport (for advanced use)
atna_service_auditor(const syslog_transport_config &config, std::string audit_source_id)
Construct an auditor with syslog transport configuration.
void audit_security_alert(const std::string &user_id, const std::string &alert_description)
Audit a Security Alert event (e.g., access denied)
const std::string & audit_source_id() const noexcept
Get the audit source identifier.
std::atomic< size_t > events_sent_
Statistics.
atna_service_auditor & operator=(const atna_service_auditor &)=delete
void reset_statistics() noexcept
Reset statistics counters.
atna_syslog_transport transport_
Syslog transport for sending audit messages.
void audit_instance_stored(const std::string &source_ae, const std::string &dest_ae, const std::string &study_uid, const std::string &patient_id, bool success)
Audit a C-STORE (DICOM Instances Transferred) event.
Sends ATNA audit messages via Syslog protocol.
kcenon::pacs::VoidResult send(const std::string &xml_message)
Send an RFC 3881 XML audit message via Syslog.
Configuration for the Syslog transport.