Update to the latest compact-jwt version ()

This commit is contained in:
Firstyear 2023-11-24 12:53:22 +10:00 committed by GitHub
parent 916bb4ec04
commit ac299b5286
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
23 changed files with 524 additions and 314 deletions

134
Cargo.lock generated
View file

@ -212,9 +212,9 @@ dependencies = [
[[package]]
name = "async-compression"
version = "0.4.4"
version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f658e2baef915ba0f26f1f7c42bfb8e12f532a01f449a090ded75ae7a07e9ba2"
checksum = "bc2d0cfb2a7388d34f590e76686704c494ed7aaceed62ee1ba35cbf363abc2a5"
dependencies = [
"flate2",
"futures-core",
@ -578,9 +578,9 @@ checksum = "cfa8873f51c92e232f9bac4065cddef41b714152812bfc5f7672ba16d6ef8cd9"
[[package]]
name = "bstr"
version = "1.7.0"
version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c79ad7fb2dd38f3dabd76b09c6a5a20c038fc0213ef1e9afd30eb777f120f019"
checksum = "542f33a8835a0884b006a0c3df3dadd99c0c3f296ed26c2fdc8028e01ad6230c"
dependencies = [
"memchr",
"regex-automata 0.4.3",
@ -806,6 +806,24 @@ dependencies = [
"uuid",
]
[[package]]
name = "compact_jwt"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75968a6d3a1232f93c8701152281fba5ae2f936091f97fe746e35bd8a892f9d0"
dependencies = [
"base64 0.21.5",
"base64urlsafedata",
"hex",
"kanidm-hsm-crypto",
"openssl",
"serde",
"serde_json",
"tracing",
"url",
"uuid",
]
[[package]]
name = "concread"
version = "0.4.3"
@ -1216,9 +1234,9 @@ dependencies = [
[[package]]
name = "data-encoding"
version = "2.4.0"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c2e66c9d817f1720209181c316d28635c050fa304f9c79e47a520882661b7308"
checksum = "7e962a19be5cfc3f3bf6dd8f61eb50107f356ad6270fbb3ed41476571db78be5"
[[package]]
name = "der-parser"
@ -1415,18 +1433,18 @@ dependencies = [
[[package]]
name = "enum-map"
version = "2.7.1"
version = "2.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed40247825a1a0393b91b51d475ea1063a6cbbf0847592e7f13fb427aca6a716"
checksum = "09e6b4f374c071b18172e23134e01026653dc980636ee139e0dfe59c538c61e5"
dependencies = [
"enum-map-derive",
]
[[package]]
name = "enum-map-derive"
version = "0.15.0"
version = "0.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7933cd46e720348d29ed1493f89df9792563f272f96d8f13d18afe03b32f8cb8"
checksum = "bfdb3d73d1beaf47c8593a1364e577fde072677cbfd103600345c0f547408cc0"
dependencies = [
"proc-macro2",
"quote",
@ -1482,9 +1500,9 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
[[package]]
name = "errno"
version = "0.3.6"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7c18ee0ed65a5f1f81cac6b1d213b69c35fa47d4252ad41f1486dbd8226fe36e"
checksum = "f258a7194e7f7c2a7837a8913aeab7fd8c383457034fa20ce4dd3dcb813e8eb8"
dependencies = [
"libc",
"windows-sys 0.48.0",
@ -1649,9 +1667,9 @@ checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
[[package]]
name = "form_urlencoded"
version = "1.2.0"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652"
checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456"
dependencies = [
"percent-encoding",
]
@ -2503,9 +2521,9 @@ dependencies = [
[[package]]
name = "h2"
version = "0.3.21"
version = "0.3.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "91fc23aa11be92976ef4729127f1a74adf36d8436f7816b185d18df956790833"
checksum = "4d6250322ef6e60f93f9a2162799302cd6f68f79f6e5d85c8c16f14d1d958178"
dependencies = [
"bytes",
"fnv",
@ -2513,7 +2531,7 @@ dependencies = [
"futures-sink",
"futures-util",
"http",
"indexmap 1.9.3",
"indexmap 2.1.0",
"slab",
"tokio",
"tokio-util",
@ -2773,9 +2791,9 @@ dependencies = [
[[package]]
name = "idna"
version = "0.4.0"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c"
checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6"
dependencies = [
"unicode-bidi",
"unicode-normalization",
@ -2976,9 +2994,9 @@ dependencies = [
[[package]]
name = "kanidm-hsm-crypto"
version = "0.1.1"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2710fd18cfe2f774e6d1e743dae86ae9a7332cad1bb85cb66777f7ef63578410"
checksum = "fdc2a5dbe42b03b3e5e3f99eab1c5773032c8e508896691b3f4562c7de264d67"
dependencies = [
"argon2",
"openssl",
@ -3122,7 +3140,7 @@ dependencies = [
"async-recursion",
"clap",
"clap_complete",
"compact_jwt",
"compact_jwt 0.3.2",
"cursive",
"dialoguer",
"futures-concurrency",
@ -3206,7 +3224,7 @@ dependencies = [
"axum-server",
"bytes",
"chrono",
"compact_jwt",
"compact_jwt 0.3.2",
"cron",
"filetime",
"futures",
@ -3253,7 +3271,7 @@ version = "1.1.0-rc.15-dev"
dependencies = [
"base64 0.21.5",
"base64urlsafedata",
"compact_jwt",
"compact_jwt 0.3.2",
"concread",
"criterion",
"dyn-clone",
@ -3319,7 +3337,7 @@ name = "kanidmd_testkit"
version = "1.1.0-rc.15-dev"
dependencies = [
"assert_cmd",
"compact_jwt",
"compact_jwt 0.3.2",
"escargot",
"fantoccini",
"futures",
@ -3604,9 +3622,9 @@ dependencies = [
[[package]]
name = "lodepng"
version = "3.9.1"
version = "3.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a3cdccd0cf57a5d456f0656ebcff72c2e19503287e1afbf3b84382812adc0606"
checksum = "b00f56ff9bcd5721ab172b73eac8a7d4e9439f47a98581e666178dbe7df97e13"
dependencies = [
"crc32fast",
"fallible_collections",
@ -4085,9 +4103,9 @@ checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c"
[[package]]
name = "openssl"
version = "0.10.59"
version = "0.10.60"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a257ad03cd8fb16ad4172fedf8094451e1af1c4b70097636ef2eac9a5f0cc33"
checksum = "79a4c6c3a2b158f7f8f2a2fc5a969fa3a068df6fc9dbb4a43845436e3af7c800"
dependencies = [
"bitflags 2.4.1",
"cfg-if",
@ -4117,9 +4135,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
[[package]]
name = "openssl-sys"
version = "0.9.95"
version = "0.9.96"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "40a4130519a360279579c2053038317e40eff64d13fd3f004f9e1b72b8a6aaf9"
checksum = "3812c071ba60da8b5677cc12bcb1d42989a65553772897a7e0355545a819838f"
dependencies = [
"cc",
"libc",
@ -4413,9 +4431,9 @@ checksum = "36bae92c60fa2398ce4678b98b2c4b5a7c61099961ca1fa305aec04a9ad28922"
[[package]]
name = "percent-encoding"
version = "2.3.0"
version = "2.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94"
checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
[[package]]
name = "pest"
@ -4967,12 +4985,12 @@ dependencies = [
[[package]]
name = "rtoolbox"
version = "0.0.1"
version = "0.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "034e22c514f5c0cb8a10ff341b9b048b5ceb21591f31c8f44c43b960f9b3524a"
checksum = "c247d24e63230cdb56463ae328478bd5eac8b8faa8c69461a77e8e323afac90e"
dependencies = [
"libc",
"winapi",
"windows-sys 0.48.0",
]
[[package]]
@ -5062,9 +5080,9 @@ dependencies = [
[[package]]
name = "rustix"
version = "0.38.21"
version = "0.38.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b426b0506e5d50a7d8dafcf2e81471400deb602392c7dd110815afb4eaf02a3"
checksum = "dc99bc2d4f1fed22595588a013687477aedf3cdcfb26558c559edb67b4d9b22e"
dependencies = [
"bitflags 2.4.1",
"errno",
@ -5207,9 +5225,9 @@ dependencies = [
[[package]]
name = "serde"
version = "1.0.192"
version = "1.0.193"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bca2a08484b285dcb282d0f67b26cadc0df8b19f8c12502c13d966bf9482f001"
checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89"
dependencies = [
"serde_derive",
]
@ -5267,9 +5285,9 @@ dependencies = [
[[package]]
name = "serde_derive"
version = "1.0.192"
version = "1.0.193"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d6c7207fbec9faa48073f3e3074cbe553af6ea512d7c21ba46e434e70ea9fbc1"
checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3"
dependencies = [
"proc-macro2",
"quote",
@ -5467,9 +5485,9 @@ dependencies = [
[[package]]
name = "smallvec"
version = "1.11.1"
version = "1.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a"
checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970"
dependencies = [
"serde",
]
@ -6170,9 +6188,9 @@ checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460"
[[package]]
name = "unicode-bom"
version = "2.0.2"
version = "2.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "98e90c70c9f0d4d1ee6d0a7d04aa06cb9bbd53d8cfbdd62a0269a7c2eb640552"
checksum = "7eec5d1121208364f6793f7d2e222bf75a915c19557537745b195b253dd64217"
[[package]]
name = "unicode-ident"
@ -6209,12 +6227,12 @@ checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c"
[[package]]
name = "url"
version = "2.4.1"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "143b538f18257fac9cad154828a57c6bf5157e1aa604d4816b5995bf6de87ae5"
checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633"
dependencies = [
"form_urlencoded",
"idna 0.4.0",
"idna 0.5.0",
"percent-encoding",
"serde",
]
@ -6276,9 +6294,9 @@ dependencies = [
[[package]]
name = "uuid"
version = "1.5.0"
version = "1.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "88ad59a7560b41a70d191093a945f0b87bc1deeda46fb237479708a1d6b6cdfc"
checksum = "5e395fcf16a7a3d8127ec99782007af141946b4795001f876d54fb0d55978560"
dependencies = [
"getrandom",
"serde",
@ -6518,7 +6536,7 @@ source = "git+https://github.com/kanidm/webauthn-rs.git?rev=2218d2055c0c900ef57b
dependencies = [
"base64 0.21.5",
"base64urlsafedata",
"compact_jwt",
"compact_jwt 0.2.10",
"der-parser",
"nom",
"openssl",
@ -6949,18 +6967,18 @@ dependencies = [
[[package]]
name = "zerocopy"
version = "0.7.25"
version = "0.7.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8cd369a67c0edfef15010f980c3cbe45d7f651deac2cd67ce097cd801de16557"
checksum = "e97e415490559a91254a2979b4829267a57d2fcd741a98eee8b722fb57289aa0"
dependencies = [
"zerocopy-derive",
]
[[package]]
name = "zerocopy-derive"
version = "0.7.25"
version = "0.7.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c2f140bda219a26ccc0cdb03dba58af72590c53b22642577d88a927bc5c87d6b"
checksum = "dd7e48ccf166952882ca8bd778a43502c64f33bf94c12ebe2a7f08e5a0f6689f"
dependencies = [
"proc-macro2",
"quote",
@ -6969,9 +6987,9 @@ dependencies = [
[[package]]
name = "zeroize"
version = "1.6.0"
version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9"
checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d"
dependencies = [
"zeroize_derive",
]

View file

@ -115,7 +115,7 @@ clap = { version = "^4.4.8", features = ["derive", "env"] }
clap_complete = "^4.4.4"
# Forced by saffron/cron
chrono = "^0.4.31"
compact_jwt = { version = "^0.2.10", default-features = false }
compact_jwt = { version = "^0.3.2", default-features = false }
concread = "^0.4.3"
cron = "0.12.0"
crossbeam = "0.8.1"

View file

@ -25,7 +25,7 @@ use axum::routing::*;
use axum::Router;
use axum_csp::{CspDirectiveType, CspValue};
use axum_macros::FromRef;
use compact_jwt::{Jws, JwsSigner, JwsUnverified};
use compact_jwt::{JwsCompact, JwsHs256Signer, JwsVerifier};
use hashbrown::HashMap;
use http::{HeaderMap, HeaderValue};
use hyper::server::accept::Accept;
@ -59,8 +59,7 @@ pub struct ServerState {
pub qe_w_ref: &'static crate::actors::v1_write::QueryServerWriteV1,
pub qe_r_ref: &'static crate::actors::v1_read::QueryServerReadV1,
// Store the token management parts.
pub jws_signer: compact_jwt::JwsSigner,
pub jws_validator: compact_jwt::JwsValidator,
pub jws_signer: compact_jwt::JwsHs256Signer,
// The SHA384 hashes of javascript files we're going to serve to users
pub js_files: JavaScriptFiles,
pub(crate) trust_x_forward_for: bool,
@ -69,11 +68,13 @@ pub struct ServerState {
impl ServerState {
fn reinflate_uuid_from_bytes(&self, input: &str) -> Option<Uuid> {
match JwsUnverified::from_str(input) {
Ok(val) => val
.validate(&self.jws_validator)
.map(|jws: Jws<SessionId>| jws.into_inner().sessionid)
.ok(),
match JwsCompact::from_str(input) {
Ok(val) => self
.jws_signer
.verify(&val)
.ok()
.and_then(|jws| jws.from_json::<SessionId>().ok())
.map(|inner| inner.sessionid),
Err(_) => None,
}
}
@ -168,16 +169,12 @@ pub fn get_js_files(role: ServerRole) -> Result<JavaScriptFiles, ()> {
pub async fn create_https_server(
config: Configuration,
jws_signer: JwsSigner,
jws_signer: JwsHs256Signer,
status_ref: &'static StatusActor,
qe_w_ref: &'static QueryServerWriteV1,
qe_r_ref: &'static QueryServerReadV1,
mut rx: broadcast::Receiver<CoreAction>,
) -> Result<tokio::task::JoinHandle<()>, ()> {
let jws_validator = jws_signer.get_validator().map_err(|e| {
error!(?e, "Failed to get jws validator");
})?;
let js_files = get_js_files(config.role)?;
// set up the CSP headers
// script-src 'self'
@ -229,7 +226,6 @@ pub async fn create_https_server(
qe_w_ref,
qe_r_ref,
jws_signer,
jws_validator,
js_files,
trust_x_forward_for,
csp_header: csp_header.finish(),

View file

@ -5,7 +5,7 @@ use axum::middleware::from_fn;
use axum::response::{IntoResponse, Response};
use axum::routing::{delete, get, post, put};
use axum::{Extension, Json, Router};
use compact_jwt::Jws;
use compact_jwt::{Jws, JwsSigner};
use http::{HeaderMap, HeaderValue};
use kanidm_proto::constants::uri::V1_AUTH_VALID;
use serde::{Deserialize, Serialize};
@ -2571,9 +2571,13 @@ fn auth_session_state_management(
debug!("🧩 -> AuthState::Choose"); // TODO: this should be ... less work
// Ensure the auth-session-id is set
let kref = &state.jws_signer;
let jws = Jws::new(SessionId { sessionid });
let jws = Jws::into_json(&SessionId { sessionid }).map_err(|e| {
error!(?e);
OperationError::InvalidSessionState
})?;
// Get the header token ready.
jws.sign(kref)
kref.sign(&jws)
.map(|jwss| {
auth_session_id_tok = Some(jwss.to_string());
})
@ -2587,8 +2591,11 @@ fn auth_session_state_management(
debug!("🧩 -> AuthState::Continue");
let kref = &state.jws_signer;
// Get the header token ready.
let jws = Jws::new(SessionId { sessionid });
jws.sign(kref)
let jws = Jws::into_json(&SessionId { sessionid }).map_err(|e| {
error!(?e);
OperationError::InvalidSessionState
})?;
kref.sign(&jws)
.map(|jwss| {
auth_session_id_tok = Some(jwss.to_string());
})

View file

@ -40,7 +40,7 @@ use std::path::Path;
use std::sync::Arc;
use crate::utils::touch_file_or_quit;
use compact_jwt::JwsSigner;
use compact_jwt::JwsHs256Signer;
use kanidm_proto::v1::OperationError;
use kanidmd_lib::be::{Backend, BackendConfig, BackendTransaction};
use kanidmd_lib::idm::ldap::LdapServer;
@ -853,7 +853,7 @@ pub async fn create_server_core(
// Extract any configuration from the IDMS that we may need.
// For now we just do this per run, but we need to extract this from the db later.
let jws_signer = match JwsSigner::generate_hs256() {
let jws_signer = match JwsHs256Signer::generate_hs256() {
Ok(k) => k,
Err(e) => {
error!("Unable to setup jws signer -> {:?}", e);

View file

@ -28,7 +28,7 @@ harness = false
[dependencies]
base64 = { workspace = true }
base64urlsafedata = { workspace = true }
compact_jwt = { workspace = true, features = ["openssl"] }
compact_jwt = { workspace = true, features = ["openssl", "hsm-crypto"] }
concread = { workspace = true }
dyn-clone = { workspace = true }
enum-iterator = { workspace = true }

View file

@ -29,7 +29,7 @@ pub use std::collections::BTreeSet as Set;
use std::collections::{BTreeMap as Map, BTreeMap, BTreeSet};
use std::sync::Arc;
use compact_jwt::JwsSigner;
use compact_jwt::JwsEs256Signer;
use hashbrown::{HashMap, HashSet};
use kanidm_proto::internal::ImageValue;
use kanidm_proto::v1::{
@ -2834,7 +2834,7 @@ impl<VALID, STATE> Entry<VALID, STATE> {
.and_then(|vs| vs.to_private_binary_single())
}
pub fn get_ava_single_jws_key_es256(&self, attr: Attribute) -> Option<&JwsSigner> {
pub fn get_ava_single_jws_key_es256(&self, attr: Attribute) -> Option<&JwsEs256Signer> {
self.attrs
.get(attr.as_ref())
.and_then(|vs| vs.to_jws_key_es256_single())

View file

@ -7,13 +7,11 @@ use std::convert::TryFrom;
use std::fmt;
use std::time::Duration;
// use webauthn_rs::proto::Credential as WebauthnCredential;
use compact_jwt::{Jws, JwsSigner};
use compact_jwt::{Jws, JwsEs256Signer, JwsSigner};
use hashbrown::HashSet;
use kanidm_proto::v1::{
AuthAllowed, AuthCredential, AuthIssueSession, AuthMech, OperationError, UserAuthToken,
};
// use crossbeam::channel::Sender;
use nonempty::{nonempty, NonEmpty};
use tokio::sync::mpsc::UnboundedSender as Sender;
use uuid::Uuid;
@ -1014,7 +1012,7 @@ impl AuthSession {
async_tx: &Sender<DelayedAction>,
audit_tx: &Sender<AuditEvent>,
webauthn: &Webauthn,
uat_jwt_signer: &JwsSigner,
uat_jwt_signer: &JwsEs256Signer,
pw_badlist: &HashSet<String>,
) -> Result<AuthState, OperationError> {
let (next_state, response) = match &mut self.state {
@ -1042,14 +1040,18 @@ impl AuthSession {
self.account_policy.authsession_expiry(),
self.account_policy.privilege_expiry(),
)?;
let jwt = Jws::new(uat);
let jwt = Jws::into_json(&uat).map_err(|e| {
admin_error!(?e, "Failed to serialise into Jws");
OperationError::InvalidState
})?;
// Now encrypt and prepare the token for return to the client.
let token = jwt
let token = uat_jwt_signer
// Do we want to embed this? Or just give the URL? I think we embed
// as we only need the client to be able to check it's not tampered, but
// this isn't a root of trust.
.sign_embed_public_jwk(uat_jwt_signer)
.sign(&jwt)
.map(|jwts| jwts.to_string())
.map_err(|e| {
admin_error!(?e, "Failed to sign UserAuthToken to Jwt");
@ -1239,7 +1241,7 @@ mod tests {
use std::str::FromStr;
use std::time::Duration;
use compact_jwt::{Jws, JwsSigner, JwsUnverified};
use compact_jwt::{JwsCompact, JwsEs256Signer, JwsEs256Verifier, JwsVerifier};
use hashbrown::HashSet;
use kanidm_proto::v1::{
AuthAllowed, AuthCredential, AuthIssueSession, AuthMech, UatPurpose, UserAuthToken,
@ -1278,8 +1280,10 @@ mod tests {
.unwrap()
}
fn create_jwt_signer() -> JwsSigner {
JwsSigner::generate_es256().expect("failed to construct signer.")
fn create_jwt_signer() -> JwsEs256Signer {
JwsEs256Signer::generate_es256()
.expect("failed to construct signer.")
.set_sign_option_embed_jwk(true)
}
#[test]
@ -1411,10 +1415,16 @@ mod tests {
&pw_badlist_cache,
) {
Ok(AuthState::Success(jwt, AuthIssueSession::Token)) => {
let uat = JwsUnverified::from_str(&jwt).expect("Failed to parse jwt");
let uat: Jws<UserAuthToken> =
uat.validate_embeded().expect("Embedded uat not found");
uat.into_inner()
let jwsc = JwsCompact::from_str(&jwt).expect("Failed to parse jwt");
let jws_verifier =
JwsEs256Verifier::try_from(jwsc.get_jwk_pubkey().unwrap()).unwrap();
jws_verifier
.verify(&jwsc)
.unwrap()
.from_json::<UserAuthToken>()
.unwrap()
}
_ => panic!(),
};

View file

@ -616,7 +616,7 @@ mod tests {
use crate::prelude::*;
use std::str::FromStr;
use compact_jwt::{Jws, JwsUnverified};
use compact_jwt::{JwsCompact, JwsEs256Verifier, JwsVerifier};
use hashbrown::HashSet;
use kanidm_proto::v1::ApiToken;
use ldap3_proto::proto::{LdapFilter, LdapOp, LdapSearchScope, LdapSubstringFilter};
@ -1119,13 +1119,16 @@ mod tests {
// Inspect the token to get its uuid out.
let apitoken_unverified =
JwsUnverified::from_str(&apitoken).expect("Failed to parse apitoken");
JwsCompact::from_str(&apitoken).expect("Failed to parse apitoken");
let apitoken_inner: Jws<ApiToken> = apitoken_unverified
.validate_embeded()
.expect("Embedded jwk not found");
let jws_verifier =
JwsEs256Verifier::try_from(apitoken_unverified.get_jwk_pubkey().unwrap()).unwrap();
let apitoken_inner = apitoken_inner.into_inner();
let apitoken_inner = jws_verifier
.verify(&apitoken_unverified)
.unwrap()
.from_json::<ApiToken>()
.unwrap();
// Bind using the token as a DN
let sa_lbt = ldaps

View file

@ -13,8 +13,8 @@ use std::time::Duration;
use base64::{engine::general_purpose, Engine as _};
use base64urlsafedata::Base64UrlSafeData;
pub use compact_jwt::{JwkKeySet, OidcToken};
use compact_jwt::{JwsSigner, OidcClaims, OidcSubject};
pub use compact_jwt::{compact::JwkKeySet, OidcToken};
use compact_jwt::{crypto::JwsRs256Signer, JwsEs256Signer, JwsSigner, OidcClaims, OidcSubject};
use concread::cowcell::*;
use fernet::Fernet;
use hashbrown::HashMap;
@ -216,6 +216,12 @@ impl std::fmt::Debug for OauthRSType {
}
}
#[derive(Clone)]
enum Oauth2JwsSigner {
ES256 { signer: JwsEs256Signer },
RS256 { signer: JwsRs256Signer },
}
#[derive(Clone)]
pub struct Oauth2RS {
name: String,
@ -227,8 +233,9 @@ pub struct Oauth2RS {
sup_scope_maps: BTreeMap<Uuid, BTreeSet<String>>,
// Our internal exchange encryption material for this rs.
token_fernet: Fernet,
jws_signer: JwsSigner,
// jws_validator: JwsValidator,
jws_signer: Oauth2JwsSigner,
// For oidc we also need our issuer url.
iss: Url,
// For discovery we need to build and keep a number of values.
@ -398,7 +405,9 @@ impl<'a> Oauth2ResourceServersWriteTransaction<'a> {
.get_ava_single_private_binary(Attribute::Rs256PrivateKeyDer)
.ok_or(OperationError::InvalidValueState)
.and_then(|key_der| {
JwsSigner::from_rs256_der(key_der).map_err(|e| {
JwsRs256Signer::from_rs256_der(key_der)
.map(|signer| Oauth2JwsSigner::RS256 { signer })
.map_err(|e| {
admin_error!(err = ?e, "Unable to load Legacy RS256 JwsSigner from DER");
OperationError::CryptographyError
})
@ -409,7 +418,9 @@ impl<'a> Oauth2ResourceServersWriteTransaction<'a> {
.get_ava_single_private_binary(Attribute::Es256PrivateKeyDer)
.ok_or(OperationError::InvalidValueState)
.and_then(|key_der| {
JwsSigner::from_es256_der(key_der).map_err(|e| {
JwsEs256Signer::from_es256_der(key_der)
.map(|signer| Oauth2JwsSigner::ES256 { signer })
.map_err(|e| {
admin_error!(err = ?e, "Unable to load ES256 JwsSigner from DER");
OperationError::CryptographyError
})
@ -1081,14 +1092,16 @@ impl<'a> IdmServerProxyWriteTransaction<'a> {
trace!(?oidc);
Some(
oidc.sign(&o2rs.jws_signer)
.map(|jwt_signed| jwt_signed.to_string())
.map_err(|e| {
admin_error!(err = ?e, "Unable to encode uat data");
Oauth2Error::ServerError(OperationError::InvalidState)
})?,
)
let jwt_signed = match &o2rs.jws_signer {
Oauth2JwsSigner::ES256 { signer } => signer.sign(&oidc),
Oauth2JwsSigner::RS256 { signer } => signer.sign(&oidc),
}
.map_err(|e| {
admin_error!(err = ?e, "Unable to encode uat data");
Oauth2Error::ServerError(OperationError::InvalidState)
})?;
Some(jwt_signed.to_string())
} else {
// id_token is not required in non-openid flows.
None
@ -1820,12 +1833,8 @@ impl<'a> IdmServerProxyReadTransaction<'a> {
let subject_types_supported = vec![SubjectType::Public];
let id_token_signing_alg_values_supported = match &o2rs.jws_signer {
JwsSigner::ES256 { .. } => vec![IdTokenSignAlg::ES256],
JwsSigner::RS256 { .. } => vec![IdTokenSignAlg::RS256],
JwsSigner::HS256 { .. } => {
admin_warn!("Invalid OAuth2 configuration - HS256 is not supported!");
vec![]
}
Oauth2JwsSigner::ES256 { .. } => vec![IdTokenSignAlg::ES256],
Oauth2JwsSigner::RS256 { .. } => vec![IdTokenSignAlg::RS256],
};
let userinfo_signing_alg_values_supported = None;
@ -1888,13 +1897,15 @@ impl<'a> IdmServerProxyReadTransaction<'a> {
OperationError::NoMatchingEntries
})?;
o2rs.jws_signer
.public_key_as_jwk()
.map_err(|e| {
admin_error!("Unable to retrieve public key for {} - {:?}", o2rs.name, e);
OperationError::InvalidState
})
.map(|jwk| JwkKeySet { keys: vec![jwk] })
match &o2rs.jws_signer {
Oauth2JwsSigner::ES256 { signer } => signer.public_key_as_jwk(),
Oauth2JwsSigner::RS256 { signer } => signer.public_key_as_jwk(),
}
.map_err(|e| {
admin_error!("Unable to retrieve public key for {} - {:?}", o2rs.name, e);
OperationError::InvalidState
})
.map(|jwk| JwkKeySet { keys: vec![jwk] })
}
}
@ -1997,7 +2008,10 @@ mod tests {
use std::time::Duration;
use base64urlsafedata::Base64UrlSafeData;
use compact_jwt::{JwaAlg, Jwk, JwkUse, JwsValidator, OidcSubject, OidcUnverified};
use compact_jwt::{
compact::JwkUse, crypto::JwsRs256Verifier, JwaAlg, Jwk, JwsEs256Verifier, JwsVerifier,
OidcSubject, OidcUnverified,
};
use kanidm_proto::constants::*;
use kanidm_proto::oauth2::*;
use kanidm_proto::v1::UserAuthToken;
@ -3581,15 +3595,18 @@ mod tests {
let public_jwk = jwkset.keys.pop().expect("no such jwk");
let jws_validator = JwsValidator::try_from(&public_jwk).expect("failed to build validator");
let jws_validator =
JwsEs256Verifier::try_from(&public_jwk).expect("failed to build validator");
let oidc_unverified =
OidcUnverified::from_str(&id_token).expect("Failed to parse id_token");
let iat = ct.as_secs() as i64;
let oidc = oidc_unverified
.validate(&jws_validator, iat)
let oidc = jws_validator
.verify(&oidc_unverified)
.unwrap()
.verify_exp(iat)
.expect("Failed to verify oidc");
// Are the id_token values what we expect?
@ -3750,15 +3767,18 @@ mod tests {
.expect("Failed to get public key");
let public_jwk = jwkset.keys.pop().expect("no such jwk");
let jws_validator = JwsValidator::try_from(&public_jwk).expect("failed to build validator");
let jws_validator =
JwsEs256Verifier::try_from(&public_jwk).expect("failed to build validator");
let oidc_unverified =
OidcUnverified::from_str(&id_token).expect("Failed to parse id_token");
let iat = ct.as_secs() as i64;
let oidc = oidc_unverified
.validate(&jws_validator, iat)
let oidc = jws_validator
.verify(&oidc_unverified)
.unwrap()
.verify_exp(iat)
.expect("Failed to verify oidc");
// Do we have the short username in the token claims?
@ -3836,15 +3856,18 @@ mod tests {
.expect("Failed to get public key");
let public_jwk = jwkset.keys.pop().expect("no such jwk");
let jws_validator = JwsValidator::try_from(&public_jwk).expect("failed to build validator");
let jws_validator =
JwsEs256Verifier::try_from(&public_jwk).expect("failed to build validator");
let oidc_unverified =
OidcUnverified::from_str(&id_token).expect("Failed to parse id_token");
let iat = ct.as_secs() as i64;
let oidc = oidc_unverified
.validate(&jws_validator, iat)
let oidc = jws_validator
.verify(&oidc_unverified)
.unwrap()
.verify_exp(iat)
.expect("Failed to verify oidc");
// does our id_token contain the expected groups?
@ -3993,15 +4016,18 @@ mod tests {
assert!(token_response.token_type == "bearer");
let id_token = token_response.id_token.expect("No id_token in response!");
let jws_validator = JwsValidator::try_from(&public_jwk).expect("failed to build validator");
let jws_validator =
JwsRs256Verifier::try_from(&public_jwk).expect("failed to build validator");
let oidc_unverified =
OidcUnverified::from_str(&id_token).expect("Failed to parse id_token");
let iat = ct.as_secs() as i64;
let oidc = oidc_unverified
.validate(&jws_validator, iat)
let oidc = jws_validator
.verify(&oidc_unverified)
.unwrap()
.verify_exp(iat)
.expect("Failed to verify oidc");
assert!(oidc.sub == OidcSubject::U(UUID_ADMIN));

View file

@ -2,7 +2,7 @@ use std::time::Duration;
use base64urlsafedata::Base64UrlSafeData;
use compact_jwt::{Jws, JwsSigner};
use compact_jwt::{Jws, JwsEs256Signer, JwsSigner};
use kanidm_proto::internal::ScimSyncToken;
use kanidm_proto::scim_v1::*;
use kanidm_proto::v1::ApiTokenPurpose;
@ -23,7 +23,7 @@ pub(crate) struct SyncAccount {
pub name: String,
pub uuid: Uuid,
pub sync_tokens: BTreeMap<Uuid, ApiToken>,
pub jws_key: JwsSigner,
pub jws_key: JwsEs256Signer,
}
macro_rules! try_from_entry {
@ -48,7 +48,8 @@ macro_rules! try_from_entry {
.ok_or(OperationError::InvalidAccountState(format!(
"Missing attribute: {}",
Attribute::JwsEs256PrivateKey
)))?;
)))?
.set_sign_option_embed_jwk(true);
let sync_tokens = $value
.get_ava_as_apitoken_map(Attribute::SyncTokenSession)
@ -156,11 +157,16 @@ impl<'a> IdmServerProxyWriteTransaction<'a> {
},
);
let token = Jws::new(ScimSyncToken {
let scim_sync_token = ScimSyncToken {
token_id: session_id,
issued_at,
purpose,
});
};
let token = Jws::into_json(&scim_sync_token).map_err(|err| {
error!(?err, "Unable to serialise JWS");
OperationError::SerdeJsonError
})?;
let modlist = ModifyList::new_list(vec![Modify::Present(
Attribute::SyncTokenSession.into(),
@ -179,8 +185,9 @@ impl<'a> IdmServerProxyWriteTransaction<'a> {
)
.and_then(|_| {
// The modify succeeded and was allowed, now sign the token for return.
token
.sign_embed_public_jwk(&sync_account.jws_key)
sync_account
.jws_key
.sign(&token)
.map(|jws_signed| jws_signed.to_string())
.map_err(|e| {
admin_error!(err = ?e, "Unable to sign sync token");
@ -1517,7 +1524,7 @@ mod tests {
use crate::idm::server::{IdmServerProxyWriteTransaction, IdmServerTransaction};
use crate::prelude::*;
use base64urlsafedata::Base64UrlSafeData;
use compact_jwt::Jws;
use compact_jwt::{Jws, JwsSigner};
use kanidm_proto::scim_v1::*;
use kanidm_proto::v1::ApiTokenPurpose;
use std::sync::Arc;
@ -1706,14 +1713,16 @@ mod tests {
let purpose = ApiTokenPurpose::ReadWrite;
let token = Jws::new(ScimSyncToken {
let scim_sync_token = ScimSyncToken {
token_id,
issued_at,
purpose,
});
};
let forged_token = token
.sign(&jws_key)
let token = Jws::into_json(&scim_sync_token).expect("Unable to serialise forged token");
let forged_token = jws_key
.sign(&token)
.map(|jws_signed| jws_signed.to_string())
.expect("Unable to sign forged token");

View file

@ -5,7 +5,7 @@ use std::time::Duration;
use kanidm_lib_crypto::CryptoPolicy;
use compact_jwt::{Jws, JwsSigner, JwsUnverified, JwsValidator};
use compact_jwt::{JwsCompact, JwsEs256Signer, JwsEs256Verifier, JwsSignerToVerifier, JwsVerifier};
use concread::bptree::{BptreeMap, BptreeMapReadTxn, BptreeMapWriteTxn};
use concread::cowcell::{CowCellReadTxn, CowCellWriteTxn};
use concread::hashmap::HashMap;
@ -62,8 +62,8 @@ pub(crate) type CredSoftLockMutex = Arc<Mutex<CredSoftLock>>;
#[derive(Clone)]
pub struct DomainKeys {
pub(crate) uat_jwt_signer: JwsSigner,
pub(crate) uat_jwt_validator: JwsValidator,
pub(crate) uat_jwt_signer: JwsEs256Signer,
pub(crate) uat_jwt_validator: JwsEs256Verifier,
pub(crate) token_enc_key: Fernet,
pub(crate) cookie_key: [u8; 64],
}
@ -205,12 +205,14 @@ impl IdmServer {
OperationError::CryptographyError
})?;
let uat_jwt_signer = JwsSigner::from_es256_der(&es256_private_key).map_err(|e| {
admin_error!(err = ?e, "Unable to load ES256 JwsSigner from DER");
OperationError::CryptographyError
})?;
let uat_jwt_signer = JwsEs256Signer::from_es256_der(&es256_private_key)
.map_err(|e| {
admin_error!(err = ?e, "Unable to load ES256 JwsSigner from DER");
OperationError::CryptographyError
})?
.set_sign_option_embed_jwk(true);
let uat_jwt_validator = uat_jwt_signer.get_validator().map_err(|e| {
let uat_jwt_validator = uat_jwt_signer.get_verifier().map_err(|e| {
admin_error!(err = ?e, "Unable to load ES256 JwsValidator from JwsSigner");
OperationError::CryptographyError
})?;
@ -394,7 +396,7 @@ pub trait IdmServerTransaction<'a> {
fn get_qs_txn(&mut self) -> &mut Self::QsTransactionType;
fn get_uat_validator_txn(&self) -> &JwsValidator;
fn get_uat_validator_txn(&self) -> &JwsEs256Verifier;
/// This is the preferred method to transform and securely verify a token into
/// an identity that can be used for operations and access enforcement. This
@ -442,7 +444,7 @@ pub trait IdmServerTransaction<'a> {
OperationError::NotAuthenticated
})
.and_then(|s| {
JwsUnverified::from_str(s).map_err(|e| {
JwsCompact::from_str(s).map_err(|e| {
security_info!(?e, "Unable to decode token");
OperationError::NotAuthenticated
})
@ -456,20 +458,25 @@ pub trait IdmServerTransaction<'a> {
OperationError::NotAuthenticated
})?;
let jwsv_kid = jws_validator.get_jwk_kid().ok_or_else(|| {
let jwsv_kid = jws_validator.get_kid().ok_or_else(|| {
security_info!("JWS validator does not contain a valid kid");
OperationError::NotAuthenticated
})?;
if kid == jwsv_kid {
// It's signed by the primary jws, so it's probably a UserAuthToken.
let uat = jwsu
.validate(jws_validator)
let uat = jws_validator
.verify(&jwsu)
.map_err(|e| {
security_info!(?e, "Unable to verify token");
OperationError::NotAuthenticated
})
.map(|t: Jws<UserAuthToken>| t.into_inner())?;
.and_then(|t| {
t.from_json::<UserAuthToken>().map_err(|err| {
error!(?err, "Unable to deserialise JWS");
OperationError::SerdeJsonError
})
})?;
if let Some(exp) = uat.expiry {
let ct_odt = time::OffsetDateTime::UNIX_EPOCH + ct;
@ -514,18 +521,23 @@ pub trait IdmServerTransaction<'a> {
OperationError::NotAuthenticated
})?;
let user_validator = user_signer.get_validator().map_err(|e| {
let user_validator = user_signer.get_verifier().map_err(|e| {
security_info!(?e, "Unable to access token verifier");
OperationError::NotAuthenticated
})?;
let apit = jwsu
.validate(&user_validator)
let apit = user_validator
.verify(&jwsu)
.map_err(|e| {
security_info!(?e, "Unable to verify token");
OperationError::NotAuthenticated
})
.map(|t: Jws<ApiToken>| t.into_inner())?;
.and_then(|t| {
t.from_json::<ApiToken>().map_err(|err| {
error!(?err, "Unable to deserialise JWS");
OperationError::SerdeJsonError
})
})?;
if let Some(expiry) = apit.expiry {
if time::OffsetDateTime::UNIX_EPOCH + ct >= expiry {
@ -550,18 +562,24 @@ pub trait IdmServerTransaction<'a> {
let uat: UserAuthToken = token
.ok_or(OperationError::NotAuthenticated)
.and_then(|s| {
JwsUnverified::from_str(s).map_err(|e| {
JwsCompact::from_str(s).map_err(|e| {
security_info!(?e, "Unable to decode token");
OperationError::NotAuthenticated
})
})
.and_then(|jwtu| {
jwtu.validate(jws_validator)
jws_validator
.verify(&jwtu)
.map_err(|e| {
security_info!(?e, "Unable to verify token");
OperationError::NotAuthenticated
})
.map(|t: Jws<UserAuthToken>| t.into_inner())
.and_then(|t| {
t.from_json::<UserAuthToken>().map_err(|err| {
error!(?err, "Unable to deserialise JWS");
OperationError::SerdeJsonError
})
})
})?;
if let Some(exp) = uat.expiry {
@ -833,7 +851,7 @@ pub trait IdmServerTransaction<'a> {
OperationError::NotAuthenticated
})
.and_then(|s| {
JwsUnverified::from_str(s).map_err(|e| {
JwsCompact::from_str(s).map_err(|e| {
security_info!(?e, "Unable to decode token");
OperationError::NotAuthenticated
})
@ -872,18 +890,23 @@ pub trait IdmServerTransaction<'a> {
OperationError::NotAuthenticated
})?;
let user_validator = user_signer.get_validator().map_err(|e| {
let user_validator = user_signer.get_verifier().map_err(|e| {
security_info!(?e, "Unable to access token verifier");
OperationError::NotAuthenticated
})?;
let sync_token = jwsu
.validate(&user_validator)
let sync_token = user_validator
.verify(&jwsu)
.map_err(|e| {
security_info!(?e, "Unable to verify token");
OperationError::NotAuthenticated
})
.map(|t: Jws<ScimSyncToken>| t.into_inner())?;
.and_then(|t| {
t.from_json::<ScimSyncToken>().map_err(|err| {
error!(?err, "Unable to deserialise JWS");
OperationError::SerdeJsonError
})
})?;
let valid = SyncAccount::check_sync_token_valid(ct, &sync_token, &entry);
@ -912,7 +935,7 @@ impl<'a> IdmServerTransaction<'a> for IdmServerAuthTransaction<'a> {
&mut self.qs_read
}
fn get_uat_validator_txn(&self) -> &JwsValidator {
fn get_uat_validator_txn(&self) -> &JwsEs256Verifier {
&self.domain_keys.uat_jwt_validator
}
}
@ -1429,7 +1452,7 @@ impl<'a> IdmServerTransaction<'a> for IdmServerProxyReadTransaction<'a> {
&mut self.qs_read
}
fn get_uat_validator_txn(&self) -> &JwsValidator {
fn get_uat_validator_txn(&self) -> &JwsEs256Verifier {
&self.domain_keys.uat_jwt_validator
}
}
@ -1532,7 +1555,7 @@ impl<'a> IdmServerTransaction<'a> for IdmServerProxyWriteTransaction<'a> {
&mut self.qs_write
}
fn get_uat_validator_txn(&self) -> &JwsValidator {
fn get_uat_validator_txn(&self) -> &JwsEs256Verifier {
&self.domain_keys.uat_jwt_validator
}
}
@ -2035,14 +2058,16 @@ impl<'a> IdmServerProxyWriteTransaction<'a> {
self.qs_write
.get_domain_es256_private_key()
.and_then(|key_der| {
JwsSigner::from_es256_der(&key_der).map_err(|e| {
admin_error!("Failed to generate uat_jwt_signer - {:?}", e);
OperationError::InvalidState
})
JwsEs256Signer::from_es256_der(&key_der)
.map(|signer| signer.set_sign_option_embed_jwk(true))
.map_err(|e| {
admin_error!("Failed to generate uat_jwt_signer - {:?}", e);
OperationError::InvalidState
})
})
.and_then(|signer| {
signer
.get_validator()
.get_verifier()
.map_err(|e| {
admin_error!("Failed to generate uat_jwt_validator - {:?}", e);
OperationError::InvalidState
@ -2100,6 +2125,7 @@ mod tests {
use crate::modify::{Modify, ModifyList};
use crate::prelude::*;
use crate::value::SessionState;
use compact_jwt::{JwsCompact, JwsEs256Verifier, JwsVerifier};
use kanidm_lib_crypto::CryptoPolicy;
const TEST_PASSWORD: &str = "ntaoeuntnaoeuhraohuercahu😍";
@ -3474,7 +3500,6 @@ mod tests {
idms: &IdmServer,
idms_delayed: &mut IdmServerDelayed,
) {
use compact_jwt::{Jws, JwsUnverified};
use kanidm_proto::v1::UserAuthToken;
use std::str::FromStr;
@ -3499,11 +3524,16 @@ mod tests {
let r = idms.delayed_action(ct, da).await;
assert!(Ok(true) == r);
let uat_unverified = JwsUnverified::from_str(&token).expect("Failed to parse apitoken");
let uat_inner: Jws<UserAuthToken> = uat_unverified
.validate_embeded()
.expect("Embedded jwk not found");
let uat_inner = uat_inner.into_inner();
let uat_unverified = JwsCompact::from_str(&token).expect("Failed to parse apitoken");
let jws_validator =
JwsEs256Verifier::try_from(uat_unverified.get_jwk_pubkey().unwrap()).unwrap();
let uat_inner: UserAuthToken = jws_validator
.verify(&uat_unverified)
.unwrap()
.from_json()
.unwrap();
let mut idms_prox_read = idms.proxy_read().await;

View file

@ -1,7 +1,7 @@
use std::collections::BTreeMap;
use std::time::Duration;
use compact_jwt::{Jws, JwsSigner};
use compact_jwt::{Jws, JwsEs256Signer, JwsSigner};
use kanidm_proto::v1::ApiToken as ProtoApiToken;
use time::OffsetDateTime;
@ -48,7 +48,8 @@ macro_rules! try_from_entry {
.ok_or(OperationError::InvalidAccountState(format!(
"Missing attribute: {}",
Attribute::JwsEs256PrivateKey
)))?;
)))?
.set_sign_option_embed_jwk(true);
let api_tokens = $value
.get_ava_as_apitoken_map(Attribute::ApiTokenSession)
@ -81,7 +82,7 @@ pub struct ServiceAccount {
pub api_tokens: BTreeMap<Uuid, ApiToken>,
pub jws_key: JwsSigner,
pub jws_key: JwsEs256Signer,
}
impl ServiceAccount {
@ -240,14 +241,19 @@ impl<'a> IdmServerProxyWriteTransaction<'a> {
);
// create the session token (not yet signed)
let token = Jws::new(ProtoApiToken {
let proto_api_token = ProtoApiToken {
account_id: service_account.uuid,
token_id: session_id,
label: gte.label.clone(),
expiry: gte.expiry,
issued_at,
purpose,
});
};
let token = Jws::into_json(&proto_api_token).map_err(|err| {
error!(?err, "Unable to serialise JWS");
OperationError::SerdeJsonError
})?;
// modify the account to put the session onto it.
let modlist = ModifyList::new_list(vec![Modify::Present(
@ -267,8 +273,9 @@ impl<'a> IdmServerProxyWriteTransaction<'a> {
)
.and_then(|_| {
// The modify succeeded and was allowed, now sign the token for return.
token
.sign_embed_public_jwk(&service_account.jws_key)
service_account
.jws_key
.sign(&token)
.map(|jws_signed| jws_signed.to_string())
.map_err(|e| {
admin_error!(err = ?e, "Unable to sign api token");
@ -424,7 +431,7 @@ mod tests {
use std::str::FromStr;
use std::time::Duration;
use compact_jwt::{Jws, JwsUnverified};
use compact_jwt::{JwsCompact, JwsEs256Verifier, JwsVerifier};
use kanidm_proto::v1::ApiToken;
use super::{DestroyApiTokenEvent, GenerateApiTokenEvent};
@ -471,11 +478,16 @@ mod tests {
// Deserialise it.
let apitoken_unverified =
JwsUnverified::from_str(&api_token).expect("Failed to parse apitoken");
let apitoken_inner: Jws<ApiToken> = apitoken_unverified
.validate_embeded()
.expect("Embedded jwk not found");
let apitoken_inner = apitoken_inner.into_inner();
JwsCompact::from_str(&api_token).expect("Failed to parse apitoken");
let jws_verifier =
JwsEs256Verifier::try_from(apitoken_unverified.get_jwk_pubkey().unwrap()).unwrap();
let apitoken_inner = jws_verifier
.verify(&apitoken_unverified)
.unwrap()
.from_json::<ApiToken>()
.unwrap();
let ident = idms_prox_write
.validate_and_parse_token_to_ident(Some(&api_token), ct)

View file

@ -7,7 +7,7 @@
use std::iter::once;
use std::sync::Arc;
use compact_jwt::JwsSigner;
use compact_jwt::JwsEs256Signer;
use kanidm_proto::v1::OperationError;
use rand::prelude::*;
use regex::Regex;
@ -126,7 +126,7 @@ impl Domain {
if !e.attribute_pres(Attribute::Es256PrivateKeyDer) {
security_info!("regenerating domain es256 private key");
let der = JwsSigner::generate_es256()
let der = JwsEs256Signer::generate_es256()
.and_then(|jws| jws.private_key_to_der())
.map_err(|e| {
admin_error!(err = ?e, "Unable to generate ES256 JwsSigner private key");

View file

@ -1,4 +1,4 @@
use compact_jwt::JwsSigner;
use compact_jwt::{crypto::JwsRs256Signer, JwsEs256Signer};
use std::sync::Arc;
use crate::event::{CreateEvent, ModifyEvent};
@ -62,7 +62,7 @@ impl JwsKeygen {
}
if !e.attribute_pres(Attribute::Es256PrivateKeyDer) {
security_info!("regenerating oauth2 es256 private key");
let der = JwsSigner::generate_es256()
let der = JwsEs256Signer::generate_es256()
.and_then(|jws| jws.private_key_to_der())
.map_err(|e| {
admin_error!(err = ?e, "Unable to generate ES256 JwsSigner private key");
@ -74,7 +74,7 @@ impl JwsKeygen {
if e.get_ava_single_bool(Attribute::OAuth2JwtLegacyCryptoEnable).unwrap_or(false)
&& !e.attribute_pres(Attribute::Rs256PrivateKeyDer) {
security_info!("regenerating oauth2 legacy rs256 private key");
let der = JwsSigner::generate_legacy_rs256()
let der = JwsRs256Signer::generate_legacy_rs256()
.and_then(|jws| jws.private_key_to_der())
.map_err(|e| {
admin_error!(err = ?e, "Unable to generate Legacy RS256 JwsSigner private key");
@ -89,7 +89,7 @@ impl JwsKeygen {
e.attribute_equality(Attribute::Class, &EntryClass::SyncAccount.into())) &&
!e.attribute_pres(Attribute::JwsEs256PrivateKey) {
security_info!("regenerating jws es256 private key");
let jwssigner = JwsSigner::generate_es256()
let jwssigner = JwsEs256Signer::generate_es256()
.map_err(|e| {
admin_error!(err = ?e, "Unable to generate ES256 JwsSigner private key");
OperationError::CryptographyError

View file

@ -15,7 +15,7 @@ use std::time::Duration;
#[cfg(test)]
use base64::{engine::general_purpose, Engine as _};
use compact_jwt::JwsSigner;
use compact_jwt::{crypto::JwsRs256Signer, JwsEs256Signer};
use hashbrown::HashSet;
use kanidm_proto::internal::ImageValue;
use num_enum::TryFromPrimitive;
@ -1029,8 +1029,8 @@ pub enum Value {
ApiToken(Uuid, ApiToken),
Oauth2Session(Uuid, Oauth2Session),
JwsKeyEs256(JwsSigner),
JwsKeyRs256(JwsSigner),
JwsKeyEs256(JwsEs256Signer),
JwsKeyRs256(JwsRs256Signer),
UiHint(UiHint),
TotpSecret(String, Totp),

View file

@ -1,5 +1,5 @@
use base64urlsafedata::Base64UrlSafeData;
use compact_jwt::{JwaAlg, JwsSigner};
use compact_jwt::{crypto::JwsRs256Signer, JwsEs256Signer, JwsSigner};
use hashbrown::HashSet;
use crate::prelude::*;
@ -9,19 +9,17 @@ use crate::valueset::{DbValueSetV2, ValueSet};
#[derive(Debug, Clone)]
pub struct ValueSetJwsKeyEs256 {
set: HashSet<JwsSigner>,
set: HashSet<JwsEs256Signer>,
}
impl ValueSetJwsKeyEs256 {
pub fn new(k: JwsSigner) -> Box<Self> {
debug_assert!(k.get_jwa_alg() == JwaAlg::ES256);
pub fn new(k: JwsEs256Signer) -> Box<Self> {
let mut set = HashSet::new();
set.insert(k);
Box::new(ValueSetJwsKeyEs256 { set })
}
pub fn push(&mut self, k: JwsSigner) -> bool {
debug_assert!(k.get_jwa_alg() == JwaAlg::ES256);
pub fn push(&mut self, k: JwsEs256Signer) -> bool {
self.set.insert(k)
}
@ -29,7 +27,7 @@ impl ValueSetJwsKeyEs256 {
let set = data
.iter()
.map(|b| {
JwsSigner::from_es256_der(b).map_err(|e| {
JwsEs256Signer::from_es256_der(b).map_err(|e| {
debug!(?e, "Error occurred parsing ES256 DER");
OperationError::InvalidValueState
})
@ -42,7 +40,7 @@ impl ValueSetJwsKeyEs256 {
let set = data
.iter()
.map(|b| {
JwsSigner::from_es256_der(b.0.as_slice()).map_err(|e| {
JwsEs256Signer::from_es256_der(b.0.as_slice()).map_err(|e| {
debug!(?e, "Error occurred parsing ES256 DER");
OperationError::InvalidValueState
})
@ -56,10 +54,9 @@ impl ValueSetJwsKeyEs256 {
#[allow(clippy::should_implement_trait)]
pub fn from_iter<T>(iter: T) -> Option<Box<ValueSetJwsKeyEs256>>
where
T: IntoIterator<Item = JwsSigner>,
T: IntoIterator<Item = JwsEs256Signer>,
{
let set: HashSet<JwsSigner> = iter.into_iter().collect();
debug_assert!(set.iter().all(|k| k.get_jwa_alg() == JwaAlg::ES256));
let set: HashSet<JwsEs256Signer> = iter.into_iter().collect();
Some(Box::new(ValueSetJwsKeyEs256 { set }))
}
}
@ -126,7 +123,7 @@ impl ValueSetT for ValueSetJwsKeyEs256 {
}
fn validate(&self, _schema_attr: &SchemaAttribute) -> bool {
self.set.iter().all(|k| k.get_jwa_alg() == JwaAlg::ES256)
true
}
fn to_proto_string_clone_iter(&self) -> Box<dyn Iterator<Item = String> + '_> {
@ -186,7 +183,7 @@ impl ValueSetT for ValueSetJwsKeyEs256 {
}
}
fn to_jws_key_es256_single(&self) -> Option<&JwsSigner> {
fn to_jws_key_es256_single(&self) -> Option<&JwsEs256Signer> {
if self.set.len() == 1 {
self.set.iter().take(1).next()
} else {
@ -194,26 +191,24 @@ impl ValueSetT for ValueSetJwsKeyEs256 {
}
}
fn as_jws_key_es256_set(&self) -> Option<&HashSet<JwsSigner>> {
fn as_jws_key_es256_set(&self) -> Option<&HashSet<JwsEs256Signer>> {
Some(&self.set)
}
}
#[derive(Debug, Clone)]
pub struct ValueSetJwsKeyRs256 {
set: HashSet<JwsSigner>,
set: HashSet<JwsRs256Signer>,
}
impl ValueSetJwsKeyRs256 {
pub fn new(k: JwsSigner) -> Box<Self> {
debug_assert!(k.get_jwa_alg() == JwaAlg::RS256);
pub fn new(k: JwsRs256Signer) -> Box<Self> {
let mut set = HashSet::new();
set.insert(k);
Box::new(ValueSetJwsKeyRs256 { set })
}
pub fn push(&mut self, k: JwsSigner) -> bool {
debug_assert!(k.get_jwa_alg() == JwaAlg::RS256);
pub fn push(&mut self, k: JwsRs256Signer) -> bool {
self.set.insert(k)
}
@ -221,7 +216,7 @@ impl ValueSetJwsKeyRs256 {
let set = data
.iter()
.map(|b| {
JwsSigner::from_rs256_der(b).map_err(|e| {
JwsRs256Signer::from_rs256_der(b).map_err(|e| {
debug!(?e, "Error occurred parsing RS256 DER");
OperationError::InvalidValueState
})
@ -234,7 +229,7 @@ impl ValueSetJwsKeyRs256 {
let set = data
.iter()
.map(|b| {
JwsSigner::from_rs256_der(b.0.as_slice()).map_err(|e| {
JwsRs256Signer::from_rs256_der(b.0.as_slice()).map_err(|e| {
debug!(?e, "Error occurred parsing RS256 DER");
OperationError::InvalidValueState
})
@ -248,10 +243,9 @@ impl ValueSetJwsKeyRs256 {
#[allow(clippy::should_implement_trait)]
pub fn from_iter<T>(iter: T) -> Option<Box<ValueSetJwsKeyRs256>>
where
T: IntoIterator<Item = JwsSigner>,
T: IntoIterator<Item = JwsRs256Signer>,
{
let set: HashSet<JwsSigner> = iter.into_iter().collect();
debug_assert!(set.iter().all(|k| k.get_jwa_alg() == JwaAlg::RS256));
let set: HashSet<JwsRs256Signer> = iter.into_iter().collect();
Some(Box::new(ValueSetJwsKeyRs256 { set }))
}
}
@ -315,7 +309,7 @@ impl ValueSetT for ValueSetJwsKeyRs256 {
}
fn validate(&self, _schema_attr: &SchemaAttribute) -> bool {
self.set.iter().all(|k| k.get_jwa_alg() == JwaAlg::RS256)
true
}
fn to_proto_string_clone_iter(&self) -> Box<dyn Iterator<Item = String> + '_> {
@ -375,7 +369,7 @@ impl ValueSetT for ValueSetJwsKeyRs256 {
}
}
fn to_jws_key_rs256_single(&self) -> Option<&JwsSigner> {
fn to_jws_key_rs256_single(&self) -> Option<&JwsRs256Signer> {
if self.set.len() == 1 {
self.set.iter().take(1).next()
} else {
@ -383,7 +377,7 @@ impl ValueSetT for ValueSetJwsKeyRs256 {
}
}
fn as_jws_key_rs256_set(&self) -> Option<&HashSet<JwsSigner>> {
fn as_jws_key_rs256_set(&self) -> Option<&HashSet<JwsRs256Signer>> {
Some(&self.set)
}
}

View file

@ -1,6 +1,6 @@
use std::collections::{BTreeMap, BTreeSet};
use compact_jwt::JwsSigner;
use compact_jwt::{crypto::JwsRs256Signer, JwsEs256Signer};
use dyn_clone::DynClone;
use hashbrown::HashSet;
use kanidm_proto::internal::ImageValue;
@ -527,7 +527,7 @@ pub trait ValueSetT: std::fmt::Debug + DynClone {
None
}
fn to_jws_key_es256_single(&self) -> Option<&JwsSigner> {
fn to_jws_key_es256_single(&self) -> Option<&JwsEs256Signer> {
debug_assert!(false);
None
}
@ -542,17 +542,17 @@ pub trait ValueSetT: std::fmt::Debug + DynClone {
None
}
fn as_jws_key_es256_set(&self) -> Option<&HashSet<JwsSigner>> {
fn as_jws_key_es256_set(&self) -> Option<&HashSet<JwsEs256Signer>> {
debug_assert!(false);
None
}
fn to_jws_key_rs256_single(&self) -> Option<&JwsSigner> {
fn to_jws_key_rs256_single(&self) -> Option<&JwsRs256Signer> {
debug_assert!(false);
None
}
fn as_jws_key_rs256_set(&self) -> Option<&HashSet<JwsSigner>> {
fn as_jws_key_rs256_set(&self) -> Option<&HashSet<JwsRs256Signer>> {
debug_assert!(false);
None
}

View file

@ -3,7 +3,7 @@ use std::collections::HashMap;
use std::convert::TryFrom;
use std::str::FromStr;
use compact_jwt::{JwkKeySet, JwsValidator, OidcToken, OidcUnverified};
use compact_jwt::{JwkKeySet, JwsEs256Verifier, JwsVerifier, OidcToken, OidcUnverified};
use kanidm_proto::constants::uri::{OAUTH2_AUTHORISE, OAUTH2_AUTHORISE_PERMIT};
use kanidm_proto::constants::*;
use kanidm_proto::oauth2::{
@ -211,7 +211,7 @@ async fn test_oauth2_openid_basic_flow(rsclient: KanidmClient) {
let public_jwk = jwk_set.keys.pop().expect("No public key in set!");
let jws_validator = JwsValidator::try_from(&public_jwk).expect("failed to build validator");
let jws_validator = JwsEs256Verifier::try_from(&public_jwk).expect("failed to build validator");
// Step 1 - the Oauth2 Resource Server would send a redirect to the authorisation
// server, where the url contains a series of authorisation request parameters.
@ -366,9 +366,11 @@ async fn test_oauth2_openid_basic_flow(rsclient: KanidmClient) {
let oidc_unverified =
OidcUnverified::from_str(atr.id_token.as_ref().unwrap()).expect("Failed to parse id_token");
let oidc = oidc_unverified
.validate(&jws_validator, 0)
.expect("Failed to verify oidc");
let oidc = jws_validator
.verify(&oidc_unverified)
.expect("Failed to verify oidc")
.verify_exp(0)
.expect("Failed to check exp");
// This is mostly checked inside of idm/oauth2.rs. This is more to check the oidc
// token and the userinfo endpoints.
@ -512,7 +514,7 @@ async fn test_oauth2_openid_public_flow(rsclient: KanidmClient) {
let public_jwk = jwk_set.keys.pop().expect("No public key in set!");
let jws_validator = JwsValidator::try_from(&public_jwk).expect("failed to build validator");
let jws_validator = JwsEs256Verifier::try_from(&public_jwk).expect("failed to build validator");
// Step 1 - the Oauth2 Resource Server would send a redirect to the authorisation
// server, where the url contains a series of authorisation request parameters.
@ -624,9 +626,11 @@ async fn test_oauth2_openid_public_flow(rsclient: KanidmClient) {
let oidc_unverified =
OidcUnverified::from_str(atr.id_token.as_ref().unwrap()).expect("Failed to parse id_token");
let oidc = oidc_unverified
.validate(&jws_validator, 0)
.expect("Failed to verify oidc");
let oidc = jws_validator
.verify(&oidc_unverified)
.expect("Failed to verify oidc")
.verify_exp(0)
.expect("Failed to check exp");
// This is mostly checked inside of idm/oauth2.rs. This is more to check the oidc
// token and the userinfo endpoints.

View file

@ -18,7 +18,7 @@ use tracing::{debug, trace};
use std::str::FromStr;
use compact_jwt::JwsUnverified;
use compact_jwt::{JwsCompact, JwsEs256Verifier, JwsVerifier};
use webauthn_authenticator_rs::softpasskey::SoftPasskey;
use webauthn_authenticator_rs::WebauthnAuthenticator;
@ -1445,12 +1445,19 @@ async fn test_server_api_token_lifecycle(rsclient: KanidmClient) {
.expect("Failed to create service account api token");
// Decode it?
let token_unverified = JwsUnverified::from_str(&token).expect("Failed to parse apitoken");
let token_unverified = JwsCompact::from_str(&token).expect("Failed to parse apitoken");
let token: ApiToken = token_unverified
.validate_embeded()
.map(|j| j.into_inner())
.expect("Embedded jwk not found");
let jws_verifier = JwsEs256Verifier::try_from(
token_unverified
.get_jwk_pubkey()
.expect("No pubkey in token"),
)
.expect("Unable to build verifier");
let token = jws_verifier
.verify(&token_unverified)
.map(|j| j.from_json::<ApiToken>().expect("invalid token json"))
.expect("Failed to verify token");
let tokens = rsclient
.idm_service_account_list_api_token(test_service_account_username)
@ -1649,13 +1656,16 @@ async fn test_server_user_auth_token_lifecycle(rsclient: KanidmClient) {
let token = rsclient.get_token().await.expect("No bearer token present");
let token_unverified =
JwsUnverified::from_str(&token).expect("Failed to parse user auth token");
let jwt = JwsCompact::from_str(&token).expect("Failed to parse jwt");
let token: UserAuthToken = token_unverified
.validate_embeded()
.map(|j| j.into_inner())
.expect("Embedded jwk not found");
let jws_verifier =
JwsEs256Verifier::try_from(jwt.get_jwk_pubkey().expect("No pubkey in token"))
.expect("Unable to build verifier");
let token: UserAuthToken = jws_verifier
.verify(&jwt)
.map(|jws| jws.from_json::<UserAuthToken>().expect("Invalid json"))
.expect("Unable extract uat");
let sessions = rsclient
.idm_account_list_user_auth_token("demo_account")
@ -1719,12 +1729,17 @@ async fn test_server_user_auth_reauthentication(rsclient: KanidmClient) {
.get_token()
.await
.expect("Must have a bearer token");
let jwtu = JwsUnverified::from_str(&token).expect("Failed to parse jwsu");
let uat: UserAuthToken = jwtu
.validate_embeded()
.map(|jws| jws.into_inner())
.expect("Unable to open up token.");
let jwt = JwsCompact::from_str(&token).expect("Failed to parse jwt");
let jws_verifier =
JwsEs256Verifier::try_from(jwt.get_jwk_pubkey().expect("No pubkey in token"))
.expect("Unable to build verifier");
let uat: UserAuthToken = jws_verifier
.verify(&jwt)
.map(|jws| jws.from_json::<UserAuthToken>().expect("Invalid json"))
.expect("Unable extract uat");
let now = time::OffsetDateTime::now_utc();
assert!(!uat.purpose_readwrite_active(now));
@ -1754,12 +1769,17 @@ async fn test_server_user_auth_reauthentication(rsclient: KanidmClient) {
.get_token()
.await
.expect("Must have a bearer token");
let jwtu = JwsUnverified::from_str(&token).expect("Failed to parse jwsu");
let uat: UserAuthToken = jwtu
.validate_embeded()
.map(|jws| jws.into_inner())
.expect("Unable to open up token.");
let jwt = JwsCompact::from_str(&token).expect("Failed to parse jwt");
let jws_verifier =
JwsEs256Verifier::try_from(jwt.get_jwk_pubkey().expect("No pubkey in token"))
.expect("Unable to build verifier");
let uat: UserAuthToken = jws_verifier
.verify(&jwt)
.map(|jws| jws.from_json::<UserAuthToken>().expect("Invalid json"))
.expect("Unable extract uat");
let now = time::OffsetDateTime::now_utc();
eprintln!("{:?} {:?}", now, uat.purpose);
@ -1839,10 +1859,15 @@ async fn start_password_session(
_ => panic!("Failed to extract jwt"),
};
let jwt = JwsUnverified::from_str(&jwt).expect("Failed to parse jwt");
let uat: UserAuthToken = jwt
.validate_embeded()
.map(|jws| jws.into_inner())
let jwt = JwsCompact::from_str(&jwt).expect("Failed to parse jwt");
let jws_verifier =
JwsEs256Verifier::try_from(jwt.get_jwk_pubkey().expect("No pubkey in token"))
.expect("Unable to build verifier");
let uat: UserAuthToken = jws_verifier
.verify(&jwt)
.map(|jws| jws.from_json::<UserAuthToken>().expect("Invalid json"))
.expect("Unable extract uat");
Ok(uat)

View file

@ -1,4 +1,4 @@
use compact_jwt::JwsUnverified;
use compact_jwt::{JwsCompact, JwsEs256Verifier, JwsVerifier};
use kanidm_client::KanidmClient;
use kanidm_proto::internal::ScimSyncToken;
use kanidmd_testkit::{ADMIN_TEST_PASSWORD, ADMIN_TEST_USER};
@ -75,12 +75,19 @@ async fn test_sync_account_lifecycle(rsclient: KanidmClient) {
.await
.expect("Failed to generate token");
let token_unverified = JwsUnverified::from_str(&token).expect("Failed to parse apitoken");
let token_unverified = JwsCompact::from_str(&token).expect("Failed to parse apitoken");
let token: ScimSyncToken = token_unverified
.validate_embeded()
.map(|j| j.into_inner())
.expect("Embedded jwk not found");
let jws_verifier = JwsEs256Verifier::try_from(
token_unverified
.get_jwk_pubkey()
.expect("No pubkey in token"),
)
.expect("Unable to build verifier");
let token = jws_verifier
.verify(&token_unverified)
.map(|jws| jws.from_json::<ScimSyncToken>().expect("Invalid json"))
.expect("Unable verify token");
println!("{:?}", token);

View file

@ -2,7 +2,7 @@ use std::env;
use std::str::FromStr;
use async_recursion::async_recursion;
use compact_jwt::{Jws, JwsUnverified};
use compact_jwt::{JwsCompact, JwsEs256Verifier, JwsVerifier, JwtError};
use dialoguer::theme::ColorfulTheme;
use dialoguer::{Confirm, Select};
use kanidm_client::{KanidmClient, KanidmClientBuilder};
@ -198,7 +198,7 @@ impl CommonOpt {
}
};
let jwtu = match JwsUnverified::from_str(&token) {
let jwsc = match JwsCompact::from_str(&token) {
Ok(jwtu) => jwtu,
Err(e) => {
error!("Unable to parse token - {:?}", e);
@ -207,10 +207,25 @@ impl CommonOpt {
};
// Is the token (probably) valid?
match jwtu
.validate_embeded()
.map(|jws: Jws<UserAuthToken>| jws.into_inner())
{
let jws_verifier = if let Some(pub_jwk) = jwsc.get_jwk_pubkey() {
match JwsEs256Verifier::try_from(pub_jwk) {
Ok(verifier) => verifier,
Err(err) => {
error!(?err, "Unable to configure jws verifier");
return Err(ToClientError::Other);
}
}
} else {
error!("Unable to access token public key");
return Err(ToClientError::Other);
};
match jws_verifier.verify(&jwsc).and_then(|jws| {
jws.from_json::<UserAuthToken>().map_err(|serde_err| {
error!(?serde_err);
JwtError::InvalidJwt
})
}) {
Ok(uat) => {
let now_utc = time::OffsetDateTime::now_utc();
if let Some(exp) = uat.expiry {

View file

@ -5,7 +5,7 @@ use std::io::{self, BufReader, BufWriter, ErrorKind, IsTerminal, Write};
use std::path::PathBuf;
use std::str::FromStr;
use compact_jwt::{Jws, JwsUnverified};
use compact_jwt::{JwsCompact, JwsEs256Verifier, JwsVerifier, JwtError};
use dialoguer::theme::ColorfulTheme;
use dialoguer::Select;
use kanidm_client::{ClientError, KanidmClient};
@ -319,13 +319,36 @@ async fn process_auth_state(
// Add our new one
let (spn, tonk) = match client.get_token().await {
Some(t) => {
let tonk = match JwsUnverified::from_str(&t).and_then(|jwtu| {
jwtu.validate_embeded()
.map(|jws: Jws<UserAuthToken>| jws.into_inner())
let jwsc = match JwsCompact::from_str(&t) {
Ok(j) => j,
Err(err) => {
error!(?err, "Unable to parse token");
std::process::exit(1);
}
};
let jws_verifier = if let Some(pub_jwk) = jwsc.get_jwk_pubkey() {
match JwsEs256Verifier::try_from(pub_jwk) {
Ok(verifier) => verifier,
Err(err) => {
error!(?err, "Unable to configure jws verifier");
std::process::exit(1);
}
}
} else {
error!("Unable to access token public key");
std::process::exit(1);
};
let tonk = match jws_verifier.verify(&jwsc).and_then(|jws| {
jws.from_json::<UserAuthToken>().map_err(|serde_err| {
error!(?serde_err);
JwtError::InvalidJwt
})
}) {
Ok(uat) => uat,
Err(e) => {
error!("Unable to parse token - {:?}", e);
Err(err) => {
error!(?err, "Unable to verify token signature");
std::process::exit(1);
}
};
@ -479,16 +502,35 @@ impl LogoutOpt {
}
// Server acked the logout, lets proceed with the local cleanup now.
let jwtu = match JwsUnverified::from_str(&token) {
Ok(value) => value,
Err(e) => {
error!(?e, "Unable to parse token from str");
let jwsc = match JwsCompact::from_str(&token) {
Ok(j) => j,
Err(err) => {
error!(?err, "Unable to parse token");
std::process::exit(1);
}
};
let uat: UserAuthToken = match jwtu.validate_embeded() {
Ok(jwt) => jwt.into_inner(),
let jws_verifier = if let Some(pub_jwk) = jwsc.get_jwk_pubkey() {
match JwsEs256Verifier::try_from(pub_jwk) {
Ok(verifier) => verifier,
Err(err) => {
error!(?err, "Unable to configure jws verifier");
std::process::exit(1);
}
}
} else {
error!("Unable to access token public key");
std::process::exit(1);
};
let uat = match jws_verifier.verify(&jwsc).and_then(|jws| {
jws.from_json::<UserAuthToken>().map_err(|serde_err| {
error!(?serde_err);
JwtError::InvalidJwt
})
}) {
Ok(uat) => uat,
Err(e) => {
error!(?e, "Unable to verify token signature, may be corrupt");
std::process::exit(1);
@ -532,20 +574,32 @@ impl SessionOpt {
})
.into_iter()
.filter_map(|(u, t)| {
let jwtu = JwsUnverified::from_str(&t)
let jwsc = JwsCompact::from_str(&t)
.map_err(|e| {
error!(?e, "Unable to parse token from str");
})
.ok()?;
jwtu.validate_embeded()
let jws_verifier = jwsc.get_jwk_pubkey().and_then(|pub_jwk| {
JwsEs256Verifier::try_from(pub_jwk)
.map_err(|e| {
error!(?e, "Unable to configure jws verifier");
})
.ok()
})?;
jws_verifier
.verify(&jwsc)
.and_then(|jws| {
jws.from_json::<UserAuthToken>().map_err(|serde_err| {
error!(?serde_err);
JwtError::InvalidJwt
})
})
.map_err(|e| {
error!(?e, "Unable to verify token signature, may be corrupt");
})
.map(|jwt| {
let uat = jwt.into_inner();
(u, (t, uat))
})
.map(|uat| (u, (t, uat)))
.ok()
})
.collect()