24std::pair<ResourceType, std::uint32_t>
88 std::shared_ptr<security_storage_interface> storage) {
93 -> kcenon::common::VoidResult {
95 return kcenon::common::make_error<std::monostate>(
96 1,
"Storage not configured",
"access_control");
97 return storage_->create_user(user);
103 return kcenon::common::make_error<User>(1,
"Storage not configured",
105 return storage_->get_user(
id);
109 -> kcenon::common::VoidResult {
111 return kcenon::common::make_error<std::monostate>(
112 1,
"Storage not configured",
"access_control");
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",
120 auto user = user_res.unwrap();
121 if (!user.has_role(role)) {
122 user.roles.push_back(role);
123 return storage_->update_user(user);
125 return kcenon::common::ok();
130 std::uint32_t action_mask)
const {
134 for (
const auto &role : user.roles) {
137 for (
const auto &perm : it->second) {
138 if (perm.resource ==
resource && perm.has_action(action_mask)) {
148 return user.has_role(role);
152 Role role, std::vector<Permission> permissions) {
156const std::vector<Permission> &
158 static const std::vector<Permission>
empty;
172 std::uint32_t action_mask)
173 -> kcenon::common::VoidResult {
174 if (!ctx.is_valid()) {
175 return kcenon::common::make_error<std::monostate>(
176 1,
"User context is not valid (inactive user)",
"access_control");
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");
184 return kcenon::common::ok();
213 std::string_view ae_title,
const std::string &session_id)
const {
214 std::lock_guard<std::mutex> lock(
mutex_);
228 auto user_result =
storage_->get_user(it->second);
229 if (user_result.is_err()) {
233 auto ctx =
user_context(user_result.unwrap(), session_id);
234 ctx.set_source_ae_title(std::string(ae_title));
243 std::string_view user_id) {
244 std::lock_guard<std::mutex> lock(
mutex_);
249 std::lock_guard<std::mutex> lock(
mutex_);
254 -> std::optional<User> {
255 std::lock_guard<std::mutex> lock(mutex_);
257 auto it = ae_to_user_id_.find(std::string(ae_title));
258 if (it == ae_to_user_id_.end()) {
266 auto user_result = storage_->get_user(it->second);
267 if (user_result.is_err()) {
271 return user_result.unwrap();
279 std::lock_guard<std::mutex> lock(
mutex_);
void unregister_ae_title(std::string_view ae_title)
auto get_user_by_ae_title(std::string_view ae_title) -> std::optional< User >
Get user by AE Title.
auto create_user(const User &user) -> kcenon::common::VoidResult
bool has_role(const User &user, Role role) const
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.
AccessCheckResult check_dicom_operation(const user_context &ctx, DicomOperation op) const
Check if a DICOM operation is allowed.
void set_role_permissions(Role role, std::vector< Permission > permissions)
std::map< Role, std::vector< Permission > > role_permissions_
auto get_user(std::string_view id) -> kcenon::common::Result< User >
void register_ae_title(std::string_view ae_title, std::string_view user_id)
void initialize_default_permissions()
void set_storage(std::shared_ptr< security_storage_interface > storage)
auto validate_access(const user_context &ctx, ResourceType resource, std::uint32_t action_mask) -> kcenon::common::VoidResult
Validate access for a user context.
const std::vector< Permission > & get_role_permissions(Role role) const
std::shared_ptr< security_storage_interface > storage_
void set_audit_callback(AccessAuditCallback callback)
std::map< std::string, std::string > ae_to_user_id_
auto assign_role(std::string_view user_id, Role role) -> kcenon::common::VoidResult
std::optional< user_context > get_context_for_ae(std::string_view ae_title, const std::string &session_id) const
Get user context for an AE Title.
AccessAuditCallback audit_callback_
Represents the security context for a user session.
bool is_valid() const noexcept
Check if the context is valid (user is active)
const User & user() const noexcept
constexpr std::uint32_t None
constexpr std::uint32_t Delete
constexpr std::uint32_t Export
constexpr std::uint32_t Full
constexpr std::uint32_t Write
constexpr std::uint32_t Read
constexpr std::uint32_t Execute
Role
User roles in the PACS system.
@ 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.
std::function< void(const user_context &ctx, DicomOperation op, const AccessCheckResult &result)> AccessAuditCallback
Callback for audit logging of access attempts.
@ empty
Z - Replace with zero-length value.
ResourceType
Categories of resources requiring protection.
@ Study
DICOM studies/series/instances.
@ System
System configuration and services.
@ Metadata
Patient/Study metadata.
DicomOperation
DICOM operation types for permission checking.
@ NEventReport
N-EVENT-REPORT.
@ CMove
C-MOVE (retrieve/move)
@ CStore
C-STORE (storage)
@ CEcho
C-ECHO (verification)
Result of an access check.
static AccessCheckResult allow()
static AccessCheckResult deny(std::string reason)
Represents a user in the system.