18#ifdef PACS_WITH_DATABASE_SYSTEM
20#include <database/query_builder.h>
26using namespace security;
27using kcenon::common::make_error;
28using kcenon::common::ok;
31constexpr int kSqliteError = 1;
32constexpr int kUserNotFound = 2;
33constexpr int kDatabaseNotConnected = 4;
36sqlite_security_storage::sqlite_security_storage(std::string db_path)
37 : db_path_(std::
move(db_path)) {
38 if (
auto res = initialize_database(); res.is_err()) {
43sqlite_security_storage::~sqlite_security_storage() {
45 (void)db_manager_->disconnect_result();
49auto sqlite_security_storage::initialize_database() -> VoidResult {
50 db_context_ = std::make_shared<database::database_context>();
51 db_manager_ = std::make_shared<database::database_manager>(db_context_);
53 if (!db_manager_->set_mode(database::database_types::sqlite)) {
54 return make_error<std::monostate>(kSqliteError,
"Failed to set SQLite mode",
55 "sqlite_security_storage");
58 auto connect_result = db_manager_->connect_result(db_path_);
59 if (connect_result.is_err()) {
60 return make_error<std::monostate>(
61 kSqliteError,
"Failed to connect: " + connect_result.error().message,
62 "sqlite_security_storage");
66 const char *create_tables_sql = R
"(
67 CREATE TABLE IF NOT EXISTS users (
69 username TEXT UNIQUE NOT NULL,
70 active INTEGER DEFAULT 1
72 CREATE TABLE IF NOT EXISTS user_roles (
75 PRIMARY KEY (user_id, role),
76 FOREIGN KEY(user_id) REFERENCES users(id) ON DELETE CASCADE
80 auto exec_result = db_manager_->execute_query_result(create_tables_sql);
81 if (exec_result.is_err()) {
82 return make_error<std::monostate>(
83 kSqliteError,
"Failed to create tables: " + exec_result.error().message,
84 "sqlite_security_storage");
90auto sqlite_security_storage::create_user(
const User &user) -> VoidResult {
92 return make_error<std::monostate>(kDatabaseNotConnected,
93 "Database not connected",
94 "sqlite_security_storage");
98 database::query_builder builder(database::database_types::sqlite);
99 auto insert_sql = builder
100 .insert_into(
"users")
101 .values({{
"id", user.id},
102 {
"username", user.username},
103 {
"active", user.active ? 1 : 0}})
106 auto result = db_manager_->execute_query_result(insert_sql);
107 if (result.is_err()) {
108 return make_error<std::monostate>(
109 kSqliteError,
"Failed to insert user: " + result.error().message,
110 "sqlite_security_storage");
114 for (
const auto &role : user.roles) {
115 database::query_builder role_builder(database::database_types::sqlite);
116 auto role_sql = role_builder
117 .insert_into(
"user_roles")
118 .values({{
"user_id", user.id},
122 auto role_result = db_manager_->execute_query_result(role_sql);
123 if (role_result.is_err()) {
131auto sqlite_security_storage::get_user(std::string_view
id) ->
Result<User> {
133 return make_error<User>(kDatabaseNotConnected,
"Database not connected",
134 "sqlite_security_storage");
138 user.id = std::string(
id);
141 database::query_builder builder(database::database_types::sqlite);
143 builder.select(std::vector<std::string>{
"username",
"active"})
145 .where(
"id",
"=", std::string(
id))
148 auto result = db_manager_->select_query_result(select_sql);
149 if (result.is_err()) {
150 return make_error<User>(kSqliteError,
151 "DB Error: " + result.error().message,
152 "sqlite_security_storage");
155 const auto &
rows = result.value();
157 return make_error<User>(kUserNotFound,
"User not found",
158 "sqlite_security_storage");
162 const auto &row =
rows[0];
163 if (
auto it = row.find(
"username"); it != row.end()) {
164 if (std::holds_alternative<std::string>(it->second)) {
165 user.username = std::get<std::string>(it->second);
168 if (
auto it = row.find(
"active"); it != row.end()) {
169 if (std::holds_alternative<int64_t>(it->second)) {
170 user.active = std::get<int64_t>(it->second) != 0;
175 database::query_builder role_builder(database::database_types::sqlite);
176 auto role_sql = role_builder.select(std::vector<std::string>{
"role"})
178 .where(
"user_id",
"=", std::string(
id))
181 auto role_result = db_manager_->select_query_result(role_sql);
182 if (role_result.is_ok()) {
183 for (
const auto &role_row : role_result.value()) {
184 if (
auto it = role_row.find(
"role"); it != role_row.end()) {
185 if (std::holds_alternative<std::string>(it->second)) {
186 if (
auto role =
parse_role(std::get<std::string>(it->second))) {
187 user.roles.push_back(*role);
197auto sqlite_security_storage::get_user_by_username(std::string_view username)
200 return make_error<User>(kDatabaseNotConnected,
"Database not connected",
201 "sqlite_security_storage");
205 database::query_builder builder(database::database_types::sqlite);
207 builder.select(std::vector<std::string>{
"id",
"username",
"active"})
209 .where(
"username",
"=", std::string(username))
212 auto result = db_manager_->select_query_result(select_sql);
213 if (result.is_err()) {
214 return make_error<User>(kSqliteError,
215 "DB Error: " + result.error().message,
216 "sqlite_security_storage");
219 const auto &
rows = result.value();
221 return make_error<User>(kUserNotFound,
"User not found",
222 "sqlite_security_storage");
226 const auto &row =
rows[0];
228 if (
auto it = row.find(
"id"); it != row.end()) {
229 if (std::holds_alternative<std::string>(it->second)) {
230 user.id = std::get<std::string>(it->second);
233 if (
auto it = row.find(
"username"); it != row.end()) {
234 if (std::holds_alternative<std::string>(it->second)) {
235 user.username = std::get<std::string>(it->second);
238 if (
auto it = row.find(
"active"); it != row.end()) {
239 if (std::holds_alternative<int64_t>(it->second)) {
240 user.active = std::get<int64_t>(it->second) != 0;
245 database::query_builder role_builder(database::database_types::sqlite);
246 auto role_sql = role_builder.select(std::vector<std::string>{
"role"})
248 .where(
"user_id",
"=", user.id)
251 auto role_result = db_manager_->select_query_result(role_sql);
252 if (role_result.is_ok()) {
253 for (
const auto &role_row : role_result.value()) {
254 if (
auto it = role_row.find(
"role"); it != role_row.end()) {
255 if (std::holds_alternative<std::string>(it->second)) {
256 if (
auto role =
parse_role(std::get<std::string>(it->second))) {
257 user.roles.push_back(*role);
267auto sqlite_security_storage::update_user(
const User &user) -> VoidResult {
269 return make_error<std::monostate>(kDatabaseNotConnected,
270 "Database not connected",
271 "sqlite_security_storage");
275 auto tx_result = db_manager_->begin_transaction();
276 if (tx_result.is_err()) {
277 return make_error<std::monostate>(
279 "Failed to begin transaction: " + tx_result.error().message,
280 "sqlite_security_storage");
284 database::query_builder update_builder(database::database_types::sqlite);
285 auto update_sql = update_builder.update(
"users")
286 .set({{
"active", user.active ? 1 : 0}})
287 .where(
"id",
"=", user.id)
290 auto update_result = db_manager_->execute_query_result(update_sql);
291 if (update_result.is_err()) {
292 (void)db_manager_->rollback_transaction();
293 return make_error<std::monostate>(
294 kSqliteError,
"Failed to update user: " + update_result.error().message,
295 "sqlite_security_storage");
299 database::query_builder delete_builder(database::database_types::sqlite);
300 auto delete_sql = delete_builder.delete_from(
"user_roles")
301 .where(
"user_id",
"=", user.id)
304 auto delete_result = db_manager_->execute_query_result(delete_sql);
305 if (delete_result.is_err()) {
306 (void)db_manager_->rollback_transaction();
307 return make_error<std::monostate>(
309 "Failed to delete roles: " + delete_result.error().message,
310 "sqlite_security_storage");
314 for (
const auto &role : user.roles) {
315 database::query_builder role_builder(database::database_types::sqlite);
317 role_builder.insert_into(
"user_roles")
319 {{
"user_id", user.id}, {
"role", std::string(
to_string(role))}})
322 auto role_result = db_manager_->execute_query_result(role_sql);
323 if (role_result.is_err()) {
324 (void)db_manager_->rollback_transaction();
325 return make_error<std::monostate>(
327 "Failed to insert role: " + role_result.error().message,
328 "sqlite_security_storage");
332 auto commit_result = db_manager_->commit_transaction();
333 if (commit_result.is_err()) {
334 (void)db_manager_->rollback_transaction();
335 return make_error<std::monostate>(
337 "Failed to commit transaction: " + commit_result.error().message,
338 "sqlite_security_storage");
344auto sqlite_security_storage::delete_user(std::string_view
id) -> VoidResult {
346 return make_error<std::monostate>(kDatabaseNotConnected,
347 "Database not connected",
348 "sqlite_security_storage");
352 database::query_builder builder(database::database_types::sqlite);
353 auto delete_sql = builder.delete_from(
"users")
354 .where(
"id",
"=", std::string(
id))
357 auto result = db_manager_->execute_query_result(delete_sql);
358 if (result.is_err()) {
359 return make_error<std::monostate>(
360 kSqliteError,
"Failed to delete user: " + result.error().message,
361 "sqlite_security_storage");
367auto sqlite_security_storage::get_users_by_role(Role role)
370 return make_error<std::vector<User>>(kDatabaseNotConnected,
371 "Database not connected",
372 "sqlite_security_storage");
376 database::query_builder builder(database::database_types::sqlite);
379 .select(std::vector<std::string>{
"u.id",
"u.username",
"u.active"})
381 .join(
"user_roles ur",
"u.id = ur.user_id")
382 .where(
"ur.role",
"=", std::string(
to_string(role)))
385 auto result = db_manager_->select_query_result(select_sql);
386 if (result.is_err()) {
387 return make_error<std::vector<User>>(
388 kSqliteError,
"DB Error: " + result.error().message,
389 "sqlite_security_storage");
392 std::vector<User> users;
393 for (
const auto &row : result.value()) {
395 if (
auto it = row.find(
"id"); it != row.end()) {
396 if (std::holds_alternative<std::string>(it->second)) {
397 user.id = std::get<std::string>(it->second);
400 if (
auto it = row.find(
"username"); it != row.end()) {
401 if (std::holds_alternative<std::string>(it->second)) {
402 user.username = std::get<std::string>(it->second);
405 if (
auto it = row.find(
"active"); it != row.end()) {
406 if (std::holds_alternative<int64_t>(it->second)) {
407 user.active = std::get<int64_t>(it->second) != 0;
412 database::query_builder role_builder(database::database_types::sqlite);
414 role_builder.select(std::vector<std::string>{
"role"})
416 .where(
"user_id",
"=", user.id)
419 auto role_result = db_manager_->select_query_result(role_sql);
420 if (role_result.is_ok()) {
421 for (
const auto &role_row : role_result.value()) {
422 if (
auto it = role_row.find(
"role"); it != role_row.end()) {
423 if (std::holds_alternative<std::string>(it->second)) {
424 if (
auto r =
parse_role(std::get<std::string>(it->second))) {
425 user.roles.push_back(*r);
432 users.push_back(std::move(user));
@ move
C-MOVE move request/response.
std::optional< Role > parse_role(std::string_view str)
Parse Role from string.
kcenon::common::Result< T > Result
Result type alias for operations returning a value.
auto to_string(annotation_type type) -> std::string
Convert annotation_type to string.
SQLite implementation of security storage with SQL injection protection.