Refactor client lib to expose msgs, and improve the messages in plugins (#114)

Implements #100. This refactors our error types to be deserialiseable, and exposes these through the clienterror type with the status codes. There is probably still a lot of improvements here to be made, but they'll be shaken out as the client libs develop I think and we start to see what errors should be exposed.
This commit is contained in:
Firstyear 2019-10-10 13:17:32 +10:00 committed by GitHub
parent 09bc31e2f5
commit 6b0b2ad040
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 187 additions and 128 deletions

1
.gitignore vendored
View file

@ -5,3 +5,4 @@
/insecure
**/*.rs.bk
test.db
/vendor

View file

@ -12,15 +12,15 @@ use std::io::Read;
use kanidm_proto::v1::{
AuthCredential, AuthRequest, AuthResponse, AuthState, AuthStep, CreateRequest, DeleteRequest,
Entry, Filter, ModifyList, ModifyRequest, OperationResponse, SearchRequest, SearchResponse,
SetAuthCredential, SingleStringRequest, UserAuthToken, WhoamiResponse,
Entry, Filter, ModifyList, ModifyRequest, OperationError, OperationResponse, SearchRequest,
SearchResponse, SetAuthCredential, SingleStringRequest, UserAuthToken, WhoamiResponse,
};
use serde_json;
#[derive(Debug)]
pub enum ClientError {
Unauthorized,
Http(reqwest::StatusCode),
Http(reqwest::StatusCode, Option<OperationError>),
Transport(reqwest::Error),
AuthenticationFailed,
JsonParse,
@ -100,7 +100,7 @@ impl KanidmClient {
match response.status() {
reqwest::StatusCode::OK => {}
unexpect => return Err(ClientError::Http(unexpect)),
unexpect => return Err(ClientError::Http(unexpect, response.json().ok())),
}
// TODO: What about errors
@ -127,7 +127,7 @@ impl KanidmClient {
match response.status() {
reqwest::StatusCode::OK => {}
unexpect => return Err(ClientError::Http(unexpect)),
unexpect => return Err(ClientError::Http(unexpect, response.json().ok())),
}
// TODO: What about errors
@ -146,7 +146,7 @@ impl KanidmClient {
match response.status() {
reqwest::StatusCode::OK => {}
unexpect => return Err(ClientError::Http(unexpect)),
unexpect => return Err(ClientError::Http(unexpect, response.json().ok())),
}
// TODO: What about errors
@ -165,7 +165,7 @@ impl KanidmClient {
// Continue to process.
reqwest::StatusCode::OK => {}
reqwest::StatusCode::UNAUTHORIZED => return Ok(None),
unexpect => return Err(ClientError::Http(unexpect)),
unexpect => return Err(ClientError::Http(unexpect, response.json().ok())),
}
let r: WhoamiResponse = serde_json::from_str(response.text().unwrap().as_str()).unwrap();

View file

@ -17,6 +17,13 @@ pub enum SchemaError {
Corrupted,
}
#[derive(Serialize, Deserialize, Debug, PartialEq)]
pub enum PluginError {
AttrUnique(String),
Base(String),
ReferentialIntegrity(String),
}
#[derive(Serialize, Deserialize, Debug, PartialEq)]
pub enum OperationError {
EmptyRequest,
@ -25,20 +32,20 @@ pub enum OperationError {
CorruptedEntry(u64),
ConsistencyError(Vec<Result<(), ConsistencyError>>),
SchemaViolation(SchemaError),
Plugin,
Plugin(PluginError),
FilterGeneration,
FilterUUIDResolution,
InvalidAttributeName(String),
InvalidAttribute(&'static str),
InvalidAttribute(String),
InvalidDBState,
InvalidEntryID,
InvalidRequestState,
InvalidState,
InvalidEntryState,
InvalidUuid,
InvalidACPState(&'static str),
InvalidSchemaState(&'static str),
InvalidAccountState(&'static str),
InvalidACPState(String),
InvalidSchemaState(String),
InvalidAccountState(String),
BackendEngine,
SQLiteError, //(RusqliteError)
FsError,
@ -46,9 +53,10 @@ pub enum OperationError {
SerdeCborError,
AccessDenied,
NotAuthenticated,
InvalidAuthState(&'static str),
InvalidAuthState(String),
InvalidSessionState,
SystemProtectedObject,
SystemProtectedAttribute,
}
#[derive(Serialize, Deserialize, Debug, PartialEq)]
@ -62,7 +70,7 @@ pub enum ConsistencyError {
UuidNotUnique(String),
RefintNotUpheld(u64),
MemberOfInvalid(u64),
InvalidAttributeType(&'static str),
InvalidAttributeType(String),
DuplicateUniqueAttribute(String),
}

View file

@ -58,7 +58,7 @@ impl AccessControlSearch {
if !value.attribute_value_pres("class", &CLASS_ACS) {
audit_log!(audit, "class access_control_search not present.");
return Err(OperationError::InvalidACPState(
"Missing access_control_search",
"Missing access_control_search".to_string(),
));
}
@ -66,7 +66,9 @@ impl AccessControlSearch {
audit,
value
.get_ava_string("acp_search_attr")
.ok_or(OperationError::InvalidACPState("Missing acp_search_attr"))
.ok_or(OperationError::InvalidACPState(
"Missing acp_search_attr".to_string()
))
);
let acp = AccessControlProfile::try_from(audit, qs, value)?;
@ -111,7 +113,7 @@ impl AccessControlDelete {
if !value.attribute_value_pres("class", &CLASS_ACD) {
audit_log!(audit, "class access_control_delete not present.");
return Err(OperationError::InvalidACPState(
"Missing access_control_delete",
"Missing access_control_delete".to_string(),
));
}
@ -154,7 +156,7 @@ impl AccessControlCreate {
if !value.attribute_value_pres("class", &CLASS_ACC) {
audit_log!(audit, "class access_control_create not present.");
return Err(OperationError::InvalidACPState(
"Missing access_control_create",
"Missing access_control_create".to_string(),
));
}
@ -212,7 +214,7 @@ impl AccessControlModify {
if !value.attribute_value_pres("class", &CLASS_ACM) {
audit_log!(audit, "class access_control_modify not present.");
return Err(OperationError::InvalidACPState(
"Missing access_control_modify",
"Missing access_control_modify".to_string(),
));
}
@ -281,7 +283,7 @@ impl AccessControlProfile {
if !value.attribute_value_pres("class", &CLASS_ACP) {
audit_log!(audit, "class access_control_profile not present.");
return Err(OperationError::InvalidACPState(
"Missing access_control_profile",
"Missing access_control_profile".to_string(),
));
}
@ -290,7 +292,7 @@ impl AccessControlProfile {
audit,
value
.get_ava_single_str("name")
.ok_or(OperationError::InvalidACPState("Missing name"))
.ok_or(OperationError::InvalidACPState("Missing name".to_string()))
)
.to_string();
// copy uuid
@ -298,16 +300,16 @@ impl AccessControlProfile {
// receiver, and turn to real filter
let receiver_f: ProtoFilter = try_audit!(
audit,
value
.get_ava_single_protofilter("acp_receiver")
.ok_or(OperationError::InvalidACPState("Missing acp_receiver"))
value.get_ava_single_protofilter("acp_receiver").ok_or(
OperationError::InvalidACPState("Missing acp_receiver".to_string())
)
);
// targetscope, and turn to real filter
let targetscope_f: ProtoFilter = try_audit!(
audit,
value
.get_ava_single_protofilter("acp_targetscope")
.ok_or(OperationError::InvalidACPState("Missing acp_targetscope"))
value.get_ava_single_protofilter("acp_targetscope").ok_or(
OperationError::InvalidACPState("Missing acp_targetscope".to_string())
)
);
let receiver_i = try_audit!(audit, Filter::from_rw(audit, &receiver_f, qs));

View file

@ -55,6 +55,19 @@ fn get_current_user(req: &HttpRequest<AppState>) -> Option<UserAuthToken> {
}
}
fn operation_error_to_response(e: OperationError) -> HttpResponse {
match e {
OperationError::NotAuthenticated => HttpResponse::Unauthorized().json(e),
OperationError::AccessDenied | OperationError::SystemProtectedObject => {
HttpResponse::Forbidden().json(e)
}
OperationError::EmptyRequest
| OperationError::NoMatchingEntries
| OperationError::SchemaViolation(_) => HttpResponse::BadRequest().json(e),
_ => HttpResponse::InternalServerError().json(e),
}
}
macro_rules! json_event_post {
($req:expr, $state:expr, $message_type:ty, $request_type:ty) => {{
// This is copied every request. Is there a better way?
@ -100,7 +113,7 @@ macro_rules! json_event_post {
.from_err()
.and_then(|res| match res {
Ok(event_result) => Ok(HttpResponse::Ok().json(event_result)),
Err(e) => Ok(HttpResponse::InternalServerError().json(e)),
Err(e) => Ok(operation_error_to_response(e)),
});
Box::new(res)
@ -127,10 +140,7 @@ macro_rules! json_event_get {
let res = $state.qe.send(obj).from_err().and_then(|res| match res {
Ok(event_result) => Ok(HttpResponse::Ok().json(event_result)),
Err(e) => match e {
OperationError::NotAuthenticated => Ok(HttpResponse::Unauthorized().json(e)),
_ => Ok(HttpResponse::InternalServerError().json(e)),
},
Err(e) => Ok(operation_error_to_response(e)),
});
Box::new(res)
@ -184,10 +194,7 @@ fn json_rest_event_get(
let res = state.qe.send(obj).from_err().and_then(|res| match res {
Ok(event_result) => Ok(HttpResponse::Ok().json(event_result)),
Err(e) => match e {
OperationError::NotAuthenticated => Ok(HttpResponse::Unauthorized().json(e)),
_ => Ok(HttpResponse::InternalServerError().json(e)),
},
Err(e) => Ok(operation_error_to_response(e)),
});
Box::new(res)
@ -210,10 +217,7 @@ fn json_rest_event_get_id(
// Only send back the first result, or None
Ok(HttpResponse::Ok().json(event_result.pop()))
}
Err(e) => match e {
OperationError::NotAuthenticated => Ok(HttpResponse::Unauthorized().json(e)),
_ => Ok(HttpResponse::InternalServerError().json(e)),
},
Err(e) => Ok(operation_error_to_response(e)),
});
Box::new(res)
@ -257,7 +261,7 @@ fn json_rest_event_credential_put(
let m_obj = InternalCredentialSetMessage::new(uat, id, cred_id, obj);
let res = state.qe.send(m_obj).from_err().and_then(|res| match res {
Ok(event_result) => Ok(HttpResponse::Ok().json(event_result)),
Err(e) => Ok(HttpResponse::InternalServerError().json(e)),
Err(e) => Ok(operation_error_to_response(e)),
});
Box::new(res)
@ -321,10 +325,7 @@ fn schema_attributetype_get_id(
// Only send back the first result, or None
Ok(HttpResponse::Ok().json(event_result.pop()))
}
Err(e) => match e {
OperationError::NotAuthenticated => Ok(HttpResponse::Unauthorized().json(e)),
_ => Ok(HttpResponse::InternalServerError().json(e)),
},
Err(e) => Ok(operation_error_to_response(e)),
});
Box::new(res)
@ -355,10 +356,7 @@ fn schema_classtype_get_id(
// Only send back the first result, or None
Ok(HttpResponse::Ok().json(event_result.pop()))
}
Err(e) => match e {
OperationError::NotAuthenticated => Ok(HttpResponse::Unauthorized().json(e)),
_ => Ok(HttpResponse::InternalServerError().json(e)),
},
Err(e) => Ok(operation_error_to_response(e)),
});
Box::new(res)
@ -472,7 +470,7 @@ fn auth(
AuthState::Denied(_) => {
// Remove the auth-session-id
req.session().remove("auth-session-id");
Ok(HttpResponse::Ok().json(ar))
Ok(HttpResponse::Unauthorized().json(ar))
}
AuthState::Continue(_) => {
// Ensure the auth-session-id is set
@ -489,7 +487,7 @@ fn auth(
}
}
}
Err(e) => Ok(HttpResponse::InternalServerError().json(e)),
Err(e) => Ok(operation_error_to_response(e)),
});
Box::new(res)
}

View file

@ -670,7 +670,7 @@ impl AuthEventStep {
AuthStep::Init(name, appid) => {
if sid.is_some() {
Err(OperationError::InvalidAuthState(
"session id present in init",
"session id present in init".to_string(),
))
} else {
Ok(AuthEventStep::Init(AuthEventStepInit {
@ -685,7 +685,7 @@ impl AuthEventStep {
creds: creds,
})),
None => Err(OperationError::InvalidAuthState(
"session id not present in cred",
"session id not present in cred".to_string(),
)),
},
}

View file

@ -42,7 +42,7 @@ impl Account {
// Check the classes
if !value.attribute_value_pres("class", &PVCLASS_ACCOUNT) {
return Err(OperationError::InvalidAccountState(
"Missing class: account",
"Missing class: account".to_string(),
));
}
@ -51,11 +51,11 @@ impl Account {
value
.get_ava_single_string("name")
.ok_or(OperationError::InvalidAccountState(
"Missing attribute: name",
"Missing attribute: name".to_string(),
))?;
let displayname = value.get_ava_single_string("displayname").ok_or(
OperationError::InvalidAccountState("Missing attribute: displayname"),
OperationError::InvalidAccountState("Missing attribute: displayname".to_string()),
)?;
let primary = value

View file

@ -199,7 +199,7 @@ impl AuthSession {
) -> Result<AuthState, OperationError> {
if self.finished {
return Err(OperationError::InvalidAuthState(
"session already finalised!",
"session already finalised!".to_string(),
));
}

View file

@ -13,7 +13,7 @@ use crate::server::{
QueryServerReadTransaction, QueryServerTransaction, QueryServerWriteTransaction,
};
use crate::value::PartialValue;
use kanidm_proto::v1::{ConsistencyError, OperationError};
use kanidm_proto::v1::{ConsistencyError, OperationError, PluginError};
use std::collections::BTreeMap;
@ -59,7 +59,9 @@ fn get_cand_attr_set<VALID, STATE>(
vr,
uuid
);
return Err(OperationError::Plugin);
return Err(OperationError::Plugin(PluginError::AttrUnique(
"ava already exists".to_string(),
)));
}
}
}
@ -109,7 +111,9 @@ fn enforce_unique<STATE>(
// If all okay, okay!
if conflict_cand.len() > 0 {
return Err(OperationError::Plugin);
return Err(OperationError::Plugin(PluginError::AttrUnique(
"duplicate value detected".to_string(),
)));
}
Ok(())

View file

@ -13,7 +13,7 @@ use crate::server::{
QueryServerReadTransaction, QueryServerTransaction, QueryServerWriteTransaction,
};
use crate::value::{PartialValue, Value};
use kanidm_proto::v1::{ConsistencyError, OperationError};
use kanidm_proto::v1::{ConsistencyError, OperationError, PluginError};
lazy_static! {
static ref CLASS_OBJECT: Value = Value::new_class("object");
@ -66,7 +66,9 @@ impl Plugin for Base {
// Actually check we have a value, could be empty array ...
if u.len() > 1 {
audit_log!(au, "Entry defines uuid attr, but multiple values.");
return Err(OperationError::Plugin);
return Err(OperationError::Plugin(PluginError::Base(
"Uuid has multiple values".to_string(),
)));
};
// Schema of the value v, is checked in the filter generation. Neat!
@ -78,7 +80,9 @@ impl Plugin for Base {
let v: Value = try_audit!(
au,
u.first()
.ok_or(OperationError::Plugin)
.ok_or(OperationError::Plugin(PluginError::Base(
"Uuid format invalid".to_string()
)))
.map(|v| (*v).clone())
);
v
@ -104,14 +108,16 @@ impl Plugin for Base {
for entry in cand.iter() {
let uuid_ref: &Uuid = entry
.get_ava_single("uuid")
.ok_or(OperationError::Plugin)?
.ok_or(OperationError::InvalidEntryState)?
.to_uuid()
.ok_or(OperationError::Plugin)?;
.ok_or(OperationError::InvalidAttribute("uuid".to_string()))?;
audit_log!(au, "Entry valid UUID: {:?}", entry);
match cand_uuid.insert(uuid_ref) {
false => {
audit_log!(au, "uuid duplicate found in create set! {:?}", uuid_ref);
return Err(OperationError::Plugin);
return Err(OperationError::Plugin(PluginError::Base(
"Uuid duplicate detected in request".to_string(),
)));
}
true => {}
}
@ -137,7 +143,9 @@ impl Plugin for Base {
"uuid from protected system UUID range found in create set! {:?}",
overlap
);
return Err(OperationError::Plugin);
return Err(OperationError::Plugin(PluginError::Base(
"Uuid must not be in protected range".to_string(),
)));
}
}
@ -147,7 +155,9 @@ impl Plugin for Base {
"uuid \"does not exist\" found in create set! {:?}",
uuid_does_not_exist
);
return Err(OperationError::Plugin);
return Err(OperationError::Plugin(PluginError::Base(
"UUID_DOES_NOT_EXIST may not exist!".to_string(),
)));
}
// Now from each element, generate a filter to search for all of them
@ -175,12 +185,14 @@ impl Plugin for Base {
Ok(b) => {
if b == true {
audit_log!(au, "A UUID already exists, rejecting.");
return Err(OperationError::Plugin);
return Err(OperationError::Plugin(PluginError::Base(
"Uuid duplicate found in database".to_string(),
)));
}
}
Err(e) => {
audit_log!(au, "Error occured checking UUID existance. {:?}", e);
return Err(OperationError::Plugin);
return Err(e);
}
}
@ -201,7 +213,7 @@ impl Plugin for Base {
};
if attr == "uuid" {
audit_log!(au, "Modifications to UUID's are NOT ALLOWED");
return Err(OperationError::Plugin);
return Err(OperationError::SystemProtectedAttribute);
}
}
Ok(())

View file

@ -28,7 +28,7 @@ trait Plugin {
"plugin {} has an unimplemented pre_create_transform!",
Self::id()
);
Err(OperationError::Plugin)
Err(OperationError::InvalidState)
}
fn pre_create(
@ -39,7 +39,7 @@ trait Plugin {
_ce: &CreateEvent,
) -> Result<(), OperationError> {
debug!("plugin {} has an unimplemented pre_create!", Self::id());
Err(OperationError::Plugin)
Err(OperationError::InvalidState)
}
fn post_create(
@ -50,7 +50,7 @@ trait Plugin {
_ce: &CreateEvent,
) -> Result<(), OperationError> {
debug!("plugin {} has an unimplemented post_create!", Self::id());
Err(OperationError::Plugin)
Err(OperationError::InvalidState)
}
fn pre_modify(
@ -60,7 +60,7 @@ trait Plugin {
_me: &ModifyEvent,
) -> Result<(), OperationError> {
debug!("plugin {} has an unimplemented pre_modify!", Self::id());
Err(OperationError::Plugin)
Err(OperationError::InvalidState)
}
fn post_modify(
@ -72,7 +72,7 @@ trait Plugin {
_ce: &ModifyEvent,
) -> Result<(), OperationError> {
debug!("plugin {} has an unimplemented post_modify!", Self::id());
Err(OperationError::Plugin)
Err(OperationError::InvalidState)
}
fn pre_delete(
@ -82,7 +82,7 @@ trait Plugin {
_de: &DeleteEvent,
) -> Result<(), OperationError> {
debug!("plugin {} has an unimplemented pre_delete!", Self::id());
Err(OperationError::Plugin)
Err(OperationError::InvalidState)
}
fn post_delete(
@ -93,7 +93,7 @@ trait Plugin {
_ce: &DeleteEvent,
) -> Result<(), OperationError> {
debug!("plugin {} has an unimplemented post_delete!", Self::id());
Err(OperationError::Plugin)
Err(OperationError::InvalidState)
}
fn verify(

View file

@ -20,7 +20,7 @@ use crate::schema::SchemaTransaction;
use crate::server::QueryServerTransaction;
use crate::server::{QueryServerReadTransaction, QueryServerWriteTransaction};
use crate::value::{PartialValue, Value};
use kanidm_proto::v1::{ConsistencyError, OperationError};
use kanidm_proto::v1::{ConsistencyError, OperationError, PluginError};
use uuid::Uuid;
// NOTE: This *must* be after base.rs!!!
@ -35,7 +35,14 @@ impl ReferentialIntegrity {
uuid_value: &Value,
) -> Result<(), OperationError> {
debug!("{:?}", uuid_value);
let uuid = try_audit!(au, uuid_value.to_ref_uuid().ok_or(OperationError::Plugin));
let uuid = try_audit!(
au,
uuid_value
.to_ref_uuid()
.ok_or(OperationError::InvalidAttribute(
"uuid could not become reference value".to_string()
))
);
let mut au_qs = AuditScope::new("qs_exist");
// NOTE: This only checks LIVE entries (not using filter_all)
let filt_in = filter!(f_eq("uuid", PartialValue::new_uuid(uuid.clone())));
@ -53,7 +60,9 @@ impl ReferentialIntegrity {
rtype,
uuid
);
Err(OperationError::Plugin)
Err(OperationError::Plugin(PluginError::ReferentialIntegrity(
"Uuid referenced not found in database".to_string(),
)))
}
}
}
@ -225,7 +234,7 @@ impl Plugin for ReferentialIntegrity {
}
}
None => res.push(Err(ConsistencyError::InvalidAttributeType(
"A non-value-ref type was found.",
"A non-value-ref type was found.".to_string(),
))),
}
}

View file

@ -47,39 +47,47 @@ impl SchemaAttribute {
// class
if !value.attribute_value_pres("class", &PVCLASS_ATTRIBUTETYPE) {
audit_log!(audit, "class attribute type not present");
return Err(OperationError::InvalidSchemaState("missing attributetype"));
return Err(OperationError::InvalidSchemaState(
"missing attributetype".to_string(),
));
}
// uuid
let uuid = value.get_uuid().clone();
// name
let name = try_audit!(
audit,
value
.get_ava_single_string("attributename")
.ok_or(OperationError::InvalidSchemaState("missing attributename"))
);
let name =
try_audit!(
audit,
value.get_ava_single_string("attributename").ok_or(
OperationError::InvalidSchemaState("missing attributename".to_string())
)
);
// description
let description = try_audit!(
audit,
value
.get_ava_single_string("description")
.ok_or(OperationError::InvalidSchemaState("missing description"))
);
let description =
try_audit!(
audit,
value.get_ava_single_string("description").ok_or(
OperationError::InvalidSchemaState("missing description".to_string())
)
);
// multivalue
let multivalue = try_audit!(
audit,
value
.get_ava_single_bool("multivalue")
.ok_or(OperationError::InvalidSchemaState("missing multivalue"))
.ok_or(OperationError::InvalidSchemaState(
"missing multivalue".to_string()
))
);
let unique = try_audit!(
audit,
value
.get_ava_single_bool("unique")
.ok_or(OperationError::InvalidSchemaState("missing unique"))
.ok_or(OperationError::InvalidSchemaState(
"missing unique".to_string()
))
);
// index vec
// even if empty, it SHOULD be present ... (is that value to put an empty set?)
@ -92,7 +100,7 @@ impl SchemaAttribute {
.into_iter()
.map(|v: &IndexType| v.clone())
.collect()))
.map_err(|_| OperationError::InvalidSchemaState("Invalid index"))
.map_err(|_| OperationError::InvalidSchemaState("Invalid index".to_string()))
);
// syntax type
let syntax = try_audit!(
@ -100,7 +108,9 @@ impl SchemaAttribute {
value
.get_ava_single_syntax("syntax")
.and_then(|s: &SyntaxType| Some(s.clone()))
.ok_or(OperationError::InvalidSchemaState("missing syntax"))
.ok_or(OperationError::InvalidSchemaState(
"missing syntax".to_string()
))
);
Ok(SchemaAttribute {
@ -339,7 +349,9 @@ impl SchemaClass {
// Convert entry to a schema class.
if !value.attribute_value_pres("class", &PVCLASS_CLASSTYPE) {
audit_log!(audit, "class classtype not present");
return Err(OperationError::InvalidSchemaState("missing classtype"));
return Err(OperationError::InvalidSchemaState(
"missing classtype".to_string(),
));
}
// uuid
@ -350,36 +362,41 @@ impl SchemaClass {
audit,
value
.get_ava_single_string("classname")
.ok_or(OperationError::InvalidSchemaState("missing classname"))
.ok_or(OperationError::InvalidSchemaState(
"missing classname".to_string()
))
);
// description
let description = try_audit!(
audit,
value
.get_ava_single_string("description")
.ok_or(OperationError::InvalidSchemaState("missing description"))
);
let description =
try_audit!(
audit,
value.get_ava_single_string("description").ok_or(
OperationError::InvalidSchemaState("missing description".to_string())
)
);
// These are all "optional" lists of strings.
let systemmay =
value
.get_ava_opt_string("systemmay")
.ok_or(OperationError::InvalidSchemaState(
"Missing or invalid systemmay",
"Missing or invalid systemmay".to_string(),
))?;
let systemmust =
value
.get_ava_opt_string("systemmust")
.ok_or(OperationError::InvalidSchemaState(
"Missing or invalid systemmust",
"Missing or invalid systemmust".to_string(),
))?;
let may = value
.get_ava_opt_string("may")
.ok_or(OperationError::InvalidSchemaState("Missing or invalid may"))?;
.ok_or(OperationError::InvalidSchemaState(
"Missing or invalid may".to_string(),
))?;
let must = value
.get_ava_opt_string("must")
.ok_or(OperationError::InvalidSchemaState(
"Missing or invalid must",
"Missing or invalid must".to_string(),
))?;
Ok(SchemaClass {

View file

@ -364,11 +364,11 @@ pub trait QueryServerTransaction {
SyntaxType::UTF8STRING => Ok(Value::new_utf8(value.clone())),
SyntaxType::UTF8STRING_INSENSITIVE => Ok(Value::new_iutf8s(value.as_str())),
SyntaxType::BOOLEAN => Value::new_bools(value.as_str())
.ok_or(OperationError::InvalidAttribute("Invalid boolean syntax")),
.ok_or(OperationError::InvalidAttribute("Invalid boolean syntax".to_string())),
SyntaxType::SYNTAX_ID => Value::new_syntaxs(value.as_str())
.ok_or(OperationError::InvalidAttribute("Invalid Syntax syntax")),
.ok_or(OperationError::InvalidAttribute("Invalid Syntax syntax".to_string())),
SyntaxType::INDEX_ID => Value::new_indexs(value.as_str())
.ok_or(OperationError::InvalidAttribute("Invalid Index syntax")),
.ok_or(OperationError::InvalidAttribute("Invalid Index syntax".to_string())),
SyntaxType::UUID => {
// It's a uuid - we do NOT check for existance, because that
// could be revealing or disclosing - it is up to acp to assert
@ -386,7 +386,7 @@ pub trait QueryServerTransaction {
Some(Value::new_uuid(un))
})
// I think this is unreachable due to how the .or_else works.
.ok_or(OperationError::InvalidAttribute("Invalid UUID syntax"))
.ok_or(OperationError::InvalidAttribute("Invalid UUID syntax".to_string()))
}
SyntaxType::REFERENCE_UUID => {
// See comments above.
@ -398,11 +398,11 @@ pub trait QueryServerTransaction {
Some(Value::new_refer(un))
})
// I think this is unreachable due to how the .or_else works.
.ok_or(OperationError::InvalidAttribute("Invalid Reference syntax"))
.ok_or(OperationError::InvalidAttribute("Invalid Reference syntax".to_string()))
}
SyntaxType::JSON_FILTER => Value::new_json_filter(value)
.ok_or(OperationError::InvalidAttribute("Invalid Filter syntax")),
SyntaxType::CREDENTIAL => Err(OperationError::InvalidAttribute("Credentials can not be supplied through modification - please use the IDM api")),
.ok_or(OperationError::InvalidAttribute("Invalid Filter syntax".to_string())),
SyntaxType::CREDENTIAL => Err(OperationError::InvalidAttribute("Credentials can not be supplied through modification - please use the IDM api".to_string())),
}
}
None => {
@ -431,12 +431,15 @@ pub trait QueryServerTransaction {
SyntaxType::UTF8STRING_INSENSITIVE => {
Ok(PartialValue::new_iutf8s(value.as_str()))
}
SyntaxType::BOOLEAN => PartialValue::new_bools(value.as_str())
.ok_or(OperationError::InvalidAttribute("Invalid boolean syntax")),
SyntaxType::SYNTAX_ID => PartialValue::new_syntaxs(value.as_str())
.ok_or(OperationError::InvalidAttribute("Invalid Syntax syntax")),
SyntaxType::INDEX_ID => PartialValue::new_indexs(value.as_str())
.ok_or(OperationError::InvalidAttribute("Invalid Index syntax")),
SyntaxType::BOOLEAN => PartialValue::new_bools(value.as_str()).ok_or(
OperationError::InvalidAttribute("Invalid boolean syntax".to_string()),
),
SyntaxType::SYNTAX_ID => PartialValue::new_syntaxs(value.as_str()).ok_or(
OperationError::InvalidAttribute("Invalid Syntax syntax".to_string()),
),
SyntaxType::INDEX_ID => PartialValue::new_indexs(value.as_str()).ok_or(
OperationError::InvalidAttribute("Invalid Index syntax".to_string()),
),
SyntaxType::UUID => {
PartialValue::new_uuids(value.as_str())
.or_else(|| {
@ -450,7 +453,9 @@ pub trait QueryServerTransaction {
Some(PartialValue::new_uuid(un))
})
// I think this is unreachable due to how the .or_else works.
.ok_or(OperationError::InvalidAttribute("Invalid UUID syntax"))
.ok_or(OperationError::InvalidAttribute(
"Invalid UUID syntax".to_string(),
))
}
SyntaxType::REFERENCE_UUID => {
// See comments above.
@ -462,10 +467,13 @@ pub trait QueryServerTransaction {
Some(PartialValue::new_refer(un))
})
// I think this is unreachable due to how the .or_else works.
.ok_or(OperationError::InvalidAttribute("Invalid Reference syntax"))
.ok_or(OperationError::InvalidAttribute(
"Invalid Reference syntax".to_string(),
))
}
SyntaxType::JSON_FILTER => PartialValue::new_json_filter(value)
.ok_or(OperationError::InvalidAttribute("Invalid Filter syntax")),
SyntaxType::JSON_FILTER => PartialValue::new_json_filter(value).ok_or(
OperationError::InvalidAttribute("Invalid Filter syntax".to_string()),
),
SyntaxType::CREDENTIAL => Ok(PartialValue::new_credential_tag(value.as_str())),
}
}