Finish up todo audit

This commit is contained in:
William Brown 2019-07-28 20:18:25 +09:00
parent 82e51399e9
commit 96beb3070e
10 changed files with 70 additions and 66 deletions

View file

@ -157,13 +157,13 @@ pub static UUID_SCHEMA_ATTR_ACP_ENABLE: &'static str = "00000000-0000-0000-
pub static UUID_SCHEMA_ATTR_ACP_RECEIVER: &'static str = "00000000-0000-0000-0000-ffff00000018"; pub static UUID_SCHEMA_ATTR_ACP_RECEIVER: &'static str = "00000000-0000-0000-0000-ffff00000018";
pub static UUID_SCHEMA_ATTR_ACP_TARGETSCOPE: &'static str = "00000000-0000-0000-0000-ffff00000019"; pub static UUID_SCHEMA_ATTR_ACP_TARGETSCOPE: &'static str = "00000000-0000-0000-0000-ffff00000019";
pub static UUID_SCHEMA_ATTR_ACP_SEARCH_ATTR: &'static str = "00000000-0000-0000-0000-ffff00000020"; pub static UUID_SCHEMA_ATTR_ACP_SEARCH_ATTR: &'static str = "00000000-0000-0000-0000-ffff00000020";
pub static UUID_SCHEMA_ATTR_ACP_CREATE_CLASS: &'static str ="00000000-0000-0000-0000-ffff00000021"; pub static UUID_SCHEMA_ATTR_ACP_CREATE_CLASS: &'static str = "00000000-0000-0000-0000-ffff00000021";
pub static UUID_SCHEMA_ATTR_ACP_CREATE_ATTR: &'static str = "00000000-0000-0000-0000-ffff00000022"; pub static UUID_SCHEMA_ATTR_ACP_CREATE_ATTR: &'static str = "00000000-0000-0000-0000-ffff00000022";
pub static UUID_SCHEMA_ATTR_ACP_MODIFY_REMOVEDATTR: &'static str = pub static UUID_SCHEMA_ATTR_ACP_MODIFY_REMOVEDATTR: &'static str =
"00000000-0000-0000-0000-ffff00000023"; "00000000-0000-0000-0000-ffff00000023";
pub static UUID_SCHEMA_ATTR_ACP_MODIFY_PRESENTATTR: &'static str = pub static UUID_SCHEMA_ATTR_ACP_MODIFY_PRESENTATTR: &'static str =
"00000000-0000-0000-0000-ffff00000024"; "00000000-0000-0000-0000-ffff00000024";
pub static UUID_SCHEMA_ATTR_ACP_MODIFY_CLASS: &'static str ="00000000-0000-0000-0000-ffff00000025"; pub static UUID_SCHEMA_ATTR_ACP_MODIFY_CLASS: &'static str = "00000000-0000-0000-0000-ffff00000025";
pub static UUID_SCHEMA_CLASS_ATTRIBUTETYPE: &'static str = "00000000-0000-0000-0000-ffff00000026"; pub static UUID_SCHEMA_CLASS_ATTRIBUTETYPE: &'static str = "00000000-0000-0000-0000-ffff00000026";
pub static UUID_SCHEMA_CLASS_CLASSTYPE: &'static str = "00000000-0000-0000-0000-ffff00000027"; pub static UUID_SCHEMA_CLASS_CLASSTYPE: &'static str = "00000000-0000-0000-0000-ffff00000027";

View file

@ -332,10 +332,10 @@ impl<STATE> Entry<EntryNormalised, STATE> {
} }
} }
} else { } else {
// TODO: Again, we clone string here, but it's so we can check all // We clone string here, but it's so we can check all
// the values in "may" ar here - so we can't avoid this look up. What we // the values in "may" ar here - so we can't avoid this look up. What we
// could do though, is have &String based on the schemaattribute though?; // could do though, is have &String based on the schemaattribute though?;
let may: Result<HashMap<String, &SchemaAttribute>, _> = classes let may: Result<HashMap<&String, &SchemaAttribute>, _> = classes
.iter() .iter()
// Join our class systemmmust + must + systemmay + may into one. // Join our class systemmmust + must + systemmay + may into one.
.flat_map(|cls| { .flat_map(|cls| {
@ -348,18 +348,17 @@ impl<STATE> Entry<EntryNormalised, STATE> {
.map(|s| { .map(|s| {
// This should NOT fail - if it does, it means our schema is // This should NOT fail - if it does, it means our schema is
// in an invalid state! // in an invalid state!
Ok(( Ok((s, schema_attributes.get(s).ok_or(SchemaError::Corrupted)?))
s.clone(),
schema_attributes.get(s).ok_or(SchemaError::Corrupted)?,
))
}) })
.collect(); .collect();
let may = may?; let may = may?;
// TODO: Error needs to say what is missing // TODO #70: Error needs to say what is missing
// We need to return *all* missing attributes, not just the first error // We need to return *all* missing attributes, not just the first error
// we find. // we find. This will probably take a rewrite of the function definition
// to return a result<_, vec<schemaerror>> and for the schema errors to take
// information about what is invalid. It's pretty nontrivial.
// Check that any other attributes are in may // Check that any other attributes are in may
// for each attr on the object, check it's in the may+must set // for each attr on the object, check it's in the may+must set
@ -835,10 +834,11 @@ impl<STATE> Entry<EntryValid, STATE> {
// In the future, if we make uuid a real entry type, then this // In the future, if we make uuid a real entry type, then this
// check can "go away" because uuid will never exist as an ava. // check can "go away" because uuid will never exist as an ava.
// //
// TODO: Remove this check when uuid becomes a real attribute. // NOTE: Remove this check when uuid becomes a real attribute.
// UUID is now a real attribute, but it also has an ava for db_entry // UUID is now a real attribute, but it also has an ava for db_entry
// conversion - so what do? If we remove it here, we could have CSN issue with // conversion - so what do? If we remove it here, we could have CSN issue with
// repl on uuid conflict, but it probably shouldn't be an ava either ... // repl on uuid conflict, but it probably shouldn't be an ava either ...
// as a result, I think we need to keep this continue line to not cause issues.
if k == "uuid" { if k == "uuid" {
continue; continue;
} }

View file

@ -180,7 +180,7 @@ pub struct SearchEvent {
pub filter: Filter<FilterValid>, pub filter: Filter<FilterValid>,
// This is the original filter, for the purpose of ACI checking. // This is the original filter, for the purpose of ACI checking.
pub filter_orig: Filter<FilterValid>, pub filter_orig: Filter<FilterValid>,
// TODO: Add list of attributes to request // TODO #83: Add list of attributes to request
} }
impl SearchEvent { impl SearchEvent {

View file

@ -26,10 +26,11 @@ pub(crate) struct Account {
// account expiry? // account expiry?
} }
impl TryFrom<Entry<EntryValid, EntryCommitted>> for Account { impl Account {
type Error = OperationError; // TODO #71: We need a second try_from that doesn't do group resolve for test cases I think.
pub(crate) fn try_from_entry(
fn try_from(value: Entry<EntryValid, EntryCommitted>) -> Result<Self, Self::Error> { value: Entry<EntryValid, EntryCommitted>,
) -> Result<Self, OperationError> {
// Check the classes // Check the classes
if !value.attribute_value_pres("class", "account") { if !value.attribute_value_pres("class", "account") {
return Err(OperationError::InvalidAccountState( return Err(OperationError::InvalidAccountState(
@ -52,7 +53,7 @@ impl TryFrom<Entry<EntryValid, EntryCommitted>> for Account {
))? ))?
.clone(); .clone();
// TODO: Resolve groups!!!! // TODO #71: Resolve groups!!!!
let groups = Vec::new(); let groups = Vec::new();
let uuid = value.get_uuid().clone(); let uuid = value.get_uuid().clone();
@ -64,9 +65,7 @@ impl TryFrom<Entry<EntryValid, EntryCommitted>> for Account {
groups: groups, groups: groups,
}) })
} }
}
impl Account {
// Could this actually take a claims list and application instead? // Could this actually take a claims list and application instead?
pub(crate) fn to_userauthtoken(&self, claims: Vec<Claim>) -> Option<UserAuthToken> { pub(crate) fn to_userauthtoken(&self, claims: Vec<Claim>) -> Option<UserAuthToken> {
// This could consume self? // This could consume self?
@ -105,7 +104,7 @@ mod tests {
serde_json::from_str(JSON_ANONYMOUS_V1).expect("Json deserialise failure!"); serde_json::from_str(JSON_ANONYMOUS_V1).expect("Json deserialise failure!");
let anon_e = unsafe { anon_e.to_valid_committed() }; let anon_e = unsafe { anon_e.to_valid_committed() };
let anon_account = Account::try_from(anon_e).expect("Must not fail"); let anon_account = Account::try_from_entry(anon_e).expect("Must not fail");
println!("{:?}", anon_account); println!("{:?}", anon_account);
// I think that's it? we may want to check anonymous mech ... // I think that's it? we may want to check anonymous mech ...
} }

View file

@ -1,3 +1,4 @@
use crate::audit::AuditScope;
use crate::constants::UUID_ANONYMOUS; use crate::constants::UUID_ANONYMOUS;
use crate::error::OperationError; use crate::error::OperationError;
use crate::idm::account::Account; use crate::idm::account::Account;
@ -123,9 +124,9 @@ impl AuthSession {
} }
// This should return a AuthResult or similar state of checking? // This should return a AuthResult or similar state of checking?
// TODO: This needs some logging ....
pub fn validate_creds( pub fn validate_creds(
&mut self, &mut self,
au: &mut AuditScope,
creds: &Vec<AuthCredential>, creds: &Vec<AuthCredential>,
) -> Result<AuthState, OperationError> { ) -> Result<AuthState, OperationError> {
if self.finished { if self.finished {
@ -136,6 +137,7 @@ impl AuthSession {
match self.handler.validate(creds) { match self.handler.validate(creds) {
CredState::Success(claims) => { CredState::Success(claims) => {
audit_log!(au, "Successful cred handling");
self.finished = true; self.finished = true;
let uat = self let uat = self
.account .account
@ -143,9 +145,13 @@ impl AuthSession {
.ok_or(OperationError::InvalidState)?; .ok_or(OperationError::InvalidState)?;
Ok(AuthState::Success(uat)) Ok(AuthState::Success(uat))
} }
CredState::Continue(allowed) => Ok(AuthState::Continue(allowed)), CredState::Continue(allowed) => {
audit_log!(au, "Request credential continuation: {:?}", allowed);
Ok(AuthState::Continue(allowed))
}
CredState::Denied(reason) => { CredState::Denied(reason) => {
self.finished = true; self.finished = true;
audit_log!(au, "Credentials denied: {}", reason);
Ok(AuthState::Denied(reason.to_string())) Ok(AuthState::Denied(reason.to_string()))
} }
} }

View file

@ -8,7 +8,7 @@ macro_rules! entry_str_to_account {
serde_json::from_str($entry_str).expect("Json deserialise failure!"); serde_json::from_str($entry_str).expect("Json deserialise failure!");
let e = unsafe { e.to_valid_committed() }; let e = unsafe { e.to_valid_committed() };
Account::try_from(e).expect("Account conversion failure") Account::try_from_entry(e).expect("Account conversion failure")
}}; }};
} }

View file

@ -118,7 +118,7 @@ impl<'a> IdmServerWriteTransaction<'a> {
// typing and functionality so we can assess what auth types can // typing and functionality so we can assess what auth types can
// continue, and helps to keep non-needed entry specific data // continue, and helps to keep non-needed entry specific data
// out of the LRU. // out of the LRU.
let account = Account::try_from(entry)?; let account = Account::try_from_entry(entry)?;
let auth_session = AuthSession::new(account, init.appid.clone()); let auth_session = AuthSession::new(account, init.appid.clone());
// Get the set of mechanisms that can proceed. This is tied // Get the set of mechanisms that can proceed. This is tied
@ -153,7 +153,7 @@ impl<'a> IdmServerWriteTransaction<'a> {
// Process the credentials here as required. // Process the credentials here as required.
// Basically throw them at the auth_session and see what // Basically throw them at the auth_session and see what
// falls out. // falls out.
auth_session.validate_creds(&creds.creds).map(|aus| { auth_session.validate_creds(au, &creds.creds).map(|aus| {
AuthResult { AuthResult {
// Is this right? // Is this right?
sessionid: creds.sessionid, sessionid: creds.sessionid,

View file

@ -137,9 +137,10 @@ impl Plugin for Base {
let filt_in = filter_all!(FC::Or(cand_uuid.iter().map(|u| f_eq("uuid", u)).collect(),)); let filt_in = filter_all!(FC::Or(cand_uuid.iter().map(|u| f_eq("uuid", u)).collect(),));
// If any results exist, fail as a duplicate UUID is present. // If any results exist, fail as a duplicate UUID is present.
// TODO: Can we report which UUID exists? Probably yes, we do // TODO #69: Can we report which UUID exists? Probably yes, we do
// internal search and report the UUID *OR* we alter internal_exists // internal search and report the UUID *OR* we alter internal_exists
// to return UUID sets. // to return UUID sets. This can be done as an extension to #69 where the
// internal exists is actually a wrapper around a search for uuid internally
// //
// But does it add value? How many people will try to custom define/add uuid? // But does it add value? How many people will try to custom define/add uuid?
let mut au_qs = AuditScope::new("qs_exist"); let mut au_qs = AuditScope::new("qs_exist");

View file

@ -270,8 +270,6 @@ pub enum AuthState {
#[derive(Debug, Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct AuthResponse { pub struct AuthResponse {
// TODO: Consider moving to an AuthMessageResponse type, and leave the proto
// without the session id because it's not necesary to know.
pub sessionid: Uuid, pub sessionid: Uuid,
pub state: AuthState, pub state: AuthState,
} }

View file

@ -19,7 +19,7 @@ use concread::cowcell::{CowCell, CowCellReadTxn, CowCellWriteTxn};
// In the future this will parse/read it's schema from the db // In the future this will parse/read it's schema from the db
// but we have to bootstrap with some core types. // but we have to bootstrap with some core types.
// TODO: prefix on all schema types that are system? // TODO #72: prefix on all schema types that are system?
#[allow(non_camel_case_types)] #[allow(non_camel_case_types)]
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
@ -377,7 +377,7 @@ impl SchemaAttribute {
} }
} }
// TODO: This clones everything, which is expensive! // NOTE: This clones values, but it's hard to see a way around it.
pub fn normalise_value(&self, v: &String) -> String { pub fn normalise_value(&self, v: &String) -> String {
match self.syntax { match self.syntax {
SyntaxType::SYNTAX_ID => self.normalise_syntax(v), SyntaxType::SYNTAX_ID => self.normalise_syntax(v),