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

Manages permissions and access checks. More...

#include <access_control_manager.h>

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

Public Member Functions

 access_control_manager ()
 
bool check_permission (const User &user, ResourceType resource, std::uint32_t action_mask) const
 
bool has_role (const User &user, Role role) const
 
auto validate_access (const user_context &ctx, ResourceType resource, std::uint32_t action_mask) -> kcenon::common::VoidResult
 Validate access for a user context.
 
AccessCheckResult check_dicom_operation (const user_context &ctx, DicomOperation op) const
 Check if a DICOM operation is allowed.
 
std::optional< user_contextget_context_for_ae (std::string_view ae_title, const std::string &session_id) const
 Get user context for an AE Title.
 
void set_role_permissions (Role role, std::vector< Permission > permissions)
 
const std::vector< Permission > & get_role_permissions (Role role) const
 
void set_storage (std::shared_ptr< security_storage_interface > storage)
 
void register_ae_title (std::string_view ae_title, std::string_view user_id)
 
void unregister_ae_title (std::string_view ae_title)
 
void set_audit_callback (AccessAuditCallback callback)
 
auto create_user (const User &user) -> kcenon::common::VoidResult
 
auto assign_role (std::string_view user_id, Role role) -> kcenon::common::VoidResult
 
auto get_user (std::string_view id) -> kcenon::common::Result< User >
 
auto get_user_by_ae_title (std::string_view ae_title) -> std::optional< User >
 Get user by AE Title.
 

Private Member Functions

void initialize_default_permissions ()
 

Static Private Member Functions

static std::pair< ResourceType, std::uint32_t > map_dicom_operation (DicomOperation op)
 Map DICOM operation to resource type and action.
 

Private Attributes

std::map< Role, std::vector< Permission > > role_permissions_
 
std::shared_ptr< security_storage_interfacestorage_
 
std::map< std::string, std::string > ae_to_user_id_
 
AccessAuditCallback audit_callback_
 
std::mutex mutex_
 

Detailed Description

Manages permissions and access checks.

Definition at line 71 of file access_control_manager.h.

Constructor & Destructor Documentation

◆ access_control_manager()

kcenon::pacs::security::access_control_manager::access_control_manager ( )

Definition at line 16 of file access_control_manager.cpp.

References initialize_default_permissions().

Here is the call graph for this function:

Member Function Documentation

◆ assign_role()

auto kcenon::pacs::security::access_control_manager::assign_role ( std::string_view user_id,
Role role ) -> kcenon::common::VoidResult
nodiscard

Definition at line 108 of file access_control_manager.cpp.

109 {
110 if (!storage_)
111 return kcenon::common::make_error<std::monostate>(
112 1, "Storage not configured", "access_control");
113
114 // Get user, add role, update
115 auto user_res = storage_->get_user(user_id);
116 if (user_res.is_err())
117 return kcenon::common::make_error<std::monostate>(2, "User not found",
118 "access_control");
119
120 auto user = user_res.unwrap();
121 if (!user.has_role(role)) {
122 user.roles.push_back(role);
123 return storage_->update_user(user);
124 }
125 return kcenon::common::ok();
126}
std::shared_ptr< security_storage_interface > storage_

◆ check_dicom_operation()

AccessCheckResult kcenon::pacs::security::access_control_manager::check_dicom_operation ( const user_context & ctx,
DicomOperation op ) const
nodiscard

Check if a DICOM operation is allowed.

Parameters
ctxUser context
opDICOM operation to check
Returns
AccessCheckResult with allowed status and reason

Definition at line 188 of file access_control_manager.cpp.

189 {
190 if (!ctx.is_valid()) {
191 auto result = AccessCheckResult::deny("User context is not valid");
192 if (audit_callback_) {
193 audit_callback_(ctx, op, result);
194 }
195 return result;
196 }
197
198 auto [resource, action] = map_dicom_operation(op);
199 bool allowed = check_permission(ctx.user(), resource, action);
200
201 AccessCheckResult result =
202 allowed ? AccessCheckResult::allow()
203 : AccessCheckResult::deny("Insufficient permissions for operation");
204
205 if (audit_callback_) {
206 audit_callback_(ctx, op, result);
207 }
208
209 return result;
210}
bool check_permission(const User &user, ResourceType resource, std::uint32_t action_mask) const
static std::pair< ResourceType, std::uint32_t > map_dicom_operation(DicomOperation op)
Map DICOM operation to resource type and action.
static AccessCheckResult deny(std::string reason)

References kcenon::pacs::security::AccessCheckResult::allow(), audit_callback_, check_permission(), kcenon::pacs::security::AccessCheckResult::deny(), kcenon::pacs::security::user_context::is_valid(), map_dicom_operation(), kcenon::pacs::security::resource, and kcenon::pacs::security::user_context::user().

Here is the call graph for this function:

◆ check_permission()

bool kcenon::pacs::security::access_control_manager::check_permission ( const User & user,
ResourceType resource,
std::uint32_t action_mask ) const
nodiscard

Definition at line 128 of file access_control_manager.cpp.

130 {
131 if (!user.active)
132 return false;
133
134 for (const auto &role : user.roles) {
135 auto it = role_permissions_.find(role);
136 if (it != role_permissions_.end()) {
137 for (const auto &perm : it->second) {
138 if (perm.resource == resource && perm.has_action(action_mask)) {
139 return true;
140 }
141 }
142 }
143 }
144 return false;
145}
std::map< Role, std::vector< Permission > > role_permissions_

References kcenon::pacs::security::resource, and role_permissions_.

Referenced by check_dicom_operation().

Here is the caller graph for this function:

◆ create_user()

auto kcenon::pacs::security::access_control_manager::create_user ( const User & user) -> kcenon::common::VoidResult
nodiscard

Definition at line 92 of file access_control_manager.cpp.

93 {
94 if (!storage_)
95 return kcenon::common::make_error<std::monostate>(
96 1, "Storage not configured", "access_control");
97 return storage_->create_user(user);
98}

◆ get_context_for_ae()

std::optional< user_context > kcenon::pacs::security::access_control_manager::get_context_for_ae ( std::string_view ae_title,
const std::string & session_id ) const
nodiscard

Get user context for an AE Title.

Parameters
ae_titleThe AE Title to look up
session_idSession identifier for the context
Returns
User context if found, std::nullopt for unregistered AE titles

Definition at line 212 of file access_control_manager.cpp.

213 {
214 std::lock_guard<std::mutex> lock(mutex_);
215
216 // Look up AE Title to user mapping
217 auto it = ae_to_user_id_.find(std::string(ae_title));
218 if (it == ae_to_user_id_.end()) {
219 // Reject unregistered AE titles
220 return std::nullopt;
221 }
222
223 // Get user from storage
224 if (!storage_) {
225 return std::nullopt;
226 }
227
228 auto user_result = storage_->get_user(it->second);
229 if (user_result.is_err()) {
230 return std::nullopt;
231 }
232
233 auto ctx = user_context(user_result.unwrap(), session_id);
234 ctx.set_source_ae_title(std::string(ae_title));
235 return ctx;
236}
std::map< std::string, std::string > ae_to_user_id_

References ae_to_user_id_, mutex_, and storage_.

◆ get_role_permissions()

const std::vector< Permission > & kcenon::pacs::security::access_control_manager::get_role_permissions ( Role role) const
nodiscard

Definition at line 157 of file access_control_manager.cpp.

157 {
158 static const std::vector<Permission> empty;
159 auto it = role_permissions_.find(role);
160 if (it != role_permissions_.end()) {
161 return it->second;
162 }
163 return empty;
164}
@ empty
Z - Replace with zero-length value.

References kcenon::pacs::security::empty, and role_permissions_.

◆ get_user()

auto kcenon::pacs::security::access_control_manager::get_user ( std::string_view id) -> kcenon::common::Result<User>
nodiscard

Definition at line 100 of file access_control_manager.cpp.

101 {
102 if (!storage_)
103 return kcenon::common::make_error<User>(1, "Storage not configured",
104 "access_control");
105 return storage_->get_user(id);
106}

◆ get_user_by_ae_title()

auto kcenon::pacs::security::access_control_manager::get_user_by_ae_title ( std::string_view ae_title) -> std::optional<User>
nodiscard

Get user by AE Title.

Parameters
ae_titleThe AE Title to look up
Returns
User if found

Definition at line 253 of file access_control_manager.cpp.

254 {
255 std::lock_guard<std::mutex> lock(mutex_);
256
257 auto it = ae_to_user_id_.find(std::string(ae_title));
258 if (it == ae_to_user_id_.end()) {
259 return std::nullopt;
260 }
261
262 if (!storage_) {
263 return std::nullopt;
264 }
265
266 auto user_result = storage_->get_user(it->second);
267 if (user_result.is_err()) {
268 return std::nullopt;
269 }
270
271 return user_result.unwrap();
272}

◆ has_role()

bool kcenon::pacs::security::access_control_manager::has_role ( const User & user,
Role role ) const
nodiscard

Definition at line 147 of file access_control_manager.cpp.

147 {
148 return user.has_role(role);
149}

◆ initialize_default_permissions()

void kcenon::pacs::security::access_control_manager::initialize_default_permissions ( )
private

Definition at line 53 of file access_control_manager.cpp.

53 {
54 // Viewer: Read-only access to Studies
57
58 // Technologist: Read access, Create/Update studies (but not delete)
62
63 // Radiologist: Same as Technologist + Verification (represented as Write in
64 // this simple model or could be separate) Giving Full study access for now
65 // (Delete/Export)
69
70 // Administrator: User management, System config
78
79 // System: Internal superuser
85}
constexpr std::uint32_t Full
Definition permission.h:49
constexpr std::uint32_t Write
Definition permission.h:42
constexpr std::uint32_t Read
Definition permission.h:41
@ Technologist
Can upload/modify studies, but not delete.
@ Administrator
User management, system config.
@ System
Internal system operations.
@ Radiologist
Full clinical access (includes verification)
@ Viewer
Read-only access to studies.
@ Study
DICOM studies/series/instances.
@ System
System configuration and services.
@ Metadata
Patient/Study metadata.

References kcenon::pacs::security::Administrator, kcenon::pacs::security::Audit, kcenon::pacs::security::Action::Full, kcenon::pacs::security::Image, kcenon::pacs::security::Metadata, kcenon::pacs::security::Radiologist, kcenon::pacs::security::Action::Read, kcenon::pacs::security::Role, role_permissions_, kcenon::pacs::security::Series, kcenon::pacs::security::Study, kcenon::pacs::security::System, kcenon::pacs::security::Technologist, kcenon::pacs::security::User, kcenon::pacs::security::Viewer, and kcenon::pacs::security::Action::Write.

Referenced by access_control_manager().

Here is the caller graph for this function:

◆ map_dicom_operation()

std::pair< ResourceType, std::uint32_t > kcenon::pacs::security::access_control_manager::map_dicom_operation ( DicomOperation op)
staticprivate

Map DICOM operation to resource type and action.

Definition at line 25 of file access_control_manager.cpp.

25 {
26 switch (op) {
49 }
51}
constexpr std::uint32_t None
Definition permission.h:40
constexpr std::uint32_t Delete
Definition permission.h:43
constexpr std::uint32_t Export
Definition permission.h:44
constexpr std::uint32_t Execute
Definition permission.h:45

References kcenon::pacs::security::CEcho, kcenon::pacs::security::CFind, kcenon::pacs::security::CGet, kcenon::pacs::security::CMove, kcenon::pacs::security::CStore, kcenon::pacs::security::Action::Delete, kcenon::pacs::security::Action::Execute, kcenon::pacs::security::Action::Export, kcenon::pacs::security::Metadata, kcenon::pacs::security::NAction, kcenon::pacs::security::NCreate, kcenon::pacs::security::NDelete, kcenon::pacs::security::NEventReport, kcenon::pacs::security::NGet, kcenon::pacs::security::Action::None, kcenon::pacs::security::NSet, kcenon::pacs::security::Action::Read, kcenon::pacs::security::Study, kcenon::pacs::security::System, and kcenon::pacs::security::Action::Write.

Referenced by check_dicom_operation().

Here is the caller graph for this function:

◆ register_ae_title()

void kcenon::pacs::security::access_control_manager::register_ae_title ( std::string_view ae_title,
std::string_view user_id )

Definition at line 242 of file access_control_manager.cpp.

243 {
244 std::lock_guard<std::mutex> lock(mutex_);
245 ae_to_user_id_[std::string(ae_title)] = std::string(user_id);
246}

References ae_to_user_id_, and mutex_.

◆ set_audit_callback()

void kcenon::pacs::security::access_control_manager::set_audit_callback ( AccessAuditCallback callback)

Definition at line 278 of file access_control_manager.cpp.

278 {
279 std::lock_guard<std::mutex> lock(mutex_);
280 audit_callback_ = std::move(callback);
281}

References audit_callback_, and mutex_.

◆ set_role_permissions()

void kcenon::pacs::security::access_control_manager::set_role_permissions ( Role role,
std::vector< Permission > permissions )

Definition at line 151 of file access_control_manager.cpp.

152 {
153 role_permissions_[role] = std::move(permissions);
154}

References role_permissions_.

◆ set_storage()

void kcenon::pacs::security::access_control_manager::set_storage ( std::shared_ptr< security_storage_interface > storage)

Definition at line 87 of file access_control_manager.cpp.

88 {
89 storage_ = std::move(storage);
90}

References storage_.

◆ unregister_ae_title()

void kcenon::pacs::security::access_control_manager::unregister_ae_title ( std::string_view ae_title)

Definition at line 248 of file access_control_manager.cpp.

248 {
249 std::lock_guard<std::mutex> lock(mutex_);
250 ae_to_user_id_.erase(std::string(ae_title));
251}

References ae_to_user_id_, and mutex_.

◆ validate_access()

auto kcenon::pacs::security::access_control_manager::validate_access ( const user_context & ctx,
ResourceType resource,
std::uint32_t action_mask ) -> kcenon::common::VoidResult
nodiscard

Validate access for a user context.

Parameters
ctxUser context to validate
resourceResource being accessed
action_maskActions being performed
Returns
Result with void on success, error on denial

Definition at line 170 of file access_control_manager.cpp.

173 {
174 if (!ctx.is_valid()) {
175 return kcenon::common::make_error<std::monostate>(
176 1, "User context is not valid (inactive user)", "access_control");
177 }
178
179 if (!check_permission(ctx.user(), resource, action_mask)) {
180 return kcenon::common::make_error<std::monostate>(
181 2, "Access denied: insufficient permissions", "access_control");
182 }
183
184 return kcenon::common::ok();
185}

References kcenon::pacs::security::resource.

Member Data Documentation

◆ ae_to_user_id_

std::map<std::string, std::string> kcenon::pacs::security::access_control_manager::ae_to_user_id_
private

◆ audit_callback_

AccessAuditCallback kcenon::pacs::security::access_control_manager::audit_callback_
private

Definition at line 145 of file access_control_manager.h.

Referenced by check_dicom_operation(), and set_audit_callback().

◆ mutex_

std::mutex kcenon::pacs::security::access_control_manager::mutex_
mutableprivate

◆ role_permissions_

std::map<Role, std::vector<Permission> > kcenon::pacs::security::access_control_manager::role_permissions_
private

◆ storage_

std::shared_ptr<security_storage_interface> kcenon::pacs::security::access_control_manager::storage_
private

Definition at line 143 of file access_control_manager.h.

Referenced by get_context_for_ae(), and set_storage().


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