PACS System 0.1.0
PACS DICOM system library
Loading...
Searching...
No Matches
kcenon::pacs::security::atna_audit_logger Class Reference

RFC 3881 XML audit message generator. More...

#include <atna_audit_logger.h>

Collaboration diagram for kcenon::pacs::security::atna_audit_logger:
Collaboration graph

Static Public Member Functions

static std::string to_xml (const atna_audit_message &message)
 Serialize an audit message to RFC 3881 XML.
 
static atna_audit_message build_application_activity (const std::string &source_id, const std::string &app_name, bool is_start, atna_event_outcome outcome=atna_event_outcome::success)
 Build Application Activity audit message (start/stop)
 
static atna_audit_message build_dicom_instances_accessed (const std::string &source_id, const std::string &user_id, const std::string &user_ip, const std::string &study_uid, const std::string &patient_id="", atna_event_outcome outcome=atna_event_outcome::success)
 Build DICOM Instances Accessed audit message (C-FIND, QIDO-RS)
 
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 atna_audit_message build_study_deleted (const std::string &source_id, const std::string &user_id, const std::string &user_ip, const std::string &study_uid, const std::string &patient_id="", atna_event_outcome outcome=atna_event_outcome::success)
 Build Study Deleted audit message.
 
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)
 
static atna_audit_message build_export (const std::string &source_id, const std::string &user_id, const std::string &user_ip, const std::string &dest_id, const std::string &study_uid, const std::string &patient_id="", atna_event_outcome outcome=atna_event_outcome::success)
 Build Export audit message (media/network export)
 

Static Private Member Functions

static std::string xml_escape (const std::string &str)
 
static std::string format_datetime (std::chrono::system_clock::time_point tp)
 
static std::string format_coded_value_attrs (const atna_coded_value &cv)
 

Detailed Description

RFC 3881 XML audit message generator.

Generates well-formed XML audit messages compliant with DICOM PS3.15 Annex A.5 / RFC 3881.

Definition at line 423 of file atna_audit_logger.h.

Member Function Documentation

◆ build_application_activity()

atna_audit_message kcenon::pacs::security::atna_audit_logger::build_application_activity ( const std::string & source_id,
const std::string & app_name,
bool is_start,
atna_event_outcome outcome = atna_event_outcome::success )
staticnodiscard

Build Application Activity audit message (start/stop)

Parameters
source_idAudit source identifier
app_nameApplication name
is_starttrue for application start, false for stop
outcomeEvent outcome
Returns
Complete audit message

Definition at line 156 of file atna_audit_logger.cpp.

160 {
161
162 atna_audit_message msg;
164 msg.event_type_codes.push_back(
167 msg.event_action = atna_event_action::execute;
168 msg.event_date_time = std::chrono::system_clock::now();
169 msg.event_outcome = outcome;
170
171 atna_active_participant ap;
172 ap.user_id = app_name;
173 ap.user_is_requestor = false;
174 ap.role_id_codes.push_back(atna_role_ids::application);
175 msg.active_participants.push_back(std::move(ap));
176
177 msg.audit_source.audit_source_id = source_id;
178
179 return msg;
180}
const atna_coded_value application_activity
Application Activity (110100) — Start/Stop.
const atna_coded_value application_start
Application Start.
const atna_coded_value application_stop
Application Stop.
const atna_coded_value application
Application (110150)

References kcenon::pacs::security::atna_audit_message::active_participants, kcenon::pacs::security::atna_role_ids::application, kcenon::pacs::security::atna_event_ids::application_activity, kcenon::pacs::security::atna_event_types::application_start, kcenon::pacs::security::atna_event_types::application_stop, kcenon::pacs::security::atna_audit_message::audit_source, kcenon::pacs::security::atna_audit_source::audit_source_id, kcenon::pacs::security::atna_audit_message::event_action, kcenon::pacs::security::atna_audit_message::event_date_time, kcenon::pacs::security::atna_audit_message::event_id, kcenon::pacs::security::atna_audit_message::event_outcome, kcenon::pacs::security::atna_audit_message::event_type_codes, and kcenon::pacs::security::execute.

◆ build_dicom_instances_accessed()

atna_audit_message kcenon::pacs::security::atna_audit_logger::build_dicom_instances_accessed ( const std::string & source_id,
const std::string & user_id,
const std::string & user_ip,
const std::string & study_uid,
const std::string & patient_id = "",
atna_event_outcome outcome = atna_event_outcome::success )
staticnodiscard

Build DICOM Instances Accessed audit message (C-FIND, QIDO-RS)

Parameters
source_idAudit source identifier
user_idUser/AE Title that performed the access
user_ipSource IP address
study_uidStudy Instance UID accessed
patient_idPatient ID (if available)
outcomeEvent outcome
Returns
Complete audit message

Definition at line 182 of file atna_audit_logger.cpp.

188 {
189
190 atna_audit_message msg;
192 msg.event_action = atna_event_action::read;
193 msg.event_date_time = std::chrono::system_clock::now();
194 msg.event_outcome = outcome;
195
196 atna_active_participant ap;
197 ap.user_id = user_id;
198 ap.user_is_requestor = true;
199 ap.network_access_point_id = user_ip;
200 ap.network_access_point_type = atna_network_access_type::ip_address;
201 msg.active_participants.push_back(std::move(ap));
202
203 msg.audit_source.audit_source_id = source_id;
204
205 // Study object
206 if (!study_uid.empty()) {
207 atna_participant_object obj;
208 obj.object_type = atna_object_type::system_object;
209 obj.object_role = atna_object_role::report;
210 obj.object_id_type_code = atna_object_id_types::study_instance_uid;
211 obj.object_id = study_uid;
212 msg.participant_objects.push_back(std::move(obj));
213 }
214
215 // Patient object
216 if (!patient_id.empty()) {
217 atna_participant_object patient_obj;
218 patient_obj.object_type = atna_object_type::person;
219 patient_obj.object_role = atna_object_role::patient;
220 patient_obj.object_id_type_code = atna_object_id_types::patient_number;
221 patient_obj.object_id = patient_id;
222 msg.participant_objects.push_back(std::move(patient_obj));
223 }
224
225 return msg;
226}
constexpr dicom_tag patient_id
Patient ID.
const atna_coded_value dicom_instances_accessed
DICOM Instances Accessed (110103)
const atna_coded_value study_instance_uid
Study Instance UID.
const atna_coded_value patient_number
Patient Number (RFC 3881 defined)

References kcenon::pacs::security::atna_audit_message::active_participants, kcenon::pacs::security::atna_audit_message::audit_source, kcenon::pacs::security::atna_audit_source::audit_source_id, kcenon::pacs::security::atna_event_ids::dicom_instances_accessed, kcenon::pacs::security::atna_audit_message::event_action, kcenon::pacs::security::atna_audit_message::event_date_time, kcenon::pacs::security::atna_audit_message::event_id, kcenon::pacs::security::atna_audit_message::event_outcome, kcenon::pacs::security::ip_address, kcenon::pacs::security::atna_participant_object::object_id, kcenon::pacs::security::atna_participant_object::object_id_type_code, kcenon::pacs::security::atna_participant_object::object_role, kcenon::pacs::security::atna_participant_object::object_type, kcenon::pacs::security::atna_audit_message::participant_objects, kcenon::pacs::security::patient, kcenon::pacs::security::atna_object_id_types::patient_number, kcenon::pacs::security::person, kcenon::pacs::security::read, kcenon::pacs::security::report, kcenon::pacs::security::atna_object_id_types::study_instance_uid, and kcenon::pacs::security::system_object.

◆ build_dicom_instances_transferred()

atna_audit_message kcenon::pacs::security::atna_audit_logger::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 )
staticnodiscard

Build DICOM Instances Transferred audit message (C-STORE, C-MOVE)

Parameters
source_idAudit source identifier
source_aeSource AE Title
source_ipSource IP address
dest_aeDestination AE Title
dest_ipDestination IP address
study_uidStudy Instance UID
patient_idPatient ID (if available)
is_importtrue if receiving (import), false if sending (export)
outcomeEvent outcome
Returns
Complete audit message

Definition at line 228 of file atna_audit_logger.cpp.

237 {
238
239 atna_audit_message msg;
241 msg.event_action = is_import ? atna_event_action::create
243 msg.event_date_time = std::chrono::system_clock::now();
244 msg.event_outcome = outcome;
245
246 // Source participant
247 atna_active_participant src;
248 src.user_id = source_ae;
249 src.user_is_requestor = !is_import;
250 src.network_access_point_id = source_ip;
251 src.network_access_point_type = atna_network_access_type::ip_address;
252 src.role_id_codes.push_back(atna_role_ids::source);
253 msg.active_participants.push_back(std::move(src));
254
255 // Destination participant
256 atna_active_participant dst;
257 dst.user_id = dest_ae;
258 dst.user_is_requestor = is_import;
259 dst.network_access_point_id = dest_ip;
260 dst.network_access_point_type = atna_network_access_type::ip_address;
261 dst.role_id_codes.push_back(atna_role_ids::destination);
262 msg.active_participants.push_back(std::move(dst));
263
264 msg.audit_source.audit_source_id = source_id;
265
266 // Study object
267 if (!study_uid.empty()) {
268 atna_participant_object obj;
269 obj.object_type = atna_object_type::system_object;
270 obj.object_role = atna_object_role::report;
271 obj.object_id_type_code = atna_object_id_types::study_instance_uid;
272 obj.object_id = study_uid;
273 msg.participant_objects.push_back(std::move(obj));
274 }
275
276 // Patient object
277 if (!patient_id.empty()) {
278 atna_participant_object patient_obj;
279 patient_obj.object_type = atna_object_type::person;
280 patient_obj.object_role = atna_object_role::patient;
281 patient_obj.object_id_type_code = atna_object_id_types::patient_number;
282 patient_obj.object_id = patient_id;
283 msg.participant_objects.push_back(std::move(patient_obj));
284 }
285
286 return msg;
287}
const atna_coded_value dicom_instances_transferred
DICOM Instances Transferred (110104)
const atna_coded_value source
Source Role ID (110153)
const atna_coded_value destination
Destination Role ID (110152)

References kcenon::pacs::security::atna_audit_message::active_participants, kcenon::pacs::security::atna_audit_message::audit_source, kcenon::pacs::security::atna_audit_source::audit_source_id, kcenon::pacs::security::create, kcenon::pacs::security::atna_role_ids::destination, kcenon::pacs::security::atna_event_ids::dicom_instances_transferred, kcenon::pacs::security::atna_audit_message::event_action, kcenon::pacs::security::atna_audit_message::event_date_time, kcenon::pacs::security::atna_audit_message::event_id, kcenon::pacs::security::atna_audit_message::event_outcome, kcenon::pacs::security::ip_address, kcenon::pacs::security::atna_active_participant::network_access_point_id, kcenon::pacs::security::atna_active_participant::network_access_point_type, kcenon::pacs::security::atna_participant_object::object_id, kcenon::pacs::security::atna_participant_object::object_id_type_code, kcenon::pacs::security::atna_participant_object::object_role, kcenon::pacs::security::atna_participant_object::object_type, kcenon::pacs::security::atna_audit_message::participant_objects, kcenon::pacs::security::patient, kcenon::pacs::security::atna_object_id_types::patient_number, kcenon::pacs::security::person, kcenon::pacs::security::read, kcenon::pacs::security::report, kcenon::pacs::security::atna_active_participant::role_id_codes, kcenon::pacs::security::atna_role_ids::source, kcenon::pacs::security::atna_object_id_types::study_instance_uid, kcenon::pacs::security::system_object, kcenon::pacs::security::atna_active_participant::user_id, and kcenon::pacs::security::atna_active_participant::user_is_requestor.

Referenced by kcenon::pacs::security::atna_service_auditor::audit_instance_stored().

Here is the caller graph for this function:

◆ build_export()

atna_audit_message kcenon::pacs::security::atna_audit_logger::build_export ( const std::string & source_id,
const std::string & user_id,
const std::string & user_ip,
const std::string & dest_id,
const std::string & study_uid,
const std::string & patient_id = "",
atna_event_outcome outcome = atna_event_outcome::success )
staticnodiscard

Build Export audit message (media/network export)

Parameters
source_idAudit source identifier
user_idUser/AE Title that exported data
user_ipSource IP address
dest_idDestination identifier
study_uidStudy Instance UID
patient_idPatient ID
outcomeEvent outcome
Returns
Complete audit message

Definition at line 438 of file atna_audit_logger.cpp.

445 {
446
447 atna_audit_message msg;
448 msg.event_id = atna_event_ids::data_export;
449 msg.event_action = atna_event_action::read;
450 msg.event_date_time = std::chrono::system_clock::now();
451 msg.event_outcome = outcome;
452
453 // Exporter
454 atna_active_participant exporter;
455 exporter.user_id = user_id;
456 exporter.user_is_requestor = true;
457 exporter.network_access_point_id = user_ip;
458 exporter.network_access_point_type = atna_network_access_type::ip_address;
459 exporter.role_id_codes.push_back(atna_role_ids::source);
460 msg.active_participants.push_back(std::move(exporter));
461
462 // Destination
463 atna_active_participant dest;
464 dest.user_id = dest_id;
465 dest.user_is_requestor = false;
466 dest.role_id_codes.push_back(atna_role_ids::destination);
467 msg.active_participants.push_back(std::move(dest));
468
469 msg.audit_source.audit_source_id = source_id;
470
471 // Study object
472 if (!study_uid.empty()) {
473 atna_participant_object obj;
474 obj.object_type = atna_object_type::system_object;
475 obj.object_role = atna_object_role::report;
476 obj.object_id_type_code = atna_object_id_types::study_instance_uid;
477 obj.object_id = study_uid;
478 msg.participant_objects.push_back(std::move(obj));
479 }
480
481 // Patient object
482 if (!patient_id.empty()) {
483 atna_participant_object patient_obj;
484 patient_obj.object_type = atna_object_type::person;
485 patient_obj.object_role = atna_object_role::patient;
486 patient_obj.object_id_type_code = atna_object_id_types::patient_number;
487 patient_obj.object_id = patient_id;
488 msg.participant_objects.push_back(std::move(patient_obj));
489 }
490
491 return msg;
492}
const atna_coded_value data_export
Export (110106)

References kcenon::pacs::security::atna_audit_message::active_participants, kcenon::pacs::security::atna_audit_message::audit_source, kcenon::pacs::security::atna_audit_source::audit_source_id, kcenon::pacs::security::atna_event_ids::data_export, kcenon::pacs::security::atna_role_ids::destination, kcenon::pacs::security::atna_audit_message::event_action, kcenon::pacs::security::atna_audit_message::event_date_time, kcenon::pacs::security::atna_audit_message::event_id, kcenon::pacs::security::atna_audit_message::event_outcome, kcenon::pacs::security::ip_address, kcenon::pacs::security::atna_active_participant::network_access_point_id, kcenon::pacs::security::atna_active_participant::network_access_point_type, kcenon::pacs::security::atna_participant_object::object_id, kcenon::pacs::security::atna_participant_object::object_id_type_code, kcenon::pacs::security::atna_participant_object::object_role, kcenon::pacs::security::atna_participant_object::object_type, kcenon::pacs::security::atna_audit_message::participant_objects, kcenon::pacs::security::patient, kcenon::pacs::security::atna_object_id_types::patient_number, kcenon::pacs::security::person, kcenon::pacs::security::read, kcenon::pacs::security::report, kcenon::pacs::security::atna_active_participant::role_id_codes, kcenon::pacs::security::atna_role_ids::source, kcenon::pacs::security::atna_object_id_types::study_instance_uid, kcenon::pacs::security::system_object, kcenon::pacs::security::atna_active_participant::user_id, and kcenon::pacs::security::atna_active_participant::user_is_requestor.

◆ build_query()

atna_audit_message kcenon::pacs::security::atna_audit_logger::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 )
staticnodiscard

Build Query audit message (C-FIND, QIDO-RS)

Parameters
source_idAudit source identifier
user_idUser/AE Title that performed the query
user_ipSource IP address
query_dataThe query parameters (will be encoded)
patient_idPatient ID from query (if available)
outcomeEvent outcome
Returns
Complete audit message

Definition at line 393 of file atna_audit_logger.cpp.

399 {
400
401 atna_audit_message msg;
402 msg.event_id = atna_event_ids::query;
403 msg.event_action = atna_event_action::execute;
404 msg.event_date_time = std::chrono::system_clock::now();
405 msg.event_outcome = outcome;
406
407 atna_active_participant ap;
408 ap.user_id = user_id;
409 ap.user_is_requestor = true;
410 ap.network_access_point_id = user_ip;
411 ap.network_access_point_type = atna_network_access_type::ip_address;
412 ap.role_id_codes.push_back(atna_role_ids::source);
413 msg.active_participants.push_back(std::move(ap));
414
415 msg.audit_source.audit_source_id = source_id;
416
417 // Query object
418 atna_participant_object query_obj;
419 query_obj.object_type = atna_object_type::system_object;
420 query_obj.object_role = atna_object_role::query;
421 query_obj.object_id_type_code = atna_object_id_types::sop_class_uid;
422 query_obj.object_query = query_data;
423 msg.participant_objects.push_back(std::move(query_obj));
424
425 // Patient object
426 if (!patient_id.empty()) {
427 atna_participant_object patient_obj;
428 patient_obj.object_type = atna_object_type::person;
429 patient_obj.object_role = atna_object_role::patient;
430 patient_obj.object_id_type_code = atna_object_id_types::patient_number;
431 patient_obj.object_id = patient_id;
432 msg.participant_objects.push_back(std::move(patient_obj));
433 }
434
435 return msg;
436}
const atna_coded_value query
Query (110112)
const atna_coded_value sop_class_uid
SOP Class UID.

References kcenon::pacs::security::atna_audit_message::active_participants, kcenon::pacs::security::atna_audit_message::audit_source, kcenon::pacs::security::atna_audit_source::audit_source_id, kcenon::pacs::security::atna_audit_message::event_action, kcenon::pacs::security::atna_audit_message::event_date_time, kcenon::pacs::security::atna_audit_message::event_id, kcenon::pacs::security::atna_audit_message::event_outcome, kcenon::pacs::security::execute, kcenon::pacs::security::ip_address, kcenon::pacs::security::atna_participant_object::object_id, kcenon::pacs::security::atna_participant_object::object_id_type_code, kcenon::pacs::security::atna_participant_object::object_query, kcenon::pacs::security::atna_participant_object::object_role, kcenon::pacs::security::atna_participant_object::object_type, kcenon::pacs::security::atna_audit_message::participant_objects, kcenon::pacs::security::patient, kcenon::pacs::security::atna_object_id_types::patient_number, kcenon::pacs::security::person, kcenon::pacs::security::atna_event_ids::query, kcenon::pacs::security::query, kcenon::pacs::security::atna_object_id_types::sop_class_uid, kcenon::pacs::security::atna_role_ids::source, and kcenon::pacs::security::system_object.

Referenced by kcenon::pacs::security::atna_service_auditor::audit_query().

Here is the caller graph for this function:

◆ build_security_alert()

atna_audit_message kcenon::pacs::security::atna_audit_logger::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 )
staticnodiscard

Build Security Alert audit message.

Parameters
source_idAudit source identifier
user_idUser/system that triggered the alert
user_ipSource IP address
alert_descriptionDescription of the security alert
outcomeEvent outcome
Returns
Complete audit message

Definition at line 333 of file atna_audit_logger.cpp.

338 {
339
340 atna_audit_message msg;
341 msg.event_id = atna_event_ids::security_alert;
342 msg.event_action = atna_event_action::execute;
343 msg.event_date_time = std::chrono::system_clock::now();
344 msg.event_outcome = outcome;
345
346 atna_active_participant ap;
347 ap.user_id = user_id;
348 ap.user_is_requestor = true;
349 ap.network_access_point_id = user_ip;
350 ap.network_access_point_type = atna_network_access_type::ip_address;
351 msg.active_participants.push_back(std::move(ap));
352
353 msg.audit_source.audit_source_id = source_id;
354
355 // Alert description as participant object
356 atna_participant_object obj;
357 obj.object_type = atna_object_type::system_object;
358 obj.object_role = atna_object_role::security_resource;
359 obj.object_id = source_id;
360 obj.object_name = alert_description;
361 msg.participant_objects.push_back(std::move(obj));
362
363 return msg;
364}
const atna_coded_value security_alert
Security Alert (110113)

References kcenon::pacs::security::atna_audit_message::active_participants, kcenon::pacs::security::atna_audit_message::audit_source, kcenon::pacs::security::atna_audit_source::audit_source_id, kcenon::pacs::security::atna_audit_message::event_action, kcenon::pacs::security::atna_audit_message::event_date_time, kcenon::pacs::security::atna_audit_message::event_id, kcenon::pacs::security::atna_audit_message::event_outcome, kcenon::pacs::security::execute, kcenon::pacs::security::ip_address, kcenon::pacs::security::atna_participant_object::object_id, kcenon::pacs::security::atna_participant_object::object_name, kcenon::pacs::security::atna_participant_object::object_role, kcenon::pacs::security::atna_participant_object::object_type, kcenon::pacs::security::atna_audit_message::participant_objects, kcenon::pacs::security::atna_event_ids::security_alert, kcenon::pacs::security::security_resource, and kcenon::pacs::security::system_object.

Referenced by kcenon::pacs::security::atna_service_auditor::audit_security_alert().

Here is the caller graph for this function:

◆ build_study_deleted()

atna_audit_message kcenon::pacs::security::atna_audit_logger::build_study_deleted ( const std::string & source_id,
const std::string & user_id,
const std::string & user_ip,
const std::string & study_uid,
const std::string & patient_id = "",
atna_event_outcome outcome = atna_event_outcome::success )
staticnodiscard

Build Study Deleted audit message.

Parameters
source_idAudit source identifier
user_idUser/AE Title that deleted the study
user_ipSource IP address
study_uidDeleted Study Instance UID
patient_idPatient ID
outcomeEvent outcome
Returns
Complete audit message

Definition at line 289 of file atna_audit_logger.cpp.

295 {
296
297 atna_audit_message msg;
299 msg.event_action = atna_event_action::delete_action;
300 msg.event_date_time = std::chrono::system_clock::now();
301 msg.event_outcome = outcome;
302
303 atna_active_participant ap;
304 ap.user_id = user_id;
305 ap.user_is_requestor = true;
306 ap.network_access_point_id = user_ip;
307 ap.network_access_point_type = atna_network_access_type::ip_address;
308 msg.active_participants.push_back(std::move(ap));
309
310 msg.audit_source.audit_source_id = source_id;
311
312 // Study object
313 atna_participant_object obj;
314 obj.object_type = atna_object_type::system_object;
315 obj.object_role = atna_object_role::report;
316 obj.object_id_type_code = atna_object_id_types::study_instance_uid;
317 obj.object_id = study_uid;
318 msg.participant_objects.push_back(std::move(obj));
319
320 // Patient object
321 if (!patient_id.empty()) {
322 atna_participant_object patient_obj;
323 patient_obj.object_type = atna_object_type::person;
324 patient_obj.object_role = atna_object_role::patient;
325 patient_obj.object_id_type_code = atna_object_id_types::patient_number;
326 patient_obj.object_id = patient_id;
327 msg.participant_objects.push_back(std::move(patient_obj));
328 }
329
330 return msg;
331}
const atna_coded_value dicom_study_deleted
DICOM Study Deleted (110105)

References kcenon::pacs::security::atna_audit_message::active_participants, kcenon::pacs::security::atna_audit_message::audit_source, kcenon::pacs::security::atna_audit_source::audit_source_id, kcenon::pacs::security::delete_action, kcenon::pacs::security::atna_event_ids::dicom_study_deleted, kcenon::pacs::security::atna_audit_message::event_action, kcenon::pacs::security::atna_audit_message::event_date_time, kcenon::pacs::security::atna_audit_message::event_id, kcenon::pacs::security::atna_audit_message::event_outcome, kcenon::pacs::security::ip_address, kcenon::pacs::security::atna_participant_object::object_id, kcenon::pacs::security::atna_participant_object::object_id_type_code, kcenon::pacs::security::atna_participant_object::object_role, kcenon::pacs::security::atna_participant_object::object_type, kcenon::pacs::security::atna_audit_message::participant_objects, kcenon::pacs::security::patient, kcenon::pacs::security::atna_object_id_types::patient_number, kcenon::pacs::security::person, kcenon::pacs::security::report, kcenon::pacs::security::atna_object_id_types::study_instance_uid, and kcenon::pacs::security::system_object.

◆ build_user_authentication()

atna_audit_message kcenon::pacs::security::atna_audit_logger::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 )
staticnodiscard

Build User Authentication audit message (login/logout)

Parameters
source_idAudit source identifier
user_idUser that authenticated
user_ipSource IP address
is_logintrue for login, false for logout
outcomeEvent outcome (success/failure)
Returns
Complete audit message

Definition at line 366 of file atna_audit_logger.cpp.

371 {
372
373 atna_audit_message msg;
375 msg.event_type_codes.push_back(
377 msg.event_action = atna_event_action::execute;
378 msg.event_date_time = std::chrono::system_clock::now();
379 msg.event_outcome = outcome;
380
381 atna_active_participant ap;
382 ap.user_id = user_id;
383 ap.user_is_requestor = true;
384 ap.network_access_point_id = user_ip;
385 ap.network_access_point_type = atna_network_access_type::ip_address;
386 msg.active_participants.push_back(std::move(ap));
387
388 msg.audit_source.audit_source_id = source_id;
389
390 return msg;
391}
const atna_coded_value user_authentication
User Authentication (110114)

References kcenon::pacs::security::atna_audit_message::active_participants, kcenon::pacs::security::atna_audit_message::audit_source, kcenon::pacs::security::atna_audit_source::audit_source_id, kcenon::pacs::security::atna_audit_message::event_action, kcenon::pacs::security::atna_audit_message::event_date_time, kcenon::pacs::security::atna_audit_message::event_id, kcenon::pacs::security::atna_audit_message::event_outcome, kcenon::pacs::security::atna_audit_message::event_type_codes, kcenon::pacs::security::execute, kcenon::pacs::security::ip_address, kcenon::pacs::security::atna_event_types::login, kcenon::pacs::security::atna_event_types::logout, and kcenon::pacs::security::atna_event_ids::user_authentication.

Referenced by kcenon::pacs::security::atna_service_auditor::audit_authentication().

Here is the caller graph for this function:

◆ format_coded_value_attrs()

std::string kcenon::pacs::security::atna_audit_logger::format_coded_value_attrs ( const atna_coded_value & cv)
staticnodiscardprivate

Definition at line 538 of file atna_audit_logger.cpp.

539 {
540
541 std::ostringstream oss;
542 oss << "csd-code=\"" << xml_escape(cv.code) << "\"";
543
544 if (!cv.code_system_name.empty()) {
545 oss << " codeSystemName=\"" << xml_escape(cv.code_system_name) << "\"";
546 }
547
548 if (!cv.display_name.empty()) {
549 oss << " originalText=\"" << xml_escape(cv.display_name) << "\"";
550 }
551
552 return oss.str();
553}
static std::string xml_escape(const std::string &str)
@ cv
Cleavage View - for medial breast tissue.

References xml_escape().

Referenced by to_xml().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ format_datetime()

std::string kcenon::pacs::security::atna_audit_logger::format_datetime ( std::chrono::system_clock::time_point tp)
staticnodiscardprivate

Definition at line 516 of file atna_audit_logger.cpp.

517 {
518
519 auto time_t_val = std::chrono::system_clock::to_time_t(tp);
520 auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(
521 tp.time_since_epoch()) % 1000;
522
523 std::tm tm_val{};
524#if defined(_WIN32)
525 gmtime_s(&tm_val, &time_t_val);
526#else
527 gmtime_r(&time_t_val, &tm_val);
528#endif
529
530 std::ostringstream oss;
531 oss << std::put_time(&tm_val, "%Y-%m-%dT%H:%M:%S")
532 << '.' << std::setfill('0') << std::setw(3) << ms.count()
533 << "Z";
534
535 return oss.str();
536}

Referenced by to_xml().

Here is the caller graph for this function:

◆ to_xml()

std::string kcenon::pacs::security::atna_audit_logger::to_xml ( const atna_audit_message & message)
staticnodiscard

Serialize an audit message to RFC 3881 XML.

Parameters
messageThe audit message to serialize
Returns
Well-formed XML string

Definition at line 18 of file atna_audit_logger.cpp.

18 {
19 std::ostringstream xml;
20
21 xml << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
22 xml << "<AuditMessage>\n";
23
24 // -- EventIdentification --
25 xml << " <EventIdentification"
26 << " EventActionCode=\""
27 << static_cast<char>(msg.event_action) << "\""
28 << " EventDateTime=\"" << format_datetime(msg.event_date_time) << "\""
29 << " EventOutcomeIndicator=\""
30 << static_cast<int>(msg.event_outcome) << "\">\n";
31
32 xml << " <EventID " << format_coded_value_attrs(msg.event_id) << "/>\n";
33
34 for (const auto& etc : msg.event_type_codes) {
35 xml << " <EventTypeCode " << format_coded_value_attrs(etc)
36 << "/>\n";
37 }
38
39 xml << " </EventIdentification>\n";
40
41 // -- ActiveParticipant(s) --
42 for (const auto& ap : msg.active_participants) {
43 xml << " <ActiveParticipant"
44 << " UserID=\"" << xml_escape(ap.user_id) << "\"";
45
46 if (!ap.alternative_user_id.empty()) {
47 xml << " AlternativeUserID=\""
48 << xml_escape(ap.alternative_user_id) << "\"";
49 }
50
51 if (!ap.user_name.empty()) {
52 xml << " UserName=\"" << xml_escape(ap.user_name) << "\"";
53 }
54
55 xml << " UserIsRequestor=\""
56 << (ap.user_is_requestor ? "true" : "false") << "\"";
57
58 if (!ap.network_access_point_id.empty()) {
59 xml << " NetworkAccessPointID=\""
60 << xml_escape(ap.network_access_point_id) << "\""
61 << " NetworkAccessPointTypeCode=\""
62 << static_cast<int>(ap.network_access_point_type) << "\"";
63 }
64
65 if (ap.role_id_codes.empty()) {
66 xml << "/>\n";
67 } else {
68 xml << ">\n";
69 for (const auto& role : ap.role_id_codes) {
70 xml << " <RoleIDCode "
71 << format_coded_value_attrs(role) << "/>\n";
72 }
73 xml << " </ActiveParticipant>\n";
74 }
75 }
76
77 // -- AuditSourceIdentification --
78 xml << " <AuditSourceIdentification"
79 << " AuditSourceID=\""
80 << xml_escape(msg.audit_source.audit_source_id) << "\"";
81
82 if (!msg.audit_source.audit_enterprise_site_id.empty()) {
83 xml << " AuditEnterpriseSiteID=\""
84 << xml_escape(msg.audit_source.audit_enterprise_site_id) << "\"";
85 }
86
87 if (msg.audit_source.audit_source_type_codes.empty()) {
88 xml << "/>\n";
89 } else {
90 xml << ">\n";
91 for (auto type_code : msg.audit_source.audit_source_type_codes) {
92 xml << " <AuditSourceTypeCode code=\""
93 << static_cast<int>(type_code) << "\"/>\n";
94 }
95 xml << " </AuditSourceIdentification>\n";
96 }
97
98 // -- ParticipantObjectIdentification(s) --
99 for (const auto& po : msg.participant_objects) {
100 xml << " <ParticipantObjectIdentification"
101 << " ParticipantObjectTypeCode=\""
102 << static_cast<int>(po.object_type) << "\""
103 << " ParticipantObjectTypeCodeRole=\""
104 << static_cast<int>(po.object_role) << "\"";
105
106 if (!po.object_id.empty()) {
107 xml << " ParticipantObjectID=\""
108 << xml_escape(po.object_id) << "\"";
109 }
110
111 if (!po.object_name.empty()) {
112 xml << " ParticipantObjectName=\""
113 << xml_escape(po.object_name) << "\"";
114 }
115
116 bool has_children = !po.object_id_type_code.code.empty() ||
117 !po.object_query.empty() ||
118 !po.object_details.empty();
119
120 if (!has_children) {
121 xml << "/>\n";
122 } else {
123 xml << ">\n";
124
125 if (!po.object_id_type_code.code.empty()) {
126 xml << " <ParticipantObjectIDTypeCode "
127 << format_coded_value_attrs(po.object_id_type_code)
128 << "/>\n";
129 }
130
131 if (!po.object_query.empty()) {
132 xml << " <ParticipantObjectQuery>"
133 << xml_escape(po.object_query)
134 << "</ParticipantObjectQuery>\n";
135 }
136
137 for (const auto& detail : po.object_details) {
138 xml << " <ParticipantObjectDetail"
139 << " type=\"" << xml_escape(detail.type) << "\""
140 << " value=\"" << xml_escape(detail.value) << "\"/>\n";
141 }
142
143 xml << " </ParticipantObjectIdentification>\n";
144 }
145 }
146
147 xml << "</AuditMessage>\n";
148
149 return xml.str();
150}
static std::string format_coded_value_attrs(const atna_coded_value &cv)
static std::string format_datetime(std::chrono::system_clock::time_point tp)

References kcenon::pacs::security::atna_audit_message::active_participants, kcenon::pacs::security::atna_audit_source::audit_enterprise_site_id, kcenon::pacs::security::atna_audit_message::audit_source, kcenon::pacs::security::atna_audit_source::audit_source_id, kcenon::pacs::security::atna_audit_source::audit_source_type_codes, kcenon::pacs::security::atna_audit_message::event_action, kcenon::pacs::security::atna_audit_message::event_date_time, kcenon::pacs::security::atna_audit_message::event_id, kcenon::pacs::security::atna_audit_message::event_outcome, kcenon::pacs::security::atna_audit_message::event_type_codes, format_coded_value_attrs(), format_datetime(), kcenon::pacs::security::atna_audit_message::participant_objects, and xml_escape().

Referenced by kcenon::pacs::security::atna_service_auditor::send_audit().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ xml_escape()

std::string kcenon::pacs::security::atna_audit_logger::xml_escape ( const std::string & str)
staticnodiscardprivate

Definition at line 498 of file atna_audit_logger.cpp.

498 {
499 std::string result;
500 result.reserve(str.size());
501
502 for (char c : str) {
503 switch (c) {
504 case '&': result += "&amp;"; break;
505 case '<': result += "&lt;"; break;
506 case '>': result += "&gt;"; break;
507 case '"': result += "&quot;"; break;
508 case '\'': result += "&apos;"; break;
509 default: result += c; break;
510 }
511 }
512
513 return result;
514}

Referenced by format_coded_value_attrs(), and to_xml().

Here is the caller graph for this function:

The documentation for this class was generated from the following files: