diff --git a/Cargo.lock b/Cargo.lock index 81112b935..53ad56e80 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -68,7 +68,7 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" dependencies = [ - "getrandom 0.2.7", + "getrandom 0.2.8", "once_cell", "version_check", ] @@ -99,9 +99,9 @@ checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" [[package]] name = "anyhow" -version = "1.0.65" +version = "1.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98161a4e3e2184da77bb14f02184cdd111e83bbbcc9979dfee3c44b9a85f5602" +checksum = "216261ddc8289130e551ddcd5ce8a064710c0d064a4d2895c67151c92b5443f6" [[package]] name = "anymap2" @@ -134,7 +134,7 @@ dependencies = [ "num-traits", "rusticata-macros", "thiserror", - "time 0.3.15", + "time 0.3.16", ] [[package]] @@ -173,9 +173,9 @@ dependencies = [ [[package]] name = "async-compression" -version = "0.3.14" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "345fd392ab01f746c717b1357165b76f0b67a60192007b234058c9045fdcf695" +checksum = "942c7cd7ae39e91bde4820d74132e9862e62c2f386c3aa90ccf55949f5bad63a" dependencies = [ "flate2", "futures-core", @@ -210,9 +210,9 @@ dependencies = [ [[package]] name = "async-global-executor" -version = "2.3.0" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0da5b41ee986eed3f524c380e6d64965aea573882a8907682ad100f7859305ca" +checksum = "f1b6f5d7df27bd294849f8eec66ecfc63d11814df7a4f5d74168a2394467b776" dependencies = [ "async-channel", "async-executor", @@ -242,16 +242,16 @@ dependencies = [ [[package]] name = "async-io" -version = "1.9.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83e21f3a490c72b3b0cf44962180e60045de2925d8dff97918f7ee43c8f637c7" +checksum = "e8121296a9f05be7f34aa4196b1747243b3b62e048bb7906f644f3fbfc490cf7" dependencies = [ + "async-lock", "autocfg", "concurrent-queue", "futures-lite", "libc", "log", - "once_cell", "parking", "polling", "slab", @@ -262,11 +262,12 @@ dependencies = [ [[package]] name = "async-lock" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e97a171d191782fba31bb902b14ad94e24a68145032b7eedf871ab0bc0d077b6" +checksum = "c8101efe8695a6c17e02911402145357e718ac92d3ff88ae8419e84b1707b685" dependencies = [ "event-listener", + "futures-lite", ] [[package]] @@ -583,9 +584,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.11.0" +version = "3.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1ad822118d20d2c234f427000d5acc36eabe1e29a348c89b63dd60b13f28e5d" +checksum = "572f695136211188308f16ad2ca5c851a712c464060ae6974944458eb83880ba" [[package]] name = "byte-tools" @@ -625,9 +626,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.0.73" +version = "1.0.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" +checksum = "581f5dba903aac52ea3feb5ec4810848460ee833876f1f9b0fdeab1f19091574" dependencies = [ "jobserver", ] @@ -750,6 +751,16 @@ dependencies = [ "os_str_bytes", ] +[[package]] +name = "codespan-reporting" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" +dependencies = [ + "termcolor", + "unicode-width", +] + [[package]] name = "color_quant" version = "1.1.0" @@ -858,7 +869,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "344adc371239ef32293cb1c4fe519592fcf21206c79c02854320afcdf3ab4917" dependencies = [ "percent-encoding", - "time 0.3.15", + "time 0.3.16", "version_check", ] @@ -874,7 +885,7 @@ dependencies = [ "publicsuffix", "serde", "serde_json", - "time 0.3.15", + "time 0.3.16", "url", ] @@ -1075,9 +1086,9 @@ dependencies = [ [[package]] name = "ctor" -version = "0.1.23" +version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdffe87e1d521a10f9696f833fe502293ea446d7f256c06128293a4119bdf4cb" +checksum = "6d2301688392eb071b0bf1a37be05c469d3cc4dbbd95df672fe28ab021e6a096" dependencies = [ "quote", "syn", @@ -1092,6 +1103,50 @@ dependencies = [ "cipher", ] +[[package]] +name = "cxx" +version = "1.0.80" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b7d4e43b25d3c994662706a1d4fcfc32aaa6afd287502c111b237093bb23f3a" +dependencies = [ + "cc", + "cxxbridge-flags", + "cxxbridge-macro", + "link-cplusplus", +] + +[[package]] +name = "cxx-build" +version = "1.0.80" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84f8829ddc213e2c1368e51a2564c552b65a8cb6a28f31e576270ac81d5e5827" +dependencies = [ + "cc", + "codespan-reporting", + "once_cell", + "proc-macro2", + "quote", + "scratch", + "syn", +] + +[[package]] +name = "cxxbridge-flags" +version = "1.0.80" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e72537424b474af1460806647c41d4b6d35d09ef7fe031c5c2fa5766047cc56a" + +[[package]] +name = "cxxbridge-macro" +version = "1.0.80" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "309e4fb93eed90e1e14bea0da16b209f81813ba9fc7830c20ed151dd7bc0a4d7" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "daemon" version = "1.1.0-alpha.9" @@ -1113,9 +1168,9 @@ dependencies = [ [[package]] name = "darling" -version = "0.14.1" +version = "0.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4529658bdda7fd6769b8614be250cdcfc3aeb0ee72fe66f9e41e5e5eb73eac02" +checksum = "b0dd3cd20dc6b5a876612a6e5accfe7f3dd883db6d07acfbf14c128f61550dfa" dependencies = [ "darling_core", "darling_macro", @@ -1123,9 +1178,9 @@ dependencies = [ [[package]] name = "darling_core" -version = "0.14.1" +version = "0.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "649c91bc01e8b1eac09fb91e8dbc7d517684ca6be8ebc75bb9cafc894f9fdb6f" +checksum = "a784d2ccaf7c98501746bf0be29b2022ba41fd62a2e622af997a03e9f972859f" dependencies = [ "fnv", "ident_case", @@ -1137,9 +1192,9 @@ dependencies = [ [[package]] name = "darling_macro" -version = "0.14.1" +version = "0.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddfc69c5bfcbd2fc09a0f38451d2daf0e372e367986a83906d1b0dbc88134fb5" +checksum = "7618812407e9402654622dd402b0a89dff9ba93badd6540781526117b92aab7e" dependencies = [ "darling_core", "quote", @@ -1386,7 +1441,7 @@ checksum = "c6dedfc944f4ac38cac8b74cb1c7b4fb73c175db232d6fa98e9bd1fd81908b89" dependencies = [ "base64 0.13.1", "byteorder", - "getrandom 0.2.7", + "getrandom 0.2.8", "openssl", "zeroize", ] @@ -1596,9 +1651,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.7" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6" +checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" dependencies = [ "cfg-if 1.0.0", "js-sys", @@ -1818,9 +1873,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.3.14" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ca32592cf21ac7ccab1825cd87f6c9b3d9022c44d086172ed0966bec8af30be" +checksum = "5f9f29bc9dda355256b2916cf526ab02ce0aeaaaf2bad60d65ef3f12f11dd0f4" dependencies = [ "bytes", "fnv", @@ -1919,7 +1974,7 @@ checksum = "75f43d41e26995c17e71ee126451dd3941010b0514a81a9d11f3b341debc2399" dependencies = [ "bytes", "fnv", - "itoa 1.0.3", + "itoa 1.0.4", ] [[package]] @@ -1994,7 +2049,7 @@ dependencies = [ "http-body", "httparse", "httpdate", - "itoa 1.0.3", + "itoa 1.0.4", "pin-project-lite 0.2.9", "socket2", "tokio", @@ -2031,17 +2086,28 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.50" +version = "0.1.53" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd911b35d940d2bd0bea0f9100068e5b97b51a1cbe13d13382f132e0365257a0" +checksum = "64c122667b287044802d6ce17ee2ddf13207ed924c712de9a66a5814d5b64765" dependencies = [ "android_system_properties", "core-foundation-sys", + "iana-time-zone-haiku", "js-sys", "wasm-bindgen", "winapi", ] +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0703ae284fc167426161c2e3f1da3ea71d94b21bedbcc9494e92b28e334e3dca" +dependencies = [ + "cxx", + "cxx-build", +] + [[package]] name = "ident_case" version = "1.0.1" @@ -2157,9 +2223,9 @@ checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" [[package]] name = "itoa" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8af84674fe1f223a982c933a0ee1086ac4d4052aa0fb8060c12c6ad838e754" +checksum = "4217ad341ebadf8d8e724e264f13e593e0648f5b3e94b3896a5df283be015ecc" [[package]] name = "jobserver" @@ -2477,9 +2543,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.135" +version = "0.2.137" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68783febc7782c6c5cb401fbda4de5a9898be1762314da0bb2c10ced61f18b0c" +checksum = "fc7fcc620a3bff7cdd7a365be3376c97191aeaccc2a603e600951e452615bf89" [[package]] name = "libgit2-sys" @@ -2508,9 +2574,9 @@ dependencies = [ [[package]] name = "libsqlite3-sys" -version = "0.25.1" +version = "0.25.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f0455f2c1bc9a7caa792907026e469c1d91761fb0ea37cbb16427c77280cf35" +checksum = "29f835d03d717946d28b1d1ed632eb6f0e24a299388ee623d0c23118d3e8a7fa" dependencies = [ "cc", "pkg-config", @@ -2563,6 +2629,15 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "link-cplusplus" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9272ab7b96c9046fbc5bc56c06c117cb639fe2d509df0c421cad82d2915cf369" +dependencies = [ + "cc", +] + [[package]] name = "linked-hash-map" version = "0.5.6" @@ -2679,14 +2754,14 @@ dependencies = [ [[package]] name = "mio" -version = "0.8.4" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57ee1c23c7c63b0c9250c339ffdc69255f110b298b901b9f6c82547b7b87caaf" +checksum = "e5d732bc30207a6423068df043e3d02e0735b155ad7ce1a6f76fe2baa5b158de" dependencies = [ "libc", "log", "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys 0.36.1", + "windows-sys 0.42.0", ] [[package]] @@ -2855,7 +2930,7 @@ checksum = "6d62c436394991641b970a92e23e8eeb4eb9bca74af4f5badc53bcd568daadbd" dependencies = [ "base64 0.13.1", "chrono", - "getrandom 0.2.7", + "getrandom 0.2.8", "http", "rand 0.8.5", "reqwest", @@ -2878,9 +2953,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.15.0" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e82dad04139b71a90c080c8463fe0dc7902db5192d939bd0950f074d014339e1" +checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860" [[package]] name = "oncemutex" @@ -2940,9 +3015,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-sys" -version = "0.9.76" +version = "0.9.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5230151e44c0f05157effb743e8d517472843121cf9243e8b81393edb5acd9ce" +checksum = "b03b84c3b2d099b81f0953422b4d4ad58761589d0229b5506356afca05a3670a" dependencies = [ "autocfg", "cc", @@ -2981,9 +3056,9 @@ dependencies = [ [[package]] name = "os_str_bytes" -version = "6.3.0" +version = "6.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ff7415e9ae3fff1225851df9e0d9e4e5479f947619774677a63572e55e80eff" +checksum = "3baf96e39c5359d2eb0dd6ccb42c62b91d9678aa68160d261b9e0ccbf9e9dea9" [[package]] name = "overload" @@ -3018,15 +3093,15 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.3" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09a279cbf25cb0757810394fbc1e359949b59e348145c643a939a525692e6929" +checksum = "4dc9e0dc2adc1c69d09143aff38d3d30c5c3f0df0dad82e6d25547af174ebec0" dependencies = [ "cfg-if 1.0.0", "libc", "redox_syscall", "smallvec", - "windows-sys 0.36.1", + "windows-sys 0.42.0", ] [[package]] @@ -3154,9 +3229,9 @@ dependencies = [ [[package]] name = "polling" -version = "2.3.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "899b00b9c8ab553c743b3e11e87c5c7d423b2a2de229ba95b24a756344748011" +checksum = "ab4609a838d88b73d8238967b60dd115cc08d38e2bbaf51ee1e4b695f89122e2" dependencies = [ "autocfg", "cfg-if 1.0.0", @@ -3226,9 +3301,9 @@ checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" [[package]] name = "proc-macro2" -version = "1.0.46" +version = "1.0.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94e2ef8dbfc347b10c094890f778ee2e36ca9bb4262e86dc99cd217e35f3470b" +checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725" dependencies = [ "unicode-ident", ] @@ -3250,11 +3325,11 @@ checksum = "33cb294fe86a74cbcf50d4445b37da762029549ebeea341421c7c70370f86cac" [[package]] name = "publicsuffix" -version = "2.2.2" +version = "2.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aeeedb0b429dc462f30ad27ef3de97058b060016f47790c066757be38ef792b4" +checksum = "96a8c1bda5ae1af7f99a2962e49df150414a43d62404644d98dd5c3a93d07457" dependencies = [ - "idna 0.2.3", + "idna 0.3.0", "psl-types", ] @@ -3372,7 +3447,7 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.7", + "getrandom 0.2.8", ] [[package]] @@ -3423,7 +3498,7 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" dependencies = [ - "getrandom 0.2.7", + "getrandom 0.2.8", "redox_syscall", "thiserror", ] @@ -3688,6 +3763,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +[[package]] +name = "scratch" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8132065adcfd6e02db789d9285a0deb2f3fcb04002865ab67d5fb103533898" + [[package]] name = "sct" version = "0.7.0" @@ -3823,7 +3904,7 @@ version = "1.0.87" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ce777b7b150d76b9cf60d28b55f5847135a003f7d7350c6be7a773508ce7d45" dependencies = [ - "itoa 1.0.3", + "itoa 1.0.4", "ryu", "serde", ] @@ -3855,7 +3936,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" dependencies = [ "form_urlencoded", - "itoa 1.0.3", + "itoa 1.0.4", "ryu", "serde", ] @@ -4328,16 +4409,24 @@ dependencies = [ [[package]] name = "time" -version = "0.3.15" +version = "0.3.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d634a985c4d4238ec39cacaed2e7ae552fbd3c476b552c1deac3021b7d7eaf0c" +checksum = "0fab5c8b9980850e06d92ddbe3ab839c062c801f3927c0fb8abd6fc8e918fbca" dependencies = [ - "itoa 1.0.3", + "itoa 1.0.4", "libc", "num_threads", - "time-macros 0.2.4", + "serde", + "time-core", + "time-macros 0.2.5", ] +[[package]] +name = "time-core" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e153e1f1acaef8acc537e68b44906d2db6436e2b35ac2c6b42640fff91f00fd" + [[package]] name = "time-macros" version = "0.1.1" @@ -4350,9 +4439,12 @@ dependencies = [ [[package]] name = "time-macros" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42657b1a6f4d817cda8e7a0ace261fe0cc946cf3a80314390b22cc61ae080792" +checksum = "65bb801831d812c562ae7d2bfb531f26e66e4e1f6b17307ba4149c5064710e5b" +dependencies = [ + "time-core", +] [[package]] name = "time-macros-impl" @@ -4588,9 +4680,9 @@ checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" [[package]] name = "unicode-ident" -version = "1.0.4" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcc811dc4066ac62f84f11307873c4850cb653bfa9b1719cee2bd2204a4bc5dd" +checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3" [[package]] name = "unicode-normalization" @@ -4663,7 +4755,7 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "feb41e78f93363bb2df8b0e86a2ca30eed7806ea16ea0c790d757cf93f79be83" dependencies = [ - "getrandom 0.2.7", + "getrandom 0.2.8", "serde", ] @@ -5156,7 +5248,7 @@ dependencies = [ "oid-registry", "rusticata-macros", "thiserror", - "time 0.3.15", + "time 0.3.16", ] [[package]] @@ -5276,5 +5368,5 @@ dependencies = [ "lazy_static", "quick-error", "regex", - "time 0.3.15", + "time 0.3.16", ] diff --git a/kanidm_proto/src/v1.rs b/kanidm_proto/src/v1.rs index 4e9576112..be33fe8a6 100644 --- a/kanidm_proto/src/v1.rs +++ b/kanidm_proto/src/v1.rs @@ -393,7 +393,7 @@ pub struct UserAuthToken { pub displayname: String, pub spn: String, pub mail_primary: Option, - pub groups: Vec, + // pub groups: Vec, pub ui_hints: BTreeSet, } @@ -414,9 +414,11 @@ impl fmt::Display for UserAuthToken { writeln!(f, "purpose: read write (expiry: {})", expiry)? } } + /* for group in &self.groups { writeln!(f, "group: {:?}", group.spn)?; } + */ Ok(()) } } @@ -866,11 +868,24 @@ impl fmt::Display for AuthMech { } } +#[derive(Debug, Serialize, Deserialize, Copy, Clone)] +#[serde(rename_all = "lowercase")] +pub enum AuthIssueSession { + Token, + Cookie, +} + #[derive(Debug, Serialize, Deserialize)] #[serde(rename_all = "lowercase")] pub enum AuthStep { // name Init(String), + // A new way to issue sessions. Doing this as a new init type + // to prevent breaking existing clients. + Init2 { + username: String, + issue: AuthIssueSession, + }, // We want to talk to you like this. Begin(AuthMech), // Step @@ -959,9 +974,11 @@ pub enum AuthState { Continue(Vec), // Something was bad, your session is terminated and no cookie. Denied(String), - // Everything is good, your bearer header has been issued and is within + // Everything is good, your bearer token has been issued and is within // the result. Success(String), + // Everything is good, your cookie has been issued. + SuccessCookie, } #[derive(Debug, Serialize, Deserialize)] diff --git a/kanidmd/core/src/actors/v1_read.rs b/kanidmd/core/src/actors/v1_read.rs index 55813a136..d8b72d6cd 100644 --- a/kanidmd/core/src/actors/v1_read.rs +++ b/kanidmd/core/src/actors/v1_read.rs @@ -6,7 +6,7 @@ use std::sync::Arc; use kanidm_proto::v1::{ ApiToken, AuthRequest, BackupCodesView, CURequest, CUSessionToken, CUStatus, CredentialStatus, Entry as ProtoEntry, OperationError, RadiusAuthToken, SearchRequest, SearchResponse, UatStatus, - UnixGroupToken, UnixUserToken, WhoamiResponse, + UnixGroupToken, UnixUserToken, UserAuthToken, WhoamiResponse, }; use ldap3_proto::simple::*; use regex::Regex; @@ -320,6 +320,34 @@ impl QueryServerReadV1 { } } + #[instrument( + level = "info", + name = "whoami_uat", + skip(self, uat, eventid) + fields(uuid = ?eventid) + )] + pub async fn handle_whoami_uat( + &self, + uat: Option, + eventid: Uuid, + ) -> Result { + let ct = duration_from_epoch_now(); + let idms_prox_read = self.idms.proxy_read().await; + // Make an event from the whoami request. This will process the event and + // generate a selfuuid search. + // + // This current handles the unauthenticated check, and will + // trigger the failure, but if we can manage to work out async + // then move this to core.rs, and don't allow Option to get + // this far. + idms_prox_read + .validate_and_parse_token_to_uat(uat.as_deref(), ct) + .map_err(|e| { + admin_error!(?e, "Invalid identity"); + e + }) + } + #[instrument( level = "info", skip_all, diff --git a/kanidmd/core/src/https/mod.rs b/kanidmd/core/src/https/mod.rs index 05b56b41c..2a50127ee 100644 --- a/kanidmd/core/src/https/mod.rs +++ b/kanidmd/core/src/https/mod.rs @@ -378,11 +378,11 @@ pub fn create_https_server( tserver.with(sketching::middleware::TreeMiddleware::new( trust_x_forward_for, )); - // tserver.with(tide::log::LogMiddleware::new()); + // We do not force a session ttl, because we validate this elsewhere in usage. tserver.with( // We do not force a session ttl, because we validate this elsewhere in usage. - tide::sessions::SessionMiddleware::new(tide::sessions::MemoryStore::new(), cookie_key) + tide::sessions::SessionMiddleware::new(tide::sessions::CookieStore::new(), cookie_key) .with_cookie_name("kanidm-session") .with_same_site_policy(tide::http::cookies::SameSite::Strict), ); @@ -566,6 +566,7 @@ pub fn create_https_server( let mut self_route = appserver.at("/v1/self"); self_route.at("/").mapped_get(&mut routemap, whoami); + self_route.at("/_uat").mapped_get(&mut routemap, whoami_uat); self_route .at("/_attr/:attr") diff --git a/kanidmd/core/src/https/v1.rs b/kanidmd/core/src/https/v1.rs index ab7d8659e..437c30ecb 100644 --- a/kanidmd/core/src/https/v1.rs +++ b/kanidmd/core/src/https/v1.rs @@ -3,9 +3,10 @@ use std::time::Duration; use compact_jwt::Jws; use kanidm_proto::v1::{ - AccountUnixExtend, ApiTokenGenerate, AuthRequest, AuthResponse, AuthState as ProtoAuthState, - CUIntentToken, CURequest, CUSessionToken, CreateRequest, DeleteRequest, Entry as ProtoEntry, - GroupUnixExtend, ModifyRequest, OperationError, SearchRequest, SingleStringRequest, + AccountUnixExtend, ApiTokenGenerate, AuthIssueSession, AuthRequest, AuthResponse, + AuthState as ProtoAuthState, CUIntentToken, CURequest, CUSessionToken, CreateRequest, + DeleteRequest, Entry as ProtoEntry, GroupUnixExtend, ModifyRequest, OperationError, + SearchRequest, SingleStringRequest, }; use kanidmd_lib::filter::{Filter, FilterInvalid}; use kanidmd_lib::idm::event::AuthResult; @@ -64,10 +65,25 @@ pub async fn whoami(req: tide::Request) -> tide::Result { to_tide_response(res, hvalue) } -pub async fn logout(req: tide::Request) -> tide::Result { +pub async fn whoami_uat(req: tide::Request) -> tide::Result { let uat = req.get_current_uat(); let (eventid, hvalue) = req.new_eventid(); + let res = req.state().qe_r_ref.handle_whoami_uat(uat, eventid).await; + to_tide_response(res, hvalue) +} + +pub async fn logout(mut req: tide::Request) -> tide::Result { + let uat = req.get_current_uat(); + let (eventid, hvalue) = req.new_eventid(); + + // Now lets nuke any cookies for the session. We do this before the handle_logout + // so that if any errors occur, the cookies are still removed. + let msession = req.session_mut(); + msession.remove("auth-session-id"); + msession.remove("bearer"); + let res = req.state().qe_w_ref.handle_logout(uat, eventid).await; + to_tide_response(res, hvalue) } @@ -1125,17 +1141,21 @@ pub async fn auth(mut req: tide::Request) -> tide::Result { }) .map(|_| ProtoAuthState::Continue(allowed)) } - AuthState::Success(token) => { + AuthState::Success(token, issue) => { debug!("🧩 -> AuthState::Success"); // Remove the auth-session-id let msession = req.session_mut(); msession.remove("auth-session-id"); // Create a session cookie? msession.remove("bearer"); - msession - .insert("bearer", token.clone()) - .map_err(|_| OperationError::InvalidSessionState) - .map(|_| ProtoAuthState::Success(token)) + + match issue { + AuthIssueSession::Cookie => msession + .insert("bearer", token) + .map_err(|_| OperationError::InvalidSessionState) + .map(|_| ProtoAuthState::SuccessCookie), + AuthIssueSession::Token => Ok(ProtoAuthState::Success(token)), + } } AuthState::Denied(reason) => { debug!("🧩 -> AuthState::Denied"); diff --git a/kanidmd/lib/src/idm/account.rs b/kanidmd/lib/src/idm/account.rs index 9c712d54f..d81545dd1 100644 --- a/kanidmd/lib/src/idm/account.rs +++ b/kanidmd/lib/src/idm/account.rs @@ -213,7 +213,7 @@ impl Account { mail_primary: self.mail_primary.clone(), ui_hints: self.ui_hints.clone(), // application: None, - groups: self.groups.iter().map(|g| g.to_proto()).collect(), + // groups: self.groups.iter().map(|g| g.to_proto()).collect(), }) } diff --git a/kanidmd/lib/src/idm/authsession.rs b/kanidmd/lib/src/idm/authsession.rs index 8763bbb8e..509cce0d0 100644 --- a/kanidmd/lib/src/idm/authsession.rs +++ b/kanidmd/lib/src/idm/authsession.rs @@ -10,7 +10,9 @@ use std::time::Duration; // use webauthn_rs::proto::Credential as WebauthnCredential; use compact_jwt::{Jws, JwsSigner}; use hashbrown::HashSet; -use kanidm_proto::v1::{AuthAllowed, AuthCredential, AuthMech, AuthType, OperationError}; +use kanidm_proto::v1::{ + AuthAllowed, AuthCredential, AuthIssueSession, AuthMech, AuthType, OperationError, +}; // use crossbeam::channel::Sender; use tokio::sync::mpsc::UnboundedSender as Sender; use uuid::Uuid; @@ -569,13 +571,21 @@ pub(crate) struct AuthSession { // // This handler will then handle the mfa and stepping up through to generate the auth states state: AuthSessionState, + + // The type of session we will issue if successful + issue: AuthIssueSession, } impl AuthSession { /// Create a new auth session, based on the available credential handlers of the account. /// the session is a whole encapsulated unit of what we need to proceed, so that subsequent /// or interleved write operations do not cause inconsistency in this process. - pub fn new(account: Account, webauthn: &Webauthn, ct: Duration) -> (Option, AuthState) { + pub fn new( + account: Account, + issue: AuthIssueSession, + webauthn: &Webauthn, + ct: Duration, + ) -> (Option, AuthState) { // During this setup, determine the credential handler that we'll be using // for this session. This is currently based on presentation of an application // id. @@ -623,7 +633,11 @@ impl AuthSession { (None, AuthState::Denied(reason.to_string())) } else { // We can proceed - let auth_session = AuthSession { account, state }; + let auth_session = AuthSession { + account, + state, + issue, + }; // Get the set of mechanisms that can proceed. This is tied // to the session so that it can mutate state and have progression // of what's next, or ordering. @@ -742,8 +756,11 @@ impl AuthSession { CredState::Success(auth_type) => { security_info!("Successful cred handling"); let session_id = Uuid::new_v4(); + let issue = self.issue; + security_info!( - "Starting session {} for {} {}", + "Issuing {:?} session {} for {} {}", + issue, session_id, self.account.spn, self.account.uuid @@ -805,7 +822,7 @@ impl AuthSession { ( Some(AuthSessionState::Success), - Ok(AuthState::Success(token)), + Ok(AuthState::Success(token, issue)), ) } CredState::Continue(allowed) => { @@ -870,7 +887,7 @@ mod tests { use compact_jwt::JwsSigner; use hashbrown::HashSet; - use kanidm_proto::v1::{AuthAllowed, AuthCredential, AuthMech}; + use kanidm_proto::v1::{AuthAllowed, AuthCredential, AuthIssueSession, AuthMech}; use tokio::sync::mpsc::unbounded_channel as unbounded; use webauthn_authenticator_rs::softpasskey::SoftPasskey; use webauthn_authenticator_rs::WebauthnAuthenticator; @@ -914,7 +931,12 @@ mod tests { let anon_account = entry_str_to_account!(JSON_ANONYMOUS_V1); - let (session, state) = AuthSession::new(anon_account, &webauthn, duration_from_epoch_now()); + let (session, state) = AuthSession::new( + anon_account, + AuthIssueSession::Token, + &webauthn, + duration_from_epoch_now(), + ); if let AuthState::Choose(auth_mechs) = state { assert!(auth_mechs.iter().any(|x| matches!(x, AuthMech::Anonymous))); @@ -942,8 +964,12 @@ mod tests { $account:expr, $webauthn:expr ) => {{ - let (session, state) = - AuthSession::new($account.clone(), $webauthn, duration_from_epoch_now()); + let (session, state) = AuthSession::new( + $account.clone(), + AuthIssueSession::Token, + $webauthn, + duration_from_epoch_now(), + ); let mut session = session.unwrap(); if let AuthState::Choose(auth_mechs) = state { @@ -1013,7 +1039,7 @@ mod tests { Some(&pw_badlist_cache), &jws_signer, ) { - Ok(AuthState::Success(_)) => {} + Ok(AuthState::Success(_, AuthIssueSession::Token)) => {} _ => panic!(), }; @@ -1066,8 +1092,12 @@ mod tests { $account:expr, $webauthn:expr ) => {{ - let (session, state) = - AuthSession::new($account.clone(), $webauthn, duration_from_epoch_now()); + let (session, state) = AuthSession::new( + $account.clone(), + AuthIssueSession::Token, + $webauthn, + duration_from_epoch_now(), + ); let mut session = session.expect("Session was unable to be created."); if let AuthState::Choose(auth_mechs) = state { @@ -1260,7 +1290,7 @@ mod tests { Some(&pw_badlist_cache), &jws_signer, ) { - Ok(AuthState::Success(_)) => {} + Ok(AuthState::Success(_, AuthIssueSession::Token)) => {} _ => panic!(), }; @@ -1347,8 +1377,12 @@ mod tests { $account:expr, $webauthn:expr ) => {{ - let (session, state) = - AuthSession::new($account.clone(), $webauthn, duration_from_epoch_now()); + let (session, state) = AuthSession::new( + $account.clone(), + AuthIssueSession::Token, + $webauthn, + duration_from_epoch_now(), + ); let mut session = session.unwrap(); if let AuthState::Choose(auth_mechs) = state { @@ -1485,7 +1519,7 @@ mod tests { None, &jws_signer, ) { - Ok(AuthState::Success(_)) => {} + Ok(AuthState::Success(_, AuthIssueSession::Token)) => {} _ => panic!(), }; @@ -1724,7 +1758,7 @@ mod tests { Some(&pw_badlist_cache), &jws_signer, ) { - Ok(AuthState::Success(_)) => {} + Ok(AuthState::Success(_, AuthIssueSession::Token)) => {} _ => panic!(), }; @@ -1931,7 +1965,7 @@ mod tests { Some(&pw_badlist_cache), &jws_signer, ) { - Ok(AuthState::Success(_)) => {} + Ok(AuthState::Success(_, AuthIssueSession::Token)) => {} _ => panic!(), }; @@ -1970,7 +2004,7 @@ mod tests { Some(&pw_badlist_cache), &jws_signer, ) { - Ok(AuthState::Success(_)) => {} + Ok(AuthState::Success(_, AuthIssueSession::Token)) => {} _ => panic!(), }; @@ -2127,7 +2161,7 @@ mod tests { Some(&pw_badlist_cache), &jws_signer, ) { - Ok(AuthState::Success(_)) => {} + Ok(AuthState::Success(_, AuthIssueSession::Token)) => {} _ => panic!(), }; } @@ -2169,7 +2203,7 @@ mod tests { Some(&pw_badlist_cache), &jws_signer, ) { - Ok(AuthState::Success(_)) => {} + Ok(AuthState::Success(_, AuthIssueSession::Token)) => {} _ => panic!(), }; } diff --git a/kanidmd/lib/src/idm/credupdatesession.rs b/kanidmd/lib/src/idm/credupdatesession.rs index 3c8e51d2b..8192e54ec 100644 --- a/kanidmd/lib/src/idm/credupdatesession.rs +++ b/kanidmd/lib/src/idm/credupdatesession.rs @@ -1473,7 +1473,7 @@ mod tests { use std::time::Duration; use async_std::task; - use kanidm_proto::v1::{AuthAllowed, AuthMech, CredentialDetailType}; + use kanidm_proto::v1::{AuthAllowed, AuthIssueSession, AuthMech, CredentialDetailType}; use uuid::uuid; use webauthn_authenticator_rs::softpasskey::SoftPasskey; use webauthn_authenticator_rs::WebauthnAuthenticator; @@ -1714,7 +1714,7 @@ mod tests { match r2 { Ok(AuthResult { sessionid: _, - state: AuthState::Success(token), + state: AuthState::Success(token, AuthIssueSession::Token), delay: _, }) => { // Process the auth session @@ -1788,7 +1788,7 @@ mod tests { match r3 { Ok(AuthResult { sessionid: _, - state: AuthState::Success(token), + state: AuthState::Success(token, AuthIssueSession::Token), delay: _, }) => { // Process the auth session @@ -1857,7 +1857,7 @@ mod tests { match r3 { Ok(AuthResult { sessionid: _, - state: AuthState::Success(token), + state: AuthState::Success(token, AuthIssueSession::Token), delay: _, }) => { // There now should be a backup code invalidation present @@ -1934,7 +1934,7 @@ mod tests { match r3 { Ok(AuthResult { sessionid: _, - state: AuthState::Success(token), + state: AuthState::Success(token, AuthIssueSession::Token), delay: _, }) => { // Process the webauthn update diff --git a/kanidmd/lib/src/idm/event.rs b/kanidmd/lib/src/idm/event.rs index bc3257345..ed96ac57f 100644 --- a/kanidmd/lib/src/idm/event.rs +++ b/kanidmd/lib/src/idm/event.rs @@ -3,7 +3,7 @@ use std::time::Duration; use crate::idm::AuthState; use crate::prelude::*; use kanidm_proto::v1::OperationError; -use kanidm_proto::v1::{AuthCredential, AuthMech, AuthRequest, AuthStep}; +use kanidm_proto::v1::{AuthCredential, AuthIssueSession, AuthMech, AuthRequest, AuthStep}; #[cfg(test)] use webauthn_rs::prelude::PublicKeyCredential; @@ -294,8 +294,8 @@ impl LdapTokenAuthEvent { #[derive(Debug)] pub struct AuthEventStepInit { - pub name: String, - pub appid: Option, + pub username: String, + pub issue: AuthIssueSession, } #[derive(Debug)] @@ -320,9 +320,14 @@ pub enum AuthEventStep { impl AuthEventStep { fn from_authstep(aus: AuthStep, sid: Option) -> Result { match aus { - AuthStep::Init(name) => { - Ok(AuthEventStep::Init(AuthEventStepInit { name, appid: None })) + AuthStep::Init(username) => Ok(AuthEventStep::Init(AuthEventStepInit { + username, + issue: AuthIssueSession::Token, + })), + AuthStep::Init2 { username, issue } => { + Ok(AuthEventStep::Init(AuthEventStepInit { username, issue })) } + AuthStep::Begin(mech) => match sid { Some(ssid) => Ok(AuthEventStep::Begin(AuthEventStepMech { sessionid: ssid, @@ -347,16 +352,16 @@ impl AuthEventStep { #[cfg(test)] pub fn anonymous_init() -> Self { AuthEventStep::Init(AuthEventStepInit { - name: "anonymous".to_string(), - appid: None, + username: "anonymous".to_string(), + issue: AuthIssueSession::Token, }) } #[cfg(test)] pub fn named_init(name: &str) -> Self { AuthEventStep::Init(AuthEventStepInit { - name: name.to_string(), - appid: None, + username: name.to_string(), + issue: AuthIssueSession::Token, }) } diff --git a/kanidmd/lib/src/idm/mod.rs b/kanidmd/lib/src/idm/mod.rs index 5937d378d..d1723b06e 100644 --- a/kanidmd/lib/src/idm/mod.rs +++ b/kanidmd/lib/src/idm/mod.rs @@ -18,13 +18,13 @@ pub mod unix; use std::fmt; -use kanidm_proto::v1::{AuthAllowed, AuthMech}; +use kanidm_proto::v1::{AuthAllowed, AuthIssueSession, AuthMech}; pub enum AuthState { Choose(Vec), Continue(Vec), Denied(String), - Success(String), + Success(String, AuthIssueSession), } impl fmt::Debug for AuthState { @@ -33,7 +33,7 @@ impl fmt::Debug for AuthState { AuthState::Choose(mechs) => write!(f, "AuthState::Choose({:?})", mechs), AuthState::Continue(allow) => write!(f, "AuthState::Continue({:?})", allow), AuthState::Denied(reason) => write!(f, "AuthState::Denied({:?})", reason), - AuthState::Success(_token) => write!(f, "AuthState::Success"), + AuthState::Success(_token, issue) => write!(f, "AuthState::Success({:?})", issue), } } } diff --git a/kanidmd/lib/src/idm/server.rs b/kanidmd/lib/src/idm/server.rs index 68f7c4608..c1e18cf29 100644 --- a/kanidmd/lib/src/idm/server.rs +++ b/kanidmd/lib/src/idm/server.rs @@ -410,6 +410,21 @@ pub trait IdmServerTransaction<'a> { } } + #[instrument(level = "info", skip_all)] + fn validate_and_parse_token_to_uat( + &self, + token: Option<&str>, + ct: Duration, + ) -> Result { + match self.validate_and_parse_token_to_token(token, ct)? { + Token::UserAuthToken(uat) => Ok(uat), + Token::ApiToken(_apit, _entry) => { + warn!("Unable to process non user auth token"); + Err(OperationError::NotAuthenticated) + } + } + } + fn validate_and_parse_token_to_token( &self, token: Option<&str>, @@ -878,13 +893,14 @@ impl<'a> IdmServerAuthTransaction<'a> { // // Check anything needed? Get the current auth-session-id from request // because it associates to the nonce's etc which were all cached. - let euuid = self.qs_read.name_to_uuid(init.name.as_str())?; + let euuid = self.qs_read.name_to_uuid(init.username.as_str())?; // Get the first / single entry we expect here .... let entry = self.qs_read.internal_search_uuid(&euuid)?; security_info!( - name = %init.name, + username = %init.username, + issue = ?init.issue, uuid = %euuid, "Initiating Authentication Session", ); @@ -956,7 +972,8 @@ impl<'a> IdmServerAuthTransaction<'a> { }; */ - let (auth_session, state) = AuthSession::new(account, self.webauthn, ct); + let (auth_session, state) = + AuthSession::new(account, init.issue, self.webauthn, ct); match auth_session { Some(auth_session) => { @@ -2225,7 +2242,7 @@ mod tests { use std::time::Duration; use async_std::task; - use kanidm_proto::v1::{AuthAllowed, AuthMech, AuthType, OperationError}; + use kanidm_proto::v1::{AuthAllowed, AuthIssueSession, AuthMech, AuthType, OperationError}; use smartstring::alias::String as AttrString; use uuid::Uuid; @@ -2366,7 +2383,7 @@ mod tests { debug_assert!(delay.is_none()); match state { - AuthState::Success(_uat) => { + AuthState::Success(_uat, AuthIssueSession::Token) => { // Check the uat. } _ => { @@ -2505,7 +2522,7 @@ mod tests { debug_assert!(delay.is_none()); match state { - AuthState::Success(token) => { + AuthState::Success(token, AuthIssueSession::Token) => { // Check the uat. token } @@ -2574,7 +2591,7 @@ mod tests { } = ar; debug_assert!(delay.is_none()); match state { - AuthState::Success(_uat) => { + AuthState::Success(_uat, AuthIssueSession::Token) => { // Check the uat. } _ => { @@ -3435,7 +3452,7 @@ mod tests { } = ar; debug_assert!(delay.is_none()); match state { - AuthState::Success(_uat) => { + AuthState::Success(_uat, AuthIssueSession::Token) => { // Check the uat. } _ => { diff --git a/kanidmd_web_ui/pkg/README.md b/kanidmd_web_ui/pkg/README.md index 116d44b17..a0328d2d0 100644 --- a/kanidmd_web_ui/pkg/README.md +++ b/kanidmd_web_ui/pkg/README.md @@ -1,30 +1,47 @@ +# Kanidm - Simple and Secure Identity Management

-# Kanidm +## About -Kanidm is an identity management platform written in rust. Our goals are: +Kanidm is a simple and secure identity management platform, which provides services to allow +other systems and application to authenticate against. The project aims for the highest levels +of reliability, security and ease of use. -* Modern identity management platform -* Simple to deploy and integrate with -* Extensible for various needs -* Correct and secure behaviour by default +The goal of this project is to be a complete identity management provider, covering the broadest +possible set of requirements and integrations. You should not need any other components (like Keycloak) +when you use Kanidm. We want to create a project that will be suitable for everything +from personal home deployments, to the largest enterprise needs. -Today the project is still under heavy development to achieve these goals - We have many foundational -parts in place, and many of the required security features, but it is still an Alpha, and should be -treated as such. +To achieve this we rely heavily on strict defaults, simple configuration, and self-healing components. + +The project is still growing and some areas are developing at a fast pace. The core of the server +however is reliable and we make all effort to ensure upgrades will always work. + +Kanidm supports: + +* Oauth2/OIDC Authentication provider for web SSO +* Read only LDAPS gateway +* Linux/Unix integration (with offline authentication) +* SSH key distribution to Linux/Unix systems +* RADIUS for network authentication +* Passkeys / Webauthn for secure cryptographic authentication +* A self service web ui +* Complete CLI tooling for administration + +If you want to host your own centralised authentication service, then Kanidm is for you! ## Documentation / Getting Started / Install -If you want to deploy Kanidm to see what it can do, you should read the kanidm book. +If you want to deploy Kanidm to see what it can do, you should read the Kanidm book. -- [Kanidm book (Latest commit)](https://kanidm.github.io/kanidm/master/) - [Kanidm book (Latest stable)](https://kanidm.github.io/kanidm/stable/) +- [Kanidm book (Latest commit)](https://kanidm.github.io/kanidm/master/) - -We also publish limited [support guidelines](https://github.com/kanidm/kanidm/blob/master/project_docs/RELEASE_AND_SUPPORT.md). +We also publish [support guidelines](https://github.com/kanidm/kanidm/blob/master/project_docs/RELEASE_AND_SUPPORT.md) +for what the project will support. ## Code of Conduct / Ethics @@ -42,6 +59,46 @@ answer questions via email, which can be found on their github profile. [gitter community channel]: https://gitter.im/kanidm/community +## Comparison with other services + +### LLDAP + +[LLDAP](https://github.com/nitnelave/lldap) is a similar project aiming for a small and easy to administer +LDAP server with a web administration portal. Both projects use the [Kanidm LDAP bindings](https://github.com/kanidm/ldap3), and have +many similar ideas. + +The primary benefit of Kanidm over LLDAP is that Kanidm offers a broader set of "built in" features +like Oauth2 and OIDC. To use these from LLDAP you need an external portal like Keycloak, where in Kanidm +they are "built in". However that is also a strength of LLDAP is that is offers "less" which may make +it easier to administer and deploy for you. + +If Kanidm is too complex for your needs, you should check out LLDAP as a smaller alternative. If you +want a project which has a broader feature set out of the box, then Kanidm might be a better fit. + +### 389-ds / OpenLDAP + +Both 389-ds and OpenLDAP are generic LDAP servers. This means they only provide LDAP and you need +to bring your own IDM configuration on top. + +If you need the highest levels of customisation possible from your LDAP deployment, then these are +probably better alternatives. If you want a service that is easier to setup and focused on IDM, then +Kanidm is a better choice. + +Kanidm was originally inspired by many elements of both 389-ds and OpenLDAP. Already Kanidm is as fast +as (or faster than) 389-ds for performance and scaling. + +### FreeIPA + +FreeIPA is another identity management service for Linux/Unix, and ships a huge number of features +from LDAP, Kerberos, DNS, Certificate Authority, and more. + +FreeIPA however is a complex system, with a huge amount of parts and configuration. This adds a lot +of resource overhead and difficulty for administration. + +Kanidm aims to have the features richness of FreeIPA, but without the resource and administration +overheads. If you want a complete IDM package, but in a lighter footprint and easier to manage, then +Kanidm is probably for you. + ## Developer Getting Started If you want to develop on the server, there is a getting started [guide for developers]. IDM @@ -50,50 +107,6 @@ all backgrounds. [guide for developers]: https://kanidm.github.io/kanidm/master/DEVELOPER_README.html -## Features - -### Implemented - -* SSH key distribution for servers -* PAM/nsswitch clients (with limited offline auth) -* MFA - TOTP -* Highly concurrent design (MVCC, COW) -* RADIUS integration -* MFA - Webauthn - -### Currently Working On - -* CLI for administration -* WebUI for self-service with wifi enrollment, claim management and more. -* RBAC/Claims/Policy (limited by time and credential scope) -* OIDC/Oauth - -### Upcoming Focus Areas - -* Replication (async multiple active write servers, read-only servers) - -### Future - -* SSH CA management -* Sudo rule distribution via nsswitch -* WebUI for administration -* Account impersonation -* Synchronisation to other IDM services - -## Some key project ideas - -* All people should be respected and able to be represented securely. -* Devices represent users and their identities - they are part of the authentication. -* Human error occurs - we should be designed to minimise human mistakes and empower people. -* The system should be easy to understand and reason about for users and admins. - -### Features We Want to Avoid - -* Auditing: This is better solved by SIEM software, so we should generate data they can consume. -* Fully synchronous behaviour: This prevents scaling and our future ability to expand. -* Generic database: We don't want to be another NoSQL database, we want to be an IDM solution. -* Being like LDAP/GSSAPI/Kerberos: These are all legacy protocols that are hard to use and confine our thinking - we should avoid "being like them" or using them as models. - ## What does Kanidm mean? The original project name was rsidm while it was a thought experiment. Now that it's growing diff --git a/kanidmd_web_ui/pkg/kanidmd_web_ui.js b/kanidmd_web_ui/pkg/kanidmd_web_ui.js index faa125590..bed26b2c9 100644 --- a/kanidmd_web_ui/pkg/kanidmd_web_ui.js +++ b/kanidmd_web_ui/pkg/kanidmd_web_ui.js @@ -233,7 +233,7 @@ function addBorrowedObject(obj) { } function __wbg_adapter_48(arg0, arg1, arg2) { try { - wasm._dyn_core__ops__function__FnMut___A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__ha070437c619effa2(arg0, arg1, addBorrowedObject(arg2)); + wasm._dyn_core__ops__function__FnMut___A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__ha86bc8783d36be0a(arg0, arg1, addBorrowedObject(arg2)); } finally { heap[stack_pointer++] = undefined; } @@ -261,11 +261,11 @@ function makeClosure(arg0, arg1, dtor, f) { return real; } function __wbg_adapter_51(arg0, arg1, arg2) { - wasm._dyn_core__ops__function__Fn__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__hd36b5f2296664138(arg0, arg1, addHeapObject(arg2)); + wasm._dyn_core__ops__function__Fn__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h36bbc8108d49feb4(arg0, arg1, addHeapObject(arg2)); } function __wbg_adapter_54(arg0, arg1, arg2) { - wasm._dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h83dbed9e96aca169(arg0, arg1, addHeapObject(arg2)); + wasm._dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__hc4ba360e62a5fa4a(arg0, arg1, addHeapObject(arg2)); } /** @@ -1037,16 +1037,16 @@ function getImports() { const ret = wasm.memory; return addHeapObject(ret); }; - imports.wbg.__wbindgen_closure_wrapper5892 = function(arg0, arg1, arg2) { - const ret = makeMutClosure(arg0, arg1, 1425, __wbg_adapter_48); + imports.wbg.__wbindgen_closure_wrapper5651 = function(arg0, arg1, arg2) { + const ret = makeMutClosure(arg0, arg1, 1343, __wbg_adapter_48); return addHeapObject(ret); }; - imports.wbg.__wbindgen_closure_wrapper6052 = function(arg0, arg1, arg2) { - const ret = makeClosure(arg0, arg1, 1460, __wbg_adapter_51); + imports.wbg.__wbindgen_closure_wrapper5814 = function(arg0, arg1, arg2) { + const ret = makeClosure(arg0, arg1, 1378, __wbg_adapter_51); return addHeapObject(ret); }; - imports.wbg.__wbindgen_closure_wrapper6782 = function(arg0, arg1, arg2) { - const ret = makeMutClosure(arg0, arg1, 1724, __wbg_adapter_54); + imports.wbg.__wbindgen_closure_wrapper6542 = function(arg0, arg1, arg2) { + const ret = makeMutClosure(arg0, arg1, 1635, __wbg_adapter_54); return addHeapObject(ret); }; diff --git a/kanidmd_web_ui/pkg/kanidmd_web_ui_bg.wasm b/kanidmd_web_ui/pkg/kanidmd_web_ui_bg.wasm index a0ab9022c..871022f5f 100644 Binary files a/kanidmd_web_ui/pkg/kanidmd_web_ui_bg.wasm and b/kanidmd_web_ui/pkg/kanidmd_web_ui_bg.wasm differ diff --git a/kanidmd_web_ui/src/components/admin_accounts.rs b/kanidmd_web_ui/src/components/admin_accounts.rs index 85fd14f82..d2a6c1e01 100644 --- a/kanidmd_web_ui/src/components/admin_accounts.rs +++ b/kanidmd_web_ui/src/components/admin_accounts.rs @@ -9,7 +9,6 @@ use crate::components::alpha_warning_banner; use crate::constants::{ CSS_BREADCRUMB_ITEM, CSS_BREADCRUMB_ITEM_ACTIVE, CSS_CELL, CSS_DT, CSS_TABLE, }; -use crate::models; use crate::utils::{do_alert_error, do_page_header, init_request}; use crate::views::AdminRoute; @@ -83,7 +82,7 @@ pub struct AdminListAccountsProps { /// Pulls all accounts (service or person-class) from the backend and returns a HashMap /// with the "name" field being the keys, for easy human-facing sortability. -pub async fn get_accounts(token: &str) -> Result { +pub async fn get_accounts() -> Result { // TODO: the actual pulling and turning into a BTreeMap in this and get_groups could *probably* be rolled up into one function? The result object differs but all the widgets are the same. let mut all_accounts = BTreeMap::new(); @@ -94,7 +93,7 @@ pub async fn get_accounts(token: &str) -> Result ]; for (endpoint, object_type) in endpoints { - let request = init_request(endpoint, token); + let request = init_request(endpoint); let response = match request.send().await { Ok(value) => value, Err(error) => { @@ -146,14 +145,10 @@ impl Component for AdminListAccounts { fn create(ctx: &Context) -> Self { // TODO: work out the querystring thing so we can just show x number of elements // console::log!("query: {:?}", location().query); - let token = match models::get_bearer_token() { - Some(value) => value, - None => String::from(""), - }; // start pulling the account data on startup ctx.link().send_future(async move { - match get_accounts(token.clone().as_str()).await { + match get_accounts().await { Ok(v) => v, Err(v) => v.into(), } @@ -327,13 +322,9 @@ impl Component for AdminViewPerson { type Properties = AdminViewAccountProps; fn create(ctx: &Context) -> Self { - let token = match models::get_bearer_token() { - Some(value) => value, - None => String::from(""), - }; let uuid = ctx.props().uuid.clone(); ctx.link().send_future(async move { - match get_person(token.clone().as_str(), &uuid).await { + match get_person(&uuid).await { Ok(v) => v, Err(v) => v.into(), } @@ -480,13 +471,9 @@ impl Component for AdminViewServiceAccount { type Properties = AdminViewAccountProps; fn create(ctx: &Context) -> Self { - let token = match models::get_bearer_token() { - Some(value) => value, - None => String::from(""), - }; let uuid = ctx.props().uuid.clone(); ctx.link().send_future(async move { - match get_service_account(token.clone().as_str(), &uuid).await { + match get_service_account(&uuid).await { Ok(v) => v, Err(v) => v.into(), } @@ -553,8 +540,8 @@ impl Component for AdminViewServiceAccount { } /// pull the details for a single person by UUID -pub async fn get_person(token: &str, uuid: &str) -> Result { - let request = init_request(format!("/v1/person/{}", uuid).as_str(), token); +pub async fn get_person(uuid: &str) -> Result { + let request = init_request(format!("/v1/person/{}", uuid).as_str()); let response = match request.send().await { Ok(value) => value, Err(error) => { @@ -572,11 +559,8 @@ pub async fn get_person(token: &str, uuid: &str) -> Result Result { - let request = init_request(format!("/v1/service_account/{}", uuid).as_str(), token); +pub async fn get_service_account(uuid: &str) -> Result { + let request = init_request(format!("/v1/service_account/{}", uuid).as_str()); let response = match request.send().await { Ok(value) => value, Err(error) => { diff --git a/kanidmd_web_ui/src/components/admin_groups.rs b/kanidmd_web_ui/src/components/admin_groups.rs index 951ea055b..ba1096186 100644 --- a/kanidmd_web_ui/src/components/admin_groups.rs +++ b/kanidmd_web_ui/src/components/admin_groups.rs @@ -7,7 +7,6 @@ use yew_router::prelude::Link; use crate::components::adminmenu::{Entity, EntityType, GetError}; use crate::components::alpha_warning_banner; use crate::constants::{CSS_BREADCRUMB_ITEM, CSS_BREADCRUMB_ITEM_ACTIVE, CSS_CELL, CSS_TABLE}; -use crate::models; use crate::utils::{do_alert_error, do_page_header, init_request}; use crate::views::AdminRoute; @@ -64,14 +63,14 @@ pub struct AdminListGroupsProps { /// Pulls all accounts (service or person-class) from the backend and returns a HashMap /// with the "name" field being the keys, for easy human-facing sortability. -pub async fn get_groups(token: &str) -> Result { +pub async fn get_groups() -> Result { let mut all_groups = BTreeMap::new(); // we iterate over these endpoints let endpoints = [("/v1/group", EntityType::Group)]; for (endpoint, object_type) in endpoints { - let request = init_request(endpoint, token); + let request = init_request(endpoint); let response = match request.send().await { Ok(value) => value, Err(error) => { @@ -117,14 +116,10 @@ impl Component for AdminListGroups { fn create(ctx: &Context) -> Self { // TODO: work out the querystring thing so we can just show x number of elements // console::log!("query: {:?}", location().query); - let token = match models::get_bearer_token() { - Some(value) => value, - None => String::from(""), - }; // start pulling the account data on startup ctx.link().send_future(async move { - match get_groups(token.clone().as_str()).await { + match get_groups().await { Ok(v) => v, Err(v) => v.into(), } @@ -286,14 +281,10 @@ impl Component for AdminViewGroup { type Properties = AdminViewGroupProps; fn create(ctx: &Context) -> Self { - let token = match models::get_bearer_token() { - Some(value) => value, - None => String::from(""), - }; let uuid = ctx.props().uuid.clone(); // TODO: start pulling the group details then send the msg blep blep ctx.link().send_future(async move { - match get_group(token.clone().as_str(), &uuid).await { + match get_group(&uuid).await { Ok(v) => v, Err(v) => v.into(), } @@ -368,8 +359,8 @@ impl Component for AdminViewGroup { } /// pull the details for a single group by UUID -pub async fn get_group(token: &str, groupid: &str) -> Result { - let request = init_request(format!("/v1/group/{}", groupid).as_str(), token); +pub async fn get_group(groupid: &str) -> Result { + let request = init_request(format!("/v1/group/{}", groupid).as_str()); let response = match request.send().await { Ok(value) => value, Err(error) => { diff --git a/kanidmd_web_ui/src/components/admin_oauth2.rs b/kanidmd_web_ui/src/components/admin_oauth2.rs index c57a90525..a54b571e0 100644 --- a/kanidmd_web_ui/src/components/admin_oauth2.rs +++ b/kanidmd_web_ui/src/components/admin_oauth2.rs @@ -7,7 +7,6 @@ use yew_router::prelude::Link; use crate::components::adminmenu::{Entity, EntityType, GetError}; use crate::components::alpha_warning_banner; use crate::constants::{CSS_BREADCRUMB_ITEM, CSS_BREADCRUMB_ITEM_ACTIVE, CSS_CELL, CSS_TABLE}; -use crate::models; use crate::utils::{do_alert_error, do_page_header, init_request}; use crate::views::AdminRoute; @@ -64,7 +63,7 @@ pub struct AdminListOAuth2Props { /// Pulls all OAuth2 RPs from the backend and returns a HashMap /// with the "name" field being the keys, for easy human-facing sortability. -pub async fn get_entities(token: &str) -> Result { +pub async fn get_entities() -> Result { // TODO: the actual pulling and turning into a BTreeMap across the admin systems could *probably* be rolled up into one function? The result object differs but all the query bits are the same. let mut oauth2_objects = BTreeMap::new(); @@ -72,7 +71,7 @@ pub async fn get_entities(token: &str) -> Result { let endpoints = [("/v1/oauth2", EntityType::OAuth2RP)]; for (endpoint, object_type) in endpoints { - let request = init_request(endpoint, token); + let request = init_request(endpoint); let response = match request.send().await { Ok(value) => value, Err(error) => { @@ -113,14 +112,10 @@ impl Component for AdminListOAuth2 { fn create(ctx: &Context) -> Self { // TODO: work out the querystring thing so we can just show x number of elements - let token = match models::get_bearer_token() { - Some(value) => value, - None => String::from(""), - }; // start pulling the data on startup ctx.link().send_future(async move { - match get_entities(token.clone().as_str()).await { + match get_entities().await { Ok(v) => v, Err(v) => v.into(), } @@ -299,15 +294,11 @@ impl Component for AdminViewOAuth2 { type Properties = AdminViewOAuth2Props; fn create(ctx: &Context) -> Self { - let token = match models::get_bearer_token() { - Some(value) => value, - None => String::from(""), - }; let rs_name = ctx.props().rs_name.clone(); // start pulling the data on startup ctx.link().send_future(async move { - match get_oauth2_rp(token.clone().as_str(), &rs_name).await { + match get_oauth2_rp(&rs_name).await { Ok(v) => v, Err(v) => v.into(), } @@ -405,8 +396,8 @@ impl Component for AdminViewOAuth2 { } } -pub async fn get_oauth2_rp(token: &str, rs_name: &str) -> Result { - let request = init_request(format!("/v1/oauth2/{}", rs_name).as_str(), token); +pub async fn get_oauth2_rp(rs_name: &str) -> Result { + let request = init_request(format!("/v1/oauth2/{}", rs_name).as_str()); let response = match request.send().await { Ok(value) => value, Err(error) => { diff --git a/kanidmd_web_ui/src/components/change_unix_password.rs b/kanidmd_web_ui/src/components/change_unix_password.rs index 2ac1bea12..9f9f68978 100644 --- a/kanidmd_web_ui/src/components/change_unix_password.rs +++ b/kanidmd_web_ui/src/components/change_unix_password.rs @@ -1,7 +1,5 @@ -use std::str::FromStr; - -use compact_jwt::{Jws, JwsUnverified}; use kanidm_proto::v1::{SingleStringRequest, UserAuthToken}; +use uuid::Uuid; use wasm_bindgen::{JsCast, JsValue, UnwrapThrowExt}; use wasm_bindgen_futures::JsFuture; use web_sys::{FormData, HtmlFormElement, Request, RequestInit, RequestMode, Response}; @@ -69,7 +67,7 @@ pub enum State { #[derive(PartialEq, Eq, Properties)] pub struct ChangeUnixPasswordProps { - pub token: String, + pub uat: UserAuthToken, } impl Component for ChangeUnixPassword { @@ -98,9 +96,11 @@ impl Component for ChangeUnixPassword { }, ); } - let tk = ctx.props().token.clone(); - ctx.link().send_future(async { - match Self::update_unix_password(tk, fd.password_input).await { + + let id = ctx.props().uat.uuid; + + ctx.link().send_future(async move { + match Self::update_unix_password(id, fd.password_input).await { Ok(v) => v, Err(v) => v.into(), } @@ -257,14 +257,7 @@ impl Component for ChangeUnixPassword { } impl ChangeUnixPassword { - async fn update_unix_password(token: String, new_password: String) -> Result { - let jwtu = JwsUnverified::from_str(&token).expect_throw("Invalid UAT, unable to parse"); - - let uat: Jws = jwtu - .unsafe_release_without_verification() - .expect_throw("Invalid UAT, unable to release "); - - let id = uat.into_inner().uuid.to_string(); + async fn update_unix_password(id: Uuid, new_password: String) -> Result { let changereq_jsvalue = serde_json::to_string(&SingleStringRequest { value: new_password, }) @@ -283,10 +276,6 @@ impl ChangeUnixPassword { .headers() .set("content-type", "application/json") .expect_throw("failed to set header"); - request - .headers() - .set("authorization", format!("Bearer {}", token).as_str()) - .expect_throw("failed to set header"); let window = utils::window(); let resp_value = JsFuture::from(window.fetch_with_request(&request)).await?; diff --git a/kanidmd_web_ui/src/login.rs b/kanidmd_web_ui/src/login.rs index 681cd831f..c5f195c95 100644 --- a/kanidmd_web_ui/src/login.rs +++ b/kanidmd_web_ui/src/login.rs @@ -1,13 +1,16 @@ // use anyhow::Error; use gloo::console; use kanidm_proto::v1::{ - AuthAllowed, AuthCredential, AuthMech, AuthRequest, AuthResponse, AuthState, AuthStep, + AuthAllowed, AuthCredential, AuthIssueSession, AuthMech, AuthRequest, AuthResponse, AuthState, + AuthStep, }; use kanidm_proto::webauthn::PublicKeyCredential; use wasm_bindgen::prelude::*; use wasm_bindgen::JsCast; use wasm_bindgen_futures::{spawn_local, JsFuture}; -use web_sys::{CredentialRequestOptions, Request, RequestInit, RequestMode, Response}; +use web_sys::{ + CredentialRequestOptions, Request, RequestCredentials, RequestInit, RequestMode, Response, +}; use yew::prelude::*; use yew::virtual_dom::VNode; use yew_router::prelude::*; @@ -78,7 +81,10 @@ impl From for LoginAppMsg { impl LoginApp { async fn auth_init(username: String) -> Result { let authreq = AuthRequest { - step: AuthStep::Init(username), + step: AuthStep::Init2 { + username, + issue: AuthIssueSession::Cookie, + }, }; let authreq_jsvalue = serde_json::to_string(&authreq) .map(|s| JsValue::from(&s)) @@ -87,6 +93,7 @@ impl LoginApp { let mut opts = RequestInit::new(); opts.method("POST"); opts.mode(RequestMode::SameOrigin); + opts.credentials(RequestCredentials::SameOrigin); opts.body(Some(&authreq_jsvalue)); @@ -141,6 +148,7 @@ impl LoginApp { let mut opts = RequestInit::new(); opts.method("POST"); opts.mode(RequestMode::SameOrigin); + opts.credentials(RequestCredentials::SameOrigin); opts.body(Some(&authreq_jsvalue)); @@ -542,6 +550,7 @@ impl Component for LoginApp { #[cfg(debug)] console::debug!("create".to_string()); // Assume we are here for a good reason. + // -- clear the bearer to prevent conflict models::clear_bearer_token(); // Do we have a login hint? let inputvalue = models::pop_login_hint().unwrap_or_else(|| "".to_string()); @@ -835,11 +844,22 @@ impl Component for LoginApp { self.state = LoginState::Denied(reason); true } - AuthState::Success(bearer_token) => { + AuthState::Success(_bearer_token) => { // Store the bearer here! + /* models::set_bearer_token(bearer_token); self.state = LoginState::Authenticated; true + */ + self.state = LoginState::Error { + emsg: "Invalid Issued Session Type, expected cookie".to_string(), + kopid: None, + }; + true + } + AuthState::SuccessCookie => { + self.state = LoginState::Authenticated; + true } } } diff --git a/kanidmd_web_ui/src/models/mod.rs b/kanidmd_web_ui/src/models/mod.rs index c3d6e2e88..19f253189 100644 --- a/kanidmd_web_ui/src/models/mod.rs +++ b/kanidmd_web_ui/src/models/mod.rs @@ -12,19 +12,6 @@ use yew_router::prelude::{AnyHistory, History}; use crate::manager::Route; use crate::views::ViewRoute; -pub fn get_bearer_token() -> Option { - let prev_session: Result = PersistentStorage::get("kanidm_bearer_token"); - #[cfg(debug)] - console::debug!(format!("kanidm_bearer_token -> {:?}", prev_session).as_str()); - - prev_session.ok() -} - -pub fn set_bearer_token(bearer_token: String) { - PersistentStorage::set("kanidm_bearer_token", bearer_token) - .expect_throw("failed to set header"); -} - pub fn clear_bearer_token() { PersistentStorage::delete("kanidm_bearer_token"); } diff --git a/kanidmd_web_ui/src/oauth2.rs b/kanidmd_web_ui/src/oauth2.rs index 151546299..d01181692 100644 --- a/kanidmd_web_ui/src/oauth2.rs +++ b/kanidmd_web_ui/src/oauth2.rs @@ -6,7 +6,7 @@ pub use kanidm_proto::oauth2::{ }; use wasm_bindgen::{JsCast, JsValue, UnwrapThrowExt}; use wasm_bindgen_futures::JsFuture; -use web_sys::{Request, RequestInit, RequestMode, RequestRedirect, Response}; +use web_sys::{Request, RequestCredentials, RequestInit, RequestMode, RequestRedirect, Response}; use yew::prelude::*; use yew_router::prelude::*; @@ -15,14 +15,12 @@ use crate::manager::Route; use crate::{models, utils}; enum State { - // We don't have a token, or something is invalid. LoginRequired, // We are in the process of check the auth token to be sure we can proceed. - TokenCheck(String), + TokenCheck, // Token check done, lets do it. - SubmitAuthReq(String), + SubmitAuthReq, Consent { - token: String, client_name: String, #[allow(dead_code)] scopes: Vec, @@ -39,6 +37,7 @@ pub struct Oauth2App { } pub enum Oauth2Msg { + LoginRequired, LoginProceed, ConsentGranted(String), TokenValid, @@ -68,20 +67,17 @@ impl From for Oauth2Msg { } impl Oauth2App { - async fn fetch_token_valid(token: String) -> Result { + async fn fetch_session_valid() -> Result { let mut opts = RequestInit::new(); opts.method("GET"); opts.mode(RequestMode::SameOrigin); + opts.credentials(RequestCredentials::SameOrigin); let request = Request::new_with_str_and_init("/v1/auth/valid", &opts)?; request .headers() .set("content-type", "application/json") .expect_throw("failed to set header"); - request - .headers() - .set("authorization", format!("Bearer {}", token).as_str()) - .expect_throw("failed to set header"); let window = utils::window(); let resp_value = JsFuture::from(window.fetch_with_request(&request)).await?; @@ -91,7 +87,7 @@ impl Oauth2App { if status == 200 { Ok(Oauth2Msg::TokenValid) } else if status == 401 { - Ok(Oauth2Msg::LoginProceed) + Ok(Oauth2Msg::LoginRequired) } else { let headers = resp.headers(); let kopid = headers.get("x-kanidm-opid").ok().flatten(); @@ -102,10 +98,7 @@ impl Oauth2App { } } - async fn fetch_authreq( - token: String, - authreq: AuthorisationRequest, - ) -> Result { + async fn fetch_authreq(authreq: AuthorisationRequest) -> Result { let authreq_jsvalue = serde_json::to_string(&authreq) .map(|s| JsValue::from(&s)) .expect_throw("Failed to serialise authreq"); @@ -113,6 +106,7 @@ impl Oauth2App { let mut opts = RequestInit::new(); opts.method("POST"); opts.mode(RequestMode::SameOrigin); + opts.credentials(RequestCredentials::SameOrigin); opts.body(Some(&authreq_jsvalue)); @@ -121,10 +115,6 @@ impl Oauth2App { .headers() .set("content-type", "application/json") .expect_throw("failed to set header"); - request - .headers() - .set("authorization", format!("Bearer {}", token).as_str()) - .expect_throw("failed to set header"); let window = utils::window(); let resp_value = JsFuture::from(window.fetch_with_request(&request)).await?; @@ -173,10 +163,7 @@ impl Oauth2App { } } - async fn fetch_consent_token( - token: String, - consent_token: String, - ) -> Result { + async fn fetch_consent_token(consent_token: String) -> Result { let consentreq_jsvalue = serde_json::to_string(&consent_token) .map(|s| JsValue::from(&s)) .expect_throw("Failed to serialise consent_req"); @@ -185,6 +172,7 @@ impl Oauth2App { opts.method("POST"); opts.mode(RequestMode::SameOrigin); opts.redirect(RequestRedirect::Manual); + opts.credentials(RequestCredentials::SameOrigin); opts.body(Some(&consentreq_jsvalue)); @@ -193,10 +181,6 @@ impl Oauth2App { .headers() .set("content-type", "application/json") .expect_throw("failed to set header"); - request - .headers() - .set("authorization", format!("Bearer {}", token).as_str()) - .expect_throw("failed to set header"); let window = utils::window(); let resp_value = JsFuture::from(window.fetch_with_request(&request)).await?; @@ -274,25 +258,17 @@ impl Component for Oauth2App { // Push the request down. This covers if we move to LoginRequired. models::push_oauth2_authorisation_request(query); - match models::get_bearer_token() { - Some(token) => { - // Start the fetch req. - // Put the fetch handle into the consent type. - let token_c = token.clone(); - ctx.link().send_future(async { - match Self::fetch_token_valid(token_c).await { - Ok(v) => v, - Err(v) => v.into(), - } - }); - - Oauth2App { - state: State::TokenCheck(token), - } + // Start the fetch req. + // Put the fetch handle into the consent type. + ctx.link().send_future(async { + match Self::fetch_session_valid().await { + Ok(v) => v, + Err(v) => v.into(), } - None => Oauth2App { - state: State::LoginRequired, - }, + }); + + Oauth2App { + state: State::TokenCheck, } } @@ -307,6 +283,10 @@ impl Component for Oauth2App { console::debug!("oauth2::update"); match msg { + Oauth2Msg::LoginRequired => { + self.state = State::LoginRequired; + true + } Oauth2Msg::LoginProceed => { models::push_return_location(models::Location::Manager(Route::Oauth2)); @@ -322,15 +302,14 @@ impl Component for Oauth2App { let ar = models::pop_oauth2_authorisation_request(); self.state = match (&self.state, ar) { - (State::TokenCheck(token), Some(ar)) => { - let token_c = token.clone(); + (State::TokenCheck, Some(ar)) => { ctx.link().send_future(async { - match Self::fetch_authreq(token_c, ar).await { + match Self::fetch_authreq(ar).await { Ok(v) => v, Err(v) => v.into(), } }); - State::SubmitAuthReq(token.clone()) + State::SubmitAuthReq } _ => { console::error!("Invalid state transition"); @@ -346,8 +325,7 @@ impl Component for Oauth2App { consent_token, } => { self.state = match &self.state { - State::SubmitAuthReq(token) => State::Consent { - token: token.clone(), + State::SubmitAuthReq => State::Consent { client_name, scopes, pii_scopes, @@ -363,15 +341,13 @@ impl Component for Oauth2App { Oauth2Msg::ConsentGranted(_) => { self.state = match &self.state { State::Consent { - token, consent_token, client_name, .. } => { - let token_c = token.clone(); let cr_c = consent_token.clone(); ctx.link().send_future(async { - match Self::fetch_consent_token(token_c, cr_c).await { + match Self::fetch_consent_token(cr_c).await { Ok(v) => v, Err(v) => v.into(), } @@ -453,7 +429,6 @@ impl Component for Oauth2App { } } State::Consent { - token: _, client_name, scopes: _, pii_scopes, @@ -509,7 +484,7 @@ impl Component for Oauth2App { } } - State::SubmitAuthReq(_) | State::TokenCheck(_) => { + State::SubmitAuthReq | State::TokenCheck => { html! {
- if let Some(uat) = current_user_uat { if uat.ui_hints.contains(&UiHint::PosixAccount) {

- +

} - } } } } impl SecurityApp { - async fn fetch_token_valid(id: String, token: String) -> Result { + async fn fetch_token_valid(id: String) -> Result { let mut opts = RequestInit::new(); opts.method("GET"); opts.mode(RequestMode::SameOrigin); + opts.credentials(RequestCredentials::SameOrigin); let uri = format!("/v1/person/{}/_credential/_update", id); @@ -194,10 +183,6 @@ impl SecurityApp { .headers() .set("content-type", "application/json") .expect_throw("failed to set header"); - request - .headers() - .set("authorization", format!("Bearer {}", token).as_str()) - .expect_throw("failed to set header"); let window = utils::window(); let resp_value = JsFuture::from(window.fetch_with_request(&request)).await?;