Better WebAuthn and other error responses (#2608)

This commit is contained in:
James Hodgkinson 2024-06-05 09:57:16 +10:00 committed by GitHub
parent f779c4ebf7
commit 3c01a96348
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
29 changed files with 257 additions and 99 deletions

View file

@ -28,19 +28,17 @@ use compact_jwt::Jwk;
use kanidm_proto::constants::uri::V1_AUTH_VALID;
use kanidm_proto::constants::{
APPLICATION_JSON, ATTR_DOMAIN_DISPLAY_NAME, ATTR_DOMAIN_LDAP_BASEDN, ATTR_DOMAIN_SSID,
ATTR_ENTRY_MANAGED_BY, ATTR_KEY_ACTION_REVOKE, ATTR_LDAP_ALLOW_UNIX_PW_BIND, ATTR_NAME,
CLIENT_TOKEN_CACHE, KOPID, KVERSION,
ATTR_DOMAIN_DISPLAY_NAME, ATTR_DOMAIN_LDAP_BASEDN, ATTR_DOMAIN_SSID, ATTR_ENTRY_MANAGED_BY,
ATTR_KEY_ACTION_REVOKE, ATTR_LDAP_ALLOW_UNIX_PW_BIND, ATTR_NAME, CLIENT_TOKEN_CACHE, KOPID,
KVERSION,
};
use kanidm_proto::internal::*;
use kanidm_proto::v1::*;
use reqwest::header::CONTENT_TYPE;
use reqwest::Response;
pub use reqwest::StatusCode;
use serde::de::DeserializeOwned;
use serde::{Deserialize, Serialize};
use serde_json::error::Error as SerdeJsonError;
use serde_json::json;
use tokio::sync::{Mutex, RwLock};
use url::Url;
use uuid::Uuid;
@ -704,13 +702,7 @@ impl KanidmClient {
dest: &str,
request: &R,
) -> Result<T, ClientError> {
let req_string = serde_json::to_string(request).map_err(ClientError::JsonEncode)?;
let response = self
.client
.post(self.make_url(dest))
.body(req_string)
.header(CONTENT_TYPE, APPLICATION_JSON);
let response = self.client.post(self.make_url(dest)).json(request);
let response = response
.send()
@ -744,13 +736,8 @@ impl KanidmClient {
request: R,
) -> Result<T, ClientError> {
trace!("perform_auth_post_request connecting to {}", dest);
let req_string = serde_json::to_string(&request).map_err(ClientError::JsonEncode)?;
let response = self
.client
.post(self.make_url(dest))
.body(req_string)
.header(CONTENT_TYPE, APPLICATION_JSON);
let response = self.client.post(self.make_url(dest)).json(&request);
// If we have a bearer token, set it now.
let response = {
@ -794,12 +781,7 @@ impl KanidmClient {
dest: &str,
request: R,
) -> Result<T, ClientError> {
let req_string = serde_json::to_string(&request).map_err(ClientError::JsonEncode)?;
let response = self
.client
.post(self.make_url(dest))
.body(req_string)
.header(CONTENT_TYPE, APPLICATION_JSON);
let response = self.client.post(self.make_url(dest)).json(&request);
let response = {
let tguard = self.bearer_token.read().await;
@ -841,12 +823,8 @@ impl KanidmClient {
dest: &str,
request: R,
) -> Result<T, ClientError> {
let req_string = serde_json::to_string(&request).map_err(ClientError::JsonEncode)?;
let response = self.client.put(self.make_url(dest)).json(&request);
let response = self
.client
.put(self.make_url(dest))
.header(CONTENT_TYPE, APPLICATION_JSON);
let response = {
let tguard = self.bearer_token.read().await;
if let Some(token) = &(*tguard) {
@ -857,7 +835,6 @@ impl KanidmClient {
};
let response = response
.body(req_string)
.send()
.await
.map_err(|err| self.handle_response_error(err))?;
@ -892,12 +869,7 @@ impl KanidmClient {
dest: &str,
request: R,
) -> Result<T, ClientError> {
let req_string = serde_json::to_string(&request).map_err(ClientError::JsonEncode)?;
let response = self
.client
.patch(self.make_url(dest))
.body(req_string)
.header(CONTENT_TYPE, APPLICATION_JSON);
let response = self.client.patch(self.make_url(dest)).json(&request);
let response = {
let tguard = self.bearer_token.read().await;
@ -980,7 +952,7 @@ impl KanidmClient {
.client
.delete(self.make_url(dest))
// empty-ish body that makes the parser happy
.json(&json!([]));
.json(&serde_json::json!([]));
let response = {
let tguard = self.bearer_token.read().await;

View file

@ -32,4 +32,4 @@ url = { workspace = true, features = ["serde"] }
urlencoding = { workspace = true }
utoipa = { workspace = true }
uuid = { workspace = true, features = ["serde"] }
webauthn-rs-proto = { workspace = true }
webauthn-rs-proto = { workspace = true }

View file

@ -1,3 +1,5 @@
use std::fmt::{Display, Formatter};
use serde::{Deserialize, Serialize};
use utoipa::ToSchema;
use uuid::Uuid;
@ -127,6 +129,7 @@ pub enum OperationError {
// Credential Update Errors
CU0001WebauthnAttestationNotTrusted,
CU0002WebauthnRegistrationError,
CU0003WebauthnUserNotVerified,
// ValueSet errors
VS0001IncomingReplSshPublicKey,
// Value Errors
@ -203,3 +206,160 @@ impl PartialEq for OperationError {
std::mem::discriminant(self) == std::mem::discriminant(other)
}
}
impl Display for OperationError {
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
let mut output = format!("{:?}", self)
.split("::")
.last()
.unwrap_or("")
.to_string();
if let Some(msg) = self.message() {
output += &format!(" - {}", msg);
};
f.write_str(&output)
}
}
impl OperationError {
/// Return the message associated with the error if there is one.
fn message(&self) -> Option<&'static str> {
match self {
OperationError::SessionExpired => None,
OperationError::EmptyRequest => None,
OperationError::Backend => None,
OperationError::NoMatchingEntries => None,
OperationError::NoMatchingAttributes => None,
OperationError::CorruptedEntry(_) => None,
OperationError::CorruptedIndex(_) => None,
OperationError::ConsistencyError(_) => None,
OperationError::SchemaViolation(_) => None,
OperationError::Plugin(_) => None,
OperationError::FilterGeneration => None,
OperationError::FilterUuidResolution => None,
OperationError::InvalidAttributeName(_) => None,
OperationError::InvalidAttribute(_) => None,
OperationError::InvalidDbState => None,
OperationError::InvalidCacheState => None,
OperationError::InvalidValueState => None,
OperationError::InvalidEntryId => None,
OperationError::InvalidRequestState => None,
OperationError::InvalidSyncState => None,
OperationError::InvalidState => None,
OperationError::InvalidEntryState => None,
OperationError::InvalidUuid => None,
OperationError::InvalidReplChangeId => None,
OperationError::InvalidAcpState(_) => None,
OperationError::InvalidSchemaState(_) => None,
OperationError::InvalidAccountState(_) => None,
OperationError::MissingEntries => None,
OperationError::ModifyAssertionFailed => None,
OperationError::BackendEngine => None,
OperationError::SqliteError => None,
OperationError::FsError => None,
OperationError::SerdeJsonError => None,
OperationError::SerdeCborError => None,
OperationError::AccessDenied => None,
OperationError::NotAuthenticated => None,
OperationError::NotAuthorised => None,
OperationError::InvalidAuthState(_) => None,
OperationError::InvalidSessionState => None,
OperationError::SystemProtectedObject => None,
OperationError::SystemProtectedAttribute => None,
OperationError::PasswordQuality(_) => None,
OperationError::CryptographyError => None,
OperationError::ResourceLimit => None,
OperationError::QueueDisconnected => None,
OperationError::Webauthn => None,
OperationError::Wait(_) => None,
OperationError::ReplReplayFailure => None,
OperationError::ReplEntryNotChanged => None,
OperationError::ReplInvalidRUVState => None,
OperationError::ReplDomainLevelUnsatisfiable => None,
OperationError::ReplDomainUuidMismatch => None,
OperationError::ReplServerUuidSplitDataState => None,
OperationError::TransactionAlreadyCommitted => None,
OperationError::ValueDenyName => None,
OperationError::CU0002WebauthnRegistrationError => None,
OperationError::CU0003WebauthnUserNotVerified => Some("User Verification bit not set while registering credential, you may need to configure a PIN on this device."),
OperationError::CU0001WebauthnAttestationNotTrusted => None,
OperationError::VS0001IncomingReplSshPublicKey => None,
OperationError::VL0001ValueSshPublicKeyString => None,
OperationError::SC0001IncomingSshPublicKey => None,
OperationError::MG0001InvalidReMigrationLevel => None,
OperationError::MG0002RaiseDomainLevelExceedsMaximum => None,
OperationError::MG0003ServerPhaseInvalidForMigration => None,
OperationError::DB0001MismatchedRestoreVersion => None,
OperationError::DB0002MismatchedRestoreVersion => None,
OperationError::MG0004DomainLevelInDevelopment => None,
OperationError::MG0005GidConstraintsNotMet => None,
OperationError::KP0001KeyProviderNotLoaded => None,
OperationError::KP0002KeyProviderInvalidClass => None,
OperationError::KP0003KeyProviderInvalidType => None,
OperationError::KP0004KeyProviderMissingAttributeName => None,
OperationError::KP0005KeyProviderDuplicate => None,
OperationError::KP0006KeyObjectJwtEs256Generation => None,
OperationError::KP0007KeyProviderDefaultNotAvailable => None,
OperationError::KP0008KeyObjectMissingUuid => None,
OperationError::KP0009KeyObjectPrivateToDer => None,
OperationError::KP0010KeyObjectSignerToVerifier => None,
OperationError::KP0011KeyObjectMissingClass => None,
OperationError::KP0012KeyObjectMissingProvider => None,
OperationError::KP0012KeyProviderNotLoaded => None,
OperationError::KP0013KeyObjectJwsEs256DerInvalid => None,
OperationError::KP0014KeyObjectSignerToVerifier => None,
OperationError::KP0015KeyObjectJwsEs256DerInvalid => None,
OperationError::KP0016KeyObjectJwsEs256DerInvalid => None,
OperationError::KP0017KeyProviderNoSuchKey => None,
OperationError::KP0018KeyProviderNoSuchKey => None,
OperationError::KP0019KeyProviderUnsupportedAlgorithm => None,
OperationError::KP0020KeyObjectNoActiveSigningKeys => None,
OperationError::KP0021KeyObjectJwsEs256Signature => None,
OperationError::KP0022KeyObjectJwsNotAssociated => None,
OperationError::KP0023KeyObjectJwsKeyRevoked => None,
OperationError::KP0024KeyObjectJwsInvalid => None,
OperationError::KP0025KeyProviderNotAvailable => None,
OperationError::KP0026KeyObjectNoSuchKey => None,
OperationError::KP0027KeyObjectPublicToDer => None,
OperationError::KP0028KeyObjectImportJwsEs256DerInvalid => None,
OperationError::KP0029KeyObjectSignerToVerifier => None,
OperationError::KP0030KeyObjectPublicToDer => None,
OperationError::KP0031KeyObjectNotFound => None,
OperationError::KP0032KeyProviderNoSuchKey => None,
OperationError::KP0033KeyProviderNoSuchKey => None,
OperationError::KP0034KeyProviderUnsupportedAlgorithm => None,
OperationError::KP0035KeyObjectJweA128GCMGeneration => None,
OperationError::KP0036KeyObjectPrivateToBytes => None,
OperationError::KP0037KeyObjectImportJweA128GCMInvalid => None,
OperationError::KP0038KeyObjectImportJweA128GCMInvalid => None,
OperationError::KP0039KeyObjectJweNotAssociated => None,
OperationError::KP0040KeyObjectJweInvalid => None,
OperationError::KP0041KeyObjectJweRevoked => None,
OperationError::KP0042KeyObjectNoActiveEncryptionKeys => None,
OperationError::KP0043KeyObjectJweA128GCMEncryption => None,
OperationError::KP0044KeyObjectJwsPublicJwk => None,
OperationError::PL0001GidOverlapsSystemRange => None,
}
}
}
#[test]
fn test_operationerror_as_nice_string() {
assert_eq!(
OperationError::CU0001WebauthnAttestationNotTrusted.to_string(),
"CU0001WebauthnAttestationNotTrusted".to_string()
);
assert_eq!(
OperationError::CU0003WebauthnUserNotVerified.to_string(),
"CU0003WebauthnUserNotVerified - User Verification bit not set while registering credential, you may need to configure a PIN on this device.".to_string()
);
assert_eq!(
OperationError::SessionExpired.to_string(),
"SessionExpired".to_string()
);
assert_eq!(
OperationError::CorruptedEntry(12345).to_string(),
"CorruptedEntry(12345)".to_string()
);
}

View file

@ -128,7 +128,7 @@ echo "Creating the ${OAUTH2_RP_ID} OAuth2 RP Supplemental Scope Map"
${KANIDM} system oauth2 update-sup-scope-map "${OAUTH2_RP_ID}" "${TEST_GROUP}" admin -D "${IDM_ADMIN_USER}"
echo "Creating a claim map for RS ${OAUTH2_RP_ID}"
${KANIDM} system oauth2 update-claim-map "${OAUTH2_RP_ID}" testclaim "${TEST_GROUP}" foo bar
${KANIDM} system oauth2 update-claim-map "${OAUTH2_RP_ID}" testclaim "${TEST_GROUP}" foo bar -D "${IDM_ADMIN_USER}"
echo "Creating the OAuth2 RP Secondary Supplemental Crab-baite Scope Map.... wait, no that's not a thing."

View file

@ -277,6 +277,8 @@ impl Modify for SecurityAddon {
response_schema::Result,
// terrible workaround for other things
response_schema::ScimEntry,
// terrible workaround for other things
response_schema::Jwk,
WebError,
)

View file

@ -91,3 +91,6 @@ pub(crate) struct Result {}
#[derive(Debug, Clone, ToSchema)]
// TODO: this should be handled elsewhere, but ... I don't know how to make it possible in utoipa
pub(crate) struct ScimEntry {}
#[derive(Debug, Clone, ToSchema)]
pub(crate) struct Jwk {}

View file

@ -40,12 +40,11 @@ impl IntoResponse for WebError {
(StatusCode::INTERNAL_SERVER_ERROR, inner).into_response()
}
WebError::OperationError(inner) => {
let (response_code, headers) = match &inner {
let (code, headers) = match &inner {
OperationError::NotAuthenticated | OperationError::SessionExpired => {
// https://datatracker.ietf.org/doc/html/rfc7235#section-4.1
(
StatusCode::UNAUTHORIZED,
// Some([("WWW-Authenticate", "Bearer")]),
Some([("WWW-Authenticate", "Bearer"); 1]),
)
}
@ -55,14 +54,17 @@ impl IntoResponse for WebError {
OperationError::NoMatchingEntries => (StatusCode::NOT_FOUND, None),
OperationError::PasswordQuality(_)
| OperationError::EmptyRequest
| OperationError::SchemaViolation(_) => (StatusCode::BAD_REQUEST, None),
| OperationError::SchemaViolation(_)
| OperationError::CU0003WebauthnUserNotVerified => {
(StatusCode::BAD_REQUEST, None)
}
_ => (StatusCode::INTERNAL_SERVER_ERROR, None),
};
let body =
serde_json::to_string(&inner).unwrap_or_else(|_err| format!("{:?}", inner));
let body = serde_json::to_string(&inner).unwrap_or(inner.to_string());
match headers {
Some(headers) => (response_code, headers, body).into_response(),
None => (response_code, body).into_response(),
Some(headers) => (code, headers, body).into_response(),
None => (code, body).into_response(),
}
}
}

View file

@ -2099,7 +2099,12 @@ impl<'a> IdmServerCredUpdateTransaction<'a> {
.finish_passkey_registration(reg, pk_reg)
.map_err(|e| {
error!(eclass=?e, emsg=%e, "Unable to complete passkey registration");
OperationError::Webauthn
match e {
WebauthnError::UserNotVerified => {
OperationError::CU0003WebauthnUserNotVerified
}
_ => OperationError::CU0002WebauthnRegistrationError,
}
});
// The reg is done. Clean up state before returning errors.
@ -2220,13 +2225,16 @@ impl<'a> IdmServerCredUpdateTransaction<'a> {
.webauthn
.finish_attested_passkey_registration(reg, pk_reg)
.map_err(|e| {
error!(eclass=?e, emsg=%e, "Unable to complete passkey registration");
error!(eclass=?e, emsg=%e, "Unable to complete attested passkey registration");
match e {
WebauthnError::AttestationChainNotTrusted(_)
| WebauthnError::AttestationNotVerifiable => {
OperationError::CU0001WebauthnAttestationNotTrusted
}
},
WebauthnError::UserNotVerified => {
OperationError::CU0003WebauthnUserNotVerified
},
_ => OperationError::CU0002WebauthnRegistrationError,
}
});

View file

@ -42,7 +42,7 @@ async fn get_webdriver_client() -> fantoccini::Client {
Err(_) => {
// trying the default chromedriver port
eprintln!("Couldn't connect on 4444, trying 9515");
fantoccini::ClientBuilder::new(hyper_tls::HttpsConnector::new())
fantoccini::ClientBuilder::native()
.connect("http://localhost:9515")
.await
.unwrap()
@ -56,7 +56,7 @@ async fn get_webdriver_client() -> fantoccini::Client {
}
});
let cap: Capabilities = serde_json::from_value(cap).unwrap();
fantoccini::ClientBuilder::new(hyper_tls::HttpsConnector::new())
fantoccini::ClientBuilder::native()
.capabilities(cap)
.connect("http://localhost:9515")
.await

Binary file not shown.

Binary file not shown.

View file

@ -232,19 +232,19 @@ function addBorrowedObject(obj) {
}
function __wbg_adapter_38(arg0, arg1, arg2) {
try {
wasm._dyn_core__ops__function__FnMut___A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h5869fca7f8c0640c(arg0, arg1, addBorrowedObject(arg2));
wasm._dyn_core__ops__function__FnMut___A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h310d1129d0c292ca(arg0, arg1, addBorrowedObject(arg2));
} finally {
heap[stack_pointer++] = undefined;
}
}
function __wbg_adapter_41(arg0, arg1, arg2) {
wasm._dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h1aa6653248d58742(arg0, arg1, addHeapObject(arg2));
wasm._dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h027c38da75b21f7b(arg0, arg1, addHeapObject(arg2));
}
function __wbg_adapter_44(arg0, arg1, arg2) {
try {
wasm._dyn_core__ops__function__FnMut___A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__haed7e087111b3b75(arg0, arg1, addBorrowedObject(arg2));
wasm._dyn_core__ops__function__FnMut___A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__hea5c5c7c205dc9e3(arg0, arg1, addBorrowedObject(arg2));
} finally {
heap[stack_pointer++] = undefined;
}
@ -686,6 +686,13 @@ function __wbg_get_imports() {
getInt32Memory0()[arg0 / 4 + 1] = len1;
getInt32Memory0()[arg0 / 4 + 0] = ptr1;
}, arguments) };
imports.wbg.__wbg_href_2edbae9e92cdfeff = function(arg0, arg1) {
const ret = getObject(arg1).href;
const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
const len1 = WASM_VECTOR_LEN;
getInt32Memory0()[arg0 / 4 + 1] = len1;
getInt32Memory0()[arg0 / 4 + 0] = ptr1;
};
imports.wbg.__wbg_parentNode_6be3abff20e1a5fb = function(arg0) {
const ret = getObject(arg0).parentNode;
return isLikeNone(ret) ? 0 : addHeapObject(ret);
@ -755,13 +762,6 @@ function __wbg_get_imports() {
imports.wbg.__wbg_pushState_b8e8d346f8bb33fd = function() { return handleError(function (arg0, arg1, arg2, arg3, arg4, arg5) {
getObject(arg0).pushState(getObject(arg1), getStringFromWasm0(arg2, arg3), arg4 === 0 ? undefined : getStringFromWasm0(arg4, arg5));
}, arguments) };
imports.wbg.__wbg_href_2edbae9e92cdfeff = function(arg0, arg1) {
const ret = getObject(arg1).href;
const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
const len1 = WASM_VECTOR_LEN;
getInt32Memory0()[arg0 / 4 + 1] = len1;
getInt32Memory0()[arg0 / 4 + 0] = ptr1;
};
imports.wbg.__wbg_headers_abb199c3be8d817c = function(arg0) {
const ret = getObject(arg0).headers;
return addHeapObject(ret);
@ -963,16 +963,16 @@ function __wbg_get_imports() {
const ret = wasm.memory;
return addHeapObject(ret);
};
imports.wbg.__wbindgen_closure_wrapper1260 = function(arg0, arg1, arg2) {
const ret = makeMutClosure(arg0, arg1, 582, __wbg_adapter_38);
imports.wbg.__wbindgen_closure_wrapper1262 = function(arg0, arg1, arg2) {
const ret = makeMutClosure(arg0, arg1, 585, __wbg_adapter_38);
return addHeapObject(ret);
};
imports.wbg.__wbindgen_closure_wrapper1368 = function(arg0, arg1, arg2) {
const ret = makeMutClosure(arg0, arg1, 630, __wbg_adapter_41);
imports.wbg.__wbindgen_closure_wrapper1369 = function(arg0, arg1, arg2) {
const ret = makeMutClosure(arg0, arg1, 631, __wbg_adapter_41);
return addHeapObject(ret);
};
imports.wbg.__wbindgen_closure_wrapper1399 = function(arg0, arg1, arg2) {
const ret = makeMutClosure(arg0, arg1, 647, __wbg_adapter_44);
imports.wbg.__wbindgen_closure_wrapper1400 = function(arg0, arg1, arg2) {
const ret = makeMutClosure(arg0, arg1, 648, __wbg_adapter_44);
return addHeapObject(ret);
};

View file

@ -239,19 +239,19 @@ 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__hde2cadb5f0b706d2(arg0, arg1, addBorrowedObject(arg2));
wasm._dyn_core__ops__function__FnMut___A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h17ac9e19f3ddff30(arg0, arg1, addBorrowedObject(arg2));
} finally {
heap[stack_pointer++] = undefined;
}
}
function __wbg_adapter_51(arg0, arg1, arg2) {
wasm._dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h1aa6653248d58742(arg0, arg1, addHeapObject(arg2));
wasm._dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h027c38da75b21f7b(arg0, arg1, addHeapObject(arg2));
}
function __wbg_adapter_54(arg0, arg1, arg2) {
try {
wasm._dyn_core__ops__function__FnMut___A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h1adeb92879459ba7(arg0, arg1, addBorrowedObject(arg2));
wasm._dyn_core__ops__function__FnMut___A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h6d223bcdfbf7f3c4(arg0, arg1, addBorrowedObject(arg2));
} finally {
heap[stack_pointer++] = undefined;
}
@ -630,6 +630,12 @@ function __wbg_get_imports() {
imports.wbg.__wbg_focus_39d4b8ba8ff9df14 = function() { return handleError(function (arg0) {
getObject(arg0).focus();
}, arguments) };
imports.wbg.__wbg_add_dcb05a8ba423bdac = function() { return handleError(function (arg0, arg1, arg2) {
getObject(arg0).add(getStringFromWasm0(arg1, arg2));
}, arguments) };
imports.wbg.__wbg_remove_698118fb25ab8150 = function() { return handleError(function (arg0, arg1, arg2) {
getObject(arg0).remove(getStringFromWasm0(arg1, arg2));
}, arguments) };
imports.wbg.__wbg_href_2edbae9e92cdfeff = function(arg0, arg1) {
const ret = getObject(arg1).href;
const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
@ -637,12 +643,6 @@ function __wbg_get_imports() {
getInt32Memory0()[arg0 / 4 + 1] = len1;
getInt32Memory0()[arg0 / 4 + 0] = ptr1;
};
imports.wbg.__wbg_add_dcb05a8ba423bdac = function() { return handleError(function (arg0, arg1, arg2) {
getObject(arg0).add(getStringFromWasm0(arg1, arg2));
}, arguments) };
imports.wbg.__wbg_remove_698118fb25ab8150 = function() { return handleError(function (arg0, arg1, arg2) {
getObject(arg0).remove(getStringFromWasm0(arg1, arg2));
}, arguments) };
imports.wbg.__wbg_href_706b235ecfe6848c = function() { return handleError(function (arg0, arg1) {
const ret = getObject(arg1).href;
const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
@ -1101,7 +1101,7 @@ function __wbg_get_imports() {
const ret = wasm.memory;
return addHeapObject(ret);
};
imports.wbg.__wbindgen_closure_wrapper1415 = function(arg0, arg1, arg2) {
imports.wbg.__wbindgen_closure_wrapper1416 = function(arg0, arg1, arg2) {
const ret = makeMutClosure(arg0, arg1, 538, __wbg_adapter_48);
return addHeapObject(ret);
};

View file

@ -232,7 +232,7 @@ function makeMutClosure(arg0, arg1, dtor, f) {
return real;
}
function __wbg_adapter_48(arg0, arg1) {
wasm._dyn_core__ops__function__FnMut_____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h96f7c6547f3957ee(arg0, arg1);
wasm._dyn_core__ops__function__FnMut_____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h4032d96dca0d1c1e(arg0, arg1);
}
let stack_pointer = 128;
@ -244,19 +244,19 @@ function addBorrowedObject(obj) {
}
function __wbg_adapter_51(arg0, arg1, arg2) {
try {
wasm._dyn_core__ops__function__FnMut___A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__hb105de8e9efc9ac9(arg0, arg1, addBorrowedObject(arg2));
wasm._dyn_core__ops__function__FnMut___A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h73c5fab6b46e1b10(arg0, arg1, addBorrowedObject(arg2));
} finally {
heap[stack_pointer++] = undefined;
}
}
function __wbg_adapter_54(arg0, arg1, arg2) {
wasm._dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h1aa6653248d58742(arg0, arg1, addHeapObject(arg2));
wasm._dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h027c38da75b21f7b(arg0, arg1, addHeapObject(arg2));
}
function __wbg_adapter_57(arg0, arg1, arg2) {
try {
wasm._dyn_core__ops__function__FnMut___A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__he6ae5361a1f44a8b(arg0, arg1, addBorrowedObject(arg2));
wasm._dyn_core__ops__function__FnMut___A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h54846433116134af(arg0, arg1, addBorrowedObject(arg2));
} finally {
heap[stack_pointer++] = undefined;
}
@ -658,13 +658,6 @@ function __wbg_get_imports() {
const ret = getObject(arg0).get(getStringFromWasm0(arg1, arg2));
return addHeapObject(ret);
};
imports.wbg.__wbg_href_2edbae9e92cdfeff = function(arg0, arg1) {
const ret = getObject(arg1).href;
const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
const len1 = WASM_VECTOR_LEN;
getInt32Memory0()[arg0 / 4 + 1] = len1;
getInt32Memory0()[arg0 / 4 + 0] = ptr1;
};
imports.wbg.__wbg_addEventListener_4283b15b4f039eb5 = function() { return handleError(function (arg0, arg1, arg2, arg3, arg4) {
getObject(arg0).addEventListener(getStringFromWasm0(arg1, arg2), getObject(arg3), getObject(arg4));
}, arguments) };
@ -677,6 +670,13 @@ function __wbg_get_imports() {
imports.wbg.__wbg_remove_698118fb25ab8150 = function() { return handleError(function (arg0, arg1, arg2) {
getObject(arg0).remove(getStringFromWasm0(arg1, arg2));
}, arguments) };
imports.wbg.__wbg_href_2edbae9e92cdfeff = function(arg0, arg1) {
const ret = getObject(arg1).href;
const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
const len1 = WASM_VECTOR_LEN;
getInt32Memory0()[arg0 / 4 + 1] = len1;
getInt32Memory0()[arg0 / 4 + 0] = ptr1;
};
imports.wbg.__wbg_href_706b235ecfe6848c = function() { return handleError(function (arg0, arg1) {
const ret = getObject(arg1).href;
const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
@ -1148,20 +1148,20 @@ function __wbg_get_imports() {
const ret = wasm.memory;
return addHeapObject(ret);
};
imports.wbg.__wbindgen_closure_wrapper1348 = function(arg0, arg1, arg2) {
const ret = makeMutClosure(arg0, arg1, 692, __wbg_adapter_48);
imports.wbg.__wbindgen_closure_wrapper971 = function(arg0, arg1, arg2) {
const ret = makeMutClosure(arg0, arg1, 583, __wbg_adapter_48);
return addHeapObject(ret);
};
imports.wbg.__wbindgen_closure_wrapper3876 = function(arg0, arg1, arg2) {
const ret = makeMutClosure(arg0, arg1, 1949, __wbg_adapter_51);
imports.wbg.__wbindgen_closure_wrapper3891 = function(arg0, arg1, arg2) {
const ret = makeMutClosure(arg0, arg1, 1956, __wbg_adapter_51);
return addHeapObject(ret);
};
imports.wbg.__wbindgen_closure_wrapper3955 = function(arg0, arg1, arg2) {
const ret = makeMutClosure(arg0, arg1, 1975, __wbg_adapter_54);
imports.wbg.__wbindgen_closure_wrapper3970 = function(arg0, arg1, arg2) {
const ret = makeMutClosure(arg0, arg1, 1982, __wbg_adapter_54);
return addHeapObject(ret);
};
imports.wbg.__wbindgen_closure_wrapper3986 = function(arg0, arg1, arg2) {
const ret = makeMutClosure(arg0, arg1, 1992, __wbg_adapter_57);
imports.wbg.__wbindgen_closure_wrapper4001 = function(arg0, arg1, arg2) {
const ret = makeMutClosure(arg0, arg1, 1999, __wbg_adapter_57);
return addHeapObject(ret);
};

View file

@ -9,7 +9,7 @@ use kanidm_proto::internal::{Filter, Modify, ModifyList};
use kanidm_proto::v1::Entry;
use serde::de::DeserializeOwned;
use crate::RawOpt;
use crate::{OutputMode, RawOpt};
fn read_file<T: DeserializeOwned, P: AsRef<Path>>(path: P) -> Result<T, Box<dyn Error>> {
let f = File::open(path)?;
@ -36,13 +36,24 @@ impl RawOpt {
let filter: Filter = match serde_json::from_str(sopt.filter.as_str()) {
Ok(f) => f,
Err(e) => {
error!("Error -> {:?}", e);
error!("Error parsing filter -> {:?}", e);
return;
}
};
match client.search(filter).await {
Ok(rset) => rset.iter().for_each(|e| println!("{}", e)),
Ok(rset) => match sopt.commonopts.output_mode {
#[allow(clippy::expect_used)]
OutputMode::Json => {
println!(
"{}",
serde_json::to_string(&rset).expect("Failed to serialize entry!")
)
}
OutputMode::Text => {
rset.iter().for_each(|e| println!("{}", e));
}
},
Err(e) => error!("Error -> {:?}", e),
}
}