From 769f5a3aff6b7689ebf88ba43a474b47dca4a47d Mon Sep 17 00:00:00 2001
From: petru <smart__petea@mail.ru>
Date: Mon, 5 Feb 2024 17:58:30 +0200
Subject: [PATCH 01/24] 30-access-policies app domain

---
 Cargo.lock                  | 138 +++++++++++++++++++++---------------
 access_control.conf.dist    |   8 +--
 src/middleware/client.rs    |   8 +++
 src/middleware/trydirect.rs |   2 +-
 src/startup.rs              |   1 +
 5 files changed, 96 insertions(+), 61 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock
index f844c9c0..1dc15f9e 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -5,7 +5,7 @@ version = 3
 [[package]]
 name = "actix-casbin-auth"
 version = "0.4.4"
-source = "git+https://github.com/smart--petea/actix-casbin-auth.git?branch=dirty-master#795c1209e4dea6078a787ccf7a882bd5d1148be7"
+source = "git+https://github.com/smart--petea/actix-casbin-auth.git?branch=dirty-master#5b76cc4e0df68ccee02c563b947a788ab1cb5193"
 dependencies = [
  "actix-service",
  "actix-web",
@@ -16,11 +16,11 @@ dependencies = [
 
 [[package]]
 name = "actix-codec"
-version = "0.5.1"
+version = "0.5.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "617a8268e3537fe1d8c9ead925fca49ef6400927ee7bc26750e90ecee14ce4b8"
+checksum = "5f7b0a21988c1bf877cf4759ef5ddaac04c1c9fe808c9142ecb78ba97d97a28a"
 dependencies = [
- "bitflags 1.3.2",
+ "bitflags 2.4.2",
  "bytes",
  "futures-core",
  "futures-sink",
@@ -48,9 +48,9 @@ dependencies = [
 
 [[package]]
 name = "actix-http"
-version = "3.5.1"
+version = "3.6.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "129d4c88e98860e1758c5de288d1632b07970a16d59bdf7b8d66053d582bb71f"
+checksum = "d223b13fd481fc0d1f83bb12659ae774d9e3601814c68a0bc539731698cca743"
 dependencies = [
  "actix-codec",
  "actix-rt",
@@ -158,9 +158,9 @@ dependencies = [
 
 [[package]]
 name = "actix-web"
-version = "4.4.1"
+version = "4.5.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e43428f3bf11dee6d166b00ec2df4e3aa8cc1606aaa0b7433c146852e2f4e03b"
+checksum = "43a6556ddebb638c2358714d853257ed226ece6023ef9364f23f0c70737ea984"
 dependencies = [
  "actix-codec",
  "actix-http",
@@ -192,7 +192,7 @@ dependencies = [
  "serde_urlencoded",
  "smallvec",
  "socket2 0.5.5",
- "time 0.3.31",
+ "time 0.3.34",
  "url",
 ]
 
@@ -372,9 +372,9 @@ dependencies = [
 
 [[package]]
 name = "anstyle"
-version = "1.0.4"
+version = "1.0.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87"
+checksum = "2faccea4cc4ab4a667ce676a30e8ec13922a692c99bb8f5b11f1502c72e04220"
 
 [[package]]
 name = "anstyle-parse"
@@ -517,7 +517,7 @@ dependencies = [
  "futures-lite 2.2.0",
  "parking",
  "polling 3.3.2",
- "rustix 0.38.30",
+ "rustix 0.38.31",
  "slab",
  "tracing",
  "windows-sys 0.52.0",
@@ -753,9 +753,9 @@ dependencies = [
 
 [[package]]
 name = "casbin"
-version = "2.1.0"
+version = "2.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "53fd06051bc34aa7ee753647dbd36506fa9f84026993d9871e65e0ee71ac3632"
+checksum = "b71063d3ee2f5ecc89229ccade0f3f8fb413b5e3978124a38b611216f91dd7c9"
 dependencies = [
  "async-trait",
  "fixedbitset",
@@ -930,7 +930,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "e859cd57d0710d9e06c381b550c06e76992472a8c6d527aecd2fc673dcc231fb"
 dependencies = [
  "percent-encoding",
- "time 0.3.31",
+ "time 0.3.34",
  "version_check",
 ]
 
@@ -1265,7 +1265,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "6e366950e7785fe0e404901a2b4e5c09ebd6656767f0c2167e34c5068ce0cc2d"
 dependencies = [
  "derive_builder 0.13.0",
- "indexmap 2.2.1",
+ "indexmap 2.2.2",
  "serde",
  "serde_yaml",
 ]
@@ -1651,7 +1651,7 @@ dependencies = [
  "futures-sink",
  "futures-util",
  "http",
- "indexmap 2.2.1",
+ "indexmap 2.2.2",
  "slab",
  "tokio",
  "tokio-util",
@@ -1828,9 +1828,9 @@ dependencies = [
 
 [[package]]
 name = "iana-time-zone"
-version = "0.1.59"
+version = "0.1.60"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b6a67363e2aa4443928ce15e57ebae94fd8949958fd1223c4cfc0cd473ad7539"
+checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141"
 dependencies = [
  "android_system_properties",
  "core-foundation-sys",
@@ -1878,9 +1878,9 @@ dependencies = [
 
 [[package]]
 name = "indexmap"
-version = "2.2.1"
+version = "2.2.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "433de089bd45971eecf4668ee0ee8f4cec17db4f8bd8f7bc3197a6ce37aa7d9b"
+checksum = "824b2ae422412366ba479e8111fd301f7b5faece8149317bb81925979a53f520"
 dependencies = [
  "equivalent",
  "hashbrown 0.14.3",
@@ -1940,9 +1940,9 @@ dependencies = [
 
 [[package]]
 name = "itertools"
-version = "0.12.0"
+version = "0.12.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "25db6b064527c5d482d0423354fcd07a89a2dfe07b67892e62411946db7f07b0"
+checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569"
 dependencies = [
  "either",
 ]
@@ -2019,9 +2019,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
 
 [[package]]
 name = "libc"
-version = "0.2.152"
+version = "0.2.153"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7"
+checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd"
 
 [[package]]
 name = "libredox"
@@ -2139,9 +2139,9 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
 
 [[package]]
 name = "miniz_oxide"
-version = "0.7.1"
+version = "0.7.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7"
+checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7"
 dependencies = [
  "adler",
 ]
@@ -2202,6 +2202,12 @@ dependencies = [
  "winapi",
 ]
 
+[[package]]
+name = "num-conv"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
+
 [[package]]
 name = "num-traits"
 version = "0.2.17"
@@ -2387,9 +2393,9 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
 
 [[package]]
 name = "pest"
-version = "2.7.6"
+version = "2.7.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1f200d8d83c44a45b21764d1916299752ca035d15ecd46faca3e9a2a2bf6ad06"
+checksum = "219c0dcc30b6a27553f9cc242972b67f75b60eb0db71f0b5462f38b058c41546"
 dependencies = [
  "memchr",
  "thiserror",
@@ -2398,9 +2404,9 @@ dependencies = [
 
 [[package]]
 name = "pest_derive"
-version = "2.7.6"
+version = "2.7.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bcd6ab1236bbdb3a49027e920e693192ebfe8913f6d60e294de57463a493cfde"
+checksum = "22e1288dbd7786462961e69bfd4df7848c1e37e8b74303dbdab82c3a9cdd2809"
 dependencies = [
  "pest",
  "pest_generator",
@@ -2408,9 +2414,9 @@ dependencies = [
 
 [[package]]
 name = "pest_generator"
-version = "2.7.6"
+version = "2.7.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2a31940305ffc96863a735bef7c7994a00b325a7138fdbc5bda0f1a0476d3275"
+checksum = "1381c29a877c6d34b8c176e734f35d7f7f5b3adaefe940cb4d1bb7af94678e2e"
 dependencies = [
  "pest",
  "pest_meta",
@@ -2421,9 +2427,9 @@ dependencies = [
 
 [[package]]
 name = "pest_meta"
-version = "2.7.6"
+version = "2.7.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a7ff62f5259e53b78d1af898941cdcdccfae7385cf7d793a6e55de5d05bb4b7d"
+checksum = "d0934d6907f148c22a3acbda520c7eed243ad7487a30f51f6ce52b58b7077a8a"
 dependencies = [
  "once_cell",
  "pest",
@@ -2437,7 +2443,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9"
 dependencies = [
  "fixedbitset",
- "indexmap 2.2.1",
+ "indexmap 2.2.2",
 ]
 
 [[package]]
@@ -2526,7 +2532,7 @@ dependencies = [
  "cfg-if",
  "concurrent-queue",
  "pin-project-lite",
- "rustix 0.38.30",
+ "rustix 0.38.31",
  "tracing",
  "windows-sys 0.52.0",
 ]
@@ -2762,9 +2768,9 @@ checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
 
 [[package]]
 name = "reqwest"
-version = "0.11.23"
+version = "0.11.24"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "37b1ae8d9ac08420c66222fb9096fc5de435c3c48542bc5336c51892cffafb41"
+checksum = "c6920094eb85afde5e4a138be3f2de8bbdf28000f0029e72c45025a56b042251"
 dependencies = [
  "base64 0.21.7",
  "bytes",
@@ -2784,9 +2790,11 @@ dependencies = [
  "once_cell",
  "percent-encoding",
  "pin-project-lite",
+ "rustls-pemfile",
  "serde",
  "serde_json",
  "serde_urlencoded",
+ "sync_wrapper",
  "system-configuration",
  "tokio",
  "tokio-native-tls",
@@ -2806,9 +2814,9 @@ checksum = "4389f1d5789befaf6029ebd9f7dac4af7f7e3d61b69d4f30e2ac02b57e7712b0"
 
 [[package]]
 name = "rhai"
-version = "1.16.3"
+version = "1.17.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e3625f343d89990133d013e39c46e350915178cf94f1bec9f49b0cbef98a3e3c"
+checksum = "f6273372244d04a8a4b0bec080ea1e710403e88c5d9d83f9808b2bfa64f0982a"
 dependencies = [
  "ahash 0.8.7",
  "bitflags 2.4.2",
@@ -2819,13 +2827,14 @@ dependencies = [
  "serde",
  "smallvec",
  "smartstring",
+ "thin-vec",
 ]
 
 [[package]]
 name = "rhai_codegen"
-version = "1.6.0"
+version = "2.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "853977598f084a492323fe2f7896b4100a86284ee8473612de60021ea341310f"
+checksum = "9db7f8dc4c9d48183a17ce550574c42995252b82d267eaca3fcd1b979159856c"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -2923,9 +2932,9 @@ dependencies = [
 
 [[package]]
 name = "rustix"
-version = "0.38.30"
+version = "0.38.31"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "322394588aaf33c24007e8bb3238ee3e4c5c09c084ab32bc73890b99ff326bca"
+checksum = "6ea3e1a662af26cd7a3ba09c0297a31af215563ecf42817c98df621387f4e949"
 dependencies = [
  "bitflags 2.4.2",
  "errno",
@@ -3187,7 +3196,7 @@ version = "0.9.31"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "adf8a49373e98a4c5f0ceb5d05aa7c648d75f63774981ed95b7c7443bbd50c6e"
 dependencies = [
- "indexmap 2.2.1",
+ "indexmap 2.2.2",
  "itoa",
  "ryu",
  "serde",
@@ -3320,7 +3329,7 @@ version = "0.2.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "ce81b7bd7c4493975347ef60d8c7e8b742d4694f4c49f93e0a12ea263938176c"
 dependencies = [
- "itertools 0.12.0",
+ "itertools 0.12.1",
  "nom",
  "unicode_categories",
 ]
@@ -3454,7 +3463,7 @@ dependencies = [
  "futures-util",
  "glob",
  "hmac",
- "indexmap 2.2.1",
+ "indexmap 2.2.2",
  "lapin",
  "rand 0.8.5",
  "regex",
@@ -3531,6 +3540,12 @@ dependencies = [
  "unicode-ident",
 ]
 
+[[package]]
+name = "sync_wrapper"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160"
+
 [[package]]
 name = "system-configuration"
 version = "0.5.1"
@@ -3579,10 +3594,19 @@ dependencies = [
  "cfg-if",
  "fastrand 2.0.1",
  "redox_syscall 0.4.1",
- "rustix 0.38.30",
+ "rustix 0.38.31",
  "windows-sys 0.52.0",
 ]
 
+[[package]]
+name = "thin-vec"
+version = "0.2.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a38c90d48152c236a3ab59271da4f4ae63d678c5d7ad6b7714d7cb9760be5e4b"
+dependencies = [
+ "serde",
+]
+
 [[package]]
 name = "thiserror"
 version = "1.0.56"
@@ -3626,12 +3650,13 @@ dependencies = [
 
 [[package]]
 name = "time"
-version = "0.3.31"
+version = "0.3.34"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f657ba42c3f86e7680e53c8cd3af8abbe56b5491790b46e22e19c0d57463583e"
+checksum = "c8248b6521bb14bc45b4067159b9b6ad792e2d6d754d6c41fb50e29fefe38749"
 dependencies = [
  "deranged",
  "itoa",
+ "num-conv",
  "powerfmt",
  "serde",
  "time-core",
@@ -3646,10 +3671,11 @@ checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3"
 
 [[package]]
 name = "time-macros"
-version = "0.2.16"
+version = "0.2.17"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "26197e33420244aeb70c3e8c78376ca46571bc4e701e4791c2cd9f57dcb3a43f"
+checksum = "7ba3a3ef41e6672a2f0f001392bb5dcd3ff0a9992d618ca761a11c3121547774"
 dependencies = [
+ "num-conv",
  "time-core",
 ]
 
@@ -3679,9 +3705,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
 
 [[package]]
 name = "tokio"
-version = "1.35.1"
+version = "1.36.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c89b4efa943be685f629b149f53829423f8f5531ea21249408e8e2f8671ec104"
+checksum = "61285f6515fa018fb2d1e46eb21223fff441ee8db5d0f1435e8ab4f5cdb80931"
 dependencies = [
  "backtrace",
  "bytes",
@@ -3826,7 +3852,7 @@ dependencies = [
  "log",
  "serde",
  "serde_json",
- "time 0.3.31",
+ "time 0.3.34",
  "tracing",
  "tracing-core",
  "tracing-log 0.1.4",
diff --git a/access_control.conf.dist b/access_control.conf.dist
index 459a15fc..5d047154 100644
--- a/access_control.conf.dist
+++ b/access_control.conf.dist
@@ -1,14 +1,14 @@
 [request_definition]
-r = sub, obj, act
+r = sub, dom, obj, act
 
 [policy_definition]
-p = sub, obj, act
+p = sub, dom, obj, act
 
 [role_definition]
-g = _, _
+g = _, _, _
 
 [policy_effect]
 e = some(where (p.eft == allow))
 
 [matchers]
-m = g(r.sub, p.sub) && r.obj == p.obj && regexMatch(r.act, p.act)
+m = g(r.sub, p.sub, r.dom) && r.dom == p.dom && r.obj == p.obj && regexMatch(r.act, p.act)
diff --git a/src/middleware/client.rs b/src/middleware/client.rs
index a6915d55..def95b06 100644
--- a/src/middleware/client.rs
+++ b/src/middleware/client.rs
@@ -96,6 +96,14 @@ where
                 None => {}
             }
 
+            let accesscontrol_vals = actix_casbin_auth::CasbinVals {
+                subject: client_id.to_string(),
+                domain: Some(String::from("app")),
+            };
+            if req.extensions_mut().insert(accesscontrol_vals).is_some() {
+                return Err("sth wrong with access control".to_string());
+            }
+
             Ok(req)
         }
         .then(|req| async move {
diff --git a/src/middleware/trydirect.rs b/src/middleware/trydirect.rs
index 1c61049f..c0703799 100644
--- a/src/middleware/trydirect.rs
+++ b/src/middleware/trydirect.rs
@@ -22,7 +22,7 @@ pub async fn bearer_guard( req: ServiceRequest, credentials: BearerAuth) -> Resu
 
     let accesscontrol_vals = actix_casbin_auth::CasbinVals {
         subject: String::from("alice"),
-        domain: None,
+        domain: Some(String::from("human")),
     };
     if req.extensions_mut().insert(accesscontrol_vals).is_some() {
         return Err((JsonResponse::<i32>::build().unauthorized("sth wrong with access control"), req));
diff --git a/src/startup.rs b/src/startup.rs
index 35481927..1c43fc77 100644
--- a/src/startup.rs
+++ b/src/startup.rs
@@ -42,6 +42,7 @@ pub async fn run(
             )
             .service(
                 web::scope("/test")
+                    .wrap(access_control_manager.clone()) 
                     .wrap(middleware::client::Guard::new())
                     .wrap(Cors::permissive())
                     .service(crate::routes::test::deploy::handler),

From 4d39ea5300f704044156bd3d277d0d6cff7710c3 Mon Sep 17 00:00:00 2001
From: petru <smart__petea@mail.ru>
Date: Sat, 10 Feb 2024 20:00:14 +0200
Subject: [PATCH 02/24] 30-access-policies sqlx-adapter. new version

---
 Cargo.lock | 343 +++++++++++++++++++++++++++++++++++++++++++----------
 Cargo.toml |   3 +-
 2 files changed, 281 insertions(+), 65 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock
index 1dc15f9e..269e5798 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -372,9 +372,9 @@ dependencies = [
 
 [[package]]
 name = "anstyle"
-version = "1.0.5"
+version = "1.0.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2faccea4cc4ab4a667ce676a30e8ec13922a692c99bb8f5b11f1502c72e04220"
+checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc"
 
 [[package]]
 name = "anstyle-parse"
@@ -433,13 +433,13 @@ dependencies = [
 
 [[package]]
 name = "async-channel"
-version = "2.1.1"
+version = "2.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1ca33f4bc4ed1babef42cad36cc1f51fa88be00420404e5b1e80ab1b18f7678c"
+checksum = "f28243a43d821d11341ab73c80bed182dc015c514b951616cf79bd4af39af0c3"
 dependencies = [
  "concurrent-queue",
- "event-listener 4.0.3",
- "event-listener-strategy",
+ "event-listener 5.0.0",
+ "event-listener-strategy 0.5.0",
  "futures-core",
  "pin-project-lite",
 ]
@@ -464,7 +464,7 @@ version = "2.4.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "05b1b633a2115cd122d73b955eadd9916c18c8f510ec9cd1686404c60ad1c29c"
 dependencies = [
- "async-channel 2.1.1",
+ "async-channel 2.2.0",
  "async-executor",
  "async-io 2.3.1",
  "async-lock 3.3.0",
@@ -516,7 +516,7 @@ dependencies = [
  "futures-io",
  "futures-lite 2.2.0",
  "parking",
- "polling 3.3.2",
+ "polling 3.4.0",
  "rustix 0.38.31",
  "slab",
  "tracing",
@@ -539,7 +539,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "d034b430882f8381900d3fe6f0aaa3ad94f2cb4ac519b429692a1bc2dda4ae7b"
 dependencies = [
  "event-listener 4.0.3",
- "event-listener-strategy",
+ "event-listener-strategy 0.4.0",
  "pin-project-lite",
 ]
 
@@ -581,12 +581,31 @@ dependencies = [
  "num-traits",
 ]
 
+[[package]]
+name = "atoi"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f28d99ec8bfea296261ca1af174f24225171fea9664ba9003cbebee704810528"
+dependencies = [
+ "num-traits",
+]
+
 [[package]]
 name = "atomic-waker"
 version = "1.1.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
 
+[[package]]
+name = "atomic-write-file"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "edcdbedc2236483ab103a53415653d6b4442ea6141baf1ffa85df29635e88436"
+dependencies = [
+ "nix",
+ "rand 0.8.5",
+]
+
 [[package]]
 name = "autocfg"
 version = "1.1.0"
@@ -656,7 +675,7 @@ version = "1.5.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "6a37913e8dc4ddcc604f0c6d3bf2887c995153af3611de9e23c352b44c1b9118"
 dependencies = [
- "async-channel 2.1.1",
+ "async-channel 2.2.0",
  "async-lock 3.3.0",
  "async-task",
  "fastrand 2.0.1",
@@ -731,9 +750,9 @@ dependencies = [
 
 [[package]]
 name = "cargo-platform"
-version = "0.1.6"
+version = "0.1.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ceed8ef69d8518a5dda55c07425450b58a4e1946f4951eab6d7191ee86c2443d"
+checksum = "694c8807f2ae16faecc43dc17d74b3eb042482789fd0eb64b39a2e04e087053f"
 dependencies = [
  "serde",
 ]
@@ -825,9 +844,9 @@ dependencies = [
 
 [[package]]
 name = "clap"
-version = "4.4.18"
+version = "4.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1e578d6ec4194633722ccf9544794b71b1385c3c027efe0c55db226fc880865c"
+checksum = "80c21025abd42669a92efc996ef13cfb2c5c627858421ea58d5c3b331a6c134f"
 dependencies = [
  "clap_builder",
  "clap_derive",
@@ -835,21 +854,21 @@ dependencies = [
 
 [[package]]
 name = "clap_builder"
-version = "4.4.18"
+version = "4.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4df4df40ec50c46000231c914968278b1eb05098cf8f1b3a518a95030e71d1c7"
+checksum = "458bf1f341769dfcf849846f65dffdf9146daa56bcd2a47cb4e1de9915567c99"
 dependencies = [
  "anstream",
  "anstyle",
  "clap_lex",
- "strsim",
+ "strsim 0.11.0",
 ]
 
 [[package]]
 name = "clap_derive"
-version = "4.4.7"
+version = "4.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cf9804afaaf59a91e75b022a30fb7229a7901f60c755489cc61c9b423b836442"
+checksum = "307bc0538d5f0f83b8248db3087aa92fe504e4691294d0c96c0eabc33f47ba47"
 dependencies = [
  "heck",
  "proc-macro2",
@@ -859,9 +878,9 @@ dependencies = [
 
 [[package]]
 name = "clap_lex"
-version = "0.6.0"
+version = "0.7.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1"
+checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce"
 
 [[package]]
 name = "colorchoice"
@@ -1049,7 +1068,7 @@ dependencies = [
  "ident_case",
  "proc-macro2",
  "quote",
- "strsim",
+ "strsim 0.10.0",
  "syn 1.0.109",
 ]
 
@@ -1284,9 +1303,9 @@ checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b"
 
 [[package]]
 name = "either"
-version = "1.9.0"
+version = "1.10.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07"
+checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a"
 dependencies = [
  "serde",
 ]
@@ -1325,6 +1344,17 @@ dependencies = [
  "version_check",
 ]
 
+[[package]]
+name = "etcetera"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "136d1b5283a1ab77bd9257427ffd09d8667ced0570b6f938942bc7568ed5b943"
+dependencies = [
+ "cfg-if",
+ "home",
+ "windows-sys 0.48.0",
+]
+
 [[package]]
 name = "event-listener"
 version = "2.5.3"
@@ -1342,6 +1372,17 @@ dependencies = [
  "pin-project-lite",
 ]
 
+[[package]]
+name = "event-listener"
+version = "5.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b72557800024fabbaa2449dd4bf24e37b93702d457a4d4f2b0dd1f0f039f20c1"
+dependencies = [
+ "concurrent-queue",
+ "parking",
+ "pin-project-lite",
+]
+
 [[package]]
 name = "event-listener-strategy"
 version = "0.4.0"
@@ -1352,6 +1393,16 @@ dependencies = [
  "pin-project-lite",
 ]
 
+[[package]]
+name = "event-listener-strategy"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "feedafcaa9b749175d5ac357452a9d41ea2911da598fde46ce1fe02c37751291"
+dependencies = [
+ "event-listener 5.0.0",
+ "pin-project-lite",
+]
+
 [[package]]
 name = "executor-trait"
 version = "2.1.0"
@@ -1502,6 +1553,17 @@ dependencies = [
  "parking_lot 0.11.2",
 ]
 
+[[package]]
+name = "futures-intrusive"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1d930c203dd0b6ff06e0201a4a2fe9149b43c684fd4420555b26d21b1a02956f"
+dependencies = [
+ "futures-core",
+ "lock_api",
+ "parking_lot 0.12.1",
+]
+
 [[package]]
 name = "futures-io"
 version = "0.3.30"
@@ -1706,9 +1768,9 @@ dependencies = [
 
 [[package]]
 name = "hermit-abi"
-version = "0.3.4"
+version = "0.3.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5d3d0e0f38255e7fa3cf31335b3a56f05febd18025f4db5ef7a0cfb4f8da651f"
+checksum = "d0c62115964e08cb8039170eb33c1d0e2388a256930279edca206fff675f82c3"
 
 [[package]]
 name = "hex"
@@ -1734,6 +1796,15 @@ dependencies = [
  "digest",
 ]
 
+[[package]]
+name = "home"
+version = "0.5.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5"
+dependencies = [
+ "windows-sys 0.52.0",
+]
+
 [[package]]
 name = "http"
 version = "0.2.11"
@@ -1955,18 +2026,18 @@ checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c"
 
 [[package]]
 name = "jobserver"
-version = "0.1.27"
+version = "0.1.28"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8c37f63953c4c63420ed5fd3d6d398c719489b9f872b9fa683262f8edd363c7d"
+checksum = "ab46a6e9526ddef3ae7f787c06f0f2600639ba80ea3eade3d8e670a2230f51d6"
 dependencies = [
  "libc",
 ]
 
 [[package]]
 name = "js-sys"
-version = "0.3.67"
+version = "0.3.68"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9a1d36f1235bc969acba30b7f5990b864423a6068a10f7c90ae8f0112e3a59d1"
+checksum = "406cda4b368d531c842222cf9d2600a9a4acce8d29423695379c6868a143a9ee"
 dependencies = [
  "wasm-bindgen",
 ]
@@ -2182,6 +2253,17 @@ dependencies = [
  "tempfile",
 ]
 
+[[package]]
+name = "nix"
+version = "0.27.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053"
+dependencies = [
+ "bitflags 2.4.2",
+ "cfg-if",
+ "libc",
+]
+
 [[package]]
 name = "nom"
 version = "7.1.3"
@@ -2210,9 +2292,9 @@ checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
 
 [[package]]
 name = "num-traits"
-version = "0.2.17"
+version = "0.2.18"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c"
+checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a"
 dependencies = [
  "autocfg",
 ]
@@ -2525,9 +2607,9 @@ dependencies = [
 
 [[package]]
 name = "polling"
-version = "3.3.2"
+version = "3.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "545c980a3880efd47b2e262f6a4bb6daad6555cf3367aa9c4e52895f69537a41"
+checksum = "30054e72317ab98eddd8561db0f6524df3367636884b7b21b703e4b280a84a14"
 dependencies = [
  "cfg-if",
  "concurrent-queue",
@@ -3176,7 +3258,7 @@ dependencies = [
  "proc-macro-error",
  "proc-macro2",
  "quote",
- "strsim",
+ "strsim 0.10.0",
  "syn 1.0.109",
 ]
 
@@ -3340,19 +3422,31 @@ version = "0.6.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "f8de3b03a925878ed54a954f621e64bf55a3c1bd29652d0d1a17830405350188"
 dependencies = [
- "sqlx-core",
- "sqlx-macros",
+ "sqlx-core 0.6.3",
+ "sqlx-macros 0.6.3",
+]
+
+[[package]]
+name = "sqlx"
+version = "0.7.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dba03c279da73694ef99763320dea58b51095dfe87d001b1d4b5fe78ba8763cf"
+dependencies = [
+ "sqlx-core 0.7.3",
+ "sqlx-macros 0.7.3",
+ "sqlx-postgres",
 ]
 
 [[package]]
 name = "sqlx-adapter"
-version = "0.4.2"
-source = "git+https://github.com/smart--petea/sqlx-adapter.git?branch=dirty-master#5f7cabbde494098a1b460f26c4b74fcbcf2d5857"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e39a25e18b8f9cd4f61b1653be67260d28dcd31b0bd8d3a08ed3ecbe2afa3b84"
 dependencies = [
  "async-trait",
  "casbin",
  "dotenv",
- "sqlx",
+ "sqlx 0.7.3",
 ]
 
 [[package]]
@@ -3362,7 +3456,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "fa8241483a83a3f33aa5fff7e7d9def398ff9990b2752b6c6112b83c6d246029"
 dependencies = [
  "ahash 0.7.7",
- "atoi",
+ "atoi 1.0.0",
  "base64 0.13.1",
  "bitflags 1.3.2",
  "byteorder",
@@ -3376,7 +3470,7 @@ dependencies = [
  "event-listener 2.5.3",
  "futures-channel",
  "futures-core",
- "futures-intrusive",
+ "futures-intrusive 0.4.2",
  "futures-util",
  "hashlink",
  "hex",
@@ -3410,6 +3504,47 @@ dependencies = [
  "whoami",
 ]
 
+[[package]]
+name = "sqlx-core"
+version = "0.7.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d84b0a3c3739e220d94b3239fd69fb1f74bc36e16643423bd99de3b43c21bfbd"
+dependencies = [
+ "ahash 0.8.7",
+ "atoi 2.0.0",
+ "byteorder",
+ "bytes",
+ "crc",
+ "crossbeam-queue",
+ "dotenvy",
+ "either",
+ "event-listener 2.5.3",
+ "futures-channel",
+ "futures-core",
+ "futures-intrusive 0.5.0",
+ "futures-io",
+ "futures-util",
+ "hashlink",
+ "hex",
+ "indexmap 2.2.2",
+ "log",
+ "memchr",
+ "native-tls",
+ "once_cell",
+ "paste",
+ "percent-encoding",
+ "serde",
+ "serde_json",
+ "sha2",
+ "smallvec",
+ "sqlformat",
+ "thiserror",
+ "tokio",
+ "tokio-stream",
+ "tracing",
+ "url",
+]
+
 [[package]]
 name = "sqlx-macros"
 version = "0.6.3"
@@ -3426,12 +3561,89 @@ dependencies = [
  "serde",
  "serde_json",
  "sha2",
- "sqlx-core",
+ "sqlx-core 0.6.3",
  "sqlx-rt",
  "syn 1.0.109",
  "url",
 ]
 
+[[package]]
+name = "sqlx-macros"
+version = "0.7.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "89961c00dc4d7dffb7aee214964b065072bff69e36ddb9e2c107541f75e4f2a5"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "sqlx-core 0.7.3",
+ "sqlx-macros-core",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "sqlx-macros-core"
+version = "0.7.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d0bd4519486723648186a08785143599760f7cc81c52334a55d6a83ea1e20841"
+dependencies = [
+ "atomic-write-file",
+ "dotenvy",
+ "either",
+ "heck",
+ "hex",
+ "once_cell",
+ "proc-macro2",
+ "quote",
+ "serde",
+ "serde_json",
+ "sha2",
+ "sqlx-core 0.7.3",
+ "sqlx-postgres",
+ "syn 1.0.109",
+ "tempfile",
+ "tokio",
+ "url",
+]
+
+[[package]]
+name = "sqlx-postgres"
+version = "0.7.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d6ac0ac3b7ccd10cc96c7ab29791a7dd236bd94021f31eec7ba3d46a74aa1c24"
+dependencies = [
+ "atoi 2.0.0",
+ "base64 0.21.7",
+ "bitflags 2.4.2",
+ "byteorder",
+ "crc",
+ "dotenvy",
+ "etcetera",
+ "futures-channel",
+ "futures-core",
+ "futures-io",
+ "futures-util",
+ "hex",
+ "hkdf",
+ "hmac",
+ "home",
+ "itoa",
+ "log",
+ "md-5",
+ "memchr",
+ "once_cell",
+ "rand 0.8.5",
+ "serde",
+ "serde_json",
+ "sha1",
+ "sha2",
+ "smallvec",
+ "sqlx-core 0.7.3",
+ "stringprep",
+ "thiserror",
+ "tracing",
+ "whoami",
+]
+
 [[package]]
 name = "sqlx-rt"
 version = "0.6.3"
@@ -3475,7 +3687,7 @@ dependencies = [
  "serde_valid",
  "serde_yaml",
  "sha2",
- "sqlx",
+ "sqlx 0.6.3",
  "sqlx-adapter",
  "thiserror",
  "tokio",
@@ -3512,6 +3724,12 @@ version = "0.10.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
 
+[[package]]
+name = "strsim"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5ee073c9e4cd00e28217186dbe12796d692868f432bf2e97ee73bed0c56dfa01"
+
 [[package]]
 name = "subtle"
 version = "2.5.0"
@@ -3587,13 +3805,12 @@ dependencies = [
 
 [[package]]
 name = "tempfile"
-version = "3.9.0"
+version = "3.10.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "01ce4141aa927a6d1bd34a041795abd0db1cccba5d5f24b009f694bdf3a1f3fa"
+checksum = "a365e8cd18e44762ef95d87f284f4b5cd04107fec2ff3052bd6a3e6069669e67"
 dependencies = [
  "cfg-if",
  "fastrand 2.0.1",
- "redox_syscall 0.4.1",
  "rustix 0.38.31",
  "windows-sys 0.52.0",
 ]
@@ -3965,9 +4182,9 @@ dependencies = [
 
 [[package]]
 name = "unicode-segmentation"
-version = "1.10.1"
+version = "1.11.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36"
+checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202"
 
 [[package]]
 name = "unicode_categories"
@@ -4084,9 +4301,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
 
 [[package]]
 name = "wasm-bindgen"
-version = "0.2.90"
+version = "0.2.91"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b1223296a201415c7fad14792dbefaace9bd52b62d33453ade1c5b5f07555406"
+checksum = "c1e124130aee3fb58c5bdd6b639a0509486b0338acaaae0c84a5124b0f588b7f"
 dependencies = [
  "cfg-if",
  "wasm-bindgen-macro",
@@ -4094,9 +4311,9 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen-backend"
-version = "0.2.90"
+version = "0.2.91"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fcdc935b63408d58a32f8cc9738a0bffd8f05cc7c002086c6ef20b7312ad9dcd"
+checksum = "c9e7e1900c352b609c8488ad12639a311045f40a35491fb69ba8c12f758af70b"
 dependencies = [
  "bumpalo",
  "log",
@@ -4109,9 +4326,9 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen-futures"
-version = "0.4.40"
+version = "0.4.41"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bde2032aeb86bdfaecc8b261eef3cba735cc426c1f3a3416d1e0791be95fc461"
+checksum = "877b9c3f61ceea0e56331985743b13f3d25c406a7098d45180fb5f09bc19ed97"
 dependencies = [
  "cfg-if",
  "js-sys",
@@ -4121,9 +4338,9 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen-macro"
-version = "0.2.90"
+version = "0.2.91"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3e4c238561b2d428924c49815533a8b9121c664599558a5d9ec51f8a1740a999"
+checksum = "b30af9e2d358182b5c7449424f017eba305ed32a7010509ede96cdc4696c46ed"
 dependencies = [
  "quote",
  "wasm-bindgen-macro-support",
@@ -4131,9 +4348,9 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen-macro-support"
-version = "0.2.90"
+version = "0.2.91"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bae1abb6806dc1ad9e560ed242107c0f6c84335f1749dd4e8ddb012ebd5e25a7"
+checksum = "642f325be6301eb8107a83d12a8ac6c1e1c54345a7ef1a9261962dfefda09e66"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -4144,15 +4361,15 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen-shared"
-version = "0.2.90"
+version = "0.2.91"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4d91413b1c31d7539ba5ef2451af3f0b833a005eb27a631cec32bc0635a8602b"
+checksum = "4f186bd2dcf04330886ce82d6f33dd75a7bfcf69ecf5763b89fcde53b6ac9838"
 
 [[package]]
 name = "web-sys"
-version = "0.3.67"
+version = "0.3.68"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "58cd2333b6e0be7a39605f0e255892fd7418a682d8da8fe042fe25128794d2ed"
+checksum = "96565907687f7aceb35bc5fc03770a8a0471d82e479f25832f54a0e3f4b28446"
 dependencies = [
  "js-sys",
  "wasm-bindgen",
diff --git a/Cargo.toml b/Cargo.toml
index 89420989..20a127c1 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -44,8 +44,7 @@ tokio-stream = "0.1.14"
 actix-http = "3.4.0"
 hmac = "0.12.1"
 sha2 = "0.10.8"
-#sqlx-adapter = { version = "0.4.2", default-features = false, features = ["postgres", "runtime-tokio-native-tls"]}
-sqlx-adapter = { git="https://github.com/smart--petea/sqlx-adapter.git", branch="dirty-master", default-features = false, features = ["postgres"]}
+sqlx-adapter = { version = "1.0.0", default-features = false, features = ["postgres", "runtime-tokio-native-tls"]}
 
 # dctypes
 derive_builder = "0.12.0"

From c53bcb79f77e353633730294dfb1c4b0efca9960 Mon Sep 17 00:00:00 2001
From: petru <smart__petea@mail.ru>
Date: Wed, 14 Feb 2024 18:18:35 +0200
Subject: [PATCH 03/24] 30-access-policies

---
 access_control.conf.dist    |  8 ++++----
 src/forms/mod.rs            |  1 +
 src/forms/user.rs           |  4 +++-
 src/middleware/client.rs    |  2 +-
 src/middleware/trydirect.rs | 16 +++++++++-------
 src/startup.rs              |  9 ++++++++-
 6 files changed, 26 insertions(+), 14 deletions(-)

diff --git a/access_control.conf.dist b/access_control.conf.dist
index 5d047154..f164af1a 100644
--- a/access_control.conf.dist
+++ b/access_control.conf.dist
@@ -1,14 +1,14 @@
 [request_definition]
-r = sub, dom, obj, act
+r = sub, obj, act
 
 [policy_definition]
-p = sub, dom, obj, act
+p = sub, obj, act
 
 [role_definition]
-g = _, _, _
+g = _, _
 
 [policy_effect]
 e = some(where (p.eft == allow))
 
 [matchers]
-m = g(r.sub, p.sub, r.dom) && r.dom == p.dom && r.obj == p.obj && regexMatch(r.act, p.act)
+m = g(r.sub, p.sub) && keyMatch2(r.obj, p.obj) && r.act == p.act
diff --git a/src/forms/mod.rs b/src/forms/mod.rs
index 9647ea6e..273c2a06 100644
--- a/src/forms/mod.rs
+++ b/src/forms/mod.rs
@@ -3,3 +3,4 @@ pub mod stack;
 pub mod user;
 
 pub use rating::*;
+pub use user::UserForm;
diff --git a/src/forms/user.rs b/src/forms/user.rs
index 8ff0b4ce..0fd00246 100644
--- a/src/forms/user.rs
+++ b/src/forms/user.rs
@@ -10,6 +10,8 @@ pub struct UserForm {
     pub user: User,
 }
 
+//todo deref for UserForm. userForm.id, userForm.first_name
+
 #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)]
 #[serde(rename_all = "camelCase")]
 pub struct User {
@@ -139,4 +141,4 @@ impl TryInto<UserModel> for UserForm {
         })
     }
 
-}
\ No newline at end of file
+}
diff --git a/src/middleware/client.rs b/src/middleware/client.rs
index def95b06..7345223e 100644
--- a/src/middleware/client.rs
+++ b/src/middleware/client.rs
@@ -98,7 +98,7 @@ where
 
             let accesscontrol_vals = actix_casbin_auth::CasbinVals {
                 subject: client_id.to_string(),
-                domain: Some(String::from("app")),
+                domain: None,
             };
             if req.extensions_mut().insert(accesscontrol_vals).is_some() {
                 return Err("sth wrong with access control".to_string());
diff --git a/src/middleware/trydirect.rs b/src/middleware/trydirect.rs
index c0703799..e9ce5eb8 100644
--- a/src/middleware/trydirect.rs
+++ b/src/middleware/trydirect.rs
@@ -1,4 +1,6 @@
-use crate::{models, configuration::Settings, forms::user::UserForm, helpers::JsonResponse};
+use crate::{configuration::Settings, helpers::JsonResponse};
+use crate::models;
+use crate::forms;
 use actix_web::{web, dev::ServiceRequest, Error, HttpMessage};
 use actix_web_httpauth::extractors::bearer::BearerAuth;
 use futures::future::{FutureExt};
@@ -12,20 +14,20 @@ pub async fn bearer_guard( req: ServiceRequest, credentials: BearerAuth) -> Resu
     let user = match fetch_user(settings.auth_url.as_str(), token).await {
         Ok(user) => user,
         Err(err) => {
-            return Err((JsonResponse::<i32>::build().unauthorized(err), req));
+            return Err((JsonResponse::<i32>::build().unauthorized(err), req)); //todo anonymous
         }
     };
 
     if req.extensions_mut().insert(Arc::new(user)).is_some() {
-        return Err((JsonResponse::<i32>::build().unauthorized("user already logged"), req));
+        return Err((JsonResponse::<i32>::build().unauthorized("user already logged"), req)); //todo 500 internal error
     }
 
     let accesscontrol_vals = actix_casbin_auth::CasbinVals {
-        subject: String::from("alice"),
-        domain: Some(String::from("human")),
+        subject: String::from("alice"), //todo username or anonymous
+        domain: None,
     };
     if req.extensions_mut().insert(accesscontrol_vals).is_some() {
-        return Err((JsonResponse::<i32>::build().unauthorized("sth wrong with access control"), req));
+        return Err((JsonResponse::<i32>::build().unauthorized("sth wrong with access control"), req)); //todo 500 internal error
     }
 
     Ok(req)
@@ -47,7 +49,7 @@ async fn fetch_user(auth_url: &str, token: &str) -> Result<models::User, String>
     }
 
     resp
-        .json::<UserForm>()
+        .json::<forms::UserForm>()
         .await
         .map_err(|_err| "can't parse the response body".to_string())?
         .try_into()
diff --git a/src/startup.rs b/src/startup.rs
index 1c43fc77..45f14640 100644
--- a/src/startup.rs
+++ b/src/startup.rs
@@ -28,7 +28,14 @@ pub async fn run(
     let server = HttpServer::new(move || {
         App::new()
             .wrap(TracingLogger::default())
-            .service(web::scope("/health_check").service(crate::routes::health_check))
+            .service(
+                web::scope("/health_check")
+                .wrap(HttpAuthentication::bearer(
+                        middleware::trydirect::bearer_guard,
+                        ))
+                .wrap(Cors::permissive())
+                .service(crate::routes::health_check)
+            )
             .service(
                 web::scope("/client")
                     .wrap(HttpAuthentication::bearer(

From ff82dbf72bbae09dfc0229f4721e3743f591b39c Mon Sep 17 00:00:00 2001
From: petru <smart__petea@mail.ru>
Date: Sat, 17 Feb 2024 08:03:05 +0200
Subject: [PATCH 04/24] 30-access-policies replace crate::routes::xxx with
 routes::xx

---
 src/startup.rs | 70 +++++++++++++++++++-------------------------------
 1 file changed, 26 insertions(+), 44 deletions(-)

diff --git a/src/startup.rs b/src/startup.rs
index 45f14640..447f2dd2 100644
--- a/src/startup.rs
+++ b/src/startup.rs
@@ -1,5 +1,6 @@
 use crate::configuration::Settings;
 use crate::helpers;
+use crate::routes;
 use actix_cors::Cors;
 use actix_web::dev::Server;
 use actix_web::{
@@ -28,64 +29,45 @@ pub async fn run(
     let server = HttpServer::new(move || {
         App::new()
             .wrap(TracingLogger::default())
-            .service(
-                web::scope("/health_check")
-                .wrap(HttpAuthentication::bearer(
+            /*
+                    .wrap(middleware::client::Guard::new())
+                    .wrap(HttpAuthentication::bearer(
                         middleware::trydirect::bearer_guard,
-                        ))
-                .wrap(Cors::permissive())
-                .service(crate::routes::health_check)
+                    ))
+            */
+            .wrap(access_control_manager.clone()) 
+            .wrap(Cors::permissive())
+            .service(
+                web::scope("/health_check").service(routes::health_check)
             )
             .service(
                 web::scope("/client")
-                    .wrap(HttpAuthentication::bearer(
-                        middleware::trydirect::bearer_guard,
-                    ))
-                    .wrap(Cors::permissive())
-                    .service(crate::routes::client::add_handler)
-                    .service(crate::routes::client::update_handler)
-                    .service(crate::routes::client::enable_handler)
-                    .service(crate::routes::client::disable_handler),
+                    .service(routes::client::add_handler)
+                    .service(routes::client::update_handler)
+                    .service(routes::client::enable_handler)
+                    .service(routes::client::disable_handler),
             )
             .service(
-                web::scope("/test")
-                    .wrap(access_control_manager.clone()) 
-                    .wrap(middleware::client::Guard::new())
-                    .wrap(Cors::permissive())
-                    .service(crate::routes::test::deploy::handler),
+                web::scope("/test").service(routes::test::deploy::handler),
             )
             .service(
-                web::scope("/pen/1")
-                    .wrap(access_control_manager.clone()) 
-                    .wrap(HttpAuthentication::bearer(
-                        middleware::trydirect::bearer_guard,
-                    ))
-                    .wrap(Cors::permissive())
-                    .service(crate::routes::test::casbin::handler),
+                web::scope("/pen/1").service(routes::test::casbin::handler),
             )
             .service(
                 web::scope("/rating")
-                    .wrap(HttpAuthentication::bearer(
-                        middleware::trydirect::bearer_guard,
-                    ))
-                    .wrap(Cors::permissive())
-                    .service(crate::routes::rating::add_handler)
-                    .service(crate::routes::rating::get_handler)
-                    .service(crate::routes::rating::list_handler),
+                    .service(routes::rating::add_handler)
+                    .service(routes::rating::get_handler)
+                    .service(routes::rating::list_handler),
             )
             .service(
                 web::scope("/stack")
-                    .wrap(HttpAuthentication::bearer(
-                        middleware::trydirect::bearer_guard,
-                    ))
-                    .wrap(Cors::permissive())
-                    .service(crate::routes::stack::deploy::add)
-                    .service(crate::routes::stack::compose::add)
-                    .service(crate::routes::stack::compose::admin)
-                    .service(crate::routes::stack::get::item)
-                    .service(crate::routes::stack::get::list)
-                    .service(crate::routes::stack::add::add)
-                    .service(crate::routes::stack::update::update),
+                    .service(routes::stack::deploy::add)
+                    .service(routes::stack::compose::add)
+                    .service(routes::stack::compose::admin)
+                    .service(routes::stack::get::item)
+                    .service(routes::stack::get::list)
+                    .service(routes::stack::add::add)
+                    .service(routes::stack::update::update),
             )
             .app_data(pg_pool.clone())
             .app_data(mq_manager.clone())

From 7e575c699252a2afbe35c0e7037b8d2c7248483c Mon Sep 17 00:00:00 2001
From: petru <smart__petea@mail.ru>
Date: Sat, 17 Feb 2024 08:12:46 +0200
Subject: [PATCH 05/24] 30-access-policies authorization manager

---
 .../{access_manager.rs => authorization_manager.rs}           | 0
 src/middleware/mod.rs                                         | 2 +-
 src/startup.rs                                                | 4 ++--
 3 files changed, 3 insertions(+), 3 deletions(-)
 rename src/middleware/{access_manager.rs => authorization_manager.rs} (100%)

diff --git a/src/middleware/access_manager.rs b/src/middleware/authorization_manager.rs
similarity index 100%
rename from src/middleware/access_manager.rs
rename to src/middleware/authorization_manager.rs
diff --git a/src/middleware/mod.rs b/src/middleware/mod.rs
index 59debf10..97bbd746 100644
--- a/src/middleware/mod.rs
+++ b/src/middleware/mod.rs
@@ -1,3 +1,3 @@
 pub mod client;
 pub mod trydirect;
-pub mod access_manager;
+pub mod authorization_manager;
diff --git a/src/startup.rs b/src/startup.rs
index 447f2dd2..9df9ab20 100644
--- a/src/startup.rs
+++ b/src/startup.rs
@@ -24,7 +24,7 @@ pub async fn run(
     let mq_manager = helpers::MqManager::try_new(settings.amqp.connection_string())?;
     let mq_manager = web::Data::new(mq_manager);
 
-    let access_control_manager = middleware::access_manager::try_new(settings.database.connection_string()).await?;
+    let authorization_manager = middleware::authorization_manager::try_new(settings.database.connection_string()).await?;
 
     let server = HttpServer::new(move || {
         App::new()
@@ -35,7 +35,7 @@ pub async fn run(
                         middleware::trydirect::bearer_guard,
                     ))
             */
-            .wrap(access_control_manager.clone()) 
+            .wrap(authorization_manager.clone()) 
             .wrap(Cors::permissive())
             .service(
                 web::scope("/health_check").service(routes::health_check)

From eae011695cb9e64d8ece1442f1c2e4c2738ca362 Mon Sep 17 00:00:00 2001
From: petru <smart__petea@mail.ru>
Date: Sat, 17 Feb 2024 08:25:13 +0200
Subject: [PATCH 06/24] 30-access-polices - Authorization/Authentication
 manager

---
 .../{client.rs => authentication/mod.rs}      | 16 +++++-----
 src/middleware/authorization_manager.rs       | 32 -------------------
 src/middleware/mod.rs                         |  4 +--
 src/startup.rs                                | 11 ++-----
 4 files changed, 13 insertions(+), 50 deletions(-)
 rename src/middleware/{client.rs => authentication/mod.rs} (94%)
 delete mode 100644 src/middleware/authorization_manager.rs

diff --git a/src/middleware/client.rs b/src/middleware/authentication/mod.rs
similarity index 94%
rename from src/middleware/client.rs
rename to src/middleware/authentication/mod.rs
index 7345223e..81adf906 100644
--- a/src/middleware/client.rs
+++ b/src/middleware/authentication/mod.rs
@@ -22,15 +22,15 @@ use actix_web::{
 };
 use sqlx::{Pool, Postgres};
 
-pub struct Guard {}
+pub struct Manager {}
 
-impl Guard {
+impl Manager {
     pub fn new() -> Self {
         Self {}
     }
 }
 
-impl<S, B> Transform<S, ServiceRequest> for Guard
+impl<S, B> Transform<S, ServiceRequest> for Manager
 where
     S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error> + 'static,
     S::Future: 'static,
@@ -39,21 +39,21 @@ where
     type Response = ServiceResponse<B>;
     type Error = Error;
     type InitError = ();
-    type Transform = GuardMiddleware<S>;
+    type Transform = ManagerMiddleware<S>;
     type Future = Ready<Result<Self::Transform, Self::InitError>>;
 
     fn new_transform(&self, service: S) -> Self::Future {
-        ready(Ok(GuardMiddleware {
+        ready(Ok(ManagerMiddleware {
             service: Arc::new(Mutex::new(service)),
         }))
     }
 }
 
-pub struct GuardMiddleware<S> {
+pub struct ManagerMiddleware<S> {
     service: Arc<Mutex<S>>,
 }
 
-impl<S, B> Service<ServiceRequest> for GuardMiddleware<S>
+impl<S, B> Service<ServiceRequest> for ManagerMiddleware<S>
 where
     S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error> + 'static,
     S::Future: 'static,
@@ -66,7 +66,7 @@ where
     fn poll_ready(&self, ctx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
         self.service
             .try_lock()
-            .expect("GuardMiddleware was called allready")
+            .expect("Authentication ManagerMiddleware was called allready")
             .poll_ready(ctx)
     }
 
diff --git a/src/middleware/authorization_manager.rs b/src/middleware/authorization_manager.rs
deleted file mode 100644
index 47601146..00000000
--- a/src/middleware/authorization_manager.rs
+++ /dev/null
@@ -1,32 +0,0 @@
-use actix_casbin_auth::{
-    CasbinService,
-    casbin::{
-        DefaultModel,
-        CoreApi,
-        function_map::key_match2
-    }
-};
-use std::io::{Error, ErrorKind};
-use sqlx_adapter::SqlxAdapter;
-
-pub async fn try_new(db_connection_address: String) -> Result<CasbinService, Error> {
-    let m = DefaultModel::from_file("access_control.conf")
-        .await
-        .map_err(|err| Error::new(ErrorKind::Other, format!("{err:?}")))?;
-    let a = SqlxAdapter::new(db_connection_address, 8)
-        .await
-        .map_err(|err| Error::new(ErrorKind::Other, format!("{err:?}")))?;
-
-    let mut casbin_service = CasbinService::new(m, a)
-        .await
-        .map_err(|err| Error::new(ErrorKind::Other, format!("{err:?}")))?;
-
-    casbin_service
-        .write()
-        .await
-        .get_role_manager()
-        .write()
-        .matching_fn(Some(key_match2), None);
-
-    Ok(casbin_service)
-}
diff --git a/src/middleware/mod.rs b/src/middleware/mod.rs
index 97bbd746..5efc32ed 100644
--- a/src/middleware/mod.rs
+++ b/src/middleware/mod.rs
@@ -1,3 +1,3 @@
-pub mod client;
+pub mod authentication;
 pub mod trydirect;
-pub mod authorization_manager;
+pub mod authorization;
diff --git a/src/startup.rs b/src/startup.rs
index 9df9ab20..83b8548b 100644
--- a/src/startup.rs
+++ b/src/startup.rs
@@ -24,18 +24,13 @@ pub async fn run(
     let mq_manager = helpers::MqManager::try_new(settings.amqp.connection_string())?;
     let mq_manager = web::Data::new(mq_manager);
 
-    let authorization_manager = middleware::authorization_manager::try_new(settings.database.connection_string()).await?;
+    let authorization = middleware::authorization::try_new(settings.database.connection_string()).await?;
 
     let server = HttpServer::new(move || {
         App::new()
             .wrap(TracingLogger::default())
-            /*
-                    .wrap(middleware::client::Guard::new())
-                    .wrap(HttpAuthentication::bearer(
-                        middleware::trydirect::bearer_guard,
-                    ))
-            */
-            .wrap(authorization_manager.clone()) 
+            .wrap(middleware::authentication::Manager::new())
+            .wrap(authorization.clone()) 
             .wrap(Cors::permissive())
             .service(
                 web::scope("/health_check").service(routes::health_check)

From e4ad08ab5ed81d94094de3c7a24672769384b44b Mon Sep 17 00:00:00 2001
From: petru <smart__petea@mail.ru>
Date: Sat, 17 Feb 2024 08:43:02 +0200
Subject: [PATCH 07/24] 30-access-policies get_header

---
 src/middleware/authentication/mod.rs | 23 +++++++++++++----------
 1 file changed, 13 insertions(+), 10 deletions(-)

diff --git a/src/middleware/authentication/mod.rs b/src/middleware/authentication/mod.rs
index 81adf906..c2a1450e 100644
--- a/src/middleware/authentication/mod.rs
+++ b/src/middleware/authentication/mod.rs
@@ -73,8 +73,8 @@ where
     fn call(&self, mut req: ServiceRequest) -> Self::Future {
         let service = self.service.clone();
         async move {
-            let client_id: i32 = get_header(&req, "stacker-id")?;
-            let header_hash: String = get_header(&req, "stacker-hash")?;
+            let client_id: i32 = get_header(&req, "stacker-id")?.unwrap(); //todo
+            let header_hash: String = get_header(&req, "stacker-hash")?.unwrap(); //todo
 
             let db_pool = req.app_data::<web::Data<Pool<Postgres>>>().unwrap().get_ref();
             let client: Client = db_fetch_client(db_pool, client_id).await?;
@@ -121,25 +121,28 @@ where
     }
 }
 
-fn get_header<T>(req: &ServiceRequest, header_name: &'static str) -> Result<T, String>
+fn get_header<T>(req: &ServiceRequest, header_name: &'static str) -> Result<Option<T>, String>
 where
     T: FromStr,
 {
     let header_value = req
         .headers()
-        .get(HeaderName::from_static(header_name))
-        .ok_or(format!("header {header_name} not found"))?;
+        .get(HeaderName::from_static(header_name));
 
-    let header_value: &str = header_value
-        .to_str()
-        .map_err(|_| format!("header {header_name} can't be converted to string"))?; 
+    if header_value.is_none() {
+        return Ok(None);
+    }
 
     header_value
+        .unwrap()
+        .to_str()
+        .map_err(|_| format!("header {header_name} can't be converted to string"))? 
         .parse::<T>()
         .map_err(|_| format!("header {header_name} has wrong type"))
+        .map(|v| Some(v))
 }
 
-async fn db_fetch_client(db_pool: &Pool<Postgres>, client_id: i32) -> Result<Client, String> {
+async fn db_fetch_client(db_pool: &Pool<Postgres>, client_id: i32) -> Result<Client, String> { //todo
     let query_span = tracing::info_span!("Fetching the client by ID");
 
     sqlx::query_as!(
@@ -162,7 +165,7 @@ async fn db_fetch_client(db_pool: &Pool<Postgres>, client_id: i32) -> Result<Cli
 }
 
 async fn compute_body_hash(req: &mut ServiceRequest, client_secret: &[u8]) -> Result<String, String> {
-    let content_length: usize = get_header(req, CONTENT_LENGTH.as_str())?;
+    let content_length: usize = get_header(req, CONTENT_LENGTH.as_str())?.unwrap(); //todo
     let mut body = BytesMut::with_capacity(content_length);
     let mut payload = req.take_payload();
     while let Some(chunk) = payload.next().await {

From be13d2a572a0a43a07af931fb127bc46d4f58d82 Mon Sep 17 00:00:00 2001
From: petru <smart__petea@mail.ru>
Date: Sat, 17 Feb 2024 17:38:08 +0200
Subject: [PATCH 08/24] 30-access-policies app authorization

---
 src/middleware/authentication/mod.rs | 83 ++++++++++++++++++----------
 src/startup.rs                       |  2 +-
 2 files changed, 54 insertions(+), 31 deletions(-)

diff --git a/src/middleware/authentication/mod.rs b/src/middleware/authentication/mod.rs
index c2a1450e..4a1851e3 100644
--- a/src/middleware/authentication/mod.rs
+++ b/src/middleware/authentication/mod.rs
@@ -73,40 +73,25 @@ where
     fn call(&self, mut req: ServiceRequest) -> Self::Future {
         let service = self.service.clone();
         async move {
-            let client_id: i32 = get_header(&req, "stacker-id")?.unwrap(); //todo
-            let header_hash: String = get_header(&req, "stacker-hash")?.unwrap(); //todo
-
-            let db_pool = req.app_data::<web::Data<Pool<Postgres>>>().unwrap().get_ref();
-            let client: Client = db_fetch_client(db_pool, client_id).await?;
-            if client.secret.is_none() {
-                return Err("client is not active".to_string());
-            }
-
-            let client_secret = client.secret.as_ref().unwrap().as_bytes();
-            let body_hash = compute_body_hash(&mut req, client_secret).await?;
-            if header_hash != body_hash {
-                return Err("hash is wrong".to_string());
-            }
-
-            match req.extensions_mut().insert(Arc::new(client)) {
-                Some(_) => {
-                    tracing::error!("client middleware already called once");
-                    return Err("".to_string());
+            let authorization = get_header::<String>(&req, "authorization")?;
+            let client_id = get_header::<i32>(&req, "stacker-id")?;
+            if authorization.is_some() {
+                //try_authorize_bearer(); //todo
+            } else if client_id.is_some() {
+                try_authorize_id_hash(&mut req, client_id.unwrap()).await?;
+            } else {
+                let accesscontrol_vals = actix_casbin_auth::CasbinVals {
+                    subject: "anonym".to_string(),
+                    domain: None,
+                };
+                if req.extensions_mut().insert(accesscontrol_vals).is_some() {
+                    return Err("sth wrong with access control".to_string());
                 }
-                None => {}
-            }
-
-            let accesscontrol_vals = actix_casbin_auth::CasbinVals {
-                subject: client_id.to_string(),
-                domain: None,
-            };
-            if req.extensions_mut().insert(accesscontrol_vals).is_some() {
-                return Err("sth wrong with access control".to_string());
             }
 
             Ok(req)
         }
-        .then(|req| async move {
+        .then(|req: Result<ServiceRequest, String>| async move {
             match req {
                 Ok(req) => {
                     let service = service.lock().await;
@@ -165,7 +150,7 @@ async fn db_fetch_client(db_pool: &Pool<Postgres>, client_id: i32) -> Result<Cli
 }
 
 async fn compute_body_hash(req: &mut ServiceRequest, client_secret: &[u8]) -> Result<String, String> {
-    let content_length: usize = get_header(req, CONTENT_LENGTH.as_str())?.unwrap(); //todo
+    let content_length: usize = get_header(req, CONTENT_LENGTH.as_str())?.unwrap(); 
     let mut body = BytesMut::with_capacity(content_length);
     let mut payload = req.take_payload();
     while let Some(chunk) = payload.next().await {
@@ -188,3 +173,41 @@ async fn compute_body_hash(req: &mut ServiceRequest, client_secret: &[u8]) -> Re
 
     Ok(format!("{:x}", mac.finalize().into_bytes()))
 }
+
+async fn try_authorize_id_hash(req: &mut ServiceRequest, client_id: i32) -> Result<(), String> {
+    let header_hash = get_header::<String>(&req, "stacker-hash")?; 
+    if header_hash.is_none() {
+        return Err("stacker-hash header is not set".to_string());
+    } //todo
+    let header_hash = header_hash.unwrap();
+
+    let db_pool = req.app_data::<web::Data<Pool<Postgres>>>().unwrap().get_ref();
+    let client: Client = db_fetch_client(db_pool, client_id).await?;
+    if client.secret.is_none() {
+        return Err("client is not active".to_string());
+    }
+
+    let client_secret = client.secret.as_ref().unwrap().as_bytes();
+    let body_hash = compute_body_hash(req, client_secret).await?;
+    if header_hash != body_hash {
+        return Err("hash is wrong".to_string());
+    }
+
+    match req.extensions_mut().insert(Arc::new(client)) {
+        Some(_) => {
+            tracing::error!("client middleware already called once");
+            return Err("".to_string());
+        }
+        None => {}
+    }
+
+    let accesscontrol_vals = actix_casbin_auth::CasbinVals {
+        subject: client_id.to_string(),
+        domain: None,
+    };
+    if req.extensions_mut().insert(accesscontrol_vals).is_some() {
+        return Err("sth wrong with access control".to_string());
+    }
+
+    Ok(())
+}
diff --git a/src/startup.rs b/src/startup.rs
index 83b8548b..279044e6 100644
--- a/src/startup.rs
+++ b/src/startup.rs
@@ -29,8 +29,8 @@ pub async fn run(
     let server = HttpServer::new(move || {
         App::new()
             .wrap(TracingLogger::default())
-            .wrap(middleware::authentication::Manager::new())
             .wrap(authorization.clone()) 
+            .wrap(middleware::authentication::Manager::new())
             .wrap(Cors::permissive())
             .service(
                 web::scope("/health_check").service(routes::health_check)

From be1cb818a35f8743bbddde63dfcb833809441455 Mon Sep 17 00:00:00 2001
From: petru <smart__petea@mail.ru>
Date: Sat, 17 Feb 2024 17:56:54 +0200
Subject: [PATCH 09/24] 30-access-policies two authentication managers in one
 bowl

---
 src/middleware/authentication/mod.rs | 99 ++++++++++++++++++++++------
 src/middleware/mod.rs                |  1 -
 src/middleware/trydirect.rs          | 56 ----------------
 3 files changed, 79 insertions(+), 77 deletions(-)
 delete mode 100644 src/middleware/trydirect.rs

diff --git a/src/middleware/authentication/mod.rs b/src/middleware/authentication/mod.rs
index 4a1851e3..1b79f1c3 100644
--- a/src/middleware/authentication/mod.rs
+++ b/src/middleware/authentication/mod.rs
@@ -1,24 +1,34 @@
-use crate::helpers::JsonResponse;
-use crate::models::Client;
+use crate::{
+    helpers::JsonResponse,
+    models,
+    forms,
+    configuration::Settings,
+};
 use actix_http::header::CONTENT_LENGTH;
-use actix_web::web::BytesMut;
-use actix_web::HttpMessage;
-use futures::future::{FutureExt, LocalBoxFuture};
-use futures::lock::Mutex;
-use futures::task::{Context, Poll};
-use futures::StreamExt;
+use futures::{
+    future::{FutureExt, LocalBoxFuture},
+    lock::Mutex,
+    task::{Context, Poll},
+    StreamExt,
+};
 use hmac::{Hmac, Mac};
 use sha2::Sha256;
-use std::future::{ready, Ready};
-use std::str::FromStr;
-use std::sync::Arc;
+use std::{
+    future::{ready, Ready},
+    str::FromStr,
+    sync::Arc,
+};
 use tracing::Instrument;
-
-use actix_web::{
-    dev::{Service, ServiceRequest, ServiceResponse, Transform},
+use actix_web::{};
+use reqwest::header::{ACCEPT, CONTENT_TYPE};
+use actix_web::{ 
+    web::BytesMut,
+    HttpMessage,
+    web,
+    Error,
+    dev::{ServiceRequest, Service, ServiceResponse, Transform},
     error::ErrorBadRequest,
     http::header::HeaderName,
-    web, Error,
 };
 use sqlx::{Pool, Postgres};
 
@@ -76,7 +86,7 @@ where
             let authorization = get_header::<String>(&req, "authorization")?;
             let client_id = get_header::<i32>(&req, "stacker-id")?;
             if authorization.is_some() {
-                //try_authorize_bearer(); //todo
+                try_authorize_bearer(&mut req, authorization.unwrap()).await?; 
             } else if client_id.is_some() {
                 try_authorize_id_hash(&mut req, client_id.unwrap()).await?;
             } else {
@@ -98,7 +108,7 @@ where
                     service.call(req).await
                 }
                 Err(msg) => Err(ErrorBadRequest(
-                    JsonResponse::<Client>::build().set_msg(msg).to_string(),
+                    JsonResponse::<models::Client>::build().set_msg(msg).to_string(),
                 )),
             }
         })
@@ -127,11 +137,11 @@ where
         .map(|v| Some(v))
 }
 
-async fn db_fetch_client(db_pool: &Pool<Postgres>, client_id: i32) -> Result<Client, String> { //todo
+async fn db_fetch_client(db_pool: &Pool<Postgres>, client_id: i32) -> Result<models::Client, String> { //todo
     let query_span = tracing::info_span!("Fetching the client by ID");
 
     sqlx::query_as!(
-        Client,
+        models::Client,
         r#"SELECT id, user_id, secret FROM client c WHERE c.id = $1"#,
         client_id,
         )
@@ -174,6 +184,7 @@ async fn compute_body_hash(req: &mut ServiceRequest, client_secret: &[u8]) -> Re
     Ok(format!("{:x}", mac.finalize().into_bytes()))
 }
 
+#[tracing::instrument(name = "try authorize. stacker-id header")]
 async fn try_authorize_id_hash(req: &mut ServiceRequest, client_id: i32) -> Result<(), String> {
     let header_hash = get_header::<String>(&req, "stacker-hash")?; 
     if header_hash.is_none() {
@@ -182,7 +193,7 @@ async fn try_authorize_id_hash(req: &mut ServiceRequest, client_id: i32) -> Resu
     let header_hash = header_hash.unwrap();
 
     let db_pool = req.app_data::<web::Data<Pool<Postgres>>>().unwrap().get_ref();
-    let client: Client = db_fetch_client(db_pool, client_id).await?;
+    let client: models::Client = db_fetch_client(db_pool, client_id).await?;
     if client.secret.is_none() {
         return Err("client is not active".to_string());
     }
@@ -211,3 +222,51 @@ async fn try_authorize_id_hash(req: &mut ServiceRequest, client_id: i32) -> Resu
 
     Ok(())
 }
+
+#[tracing::instrument(name = "try authorize. Authorization header")]
+async fn try_authorize_bearer(req: &mut ServiceRequest, authorization: String) -> Result<(), String> {
+    let settings = req.app_data::<web::Data<Settings>>().unwrap();
+    let token = "abc"; //todo
+    let user = match fetch_user(settings.auth_url.as_str(), token).await {
+        Ok(user) => user,
+        Err(err) => {
+            return Err(format!("{}", err));
+        }
+    }; //todo . process the err
+
+    if req.extensions_mut().insert(Arc::new(user)).is_some() {
+        return Err("user already logged".to_string());
+    }
+
+    let accesscontrol_vals = actix_casbin_auth::CasbinVals {
+        subject: String::from("alice"), //todo username or anonymous
+        domain: None,
+    };
+    if req.extensions_mut().insert(accesscontrol_vals).is_some() {
+        return Err("sth wrong with access control".to_string());
+    }
+
+    Ok(())
+}
+
+async fn fetch_user(auth_url: &str, token: &str) -> Result<models::User, String> {
+    let client = reqwest::Client::new();
+    let resp = client
+        .get(auth_url)
+        .bearer_auth(token)
+        .header(CONTENT_TYPE, "application/json")
+        .header(ACCEPT, "application/json")
+        .send()
+        .await
+        .map_err(|_err| "no resp from auth server".to_string())?;
+
+    if !resp.status().is_success() {
+        return Err("401 Unauthorized".to_string());
+    }
+
+    resp
+        .json::<forms::UserForm>()
+        .await
+        .map_err(|_err| "can't parse the response body".to_string())?
+        .try_into()
+}
diff --git a/src/middleware/mod.rs b/src/middleware/mod.rs
index 5efc32ed..6d342506 100644
--- a/src/middleware/mod.rs
+++ b/src/middleware/mod.rs
@@ -1,3 +1,2 @@
 pub mod authentication;
-pub mod trydirect;
 pub mod authorization;
diff --git a/src/middleware/trydirect.rs b/src/middleware/trydirect.rs
deleted file mode 100644
index e9ce5eb8..00000000
--- a/src/middleware/trydirect.rs
+++ /dev/null
@@ -1,56 +0,0 @@
-use crate::{configuration::Settings, helpers::JsonResponse};
-use crate::models;
-use crate::forms;
-use actix_web::{web, dev::ServiceRequest, Error, HttpMessage};
-use actix_web_httpauth::extractors::bearer::BearerAuth;
-use futures::future::{FutureExt};
-use reqwest::header::{ACCEPT, CONTENT_TYPE};
-use std::sync::Arc;
-
-#[tracing::instrument(name = "TryDirect bearer guard.")]
-pub async fn bearer_guard( req: ServiceRequest, credentials: BearerAuth) -> Result<ServiceRequest, (Error, ServiceRequest)> {
-    let settings = req.app_data::<web::Data<Settings>>().unwrap();
-    let token = credentials.token();
-    let user = match fetch_user(settings.auth_url.as_str(), token).await {
-        Ok(user) => user,
-        Err(err) => {
-            return Err((JsonResponse::<i32>::build().unauthorized(err), req)); //todo anonymous
-        }
-    };
-
-    if req.extensions_mut().insert(Arc::new(user)).is_some() {
-        return Err((JsonResponse::<i32>::build().unauthorized("user already logged"), req)); //todo 500 internal error
-    }
-
-    let accesscontrol_vals = actix_casbin_auth::CasbinVals {
-        subject: String::from("alice"), //todo username or anonymous
-        domain: None,
-    };
-    if req.extensions_mut().insert(accesscontrol_vals).is_some() {
-        return Err((JsonResponse::<i32>::build().unauthorized("sth wrong with access control"), req)); //todo 500 internal error
-    }
-
-    Ok(req)
-}
-
-async fn fetch_user(auth_url: &str, token: &str) -> Result<models::User, String> {
-    let client = reqwest::Client::new();
-    let resp = client
-        .get(auth_url)
-        .bearer_auth(token)
-        .header(CONTENT_TYPE, "application/json")
-        .header(ACCEPT, "application/json")
-        .send()
-        .await
-        .map_err(|_err| "no resp from auth server".to_string())?;
-
-    if !resp.status().is_success() {
-        return Err("401 Unauthorized".to_string());
-    }
-
-    resp
-        .json::<forms::UserForm>()
-        .await
-        .map_err(|_err| "can't parse the response body".to_string())?
-        .try_into()
-}

From f0e3df50bfe94d296bde4a827cb231080ccb477c Mon Sep 17 00:00:00 2001
From: petru <smart__petea@mail.ru>
Date: Sun, 18 Feb 2024 08:25:30 +0200
Subject: [PATCH 10/24] 30-access-policies authorization.rs

---
 src/middleware/authorization.rs | 32 ++++++++++++++++++++++++++++++++
 1 file changed, 32 insertions(+)
 create mode 100644 src/middleware/authorization.rs

diff --git a/src/middleware/authorization.rs b/src/middleware/authorization.rs
new file mode 100644
index 00000000..47601146
--- /dev/null
+++ b/src/middleware/authorization.rs
@@ -0,0 +1,32 @@
+use actix_casbin_auth::{
+    CasbinService,
+    casbin::{
+        DefaultModel,
+        CoreApi,
+        function_map::key_match2
+    }
+};
+use std::io::{Error, ErrorKind};
+use sqlx_adapter::SqlxAdapter;
+
+pub async fn try_new(db_connection_address: String) -> Result<CasbinService, Error> {
+    let m = DefaultModel::from_file("access_control.conf")
+        .await
+        .map_err(|err| Error::new(ErrorKind::Other, format!("{err:?}")))?;
+    let a = SqlxAdapter::new(db_connection_address, 8)
+        .await
+        .map_err(|err| Error::new(ErrorKind::Other, format!("{err:?}")))?;
+
+    let mut casbin_service = CasbinService::new(m, a)
+        .await
+        .map_err(|err| Error::new(ErrorKind::Other, format!("{err:?}")))?;
+
+    casbin_service
+        .write()
+        .await
+        .get_role_manager()
+        .write()
+        .matching_fn(Some(key_match2), None);
+
+    Ok(casbin_service)
+}

From 626baec4f5f098ad59d83cbd99e5d67342606c15 Mon Sep 17 00:00:00 2001
From: petru <smart__petea@mail.ru>
Date: Sun, 18 Feb 2024 08:51:31 +0200
Subject: [PATCH 11/24] 30-access-policies

---
 src/middleware/authentication/manager.rs      | 37 ++++++++
 .../authentication/manager_middleware.rs      | 58 ++++++++++++
 src/middleware/authentication/mod.rs          | 91 ++-----------------
 3 files changed, 102 insertions(+), 84 deletions(-)
 create mode 100644 src/middleware/authentication/manager.rs
 create mode 100644 src/middleware/authentication/manager_middleware.rs

diff --git a/src/middleware/authentication/manager.rs b/src/middleware/authentication/manager.rs
new file mode 100644
index 00000000..2b8e09de
--- /dev/null
+++ b/src/middleware/authentication/manager.rs
@@ -0,0 +1,37 @@
+use crate::middleware::authentication::*;
+
+use std::sync::Arc;
+use std::future::{ready, Ready};
+use futures::lock::Mutex;
+
+use actix_web::{ 
+    Error,
+    dev::{Service, ServiceRequest, ServiceResponse, Transform},
+};
+
+pub struct Manager {}
+
+impl Manager {
+    pub fn new() -> Self {
+        Self {}
+    }
+}
+
+impl<S, B> Transform<S, ServiceRequest> for Manager
+where
+    S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error> + 'static,
+    S::Future: 'static,
+    B: 'static,
+{
+    type Response = ServiceResponse<B>;
+    type Error = Error;
+    type InitError = ();
+    type Transform = ManagerMiddleware<S>;
+    type Future = Ready<Result<Self::Transform, Self::InitError>>;
+
+    fn new_transform(&self, service: S) -> Self::Future {
+        ready(Ok(ManagerMiddleware {
+            service: Arc::new(Mutex::new(service)),
+        }))
+    }
+}
diff --git a/src/middleware/authentication/manager_middleware.rs b/src/middleware/authentication/manager_middleware.rs
new file mode 100644
index 00000000..67ecbf7d
--- /dev/null
+++ b/src/middleware/authentication/manager_middleware.rs
@@ -0,0 +1,58 @@
+use crate::middleware::authentication::*;
+
+pub struct ManagerMiddleware<S> {
+    pub service: Arc<Mutex<S>>,
+}
+
+impl<S, B> Service<ServiceRequest> for ManagerMiddleware<S>
+where
+    S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error> + 'static,
+    S::Future: 'static,
+    B: 'static,
+{
+    type Response = ServiceResponse<B>;
+    type Error = S::Error;
+    type Future = LocalBoxFuture<'static, Result<ServiceResponse<B>, Error>>;
+
+    fn poll_ready(&self, ctx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
+        self.service
+            .try_lock()
+            .expect("Authentication ManagerMiddleware was called allready")
+            .poll_ready(ctx)
+    }
+
+    fn call(&self, mut req: ServiceRequest) -> Self::Future {
+        let service = self.service.clone();
+        async move {
+            let authorization = get_header::<String>(&req, "authorization")?;
+            let client_id = get_header::<i32>(&req, "stacker-id")?;
+            if authorization.is_some() {
+                try_authorize_bearer(&mut req, authorization.unwrap()).await?; 
+            } else if client_id.is_some() {
+                try_authorize_id_hash(&mut req, client_id.unwrap()).await?;
+            } else {
+                let accesscontrol_vals = actix_casbin_auth::CasbinVals {
+                    subject: "anonym".to_string(),
+                    domain: None,
+                };
+                if req.extensions_mut().insert(accesscontrol_vals).is_some() {
+                    return Err("sth wrong with access control".to_string());
+                }
+            }
+
+            Ok(req)
+        }
+        .then(|req: Result<ServiceRequest, String>| async move {
+            match req {
+                Ok(req) => {
+                    let service = service.lock().await;
+                    service.call(req).await
+                }
+                Err(msg) => Err(ErrorBadRequest(
+                    JsonResponse::<models::Client>::build().set_msg(msg).to_string(),
+                )),
+            }
+        })
+        .boxed_local()
+    }
+}
diff --git a/src/middleware/authentication/mod.rs b/src/middleware/authentication/mod.rs
index 1b79f1c3..36986c56 100644
--- a/src/middleware/authentication/mod.rs
+++ b/src/middleware/authentication/mod.rs
@@ -1,3 +1,9 @@
+mod manager;
+mod manager_middleware;
+
+pub use manager::*;
+pub use manager_middleware::*;
+
 use crate::{
     helpers::JsonResponse,
     models,
@@ -32,90 +38,6 @@ use actix_web::{
 };
 use sqlx::{Pool, Postgres};
 
-pub struct Manager {}
-
-impl Manager {
-    pub fn new() -> Self {
-        Self {}
-    }
-}
-
-impl<S, B> Transform<S, ServiceRequest> for Manager
-where
-    S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error> + 'static,
-    S::Future: 'static,
-    B: 'static,
-{
-    type Response = ServiceResponse<B>;
-    type Error = Error;
-    type InitError = ();
-    type Transform = ManagerMiddleware<S>;
-    type Future = Ready<Result<Self::Transform, Self::InitError>>;
-
-    fn new_transform(&self, service: S) -> Self::Future {
-        ready(Ok(ManagerMiddleware {
-            service: Arc::new(Mutex::new(service)),
-        }))
-    }
-}
-
-pub struct ManagerMiddleware<S> {
-    service: Arc<Mutex<S>>,
-}
-
-impl<S, B> Service<ServiceRequest> for ManagerMiddleware<S>
-where
-    S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error> + 'static,
-    S::Future: 'static,
-    B: 'static,
-{
-    type Response = ServiceResponse<B>;
-    type Error = S::Error;
-    type Future = LocalBoxFuture<'static, Result<ServiceResponse<B>, Error>>;
-
-    fn poll_ready(&self, ctx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
-        self.service
-            .try_lock()
-            .expect("Authentication ManagerMiddleware was called allready")
-            .poll_ready(ctx)
-    }
-
-    fn call(&self, mut req: ServiceRequest) -> Self::Future {
-        let service = self.service.clone();
-        async move {
-            let authorization = get_header::<String>(&req, "authorization")?;
-            let client_id = get_header::<i32>(&req, "stacker-id")?;
-            if authorization.is_some() {
-                try_authorize_bearer(&mut req, authorization.unwrap()).await?; 
-            } else if client_id.is_some() {
-                try_authorize_id_hash(&mut req, client_id.unwrap()).await?;
-            } else {
-                let accesscontrol_vals = actix_casbin_auth::CasbinVals {
-                    subject: "anonym".to_string(),
-                    domain: None,
-                };
-                if req.extensions_mut().insert(accesscontrol_vals).is_some() {
-                    return Err("sth wrong with access control".to_string());
-                }
-            }
-
-            Ok(req)
-        }
-        .then(|req: Result<ServiceRequest, String>| async move {
-            match req {
-                Ok(req) => {
-                    let service = service.lock().await;
-                    service.call(req).await
-                }
-                Err(msg) => Err(ErrorBadRequest(
-                    JsonResponse::<models::Client>::build().set_msg(msg).to_string(),
-                )),
-            }
-        })
-        .boxed_local()
-    }
-}
-
 fn get_header<T>(req: &ServiceRequest, header_name: &'static str) -> Result<Option<T>, String>
 where
     T: FromStr,
@@ -270,3 +192,4 @@ async fn fetch_user(auth_url: &str, token: &str) -> Result<models::User, String>
         .map_err(|_err| "can't parse the response body".to_string())?
         .try_into()
 }
+

From 1820776afe98d894731ee4779d19d622252a58b3 Mon Sep 17 00:00:00 2001
From: petru <smart__petea@mail.ru>
Date: Mon, 19 Feb 2024 17:59:02 +0200
Subject: [PATCH 12/24] 30-access-policies refactor

---
 src/middleware/authentication/getheader.rs    |  24 +++
 .../authentication/manager_middleware.rs      |  20 +-
 .../authentication/method/f_hmac.rs           | 102 +++++++++
 .../authentication/method/f_oauth.rs          |  60 ++++++
 src/middleware/authentication/method/mod.rs   |   5 +
 src/middleware/authentication/mod.rs          | 193 +-----------------
 6 files changed, 207 insertions(+), 197 deletions(-)
 create mode 100644 src/middleware/authentication/getheader.rs
 create mode 100644 src/middleware/authentication/method/f_hmac.rs
 create mode 100644 src/middleware/authentication/method/f_oauth.rs
 create mode 100644 src/middleware/authentication/method/mod.rs

diff --git a/src/middleware/authentication/getheader.rs b/src/middleware/authentication/getheader.rs
new file mode 100644
index 00000000..d8104001
--- /dev/null
+++ b/src/middleware/authentication/getheader.rs
@@ -0,0 +1,24 @@
+use actix_web::{ http::header::HeaderName, dev::ServiceRequest};
+use std::str::FromStr;
+
+pub fn get_header<T>(req: &ServiceRequest, header_name: &'static str) -> Result<Option<T>, String>
+where
+    T: FromStr,
+{
+    let header_value = req
+        .headers()
+        .get(HeaderName::from_static(header_name));
+
+    if header_value.is_none() {
+        return Ok(None);
+    }
+
+    header_value
+        .unwrap()
+        .to_str()
+        .map_err(|_| format!("header {header_name} can't be converted to string"))? 
+        .parse::<T>()
+        .map_err(|_| format!("header {header_name} has wrong type"))
+        .map(|v| Some(v))
+}
+
diff --git a/src/middleware/authentication/manager_middleware.rs b/src/middleware/authentication/manager_middleware.rs
index 67ecbf7d..8faa9db7 100644
--- a/src/middleware/authentication/manager_middleware.rs
+++ b/src/middleware/authentication/manager_middleware.rs
@@ -1,4 +1,9 @@
 use crate::middleware::authentication::*;
+use actix_web::{error::ErrorBadRequest, HttpMessage, Error, dev::{ServiceRequest, ServiceResponse, Service}};
+use crate::helpers::JsonResponse;
+use futures::{task::{Poll, Context}, future::{FutureExt, LocalBoxFuture}, lock::Mutex};
+use crate::models;
+use std::sync::Arc;
 
 pub struct ManagerMiddleware<S> {
     pub service: Arc<Mutex<S>>,
@@ -24,13 +29,14 @@ where
     fn call(&self, mut req: ServiceRequest) -> Self::Future {
         let service = self.service.clone();
         async move {
-            let authorization = get_header::<String>(&req, "authorization")?;
-            let client_id = get_header::<i32>(&req, "stacker-id")?;
-            if authorization.is_some() {
-                try_authorize_bearer(&mut req, authorization.unwrap()).await?; 
-            } else if client_id.is_some() {
-                try_authorize_id_hash(&mut req, client_id.unwrap()).await?;
-            } else {
+            /*
+            method::try_oauth(&mut req).await?
+            || method::try_hmac(&mut req).await?
+            || method::anonym(&mut req); //todo
+            */
+
+            if (!(method::try_oauth(&mut req).await? || method::try_hmac(&mut req).await?)) 
+            {
                 let accesscontrol_vals = actix_casbin_auth::CasbinVals {
                     subject: "anonym".to_string(),
                     domain: None,
diff --git a/src/middleware/authentication/method/f_hmac.rs b/src/middleware/authentication/method/f_hmac.rs
new file mode 100644
index 00000000..998a237f
--- /dev/null
+++ b/src/middleware/authentication/method/f_hmac.rs
@@ -0,0 +1,102 @@
+use hmac::{Hmac, Mac};
+use sha2::Sha256;
+use sqlx::{Pool, Postgres};
+use tracing::Instrument;
+use std::sync::Arc;
+use crate::models;
+use actix_web::{web, dev::ServiceRequest, HttpMessage};
+use crate::middleware::authentication::get_header; //todo move to helpers
+use actix_http::header::CONTENT_LENGTH;
+use futures::StreamExt;
+
+async fn db_fetch_client(db_pool: &Pool<Postgres>, client_id: i32) -> Result<models::Client, String> { //todo
+    let query_span = tracing::info_span!("Fetching the client by ID");
+
+    sqlx::query_as!(
+        models::Client,
+        r#"SELECT id, user_id, secret FROM client c WHERE c.id = $1"#,
+        client_id,
+        )
+        .fetch_one(db_pool)
+        .instrument(query_span)
+        .await
+        .map_err(|err| {
+            match err {
+                sqlx::Error::RowNotFound => "the client is not found".to_string(),
+                e => {
+                    tracing::error!("Failed to execute fetch query: {:?}", e);
+                    String::new()
+                }
+            }
+        })
+}
+
+async fn compute_body_hash(req: &mut ServiceRequest, client_secret: &[u8]) -> Result<String, String> {
+    let content_length: usize = get_header(req, CONTENT_LENGTH.as_str())?.unwrap(); 
+    let mut body = web::BytesMut::with_capacity(content_length);
+    let mut payload = req.take_payload();
+    while let Some(chunk) = payload.next().await {
+        body.extend_from_slice(&chunk.expect("can't unwrap the chunk"));
+    }
+
+    let mut mac =
+        match Hmac::<Sha256>::new_from_slice(client_secret) {
+            Ok(mac) => mac,
+            Err(err) => {
+                tracing::error!("error generating hmac {err:?}");
+                return Err("".to_string());
+            }
+        };
+
+    mac.update(body.as_ref());
+    let (_, mut payload) = actix_http::h1::Payload::create(true);
+    payload.unread_data(body.into());
+    req.set_payload(payload.into());
+
+    Ok(format!("{:x}", mac.finalize().into_bytes()))
+}
+
+#[tracing::instrument(name = "try authorize. stacker-id header")]
+pub async fn try_hmac(req: &mut ServiceRequest) -> Result<bool, String> {
+    let client_id = get_header::<i32>(&req, "stacker-id")?;
+    if client_id.is_none() {
+        return Ok(false);
+    }
+    let client_id = client_id.unwrap();
+
+    let header_hash = get_header::<String>(&req, "stacker-hash")?; 
+    if header_hash.is_none() {
+        return Err("stacker-hash header is not set".to_string());
+    } //todo
+    let header_hash = header_hash.unwrap();
+
+    let db_pool = req.app_data::<web::Data<Pool<Postgres>>>().unwrap().get_ref();
+    let client: models::Client = db_fetch_client(db_pool, client_id).await?;
+    if client.secret.is_none() {
+        return Err("client is not active".to_string());
+    }
+
+    let client_secret = client.secret.as_ref().unwrap().as_bytes();
+    let body_hash = compute_body_hash(req, client_secret).await?;
+    if header_hash != body_hash {
+        return Err("hash is wrong".to_string());
+    }
+
+    match req.extensions_mut().insert(Arc::new(client)) {
+        Some(_) => {
+            tracing::error!("client middleware already called once");
+            return Err("".to_string());
+        }
+        None => {}
+    }
+
+    let accesscontrol_vals = actix_casbin_auth::CasbinVals {
+        subject: client_id.to_string(),
+        domain: None,
+    };
+    if req.extensions_mut().insert(accesscontrol_vals).is_some() {
+        return Err("sth wrong with access control".to_string());
+    }
+
+    Ok(true)
+}
diff --git a/src/middleware/authentication/method/f_oauth.rs b/src/middleware/authentication/method/f_oauth.rs
new file mode 100644
index 00000000..02b20243
--- /dev/null
+++ b/src/middleware/authentication/method/f_oauth.rs
@@ -0,0 +1,60 @@
+use crate::middleware::authentication::get_header;
+use actix_web::{web, dev::{ServiceRequest}, HttpMessage};
+use crate::configuration::Settings;
+use crate::models;
+use crate::forms;
+use reqwest::header::{ACCEPT, CONTENT_TYPE};
+use std::sync::Arc;
+
+#[tracing::instrument(name = "try authorize. Authorization header")]
+pub async fn try_oauth(req: &mut ServiceRequest) -> Result<bool, String> {
+    let authentication = get_header::<String>(&req, "authorization")?; //todo
+    if authentication.is_none() {
+        return Ok(false);
+    }
+
+    let settings = req.app_data::<web::Data<Settings>>().unwrap();
+    let token = "abc"; //todo
+    let user = match fetch_user(settings.auth_url.as_str(), token).await {
+        Ok(user) => user,
+        Err(err) => {
+            return Err(format!("{}", err));
+        }
+    }; //todo . process the err
+
+    if req.extensions_mut().insert(Arc::new(user)).is_some() {
+        return Err("user already logged".to_string());
+    }
+
+    let accesscontrol_vals = actix_casbin_auth::CasbinVals {
+        subject: String::from("alice"), //todo username or anonymous
+        domain: None,
+    };
+    if req.extensions_mut().insert(accesscontrol_vals).is_some() {
+        return Err("sth wrong with access control".to_string());
+    }
+
+    Ok(true)
+}
+
+async fn fetch_user(auth_url: &str, token: &str) -> Result<models::User, String> {
+    let client = reqwest::Client::new();
+    let resp = client
+        .get(auth_url)
+        .bearer_auth(token)
+        .header(CONTENT_TYPE, "application/json")
+        .header(ACCEPT, "application/json")
+        .send()
+        .await
+        .map_err(|_err| "no resp from auth server".to_string())?;
+
+    if !resp.status().is_success() {
+        return Err("401 Unauthorized".to_string());
+    }
+
+    resp
+        .json::<forms::UserForm>()
+        .await
+        .map_err(|_err| "can't parse the response body".to_string())?
+        .try_into()
+}
diff --git a/src/middleware/authentication/method/mod.rs b/src/middleware/authentication/method/mod.rs
new file mode 100644
index 00000000..5d82a318
--- /dev/null
+++ b/src/middleware/authentication/method/mod.rs
@@ -0,0 +1,5 @@
+mod f_oauth;
+mod f_hmac;
+
+pub use f_oauth::try_oauth;
+pub use f_hmac::try_hmac;
diff --git a/src/middleware/authentication/mod.rs b/src/middleware/authentication/mod.rs
index 36986c56..5338d6dd 100644
--- a/src/middleware/authentication/mod.rs
+++ b/src/middleware/authentication/mod.rs
@@ -1,195 +1,8 @@
+mod getheader;
 mod manager;
 mod manager_middleware;
+mod method;
 
+pub use getheader::*;
 pub use manager::*;
 pub use manager_middleware::*;
-
-use crate::{
-    helpers::JsonResponse,
-    models,
-    forms,
-    configuration::Settings,
-};
-use actix_http::header::CONTENT_LENGTH;
-use futures::{
-    future::{FutureExt, LocalBoxFuture},
-    lock::Mutex,
-    task::{Context, Poll},
-    StreamExt,
-};
-use hmac::{Hmac, Mac};
-use sha2::Sha256;
-use std::{
-    future::{ready, Ready},
-    str::FromStr,
-    sync::Arc,
-};
-use tracing::Instrument;
-use actix_web::{};
-use reqwest::header::{ACCEPT, CONTENT_TYPE};
-use actix_web::{ 
-    web::BytesMut,
-    HttpMessage,
-    web,
-    Error,
-    dev::{ServiceRequest, Service, ServiceResponse, Transform},
-    error::ErrorBadRequest,
-    http::header::HeaderName,
-};
-use sqlx::{Pool, Postgres};
-
-fn get_header<T>(req: &ServiceRequest, header_name: &'static str) -> Result<Option<T>, String>
-where
-    T: FromStr,
-{
-    let header_value = req
-        .headers()
-        .get(HeaderName::from_static(header_name));
-
-    if header_value.is_none() {
-        return Ok(None);
-    }
-
-    header_value
-        .unwrap()
-        .to_str()
-        .map_err(|_| format!("header {header_name} can't be converted to string"))? 
-        .parse::<T>()
-        .map_err(|_| format!("header {header_name} has wrong type"))
-        .map(|v| Some(v))
-}
-
-async fn db_fetch_client(db_pool: &Pool<Postgres>, client_id: i32) -> Result<models::Client, String> { //todo
-    let query_span = tracing::info_span!("Fetching the client by ID");
-
-    sqlx::query_as!(
-        models::Client,
-        r#"SELECT id, user_id, secret FROM client c WHERE c.id = $1"#,
-        client_id,
-        )
-        .fetch_one(db_pool)
-        .instrument(query_span)
-        .await
-        .map_err(|err| {
-            match err {
-                sqlx::Error::RowNotFound => "the client is not found".to_string(),
-                e => {
-                    tracing::error!("Failed to execute fetch query: {:?}", e);
-                    String::new()
-                }
-            }
-        })
-}
-
-async fn compute_body_hash(req: &mut ServiceRequest, client_secret: &[u8]) -> Result<String, String> {
-    let content_length: usize = get_header(req, CONTENT_LENGTH.as_str())?.unwrap(); 
-    let mut body = BytesMut::with_capacity(content_length);
-    let mut payload = req.take_payload();
-    while let Some(chunk) = payload.next().await {
-        body.extend_from_slice(&chunk.expect("can't unwrap the chunk"));
-    }
-
-    let mut mac =
-        match Hmac::<Sha256>::new_from_slice(client_secret) {
-            Ok(mac) => mac,
-            Err(err) => {
-                tracing::error!("error generating hmac {err:?}");
-                return Err("".to_string());
-            }
-        };
-
-    mac.update(body.as_ref());
-    let (_, mut payload) = actix_http::h1::Payload::create(true);
-    payload.unread_data(body.into());
-    req.set_payload(payload.into());
-
-    Ok(format!("{:x}", mac.finalize().into_bytes()))
-}
-
-#[tracing::instrument(name = "try authorize. stacker-id header")]
-async fn try_authorize_id_hash(req: &mut ServiceRequest, client_id: i32) -> Result<(), String> {
-    let header_hash = get_header::<String>(&req, "stacker-hash")?; 
-    if header_hash.is_none() {
-        return Err("stacker-hash header is not set".to_string());
-    } //todo
-    let header_hash = header_hash.unwrap();
-
-    let db_pool = req.app_data::<web::Data<Pool<Postgres>>>().unwrap().get_ref();
-    let client: models::Client = db_fetch_client(db_pool, client_id).await?;
-    if client.secret.is_none() {
-        return Err("client is not active".to_string());
-    }
-
-    let client_secret = client.secret.as_ref().unwrap().as_bytes();
-    let body_hash = compute_body_hash(req, client_secret).await?;
-    if header_hash != body_hash {
-        return Err("hash is wrong".to_string());
-    }
-
-    match req.extensions_mut().insert(Arc::new(client)) {
-        Some(_) => {
-            tracing::error!("client middleware already called once");
-            return Err("".to_string());
-        }
-        None => {}
-    }
-
-    let accesscontrol_vals = actix_casbin_auth::CasbinVals {
-        subject: client_id.to_string(),
-        domain: None,
-    };
-    if req.extensions_mut().insert(accesscontrol_vals).is_some() {
-        return Err("sth wrong with access control".to_string());
-    }
-
-    Ok(())
-}
-
-#[tracing::instrument(name = "try authorize. Authorization header")]
-async fn try_authorize_bearer(req: &mut ServiceRequest, authorization: String) -> Result<(), String> {
-    let settings = req.app_data::<web::Data<Settings>>().unwrap();
-    let token = "abc"; //todo
-    let user = match fetch_user(settings.auth_url.as_str(), token).await {
-        Ok(user) => user,
-        Err(err) => {
-            return Err(format!("{}", err));
-        }
-    }; //todo . process the err
-
-    if req.extensions_mut().insert(Arc::new(user)).is_some() {
-        return Err("user already logged".to_string());
-    }
-
-    let accesscontrol_vals = actix_casbin_auth::CasbinVals {
-        subject: String::from("alice"), //todo username or anonymous
-        domain: None,
-    };
-    if req.extensions_mut().insert(accesscontrol_vals).is_some() {
-        return Err("sth wrong with access control".to_string());
-    }
-
-    Ok(())
-}
-
-async fn fetch_user(auth_url: &str, token: &str) -> Result<models::User, String> {
-    let client = reqwest::Client::new();
-    let resp = client
-        .get(auth_url)
-        .bearer_auth(token)
-        .header(CONTENT_TYPE, "application/json")
-        .header(ACCEPT, "application/json")
-        .send()
-        .await
-        .map_err(|_err| "no resp from auth server".to_string())?;
-
-    if !resp.status().is_success() {
-        return Err("401 Unauthorized".to_string());
-    }
-
-    resp
-        .json::<forms::UserForm>()
-        .await
-        .map_err(|_err| "can't parse the response body".to_string())?
-        .try_into()
-}
-

From 5330ad931ecc37b056539d50ab12447cae404f66 Mon Sep 17 00:00:00 2001
From: petru <smart__petea@mail.ru>
Date: Tue, 20 Feb 2024 07:40:33 +0200
Subject: [PATCH 13/24] 30-access-policies anonym logic separated

---
 .../authentication/manager_middleware.rs          | 15 +--------------
 src/middleware/authentication/method/f_anonym.rs  | 15 +++++++++++++++
 src/middleware/authentication/method/f_hmac.rs    |  2 +-
 src/middleware/authentication/method/f_oauth.rs   |  2 +-
 src/middleware/authentication/method/mod.rs       |  2 ++
 5 files changed, 20 insertions(+), 16 deletions(-)
 create mode 100644 src/middleware/authentication/method/f_anonym.rs

diff --git a/src/middleware/authentication/manager_middleware.rs b/src/middleware/authentication/manager_middleware.rs
index 8faa9db7..0a72c8d3 100644
--- a/src/middleware/authentication/manager_middleware.rs
+++ b/src/middleware/authentication/manager_middleware.rs
@@ -29,22 +29,9 @@ where
     fn call(&self, mut req: ServiceRequest) -> Self::Future {
         let service = self.service.clone();
         async move {
-            /*
             method::try_oauth(&mut req).await?
             || method::try_hmac(&mut req).await?
-            || method::anonym(&mut req); //todo
-            */
-
-            if (!(method::try_oauth(&mut req).await? || method::try_hmac(&mut req).await?)) 
-            {
-                let accesscontrol_vals = actix_casbin_auth::CasbinVals {
-                    subject: "anonym".to_string(),
-                    domain: None,
-                };
-                if req.extensions_mut().insert(accesscontrol_vals).is_some() {
-                    return Err("sth wrong with access control".to_string());
-                }
-            }
+            || method::anonym(&mut req)?;
 
             Ok(req)
         }
diff --git a/src/middleware/authentication/method/f_anonym.rs b/src/middleware/authentication/method/f_anonym.rs
new file mode 100644
index 00000000..fa7c2888
--- /dev/null
+++ b/src/middleware/authentication/method/f_anonym.rs
@@ -0,0 +1,15 @@
+use actix_web::dev::ServiceRequest;
+use actix_web::HttpMessage;
+
+#[tracing::instrument(name = "authenticate as anonym")]
+pub fn anonym(req: &mut ServiceRequest) -> Result<bool, String> {
+    let accesscontrol_vals = actix_casbin_auth::CasbinVals {
+        subject: "anonym".to_string(),
+        domain: None,
+    };
+    if req.extensions_mut().insert(accesscontrol_vals).is_some() {
+        return Err("sth wrong with access control".to_string());
+    }
+
+    Ok(true)
+}
diff --git a/src/middleware/authentication/method/f_hmac.rs b/src/middleware/authentication/method/f_hmac.rs
index 998a237f..e385f8f7 100644
--- a/src/middleware/authentication/method/f_hmac.rs
+++ b/src/middleware/authentication/method/f_hmac.rs
@@ -56,7 +56,7 @@ async fn compute_body_hash(req: &mut ServiceRequest, client_secret: &[u8]) -> Re
     Ok(format!("{:x}", mac.finalize().into_bytes()))
 }
 
-#[tracing::instrument(name = "try authorize. stacker-id header")]
+#[tracing::instrument(name = "try authenticate via hmac")]
 pub async fn try_hmac(req: &mut ServiceRequest) -> Result<bool, String> {
     let client_id = get_header::<i32>(&req, "stacker-id")?;
     if client_id.is_none() {
diff --git a/src/middleware/authentication/method/f_oauth.rs b/src/middleware/authentication/method/f_oauth.rs
index 02b20243..5566f49b 100644
--- a/src/middleware/authentication/method/f_oauth.rs
+++ b/src/middleware/authentication/method/f_oauth.rs
@@ -6,7 +6,7 @@ use crate::forms;
 use reqwest::header::{ACCEPT, CONTENT_TYPE};
 use std::sync::Arc;
 
-#[tracing::instrument(name = "try authorize. Authorization header")]
+#[tracing::instrument(name = "try authenticate via bearer")]
 pub async fn try_oauth(req: &mut ServiceRequest) -> Result<bool, String> {
     let authentication = get_header::<String>(&req, "authorization")?; //todo
     if authentication.is_none() {
diff --git a/src/middleware/authentication/method/mod.rs b/src/middleware/authentication/method/mod.rs
index 5d82a318..3d55881a 100644
--- a/src/middleware/authentication/method/mod.rs
+++ b/src/middleware/authentication/method/mod.rs
@@ -1,5 +1,7 @@
 mod f_oauth;
+mod f_anonym;
 mod f_hmac;
 
 pub use f_oauth::try_oauth;
+pub use f_anonym::anonym;
 pub use f_hmac::try_hmac;

From 44c28efbe555b35bfe6976947aa0cc68412322e0 Mon Sep 17 00:00:00 2001
From: petru <smart__petea@mail.ru>
Date: Tue, 20 Feb 2024 17:18:04 +0200
Subject: [PATCH 14/24] 30-access-policies removed http authentication

---
 Cargo.lock                                    | 219 ++++++++----------
 Cargo.toml                                    |   1 -
 .../authentication/manager_middleware.rs      |   2 +-
 .../authentication/method/f_oauth.rs          |   1 +
 src/startup.rs                                |   1 -
 5 files changed, 104 insertions(+), 120 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock
index 269e5798..da5e64ea 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -56,7 +56,7 @@ dependencies = [
  "actix-rt",
  "actix-service",
  "actix-utils",
- "ahash 0.8.7",
+ "ahash 0.8.9",
  "base64 0.21.7",
  "bitflags 2.4.2",
  "brotli",
@@ -92,7 +92,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "e01ed3140b2f8d422c68afa1ed2e85d996ea619c988ac834d255db32138655cb"
 dependencies = [
  "quote",
- "syn 2.0.48",
+ "syn 2.0.50",
 ]
 
 [[package]]
@@ -171,7 +171,7 @@ dependencies = [
  "actix-service",
  "actix-utils",
  "actix-web-codegen",
- "ahash 0.8.7",
+ "ahash 0.8.9",
  "bytes",
  "bytestring",
  "cfg-if",
@@ -205,22 +205,7 @@ dependencies = [
  "actix-router",
  "proc-macro2",
  "quote",
- "syn 2.0.48",
-]
-
-[[package]]
-name = "actix-web-httpauth"
-version = "0.8.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1d613edf08a42ccc6864c941d30fe14e1b676a77d16f1dbadc1174d065a0a775"
-dependencies = [
- "actix-utils",
- "actix-web",
- "base64 0.21.7",
- "futures-core",
- "futures-util",
- "log",
- "pin-project-lite",
+ "syn 2.0.50",
 ]
 
 [[package]]
@@ -240,9 +225,9 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
 
 [[package]]
 name = "ahash"
-version = "0.7.7"
+version = "0.7.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5a824f2aa7e75a0c98c5a504fceb80649e9c35265d44525b5f94de4771a395cd"
+checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9"
 dependencies = [
  "getrandom 0.2.12",
  "once_cell",
@@ -251,9 +236,9 @@ dependencies = [
 
 [[package]]
 name = "ahash"
-version = "0.8.7"
+version = "0.8.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "77c3a9648d43b9cd48db467b3f87fdd6e146bcc88ab0180006cef2179fe11d01"
+checksum = "d713b3834d76b85304d4d525563c1276e2e30dc97cc67bfb4585a4a29fc2c89f"
 dependencies = [
  "cfg-if",
  "const-random",
@@ -358,9 +343,9 @@ dependencies = [
 
 [[package]]
 name = "anstream"
-version = "0.6.11"
+version = "0.6.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6e2e1ebcb11de5c03c67de28a7df593d32191b44939c482e97702baaaa6ab6a5"
+checksum = "96b09b5178381e0874812a9b157f7fe84982617e48f71f4e3235482775e5b540"
 dependencies = [
  "anstyle",
  "anstyle-parse",
@@ -406,9 +391,9 @@ dependencies = [
 
 [[package]]
 name = "anyhow"
-version = "1.0.79"
+version = "1.0.80"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca"
+checksum = "5ad32ce52e4161730f7098c077cd2ed6229b5804ccf99e5366be1ab72a98b4e1"
 
 [[package]]
 name = "assert-json-diff"
@@ -438,7 +423,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "f28243a43d821d11341ab73c80bed182dc015c514b951616cf79bd4af39af0c3"
 dependencies = [
  "concurrent-queue",
- "event-listener 5.0.0",
+ "event-listener 5.1.0",
  "event-listener-strategy 0.5.0",
  "futures-core",
  "pin-project-lite",
@@ -516,7 +501,7 @@ dependencies = [
  "futures-io",
  "futures-lite 2.2.0",
  "parking",
- "polling 3.4.0",
+ "polling 3.5.0",
  "rustix 0.38.31",
  "slab",
  "tracing",
@@ -569,7 +554,7 @@ checksum = "c980ee35e870bd1a4d2c8294d4c04d0499e67bca1e4b5cefcc693c2fa00caea9"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.48",
+ "syn 2.0.50",
 ]
 
 [[package]]
@@ -708,9 +693,9 @@ dependencies = [
 
 [[package]]
 name = "bumpalo"
-version = "3.14.0"
+version = "3.15.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec"
+checksum = "d32a994c2b3ca201d9b263612a374263f05e7adde37c4707f693dcd375076d1f"
 
 [[package]]
 name = "bytecount"
@@ -844,9 +829,9 @@ dependencies = [
 
 [[package]]
 name = "clap"
-version = "4.5.0"
+version = "4.5.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "80c21025abd42669a92efc996ef13cfb2c5c627858421ea58d5c3b331a6c134f"
+checksum = "c918d541ef2913577a0f9566e9ce27cb35b6df072075769e0b26cb5a554520da"
 dependencies = [
  "clap_builder",
  "clap_derive",
@@ -854,9 +839,9 @@ dependencies = [
 
 [[package]]
 name = "clap_builder"
-version = "4.5.0"
+version = "4.5.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "458bf1f341769dfcf849846f65dffdf9146daa56bcd2a47cb4e1de9915567c99"
+checksum = "9f3e7391dad68afb0c2ede1bf619f579a3dc9c2ec67f089baa397123a2f3d1eb"
 dependencies = [
  "anstream",
  "anstyle",
@@ -873,7 +858,7 @@ dependencies = [
  "heck",
  "proc-macro2",
  "quote",
- "syn 2.0.48",
+ "syn 2.0.50",
 ]
 
 [[package]]
@@ -1001,9 +986,9 @@ checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5"
 
 [[package]]
 name = "crc32fast"
-version = "1.3.2"
+version = "1.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d"
+checksum = "b3855a8a784b474f333699ef2bbca9db2c4a1f6d9088a90a2d25b1eb53111eaa"
 dependencies = [
  "cfg-if",
 ]
@@ -1161,11 +1146,11 @@ dependencies = [
 
 [[package]]
 name = "derive_builder"
-version = "0.13.0"
+version = "0.13.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "660047478bc508c0fde22c868991eec0c40a63e48d610befef466d48e2bee574"
+checksum = "8f59169f400d8087f238c5c0c7db6a28af18681717f3b623227d92f397e938c7"
 dependencies = [
- "derive_builder_macro 0.13.0",
+ "derive_builder_macro 0.13.1",
 ]
 
 [[package]]
@@ -1182,9 +1167,9 @@ dependencies = [
 
 [[package]]
 name = "derive_builder_core"
-version = "0.13.0"
+version = "0.13.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9b217e6dd1011a54d12f3b920a411b5abd44b1716ecfe94f5f2f2f7b52e08ab7"
+checksum = "a4ec317cc3e7ef0928b0ca6e4a634a4d6c001672ae210438cf114a83e56b018d"
 dependencies = [
  "darling",
  "proc-macro2",
@@ -1204,11 +1189,11 @@ dependencies = [
 
 [[package]]
 name = "derive_builder_macro"
-version = "0.13.0"
+version = "0.13.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7a5f77d7e20ac9153428f7ca14a88aba652adfc7a0ef0a06d654386310ef663b"
+checksum = "870368c3fb35b8031abb378861d4460f573b92238ec2152c927a21f77e3e0127"
 dependencies = [
- "derive_builder_core 0.13.0",
+ "derive_builder_core 0.13.1",
  "syn 1.0.109",
 ]
 
@@ -1283,8 +1268,8 @@ version = "0.7.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "6e366950e7785fe0e404901a2b4e5c09ebd6656767f0c2167e34c5068ce0cc2d"
 dependencies = [
- "derive_builder 0.13.0",
- "indexmap 2.2.2",
+ "derive_builder 0.13.1",
+ "indexmap 2.2.3",
  "serde",
  "serde_yaml",
 ]
@@ -1374,9 +1359,9 @@ dependencies = [
 
 [[package]]
 name = "event-listener"
-version = "5.0.0"
+version = "5.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b72557800024fabbaa2449dd4bf24e37b93702d457a4d4f2b0dd1f0f039f20c1"
+checksum = "b7ad6fd685ce13acd6d9541a30f6db6567a7a24c9ffd4ba2955d29e3f22c8b27"
 dependencies = [
  "concurrent-queue",
  "parking",
@@ -1399,7 +1384,7 @@ version = "0.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "feedafcaa9b749175d5ac357452a9d41ea2911da598fde46ce1fe02c37751291"
 dependencies = [
- "event-listener 5.0.0",
+ "event-listener 5.1.0",
  "pin-project-lite",
 ]
 
@@ -1606,7 +1591,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.48",
+ "syn 2.0.50",
 ]
 
 [[package]]
@@ -1713,7 +1698,7 @@ dependencies = [
  "futures-sink",
  "futures-util",
  "http",
- "indexmap 2.2.2",
+ "indexmap 2.2.3",
  "slab",
  "tokio",
  "tokio-util",
@@ -1726,7 +1711,7 @@ version = "0.11.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
 dependencies = [
- "ahash 0.7.7",
+ "ahash 0.7.8",
 ]
 
 [[package]]
@@ -1735,7 +1720,7 @@ version = "0.12.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
 dependencies = [
- "ahash 0.7.7",
+ "ahash 0.7.8",
 ]
 
 [[package]]
@@ -1744,7 +1729,7 @@ version = "0.14.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604"
 dependencies = [
- "ahash 0.8.7",
+ "ahash 0.8.9",
  "allocator-api2",
 ]
 
@@ -1768,9 +1753,9 @@ dependencies = [
 
 [[package]]
 name = "hermit-abi"
-version = "0.3.5"
+version = "0.3.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d0c62115964e08cb8039170eb33c1d0e2388a256930279edca206fff675f82c3"
+checksum = "bd5256b483761cd23699d0da46cc6fd2ee3be420bbe6d020ae4a091e70b7e9fd"
 
 [[package]]
 name = "hex"
@@ -1949,9 +1934,9 @@ dependencies = [
 
 [[package]]
 name = "indexmap"
-version = "2.2.2"
+version = "2.2.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "824b2ae422412366ba479e8111fd301f7b5faece8149317bb81925979a53f520"
+checksum = "233cf39063f058ea2caae4091bf4a3ef70a653afbc026f5c4a4135d114e3c177"
 dependencies = [
  "equivalent",
  "hashbrown 0.14.3",
@@ -2326,9 +2311,9 @@ checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
 
 [[package]]
 name = "openssl"
-version = "0.10.63"
+version = "0.10.64"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "15c9d69dd87a29568d4d017cfe8ec518706046a05184e5aea92d0af890b803c8"
+checksum = "95a0481286a310808298130d22dd1fef0fa571e05a8f44ec801801e84b216b1f"
 dependencies = [
  "bitflags 2.4.2",
  "cfg-if",
@@ -2347,7 +2332,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.48",
+ "syn 2.0.50",
 ]
 
 [[package]]
@@ -2358,9 +2343,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
 
 [[package]]
 name = "openssl-sys"
-version = "0.9.99"
+version = "0.9.100"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "22e1bf214306098e4832460f797824c05d25aacdf896f64a985fb0fd992454ae"
+checksum = "ae94056a791d0e1217d18b6cbdccb02c61e3054fc69893607f4067e3bb0b1fd1"
 dependencies = [
  "cc",
  "libc",
@@ -2504,7 +2489,7 @@ dependencies = [
  "pest_meta",
  "proc-macro2",
  "quote",
- "syn 2.0.48",
+ "syn 2.0.50",
 ]
 
 [[package]]
@@ -2525,7 +2510,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9"
 dependencies = [
  "fixedbitset",
- "indexmap 2.2.2",
+ "indexmap 2.2.3",
 ]
 
 [[package]]
@@ -2545,7 +2530,7 @@ checksum = "266c042b60c9c76b8d53061e52b2e0d1116abc57cefc8c5cd671619a56ac3690"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.48",
+ "syn 2.0.50",
 ]
 
 [[package]]
@@ -2585,9 +2570,9 @@ dependencies = [
 
 [[package]]
 name = "pkg-config"
-version = "0.3.29"
+version = "0.3.30"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2900ede94e305130c13ddd391e0ab7cbaeb783945ae07a279c268cb05109c6cb"
+checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec"
 
 [[package]]
 name = "polling"
@@ -2607,9 +2592,9 @@ dependencies = [
 
 [[package]]
 name = "polling"
-version = "3.4.0"
+version = "3.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "30054e72317ab98eddd8561db0f6524df3367636884b7b21b703e4b280a84a14"
+checksum = "24f040dee2588b4963afb4e420540439d126f73fdacf4a9c486a96d840bac3c9"
 dependencies = [
  "cfg-if",
  "concurrent-queue",
@@ -2900,7 +2885,7 @@ version = "1.17.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "f6273372244d04a8a4b0bec080ea1e710403e88c5d9d83f9808b2bfa64f0982a"
 dependencies = [
- "ahash 0.8.7",
+ "ahash 0.8.9",
  "bitflags 2.4.2",
  "instant",
  "num-traits",
@@ -2920,7 +2905,7 @@ checksum = "9db7f8dc4c9d48183a17ce550574c42995252b82d267eaca3fcd1b979159856c"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.48",
+ "syn 2.0.50",
 ]
 
 [[package]]
@@ -2940,16 +2925,17 @@ dependencies = [
 
 [[package]]
 name = "ring"
-version = "0.17.7"
+version = "0.17.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "688c63d65483050968b2a8937f7995f443e27041a0f7700aa59b0822aedebb74"
+checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d"
 dependencies = [
  "cc",
+ "cfg-if",
  "getrandom 0.2.12",
  "libc",
  "spin 0.9.8",
  "untrusted 0.9.0",
- "windows-sys 0.48.0",
+ "windows-sys 0.52.0",
 ]
 
 [[package]]
@@ -2958,7 +2944,7 @@ version = "0.3.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "98f2771d255fd99f0294f13249fecd0cae6e074f86b4197ec1f1689d537b44d3"
 dependencies = [
- "ahash 0.7.7",
+ "ahash 0.7.8",
  "hashbrown 0.11.2",
 ]
 
@@ -3044,7 +3030,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "f9d5a6813c0759e4609cd494e8e725babae6a2ca7b62a5536a13daaec6fcb7ba"
 dependencies = [
  "log",
- "ring 0.17.7",
+ "ring 0.17.8",
  "rustls-webpki",
  "sct",
 ]
@@ -3088,15 +3074,15 @@ version = "0.101.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765"
 dependencies = [
- "ring 0.17.7",
+ "ring 0.17.8",
  "untrusted 0.9.0",
 ]
 
 [[package]]
 name = "ryu"
-version = "1.0.16"
+version = "1.0.17"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c"
+checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1"
 
 [[package]]
 name = "same-file"
@@ -3128,7 +3114,7 @@ version = "0.7.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414"
 dependencies = [
- "ring 0.17.7",
+ "ring 0.17.8",
  "untrusted 0.9.0",
 ]
 
@@ -3157,38 +3143,38 @@ dependencies = [
 
 [[package]]
 name = "semver"
-version = "1.0.21"
+version = "1.0.22"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b97ed7a9823b74f99c7742f5336af7be5ecd3eeafcb1507d1fa93347b1d589b0"
+checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca"
 dependencies = [
  "serde",
 ]
 
 [[package]]
 name = "serde"
-version = "1.0.196"
+version = "1.0.197"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "870026e60fa08c69f064aa766c10f10b1d62db9ccd4d0abb206472bee0ce3b32"
+checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2"
 dependencies = [
  "serde_derive",
 ]
 
 [[package]]
 name = "serde_derive"
-version = "1.0.196"
+version = "1.0.197"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "33c85360c95e7d137454dc81d9a4ed2b8efd8fbe19cee57357b32b9771fccb67"
+checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.48",
+ "syn 2.0.50",
 ]
 
 [[package]]
 name = "serde_json"
-version = "1.0.113"
+version = "1.0.114"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "69801b70b1c3dac963ecb03a364ba0ceda9cf60c71cfe475e99864759c8b8a79"
+checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0"
 dependencies = [
  "itoa",
  "ryu",
@@ -3274,11 +3260,11 @@ dependencies = [
 
 [[package]]
 name = "serde_yaml"
-version = "0.9.31"
+version = "0.9.32"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "adf8a49373e98a4c5f0ceb5d05aa7c648d75f63774981ed95b7c7443bbd50c6e"
+checksum = "8fd075d994154d4a774f95b51fb96bdc2832b0ea48425c92546073816cda1f2f"
 dependencies = [
- "indexmap 2.2.2",
+ "indexmap 2.2.3",
  "itoa",
  "ryu",
  "serde",
@@ -3439,9 +3425,9 @@ dependencies = [
 
 [[package]]
 name = "sqlx-adapter"
-version = "1.0.0"
+version = "1.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e39a25e18b8f9cd4f61b1653be67260d28dcd31b0bd8d3a08ed3ecbe2afa3b84"
+checksum = "24fe30f13db95ad25c9b7480d9a3c8b1fabe42a9ebd670428fa56a7173281eaa"
 dependencies = [
  "async-trait",
  "casbin",
@@ -3455,7 +3441,7 @@ version = "0.6.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "fa8241483a83a3f33aa5fff7e7d9def398ff9990b2752b6c6112b83c6d246029"
 dependencies = [
- "ahash 0.7.7",
+ "ahash 0.7.8",
  "atoi 1.0.0",
  "base64 0.13.1",
  "bitflags 1.3.2",
@@ -3510,7 +3496,7 @@ version = "0.7.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "d84b0a3c3739e220d94b3239fd69fb1f74bc36e16643423bd99de3b43c21bfbd"
 dependencies = [
- "ahash 0.8.7",
+ "ahash 0.8.9",
  "atoi 2.0.0",
  "byteorder",
  "bytes",
@@ -3526,7 +3512,7 @@ dependencies = [
  "futures-util",
  "hashlink",
  "hex",
- "indexmap 2.2.2",
+ "indexmap 2.2.3",
  "log",
  "memchr",
  "native-tls",
@@ -3663,7 +3649,6 @@ dependencies = [
  "actix-cors",
  "actix-http",
  "actix-web",
- "actix-web-httpauth",
  "chrono",
  "clap",
  "config",
@@ -3675,7 +3660,7 @@ dependencies = [
  "futures-util",
  "glob",
  "hmac",
- "indexmap 2.2.2",
+ "indexmap 2.2.3",
  "lapin",
  "rand 0.8.5",
  "regex",
@@ -3749,9 +3734,9 @@ dependencies = [
 
 [[package]]
 name = "syn"
-version = "2.0.48"
+version = "2.0.50"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f"
+checksum = "74f1bdc9872430ce9b75da68329d1c1746faf50ffac5f19e02b71e37ff881ffb"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -3826,22 +3811,22 @@ dependencies = [
 
 [[package]]
 name = "thiserror"
-version = "1.0.56"
+version = "1.0.57"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d54378c645627613241d077a3a79db965db602882668f9136ac42af9ecb730ad"
+checksum = "1e45bcbe8ed29775f228095caf2cd67af7a4ccf756ebff23a306bf3e8b47b24b"
 dependencies = [
  "thiserror-impl",
 ]
 
 [[package]]
 name = "thiserror-impl"
-version = "1.0.56"
+version = "1.0.57"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471"
+checksum = "a953cb265bef375dae3de6663da4d3804eee9682ea80d8e2542529b73c531c81"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.48",
+ "syn 2.0.50",
 ]
 
 [[package]]
@@ -3958,7 +3943,7 @@ checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.48",
+ "syn 2.0.50",
 ]
 
 [[package]]
@@ -4055,7 +4040,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.48",
+ "syn 2.0.50",
 ]
 
 [[package]]
@@ -4064,7 +4049,7 @@ version = "0.3.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "b5c266b9ac83dedf0e0385ad78514949e6d89491269e7065bee51d2bb8ec7373"
 dependencies = [
- "ahash 0.8.7",
+ "ahash 0.8.9",
  "gethostname",
  "log",
  "serde",
@@ -4320,7 +4305,7 @@ dependencies = [
  "once_cell",
  "proc-macro2",
  "quote",
- "syn 2.0.48",
+ "syn 2.0.50",
  "wasm-bindgen-shared",
 ]
 
@@ -4354,7 +4339,7 @@ checksum = "642f325be6301eb8107a83d12a8ac6c1e1c54345a7ef1a9261962dfefda09e66"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.48",
+ "syn 2.0.50",
  "wasm-bindgen-backend",
  "wasm-bindgen-shared",
 ]
@@ -4381,7 +4366,7 @@ version = "0.22.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "ed63aea5ce73d0ff405984102c42de94fc55a6b75765d621c65262469b3c9b53"
 dependencies = [
- "ring 0.17.7",
+ "ring 0.17.8",
  "untrusted 0.9.0",
 ]
 
@@ -4640,7 +4625,7 @@ checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.48",
+ "syn 2.0.50",
 ]
 
 [[package]]
diff --git a/Cargo.toml b/Cargo.toml
index 20a127c1..56ef8125 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -33,7 +33,6 @@ thiserror = "1.0"
 serde_valid = "0.16.3"
 serde_json = { version = "1.0.105", features = [] }
 serde_derive = "1.0.188"
-actix-web-httpauth = "0.8.1"
 actix-cors = "0.6.4"
 tracing-actix-web = "0.7.7"
 regex = "1.10.2"
diff --git a/src/middleware/authentication/manager_middleware.rs b/src/middleware/authentication/manager_middleware.rs
index 0a72c8d3..7b9dc6b9 100644
--- a/src/middleware/authentication/manager_middleware.rs
+++ b/src/middleware/authentication/manager_middleware.rs
@@ -29,7 +29,7 @@ where
     fn call(&self, mut req: ServiceRequest) -> Self::Future {
         let service = self.service.clone();
         async move {
-            method::try_oauth(&mut req).await?
+            let _ = method::try_oauth(&mut req).await?
             || method::try_hmac(&mut req).await?
             || method::anonym(&mut req)?;
 
diff --git a/src/middleware/authentication/method/f_oauth.rs b/src/middleware/authentication/method/f_oauth.rs
index 5566f49b..5befe353 100644
--- a/src/middleware/authentication/method/f_oauth.rs
+++ b/src/middleware/authentication/method/f_oauth.rs
@@ -9,6 +9,7 @@ use std::sync::Arc;
 #[tracing::instrument(name = "try authenticate via bearer")]
 pub async fn try_oauth(req: &mut ServiceRequest) -> Result<bool, String> {
     let authentication = get_header::<String>(&req, "authorization")?; //todo
+    println!("{authentication:?}");
     if authentication.is_none() {
         return Ok(false);
     }
diff --git a/src/startup.rs b/src/startup.rs
index 279044e6..5e57dc85 100644
--- a/src/startup.rs
+++ b/src/startup.rs
@@ -8,7 +8,6 @@ use actix_web::{
     App, HttpServer,
 };
 use crate::middleware;
-use actix_web_httpauth::middleware::HttpAuthentication;
 use sqlx::{Pool, Postgres};
 use std::net::TcpListener;
 use tracing_actix_web::TracingLogger;

From 0e5901da64a4987dee929a45d5d93a874b6dcb3c Mon Sep 17 00:00:00 2001
From: petru <smart__petea@mail.ru>
Date: Tue, 20 Feb 2024 18:30:50 +0200
Subject: [PATCH 15/24] 30-access-policies Bearer token extract logic

---
 .../authentication/method/f_oauth.rs          | 21 +++++++++++++++----
 1 file changed, 17 insertions(+), 4 deletions(-)

diff --git a/src/middleware/authentication/method/f_oauth.rs b/src/middleware/authentication/method/f_oauth.rs
index 5befe353..2b8ccb81 100644
--- a/src/middleware/authentication/method/f_oauth.rs
+++ b/src/middleware/authentication/method/f_oauth.rs
@@ -6,17 +6,30 @@ use crate::forms;
 use reqwest::header::{ACCEPT, CONTENT_TYPE};
 use std::sync::Arc;
 
+fn try_extract_token(authentication: String) -> Result<String, String> {
+    let mut authentication_parts = authentication.splitn(2, ' ');
+    match authentication_parts.next() {
+        Some("Bearer") => {}
+        _ => return Err("Bearer missing scheme".to_string())
+    }
+    let token = authentication_parts.next();
+    if token.is_none() {
+        return Err("Empty bearer token".to_string());
+    }
+
+    Ok(token.unwrap().into())
+}
+
 #[tracing::instrument(name = "try authenticate via bearer")]
 pub async fn try_oauth(req: &mut ServiceRequest) -> Result<bool, String> {
-    let authentication = get_header::<String>(&req, "authorization")?; //todo
-    println!("{authentication:?}");
+    let authentication = get_header::<String>(&req, "authorization")?;
     if authentication.is_none() {
         return Ok(false);
     }
 
+    let token = try_extract_token(authentication.unwrap())?; 
     let settings = req.app_data::<web::Data<Settings>>().unwrap();
-    let token = "abc"; //todo
-    let user = match fetch_user(settings.auth_url.as_str(), token).await {
+    let user = match fetch_user(settings.auth_url.as_str(), &token).await {
         Ok(user) => user,
         Err(err) => {
             return Err(format!("{}", err));

From 35815f61cccae763bfce7221661fabde219b98a1 Mon Sep 17 00:00:00 2001
From: petru <smart__petea@mail.ru>
Date: Wed, 21 Feb 2024 16:36:36 +0200
Subject: [PATCH 16/24] 30-access-policies user_fetch improved

---
 .../authentication/method/f_oauth.rs           | 18 ++++++++----------
 src/routes/client/disable.rs                   |  2 ++
 src/routes/client/enable.rs                    |  2 ++
 src/routes/client/update.rs                    |  2 ++
 4 files changed, 14 insertions(+), 10 deletions(-)

diff --git a/src/middleware/authentication/method/f_oauth.rs b/src/middleware/authentication/method/f_oauth.rs
index 2b8ccb81..efe215c6 100644
--- a/src/middleware/authentication/method/f_oauth.rs
+++ b/src/middleware/authentication/method/f_oauth.rs
@@ -29,21 +29,19 @@ pub async fn try_oauth(req: &mut ServiceRequest) -> Result<bool, String> {
 
     let token = try_extract_token(authentication.unwrap())?; 
     let settings = req.app_data::<web::Data<Settings>>().unwrap();
-    let user = match fetch_user(settings.auth_url.as_str(), &token).await {
-        Ok(user) => user,
-        Err(err) => {
-            return Err(format!("{}", err));
-        }
-    }; //todo . process the err
+    let user = fetch_user(settings.auth_url.as_str(), &token)
+        .await
+        .map_err(|err| format!("{err}"))?;
+
+    let accesscontrol_vals = actix_casbin_auth::CasbinVals {
+        subject: user.id.clone(),
+        domain: None,
+    };
 
     if req.extensions_mut().insert(Arc::new(user)).is_some() {
         return Err("user already logged".to_string());
     }
 
-    let accesscontrol_vals = actix_casbin_auth::CasbinVals {
-        subject: String::from("alice"), //todo username or anonymous
-        domain: None,
-    };
     if req.extensions_mut().insert(accesscontrol_vals).is_some() {
         return Err("sth wrong with access control".to_string());
     }
diff --git a/src/routes/client/disable.rs b/src/routes/client/disable.rs
index 70d2a1cb..3c46fa65 100644
--- a/src/routes/client/disable.rs
+++ b/src/routes/client/disable.rs
@@ -15,6 +15,8 @@ pub async fn disable_handler(
     pg_pool: web::Data<PgPool>,
     path: web::Path<(i32,)>,
 ) -> Result<impl Responder> {
+    //todo. the owner
+    //todo. add admin endpoint
     let client_id = path.0;
     let mut client = db::client::fetch(pg_pool.get_ref(), client_id)
         .await
diff --git a/src/routes/client/enable.rs b/src/routes/client/enable.rs
index c87fc445..ca36451c 100644
--- a/src/routes/client/enable.rs
+++ b/src/routes/client/enable.rs
@@ -16,6 +16,8 @@ pub async fn enable_handler(
     pg_pool: web::Data<PgPool>,
     path: web::Path<(i32,)>,
 ) -> Result<impl Responder> {
+    //todo the owner
+    //todo add admin endpoint
     let client_id = path.0;
     let mut client = db::client::fetch(pg_pool.get_ref(), client_id)
         .await
diff --git a/src/routes/client/update.rs b/src/routes/client/update.rs
index 5f19de51..fe8db12e 100644
--- a/src/routes/client/update.rs
+++ b/src/routes/client/update.rs
@@ -15,6 +15,8 @@ pub async fn update_handler(
     pg_pool: web::Data<PgPool>,
     path: web::Path<(i32,)>,
 ) -> Result<impl Responder> {
+    //todo owner
+    //todo admin endpoint
     let client_id = path.0;
     let mut client = db::client::fetch(pg_pool.get_ref(), client_id)
         .await

From 046425cb5d3315bebbcc24634b43597ab972f8b4 Mon Sep 17 00:00:00 2001
From: petru <smart__petea@mail.ru>
Date: Wed, 28 Feb 2024 17:09:36 +0200
Subject: [PATCH 17/24] 30-access-policies

---
 src/routes/client/enable.rs   | 5 +++--
 src/startup.rs                | 6 ++++++
 tests/middleware_trydirect.rs | 4 ----
 3 files changed, 9 insertions(+), 6 deletions(-)

diff --git a/src/routes/client/enable.rs b/src/routes/client/enable.rs
index ca36451c..c390a4ef 100644
--- a/src/routes/client/enable.rs
+++ b/src/routes/client/enable.rs
@@ -1,6 +1,6 @@
 use crate::configuration::Settings;
 use crate::db;
-use crate::helpers::client;
+use crate::helpers;
 use crate::helpers::JsonResponse;
 use crate::models;
 use actix_web::{put, web, Responder, Result};
@@ -16,6 +16,7 @@ pub async fn enable_handler(
     pg_pool: web::Data<PgPool>,
     path: web::Path<(i32,)>,
 ) -> Result<impl Responder> {
+    println!("user.id {}", user.id);
     //todo the owner
     //todo add admin endpoint
     let client_id = path.0;
@@ -28,7 +29,7 @@ pub async fn enable_handler(
         return Err(JsonResponse::<models::Client>::build().bad_request("client is already active"));
     }
 
-    client.secret = client::generate_secret(pg_pool.get_ref(), 255)
+    client.secret = helpers::client::generate_secret(pg_pool.get_ref(), 255)
         .await
         .map(|secret| Some(secret))
         .map_err(|err| JsonResponse::<models::Client>::build().bad_request(err))?;
diff --git a/src/startup.rs b/src/startup.rs
index 5e57dc85..5f0b30b8 100644
--- a/src/startup.rs
+++ b/src/startup.rs
@@ -41,6 +41,12 @@ pub async fn run(
                     .service(routes::client::enable_handler)
                     .service(routes::client::disable_handler),
             )
+            /*
+            .service(
+                web::scope("/admin/client")
+                    .service(routes::client::admin_enable_handler)
+            )
+            */
             .service(
                 web::scope("/test").service(routes::test::deploy::handler),
             )
diff --git a/tests/middleware_trydirect.rs b/tests/middleware_trydirect.rs
index 05906181..49377813 100644
--- a/tests/middleware_trydirect.rs
+++ b/tests/middleware_trydirect.rs
@@ -22,8 +22,4 @@ async fn middleware_trydirect_works() {
 
     assert!(response.status().is_success());
     assert_eq!(Some(0), response.content_length());
-
-
-    //todo header stacker-id not found
-    //
 }

From 47eac8fcf274bf1cb973797177c8354e671fd402 Mon Sep 17 00:00:00 2001
From: petru <smart__petea@mail.ru>
Date: Fri, 1 Mar 2024 16:54:41 +0200
Subject: [PATCH 18/24] 30-access-policies admin enable client

---
 src/routes/client/enable.rs | 30 ++++++++++++++++++++++++++----
 src/startup.rs              |  2 --
 2 files changed, 26 insertions(+), 6 deletions(-)

diff --git a/src/routes/client/enable.rs b/src/routes/client/enable.rs
index c390a4ef..79764110 100644
--- a/src/routes/client/enable.rs
+++ b/src/routes/client/enable.rs
@@ -8,7 +8,7 @@ use sqlx::PgPool;
 use std::sync::Arc;
 use tracing::Instrument;
 
-#[tracing::instrument(name = "Enable client.")]
+#[tracing::instrument(name = "User enable client.")]
 #[put("/{id}/enable")]
 pub async fn enable_handler(
     user: web::ReqData<Arc<models::User>>,
@@ -16,15 +16,37 @@ pub async fn enable_handler(
     pg_pool: web::Data<PgPool>,
     path: web::Path<(i32,)>,
 ) -> Result<impl Responder> {
-    println!("user.id {}", user.id);
-    //todo the owner
-    //todo add admin endpoint
     let client_id = path.0;
     let mut client = db::client::fetch(pg_pool.get_ref(), client_id)
         .await
         .map_err(|msg| JsonResponse::<models::Client>::build().internal_server_error(msg))?
         .ok_or_else(|| JsonResponse::<models::Client>::build().not_found("not found"))?;
 
+    if client.user_id != user.id {
+        return Err(JsonResponse::<models::Client>::build().bad_request("client is not the owner"));
+    }
+
+    enable_client(pg_pool, client).await
+}
+
+#[tracing::instrument(name = "Admin enable client.")]
+#[put("/{id}/enable")]
+pub async fn admin_enable_handler(
+    user: web::ReqData<Arc<models::User>>,
+    settings: web::Data<Settings>,
+    pg_pool: web::Data<PgPool>,
+    path: web::Path<(i32,)>,
+) -> Result<impl Responder> {
+    let client_id = path.0;
+    let mut client = db::client::fetch(pg_pool.get_ref(), client_id)
+        .await
+        .map_err(|msg| JsonResponse::<models::Client>::build().internal_server_error(msg))?
+        .ok_or_else(|| JsonResponse::<models::Client>::build().not_found("not found"))?;
+
+    enable_client(pg_pool, client).await
+}
+
+async fn enable_client(pg_pool: web::Data<PgPool>, mut client: models::Client) -> Result<impl Responder> {
     if client.secret.is_some() {
         return Err(JsonResponse::<models::Client>::build().bad_request("client is already active"));
     }
diff --git a/src/startup.rs b/src/startup.rs
index 5f0b30b8..7e3786dc 100644
--- a/src/startup.rs
+++ b/src/startup.rs
@@ -41,12 +41,10 @@ pub async fn run(
                     .service(routes::client::enable_handler)
                     .service(routes::client::disable_handler),
             )
-            /*
             .service(
                 web::scope("/admin/client")
                     .service(routes::client::admin_enable_handler)
             )
-            */
             .service(
                 web::scope("/test").service(routes::test::deploy::handler),
             )

From b9e6284ff791af65470eed20bcecf65ed8acfb20 Mon Sep 17 00:00:00 2001
From: petru <smart__petea@mail.ru>
Date: Sat, 2 Mar 2024 16:36:36 +0200
Subject: [PATCH 19/24] 30-access-policies client admin

---
 src/routes/client/disable.rs | 31 +++++++++++++++++++++++++++----
 src/routes/client/enable.rs  | 10 +++++-----
 src/routes/client/update.rs  | 33 ++++++++++++++++++++++++++++-----
 src/startup.rs               |  2 ++
 4 files changed, 62 insertions(+), 14 deletions(-)

diff --git a/src/routes/client/disable.rs b/src/routes/client/disable.rs
index 3c46fa65..892d3886 100644
--- a/src/routes/client/disable.rs
+++ b/src/routes/client/disable.rs
@@ -7,7 +7,7 @@ use sqlx::PgPool;
 use std::sync::Arc;
 use tracing::Instrument;
 
-#[tracing::instrument(name = "Disable client.")]
+#[tracing::instrument(name = "User disable client.")]
 #[put("/{id}/disable")]
 pub async fn disable_handler(
     user: web::ReqData<Arc<models::User>>,
@@ -15,20 +15,43 @@ pub async fn disable_handler(
     pg_pool: web::Data<PgPool>,
     path: web::Path<(i32,)>,
 ) -> Result<impl Responder> {
-    //todo. the owner
-    //todo. add admin endpoint
     let client_id = path.0;
     let mut client = db::client::fetch(pg_pool.get_ref(), client_id)
         .await
         .map_err(|msg| JsonResponse::<models::Client>::build().internal_server_error(msg))?
         .ok_or_else(|| JsonResponse::<models::Client>::build().not_found("not found"))?;
 
+    if client.user_id != user.id {
+        return Err(JsonResponse::<models::Client>::build().bad_request("client is not the owner"));
+    }
+
+    disable_client(pg_pool.get_ref(), client).await
+}
+
+#[tracing::instrument(name = "Admin disable client.")]
+#[put("/{id}/disable")]
+pub async fn admin_disable_handler(
+    user: web::ReqData<Arc<models::User>>,
+    settings: web::Data<Settings>,
+    pg_pool: web::Data<PgPool>,
+    path: web::Path<(i32,)>,
+) -> Result<impl Responder> {
+    let client_id = path.0;
+    let mut client = db::client::fetch(pg_pool.get_ref(), client_id)
+        .await
+        .map_err(|msg| JsonResponse::<models::Client>::build().internal_server_error(msg))?
+        .ok_or_else(|| JsonResponse::<models::Client>::build().not_found("not found"))?;
+
+    disable_client(pg_pool.get_ref(), client).await
+}
+
+async fn disable_client(pg_pool: &PgPool, mut client: models::Client) -> Result<impl Responder> {
     if client.secret.is_none() {
         return Err(JsonResponse::<models::Client>::build().bad_request("client is not active"));
     }
 
     client.secret = None;
-    db::client::update(pg_pool.get_ref(), client)
+    db::client::update(pg_pool, client)
         .await
         .map(|client| JsonResponse::build().set_item(client).ok("success"))
         .map_err(|msg| JsonResponse::<models::Client>::build().bad_request(msg))
diff --git a/src/routes/client/enable.rs b/src/routes/client/enable.rs
index 79764110..5fb3c642 100644
--- a/src/routes/client/enable.rs
+++ b/src/routes/client/enable.rs
@@ -26,7 +26,7 @@ pub async fn enable_handler(
         return Err(JsonResponse::<models::Client>::build().bad_request("client is not the owner"));
     }
 
-    enable_client(pg_pool, client).await
+    enable_client(pg_pool.get_ref(), client).await
 }
 
 #[tracing::instrument(name = "Admin enable client.")]
@@ -43,20 +43,20 @@ pub async fn admin_enable_handler(
         .map_err(|msg| JsonResponse::<models::Client>::build().internal_server_error(msg))?
         .ok_or_else(|| JsonResponse::<models::Client>::build().not_found("not found"))?;
 
-    enable_client(pg_pool, client).await
+    enable_client(pg_pool.get_ref(), client).await
 }
 
-async fn enable_client(pg_pool: web::Data<PgPool>, mut client: models::Client) -> Result<impl Responder> {
+async fn enable_client(pg_pool: &PgPool, mut client: models::Client) -> Result<impl Responder> {
     if client.secret.is_some() {
         return Err(JsonResponse::<models::Client>::build().bad_request("client is already active"));
     }
 
-    client.secret = helpers::client::generate_secret(pg_pool.get_ref(), 255)
+    client.secret = helpers::client::generate_secret(pg_pool, 255)
         .await
         .map(|secret| Some(secret))
         .map_err(|err| JsonResponse::<models::Client>::build().bad_request(err))?;
 
-    db::client::update(pg_pool.get_ref(), client)
+    db::client::update(pg_pool, client)
         .await
         .map(|client| JsonResponse::build().set_item(client).ok("success"))
         .map_err(|err| JsonResponse::<models::Client>::build().bad_request(err))
diff --git a/src/routes/client/update.rs b/src/routes/client/update.rs
index fe8db12e..506fd53f 100644
--- a/src/routes/client/update.rs
+++ b/src/routes/client/update.rs
@@ -7,7 +7,7 @@ use sqlx::PgPool;
 use std::sync::Arc;
 use tracing::Instrument;
 
-#[tracing::instrument(name = "Update client.")]
+#[tracing::instrument(name = "User update client.")]
 #[put("/{id}")]
 pub async fn update_handler(
     user: web::ReqData<Arc<models::User>>,
@@ -15,24 +15,47 @@ pub async fn update_handler(
     pg_pool: web::Data<PgPool>,
     path: web::Path<(i32,)>,
 ) -> Result<impl Responder> {
-    //todo owner
-    //todo admin endpoint
     let client_id = path.0;
     let mut client = db::client::fetch(pg_pool.get_ref(), client_id)
         .await
         .map_err(|msg| JsonResponse::<models::Client>::build().internal_server_error(msg))?
         .ok_or_else(|| JsonResponse::<models::Client>::build().not_found("not found"))?;
 
+    if client.user_id != user.id {
+        return Err(JsonResponse::<models::Client>::build().bad_request("client is not the owner"));
+    }
+
+    update_client(pg_pool.get_ref(), client).await
+}
+
+#[tracing::instrument(name = "Admin update client.")]
+#[put("/{id}")]
+pub async fn admin_update_handler(
+    user: web::ReqData<Arc<models::User>>,
+    settings: web::Data<Settings>,
+    pg_pool: web::Data<PgPool>,
+    path: web::Path<(i32,)>,
+) -> Result<impl Responder> {
+    let client_id = path.0;
+    let mut client = db::client::fetch(pg_pool.get_ref(), client_id)
+        .await
+        .map_err(|msg| JsonResponse::<models::Client>::build().internal_server_error(msg))?
+        .ok_or_else(|| JsonResponse::<models::Client>::build().not_found("not found"))?;
+
+    update_client(pg_pool.get_ref(), client).await
+}
+
+async fn update_client(pg_pool: &PgPool, mut client: models::Client) -> Result<impl Responder> {
     if client.secret.is_none() {
         return Err(JsonResponse::<models::Client>::build().bad_request("client is not active"));
     }
 
-    client.secret = client::generate_secret(pg_pool.get_ref(), 255)
+    client.secret = client::generate_secret(pg_pool, 255)
         .await
         .map(|s| Some(s))
         .map_err(|msg| JsonResponse::<models::Client>::build().bad_request(msg))?;
 
-    db::client::update(pg_pool.get_ref(), client)
+    db::client::update(pg_pool, client)
         .await
         .map(|client| {
             JsonResponse::<models::Client>::build()
diff --git a/src/startup.rs b/src/startup.rs
index 7e3786dc..22d071f3 100644
--- a/src/startup.rs
+++ b/src/startup.rs
@@ -44,6 +44,8 @@ pub async fn run(
             .service(
                 web::scope("/admin/client")
                     .service(routes::client::admin_enable_handler)
+                    .service(routes::client::admin_update_handler)
+                    .service(routes::client::admin_disable_handler),
             )
             .service(
                 web::scope("/test").service(routes::test::deploy::handler),

From de85d4b694ba6569a28fde0e818e615bcbe9b0ca Mon Sep 17 00:00:00 2001
From: petru <smart__petea@mail.ru>
Date: Sat, 2 Mar 2024 17:19:31 +0200
Subject: [PATCH 20/24] 30-access-policies removed src/routes/stack/service.rs

---
 src/routes/stack/service.rs | 0
 1 file changed, 0 insertions(+), 0 deletions(-)
 delete mode 100644 src/routes/stack/service.rs

diff --git a/src/routes/stack/service.rs b/src/routes/stack/service.rs
deleted file mode 100644
index e69de29b..00000000

From 618c30ea735c267a85d6173d63b203a1f02373ab Mon Sep 17 00:00:00 2001
From: petru <smart__petea@mail.ru>
Date: Sat, 2 Mar 2024 17:39:46 +0200
Subject: [PATCH 21/24] 30-access-policies owner logic for POST /stack/:id

---
 src/routes/stack/update.rs | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/src/routes/stack/update.rs b/src/routes/stack/update.rs
index ef11d825..72a0b441 100644
--- a/src/routes/stack/update.rs
+++ b/src/routes/stack/update.rs
@@ -27,11 +27,15 @@ pub async fn update(
             None => Err(JsonResponse::<models::Stack>::build().not_found("Object not found")),
         })?;
 
+    if stack.user_id != user.id {
+        return Err(JsonResponse::<models::Client>::build().bad_request("client is not the owner"));
+    }
+
     let stack_name = form.custom.custom_stack_code.clone();
     tracing::debug!("form data: {:?}", form);
     let user_id = user.id.clone();
 
-    if let Err(errors) = form.validate() {
+    if let Err(errors) = form.validate() { 
         return Err(JsonResponse::<models::Stack>::build().form_error(errors.to_string()));
     }
 

From b599b98af9d5a7e5840239b270b3ff43846d4eb1 Mon Sep 17 00:00:00 2001
From: petru <smart__petea@mail.ru>
Date: Sat, 2 Mar 2024 17:59:49 +0200
Subject: [PATCH 22/24] 30-access-policies admin, GET /stack/:id

---
 src/routes/stack/get.rs | 19 +++++++++++++++++++
 src/startup.rs          |  4 ++++
 2 files changed, 23 insertions(+)

diff --git a/src/routes/stack/get.rs b/src/routes/stack/get.rs
index ccb9c9de..d6b2e27f 100644
--- a/src/routes/stack/get.rs
+++ b/src/routes/stack/get.rs
@@ -29,6 +29,25 @@ pub async fn item(
         })
 }
 
+#[tracing::instrument(name = "Get logged user stack.")]
+#[get("/{id}")]
+pub async fn admin_item(
+    user: web::ReqData<Arc<models::User>>,
+    path: web::Path<(i32,)>,
+    pg_pool: web::Data<PgPool>,
+) -> Result<impl Responder> {
+    /// Get stack apps of logged user only
+    let (id,) = path.into_inner();
+
+    db::stack::fetch(pg_pool.get_ref(), id)
+        .await
+        .map_err(|err| JsonResponse::<models::Stack>::build().internal_server_error(err))
+        .and_then(|stack| match stack {
+            Some(stack) => Ok(JsonResponse::build().set_item(Some(stack)).ok("OK")),
+            None => Err(JsonResponse::<models::Stack>::build().not_found("not found")),
+        })
+}
+
 #[tracing::instrument(name = "Get user's stack list.")]
 #[get("/user/{id}")]
 pub async fn list(
diff --git a/src/startup.rs b/src/startup.rs
index 22d071f3..c59aff8e 100644
--- a/src/startup.rs
+++ b/src/startup.rs
@@ -69,6 +69,10 @@ pub async fn run(
                     .service(routes::stack::add::add)
                     .service(routes::stack::update::update),
             )
+            .service(
+                web::scope("/admin/stack")
+                    .service(routes::stack::get::admin_item)
+            )
             .app_data(pg_pool.clone())
             .app_data(mq_manager.clone())
             .app_data(settings.clone())

From 15b890b61436ce190a41f1a52bab6ad88e74a990 Mon Sep 17 00:00:00 2001
From: petru <smart__petea@mail.ru>
Date: Sun, 3 Mar 2024 08:33:17 +0200
Subject: [PATCH 23/24] 30-access-policies GET /stack, GET
 /admin/stack/user/:id

---
 src/routes/stack/get.rs | 25 ++++++++++++++++++++-----
 src/startup.rs          |  1 +
 2 files changed, 21 insertions(+), 5 deletions(-)

diff --git a/src/routes/stack/get.rs b/src/routes/stack/get.rs
index d6b2e27f..132a6653 100644
--- a/src/routes/stack/get.rs
+++ b/src/routes/stack/get.rs
@@ -7,7 +7,22 @@ use std::convert::From;
 use std::sync::Arc;
 use tracing::Instrument;
 
-#[tracing::instrument(name = "Get logged user stack.")]
+#[tracing::instrument(name = "User get user's stack list.")]
+#[get("")]
+pub async fn list(
+    user: web::ReqData<Arc<models::User>>,
+    pg_pool: web::Data<PgPool>,
+) -> Result<impl Responder> {
+    /// This is admin endpoint, used by a client app, client app is confidential
+    /// it should return stacks by user id
+    /// in order to pass validation at external deployment service
+    db::stack::fetch_by_user(pg_pool.get_ref(), &user.id)
+        .await
+        .map_err(|err| JsonResponse::<models::Stack>::build().internal_server_error(err))
+        .map(|stacks| JsonResponse::build().set_list(stacks).ok("OK"))
+}
+
+#[tracing::instrument(name = "User get logged user stack.")]
 #[get("/{id}")]
 pub async fn item(
     user: web::ReqData<Arc<models::User>>,
@@ -29,7 +44,7 @@ pub async fn item(
         })
 }
 
-#[tracing::instrument(name = "Get logged user stack.")]
+#[tracing::instrument(name = "Admin get logged user stack.")]
 #[get("/{id}")]
 pub async fn admin_item(
     user: web::ReqData<Arc<models::User>>,
@@ -48,10 +63,10 @@ pub async fn admin_item(
         })
 }
 
-#[tracing::instrument(name = "Get user's stack list.")]
+#[tracing::instrument(name = "User get user's stack list.")]
 #[get("/user/{id}")]
-pub async fn list(
-    user: web::ReqData<Arc<models::User>>,
+pub async fn admin_list(
+    admin: web::ReqData<Arc<models::User>>,
     path: web::Path<(String,)>,
     pg_pool: web::Data<PgPool>,
 ) -> Result<impl Responder> {
diff --git a/src/startup.rs b/src/startup.rs
index c59aff8e..b8052662 100644
--- a/src/startup.rs
+++ b/src/startup.rs
@@ -72,6 +72,7 @@ pub async fn run(
             .service(
                 web::scope("/admin/stack")
                     .service(routes::stack::get::admin_item)
+                    .service(routes::stack::get::admin_list)
             )
             .app_data(pg_pool.clone())
             .app_data(mq_manager.clone())

From 98b5a7dda7a4247101dcb7072c6d34a1afe71fb3 Mon Sep 17 00:00:00 2001
From: petru <smart__petea@mail.ru>
Date: Mon, 4 Mar 2024 17:24:01 +0200
Subject: [PATCH 24/24] 30-access-policies /stack/:id/deploy

---
 src/routes/client/disable.rs | 14 ++++++++------
 src/routes/stack/deploy.rs   |  1 +
 src/routes/stack/update.rs   |  5 +----
 3 files changed, 10 insertions(+), 10 deletions(-)

diff --git a/src/routes/client/disable.rs b/src/routes/client/disable.rs
index 892d3886..08a310cc 100644
--- a/src/routes/client/disable.rs
+++ b/src/routes/client/disable.rs
@@ -18,12 +18,14 @@ pub async fn disable_handler(
     let client_id = path.0;
     let mut client = db::client::fetch(pg_pool.get_ref(), client_id)
         .await
-        .map_err(|msg| JsonResponse::<models::Client>::build().internal_server_error(msg))?
-        .ok_or_else(|| JsonResponse::<models::Client>::build().not_found("not found"))?;
-
-    if client.user_id != user.id {
-        return Err(JsonResponse::<models::Client>::build().bad_request("client is not the owner"));
-    }
+        .map_err(|msg| JsonResponse::<models::Client>::build().internal_server_error(msg))
+        .and_then( |client| {
+            match client {
+                Some(client) if client.user_id != user.id => Err(JsonResponse::<models::Client>::build().bad_request("client is not the owner")),
+                Some(client) => Ok(client),
+                None => Err(JsonResponse::<models::Client>::build().not_found("not found"))
+            }
+        })?;
 
     disable_client(pg_pool.get_ref(), client).await
 }
diff --git a/src/routes/stack/deploy.rs b/src/routes/stack/deploy.rs
index a2bf8693..2120c16d 100644
--- a/src/routes/stack/deploy.rs
+++ b/src/routes/stack/deploy.rs
@@ -25,6 +25,7 @@ pub async fn add(
         .await
         .map_err(|err| JsonResponse::<models::Stack>::build().internal_server_error(err))
         .and_then(|stack| match stack {
+            Some(stack) if stack.user_id != user.id => Err(JsonResponse::<models::Client>::build().bad_request("client is not the owner")),
             Some(stack) => Ok(stack),
             None => Err(JsonResponse::<models::Stack>::build().not_found("not found")),
         })?;
diff --git a/src/routes/stack/update.rs b/src/routes/stack/update.rs
index 72a0b441..c2eae717 100644
--- a/src/routes/stack/update.rs
+++ b/src/routes/stack/update.rs
@@ -23,14 +23,11 @@ pub async fn update(
         .await
         .map_err(|err| JsonResponse::<models::Stack>::build().internal_server_error(err))
         .and_then(|stack| match stack {
+            Some(stack) if stack.user_id != user.id => Err(JsonResponse::<models::Client>::build().bad_request("client is not the owner")),
             Some(stack) => Ok(stack),
             None => Err(JsonResponse::<models::Stack>::build().not_found("Object not found")),
         })?;
 
-    if stack.user_id != user.id {
-        return Err(JsonResponse::<models::Client>::build().bad_request("client is not the owner"));
-    }
-
     let stack_name = form.custom.custom_stack_code.clone();
     tracing::debug!("form data: {:?}", form);
     let user_id = user.id.clone();
