diff --git a/proto/Cargo.toml b/proto/Cargo.toml index c14bcacfe..a6bd3f374 100644 --- a/proto/Cargo.toml +++ b/proto/Cargo.toml @@ -17,10 +17,10 @@ doctest = true [features] wasm = ["webauthn-rs-proto/wasm"] +test = [] [dependencies] base32 = { workspace = true } -enum-iterator = { workspace = true } num_enum = { workspace = true } scim_proto = { workspace = true } serde = { workspace = true, features = ["derive"] } @@ -34,3 +34,6 @@ urlencoding = { workspace = true } utoipa = { workspace = true } uuid = { workspace = true, features = ["serde"] } webauthn-rs-proto = { workspace = true } + +[dev-dependencies] +enum-iterator = { workspace = true } diff --git a/proto/src/attribute.rs b/proto/src/attribute.rs index 4ce5f6c88..b9f05da56 100644 --- a/proto/src/attribute.rs +++ b/proto/src/attribute.rs @@ -1,16 +1,13 @@ -use enum_iterator::Sequence; use serde::{Deserialize, Serialize}; use crate::constants::*; use crate::internal::OperationError; use std::fmt; -use tracing::trace; pub use smartstring::alias::String as AttrString; -#[derive( - Serialize, Deserialize, Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Sequence, Hash, -)] +#[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash, Default)] +#[cfg_attr(test, derive(enum_iterator::Sequence))] #[serde(rename_all = "lowercase", try_from = "&str", into = "AttrString")] pub enum Attribute { Account, @@ -29,6 +26,7 @@ pub enum Attribute { ApiTokenSession, ApplicationPassword, AttestedPasskeys, + #[default] Attr, AttributeName, AttributeType, @@ -171,28 +169,30 @@ pub enum Attribute { Version, WebauthnAttestationCaList, - #[cfg(any(debug_assertions, test))] + #[cfg(any(debug_assertions, test, feature = "test"))] NonExist, - #[cfg(any(debug_assertions, test))] + #[cfg(any(debug_assertions, test, feature = "test"))] TestAttr, - #[cfg(any(debug_assertions, test))] + #[cfg(any(debug_assertions, test, feature = "test"))] TestNumber, - #[cfg(any(debug_assertions, test))] + #[cfg(any(debug_assertions, test, feature = "test"))] Extra, - #[cfg(any(debug_assertions, test))] + #[cfg(any(debug_assertions, test, feature = "test"))] TestNotAllowed, - // Custom(AttrString), + + #[cfg(not(test))] + Custom(AttrString), } impl AsRef for Attribute { fn as_ref(&self) -> &str { - self.into() + self.as_str() } } -impl From<&Attribute> for &'static str { - fn from(value: &Attribute) -> Self { - (*value).into() +impl AsRef for Attribute { + fn as_ref(&self) -> &Attribute { + self } } @@ -200,192 +200,31 @@ impl TryFrom<&AttrString> for Attribute { type Error = OperationError; fn try_from(value: &AttrString) -> Result { - Attribute::try_from(value.as_str()) + Ok(Attribute::from_str(value.as_str())) } } -impl<'a> TryFrom<&'a str> for Attribute { - type Error = OperationError; - fn try_from(val: &'a str) -> Result { - let res = match val { - ATTR_ACCOUNT => Attribute::Account, - ATTR_ACCOUNT_EXPIRE => Attribute::AccountExpire, - ATTR_ACCOUNT_VALID_FROM => Attribute::AccountValidFrom, - ATTR_ACP_CREATE_ATTR => Attribute::AcpCreateAttr, - ATTR_ACP_CREATE_CLASS => Attribute::AcpCreateClass, - ATTR_ACP_ENABLE => Attribute::AcpEnable, - ATTR_ACP_MODIFY_CLASS => Attribute::AcpModifyClass, - ATTR_ACP_MODIFY_PRESENTATTR => Attribute::AcpModifyPresentAttr, - ATTR_ACP_MODIFY_REMOVEDATTR => Attribute::AcpModifyRemovedAttr, - ATTR_ACP_RECEIVER => Attribute::AcpReceiver, - ATTR_ACP_RECEIVER_GROUP => Attribute::AcpReceiverGroup, - ATTR_ACP_SEARCH_ATTR => Attribute::AcpSearchAttr, - ATTR_ACP_TARGET_SCOPE => Attribute::AcpTargetScope, - ATTR_API_TOKEN_SESSION => Attribute::ApiTokenSession, - ATTR_APPLICATION_PASSWORD => Attribute::ApplicationPassword, - ATTR_ATTESTED_PASSKEYS => Attribute::AttestedPasskeys, - ATTR_ATTR => Attribute::Attr, - ATTR_ATTRIBUTENAME => Attribute::AttributeName, - ATTR_ATTRIBUTETYPE => Attribute::AttributeType, - ATTR_AUTH_SESSION_EXPIRY => Attribute::AuthSessionExpiry, - ATTR_AUTH_PASSWORD_MINIMUM_LENGTH => Attribute::AuthPasswordMinimumLength, - ATTR_BADLIST_PASSWORD => Attribute::BadlistPassword, - ATTR_CERTIFICATE => Attribute::Certificate, - ATTR_CLAIM => Attribute::Claim, - ATTR_CLASS => Attribute::Class, - ATTR_CLASSNAME => Attribute::ClassName, - ATTR_CN => Attribute::Cn, - ATTR_COOKIE_PRIVATE_KEY => Attribute::CookiePrivateKey, - ATTR_CREDENTIAL_UPDATE_INTENT_TOKEN => Attribute::CredentialUpdateIntentToken, - ATTR_CREDENTIAL_TYPE_MINIMUM => Attribute::CredentialTypeMinimum, - ATTR_DENIED_NAME => Attribute::DeniedName, - ATTR_DESCRIPTION => Attribute::Description, - ATTR_DIRECTMEMBEROF => Attribute::DirectMemberOf, - ATTR_DISPLAYNAME => Attribute::DisplayName, - ATTR_DN => Attribute::Dn, - ATTR_DOMAIN => Attribute::Domain, - ATTR_DOMAIN_DISPLAY_NAME => Attribute::DomainDisplayName, - ATTR_DOMAIN_DEVELOPMENT_TAINT => Attribute::DomainDevelopmentTaint, - ATTR_DOMAIN_LDAP_BASEDN => Attribute::DomainLdapBasedn, - ATTR_DOMAIN_NAME => Attribute::DomainName, - ATTR_DOMAIN_SSID => Attribute::DomainSsid, - ATTR_DOMAIN_TOKEN_KEY => Attribute::DomainTokenKey, - ATTR_DOMAIN_UUID => Attribute::DomainUuid, - ATTR_DYNGROUP => Attribute::DynGroup, - ATTR_DYNGROUP_FILTER => Attribute::DynGroupFilter, - ATTR_DYNMEMBER => Attribute::DynMember, - ATTR_EMAIL => Attribute::Email, - ATTR_EMAIL_ALTERNATIVE => Attribute::EmailAlternative, - ATTR_EMAIL_PRIMARY => Attribute::EmailPrimary, - ATTR_ENTRYDN => Attribute::EntryDn, - ATTR_ENTRY_MANAGED_BY => Attribute::EntryManagedBy, - ATTR_ENTRYUUID => Attribute::EntryUuid, - ATTR_ES256_PRIVATE_KEY_DER => Attribute::Es256PrivateKeyDer, - ATTR_EXCLUDES => Attribute::Excludes, - ATTR_FERNET_PRIVATE_KEY_STR => Attribute::FernetPrivateKeyStr, - ATTR_GECOS => Attribute::Gecos, - ATTR_GIDNUMBER => Attribute::GidNumber, - ATTR_GRANT_UI_HINT => Attribute::GrantUiHint, - ATTR_GROUP => Attribute::Group, - ATTR_ID_VERIFICATION_ECKEY => Attribute::IdVerificationEcKey, - ATTR_IMAGE => Attribute::Image, - ATTR_INDEX => Attribute::Index, - ATTR_IPANTHASH => Attribute::IpaNtHash, - ATTR_IPASSHPUBKEY => Attribute::IpaSshPubKey, - ATTR_JWS_ES256_PRIVATE_KEY => Attribute::JwsEs256PrivateKey, - ATTR_KEY_ACTION_ROTATE => Attribute::KeyActionRotate, - ATTR_KEY_ACTION_REVOKE => Attribute::KeyActionRevoke, - ATTR_KEY_ACTION_IMPORT_JWS_ES256 => Attribute::KeyActionImportJwsEs256, - ATTR_KEY_INTERNAL_DATA => Attribute::KeyInternalData, - ATTR_KEY_PROVIDER => Attribute::KeyProvider, - ATTR_LAST_MODIFIED_CID => Attribute::LastModifiedCid, - ATTR_LDAP_ALLOW_UNIX_PW_BIND => Attribute::LdapAllowUnixPwBind, - ATTR_LDAP_EMAIL_ADDRESS => Attribute::LdapEmailAddress, - ATTR_LDAP_KEYS => Attribute::LdapKeys, - ATTR_SSH_PUBLICKEY => Attribute::SshPublicKey, - ATTR_LEGALNAME => Attribute::LegalName, - ATTR_LINKEDGROUP => Attribute::LinkedGroup, - ATTR_LOGINSHELL => Attribute::LoginShell, - ATTR_LIMIT_SEARCH_MAX_RESULTS => Attribute::LimitSearchMaxResults, - ATTR_LIMIT_SEARCH_MAX_FILTER_TEST => Attribute::LimitSearchMaxFilterTest, - ATTR_MAIL => Attribute::Mail, - ATTR_MAY => Attribute::May, - ATTR_MEMBER => Attribute::Member, - ATTR_MEMBEROF => Attribute::MemberOf, - ATTR_MULTIVALUE => Attribute::MultiValue, - ATTR_MUST => Attribute::Must, - ATTR_NAME => Attribute::Name, - ATTR_NAME_HISTORY => Attribute::NameHistory, - ATTR_NO_INDEX => Attribute::NoIndex, - ATTR_NSUNIQUEID => Attribute::NsUniqueId, - ATTR_NSACCOUNTLOCK => Attribute::NsAccountLock, - ATTR_OAUTH2_ALLOW_INSECURE_CLIENT_DISABLE_PKCE => { - Attribute::OAuth2AllowInsecureClientDisablePkce - } - ATTR_OAUTH2_ALLOW_LOCALHOST_REDIRECT => Attribute::OAuth2AllowLocalhostRedirect, - ATTR_OAUTH2_CONSENT_SCOPE_MAP => Attribute::OAuth2ConsentScopeMap, - ATTR_OAUTH2_JWT_LEGACY_CRYPTO_ENABLE => Attribute::OAuth2JwtLegacyCryptoEnable, - ATTR_OAUTH2_PREFER_SHORT_USERNAME => Attribute::OAuth2PreferShortUsername, - ATTR_OAUTH2_RS_BASIC_SECRET => Attribute::OAuth2RsBasicSecret, - ATTR_OAUTH2_RS_CLAIM_MAP => Attribute::OAuth2RsClaimMap, - ATTR_OAUTH2_RS_IMPLICIT_SCOPES => Attribute::OAuth2RsImplicitScopes, - ATTR_OAUTH2_RS_NAME => Attribute::OAuth2RsName, - ATTR_OAUTH2_RS_ORIGIN => Attribute::OAuth2RsOrigin, - ATTR_OAUTH2_RS_ORIGIN_LANDING => Attribute::OAuth2RsOriginLanding, - ATTR_OAUTH2_RS_SCOPE_MAP => Attribute::OAuth2RsScopeMap, - ATTR_OAUTH2_RS_SUP_SCOPE_MAP => Attribute::OAuth2RsSupScopeMap, - ATTR_OAUTH2_RS_TOKEN_KEY => Attribute::OAuth2RsTokenKey, - ATTR_OAUTH2_SESSION => Attribute::OAuth2Session, - ATTR_OAUTH2_STRICT_REDIRECT_URI => Attribute::OAuth2StrictRedirectUri, - ATTR_OBJECTCLASS => Attribute::ObjectClass, - ATTR_OTHER_NO_INDEX => Attribute::OtherNoIndex, - ATTR_PASSKEYS => Attribute::PassKeys, - ATTR_PASSWORD_IMPORT => Attribute::PasswordImport, - ATTR_PATCH_LEVEL => Attribute::PatchLevel, - ATTR_PHANTOM => Attribute::Phantom, - ATTR_PRIMARY_CREDENTIAL => Attribute::PrimaryCredential, - ATTR_PRIVATE_COOKIE_KEY => Attribute::PrivateCookieKey, - ATTR_PRIVILEGE_EXPIRY => Attribute::PrivilegeExpiry, - ATTR_RADIUS_SECRET => Attribute::RadiusSecret, - ATTR_RECYCLEDDIRECTMEMBEROF => Attribute::RecycledDirectMemberOf, - ATTR_REFERS => Attribute::Refers, - ATTR_REPLICATED => Attribute::Replicated, - ATTR_RS256_PRIVATE_KEY_DER => Attribute::Rs256PrivateKeyDer, - ATTR_SCOPE => Attribute::Scope, - ATTR_SOURCE_UUID => Attribute::SourceUuid, - ATTR_SPN => Attribute::Spn, - ATTR_LDAP_SSHPUBLICKEY => Attribute::LdapSshPublicKey, - ATTR_SUDOHOST => Attribute::SudoHost, - ATTR_SUPPLEMENTS => Attribute::Supplements, - ATTR_SYNC_ALLOWED => Attribute::SyncAllowed, - ATTR_SYNC_CLASS => Attribute::SyncClass, - ATTR_SYNC_COOKIE => Attribute::SyncCookie, - ATTR_SYNC_CREDENTIAL_PORTAL => Attribute::SyncCredentialPortal, - ATTR_SYNC_EXTERNAL_ID => Attribute::SyncExternalId, - ATTR_SYNC_PARENT_UUID => Attribute::SyncParentUuid, - ATTR_SYNC_TOKEN_SESSION => Attribute::SyncTokenSession, - ATTR_SYNC_YIELD_AUTHORITY => Attribute::SyncYieldAuthority, - ATTR_SYNTAX => Attribute::Syntax, - ATTR_SYSTEMEXCLUDES => Attribute::SystemExcludes, - ATTR_SYSTEMMAY => Attribute::SystemMay, - ATTR_SYSTEMMUST => Attribute::SystemMust, - ATTR_SYSTEMSUPPLEMENTS => Attribute::SystemSupplements, - ATTR_TERM => Attribute::Term, - ATTR_TOTP_IMPORT => Attribute::TotpImport, - ATTR_UID => Attribute::Uid, - ATTR_UIDNUMBER => Attribute::UidNumber, - ATTR_UNIQUE => Attribute::Unique, - ATTR_UNIX_PASSWORD => Attribute::UnixPassword, - ATTR_UNIX_PASSWORD_IMPORT => Attribute::UnixPasswordImport, - ATTR_USER_AUTH_TOKEN_SESSION => Attribute::UserAuthTokenSession, - ATTR_USERID => Attribute::UserId, - ATTR_USERPASSWORD => Attribute::UserPassword, - ATTR_UUID => Attribute::Uuid, - ATTR_VERSION => Attribute::Version, - ATTR_WEBAUTHN_ATTESTATION_CA_LIST => Attribute::WebauthnAttestationCaList, - - #[cfg(any(debug_assertions, test))] - TEST_ATTR_NON_EXIST => Attribute::NonExist, - #[cfg(any(debug_assertions, test))] - TEST_ATTR_TEST_ATTR => Attribute::TestAttr, - #[cfg(any(debug_assertions, test))] - TEST_ATTR_EXTRA => Attribute::Extra, - #[cfg(any(debug_assertions, test))] - TEST_ATTR_NUMBER => Attribute::TestNumber, - #[cfg(any(debug_assertions, test))] - TEST_ATTR_NOTALLOWED => Attribute::TestNotAllowed, - _ => { - trace!("Failed to convert {} to Attribute", val); - return Err(OperationError::InvalidAttributeName(val.to_string())); - } - }; - Ok(res) +impl From<&str> for Attribute { + fn from(value: &str) -> Self { + Self::from_str(value) } } -impl From for &'static str { +impl<'a> From<&'a Attribute> for &'a str { + fn from(val: &'a Attribute) -> Self { + val.as_str() + } +} + +impl From for AttrString { fn from(val: Attribute) -> Self { - match val { + AttrString::from(val.as_str()) + } +} + +impl Attribute { + pub fn as_str(&self) -> &str { + match self { Attribute::Account => ATTR_ACCOUNT, Attribute::AccountExpire => ATTR_ACCOUNT_EXPIRE, Attribute::AccountValidFrom => ATTR_ACCOUNT_VALID_FROM, @@ -542,30 +381,210 @@ impl From for &'static str { Attribute::Version => ATTR_VERSION, Attribute::WebauthnAttestationCaList => ATTR_WEBAUTHN_ATTESTATION_CA_LIST, - #[cfg(any(debug_assertions, test))] + #[cfg(any(debug_assertions, test, feature = "test"))] Attribute::NonExist => TEST_ATTR_NON_EXIST, - #[cfg(any(debug_assertions, test))] + #[cfg(any(debug_assertions, test, feature = "test"))] Attribute::TestAttr => TEST_ATTR_TEST_ATTR, - #[cfg(any(debug_assertions, test))] + #[cfg(any(debug_assertions, test, feature = "test"))] Attribute::Extra => TEST_ATTR_EXTRA, - #[cfg(any(debug_assertions, test))] + #[cfg(any(debug_assertions, test, feature = "test"))] Attribute::TestNumber => TEST_ATTR_NUMBER, - #[cfg(any(debug_assertions, test))] + #[cfg(any(debug_assertions, test, feature = "test"))] Attribute::TestNotAllowed => TEST_ATTR_NOTALLOWED, + + #[cfg(not(test))] + Attribute::Custom(value) => value.as_str(), } } -} -impl From for AttrString { - fn from(val: Attribute) -> Self { - AttrString::from(val.to_string()) + // We allow this because the standard lib from_str is fallible, and we want an infallible version. + #[allow(clippy::should_implement_trait)] + pub fn from_str(value: &str) -> Self { + // Could this be something like heapless to save allocations? Also gives a way + // to limit length of str? + match value.to_lowercase().as_str() { + ATTR_ACCOUNT => Attribute::Account, + ATTR_ACCOUNT_EXPIRE => Attribute::AccountExpire, + ATTR_ACCOUNT_VALID_FROM => Attribute::AccountValidFrom, + ATTR_ACP_CREATE_ATTR => Attribute::AcpCreateAttr, + ATTR_ACP_CREATE_CLASS => Attribute::AcpCreateClass, + ATTR_ACP_ENABLE => Attribute::AcpEnable, + ATTR_ACP_MODIFY_CLASS => Attribute::AcpModifyClass, + ATTR_ACP_MODIFY_PRESENTATTR => Attribute::AcpModifyPresentAttr, + ATTR_ACP_MODIFY_REMOVEDATTR => Attribute::AcpModifyRemovedAttr, + ATTR_ACP_RECEIVER => Attribute::AcpReceiver, + ATTR_ACP_RECEIVER_GROUP => Attribute::AcpReceiverGroup, + ATTR_ACP_SEARCH_ATTR => Attribute::AcpSearchAttr, + ATTR_ACP_TARGET_SCOPE => Attribute::AcpTargetScope, + ATTR_API_TOKEN_SESSION => Attribute::ApiTokenSession, + ATTR_APPLICATION_PASSWORD => Attribute::ApplicationPassword, + ATTR_ATTESTED_PASSKEYS => Attribute::AttestedPasskeys, + ATTR_ATTR => Attribute::Attr, + ATTR_ATTRIBUTENAME => Attribute::AttributeName, + ATTR_ATTRIBUTETYPE => Attribute::AttributeType, + ATTR_AUTH_SESSION_EXPIRY => Attribute::AuthSessionExpiry, + ATTR_AUTH_PASSWORD_MINIMUM_LENGTH => Attribute::AuthPasswordMinimumLength, + ATTR_BADLIST_PASSWORD => Attribute::BadlistPassword, + ATTR_CERTIFICATE => Attribute::Certificate, + ATTR_CLAIM => Attribute::Claim, + ATTR_CLASS => Attribute::Class, + ATTR_CLASSNAME => Attribute::ClassName, + ATTR_CN => Attribute::Cn, + ATTR_COOKIE_PRIVATE_KEY => Attribute::CookiePrivateKey, + ATTR_CREDENTIAL_UPDATE_INTENT_TOKEN => Attribute::CredentialUpdateIntentToken, + ATTR_CREDENTIAL_TYPE_MINIMUM => Attribute::CredentialTypeMinimum, + ATTR_DENIED_NAME => Attribute::DeniedName, + ATTR_DESCRIPTION => Attribute::Description, + ATTR_DIRECTMEMBEROF => Attribute::DirectMemberOf, + ATTR_DISPLAYNAME => Attribute::DisplayName, + ATTR_DN => Attribute::Dn, + ATTR_DOMAIN => Attribute::Domain, + ATTR_DOMAIN_DISPLAY_NAME => Attribute::DomainDisplayName, + ATTR_DOMAIN_DEVELOPMENT_TAINT => Attribute::DomainDevelopmentTaint, + ATTR_DOMAIN_LDAP_BASEDN => Attribute::DomainLdapBasedn, + ATTR_DOMAIN_NAME => Attribute::DomainName, + ATTR_DOMAIN_SSID => Attribute::DomainSsid, + ATTR_DOMAIN_TOKEN_KEY => Attribute::DomainTokenKey, + ATTR_DOMAIN_UUID => Attribute::DomainUuid, + ATTR_DYNGROUP => Attribute::DynGroup, + ATTR_DYNGROUP_FILTER => Attribute::DynGroupFilter, + ATTR_DYNMEMBER => Attribute::DynMember, + ATTR_EMAIL => Attribute::Email, + ATTR_EMAIL_ALTERNATIVE => Attribute::EmailAlternative, + ATTR_EMAIL_PRIMARY => Attribute::EmailPrimary, + ATTR_ENTRYDN => Attribute::EntryDn, + ATTR_ENTRY_MANAGED_BY => Attribute::EntryManagedBy, + ATTR_ENTRYUUID => Attribute::EntryUuid, + ATTR_ES256_PRIVATE_KEY_DER => Attribute::Es256PrivateKeyDer, + ATTR_EXCLUDES => Attribute::Excludes, + ATTR_FERNET_PRIVATE_KEY_STR => Attribute::FernetPrivateKeyStr, + ATTR_GECOS => Attribute::Gecos, + ATTR_GIDNUMBER => Attribute::GidNumber, + ATTR_GRANT_UI_HINT => Attribute::GrantUiHint, + ATTR_GROUP => Attribute::Group, + ATTR_ID_VERIFICATION_ECKEY => Attribute::IdVerificationEcKey, + ATTR_IMAGE => Attribute::Image, + ATTR_INDEX => Attribute::Index, + ATTR_IPANTHASH => Attribute::IpaNtHash, + ATTR_IPASSHPUBKEY => Attribute::IpaSshPubKey, + ATTR_JWS_ES256_PRIVATE_KEY => Attribute::JwsEs256PrivateKey, + ATTR_KEY_ACTION_ROTATE => Attribute::KeyActionRotate, + ATTR_KEY_ACTION_REVOKE => Attribute::KeyActionRevoke, + ATTR_KEY_ACTION_IMPORT_JWS_ES256 => Attribute::KeyActionImportJwsEs256, + ATTR_KEY_INTERNAL_DATA => Attribute::KeyInternalData, + ATTR_KEY_PROVIDER => Attribute::KeyProvider, + ATTR_LAST_MODIFIED_CID => Attribute::LastModifiedCid, + ATTR_LDAP_ALLOW_UNIX_PW_BIND => Attribute::LdapAllowUnixPwBind, + ATTR_LDAP_EMAIL_ADDRESS => Attribute::LdapEmailAddress, + ATTR_LDAP_KEYS => Attribute::LdapKeys, + ATTR_SSH_PUBLICKEY => Attribute::SshPublicKey, + ATTR_LEGALNAME => Attribute::LegalName, + ATTR_LINKEDGROUP => Attribute::LinkedGroup, + ATTR_LOGINSHELL => Attribute::LoginShell, + ATTR_LIMIT_SEARCH_MAX_RESULTS => Attribute::LimitSearchMaxResults, + ATTR_LIMIT_SEARCH_MAX_FILTER_TEST => Attribute::LimitSearchMaxFilterTest, + ATTR_MAIL => Attribute::Mail, + ATTR_MAY => Attribute::May, + ATTR_MEMBER => Attribute::Member, + ATTR_MEMBEROF => Attribute::MemberOf, + ATTR_MULTIVALUE => Attribute::MultiValue, + ATTR_MUST => Attribute::Must, + ATTR_NAME => Attribute::Name, + ATTR_NAME_HISTORY => Attribute::NameHistory, + ATTR_NO_INDEX => Attribute::NoIndex, + ATTR_NSUNIQUEID => Attribute::NsUniqueId, + ATTR_NSACCOUNTLOCK => Attribute::NsAccountLock, + ATTR_OAUTH2_ALLOW_INSECURE_CLIENT_DISABLE_PKCE => { + Attribute::OAuth2AllowInsecureClientDisablePkce + } + ATTR_OAUTH2_ALLOW_LOCALHOST_REDIRECT => Attribute::OAuth2AllowLocalhostRedirect, + ATTR_OAUTH2_CONSENT_SCOPE_MAP => Attribute::OAuth2ConsentScopeMap, + ATTR_OAUTH2_JWT_LEGACY_CRYPTO_ENABLE => Attribute::OAuth2JwtLegacyCryptoEnable, + ATTR_OAUTH2_PREFER_SHORT_USERNAME => Attribute::OAuth2PreferShortUsername, + ATTR_OAUTH2_RS_BASIC_SECRET => Attribute::OAuth2RsBasicSecret, + ATTR_OAUTH2_RS_CLAIM_MAP => Attribute::OAuth2RsClaimMap, + ATTR_OAUTH2_RS_IMPLICIT_SCOPES => Attribute::OAuth2RsImplicitScopes, + ATTR_OAUTH2_RS_NAME => Attribute::OAuth2RsName, + ATTR_OAUTH2_RS_ORIGIN => Attribute::OAuth2RsOrigin, + ATTR_OAUTH2_RS_ORIGIN_LANDING => Attribute::OAuth2RsOriginLanding, + ATTR_OAUTH2_RS_SCOPE_MAP => Attribute::OAuth2RsScopeMap, + ATTR_OAUTH2_RS_SUP_SCOPE_MAP => Attribute::OAuth2RsSupScopeMap, + ATTR_OAUTH2_RS_TOKEN_KEY => Attribute::OAuth2RsTokenKey, + ATTR_OAUTH2_SESSION => Attribute::OAuth2Session, + ATTR_OAUTH2_STRICT_REDIRECT_URI => Attribute::OAuth2StrictRedirectUri, + ATTR_OBJECTCLASS => Attribute::ObjectClass, + ATTR_OTHER_NO_INDEX => Attribute::OtherNoIndex, + ATTR_PASSKEYS => Attribute::PassKeys, + ATTR_PASSWORD_IMPORT => Attribute::PasswordImport, + ATTR_PATCH_LEVEL => Attribute::PatchLevel, + ATTR_PHANTOM => Attribute::Phantom, + ATTR_PRIMARY_CREDENTIAL => Attribute::PrimaryCredential, + ATTR_PRIVATE_COOKIE_KEY => Attribute::PrivateCookieKey, + ATTR_PRIVILEGE_EXPIRY => Attribute::PrivilegeExpiry, + ATTR_RADIUS_SECRET => Attribute::RadiusSecret, + ATTR_RECYCLEDDIRECTMEMBEROF => Attribute::RecycledDirectMemberOf, + ATTR_REFERS => Attribute::Refers, + ATTR_REPLICATED => Attribute::Replicated, + ATTR_RS256_PRIVATE_KEY_DER => Attribute::Rs256PrivateKeyDer, + ATTR_SCOPE => Attribute::Scope, + ATTR_SOURCE_UUID => Attribute::SourceUuid, + ATTR_SPN => Attribute::Spn, + ATTR_LDAP_SSHPUBLICKEY => Attribute::LdapSshPublicKey, + ATTR_SUDOHOST => Attribute::SudoHost, + ATTR_SUPPLEMENTS => Attribute::Supplements, + ATTR_SYNC_ALLOWED => Attribute::SyncAllowed, + ATTR_SYNC_CLASS => Attribute::SyncClass, + ATTR_SYNC_COOKIE => Attribute::SyncCookie, + ATTR_SYNC_CREDENTIAL_PORTAL => Attribute::SyncCredentialPortal, + ATTR_SYNC_EXTERNAL_ID => Attribute::SyncExternalId, + ATTR_SYNC_PARENT_UUID => Attribute::SyncParentUuid, + ATTR_SYNC_TOKEN_SESSION => Attribute::SyncTokenSession, + ATTR_SYNC_YIELD_AUTHORITY => Attribute::SyncYieldAuthority, + ATTR_SYNTAX => Attribute::Syntax, + ATTR_SYSTEMEXCLUDES => Attribute::SystemExcludes, + ATTR_SYSTEMMAY => Attribute::SystemMay, + ATTR_SYSTEMMUST => Attribute::SystemMust, + ATTR_SYSTEMSUPPLEMENTS => Attribute::SystemSupplements, + ATTR_TERM => Attribute::Term, + ATTR_TOTP_IMPORT => Attribute::TotpImport, + ATTR_UID => Attribute::Uid, + ATTR_UIDNUMBER => Attribute::UidNumber, + ATTR_UNIQUE => Attribute::Unique, + ATTR_UNIX_PASSWORD => Attribute::UnixPassword, + ATTR_UNIX_PASSWORD_IMPORT => Attribute::UnixPasswordImport, + ATTR_USER_AUTH_TOKEN_SESSION => Attribute::UserAuthTokenSession, + ATTR_USERID => Attribute::UserId, + ATTR_USERPASSWORD => Attribute::UserPassword, + ATTR_UUID => Attribute::Uuid, + ATTR_VERSION => Attribute::Version, + ATTR_WEBAUTHN_ATTESTATION_CA_LIST => Attribute::WebauthnAttestationCaList, + + #[cfg(any(debug_assertions, test, feature = "test"))] + TEST_ATTR_NON_EXIST => Attribute::NonExist, + #[cfg(any(debug_assertions, test, feature = "test"))] + TEST_ATTR_TEST_ATTR => Attribute::TestAttr, + #[cfg(any(debug_assertions, test, feature = "test"))] + TEST_ATTR_EXTRA => Attribute::Extra, + #[cfg(any(debug_assertions, test, feature = "test"))] + TEST_ATTR_NUMBER => Attribute::TestNumber, + #[cfg(any(debug_assertions, test, feature = "test"))] + TEST_ATTR_NOTALLOWED => Attribute::TestNotAllowed, + + #[cfg(not(test))] + _ => Attribute::Custom(AttrString::from(value)), + // Allowed only in tests + #[allow(clippy::unreachable)] + #[cfg(test)] + _ => { + unreachable!() + } + } } } impl fmt::Display for Attribute { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let s: &'static str = (*self).into(); - write!(f, "{}", s) + write!(f, "{}", self.as_str()) } } @@ -575,7 +594,7 @@ mod test { #[test] fn test_valueattribute_as_str() { - assert!(Attribute::Class.as_ref() == "class"); + assert!(Attribute::Class.as_str() == "class"); assert!(Attribute::Class.to_string() == *"class"); } @@ -585,8 +604,7 @@ mod test { use enum_iterator::all; let the_list = all::().collect::>(); for attr in the_list { - let s: &'static str = attr.into(); - let attr2 = Attribute::try_from(s).unwrap(); + let attr2 = Attribute::from(attr.as_str()); assert!(attr == attr2); } } diff --git a/proto/src/internal/error.rs b/proto/src/internal/error.rs index d774aae37..f893c4e3f 100644 --- a/proto/src/internal/error.rs +++ b/proto/src/internal/error.rs @@ -5,6 +5,7 @@ use utoipa::ToSchema; use uuid::Uuid; use super::credupdate::PasswordFeedback; +use crate::attribute::Attribute; /* ===== errors ===== */ #[derive(Serialize, Deserialize, Debug, PartialEq, Eq, ToSchema)] @@ -13,7 +14,7 @@ pub enum SchemaError { NotImplemented, NoClassFound, InvalidClass(Vec), - MissingMustAttribute(Vec), + MissingMustAttribute(Vec), InvalidAttribute(String), InvalidAttributeSyntax(String), AttributeNotValidForClass(String), diff --git a/proto/src/oauth2.rs b/proto/src/oauth2.rs index 4dd8fe888..a17305e1a 100644 --- a/proto/src/oauth2.rs +++ b/proto/src/oauth2.rs @@ -520,7 +520,8 @@ mod tests { assert_eq!(at, super::AccessTokenType::DPoP); } - for testcase in ["cheese"] { + { + let testcase = "cheese"; let at = serde_json::from_str::(&format!("\"{}\"", testcase)); assert!(at.is_err()) } diff --git a/server/core/src/actors/v1_read.rs b/server/core/src/actors/v1_read.rs index a326a7d23..40007cfe0 100644 --- a/server/core/src/actors/v1_read.rs +++ b/server/core/src/actors/v1_read.rs @@ -77,14 +77,14 @@ impl QueryServerReadV1 { let ident = idms_prox_read .validate_client_auth_info_to_ident(client_auth_info, ct) .map_err(|e| { - admin_error!(?e, "Invalid identity"); + error!(?e, "Invalid identity"); e })?; // Make an event from the request let search = SearchEvent::from_message(ident, &req, &mut idms_prox_read.qs_read).map_err(|e| { - admin_error!(?e, "Failed to begin search"); + error!(?e, "Failed to begin search"); e })?; @@ -120,7 +120,7 @@ impl QueryServerReadV1 { // Convert the AuthRequest to an AuthEvent that the idm server // can use. let ae = AuthEvent::from_message(sessionid, req).map_err(|e| { - admin_error!(err = ?e, "Failed to parse AuthEvent"); + error!(err = ?e, "Failed to parse AuthEvent"); e })?; @@ -160,7 +160,7 @@ impl QueryServerReadV1 { let ident = idm_auth .validate_client_auth_info_to_ident(client_auth_info.clone(), ct) .map_err(|e| { - admin_error!(?e, "Invalid identity"); + error!(?e, "Invalid identity"); e })?; @@ -333,12 +333,12 @@ impl QueryServerReadV1 { let ident = idms_prox_read .validate_client_auth_info_to_ident(client_auth_info, ct) .map_err(|e| { - admin_error!(?e, "Invalid identity"); + error!(?e, "Invalid identity"); e })?; let srch = SearchEvent::from_whoami_request(ident, &idms_prox_read.qs_read).map_err(|e| { - admin_error!(?e, "Failed to begin whoami"); + error!(?e, "Failed to begin whoami"); e })?; @@ -378,7 +378,7 @@ impl QueryServerReadV1 { idms_prox_read .validate_client_auth_info_to_uat(client_auth_info, ct) .map_err(|e| { - admin_error!(?e, "Invalid identity"); + error!(?e, "Invalid identity"); e }) } @@ -396,7 +396,7 @@ impl QueryServerReadV1 { let ident = idms_prox_read .validate_client_auth_info_to_ident(client_auth_info, ct) .map_err(|e| { - admin_error!(err = ?e, "Invalid identity in handle_oauth2_rs_image_get_image"); + error!(err = ?e, "Invalid identity in handle_oauth2_rs_image_get_image"); e })?; let attrs = vec![Attribute::Image.to_string()]; @@ -431,7 +431,7 @@ impl QueryServerReadV1 { let ident = idms_prox_read .validate_client_auth_info_to_ident(client_auth_info, ct) .map_err(|e| { - admin_error!("Invalid identity: {:?}", e); + error!("Invalid identity: {:?}", e); e })?; // Make an event from the request @@ -443,7 +443,7 @@ impl QueryServerReadV1 { ) { Ok(s) => s, Err(e) => { - admin_error!("Failed to begin internal api search: {:?}", e); + error!("Failed to begin internal api search: {:?}", e); return Err(e); } }; @@ -475,16 +475,15 @@ impl QueryServerReadV1 { let ident = idms_prox_read .validate_client_auth_info_to_ident(client_auth_info, ct) .map_err(|e| { - admin_error!("Invalid identity: {:?}", e); + error!("Invalid identity: {:?}", e); e })?; let target_uuid = idms_prox_read .qs_read .name_to_uuid(uuid_or_name.as_str()) - .map_err(|e| { - admin_error!("Error resolving id to target"); - e + .inspect_err(|err| { + error!(?err, "Error resolving id to target"); })?; // Update the filter with the target_uuid @@ -502,7 +501,7 @@ impl QueryServerReadV1 { ) { Ok(s) => s, Err(e) => { - admin_error!("Failed to begin internal api search: {:?}", e); + error!("Failed to begin internal api search: {:?}", e); return Err(e); } }; @@ -534,7 +533,7 @@ impl QueryServerReadV1 { let ident = idms_prox_read .validate_client_auth_info_to_ident(client_auth_info, ct) .map_err(|e| { - admin_error!("Invalid identity: {:?}", e); + error!("Invalid identity: {:?}", e); e })?; // Make an event from the request @@ -546,7 +545,7 @@ impl QueryServerReadV1 { ) { Ok(s) => s, Err(e) => { - admin_error!("Failed to begin recycled search: {:?}", e); + error!("Failed to begin recycled search: {:?}", e); return Err(e); } }; @@ -576,16 +575,15 @@ impl QueryServerReadV1 { let ident = idms_prox_read .validate_client_auth_info_to_ident(client_auth_info, ct) .map_err(|e| { - admin_error!("Invalid identity: {:?}", e); + error!("Invalid identity: {:?}", e); e })?; let target_uuid = idms_prox_read .qs_read .name_to_uuid(uuid_or_name.as_str()) - .map_err(|e| { - admin_error!("Error resolving id to target"); - e + .inspect_err(|err| { + error!(?err, "Error resolving id to target"); })?; // Make an event from the request @@ -596,7 +594,7 @@ impl QueryServerReadV1 { ) { Ok(s) => s, Err(e) => { - admin_error!("Failed to begin radius read: {:?}", e); + error!("Failed to begin radius read: {:?}", e); return Err(e); } }; @@ -637,16 +635,15 @@ impl QueryServerReadV1 { let ident = idms_prox_read .validate_client_auth_info_to_ident(client_auth_info, ct) .map_err(|e| { - admin_error!("Invalid identity: {:?}", e); + error!("Invalid identity: {:?}", e); e })?; let target_uuid = idms_prox_read .qs_read .name_to_uuid(uuid_or_name.as_str()) - .map_err(|e| { - admin_error!("Error resolving id to target"); - e + .inspect_err(|err| { + error!(?err, "Error resolving id to target"); })?; // Make an event from the request @@ -657,7 +654,7 @@ impl QueryServerReadV1 { ) { Ok(s) => s, Err(e) => { - admin_error!("Failed to begin radius token read: {:?}", e); + error!("Failed to begin radius token read: {:?}", e); return Err(e); } }; @@ -684,7 +681,7 @@ impl QueryServerReadV1 { let ident = idms_prox_read .validate_client_auth_info_to_ident(client_auth_info, ct) .map_err(|e| { - admin_error!("Invalid identity: {:?}", e); + error!("Invalid identity: {:?}", e); e })?; @@ -710,7 +707,7 @@ impl QueryServerReadV1 { let rate = match UnixUserTokenEvent::from_parts(ident, target_uuid) { Ok(s) => s, Err(e) => { - admin_error!("Failed to begin unix token read: {:?}", e); + error!("Failed to begin unix token read: {:?}", e); return Err(e); } }; @@ -736,7 +733,7 @@ impl QueryServerReadV1 { let ident = idms_prox_read .validate_client_auth_info_to_ident(client_auth_info, ct) .map_err(|e| { - admin_error!("Invalid identity: {:?}", e); + error!("Invalid identity: {:?}", e); e })?; @@ -756,7 +753,7 @@ impl QueryServerReadV1 { ) { Ok(s) => s, Err(e) => { - admin_error!("Failed to begin unix group token read: {:?}", e); + error!("Failed to begin unix group token read: {:?}", e); return Err(e); } }; @@ -782,15 +779,14 @@ impl QueryServerReadV1 { let ident = idms_prox_read .validate_client_auth_info_to_ident(client_auth_info, ct) .map_err(|e| { - admin_error!("Invalid identity: {:?}", e); + error!("Invalid identity: {:?}", e); e })?; let target_uuid = idms_prox_read .qs_read .name_to_uuid(uuid_or_name.as_str()) - .map_err(|e| { - admin_error!("Error resolving id to target"); - e + .inspect_err(|err| { + error!(?err, "Error resolving id to target"); })?; // Make an event from the request @@ -801,7 +797,7 @@ impl QueryServerReadV1 { ) { Ok(s) => s, Err(e) => { - admin_error!("Failed to begin ssh key read: {:?}", e); + error!("Failed to begin ssh key read: {:?}", e); return Err(e); } }; @@ -845,15 +841,14 @@ impl QueryServerReadV1 { let ident = idms_prox_read .validate_client_auth_info_to_ident(client_auth_info, ct) .map_err(|e| { - admin_error!("Invalid identity: {:?}", e); + error!("Invalid identity: {:?}", e); e })?; let target_uuid = idms_prox_read .qs_read .name_to_uuid(uuid_or_name.as_str()) - .map_err(|e| { - admin_info!("Error resolving id to target"); - e + .inspect_err(|err| { + admin_info!(?err, "Error resolving id to target"); })?; // Make an event from the request @@ -864,7 +859,7 @@ impl QueryServerReadV1 { ) { Ok(s) => s, Err(e) => { - admin_error!("Failed to begin sshkey tag read: {:?}", e); + error!("Failed to begin sshkey tag read: {:?}", e); return Err(e); } }; @@ -909,15 +904,14 @@ impl QueryServerReadV1 { let ident = idms_prox_read .validate_client_auth_info_to_ident(client_auth_info, ct) .map_err(|e| { - admin_error!("Invalid identity: {:?}", e); + error!("Invalid identity: {:?}", e); e })?; let target = idms_prox_read .qs_read .name_to_uuid(uuid_or_name.as_str()) - .map_err(|e| { - admin_error!("Error resolving id to target"); - e + .inspect_err(|err| { + error!(?err, "Error resolving id to target"); })?; let lte = ListApiTokenEvent { ident, target }; @@ -941,15 +935,14 @@ impl QueryServerReadV1 { let ident = idms_prox_read .validate_client_auth_info_to_ident(client_auth_info, ct) .map_err(|e| { - admin_error!("Invalid identity: {:?}", e); + error!("Invalid identity: {:?}", e); e })?; let target = idms_prox_read .qs_read .name_to_uuid(uuid_or_name.as_str()) - .map_err(|e| { - admin_error!("Error resolving id to target"); - e + .inspect_err(|err| { + error!(?err, "Error resolving id to target"); })?; let lte = ListUserAuthTokenEvent { ident, target }; @@ -975,14 +968,14 @@ impl QueryServerReadV1 { let ident = idms_prox_read .validate_client_auth_info_to_ident(client_auth_info, ct) .map_err(|e| { - admin_error!("Invalid identity: {:?}", e); + error!("Invalid identity: {:?}", e); e })?; let target = idms_prox_read .qs_read .name_to_uuid(&other_id) .map_err(|e| { - admin_error!("No user found with the provided ID: {:?}", e); + error!("No user found with the provided ID: {:?}", e); e })?; match user_request { @@ -1016,7 +1009,7 @@ impl QueryServerReadV1 { let ident = idm_auth .validate_client_auth_info_to_ident(client_auth_info, ct) .map_err(|e| { - admin_error!(err = ?e, "Invalid identity"); + error!(err = ?e, "Invalid identity"); e })?; @@ -1031,7 +1024,7 @@ impl QueryServerReadV1 { let uuae = match UnixUserAuthEvent::from_parts(ident, target_uuid, cred) { Ok(s) => s, Err(e) => { - admin_error!(err = ?e, "Failed to begin unix auth"); + error!(err = ?e, "Failed to begin unix auth"); return Err(e); } }; @@ -1065,14 +1058,14 @@ impl QueryServerReadV1 { let ident = idms_prox_read .validate_client_auth_info_to_ident(client_auth_info, ct) .map_err(|e| { - admin_error!(err = ?e, "Invalid identity"); + error!(err = ?e, "Invalid identity"); e })?; let target_uuid = idms_prox_read .qs_read .name_to_uuid(uuid_or_name.as_str()) .map_err(|e| { - admin_error!(err = ?e, "Error resolving id to target"); + error!(err = ?e, "Error resolving id to target"); e })?; @@ -1084,7 +1077,7 @@ impl QueryServerReadV1 { ) { Ok(s) => s, Err(e) => { - admin_error!(err = ?e, "Failed to begin credential status read"); + error!(err = ?e, "Failed to begin credential status read"); return Err(e); } }; @@ -1111,15 +1104,14 @@ impl QueryServerReadV1 { let ident = idms_prox_read .validate_client_auth_info_to_ident(client_auth_info, ct) .map_err(|e| { - admin_error!("Invalid identity: {:?}", e); + error!("Invalid identity: {:?}", e); e })?; let target_uuid = idms_prox_read .qs_read .name_to_uuid(uuid_or_name.as_str()) - .map_err(|e| { - admin_error!("Error resolving id to target"); - e + .inspect_err(|err| { + error!(?err, "Error resolving id to target"); })?; // Make an event from the request @@ -1130,7 +1122,7 @@ impl QueryServerReadV1 { ) { Ok(s) => s, Err(e) => { - admin_error!("Failed to begin backup code read: {:?}", e); + error!("Failed to begin backup code read: {:?}", e); return Err(e); } }; @@ -1164,7 +1156,7 @@ impl QueryServerReadV1 { idms_cred_update .credential_update_status(&session_token, ct) .map_err(|e| { - admin_error!( + error!( err = ?e, "Failed to begin credential_update_status", ); @@ -1200,7 +1192,7 @@ impl QueryServerReadV1 { CURequest::PrimaryRemove => idms_cred_update .credential_primary_delete(&session_token, ct) .map_err(|e| { - admin_error!( + error!( err = ?e, "Failed to begin credential_primary_delete", ); @@ -1209,7 +1201,7 @@ impl QueryServerReadV1 { CURequest::Password(pw) => idms_cred_update .credential_primary_set_password(&session_token, ct, &pw) .map_err(|e| { - admin_error!( + error!( err = ?e, "Failed to begin credential_primary_set_password", ); @@ -1218,7 +1210,7 @@ impl QueryServerReadV1 { CURequest::CancelMFAReg => idms_cred_update .credential_update_cancel_mfareg(&session_token, ct) .map_err(|e| { - admin_error!( + error!( err = ?e, "Failed to begin credential_update_cancel_mfareg", ); @@ -1227,7 +1219,7 @@ impl QueryServerReadV1 { CURequest::TotpGenerate => idms_cred_update .credential_primary_init_totp(&session_token, ct) .map_err(|e| { - admin_error!( + error!( err = ?e, "Failed to begin credential_primary_init_totp", ); @@ -1236,7 +1228,7 @@ impl QueryServerReadV1 { CURequest::TotpVerify(totp_chal, label) => idms_cred_update .credential_primary_check_totp(&session_token, ct, totp_chal, &label) .map_err(|e| { - admin_error!( + error!( err = ?e, "Failed to begin credential_primary_check_totp", ); @@ -1245,7 +1237,7 @@ impl QueryServerReadV1 { CURequest::TotpAcceptSha1 => idms_cred_update .credential_primary_accept_sha1_totp(&session_token, ct) .map_err(|e| { - admin_error!( + error!( err = ?e, "Failed to begin credential_primary_accept_sha1_totp", ); @@ -1254,7 +1246,7 @@ impl QueryServerReadV1 { CURequest::TotpRemove(label) => idms_cred_update .credential_primary_remove_totp(&session_token, ct, &label) .map_err(|e| { - admin_error!( + error!( err = ?e, "Failed to begin credential_primary_remove_totp", ); @@ -1263,7 +1255,7 @@ impl QueryServerReadV1 { CURequest::BackupCodeGenerate => idms_cred_update .credential_primary_init_backup_codes(&session_token, ct) .map_err(|e| { - admin_error!( + error!( err = ?e, "Failed to begin credential_primary_init_backup_codes", ); @@ -1272,7 +1264,7 @@ impl QueryServerReadV1 { CURequest::BackupCodeRemove => idms_cred_update .credential_primary_remove_backup_codes(&session_token, ct) .map_err(|e| { - admin_error!( + error!( err = ?e, "Failed to begin credential_primary_remove_backup_codes", ); @@ -1281,7 +1273,7 @@ impl QueryServerReadV1 { CURequest::PasskeyInit => idms_cred_update .credential_passkey_init(&session_token, ct) .map_err(|e| { - admin_error!( + error!( err = ?e, "Failed to begin credential_passkey_init", ); @@ -1290,7 +1282,7 @@ impl QueryServerReadV1 { CURequest::PasskeyFinish(label, rpkc) => idms_cred_update .credential_passkey_finish(&session_token, ct, label, &rpkc) .map_err(|e| { - admin_error!( + error!( err = ?e, "Failed to begin credential_passkey_finish", ); @@ -1299,7 +1291,7 @@ impl QueryServerReadV1 { CURequest::PasskeyRemove(uuid) => idms_cred_update .credential_passkey_remove(&session_token, ct, uuid) .map_err(|e| { - admin_error!( + error!( err = ?e, "Failed to begin credential_passkey_remove", ); @@ -1308,7 +1300,7 @@ impl QueryServerReadV1 { CURequest::AttestedPasskeyInit => idms_cred_update .credential_attested_passkey_init(&session_token, ct) .map_err(|e| { - admin_error!( + error!( err = ?e, "Failed to begin credential_attested_passkey_init", ); @@ -1317,7 +1309,7 @@ impl QueryServerReadV1 { CURequest::AttestedPasskeyFinish(label, rpkc) => idms_cred_update .credential_attested_passkey_finish(&session_token, ct, label, &rpkc) .map_err(|e| { - admin_error!( + error!( err = ?e, "Failed to begin credential_attested_passkey_finish", ); @@ -1326,7 +1318,7 @@ impl QueryServerReadV1 { CURequest::AttestedPasskeyRemove(uuid) => idms_cred_update .credential_attested_passkey_remove(&session_token, ct, uuid) .map_err(|e| { - admin_error!( + error!( err = ?e, "Failed to begin credential_attested_passkey_remove", ); @@ -1352,7 +1344,7 @@ impl QueryServerReadV1 { let ident = idms_prox_read .validate_client_auth_info_to_ident(client_auth_info, ct) .map_err(|e| { - admin_error!("Invalid identity: {:?}", e); + error!("Invalid identity: {:?}", e); e })?; @@ -1365,7 +1357,7 @@ impl QueryServerReadV1 { ) { Ok(s) => s, Err(e) => { - admin_error!("Failed to begin oauth2 basic secret read: {:?}", e); + error!("Failed to begin oauth2 basic secret read: {:?}", e); return Err(e); } }; @@ -1409,7 +1401,7 @@ impl QueryServerReadV1 { let ident = idms_prox_read .validate_client_auth_info_to_ident(client_auth_info, ct) .map_err(|e| { - admin_error!("Invalid identity: {:?}", e); + error!("Invalid identity: {:?}", e); Oauth2Error::AuthenticationRequired })?; @@ -1433,7 +1425,7 @@ impl QueryServerReadV1 { let ident = idms_prox_read .validate_client_auth_info_to_ident(client_auth_info, ct) .map_err(|e| { - admin_error!("Invalid identity: {:?}", e); + error!("Invalid identity: {:?}", e); e })?; @@ -1538,7 +1530,7 @@ impl QueryServerReadV1 { let ident = idms_prox_read .validate_client_auth_info_to_ident(client_auth_info, ct) .map_err(|e| { - admin_error!("Invalid identity: {:?}", e); + error!("Invalid identity: {:?}", e); e })?; @@ -1563,7 +1555,7 @@ impl QueryServerReadV1 { .validate_client_auth_info_to_ident(client_auth_info, ct) .map(|_| ()) .map_err(|e| { - admin_error!("Invalid identity: {:?}", e); + error!("Invalid identity: {:?}", e); e }) } @@ -1602,7 +1594,7 @@ impl QueryServerReadV1 { .do_op(&self.idms, server_op, uat, ip_addr, eventid) .await .unwrap_or_else(|e| { - admin_error!("do_op failed -> {:?}", e); + error!("do_op failed -> {:?}", e); LdapResponseState::Disconnect(DisconnectionNotice::gen( LdapResultCode::Other, format!("Internal Server Error {:?}", &eventid).as_str(), diff --git a/server/core/src/actors/v1_write.rs b/server/core/src/actors/v1_write.rs index e291b0b17..b27f3afa8 100644 --- a/server/core/src/actors/v1_write.rs +++ b/server/core/src/actors/v1_write.rs @@ -50,7 +50,7 @@ impl QueryServerWriteV1 { let ident = idms_prox_write .validate_client_auth_info_to_ident(client_auth_info, ct) .map_err(|e| { - admin_error!(err = ?e, "Invalid identity"); + error!(err = ?e, "Invalid identity"); e })?; @@ -58,7 +58,7 @@ impl QueryServerWriteV1 { .qs_write .name_to_uuid(uuid_or_name) .map_err(|e| { - admin_error!(err = ?e, "Error resolving id to target"); + error!(err = ?e, "Error resolving id to target"); e })?; @@ -71,7 +71,7 @@ impl QueryServerWriteV1 { ) { Ok(m) => m, Err(e) => { - admin_error!(err=?e, "Failed to begin modify during modify_from_parts"); + error!(err=?e, "Failed to begin modify during modify_from_parts"); return Err(e); } }; @@ -98,16 +98,15 @@ impl QueryServerWriteV1 { let ident = idms_prox_write .validate_client_auth_info_to_ident(client_auth_info, ct) .map_err(|e| { - admin_error!(err = ?e, "Invalid identity"); + error!(err = ?e, "Invalid identity"); e })?; let target_uuid = idms_prox_write .qs_write .name_to_uuid(uuid_or_name) - .map_err(|e| { - admin_error!("Error resolving id to target"); - e + .inspect_err(|err| { + error!(?err, "Error resolving id to target"); })?; let f_uuid = filter_all!(f_eq(Attribute::Uuid, PartialValue::Uuid(target_uuid))); @@ -122,7 +121,7 @@ impl QueryServerWriteV1 { ) { Ok(m) => m, Err(e) => { - admin_error!(err = ?e, "Failed to begin modify during modify_from_internal_parts"); + error!(err = ?e, "Failed to begin modify during modify_from_internal_parts"); return Err(e); } }; @@ -152,7 +151,7 @@ impl QueryServerWriteV1 { let ident = idms_prox_write .validate_client_auth_info_to_ident(client_auth_info, ct) .map_err(|e| { - admin_error!(err = ?e, "Invalid identity"); + error!(err = ?e, "Invalid identity"); e })?; @@ -188,14 +187,14 @@ impl QueryServerWriteV1 { let ident = idms_prox_write .validate_client_auth_info_to_ident(client_auth_info, ct) .map_err(|e| { - admin_error!(err = ?e, "Invalid identity"); + error!(err = ?e, "Invalid identity"); e })?; let mdf = match ModifyEvent::from_message(ident, &req, &mut idms_prox_write.qs_write) { Ok(m) => m, Err(e) => { - admin_error!(err = ?e, "Failed to begin modify during handle_modify"); + error!(err = ?e, "Failed to begin modify during handle_modify"); return Err(e); } }; @@ -224,13 +223,13 @@ impl QueryServerWriteV1 { let ident = idms_prox_write .validate_client_auth_info_to_ident(client_auth_info, ct) .map_err(|e| { - admin_error!(err = ?e, "Invalid identity"); + error!(err = ?e, "Invalid identity"); e })?; let del = match DeleteEvent::from_message(ident, &req, &mut idms_prox_write.qs_write) { Ok(d) => d, Err(e) => { - admin_error!(err = ?e, "Failed to begin delete"); + error!(err = ?e, "Failed to begin delete"); return Err(e); } }; @@ -261,21 +260,21 @@ impl QueryServerWriteV1 { let ident = idms_prox_write .validate_client_auth_info_to_ident(client_auth_info, ct) .map_err(|e| { - admin_error!(err = ?e, "Invalid identity"); + error!(err = ?e, "Invalid identity"); e })?; // Transform the ProtoEntry to a Modlist let modlist = ModifyList::from_patch(&update, &mut idms_prox_write.qs_write).map_err(|e| { - admin_error!(err = ?e, "Invalid Patch Request"); + error!(err = ?e, "Invalid Patch Request"); e })?; let mdf = ModifyEvent::from_internal_parts(ident, &modlist, &filter, &idms_prox_write.qs_write) .map_err(|e| { - admin_error!(err = ?e, "Failed to begin modify during handle_internalpatch"); + error!(err = ?e, "Failed to begin modify during handle_internalpatch"); e })?; @@ -303,13 +302,13 @@ impl QueryServerWriteV1 { let ident = idms_prox_write .validate_client_auth_info_to_ident(client_auth_info, ct) .map_err(|e| { - admin_error!(err = ?e, "Invalid identity"); + error!(err = ?e, "Invalid identity"); e })?; let del = match DeleteEvent::from_parts(ident, &filter, &mut idms_prox_write.qs_write) { Ok(d) => d, Err(e) => { - admin_error!(err = ?e, "Failed to begin delete"); + error!(err = ?e, "Failed to begin delete"); return Err(e); } }; @@ -338,13 +337,13 @@ impl QueryServerWriteV1 { let ident = idms_prox_write .validate_client_auth_info_to_ident(client_auth_info, ct) .map_err(|e| { - admin_error!(err = ?e, "Invalid identity"); + error!(err = ?e, "Invalid identity"); e })?; let rev = match ReviveRecycledEvent::from_parts(ident, &filter, &idms_prox_write.qs_write) { Ok(r) => r, Err(e) => { - admin_error!(err = ?e, "Failed to begin revive"); + error!(err = ?e, "Failed to begin revive"); return Err(e); } }; @@ -373,7 +372,7 @@ impl QueryServerWriteV1 { let ident = idms_prox_write .validate_client_auth_info_to_ident(client_auth_info, ct) .map_err(|e| { - admin_error!(err = ?e, "Invalid identity"); + error!(err = ?e, "Invalid identity"); e })?; @@ -386,12 +385,12 @@ impl QueryServerWriteV1 { .qs_write .name_to_uuid(uuid_or_name.as_str()) .map_err(|e| { - admin_error!(err = ?e, "Error resolving id to target"); + error!(err = ?e, "Error resolving id to target"); e })?; let gpe = GeneratePasswordEvent::from_parts(ident, target_uuid).map_err(|e| { - admin_error!( + error!( err = ?e, "Failed to begin handle_service_account_credential_generate", ); @@ -421,7 +420,7 @@ impl QueryServerWriteV1 { let ident = idms_prox_write .validate_client_auth_info_to_ident(client_auth_info, ct) .map_err(|e| { - admin_error!(err = ?e, "Invalid identity"); + error!(err = ?e, "Invalid identity"); e })?; @@ -429,7 +428,7 @@ impl QueryServerWriteV1 { .qs_write .name_to_uuid(uuid_or_name.as_str()) .map_err(|e| { - admin_error!(err = ?e, "Error resolving id to target"); + error!(err = ?e, "Error resolving id to target"); e })?; @@ -464,7 +463,7 @@ impl QueryServerWriteV1 { let ident = idms_prox_write .validate_client_auth_info_to_ident(client_auth_info, ct) .map_err(|e| { - admin_error!(err = ?e, "Invalid identity"); + error!(err = ?e, "Invalid identity"); e })?; @@ -472,7 +471,7 @@ impl QueryServerWriteV1 { .qs_write .name_to_uuid(uuid_or_name.as_str()) .map_err(|e| { - admin_error!(err = ?e, "Error resolving id to target"); + error!(err = ?e, "Error resolving id to target"); e })?; @@ -504,7 +503,7 @@ impl QueryServerWriteV1 { let ident = idms_prox_write .validate_client_auth_info_to_ident(client_auth_info, ct) .map_err(|e| { - admin_error!(err = ?e, "Invalid identity"); + error!(err = ?e, "Invalid identity"); e })?; @@ -512,7 +511,7 @@ impl QueryServerWriteV1 { .qs_write .name_to_uuid(uuid_or_name.as_str()) .map_err(|e| { - admin_error!(err = ?e, "Error resolving id to target"); + error!(err = ?e, "Error resolving id to target"); e })?; @@ -550,7 +549,7 @@ impl QueryServerWriteV1 { return Ok(()) } Err(err) => { - admin_error!(?err, "Invalid identity"); + error!(?err, "Invalid identity"); return Err(err); } }; @@ -561,7 +560,7 @@ impl QueryServerWriteV1 { }; let target = ident.get_uuid().ok_or_else(|| { - admin_error!("Invalid identity - no uuid present"); + error!("Invalid identity - no uuid present"); OperationError::InvalidState })?; @@ -594,7 +593,7 @@ impl QueryServerWriteV1 { let ident = idms_prox_write .validate_client_auth_info_to_ident(client_auth_info, ct) .map_err(|e| { - admin_error!(err = ?e, "Invalid identity"); + error!(err = ?e, "Invalid identity"); e })?; @@ -602,7 +601,7 @@ impl QueryServerWriteV1 { .qs_write .name_to_uuid(uuid_or_name.as_str()) .map_err(|e| { - admin_error!(err = ?e, "Error resolving id to target"); + error!(err = ?e, "Error resolving id to target"); e })?; @@ -610,7 +609,7 @@ impl QueryServerWriteV1 { .init_credential_update(&InitCredentialUpdateEvent::new(ident, target_uuid), ct) .and_then(|tok| idms_prox_write.commit().map(|_| tok)) .map_err(|e| { - admin_error!( + error!( err = ?e, "Failed to begin init_credential_update", ); @@ -643,7 +642,7 @@ impl QueryServerWriteV1 { let ident = idms_prox_write .validate_client_auth_info_to_ident(client_auth_info, ct) .map_err(|e| { - admin_error!(err = ?e, "Invalid identity"); + error!(err = ?e, "Invalid identity"); e })?; @@ -651,7 +650,7 @@ impl QueryServerWriteV1 { .qs_write .name_to_uuid(uuid_or_name.as_str()) .map_err(|e| { - admin_error!(err = ?e, "Error resolving id to target"); + error!(err = ?e, "Error resolving id to target"); e })?; @@ -662,7 +661,7 @@ impl QueryServerWriteV1 { ) .and_then(|tok| idms_prox_write.commit().map(|_| tok)) .map_err(|e| { - admin_error!( + error!( err = ?e, "Failed to begin init_credential_update_intent", ); @@ -693,7 +692,7 @@ impl QueryServerWriteV1 { .exchange_intent_credential_update(intent_token, ct) .and_then(|tok| idms_prox_write.commit().map(|_| tok)) .map_err(|e| { - admin_error!( + error!( err = ?e, "Failed to begin exchange_intent_credential_update", ); @@ -733,7 +732,7 @@ impl QueryServerWriteV1 { .commit_credential_update(&session_token, ct) .and_then(|tok| idms_prox_write.commit().map(|_| tok)) .map_err(|e| { - admin_error!( + error!( err = ?e, "Failed to begin commit_credential_update", ); @@ -765,7 +764,7 @@ impl QueryServerWriteV1 { .cancel_credential_update(&session_token, ct) .and_then(|tok| idms_prox_write.commit().map(|_| tok)) .map_err(|e| { - admin_error!( + error!( err = ?e, "Failed to begin commit_credential_cancel", ); @@ -789,14 +788,14 @@ impl QueryServerWriteV1 { let ident = idms_prox_write .validate_client_auth_info_to_ident(client_auth_info, ct) .map_err(|e| { - admin_error!(err = ?e, "Invalid identity"); + error!(err = ?e, "Invalid identity"); e })?; let target_uuid = idms_prox_write .qs_write .name_to_uuid(uuid_or_name.as_str()) .map_err(|e| { - admin_error!(err = ?e, "Error resolving id to target"); + error!(err = ?e, "Error resolving id to target"); e })?; @@ -821,7 +820,7 @@ impl QueryServerWriteV1 { let ident = idms_prox_write .validate_client_auth_info_to_ident(client_auth_info, ct) .map_err(|e| { - admin_error!(err = ?e, "Invalid identity"); + error!(err = ?e, "Invalid identity"); e })?; @@ -829,7 +828,7 @@ impl QueryServerWriteV1 { .qs_write .name_to_uuid(uuid_or_name.as_str()) .map_err(|e| { - admin_error!(err = ?e, "Error resolving id to target"); + error!(err = ?e, "Error resolving id to target"); e })?; @@ -839,7 +838,7 @@ impl QueryServerWriteV1 { target_uuid, ) .map_err(|e| { - admin_error!( + error!( err = ?e, "Failed to begin idm_account_regenerate_radius", ); @@ -869,18 +868,18 @@ impl QueryServerWriteV1 { let ident = idms_prox_write .validate_client_auth_info_to_ident(client_auth_info, ct) .map_err(|e| { - admin_error!(err = ?e, "Invalid identity"); + error!(err = ?e, "Invalid identity"); e })?; let target_uuid = idms_prox_write .qs_write .name_to_uuid(uuid_or_name.as_str()) .map_err(|e| { - admin_error!(err = ?e, "Error resolving id to target"); + error!(err = ?e, "Error resolving id to target"); e })?; - let target_attr = Attribute::try_from(attr.as_str())?; + let target_attr = Attribute::from(attr.as_str()); let mdf = match ModifyEvent::from_target_uuid_attr_purge( ident, target_uuid, @@ -890,7 +889,7 @@ impl QueryServerWriteV1 { ) { Ok(m) => m, Err(e) => { - admin_error!(err = ?e, "Failed to begin modify during purge attribute"); + error!(err = ?e, "Failed to begin modify during purge attribute"); return Err(e); } }; @@ -922,14 +921,14 @@ impl QueryServerWriteV1 { let ident = idms_prox_write .validate_client_auth_info_to_ident(client_auth_info, ct) .map_err(|e| { - admin_error!(err = ?e, "Invalid identity"); + error!(err = ?e, "Invalid identity"); e })?; let target_uuid = idms_prox_write .qs_write .name_to_uuid(uuid_or_name.as_str()) .map_err(|e| { - admin_error!(err = ?e, "Error resolving id to target"); + error!(err = ?e, "Error resolving id to target"); e })?; @@ -949,7 +948,7 @@ impl QueryServerWriteV1 { ) { Ok(m) => m, Err(e) => { - admin_error!(err = ?e, "Failed to begin modify"); + error!(err = ?e, "Failed to begin modify"); return Err(e); } }; @@ -1061,24 +1060,24 @@ impl QueryServerWriteV1 { // The filter_map here means we only create the mods if the gidnumber or shell are set // in the actual request. let mods: Vec<_> = iter::once(Some(Modify::Present( - Attribute::Class.into(), + Attribute::Class, EntryClass::PosixAccount.into(), ))) .chain(iter::once( gidnumber .as_ref() - .map(|_| Modify::Purged(Attribute::GidNumber.into())), + .map(|_| Modify::Purged(Attribute::GidNumber)), )) .chain(iter::once(gidnumber.map(|n| { - Modify::Present(Attribute::GidNumber.into(), Value::new_uint32(n)) + Modify::Present(Attribute::GidNumber, Value::new_uint32(n)) }))) .chain(iter::once( shell .as_ref() - .map(|_| Modify::Purged(Attribute::LoginShell.into())), + .map(|_| Modify::Purged(Attribute::LoginShell)), )) .chain(iter::once(shell.map(|s| { - Modify::Present(Attribute::LoginShell.into(), Value::new_iutf8(s.as_str())) + Modify::Present(Attribute::LoginShell, Value::new_iutf8(s.as_str())) }))) .flatten() .collect(); @@ -1109,9 +1108,9 @@ impl QueryServerWriteV1 { let gidnumber_mods = if let Some(gid) = gx.gidnumber { [ - Some(Modify::Purged(Attribute::GidNumber.into())), + Some(Modify::Purged(Attribute::GidNumber)), Some(Modify::Present( - Attribute::GidNumber.into(), + Attribute::GidNumber, Value::new_uint32(gid), )), ] @@ -1119,7 +1118,7 @@ impl QueryServerWriteV1 { [None, None] }; let mods: Vec<_> = iter::once(Some(Modify::Present( - Attribute::Class.into(), + Attribute::Class, EntryClass::PosixGroup.into(), ))) .chain(gidnumber_mods) @@ -1151,7 +1150,7 @@ impl QueryServerWriteV1 { let ident = idms_prox_write .validate_client_auth_info_to_ident(client_auth_info, ct) .map_err(|e| { - admin_error!(err = ?e, "Invalid identity"); + error!(err = ?e, "Invalid identity"); e })?; @@ -1159,9 +1158,8 @@ impl QueryServerWriteV1 { idms_prox_write .qs_write .name_to_uuid(uuid_or_name.as_str()) - .map_err(|e| { - admin_info!("Error resolving as gidnumber continuing ..."); - e + .inspect_err(|err| { + info!(?err, "Error resolving as gidnumber continuing ..."); }) })?; @@ -1172,7 +1170,7 @@ impl QueryServerWriteV1 { cred, ) .map_err(|e| { - admin_error!(err = ?e, "Failed to begin UnixPasswordChangeEvent"); + error!(err = ?e, "Failed to begin UnixPasswordChangeEvent"); e })?; idms_prox_write @@ -1240,7 +1238,7 @@ impl QueryServerWriteV1 { let ident = idms_prox_write .validate_client_auth_info_to_ident(client_auth_info, ct) .map_err(|e| { - admin_error!(err = ?e, "Invalid identity"); + error!(err = ?e, "Invalid identity"); e })?; @@ -1248,7 +1246,7 @@ impl QueryServerWriteV1 { .qs_write .name_to_uuid(group.as_str()) .map_err(|e| { - admin_error!(err = ?e, "Error resolving group name to target"); + error!(err = ?e, "Error resolving group name to target"); e })?; @@ -1267,7 +1265,7 @@ impl QueryServerWriteV1 { ) { Ok(m) => m, Err(e) => { - admin_error!(err = ?e, "Failed to begin modify"); + error!(err = ?e, "Failed to begin modify"); return Err(e); } }; @@ -1298,7 +1296,7 @@ impl QueryServerWriteV1 { let ident = idms_prox_write .validate_client_auth_info_to_ident(client_auth_info, ct) .map_err(|e| { - admin_error!(err = ?e, "Invalid identity"); + error!(err = ?e, "Invalid identity"); e })?; @@ -1306,7 +1304,7 @@ impl QueryServerWriteV1 { .qs_write .name_to_uuid(group.as_str()) .map_err(|e| { - admin_error!(err = ?e, "Error resolving group name to target"); + error!(err = ?e, "Error resolving group name to target"); e })?; @@ -1321,7 +1319,7 @@ impl QueryServerWriteV1 { ) { Ok(m) => m, Err(e) => { - admin_error!(err = ?e, "Failed to begin modify"); + error!(err = ?e, "Failed to begin modify"); return Err(e); } }; @@ -1356,7 +1354,7 @@ impl QueryServerWriteV1 { let ident = idms_prox_write .validate_client_auth_info_to_ident(client_auth_info, ct) .map_err(|e| { - admin_error!(err = ?e, "Invalid identity"); + error!(err = ?e, "Invalid identity"); e })?; @@ -1364,7 +1362,7 @@ impl QueryServerWriteV1 { .qs_write .name_to_uuid(group.as_str()) .map_err(|e| { - admin_error!(err = ?e, "Error resolving group name to target"); + error!(err = ?e, "Error resolving group name to target"); e })?; @@ -1384,7 +1382,7 @@ impl QueryServerWriteV1 { ) { Ok(m) => m, Err(e) => { - admin_error!(err = ?e, "Failed to begin modify"); + error!(err = ?e, "Failed to begin modify"); return Err(e); } }; @@ -1418,7 +1416,7 @@ impl QueryServerWriteV1 { let ident = idms_prox_write .validate_client_auth_info_to_ident(client_auth_info, ct) .map_err(|e| { - admin_error!(err = ?e, "Invalid identity"); + error!(err = ?e, "Invalid identity"); e })?; @@ -1441,7 +1439,7 @@ impl QueryServerWriteV1 { ) { Ok(m) => m, Err(e) => { - admin_error!(err = ?e, "Failed to begin modify"); + error!(err = ?e, "Failed to begin modify"); return Err(e); } }; @@ -1473,7 +1471,7 @@ impl QueryServerWriteV1 { let ident = idms_prox_write .validate_client_auth_info_to_ident(client_auth_info, ct) .map_err(|e| { - admin_error!(err = ?e, "Invalid identity"); + error!(err = ?e, "Invalid identity"); e })?; @@ -1481,7 +1479,7 @@ impl QueryServerWriteV1 { .qs_write .name_to_uuid(group.as_str()) .map_err(|e| { - admin_error!(err = ?e, "Error resolving group name to target"); + error!(err = ?e, "Error resolving group name to target"); e })?; @@ -1498,7 +1496,7 @@ impl QueryServerWriteV1 { ) { Ok(m) => m, Err(e) => { - admin_error!(err = ?e, "Failed to begin modify"); + error!(err = ?e, "Failed to begin modify"); return Err(e); } }; @@ -1532,7 +1530,7 @@ impl QueryServerWriteV1 { let ident = idms_prox_write .validate_client_auth_info_to_ident(client_auth_info, ct) .map_err(|e| { - admin_error!(err = ?e, "Invalid identity"); + error!(err = ?e, "Invalid identity"); e })?; @@ -1540,7 +1538,7 @@ impl QueryServerWriteV1 { .qs_write .name_to_uuid(group.as_str()) .map_err(|e| { - admin_error!(err = ?e, "Error resolving group name to target"); + error!(err = ?e, "Error resolving group name to target"); e })?; @@ -1559,7 +1557,7 @@ impl QueryServerWriteV1 { ) { Ok(m) => m, Err(e) => { - admin_error!(err = ?e, "Failed to begin modify"); + error!(err = ?e, "Failed to begin modify"); return Err(e); } }; @@ -1590,7 +1588,7 @@ impl QueryServerWriteV1 { let ident = idms_prox_write .validate_client_auth_info_to_ident(client_auth_info, ct) .map_err(|e| { - admin_error!(err = ?e, "Invalid identity"); + error!(err = ?e, "Invalid identity"); e })?; @@ -1598,7 +1596,7 @@ impl QueryServerWriteV1 { .qs_write .name_to_uuid(group.as_str()) .map_err(|e| { - admin_error!(err = ?e, "Error resolving group name to target"); + error!(err = ?e, "Error resolving group name to target"); e })?; @@ -1615,7 +1613,7 @@ impl QueryServerWriteV1 { ) { Ok(m) => m, Err(e) => { - admin_error!(err = ?e, "Failed to begin modify"); + error!(err = ?e, "Failed to begin modify"); return Err(e); } }; @@ -1644,9 +1642,8 @@ impl QueryServerWriteV1 { let ident = idms_prox_write .validate_client_auth_info_to_ident(client_auth_info, ct) - .map_err(|e| { - admin_error!(err = ?e, "Invalid identity"); - e + .inspect_err(|err| { + error!(?err, "Invalid identity"); })?; idms_prox_write diff --git a/server/core/src/https/manifest.rs b/server/core/src/https/manifest.rs index 6229ac844..587ef8d31 100644 --- a/server/core/src/https/manifest.rs +++ b/server/core/src/https/manifest.rs @@ -149,10 +149,7 @@ pub(crate) async fn manifest(DomainInfo(domain_info): DomainInfo) -> impl IntoRe let domain_display_name = domain_info.display_name().to_string(); // TODO: fix the None here to make it the request host let manifest_string = - match serde_json::to_string_pretty(&manifest_data(None, domain_display_name)) { - Ok(val) => val, - Err(_) => String::from(""), - }; + serde_json::to_string_pretty(&manifest_data(None, domain_display_name)).unwrap_or_default(); let mut res = Response::new(manifest_string); res.headers_mut() diff --git a/server/core/src/repl/mod.rs b/server/core/src/repl/mod.rs index bc05a84eb..13c947fe3 100644 --- a/server/core/src/repl/mod.rs +++ b/server/core/src/repl/mod.rs @@ -485,7 +485,7 @@ async fn repl_task( match task { ReplConsumerCtrl::Stop => break, ReplConsumerCtrl::Refresh ( refresh_coord ) => { - last_working_address = match repl_run_consumer_refresh( + last_working_address = (repl_run_consumer_refresh( refresh_coord, domain, &sorted_socket_addrs, @@ -493,10 +493,7 @@ async fn repl_task( &idms, &consumer_conn_settings ) - .await { - Ok(val) => val, - Err(_) => None - }; + .await).unwrap_or_default(); } } } diff --git a/server/lib/Cargo.toml b/server/lib/Cargo.toml index 5b562a75d..35e509d76 100644 --- a/server/lib/Cargo.toml +++ b/server/lib/Cargo.toml @@ -109,8 +109,12 @@ compact_jwt = { workspace = true, features = ["openssl", "hsm-crypto", "unsafe_r criterion = { workspace = true, features = ["html_reports"] } futures = { workspace = true } kanidmd_lib_macros = { workspace = true } +# This is needed so that we can use a test feature across the crate boundary to proto +# so we can enable certain hidden test only attributes. +kanidm_proto = { workspace = true, features = ["test"] } webauthn-authenticator-rs = { workspace = true } + [target.'cfg(not(target_os = "illumos"))'.dev-dependencies] mimalloc = { workspace = true } diff --git a/server/lib/src/be/dbentry.rs b/server/lib/src/be/dbentry.rs index 2000d24e4..54f10bab7 100644 --- a/server/lib/src/be/dbentry.rs +++ b/server/lib/src/be/dbentry.rs @@ -3,7 +3,6 @@ use std::time::Duration; use nonempty::NonEmpty; use serde::{Deserialize, Serialize}; -use smartstring::alias::String as AttrString; use uuid::Uuid; use super::dbrepl::{DbEntryChangeState, DbReplMeta}; @@ -14,12 +13,12 @@ use crate::prelude::OperationError; #[derive(Serialize, Deserialize, Debug)] pub struct DbEntryV1 { - pub attrs: BTreeMap>, + pub attrs: BTreeMap>, } #[derive(Serialize, Deserialize, Debug)] pub struct DbEntryV2 { - pub attrs: BTreeMap, + pub attrs: BTreeMap, } // REMEMBER: If you add a new version here, you MUST @@ -31,7 +30,7 @@ pub enum DbEntryVers { V2(DbEntryV2), V3 { changestate: DbEntryChangeState, - attrs: BTreeMap, + attrs: BTreeMap, }, } @@ -469,7 +468,7 @@ impl std::fmt::Debug for DbEntry { writeln!(f, "\nlive {at:>32}")?; for (attr, cid) in changes { write!(f, "\n{attr:>32} - {cid} ")?; - if let Some(vs) = attrs.get(attr.as_str()) { + if let Some(vs) = attrs.get(attr) { write!(f, "{vs:?}")?; } else { write!(f, "-")?; @@ -491,7 +490,7 @@ impl std::fmt::Display for DbEntry { match &self.ent { DbEntryVers::V1(dbe_v1) => { write!(f, "v1 - {{ ")?; - match dbe_v1.attrs.get(Attribute::Uuid.as_ref()) { + match dbe_v1.attrs.get(&Attribute::Uuid) { Some(uuids) => { for uuid in uuids { write!(f, "{uuid:?}, ")?; @@ -499,17 +498,17 @@ impl std::fmt::Display for DbEntry { } None => write!(f, "Uuid(INVALID), ")?, }; - if let Some(names) = dbe_v1.attrs.get(Attribute::Name.as_ref()) { + if let Some(names) = dbe_v1.attrs.get(&Attribute::Name) { for name in names { write!(f, "{name:?}, ")?; } } - if let Some(names) = dbe_v1.attrs.get(Attribute::AttributeName.as_ref()) { + if let Some(names) = dbe_v1.attrs.get(&Attribute::AttributeName) { for name in names { write!(f, "{name:?}, ")?; } } - if let Some(names) = dbe_v1.attrs.get(Attribute::ClassName.as_ref()) { + if let Some(names) = dbe_v1.attrs.get(&Attribute::ClassName) { for name in names { write!(f, "{name:?}, ")?; } @@ -518,26 +517,26 @@ impl std::fmt::Display for DbEntry { } DbEntryVers::V2(dbe_v2) => { write!(f, "v2 - {{ ")?; - match dbe_v2.attrs.get(Attribute::Uuid.as_ref()) { + match dbe_v2.attrs.get(&Attribute::Uuid) { Some(uuids) => { write!(f, "{uuids:?}, ")?; } None => write!(f, "Uuid(INVALID), ")?, }; - if let Some(names) = dbe_v2.attrs.get(Attribute::Name.as_ref()) { + if let Some(names) = dbe_v2.attrs.get(&Attribute::Name) { write!(f, "{names:?}, ")?; } - if let Some(names) = dbe_v2.attrs.get(Attribute::AttributeName.as_ref()) { + if let Some(names) = dbe_v2.attrs.get(&Attribute::AttributeName) { write!(f, "{names:?}, ")?; } - if let Some(names) = dbe_v2.attrs.get(Attribute::ClassName.as_ref()) { + if let Some(names) = dbe_v2.attrs.get(&Attribute::ClassName) { write!(f, "{names:?}, ")?; } write!(f, "}}") } DbEntryVers::V3 { changestate, attrs } => { write!(f, "v3 - {{ ")?; - match attrs.get(Attribute::Uuid.as_ref()) { + match attrs.get(&Attribute::Uuid) { Some(uuids) => { write!(f, "{uuids:?}, ")?; } @@ -547,13 +546,13 @@ impl std::fmt::Display for DbEntry { match changestate { DbEntryChangeState::V1Live { at, changes: _ } => { write!(f, "created: {at}, ")?; - if let Some(names) = attrs.get(Attribute::Name.as_ref()) { + if let Some(names) = attrs.get(&Attribute::Name) { write!(f, "{names:?}, ")?; } - if let Some(names) = attrs.get(Attribute::AttributeName.as_ref()) { + if let Some(names) = attrs.get(&Attribute::AttributeName) { write!(f, "{names:?}, ")?; } - if let Some(names) = attrs.get(Attribute::ClassName.as_ref()) { + if let Some(names) = attrs.get(&Attribute::ClassName) { write!(f, "{names:?}, ")?; } } diff --git a/server/lib/src/be/dbrepl.rs b/server/lib/src/be/dbrepl.rs index aa086bb2d..865bbefe1 100644 --- a/server/lib/src/be/dbrepl.rs +++ b/server/lib/src/be/dbrepl.rs @@ -1,4 +1,5 @@ use super::dbvalue::DbCidV1; +use crate::prelude::entries::Attribute; use std::collections::{BTreeMap, BTreeSet}; use serde::{Deserialize, Serialize}; @@ -7,7 +8,7 @@ use serde::{Deserialize, Serialize}; pub enum DbEntryChangeState { V1Live { at: DbCidV1, - changes: BTreeMap, + changes: BTreeMap, }, V1Tombstone { at: DbCidV1, diff --git a/server/lib/src/be/idl_arc_sqlite.rs b/server/lib/src/be/idl_arc_sqlite.rs index 580f63241..4cc831cb3 100644 --- a/server/lib/src/be/idl_arc_sqlite.rs +++ b/server/lib/src/be/idl_arc_sqlite.rs @@ -199,7 +199,7 @@ macro_rules! get_idl { let db_r = $self.db.get_idl($attr, $itype, $idx_key)?; if let Some(ref idl) = db_r { let ncache_key = IdlCacheKey { - a: $attr.into(), + a: $attr.clone(), i: $itype.clone(), k: $idx_key.into(), }; @@ -346,7 +346,7 @@ pub trait IdlArcSqliteTransaction { fn get_idl( &mut self, - attr: &str, + attr: &Attribute, itype: IndexType, idx_key: &str, ) -> Result, OperationError>; @@ -404,7 +404,7 @@ impl<'a> IdlArcSqliteTransaction for IdlArcSqliteReadTransaction<'a> { #[instrument(level = "trace", skip_all)] fn get_idl( &mut self, - attr: &str, + attr: &Attribute, itype: IndexType, idx_key: &str, ) -> Result, OperationError> { @@ -499,7 +499,7 @@ impl<'a> IdlArcSqliteTransaction for IdlArcSqliteWriteTransaction<'a> { #[instrument(level = "trace", skip_all)] fn get_idl( &mut self, - attr: &str, + attr: &Attribute, itype: IndexType, idx_key: &str, ) -> Result, OperationError> { @@ -626,7 +626,7 @@ impl<'a> IdlArcSqliteWriteTransaction<'a> { .iter_mut_mark_clean() .try_for_each(|(k, v)| { match v { - Some(idl) => db.write_idl(k.a.as_str(), k.i, k.k.as_str(), idl), + Some(idl) => db.write_idl(&k.a, k.i, k.k.as_str(), idl), #[allow(clippy::unreachable)] None => { // Due to how we remove items, we always write an empty idl @@ -759,13 +759,13 @@ impl<'a> IdlArcSqliteWriteTransaction<'a> { pub fn write_idl( &mut self, - attr: &str, + attr: &Attribute, itype: IndexType, idx_key: &str, idl: &IDLBitRange, ) -> Result<(), OperationError> { let cache_key = IdlCacheKey { - a: attr.into(), + a: attr.clone(), i: itype, k: idx_key.into(), }; @@ -1127,7 +1127,7 @@ impl<'a> IdlArcSqliteWriteTransaction<'a> { Ok(()) } - pub fn create_idx(&self, attr: Attribute, itype: IndexType) -> Result<(), OperationError> { + pub fn create_idx(&self, attr: &Attribute, itype: IndexType) -> Result<(), OperationError> { // We don't need to affect this, so pass it down. self.db.create_idx(attr, itype) } diff --git a/server/lib/src/be/idl_sqlite.rs b/server/lib/src/be/idl_sqlite.rs index b29f4db4a..534731627 100644 --- a/server/lib/src/be/idl_sqlite.rs +++ b/server/lib/src/be/idl_sqlite.rs @@ -219,15 +219,15 @@ pub(crate) trait IdlSqliteTransaction { } } - fn exists_idx(&self, attr: &str, itype: IndexType) -> Result { - let tname = format!("idx_{}_{}", itype.as_idx_str(), attr); + fn exists_idx(&self, attr: &Attribute, itype: IndexType) -> Result { + let tname = format!("idx_{}_{}", itype.as_idx_str(), attr.as_str()); self.exists_table(&tname) } #[instrument(level = "trace", skip_all)] fn get_idl( &self, - attr: &str, + attr: &Attribute, itype: IndexType, idx_key: &str, ) -> Result, OperationError> { @@ -244,7 +244,7 @@ pub(crate) trait IdlSqliteTransaction { "SELECT idl FROM {}.idx_{}_{} WHERE key = :idx_key", self.get_db_name(), itype.as_idx_str(), - attr + attr.as_str() ); let mut stmt = self.get_conn()?.prepare(&query).map_err(sqlite_error)?; let idl_raw: Option> = stmt @@ -867,7 +867,7 @@ impl IdlSqliteWriteTransaction { pub fn write_idl( &self, - attr: &str, + attr: &Attribute, itype: IndexType, idx_key: &str, idl: &IDLBitRange, @@ -879,7 +879,7 @@ impl IdlSqliteWriteTransaction { "DELETE FROM {}.idx_{}_{} WHERE key = :key", self.get_db_name(), itype.as_idx_str(), - attr + attr.as_str() ); self.get_conn()? @@ -895,7 +895,7 @@ impl IdlSqliteWriteTransaction { "INSERT OR REPLACE INTO {}.idx_{}_{} (key, idl) VALUES(:key, :idl)", self.get_db_name(), itype.as_idx_str(), - attr + attr.as_str() ); self.get_conn()? @@ -1205,7 +1205,7 @@ impl IdlSqliteWriteTransaction { } #[instrument(level = "debug", skip(self))] - pub fn create_idx(&self, attr: Attribute, itype: IndexType) -> Result<(), OperationError> { + pub fn create_idx(&self, attr: &Attribute, itype: IndexType) -> Result<(), OperationError> { // Is there a better way than formatting this? I can't seem // to template into the str. // @@ -1214,7 +1214,7 @@ impl IdlSqliteWriteTransaction { "CREATE TABLE IF NOT EXISTS {}.idx_{}_{} (key TEXT PRIMARY KEY, idl BLOB)", self.get_db_name(), itype.as_idx_str(), - attr + attr.as_str(), ); self.get_conn()? diff --git a/server/lib/src/be/idxkey.rs b/server/lib/src/be/idxkey.rs index 7b71ab772..f6041d695 100644 --- a/server/lib/src/be/idxkey.rs +++ b/server/lib/src/be/idxkey.rs @@ -1,45 +1,39 @@ +use crate::prelude::entries::Attribute; +use crate::value::IndexType; use std::borrow::Borrow; use std::cmp::Ordering; use std::hash::{Hash, Hasher}; -use smartstring::alias::String as AttrString; - -use crate::prelude::entries::Attribute; -use crate::value::IndexType; - pub type IdxSlope = u8; // Huge props to https://github.com/sunshowers/borrow-complex-key-example/blob/master/src/lib.rs #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct IdxKey { - pub attr: AttrString, + pub attr: Attribute, pub itype: IndexType, } impl IdxKey { pub fn new(attr: Attribute, itype: IndexType) -> Self { - IdxKey { - attr: attr.into(), - itype, - } + IdxKey { attr, itype } } } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct IdxKeyRef<'a> { - pub attr: &'a str, + pub attr: &'a Attribute, pub itype: &'a IndexType, } impl<'a> IdxKeyRef<'a> { - pub fn new(attr: &'a str, itype: &'a IndexType) -> Self { + pub fn new(attr: &'a Attribute, itype: &'a IndexType) -> Self { IdxKeyRef { attr, itype } } pub fn as_key(&self) -> IdxKey { IdxKey { - attr: self.attr.into(), + attr: self.attr.clone(), itype: *self.itype, } } @@ -59,7 +53,7 @@ impl<'a> IdxKeyToRef for IdxKeyRef<'a> { impl IdxKeyToRef for IdxKey { fn keyref(&self) -> IdxKeyRef<'_> { IdxKeyRef { - attr: self.attr.as_str(), + attr: &self.attr, itype: &self.itype, } } @@ -89,14 +83,14 @@ impl<'a> Hash for (dyn IdxKeyToRef + 'a) { #[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)] pub struct IdlCacheKey { - pub a: AttrString, + pub a: Attribute, pub i: IndexType, pub k: String, } #[derive(Debug, Clone, Copy, Ord, PartialOrd, Eq, PartialEq, Hash)] pub struct IdlCacheKeyRef<'a> { - pub a: &'a str, + pub a: &'a Attribute, pub i: IndexType, pub k: &'a str, } @@ -123,7 +117,7 @@ impl<'a> IdlCacheKeyToRef for IdlCacheKeyRef<'a> { impl IdlCacheKeyToRef for IdlCacheKey { fn keyref(&self) -> IdlCacheKeyRef<'_> { IdlCacheKeyRef { - a: self.a.as_str(), + a: &self.a, i: self.i, k: self.k.as_str(), } diff --git a/server/lib/src/be/mod.rs b/server/lib/src/be/mod.rs index 7900f9b3f..73096c33d 100644 --- a/server/lib/src/be/mod.rs +++ b/server/lib/src/be/mod.rs @@ -15,7 +15,6 @@ use hashbrown::{HashMap as Map, HashSet}; use idlset::v2::IDLBitRange; use idlset::AndNot; use kanidm_proto::internal::{ConsistencyError, OperationError}; -use smartstring::alias::String as AttrString; use tracing::{trace, trace_span}; use uuid::Uuid; @@ -566,7 +565,7 @@ pub trait BackendTransaction { fn filter2idl_sub( &mut self, - attr: &AttrString, + attr: &Attribute, sub_idx_key: String, ) -> Result<(IdList, FilterPlan), OperationError> { // Now given that idx_key, we will iterate over the possible graphemes. @@ -1209,11 +1208,9 @@ impl<'a> BackendWriteTransaction<'a> { let ctx_ent_uuid = ctx_ent.get_uuid(); let idx_key = ctx_ent_uuid.as_hyphenated().to_string(); - let idl = self.get_idlayer().get_idl( - Attribute::Uuid.as_ref(), - IndexType::Equality, - &idx_key, - )?; + let idl = + self.get_idlayer() + .get_idl(&Attribute::Uuid, IndexType::Equality, &idx_key)?; let entry = match idl { Some(idl) if idl.is_empty() => { @@ -1591,7 +1588,7 @@ impl<'a> BackendWriteTransaction<'a> { Some(mut idl) => { idl.insert_id(e_id); if cfg!(debug_assertions) - && attr == Attribute::Uuid.as_ref() && itype == IndexType::Equality { + && *attr == Attribute::Uuid && itype == IndexType::Equality { // This means a duplicate UUID has appeared in the index. if idl.len() > 1 { trace!(duplicate_idl = ?idl, ?idx_key); @@ -1614,7 +1611,7 @@ impl<'a> BackendWriteTransaction<'a> { match self.idlayer.get_idl(attr, itype, &idx_key)? { Some(mut idl) => { idl.remove_id(e_id); - if cfg!(debug_assertions) && attr == Attribute::Uuid.as_ref() && itype == IndexType::Equality { + if cfg!(debug_assertions) && *attr == Attribute::Uuid && itype == IndexType::Equality { // This means a duplicate UUID has appeared in the index. if idl.len() > 1 { trace!(duplicate_idl = ?idl, ?idx_key); @@ -1638,7 +1635,7 @@ impl<'a> BackendWriteTransaction<'a> { } #[allow(dead_code)] - fn missing_idxs(&mut self) -> Result, OperationError> { + fn missing_idxs(&mut self) -> Result, OperationError> { let idx_table_list = self.get_idlayer().list_idxs()?; // Turn the vec to a real set @@ -1677,10 +1674,10 @@ impl<'a> BackendWriteTransaction<'a> { trace!("Creating index -> uuid2rdn"); self.idlayer.create_uuid2rdn()?; - self.idxmeta_wr.idxkeys.keys().try_for_each(|ikey| { - let attr: Attribute = (&ikey.attr).try_into()?; - self.idlayer.create_idx(attr, ikey.itype) - }) + self.idxmeta_wr + .idxkeys + .keys() + .try_for_each(|ikey| self.idlayer.create_idx(&ikey.attr, ikey.itype)) } pub fn upgrade_reindex(&mut self, v: i64) -> Result<(), OperationError> { @@ -1765,7 +1762,7 @@ impl<'a> BackendWriteTransaction<'a> { #[cfg(test)] pub fn load_test_idl( &mut self, - attr: &str, + attr: &Attribute, itype: IndexType, idx_key: &str, ) -> Result, OperationError> { @@ -2297,7 +2294,7 @@ mod tests { macro_rules! idl_state { ($be:expr, $attr:expr, $itype:expr, $idx_key:expr, $expect:expr) => {{ let t_idl = $be - .load_test_idl(&$attr.to_string(), $itype, &$idx_key.to_string()) + .load_test_idl(&$attr, $itype, &$idx_key.to_string()) .expect("IdList Load failed"); let t = $expect.map(|v: Vec| IDLBitRange::from_iter(v)); assert_eq!(t_idl, t); @@ -2745,7 +2742,7 @@ mod tests { idl_state!( be, - Attribute::Name.as_ref(), + Attribute::Name, IndexType::Equality, "william", Some(vec![1]) @@ -2753,7 +2750,7 @@ mod tests { idl_state!( be, - Attribute::Name.as_ref(), + Attribute::Name, IndexType::Equality, "claire", Some(vec![2]) @@ -2764,7 +2761,7 @@ mod tests { ] { idl_state!( be, - Attribute::Name.as_ref(), + Attribute::Name, IndexType::SubString, sub, Some(vec![1]) @@ -2776,7 +2773,7 @@ mod tests { ] { idl_state!( be, - Attribute::Name.as_ref(), + Attribute::Name, IndexType::SubString, sub, Some(vec![2]) @@ -2786,7 +2783,7 @@ mod tests { for sub in ["i", "a", "l"] { idl_state!( be, - Attribute::Name.as_ref(), + Attribute::Name, IndexType::SubString, sub, Some(vec![1, 2]) @@ -2795,7 +2792,7 @@ mod tests { idl_state!( be, - Attribute::Name.as_ref(), + Attribute::Name, IndexType::Presence, "_", Some(vec![1, 2]) @@ -2803,7 +2800,7 @@ mod tests { idl_state!( be, - Attribute::Uuid.as_ref(), + Attribute::Uuid, IndexType::Equality, "db237e8a-0079-4b8c-8a56-593b22aa44d1", Some(vec![1]) @@ -2811,7 +2808,7 @@ mod tests { idl_state!( be, - Attribute::Uuid.as_ref(), + Attribute::Uuid, IndexType::Equality, "bd651620-00dd-426b-aaa0-4494f7b7906f", Some(vec![2]) @@ -2819,7 +2816,7 @@ mod tests { idl_state!( be, - Attribute::Uuid.as_ref(), + Attribute::Uuid, IndexType::Presence, "_", Some(vec![1, 2]) @@ -2829,7 +2826,7 @@ mod tests { idl_state!( be, - Attribute::Name.as_ref(), + Attribute::Name, IndexType::Equality, "not-exist", Some(Vec::with_capacity(0)) @@ -2837,14 +2834,14 @@ mod tests { idl_state!( be, - Attribute::Uuid.as_ref(), + Attribute::Uuid, IndexType::Equality, "fake-0079-4b8c-8a56-593b22aa44d1", Some(Vec::with_capacity(0)) ); let uuid_p_idl = be - .load_test_idl("not_indexed", IndexType::Presence, "_") + .load_test_idl(&Attribute::from("not_indexed"), IndexType::Presence, "_") .unwrap(); // unwrap the result assert_eq!(uuid_p_idl, None); @@ -3683,7 +3680,7 @@ mod tests { assert!(single_result.is_ok()); let filt = e - .filter_from_attrs(&[Attribute::NonExist.into()]) + .filter_from_attrs(&[Attribute::NonExist]) .expect("failed to generate filter") .into_valid_resolved(); // check allow on allids @@ -3721,7 +3718,7 @@ mod tests { assert!(single_result.is_ok()); let filt = e - .filter_from_attrs(&[Attribute::NonExist.into()]) + .filter_from_attrs(&[Attribute::NonExist]) .expect("failed to generate filter") .into_valid_resolved(); @@ -3824,7 +3821,7 @@ mod tests { // This is a demo idxmeta, purely for testing. let idxmeta = vec![IdxKey { - attr: Attribute::Uuid.into(), + attr: Attribute::Uuid, itype: IndexType::Equality, }]; diff --git a/server/lib/src/constants/schema.rs b/server/lib/src/constants/schema.rs index 44dff84f6..d1564fac0 100644 --- a/server/lib/src/constants/schema.rs +++ b/server/lib/src/constants/schema.rs @@ -12,7 +12,7 @@ lazy_static!( pub static ref SCHEMA_ATTR_DISPLAYNAME: SchemaAttribute = SchemaAttribute { uuid: UUID_SCHEMA_ATTR_DISPLAYNAME, - name: Attribute::DisplayName.into(), + name: Attribute::DisplayName, description: "The publicly visible display name of this person".to_string(), index: vec![IndexType::Equality], @@ -23,7 +23,7 @@ pub static ref SCHEMA_ATTR_DISPLAYNAME: SchemaAttribute = SchemaAttribute { pub static ref SCHEMA_ATTR_DISPLAYNAME_DL7: SchemaAttribute = SchemaAttribute { uuid: UUID_SCHEMA_ATTR_DISPLAYNAME, - name: Attribute::DisplayName.into(), + name: Attribute::DisplayName, description: "The publicly visible display name of this person".to_string(), index: vec![IndexType::Equality, IndexType::SubString], @@ -34,7 +34,7 @@ pub static ref SCHEMA_ATTR_DISPLAYNAME_DL7: SchemaAttribute = SchemaAttribute { pub static ref SCHEMA_ATTR_MAIL: SchemaAttribute = SchemaAttribute { uuid: UUID_SCHEMA_ATTR_MAIL, - name: Attribute::Mail.into(), + name: Attribute::Mail, description: "Mail addresses of the object".to_string(), index: vec![IndexType::Equality], @@ -47,7 +47,7 @@ pub static ref SCHEMA_ATTR_MAIL: SchemaAttribute = SchemaAttribute { pub static ref SCHEMA_ATTR_MAIL_DL7: SchemaAttribute = SchemaAttribute { uuid: UUID_SCHEMA_ATTR_MAIL, - name: Attribute::Mail.into(), + name: Attribute::Mail, description: "Mail addresses of the object".to_string(), index: vec![IndexType::Equality, IndexType::SubString], @@ -60,7 +60,7 @@ pub static ref SCHEMA_ATTR_MAIL_DL7: SchemaAttribute = SchemaAttribute { pub static ref SCHEMA_ATTR_EC_KEY_PRIVATE: SchemaAttribute = SchemaAttribute { uuid: UUID_SCHEMA_ATTR_EC_KEY_PRIVATE, - name: Attribute::IdVerificationEcKey.into(), + name: Attribute::IdVerificationEcKey, description: "Account verification private key".to_string(), index: vec![IndexType::Presence], @@ -72,7 +72,7 @@ pub static ref SCHEMA_ATTR_EC_KEY_PRIVATE: SchemaAttribute = SchemaAttribute { pub static ref SCHEMA_ATTR_SSH_PUBLICKEY: SchemaAttribute = SchemaAttribute { uuid: UUID_SCHEMA_ATTR_SSH_PUBLICKEY, - name: Attribute::SshPublicKey.into(), + name: Attribute::SshPublicKey, description: "SSH public keys of the object".to_string(), multivalue: true, @@ -83,7 +83,7 @@ pub static ref SCHEMA_ATTR_SSH_PUBLICKEY: SchemaAttribute = SchemaAttribute { pub static ref SCHEMA_ATTR_PRIMARY_CREDENTIAL: SchemaAttribute = SchemaAttribute { uuid: UUID_SCHEMA_ATTR_PRIMARY_CREDENTIAL, - name: Attribute::PrimaryCredential.into(), + name: Attribute::PrimaryCredential, description: "Primary credential material of the account for authentication interactively".to_string(), index: vec![IndexType::Presence], @@ -94,7 +94,7 @@ pub static ref SCHEMA_ATTR_PRIMARY_CREDENTIAL: SchemaAttribute = SchemaAttribute pub static ref SCHEMA_ATTR_LEGALNAME: SchemaAttribute = SchemaAttribute { uuid: UUID_SCHEMA_ATTR_LEGALNAME, - name: Attribute::LegalName.into(), + name: Attribute::LegalName, description: "The private and sensitive legal name of this person".to_string(), index: vec![IndexType::Equality], @@ -105,7 +105,7 @@ pub static ref SCHEMA_ATTR_LEGALNAME: SchemaAttribute = SchemaAttribute { pub static ref SCHEMA_ATTR_LEGALNAME_DL7: SchemaAttribute = SchemaAttribute { uuid: UUID_SCHEMA_ATTR_LEGALNAME, - name: Attribute::LegalName.into(), + name: Attribute::LegalName, description: "The private and sensitive legal name of this person".to_string(), index: vec![IndexType::Equality, IndexType::SubString], @@ -116,7 +116,7 @@ pub static ref SCHEMA_ATTR_LEGALNAME_DL7: SchemaAttribute = SchemaAttribute { pub static ref SCHEMA_ATTR_NAME_HISTORY: SchemaAttribute = SchemaAttribute { uuid: UUID_SCHEMA_ATTR_NAME_HISTORY, - name: Attribute::NameHistory.into(), + name: Attribute::NameHistory, description: "The history of names that a person has had".to_string(), index: vec![IndexType::Equality], @@ -128,7 +128,7 @@ pub static ref SCHEMA_ATTR_NAME_HISTORY: SchemaAttribute = SchemaAttribute { pub static ref SCHEMA_ATTR_RADIUS_SECRET: SchemaAttribute = SchemaAttribute { uuid: UUID_SCHEMA_ATTR_RADIUS_SECRET, - name: Attribute::RadiusSecret.into(), + name: Attribute::RadiusSecret, description: "The accounts generated radius secret for device network authentication".to_string(), sync_allowed: true, @@ -138,7 +138,7 @@ pub static ref SCHEMA_ATTR_RADIUS_SECRET: SchemaAttribute = SchemaAttribute { pub static ref SCHEMA_ATTR_DOMAIN_NAME: SchemaAttribute = SchemaAttribute { uuid: UUID_SCHEMA_ATTR_DOMAIN_NAME, - name: Attribute::DomainName.into(), + name: Attribute::DomainName, description: "The domain's DNS name for webauthn and SPN generation purposes".to_string(), index: vec![IndexType::Equality, IndexType::Presence], @@ -149,7 +149,7 @@ pub static ref SCHEMA_ATTR_DOMAIN_NAME: SchemaAttribute = SchemaAttribute { pub static ref SCHEMA_ATTR_LDAP_ALLOW_UNIX_PW_BIND: SchemaAttribute = SchemaAttribute { uuid: UUID_SCHEMA_ATTR_LDAP_ALLOW_UNIX_PW_BIND, - name: Attribute::LdapAllowUnixPwBind.into(), + name: Attribute::LdapAllowUnixPwBind, description: "Configuration to enable binds to LDAP objects using their UNIX password".to_string(), unique: false, @@ -159,7 +159,7 @@ pub static ref SCHEMA_ATTR_LDAP_ALLOW_UNIX_PW_BIND: SchemaAttribute = SchemaAttr pub static ref SCHEMA_ATTR_DOMAIN_LDAP_BASEDN: SchemaAttribute = SchemaAttribute { uuid: UUID_SCHEMA_ATTR_DOMAIN_LDAP_BASEDN, - name: Attribute::DomainLdapBasedn.into(), + name: Attribute::DomainLdapBasedn, description: "The domain's optional ldap basedn. If unset defaults to domain components of domain name".to_string(), unique: true, @@ -169,7 +169,7 @@ pub static ref SCHEMA_ATTR_DOMAIN_LDAP_BASEDN: SchemaAttribute = SchemaAttribute pub static ref SCHEMA_ATTR_DOMAIN_DISPLAY_NAME: SchemaAttribute = SchemaAttribute { uuid: UUID_SCHEMA_ATTR_DOMAIN_DISPLAY_NAME, - name: Attribute::DomainDisplayName.into(), + name: Attribute::DomainDisplayName, description: "The user-facing display name of the Kanidm domain".to_string(), index: vec![IndexType::Equality], @@ -179,7 +179,7 @@ pub static ref SCHEMA_ATTR_DOMAIN_DISPLAY_NAME: SchemaAttribute = SchemaAttribut pub static ref SCHEMA_ATTR_DOMAIN_UUID: SchemaAttribute = SchemaAttribute { uuid: UUID_SCHEMA_ATTR_DOMAIN_UUID, - name: Attribute::DomainUuid.into(), + name: Attribute::DomainUuid, description: "The domain's uuid, used in CSN and trust relationships".to_string(), index: vec![IndexType::Equality], @@ -190,7 +190,7 @@ pub static ref SCHEMA_ATTR_DOMAIN_UUID: SchemaAttribute = SchemaAttribute { pub static ref SCHEMA_ATTR_DOMAIN_SSID: SchemaAttribute = SchemaAttribute { uuid: UUID_SCHEMA_ATTR_DOMAIN_SSID, - name: Attribute::DomainSsid.into(), + name: Attribute::DomainSsid, description: "The domains site-wide SSID for device autoconfiguration of wireless".to_string(), index: vec![IndexType::Equality], @@ -201,7 +201,7 @@ pub static ref SCHEMA_ATTR_DOMAIN_SSID: SchemaAttribute = SchemaAttribute { pub static ref SCHEMA_ATTR_DENIED_NAME: SchemaAttribute = SchemaAttribute { uuid: UUID_SCHEMA_ATTR_DENIED_NAME, - name: Attribute::DeniedName.into(), + name: Attribute::DeniedName, description: "Iname values that are not allowed to be used in 'name'.".to_string(), syntax: SyntaxType::Utf8StringIname, @@ -210,7 +210,7 @@ pub static ref SCHEMA_ATTR_DENIED_NAME: SchemaAttribute = SchemaAttribute { pub static ref SCHEMA_ATTR_DOMAIN_TOKEN_KEY: SchemaAttribute = SchemaAttribute { uuid: UUID_SCHEMA_ATTR_DOMAIN_TOKEN_KEY, - name: Attribute::DomainTokenKey.into(), + name: Attribute::DomainTokenKey, description: "The domain token encryption private key (NOT USED)".to_string(), syntax: SyntaxType::SecretUtf8String, @@ -219,7 +219,7 @@ pub static ref SCHEMA_ATTR_DOMAIN_TOKEN_KEY: SchemaAttribute = SchemaAttribute { pub static ref SCHEMA_ATTR_FERNET_PRIVATE_KEY_STR: SchemaAttribute = SchemaAttribute { uuid: UUID_SCHEMA_ATTR_FERNET_PRIVATE_KEY_STR, - name: Attribute::FernetPrivateKeyStr.into(), + name: Attribute::FernetPrivateKeyStr, description: "The token encryption private key".to_string(), syntax: SyntaxType::SecretUtf8String, @@ -228,7 +228,7 @@ pub static ref SCHEMA_ATTR_FERNET_PRIVATE_KEY_STR: SchemaAttribute = SchemaAttri pub static ref SCHEMA_ATTR_GIDNUMBER: SchemaAttribute = SchemaAttribute { uuid: UUID_SCHEMA_ATTR_GIDNUMBER, - name: Attribute::GidNumber.into(), + name: Attribute::GidNumber, description: "The groupid (uid) number of a group or account.to_string(). This is the same value as the UID number on posix accounts for security reasons".to_string(), index: vec![IndexType::Equality], @@ -240,7 +240,7 @@ pub static ref SCHEMA_ATTR_GIDNUMBER: SchemaAttribute = SchemaAttribute { pub static ref SCHEMA_ATTR_BADLIST_PASSWORD: SchemaAttribute = SchemaAttribute { uuid: UUID_SCHEMA_ATTR_BADLIST_PASSWORD, - name: Attribute::BadlistPassword.into(), + name: Attribute::BadlistPassword, description: "A password that is badlisted meaning that it can not be set as a valid password by any user account".to_string(), multivalue: true, @@ -250,7 +250,7 @@ pub static ref SCHEMA_ATTR_BADLIST_PASSWORD: SchemaAttribute = SchemaAttribute { pub static ref SCHEMA_ATTR_AUTH_SESSION_EXPIRY: SchemaAttribute = SchemaAttribute { uuid: UUID_SCHEMA_ATTR_AUTH_SESSION_EXPIRY, - name: Attribute::AuthSessionExpiry.into(), + name: Attribute::AuthSessionExpiry, description: "An expiration time for an authentication session".to_string(), syntax: SyntaxType::Uint32, @@ -259,7 +259,7 @@ pub static ref SCHEMA_ATTR_AUTH_SESSION_EXPIRY: SchemaAttribute = SchemaAttribut pub static ref SCHEMA_ATTR_AUTH_PRIVILEGE_EXPIRY: SchemaAttribute = SchemaAttribute { uuid: UUID_SCHEMA_ATTR_AUTH_PRIVILEGE_EXPIRY, - name: Attribute::PrivilegeExpiry.into(), + name: Attribute::PrivilegeExpiry, description: "An expiration time for a privileged authentication session".to_string(), syntax: SyntaxType::Uint32, @@ -268,7 +268,7 @@ pub static ref SCHEMA_ATTR_AUTH_PRIVILEGE_EXPIRY: SchemaAttribute = SchemaAttrib pub static ref SCHEMA_ATTR_AUTH_PASSWORD_MINIMUM_LENGTH: SchemaAttribute = SchemaAttribute { uuid: UUID_SCHEMA_ATTR_AUTH_PASSWORD_MINIMUM_LENGTH, - name: Attribute::AuthPasswordMinimumLength.into(), + name: Attribute::AuthPasswordMinimumLength, description: "Minimum length of passwords".to_string(), syntax: SyntaxType::Uint32, @@ -277,7 +277,7 @@ pub static ref SCHEMA_ATTR_AUTH_PASSWORD_MINIMUM_LENGTH: SchemaAttribute = Schem pub static ref SCHEMA_ATTR_LOGINSHELL: SchemaAttribute = SchemaAttribute { uuid: UUID_SCHEMA_ATTR_LOGINSHELL, - name: Attribute::LoginShell.into(), + name: Attribute::LoginShell, description: "A POSIX user's UNIX login shell".to_string(), sync_allowed: true, @@ -287,7 +287,7 @@ pub static ref SCHEMA_ATTR_LOGINSHELL: SchemaAttribute = SchemaAttribute { pub static ref SCHEMA_ATTR_UNIX_PASSWORD: SchemaAttribute = SchemaAttribute { uuid: UUID_SCHEMA_ATTR_UNIX_PASSWORD, - name: Attribute::UnixPassword.into(), + name: Attribute::UnixPassword, description: "A POSIX user's UNIX login password".to_string(), index: vec![IndexType::Presence], @@ -297,7 +297,7 @@ pub static ref SCHEMA_ATTR_UNIX_PASSWORD: SchemaAttribute = SchemaAttribute { pub static ref SCHEMA_ATTR_NSUNIQUEID: SchemaAttribute = SchemaAttribute { uuid: UUID_SCHEMA_ATTR_NSUNIQUEID, - name: Attribute::NsUniqueId.into(), + name: Attribute::NsUniqueId, description: "A unique id compatibility for 389-ds/dsee".to_string(), index: vec![IndexType::Equality], @@ -309,7 +309,7 @@ pub static ref SCHEMA_ATTR_NSUNIQUEID: SchemaAttribute = SchemaAttribute { pub static ref SCHEMA_ATTR_ACCOUNT_EXPIRE: SchemaAttribute = SchemaAttribute { uuid: UUID_SCHEMA_ATTR_ACCOUNT_EXPIRE, - name: Attribute::AccountExpire.into(), + name: Attribute::AccountExpire, description: "The datetime after which this account no longer may authenticate".to_string(), sync_allowed: true, @@ -319,7 +319,7 @@ pub static ref SCHEMA_ATTR_ACCOUNT_EXPIRE: SchemaAttribute = SchemaAttribute { pub static ref SCHEMA_ATTR_ACCOUNT_VALID_FROM: SchemaAttribute = SchemaAttribute { uuid: UUID_SCHEMA_ATTR_ACCOUNT_VALID_FROM, - name: Attribute::AccountValidFrom.into(), + name: Attribute::AccountValidFrom, description: "The datetime after which this account may commence authenticating".to_string(), sync_allowed: true, @@ -329,7 +329,7 @@ pub static ref SCHEMA_ATTR_ACCOUNT_VALID_FROM: SchemaAttribute = SchemaAttribute pub static ref SCHEMA_ATTR_WEBAUTHN_ATTESTATION_CA_LIST: SchemaAttribute = SchemaAttribute { uuid: UUID_SCHEMA_ATTR_WEBAUTHN_ATTESTATION_CA_LIST, - name: Attribute::WebauthnAttestationCaList.into(), + name: Attribute::WebauthnAttestationCaList, description: "A set of CA's that limit devices that can be used with webauthn".to_string(), syntax: SyntaxType::WebauthnAttestationCaList, @@ -339,7 +339,7 @@ pub static ref SCHEMA_ATTR_WEBAUTHN_ATTESTATION_CA_LIST: SchemaAttribute = Schem pub static ref SCHEMA_ATTR_OAUTH2_RS_NAME: SchemaAttribute = SchemaAttribute { uuid: UUID_SCHEMA_ATTR_OAUTH2_RS_NAME, - name: Attribute::OAuth2RsName.into(), + name: Attribute::OAuth2RsName, description: "The unique name of an external Oauth2 resource".to_string(), index: vec![IndexType::Equality], @@ -350,7 +350,7 @@ pub static ref SCHEMA_ATTR_OAUTH2_RS_NAME: SchemaAttribute = SchemaAttribute { pub static ref SCHEMA_ATTR_OAUTH2_RS_ORIGIN: SchemaAttribute = SchemaAttribute { uuid: UUID_SCHEMA_ATTR_OAUTH2_RS_ORIGIN, - name: Attribute::OAuth2RsOrigin.into(), + name: Attribute::OAuth2RsOrigin, description: "The origin domain of an oauth2 resource server".to_string(), syntax: SyntaxType::Url, @@ -359,7 +359,7 @@ pub static ref SCHEMA_ATTR_OAUTH2_RS_ORIGIN: SchemaAttribute = SchemaAttribute { pub static ref SCHEMA_ATTR_OAUTH2_RS_ORIGIN_DL7: SchemaAttribute = SchemaAttribute { uuid: UUID_SCHEMA_ATTR_OAUTH2_RS_ORIGIN, - name: Attribute::OAuth2RsOrigin.into(), + name: Attribute::OAuth2RsOrigin, description: "The origin domain of an OAuth2 client".to_string(), syntax: SyntaxType::Url, @@ -369,7 +369,7 @@ pub static ref SCHEMA_ATTR_OAUTH2_RS_ORIGIN_DL7: SchemaAttribute = SchemaAttribu pub static ref SCHEMA_ATTR_OAUTH2_RS_ORIGIN_LANDING: SchemaAttribute = SchemaAttribute { uuid: UUID_SCHEMA_ATTR_OAUTH2_RS_ORIGIN_LANDING, - name: Attribute::OAuth2RsOriginLanding.into(), + name: Attribute::OAuth2RsOriginLanding, description: "The landing page of an RS, that will automatically trigger the auth process".to_string(), syntax: SyntaxType::Url, @@ -379,7 +379,7 @@ pub static ref SCHEMA_ATTR_OAUTH2_RS_ORIGIN_LANDING: SchemaAttribute = SchemaAtt // Introduced in DomainLevel4 pub static ref SCHEMA_ATTR_OAUTH2_ALLOW_LOCALHOST_REDIRECT_DL4: SchemaAttribute = SchemaAttribute { uuid: UUID_SCHEMA_ATTR_OAUTH2_ALLOW_LOCALHOST_REDIRECT, - name: Attribute::OAuth2AllowLocalhostRedirect.into(), + name: Attribute::OAuth2AllowLocalhostRedirect, description: "Allow public clients associated to this RS to redirect to localhost".to_string(), syntax: SyntaxType::Boolean, @@ -388,7 +388,7 @@ pub static ref SCHEMA_ATTR_OAUTH2_ALLOW_LOCALHOST_REDIRECT_DL4: SchemaAttribute pub static ref SCHEMA_ATTR_OAUTH2_RS_CLAIM_MAP_DL4: SchemaAttribute = SchemaAttribute { uuid: UUID_SCHEMA_ATTR_OAUTH2_RS_CLAIM_MAP, - name: Attribute::OAuth2RsClaimMap.into(), + name: Attribute::OAuth2RsClaimMap, description: "A set of custom claims mapped to group memberships of accounts".to_string(), index: vec![IndexType::Equality], @@ -400,7 +400,7 @@ pub static ref SCHEMA_ATTR_OAUTH2_RS_CLAIM_MAP_DL4: SchemaAttribute = SchemaAttr pub static ref SCHEMA_ATTR_OAUTH2_RS_SCOPE_MAP: SchemaAttribute = SchemaAttribute { uuid: UUID_SCHEMA_ATTR_OAUTH2_RS_SCOPE_MAP, - name: Attribute::OAuth2RsScopeMap.into(), + name: Attribute::OAuth2RsScopeMap, description: "A reference to a group mapped to scopes for the associated oauth2 resource server".to_string(), index: vec![IndexType::Equality], @@ -411,7 +411,7 @@ pub static ref SCHEMA_ATTR_OAUTH2_RS_SCOPE_MAP: SchemaAttribute = SchemaAttribut pub static ref SCHEMA_ATTR_OAUTH2_RS_SUP_SCOPE_MAP: SchemaAttribute = SchemaAttribute { uuid: UUID_SCHEMA_ATTR_OAUTH2_RS_SUP_SCOPE_MAP, - name: Attribute::OAuth2RsSupScopeMap.into(), + name: Attribute::OAuth2RsSupScopeMap, description: "A reference to a group mapped to scopes for the associated oauth2 resource server".to_string(), index: vec![IndexType::Equality], @@ -422,7 +422,7 @@ pub static ref SCHEMA_ATTR_OAUTH2_RS_SUP_SCOPE_MAP: SchemaAttribute = SchemaAttr pub static ref SCHEMA_ATTR_OAUTH2_RS_BASIC_SECRET: SchemaAttribute = SchemaAttribute { uuid: UUID_SCHEMA_ATTR_OAUTH2_RS_BASIC_SECRET, - name: Attribute::OAuth2RsBasicSecret.into(), + name: Attribute::OAuth2RsBasicSecret, description: "When using oauth2 basic authentication, the secret string of the resource server".to_string(), syntax: SyntaxType::SecretUtf8String, @@ -431,7 +431,7 @@ pub static ref SCHEMA_ATTR_OAUTH2_RS_BASIC_SECRET: SchemaAttribute = SchemaAttri pub static ref SCHEMA_ATTR_OAUTH2_RS_TOKEN_KEY: SchemaAttribute = SchemaAttribute { uuid: UUID_SCHEMA_ATTR_OAUTH2_RS_TOKEN_KEY, - name: Attribute::OAuth2RsTokenKey.into(), + name: Attribute::OAuth2RsTokenKey, description: "An oauth2 resource servers unique token signing key".to_string(), syntax: SyntaxType::SecretUtf8String, @@ -440,7 +440,7 @@ pub static ref SCHEMA_ATTR_OAUTH2_RS_TOKEN_KEY: SchemaAttribute = SchemaAttribut pub static ref SCHEMA_ATTR_OAUTH2_RS_IMPLICIT_SCOPES: SchemaAttribute = SchemaAttribute { uuid: UUID_SCHEMA_ATTR_OAUTH2_RS_IMPLICIT_SCOPES, - name: Attribute::OAuth2RsImplicitScopes.into(), + name: Attribute::OAuth2RsImplicitScopes, description: "An oauth2 resource servers scopes that are implicitly granted to all users".to_string(), multivalue: true, @@ -450,7 +450,7 @@ pub static ref SCHEMA_ATTR_OAUTH2_RS_IMPLICIT_SCOPES: SchemaAttribute = SchemaAt pub static ref SCHEMA_ATTR_OAUTH2_CONSENT_SCOPE_MAP: SchemaAttribute = SchemaAttribute { uuid: UUID_SCHEMA_ATTR_OAUTH2_CONSENT_SCOPE_MAP, - name: Attribute::OAuth2ConsentScopeMap.into(), + name: Attribute::OAuth2ConsentScopeMap, description: "A set of scopes mapped from a relying server to a user, where the user has previously consented to the following. If changed or deleted, consent will be re-sought".to_string(), index: vec![IndexType::Equality], @@ -461,7 +461,7 @@ pub static ref SCHEMA_ATTR_OAUTH2_CONSENT_SCOPE_MAP: SchemaAttribute = SchemaAtt pub static ref SCHEMA_ATTR_OAUTH2_STRICT_REDIRECT_URI_DL7: SchemaAttribute = SchemaAttribute { uuid: UUID_SCHEMA_ATTR_OAUTH2_STRICT_REDIRECT_URI, - name: Attribute::OAuth2StrictRedirectUri.into(), + name: Attribute::OAuth2StrictRedirectUri, description: "Represents if strict redirect uri enforcement is enabled.".to_string(), syntax: SyntaxType::Boolean, @@ -470,7 +470,7 @@ pub static ref SCHEMA_ATTR_OAUTH2_STRICT_REDIRECT_URI_DL7: SchemaAttribute = Sch pub static ref SCHEMA_ATTR_ES256_PRIVATE_KEY_DER: SchemaAttribute = SchemaAttribute { uuid: UUID_SCHEMA_ATTR_ES256_PRIVATE_KEY_DER, - name: Attribute::Es256PrivateKeyDer.into(), + name: Attribute::Es256PrivateKeyDer, description: "An es256 private key".to_string(), syntax: SyntaxType::PrivateBinary, @@ -479,7 +479,7 @@ pub static ref SCHEMA_ATTR_ES256_PRIVATE_KEY_DER: SchemaAttribute = SchemaAttrib pub static ref SCHEMA_ATTR_RS256_PRIVATE_KEY_DER: SchemaAttribute = SchemaAttribute { uuid: UUID_SCHEMA_ATTR_RS256_PRIVATE_KEY_DER, - name: Attribute::Rs256PrivateKeyDer.into(), + name: Attribute::Rs256PrivateKeyDer, description: "An rs256 private key".to_string(), syntax: SyntaxType::PrivateBinary, @@ -488,7 +488,7 @@ pub static ref SCHEMA_ATTR_RS256_PRIVATE_KEY_DER: SchemaAttribute = SchemaAttrib pub static ref SCHEMA_ATTR_JWS_ES256_PRIVATE_KEY: SchemaAttribute = SchemaAttribute { uuid: UUID_SCHEMA_ATTR_JWS_ES256_PRIVATE_KEY, - name: Attribute::JwsEs256PrivateKey.into(), + name: Attribute::JwsEs256PrivateKey, description: "An es256 private key for jws".to_string(), index: vec![IndexType::Equality], @@ -500,7 +500,7 @@ pub static ref SCHEMA_ATTR_JWS_ES256_PRIVATE_KEY: SchemaAttribute = SchemaAttrib // TO BE REMOVED IN A FUTURE RELEASE pub static ref SCHEMA_ATTR_PRIVATE_COOKIE_KEY: SchemaAttribute = SchemaAttribute { uuid: UUID_SCHEMA_ATTR_PRIVATE_COOKIE_KEY, - name: Attribute::PrivateCookieKey.into(), + name: Attribute::PrivateCookieKey, description: "An private cookie hmac key".to_string(), syntax: SyntaxType::PrivateBinary, @@ -509,7 +509,7 @@ pub static ref SCHEMA_ATTR_PRIVATE_COOKIE_KEY: SchemaAttribute = SchemaAttribute pub static ref SCHEMA_ATTR_OAUTH2_ALLOW_INSECURE_CLIENT_DISABLE_PKCE: SchemaAttribute = SchemaAttribute { uuid: UUID_SCHEMA_ATTR_OAUTH2_ALLOW_INSECURE_CLIENT_DISABLE_PKCE, - name: Attribute::OAuth2AllowInsecureClientDisablePkce.into(), + name: Attribute::OAuth2AllowInsecureClientDisablePkce, description: "Allows disabling of PKCE for insecure OAuth2 clients".to_string(), syntax: SyntaxType::Boolean, @@ -518,7 +518,7 @@ pub static ref SCHEMA_ATTR_OAUTH2_ALLOW_INSECURE_CLIENT_DISABLE_PKCE: SchemaAttr pub static ref SCHEMA_ATTR_OAUTH2_JWT_LEGACY_CRYPTO_ENABLE: SchemaAttribute = SchemaAttribute { uuid: UUID_SCHEMA_ATTR_OAUTH2_JWT_LEGACY_CRYPTO_ENABLE, - name: Attribute::OAuth2JwtLegacyCryptoEnable.into(), + name: Attribute::OAuth2JwtLegacyCryptoEnable, description: "Allows enabling legacy JWT cryptograhpy for clients".to_string(), syntax: SyntaxType::Boolean, @@ -527,7 +527,7 @@ pub static ref SCHEMA_ATTR_OAUTH2_JWT_LEGACY_CRYPTO_ENABLE: SchemaAttribute = Sc pub static ref SCHEMA_ATTR_CREDENTIAL_UPDATE_INTENT_TOKEN: SchemaAttribute = SchemaAttribute { uuid: UUID_SCHEMA_ATTR_CREDENTIAL_UPDATE_INTENT_TOKEN, - name: Attribute::CredentialUpdateIntentToken.into(), + name: Attribute::CredentialUpdateIntentToken, description: "The status of a credential update intent token".to_string(), index: vec![IndexType::Equality], @@ -538,7 +538,7 @@ pub static ref SCHEMA_ATTR_CREDENTIAL_UPDATE_INTENT_TOKEN: SchemaAttribute = Sch pub static ref SCHEMA_ATTR_PASSKEYS: SchemaAttribute = SchemaAttribute { uuid: UUID_SCHEMA_ATTR_PASSKEYS, - name: Attribute::PassKeys.into(), + name: Attribute::PassKeys, description: "A set of registered passkeys".to_string(), index: vec![IndexType::Equality], @@ -550,7 +550,7 @@ pub static ref SCHEMA_ATTR_PASSKEYS: SchemaAttribute = SchemaAttribute { pub static ref SCHEMA_ATTR_ATTESTED_PASSKEYS: SchemaAttribute = SchemaAttribute { uuid: UUID_SCHEMA_ATTR_ATTESTED_PASSKEYS, - name: Attribute::AttestedPasskeys.into(), + name: Attribute::AttestedPasskeys, description: "A set of registered device keys".to_string(), index: vec![IndexType::Equality], @@ -562,7 +562,7 @@ pub static ref SCHEMA_ATTR_ATTESTED_PASSKEYS: SchemaAttribute = SchemaAttribute pub static ref SCHEMA_ATTR_DYNGROUP_FILTER: SchemaAttribute = SchemaAttribute { uuid: UUID_SCHEMA_ATTR_DYNGROUP_FILTER, - name: Attribute::DynGroupFilter.into(), + name: Attribute::DynGroupFilter, description: "A filter describing the set of entries to add to a dynamic group".to_string(), syntax: SyntaxType::JsonFilter, @@ -571,7 +571,7 @@ pub static ref SCHEMA_ATTR_DYNGROUP_FILTER: SchemaAttribute = SchemaAttribute { pub static ref SCHEMA_ATTR_OAUTH2_PREFER_SHORT_USERNAME: SchemaAttribute = SchemaAttribute { uuid: UUID_SCHEMA_ATTR_OAUTH2_PREFER_SHORT_USERNAME, - name: Attribute::OAuth2PreferShortUsername.into(), + name: Attribute::OAuth2PreferShortUsername, description: "Use 'name' instead of 'spn' in the preferred_username claim".to_string(), syntax: SyntaxType::Boolean, @@ -580,7 +580,7 @@ pub static ref SCHEMA_ATTR_OAUTH2_PREFER_SHORT_USERNAME: SchemaAttribute = Schem pub static ref SCHEMA_ATTR_API_TOKEN_SESSION: SchemaAttribute = SchemaAttribute { uuid: UUID_SCHEMA_ATTR_API_TOKEN_SESSION, - name: Attribute::ApiTokenSession.into(), + name: Attribute::ApiTokenSession, description: "A session entry related to an issued API token".to_string(), index: vec![IndexType::Equality], @@ -592,7 +592,7 @@ pub static ref SCHEMA_ATTR_API_TOKEN_SESSION: SchemaAttribute = SchemaAttribute pub static ref SCHEMA_ATTR_USER_AUTH_TOKEN_SESSION: SchemaAttribute = SchemaAttribute { uuid: UUID_SCHEMA_ATTR_USER_AUTH_TOKEN_SESSION, - name: Attribute::UserAuthTokenSession.into(), + name: Attribute::UserAuthTokenSession, description: "A session entry related to an issued user auth token".to_string(), index: vec![IndexType::Equality], @@ -604,7 +604,7 @@ pub static ref SCHEMA_ATTR_USER_AUTH_TOKEN_SESSION: SchemaAttribute = SchemaAttr pub static ref SCHEMA_ATTR_OAUTH2_SESSION: SchemaAttribute = SchemaAttribute { uuid: UUID_SCHEMA_ATTR_OAUTH2_SESSION, - name: Attribute::OAuth2Session.into(), + name: Attribute::OAuth2Session, description: "A session entry to an active oauth2 session, bound to a parent user auth token".to_string(), index: vec![IndexType::Equality], @@ -615,7 +615,7 @@ pub static ref SCHEMA_ATTR_OAUTH2_SESSION: SchemaAttribute = SchemaAttribute { pub static ref SCHEMA_ATTR_SYNC_TOKEN_SESSION: SchemaAttribute = SchemaAttribute { uuid: UUID_SCHEMA_ATTR_SYNC_TOKEN_SESSION, - name: Attribute::SyncTokenSession.into(), + name: Attribute::SyncTokenSession, description: "A session entry related to an issued sync token".to_string(), index: vec![IndexType::Equality], @@ -626,7 +626,7 @@ pub static ref SCHEMA_ATTR_SYNC_TOKEN_SESSION: SchemaAttribute = SchemaAttribute pub static ref SCHEMA_ATTR_SYNC_COOKIE: SchemaAttribute = SchemaAttribute { uuid: UUID_SCHEMA_ATTR_SYNC_COOKIE, - name: Attribute::SyncCookie.into(), + name: Attribute::SyncCookie, description: "A private sync cookie for a remote IDM source".to_string(), syntax: SyntaxType::PrivateBinary, @@ -635,7 +635,7 @@ pub static ref SCHEMA_ATTR_SYNC_COOKIE: SchemaAttribute = SchemaAttribute { pub static ref SCHEMA_ATTR_GRANT_UI_HINT: SchemaAttribute = SchemaAttribute { uuid: UUID_SCHEMA_ATTR_GRANT_UI_HINT, - name: Attribute::GrantUiHint.into(), + name: Attribute::GrantUiHint, description: "A UI hint that is granted via membership to a group".to_string(), index: vec![IndexType::Equality], @@ -646,7 +646,7 @@ pub static ref SCHEMA_ATTR_GRANT_UI_HINT: SchemaAttribute = SchemaAttribute { pub static ref SCHEMA_ATTR_SYNC_CREDENTIAL_PORTAL: SchemaAttribute = SchemaAttribute { uuid: UUID_SCHEMA_ATTR_SYNC_CREDENTIAL_PORTAL, - name: Attribute::SyncCredentialPortal.into(), + name: Attribute::SyncCredentialPortal, description: "The url of an external credential portal for synced accounts to visit to update their credentials".to_string(), syntax: SyntaxType::Url, @@ -655,7 +655,7 @@ pub static ref SCHEMA_ATTR_SYNC_CREDENTIAL_PORTAL: SchemaAttribute = SchemaAttri pub static ref SCHEMA_ATTR_SYNC_YIELD_AUTHORITY: SchemaAttribute = SchemaAttribute { uuid: UUID_SCHEMA_ATTR_SYNC_YIELD_AUTHORITY, - name: Attribute::SyncYieldAuthority.into(), + name: Attribute::SyncYieldAuthority, description: "A set of attributes that have their authority yielded to Kanidm in a sync agreement".to_string(), multivalue: true, @@ -665,7 +665,7 @@ pub static ref SCHEMA_ATTR_SYNC_YIELD_AUTHORITY: SchemaAttribute = SchemaAttribu pub static ref SCHEMA_ATTR_CREDENTIAL_TYPE_MINIMUM: SchemaAttribute = SchemaAttribute { uuid: UUID_SCHEMA_ATTR_CREDENTIAL_TYPE_MINIMUM, - name: Attribute::CredentialTypeMinimum.into(), + name: Attribute::CredentialTypeMinimum, description: "The minimum level of credential type that can satisfy this policy".to_string(), multivalue: false, @@ -675,7 +675,7 @@ pub static ref SCHEMA_ATTR_CREDENTIAL_TYPE_MINIMUM: SchemaAttribute = SchemaAttr pub static ref SCHEMA_ATTR_LIMIT_SEARCH_MAX_RESULTS_DL6: SchemaAttribute = SchemaAttribute { uuid: UUID_SCHEMA_ATTR_LIMIT_SEARCH_MAX_RESULTS, - name: Attribute::LimitSearchMaxResults.into(), + name: Attribute::LimitSearchMaxResults, description: "The maximum number of query results that may be returned in a single operation".to_string(), multivalue: false, @@ -685,7 +685,7 @@ pub static ref SCHEMA_ATTR_LIMIT_SEARCH_MAX_RESULTS_DL6: SchemaAttribute = Schem pub static ref SCHEMA_ATTR_LIMIT_SEARCH_MAX_FILTER_TEST_DL6: SchemaAttribute = SchemaAttribute { uuid: UUID_SCHEMA_ATTR_LIMIT_SEARCH_MAX_FILTER_TEST, - name: Attribute::LimitSearchMaxFilterTest.into(), + name: Attribute::LimitSearchMaxFilterTest, description: "The maximum number of entries that may be examined in a partially indexed query".to_string(), multivalue: false, @@ -695,7 +695,7 @@ pub static ref SCHEMA_ATTR_LIMIT_SEARCH_MAX_FILTER_TEST_DL6: SchemaAttribute = S pub static ref SCHEMA_ATTR_KEY_INTERNAL_DATA_DL6: SchemaAttribute = SchemaAttribute { uuid: UUID_SCHEMA_ATTR_KEY_INTERNAL_DATA, - name: Attribute::KeyInternalData.into(), + name: Attribute::KeyInternalData, description: "".to_string(), multivalue: true, syntax: SyntaxType::KeyInternal, @@ -704,7 +704,7 @@ pub static ref SCHEMA_ATTR_KEY_INTERNAL_DATA_DL6: SchemaAttribute = SchemaAttrib pub static ref SCHEMA_ATTR_KEY_PROVIDER_DL6: SchemaAttribute = SchemaAttribute { uuid: UUID_SCHEMA_ATTR_KEY_PROVIDER, - name: Attribute::KeyProvider.into(), + name: Attribute::KeyProvider, description: "".to_string(), multivalue: false, syntax: SyntaxType::ReferenceUuid, @@ -713,7 +713,7 @@ pub static ref SCHEMA_ATTR_KEY_PROVIDER_DL6: SchemaAttribute = SchemaAttribute { pub static ref SCHEMA_ATTR_KEY_ACTION_ROTATE_DL6: SchemaAttribute = SchemaAttribute { uuid: UUID_SCHEMA_ATTR_KEY_ACTION_ROTATE, - name: Attribute::KeyActionRotate.into(), + name: Attribute::KeyActionRotate, description: "".to_string(), multivalue: false, // Ephemeral action. @@ -724,7 +724,7 @@ pub static ref SCHEMA_ATTR_KEY_ACTION_ROTATE_DL6: SchemaAttribute = SchemaAttrib pub static ref SCHEMA_ATTR_KEY_ACTION_REVOKE_DL6: SchemaAttribute = SchemaAttribute { uuid: UUID_SCHEMA_ATTR_KEY_ACTION_REVOKE, - name: Attribute::KeyActionRevoke.into(), + name: Attribute::KeyActionRevoke, description: "".to_string(), multivalue: true, // Ephemeral action. @@ -735,7 +735,7 @@ pub static ref SCHEMA_ATTR_KEY_ACTION_REVOKE_DL6: SchemaAttribute = SchemaAttrib pub static ref SCHEMA_ATTR_KEY_ACTION_IMPORT_JWS_ES256_DL6: SchemaAttribute = SchemaAttribute { uuid: UUID_SCHEMA_ATTR_KEY_ACTION_IMPORT_JWS_ES256, - name: Attribute::KeyActionImportJwsEs256.into(), + name: Attribute::KeyActionImportJwsEs256, description: "".to_string(), multivalue: true, // Ephemeral action. @@ -746,7 +746,7 @@ pub static ref SCHEMA_ATTR_KEY_ACTION_IMPORT_JWS_ES256_DL6: SchemaAttribute = Sc pub static ref SCHEMA_ATTR_PATCH_LEVEL_DL7: SchemaAttribute = SchemaAttribute { uuid: UUID_SCHEMA_ATTR_PATCH_LEVEL, - name: Attribute::PatchLevel.into(), + name: Attribute::PatchLevel, description: "".to_string(), syntax: SyntaxType::Uint32, ..Default::default() @@ -754,7 +754,7 @@ pub static ref SCHEMA_ATTR_PATCH_LEVEL_DL7: SchemaAttribute = SchemaAttribute { pub static ref SCHEMA_ATTR_DOMAIN_DEVELOPMENT_TAINT_DL7: SchemaAttribute = SchemaAttribute { uuid: UUID_SCHEMA_ATTR_DOMAIN_DEVELOPMENT_TAINT, - name: Attribute::DomainDevelopmentTaint.into(), + name: Attribute::DomainDevelopmentTaint, description: "A flag to show that the domain has been run on a development build, and will need additional work to upgrade/migrate.".to_string(), syntax: SyntaxType::Boolean, ..Default::default() @@ -762,7 +762,7 @@ pub static ref SCHEMA_ATTR_DOMAIN_DEVELOPMENT_TAINT_DL7: SchemaAttribute = Schem pub static ref SCHEMA_ATTR_REFERS_DL7: SchemaAttribute = SchemaAttribute { uuid: UUID_SCHEMA_ATTR_REFERS, - name: Attribute::Refers.into(), + name: Attribute::Refers, description: "A reference to linked object".to_string(), multivalue: false, syntax: SyntaxType::ReferenceUuid, @@ -771,7 +771,7 @@ pub static ref SCHEMA_ATTR_REFERS_DL7: SchemaAttribute = SchemaAttribute { pub static ref SCHEMA_ATTR_LINKED_GROUP_DL8: SchemaAttribute = SchemaAttribute { uuid: UUID_SCHEMA_ATTR_LINKED_GROUP, - name: Attribute::LinkedGroup.into(), + name: Attribute::LinkedGroup, description: "A reference linking a group to an entry".to_string(), multivalue: false, @@ -781,7 +781,7 @@ pub static ref SCHEMA_ATTR_LINKED_GROUP_DL8: SchemaAttribute = SchemaAttribute { pub static ref SCHEMA_ATTR_CERTIFICATE_DL7: SchemaAttribute = SchemaAttribute { uuid: UUID_SCHEMA_ATTR_CERTIFICATE, - name: Attribute::Certificate.into(), + name: Attribute::Certificate, description: "An x509 Certificate".to_string(), multivalue: false, syntax: SyntaxType::Certificate, @@ -790,7 +790,7 @@ pub static ref SCHEMA_ATTR_CERTIFICATE_DL7: SchemaAttribute = SchemaAttribute { pub static ref SCHEMA_ATTR_APPLICATION_PASSWORD_DL8: SchemaAttribute = SchemaAttribute { uuid: UUID_SCHEMA_ATTR_APPLICATION_PASSWORD, - name: Attribute::ApplicationPassword.into(), + name: Attribute::ApplicationPassword, description: "A set of application passwords".to_string(), multivalue: true, @@ -807,13 +807,13 @@ pub static ref SCHEMA_CLASS_PERSON: SchemaClass = SchemaClass { sync_allowed: true, systemmay: vec![ - Attribute::Mail.into(), - Attribute::LegalName.into(), + Attribute::Mail, + Attribute::LegalName, ], systemmust: vec![ - Attribute::DisplayName.into(), - Attribute::Name.into(), - Attribute::IdVerificationEcKey.into()], + Attribute::DisplayName, + Attribute::Name, + Attribute::IdVerificationEcKey], ..Default::default() }; @@ -824,20 +824,20 @@ pub static ref SCHEMA_CLASS_PERSON_DL5: SchemaClass = SchemaClass { sync_allowed: true, systemmay: vec![ - Attribute::PrimaryCredential.into(), - Attribute::PassKeys.into(), - Attribute::AttestedPasskeys.into(), - Attribute::CredentialUpdateIntentToken.into(), - Attribute::SshPublicKey.into(), - Attribute::RadiusSecret.into(), - Attribute::OAuth2ConsentScopeMap.into(), - Attribute::UserAuthTokenSession.into(), - Attribute::OAuth2Session.into(), - Attribute::Mail.into(), - Attribute::LegalName.into(), + Attribute::PrimaryCredential, + Attribute::PassKeys, + Attribute::AttestedPasskeys, + Attribute::CredentialUpdateIntentToken, + Attribute::SshPublicKey, + Attribute::RadiusSecret, + Attribute::OAuth2ConsentScopeMap, + Attribute::UserAuthTokenSession, + Attribute::OAuth2Session, + Attribute::Mail, + Attribute::LegalName, ], systemmust: vec![ - Attribute::IdVerificationEcKey.into() + Attribute::IdVerificationEcKey ], systemexcludes: vec![EntryClass::ServiceAccount.into(), EntryClass::Application.into()], ..Default::default() @@ -850,21 +850,21 @@ pub static ref SCHEMA_CLASS_PERSON_DL8: SchemaClass = SchemaClass { sync_allowed: true, systemmay: vec![ - Attribute::PrimaryCredential.into(), - Attribute::PassKeys.into(), - Attribute::AttestedPasskeys.into(), - Attribute::CredentialUpdateIntentToken.into(), - Attribute::SshPublicKey.into(), - Attribute::RadiusSecret.into(), - Attribute::OAuth2ConsentScopeMap.into(), - Attribute::UserAuthTokenSession.into(), - Attribute::OAuth2Session.into(), - Attribute::Mail.into(), - Attribute::LegalName.into(), - Attribute::ApplicationPassword.into(), + Attribute::PrimaryCredential, + Attribute::PassKeys, + Attribute::AttestedPasskeys, + Attribute::CredentialUpdateIntentToken, + Attribute::SshPublicKey, + Attribute::RadiusSecret, + Attribute::OAuth2ConsentScopeMap, + Attribute::UserAuthTokenSession, + Attribute::OAuth2Session, + Attribute::Mail, + Attribute::LegalName, + Attribute::ApplicationPassword, ], systemmust: vec![ - Attribute::IdVerificationEcKey.into() + Attribute::IdVerificationEcKey ], systemexcludes: vec![EntryClass::ServiceAccount.into(), EntryClass::Application.into()], ..Default::default() @@ -876,12 +876,12 @@ pub static ref SCHEMA_CLASS_ORGPERSON: SchemaClass = SchemaClass { description: "Object representation of an org person".to_string(), systemmay: vec![ - Attribute::LegalName.into() + Attribute::LegalName ], systemmust: vec![ - Attribute::Mail.into(), - Attribute::DisplayName.into(), - Attribute::Name.into() + Attribute::Mail, + Attribute::DisplayName, + Attribute::Name ], ..Default::default() }; @@ -893,14 +893,14 @@ pub static ref SCHEMA_CLASS_GROUP_DL6: SchemaClass = SchemaClass { sync_allowed: true, systemmay: vec![ - Attribute::Member.into(), - Attribute::GrantUiHint.into(), - Attribute::Description.into(), - Attribute::Mail.into(), + Attribute::Member, + Attribute::GrantUiHint, + Attribute::Description, + Attribute::Mail, ], systemmust: vec![ - Attribute::Name.into(), - Attribute::Spn.into()], + Attribute::Name, + Attribute::Spn], ..Default::default() }; @@ -909,8 +909,8 @@ pub static ref SCHEMA_CLASS_DYNGROUP: SchemaClass = SchemaClass { name: EntryClass::DynGroup.into(), description: "Object representation of a dynamic group".to_string(), - systemmust: vec![Attribute::DynGroupFilter.into()], - systemmay: vec![Attribute::DynMember.into()], + systemmust: vec![Attribute::DynGroupFilter], + systemmay: vec![Attribute::DynMember], systemsupplements: vec![Attribute::Group.into()], ..Default::default() }; @@ -921,13 +921,13 @@ pub static ref SCHEMA_CLASS_ACCOUNT_POLICY_DL6: SchemaClass = SchemaClass { description: "Policies applied to accounts that are members of a group".to_string(), systemmay: vec![ - Attribute::AuthSessionExpiry.into(), - Attribute::PrivilegeExpiry.into(), - Attribute::AuthPasswordMinimumLength.into(), - Attribute::CredentialTypeMinimum.into(), - Attribute::WebauthnAttestationCaList.into(), - Attribute::LimitSearchMaxResults.into(), - Attribute::LimitSearchMaxFilterTest.into(), + Attribute::AuthSessionExpiry, + Attribute::PrivilegeExpiry, + Attribute::AuthPasswordMinimumLength, + Attribute::CredentialTypeMinimum, + Attribute::WebauthnAttestationCaList, + Attribute::LimitSearchMaxResults, + Attribute::LimitSearchMaxFilterTest, ], systemsupplements: vec![Attribute::Group.into()], ..Default::default() @@ -940,25 +940,25 @@ pub static ref SCHEMA_CLASS_ACCOUNT: SchemaClass = SchemaClass { sync_allowed: true, systemmay: vec![ - Attribute::PrimaryCredential.into(), - Attribute::PassKeys.into(), - Attribute::AttestedPasskeys.into(), - Attribute::CredentialUpdateIntentToken.into(), - Attribute::SshPublicKey.into(), - Attribute::RadiusSecret.into(), - Attribute::AccountExpire.into(), - Attribute::AccountValidFrom.into(), - Attribute::Mail.into(), - Attribute::OAuth2ConsentScopeMap.into(), - Attribute::UserAuthTokenSession.into(), - Attribute::OAuth2Session.into(), - Attribute::Description.into(), - Attribute::NameHistory.into(), + Attribute::PrimaryCredential, + Attribute::PassKeys, + Attribute::AttestedPasskeys, + Attribute::CredentialUpdateIntentToken, + Attribute::SshPublicKey, + Attribute::RadiusSecret, + Attribute::AccountExpire, + Attribute::AccountValidFrom, + Attribute::Mail, + Attribute::OAuth2ConsentScopeMap, + Attribute::UserAuthTokenSession, + Attribute::OAuth2Session, + Attribute::Description, + Attribute::NameHistory, ], systemmust: vec![ - Attribute::DisplayName.into(), - Attribute::Name.into(), - Attribute::Spn.into() + Attribute::DisplayName, + Attribute::Name, + Attribute::Spn ], systemsupplements: vec![ EntryClass::Person.into(), @@ -974,14 +974,14 @@ pub static ref SCHEMA_CLASS_ACCOUNT_DL5: SchemaClass = SchemaClass { sync_allowed: true, systemmay: vec![ - Attribute::AccountExpire.into(), - Attribute::AccountValidFrom.into(), - Attribute::NameHistory.into(), + Attribute::AccountExpire, + Attribute::AccountValidFrom, + Attribute::NameHistory, ], systemmust: vec![ - Attribute::DisplayName.into(), - Attribute::Name.into(), - Attribute::Spn.into() + Attribute::DisplayName, + Attribute::Name, + Attribute::Spn ], systemsupplements: vec![ EntryClass::Person.into(), @@ -998,17 +998,17 @@ pub static ref SCHEMA_CLASS_SERVICE_ACCOUNT_DL6: SchemaClass = SchemaClass { sync_allowed: true, systemmay: vec![ - Attribute::SshPublicKey.into(), - Attribute::UserAuthTokenSession.into(), - Attribute::OAuth2Session.into(), - Attribute::OAuth2ConsentScopeMap.into(), - Attribute::Description.into(), + Attribute::SshPublicKey, + Attribute::UserAuthTokenSession, + Attribute::OAuth2Session, + Attribute::OAuth2ConsentScopeMap, + Attribute::Description, - Attribute::Mail.into(), - Attribute::PrimaryCredential.into(), - Attribute::ApiTokenSession.into(), + Attribute::Mail, + Attribute::PrimaryCredential, + Attribute::ApiTokenSession, - Attribute::JwsEs256PrivateKey.into(), + Attribute::JwsEs256PrivateKey, ], systemexcludes: vec![EntryClass::Person.into()], ..Default::default() @@ -1021,15 +1021,15 @@ pub static ref SCHEMA_CLASS_SERVICE_ACCOUNT_DL7: SchemaClass = SchemaClass { sync_allowed: true, systemmay: vec![ - Attribute::SshPublicKey.into(), - Attribute::UserAuthTokenSession.into(), - Attribute::OAuth2Session.into(), - Attribute::OAuth2ConsentScopeMap.into(), - Attribute::Description.into(), + Attribute::SshPublicKey, + Attribute::UserAuthTokenSession, + Attribute::OAuth2Session, + Attribute::OAuth2ConsentScopeMap, + Attribute::Description, - Attribute::Mail.into(), - Attribute::PrimaryCredential.into(), - Attribute::ApiTokenSession.into(), + Attribute::Mail, + Attribute::PrimaryCredential, + Attribute::ApiTokenSession, ], systemexcludes: vec![EntryClass::Person.into()], ..Default::default() @@ -1040,13 +1040,13 @@ pub static ref SCHEMA_CLASS_SYNC_ACCOUNT_DL6: SchemaClass = SchemaClass { name: EntryClass::SyncAccount.into(), description: "Object representation of sync account".to_string(), - systemmust: vec![Attribute::Name.into()], + systemmust: vec![Attribute::Name], systemmay: vec![ - Attribute::SyncTokenSession.into(), - Attribute::SyncCookie.into(), - Attribute::SyncCredentialPortal.into(), - Attribute::SyncYieldAuthority.into(), - Attribute::JwsEs256PrivateKey.into(), + Attribute::SyncTokenSession, + Attribute::SyncCookie, + Attribute::SyncCredentialPortal, + Attribute::SyncYieldAuthority, + Attribute::JwsEs256PrivateKey, ], systemexcludes: vec![EntryClass::Account.into()], ..Default::default() @@ -1057,12 +1057,12 @@ pub static ref SCHEMA_CLASS_SYNC_ACCOUNT_DL7: SchemaClass = SchemaClass { name: EntryClass::SyncAccount.into(), description: "Object representation of sync account".to_string(), - systemmust: vec![Attribute::Name.into()], + systemmust: vec![Attribute::Name], systemmay: vec![ - Attribute::SyncTokenSession.into(), - Attribute::SyncCookie.into(), - Attribute::SyncCredentialPortal.into(), - Attribute::SyncYieldAuthority.into(), + Attribute::SyncTokenSession, + Attribute::SyncCookie, + Attribute::SyncCredentialPortal, + Attribute::SyncYieldAuthority, ], systemexcludes: vec![EntryClass::Account.into()], ..Default::default() @@ -1074,19 +1074,19 @@ pub static ref SCHEMA_CLASS_DOMAIN_INFO_DL6: SchemaClass = SchemaClass { description: "Local domain information and configuration".to_string(), systemmay: vec![ - Attribute::DomainSsid.into(), - Attribute::DomainLdapBasedn.into(), - Attribute::LdapAllowUnixPwBind.into(), - Attribute::PrivateCookieKey.into(), - Attribute::FernetPrivateKeyStr.into(), - Attribute::Es256PrivateKeyDer.into(), + Attribute::DomainSsid, + Attribute::DomainLdapBasedn, + Attribute::LdapAllowUnixPwBind, + Attribute::PrivateCookieKey, + Attribute::FernetPrivateKeyStr, + Attribute::Es256PrivateKeyDer, ], systemmust: vec![ - Attribute::Name.into(), - Attribute::DomainUuid.into(), - Attribute::DomainName.into(), - Attribute::DomainDisplayName.into(), - Attribute::Version.into(), + Attribute::Name, + Attribute::DomainUuid, + Attribute::DomainName, + Attribute::DomainDisplayName, + Attribute::Version, ], ..Default::default() }; @@ -1097,18 +1097,18 @@ pub static ref SCHEMA_CLASS_DOMAIN_INFO_DL7: SchemaClass = SchemaClass { description: "Local domain information and configuration".to_string(), systemmay: vec![ - Attribute::DomainSsid.into(), - Attribute::DomainLdapBasedn.into(), - Attribute::LdapAllowUnixPwBind.into(), - Attribute::PatchLevel.into(), - Attribute::DomainDevelopmentTaint.into(), + Attribute::DomainSsid, + Attribute::DomainLdapBasedn, + Attribute::LdapAllowUnixPwBind, + Attribute::PatchLevel, + Attribute::DomainDevelopmentTaint, ], systemmust: vec![ - Attribute::Name.into(), - Attribute::DomainUuid.into(), - Attribute::DomainName.into(), - Attribute::DomainDisplayName.into(), - Attribute::Version.into(), + Attribute::Name, + Attribute::DomainUuid, + Attribute::DomainName, + Attribute::DomainDisplayName, + Attribute::Version, ], ..Default::default() }; @@ -1119,19 +1119,19 @@ pub static ref SCHEMA_CLASS_DOMAIN_INFO_DL8: SchemaClass = SchemaClass { description: "Local domain information and configuration".to_string(), systemmay: vec![ - Attribute::DomainSsid.into(), - Attribute::DomainLdapBasedn.into(), - Attribute::LdapAllowUnixPwBind.into(), - Attribute::Image.into(), - Attribute::PatchLevel.into(), - Attribute::DomainDevelopmentTaint.into(), + Attribute::DomainSsid, + Attribute::DomainLdapBasedn, + Attribute::LdapAllowUnixPwBind, + Attribute::Image, + Attribute::PatchLevel, + Attribute::DomainDevelopmentTaint, ], systemmust: vec![ - Attribute::Name.into(), - Attribute::DomainUuid.into(), - Attribute::DomainName.into(), - Attribute::DomainDisplayName.into(), - Attribute::Version.into(), + Attribute::Name, + Attribute::DomainUuid, + Attribute::DomainName, + Attribute::DomainDisplayName, + Attribute::Version, ], ..Default::default() }; @@ -1142,7 +1142,7 @@ pub static ref SCHEMA_CLASS_POSIXGROUP: SchemaClass = SchemaClass { description: "Object representation of a posix group, requires group".to_string(), sync_allowed: true, - systemmust: vec![Attribute::GidNumber.into()], + systemmust: vec![Attribute::GidNumber], systemsupplements: vec![Attribute::Group.into()], ..Default::default() }; @@ -1153,8 +1153,8 @@ pub static ref SCHEMA_CLASS_POSIXACCOUNT: SchemaClass = SchemaClass { description: "Object representation of a posix account, requires account".to_string(), sync_allowed: true, - systemmay: vec![Attribute::LoginShell.into(), Attribute::UnixPassword.into()], - systemmust: vec![Attribute::GidNumber.into()], + systemmay: vec![Attribute::LoginShell, Attribute::UnixPassword], + systemmust: vec![Attribute::GidNumber], systemsupplements: vec![Attribute::Account.into()], ..Default::default() }; @@ -1165,11 +1165,11 @@ pub static ref SCHEMA_CLASS_SYSTEM_CONFIG: SchemaClass = SchemaClass { description: "The class representing a system (topologies) configuration options".to_string(), systemmay: vec![ - Attribute::Description.into(), - Attribute::BadlistPassword.into(), - Attribute::AuthSessionExpiry.into(), - Attribute::PrivilegeExpiry.into(), - Attribute::DeniedName.into() + Attribute::Description, + Attribute::BadlistPassword, + Attribute::AuthSessionExpiry, + Attribute::PrivilegeExpiry, + Attribute::DeniedName ], ..Default::default() }; @@ -1180,22 +1180,22 @@ pub static ref SCHEMA_CLASS_OAUTH2_RS_DL4: SchemaClass = SchemaClass { description: "The class representing a configured Oauth2 Resource Server".to_string(), systemmay: vec![ - Attribute::Description.into(), - Attribute::OAuth2RsScopeMap.into(), - Attribute::OAuth2RsSupScopeMap.into(), - Attribute::Rs256PrivateKeyDer.into(), - Attribute::OAuth2JwtLegacyCryptoEnable.into(), - Attribute::OAuth2PreferShortUsername.into(), - Attribute::OAuth2RsOriginLanding.into(), - Attribute::Image.into(), - Attribute::OAuth2RsClaimMap.into(), + Attribute::Description, + Attribute::OAuth2RsScopeMap, + Attribute::OAuth2RsSupScopeMap, + Attribute::Rs256PrivateKeyDer, + Attribute::OAuth2JwtLegacyCryptoEnable, + Attribute::OAuth2PreferShortUsername, + Attribute::OAuth2RsOriginLanding, + Attribute::Image, + Attribute::OAuth2RsClaimMap, ], systemmust: vec![ - Attribute::OAuth2RsName.into(), - Attribute::DisplayName.into(), - Attribute::OAuth2RsOrigin.into(), - Attribute::OAuth2RsTokenKey.into(), - Attribute::Es256PrivateKeyDer.into(), + Attribute::OAuth2RsName, + Attribute::DisplayName, + Attribute::OAuth2RsOrigin, + Attribute::OAuth2RsTokenKey, + Attribute::Es256PrivateKeyDer, ], ..Default::default() }; @@ -1206,21 +1206,21 @@ pub static ref SCHEMA_CLASS_OAUTH2_RS_DL5: SchemaClass = SchemaClass { description: "The class representing a configured Oauth2 Resource Server".to_string(), systemmay: vec![ - Attribute::Description.into(), - Attribute::OAuth2RsScopeMap.into(), - Attribute::OAuth2RsSupScopeMap.into(), - Attribute::Rs256PrivateKeyDer.into(), - Attribute::OAuth2JwtLegacyCryptoEnable.into(), - Attribute::OAuth2PreferShortUsername.into(), - Attribute::OAuth2RsOriginLanding.into(), - Attribute::Image.into(), - Attribute::OAuth2RsClaimMap.into(), - Attribute::OAuth2Session.into(), + Attribute::Description, + Attribute::OAuth2RsScopeMap, + Attribute::OAuth2RsSupScopeMap, + Attribute::Rs256PrivateKeyDer, + Attribute::OAuth2JwtLegacyCryptoEnable, + Attribute::OAuth2PreferShortUsername, + Attribute::OAuth2RsOriginLanding, + Attribute::Image, + Attribute::OAuth2RsClaimMap, + Attribute::OAuth2Session, ], systemmust: vec![ - Attribute::OAuth2RsOrigin.into(), - Attribute::OAuth2RsTokenKey.into(), - Attribute::Es256PrivateKeyDer.into(), + Attribute::OAuth2RsOrigin, + Attribute::OAuth2RsTokenKey, + Attribute::Es256PrivateKeyDer, ], ..Default::default() }; @@ -1231,22 +1231,22 @@ pub static ref SCHEMA_CLASS_OAUTH2_RS_DL7: SchemaClass = SchemaClass { description: "The class representing a configured OAuth2 Client".to_string(), systemmay: vec![ - Attribute::Description.into(), - Attribute::OAuth2RsScopeMap.into(), - Attribute::OAuth2RsSupScopeMap.into(), - Attribute::Rs256PrivateKeyDer.into(), - Attribute::OAuth2JwtLegacyCryptoEnable.into(), - Attribute::OAuth2PreferShortUsername.into(), - Attribute::Image.into(), - Attribute::OAuth2RsClaimMap.into(), - Attribute::OAuth2Session.into(), - Attribute::OAuth2RsOrigin.into(), - Attribute::OAuth2StrictRedirectUri.into(), + Attribute::Description, + Attribute::OAuth2RsScopeMap, + Attribute::OAuth2RsSupScopeMap, + Attribute::Rs256PrivateKeyDer, + Attribute::OAuth2JwtLegacyCryptoEnable, + Attribute::OAuth2PreferShortUsername, + Attribute::Image, + Attribute::OAuth2RsClaimMap, + Attribute::OAuth2Session, + Attribute::OAuth2RsOrigin, + Attribute::OAuth2StrictRedirectUri, ], systemmust: vec![ - Attribute::OAuth2RsOriginLanding.into(), - Attribute::OAuth2RsTokenKey.into(), - Attribute::Es256PrivateKeyDer.into(), + Attribute::OAuth2RsOriginLanding, + Attribute::OAuth2RsTokenKey, + Attribute::Es256PrivateKeyDer, ], ..Default::default() }; @@ -1257,9 +1257,9 @@ pub static ref SCHEMA_CLASS_OAUTH2_RS_BASIC_DL5: SchemaClass = SchemaClass { description: "The class representing a configured OAuth2 client authenticated with HTTP basic authentication".to_string(), systemmay: vec![ - Attribute::OAuth2AllowInsecureClientDisablePkce.into(), + Attribute::OAuth2AllowInsecureClientDisablePkce, ], - systemmust: vec![ Attribute::OAuth2RsBasicSecret.into()], + systemmust: vec![ Attribute::OAuth2RsBasicSecret], systemexcludes: vec![ EntryClass::OAuth2ResourceServerPublic.into()], ..Default::default() }; @@ -1270,7 +1270,7 @@ pub static ref SCHEMA_CLASS_OAUTH2_RS_PUBLIC_DL4: SchemaClass = SchemaClass { name: EntryClass::OAuth2ResourceServerPublic.into(), description: "The class representing a configured Public OAuth2 Client with PKCE verification".to_string(), - systemmay: vec![Attribute::OAuth2AllowLocalhostRedirect.into()], + systemmay: vec![Attribute::OAuth2AllowLocalhostRedirect], systemexcludes: vec![EntryClass::OAuth2ResourceServerBasic.into()], ..Default::default() }; @@ -1283,10 +1283,10 @@ pub static ref SCHEMA_CLASS_KEY_PROVIDER_DL6: SchemaClass = SchemaClass { name: EntryClass::KeyProvider.into(), description: "A provider for cryptographic key storage and operations".to_string(), systemmay: vec![ - Attribute::Description.into(), + Attribute::Description, ], systemmust: vec![ - Attribute::Name.into(), + Attribute::Name, ], systemsupplements: vec![ EntryClass::KeyProviderInternal.into(), @@ -1309,7 +1309,7 @@ pub static ref SCHEMA_CLASS_KEY_OBJECT_DL6: SchemaClass = SchemaClass { name: EntryClass::KeyObject.into(), description: "A cryptographic key object that can be used by a provider".to_string(), systemmust: vec![ - Attribute::KeyProvider.into(), + Attribute::KeyProvider, ], ..Default::default() }; @@ -1339,7 +1339,7 @@ pub static ref SCHEMA_CLASS_KEY_OBJECT_INTERNAL_DL6: SchemaClass = SchemaClass { name: EntryClass::KeyObjectInternal.into(), description: "A cryptographic key object that can be used by the internal provider".to_string(), systemmay: vec![ - Attribute::KeyInternalData.into(), + Attribute::KeyInternalData, ], systemsupplements: vec![ EntryClass::KeyObject.into(), @@ -1355,8 +1355,8 @@ pub static ref SCHEMA_CLASS_CLIENT_CERTIFICATE_DL7: SchemaClass = SchemaClass { description: "A client authentication certificate".to_string(), systemmay: vec![], systemmust: vec![ - Attribute::Certificate.into(), - Attribute::Refers.into(), + Attribute::Certificate, + Attribute::Refers, ], ..Default::default() }; @@ -1366,8 +1366,8 @@ pub static ref SCHEMA_CLASS_APPLICATION_DL8: SchemaClass = SchemaClass { name: EntryClass::Application.into(), description: "The class representing an application".to_string(), - systemmust: vec![Attribute::Name.into(), Attribute::LinkedGroup.into()], - systemmay: vec![Attribute::Description.into()], + systemmust: vec![Attribute::Name, Attribute::LinkedGroup], + systemmay: vec![Attribute::Description], systemsupplements: vec![EntryClass::ServiceAccount.into()], ..Default::default() }; diff --git a/server/lib/src/entry.rs b/server/lib/src/entry.rs index b32a3ac4f..35d039b0f 100644 --- a/server/lib/src/entry.rs +++ b/server/lib/src/entry.rs @@ -39,7 +39,6 @@ use kanidm_proto::v1::Entry as ProtoEntry; use ldap3_proto::simple::{LdapPartialAttribute, LdapSearchResultEntry}; use openssl::ec::EcKey; use openssl::pkey::{Private, Public}; -use smartstring::alias::String as AttrString; use time::OffsetDateTime; use tracing::trace; use uuid::Uuid; @@ -165,31 +164,28 @@ pub struct EntryReduced { } // One day this is going to be Map - @yaleman -// pub type Eattrs = Map; -pub type Eattrs = Map; +// Today is that day - @firstyear +pub type Eattrs = Map; pub(crate) fn compare_attrs(left: &Eattrs, right: &Eattrs) -> bool { // We can't shortcut based on len because cid mod may not be present. // Build the set of all keys between both. - let allkeys: Set<&str> = left + let allkeys: Set<&Attribute> = left .keys() - .filter(|k| k != &Attribute::LastModifiedCid.as_ref()) - .chain( - right - .keys() - .filter(|k| k != &Attribute::LastModifiedCid.as_ref()), - ) - .map(|s| s.as_ref()) + .chain(right.keys()) + .filter(|k| *k != &Attribute::LastModifiedCid) .collect(); allkeys.into_iter().all(|k| { // Both must be Some, and both must have the same interiors. - let r = match (left.get(k), right.get(k)) { + let left_vs = left.get(k); + let right_vs = right.get(k); + let r = match (left_vs, right_vs) { (Some(l), Some(r)) => l.eq(r), _ => false, }; if !r { - trace!(?k, "compare_attrs_allkeys"); + trace!(?k, ?left_vs, ?right_vs, "compare_attrs_allkeys"); } r }) @@ -267,7 +263,7 @@ where /// Get the uuid of this entry. pub(crate) fn get_uuid(&self) -> Option { self.attrs - .get(Attribute::Uuid.as_ref()) + .get(&Attribute::Uuid) .and_then(|vs| vs.to_uuid_single()) } } @@ -308,12 +304,13 @@ impl Entry { .filter(|(_, v)| !v.is_empty()) .map(|(k, v)| { trace!(?k, ?v, "attribute"); - let nk = qs.get_schema().normalise_attr_name(k); - let nv = - valueset::from_result_value_iter(v.iter().map(|vr| qs.clone_value(&nk, vr))); + let attr_nk = Attribute::from(k.as_str()); + let nv = valueset::from_result_value_iter( + v.iter().map(|vr| qs.clone_value(&attr_nk, vr)), + ); trace!(?nv, "new valueset transform"); match nv { - Ok(nvi) => Ok((nk, nvi)), + Ok(nvi) => Ok((attr_nk, nvi)), Err(e) => Err(e), } }) @@ -366,155 +363,154 @@ impl Entry { if vs.is_empty() { None } else { - // TODO: this should be an "Attribute::from(k)" - let attr = AttrString::from(k.to_lowercase()); - let vv: ValueSet = match attr.as_str() { - kanidm_proto::constants::ATTR_ATTRIBUTENAME | kanidm_proto::constants::ATTR_CLASSNAME | kanidm_proto::constants::ATTR_DOMAIN => { - valueset::from_value_iter( - vs.into_iter().map(|v| Value::new_iutf8(&v)) - ) - } - kanidm_proto::constants::ATTR_NAME | kanidm_proto::constants::ATTR_DOMAIN_NAME => { - valueset::from_value_iter( - vs.into_iter().map(|v| Value::new_iname(&v)) - ) - } - kanidm_proto::constants::ATTR_USERID | kanidm_proto::constants::ATTR_UIDNUMBER => { - warn!("WARNING: Use of unstabilised attributes userid/uidnumber"); - valueset::from_value_iter( - vs.into_iter().map(|v| Value::new_iutf8(&v)) - ) - } - kanidm_proto::constants::ATTR_CLASS | kanidm_proto::constants::ATTR_ACP_CREATE_CLASS | kanidm_proto::constants::ATTR_ACP_MODIFY_CLASS => { - valueset::from_value_iter( - vs.into_iter().map(|v| Value::new_class(v.as_str())) - ) - } - kanidm_proto::constants::ATTR_ACP_CREATE_ATTR | - kanidm_proto::constants::ATTR_ACP_SEARCH_ATTR | - kanidm_proto::constants::ATTR_ACP_MODIFY_REMOVEDATTR | - kanidm_proto::constants::ATTR_ACP_MODIFY_PRESENTATTR | - kanidm_proto::constants::ATTR_SYSTEMMAY | - kanidm_proto::constants::ATTR_SYSTEMMUST | - kanidm_proto::constants::ATTR_MAY | - kanidm_proto::constants::ATTR_MUST - => { - valueset::from_value_iter( - vs.into_iter().map(|v| Value::new_attr(v.as_str())) - ) - } - kanidm_proto::constants::ATTR_UUID | - kanidm_proto::constants::ATTR_DOMAIN_UUID => { - valueset::from_value_iter( - vs.into_iter().map(|v| Value::new_uuid_s(v.as_str()) + let attr = Attribute::from(k.to_lowercase().as_str()); + let vv: ValueSet = match attr.as_str() { + kanidm_proto::constants::ATTR_ATTRIBUTENAME | kanidm_proto::constants::ATTR_CLASSNAME | kanidm_proto::constants::ATTR_DOMAIN => { + valueset::from_value_iter( + vs.into_iter().map(|v| Value::new_iutf8(&v)) + ) + } + kanidm_proto::constants::ATTR_NAME | kanidm_proto::constants::ATTR_DOMAIN_NAME => { + valueset::from_value_iter( + vs.into_iter().map(|v| Value::new_iname(&v)) + ) + } + kanidm_proto::constants::ATTR_USERID | kanidm_proto::constants::ATTR_UIDNUMBER => { + warn!("WARNING: Use of unstabilised attributes userid/uidnumber"); + valueset::from_value_iter( + vs.into_iter().map(|v| Value::new_iutf8(&v)) + ) + } + kanidm_proto::constants::ATTR_CLASS | kanidm_proto::constants::ATTR_ACP_CREATE_CLASS | kanidm_proto::constants::ATTR_ACP_MODIFY_CLASS => { + valueset::from_value_iter( + vs.into_iter().map(|v| Value::new_class(v.as_str())) + ) + } + kanidm_proto::constants::ATTR_ACP_CREATE_ATTR | + kanidm_proto::constants::ATTR_ACP_SEARCH_ATTR | + kanidm_proto::constants::ATTR_ACP_MODIFY_REMOVEDATTR | + kanidm_proto::constants::ATTR_ACP_MODIFY_PRESENTATTR | + kanidm_proto::constants::ATTR_SYSTEMMAY | + kanidm_proto::constants::ATTR_SYSTEMMUST | + kanidm_proto::constants::ATTR_MAY | + kanidm_proto::constants::ATTR_MUST + => { + valueset::from_value_iter( + vs.into_iter().map(|v| Value::new_attr(v.as_str())) + ) + } + kanidm_proto::constants::ATTR_UUID | + kanidm_proto::constants::ATTR_DOMAIN_UUID => { + valueset::from_value_iter( + vs.into_iter().map(|v| Value::new_uuid_s(v.as_str()) + .unwrap_or_else(|| { + warn!("WARNING: Allowing syntax incorrect attribute to be presented UTF8 string"); + Value::new_utf8(v) + }) + ) + ) + } + kanidm_proto::constants::ATTR_MEMBER | + kanidm_proto::constants::ATTR_MEMBEROF | + kanidm_proto::constants::ATTR_DIRECTMEMBEROF | + kanidm_proto::constants::ATTR_ACP_RECEIVER_GROUP => { + valueset::from_value_iter( + vs.into_iter().map(|v| Value::new_refer_s(v.as_str()).expect("Failed to convert value") ) + ) + } + kanidm_proto::constants::ATTR_ACP_ENABLE | + kanidm_proto::constants::ATTR_MULTIVALUE | + kanidm_proto::constants::ATTR_UNIQUE => { + valueset::from_value_iter( + vs.into_iter().map(|v| Value::new_bools(v.as_str()) + .unwrap_or_else(|| { + warn!("WARNING: Allowing syntax incorrect attribute to be presented UTF8 string"); + Value::new_utf8(v) + }) + ) + ) + } + kanidm_proto::constants::ATTR_SYNTAX => { + valueset::from_value_iter( + vs.into_iter().map(|v| Value::new_syntaxs(v.as_str()) .unwrap_or_else(|| { warn!("WARNING: Allowing syntax incorrect attribute to be presented UTF8 string"); Value::new_utf8(v) }) ) - ) - } - kanidm_proto::constants::ATTR_MEMBER | - kanidm_proto::constants::ATTR_MEMBEROF | - kanidm_proto::constants::ATTR_DIRECTMEMBEROF | - kanidm_proto::constants::ATTR_ACP_RECEIVER_GROUP => { - valueset::from_value_iter( - vs.into_iter().map(|v| Value::new_refer_s(v.as_str()).expect("Failed to convert value") ) - ) - } - kanidm_proto::constants::ATTR_ACP_ENABLE | - kanidm_proto::constants::ATTR_MULTIVALUE | - kanidm_proto::constants::ATTR_UNIQUE => { - valueset::from_value_iter( - vs.into_iter().map(|v| Value::new_bools(v.as_str()) - .unwrap_or_else(|| { - warn!("WARNING: Allowing syntax incorrect attribute to be presented UTF8 string"); - Value::new_utf8(v) + ) + } + kanidm_proto::constants::ATTR_INDEX => { + valueset::from_value_iter( + vs.into_iter().map(|v| Value::new_indexes(v.as_str()) + .unwrap_or_else(|| { + warn!("WARNING: Allowing syntax incorrect attribute to be presented UTF8 string"); + Value::new_utf8(v) + }) + ) + ) + } + kanidm_proto::constants::ATTR_ACP_TARGET_SCOPE | + kanidm_proto::constants::ATTR_ACP_RECEIVER + => { + valueset::from_value_iter( + vs.into_iter().map(|v| Value::new_json_filter_s(v.as_str()) + .unwrap_or_else(|| { + warn!("WARNING: Allowing syntax incorrect attribute to be presented UTF8 string"); + Value::new_utf8(v) + }) + ) + ) + } + kanidm_proto::constants::ATTR_DISPLAYNAME | kanidm_proto::constants::ATTR_DESCRIPTION | kanidm_proto::constants::ATTR_DOMAIN_DISPLAY_NAME => { + valueset::from_value_iter( + vs.into_iter().map(Value::new_utf8) + ) + } + kanidm_proto::constants::ATTR_SPN => { + valueset::from_value_iter( + vs.into_iter().map(|v| { + Value::new_spn_parse(v.as_str()) + .unwrap_or_else(|| { + warn!("WARNING: Allowing syntax incorrect SPN attribute to be presented UTF8 string"); + Value::new_utf8(v) + }) }) ) - ) - } - kanidm_proto::constants::ATTR_SYNTAX => { - valueset::from_value_iter( - vs.into_iter().map(|v| Value::new_syntaxs(v.as_str()) - .unwrap_or_else(|| { - warn!("WARNING: Allowing syntax incorrect attribute to be presented UTF8 string"); - Value::new_utf8(v) + } + kanidm_proto::constants::ATTR_GIDNUMBER | + kanidm_proto::constants::ATTR_VERSION => { + valueset::from_value_iter( + vs.into_iter().map(|v| { + Value::new_uint32_str(v.as_str()) + .unwrap_or_else(|| { + warn!("WARNING: Allowing syntax incorrect UINT32 attribute to be presented UTF8 string"); + Value::new_utf8(v) + }) }) - ) - ) + ) + } + kanidm_proto::constants::ATTR_DOMAIN_TOKEN_KEY | + kanidm_proto::constants::ATTR_FERNET_PRIVATE_KEY_STR => { + valueset::from_value_iter( + vs.into_iter().map(|v| Value::new_secret_str(&v)) + ) + } + kanidm_proto::constants::ATTR_ES256_PRIVATE_KEY_DER | + kanidm_proto::constants::ATTR_PRIVATE_COOKIE_KEY => { + valueset::from_value_iter( + vs.into_iter().map(|v| Value::new_privatebinary_base64(&v)) + ) + } + ia => { + error!("WARNING: Allowing invalid attribute {} to be interpreted as UTF8 string. YOU MAY ENCOUNTER ODD BEHAVIOUR!!!", ia); + valueset::from_value_iter( + vs.into_iter().map(Value::new_utf8) + ) + } } - kanidm_proto::constants::ATTR_INDEX => { - valueset::from_value_iter( - vs.into_iter().map(|v| Value::new_indexes(v.as_str()) - .unwrap_or_else(|| { - warn!("WARNING: Allowing syntax incorrect attribute to be presented UTF8 string"); - Value::new_utf8(v) - }) - ) - ) - } - kanidm_proto::constants::ATTR_ACP_TARGET_SCOPE | - kanidm_proto::constants::ATTR_ACP_RECEIVER - => { - valueset::from_value_iter( - vs.into_iter().map(|v| Value::new_json_filter_s(v.as_str()) - .unwrap_or_else(|| { - warn!("WARNING: Allowing syntax incorrect attribute to be presented UTF8 string"); - Value::new_utf8(v) - }) - ) - ) - } - kanidm_proto::constants::ATTR_DISPLAYNAME | kanidm_proto::constants::ATTR_DESCRIPTION | kanidm_proto::constants::ATTR_DOMAIN_DISPLAY_NAME => { - valueset::from_value_iter( - vs.into_iter().map(Value::new_utf8) - ) - } - kanidm_proto::constants::ATTR_SPN => { - valueset::from_value_iter( - vs.into_iter().map(|v| { - Value::new_spn_parse(v.as_str()) - .unwrap_or_else(|| { - warn!("WARNING: Allowing syntax incorrect SPN attribute to be presented UTF8 string"); - Value::new_utf8(v) - }) - }) - ) - } - kanidm_proto::constants::ATTR_GIDNUMBER | - kanidm_proto::constants::ATTR_VERSION => { - valueset::from_value_iter( - vs.into_iter().map(|v| { - Value::new_uint32_str(v.as_str()) - .unwrap_or_else(|| { - warn!("WARNING: Allowing syntax incorrect UINT32 attribute to be presented UTF8 string"); - Value::new_utf8(v) - }) - }) - ) - } - kanidm_proto::constants::ATTR_DOMAIN_TOKEN_KEY | - kanidm_proto::constants::ATTR_FERNET_PRIVATE_KEY_STR => { - valueset::from_value_iter( - vs.into_iter().map(|v| Value::new_secret_str(&v)) - ) - } - kanidm_proto::constants::ATTR_ES256_PRIVATE_KEY_DER | - kanidm_proto::constants::ATTR_PRIVATE_COOKIE_KEY => { - valueset::from_value_iter( - vs.into_iter().map(|v| Value::new_privatebinary_base64(&v)) - ) - } - ia => { - error!("WARNING: Allowing invalid attribute {} to be interpreted as UTF8 string. YOU MAY ENCOUNTER ODD BEHAVIOUR!!!", ia); - valueset::from_value_iter( - vs.into_iter().map(Value::new_utf8) - ) - } - } - .expect("Failed to convert value from string"); - Some((attr, vv)) + .expect("Failed to convert value from string"); + Some((attr, vv)) } }) .collect(); @@ -636,8 +632,8 @@ impl Entry { self.add_ava_int(attr, value); } - pub fn remove_ava(&mut self, attr: Attribute) { - self.attrs.remove(attr.as_ref()); + pub fn remove_ava(&mut self, attr: &Attribute) { + self.attrs.remove(attr); } /// Replace the existing content of an attribute set of this Entry, with a new set of Values. @@ -648,7 +644,7 @@ impl Entry { self.set_ava_iter_int(attr, iter); } - pub fn get_ava_mut(&mut self, attr: Attribute) -> Option<&mut ValueSet> { + pub fn get_ava_mut>(&mut self, attr: A) -> Option<&mut ValueSet> { self.attrs.get_mut(attr.as_ref()) } } @@ -673,12 +669,11 @@ impl Entry { ) -> Result, SchemaError> { let uuid: Uuid = self .attrs - .get(Attribute::Uuid.as_ref()) - .ok_or_else(|| SchemaError::MissingMustAttribute(vec![Attribute::Uuid.to_string()])) + .get(&Attribute::Uuid) + .ok_or_else(|| SchemaError::MissingMustAttribute(vec![Attribute::Uuid])) .and_then(|vs| { - vs.to_uuid_single().ok_or_else(|| { - SchemaError::MissingMustAttribute(vec![Attribute::Uuid.to_string()]) - }) + vs.to_uuid_single() + .ok_or_else(|| SchemaError::MissingMustAttribute(vec![Attribute::Uuid])) })?; // Build the new valid entry ... @@ -1011,9 +1006,9 @@ impl Entry { let class_ava = vs_iutf8![EntryClass::Object.into(), EntryClass::Tombstone.into()]; let last_mod_ava = vs_cid![left_at.clone()]; - attrs_new.insert(Attribute::Uuid.into(), vs_uuid![self.valid.uuid]); - attrs_new.insert(Attribute::Class.into(), class_ava); - attrs_new.insert(Attribute::LastModifiedCid.into(), last_mod_ava); + attrs_new.insert(Attribute::Uuid, vs_uuid![self.valid.uuid]); + attrs_new.insert(Attribute::Class, class_ava); + attrs_new.insert(Attribute::LastModifiedCid, last_mod_ava); Entry { valid: EntryIncremental { @@ -1060,9 +1055,9 @@ impl Entry { let class_ava = vs_iutf8![EntryClass::Object.into(), EntryClass::Tombstone.into()]; let last_mod_ava = vs_cid![at.clone()]; - attrs_new.insert(Attribute::Uuid.into(), vs_uuid![db_ent.valid.uuid]); - attrs_new.insert(Attribute::Class.into(), class_ava); - attrs_new.insert(Attribute::LastModifiedCid.into(), last_mod_ava); + attrs_new.insert(Attribute::Uuid, vs_uuid![db_ent.valid.uuid]); + attrs_new.insert(Attribute::Class, class_ava); + attrs_new.insert(Attribute::LastModifiedCid, last_mod_ava); Entry { valid: EntryIncremental { @@ -1107,7 +1102,7 @@ impl Entry { impl Entry { pub(crate) fn get_uuid(&self) -> Option { self.attrs - .get(Attribute::Uuid.as_ref()) + .get(&Attribute::Uuid) .and_then(|vs| vs.to_uuid_single()) } @@ -1119,12 +1114,11 @@ impl Entry { ) -> Result, SchemaError> { let uuid: Uuid = self .attrs - .get(Attribute::Uuid.as_ref()) - .ok_or_else(|| SchemaError::MissingMustAttribute(vec![Attribute::Uuid.to_string()])) + .get(&Attribute::Uuid) + .ok_or_else(|| SchemaError::MissingMustAttribute(vec![Attribute::Uuid])) .and_then(|vs| { - vs.to_uuid_single().ok_or_else(|| { - SchemaError::MissingMustAttribute(vec![Attribute::Uuid.to_string()]) - }) + vs.to_uuid_single() + .ok_or_else(|| SchemaError::MissingMustAttribute(vec![Attribute::Uuid])) })?; // Build the new valid entry ... @@ -1143,7 +1137,10 @@ impl Entry { /// Access a reference set in a directly mutable form. This is "safe" because /// referential integrity will check the values added are valid, and because /// this is strongly typed it can't violate syntax. - pub(crate) fn get_ava_refer_mut(&mut self, attr: Attribute) -> Option<&mut BTreeSet> { + pub(crate) fn get_ava_refer_mut>( + &mut self, + attr: A, + ) -> Option<&mut BTreeSet> { self.attrs .get_mut(attr.as_ref()) .and_then(|vs| vs.as_refer_set_mut()) @@ -1327,7 +1324,7 @@ impl Entry { } type IdxDiff<'a> = - Vec>; + Vec>; impl Entry { /// If this entry has ever been committed to disk, retrieve its database id number. @@ -1414,9 +1411,9 @@ impl Entry { let cands = [Attribute::Spn, Attribute::Name, Attribute::GidNumber]; cands .iter() - .filter_map(|c| { + .filter_map(|cand| { self.attrs - .get((*c).as_ref()) + .get(cand) .map(|vs| vs.to_proto_string_clone_iter()) }) .flatten() @@ -1428,7 +1425,7 @@ impl Entry { /// entry for sync purposes. These strings are then indexed. fn get_externalid2uuid(&self) -> Option { self.attrs - .get(Attribute::SyncExternalId.as_ref()) + .get(&Attribute::SyncExternalId) .and_then(|vs| vs.to_proto_string_single()) } @@ -1437,11 +1434,11 @@ impl Entry { /// extract its name, and if that's not present, extract its uuid. pub(crate) fn get_uuid2spn(&self) -> Value { self.attrs - .get("spn") + .get(&Attribute::Spn) .and_then(|vs| vs.to_value_single()) .or_else(|| { self.attrs - .get(Attribute::Name.as_ref()) + .get(&Attribute::Name) .and_then(|vs| vs.to_value_single()) }) .unwrap_or_else(|| Value::Uuid(self.get_uuid())) @@ -1453,11 +1450,11 @@ impl Entry { /// See also - `get_display_id` pub(crate) fn get_uuid2rdn(&self) -> String { self.attrs - .get("spn") + .get(&Attribute::Spn) .and_then(|vs| vs.to_proto_string_single().map(|v| format!("spn={v}"))) .or_else(|| { self.attrs - .get(Attribute::Name.as_ref()) + .get(&Attribute::Name) .and_then(|vs| vs.to_proto_string_single().map(|v| format!("name={v}"))) }) .unwrap_or_else(|| format!("uuid={}", self.get_uuid().as_hyphenated())) @@ -1622,18 +1619,7 @@ impl Entry { idxmeta .keys() .flat_map(|ikey| { - let attr: Attribute = match Attribute::try_from(ikey.attr.as_str()) { - Ok(val) => val, - Err(err) => { - admin_error!( - "Failed to convert '{}' to attribute: {:?}", - ikey.attr, - err - ); - return Vec::with_capacity(0); - } - }; - match pre_e.get_ava_set(attr) { + match pre_e.get_ava_set(&ikey.attr) { None => Vec::with_capacity(0), Some(vs) => { let changes: Vec> = match ikey.itype { @@ -1664,18 +1650,7 @@ impl Entry { idxmeta .keys() .flat_map(|ikey| { - let attr: Attribute = match Attribute::try_from(ikey.attr.as_str()) { - Ok(val) => val, - Err(err) => { - admin_error!( - "Failed to convert '{}' to attribute: {:?}", - ikey.attr, - err - ); - return Vec::with_capacity(0); - } - }; - match post_e.get_ava_set(attr) { + match post_e.get_ava_set(&ikey.attr) { None => Vec::with_capacity(0), Some(vs) => { let changes: Vec> = match ikey.itype { @@ -1706,18 +1681,10 @@ impl Entry { idxmeta .keys() .flat_map(|ikey| { - let attr: Attribute = match Attribute::try_from(ikey.attr.as_str()) { - Ok(val) => val, - Err(err) => { - admin_error!( - "Failed to convert '{}' to attribute: {:?}", - ikey.attr, - err - ); - return Vec::with_capacity(0); - } - }; - match (pre_e.get_ava_set(attr), post_e.get_ava_set(attr)) { + match ( + pre_e.get_ava_set(&ikey.attr), + post_e.get_ava_set(&ikey.attr), + ) { (None, None) => { // Neither have it, do nothing. Vec::with_capacity(0) @@ -1900,7 +1867,7 @@ impl Entry { * This should only be done *once* on entry load. */ let cid = r_attrs - .get(Attribute::LastModifiedCid.as_ref()) + .get(&Attribute::LastModifiedCid) .and_then(|vs| vs.as_cid_set()) .and_then(|set| set.iter().next().cloned()) .or_else(|| { @@ -1935,7 +1902,7 @@ impl Entry { }; let uuid = attrs - .get(Attribute::Uuid.as_ref()) + .get(&Attribute::Uuid) .and_then(|vs| vs.to_uuid_single())?; Some(Entry { @@ -1967,14 +1934,14 @@ impl Entry { /// all other values that are NOT allowed in this query. pub fn reduce_attributes( &self, - allowed_attrs: &BTreeSet<&str>, + allowed_attrs: &BTreeSet, ) -> Entry { // Remove all attrs from our tree that are NOT in the allowed set. let f_attrs: Map<_, _> = self .attrs .iter() .filter_map(|(k, v)| { - if allowed_attrs.contains(k.as_str()) { + if allowed_attrs.contains(k) { Some((k.clone(), v.clone())) } else { None @@ -2003,9 +1970,9 @@ impl Entry { let class_ava = vs_iutf8![EntryClass::Object.into(), EntryClass::Tombstone.into()]; let last_mod_ava = vs_cid![cid.clone()]; - attrs_new.insert(Attribute::Uuid.into(), vs_uuid![self.get_uuid()]); - attrs_new.insert(Attribute::Class.into(), class_ava); - attrs_new.insert(Attribute::LastModifiedCid.into(), last_mod_ava); + attrs_new.insert(Attribute::Uuid, vs_uuid![self.get_uuid()]); + attrs_new.insert(Attribute::Class, class_ava); + attrs_new.insert(Attribute::LastModifiedCid, last_mod_ava); // ⚠️ No return from this point! ecstate.tombstone(&cid); @@ -2174,21 +2141,9 @@ impl Entry { // for each attr in must, check it's present on our ent let mut missing_must = Vec::with_capacity(0); for attr in must.iter() { - let attribute: Attribute = match Attribute::try_from(attr.name.as_str()) { - Ok(val) => val, - Err(err) => { - admin_error!( - "Failed to convert missing_must '{}' to attribute: {:?}", - attr.name, - err - ); - return Err(SchemaError::InvalidAttribute(attr.name.to_string())); - } - }; - - let avas = self.get_ava_set(attribute); + let avas = self.get_ava_set(&attr.name); if avas.is_none() { - missing_must.push(attr.name.to_string()); + missing_must.push(attr.name.clone()); } } @@ -2220,7 +2175,7 @@ impl Entry { ); Err(SchemaError::PhantomAttribute(attr_name.to_string())) } else { - a_schema.validate_ava(attr_name.as_str(), avas) + a_schema.validate_ava(attr_name, avas) // .map_err(|e| lrequest_error!("Failed to validate: {}", attr_name);) } } @@ -2243,10 +2198,11 @@ impl Entry { // The set of "may" is a combination of may and must, since we have already // asserted that all must requirements are fulfilled. This allows us to // perform extended attribute checking in a single pass. - let may: Result, _> = classes + let may: Result, _> = classes .iter() // Join our class systemmmust + must + systemmay + may into one. .flat_map(|cls| { + trace!(?cls); cls.systemmust .iter() .chain(cls.must.iter()) @@ -2275,14 +2231,14 @@ impl Entry { Some(a_schema) => { // Now, for each type we do a *full* check of the syntax // and validity of the ava. - a_schema.validate_ava(attr_name.as_str(), avas) + a_schema.validate_ava(attr_name, avas) // .map_err(|e| lrequest_error!("Failed to validate: {}", attr_name); } None => { admin_error!( "{} {} - not found in the list of valid attributes for this set of classes {:?} - valid attributes are {:?}", - attr_name.to_string(), + attr_name.as_str(), self.get_display_id(), entry_classes.iter().collect::>(), may.keys().collect::>() @@ -2360,16 +2316,22 @@ where /// Determine if any attribute of this entry changed excluding the attribute named. /// This allows for detection of entry changes unless the change was to a specific /// attribute. - pub(crate) fn entry_changed_excluding_attribute(&self, attr: Attribute, cid: &Cid) -> bool { + pub(crate) fn entry_changed_excluding_attribute>( + &self, + attr: A, + cid: &Cid, + ) -> bool { + let attr_ref = attr.as_ref(); + use crate::repl::entry::State; match self.get_changestate().current() { State::Live { at: _, changes } => { changes.iter().any(|(change_attr, change_id)| { change_id >= cid && - change_attr != attr.as_ref() && + *change_attr != *attr_ref && // This always changes, and could throw off other detections. - change_attr != Attribute::LastModifiedCid.as_ref() + *change_attr != Attribute::LastModifiedCid }) } State::Tombstone { at } => at == cid, @@ -2411,17 +2373,11 @@ impl Entry { } pub fn to_scim_kanidm(&self) -> Result { - let attrs = Default::default(); - /* let attrs = self .attrs .iter() - .filter_map(|(k, vs)| { - vs.to_scim_value() - .map(|scim_value| (k, scim_value)) - }) + .filter_map(|(k, vs)| vs.to_scim_value().map(|scim_value| (k.clone(), scim_value))) .collect(); - */ let id = self.get_uuid(); @@ -2544,7 +2500,7 @@ impl Entry { /// you can think of this boolean as "if a write occurred to the structure", true indicating that /// a change occurred. fn add_ava_int(&mut self, attr: Attribute, value: Value) -> bool { - if let Some(vs) = self.attrs.get_mut(attr.as_ref()) { + if let Some(vs) = self.attrs.get_mut(&attr) { let r = vs.insert_checked(value); debug_assert!(r.is_ok()); // Default to the value not being present if wrong typed. @@ -2553,7 +2509,7 @@ impl Entry { #[allow(clippy::expect_used)] let vs = valueset::from_value_iter(std::iter::once(value)) .expect("Unable to fail - non-zero iter, and single value type!"); - self.attrs.insert(attr.into(), vs); + self.attrs.insert(attr, vs); // The attribute did not exist before. true } @@ -2570,12 +2526,12 @@ impl Entry { return; }; - if let Some(existing_vs) = self.attrs.get_mut(attr.as_ref()) { + if let Some(existing_vs) = self.attrs.get_mut(&attr) { // This is the suboptimal path. This can only exist in rare cases. let _ = existing_vs.merge(&vs); } else { // Normally this is what's taken. - self.attrs.insert(AttrString::from(attr), vs); + self.attrs.insert(attr, vs); } } @@ -2583,178 +2539,153 @@ impl Entry { #[cfg(test)] fn set_last_changed(&mut self, cid: Cid) { let cv = vs_cid![cid]; - let _ = self.attrs.insert(Attribute::LastModifiedCid.into(), cv); + let _ = self.attrs.insert(Attribute::LastModifiedCid, cv); } pub(crate) fn get_display_id(&self) -> String { self.attrs - .get(Attribute::Spn.as_ref()) + .get(&Attribute::Spn) .and_then(|vs| vs.to_value_single()) .or_else(|| { self.attrs - .get(Attribute::Name.as_ref()) + .get(&Attribute::Name) .and_then(|vs| vs.to_value_single()) }) .or_else(|| { self.attrs - .get(Attribute::Uuid.as_ref()) + .get(&Attribute::Uuid) .and_then(|vs| vs.to_value_single()) }) .map(|value| value.to_proto_string_clone()) .unwrap_or_else(|| "no entry id available".to_string()) } - #[inline(always)] /// Get an iterator over the current set of attribute names that this entry contains. pub fn get_ava_names(&self) -> impl Iterator { // Get the set of all attribute names in the entry self.attrs.keys().map(|a| a.as_str()) } - #[inline(always)] /// Get an iterator over the current set of values for an attribute name. pub fn get_ava(&self) -> &Eattrs { &self.attrs } - #[inline(always)] - pub fn get_ava_iter(&self) -> impl Iterator { + pub fn get_ava_iter(&self) -> impl Iterator { self.attrs.iter() } - #[inline(always)] /// Return a reference to the current set of values that are associated to this attribute. - pub fn get_ava_set(&self, attr: Attribute) -> Option<&ValueSet> { + pub fn get_ava_set>(&self, attr: A) -> Option<&ValueSet> { self.attrs.get(attr.as_ref()) } - pub fn get_ava_refer(&self, attr: Attribute) -> Option<&BTreeSet> { - self.attrs - .get(attr.as_ref()) - .and_then(|vs| vs.as_refer_set()) + pub fn get_ava_refer>(&self, attr: A) -> Option<&BTreeSet> { + self.get_ava_set(attr).and_then(|vs| vs.as_refer_set()) } - #[inline(always)] - pub fn get_ava_as_iutf8_iter(&self, attr: Attribute) -> Option> { - self.attrs - .get(attr.as_ref()) - .and_then(|vs| vs.as_iutf8_iter()) - } - - #[inline(always)] - pub fn get_ava_as_iutf8(&self, attr: Attribute) -> Option<&BTreeSet> { - self.attrs - .get(attr.as_ref()) - .and_then(|vs| vs.as_iutf8_set()) - } - - #[inline(always)] - pub fn get_ava_as_image(&self, attr: Attribute) -> Option<&HashSet> { - self.attrs - .get(attr.as_ref()) - .and_then(|vs| vs.as_imageset()) - } - - #[inline(always)] - pub fn get_ava_single_image(&self, attr: Attribute) -> Option { - let images = self - .attrs - .get(attr.as_ref()) - .and_then(|vs| vs.as_imageset())?; - images.iter().next().cloned() - } - - #[inline(always)] - pub fn get_ava_single_credential_type(&self, attr: Attribute) -> Option { - self.attrs - .get(attr.as_ref()) - .and_then(|vs| vs.to_credentialtype_single()) - } - - #[inline(always)] - pub fn get_ava_as_oauthscopes(&self, attr: Attribute) -> Option> { - self.attrs - .get(attr.as_ref()) - .and_then(|vs| vs.as_oauthscope_iter()) - } - - #[inline(always)] - pub fn get_ava_as_oauthscopemaps( + pub fn get_ava_as_iutf8_iter>( &self, - attr: Attribute, - ) -> Option<&std::collections::BTreeMap>> { - self.attrs - .get(attr.as_ref()) - .and_then(|vs| vs.as_oauthscopemap()) - } - - #[inline(always)] - pub fn get_ava_as_intenttokens( - &self, - attr: Attribute, - ) -> Option<&std::collections::BTreeMap> { - self.attrs - .get(attr.as_ref()) - .and_then(|vs| vs.as_intenttoken_map()) - } - - #[inline(always)] - pub fn get_ava_as_session_map( - &self, - attr: Attribute, - ) -> Option<&std::collections::BTreeMap> { - self.attrs - .get(attr.as_ref()) - .and_then(|vs| vs.as_session_map()) - } - - #[inline(always)] - pub fn get_ava_as_apitoken_map( - &self, - attr: Attribute, - ) -> Option<&std::collections::BTreeMap> { - self.attrs - .get(attr.as_ref()) - .and_then(|vs| vs.as_apitoken_map()) - } - - #[inline(always)] - pub fn get_ava_as_oauth2session_map( - &self, - attr: Attribute, - ) -> Option<&std::collections::BTreeMap> { - self.attrs - .get(attr.as_ref()) - .and_then(|vs| vs.as_oauth2session_map()) - } - - #[inline(always)] - /// If possible, return an iterator over the set of values transformed into a `&str`. - pub fn get_ava_iter_iname(&self, attr: Attribute) -> Option> { - self.get_ava_set(attr).and_then(|vs| vs.as_iname_iter()) - } - - #[inline(always)] - /// If possible, return an iterator over the set of values transformed into a `&str`. - pub fn get_ava_iter_iutf8(&self, attr: Attribute) -> Option> { + attr: A, + ) -> Option> { self.get_ava_set(attr).and_then(|vs| vs.as_iutf8_iter()) } - #[inline(always)] - /// If possible, return an iterator over the set of values transformed into a `Uuid`. - pub fn get_ava_as_refuuid( + pub fn get_ava_as_iutf8>(&self, attr: A) -> Option<&BTreeSet> { + self.get_ava_set(attr).and_then(|vs| vs.as_iutf8_set()) + } + + pub fn get_ava_as_image>(&self, attr: A) -> Option<&HashSet> { + self.get_ava_set(attr).and_then(|vs| vs.as_imageset()) + } + + pub fn get_ava_single_image>(&self, attr: A) -> Option { + let images = self.get_ava_set(attr).and_then(|vs| vs.as_imageset())?; + images.iter().next().cloned() + } + + pub fn get_ava_single_credential_type>( &self, - attr: Attribute, + attr: A, + ) -> Option { + self.get_ava_set(attr) + .and_then(|vs| vs.to_credentialtype_single()) + } + + pub fn get_ava_as_oauthscopes>( + &self, + attr: A, + ) -> Option> { + self.get_ava_set(attr) + .and_then(|vs| vs.as_oauthscope_iter()) + } + + pub fn get_ava_as_oauthscopemaps>( + &self, + attr: A, + ) -> Option<&std::collections::BTreeMap>> { + self.get_ava_set(attr).and_then(|vs| vs.as_oauthscopemap()) + } + + pub fn get_ava_as_intenttokens>( + &self, + attr: A, + ) -> Option<&std::collections::BTreeMap> { + self.get_ava_set(attr) + .and_then(|vs| vs.as_intenttoken_map()) + } + + pub fn get_ava_as_session_map>( + &self, + attr: A, + ) -> Option<&std::collections::BTreeMap> { + self.get_ava_set(attr).and_then(|vs| vs.as_session_map()) + } + + pub fn get_ava_as_apitoken_map>( + &self, + attr: A, + ) -> Option<&std::collections::BTreeMap> { + self.get_ava_set(attr).and_then(|vs| vs.as_apitoken_map()) + } + + pub fn get_ava_as_oauth2session_map>( + &self, + attr: A, + ) -> Option<&std::collections::BTreeMap> { + self.get_ava_set(attr) + .and_then(|vs| vs.as_oauth2session_map()) + } + + /// If possible, return an iterator over the set of values transformed into a `&str`. + pub fn get_ava_iter_iname>( + &self, + attr: A, + ) -> Option> { + self.get_ava_set(attr).and_then(|vs| vs.as_iname_iter()) + } + + /// If possible, return an iterator over the set of values transformed into a `&str`. + pub fn get_ava_iter_iutf8>( + &self, + attr: A, + ) -> Option> { + self.get_ava_set(attr).and_then(|vs| vs.as_iutf8_iter()) + } + + /// If possible, return an iterator over the set of values transformed into a `Uuid`. + pub fn get_ava_as_refuuid>( + &self, + attr: A, ) -> Option + '_>> { // If any value is NOT a reference, it's filtered out. self.get_ava_set(attr).and_then(|vs| vs.as_ref_uuid_iter()) } - #[inline(always)] /// If possible, return an iterator over the set of ssh key values transformed into a `&str`. - pub fn get_ava_iter_sshpubkeys( + pub fn get_ava_iter_sshpubkeys>( &self, - attr: Attribute, + attr: A, ) -> Option + '_> { self.get_ava_set(attr) .and_then(|vs| vs.as_sshpubkey_string_iter()) @@ -2769,8 +2700,7 @@ impl Entry { /// /// However, the conversion to IndexType is fallible, so in case of a failure /// to convert, an empty vec is returned - #[inline(always)] - pub(crate) fn get_ava_opt_index(&self, attr: Attribute) -> Option> { + pub(crate) fn get_ava_opt_index>(&self, attr: A) -> Option> { if let Some(vs) = self.get_ava_set(attr) { vs.as_indextype_iter().map(|i| i.collect()) } else { @@ -2781,218 +2711,175 @@ impl Entry { /// Return a single value of this attributes name, or `None` if it is NOT present, or /// there are multiple values present (ambiguous). - #[inline(always)] - pub fn get_ava_single(&self, attr: Attribute) -> Option { - self.attrs - .get(attr.as_ref()) - .and_then(|vs| vs.to_value_single()) + pub fn get_ava_single>(&self, attr: A) -> Option { + self.get_ava_set(attr).and_then(|vs| vs.to_value_single()) } - pub fn get_ava_single_proto_string(&self, attr: Attribute) -> Option { - self.attrs - .get(attr.as_ref()) + pub fn get_ava_single_proto_string>(&self, attr: A) -> Option { + self.get_ava_set(attr) .and_then(|vs| vs.to_proto_string_single()) } - #[inline(always)] /// Return a single bool, if valid to transform this value into a boolean. - pub fn get_ava_single_bool(&self, attr: Attribute) -> Option { - self.attrs - .get(attr.as_ref()) - .and_then(|vs| vs.to_bool_single()) + pub fn get_ava_single_bool>(&self, attr: A) -> Option { + self.get_ava_set(attr).and_then(|vs| vs.to_bool_single()) } - #[inline(always)] /// Return a single uint32, if valid to transform this value. - pub fn get_ava_single_uint32(&self, attr: Attribute) -> Option { - self.attrs - .get(attr.as_ref()) - .and_then(|vs| vs.to_uint32_single()) + pub fn get_ava_single_uint32>(&self, attr: A) -> Option { + self.get_ava_set(attr).and_then(|vs| vs.to_uint32_single()) } - #[inline(always)] /// Return a single syntax type, if valid to transform this value. - pub fn get_ava_single_syntax(&self, attr: Attribute) -> Option { - self.attrs - .get(attr.as_ref()) + pub fn get_ava_single_syntax>(&self, attr: A) -> Option { + self.get_ava_set(attr) .and_then(|vs| vs.to_syntaxtype_single()) } - #[inline(always)] /// Return a single credential, if valid to transform this value. - pub fn get_ava_single_credential(&self, attr: Attribute) -> Option<&Credential> { - self.attrs - .get(attr.as_ref()) + pub fn get_ava_single_credential>(&self, attr: A) -> Option<&Credential> { + self.get_ava_set(attr) .and_then(|vs| vs.to_credential_single()) } - #[inline(always)] /// Get the set of passkeys on this account, if any are present. - pub fn get_ava_passkeys( + pub fn get_ava_passkeys>( &self, - attr: Attribute, + attr: A, ) -> Option<&BTreeMap> { - self.attrs - .get(attr.as_ref()) - .and_then(|vs| vs.as_passkey_map()) + self.get_ava_set(attr).and_then(|vs| vs.as_passkey_map()) } - #[inline(always)] /// Get the set of devicekeys on this account, if any are present. - pub fn get_ava_attestedpasskeys( + pub fn get_ava_attestedpasskeys>( &self, - attr: Attribute, + attr: A, ) -> Option<&BTreeMap> { - self.attrs - .get(attr.as_ref()) + self.get_ava_set(attr) .and_then(|vs| vs.as_attestedpasskey_map()) } - #[inline(always)] /// Get the set of uihints on this account, if any are present. - pub fn get_ava_uihint(&self, attr: Attribute) -> Option<&BTreeSet> { - self.attrs - .get(attr.as_ref()) - .and_then(|vs| vs.as_uihint_set()) + pub fn get_ava_uihint>(&self, attr: A) -> Option<&BTreeSet> { + self.get_ava_set(attr).and_then(|vs| vs.as_uihint_set()) } - #[inline(always)] /// Return a single secret value, if valid to transform this value. - pub fn get_ava_single_secret(&self, attr: Attribute) -> Option<&str> { - self.attrs - .get(attr.as_ref()) - .and_then(|vs| vs.to_secret_single()) + pub fn get_ava_single_secret>(&self, attr: A) -> Option<&str> { + self.get_ava_set(attr).and_then(|vs| vs.to_secret_single()) } - #[inline(always)] /// Return a single datetime, if valid to transform this value. - pub fn get_ava_single_datetime(&self, attr: Attribute) -> Option { - self.attrs - .get(attr.as_ref()) + pub fn get_ava_single_datetime>(&self, attr: A) -> Option { + self.get_ava_set(attr) .and_then(|vs| vs.to_datetime_single()) } - #[inline(always)] /// Return a single `&str`, if valid to transform this value. - pub(crate) fn get_ava_single_utf8(&self, attr: Attribute) -> Option<&str> { - self.attrs - .get(attr.as_ref()) - .and_then(|vs| vs.to_utf8_single()) + pub(crate) fn get_ava_single_utf8>(&self, attr: A) -> Option<&str> { + self.get_ava_set(attr).and_then(|vs| vs.to_utf8_single()) } - #[inline(always)] /// Return a single `&str`, if valid to transform this value. - pub(crate) fn get_ava_single_iutf8(&self, attr: Attribute) -> Option<&str> { - self.attrs - .get(attr.as_ref()) - .and_then(|vs| vs.to_iutf8_single()) + pub(crate) fn get_ava_single_iutf8>(&self, attr: A) -> Option<&str> { + self.get_ava_set(attr).and_then(|vs| vs.to_iutf8_single()) } - #[inline(always)] /// Return a single `&str`, if valid to transform this value. - pub(crate) fn get_ava_single_iname(&self, attr: Attribute) -> Option<&str> { - self.attrs - .get(attr.as_ref()) - .and_then(|vs| vs.to_iname_single()) + pub(crate) fn get_ava_single_iname>(&self, attr: A) -> Option<&str> { + self.get_ava_set(attr).and_then(|vs| vs.to_iname_single()) } - #[inline(always)] /// Return a single `&Url`, if valid to transform this value. - pub fn get_ava_single_url(&self, attr: Attribute) -> Option<&Url> { - self.attrs - .get(attr.as_ref()) - .and_then(|vs| vs.to_url_single()) + pub fn get_ava_single_url>(&self, attr: A) -> Option<&Url> { + self.get_ava_set(attr).and_then(|vs| vs.to_url_single()) } - pub fn get_ava_single_uuid(&self, attr: Attribute) -> Option { - self.attrs - .get(attr.as_ref()) - .and_then(|vs| vs.to_uuid_single()) + pub fn get_ava_single_uuid>(&self, attr: A) -> Option { + self.get_ava_set(attr).and_then(|vs| vs.to_uuid_single()) } - pub fn get_ava_single_refer(&self, attr: Attribute) -> Option { - self.attrs - .get(attr.as_ref()) - .and_then(|vs| vs.to_refer_single()) + pub fn get_ava_single_refer>(&self, attr: A) -> Option { + self.get_ava_set(attr).and_then(|vs| vs.to_refer_single()) } - pub fn get_ava_mail_primary(&self, attr: Attribute) -> Option<&str> { - self.attrs - .get(attr.as_ref()) + pub fn get_ava_mail_primary>(&self, attr: A) -> Option<&str> { + self.get_ava_set(attr) .and_then(|vs| vs.to_email_address_primary_str()) } - pub fn get_ava_iter_mail(&self, attr: Attribute) -> Option> { + pub fn get_ava_iter_mail>( + &self, + attr: A, + ) -> Option> { self.get_ava_set(attr).and_then(|vs| vs.as_email_str_iter()) } - #[inline(always)] /// Return a single protocol filter, if valid to transform this value. - pub fn get_ava_single_protofilter(&self, attr: Attribute) -> Option<&ProtoFilter> { - self.attrs - .get(attr.as_ref()) + pub fn get_ava_single_protofilter>(&self, attr: A) -> Option<&ProtoFilter> { + self.get_ava_set(attr) .and_then(|vs| vs.to_json_filter_single()) } - pub fn get_ava_single_private_binary(&self, attr: Attribute) -> Option<&[u8]> { - self.attrs - .get(attr.as_ref()) + pub fn get_ava_single_private_binary>(&self, attr: A) -> Option<&[u8]> { + self.get_ava_set(attr) .and_then(|vs| vs.to_private_binary_single()) } - pub fn get_ava_single_jws_key_es256(&self, attr: Attribute) -> Option<&JwsEs256Signer> { - self.attrs - .get(attr.as_ref()) + pub fn get_ava_single_jws_key_es256>( + &self, + attr: A, + ) -> Option<&JwsEs256Signer> { + self.get_ava_set(attr) .and_then(|vs| vs.to_jws_key_es256_single()) } - pub fn get_ava_single_eckey_private(&self, attr: Attribute) -> Option<&EcKey> { - self.attrs - .get(attr.as_ref()) + pub fn get_ava_single_eckey_private>( + &self, + attr: A, + ) -> Option<&EcKey> { + self.get_ava_set(attr) .and_then(|vs| vs.to_eckey_private_single()) } - pub fn get_ava_single_eckey_public(&self, attr: Attribute) -> Option<&EcKey> { - self.attrs - .get(attr.as_ref()) + pub fn get_ava_single_eckey_public>( + &self, + attr: A, + ) -> Option<&EcKey> { + self.get_ava_set(attr) .and_then(|vs| vs.to_eckey_public_single()) } - pub fn get_ava_webauthn_attestation_ca_list( + pub fn get_ava_webauthn_attestation_ca_list>( &self, - attr: Attribute, + attr: A, ) -> Option<&AttestationCaList> { - self.attrs - .get(attr.as_ref()) + self.get_ava_set(attr) .and_then(|vs| vs.as_webauthn_attestation_ca_list()) } - pub fn get_ava_application_password( + pub fn get_ava_application_password>( &self, - attr: Attribute, + attr: A, ) -> Option<&BTreeMap>> { - self.attrs - .get(attr.as_ref()) + self.get_ava_set(attr) .and_then(|vs| vs.as_application_password_map()) } - #[inline(always)] /// Return a single security principle name, if valid to transform this value. pub(crate) fn generate_spn(&self, domain_name: &str) -> Option { self.get_ava_single_iname(Attribute::Name) .map(|name| Value::new_spn_str(name, domain_name)) } - #[inline(always)] /// Assert if an attribute of this name is present on this entry. - pub fn attribute_pres(&self, attr: Attribute) -> bool { + pub fn attribute_pres>(&self, attr: A) -> bool { self.attrs.contains_key(attr.as_ref()) } - #[inline(always)] /// Assert if an attribute of this name is present, and one of its values contains /// an exact match of this partial value. - pub fn attribute_equality(&self, attr: Attribute, value: &PartialValue) -> bool { + pub fn attribute_equality>(&self, attr: A, value: &PartialValue) -> bool { // we assume based on schema normalisation on the way in // that the equality here of the raw values MUST be correct. // We also normalise filters, to ensure that their values are @@ -3003,42 +2890,50 @@ impl Entry { } } - #[inline(always)] /// Assert if an attribute of this name is present, and one of it's values contains /// the following substring, if possible to perform the substring comparison. - pub fn attribute_substring(&self, attr: Attribute, subvalue: &PartialValue) -> bool { - self.attrs - .get(attr.as_ref()) + pub fn attribute_substring>( + &self, + attr: A, + subvalue: &PartialValue, + ) -> bool { + self.get_ava_set(attr) .map(|vset| vset.substring(subvalue)) .unwrap_or(false) } - #[inline(always)] /// Assert if an attribute of this name is present, and one of its values startswith /// the following string, if possible to perform the comparison. - pub fn attribute_startswith(&self, attr: Attribute, subvalue: &PartialValue) -> bool { - self.attrs - .get(attr.as_ref()) + pub fn attribute_startswith>( + &self, + attr: A, + subvalue: &PartialValue, + ) -> bool { + self.get_ava_set(attr) .map(|vset| vset.startswith(subvalue)) .unwrap_or(false) } - #[inline(always)] /// Assert if an attribute of this name is present, and one of its values startswith /// the following string, if possible to perform the comparison. - pub fn attribute_endswith(&self, attr: Attribute, subvalue: &PartialValue) -> bool { - self.attrs - .get(attr.as_ref()) + pub fn attribute_endswith>( + &self, + attr: A, + subvalue: &PartialValue, + ) -> bool { + self.get_ava_set(attr) .map(|vset| vset.endswith(subvalue)) .unwrap_or(false) } - #[inline(always)] /// Assert if an attribute of this name is present, and one of its values is less than /// the following partial value - pub fn attribute_lessthan(&self, attr: Attribute, subvalue: &PartialValue) -> bool { - self.attrs - .get(attr.as_ref()) + pub fn attribute_lessthan>( + &self, + attr: A, + subvalue: &PartialValue, + ) -> bool { + self.get_ava_set(attr) .map(|vset| vset.lessthan(subvalue)) .unwrap_or(false) } @@ -3061,48 +2956,12 @@ impl Entry { // Go through the filter components and check them in the entry. // This is recursive!!!! match filter { - FilterResolved::Eq(attr, value, _) => match attr.try_into() { - Ok(a) => self.attribute_equality(a, value), - Err(_) => { - admin_error!("Failed to convert {} to attribute!", attr); - false - } - }, - FilterResolved::Cnt(attr, subvalue, _) => match attr.try_into() { - Ok(a) => self.attribute_substring(a, subvalue), - Err(_) => { - admin_error!("Failed to convert {} to attribute!", attr); - false - } - }, - FilterResolved::Stw(attr, subvalue, _) => match attr.try_into() { - Ok(a) => self.attribute_startswith(a, subvalue), - Err(_) => { - admin_error!("Failed to convert {} to attribute!", attr); - false - } - }, - FilterResolved::Enw(attr, subvalue, _) => match attr.try_into() { - Ok(a) => self.attribute_endswith(a, subvalue), - Err(_) => { - admin_error!("Failed to convert {} to attribute!", attr); - false - } - }, - FilterResolved::Pres(attr, _) => match attr.try_into() { - Ok(a) => self.attribute_pres(a), - Err(_) => { - admin_error!("Failed to convert {} to attribute!", attr); - false - } - }, - FilterResolved::LessThan(attr, subvalue, _) => match attr.try_into() { - Ok(a) => self.attribute_lessthan(a, subvalue), - Err(_) => { - admin_error!("Failed to convert {} to attribute!", attr); - false - } - }, + FilterResolved::Eq(attr, value, _) => self.attribute_equality(attr, value), + FilterResolved::Cnt(attr, subvalue, _) => self.attribute_substring(attr, subvalue), + FilterResolved::Stw(attr, subvalue, _) => self.attribute_startswith(attr, subvalue), + FilterResolved::Enw(attr, subvalue, _) => self.attribute_endswith(attr, subvalue), + FilterResolved::Pres(attr, _) => self.attribute_pres(attr), + FilterResolved::LessThan(attr, subvalue, _) => self.attribute_lessthan(attr, subvalue), // Check with ftweedal about or filter zero len correctness. FilterResolved::Or(l, _) => l.iter().any(|f| self.entry_match_no_index_inner(f)), // Check with ftweedal about and filter zero len correctness. @@ -3119,7 +2978,7 @@ impl Entry { /// Given this entry, generate a filter containing the requested attributes strings as /// equality components. - pub fn filter_from_attrs(&self, attrs: &[AttrString]) -> Option> { + pub fn filter_from_attrs(&self, attrs: &[Attribute]) -> Option> { // Because we are a valid entry, a filter we create still may not // be valid because the internal server entry templates are still // created by humans! Plus double checking something already valid @@ -3131,18 +2990,18 @@ impl Entry { // Take name: (a, b), name: (c, d) -> (name, a), (name, b), (name, c), (name, d) - let mut pairs: Vec<(&str, PartialValue)> = Vec::with_capacity(0); + let mut pairs: Vec<(Attribute, PartialValue)> = Vec::with_capacity(0); for attr in attrs { match self.attrs.get(attr) { Some(values) => values .to_partialvalue_iter() - .for_each(|pv| pairs.push((attr, pv))), + .for_each(|pv| pairs.push((attr.clone(), pv))), None => return None, } } - let res: Vec> = pairs + let res: Vec = pairs .into_iter() .map(|(attr, pv)| FC::Eq(attr, pv)) .collect(); @@ -3176,17 +3035,17 @@ impl Entry { // 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 ... // as a result, I think we need to keep this continue line to not cause issues. - if k == Attribute::Uuid.as_ref() { + if *k == Attribute::Uuid { continue; } // Get the schema attribute type out. match schema.is_multivalue(k) { Ok(r) => { - if !r || k == "systemmust" || k == "systemmay" { - // As this is single value, purge then present to maintain this - // invariant. The other situation we purge is within schema with - // the system types where we need to be able to express REMOVAL - // of attributes, thus we need the purge. + // As this is single value, purge then present to maintain this + // invariant. The other situation we purge is within schema with + // the system types where we need to be able to express REMOVAL + // of attributes, thus we need the purge. + if !r || *k == Attribute::SystemMust || *k == Attribute::SystemMay { mods.push_mod(Modify::Purged(k.clone())); } } @@ -3205,7 +3064,7 @@ impl Entry { /// filter_map to effectively remove entries that should not be considered as "alive". pub fn mask_recycled_ts(&self) -> Option<&Self> { // Only when cls has ts/rc then None, else always Some(self). - match self.attrs.get(Attribute::Class.as_ref()) { + match self.attrs.get(&Attribute::Class) { Some(cls) => { if cls.contains(&EntryClass::Tombstone.to_partialvalue()) || cls.contains(&EntryClass::Recycled.to_partialvalue()) @@ -3223,7 +3082,7 @@ impl Entry { /// filter_map to effectively remove entries that are recycled in some cases. pub fn mask_recycled(&self) -> Option<&Self> { // Only when cls has ts/rc then None, else lways Some(self). - match self.attrs.get(Attribute::Class.as_ref()) { + match self.attrs.get(&Attribute::Class) { Some(cls) => { if cls.contains(&EntryClass::Recycled.to_partialvalue()) { None @@ -3239,7 +3098,7 @@ impl Entry { /// filter_map to effectively remove entries that are tombstones in some cases. pub fn mask_tombstone(&self) -> Option<&Self> { // Only when cls has ts/rc then None, else lways Some(self). - match self.attrs.get(Attribute::Class.as_ref()) { + match self.attrs.get(&Attribute::Class) { Some(cls) => { if cls.contains(&EntryClass::Tombstone.to_partialvalue()) { None @@ -3259,9 +3118,9 @@ where fn trigger_last_changed(&mut self) { self.valid .ecstate - .change_ava(&self.valid.cid, Attribute::LastModifiedCid); + .change_ava(&self.valid.cid, &Attribute::LastModifiedCid); let cv = vs_cid![self.valid.cid.clone()]; - let _ = self.attrs.insert(Attribute::LastModifiedCid.into(), cv); + let _ = self.attrs.insert(Attribute::LastModifiedCid, cv); } // This should always work? It's only on validate that we'll build @@ -3269,20 +3128,27 @@ where // If this already exists, we silently drop the event. This is because // we need this to be *state* based where we assert presence. pub fn add_ava(&mut self, attr: Attribute, value: Value) { - self.valid.ecstate.change_ava(&self.valid.cid, attr); + self.valid.ecstate.change_ava(&self.valid.cid, &attr); self.add_ava_int(attr, value); } - pub fn add_ava_if_not_exist(&mut self, attr: Attribute, value: Value) { + pub fn add_ava_if_not_exist>(&mut self, attr: A, value: Value) { + let attr_ref = attr.as_ref(); // This returns true if the value WAS changed! See add_ava_int. - if self.add_ava_int(attr, value) { + if self.add_ava_int(attr_ref.clone(), value) { // In this case, we ONLY update the changestate if the value was already present! - self.valid.ecstate.change_ava(&self.valid.cid, attr); + self.valid.ecstate.change_ava(&self.valid.cid, attr_ref); } } - fn assert_ava(&mut self, attr: Attribute, value: &PartialValue) -> Result<(), OperationError> { - self.valid.ecstate.change_ava(&self.valid.cid, attr); + fn assert_ava>( + &mut self, + attr: A, + value: &PartialValue, + ) -> Result<(), OperationError> { + self.valid + .ecstate + .change_ava(&self.valid.cid, attr.as_ref()); if self.attribute_equality(attr, value) { Ok(()) @@ -3293,24 +3159,30 @@ where /// Remove an attribute-value pair from this entry. If the ava doesn't exist, we /// don't do anything else since we are asserting the absence of a value. - pub(crate) fn remove_ava(&mut self, attr: Attribute, value: &PartialValue) { - self.valid.ecstate.change_ava(&self.valid.cid, attr); + pub(crate) fn remove_ava>(&mut self, attr: A, value: &PartialValue) { + let attr_ref = attr.as_ref(); + self.valid.ecstate.change_ava(&self.valid.cid, attr_ref); - let rm = if let Some(vs) = self.attrs.get_mut(attr.as_ref()) { + let rm = if let Some(vs) = self.attrs.get_mut(attr_ref) { vs.remove(value, &self.valid.cid); vs.is_empty() } else { false }; if rm { - self.attrs.remove(attr.as_ref()); + self.attrs.remove(attr_ref); }; } - pub(crate) fn remove_avas(&mut self, attr: Attribute, values: &BTreeSet) { - self.valid.ecstate.change_ava(&self.valid.cid, attr); + pub(crate) fn remove_avas>( + &mut self, + attr: A, + values: &BTreeSet, + ) { + let attr_ref = attr.as_ref(); + self.valid.ecstate.change_ava(&self.valid.cid, attr_ref); - let rm = if let Some(vs) = self.attrs.get_mut(attr.as_ref()) { + let rm = if let Some(vs) = self.attrs.get_mut(attr_ref) { values.iter().for_each(|k| { vs.remove(k, &self.valid.cid); }); @@ -3319,39 +3191,41 @@ where false }; if rm { - self.attrs.remove(attr.as_ref()); + self.attrs.remove(attr_ref); }; } /// Remove all values of this attribute from the entry. If it doesn't exist, this /// asserts that no content of that attribute exist. - pub(crate) fn purge_ava(&mut self, attr: Attribute) { - self.valid.ecstate.change_ava(&self.valid.cid, attr); + pub(crate) fn purge_ava>(&mut self, attr: A) { + let attr_ref = attr.as_ref(); + self.valid.ecstate.change_ava(&self.valid.cid, attr_ref); // self.valid.eclog.purge_ava(&self.valid.cid, attr); let can_remove = self .attrs - .get_mut(attr.as_ref()) + .get_mut(attr_ref) .map(|vs| vs.purge(&self.valid.cid)) // Default to false since a missing attr can't be removed! .unwrap_or_default(); if can_remove { - self.attrs.remove(attr.as_ref()); + self.attrs.remove(attr_ref); } } /// Remove this value set from the entry, returning the value set at the time of removal. - pub fn pop_ava(&mut self, attr: Attribute) -> Option { - self.valid.ecstate.change_ava(&self.valid.cid, attr); + pub fn pop_ava>(&mut self, attr: A) -> Option { + let attr_ref = attr.as_ref(); + self.valid.ecstate.change_ava(&self.valid.cid, attr_ref); - let mut vs = self.attrs.remove(attr.as_ref())?; + let mut vs = self.attrs.remove(attr_ref)?; if vs.purge(&self.valid.cid) { // Can return as is. Some(vs) } else { // This type may need special handling. Clone and reinsert. let r_vs = vs.clone(); - self.attrs.insert(attr.into(), vs); + self.attrs.insert(attr_ref.clone(), vs); Some(r_vs) } } @@ -3361,40 +3235,42 @@ where /// useful for things like "session" to test the grace window by removing the revoked /// sessions from the value set that you otherwise, could not. #[cfg(test)] - pub(crate) fn force_trim_ava(&mut self, attr: Attribute) -> Option { - self.valid.ecstate.change_ava(&self.valid.cid, attr); + pub(crate) fn force_trim_ava>(&mut self, attr: A) -> Option { + self.valid + .ecstate + .change_ava(&self.valid.cid, attr.as_ref()); self.attrs.remove(attr.as_ref()) } /// Replace the content of this attribute with the values from this /// iterator. If the iterator is empty, the attribute is purged. - pub fn set_ava(&mut self, attr: Attribute, iter: T) + pub fn set_ava(&mut self, attr: &Attribute, iter: T) where T: Clone + IntoIterator, { self.purge_ava(attr); - self.set_ava_iter_int(attr, iter) + self.set_ava_iter_int(attr.clone(), iter) } /// Replace the content of this attribute with a new value set. Effectively this is /// a a "purge and set". - pub fn set_ava_set(&mut self, attr: Attribute, vs: ValueSet) { + pub fn set_ava_set(&mut self, attr: &Attribute, vs: ValueSet) { self.purge_ava(attr); - if let Some(existing_vs) = self.attrs.get_mut(attr.as_ref()) { + if let Some(existing_vs) = self.attrs.get_mut(attr) { let _ = existing_vs.merge(&vs); } else { - self.attrs.insert(attr.into(), vs); + self.attrs.insert(attr.clone(), vs); } } /// Merge the content from the new ValueSet into the existing ValueSet. If no existing /// ValueSet is present, then these data are inserted. - pub fn merge_ava_set(&mut self, attr: Attribute, vs: ValueSet) -> Result<(), OperationError> { + pub fn merge_ava_set(&mut self, attr: &Attribute, vs: ValueSet) -> Result<(), OperationError> { self.valid.ecstate.change_ava(&self.valid.cid, attr); - if let Some(existing_vs) = self.attrs.get_mut(attr.as_ref()) { + if let Some(existing_vs) = self.attrs.get_mut(attr) { existing_vs.merge(&vs) } else { - self.attrs.insert(attr.into(), vs); + self.attrs.insert(attr.clone(), vs); Ok(()) } } @@ -3407,16 +3283,16 @@ where for modify in modlist { match modify { Modify::Present(attr, value) => { - self.add_ava(Attribute::try_from(attr)?, value.clone()); + self.add_ava(attr.clone(), value.clone()); } Modify::Removed(attr, value) => { - self.remove_ava(Attribute::try_from(attr)?, value); + self.remove_ava(attr, value); } Modify::Purged(attr) => { - self.purge_ava(Attribute::try_from(attr)?); + self.purge_ava(attr); } Modify::Assert(attr, value) => { - self.assert_ava(attr.to_owned(), value).inspect_err(|_e| { + self.assert_ava(attr, value).inspect_err(|_e| { error!("Modification assertion was not met. {} {:?}", attr, value); })?; } @@ -3461,21 +3337,21 @@ impl From<&SchemaAttribute> for Entry { // Build the Map of the attributes relevant // let mut attrs: Map> = Map::with_capacity(8); - let mut attrs: Map = Map::new(); - attrs.insert(Attribute::AttributeName.into(), name_v); - attrs.insert(Attribute::Description.into(), desc_v); - attrs.insert(Attribute::Uuid.into(), uuid_v); - attrs.insert(Attribute::MultiValue.into(), multivalue_v); - attrs.insert(Attribute::Phantom.into(), phantom_v); - attrs.insert(Attribute::SyncAllowed.into(), sync_allowed_v); - attrs.insert(Attribute::Replicated.into(), replicated_v); - attrs.insert(Attribute::Unique.into(), unique_v); + let mut attrs: Map = Map::new(); + attrs.insert(Attribute::AttributeName, name_v); + attrs.insert(Attribute::Description, desc_v); + attrs.insert(Attribute::Uuid, uuid_v); + attrs.insert(Attribute::MultiValue, multivalue_v); + attrs.insert(Attribute::Phantom, phantom_v); + attrs.insert(Attribute::SyncAllowed, sync_allowed_v); + attrs.insert(Attribute::Replicated, replicated_v); + attrs.insert(Attribute::Unique, unique_v); if let Some(vs) = index_v { - attrs.insert(Attribute::Index.into(), vs); + attrs.insert(Attribute::Index, vs); } - attrs.insert(Attribute::Syntax.into(), syntax_v); + attrs.insert(Attribute::Syntax, syntax_v); attrs.insert( - Attribute::Class.into(), + Attribute::Class, vs_iutf8![ EntryClass::Object.into(), EntryClass::System.into(), @@ -3500,14 +3376,13 @@ impl From<&SchemaClass> for Entry { let desc_v = vs_utf8![s.description.to_owned()]; let sync_allowed_v = vs_bool![s.sync_allowed]; - // let mut attrs: Map> = Map::with_capacity(8); - let mut attrs: Map = Map::new(); - attrs.insert(Attribute::ClassName.into(), name_v); - attrs.insert(Attribute::Description.into(), desc_v); - attrs.insert(Attribute::SyncAllowed.into(), sync_allowed_v); - attrs.insert(Attribute::Uuid.into(), uuid_v); + let mut attrs: Map = Map::new(); + attrs.insert(Attribute::ClassName, name_v); + attrs.insert(Attribute::Description, desc_v); + attrs.insert(Attribute::SyncAllowed, sync_allowed_v); + attrs.insert(Attribute::Uuid, uuid_v); attrs.insert( - Attribute::Class.into(), + Attribute::Class, vs_iutf8![ EntryClass::Object.into(), EntryClass::System.into(), @@ -3517,13 +3392,13 @@ impl From<&SchemaClass> for Entry { let vs_systemmay = ValueSetIutf8::from_iter(s.systemmay.iter().map(|sm| sm.as_str())); if let Some(vs) = vs_systemmay { - attrs.insert(Attribute::SystemMay.into(), vs); + attrs.insert(Attribute::SystemMay, vs); } let vs_systemmust = ValueSetIutf8::from_iter(s.systemmust.iter().map(|sm| sm.as_str())); if let Some(vs) = vs_systemmust { - attrs.insert(Attribute::SystemMust.into(), vs); + attrs.insert(Attribute::SystemMust, vs); } Entry { @@ -3653,7 +3528,7 @@ mod tests { e.add_ava(Attribute::UserId, Value::from("william")); let present_single_mods = ModifyList::new_valid_list(vec![Modify::Present( - Attribute::Attr.into(), + Attribute::Attr, Value::new_iutf8("value"), )]); @@ -3665,8 +3540,8 @@ mod tests { // Assert present for multivalue let present_multivalue_mods = ModifyList::new_valid_list(vec![ - Modify::Present(Attribute::Class.into(), Value::new_iutf8("test")), - Modify::Present(Attribute::Class.into(), Value::new_iutf8("multi_test")), + Modify::Present(Attribute::Class, Value::new_iutf8("test")), + Modify::Present(Attribute::Class, Value::new_iutf8("multi_test")), ]); assert!(e.apply_modlist(&present_multivalue_mods).is_ok()); @@ -3675,15 +3550,13 @@ mod tests { assert!(e.attribute_equality(Attribute::Class, &PartialValue::new_iutf8("multi_test"))); // Assert purge on single/multi/empty value - let purge_single_mods = - ModifyList::new_valid_list(vec![Modify::Purged(Attribute::Attr.into())]); + let purge_single_mods = ModifyList::new_valid_list(vec![Modify::Purged(Attribute::Attr)]); assert!(e.apply_modlist(&purge_single_mods).is_ok()); assert!(!e.attribute_pres(Attribute::Attr)); - let purge_multi_mods = - ModifyList::new_valid_list(vec![Modify::Purged(Attribute::Class.into())]); + let purge_multi_mods = ModifyList::new_valid_list(vec![Modify::Purged(Attribute::Class)]); assert!(e.apply_modlist(&purge_multi_mods).is_ok()); @@ -3695,20 +3568,20 @@ mod tests { // Assert removed on value that exists and doesn't exist let remove_mods = ModifyList::new_valid_list(vec![Modify::Removed( - Attribute::Attr.into(), + Attribute::Attr, PartialValue::new_iutf8("value"), )]); assert!(e.apply_modlist(&present_single_mods).is_ok()); assert!(e.attribute_equality(Attribute::Attr, &PartialValue::new_iutf8("value"))); assert!(e.apply_modlist(&remove_mods).is_ok()); - assert!(!e.attrs.contains_key(Attribute::Attr.as_ref())); + assert!(!e.attrs.contains_key(&Attribute::Attr)); let remove_empty_mods = remove_mods; assert!(e.apply_modlist(&remove_empty_mods).is_ok()); - assert!(!e.attrs.contains_key(Attribute::Attr.as_ref())); + assert!(!e.attrs.contains_key(&Attribute::Attr)); } #[test] @@ -3728,21 +3601,21 @@ mod tests { let mut idxmeta = HashMap::with_capacity(8); idxmeta.insert( IdxKey { - attr: Attribute::UserId.into(), + attr: Attribute::UserId, itype: IndexType::Equality, }, IdxSlope::MAX, ); idxmeta.insert( IdxKey { - attr: Attribute::UserId.into(), + attr: Attribute::UserId, itype: IndexType::Presence, }, IdxSlope::MAX, ); idxmeta.insert( IdxKey { - attr: Attribute::Extra.into(), + attr: Attribute::Extra, itype: IndexType::Equality, }, IdxSlope::MAX, @@ -3760,19 +3633,12 @@ mod tests { assert!( del_r[0] == Err(( - &Attribute::UserId.into(), + &Attribute::UserId, IndexType::Equality, "william".to_string() )) ); - assert!( - del_r[1] - == Err(( - &Attribute::UserId.into(), - IndexType::Presence, - "_".to_string() - )) - ); + assert!(del_r[1] == Err((&Attribute::UserId, IndexType::Presence, "_".to_string()))); // Check generating an add diff let mut add_r = Entry::idx_diff(&idxmeta, None, Some(&e1)); @@ -3781,19 +3647,12 @@ mod tests { assert!( add_r[0] == Ok(( - &Attribute::UserId.into(), + &Attribute::UserId, IndexType::Equality, "william".to_string() )) ); - assert!( - add_r[1] - == Ok(( - &Attribute::UserId.into(), - IndexType::Presence, - "_".to_string() - )) - ); + assert!(add_r[1] == Ok((&Attribute::UserId, IndexType::Presence, "_".to_string()))); // Check the mod cases now @@ -3803,25 +3662,11 @@ mod tests { // Check "adding" an attribute. let add_a_r = Entry::idx_diff(&idxmeta, Some(&e1), Some(&e1_mod)); - assert!( - add_a_r[0] - == Ok(( - &Attribute::Extra.into(), - IndexType::Equality, - "test".to_string() - )) - ); + assert!(add_a_r[0] == Ok((&Attribute::Extra, IndexType::Equality, "test".to_string()))); // Check "removing" an attribute. let del_a_r = Entry::idx_diff(&idxmeta, Some(&e1_mod), Some(&e1)); - assert!( - del_a_r[0] - == Err(( - &Attribute::Extra.into(), - IndexType::Equality, - "test".to_string() - )) - ); + assert!(del_a_r[0] == Err((&Attribute::Extra, IndexType::Equality, "test".to_string()))); // Change an attribute. let mut chg_r = Entry::idx_diff(&idxmeta, Some(&e1), Some(&e2)); @@ -3830,7 +3675,7 @@ mod tests { assert!( chg_r[1] == Err(( - &Attribute::UserId.into(), + &Attribute::UserId, IndexType::Equality, "william".to_string() )) @@ -3839,7 +3684,7 @@ mod tests { assert!( chg_r[0] == Ok(( - &Attribute::UserId.into(), + &Attribute::UserId, IndexType::Equality, "claire".to_string() )) diff --git a/server/lib/src/event.rs b/server/lib/src/event.rs index cf6ea8449..8233731b3 100644 --- a/server/lib/src/event.rs +++ b/server/lib/src/event.rs @@ -76,7 +76,7 @@ pub struct SearchEvent { pub filter: Filter, // This is the original filter, for the purpose of ACI checking. pub filter_orig: Filter, - pub attrs: Option>, + pub attrs: Option>, } impl SearchEvent { @@ -108,7 +108,7 @@ impl SearchEvent { attrs: Option<&[String]>, qs: &mut QueryServerReadTransaction, ) -> Result { - let r_attrs: Option> = attrs.map(|vs| { + let r_attrs: Option> = attrs.map(|vs| { vs.iter() .filter_map(|a| qs.get_schema().normalise_attr_if_exists(a.as_str())) .collect() @@ -141,9 +141,13 @@ impl SearchEvent { attrs: Option<&[String]>, qs: &QueryServerReadTransaction, ) -> Result { - let r_attrs: Option> = attrs.map(|vs| { + let r_attrs: Option> = attrs.map(|vs| { vs.iter() - .filter_map(|a| qs.get_schema().normalise_attr_if_exists(a.as_str())) + .filter_map(|a| { + qs.get_schema() + .normalise_attr_if_exists(a.as_str()) + .map(|a_str| Attribute::from(a_str.as_str())) + }) .collect() }); @@ -293,7 +297,7 @@ impl SearchEvent { qs: &mut QueryServerReadTransaction, ident: Identity, lf: &LdapFilter, - attrs: Option>, + attrs: Option>, ) -> Result { // Kanidm Filter from LdapFilter let f = Filter::from_ldap_ro(&ident, lf, qs)?; diff --git a/server/lib/src/filter.rs b/server/lib/src/filter.rs index 8918777dd..0d027d7b2 100644 --- a/server/lib/src/filter.rs +++ b/server/lib/src/filter.rs @@ -24,7 +24,6 @@ use hashbrown::HashSet; use kanidm_proto::constants::ATTR_UUID; use kanidm_proto::internal::{Filter as ProtoFilter, OperationError, SchemaError}; use ldap3_proto::proto::{LdapFilter, LdapSubstringFilter}; -// use smartstring::alias::String as AttrString; use serde::Deserialize; use uuid::Uuid; @@ -48,20 +47,20 @@ pub type ResolveFilterCacheReadTxn<'a> = ARCacheReadTxn< // This is &Value so we can lazy const then clone, but perhaps we can reconsider // later if this should just take Value. -pub fn f_eq<'a>(a: Attribute, v: PartialValue) -> FC<'a> { - FC::Eq(a.into(), v) +pub fn f_eq(a: Attribute, v: PartialValue) -> FC { + FC::Eq(a, v) } -pub fn f_sub<'a>(a: Attribute, v: PartialValue) -> FC<'a> { - FC::Cnt(a.into(), v) +pub fn f_sub(a: Attribute, v: PartialValue) -> FC { + FC::Cnt(a, v) } -pub fn f_pres<'a>(a: Attribute) -> FC<'a> { - FC::Pres(a.into()) +pub fn f_pres(a: Attribute) -> FC { + FC::Pres(a) } -pub fn f_lt<'a>(a: Attribute, v: PartialValue) -> FC<'a> { - FC::LessThan(a.into(), v) +pub fn f_lt(a: Attribute, v: PartialValue) -> FC { + FC::LessThan(a, v) } pub fn f_or(vs: Vec) -> FC { @@ -80,16 +79,16 @@ pub fn f_andnot(fc: FC) -> FC { FC::AndNot(Box::new(fc)) } -pub fn f_self<'a>() -> FC<'a> { +pub fn f_self() -> FC { FC::SelfUuid } -pub fn f_id(uuid: &str) -> FC<'static> { +pub fn f_id(uuid: &str) -> FC { let uf = Uuid::parse_str(uuid) .ok() - .map(|u| FC::Eq(Attribute::Uuid.as_ref(), PartialValue::Uuid(u))); - let spnf = PartialValue::new_spn_s(uuid).map(|spn| FC::Eq(Attribute::Spn.as_ref(), spn)); - let nf = FC::Eq(Attribute::Name.as_ref(), PartialValue::new_iname(uuid)); + .map(|u| FC::Eq(Attribute::Uuid, PartialValue::Uuid(u))); + let spnf = PartialValue::new_spn_s(uuid).map(|spn| FC::Eq(Attribute::Spn, spn)); + let nf = FC::Eq(Attribute::Name, PartialValue::new_iname(uuid)); let f: Vec<_> = iter::once(uf) .chain(iter::once(spnf)) .flatten() @@ -98,9 +97,9 @@ pub fn f_id(uuid: &str) -> FC<'static> { FC::Or(f) } -pub fn f_spn_name(id: &str) -> FC<'static> { - let spnf = PartialValue::new_spn_s(id).map(|spn| FC::Eq(Attribute::Spn.as_ref(), spn)); - let nf = FC::Eq(Attribute::Name.as_ref(), PartialValue::new_iname(id)); +pub fn f_spn_name(id: &str) -> FC { + let spnf = PartialValue::new_spn_s(id).map(|spn| FC::Eq(Attribute::Spn, spn)); + let nf = FC::Eq(Attribute::Name, PartialValue::new_iname(id)); let f: Vec<_> = iter::once(spnf).flatten().chain(iter::once(nf)).collect(); FC::Or(f) } @@ -108,15 +107,15 @@ pub fn f_spn_name(id: &str) -> FC<'static> { /// This is the short-form for tests and internal filters that can then /// be transformed into a filter for the server to use. #[derive(Clone, Debug, Deserialize)] -pub enum FC<'a> { - Eq(&'a str, PartialValue), - Cnt(&'a str, PartialValue), - Pres(&'a str), - LessThan(&'a str, PartialValue), - Or(Vec>), - And(Vec>), - Inclusion(Vec>), - AndNot(Box>), +pub enum FC { + Eq(Attribute, PartialValue), + Cnt(Attribute, PartialValue), + Pres(Attribute), + LessThan(Attribute, PartialValue), + Or(Vec), + And(Vec), + Inclusion(Vec), + AndNot(Box), SelfUuid, // Not(Box), } @@ -125,12 +124,12 @@ pub enum FC<'a> { #[derive(Clone, Hash, PartialEq, PartialOrd, Ord, Eq)] enum FilterComp { // This is attr - value - Eq(AttrString, PartialValue), - Cnt(AttrString, PartialValue), - Stw(AttrString, PartialValue), - Enw(AttrString, PartialValue), - Pres(AttrString), - LessThan(AttrString, PartialValue), + Eq(Attribute, PartialValue), + Cnt(Attribute, PartialValue), + Stw(Attribute, PartialValue), + Enw(Attribute, PartialValue), + Pres(Attribute), + LessThan(Attribute, PartialValue), Or(Vec), And(Vec), Inclusion(Vec), @@ -214,12 +213,12 @@ impl fmt::Debug for FilterComp { #[derive(Clone, Eq)] pub enum FilterResolved { // This is attr - value - indexed slope factor - Eq(AttrString, PartialValue, Option), - Cnt(AttrString, PartialValue, Option), - Stw(AttrString, PartialValue, Option), - Enw(AttrString, PartialValue, Option), - Pres(AttrString, Option), - LessThan(AttrString, PartialValue, Option), + Eq(Attribute, PartialValue, Option), + Cnt(Attribute, PartialValue, Option), + Stw(Attribute, PartialValue, Option), + Enw(Attribute, PartialValue, Option), + Pres(Attribute, Option), + LessThan(Attribute, PartialValue, Option), Or(Vec, Option), And(Vec, Option), // All terms must have 1 or more items, or the inclusion is false! @@ -335,16 +334,16 @@ pub struct FilterValidResolved { #[derive(Debug)] pub enum FilterPlan { Invalid, - EqIndexed(AttrString, String), - EqUnindexed(AttrString), - EqCorrupt(AttrString), - SubIndexed(AttrString, String), - SubUnindexed(AttrString), - SubCorrupt(AttrString), - PresIndexed(AttrString), - PresUnindexed(AttrString), - PresCorrupt(AttrString), - LessThanUnindexed(AttrString), + EqIndexed(Attribute, String), + EqUnindexed(Attribute), + EqCorrupt(Attribute), + SubIndexed(Attribute, String), + SubUnindexed(Attribute), + SubCorrupt(Attribute), + PresIndexed(Attribute), + PresUnindexed(Attribute), + PresCorrupt(Attribute), + LessThanUnindexed(Attribute), OrUnindexed(Vec), OrIndexed(Vec), OrPartial(Vec), @@ -520,7 +519,7 @@ impl Filter { Ok(resolved_filt) } - pub fn get_attr_set(&self) -> BTreeSet<&str> { + pub fn get_attr_set(&self) -> BTreeSet { // Recurse through the filter getting an attribute set. let mut r_set = BTreeSet::new(); self.state.inner.get_attr_set(&mut r_set); @@ -603,19 +602,19 @@ impl Filter { // some core test idxs faster. This is never used in production, it's JUST for // test case speedups. let idxmeta = vec![ - (Attribute::Uuid.into(), IndexType::Equality), - (Attribute::Uuid.into(), IndexType::Presence), - (Attribute::Name.into(), IndexType::Equality), - (Attribute::Name.into(), IndexType::SubString), - (Attribute::Name.into(), IndexType::Presence), - (Attribute::Class.into(), IndexType::Equality), - (Attribute::Class.into(), IndexType::Presence), - (Attribute::Member.into(), IndexType::Equality), - (Attribute::Member.into(), IndexType::Presence), - (Attribute::MemberOf.into(), IndexType::Equality), - (Attribute::MemberOf.into(), IndexType::Presence), - (Attribute::DirectMemberOf.into(), IndexType::Equality), - (Attribute::DirectMemberOf.into(), IndexType::Presence), + (Attribute::Uuid, IndexType::Equality), + (Attribute::Uuid, IndexType::Presence), + (Attribute::Name, IndexType::Equality), + (Attribute::Name, IndexType::SubString), + (Attribute::Name, IndexType::Presence), + (Attribute::Class, IndexType::Equality), + (Attribute::Class, IndexType::Presence), + (Attribute::Member, IndexType::Equality), + (Attribute::Member, IndexType::Presence), + (Attribute::MemberOf, IndexType::Equality), + (Attribute::MemberOf, IndexType::Presence), + (Attribute::DirectMemberOf, IndexType::Equality), + (Attribute::DirectMemberOf, IndexType::Presence), ]; let idxmeta_ref = idxmeta.iter().map(|(attr, itype)| (attr, itype)).collect(); @@ -721,10 +720,10 @@ impl FromStr for Filter { impl FilterComp { fn new(fc: FC) -> Self { match fc { - FC::Eq(a, v) => FilterComp::Eq(AttrString::from(a), v), - FC::Cnt(a, v) => FilterComp::Cnt(AttrString::from(a), v), - FC::Pres(a) => FilterComp::Pres(AttrString::from(a)), - FC::LessThan(a, v) => FilterComp::LessThan(AttrString::from(a), v), + FC::Eq(a, v) => FilterComp::Eq(a, v), + FC::Cnt(a, v) => FilterComp::Cnt(a, v), + FC::Pres(a) => FilterComp::Pres(a), + FC::LessThan(a, v) => FilterComp::LessThan(a, v), FC::Or(v) => FilterComp::Or(v.into_iter().map(FilterComp::new).collect()), FC::And(v) => FilterComp::And(v.into_iter().map(FilterComp::new).collect()), FC::Inclusion(v) => FilterComp::Inclusion(v.into_iter().map(FilterComp::new).collect()), @@ -736,8 +735,8 @@ impl FilterComp { fn new_ignore_hidden(fc: FilterComp) -> Self { FilterComp::And(vec![ FilterComp::AndNot(Box::new(FilterComp::Or(vec![ - FilterComp::Eq(Attribute::Class.into(), EntryClass::Tombstone.into()), - FilterComp::Eq(Attribute::Class.into(), EntryClass::Recycled.into()), + FilterComp::Eq(Attribute::Class, EntryClass::Tombstone.into()), + FilterComp::Eq(Attribute::Class, EntryClass::Recycled.into()), ]))), fc, ]) @@ -745,12 +744,12 @@ impl FilterComp { fn new_recycled(fc: FilterComp) -> Self { FilterComp::And(vec![ - FilterComp::Eq(Attribute::Class.into(), EntryClass::Recycled.into()), + FilterComp::Eq(Attribute::Class, EntryClass::Recycled.into()), fc, ]) } - fn get_attr_set<'a>(&'a self, r_set: &mut BTreeSet<&'a str>) { + fn get_attr_set(&self, r_set: &mut BTreeSet) { match self { FilterComp::Eq(attr, _) | FilterComp::Cnt(attr, _) @@ -758,14 +757,14 @@ impl FilterComp { | FilterComp::Enw(attr, _) | FilterComp::Pres(attr) | FilterComp::LessThan(attr, _) => { - r_set.insert(attr.as_str()); + r_set.insert(attr.clone()); } FilterComp::Or(vs) => vs.iter().for_each(|f| f.get_attr_set(r_set)), FilterComp::And(vs) => vs.iter().for_each(|f| f.get_attr_set(r_set)), FilterComp::Inclusion(vs) => vs.iter().for_each(|f| f.get_attr_set(r_set)), FilterComp::AndNot(f) => f.get_attr_set(r_set), FilterComp::SelfUuid => { - r_set.insert(ATTR_UUID); + r_set.insert(Attribute::Uuid); } } } @@ -784,89 +783,74 @@ impl FilterComp { match self { FilterComp::Eq(attr, value) => { - // Validate/normalise the attr name. - let attr_norm = schema.normalise_attr_name(attr); - // Now check it exists - match schema_attributes.get(&attr_norm) { + // Check the requested attribute exists, and this PV type matches something + // that can be queried of the attribute. + match schema_attributes.get(attr) { Some(schema_a) => { schema_a - .validate_partialvalue(attr_norm.as_str(), value) + .validate_partialvalue(attr, value) // Okay, it worked, transform to a filter component - .map(|_| FilterComp::Eq(attr_norm, value.clone())) + .map(|_| FilterComp::Eq(attr.clone(), value.clone())) // On error, pass the error back out. } - None => Err(SchemaError::InvalidAttribute(attr_norm.to_string())), + None => Err(SchemaError::InvalidAttribute(attr.to_string())), } } FilterComp::Cnt(attr, value) => { - // Validate/normalise the attr name. - let attr_norm = schema.normalise_attr_name(attr); - // Now check it exists - match schema_attributes.get(&attr_norm) { + match schema_attributes.get(attr) { Some(schema_a) => { schema_a - .validate_partialvalue(attr_norm.as_str(), value) + .validate_partialvalue(attr, value) // Okay, it worked, transform to a filter component - .map(|_| FilterComp::Cnt(attr_norm, value.clone())) + .map(|_| FilterComp::Cnt(attr.clone(), value.clone())) // On error, pass the error back out. } - None => Err(SchemaError::InvalidAttribute(attr_norm.to_string())), + None => Err(SchemaError::InvalidAttribute(attr.to_string())), } } FilterComp::Stw(attr, value) => { - // Validate/normalise the attr name. - let attr_norm = schema.normalise_attr_name(attr); - // Now check it exists - match schema_attributes.get(&attr_norm) { + match schema_attributes.get(attr) { Some(schema_a) => { schema_a - .validate_partialvalue(attr_norm.as_str(), value) + .validate_partialvalue(attr, value) // Okay, it worked, transform to a filter component - .map(|_| FilterComp::Stw(attr_norm, value.clone())) + .map(|_| FilterComp::Stw(attr.clone(), value.clone())) // On error, pass the error back out. } - None => Err(SchemaError::InvalidAttribute(attr_norm.to_string())), + None => Err(SchemaError::InvalidAttribute(attr.to_string())), } } FilterComp::Enw(attr, value) => { - // Validate/normalise the attr name. - let attr_norm = schema.normalise_attr_name(attr); - // Now check it exists - match schema_attributes.get(&attr_norm) { + match schema_attributes.get(attr) { Some(schema_a) => { schema_a - .validate_partialvalue(attr_norm.as_str(), value) + .validate_partialvalue(attr, value) // Okay, it worked, transform to a filter component - .map(|_| FilterComp::Enw(attr_norm, value.clone())) + .map(|_| FilterComp::Enw(attr.clone(), value.clone())) // On error, pass the error back out. } - None => Err(SchemaError::InvalidAttribute(attr_norm.to_string())), + None => Err(SchemaError::InvalidAttribute(attr.to_string())), } } FilterComp::Pres(attr) => { - let attr_norm = schema.normalise_attr_name(attr); - // Now check it exists - match schema_attributes.get(&attr_norm) { + match schema_attributes.get(attr) { Some(_attr_name) => { // Return our valid data - Ok(FilterComp::Pres(attr_norm)) + Ok(FilterComp::Pres(attr.clone())) } - None => Err(SchemaError::InvalidAttribute(attr_norm.to_string())), + None => Err(SchemaError::InvalidAttribute(attr.to_string())), } } FilterComp::LessThan(attr, value) => { - // Validate/normalise the attr name. - let attr_norm = schema.normalise_attr_name(attr); - // Now check it exists - match schema_attributes.get(&attr_norm) { + match schema_attributes.get(attr) { Some(schema_a) => { schema_a - .validate_partialvalue(attr_norm.as_str(), value) + .validate_partialvalue(attr, value) // Okay, it worked, transform to a filter component - .map(|_| FilterComp::LessThan(attr_norm, value.clone())) + .map(|_| FilterComp::LessThan(attr.clone(), value.clone())) // On error, pass the error back out. } - None => Err(SchemaError::InvalidAttribute(attr_norm.to_string())), + None => Err(SchemaError::InvalidAttribute(attr.to_string())), } } FilterComp::Or(filters) => { @@ -932,17 +916,17 @@ impl FilterComp { let ndepth = depth.checked_sub(1).ok_or(OperationError::ResourceLimit)?; Ok(match f { ProtoFilter::Eq(a, v) => { - let nk = qs.get_schema().normalise_attr_name(a); - let v = qs.clone_partialvalue(nk.as_str(), v)?; + let nk = Attribute::from(a.as_str()); + let v = qs.clone_partialvalue(&nk, v)?; FilterComp::Eq(nk, v) } ProtoFilter::Cnt(a, v) => { - let nk = qs.get_schema().normalise_attr_name(a); - let v = qs.clone_partialvalue(nk.as_str(), v)?; + let nk = Attribute::from(a.as_str()); + let v = qs.clone_partialvalue(&nk, v)?; FilterComp::Cnt(nk, v) } ProtoFilter::Pres(a) => { - let nk = qs.get_schema().normalise_attr_name(a); + let nk = Attribute::from(a.as_str()); FilterComp::Pres(nk) } ProtoFilter::Or(l) => { @@ -984,17 +968,17 @@ impl FilterComp { let ndepth = depth.checked_sub(1).ok_or(OperationError::ResourceLimit)?; Ok(match f { ProtoFilter::Eq(a, v) => { - let nk = qs.get_schema().normalise_attr_name(a); - let v = qs.clone_partialvalue(nk.as_str(), v)?; + let nk = Attribute::from(a.as_str()); + let v = qs.clone_partialvalue(&nk, v)?; FilterComp::Eq(nk, v) } ProtoFilter::Cnt(a, v) => { - let nk = qs.get_schema().normalise_attr_name(a); - let v = qs.clone_partialvalue(nk.as_str(), v)?; + let nk = Attribute::from(a.as_str()); + let v = qs.clone_partialvalue(&nk, v)?; FilterComp::Cnt(nk, v) } ProtoFilter::Pres(a) => { - let nk = qs.get_schema().normalise_attr_name(a); + let nk = Attribute::from(a.as_str()); FilterComp::Pres(nk) } ProtoFilter::Or(l) => { @@ -1065,7 +1049,7 @@ impl FilterComp { } LdapFilter::Equality(a, v) => { let a = ldap_attr_filter_map(a); - let v = qs.clone_partialvalue(a.as_str(), v)?; + let v = qs.clone_partialvalue(&a, v)?; FilterComp::Eq(a, v) } LdapFilter::Present(a) => FilterComp::Pres(ldap_attr_filter_map(a)), @@ -1081,17 +1065,17 @@ impl FilterComp { let mut terms = Vec::with_capacity(any.len() + 2); if let Some(ini) = initial { - let v = qs.clone_partialvalue(a.as_str(), ini)?; + let v = qs.clone_partialvalue(&a, ini)?; terms.push(FilterComp::Stw(a.clone(), v)); } for term in any.iter() { - let v = qs.clone_partialvalue(a.as_str(), term)?; + let v = qs.clone_partialvalue(&a, term)?; terms.push(FilterComp::Cnt(a.clone(), v)); } if let Some(fin) = final_ { - let v = qs.clone_partialvalue(a.as_str(), fin)?; + let v = qs.clone_partialvalue(&a, fin)?; terms.push(FilterComp::Enw(a.clone(), v)); } @@ -1227,7 +1211,7 @@ impl FilterResolved { /// ⚠️ - Process a filter without verifying with schema. /// This is a TEST ONLY method and will never be exposed in production. #[cfg(test)] - fn from_invalid(fc: FilterComp, idxmeta: &HashSet<(&AttrString, &IndexType)>) -> Self { + fn from_invalid(fc: FilterComp, idxmeta: &HashSet<(&Attribute, &IndexType)>) -> Self { match fc { FilterComp::Eq(a, v) => { let idx = idxmeta.contains(&(&a, &IndexType::Equality)); @@ -1332,7 +1316,7 @@ impl FilterResolved { .get(&idxkref as &dyn IdxKeyToRef) .copied() .and_then(NonZeroU8::new); - FilterResolved::Eq(Attribute::Uuid.into(), PartialValue::Uuid(uuid), idx) + FilterResolved::Eq(Attribute::Uuid, PartialValue::Uuid(uuid), idx) }), FilterComp::Cnt(a, v) => { let idxkref = IdxKeyRef::new(&a, &IndexType::SubString); @@ -1421,7 +1405,7 @@ impl FilterResolved { } FilterComp::SelfUuid => ev.get_uuid().map(|uuid| { FilterResolved::Eq( - Attribute::Uuid.into(), + Attribute::Uuid, PartialValue::Uuid(uuid), NonZeroU8::new(true as u8), ) @@ -2012,8 +1996,8 @@ mod tests { #[test] fn test_attr_set_filter() { let mut f_expect = BTreeSet::new(); - f_expect.insert("userid"); - f_expect.insert(Attribute::Class.as_ref()); + f_expect.insert(Attribute::from("userid")); + f_expect.insert(Attribute::Class); // Given filters, get their expected attribute sets - this is used by access control profiles // to determine what attrs we are requesting regardless of the partialvalue. let f_t1a = filter_valid!(f_and!([ diff --git a/server/lib/src/idm/account.rs b/server/lib/src/idm/account.rs index f012931ae..9d1d3f7dc 100644 --- a/server/lib/src/idm/account.rs +++ b/server/lib/src/idm/account.rs @@ -567,20 +567,20 @@ impl Account { if let Some(ncred) = opt_ncred { let vcred = Value::new_credential("primary", ncred); - ml.push(Modify::Purged(Attribute::PrimaryCredential.into())); - ml.push(Modify::Present(Attribute::PrimaryCredential.into(), vcred)); + ml.push(Modify::Purged(Attribute::PrimaryCredential)); + ml.push(Modify::Present(Attribute::PrimaryCredential, vcred)); } // Is it a passkey? self.passkeys.iter_mut().for_each(|(u, (t, k))| { if let Some(true) = k.update_credential(auth_result) { ml.push(Modify::Removed( - Attribute::PassKeys.into(), + Attribute::PassKeys, PartialValue::Passkey(*u), )); ml.push(Modify::Present( - Attribute::PassKeys.into(), + Attribute::PassKeys, Value::Passkey(*u, t.clone(), k.clone()), )); } @@ -590,12 +590,12 @@ impl Account { self.attested_passkeys.iter_mut().for_each(|(u, (t, k))| { if let Some(true) = k.update_credential(auth_result) { ml.push(Modify::Removed( - Attribute::AttestedPasskeys.into(), + Attribute::AttestedPasskeys, PartialValue::AttestedPasskey(*u), )); ml.push(Modify::Present( - Attribute::AttestedPasskeys.into(), + Attribute::AttestedPasskeys, Value::AttestedPasskey(*u, t.clone(), k.clone()), )); } @@ -827,7 +827,7 @@ impl<'a> IdmServerProxyWriteTransaction<'a> { ) -> Result<(), OperationError> { // Delete the attribute with uuid. let modlist = ModifyList::new_list(vec![Modify::Removed( - Attribute::UserAuthTokenSession.into(), + Attribute::UserAuthTokenSession, PartialValue::Refer(dte.token_id), )]); @@ -881,9 +881,9 @@ impl<'a> IdmServerProxyWriteTransaction<'a> { let prev_classes: BTreeSet<_> = account_entry .get_ava_as_iutf8_iter(Attribute::Class) .ok_or_else(|| { - admin_error!( + error!( "Invalid entry, {} attribute is not present or not iutf8", - Attribute::Class.as_ref() + Attribute::Class ); OperationError::InvalidAccountState(format!( "Missing attribute: {}", @@ -916,7 +916,7 @@ impl<'a> IdmServerProxyWriteTransaction<'a> { ); // add person modlist.push_mod(Modify::Present( - Attribute::Class.into(), + Attribute::Class, EntryClass::Person.to_value(), )); // purge the other attrs that are SA only. @@ -1076,8 +1076,8 @@ mod tests { PartialValue::new_iname("testaccount") )), ModifyList::new_list(vec![ - Modify::Present(Attribute::Class.into(), EntryClass::PosixAccount.into()), - Modify::Present(Attribute::GidNumber.into(), Value::new_uint32(2001)), + Modify::Present(Attribute::Class, EntryClass::PosixAccount.into()), + Modify::Present(Attribute::GidNumber, Value::new_uint32(2001)), ]), ); assert!(idms_prox_write.qs_write.modify(&me_posix).is_ok()); diff --git a/server/lib/src/idm/credupdatesession.rs b/server/lib/src/idm/credupdatesession.rs index 03aca1fae..7abfc0e1e 100644 --- a/server/lib/src/idm/credupdatesession.rs +++ b/server/lib/src/idm/credupdatesession.rs @@ -518,11 +518,11 @@ impl<'a> IdmServerProxyWriteTransaction<'a> { .effective_permission_check( ident, Some(btreeset![ - Attribute::PrimaryCredential.into(), - Attribute::PassKeys.into(), - Attribute::AttestedPasskeys.into(), - Attribute::UnixPassword.into(), - Attribute::SshPublicKey.into() + Attribute::PrimaryCredential, + Attribute::PassKeys, + Attribute::AttestedPasskeys, + Attribute::UnixPassword, + Attribute::SshPublicKey ]), &[entry], )?; @@ -543,19 +543,19 @@ impl<'a> IdmServerProxyWriteTransaction<'a> { let eperm_search_primary_cred = match &eperm.search { Access::Denied => false, Access::Grant => true, - Access::Allow(attrs) => attrs.contains(Attribute::PrimaryCredential.as_ref()), + Access::Allow(attrs) => attrs.contains(&Attribute::PrimaryCredential), }; let eperm_mod_primary_cred = match &eperm.modify_pres { Access::Denied => false, Access::Grant => true, - Access::Allow(attrs) => attrs.contains(Attribute::PrimaryCredential.as_ref()), + Access::Allow(attrs) => attrs.contains(&Attribute::PrimaryCredential), }; let eperm_rem_primary_cred = match &eperm.modify_rem { Access::Denied => false, Access::Grant => true, - Access::Allow(attrs) => attrs.contains(Attribute::PrimaryCredential.as_ref()), + Access::Allow(attrs) => attrs.contains(&Attribute::PrimaryCredential), }; let primary_can_edit = @@ -564,19 +564,19 @@ impl<'a> IdmServerProxyWriteTransaction<'a> { let eperm_search_passkeys = match &eperm.search { Access::Denied => false, Access::Grant => true, - Access::Allow(attrs) => attrs.contains(Attribute::PassKeys.as_ref()), + Access::Allow(attrs) => attrs.contains(&Attribute::PassKeys), }; let eperm_mod_passkeys = match &eperm.modify_pres { Access::Denied => false, Access::Grant => true, - Access::Allow(attrs) => attrs.contains(Attribute::PassKeys.as_ref()), + Access::Allow(attrs) => attrs.contains(&Attribute::PassKeys), }; let eperm_rem_passkeys = match &eperm.modify_rem { Access::Denied => false, Access::Grant => true, - Access::Allow(attrs) => attrs.contains(Attribute::PassKeys.as_ref()), + Access::Allow(attrs) => attrs.contains(&Attribute::PassKeys), }; let passkeys_can_edit = eperm_search_passkeys && eperm_mod_passkeys && eperm_rem_passkeys; @@ -584,19 +584,19 @@ impl<'a> IdmServerProxyWriteTransaction<'a> { let eperm_search_attested_passkeys = match &eperm.search { Access::Denied => false, Access::Grant => true, - Access::Allow(attrs) => attrs.contains(Attribute::AttestedPasskeys.as_ref()), + Access::Allow(attrs) => attrs.contains(&Attribute::AttestedPasskeys), }; let eperm_mod_attested_passkeys = match &eperm.modify_pres { Access::Denied => false, Access::Grant => true, - Access::Allow(attrs) => attrs.contains(Attribute::AttestedPasskeys.as_ref()), + Access::Allow(attrs) => attrs.contains(&Attribute::AttestedPasskeys), }; let eperm_rem_attested_passkeys = match &eperm.modify_rem { Access::Denied => false, Access::Grant => true, - Access::Allow(attrs) => attrs.contains(Attribute::AttestedPasskeys.as_ref()), + Access::Allow(attrs) => attrs.contains(&Attribute::AttestedPasskeys), }; let attested_passkeys_can_edit = eperm_search_attested_passkeys @@ -606,19 +606,19 @@ impl<'a> IdmServerProxyWriteTransaction<'a> { let eperm_search_unixcred = match &eperm.search { Access::Denied => false, Access::Grant => true, - Access::Allow(attrs) => attrs.contains(Attribute::UnixPassword.as_ref()), + Access::Allow(attrs) => attrs.contains(&Attribute::UnixPassword), }; let eperm_mod_unixcred = match &eperm.modify_pres { Access::Denied => false, Access::Grant => true, - Access::Allow(attrs) => attrs.contains(Attribute::UnixPassword.as_ref()), + Access::Allow(attrs) => attrs.contains(&Attribute::UnixPassword), }; let eperm_rem_unixcred = match &eperm.modify_rem { Access::Denied => false, Access::Grant => true, - Access::Allow(attrs) => attrs.contains(Attribute::UnixPassword.as_ref()), + Access::Allow(attrs) => attrs.contains(&Attribute::UnixPassword), }; let unixcred_can_edit = account.unix_extn().is_some() @@ -629,19 +629,19 @@ impl<'a> IdmServerProxyWriteTransaction<'a> { let eperm_search_sshpubkey = match &eperm.search { Access::Denied => false, Access::Grant => true, - Access::Allow(attrs) => attrs.contains(Attribute::SshPublicKey.as_ref()), + Access::Allow(attrs) => attrs.contains(&Attribute::SshPublicKey), }; let eperm_mod_sshpubkey = match &eperm.modify_pres { Access::Denied => false, Access::Grant => true, - Access::Allow(attrs) => attrs.contains(Attribute::SshPublicKey.as_ref()), + Access::Allow(attrs) => attrs.contains(&Attribute::SshPublicKey), }; let eperm_rem_sshpubkey = match &eperm.modify_rem { Access::Denied => false, Access::Grant => true, - Access::Allow(attrs) => attrs.contains(Attribute::SshPublicKey.as_ref()), + Access::Allow(attrs) => attrs.contains(&Attribute::SshPublicKey), }; let sshpubkey_can_edit = account.unix_extn().is_some() @@ -658,7 +658,7 @@ impl<'a> IdmServerProxyWriteTransaction<'a> { .get_accesscontrols() .effective_permission_check( ident, - Some(btreeset![Attribute::SyncCredentialPortal.into()]), + Some(btreeset![Attribute::SyncCredentialPortal]), &[entry], )?; @@ -670,7 +670,7 @@ impl<'a> IdmServerProxyWriteTransaction<'a> { match &eperm.search { Access::Denied => false, Access::Grant => true, - Access::Allow(attrs) => attrs.contains(Attribute::SyncCredentialPortal.as_ref()), + Access::Allow(attrs) => attrs.contains(&Attribute::SyncCredentialPortal), } } else { false @@ -940,7 +940,7 @@ impl<'a> IdmServerProxyWriteTransaction<'a> { if ct >= max_ttl { modlist.push_mod(Modify::Removed( - Attribute::CredentialUpdateIntentToken.into(), + Attribute::CredentialUpdateIntentToken, PartialValue::IntentToken(existing_intent_id.clone()), )); } @@ -1113,11 +1113,11 @@ impl<'a> IdmServerProxyWriteTransaction<'a> { let mut modlist = ModifyList::new(); modlist.push_mod(Modify::Removed( - Attribute::CredentialUpdateIntentToken.into(), + Attribute::CredentialUpdateIntentToken, PartialValue::IntentToken(intent_id.clone()), )); modlist.push_mod(Modify::Present( - Attribute::CredentialUpdateIntentToken.into(), + Attribute::CredentialUpdateIntentToken, Value::IntentToken( intent_id.clone(), IntentTokenState::InProgress { @@ -1309,11 +1309,11 @@ impl<'a> IdmServerProxyWriteTransaction<'a> { }; modlist.push_mod(Modify::Removed( - Attribute::CredentialUpdateIntentToken.into(), + Attribute::CredentialUpdateIntentToken, PartialValue::IntentToken(intent_token_id.clone()), )); modlist.push_mod(Modify::Present( - Attribute::CredentialUpdateIntentToken.into(), + Attribute::CredentialUpdateIntentToken, Value::IntentToken( intent_token_id.clone(), IntentTokenState::Consumed { max_ttl }, @@ -1323,37 +1323,37 @@ impl<'a> IdmServerProxyWriteTransaction<'a> { match session.primary_state { CredentialState::Modifiable => { - modlist.push_mod(Modify::Purged(Attribute::PrimaryCredential.into())); + modlist.push_mod(Modify::Purged(Attribute::PrimaryCredential)); if let Some(ncred) = &session.primary { let vcred = Value::new_credential("primary", ncred.clone()); - modlist.push_mod(Modify::Present(Attribute::PrimaryCredential.into(), vcred)); + modlist.push_mod(Modify::Present(Attribute::PrimaryCredential, vcred)); }; } CredentialState::DeleteOnly | CredentialState::PolicyDeny => { - modlist.push_mod(Modify::Purged(Attribute::PrimaryCredential.into())); + modlist.push_mod(Modify::Purged(Attribute::PrimaryCredential)); } CredentialState::AccessDeny => {} }; match session.passkeys_state { CredentialState::DeleteOnly | CredentialState::Modifiable => { - modlist.push_mod(Modify::Purged(Attribute::PassKeys.into())); + modlist.push_mod(Modify::Purged(Attribute::PassKeys)); // Add all the passkeys. If none, nothing will be added! This handles // the delete case quite cleanly :) session.passkeys.iter().for_each(|(uuid, (tag, pk))| { let v_pk = Value::Passkey(*uuid, tag.clone(), pk.clone()); - modlist.push_mod(Modify::Present(Attribute::PassKeys.into(), v_pk)); + modlist.push_mod(Modify::Present(Attribute::PassKeys, v_pk)); }); } CredentialState::PolicyDeny => { - modlist.push_mod(Modify::Purged(Attribute::PassKeys.into())); + modlist.push_mod(Modify::Purged(Attribute::PassKeys)); } CredentialState::AccessDeny => {} }; match session.attested_passkeys_state { CredentialState::DeleteOnly | CredentialState::Modifiable => { - modlist.push_mod(Modify::Purged(Attribute::AttestedPasskeys.into())); + modlist.push_mod(Modify::Purged(Attribute::AttestedPasskeys)); // Add all the passkeys. If none, nothing will be added! This handles // the delete case quite cleanly :) session @@ -1361,29 +1361,29 @@ impl<'a> IdmServerProxyWriteTransaction<'a> { .iter() .for_each(|(uuid, (tag, pk))| { let v_pk = Value::AttestedPasskey(*uuid, tag.clone(), pk.clone()); - modlist.push_mod(Modify::Present(Attribute::AttestedPasskeys.into(), v_pk)); + modlist.push_mod(Modify::Present(Attribute::AttestedPasskeys, v_pk)); }); } CredentialState::PolicyDeny => { - modlist.push_mod(Modify::Purged(Attribute::AttestedPasskeys.into())); + modlist.push_mod(Modify::Purged(Attribute::AttestedPasskeys)); } // CredentialState::Disabled | CredentialState::AccessDeny => {} }; if session.unixcred_can_edit { - modlist.push_mod(Modify::Purged(Attribute::UnixPassword.into())); + modlist.push_mod(Modify::Purged(Attribute::UnixPassword)); if let Some(ncred) = &session.unixcred { let vcred = Value::new_credential("unix", ncred.clone()); - modlist.push_mod(Modify::Present(Attribute::UnixPassword.into(), vcred)); + modlist.push_mod(Modify::Present(Attribute::UnixPassword, vcred)); } } if session.sshpubkey_can_edit { - modlist.push_mod(Modify::Purged(Attribute::SshPublicKey.into())); + modlist.push_mod(Modify::Purged(Attribute::SshPublicKey)); for (tag, pk) in &session.sshkeys { let v_sk = Value::SshKey(tag.clone(), pk.clone()); - modlist.push_mod(Modify::Present(Attribute::SshPublicKey.into(), v_sk)); + modlist.push_mod(Modify::Present(Attribute::SshPublicKey, v_sk)); } } @@ -1452,11 +1452,11 @@ impl<'a> IdmServerProxyWriteTransaction<'a> { }; modlist.push_mod(Modify::Removed( - Attribute::CredentialUpdateIntentToken.into(), + Attribute::CredentialUpdateIntentToken, PartialValue::IntentToken(intent_token_id.clone()), )); modlist.push_mod(Modify::Present( - Attribute::CredentialUpdateIntentToken.into(), + Attribute::CredentialUpdateIntentToken, Value::IntentToken( intent_token_id.clone(), IntentTokenState::Valid { max_ttl, perms }, diff --git a/server/lib/src/idm/ldap.rs b/server/lib/src/idm/ldap.rs index 35b6a7789..4f572f7cc 100644 --- a/server/lib/src/idm/ldap.rs +++ b/server/lib/src/idm/ldap.rs @@ -311,7 +311,7 @@ impl LdapServer { // NOTE: All req_attrs are lowercase at this point. let mapped_attrs: BTreeSet<_> = req_attrs .iter() - .map(|a| AttrString::from(ldap_vattr_map(a).unwrap_or(a))) + .map(|a| Attribute::from(ldap_vattr_map(a).unwrap_or(a))) .collect(); (Some(mapped_attrs), req_attrs) @@ -833,9 +833,9 @@ pub(crate) fn ldap_vattr_map(input: &str) -> Option<&str> { } #[inline] -pub(crate) fn ldap_attr_filter_map(input: &str) -> AttrString { +pub(crate) fn ldap_attr_filter_map(input: &str) -> Attribute { let a_lower = input.to_lowercase(); - AttrString::from(ldap_vattr_map(&a_lower).unwrap_or(a_lower.as_str())) + Attribute::from(ldap_vattr_map(&a_lower).unwrap_or(a_lower.as_str())) } #[cfg(test)] @@ -866,8 +866,8 @@ mod tests { let me_posix = ModifyEvent::new_internal_invalid( filter!(f_eq(Attribute::Name, PartialValue::new_iname("admin"))), ModifyList::new_list(vec![ - Modify::Present(Attribute::Class.into(), EntryClass::PosixAccount.into()), - Modify::Present(Attribute::GidNumber.into(), Value::new_uint32(2001)), + Modify::Present(Attribute::Class, EntryClass::PosixAccount.into()), + Modify::Present(Attribute::GidNumber, Value::new_uint32(2001)), ]), ); assert!(idms_prox_write.qs_write.modify(&me_posix).is_ok()); @@ -1507,8 +1507,8 @@ mod tests { let me = ModifyEvent::new_internal_invalid( filter!(f_eq(Attribute::Uuid, PartialValue::Uuid(acct))), ModifyList::new_list(vec![ - Modify::Present(Attribute::AccountExpire.into(), v_expire), - Modify::Present(Attribute::AccountValidFrom.into(), v_valid_from), + Modify::Present(Attribute::AccountExpire, v_expire), + Modify::Present(Attribute::AccountValidFrom, v_valid_from), ]), ); assert!(idms_write.qs_write.modify(&me).is_ok()); @@ -1896,7 +1896,7 @@ mod tests { PartialValue::new_iname(BUILTIN_GROUP_PEOPLE_PII_READ.name) )), ModifyList::new_list(vec![Modify::Present( - Attribute::Member.into(), + Attribute::Member, Value::Refer(sa_uuid), )]), ); @@ -1984,12 +1984,9 @@ mod tests { assert_entry_contains!( lsre, "spn=testperson1@example.com,dc=example,dc=com", - (Attribute::Name.as_ref(), "testperson1"), - (Attribute::Mail.as_ref(), "testperson1@example.com"), - ( - Attribute::Mail.as_ref(), - "testperson1.alternative@example.com" - ), + (Attribute::Name, "testperson1"), + (Attribute::Mail, "testperson1@example.com"), + (Attribute::Mail, "testperson1.alternative@example.com"), (LDAP_ATTR_MAIL_PRIMARY, "testperson1@example.com"), ( LDAP_ATTR_MAIL_ALTERNATIVE, @@ -2044,12 +2041,9 @@ mod tests { assert_entry_contains!( lsre, "spn=testperson1@example.com,dc=example,dc=com", - (Attribute::Name.as_ref(), "testperson1"), - (Attribute::Mail.as_ref(), "testperson1@example.com"), - ( - Attribute::Mail.as_ref(), - "testperson1.alternative@example.com" - ), + (Attribute::Name, "testperson1"), + (Attribute::Mail, "testperson1@example.com"), + (Attribute::Mail, "testperson1.alternative@example.com"), (LDAP_ATTR_MAIL_PRIMARY, "testperson1@example.com"), ( LDAP_ATTR_MAIL_ALTERNATIVE, @@ -2125,10 +2119,7 @@ mod tests { (Attribute::Name, "testperson1"), (Attribute::DisplayName, "testperson1"), (Attribute::Uuid, "cc8e95b4-c24f-4d68-ba54-8bed76f63930"), - ( - Attribute::EntryUuid.as_ref(), - "cc8e95b4-c24f-4d68-ba54-8bed76f63930" - ) + (Attribute::EntryUuid, "cc8e95b4-c24f-4d68-ba54-8bed76f63930") ); } _ => panic!("Oh no"), @@ -2218,10 +2209,7 @@ mod tests { assert_entry_contains!( lsre, "spn=testperson1@example.com,dc=example,dc=com", - ( - Attribute::EntryUuid.as_ref(), - "cc8e95b4-c24f-4d68-ba54-8bed76f63930" - ) + (Attribute::EntryUuid, "cc8e95b4-c24f-4d68-ba54-8bed76f63930") ); } _ => panic!("Oh no"), @@ -2426,10 +2414,7 @@ mod tests { (Attribute::Gecos, "testperson1"), (Attribute::UidNumber, "12345"), (Attribute::GidNumber, "12345"), - ( - Attribute::EntryUuid.as_ref(), - "cc8e95b4-c24f-4d68-ba54-8bed76f63930" - ) + (Attribute::EntryUuid, "cc8e95b4-c24f-4d68-ba54-8bed76f63930") ); } _ => panic!("Oh no"), diff --git a/server/lib/src/idm/oauth2.rs b/server/lib/src/idm/oauth2.rs index 4f30dd99c..8e205e7b5 100644 --- a/server/lib/src/idm/oauth2.rs +++ b/server/lib/src/idm/oauth2.rs @@ -588,7 +588,7 @@ impl<'a> Oauth2ResourceServersWriteTransaction<'a> { BTreeMap::default() }; - trace!("{}", Attribute::OAuth2JwtLegacyCryptoEnable.as_ref()); + trace!("{}", Attribute::OAuth2JwtLegacyCryptoEnable); let jws_signer = if ent.get_ava_single_bool(Attribute::OAuth2JwtLegacyCryptoEnable).unwrap_or(false) { trace!("{}", Attribute::Rs256PrivateKeyDer); ent @@ -819,7 +819,7 @@ impl<'a> IdmServerProxyWriteTransaction<'a> { // and when replication converges the session is actually removed. let modlist = ModifyList::new_list(vec![Modify::Removed( - Attribute::OAuth2Session.into(), + Attribute::OAuth2Session, PartialValue::Refer(session_id), )]); @@ -1005,11 +1005,11 @@ impl<'a> IdmServerProxyWriteTransaction<'a> { let modlist = ModifyList::new_list(vec![ Modify::Removed( - Attribute::OAuth2ConsentScopeMap.into(), + Attribute::OAuth2ConsentScopeMap, PartialValue::Refer(o2rs.uuid), ), Modify::Present( - Attribute::OAuth2ConsentScopeMap.into(), + Attribute::OAuth2ConsentScopeMap, Value::OauthScopeMap(o2rs.uuid, consent_req.scopes.iter().cloned().collect()), ), ]); @@ -1219,7 +1219,7 @@ impl<'a> IdmServerProxyWriteTransaction<'a> { // Revoke it let modlist = ModifyList::new_list(vec![Modify::Removed( - Attribute::OAuth2Session.into(), + Attribute::OAuth2Session, PartialValue::Refer(session_id), )]); @@ -1352,10 +1352,8 @@ impl<'a> IdmServerProxyWriteTransaction<'a> { ); // We need to create this session on the o2rs - let modlist = ModifyList::new_list(vec![Modify::Present( - Attribute::OAuth2Session.into(), - session, - )]); + let modlist = + ModifyList::new_list(vec![Modify::Present(Attribute::OAuth2Session, session)]); self.qs_write .internal_modify( @@ -1562,7 +1560,7 @@ impl<'a> IdmServerProxyWriteTransaction<'a> { // NOTE: Oauth2_session has special handling that allows update in place without // the remove step needing to be carried out. // Modify::Removed("oauth2_session".into(), PartialValue::Refer(session_id)), - Modify::Present(Attribute::OAuth2Session.into(), session), + Modify::Present(Attribute::OAuth2Session, session), ]); self.qs_write @@ -2900,9 +2898,9 @@ mod tests { // Mod the user let modlist = ModifyList::new_list(vec![ - Modify::Present(Attribute::UserAuthTokenSession.into(), session), + Modify::Present(Attribute::UserAuthTokenSession, session), Modify::Present( - Attribute::PrimaryCredential.into(), + Attribute::PrimaryCredential, Value::Cred("primary".to_string(), cred), ), ]); @@ -3033,9 +3031,9 @@ mod tests { // Mod the user let modlist = ModifyList::new_list(vec![ - Modify::Present(Attribute::UserAuthTokenSession.into(), session), + Modify::Present(Attribute::UserAuthTokenSession, session), Modify::Present( - Attribute::PrimaryCredential.into(), + Attribute::PrimaryCredential, Value::Cred("primary".to_string(), cred), ), ]); @@ -3222,7 +3220,7 @@ mod tests { let (_code_verifier, code_challenge) = create_code_verifier!("Whar Garble"); let pkce_request = Some(PkceRequest { - code_challenge: code_challenge.into(), + code_challenge: code_challenge, code_challenge_method: CodeChallengeMethod::S256, }); @@ -3662,7 +3660,7 @@ mod tests { client_id: "test_resource_server".to_string(), state: "123".to_string(), pkce_request: Some(PkceRequest { - code_challenge: code_challenge.clone().into(), + code_challenge: code_challenge.clone(), code_challenge_method: CodeChallengeMethod::S256, }), redirect_uri: Url::parse("https://portal.example.com").unwrap(), @@ -3731,7 +3729,7 @@ mod tests { client_id: "test_resource_server".to_string(), state: "123".to_string(), pkce_request: Some(PkceRequest { - code_challenge: code_challenge.into(), + code_challenge: code_challenge, code_challenge_method: CodeChallengeMethod::S256, }), redirect_uri: Url::parse("app://cheese").unwrap(), @@ -3859,10 +3857,7 @@ mod tests { let v_expire = Value::new_datetime_epoch(Duration::from_secs(TEST_CURRENT_TIME - 1)); let me_inv_m = ModifyEvent::new_internal_invalid( filter!(f_eq(Attribute::Uuid, PartialValue::Uuid(UUID_TESTPERSON_1))), - ModifyList::new_list(vec![Modify::Present( - Attribute::AccountExpire.into(), - v_expire, - )]), + ModifyList::new_list(vec![Modify::Present(Attribute::AccountExpire, v_expire)]), ); // go! assert!(idms_prox_write.qs_write.modify(&me_inv_m).is_ok()); @@ -5061,7 +5056,7 @@ mod tests { PartialValue::new_iname("test_resource_server") )), ModifyList::new_list(vec![Modify::Present( - AttrString::from(Attribute::OAuth2RsScopeMap.as_ref()), + Attribute::OAuth2RsScopeMap, Value::new_oauthscopemap( UUID_IDM_ALL_ACCOUNTS, btreeset![ @@ -5092,7 +5087,7 @@ mod tests { client_id: "test_resource_server".to_string(), state: "123".to_string(), pkce_request: Some(PkceRequest { - code_challenge: code_challenge.into(), + code_challenge: code_challenge, code_challenge_method: CodeChallengeMethod::S256, }), redirect_uri: Url::parse("https://demo.example.com/oauth2/result").unwrap(), @@ -5124,7 +5119,7 @@ mod tests { PartialValue::new_iname("test_resource_server") )), ModifyList::new_list(vec![Modify::Present( - Attribute::OAuth2RsSupScopeMap.into(), + Attribute::OAuth2RsSupScopeMap, Value::new_oauthscopemap(UUID_IDM_ALL_ACCOUNTS, btreeset!["newscope".to_string()]) .expect("invalid oauthscope"), )]), @@ -5149,7 +5144,7 @@ mod tests { client_id: "test_resource_server".to_string(), state: "123".to_string(), pkce_request: Some(PkceRequest { - code_challenge: code_challenge.into(), + code_challenge: code_challenge, code_challenge_method: CodeChallengeMethod::S256, }), redirect_uri: Url::parse("https://demo.example.com/oauth2/result").unwrap(), @@ -5364,7 +5359,7 @@ mod tests { client_id: "test_resource_server".to_string(), state: "123".to_string(), pkce_request: Some(PkceRequest { - code_challenge: code_challenge.clone().into(), + code_challenge: code_challenge.clone(), code_challenge_method: CodeChallengeMethod::S256, }), redirect_uri: Url::parse("http://demo.example.com/oauth2/result").unwrap(), @@ -6057,14 +6052,14 @@ mod tests { let modlist = ModifyList::new_list(vec![ // Member of a claim map. Modify::Present( - Attribute::OAuth2RsClaimMap.into(), + Attribute::OAuth2RsClaimMap, Value::OauthClaimMap( "custom_a".to_string(), OauthClaimMapJoin::CommaSeparatedValue, ), ), Modify::Present( - Attribute::OAuth2RsClaimMap.into(), + Attribute::OAuth2RsClaimMap, Value::OauthClaimValue( "custom_a".to_string(), UUID_TESTGROUP, @@ -6073,7 +6068,7 @@ mod tests { ), // If you are a member of two groups, the claim maps merge. Modify::Present( - Attribute::OAuth2RsClaimMap.into(), + Attribute::OAuth2RsClaimMap, Value::OauthClaimValue( "custom_a".to_string(), UUID_IDM_ALL_ACCOUNTS, @@ -6082,14 +6077,14 @@ mod tests { ), // Map with a different seperator Modify::Present( - Attribute::OAuth2RsClaimMap.into(), + Attribute::OAuth2RsClaimMap, Value::OauthClaimMap( "custom_b".to_string(), OauthClaimMapJoin::SpaceSeparatedValue, ), ), Modify::Present( - Attribute::OAuth2RsClaimMap.into(), + Attribute::OAuth2RsClaimMap, Value::OauthClaimValue( "custom_b".to_string(), UUID_TESTGROUP, @@ -6097,7 +6092,7 @@ mod tests { ), ), Modify::Present( - Attribute::OAuth2RsClaimMap.into(), + Attribute::OAuth2RsClaimMap, Value::OauthClaimValue( "custom_b".to_string(), UUID_IDM_ALL_ACCOUNTS, @@ -6106,7 +6101,7 @@ mod tests { ), // Not a member of the claim map. Modify::Present( - Attribute::OAuth2RsClaimMap.into(), + Attribute::OAuth2RsClaimMap, Value::OauthClaimValue( "custom_b".to_string(), UUID_IDM_ADMINS, @@ -6296,7 +6291,7 @@ mod tests { let mut idms_prox_write = idms.proxy_write(ct).await.unwrap(); let modlist = ModifyList::new_list(vec![Modify::Present( - Attribute::OAuth2AllowLocalhostRedirect.into(), + Attribute::OAuth2AllowLocalhostRedirect, Value::Bool(true), )]); @@ -6320,7 +6315,7 @@ mod tests { client_id: "test_resource_server".to_string(), state: "123".to_string(), pkce_request: Some(PkceRequest { - code_challenge: code_challenge.into(), + code_challenge: code_challenge, code_challenge_method: CodeChallengeMethod::S256, }), redirect_uri: Url::parse("http://localhost:8765/oauth2/result").unwrap(), diff --git a/server/lib/src/idm/scim.rs b/server/lib/src/idm/scim.rs index 1e0a889d9..8466069a8 100644 --- a/server/lib/src/idm/scim.rs +++ b/server/lib/src/idm/scim.rs @@ -167,10 +167,8 @@ impl<'a> IdmServerProxyWriteTransaction<'a> { OperationError::SerdeJsonError })?; - let modlist = ModifyList::new_list(vec![Modify::Present( - Attribute::SyncTokenSession.into(), - session, - )]); + let modlist = + ModifyList::new_list(vec![Modify::Present(Attribute::SyncTokenSession, session)]); self.qs_write .impersonate_modify( @@ -216,8 +214,7 @@ impl<'a> IdmServerProxyWriteTransaction<'a> { target: Uuid, _ct: Duration, ) -> Result<(), OperationError> { - let modlist = - ModifyList::new_list(vec![Modify::Purged(Attribute::SyncTokenSession.into())]); + let modlist = ModifyList::new_list(vec![Modify::Purged(Attribute::SyncTokenSession)]); self.qs_write .impersonate_modify( @@ -339,7 +336,7 @@ impl<'a> IdmServerProxyWriteTransaction<'a> { })?; let modlist = std::iter::once(Modify::Removed( - Attribute::Class.into(), + Attribute::Class, EntryClass::SyncObject.into(), )) .chain( @@ -438,9 +435,8 @@ impl<'a> IdmServerProxyWriteTransaction<'a> { let existing_entries = self .qs_write .internal_search(f_all_sync.clone()) - .map_err(|e| { - error!("Failed to determine existing entries set"); - e + .inspect_err(|err| { + error!(?err, "Failed to determine existing entries set"); })?; let delete_filter = if existing_entries.is_empty() { @@ -467,7 +463,7 @@ impl<'a> IdmServerProxyWriteTransaction<'a> { })?; let modlist = std::iter::once(Modify::Removed( - Attribute::Class.into(), + Attribute::Class, EntryClass::SyncObject.into(), )) .chain( @@ -481,9 +477,11 @@ impl<'a> IdmServerProxyWriteTransaction<'a> { self.qs_write .internal_modify(&f_all_sync, &mods) - .map_err(|e| { - error!("Failed to modify sync objects to grant authority to kanidm"); - e + .inspect_err(|err| { + error!( + ?err, + "Failed to modify sync objects to grant authority to Kanidm" + ); })?; filter!(f_or!([ @@ -570,10 +568,15 @@ impl<'a> IdmServerProxyWriteTransaction<'a> { }; // Retrieve the related sync entry. - let sync_entry = self.qs_write.internal_search_uuid(sync_uuid).map_err(|e| { - error!("Failed to located sync entry related to {}", sync_uuid); - e - })?; + let sync_entry = self + .qs_write + .internal_search_uuid(sync_uuid) + .inspect_err(|err| { + error!( + ?err, + "Failed to located sync entry related to {}", sync_uuid + ); + })?; // Assert that the requested "from" state is consistent to this entry. // OperationError::InvalidSyncState @@ -649,9 +652,8 @@ impl<'a> IdmServerProxyWriteTransaction<'a> { let existing_entries = self .qs_write .internal_search(filter_all!(f_or(filter_or))) - .map_err(|e| { - error!("Failed to determine existing entries set"); - e + .inspect_err(|err| { + error!(?err, "Failed to determine existing entries set"); })?; // Refuse to proceed if any entries are in the recycled or tombstone state, since subsequent @@ -703,10 +705,11 @@ impl<'a> IdmServerProxyWriteTransaction<'a> { // We know that uuid won't conflict because it didn't exist in the previous search, so if we error // it has to be something bad. if !create_stubs.is_empty() { - self.qs_write.internal_create(create_stubs).map_err(|e| { - error!("Unable to create stub entries"); - e - })?; + self.qs_write + .internal_create(create_stubs) + .inspect_err(|err| { + error!(?err, "Unable to create stub entries"); + })?; } // We have to search again now, this way we can do the internal mod process for @@ -727,18 +730,14 @@ impl<'a> IdmServerProxyWriteTransaction<'a> { Attribute::SyncParentUuid, PartialValue::Refer(sync_uuid), ), - Modify::Purged(Attribute::SyncExternalId.into()), - Modify::Present( - Attribute::SyncExternalId.into(), - Value::new_iutf8(ext_id), - ), + Modify::Purged(Attribute::SyncExternalId), + Modify::Present(Attribute::SyncExternalId, Value::new_iutf8(ext_id)), ]), ) }) })) - .map_err(|e| { - error!("Unable to setup external ids from sync entries"); - e + .inspect_err(|err| { + error!(?err, "Unable to setup external ids from sync entries"); })?; // Ready to go. @@ -805,7 +804,7 @@ impl<'a> IdmServerProxyWriteTransaction<'a> { fn scim_attr_to_values( &mut self, - scim_attr_name: &str, + scim_attr_name: &Attribute, scim_attr: &ScimValue, ) -> Result, OperationError> { let schema = self.qs_write.get_schema(); @@ -1154,11 +1153,11 @@ impl<'a> IdmServerProxyWriteTransaction<'a> { for req_class in requested_classes.keys() { mods.push(Modify::Present( - Attribute::SyncClass.into(), + Attribute::SyncClass, Value::new_iutf8(req_class), )); mods.push(Modify::Present( - Attribute::Class.into(), + Attribute::Class, Value::new_iutf8(req_class), )); } @@ -1220,21 +1219,23 @@ impl<'a> IdmServerProxyWriteTransaction<'a> { return Err(OperationError::InvalidEntryState); } + // Make it a native attribute name. + let scim_attr_name = Attribute::from(scim_attr_name.as_str()); + // Convert each scim_attr to a set of values. let values = self - .scim_attr_to_values(scim_attr_name, scim_attr) - .map_err(|e| { + .scim_attr_to_values(&scim_attr_name, scim_attr) + .inspect_err(|err| { error!( - "Failed to convert {} for entry {}", - scim_attr_name, scim_ent.id + ?err, + "Failed to convert {} for entry {}", scim_attr_name, scim_ent.id ); - e })?; mods.extend( values .into_iter() - .map(|val| Modify::Present(scim_attr_name.into(), val)), + .map(|val| Modify::Present(scim_attr_name.clone(), val)), ); } @@ -1324,9 +1325,8 @@ impl<'a> IdmServerProxyWriteTransaction<'a> { self.qs_write .internal_batch_modify(asserts.into_iter()) - .map_err(|e| { - error!("Unable to apply modifications to sync entries."); - e + .inspect_err(|err| { + error!(?err, "Unable to apply modifications to sync entries."); }) } @@ -1380,9 +1380,8 @@ impl<'a> IdmServerProxyWriteTransaction<'a> { let delete_cands = self .qs_write .internal_search(filter_all!(f_or(filter_or))) - .map_err(|e| { - error!("Failed to determine existing entries set"); - e + .inspect_err(|err| { + error!(?err, "Failed to determine existing entries set"); })?; let delete_filter = delete_cands @@ -1456,9 +1455,8 @@ impl<'a> IdmServerProxyWriteTransaction<'a> { self.qs_write .internal_modify_uuid(sync_uuid, &modlist) - .map_err(|e| { - error!("Failed to update sync entry state"); - e + .inspect_err(|err| { + error!(?err, "Failed to update sync entry state"); }) } } @@ -1639,7 +1637,7 @@ mod tests { Attribute::Name, PartialValue::new_iname("test_scim_sync") )), - ModifyList::new_list(vec![Modify::Purged(Attribute::SyncTokenSession.into())]), + ModifyList::new_list(vec![Modify::Purged(Attribute::SyncTokenSession)]), ); assert!(idms_prox_write.qs_write.modify(&me_inv_m).is_ok()); assert!(idms_prox_write.commit().is_ok()); @@ -1762,7 +1760,7 @@ mod tests { let changes = ScimSyncRequest { from_state: ScimSyncState::Active { - cookie: vec![1, 2, 3, 4].into(), + cookie: vec![1, 2, 3, 4], }, to_state: ScimSyncState::Refresh, entries: Vec::with_capacity(0), @@ -1791,7 +1789,7 @@ mod tests { let changes = ScimSyncRequest { from_state: ScimSyncState::Refresh, to_state: ScimSyncState::Active { - cookie: vec![1, 2, 3, 4].into(), + cookie: vec![1, 2, 3, 4], }, entries: vec![ScimEntry { schemas: vec![SCIM_SCHEMA_SYNC_PERSON.to_string()], @@ -1859,7 +1857,7 @@ mod tests { let changes = ScimSyncRequest { from_state: ScimSyncState::Refresh, to_state: ScimSyncState::Active { - cookie: vec![1, 2, 3, 4].into(), + cookie: vec![1, 2, 3, 4], }, entries: vec![ScimEntry { schemas: vec![SCIM_SCHEMA_SYNC_PERSON.to_string()], @@ -1899,7 +1897,7 @@ mod tests { let changes = ScimSyncRequest { from_state: ScimSyncState::Refresh, to_state: ScimSyncState::Active { - cookie: vec![1, 2, 3, 4].into(), + cookie: vec![1, 2, 3, 4], }, entries, retain: ScimSyncRetentionMode::Ignore, @@ -2102,7 +2100,7 @@ mod tests { let changes = ScimSyncRequest { from_state: ScimSyncState::Refresh, to_state: ScimSyncState::Active { - cookie: vec![1, 2, 3, 4].into(), + cookie: vec![1, 2, 3, 4], }, entries: vec![ScimEntry { schemas: vec![SCIM_SCHEMA_SYNC_GROUP.to_string()], @@ -2126,10 +2124,10 @@ mod tests { let changes = ScimSyncRequest { from_state: ScimSyncState::Active { - cookie: vec![1, 2, 3, 4].into(), + cookie: vec![1, 2, 3, 4], }, to_state: ScimSyncState::Active { - cookie: vec![2, 3, 4, 5].into(), + cookie: vec![2, 3, 4, 5], }, entries: vec![], retain: ScimSyncRetentionMode::Delete(vec![user_sync_uuid]), @@ -2169,7 +2167,7 @@ mod tests { let changes = ScimSyncRequest { from_state: ScimSyncState::Refresh, to_state: ScimSyncState::Active { - cookie: vec![1, 2, 3, 4].into(), + cookie: vec![1, 2, 3, 4], }, // Doesn't exist. If it does, then bless rng. entries: Vec::with_capacity(0), @@ -2208,7 +2206,7 @@ mod tests { let changes = ScimSyncRequest { from_state: ScimSyncState::Refresh, to_state: ScimSyncState::Active { - cookie: vec![1, 2, 3, 4].into(), + cookie: vec![1, 2, 3, 4], }, // Doesn't exist. If it does, then bless rng. entries: Vec::with_capacity(0), @@ -2250,7 +2248,7 @@ mod tests { let changes = ScimSyncRequest { from_state: ScimSyncState::Refresh, to_state: ScimSyncState::Active { - cookie: vec![1, 2, 3, 4].into(), + cookie: vec![1, 2, 3, 4], }, // Doesn't exist. If it does, then bless rng. entries: Vec::with_capacity(0), @@ -2285,7 +2283,7 @@ mod tests { let changes = ScimSyncRequest { from_state: ScimSyncState::Refresh, to_state: ScimSyncState::Active { - cookie: vec![1, 2, 3, 4].into(), + cookie: vec![1, 2, 3, 4], }, entries: vec![ ScimEntry { @@ -2321,10 +2319,10 @@ mod tests { let changes = ScimSyncRequest { from_state: ScimSyncState::Active { - cookie: vec![1, 2, 3, 4].into(), + cookie: vec![1, 2, 3, 4], }, to_state: ScimSyncState::Active { - cookie: vec![2, 3, 4, 5].into(), + cookie: vec![2, 3, 4, 5], }, entries: vec![], retain: ScimSyncRetentionMode::Retain(vec![sync_uuid_a]), @@ -2369,7 +2367,7 @@ mod tests { let changes = ScimSyncRequest { from_state: ScimSyncState::Refresh, to_state: ScimSyncState::Active { - cookie: vec![1, 2, 3, 4].into(), + cookie: vec![1, 2, 3, 4], }, entries: vec![ ScimEntry { @@ -2405,10 +2403,10 @@ mod tests { let changes = ScimSyncRequest { from_state: ScimSyncState::Active { - cookie: vec![1, 2, 3, 4].into(), + cookie: vec![1, 2, 3, 4], }, to_state: ScimSyncState::Active { - cookie: vec![2, 3, 4, 5].into(), + cookie: vec![2, 3, 4, 5], }, entries: vec![], retain: ScimSyncRetentionMode::Retain(vec![]), @@ -2467,7 +2465,7 @@ mod tests { let changes = ScimSyncRequest { from_state: ScimSyncState::Refresh, to_state: ScimSyncState::Active { - cookie: vec![1, 2, 3, 4].into(), + cookie: vec![1, 2, 3, 4], }, entries: vec![ScimEntry { schemas: vec![SCIM_SCHEMA_SYNC_GROUP.to_string()], @@ -2491,10 +2489,10 @@ mod tests { let changes = ScimSyncRequest { from_state: ScimSyncState::Active { - cookie: vec![1, 2, 3, 4].into(), + cookie: vec![1, 2, 3, 4], }, to_state: ScimSyncState::Active { - cookie: vec![2, 3, 4, 5].into(), + cookie: vec![2, 3, 4, 5], }, entries: vec![], retain: ScimSyncRetentionMode::Retain(vec![sync_uuid_a]), @@ -2529,7 +2527,7 @@ mod tests { let changes = ScimSyncRequest { from_state: ScimSyncState::Refresh, to_state: ScimSyncState::Active { - cookie: vec![1, 2, 3, 4].into(), + cookie: vec![1, 2, 3, 4], }, entries: Vec::with_capacity(0), retain: ScimSyncRetentionMode::Ignore, @@ -2544,10 +2542,10 @@ mod tests { let changes = ScimSyncRequest { from_state: ScimSyncState::Active { - cookie: vec![1, 2, 3, 4].into(), + cookie: vec![1, 2, 3, 4], }, to_state: ScimSyncState::Active { - cookie: vec![2, 3, 4, 5].into(), + cookie: vec![2, 3, 4, 5], }, entries: vec![], retain: ScimSyncRetentionMode::Ignore, diff --git a/server/lib/src/idm/server.rs b/server/lib/src/idm/server.rs index 1c246ca1a..7f9855564 100644 --- a/server/lib/src/idm/server.rs +++ b/server/lib/src/idm/server.rs @@ -1252,16 +1252,15 @@ impl<'a> IdmServerAuthTransaction<'a> { self.webauthn, self.qs_read.pw_badlist(), ) - .map(|aus| { + .inspect(|aus| { // Inspect the result: // if it was a failure, we need to inc the softlock. - if let AuthState::Denied(_) = &aus { + if let AuthState::Denied(_) = aus { // Update it. if let Some(ref mut slock) = maybe_slock { slock.record_failure(ct); } }; - aus }) } else { // Fail the session @@ -1341,12 +1340,11 @@ impl<'a> IdmServerAuthTransaction<'a> { // Account is unlocked, can proceed. account .verify_unix_credential(uae.cleartext.as_str(), &self.async_tx, ct) - .map(|res| { + .inspect(|res| { if res.is_none() { // Update it. slock.record_failure(ct); }; - res }) } else { // Account is slocked! @@ -1671,9 +1669,8 @@ impl<'a> IdmServerProxyWriteTransaction<'a> { .as_ref() .ok_or(OperationError::InvalidState) .cloned() - .map_err(|e| { - security_info!("zxcvbn returned no feedback when score < 3"); - e + .inspect_err(|err| { + security_info!(?err, "zxcvbn returned no feedback when score < 3"); })?; security_info!(?feedback, "pw quality feedback"); @@ -1881,7 +1878,7 @@ impl<'a> IdmServerProxyWriteTransaction<'a> { let modlist = ModifyList::new_list(vec![ m_purge(Attribute::PassKeys), m_purge(Attribute::PrimaryCredential), - Modify::Present(Attribute::PrimaryCredential.into(), vcred), + Modify::Present(Attribute::PrimaryCredential, vcred), ]); trace!(?modlist, "processing change"); @@ -2386,10 +2383,7 @@ mod tests { // now modify and provide a primary credential. let me_inv_m = ModifyEvent::new_internal_invalid( filter!(f_eq(Attribute::Uuid, PartialValue::Uuid(UUID_TESTPERSON_1))), - ModifyList::new_list(vec![Modify::Present( - Attribute::PrimaryCredential.into(), - v_cred, - )]), + ModifyList::new_list(vec![Modify::Present(Attribute::PrimaryCredential, v_cred)]), ); // go! assert!(idms_write.qs_write.modify(&me_inv_m).is_ok()); @@ -2684,8 +2678,8 @@ mod tests { let me_posix = ModifyEvent::new_internal_invalid( filter!(f_eq(Attribute::Name, PartialValue::new_iname("admin"))), ModifyList::new_list(vec![ - Modify::Present(Attribute::Class.into(), EntryClass::PosixAccount.into()), - Modify::Present(Attribute::GidNumber.into(), Value::new_uint32(2001)), + Modify::Present(Attribute::Class, EntryClass::PosixAccount.into()), + Modify::Present(Attribute::GidNumber, Value::new_uint32(2001)), ]), ); assert!(idms_prox_write.qs_write.modify(&me_posix).is_ok()); @@ -2766,8 +2760,8 @@ mod tests { let me_posix = ModifyEvent::new_internal_invalid( filter!(f_eq(Attribute::Name, PartialValue::new_iname("admin"))), ModifyList::new_list(vec![ - Modify::Present(Attribute::Class.into(), EntryClass::PosixAccount.into()), - Modify::Present(Attribute::GidNumber.into(), Value::new_uint32(2001)), + Modify::Present(Attribute::Class, EntryClass::PosixAccount.into()), + Modify::Present(Attribute::GidNumber, Value::new_uint32(2001)), ]), ); assert!(idms_prox_write.qs_write.modify(&me_posix).is_ok()); @@ -2803,7 +2797,7 @@ mod tests { let mut idms_prox_write = idms.proxy_write(duration_from_epoch_now()).await.unwrap(); let me_purge_up = ModifyEvent::new_internal_invalid( filter!(f_eq(Attribute::Name, PartialValue::new_iname("admin"))), - ModifyList::new_list(vec![Modify::Purged(Attribute::UnixPassword.into())]), + ModifyList::new_list(vec![Modify::Purged(Attribute::UnixPassword)]), ); assert!(idms_prox_write.qs_write.modify(&me_purge_up).is_ok()); assert!(idms_prox_write.commit().is_ok()); @@ -2843,7 +2837,7 @@ mod tests { ModifyEvent::new_internal_invalid( filter!(f_eq(Attribute::Uuid, PartialValue::Uuid(UUID_TESTPERSON_1))), ModifyList::new_list(vec![Modify::Present( - Attribute::PasswordImport.into(), + Attribute::PasswordImport, Value::from("{SSHA512}JwrSUHkI7FTAfHRVR6KoFlSN0E3dmaQWARjZ+/UsShYlENOqDtFVU77HJLLrY2MuSp0jve52+pwtdVl2QUAHukQ0XUf5LDtM") )]), ); @@ -2923,9 +2917,9 @@ mod tests { let me_posix = ModifyEvent::new_internal_invalid( filter!(f_eq(Attribute::Name, PartialValue::new_iname("admin"))), ModifyList::new_list(vec![ - Modify::Present(Attribute::Class.into(), EntryClass::PosixAccount.into()), - Modify::Present(Attribute::GidNumber.into(), Value::new_uint32(2001)), - Modify::Present(Attribute::UnixPassword.into(), v_cred), + Modify::Present(Attribute::Class, EntryClass::PosixAccount.into()), + Modify::Present(Attribute::GidNumber, Value::new_uint32(2001)), + Modify::Present(Attribute::UnixPassword, v_cred), ]), ); assert!(idms_prox_write.qs_write.modify(&me_posix).is_ok()); @@ -2978,8 +2972,8 @@ mod tests { let me_inv_m = ModifyEvent::new_internal_invalid( filter!(f_eq(Attribute::Uuid, PartialValue::Uuid(UUID_TESTPERSON_1))), ModifyList::new_list(vec![ - Modify::Present(Attribute::AccountExpire.into(), v_expire), - Modify::Present(Attribute::AccountValidFrom.into(), v_valid_from), + Modify::Present(Attribute::AccountExpire, v_expire), + Modify::Present(Attribute::AccountValidFrom, v_valid_from), ]), ); // go! @@ -3068,8 +3062,8 @@ mod tests { let me_posix = ModifyEvent::new_internal_invalid( filter!(f_eq(Attribute::Uuid, PartialValue::Uuid(UUID_TESTPERSON_1))), ModifyList::new_list(vec![ - Modify::Present(Attribute::Class.into(), EntryClass::PosixAccount.into()), - Modify::Present(Attribute::GidNumber.into(), Value::new_uint32(2001)), + Modify::Present(Attribute::Class, EntryClass::PosixAccount.into()), + Modify::Present(Attribute::GidNumber, Value::new_uint32(2001)), ]), ); assert!(idms_prox_write.qs_write.modify(&me_posix).is_ok()); @@ -3434,8 +3428,8 @@ mod tests { let me_posix = ModifyEvent::new_internal_invalid( filter!(f_eq(Attribute::Uuid, PartialValue::Uuid(UUID_TESTPERSON_1))), ModifyList::new_list(vec![ - Modify::Present(Attribute::Class.into(), EntryClass::PosixAccount.into()), - Modify::Present(Attribute::GidNumber.into(), Value::new_uint32(2001)), + Modify::Present(Attribute::Class, EntryClass::PosixAccount.into()), + Modify::Present(Attribute::GidNumber, Value::new_uint32(2001)), ]), ); assert!(idms_prox_write.qs_write.modify(&me_posix).is_ok()); diff --git a/server/lib/src/idm/serviceaccount.rs b/server/lib/src/idm/serviceaccount.rs index e6d1aac7b..c781e5c0e 100644 --- a/server/lib/src/idm/serviceaccount.rs +++ b/server/lib/src/idm/serviceaccount.rs @@ -235,10 +235,8 @@ impl<'a> IdmServerProxyWriteTransaction<'a> { })?; // modify the account to put the session onto it. - let modlist = ModifyList::new_list(vec![Modify::Present( - Attribute::ApiTokenSession.into(), - session, - )]); + let modlist = + ModifyList::new_list(vec![Modify::Present(Attribute::ApiTokenSession, session)]); self.qs_write .impersonate_modify( @@ -282,7 +280,7 @@ impl<'a> IdmServerProxyWriteTransaction<'a> { ) -> Result<(), OperationError> { // Delete the attribute with uuid. let modlist = ModifyList::new_list(vec![Modify::Removed( - Attribute::ApiTokenSession.into(), + Attribute::ApiTokenSession, PartialValue::Refer(dte.token_id), )]); @@ -331,7 +329,7 @@ impl<'a> IdmServerProxyWriteTransaction<'a> { let modlist = ModifyList::new_list(vec![ m_purge(Attribute::PassKeys), m_purge(Attribute::PrimaryCredential), - Modify::Present(Attribute::PrimaryCredential.into(), vcred), + Modify::Present(Attribute::PrimaryCredential, vcred), ]); trace!(?modlist, "processing change"); @@ -395,9 +393,8 @@ impl<'a> IdmServerProxyReadTransaction<'a> { issued_at: s.issued_at, purpose, }) - .map_err(|e| { - admin_error!("Invalid api_token {}", u); - e + .inspect_err(|err| { + admin_error!(?err, "Invalid api_token {}", u); }) }) .collect::, _>>() diff --git a/server/lib/src/modify.rs b/server/lib/src/modify.rs index e5c1f6594..9a8807bc1 100644 --- a/server/lib/src/modify.rs +++ b/server/lib/src/modify.rs @@ -10,7 +10,6 @@ use kanidm_proto::internal::{ use kanidm_proto::v1::Entry as ProtoEntry; // Should this be std? use serde::{Deserialize, Serialize}; -use smartstring::alias::String as AttrString; use crate::prelude::*; use crate::schema::SchemaTransaction; @@ -27,25 +26,25 @@ pub enum Modify { // This value *should* exist. // Clippy doesn't like value here, as value > pv. It could be an improvement to // box here, but not sure. ... TODO and thought needed. - Present(AttrString, Value), + Present(Attribute, Value), // This value *should not* exist. - Removed(AttrString, PartialValue), + Removed(Attribute, PartialValue), // This attr *should not* exist. - Purged(AttrString), + Purged(Attribute), // This attr and value must exist *in this state* for this change to proceed. Assert(Attribute, PartialValue), } pub fn m_pres(attr: Attribute, v: &Value) -> Modify { - Modify::Present(attr.into(), v.clone()) + Modify::Present(attr, v.clone()) } pub fn m_remove(attr: Attribute, v: &PartialValue) -> Modify { - Modify::Removed(attr.into(), v.clone()) + Modify::Removed(attr, v.clone()) } pub fn m_purge(attr: Attribute) -> Modify { - Modify::Purged(attr.into()) + Modify::Purged(attr) } pub fn m_assert(attr: Attribute, v: &PartialValue) -> Modify { @@ -58,9 +57,17 @@ impl Modify { qs: &mut QueryServerWriteTransaction, ) -> Result { Ok(match m { - ProtoModify::Present(a, v) => Modify::Present(a.into(), qs.clone_value(a, v)?), - ProtoModify::Removed(a, v) => Modify::Removed(a.into(), qs.clone_partialvalue(a, v)?), - ProtoModify::Purged(a) => Modify::Purged(a.into()), + ProtoModify::Present(a, v) => { + let a = Attribute::from(a.as_str()); + let v = qs.clone_value(&a, v)?; + Modify::Present(a, v) + } + ProtoModify::Removed(a, v) => { + let a = Attribute::from(a.as_str()); + let v = qs.clone_partialvalue(&a, v)?; + Modify::Removed(a, v) + } + ProtoModify::Purged(a) => Modify::Purged(Attribute::from(a.as_str())), }) } } @@ -99,15 +106,15 @@ impl ModifyList { } pub fn new_purge_and_set(attr: Attribute, v: Value) -> Self { - Self::new_list(vec![m_purge(attr), Modify::Present(attr.into(), v)]) + Self::new_list(vec![m_purge(attr.clone()), Modify::Present(attr, v)]) } pub fn new_append(attr: Attribute, v: Value) -> Self { - Self::new_list(vec![Modify::Present(attr.into(), v)]) + Self::new_list(vec![Modify::Present(attr, v)]) } pub fn new_remove(attr: Attribute, pv: PartialValue) -> Self { - Self::new_list(vec![Modify::Removed(attr.into(), pv)]) + Self::new_list(vec![Modify::Removed(attr, pv)]) } pub fn new_purge(attr: Attribute) -> Self { @@ -141,13 +148,13 @@ impl ModifyList { pe.attrs.iter().try_for_each(|(attr, vals)| { // Issue a purge to the attr. - let attr: Attribute = attr.as_str().try_into()?; - mods.push(m_purge(attr)); + let attr: Attribute = attr.as_str().into(); + mods.push(m_purge(attr.clone())); // Now if there are vals, push those too. // For each value we want to now be present. vals.iter().try_for_each(|val| { - qs.clone_value(attr.as_ref(), val).map(|resolved_v| { - mods.push(Modify::Present(attr.into(), resolved_v)); + qs.clone_value(&attr, val).map(|resolved_v| { + mods.push(Modify::Present(attr.clone(), resolved_v)); }) }) })?; @@ -172,38 +179,28 @@ impl ModifyList { .mods .iter() .map(|m| match m { - Modify::Present(attr, value) => { - let attr_norm = schema.normalise_attr_name(attr); - match schema_attributes.get(&attr_norm) { - Some(schema_a) => schema_a - .validate_value(attr_norm.as_str(), value) - .map(|_| Modify::Present(attr_norm, value.clone())), - None => Err(SchemaError::InvalidAttribute(attr_norm.to_string())), - } - } - Modify::Removed(attr, value) => { - let attr_norm = schema.normalise_attr_name(attr); - match schema_attributes.get(&attr_norm) { - Some(schema_a) => schema_a - .validate_partialvalue(attr_norm.as_str(), value) - .map(|_| Modify::Removed(attr_norm, value.clone())), - None => Err(SchemaError::InvalidAttribute(attr_norm.to_string())), - } - } - Modify::Assert(attr, value) => match schema_attributes.get(attr.as_ref()) { - // TODO: given attr is an enum... you can't get this wrong anymore? + Modify::Present(attr, value) => match schema_attributes.get(attr) { Some(schema_a) => schema_a - .validate_partialvalue(attr.as_ref(), value) - .map(|_| Modify::Assert(attr.to_owned(), value.clone())), + .validate_value(attr, value) + .map(|_| Modify::Present(attr.clone(), value.clone())), + None => Err(SchemaError::InvalidAttribute(attr.to_string())), + }, + Modify::Removed(attr, value) => match schema_attributes.get(attr) { + Some(schema_a) => schema_a + .validate_partialvalue(attr, value) + .map(|_| Modify::Removed(attr.clone(), value.clone())), + None => Err(SchemaError::InvalidAttribute(attr.to_string())), + }, + Modify::Assert(attr, value) => match schema_attributes.get(attr) { + Some(schema_a) => schema_a + .validate_partialvalue(attr, value) + .map(|_| Modify::Assert(attr.clone(), value.clone())), + None => Err(SchemaError::InvalidAttribute(attr.to_string())), + }, + Modify::Purged(attr) => match schema_attributes.get(attr) { + Some(_attr_name) => Ok(Modify::Purged(attr.clone())), None => Err(SchemaError::InvalidAttribute(attr.to_string())), }, - Modify::Purged(attr) => { - let attr_norm = schema.normalise_attr_name(attr); - match schema_attributes.get(&attr_norm) { - Some(_attr_name) => Ok(Modify::Purged(attr_norm)), - None => Err(SchemaError::InvalidAttribute(attr_norm.to_string())), - } - } }) .collect(); diff --git a/server/lib/src/plugins/attrunique.rs b/server/lib/src/plugins/attrunique.rs index 0a7fb4615..62cc0ffc1 100644 --- a/server/lib/src/plugins/attrunique.rs +++ b/server/lib/src/plugins/attrunique.rs @@ -20,12 +20,12 @@ pub struct AttrUnique; fn get_cand_attr_set<'a, VALID: 'a, STATE: 'a, T>( // cand: &[Entry], cand: T, - uniqueattrs: &[AttrString], -) -> Result>, OperationError> + uniqueattrs: &[Attribute], +) -> Result>, OperationError> where T: IntoIterator>, { - let mut cand_attr: BTreeMap<(AttrString, PartialValue), Vec> = BTreeMap::new(); + let mut cand_attr: BTreeMap<(Attribute, PartialValue), Vec> = BTreeMap::new(); cand.into_iter() // We don't need to consider recycled or tombstoned entries @@ -39,16 +39,16 @@ where })?; // Faster to iterate over the attr vec inside this loop. - for attrstr in uniqueattrs.iter() { - if let Some(vs) = e.get_ava_set(attrstr.try_into()?) { + for attr in uniqueattrs.iter() { + if let Some(vs) = e.get_ava_set(attr) { for pv in vs.to_partialvalue_iter() { - let key = (attrstr.clone(), pv); + let key = (attr.clone(), pv); cand_attr.entry(key) // Must have conflicted, lets append. .and_modify(|v| { warn!( "ava already exists -> {:?} on entry {:?} has conflicts within change set", - attrstr, + attr, e.get_display_id() ); v.push(uuid) @@ -120,8 +120,8 @@ fn enforce_unique( // and[ attr eq k, andnot [ uuid eq v ]] // Basically this says where name but also not self. cand_filters.push(f_and(vec![ - FC::Eq(attr, v.clone()), - f_andnot(FC::Eq(Attribute::Uuid.as_ref(), PartialValue::Uuid(*uuid))), + FC::Eq(attr.clone(), v.clone()), + f_andnot(FC::Eq(Attribute::Uuid, PartialValue::Uuid(*uuid))), ])); } @@ -308,8 +308,8 @@ impl Plugin for AttrUnique { // and[ attr eq k, andnot [ uuid eq v ]] // Basically this says where name but also not self. f_and(vec![ - FC::Eq(attr, v.clone()), - f_andnot(FC::Eq(Attribute::Uuid.as_ref(), PartialValue::Uuid(*uuid))), + FC::Eq(attr.clone(), v.clone()), + f_andnot(FC::Eq(Attribute::Uuid, PartialValue::Uuid(*uuid))), ]) }) }) @@ -364,8 +364,8 @@ impl Plugin for AttrUnique { .iter() .map(|(attr, pv)| { f_and(vec![ - FC::Eq(attr, pv.clone()), - f_andnot(FC::Eq(Attribute::Uuid.as_ref(), PartialValue::Uuid(uuid))), + FC::Eq(attr.clone(), pv.clone()), + f_andnot(FC::Eq(Attribute::Uuid, PartialValue::Uuid(uuid))), ]) }) .collect(); @@ -571,8 +571,8 @@ mod tests { PartialValue::new_iname("testgroup_b") ),])), ModifyList::new_list(vec![ - Modify::Purged(Attribute::Name.into()), - Modify::Present(Attribute::Name.into(), Value::new_iname("testgroup_a")) + Modify::Purged(Attribute::Name), + Modify::Present(Attribute::Name, Value::new_iname("testgroup_a")) ]), None, |_| {}, @@ -606,8 +606,8 @@ mod tests { f_eq(Attribute::Name, PartialValue::new_iname("testgroup_b")), ])), ModifyList::new_list(vec![ - Modify::Purged(Attribute::Name.into()), - Modify::Present(Attribute::Name.into(), Value::new_iname("testgroup")) + Modify::Purged(Attribute::Name), + Modify::Present(Attribute::Name, Value::new_iname("testgroup")) ]), None, |_| {}, diff --git a/server/lib/src/plugins/base.rs b/server/lib/src/plugins/base.rs index 5f80688f7..df7d7c6fa 100644 --- a/server/lib/src/plugins/base.rs +++ b/server/lib/src/plugins/base.rs @@ -45,7 +45,7 @@ impl Plugin for Base { // Generate let ava_uuid = Value::Uuid(Uuid::new_v4()); trace!("Setting temporary UUID {:?} to entry", ava_uuid); - entry.set_ava(Attribute::Uuid, once(ava_uuid)); + entry.set_ava(&Attribute::Uuid, once(ava_uuid)); } Some(1) => { // Do nothing @@ -124,7 +124,7 @@ impl Plugin for Base { let filt_in = filter_all!(FC::Or( cand_uuid .into_iter() - .map(|u| FC::Eq(Attribute::Uuid.as_ref(), PartialValue::Uuid(u))) + .map(|u| FC::Eq(Attribute::Uuid, PartialValue::Uuid(u))) .collect(), )); @@ -169,7 +169,7 @@ impl Plugin for Base { Modify::Purged(a) => Some(a), Modify::Assert(_, _) => None, }; - if attr == Some(&AttrString::from(Attribute::Uuid)) { + if attr == Some(&Attribute::Uuid) { debug!(?modify, "Modify in violation"); request_error!("Modifications to UUID's are NOT ALLOWED"); Err(OperationError::SystemProtectedAttribute) @@ -196,7 +196,7 @@ impl Plugin for Base { Modify::Purged(a) => Some(a), Modify::Assert(_, _) => None, }; - if attr == Some(&AttrString::from(Attribute::Uuid)) { + if attr == Some(&Attribute::Uuid) { debug!(?modify, "Modify in violation"); request_error!("Modifications to UUID's are NOT ALLOWED"); Err(OperationError::SystemProtectedAttribute) @@ -616,7 +616,7 @@ mod tests { PartialValue::new_iname("testgroup_a") )), ModifyList::new_list(vec![Modify::Present( - Attribute::Uuid.into(), + Attribute::Uuid, Value::from("f15a7219-1d15-44e3-a7b4-bec899c07788") )]), None, @@ -649,7 +649,7 @@ mod tests { PartialValue::new_iname("testgroup_a") )), ModifyList::new_list(vec![Modify::Removed( - Attribute::Uuid.into(), + Attribute::Uuid, PartialValue::Uuid(uuid!("f15a7219-1d15-44e3-a7b4-bec899c07788")) )]), None, @@ -681,7 +681,7 @@ mod tests { Attribute::Name, PartialValue::new_iname("testgroup_a") )), - ModifyList::new_list(vec![Modify::Purged(Attribute::Uuid.into())]), + ModifyList::new_list(vec![Modify::Purged(Attribute::Uuid)]), None, |_| {}, |_| {} diff --git a/server/lib/src/plugins/cred_import.rs b/server/lib/src/plugins/cred_import.rs index 752bfab39..11de5164c 100644 --- a/server/lib/src/plugins/cred_import.rs +++ b/server/lib/src/plugins/cred_import.rs @@ -83,7 +83,7 @@ impl CredImport { Some(c) => { let c = c.update_password(pw); e.set_ava( - Attribute::PrimaryCredential, + &Attribute::PrimaryCredential, once(Value::new_credential("primary", c)), ); } @@ -91,7 +91,7 @@ impl CredImport { // just set it then! let c = Credential::new_from_password(pw); e.set_ava( - Attribute::PrimaryCredential, + &Attribute::PrimaryCredential, once(Value::new_credential("primary", c)), ); } @@ -113,7 +113,7 @@ impl CredImport { acc.append_totp(label.clone(), totp.clone()) }); e.set_ava( - Attribute::PrimaryCredential, + &Attribute::PrimaryCredential, once(Value::new_credential("primary", c)), ); } else { @@ -153,7 +153,7 @@ impl CredImport { // Unix pw's aren't like primary, we can just splat them here. let c = Credential::new_from_password(pw); e.set_ava( - Attribute::UnixPassword, + &Attribute::UnixPassword, once(Value::new_credential("primary", c)), ); }; @@ -235,7 +235,7 @@ mod tests { preload, filter!(f_eq(Attribute::Name, PartialValue::new_iutf8("testperson"))), ModifyList::new_list(vec![Modify::Present( - Attribute::PasswordImport.into(), + Attribute::PasswordImport, Value::from(IMPORT_HASH) )]), None, @@ -278,7 +278,7 @@ mod tests { preload, filter!(f_eq(Attribute::Name, PartialValue::new_iutf8("testperson"))), ModifyList::new_list(vec![Modify::Present( - Attribute::PasswordImport.into(), + Attribute::PasswordImport, Value::from(IMPORT_HASH) )]), None, @@ -324,7 +324,7 @@ mod tests { preload, filter!(f_eq(Attribute::Name, PartialValue::new_iutf8("testperson"))), ModifyList::new_list(vec![Modify::Present( - Attribute::PasswordImport.into(), + Attribute::PasswordImport, Value::from(IMPORT_HASH) )]), None, @@ -378,15 +378,15 @@ mod tests { filter!(f_eq(Attribute::Name, PartialValue::new_iutf8("testperson"))), ModifyList::new_list(vec![ Modify::Present( - Attribute::PasswordImport.into(), + Attribute::PasswordImport, Value::Utf8(IMPORT_HASH.to_string()) ), Modify::Present( - Attribute::TotpImport.into(), + Attribute::TotpImport, Value::TotpSecret("a".to_string(), totp_a.clone()) ), Modify::Present( - Attribute::TotpImport.into(), + Attribute::TotpImport, Value::TotpSecret("b".to_string(), totp_b.clone()) ) ]), @@ -443,7 +443,7 @@ mod tests { preload, filter!(f_eq(Attribute::Name, PartialValue::new_iutf8("testperson"))), ModifyList::new_list(vec![Modify::Present( - Attribute::TotpImport.into(), + Attribute::TotpImport, Value::TotpSecret("a".to_string(), totp_a) )]), None, @@ -480,7 +480,7 @@ mod tests { preload, filter!(f_eq(Attribute::Name, PartialValue::new_iutf8("testperson"))), ModifyList::new_list(vec![Modify::Present( - Attribute::UnixPasswordImport.into(), + Attribute::UnixPasswordImport, Value::from(IMPORT_HASH) )]), None, diff --git a/server/lib/src/plugins/default_values.rs b/server/lib/src/plugins/default_values.rs index fdeda102d..47c6a7bd9 100644 --- a/server/lib/src/plugins/default_values.rs +++ b/server/lib/src/plugins/default_values.rs @@ -68,7 +68,7 @@ impl DefaultValues { e.add_ava(Attribute::Class, EntryClass::AccountPolicy.to_value()); if !e.attribute_pres(Attribute::AuthSessionExpiry) { - e.set_ava(Attribute::AuthSessionExpiry, once( + e.set_ava(&Attribute::AuthSessionExpiry, once( Value::Uint32(DEFAULT_AUTH_SESSION_EXPIRY), )); debug!("default_values: idm_all_accounts - restore default auth_session_expiry"); @@ -76,7 +76,7 @@ impl DefaultValues { // Setup the minimum functional level if one is not set already. if !e.attribute_pres(Attribute::PrivilegeExpiry) { - e.set_ava(Attribute::PrivilegeExpiry, once( + e.set_ava(&Attribute::PrivilegeExpiry, once( Value::Uint32(DEFAULT_AUTH_PRIVILEGE_EXPIRY), )); debug!("default_values: idm_all_accounts - restore default privilege_session_expiry"); @@ -117,8 +117,8 @@ mod tests { .internal_modify_uuid( UUID_IDM_ALL_ACCOUNTS, &ModifyList::new_list(vec![ - Modify::Purged(Attribute::AuthSessionExpiry.into()), - Modify::Purged(Attribute::PrivilegeExpiry.into()), + Modify::Purged(Attribute::AuthSessionExpiry), + Modify::Purged(Attribute::PrivilegeExpiry), ]), ) .expect("failed to modify account"); diff --git a/server/lib/src/plugins/domain.rs b/server/lib/src/plugins/domain.rs index 31b2cce4f..37c8011af 100644 --- a/server/lib/src/plugins/domain.rs +++ b/server/lib/src/plugins/domain.rs @@ -91,20 +91,20 @@ impl Domain { // We always set this, because the DB uuid is authoritative. let u = Value::Uuid(qs.get_domain_uuid()); - e.set_ava(Attribute::DomainUuid, once(u)); + e.set_ava(&Attribute::DomainUuid, once(u)); trace!("plugin_domain: Applying uuid transform"); // We only apply this if one isn't provided. if !e.attribute_pres(Attribute::DomainName) { let n = Value::new_iname(qs.get_domain_name()); - e.set_ava(Attribute::DomainName, once(n)); + e.set_ava(&Attribute::DomainName, once(n)); trace!("plugin_domain: Applying domain_name transform"); } // Setup the minimum functional level if one is not set already. if !e.attribute_pres(Attribute::Version) { let n = Value::Uint32(DOMAIN_LEVEL_0); - e.set_ava(Attribute::Version, once(n)); + e.set_ava(&Attribute::Version, once(n)); warn!("plugin_domain: Applying domain version transform"); } else { debug!("plugin_domain: NOT Applying domain version transform"); @@ -115,7 +115,7 @@ impl Domain { let domain_display_name = Value::new_utf8(format!("Kanidm {}", qs.get_domain_name())); security_info!("plugin_domain: setting default domain_display_name to {:?}", domain_display_name); - e.set_ava(Attribute::DomainDisplayName, once(domain_display_name)); + e.set_ava(&Attribute::DomainDisplayName, once(domain_display_name)); } if qs.get_domain_version() < DOMAIN_LEVEL_6 && !e.attribute_pres(Attribute::FernetPrivateKeyStr) { diff --git a/server/lib/src/plugins/dyngroup.rs b/server/lib/src/plugins/dyngroup.rs index 5f20ea14a..ae7fd2337 100644 --- a/server/lib/src/plugins/dyngroup.rs +++ b/server/lib/src/plugins/dyngroup.rs @@ -103,7 +103,7 @@ impl DynGroup { if let Some(members) = members { // Only set something if there is actually something to do! - nd_group.set_ava_set(Attribute::DynMember, members); + nd_group.set_ava_set(&Attribute::DynMember, members); // push the entries to pre/cand } else { nd_group.purge_ava(Attribute::DynMember); @@ -659,7 +659,7 @@ mod tests { ModifyList::new_list(vec![ Modify::Purged("dyngroup_filter".into()), Modify::Present( - Attribute::DynGroupFilter.into(), + Attribute::DynGroupFilter, Value::JsonFilt(ProtoFilter::Eq( Attribute::Name.to_string(), "testgroup".to_string() @@ -720,7 +720,7 @@ mod tests { ModifyList::new_list(vec![ Modify::Purged("dyngroup_filter".into()), Modify::Present( - Attribute::DynGroupFilter.into(), + Attribute::DynGroupFilter, Value::JsonFilt(ProtoFilter::Eq( Attribute::Name.to_string(), "no_such_entry_exists".to_string() @@ -775,7 +775,7 @@ mod tests { PartialValue::new_iname("test_dyngroup") )), ModifyList::new_list(vec![Modify::Present( - Attribute::DynMember.into(), + Attribute::DynMember, Value::Refer(UUID_ADMIN) )]), None, @@ -830,7 +830,7 @@ mod tests { Attribute::Name, PartialValue::new_iname("test_dyngroup") )), - ModifyList::new_list(vec![Modify::Purged(Attribute::DynMember.into(),)]), + ModifyList::new_list(vec![Modify::Purged(Attribute::DynMember,)]), None, |_| {}, |qs: &mut QueryServerWriteTransaction| { @@ -883,8 +883,8 @@ mod tests { PartialValue::new_iname("not_testgroup") )), ModifyList::new_list(vec![ - Modify::Purged(Attribute::Name.into(),), - Modify::Present(Attribute::Name.into(), Value::new_iname("testgroup")) + Modify::Purged(Attribute::Name,), + Modify::Present(Attribute::Name, Value::new_iname("testgroup")) ]), None, |_| {}, @@ -935,8 +935,8 @@ mod tests { preload, filter!(f_eq(Attribute::Name, PartialValue::new_iname("testgroup"))), ModifyList::new_list(vec![ - Modify::Purged(Attribute::Name.into(),), - Modify::Present(Attribute::Name.into(), Value::new_iname("not_testgroup")) + Modify::Purged(Attribute::Name,), + Modify::Present(Attribute::Name, Value::new_iname("not_testgroup")) ]), None, |_| {}, diff --git a/server/lib/src/plugins/gidnumber.rs b/server/lib/src/plugins/gidnumber.rs index 7115ce5da..2c90a67b7 100644 --- a/server/lib/src/plugins/gidnumber.rs +++ b/server/lib/src/plugins/gidnumber.rs @@ -86,7 +86,7 @@ fn apply_gidnumber( let gid_v = Value::new_uint32(gid); admin_info!("Generated {} for {:?}", gid, u_ref); - e.set_ava(Attribute::GidNumber, once(gid_v)); + e.set_ava(&Attribute::GidNumber, once(gid_v)); Ok(()) } else if let Some(gid) = e.get_ava_single_uint32(Attribute::GidNumber) { if domain_version <= DOMAIN_LEVEL_6 { diff --git a/server/lib/src/plugins/jwskeygen.rs b/server/lib/src/plugins/jwskeygen.rs index 848a8a42f..629375fe1 100644 --- a/server/lib/src/plugins/jwskeygen.rs +++ b/server/lib/src/plugins/jwskeygen.rs @@ -211,8 +211,8 @@ mod tests { preload, filter!(f_eq(Attribute::Uuid, PartialValue::Uuid(uuid))), ModifyList::new_list(vec![ - Modify::Purged(Attribute::OAuth2RsBasicSecret.into(),), - Modify::Purged(Attribute::OAuth2RsTokenKey.into(),) + Modify::Purged(Attribute::OAuth2RsBasicSecret,), + Modify::Purged(Attribute::OAuth2RsTokenKey,) ]), None, |_| {}, diff --git a/server/lib/src/plugins/keyobject.rs b/server/lib/src/plugins/keyobject.rs index cdf8c2675..b24f8cbff 100644 --- a/server/lib/src/plugins/keyobject.rs +++ b/server/lib/src/plugins/keyobject.rs @@ -220,7 +220,7 @@ impl KeyObjectManagement { .as_valuesets()? .into_iter() .try_for_each(|(attribute, valueset)| { - entry.merge_ava_set(attribute, valueset) + entry.merge_ava_set(&attribute, valueset) })?; Ok(()) diff --git a/server/lib/src/plugins/memberof.rs b/server/lib/src/plugins/memberof.rs index 751395a31..c8c629f87 100644 --- a/server/lib/src/plugins/memberof.rs +++ b/server/lib/src/plugins/memberof.rs @@ -65,7 +65,7 @@ fn do_group_memberof( // Add all the direct mo's and mos. if let Some(dmo) = dmo { // We need to clone this else type checker gets real sad. - tgte.set_ava_set(Attribute::DirectMemberOf, dmo.clone()); + tgte.set_ava_set(&Attribute::DirectMemberOf, dmo.clone()); if let Some(mo) = &mut mo { let dmo = dmo as ValueSet; @@ -78,7 +78,7 @@ fn do_group_memberof( }; if let Some(mo) = mo { - tgte.set_ava_set(Attribute::MemberOf, mo); + tgte.set_ava_set(&Attribute::MemberOf, mo); } trace!( @@ -205,7 +205,7 @@ fn do_leaf_memberof( dmo_set.insert(group_uuid); } else { let dmo = ValueSetRefer::new(group_uuid); - tgte.set_ava_set(Attribute::DirectMemberOf, dmo); + tgte.set_ava_set(&Attribute::DirectMemberOf, dmo); } // We're also in member of this group. @@ -213,7 +213,7 @@ fn do_leaf_memberof( mo_set.insert(group_uuid); } else { let mo = ValueSetRefer::new(group_uuid); - tgte.set_ava_set(Attribute::MemberOf, mo); + tgte.set_ava_set(&Attribute::MemberOf, mo); } // If the group has memberOf attributes, we propogate these to @@ -510,7 +510,7 @@ impl Plugin for MemberOf { for entry in cand.iter_mut() { if let Some(direct_mo_vs) = entry.pop_ava(Attribute::DirectMemberOf) { - entry.set_ava_set(Attribute::RecycledDirectMemberOf, direct_mo_vs); + entry.set_ava_set(&Attribute::RecycledDirectMemberOf, direct_mo_vs); } else { // Ensure it's empty entry.purge_ava(Attribute::RecycledDirectMemberOf); @@ -1074,7 +1074,7 @@ mod tests { PartialValue::new_uuid_s(UUID_A).unwrap() )), ModifyList::new_list(vec![Modify::Present( - Attribute::Member.into(), + Attribute::Member, Value::new_refer_s(UUID_B).unwrap() )]), None, @@ -1113,7 +1113,7 @@ mod tests { PartialValue::new_uuid_s(UUID_A).unwrap() )), ModifyList::new_list(vec![Modify::Present( - Attribute::Member.into(), + Attribute::Member, Value::new_refer_s(UUID_B).unwrap() )]), None, @@ -1170,7 +1170,7 @@ mod tests { PartialValue::new_uuid_s(UUID_B).unwrap() )), ModifyList::new_list(vec![Modify::Present( - Attribute::Member.into(), + Attribute::Member, Value::new_refer_s(UUID_C).unwrap() )]), None, @@ -1230,7 +1230,7 @@ mod tests { PartialValue::new_uuid_s(UUID_C).unwrap() )), ModifyList::new_list(vec![Modify::Present( - Attribute::Member.into(), + Attribute::Member, Value::new_refer_s(UUID_A).unwrap() )]), None, @@ -1297,7 +1297,7 @@ mod tests { f_eq(Attribute::Uuid, PartialValue::new_uuid_s(UUID_D).unwrap()), ])), ModifyList::new_list(vec![Modify::Present( - Attribute::Member.into(), + Attribute::Member, Value::new_refer_s(UUID_A).unwrap() )]), None, @@ -1369,7 +1369,7 @@ mod tests { PartialValue::new_uuid_s(UUID_A).unwrap() )), ModifyList::new_list(vec![Modify::Removed( - Attribute::Member.into(), + Attribute::Member, PartialValue::new_refer_s(UUID_B).unwrap() )]), None, @@ -1411,7 +1411,7 @@ mod tests { PartialValue::new_uuid_s(UUID_A).unwrap() )), ModifyList::new_list(vec![Modify::Removed( - Attribute::Member.into(), + Attribute::Member, PartialValue::new_refer_s(UUID_B).unwrap() )]), None, @@ -1472,7 +1472,7 @@ mod tests { PartialValue::new_uuid_s(UUID_B).unwrap() )), ModifyList::new_list(vec![Modify::Removed( - Attribute::Member.into(), + Attribute::Member, PartialValue::new_refer_s(UUID_C).unwrap() )]), None, @@ -1543,7 +1543,7 @@ mod tests { PartialValue::new_uuid_s(UUID_C).unwrap() )), ModifyList::new_list(vec![Modify::Removed( - Attribute::Member.into(), + Attribute::Member, PartialValue::new_refer_s(UUID_A).unwrap() )]), None, @@ -1633,11 +1633,11 @@ mod tests { )), ModifyList::new_list(vec![ Modify::Removed( - Attribute::Member.into(), + Attribute::Member, PartialValue::new_refer_s(UUID_A).unwrap() ), Modify::Removed( - Attribute::Member.into(), + Attribute::Member, PartialValue::new_refer_s(UUID_D).unwrap() ), ]), diff --git a/server/lib/src/plugins/namehistory.rs b/server/lib/src/plugins/namehistory.rs index e44cd4c48..2645e2413 100644 --- a/server/lib/src/plugins/namehistory.rs +++ b/server/lib/src/plugins/namehistory.rs @@ -13,25 +13,12 @@ pub struct NameHistory {} lazy_static! { // it contains all the partialvalues used to match against an Entry's class, // we just need a partialvalue to match in order to target the entry - static ref CLASSES_TO_UPDATE: [PartialValue; 1] = [PartialValue::new_iutf8(EntryClass::Account.into())]; -} - -const HISTORY_ATTRIBUTES: [Attribute; 1] = [Attribute::Name]; - -#[test] -fn test_history_attribute() { - assert_eq!(NameHistory::get_ava_name(Attribute::Name), "name_history"); + static ref CLASS_TO_UPDATE: PartialValue = PartialValue::new_iutf8(EntryClass::Account.into()); } impl NameHistory { fn is_entry_to_update(entry: &mut Entry) -> bool { - CLASSES_TO_UPDATE - .iter() - .any(|pv| entry.attribute_equality(Attribute::Class, pv)) - } - - fn get_ava_name(history_attr: Attribute) -> String { - format!("{}_history", history_attr) + entry.attribute_equality(Attribute::Class, &CLASS_TO_UPDATE) } fn handle_name_updates( @@ -42,22 +29,16 @@ impl NameHistory { for (pre, post) in pre_cand.iter().zip(cand) { // here we check if the current entry has at least one of the classes we intend to target if Self::is_entry_to_update(post) { - for history_attr in HISTORY_ATTRIBUTES.into_iter() { - let pre_name_option = pre.get_ava_single(history_attr); - let post_name_option = post.get_ava_single(history_attr); - if let (Some(pre_name), Some(post_name)) = (pre_name_option, post_name_option) { - if pre_name != post_name { - let ava_name = Self::get_ava_name(history_attr); - //// WARNING!!! this match will have to be adjusted based on what kind of attribute - //// we are matching on, for example for displayname we would have to use Value::utf8 instead!! - // as of now we're interested just in the name so we use Iname - match post_name { - Value::Iname(n) => post.add_ava_if_not_exist( - ava_name.as_str().try_into()?, - Value::AuditLogString(cid.clone(), n), - ), - _ => return Err(OperationError::InvalidValueState), - } + let pre_name_option = pre.get_ava_single(Attribute::Name); + let post_name_option = post.get_ava_single(Attribute::Name); + if let (Some(pre_name), Some(post_name)) = (pre_name_option, post_name_option) { + if pre_name != post_name { + match post_name { + Value::Iname(n) => post.add_ava_if_not_exist( + Attribute::NameHistory, + Value::AuditLogString(cid.clone(), n), + ), + _ => return Err(OperationError::InvalidValueState), } } } @@ -72,16 +53,13 @@ impl NameHistory { ) -> Result<(), OperationError> { for cand in cands.iter_mut() { if Self::is_entry_to_update(cand) { - for history_attr in HISTORY_ATTRIBUTES.into_iter() { - if let Some(name) = cand.get_ava_single(history_attr) { - let ava_name = Self::get_ava_name(history_attr); - match name { - Value::Iname(n) => cand.add_ava_if_not_exist( - ava_name.as_str().try_into()?, - Value::AuditLogString(cid.clone(), n), - ), - _ => return Err(OperationError::InvalidValueState), - } + if let Some(name) = cand.get_ava_single(Attribute::Name) { + match name { + Value::Iname(n) => cand.add_ava_if_not_exist( + Attribute::NameHistory, + Value::AuditLogString(cid.clone(), n), + ), + _ => return Err(OperationError::InvalidValueState), } } } diff --git a/server/lib/src/plugins/protected.rs b/server/lib/src/plugins/protected.rs index 4559d701c..3da0e5285 100644 --- a/server/lib/src/plugins/protected.rs +++ b/server/lib/src/plugins/protected.rs @@ -149,9 +149,8 @@ impl Plugin for Protected { Modify::Present(a, _) | Modify::Removed(a, _) | Modify::Purged(a) => Some(a), Modify::Assert(_, _) => None, }; - if let Some(a) = a { - let attr: Attribute = a.try_into()?; - match ALLOWED_ATTRS.contains(&attr) { + if let Some(attr) = a { + match ALLOWED_ATTRS.contains(attr) { true => Ok(()), false => { trace!("If you're getting this, you need to modify the ALLOWED_ATTRS list"); @@ -229,9 +228,8 @@ impl Plugin for Protected { Modify::Present(a, _) | Modify::Removed(a, _) | Modify::Purged(a) => Some(a), Modify::Assert(_, _) => None, }; - if let Some(a) = a { - let attr: Attribute = a.try_into()?; - match ALLOWED_ATTRS.contains(&attr) { + if let Some(attr) = a { + match ALLOWED_ATTRS.contains(attr) { true => Ok(()), false => { diff --git a/server/lib/src/plugins/refint.rs b/server/lib/src/plugins/refint.rs index 0f4ff2ad6..23155b866 100644 --- a/server/lib/src/plugins/refint.rs +++ b/server/lib/src/plugins/refint.rs @@ -103,24 +103,9 @@ impl ReferentialIntegrity { let filt = filter_all!(FC::Or( uuids .into_iter() - .flat_map(|u| ref_types.values().filter_map(move |r_type| { - let value_attribute = r_type.name.to_string(); - // For everything that references the uuid's in the deleted set. - let val: Result = value_attribute.as_str().try_into(); - // error!("{:?}", val); - let res = match val { - Ok(val) => { - let res = f_eq(val, PartialValue::Refer(u)); - Some(res) - } - Err(err) => { - // we shouldn't be able to get here... - admin_error!("post_delete invalid attribute specified - please log this as a bug! {:?}", err); - None - } - }; - res - })) + .flat_map(|u| ref_types + .values() + .map(move |r_type| { f_eq(r_type.name.clone(), PartialValue::Refer(u)) })) .collect(), )); @@ -130,8 +115,7 @@ impl ReferentialIntegrity { for (_, post) in work_set.iter_mut() { for schema_attribute in ref_types.values() { - let attribute = (&schema_attribute.name).try_into()?; - post.remove_avas(attribute, &removed_ids); + post.remove_avas(&schema_attribute.name, &removed_ids); } } @@ -324,19 +308,8 @@ impl Plugin for ReferentialIntegrity { for c in &all_cand { // For all reference in each cand. for rtype in ref_types.values() { - let attr: Attribute = match (&rtype.name).try_into() { - Ok(val) => val, - Err(err) => { - // we shouldn't be able to get here... - admin_error!("verify referential integrity invalid attribute {} specified - please log this as a bug! {:?}", &rtype.name, err); - res.push(Err(ConsistencyError::InvalidAttributeType( - rtype.name.to_string(), - ))); - continue; - } - }; // If the attribute is present - if let Some(vs) = c.get_ava_set(attr) { + if let Some(vs) = c.get_ava_set(&rtype.name) { // For each value in the set. match vs.as_ref_uuid_iter() { Some(uuid_iter) => { @@ -359,7 +332,7 @@ impl Plugin for ReferentialIntegrity { } fn update_reference_set<'a, I>( - ref_types: &HashMap, + ref_types: &HashMap, entry_iter: I, reference_set: &mut BTreeSet, ) -> Result<(), OperationError> @@ -374,23 +347,14 @@ where // For all reference types that exist in the schema. let cand_ref_valuesets = ref_types.values().filter_map(|rtype| { // If the entry is a dyn-group, skip dyn member. - let skip_mb = dyn_group && rtype.name == Attribute::DynMember.as_ref(); + let skip_mb = dyn_group && rtype.name == Attribute::DynMember; // MemberOf is always recalculated, so it can be skipped - let skip_mo = rtype.name == Attribute::MemberOf.as_ref(); + let skip_mo = rtype.name == Attribute::MemberOf; if skip_mb || skip_mo { None } else { - trace!(rtype_name = ?rtype.name, "examining"); - cand.get_ava_set( - (&rtype.name) - .try_into() - .map_err(|e| { - admin_error!(?e, "invalid attribute type {}", &rtype.name); - None:: - }) - .ok()?, - ) + cand.get_ava_set(&rtype.name) } }); @@ -399,8 +363,8 @@ where reference_set.extend(uuid_iter); Ok(()) } else { - admin_error!(?vs, "reference value could not convert to reference uuid."); - admin_error!("If you are sure the name/uuid/spn exist, and that this is in error, you should run a verify task."); + error!(?vs, "reference value could not convert to reference uuid."); + error!("If you are sure the name/uuid/spn exist, and that this is in error, you should run a verify task."); Err(OperationError::InvalidAttribute( "uuid could not become reference value".to_string(), )) @@ -623,7 +587,7 @@ mod tests { PartialValue::new_iname("testgroup_b") )), ModifyList::new_list(vec![Modify::Present( - Attribute::Member.into(), + Attribute::Member, Value::new_refer_s(TEST_TESTGROUP_A_UUID).unwrap() )]), None, @@ -657,7 +621,7 @@ mod tests { PartialValue::new_iname("testgroup_b") )), ModifyList::new_list(vec![Modify::Present( - Attribute::Member.into(), + Attribute::Member, Value::new_refer_s(TEST_TESTGROUP_A_UUID).unwrap() )]), None, @@ -704,10 +668,10 @@ mod tests { )), ModifyList::new_list(vec![ Modify::Present( - Attribute::Member.into(), + Attribute::Member, Value::Refer(Uuid::parse_str(TEST_TESTGROUP_A_UUID).unwrap()) ), - Modify::Present(Attribute::Member.into(), Value::Refer(UUID_DOES_NOT_EXIST)), + Modify::Present(Attribute::Member, Value::Refer(UUID_DOES_NOT_EXIST)), ]), None, |_| {}, @@ -749,7 +713,7 @@ mod tests { Attribute::Name, PartialValue::new_iname("testgroup_b") )), - ModifyList::new_list(vec![Modify::Purged(Attribute::Member.into())]), + ModifyList::new_list(vec![Modify::Purged(Attribute::Member)]), None, |_| {}, |_| {} @@ -780,7 +744,7 @@ mod tests { PartialValue::new_iname("testgroup_a") )), ModifyList::new_list(vec![Modify::Present( - Attribute::Member.into(), + Attribute::Member, Value::new_refer_s(TEST_TESTGROUP_A_UUID).unwrap() )]), None, @@ -825,7 +789,7 @@ mod tests { PartialValue::new_iname("testgroup_b") )), ModifyList::new_list(vec![Modify::Present( - Attribute::Member.into(), + Attribute::Member, Value::new_refer_s(TEST_TESTGROUP_A_UUID).unwrap() )]), None, @@ -927,7 +891,7 @@ mod tests { run_delete_test!( Err(OperationError::SchemaViolation( - SchemaError::MissingMustAttribute(vec!["acp_receiver_group".to_string()]) + SchemaError::MissingMustAttribute(vec![Attribute::AcpReceiverGroup]) )), preload, filter!(f_eq( @@ -1143,7 +1107,7 @@ mod tests { // Mod the user let modlist = modlist!([ Modify::Present( - Attribute::OAuth2Session.into(), + Attribute::OAuth2Session, Value::Oauth2Session( session_id, Oauth2Session { @@ -1156,7 +1120,7 @@ mod tests { ) ), Modify::Present( - Attribute::UserAuthTokenSession.into(), + Attribute::UserAuthTokenSession, Value::Session( parent_id, Session { diff --git a/server/lib/src/plugins/session.rs b/server/lib/src/plugins/session.rs index 10a53da45..6bbaecebb 100644 --- a/server/lib/src/plugins/session.rs +++ b/server/lib/src/plugins/session.rs @@ -403,7 +403,7 @@ mod tests { ) ), Modify::Present( - Attribute::UserAuthTokenSession.into(), + Attribute::UserAuthTokenSession, Value::Session( parent_id, Session { @@ -576,7 +576,7 @@ mod tests { ) ), Modify::Present( - Attribute::UserAuthTokenSession.into(), + Attribute::UserAuthTokenSession, Value::Session( parent_id, Session { diff --git a/server/lib/src/plugins/spn.rs b/server/lib/src/plugins/spn.rs index 499dccd37..6a6e759d6 100644 --- a/server/lib/src/plugins/spn.rs +++ b/server/lib/src/plugins/spn.rs @@ -166,7 +166,7 @@ impl Spn { Attribute::Spn, spn ); - ent.set_ava(Attribute::Spn, once(spn)); + ent.set_ava(&Attribute::Spn, once(spn)); } } Ok(()) diff --git a/server/lib/src/plugins/valuedeny.rs b/server/lib/src/plugins/valuedeny.rs index 835384168..e0a360ee0 100644 --- a/server/lib/src/plugins/valuedeny.rs +++ b/server/lib/src/plugins/valuedeny.rs @@ -118,7 +118,7 @@ mod tests { let me_inv_m = ModifyEvent::new_internal_invalid( filter!(f_eq(Attribute::Uuid, PVUUID_SYSTEM_CONFIG.clone())), ModifyList::new_list(vec![Modify::Present( - Attribute::DeniedName.into(), + Attribute::DeniedName, Value::new_iname("tobias"), )]), ); diff --git a/server/lib/src/repl/consumer.rs b/server/lib/src/repl/consumer.rs index aa566bc2a..c32905980 100644 --- a/server/lib/src/repl/consumer.rs +++ b/server/lib/src/repl/consumer.rs @@ -41,10 +41,12 @@ impl<'a> QueryServerWriteTransaction<'a> { trace!(?ctx_entries); - let db_entries = self.be_txn.incremental_prepare(&ctx_entries).map_err(|e| { - error!("Failed to access entries from db"); - e - })?; + let db_entries = self + .be_txn + .incremental_prepare(&ctx_entries) + .inspect_err(|err| { + error!(?err, "Failed to access entries from db"); + })?; trace!(?db_entries); @@ -366,9 +368,11 @@ impl<'a> QueryServerWriteTransaction<'a> { let ruv = self.be_txn.get_ruv_write(); ruv.incremental_preflight_validate_ruv(ctx_ranges, &txn_cid) - .map_err(|e| { - error!("Incoming RUV failed preflight checks, unable to proceed."); - e + .inspect_err(|err| { + error!( + ?err, + "Incoming RUV failed preflight checks, unable to proceed." + ); })?; // == ⚠️ Below this point we begin to make changes! == @@ -383,16 +387,14 @@ impl<'a> QueryServerWriteTransaction<'a> { // Apply the schema entries first. let schema_changed = self .consumer_incremental_apply_entries(ctx_schema_entries) - .map_err(|e| { - error!("Failed to apply incremental schema entries"); - e + .inspect_err(|err| { + error!(?err, "Failed to apply incremental schema entries"); })?; if schema_changed { // We need to reload schema now! - self.reload_schema().map_err(|e| { - error!("Failed to reload schema"); - e + self.reload_schema().inspect_err(|err| { + error!(?err, "Failed to reload schema"); })?; } @@ -400,29 +402,25 @@ impl<'a> QueryServerWriteTransaction<'a> { // Apply meta entries now. let meta_changed = self .consumer_incremental_apply_entries(ctx_meta_entries) - .map_err(|e| { - error!("Failed to apply incremental schema entries"); - e + .inspect_err(|err| { + error!(?err, "Failed to apply incremental schema entries"); })?; // This is re-loaded in case the domain name changed on the remote if meta_changed { - self.reload_domain_info().map_err(|e| { - error!("Failed to reload domain info"); - e + self.reload_domain_info().inspect_err(|err| { + error!(?err, "Failed to reload domain info"); })?; - self.reload_system_config().map_err(|e| { - error!("Failed to reload system configuration"); - e + self.reload_system_config().inspect_err(|err| { + error!(?err, "Failed to reload system configuration"); })?; } debug!("Applying all context entries"); // Update all other entries now. self.consumer_incremental_apply_entries(ctx_entries) - .map_err(|e| { - error!("Failed to apply incremental schema entries"); - e + .inspect_err(|err| { + error!(?err, "Failed to apply incremental schema entries"); })?; // Reload the domain version, doing any needed migrations. @@ -432,9 +430,8 @@ impl<'a> QueryServerWriteTransaction<'a> { // was just migrated. As a result, we only need to apply the migrations to entries // that were not on the supplier, and therefore need updates here. if meta_changed { - self.reload_domain_info_version().map_err(|e| { - error!("Failed to reload domain info version"); - e + self.reload_domain_info_version().inspect_err(|err| { + error!(?err, "Failed to reload domain info version"); })?; } @@ -442,14 +439,12 @@ impl<'a> QueryServerWriteTransaction<'a> { // context. Note that we get this in a writeable form! let ruv = self.be_txn.get_ruv_write(); - ruv.refresh_validate_ruv(ctx_ranges).map_err(|e| { - error!("RUV ranges were not rebuilt correctly."); - e + ruv.refresh_validate_ruv(ctx_ranges).inspect_err(|err| { + error!(?err, "RUV ranges were not rebuilt correctly."); })?; - ruv.refresh_update_ruv(ctx_ranges).map_err(|e| { - error!("Unable to update RUV with supplier ranges."); - e + ruv.refresh_update_ruv(ctx_ranges).inspect_err(|err| { + error!(?err, "Unable to update RUV with supplier ranges."); })?; Ok(ConsumerState::Ok) @@ -488,9 +483,8 @@ impl<'a> QueryServerWriteTransaction<'a> { .iter() .map(EntryRefreshNew::from_repl_entry_v1) .collect::, _>>() - .map_err(|e| { - error!("Failed to convert entries from supplier"); - e + .inspect_err(|err| { + error!(?err, "Failed to convert entries from supplier"); })?; Plugins::run_pre_repl_refresh(self, candidates.as_slice()).map_err(|e| { @@ -573,10 +567,11 @@ impl<'a> QueryServerWriteTransaction<'a> { // == ⚠️ Below this point we begin to make changes! == // Update the d_uuid. This is what defines us as being part of this repl topology! - self.be_txn.set_db_d_uuid(ctx_domain_uuid).map_err(|e| { - error!("Failed to reset domain uuid"); - e - })?; + self.be_txn + .set_db_d_uuid(ctx_domain_uuid) + .inspect_err(|err| { + error!(?err, "Failed to reset domain uuid"); + })?; // We need to reset our server uuid now. This is so that any other servers // which had our former server_uuid in their RUV, is able to start to age it @@ -585,51 +580,46 @@ impl<'a> QueryServerWriteTransaction<'a> { // Delete all entries - *proper delete, not just tombstone!* - self.be_txn.danger_delete_all_db_content().map_err(|e| { - error!("Failed to clear existing server database content"); - e - })?; + self.be_txn + .danger_delete_all_db_content() + .inspect_err(|err| { + error!(?err, "Failed to clear existing server database content"); + })?; // Reset this transactions schema to a completely clean slate. - self.schema.generate_in_memory().map_err(|e| { - error!("Failed to reset in memory schema to clean state"); - e + self.schema.generate_in_memory().inspect_err(|err| { + error!(?err, "Failed to reset in memory schema to clean state"); })?; // Apply the schema entries first. This is the foundation that everything // else will build upon! self.consumer_refresh_create_entries(ctx_schema_entries) - .map_err(|e| { - error!("Failed to refresh schema entries"); - e + .inspect_err(|err| { + error!(?err, "Failed to refresh schema entries"); })?; // We need to reload schema now! - self.reload_schema().map_err(|e| { - error!("Failed to reload schema"); - e + self.reload_schema().inspect_err(|err| { + error!(?err, "Failed to reload schema"); })?; // We have to reindex to force all the existing indexes to be dumped // and recreated before we start to import. - self.reindex().map_err(|e| { - error!("Failed to reload schema"); - e + self.reindex().inspect_err(|err| { + error!(?err, "Failed to reload schema"); })?; // Apply the domain info entry / system info / system config entry? self.consumer_refresh_create_entries(ctx_meta_entries) - .map_err(|e| { - error!("Failed to refresh meta entries"); - e + .inspect_err(|err| { + error!(?err, "Failed to refresh meta entries"); })?; // NOTE: The domain info we receive here will have the domain version populated! // That's okay though, because all the incoming data is already at the right // version! - self.reload_domain_info().map_err(|e| { - error!("Failed to reload domain info"); - e + self.reload_domain_info().inspect_err(|err| { + error!(?err, "Failed to reload domain info"); })?; // Mark that everything changed so that post commit hooks function as expected. @@ -648,23 +638,20 @@ impl<'a> QueryServerWriteTransaction<'a> { // Create all the entries. Note we don't hit plugins here beside post repl plugs. self.consumer_refresh_create_entries(ctx_entries) - .map_err(|e| { - error!("Failed to refresh schema entries"); - e + .inspect_err(|err| { + error!(?err, "Failed to refresh schema entries"); })?; // Finally, confirm that the ranges that we have recreated match the ranges from our // context. Note that we get this in a writeable form! let ruv = self.be_txn.get_ruv_write(); - ruv.refresh_validate_ruv(ctx_ranges).map_err(|e| { - error!("RUV ranges were not rebuilt correctly."); - e + ruv.refresh_validate_ruv(ctx_ranges).inspect_err(|err| { + error!(?err, "RUV ranges were not rebuilt correctly."); })?; - ruv.refresh_update_ruv(ctx_ranges).map_err(|e| { - error!("Unable to update RUV with supplier ranges."); - e + ruv.refresh_update_ruv(ctx_ranges).inspect_err(|err| { + error!(?err, "Unable to update RUV with supplier ranges."); })?; Ok(()) diff --git a/server/lib/src/repl/entry.rs b/server/lib/src/repl/entry.rs index 8a8d94b28..620f7a43d 100644 --- a/server/lib/src/repl/entry.rs +++ b/server/lib/src/repl/entry.rs @@ -11,7 +11,7 @@ use std::collections::BTreeMap; pub enum State { Live { at: Cid, - changes: BTreeMap, + changes: BTreeMap, }, Tombstone { at: Cid, @@ -40,7 +40,7 @@ impl EntryChangeState { } pub fn new_without_schema(cid: &Cid, attrs: &Eattrs) -> Self { - let class = attrs.get(Attribute::Class.as_ref()); + let class = attrs.get(&Attribute::Class); let st = if class .as_ref() .map(|c| c.contains(&EntryClass::Tombstone.to_partialvalue())) @@ -75,7 +75,7 @@ impl EntryChangeState { .iter() .map(|(attr, cid)| { ( - attr.to_string(), + attr.clone(), DbCidV1 { server_id: cid.s_uuid, timestamp: cid.ts, @@ -109,7 +109,7 @@ impl EntryChangeState { .iter() .map(|(attr, cid)| { ( - attr.into(), + attr.clone(), Cid { s_uuid: cid.server_id, ts: cid.timestamp, @@ -159,19 +159,19 @@ impl EntryChangeState { EntryChangeState { st } } - pub fn change_ava(&mut self, cid: &Cid, attr: Attribute) { + pub fn change_ava(&mut self, cid: &Cid, attr: &Attribute) { match &mut self.st { State::Live { at: _, ref mut changes, } => { - if let Some(change) = changes.get_mut(attr.as_ref()) { + if let Some(change) = changes.get_mut(attr) { // Update the cid. if change != cid { *change = cid.clone() } } else { - changes.insert(attr.into(), cid.clone()); + changes.insert(attr.clone(), cid.clone()); } } State::Tombstone { .. } => { @@ -221,7 +221,7 @@ impl EntryChangeState { #[cfg(test)] pub(crate) fn get_attr_cid(&self, attr: Attribute) -> Option<&Cid> { match &self.st { - State::Live { at: _, changes } => changes.get(attr.as_ref()), + State::Live { at: _, changes } => changes.get(&attr), State::Tombstone { at: _ } => None, } } @@ -240,7 +240,7 @@ impl EntryChangeState { pub fn retain(&mut self, f: F) where - F: FnMut(&AttrString, &mut Cid) -> bool, + F: FnMut(&Attribute, &mut Cid) -> bool, { match &mut self.st { State::Live { at: _, changes } => changes.retain(f), @@ -256,7 +256,7 @@ impl EntryChangeState { entry_id: u64, results: &mut Vec>, ) { - let class = expected_attrs.get(Attribute::Class.as_ref()); + let class = expected_attrs.get(&Attribute::Class); let is_ts = class .as_ref() .map(|c| c.contains(&EntryClass::Tombstone.to_partialvalue())) diff --git a/server/lib/src/repl/proto.rs b/server/lib/src/repl/proto.rs index 0987dc747..7cd03a5b1 100644 --- a/server/lib/src/repl/proto.rs +++ b/server/lib/src/repl/proto.rs @@ -460,7 +460,7 @@ pub enum ReplStateV1 { Live { at: ReplCidV1, // Also add AT here for breaking entry origin on conflict. - attrs: BTreeMap, + attrs: BTreeMap, }, Tombstone { at: ReplCidV1, @@ -489,7 +489,7 @@ impl ReplEntryV1 { .iter() .filter_map(|(attr_name, cid)| { if schema.is_replicated(attr_name) { - let live_attr = live_attrs.get(attr_name.as_str()); + let live_attr = live_attrs.get(attr_name); let cid = cid.into(); let attr = live_attr.and_then(|maybe| @@ -507,7 +507,7 @@ impl ReplEntryV1 { } ); - Some((attr_name.to_string(), ReplAttrStateV1 { cid, attr })) + Some((attr_name.clone(), ReplAttrStateV1 { cid, attr })) } else { None } @@ -535,15 +535,13 @@ impl ReplEntryV1 { let mut eattrs = Eattrs::default(); for (attr_name, ReplAttrStateV1 { cid, attr }) in attrs.iter() { - let astring: AttrString = attr_name.as_str().into(); let cid: Cid = cid.into(); if let Some(attr_value) = attr { - let v = valueset::from_repl_v1(attr_value).map_err(|e| { - error!("Unable to restore valueset for {}", attr_name); - e + let v = valueset::from_repl_v1(attr_value).inspect_err(|err| { + error!(?err, "Unable to restore valueset for {}", attr_name); })?; - if eattrs.insert(astring.clone(), v).is_some() { + if eattrs.insert(attr_name.clone(), v).is_some() { error!( "Impossible eattrs state, attribute {} appears to be duplicated!", attr_name @@ -552,7 +550,7 @@ impl ReplEntryV1 { } } - if changes.insert(astring, cid).is_some() { + if changes.insert(attr_name.clone(), cid).is_some() { error!( "Impossible changes state, attribute {} appears to be duplicated!", attr_name @@ -576,9 +574,9 @@ impl ReplEntryV1 { let class_ava = vs_iutf8![EntryClass::Object.into(), EntryClass::Tombstone.into()]; let last_mod_ava = vs_cid![at.clone()]; - eattrs.insert(Attribute::Uuid.into(), vs_uuid![self.uuid]); - eattrs.insert(Attribute::Class.into(), class_ava); - eattrs.insert(Attribute::LastModifiedCid.into(), last_mod_ava); + eattrs.insert(Attribute::Uuid, vs_uuid![self.uuid]); + eattrs.insert(Attribute::Class, class_ava); + eattrs.insert(Attribute::LastModifiedCid, last_mod_ava); let ecstate = EntryChangeState { st: State::Tombstone { at }, @@ -632,7 +630,7 @@ impl ReplIncrementalEntryV1 { // Then setup to supply it. if within { - let live_attr = live_attrs.get(attr_name.as_str()); + let live_attr = live_attrs.get(attr_name); let cid = cid.into(); let attr = live_attr.and_then(|maybe| { if maybe.len() > 0 { @@ -642,7 +640,7 @@ impl ReplIncrementalEntryV1 { } }); - Some((attr_name.to_string(), ReplAttrStateV1 { cid, attr })) + Some((attr_name.clone(), ReplAttrStateV1 { cid, attr })) } else { None } @@ -669,15 +667,13 @@ impl ReplIncrementalEntryV1 { let mut eattrs = Eattrs::default(); for (attr_name, ReplAttrStateV1 { cid, attr }) in attrs.iter() { - let astring: AttrString = attr_name.as_str().into(); let cid: Cid = cid.into(); if let Some(attr_value) = attr { - let v = valueset::from_repl_v1(attr_value).map_err(|e| { - error!("Unable to restore valueset for {}", attr_name); - e + let v = valueset::from_repl_v1(attr_value).inspect_err(|err| { + error!(?err, "Unable to restore valueset for {}", attr_name); })?; - if eattrs.insert(astring.clone(), v).is_some() { + if eattrs.insert(attr_name.clone(), v).is_some() { error!( "Impossible eattrs state, attribute {} appears to be duplicated!", attr_name @@ -686,7 +682,7 @@ impl ReplIncrementalEntryV1 { } } - if changes.insert(astring, cid).is_some() { + if changes.insert(attr_name.clone(), cid).is_some() { error!( "Impossible changes state, attribute {} appears to be duplicated!", attr_name diff --git a/server/lib/src/repl/supplier.rs b/server/lib/src/repl/supplier.rs index 5e9145cd7..02136b1e3 100644 --- a/server/lib/src/repl/supplier.rs +++ b/server/lib/src/repl/supplier.rs @@ -327,9 +327,8 @@ impl<'a> QueryServerReadTransaction<'a> { .map(|e| ReplEntryV1::new(e.as_ref(), schema)) .collect() }) - .map_err(|e| { - error!("Failed to access schema entries"); - e + .inspect_err(|err| { + error!(?err, "Failed to access schema entries"); })?; let meta_entries = self @@ -339,9 +338,8 @@ impl<'a> QueryServerReadTransaction<'a> { .map(|e| ReplEntryV1::new(e.as_ref(), schema)) .collect() }) - .map_err(|e| { - error!("Failed to access meta entries"); - e + .inspect_err(|err| { + error!(?err, "Failed to access meta entries"); })?; let entries = self @@ -351,9 +349,8 @@ impl<'a> QueryServerReadTransaction<'a> { .map(|e| ReplEntryV1::new(e.as_ref(), schema)) .collect() }) - .map_err(|e| { - error!("Failed to access entries"); - e + .inspect_err(|err| { + error!(?err, "Failed to access entries"); })?; // Finally, populate the ranges with anchors from the RUV diff --git a/server/lib/src/repl/tests.rs b/server/lib/src/repl/tests.rs index 70b9fa51a..809ed8c38 100644 --- a/server/lib/src/repl/tests.rs +++ b/server/lib/src/repl/tests.rs @@ -1075,8 +1075,8 @@ async fn test_repl_increment_basic_bidirectional_recycle( changes: changes_right, }, ) => match ( - changes_left.get(Attribute::Class.into()), - changes_right.get(Attribute::Class.into()), + changes_left.get(&Attribute::Class), + changes_right.get(&Attribute::Class), ) { (Some(cid_left), Some(cid_right)) => cid_left < cid_right, _ => false, @@ -1647,12 +1647,12 @@ async fn test_repl_increment_schema_conflict(server_a: &QueryServer, server_b: & let ct = ct + Duration::from_secs(1); let mut server_b_txn = server_b.write(ct).await.unwrap(); let modlist = ModifyList::new_list(vec![ - Modify::Removed(Attribute::Class.into(), EntryClass::Person.into()), - Modify::Removed(Attribute::Class.into(), EntryClass::Account.into()), - Modify::Present(Attribute::Class.into(), EntryClass::Group.into()), - Modify::Purged(Attribute::IdVerificationEcKey.into()), - Modify::Purged(Attribute::NameHistory.into()), - Modify::Purged(Attribute::DisplayName.into()), + Modify::Removed(Attribute::Class, EntryClass::Person.into()), + Modify::Removed(Attribute::Class, EntryClass::Account.into()), + Modify::Present(Attribute::Class, EntryClass::Group.into()), + Modify::Purged(Attribute::IdVerificationEcKey), + Modify::Purged(Attribute::NameHistory), + Modify::Purged(Attribute::DisplayName), ]); assert!(server_b_txn.internal_modify_uuid(t_uuid, &modlist).is_ok()); server_b_txn.commit().expect("Failed to commit"); diff --git a/server/lib/src/schema.rs b/server/lib/src/schema.rs index a44da1f37..9dd07d173 100644 --- a/server/lib/src/schema.rs +++ b/server/lib/src/schema.rs @@ -45,9 +45,9 @@ use crate::valueset::ValueSet; /// [`Classes`]: struct.SchemaClass.html pub struct Schema { classes: CowCell>, - attributes: CowCell>, - unique_cache: CowCell>, - ref_cache: CowCell>, + attributes: CowCell>, + unique_cache: CowCell>, + ref_cache: CowCell>, } /// A writable transaction of the working schema set. You should not change this directly, @@ -55,19 +55,19 @@ pub struct Schema { /// you make will be lost when the server re-reads the schema from disk. pub struct SchemaWriteTransaction<'a> { classes: CowCellWriteTxn<'a, HashMap>, - attributes: CowCellWriteTxn<'a, HashMap>, + attributes: CowCellWriteTxn<'a, HashMap>, - unique_cache: CowCellWriteTxn<'a, Vec>, - ref_cache: CowCellWriteTxn<'a, HashMap>, + unique_cache: CowCellWriteTxn<'a, Vec>, + ref_cache: CowCellWriteTxn<'a, HashMap>, } /// A readonly transaction of the working schema set. pub struct SchemaReadTransaction { classes: CowCellReadTxn>, - attributes: CowCellReadTxn>, + attributes: CowCellReadTxn>, - unique_cache: CowCellReadTxn>, - ref_cache: CowCellReadTxn>, + unique_cache: CowCellReadTxn>, + ref_cache: CowCellReadTxn>, } /// An item representing an attribute and the rules that enforce it. These rules enforce if an @@ -79,7 +79,7 @@ pub struct SchemaReadTransaction { /// [`syntax`]: ../value/enum.SyntaxType.html #[derive(Debug, Clone, Default)] pub struct SchemaAttribute { - pub name: AttrString, + pub name: Attribute, pub uuid: Uuid, // Perhaps later add aliases? pub description: String, @@ -117,7 +117,7 @@ impl SchemaAttribute { .get_ava_single_iutf8(Attribute::AttributeName) .map(|s| s.into()) .ok_or_else(|| { - admin_error!("missing {} - {:?}", Attribute::AttributeName.as_ref(), uuid); + admin_error!("missing {} - {:?}", Attribute::AttributeName, uuid); OperationError::InvalidSchemaState("missing attributename".to_string()) })?; // description @@ -189,7 +189,11 @@ impl SchemaAttribute { // There may be a difference between a value and a filter value on complex // types - IE a complex type may have multiple parts that are secret, but a filter // on that may only use a single tagged attribute for example. - pub fn validate_partialvalue(&self, a: &str, v: &PartialValue) -> Result<(), SchemaError> { + pub fn validate_partialvalue( + &self, + a: &Attribute, + v: &PartialValue, + ) -> Result<(), SchemaError> { let r = match self.syntax { SyntaxType::Boolean => matches!(v, PartialValue::Bool(_)), SyntaxType::SyntaxId => matches!(v, PartialValue::Syntax(_)), @@ -259,7 +263,7 @@ impl SchemaAttribute { } } - pub fn validate_value(&self, a: &str, v: &Value) -> Result<(), SchemaError> { + pub fn validate_value(&self, a: &Attribute, v: &Value) -> Result<(), SchemaError> { let r = v.validate() && match self.syntax { SyntaxType::Boolean => matches!(v, Value::Bool(_)), @@ -323,7 +327,7 @@ impl SchemaAttribute { } } - pub fn validate_ava(&self, a: &str, ava: &ValueSet) -> Result<(), SchemaError> { + pub fn validate_ava(&self, a: &Attribute, ava: &ValueSet) -> Result<(), SchemaError> { trace!("Checking for valid {:?} -> {:?}", self.name, ava); // Check multivalue if !self.multivalue && ava.len() > 1 { @@ -351,7 +355,7 @@ impl From for EntryInitNew { entry.set_ava( Attribute::AttributeName, - vec![Value::new_iutf8(&value.name)], + vec![Value::new_iutf8(value.name.as_str())], ); entry.add_ava(Attribute::MultiValue, Value::Bool(value.multivalue)); // syntax @@ -409,17 +413,15 @@ impl From for EntryInitNew { /// [`access`]: ../access/index.html #[derive(Debug, Clone, Default)] pub struct SchemaClass { - // Is this used? - // class: Vec, pub name: AttrString, pub uuid: Uuid, pub description: String, pub sync_allowed: bool, /// This allows modification of system types to be extended in custom ways - pub systemmay: Vec, - pub may: Vec, - pub systemmust: Vec, - pub must: Vec, + pub systemmay: Vec, + pub may: Vec, + pub systemmust: Vec, + pub must: Vec, /// A list of classes that this extends. These are an "or", as at least one /// of the supplementing classes must also be present. Think of this as /// "inherits toward" or "provides". This is just as "strict" as requires but @@ -433,12 +435,11 @@ pub struct SchemaClass { impl SchemaClass { pub fn try_from(value: &Entry) -> Result { - trace!("Converting {}", value); // uuid let uuid = value.get_uuid(); // Convert entry to a schema class. if !value.attribute_equality(Attribute::Class, &EntryClass::ClassType.into()) { - admin_error!("class classtype not present - {:?}", uuid); + error!("class classtype not present - {:?}", uuid); return Err(OperationError::InvalidSchemaState( "missing classtype".to_string(), )); @@ -449,15 +450,16 @@ impl SchemaClass { .get_ava_single_iutf8(Attribute::ClassName) .map(AttrString::from) .ok_or_else(|| { - admin_error!("missing {} - {:?}", Attribute::ClassName, uuid); + error!("missing {} - {:?}", Attribute::ClassName, uuid); OperationError::InvalidSchemaState(format!("missing {}", Attribute::ClassName)) })?; + // description let description = value .get_ava_single_utf8(Attribute::Description) .map(String::from) .ok_or_else(|| { - admin_error!("missing {} - {}", Attribute::Description, name); + error!("missing {} - {}", Attribute::Description, name); OperationError::InvalidSchemaState(format!("missing {}", Attribute::Description)) })?; @@ -468,20 +470,24 @@ impl SchemaClass { // These are all "optional" lists of strings. let systemmay = value .get_ava_iter_iutf8(Attribute::SystemMay) - .map(|i| i.map(|v| v.into()).collect()) - .unwrap_or_default(); + .into_iter() + .flat_map(|iter| iter.map(Attribute::from)) + .collect(); let systemmust = value .get_ava_iter_iutf8(Attribute::SystemMust) - .map(|i| i.map(|v| v.into()).collect()) - .unwrap_or_default(); + .into_iter() + .flat_map(|iter| iter.map(Attribute::from)) + .collect(); let may = value .get_ava_iter_iutf8(Attribute::May) - .map(|i| i.map(|v| v.into()).collect()) - .unwrap_or_default(); + .into_iter() + .flat_map(|iter| iter.map(Attribute::from)) + .collect(); let must = value .get_ava_iter_iutf8(Attribute::Must) - .map(|i| i.map(|v| v.into()).collect()) - .unwrap_or_default(); + .into_iter() + .flat_map(|iter| iter.map(Attribute::from)) + .collect(); let systemsupplements = value .get_ava_iter_iutf8(Attribute::SystemSupplements) @@ -518,7 +524,7 @@ impl SchemaClass { /// An iterator over the full set of attrs that may or must exist /// on this class. - pub fn may_iter(&self) -> impl Iterator { + pub fn may_iter(&self) -> impl Iterator { self.systemmay .iter() .chain(self.may.iter()) @@ -562,7 +568,7 @@ impl From for EntryInitNew { if !value.systemmay.is_empty() { entry.set_ava( Attribute::SystemMay, - value.systemmay.iter().map(|s| Value::new_iutf8(s)), + value.systemmay.iter().map(|s| Value::new_iutf8(s.as_str())), ); } // systemexcludes @@ -576,7 +582,10 @@ impl From for EntryInitNew { if !value.systemmust.is_empty() { entry.set_ava( Attribute::SystemMust, - value.systemmust.iter().map(|s| Value::new_iutf8(s)), + value + .systemmust + .iter() + .map(|s| Value::new_iutf8(s.as_str())), ); } // systemsupplements @@ -593,10 +602,10 @@ impl From for EntryInitNew { pub trait SchemaTransaction { fn get_classes(&self) -> &HashMap; - fn get_attributes(&self) -> &HashMap; + fn get_attributes(&self) -> &HashMap; - fn get_attributes_unique(&self) -> &Vec; - fn get_reference_types(&self) -> &HashMap; + fn get_attributes_unique(&self) -> &Vec; + fn get_reference_types(&self) -> &HashMap; fn validate(&self) -> Vec> { let mut res = Vec::with_capacity(0); @@ -652,7 +661,7 @@ pub trait SchemaTransaction { res } - fn is_replicated(&self, attr: &str) -> bool { + fn is_replicated(&self, attr: &Attribute) -> bool { match self.get_attributes().get(attr) { Some(a_schema) => { // We'll likely add more conditions here later. @@ -669,7 +678,7 @@ pub trait SchemaTransaction { } } - fn is_multivalue(&self, attr: &str) -> Result { + fn is_multivalue(&self, attr: &Attribute) -> Result { match self.get_attributes().get(attr) { Some(a_schema) => Ok(a_schema.multivalue), None => { @@ -679,14 +688,10 @@ pub trait SchemaTransaction { } } - fn normalise_attr_name(&self, an: &str) -> AttrString { - // Will duplicate. - AttrString::from(an.to_lowercase()) - } - - fn normalise_attr_if_exists(&self, an: &str) -> Option { - if self.get_attributes().contains_key(an) { - Some(self.normalise_attr_name(an)) + fn normalise_attr_if_exists(&self, an: &str) -> Option { + let attr = Attribute::from(an); + if self.get_attributes().contains_key(&attr) { + Some(attr) } else { None } @@ -849,9 +854,9 @@ impl<'a> SchemaWriteTransaction<'a> { // Bootstrap in definitions of our own schema types // First, add all the needed core attributes for schema parsing self.attributes.insert( - EntryClass::Class.into(), + Attribute::Class, SchemaAttribute { - name: Attribute::Class.into(), + name: Attribute::Class, uuid: UUID_SCHEMA_ATTR_CLASS, description: String::from("The set of classes defining an object"), multivalue: true, @@ -864,9 +869,9 @@ impl<'a> SchemaWriteTransaction<'a> { }, ); self.attributes.insert( - Attribute::Uuid.into(), + Attribute::Uuid, SchemaAttribute { - name: Attribute::Uuid.into(), + name: Attribute::Uuid, uuid: UUID_SCHEMA_ATTR_UUID, description: String::from("The universal unique id of the object"), multivalue: false, @@ -881,9 +886,9 @@ impl<'a> SchemaWriteTransaction<'a> { }, ); self.attributes.insert( - Attribute::SourceUuid.into(), + Attribute::SourceUuid, SchemaAttribute { - name: Attribute::SourceUuid.into(), + name: Attribute::SourceUuid, uuid: UUID_SCHEMA_ATTR_SOURCE_UUID, description: String::from( "The universal unique id of the source object(s) which conflicted with this entry", @@ -900,9 +905,9 @@ impl<'a> SchemaWriteTransaction<'a> { }, ); self.attributes.insert( - Attribute::LastModifiedCid.into(), + Attribute::LastModifiedCid, SchemaAttribute { - name: Attribute::LastModifiedCid.into(), + name: Attribute::LastModifiedCid, uuid: UUID_SCHEMA_ATTR_LAST_MOD_CID, description: String::from("The cid of the last change to this object"), multivalue: false, @@ -917,9 +922,9 @@ impl<'a> SchemaWriteTransaction<'a> { }, ); self.attributes.insert( - Attribute::Name.into(), + Attribute::Name, SchemaAttribute { - name: Attribute::Name.into(), + name: Attribute::Name, uuid: UUID_SCHEMA_ATTR_NAME, description: String::from("The shortform name of an object"), multivalue: false, @@ -936,9 +941,9 @@ impl<'a> SchemaWriteTransaction<'a> { }, ); self.attributes.insert( - Attribute::Spn.into(), + Attribute::Spn, SchemaAttribute { - name: Attribute::Spn.into(), + name: Attribute::Spn, uuid: UUID_SCHEMA_ATTR_SPN, description: String::from( "The Security Principal Name of an object, unique across all domain trusts", @@ -953,9 +958,9 @@ impl<'a> SchemaWriteTransaction<'a> { }, ); self.attributes.insert( - Attribute::AttributeName.into(), + Attribute::AttributeName, SchemaAttribute { - name: Attribute::AttributeName.into(), + name: Attribute::AttributeName, uuid: UUID_SCHEMA_ATTR_ATTRIBUTENAME, description: String::from("The name of a schema attribute"), multivalue: false, @@ -968,9 +973,9 @@ impl<'a> SchemaWriteTransaction<'a> { }, ); self.attributes.insert( - Attribute::ClassName.into(), + Attribute::ClassName, SchemaAttribute { - name: Attribute::ClassName.into(), + name: Attribute::ClassName, uuid: UUID_SCHEMA_ATTR_CLASSNAME, description: String::from("The name of a schema class"), multivalue: false, @@ -983,9 +988,9 @@ impl<'a> SchemaWriteTransaction<'a> { }, ); self.attributes.insert( - Attribute::Description.into(), + Attribute::Description, SchemaAttribute { - name: Attribute::Description.into(), + name: Attribute::Description, uuid: UUID_SCHEMA_ATTR_DESCRIPTION, description: String::from("A description of an attribute, object or class"), multivalue: false, @@ -997,8 +1002,8 @@ impl<'a> SchemaWriteTransaction<'a> { syntax: SyntaxType::Utf8String, }, ); - self.attributes.insert(Attribute::MultiValue.into(), SchemaAttribute { - name: Attribute::MultiValue.into(), + self.attributes.insert(Attribute::MultiValue, SchemaAttribute { + name: Attribute::MultiValue, uuid: UUID_SCHEMA_ATTR_MULTIVALUE, description: String::from("If true, this attribute is able to store multiple values rather than just a single value."), multivalue: false, @@ -1009,8 +1014,8 @@ impl<'a> SchemaWriteTransaction<'a> { index: vec![], syntax: SyntaxType::Boolean, }); - self.attributes.insert(Attribute::Phantom.into(), SchemaAttribute { - name: Attribute::Phantom.into(), + self.attributes.insert(Attribute::Phantom, SchemaAttribute { + name: Attribute::Phantom, uuid: UUID_SCHEMA_ATTR_PHANTOM, description: String::from("If true, this attribute must NOT be present in any may/must sets of a class as. This represents generated attributes."), multivalue: false, @@ -1021,8 +1026,8 @@ impl<'a> SchemaWriteTransaction<'a> { index: vec![], syntax: SyntaxType::Boolean, }); - self.attributes.insert(Attribute::SyncAllowed.into(), SchemaAttribute { - name: Attribute::SyncAllowed.into(), + self.attributes.insert(Attribute::SyncAllowed, SchemaAttribute { + name: Attribute::SyncAllowed, uuid: UUID_SCHEMA_ATTR_SYNC_ALLOWED, description: String::from("If true, this attribute or class can by synchronised by an external scim import"), multivalue: false, @@ -1033,8 +1038,8 @@ impl<'a> SchemaWriteTransaction<'a> { index: vec![], syntax: SyntaxType::Boolean, }); - self.attributes.insert(Attribute::Replicated.into(), SchemaAttribute { - name: Attribute::Replicated.into(), + self.attributes.insert(Attribute::Replicated, SchemaAttribute { + name: Attribute::Replicated, uuid: UUID_SCHEMA_ATTR_REPLICATED, description: String::from("If true, this attribute or class can by replicated between nodes in the topology"), multivalue: false, @@ -1046,9 +1051,9 @@ impl<'a> SchemaWriteTransaction<'a> { syntax: SyntaxType::Boolean, }); self.attributes.insert( - Attribute::Unique.into(), + Attribute::Unique, SchemaAttribute { - name: Attribute::Unique.into(), + name: Attribute::Unique, uuid: UUID_SCHEMA_ATTR_UNIQUE, description: String::from( "If true, this attribute must store a unique value through out the database.", @@ -1063,9 +1068,9 @@ impl<'a> SchemaWriteTransaction<'a> { }, ); self.attributes.insert( - Attribute::Index.into(), + Attribute::Index, SchemaAttribute { - name: Attribute::Index.into(), + name: Attribute::Index, uuid: UUID_SCHEMA_ATTR_INDEX, description: String::from( "Describe the indexes to apply to instances of this attribute.", @@ -1080,9 +1085,9 @@ impl<'a> SchemaWriteTransaction<'a> { }, ); self.attributes.insert( - Attribute::Syntax.into(), + Attribute::Syntax, SchemaAttribute { - name: Attribute::Syntax.into(), + name: Attribute::Syntax, uuid: UUID_SCHEMA_ATTR_SYNTAX, description: String::from( "Describe the syntax of this attribute. This affects indexing and sorting.", @@ -1097,9 +1102,9 @@ impl<'a> SchemaWriteTransaction<'a> { }, ); self.attributes.insert( - Attribute::SystemMay.into(), + Attribute::SystemMay, SchemaAttribute { - name: Attribute::SystemMay.into(), + name: Attribute::SystemMay, uuid: UUID_SCHEMA_ATTR_SYSTEMMAY, description: String::from( "A list of system provided optional attributes this class can store.", @@ -1114,9 +1119,9 @@ impl<'a> SchemaWriteTransaction<'a> { }, ); self.attributes.insert( - Attribute::May.into(), + Attribute::May, SchemaAttribute { - name: Attribute::May.into(), + name: Attribute::May, uuid: UUID_SCHEMA_ATTR_MAY, description: String::from( "A user modifiable list of optional attributes this class can store.", @@ -1131,9 +1136,9 @@ impl<'a> SchemaWriteTransaction<'a> { }, ); self.attributes.insert( - Attribute::SystemMust.into(), + Attribute::SystemMust, SchemaAttribute { - name: Attribute::SystemMust.into(), + name: Attribute::SystemMust, uuid: UUID_SCHEMA_ATTR_SYSTEMMUST, description: String::from( "A list of system provided required attributes this class must store.", @@ -1148,9 +1153,9 @@ impl<'a> SchemaWriteTransaction<'a> { }, ); self.attributes.insert( - Attribute::Must.into(), + Attribute::Must, SchemaAttribute { - name: Attribute::Must.into(), + name: Attribute::Must, uuid: UUID_SCHEMA_ATTR_MUST, description: String::from( "A user modifiable list of required attributes this class must store.", @@ -1165,9 +1170,9 @@ impl<'a> SchemaWriteTransaction<'a> { }, ); self.attributes.insert( - Attribute::SystemSupplements.into(), + Attribute::SystemSupplements, SchemaAttribute { - name: Attribute::SystemSupplements.into(), + name: Attribute::SystemSupplements, uuid: UUID_SCHEMA_ATTR_SYSTEMSUPPLEMENTS, description: String::from( "A set of classes that this type supplements too, where this class can't exist without their presence.", @@ -1182,9 +1187,9 @@ impl<'a> SchemaWriteTransaction<'a> { }, ); self.attributes.insert( - Attribute::Supplements.into(), + Attribute::Supplements, SchemaAttribute { - name: Attribute::Supplements.into(), + name: Attribute::Supplements, uuid: UUID_SCHEMA_ATTR_SUPPLEMENTS, description: String::from( "A set of user modifiable classes, where this determines that at least one other type must supplement this type", @@ -1199,9 +1204,9 @@ impl<'a> SchemaWriteTransaction<'a> { }, ); self.attributes.insert( - Attribute::SystemExcludes.into(), + Attribute::SystemExcludes, SchemaAttribute { - name: Attribute::SystemExcludes.into(), + name: Attribute::SystemExcludes, uuid: UUID_SCHEMA_ATTR_SYSTEMEXCLUDES, description: String::from( "A set of classes that are denied presence in connection to this class", @@ -1216,9 +1221,9 @@ impl<'a> SchemaWriteTransaction<'a> { }, ); self.attributes.insert( - Attribute::Excludes.into(), + Attribute::Excludes, SchemaAttribute { - name: Attribute::Excludes.into(), + name: Attribute::Excludes, uuid: UUID_SCHEMA_ATTR_EXCLUDES, description: String::from( "A set of user modifiable classes that are denied presence in connection to this class", @@ -1236,9 +1241,9 @@ impl<'a> SchemaWriteTransaction<'a> { // SYSINFO attrs // ACP attributes. self.attributes.insert( - Attribute::AcpEnable.into(), + Attribute::AcpEnable, SchemaAttribute { - name: Attribute::AcpEnable.into(), + name: Attribute::AcpEnable, uuid: UUID_SCHEMA_ATTR_ACP_ENABLE, description: String::from("A flag to determine if this ACP is active for application. True is enabled, and enforce. False is checked but not enforced."), multivalue: false, @@ -1252,9 +1257,9 @@ impl<'a> SchemaWriteTransaction<'a> { ); self.attributes.insert( - Attribute::AcpReceiver.into(), + Attribute::AcpReceiver, SchemaAttribute { - name: Attribute::AcpReceiver.into(), + name: Attribute::AcpReceiver, uuid: UUID_SCHEMA_ATTR_ACP_RECEIVER, description: String::from( "Who the ACP applies to, constraining or allowing operations.", @@ -1269,9 +1274,9 @@ impl<'a> SchemaWriteTransaction<'a> { }, ); self.attributes.insert( - Attribute::AcpReceiverGroup.into(), + Attribute::AcpReceiverGroup, SchemaAttribute { - name: Attribute::AcpReceiverGroup.into(), + name: Attribute::AcpReceiverGroup, uuid: UUID_SCHEMA_ATTR_ACP_RECEIVER_GROUP, description: String::from( "The group that receives this access control to allow access", @@ -1287,9 +1292,9 @@ impl<'a> SchemaWriteTransaction<'a> { ); self.attributes.insert( - Attribute::AcpTargetScope.into(), + Attribute::AcpTargetScope, SchemaAttribute { - name: Attribute::AcpTargetScope.into(), + name: Attribute::AcpTargetScope, uuid: UUID_SCHEMA_ATTR_ACP_TARGETSCOPE, description: String::from( "The effective targets of the ACP, e.g. what will be acted upon.", @@ -1304,9 +1309,9 @@ impl<'a> SchemaWriteTransaction<'a> { }, ); self.attributes.insert( - Attribute::AcpSearchAttr.into(), + Attribute::AcpSearchAttr, SchemaAttribute { - name: Attribute::AcpSearchAttr.into(), + name: Attribute::AcpSearchAttr, uuid: UUID_SCHEMA_ATTR_ACP_SEARCH_ATTR, description: String::from( "The attributes that may be viewed or searched by the receiver on targetscope.", @@ -1321,9 +1326,9 @@ impl<'a> SchemaWriteTransaction<'a> { }, ); self.attributes.insert( - Attribute::AcpCreateClass.into(), + Attribute::AcpCreateClass, SchemaAttribute { - name: Attribute::AcpCreateClass.into(), + name: Attribute::AcpCreateClass, uuid: UUID_SCHEMA_ATTR_ACP_CREATE_CLASS, description: String::from("The set of classes that can be created on a new entry."), multivalue: true, @@ -1336,9 +1341,9 @@ impl<'a> SchemaWriteTransaction<'a> { }, ); self.attributes.insert( - Attribute::AcpCreateAttr.into(), + Attribute::AcpCreateAttr, SchemaAttribute { - name: Attribute::AcpCreateAttr.into(), + name: Attribute::AcpCreateAttr, uuid: UUID_SCHEMA_ATTR_ACP_CREATE_ATTR, description: String::from( "The set of attribute types that can be created on an entry.", @@ -1354,9 +1359,9 @@ impl<'a> SchemaWriteTransaction<'a> { ); self.attributes.insert( - Attribute::AcpModifyRemovedAttr.into(), + Attribute::AcpModifyRemovedAttr, SchemaAttribute { - name: Attribute::AcpModifyRemovedAttr.into(), + name: Attribute::AcpModifyRemovedAttr, uuid: UUID_SCHEMA_ATTR_ACP_MODIFY_REMOVEDATTR, description: String::from( "The set of attribute types that could be removed or purged in a modification.", @@ -1371,9 +1376,9 @@ impl<'a> SchemaWriteTransaction<'a> { }, ); self.attributes.insert( - Attribute::AcpModifyPresentAttr.into(), + Attribute::AcpModifyPresentAttr, SchemaAttribute { - name: Attribute::AcpModifyPresentAttr.into(), + name: Attribute::AcpModifyPresentAttr, uuid: UUID_SCHEMA_ATTR_ACP_MODIFY_PRESENTATTR, description: String::from( "The set of attribute types that could be added or asserted in a modification.", @@ -1388,9 +1393,9 @@ impl<'a> SchemaWriteTransaction<'a> { }, ); self.attributes.insert( - Attribute::AcpModifyClass.into(), + Attribute::AcpModifyClass, SchemaAttribute { - name: Attribute::AcpModifyClass.into(), + name: Attribute::AcpModifyClass, uuid: UUID_SCHEMA_ATTR_ACP_MODIFY_CLASS, description: String::from("The set of class values that could be asserted or added to an entry. Only applies to modify::present operations on class."), multivalue: true, @@ -1403,9 +1408,9 @@ impl<'a> SchemaWriteTransaction<'a> { }, ); self.attributes.insert( - Attribute::EntryManagedBy.into(), + Attribute::EntryManagedBy, SchemaAttribute { - name: Attribute::EntryManagedBy.into(), + name: Attribute::EntryManagedBy, uuid: UUID_SCHEMA_ATTR_ENTRY_MANAGED_BY, description: String::from( "A reference to a group that has access to manage the content of this entry.", @@ -1421,9 +1426,9 @@ impl<'a> SchemaWriteTransaction<'a> { ); // MO/Member self.attributes.insert( - Attribute::MemberOf.into(), + Attribute::MemberOf, SchemaAttribute { - name: Attribute::MemberOf.into(), + name: Attribute::MemberOf, uuid: UUID_SCHEMA_ATTR_MEMBEROF, description: String::from("reverse group membership of the object"), multivalue: true, @@ -1436,9 +1441,9 @@ impl<'a> SchemaWriteTransaction<'a> { }, ); self.attributes.insert( - Attribute::DirectMemberOf.into(), + Attribute::DirectMemberOf, SchemaAttribute { - name: Attribute::DirectMemberOf.into(), + name: Attribute::DirectMemberOf, uuid: UUID_SCHEMA_ATTR_DIRECTMEMBEROF, description: String::from("reverse direct group membership of the object"), multivalue: true, @@ -1451,9 +1456,9 @@ impl<'a> SchemaWriteTransaction<'a> { }, ); self.attributes.insert( - Attribute::RecycledDirectMemberOf.into(), + Attribute::RecycledDirectMemberOf, SchemaAttribute { - name: Attribute::RecycledDirectMemberOf.into(), + name: Attribute::RecycledDirectMemberOf, uuid: UUID_SCHEMA_ATTR_RECYCLEDDIRECTMEMBEROF, description: String::from("recycled reverse direct group membership of the object to assist in revive operations."), multivalue: true, @@ -1470,9 +1475,9 @@ impl<'a> SchemaWriteTransaction<'a> { }, ); self.attributes.insert( - Attribute::Member.into(), + Attribute::Member, SchemaAttribute { - name: Attribute::Member.into(), + name: Attribute::Member, uuid: UUID_SCHEMA_ATTR_MEMBER, description: String::from("List of members of the group"), multivalue: true, @@ -1485,9 +1490,9 @@ impl<'a> SchemaWriteTransaction<'a> { }, ); self.attributes.insert( - Attribute::DynMember.into(), + Attribute::DynMember, SchemaAttribute { - name: Attribute::DynMember.into(), + name: Attribute::DynMember, uuid: UUID_SCHEMA_ATTR_DYNMEMBER, description: String::from("List of dynamic members of the group"), multivalue: true, @@ -1501,9 +1506,9 @@ impl<'a> SchemaWriteTransaction<'a> { ); // Migration related self.attributes.insert( - Attribute::Version.into(), + Attribute::Version, SchemaAttribute { - name: Attribute::Version.into(), + name: Attribute::Version, uuid: UUID_SCHEMA_ATTR_VERSION, description: String::from( "The systems internal migration version for provided objects", @@ -1519,9 +1524,9 @@ impl<'a> SchemaWriteTransaction<'a> { ); // Domain for sysinfo self.attributes.insert( - Attribute::Domain.into(), + Attribute::Domain, SchemaAttribute { - name: Attribute::Domain.into(), + name: Attribute::Domain, uuid: UUID_SCHEMA_ATTR_DOMAIN, description: String::from("A DNS Domain name entry."), multivalue: true, @@ -1534,9 +1539,9 @@ impl<'a> SchemaWriteTransaction<'a> { }, ); self.attributes.insert( - Attribute::Claim.into(), + Attribute::Claim, SchemaAttribute { - name: Attribute::Claim.into(), + name: Attribute::Claim, uuid: UUID_SCHEMA_ATTR_CLAIM, description: String::from( "The string identifier of an extracted claim that can be filtered", @@ -1551,9 +1556,9 @@ impl<'a> SchemaWriteTransaction<'a> { }, ); self.attributes.insert( - Attribute::Scope.into(), + Attribute::Scope, SchemaAttribute { - name: Attribute::Scope.into(), + name: Attribute::Scope, uuid: UUID_SCHEMA_ATTR_SCOPE, description: String::from( "The string identifier of a permission scope in a session", @@ -1570,9 +1575,9 @@ impl<'a> SchemaWriteTransaction<'a> { // External Scim Sync self.attributes.insert( - Attribute::SyncExternalId.into(), + Attribute::SyncExternalId, SchemaAttribute { - name: Attribute::SyncExternalId.into(), + name: Attribute::SyncExternalId, uuid: UUID_SCHEMA_ATTR_SYNC_EXTERNAL_ID, description: String::from( "An external string ID of an entry imported from a sync agreement", @@ -1587,9 +1592,9 @@ impl<'a> SchemaWriteTransaction<'a> { }, ); self.attributes.insert( - Attribute::SyncParentUuid.into(), + Attribute::SyncParentUuid, SchemaAttribute { - name: Attribute::SyncParentUuid.into(), + name: Attribute::SyncParentUuid, uuid: UUID_SCHEMA_ATTR_SYNC_PARENT_UUID, description: String::from( "The UUID of the parent sync agreement that created this entry.", @@ -1604,9 +1609,9 @@ impl<'a> SchemaWriteTransaction<'a> { }, ); self.attributes.insert( - Attribute::SyncClass.into(), + Attribute::SyncClass, SchemaAttribute { - name: Attribute::SyncClass.into(), + name: Attribute::SyncClass, uuid: UUID_SCHEMA_ATTR_SYNC_CLASS, description: String::from("The set of classes requested by the sync client."), multivalue: true, @@ -1620,9 +1625,9 @@ impl<'a> SchemaWriteTransaction<'a> { ); self.attributes.insert( - Attribute::PasswordImport.into(), + Attribute::PasswordImport, SchemaAttribute { - name: Attribute::PasswordImport.into(), + name: Attribute::PasswordImport, uuid: UUID_SCHEMA_ATTR_PASSWORD_IMPORT, description: String::from("An imported password hash from an external system."), multivalue: false, @@ -1636,9 +1641,9 @@ impl<'a> SchemaWriteTransaction<'a> { ); self.attributes.insert( - Attribute::UnixPasswordImport.into(), + Attribute::UnixPasswordImport, SchemaAttribute { - name: Attribute::UnixPasswordImport.into(), + name: Attribute::UnixPasswordImport, uuid: UUID_SCHEMA_ATTR_UNIX_PASSWORD_IMPORT, description: String::from( "An imported unix password hash from an external system.", @@ -1654,9 +1659,9 @@ impl<'a> SchemaWriteTransaction<'a> { ); self.attributes.insert( - Attribute::TotpImport.into(), + Attribute::TotpImport, SchemaAttribute { - name: Attribute::TotpImport.into(), + name: Attribute::TotpImport, uuid: UUID_SCHEMA_ATTR_TOTP_IMPORT, description: String::from("An imported totp secret from an external system."), multivalue: true, @@ -1671,9 +1676,9 @@ impl<'a> SchemaWriteTransaction<'a> { // LDAP Masking Phantoms self.attributes.insert( - Attribute::Dn.into(), + Attribute::Dn, SchemaAttribute { - name: Attribute::Dn.into(), + name: Attribute::Dn, uuid: UUID_SCHEMA_ATTR_DN, description: String::from("An LDAP Compatible DN"), multivalue: false, @@ -1686,9 +1691,9 @@ impl<'a> SchemaWriteTransaction<'a> { }, ); self.attributes.insert( - Attribute::EntryDn.into(), + Attribute::EntryDn, SchemaAttribute { - name: Attribute::EntryDn.into(), + name: Attribute::EntryDn, uuid: UUID_SCHEMA_ATTR_ENTRYDN, description: String::from("An LDAP Compatible EntryDN"), multivalue: false, @@ -1701,9 +1706,9 @@ impl<'a> SchemaWriteTransaction<'a> { }, ); self.attributes.insert( - Attribute::EntryUuid.into(), + Attribute::EntryUuid, SchemaAttribute { - name: Attribute::EntryUuid.into(), + name: Attribute::EntryUuid, uuid: UUID_SCHEMA_ATTR_ENTRYUUID, description: String::from("An LDAP Compatible entryUUID"), multivalue: false, @@ -1716,9 +1721,9 @@ impl<'a> SchemaWriteTransaction<'a> { }, ); self.attributes.insert( - Attribute::ObjectClass.into(), + Attribute::ObjectClass, SchemaAttribute { - name: Attribute::ObjectClass.into(), + name: Attribute::ObjectClass, uuid: UUID_SCHEMA_ATTR_OBJECTCLASS, description: String::from("An LDAP Compatible objectClass"), multivalue: true, @@ -1731,9 +1736,9 @@ impl<'a> SchemaWriteTransaction<'a> { }, ); self.attributes.insert( - Attribute::Cn.into(), + Attribute::Cn, SchemaAttribute { - name: Attribute::Cn.into(), + name: Attribute::Cn, uuid: UUID_SCHEMA_ATTR_CN, description: String::from("An LDAP Compatible objectClass"), multivalue: false, @@ -1746,9 +1751,9 @@ impl<'a> SchemaWriteTransaction<'a> { }, ); self.attributes.insert( - Attribute::LdapKeys.into(), // keys + Attribute::LdapKeys, // keys SchemaAttribute { - name: Attribute::LdapKeys.into(), // keys + name: Attribute::LdapKeys, // keys uuid: UUID_SCHEMA_ATTR_KEYS, description: String::from("An LDAP Compatible keys (ssh)"), multivalue: true, @@ -1761,9 +1766,9 @@ impl<'a> SchemaWriteTransaction<'a> { }, ); self.attributes.insert( - Attribute::LdapSshPublicKey.into(), + Attribute::LdapSshPublicKey, SchemaAttribute { - name: Attribute::LdapSshPublicKey.into(), + name: Attribute::LdapSshPublicKey, uuid: UUID_SCHEMA_ATTR_SSHPUBLICKEY, description: String::from("An LDAP Compatible sshPublicKey"), multivalue: true, @@ -1776,9 +1781,9 @@ impl<'a> SchemaWriteTransaction<'a> { }, ); self.attributes.insert( - Attribute::Email.into(), + Attribute::Email, SchemaAttribute { - name: Attribute::Email.into(), + name: Attribute::Email, uuid: UUID_SCHEMA_ATTR_EMAIL, description: String::from("An LDAP Compatible email"), multivalue: true, @@ -1791,9 +1796,9 @@ impl<'a> SchemaWriteTransaction<'a> { }, ); self.attributes.insert( - Attribute::EmailPrimary.into(), + Attribute::EmailPrimary, SchemaAttribute { - name: Attribute::EmailPrimary.into(), + name: Attribute::EmailPrimary, uuid: UUID_SCHEMA_ATTR_EMAILPRIMARY, description: String::from("An LDAP Compatible primary email"), multivalue: false, @@ -1806,9 +1811,9 @@ impl<'a> SchemaWriteTransaction<'a> { }, ); self.attributes.insert( - Attribute::EmailAlternative.into(), + Attribute::EmailAlternative, SchemaAttribute { - name: Attribute::EmailAlternative.into(), + name: Attribute::EmailAlternative, uuid: UUID_SCHEMA_ATTR_EMAILALTERNATIVE, description: String::from("An LDAP Compatible alternative email"), multivalue: false, @@ -1821,9 +1826,9 @@ impl<'a> SchemaWriteTransaction<'a> { }, ); self.attributes.insert( - Attribute::LdapEmailAddress.into(), + Attribute::LdapEmailAddress, SchemaAttribute { - name: Attribute::LdapEmailAddress.into(), + name: Attribute::LdapEmailAddress, uuid: UUID_SCHEMA_ATTR_EMAILADDRESS, description: String::from("An LDAP Compatible emailAddress"), multivalue: true, @@ -1836,9 +1841,9 @@ impl<'a> SchemaWriteTransaction<'a> { }, ); self.attributes.insert( - Attribute::Gecos.into(), + Attribute::Gecos, SchemaAttribute { - name: Attribute::Gecos.into(), + name: Attribute::Gecos, uuid: UUID_SCHEMA_ATTR_GECOS, description: String::from("An LDAP Compatible gecos."), multivalue: false, @@ -1851,9 +1856,9 @@ impl<'a> SchemaWriteTransaction<'a> { }, ); self.attributes.insert( - Attribute::Uid.into(), + Attribute::Uid, SchemaAttribute { - name: Attribute::Uid.into(), + name: Attribute::Uid, uuid: UUID_SCHEMA_ATTR_UID, description: String::from("An LDAP Compatible uid."), multivalue: false, @@ -1866,9 +1871,9 @@ impl<'a> SchemaWriteTransaction<'a> { }, ); self.attributes.insert( - Attribute::UidNumber.into(), + Attribute::UidNumber, SchemaAttribute { - name: Attribute::UidNumber.into(), + name: Attribute::UidNumber, uuid: UUID_SCHEMA_ATTR_UIDNUMBER, description: String::from("An LDAP Compatible uidNumber."), multivalue: false, @@ -1881,9 +1886,9 @@ impl<'a> SchemaWriteTransaction<'a> { }, ); self.attributes.insert( - Attribute::SudoHost.into(), + Attribute::SudoHost, SchemaAttribute { - name: Attribute::SudoHost.into(), + name: Attribute::SudoHost, uuid: UUID_SCHEMA_ATTR_SUDOHOST, description: String::from("An LDAP Compatible sudohost."), multivalue: false, @@ -1897,9 +1902,9 @@ impl<'a> SchemaWriteTransaction<'a> { ); // end LDAP masking phantoms self.attributes.insert( - Attribute::Image.into(), + Attribute::Image, SchemaAttribute { - name: Attribute::Image.into(), + name: Attribute::Image, uuid: UUID_SCHEMA_ATTR_IMAGE, description: String::from("An image for display to end users."), multivalue: false, @@ -1919,18 +1924,18 @@ impl<'a> SchemaWriteTransaction<'a> { uuid: UUID_SCHEMA_CLASS_ATTRIBUTETYPE, description: String::from("Definition of a schema attribute"), systemmay: vec![ - Attribute::Replicated.into(), - Attribute::Phantom.into(), - Attribute::SyncAllowed.into(), - Attribute::Index.into(), + Attribute::Replicated, + Attribute::Phantom, + Attribute::SyncAllowed, + Attribute::Index, ], systemmust: vec![ - Attribute::Class.into(), - Attribute::AttributeName.into(), - Attribute::MultiValue.into(), - Attribute::Unique.into(), - Attribute::Syntax.into(), - Attribute::Description.into(), + Attribute::Class, + Attribute::AttributeName, + Attribute::MultiValue, + Attribute::Unique, + Attribute::Syntax, + Attribute::Description, ], systemexcludes: vec![EntryClass::ClassType.into()], ..Default::default() @@ -1943,20 +1948,20 @@ impl<'a> SchemaWriteTransaction<'a> { uuid: UUID_SCHEMA_CLASS_CLASSTYPE, description: String::from("Definition of a schema classtype"), systemmay: vec![ - Attribute::SyncAllowed.into(), - Attribute::SystemMay.into(), - Attribute::May.into(), - Attribute::SystemMust.into(), - Attribute::Must.into(), - Attribute::SystemSupplements.into(), - Attribute::Supplements.into(), - Attribute::SystemExcludes.into(), - Attribute::Excludes.into(), + Attribute::SyncAllowed, + Attribute::SystemMay, + Attribute::May, + Attribute::SystemMust, + Attribute::Must, + Attribute::SystemSupplements, + Attribute::Supplements, + Attribute::SystemExcludes, + Attribute::Excludes, ], systemmust: vec![ - Attribute::Class.into(), - Attribute::ClassName.into(), - Attribute::Description.into(), + Attribute::Class, + Attribute::ClassName, + Attribute::Description, ], systemexcludes: vec![Attribute::AttributeType.into()], ..Default::default() @@ -1968,14 +1973,11 @@ impl<'a> SchemaWriteTransaction<'a> { name: EntryClass::Object.into(), uuid: UUID_SCHEMA_CLASS_OBJECT, description: String::from("A system created class that all objects must contain"), - systemmay: vec![ - Attribute::Description.into(), - Attribute::EntryManagedBy.into(), - ], + systemmay: vec![Attribute::Description, Attribute::EntryManagedBy], systemmust: vec![ - Attribute::Class.into(), - Attribute::Uuid.into(), - Attribute::LastModifiedCid.into(), + Attribute::Class, + Attribute::Uuid, + Attribute::LastModifiedCid, ], ..Default::default() }, @@ -1997,7 +1999,7 @@ impl<'a> SchemaWriteTransaction<'a> { description: String::from( "Class that is dynamically added to recipients of memberof or directmemberof", ), - systemmay: vec![Attribute::MemberOf.into(), Attribute::DirectMemberOf.into()], + systemmay: vec![Attribute::MemberOf, Attribute::DirectMemberOf], ..Default::default() }, ); @@ -2019,7 +2021,7 @@ impl<'a> SchemaWriteTransaction<'a> { name: EntryClass::Recycled.into(), uuid: UUID_SCHEMA_CLASS_RECYCLED, description: String::from("An object that has been deleted, but still recoverable via the revive operation. Recycled objects are not modifiable, only revivable."), - systemmay: vec![Attribute::RecycledDirectMemberOf.into()], + systemmay: vec![Attribute::RecycledDirectMemberOf], .. Default::default() }, ); @@ -2030,8 +2032,8 @@ impl<'a> SchemaWriteTransaction<'a> { uuid: UUID_SCHEMA_CLASS_TOMBSTONE, description: String::from("An object that is purged from the recycle bin. This is a system internal state. Tombstones have no attributes beside UUID."), systemmust: vec![ - Attribute::Class.into(), - Attribute::Uuid.into(), + Attribute::Class, + Attribute::Uuid, ], .. Default::default() }, @@ -2044,7 +2046,7 @@ impl<'a> SchemaWriteTransaction<'a> { description: String::from( "An entry representing conflicts that occurred during replication", ), - systemmust: vec![Attribute::SourceUuid.into()], + systemmust: vec![Attribute::SourceUuid], systemsupplements: vec![EntryClass::Recycled.into()], ..Default::default() }, @@ -2056,7 +2058,7 @@ impl<'a> SchemaWriteTransaction<'a> { name: EntryClass::SystemInfo.into(), uuid: UUID_SCHEMA_CLASS_SYSTEM_INFO, description: String::from("System metadata object class"), - systemmust: vec![Attribute::Version.into()], + systemmust: vec![Attribute::Version], ..Default::default() }, ); @@ -2067,7 +2069,7 @@ impl<'a> SchemaWriteTransaction<'a> { name: EntryClass::AccessControlSearch.into(), uuid: UUID_SCHEMA_CLASS_ACCESS_CONTROL_SEARCH, description: String::from("System Access Control Search Class"), - systemmust: vec![Attribute::AcpSearchAttr.into()], + systemmust: vec![Attribute::AcpSearchAttr], ..Default::default() }, ); @@ -2087,9 +2089,9 @@ impl<'a> SchemaWriteTransaction<'a> { uuid: UUID_SCHEMA_CLASS_ACCESS_CONTROL_MODIFY, description: String::from("System Access Control Modify Class"), systemmay: vec![ - Attribute::AcpModifyRemovedAttr.into(), - Attribute::AcpModifyPresentAttr.into(), - Attribute::AcpModifyClass.into(), + Attribute::AcpModifyRemovedAttr, + Attribute::AcpModifyPresentAttr, + Attribute::AcpModifyClass, ], ..Default::default() }, @@ -2100,10 +2102,7 @@ impl<'a> SchemaWriteTransaction<'a> { name: EntryClass::AccessControlCreate.into(), uuid: UUID_SCHEMA_CLASS_ACCESS_CONTROL_CREATE, description: String::from("System Access Control Create Class"), - systemmay: vec![ - Attribute::AcpCreateClass.into(), - Attribute::AcpCreateAttr.into(), - ], + systemmay: vec![Attribute::AcpCreateClass, Attribute::AcpCreateAttr], ..Default::default() }, ); @@ -2113,8 +2112,8 @@ impl<'a> SchemaWriteTransaction<'a> { name: EntryClass::AccessControlProfile.into(), uuid: UUID_SCHEMA_CLASS_ACCESS_CONTROL_PROFILE, description: String::from("System Access Control Profile Class"), - systemmay: vec![Attribute::AcpEnable.into(), Attribute::Description.into()], - systemmust: vec![Attribute::Name.into()], + systemmay: vec![Attribute::AcpEnable, Attribute::Description], + systemmust: vec![Attribute::Name], systemsupplements: vec![ EntryClass::AccessControlSearch.into(), EntryClass::AccessControlDelete.into(), @@ -2141,8 +2140,8 @@ impl<'a> SchemaWriteTransaction<'a> { name: EntryClass::AccessControlReceiverGroup.into(), uuid: UUID_SCHEMA_CLASS_ACCESS_CONTROL_RECEIVER_GROUP, description: String::from("System Access Control Profile Receiver - Group"), - systemmay: vec![Attribute::AcpReceiver.into()], - systemmust: vec![Attribute::AcpReceiverGroup.into()], + systemmay: vec![Attribute::AcpReceiver], + systemmust: vec![Attribute::AcpReceiverGroup], systemsupplements: vec![EntryClass::AccessControlProfile.into()], systemexcludes: vec![EntryClass::AccessControlReceiverEntryManager.into()], ..Default::default() @@ -2154,7 +2153,7 @@ impl<'a> SchemaWriteTransaction<'a> { name: EntryClass::AccessControlTargetScope.into(), uuid: UUID_SCHEMA_CLASS_ACCESS_CONTROL_TARGET_SCOPE, description: String::from("System Access Control Profile Target - Scope"), - systemmust: vec![Attribute::AcpTargetScope.into()], + systemmust: vec![Attribute::AcpTargetScope], systemsupplements: vec![EntryClass::AccessControlProfile.into()], ..Default::default() }, @@ -2177,11 +2176,11 @@ impl<'a> SchemaWriteTransaction<'a> { uuid: UUID_SCHEMA_CLASS_SYNC_OBJECT, description: String::from("A class denoting that an entry is synchronised from an external source. This entry may not be modifiable."), systemmust: vec![ - Attribute::SyncParentUuid.into() + Attribute::SyncParentUuid ], systemmay: vec![ - Attribute::SyncExternalId.into(), - Attribute::SyncClass.into(), + Attribute::SyncExternalId, + Attribute::SyncClass, ], .. Default::default() }, @@ -2199,11 +2198,11 @@ impl<'a> SchemaWriteTransaction<'a> { } impl<'a> SchemaTransaction for SchemaWriteTransaction<'a> { - fn get_attributes_unique(&self) -> &Vec { + fn get_attributes_unique(&self) -> &Vec { &self.unique_cache } - fn get_reference_types(&self) -> &HashMap { + fn get_reference_types(&self) -> &HashMap { &self.ref_cache } @@ -2211,17 +2210,17 @@ impl<'a> SchemaTransaction for SchemaWriteTransaction<'a> { &self.classes } - fn get_attributes(&self) -> &HashMap { + fn get_attributes(&self) -> &HashMap { &self.attributes } } impl SchemaTransaction for SchemaReadTransaction { - fn get_attributes_unique(&self) -> &Vec { + fn get_attributes_unique(&self) -> &Vec { &self.unique_cache } - fn get_reference_types(&self) -> &HashMap { + fn get_reference_types(&self) -> &HashMap { &self.ref_cache } @@ -2229,7 +2228,7 @@ impl SchemaTransaction for SchemaReadTransaction { &self.classes } - fn get_attributes(&self) -> &HashMap { + fn get_attributes(&self) -> &HashMap { &self.attributes } } @@ -2549,7 +2548,7 @@ mod tests { // Test single value string let single_value_string = SchemaAttribute { - name: AttrString::from("single_value"), + name: Attribute::from("single_value"), uuid: Uuid::new_v4(), description: String::from(""), index: vec![IndexType::Equality], @@ -2557,11 +2556,12 @@ mod tests { ..Default::default() }; - let r1 = single_value_string.validate_ava("single_value", &(vs_iutf8!["test"] as _)); + let r1 = single_value_string + .validate_ava(&Attribute::from("single_value"), &(vs_iutf8!["test"] as _)); assert_eq!(r1, Ok(())); let rvs = vs_iutf8!["test1", "test2"] as _; - let r2 = single_value_string.validate_ava("single_value", &rvs); + let r2 = single_value_string.validate_ava(&Attribute::from("single_value"), &rvs); assert_eq!( r2, Err(SchemaError::InvalidAttributeSyntax( @@ -2572,7 +2572,7 @@ mod tests { // test multivalue string, boolean let multi_value_string = SchemaAttribute { - name: AttrString::from("mv_string"), + name: Attribute::from("mv_string"), uuid: Uuid::new_v4(), description: String::from(""), multivalue: true, @@ -2582,11 +2582,11 @@ mod tests { }; let rvs = vs_utf8!["test1".to_string(), "test2".to_string()] as _; - let r5 = multi_value_string.validate_ava("mv_string", &rvs); + let r5 = multi_value_string.validate_ava(&Attribute::from("mv_string"), &rvs); assert_eq!(r5, Ok(())); let multi_value_boolean = SchemaAttribute { - name: AttrString::from("mv_bool"), + name: Attribute::from("mv_bool"), uuid: Uuid::new_v4(), description: String::from(""), multivalue: true, @@ -2612,12 +2612,12 @@ mod tests { */ let rvs = vs_bool![true, false]; - let r4 = multi_value_boolean.validate_ava("mv_bool", &(rvs as _)); + let r4 = multi_value_boolean.validate_ava(&Attribute::from("mv_bool"), &(rvs as _)); assert_eq!(r4, Ok(())); // syntax_id and index_type values let single_value_syntax = SchemaAttribute { - name: AttrString::from("sv_syntax"), + name: Attribute::from("sv_syntax"), uuid: Uuid::new_v4(), description: String::from(""), index: vec![IndexType::Equality], @@ -2626,18 +2626,18 @@ mod tests { }; let rvs = vs_syntax![SyntaxType::try_from("UTF8STRING").unwrap()] as _; - let r6 = single_value_syntax.validate_ava("sv_syntax", &rvs); + let r6 = single_value_syntax.validate_ava(&Attribute::from("sv_syntax"), &rvs); assert_eq!(r6, Ok(())); let rvs = vs_utf8!["thaeountaheu".to_string()] as _; - let r7 = single_value_syntax.validate_ava("sv_syntax", &rvs); + let r7 = single_value_syntax.validate_ava(&Attribute::from("sv_syntax"), &rvs); assert_eq!( r7, Err(SchemaError::InvalidAttributeSyntax("sv_syntax".to_string())) ); let single_value_index = SchemaAttribute { - name: AttrString::from("sv_index"), + name: Attribute::from("sv_index"), uuid: Uuid::new_v4(), description: String::from(""), index: vec![IndexType::Equality], @@ -2646,11 +2646,11 @@ mod tests { }; // let rvs = vs_index![IndexType::try_from("EQUALITY").unwrap()] as _; - let r8 = single_value_index.validate_ava("sv_index", &rvs); + let r8 = single_value_index.validate_ava(&Attribute::from("sv_index"), &rvs); assert_eq!(r8, Ok(())); let rvs = vs_utf8!["thaeountaheu".to_string()] as _; - let r9 = single_value_index.validate_ava("sv_index", &rvs); + let r9 = single_value_index.validate_ava(&Attribute::from("sv_index"), &rvs); assert_eq!( r9, Err(SchemaError::InvalidAttributeSyntax("sv_index".to_string())) @@ -2676,9 +2676,7 @@ mod tests { assert_eq!( e_no_uuid.validate(&schema), - Err(SchemaError::MissingMustAttribute(vec![ - Attribute::Uuid.to_string() - ])) + Err(SchemaError::MissingMustAttribute(vec![Attribute::Uuid])) ); let e_no_class = entry_init!(( @@ -2970,7 +2968,7 @@ mod tests { name: AttrString::from("testobject"), uuid: Uuid::new_v4(), description: String::from("test object"), - systemmay: vec![Attribute::Claim.into()], + systemmay: vec![Attribute::Claim], ..Default::default() }; @@ -2995,9 +2993,9 @@ mod tests { uuid: Uuid::new_v4(), description: String::from("account object"), systemmust: vec![ - Attribute::Class.into(), - Attribute::Uuid.into(), - Attribute::LastModifiedCid.into(), + Attribute::Class, + Attribute::Uuid, + Attribute::LastModifiedCid, ], systemsupplements: vec![EntryClass::Service.into(), EntryClass::Person.into()], ..Default::default() @@ -3008,9 +3006,9 @@ mod tests { uuid: Uuid::new_v4(), description: String::from("person object"), systemmust: vec![ - Attribute::Class.into(), - Attribute::Uuid.into(), - Attribute::LastModifiedCid.into(), + Attribute::Class, + Attribute::Uuid, + Attribute::LastModifiedCid, ], ..Default::default() }; @@ -3020,9 +3018,9 @@ mod tests { uuid: Uuid::new_v4(), description: String::from("service object"), systemmust: vec![ - Attribute::Class.into(), - Attribute::Uuid.into(), - Attribute::LastModifiedCid.into(), + Attribute::Class, + Attribute::Uuid, + Attribute::LastModifiedCid, ], excludes: vec![EntryClass::Person.into()], ..Default::default() diff --git a/server/lib/src/server/access/mod.rs b/server/lib/src/server/access/mod.rs index e8dd80fd4..358f3a825 100644 --- a/server/lib/src/server/access/mod.rs +++ b/server/lib/src/server/access/mod.rs @@ -52,6 +52,13 @@ mod search; #[derive(Debug, Clone, PartialEq, Eq)] pub enum Access { + Grant, + Denied, + Allow(BTreeSet), +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum AccessClass { Grant, Denied, Allow(BTreeSet), @@ -66,17 +73,33 @@ pub struct AccessEffectivePermission { pub search: Access, pub modify_pres: Access, pub modify_rem: Access, - pub modify_class: Access, + pub modify_class: AccessClass, } -pub enum AccessResult<'a> { +pub enum AccessResult { // Deny this operation unconditionally. Denied, // Unbounded allow, provided no denied exists. Grant, // This module makes no decisions about this entry. Ignore, - // Limit the allowed attr set to this. + // Limit the allowed attr set to this - this doesn't + // allow anything, it constrains what might be allowed. + Constrain(BTreeSet), + // Allow these attributes within constraints. + Allow(BTreeSet), +} + +#[allow(dead_code)] +pub enum AccessResultClass<'a> { + // Deny this operation unconditionally. + Denied, + // Unbounded allow, provided no denied exists. + Grant, + // This module makes no decisions about this entry. + Ignore, + // Limit the allowed attr set to this - this doesn't + // allow anything, it constrains what might be allowed. Constrain(BTreeSet<&'a str>), // Allow these attributes within constraints. Allow(BTreeSet<&'a str>), @@ -92,7 +115,7 @@ struct AccessControlsInner { acps_create: Vec, acps_modify: Vec, acps_delete: Vec, - sync_agreements: HashMap>, + sync_agreements: HashMap>, // Oauth2 // Sync prov } @@ -149,7 +172,7 @@ pub trait AccessControlsTransaction<'a> { fn get_create(&self) -> &Vec; fn get_modify(&self) -> &Vec; fn get_delete(&self) -> &Vec; - fn get_sync_agreements(&self) -> &HashMap>; + fn get_sync_agreements(&self) -> &HashMap>; #[allow(clippy::mut_from_ref)] fn get_acp_resolve_filter_cache(&self) -> &mut ResolveFilterCacheReadTxn<'a>; @@ -238,7 +261,7 @@ pub trait AccessControlsTransaction<'a> { // Get the set of attributes requested by this se filter. This is what we are // going to access check. - let requested_attrs: BTreeSet<&str> = filter_orig.get_attr_set(); + let requested_attrs: BTreeSet = filter_orig.get_attr_set(); // First get the set of acps that apply to this receiver let related_acp = self.search_related_acp(ident); @@ -299,10 +322,6 @@ pub trait AccessControlsTransaction<'a> { ) -> Result>, OperationError> { // Build a reference set from the req_attrs. This is what we test against // to see if the attribute is something we currently want. - let requested_attrs: Option> = se - .attrs - .as_ref() - .map(|vs| vs.iter().map(|s| s.as_str()).collect()); // Get the relevant acps for this receiver. let related_acp = self.search_related_acp(&se.ident); @@ -331,13 +350,13 @@ pub trait AccessControlsTransaction<'a> { SearchResult::Allow(allowed_attrs) => { // The allow set constrained. debug!( - requested = ?requested_attrs, + requested = ?se.attrs, allowed = ?allowed_attrs, "reduction", ); // Reduce requested by allowed. - let reduced_attrs = if let Some(requested) = requested_attrs.as_ref() { + let reduced_attrs = if let Some(requested) = se.attrs.as_ref() { requested & &allowed_attrs } else { allowed_attrs @@ -423,21 +442,21 @@ pub trait AccessControlsTransaction<'a> { let related_acp: Vec<_> = self.modify_related_acp(&me.ident); // build two sets of "requested pres" and "requested rem" - let requested_pres: BTreeSet<&str> = me + let requested_pres: BTreeSet = me .modlist .iter() .filter_map(|m| match m { - Modify::Present(a, _) => Some(a.as_str()), + Modify::Present(a, _) => Some(a.clone()), _ => None, }) .collect(); - let requested_rem: BTreeSet<&str> = me + let requested_rem: BTreeSet = me .modlist .iter() .filter_map(|m| match m { - Modify::Removed(a, _) => Some(a.as_str()), - Modify::Purged(a) => Some(a.as_str()), + Modify::Removed(a, _) => Some(a.clone()), + Modify::Purged(a) => Some(a.clone()), _ => None, }) .collect(); @@ -556,19 +575,19 @@ pub trait AccessControlsTransaction<'a> { } // build two sets of "requested pres" and "requested rem" - let requested_pres: BTreeSet<&str> = modlist + let requested_pres: BTreeSet = modlist .iter() .filter_map(|m| match m { - Modify::Present(a, _) => Some(a.as_str()), + Modify::Present(a, _) => Some(a.clone()), _ => None, }) .collect(); - let requested_rem: BTreeSet<&str> = modlist + let requested_rem: BTreeSet = modlist .iter() .filter_map(|m| match m { - Modify::Removed(a, _) => Some(a.as_str()), - Modify::Purged(a) => Some(a.as_str()), + Modify::Removed(a, _) => Some(a.clone()), + Modify::Purged(a) => Some(a.clone()), _ => None, }) .collect(); @@ -756,7 +775,7 @@ pub trait AccessControlsTransaction<'a> { fn effective_permission_check( &self, ident: &Identity, - attrs: Option>, + attrs: Option>, entries: &[Arc], ) -> Result, OperationError> { // I think we need a structure like " CheckResult, which is in the order of the @@ -816,7 +835,7 @@ pub trait AccessControlsTransaction<'a> { SearchResult::Grant => Access::Grant, SearchResult::Allow(allowed_attrs) => { // Bound by requested attrs? - Access::Allow(allowed_attrs.into_iter().map(|s| s.into()).collect()) + Access::Allow(allowed_attrs.into_iter().collect()) } }; @@ -827,12 +846,12 @@ pub trait AccessControlsTransaction<'a> { sync_agmts, e, ) { - ModifyResult::Denied => (Access::Denied, Access::Denied, Access::Denied), - ModifyResult::Grant => (Access::Grant, Access::Grant, Access::Grant), + ModifyResult::Denied => (Access::Denied, Access::Denied, AccessClass::Denied), + ModifyResult::Grant => (Access::Grant, Access::Grant, AccessClass::Grant), ModifyResult::Allow { pres, rem, cls } => ( - Access::Allow(pres.into_iter().map(|s| s.into()).collect()), - Access::Allow(rem.into_iter().map(|s| s.into()).collect()), - Access::Allow(cls.into_iter().map(|s| s.into()).collect()), + Access::Allow(pres.into_iter().collect()), + Access::Allow(rem.into_iter().collect()), + AccessClass::Allow(cls.into_iter().map(|s| s.into()).collect()), ), }; @@ -904,7 +923,10 @@ impl<'a> AccessControlsWriteTransaction<'a> { Ok(()) } - pub fn update_sync_agreements(&mut self, mut sync_agreements: HashMap>) { + pub fn update_sync_agreements( + &mut self, + mut sync_agreements: HashMap>, + ) { std::mem::swap( &mut sync_agreements, &mut self.inner.deref_mut().sync_agreements, @@ -935,7 +957,7 @@ impl<'a> AccessControlsTransaction<'a> for AccessControlsWriteTransaction<'a> { &self.inner.acps_delete } - fn get_sync_agreements(&self) -> &HashMap> { + fn get_sync_agreements(&self) -> &HashMap> { &self.inner.sync_agreements } @@ -978,7 +1000,7 @@ impl<'a> AccessControlsTransaction<'a> for AccessControlsReadTransaction<'a> { &self.inner.acps_delete } - fn get_sync_agreements(&self) -> &HashMap> { + fn get_sync_agreements(&self) -> &HashMap> { &self.inner.sync_agreements } @@ -1052,7 +1074,7 @@ mod tests { AccessControlCreate, AccessControlDelete, AccessControlModify, AccessControlProfile, AccessControlSearch, AccessControlTarget, }, - Access, AccessControls, AccessControlsTransaction, AccessEffectivePermission, + Access, AccessClass, AccessControls, AccessControlsTransaction, AccessEffectivePermission, }; use crate::prelude::*; @@ -1797,7 +1819,7 @@ mod tests { )), ); // the requested attrs here. - se_anon.attrs = Some(btreeset![Attribute::Name.into()]); + se_anon.attrs = Some(btreeset![Attribute::Name]); let acp = AccessControlSearch::from_raw( "test_acp", @@ -1852,7 +1874,7 @@ mod tests { acw.update_modify($controls).expect("Failed to update"); let mut sync_agmt = HashMap::new(); let mut set = BTreeSet::new(); - set.insert($sync_yield_attr.to_string()); + set.insert($sync_yield_attr); sync_agmt.insert($sync_uuid, set); acw.update_sync_agreements(sync_agmt); let acw = acw; @@ -2381,10 +2403,10 @@ mod tests { vec![AccessEffectivePermission { delete: false, target: uuid!("cc8e95b4-c24f-4d68-ba54-8bed76f63930"), - search: Access::Allow(btreeset![Attribute::Name.into()]), + search: Access::Allow(btreeset![Attribute::Name]), modify_pres: Access::Allow(BTreeSet::new()), modify_rem: Access::Allow(BTreeSet::new()), - modify_class: Access::Allow(BTreeSet::new()), + modify_class: AccessClass::Allow(BTreeSet::new()), }] ) } @@ -2423,9 +2445,9 @@ mod tests { delete: false, target: uuid!("cc8e95b4-c24f-4d68-ba54-8bed76f63930"), search: Access::Allow(BTreeSet::new()), - modify_pres: Access::Allow(btreeset![Attribute::Name.into()]), - modify_rem: Access::Allow(btreeset![Attribute::Name.into()]), - modify_class: Access::Allow(btreeset![EntryClass::Object.into()]), + modify_pres: Access::Allow(btreeset![Attribute::Name]), + modify_rem: Access::Allow(btreeset![Attribute::Name]), + modify_class: AccessClass::Allow(btreeset![EntryClass::Object.into()]), }] ) } @@ -2660,7 +2682,7 @@ mod tests { &me_pres, vec![acp_allow.clone()], sync_uuid, - Attribute::Name.as_ref(), + Attribute::Name, &r2_set, true ); @@ -2669,7 +2691,7 @@ mod tests { &me_rem, vec![acp_allow.clone()], sync_uuid, - Attribute::Name.as_ref(), + Attribute::Name, &r2_set, true ); @@ -2678,7 +2700,7 @@ mod tests { &me_purge, vec![acp_allow], sync_uuid, - Attribute::Name.as_ref(), + Attribute::Name, &r2_set, true ); diff --git a/server/lib/src/server/access/modify.rs b/server/lib/src/server/access/modify.rs index 488fb73cc..853ad4088 100644 --- a/server/lib/src/server/access/modify.rs +++ b/server/lib/src/server/access/modify.rs @@ -6,15 +6,15 @@ use super::profiles::{ AccessControlModify, AccessControlModifyResolved, AccessControlReceiverCondition, AccessControlTargetCondition, }; -use super::AccessResult; +use super::{AccessResult, AccessResultClass}; use std::sync::Arc; pub(super) enum ModifyResult<'a> { Denied, Grant, Allow { - pres: BTreeSet<&'a str>, - rem: BTreeSet<&'a str>, + pres: BTreeSet, + rem: BTreeSet, cls: BTreeSet<&'a str>, }, } @@ -22,8 +22,8 @@ pub(super) enum ModifyResult<'a> { pub(super) fn apply_modify_access<'a>( ident: &Identity, related_acp: &'a [AccessControlModifyResolved], - sync_agreements: &'a HashMap>, - entry: &'a Arc, + sync_agreements: &HashMap>, + entry: &Arc, ) -> ModifyResult<'a> { let mut denied = false; let mut grant = false; @@ -57,7 +57,7 @@ pub(super) fn apply_modify_access<'a>( match modify_sync_constrain(ident, entry, sync_agreements) { AccessResult::Denied => denied = true, AccessResult::Constrain(mut set) => { - constrain_rem.extend(set.iter().copied()); + constrain_rem.extend(set.iter().cloned()); constrain_pres.append(&mut set) } // Can't grant. @@ -140,12 +140,12 @@ pub(super) fn apply_modify_access<'a>( } match modify_cls_test(scoped_acp.as_slice()) { - AccessResult::Denied => denied = true, + AccessResultClass::Denied => denied = true, // Can never return a unilateral grant. - AccessResult::Grant => {} - AccessResult::Ignore => {} - AccessResult::Constrain(mut set) => constrain_cls.append(&mut set), - AccessResult::Allow(mut set) => allow_cls.append(&mut set), + AccessResultClass::Grant => {} + AccessResultClass::Ignore => {} + AccessResultClass::Constrain(mut set) => constrain_cls.append(&mut set), + AccessResultClass::Allow(mut set) => allow_cls.append(&mut set), } } @@ -183,7 +183,7 @@ pub(super) fn apply_modify_access<'a>( } } -fn modify_ident_test<'a>(ident: &Identity) -> AccessResult<'a> { +fn modify_ident_test(ident: &Identity) -> AccessResult { match &ident.origin { IdentType::Internal => { trace!("Internal operation, bypassing access check"); @@ -211,35 +211,37 @@ fn modify_ident_test<'a>(ident: &Identity) -> AccessResult<'a> { AccessResult::Ignore } -fn modify_pres_test<'a>(scoped_acp: &[&'a AccessControlModify]) -> AccessResult<'a> { - let allowed_pres: BTreeSet<&str> = scoped_acp +fn modify_pres_test(scoped_acp: &[&AccessControlModify]) -> AccessResult { + let allowed_pres: BTreeSet = scoped_acp .iter() - .flat_map(|acp| acp.presattrs.iter().map(|v| v.as_str())) + .flat_map(|acp| acp.presattrs.iter().cloned()) .collect(); AccessResult::Allow(allowed_pres) } -fn modify_rem_test<'a>(scoped_acp: &[&'a AccessControlModify]) -> AccessResult<'a> { - let allowed_rem: BTreeSet<&str> = scoped_acp +fn modify_rem_test(scoped_acp: &[&AccessControlModify]) -> AccessResult { + let allowed_rem: BTreeSet = scoped_acp .iter() - .flat_map(|acp| acp.remattrs.iter().map(|v| v.as_str())) + .flat_map(|acp| acp.remattrs.iter().cloned()) .collect(); AccessResult::Allow(allowed_rem) } -fn modify_cls_test<'a>(scoped_acp: &[&'a AccessControlModify]) -> AccessResult<'a> { - let allowed_classes: BTreeSet<&str> = scoped_acp +// TODO: Should this be reverted to the Str borrow method? Or do we try to change +// to EntryClass? +fn modify_cls_test<'a>(scoped_acp: &[&'a AccessControlModify]) -> AccessResultClass<'a> { + let allowed_classes: BTreeSet<&'a str> = scoped_acp .iter() - .flat_map(|acp| acp.classes.iter().map(|v| v.as_str())) + .flat_map(|acp| acp.classes.iter().map(|s| s.as_str())) .collect(); - AccessResult::Allow(allowed_classes) + AccessResultClass::Allow(allowed_classes) } -fn modify_sync_constrain<'a>( +fn modify_sync_constrain( ident: &Identity, - entry: &'a Arc, - sync_agreements: &'a HashMap>, -) -> AccessResult<'a> { + entry: &Arc, + sync_agreements: &HashMap>, +) -> AccessResult { match &ident.origin { IdentType::Internal => AccessResult::Ignore, IdentType::Synch(_) => { @@ -262,14 +264,14 @@ fn modify_sync_constrain<'a>( if let Some(sync_uuid) = entry.get_ava_single_refer(Attribute::SyncParentUuid) { let mut set = btreeset![ - Attribute::UserAuthTokenSession.as_ref(), - Attribute::OAuth2Session.as_ref(), - Attribute::OAuth2ConsentScopeMap.as_ref(), - Attribute::CredentialUpdateIntentToken.as_ref() + Attribute::UserAuthTokenSession, + Attribute::OAuth2Session, + Attribute::OAuth2ConsentScopeMap, + Attribute::CredentialUpdateIntentToken ]; if let Some(sync_yield_authority) = sync_agreements.get(&sync_uuid) { - set.extend(sync_yield_authority.iter().map(|s| s.as_str())) + set.extend(sync_yield_authority.iter().cloned()) } AccessResult::Constrain(set) diff --git a/server/lib/src/server/access/profiles.rs b/server/lib/src/server/access/profiles.rs index a0911233a..b3ab09d1f 100644 --- a/server/lib/src/server/access/profiles.rs +++ b/server/lib/src/server/access/profiles.rs @@ -19,7 +19,7 @@ pub struct AccessControlSearchResolved<'a> { #[derive(Debug, Clone)] pub struct AccessControlSearch { pub acp: AccessControlProfile, - pub attrs: BTreeSet, + pub attrs: BTreeSet, } impl AccessControlSearch { @@ -41,12 +41,12 @@ impl AccessControlSearch { admin_error!("Missing {}", Attribute::AcpSearchAttr); OperationError::InvalidAcpState(format!("Missing {}", Attribute::AcpSearchAttr)) })? - .map(AttrString::from) + .map(Attribute::from) .collect(); // Ability to search memberof, implies the ability to read directmemberof - if attrs.contains(Attribute::MemberOf.as_ref()) { - attrs.insert(Attribute::DirectMemberOf.into()); + if attrs.contains(&Attribute::MemberOf) { + attrs.insert(Attribute::DirectMemberOf); } let acp = AccessControlProfile::try_from(qs, value)?; @@ -64,11 +64,11 @@ impl AccessControlSearch { targetscope: Filter, attrs: &str, ) -> Self { - let mut attrs: BTreeSet<_> = attrs.split_whitespace().map(AttrString::from).collect(); + let mut attrs: BTreeSet<_> = attrs.split_whitespace().map(Attribute::from).collect(); // Ability to search memberof, implies the ability to read directmemberof - if attrs.contains(Attribute::MemberOf.as_ref()) { - attrs.insert(Attribute::DirectMemberOf.into()); + if attrs.contains(&Attribute::MemberOf) { + attrs.insert(Attribute::DirectMemberOf); } AccessControlSearch { @@ -98,7 +98,7 @@ impl AccessControlSearch { receiver: AccessControlReceiver::EntryManager, target, }, - attrs: attrs.split_whitespace().map(AttrString::from).collect(), + attrs: attrs.split_whitespace().map(Attribute::from).collect(), } } } @@ -177,7 +177,7 @@ pub struct AccessControlCreateResolved<'a> { pub struct AccessControlCreate { pub acp: AccessControlProfile, pub classes: Vec, - pub attrs: Vec, + pub attrs: Vec, } impl AccessControlCreate { @@ -195,7 +195,7 @@ impl AccessControlCreate { let attrs = value .get_ava_iter_iutf8(Attribute::AcpCreateAttr) - .map(|i| i.map(AttrString::from).collect()) + .map(|i| i.map(Attribute::from).collect()) .unwrap_or_default(); let classes = value @@ -229,7 +229,7 @@ impl AccessControlCreate { target: AccessControlTarget::Scope(targetscope), }, classes: classes.split_whitespace().map(AttrString::from).collect(), - attrs: attrs.split_whitespace().map(AttrString::from).collect(), + attrs: attrs.split_whitespace().map(Attribute::from).collect(), } } @@ -251,7 +251,7 @@ impl AccessControlCreate { target, }, classes: classes.split_whitespace().map(AttrString::from).collect(), - attrs: attrs.split_whitespace().map(AttrString::from).collect(), + attrs: attrs.split_whitespace().map(Attribute::from).collect(), } } } @@ -267,8 +267,8 @@ pub struct AccessControlModifyResolved<'a> { pub struct AccessControlModify { pub acp: AccessControlProfile, pub classes: Vec, - pub presattrs: Vec, - pub remattrs: Vec, + pub presattrs: Vec, + pub remattrs: Vec, } impl AccessControlModify { @@ -285,12 +285,12 @@ impl AccessControlModify { let presattrs = value .get_ava_iter_iutf8(Attribute::AcpModifyPresentAttr) - .map(|i| i.map(AttrString::from).collect()) + .map(|i| i.map(Attribute::from).collect()) .unwrap_or_default(); let remattrs = value .get_ava_iter_iutf8(Attribute::AcpModifyRemovedAttr) - .map(|i| i.map(AttrString::from).collect()) + .map(|i| i.map(Attribute::from).collect()) .unwrap_or_default(); let classes = value @@ -326,8 +326,8 @@ impl AccessControlModify { target: AccessControlTarget::Scope(targetscope), }, classes: classes.split_whitespace().map(AttrString::from).collect(), - presattrs: presattrs.split_whitespace().map(AttrString::from).collect(), - remattrs: remattrs.split_whitespace().map(AttrString::from).collect(), + presattrs: presattrs.split_whitespace().map(Attribute::from).collect(), + remattrs: remattrs.split_whitespace().map(Attribute::from).collect(), } } @@ -350,8 +350,8 @@ impl AccessControlModify { target, }, classes: classes.split_whitespace().map(AttrString::from).collect(), - presattrs: presattrs.split_whitespace().map(AttrString::from).collect(), - remattrs: remattrs.split_whitespace().map(AttrString::from).collect(), + presattrs: presattrs.split_whitespace().map(Attribute::from).collect(), + remattrs: remattrs.split_whitespace().map(Attribute::from).collect(), } } } diff --git a/server/lib/src/server/access/search.rs b/server/lib/src/server/access/search.rs index d61e95f1f..023cc099c 100644 --- a/server/lib/src/server/access/search.rs +++ b/server/lib/src/server/access/search.rs @@ -7,17 +7,17 @@ use super::profiles::{ use super::AccessResult; use std::sync::Arc; -pub(super) enum SearchResult<'a> { +pub(super) enum SearchResult { Denied, Grant, - Allow(BTreeSet<&'a str>), + Allow(BTreeSet), } -pub(super) fn apply_search_access<'a>( +pub(super) fn apply_search_access( ident: &Identity, - related_acp: &'a [AccessControlSearchResolved], - entry: &'a Arc, -) -> SearchResult<'a> { + related_acp: &[AccessControlSearchResolved], + entry: &Arc, +) -> SearchResult { // This could be considered "slow" due to allocs each iter with the entry. We // could move these out of the loop and reuse, but there are likely risks to // that. @@ -70,11 +70,11 @@ pub(super) fn apply_search_access<'a>( } } -fn search_filter_entry<'a>( +fn search_filter_entry( ident: &Identity, - related_acp: &'a [AccessControlSearchResolved], - entry: &'a Arc, -) -> AccessResult<'a> { + related_acp: &[AccessControlSearchResolved], + entry: &Arc, +) -> AccessResult { // If this is an internal search, return our working set. match &ident.origin { IdentType::Internal => { @@ -106,7 +106,7 @@ fn search_filter_entry<'a>( let ident_memberof = ident.get_memberof(); let ident_uuid = ident.get_uuid(); - let allowed_attrs: BTreeSet<&str> = related_acp + let allowed_attrs: BTreeSet = related_acp .iter() .filter_map(|acs| { // Assert that the receiver condition applies. @@ -156,7 +156,7 @@ fn search_filter_entry<'a>( security_debug!(entry = ?entry.get_display_id(), acs = %acs.acp.acp.name, "acs applied to entry"); // add search_attrs to allowed. - Some(acs.acp.attrs.iter().map(|s| s.as_str())) + Some(acs.acp.attrs.iter().cloned()) }) .flatten() .collect(); @@ -164,10 +164,7 @@ fn search_filter_entry<'a>( AccessResult::Allow(allowed_attrs) } -fn search_oauth2_filter_entry<'a>( - ident: &Identity, - entry: &'a Arc, -) -> AccessResult<'a> { +fn search_oauth2_filter_entry(ident: &Identity, entry: &Arc) -> AccessResult { match &ident.origin { IdentType::Internal | IdentType::Synch(_) => AccessResult::Ignore, IdentType::User(iuser) => { @@ -189,12 +186,12 @@ fn search_oauth2_filter_entry<'a>( security_debug!(entry = ?entry.get_uuid(), ident = ?iuser.entry.get_uuid2rdn(), "ident is a memberof a group granted an oauth2 scope by this entry"); return AccessResult::Allow(btreeset!( - Attribute::Class.as_ref(), - Attribute::DisplayName.as_ref(), - Attribute::Uuid.as_ref(), - Attribute::Name.as_ref(), - Attribute::OAuth2RsOriginLanding.as_ref(), - Attribute::Image.as_ref() + Attribute::Class, + Attribute::DisplayName, + Attribute::Uuid, + Attribute::Name, + Attribute::OAuth2RsOriginLanding, + Attribute::Image )); } AccessResult::Ignore @@ -202,10 +199,10 @@ fn search_oauth2_filter_entry<'a>( } } -fn search_sync_account_filter_entry<'a>( +fn search_sync_account_filter_entry( ident: &Identity, - entry: &'a Arc, -) -> AccessResult<'a> { + entry: &Arc, +) -> AccessResult { match &ident.origin { IdentType::Internal | IdentType::Synch(_) => AccessResult::Ignore, IdentType::User(iuser) => { @@ -243,9 +240,9 @@ fn search_sync_account_filter_entry<'a>( security_debug!(entry = ?entry.get_uuid(), ident = ?iuser.entry.get_uuid2rdn(), "ident is a synchronised account from this sync account"); return AccessResult::Allow(btreeset!( - Attribute::Class.as_ref(), - Attribute::Uuid.as_ref(), - Attribute::SyncCredentialPortal.as_ref() + Attribute::Class, + Attribute::Uuid, + Attribute::SyncCredentialPortal )); } } diff --git a/server/lib/src/server/migrations.rs b/server/lib/src/server/migrations.rs index a0791c7f2..8b17f6747 100644 --- a/server/lib/src/server/migrations.rs +++ b/server/lib/src/server/migrations.rs @@ -263,7 +263,7 @@ impl<'a> QueryServerWriteTransaction<'a> { ) -> Result<(), OperationError> { trace!("operating on {:?}", e.get_uuid()); - let Some(filt) = e.filter_from_attrs(&[Attribute::Uuid.into()]) else { + let Some(filt) = e.filter_from_attrs(&[Attribute::Uuid]) else { return Err(OperationError::FilterGeneration); }; @@ -277,7 +277,7 @@ impl<'a> QueryServerWriteTransaction<'a> { } else if results.len() == 1 { // For each ignored attr, we remove it from entry. for attr in attrs.iter() { - e.remove_ava(*attr); + e.remove_ava(attr); } // If the thing is subset, pass @@ -412,7 +412,7 @@ impl<'a> QueryServerWriteTransaction<'a> { .map(|origin_url| { // Copy the origin url to the landing. let modlist = vec![Modify::Present( - Attribute::OAuth2RsOriginLanding.into(), + Attribute::OAuth2RsOriginLanding, Value::Url(origin_url.clone()), )]; @@ -431,9 +431,9 @@ impl<'a> QueryServerWriteTransaction<'a> { // // Domain info should have the attribute private cookie key removed. let modlist = ModifyList::new_list(vec![ - Modify::Purged(Attribute::PrivateCookieKey.into()), - Modify::Purged(Attribute::Es256PrivateKeyDer.into()), - Modify::Purged(Attribute::FernetPrivateKeyStr.into()), + Modify::Purged(Attribute::PrivateCookieKey), + Modify::Purged(Attribute::Es256PrivateKeyDer), + Modify::Purged(Attribute::FernetPrivateKeyStr), ]); self.internal_modify_uuid(UUID_DOMAIN_INFO, &modlist)?; @@ -443,8 +443,7 @@ impl<'a> QueryServerWriteTransaction<'a> { f_eq(Attribute::Class, EntryClass::SyncAccount.into()) ])); - let modlist = - ModifyList::new_list(vec![Modify::Purged(Attribute::JwsEs256PrivateKey.into())]); + let modlist = ModifyList::new_list(vec![Modify::Purged(Attribute::JwsEs256PrivateKey)]); self.internal_modify(&filter, &modlist)?; diff --git a/server/lib/src/server/mod.rs b/server/lib/src/server/mod.rs index ac5031961..ce3e3d6a5 100644 --- a/server/lib/src/server/mod.rs +++ b/server/lib/src/server/mod.rs @@ -608,7 +608,7 @@ pub trait QueryServerTransaction<'a> { /// Do a schema aware conversion from a String:String to String:Value for modification /// present. - fn clone_value(&mut self, attr: &str, value: &str) -> Result { + fn clone_value(&mut self, attr: &Attribute, value: &str) -> Result { let schema = self.get_schema(); // Should this actually be a fn of Value - no - I think that introduces issues with the @@ -702,7 +702,7 @@ pub trait QueryServerTransaction<'a> { fn clone_partialvalue( &mut self, - attr: &str, + attr: &Attribute, value: &str, ) -> Result { let schema = self.get_schema(); @@ -1652,6 +1652,7 @@ impl<'a> QueryServerWriteTransaction<'a> { // load them. let attributetypes: Result, _> = res.iter().map(|e| SchemaAttribute::try_from(e)).collect(); + let attributetypes = attributetypes.map_err(|e| { admin_error!("reload schema attributetypes {:?}", e); e @@ -1736,12 +1737,15 @@ impl<'a> QueryServerWriteTransaction<'a> { e })?; - let sync_agreement_map: HashMap> = res + let sync_agreement_map: HashMap> = res .iter() .filter_map(|e| { e.get_ava_as_iutf8(Attribute::SyncYieldAuthority) - .cloned() - .map(|set| (e.get_uuid(), set)) + .map(|set| { + let set: BTreeSet<_> = + set.iter().map(|s| Attribute::from(s.as_str())).collect(); + (e.get_uuid(), set) + }) }) .collect(); @@ -2416,18 +2420,18 @@ mod tests { assert!(cr.is_ok()); // test attr not exist - let r1 = server_txn.clone_value("tausau", "naoeutnhaou"); + let r1 = server_txn.clone_value(&Attribute::from("tausau"), "naoeutnhaou"); assert!(r1.is_err()); // test attr not-normalised (error) // test attr not-reference - let r2 = server_txn.clone_value("NaMe", "NaMe"); + let r2 = server_txn.clone_value(&Attribute::Custom("NaMe".into()), "NaMe"); assert!(r2.is_err()); // test attr reference - let r3 = server_txn.clone_value("member", "testperson1"); + let r3 = server_txn.clone_value(&Attribute::from("member"), "testperson1"); assert_eq!( r3, @@ -2435,7 +2439,10 @@ mod tests { ); // test attr reference already resolved. - let r4 = server_txn.clone_value("member", "cc8e95b4-c24f-4d68-ba54-8bed76f63930"); + let r4 = server_txn.clone_value( + &Attribute::from("member"), + "cc8e95b4-c24f-4d68-ba54-8bed76f63930", + ); debug!("{:?}", r4); assert_eq!( diff --git a/server/lib/src/server/modify.rs b/server/lib/src/server/modify.rs index 81a542890..6ced0baa1 100644 --- a/server/lib/src/server/modify.rs +++ b/server/lib/src/server/modify.rs @@ -623,7 +623,7 @@ mod tests { PartialValue::new_iname("flarbalgarble") )), ModifyList::new_list(vec![Modify::Present( - Attribute::Description.into(), + Attribute::Description, Value::from("anusaosu"), )]), ); @@ -658,7 +658,7 @@ mod tests { let me_inv_m = ModifyEvent::new_internal_invalid( filter!(f_pres(Attribute::Class)), ModifyList::new_list(vec![Modify::Present( - Attribute::NonExist.into(), + Attribute::NonExist, Value::from("anusaosu"), )]), ); @@ -676,8 +676,8 @@ mod tests { PartialValue::new_iname("testperson2") )), ModifyList::new_list(vec![ - Modify::Purged(Attribute::Description.into()), - Modify::Present(Attribute::Description.into(), Value::from("anusaosu")), + Modify::Purged(Attribute::Description), + Modify::Present(Attribute::Description, Value::from("anusaosu")), ]), ); assert!(server_txn.modify(&me_sin).is_ok()); @@ -689,8 +689,8 @@ mod tests { f_eq(Attribute::Name, PartialValue::new_iname("testperson2")), ])), ModifyList::new_list(vec![ - Modify::Purged(Attribute::Description.into()), - Modify::Present(Attribute::Description.into(), Value::from("anusaosu")), + Modify::Purged(Attribute::Description), + Modify::Present(Attribute::Description, Value::from("anusaosu")), ]), ); assert!(server_txn.modify(&me_mult).is_ok()); @@ -767,7 +767,7 @@ mod tests { PartialValue::new_iname("testperson1") )), ModifyList::new_list(vec![Modify::Present( - Attribute::Class.into(), + Attribute::Class, EntryClass::SystemInfo.to_value(), )]), ); @@ -780,7 +780,7 @@ mod tests { PartialValue::new_iname("testperson1") )), ModifyList::new_list(vec![Modify::Present( - Attribute::Name.into(), + Attribute::Name, Value::new_iname("testpersonx"), )]), ); @@ -793,9 +793,9 @@ mod tests { PartialValue::new_iname("testperson1") )), ModifyList::new_list(vec![ - Modify::Present(Attribute::Class.into(), EntryClass::SystemInfo.to_value()), + Modify::Present(Attribute::Class, EntryClass::SystemInfo.to_value()), // Modify::Present(Attribute::Domain.into(), Value::new_iutf8("domain.name")), - Modify::Present(Attribute::Version.into(), Value::new_uint32(1)), + Modify::Present(Attribute::Version, Value::new_uint32(1)), ]), ); assert!(server_txn.modify(&me_sin).is_ok()); @@ -807,8 +807,8 @@ mod tests { PartialValue::new_iname("testperson1") )), ModifyList::new_list(vec![ - Modify::Purged(Attribute::Name.into()), - Modify::Present(Attribute::Name.into(), Value::new_iname("testpersonx")), + Modify::Purged(Attribute::Name), + Modify::Present(Attribute::Name, Value::new_iname("testpersonx")), ]), ); assert!(server_txn.modify(&me_sin).is_ok()); @@ -847,10 +847,7 @@ mod tests { Attribute::Name, PartialValue::new_iname("testperson1") )), - ModifyList::new_list(vec![Modify::Present( - Attribute::PrimaryCredential.into(), - v_cred, - )]), + ModifyList::new_list(vec![Modify::Present(Attribute::PrimaryCredential, v_cred)]), ); // go! assert!(server_txn.modify(&me_inv_m).is_ok()); diff --git a/server/lib/src/server/recycle.rs b/server/lib/src/server/recycle.rs index 214c9ee09..564402170 100644 --- a/server/lib/src/server/recycle.rs +++ b/server/lib/src/server/recycle.rs @@ -110,7 +110,7 @@ impl<'a> QueryServerWriteTransaction<'a> { // Check access against a "fake" modify. let modlist = ModifyList::new_list(vec![Modify::Removed( - Attribute::Class.into(), + Attribute::Class, EntryClass::Recycled.into(), )]); @@ -152,11 +152,11 @@ impl<'a> QueryServerWriteTransaction<'a> { dm_mods .entry(g_uuid) .and_modify(|mlist| { - let m = Modify::Present(Attribute::Member.into(), Value::Refer(u)); + let m = Modify::Present(Attribute::Member, Value::Refer(u)); mlist.push_mod(m); }) .or_insert({ - let m = Modify::Present(Attribute::Member.into(), Value::Refer(u)); + let m = Modify::Present(Attribute::Member, Value::Refer(u)); ModifyList::new_list(vec![m]) }); } @@ -268,7 +268,7 @@ mod tests { admin.clone(), filt_i_rc.clone(), ModifyList::new_list(vec![Modify::Present( - Attribute::Class.into(), + Attribute::Class, EntryClass::Recycled.into(), )]), ); @@ -529,7 +529,7 @@ mod tests { admin.clone(), filt_i_ts.clone(), ModifyList::new_list(vec![Modify::Present( - Attribute::Class.into(), + Attribute::Class, EntryClass::Tombstone.into(), )]), ); @@ -625,8 +625,7 @@ mod tests { ( Attribute::Uuid, #[allow(clippy::panic)] - Value::new_uuid_s(uuid) - .unwrap_or_else(|| { panic!("{}", Attribute::Uuid.as_ref().to_string()) }) + Value::new_uuid_s(uuid).unwrap_or_else(|| { panic!("{}", Attribute::Uuid) }) ), (Attribute::Description, Value::new_utf8s("testperson-entry")), (Attribute::DisplayName, Value::new_utf8s(name)) @@ -641,8 +640,7 @@ mod tests { (Attribute::Name, Value::new_iname(name)), ( Attribute::Uuid, - Value::new_uuid_s(uuid) - .unwrap_or_else(|| { panic!("{}", Attribute::Uuid.as_ref().to_string()) }) + Value::new_uuid_s(uuid).unwrap_or_else(|| { panic!("{}", Attribute::Uuid) }) ), (Attribute::Description, Value::new_utf8s("testgroup-entry")) ); diff --git a/server/lib/src/value.rs b/server/lib/src/value.rs index 5ffa3b12c..9df7120a7 100644 --- a/server/lib/src/value.rs +++ b/server/lib/src/value.rs @@ -449,14 +449,14 @@ impl From for PartialValue { impl From for Value { fn from(attr: Attribute) -> Value { - let s: &str = attr.into(); + let s: &str = attr.as_str(); Value::new_iutf8(s) } } impl From for PartialValue { fn from(attr: Attribute) -> PartialValue { - let s: &str = attr.into(); + let s: &str = attr.as_str(); PartialValue::new_iutf8(s) } } diff --git a/server/lib/src/valueset/image/mod.rs b/server/lib/src/valueset/image/mod.rs index 7a3bfb5de..4d61585ea 100644 --- a/server/lib/src/valueset/image/mod.rs +++ b/server/lib/src/valueset/image/mod.rs @@ -551,7 +551,7 @@ mod tests { let res = image.validate_image(); trace!("SVG Validation result of {}: {:?}", filename, &res); assert!(res.is_ok()); - assert_eq!(image.hash_imagevalue().is_empty(), false); + assert!(!image.hash_imagevalue().is_empty()); } /* diff --git a/server/testkit/src/lib.rs b/server/testkit/src/lib.rs index c211a9219..ac448a5e4 100644 --- a/server/testkit/src/lib.rs +++ b/server/testkit/src/lib.rs @@ -242,7 +242,7 @@ pub async fn is_attr_writable(rsclient: &KanidmClient, id: &str, attr: Attribute .await .is_ok(), ), - entry => { + ref entry => { let new_value = match entry { Attribute::AcpReceiverGroup => "00000000-0000-0000-0000-000000000011".to_string(), Attribute::AcpTargetScope => "{\"and\": [{\"eq\": [\"class\",\"access_control_profile\"]}, {\"andnot\": {\"or\": [{\"eq\": [\"class\", \"tombstone\"]}, {\"eq\": [\"class\", \"recycled\"]}]}}]}".to_string(), @@ -320,7 +320,7 @@ pub async fn test_read_attrs( .await .unwrap() .is_some(), - _ => e.attrs.contains_key(attr.as_ref()), + _ => e.attrs.contains_key(attr.as_str()), }; trace!("is_ok: {}, is_readable: {}", is_ok, is_readable); assert_eq!(is_ok, is_readable) @@ -337,7 +337,7 @@ pub async fn test_write_attrs( for attr in attrs.iter() { println!("Writing to {} - ex {}", attr, is_writeable); #[allow(clippy::unwrap_used)] - let is_ok = is_attr_writable(rsclient, id, *attr).await.unwrap(); + let is_ok = is_attr_writable(rsclient, id, attr.clone()).await.unwrap(); assert_eq!(is_ok, is_writeable) } } @@ -352,7 +352,9 @@ pub async fn test_modify_group( println!("Testing group: {}", group); for attr in [Attribute::Description, Attribute::Name].into_iter() { #[allow(clippy::unwrap_used)] - let is_writable = is_attr_writable(rsclient, group, attr).await.unwrap(); + let is_writable = is_attr_writable(rsclient, group, attr.clone()) + .await + .unwrap(); dbg!(group, attr, is_writable, can_be_modified); assert_eq!(is_writable, can_be_modified) } diff --git a/server/testkit/tests/proto_v1_test.rs b/server/testkit/tests/proto_v1_test.rs index 9c793f481..33f794cd3 100644 --- a/server/testkit/tests/proto_v1_test.rs +++ b/server/testkit/tests/proto_v1_test.rs @@ -128,7 +128,7 @@ async fn test_server_search(rsclient: KanidmClient) { let e = rset.first().unwrap(); // Check it's admin. println!("{:?}", e); - let name = e.attrs.get(Attribute::Name.as_ref()).unwrap(); + let name = e.attrs.get(Attribute::Name.as_str()).unwrap(); assert_eq!(name, &vec!["admin".to_string()]); } @@ -537,7 +537,7 @@ async fn test_server_rest_domain_lifecycle(rsclient: KanidmClient) { assert!( dlocal .attrs - .get(Attribute::DomainDisplayName.as_ref()) + .get(Attribute::DomainDisplayName.as_str()) .and_then(|v| v.first()) == Some(&"Super Cool Crabz".to_string()) ); @@ -870,11 +870,11 @@ async fn test_server_rest_oauth2_basic_lifecycle(rsclient: KanidmClient) { // What can we see? assert!(oauth2_config .attrs - .contains_key(Attribute::OAuth2RsBasicSecret.as_ref())); + .contains_key(Attribute::OAuth2RsBasicSecret.as_str())); // This is present, but redacted. assert!(oauth2_config .attrs - .contains_key(Attribute::OAuth2RsTokenKey.as_ref())); + .contains_key(Attribute::OAuth2RsTokenKey.as_str())); // Mod delete the secret/key and check them again. // Check we can patch the oauth2_rs_name / oauth2_rs_origin