20240906 Attribute as an Enum Type (#3025)

Changes attribute from a string to an enum - this provides many performance improvements and memory savings throughout the server.
This commit is contained in:
Firstyear 2024-09-09 10:53:10 +10:00 committed by GitHub
parent a20a3bc673
commit 938ad90f3b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
61 changed files with 2317 additions and 2575 deletions

View file

@ -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 }

View file

@ -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<str> 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<Attribute> 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<Self, Self::Error> {
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<Self, OperationError> {
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<Attribute> for &'static str {
impl<'a> From<&'a Attribute> for &'a str {
fn from(val: &'a Attribute) -> Self {
val.as_str()
}
}
impl From<Attribute> 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<Attribute> 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<Attribute> 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::<Attribute>().collect::<Vec<_>>();
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);
}
}

View file

@ -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<String>),
MissingMustAttribute(Vec<String>),
MissingMustAttribute(Vec<Attribute>),
InvalidAttribute(String),
InvalidAttributeSyntax(String),
AttributeNotValidForClass(String),

View file

@ -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::<super::AccessTokenType>(&format!("\"{}\"", testcase));
assert!(at.is_err())
}

View file

@ -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(),

View file

@ -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

View file

@ -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()

View file

@ -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();
}
}
}

View file

@ -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 }

View file

@ -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<AttrString, NonEmpty<DbValueV1>>,
pub attrs: BTreeMap<Attribute, NonEmpty<DbValueV1>>,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct DbEntryV2 {
pub attrs: BTreeMap<AttrString, DbValueSetV2>,
pub attrs: BTreeMap<Attribute, DbValueSetV2>,
}
// REMEMBER: If you add a new version here, you MUST
@ -31,7 +30,7 @@ pub enum DbEntryVers {
V2(DbEntryV2),
V3 {
changestate: DbEntryChangeState,
attrs: BTreeMap<AttrString, DbValueSetV2>,
attrs: BTreeMap<Attribute, DbValueSetV2>,
},
}
@ -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:?}, ")?;
}
}

View file

@ -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<String, DbCidV1>,
changes: BTreeMap<Attribute, DbCidV1>,
},
V1Tombstone {
at: DbCidV1,

View file

@ -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<Option<IDLBitRange>, 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<Option<IDLBitRange>, 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<Option<IDLBitRange>, 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)
}

View file

@ -219,15 +219,15 @@ pub(crate) trait IdlSqliteTransaction {
}
}
fn exists_idx(&self, attr: &str, itype: IndexType) -> Result<bool, OperationError> {
let tname = format!("idx_{}_{}", itype.as_idx_str(), attr);
fn exists_idx(&self, attr: &Attribute, itype: IndexType) -> Result<bool, OperationError> {
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<Option<IDLBitRange>, 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<Vec<u8>> = 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()?

View file

@ -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(),
}

View file

@ -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<Vec<(AttrString, IndexType)>, OperationError> {
fn missing_idxs(&mut self) -> Result<Vec<(Attribute, IndexType)>, 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<Option<IDLBitRange>, 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<u64>| 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,
}];

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -76,7 +76,7 @@ pub struct SearchEvent {
pub filter: Filter<FilterValid>,
// This is the original filter, for the purpose of ACI checking.
pub filter_orig: Filter<FilterValid>,
pub attrs: Option<BTreeSet<AttrString>>,
pub attrs: Option<BTreeSet<Attribute>>,
}
impl SearchEvent {
@ -108,7 +108,7 @@ impl SearchEvent {
attrs: Option<&[String]>,
qs: &mut QueryServerReadTransaction,
) -> Result<Self, OperationError> {
let r_attrs: Option<BTreeSet<AttrString>> = attrs.map(|vs| {
let r_attrs: Option<BTreeSet<Attribute>> = 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<Self, OperationError> {
let r_attrs: Option<BTreeSet<AttrString>> = attrs.map(|vs| {
let r_attrs: Option<BTreeSet<Attribute>> = 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<BTreeSet<AttrString>>,
attrs: Option<BTreeSet<Attribute>>,
) -> Result<Self, OperationError> {
// Kanidm Filter from LdapFilter
let f = Filter::from_ldap_ro(&ident, lf, qs)?;

View file

@ -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>) -> 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<FC<'a>>),
And(Vec<FC<'a>>),
Inclusion(Vec<FC<'a>>),
AndNot(Box<FC<'a>>),
pub enum FC {
Eq(Attribute, PartialValue),
Cnt(Attribute, PartialValue),
Pres(Attribute),
LessThan(Attribute, PartialValue),
Or(Vec<FC>),
And(Vec<FC>),
Inclusion(Vec<FC>),
AndNot(Box<FC>),
SelfUuid,
// Not(Box<FC>),
}
@ -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<FilterComp>),
And(Vec<FilterComp>),
Inclusion(Vec<FilterComp>),
@ -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<NonZeroU8>),
Cnt(AttrString, PartialValue, Option<NonZeroU8>),
Stw(AttrString, PartialValue, Option<NonZeroU8>),
Enw(AttrString, PartialValue, Option<NonZeroU8>),
Pres(AttrString, Option<NonZeroU8>),
LessThan(AttrString, PartialValue, Option<NonZeroU8>),
Eq(Attribute, PartialValue, Option<NonZeroU8>),
Cnt(Attribute, PartialValue, Option<NonZeroU8>),
Stw(Attribute, PartialValue, Option<NonZeroU8>),
Enw(Attribute, PartialValue, Option<NonZeroU8>),
Pres(Attribute, Option<NonZeroU8>),
LessThan(Attribute, PartialValue, Option<NonZeroU8>),
Or(Vec<FilterResolved>, Option<NonZeroU8>),
And(Vec<FilterResolved>, Option<NonZeroU8>),
// 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<FilterPlan>),
OrIndexed(Vec<FilterPlan>),
OrPartial(Vec<FilterPlan>),
@ -520,7 +519,7 @@ impl Filter<FilterValid> {
Ok(resolved_filt)
}
pub fn get_attr_set(&self) -> BTreeSet<&str> {
pub fn get_attr_set(&self) -> BTreeSet<Attribute> {
// 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<FilterInvalid> {
// 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<FilterInvalid> {
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<Attribute>) {
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!([

View file

@ -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());

View file

@ -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 },

View file

@ -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"),

View file

@ -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(),

View file

@ -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<Vec<Value>, 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,

View file

@ -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());

View file

@ -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::<Result<Vec<_>, _>>()

View file

@ -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<Self, OperationError> {
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<ModifyInvalid> {
}
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<ModifyInvalid> {
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<ModifyInvalid> {
.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();

View file

@ -20,12 +20,12 @@ pub struct AttrUnique;
fn get_cand_attr_set<'a, VALID: 'a, STATE: 'a, T>(
// cand: &[Entry<VALID, STATE>],
cand: T,
uniqueattrs: &[AttrString],
) -> Result<BTreeMap<(AttrString, PartialValue), Vec<Uuid>>, OperationError>
uniqueattrs: &[Attribute],
) -> Result<BTreeMap<(Attribute, PartialValue), Vec<Uuid>>, OperationError>
where
T: IntoIterator<Item = &'a Entry<VALID, STATE>>,
{
let mut cand_attr: BTreeMap<(AttrString, PartialValue), Vec<Uuid>> = BTreeMap::new();
let mut cand_attr: BTreeMap<(Attribute, PartialValue), Vec<Uuid>> = 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<VALID, STATE>(
// 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,
|_| {},

View file

@ -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,
|_| {},
|_| {}

View file

@ -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,

View file

@ -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");

View file

@ -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) {

View file

@ -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,
|_| {},

View file

@ -86,7 +86,7 @@ fn apply_gidnumber<T: Clone>(
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 {

View file

@ -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,
|_| {},

View file

@ -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(())

View file

@ -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()
),
]),

View file

@ -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<VALUE, STATE>(entry: &mut Entry<VALUE, STATE>) -> 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),
}
}
}

View file

@ -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 => {

View file

@ -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<Attribute, OperationError> = 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<AttrString, SchemaAttribute>,
ref_types: &HashMap<Attribute, SchemaAttribute>,
entry_iter: I,
reference_set: &mut BTreeSet<Uuid>,
) -> 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::<Attribute>
})
.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 {

View file

@ -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 {

View file

@ -166,7 +166,7 @@ impl Spn {
Attribute::Spn,
spn
);
ent.set_ava(Attribute::Spn, once(spn));
ent.set_ava(&Attribute::Spn, once(spn));
}
}
Ok(())

View file

@ -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"),
)]),
);

View file

@ -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::<Result<Vec<EntryRefreshNew>, _>>()
.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(())

View file

@ -11,7 +11,7 @@ use std::collections::BTreeMap;
pub enum State {
Live {
at: Cid,
changes: BTreeMap<AttrString, Cid>,
changes: BTreeMap<Attribute, Cid>,
},
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<F>(&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<Result<(), ConsistencyError>>,
) {
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()))

View file

@ -460,7 +460,7 @@ pub enum ReplStateV1 {
Live {
at: ReplCidV1,
// Also add AT here for breaking entry origin on conflict.
attrs: BTreeMap<String, ReplAttrStateV1>,
attrs: BTreeMap<Attribute, ReplAttrStateV1>,
},
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

View file

@ -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

View file

@ -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");

File diff suppressed because it is too large Load diff

View file

@ -52,6 +52,13 @@ mod search;
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Access {
Grant,
Denied,
Allow(BTreeSet<Attribute>),
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum AccessClass {
Grant,
Denied,
Allow(BTreeSet<AttrString>),
@ -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<Attribute>),
// Allow these attributes within constraints.
Allow(BTreeSet<Attribute>),
}
#[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<AccessControlCreate>,
acps_modify: Vec<AccessControlModify>,
acps_delete: Vec<AccessControlDelete>,
sync_agreements: HashMap<Uuid, BTreeSet<String>>,
sync_agreements: HashMap<Uuid, BTreeSet<Attribute>>,
// Oauth2
// Sync prov
}
@ -149,7 +172,7 @@ pub trait AccessControlsTransaction<'a> {
fn get_create(&self) -> &Vec<AccessControlCreate>;
fn get_modify(&self) -> &Vec<AccessControlModify>;
fn get_delete(&self) -> &Vec<AccessControlDelete>;
fn get_sync_agreements(&self) -> &HashMap<Uuid, BTreeSet<String>>;
fn get_sync_agreements(&self) -> &HashMap<Uuid, BTreeSet<Attribute>>;
#[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<Attribute> = 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<Vec<Entry<EntryReduced, EntryCommitted>>, 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<BTreeSet<_>> = 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<Attribute> = 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<Attribute> = 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<Attribute> = 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<Attribute> = 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<BTreeSet<AttrString>>,
attrs: Option<BTreeSet<Attribute>>,
entries: &[Arc<EntrySealedCommitted>],
) -> Result<Vec<AccessEffectivePermission>, 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<Uuid, BTreeSet<String>>) {
pub fn update_sync_agreements(
&mut self,
mut sync_agreements: HashMap<Uuid, BTreeSet<Attribute>>,
) {
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<Uuid, BTreeSet<String>> {
fn get_sync_agreements(&self) -> &HashMap<Uuid, BTreeSet<Attribute>> {
&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<Uuid, BTreeSet<String>> {
fn get_sync_agreements(&self) -> &HashMap<Uuid, BTreeSet<Attribute>> {
&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
);

View file

@ -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<Attribute>,
rem: BTreeSet<Attribute>,
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<Uuid, BTreeSet<String>>,
entry: &'a Arc<EntrySealedCommitted>,
sync_agreements: &HashMap<Uuid, BTreeSet<Attribute>>,
entry: &Arc<EntrySealedCommitted>,
) -> 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<Attribute> = 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<Attribute> = 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<EntrySealedCommitted>,
sync_agreements: &'a HashMap<Uuid, BTreeSet<String>>,
) -> AccessResult<'a> {
entry: &Arc<EntrySealedCommitted>,
sync_agreements: &HashMap<Uuid, BTreeSet<Attribute>>,
) -> 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)

View file

@ -19,7 +19,7 @@ pub struct AccessControlSearchResolved<'a> {
#[derive(Debug, Clone)]
pub struct AccessControlSearch {
pub acp: AccessControlProfile,
pub attrs: BTreeSet<AttrString>,
pub attrs: BTreeSet<Attribute>,
}
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<FilterValid>,
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<AttrString>,
pub attrs: Vec<AttrString>,
pub attrs: Vec<Attribute>,
}
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<AttrString>,
pub presattrs: Vec<AttrString>,
pub remattrs: Vec<AttrString>,
pub presattrs: Vec<Attribute>,
pub remattrs: Vec<Attribute>,
}
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(),
}
}
}

View file

@ -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<Attribute>),
}
pub(super) fn apply_search_access<'a>(
pub(super) fn apply_search_access(
ident: &Identity,
related_acp: &'a [AccessControlSearchResolved],
entry: &'a Arc<EntrySealedCommitted>,
) -> SearchResult<'a> {
related_acp: &[AccessControlSearchResolved],
entry: &Arc<EntrySealedCommitted>,
) -> 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<EntrySealedCommitted>,
) -> AccessResult<'a> {
related_acp: &[AccessControlSearchResolved],
entry: &Arc<EntrySealedCommitted>,
) -> 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<Attribute> = 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<EntrySealedCommitted>,
) -> AccessResult<'a> {
fn search_oauth2_filter_entry(ident: &Identity, entry: &Arc<EntrySealedCommitted>) -> 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<EntrySealedCommitted>,
) -> AccessResult<'a> {
entry: &Arc<EntrySealedCommitted>,
) -> 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
));
}
}

View file

@ -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)?;

View file

@ -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<Value, OperationError> {
fn clone_value(&mut self, attr: &Attribute, value: &str) -> Result<Value, OperationError> {
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<PartialValue, OperationError> {
let schema = self.get_schema();
@ -1652,6 +1652,7 @@ impl<'a> QueryServerWriteTransaction<'a> {
// load them.
let attributetypes: Result<Vec<_>, _> =
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<Uuid, BTreeSet<String>> = res
let sync_agreement_map: HashMap<Uuid, BTreeSet<Attribute>> = 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!(

View file

@ -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());

View file

@ -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"))
);

View file

@ -449,14 +449,14 @@ impl From<CredentialType> for PartialValue {
impl From<Attribute> for Value {
fn from(attr: Attribute) -> Value {
let s: &str = attr.into();
let s: &str = attr.as_str();
Value::new_iutf8(s)
}
}
impl From<Attribute> for PartialValue {
fn from(attr: Attribute) -> PartialValue {
let s: &str = attr.into();
let s: &str = attr.as_str();
PartialValue::new_iutf8(s)
}
}

View file

@ -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());
}
/*

View file

@ -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)
}

View file

@ -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