kanidm_proto/
attribute.rs

1use serde::{Deserialize, Serialize};
2use utoipa::ToSchema;
3
4use crate::constants::*;
5use crate::internal::OperationError;
6use std::convert::Infallible;
7use std::fmt;
8use std::str::FromStr;
9
10pub use smartstring::alias::String as AttrString;
11
12#[derive(
13    Serialize, Deserialize, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash, Default, ToSchema,
14)]
15#[cfg_attr(test, derive(enum_iterator::Sequence))]
16#[serde(rename_all = "lowercase", try_from = "&str", into = "AttrString")]
17pub enum Attribute {
18    Account,
19    AccountExpire,
20    AccountValidFrom,
21    AcpCreateAttr,
22    AcpCreateClass,
23    AcpEnable,
24    AcpModifyClass,
25    AcpModifyPresentClass,
26    AcpModifyRemoveClass,
27    AcpModifyPresentAttr,
28    AcpModifyRemovedAttr,
29    AcpReceiver,
30    AcpReceiverGroup,
31    AcpSearchAttr,
32    AcpTargetScope,
33    ApiTokenSession,
34    ApplicationPassword,
35    ApplicationUrl,
36    AttestedPasskeys,
37    #[default]
38    Attr,
39    AttributeName,
40    AttributeType,
41    AuthSessionExpiry,
42    AuthPasswordMinimumLength,
43    BadlistPassword,
44    Certificate,
45    Claim,
46    Class,
47    ClassName,
48    Cn,
49    CookiePrivateKey,
50    CreatedAtCid,
51    CredentialUpdateIntentToken,
52    CredentialTypeMinimum,
53    DeniedName,
54    Description,
55    DirectMemberOf,
56    DisplayName,
57    Dn,
58    Domain,
59    DomainAllowEasterEggs,
60    DomainDevelopmentTaint,
61    DomainDisplayName,
62    DomainLdapBasedn,
63    DomainName,
64    DomainSsid,
65    DomainTokenKey,
66    DomainUuid,
67    DynGroup,
68    DynGroupFilter,
69    DynMember,
70    Email,
71    EmailAlternative,
72    EmailPrimary,
73    EntryDn,
74    EntryManagedBy,
75    EntryUuid,
76    Es256PrivateKeyDer,
77    Excludes,
78    FernetPrivateKeyStr,
79    Gecos,
80    GidNumber,
81    GrantUiHint,
82    Group,
83    IdVerificationEcKey,
84    Image,
85    Index,
86    Indexed,
87    IpaNtHash,
88    IpaSshPubKey,
89    JwsEs256PrivateKey,
90    KeyActionRotate,
91    KeyActionRevoke,
92    KeyActionImportJwsEs256,
93    KeyActionImportJwsRs256,
94    KeyInternalData,
95    KeyProvider,
96    LastModifiedCid,
97    LdapAllowUnixPwBind,
98    /// An LDAP Compatible emailAddress
99    LdapEmailAddress,
100    /// An LDAP Compatible sshkeys virtual attribute
101    LdapKeys,
102    LdapMaxQueryableAttrs,
103    LegalName,
104    LimitSearchMaxResults,
105    LimitSearchMaxFilterTest,
106    LinkedGroup,
107    LoginShell,
108    Mail,
109    May,
110    Member,
111    MemberOf,
112    MultiValue,
113    Must,
114    Name,
115    NameHistory,
116    NoIndex,
117    NsUniqueId,
118    NsAccountLock,
119    OAuth2AllowInsecureClientDisablePkce,
120    OAuth2AllowLocalhostRedirect,
121    OAuth2ConsentScopeMap,
122    OAuth2DeviceFlowEnable,
123    OAuth2JwtLegacyCryptoEnable,
124    OAuth2PreferShortUsername,
125    OAuth2RsBasicSecret,
126    OAuth2RsClaimMap,
127    OAuth2RsImplicitScopes,
128    OAuth2RsName,
129    OAuth2RsOrigin,
130    OAuth2RsOriginLanding,
131    OAuth2RsScopeMap,
132    OAuth2RsSupScopeMap,
133    OAuth2RsTokenKey,
134    OAuth2Session,
135    OAuth2StrictRedirectUri,
136    ObjectClass,
137    OtherNoIndex,
138    PassKeys,
139    PasswordImport,
140    PatchLevel,
141    Phantom,
142    PrimaryCredential,
143    PrivateCookieKey,
144    PrivilegeExpiry,
145    RadiusSecret,
146    RecycledDirectMemberOf,
147    Refers,
148    Replicated,
149    Rs256PrivateKeyDer,
150    /// A set of scim schemas. This is similar to a kanidm class.
151    #[serde(rename = "schemas")]
152    ScimSchemas,
153    Scope,
154    SourceUuid,
155    Spn,
156    /// An LDAP-compatible sshpublickey
157    LdapSshPublicKey,
158    /// The Kanidm-local ssh_publickey
159    SshPublicKey,
160    SudoHost,
161    Supplements,
162    SystemSupplements,
163    SyncAllowed,
164    SyncClass,
165    SyncCookie,
166    SyncCredentialPortal,
167    SyncExternalId,
168    SyncParentUuid,
169    SyncTokenSession,
170    SyncYieldAuthority,
171    Syntax,
172    SystemExcludes,
173    SystemMay,
174    SystemMust,
175    Term,
176    TotpImport,
177    Uid,
178    UidNumber,
179    Unique,
180    UnixPassword,
181    UnixPasswordImport,
182    UserAuthTokenSession,
183    UserId,
184    UserPassword,
185    Uuid,
186    Version,
187    WebauthnAttestationCaList,
188    AllowPrimaryCredFallback,
189
190    #[cfg(any(debug_assertions, test, feature = "test"))]
191    NonExist,
192    #[cfg(any(debug_assertions, test, feature = "test"))]
193    TestAttr,
194    #[cfg(test)]
195    TestAttrA,
196    #[cfg(test)]
197    TestAttrB,
198    #[cfg(test)]
199    TestAttrC,
200    #[cfg(test)]
201    TestAttrD,
202    #[cfg(any(debug_assertions, test, feature = "test"))]
203    TestNumber,
204    #[cfg(any(debug_assertions, test, feature = "test"))]
205    Extra,
206    #[cfg(any(debug_assertions, test, feature = "test"))]
207    TestNotAllowed,
208
209    #[cfg(not(test))]
210    #[schema(value_type = String)]
211    Custom(AttrString),
212}
213
214impl AsRef<str> for Attribute {
215    fn as_ref(&self) -> &str {
216        self.as_str()
217    }
218}
219
220impl AsRef<Attribute> for Attribute {
221    fn as_ref(&self) -> &Attribute {
222        self
223    }
224}
225
226impl TryFrom<&AttrString> for Attribute {
227    type Error = OperationError;
228
229    fn try_from(value: &AttrString) -> Result<Self, Self::Error> {
230        Ok(Attribute::inner_from_str(value.as_str()))
231    }
232}
233
234impl From<&str> for Attribute {
235    fn from(value: &str) -> Self {
236        Self::inner_from_str(value)
237    }
238}
239
240impl<'a> From<&'a Attribute> for &'a str {
241    fn from(val: &'a Attribute) -> Self {
242        val.as_str()
243    }
244}
245
246impl From<Attribute> for AttrString {
247    fn from(val: Attribute) -> Self {
248        AttrString::from(val.as_str())
249    }
250}
251
252impl FromStr for Attribute {
253    type Err = Infallible;
254
255    fn from_str(value: &str) -> Result<Self, Self::Err> {
256        Ok(Self::inner_from_str(value))
257    }
258}
259
260impl Attribute {
261    pub fn as_str(&self) -> &str {
262        match self {
263            Attribute::Account => ATTR_ACCOUNT,
264            Attribute::AccountExpire => ATTR_ACCOUNT_EXPIRE,
265            Attribute::AccountValidFrom => ATTR_ACCOUNT_VALID_FROM,
266            Attribute::AcpCreateAttr => ATTR_ACP_CREATE_ATTR,
267            Attribute::AcpCreateClass => ATTR_ACP_CREATE_CLASS,
268            Attribute::AcpEnable => ATTR_ACP_ENABLE,
269            Attribute::AcpModifyClass => ATTR_ACP_MODIFY_CLASS,
270            Attribute::AcpModifyPresentClass => ATTR_ACP_MODIFY_PRESENT_CLASS,
271            Attribute::AcpModifyRemoveClass => ATTR_ACP_MODIFY_REMOVE_CLASS,
272            Attribute::AcpModifyPresentAttr => ATTR_ACP_MODIFY_PRESENTATTR,
273            Attribute::AcpModifyRemovedAttr => ATTR_ACP_MODIFY_REMOVEDATTR,
274            Attribute::AcpReceiver => ATTR_ACP_RECEIVER,
275            Attribute::AcpReceiverGroup => ATTR_ACP_RECEIVER_GROUP,
276            Attribute::AcpSearchAttr => ATTR_ACP_SEARCH_ATTR,
277            Attribute::AcpTargetScope => ATTR_ACP_TARGET_SCOPE,
278            Attribute::ApiTokenSession => ATTR_API_TOKEN_SESSION,
279            Attribute::ApplicationPassword => ATTR_APPLICATION_PASSWORD,
280            Attribute::ApplicationUrl => ATTR_APPLICATION_URL,
281            Attribute::AttestedPasskeys => ATTR_ATTESTED_PASSKEYS,
282            Attribute::Attr => ATTR_ATTR,
283            Attribute::AttributeName => ATTR_ATTRIBUTENAME,
284            Attribute::AttributeType => ATTR_ATTRIBUTETYPE,
285            Attribute::AuthSessionExpiry => ATTR_AUTH_SESSION_EXPIRY,
286            Attribute::AuthPasswordMinimumLength => ATTR_AUTH_PASSWORD_MINIMUM_LENGTH,
287            Attribute::BadlistPassword => ATTR_BADLIST_PASSWORD,
288            Attribute::Certificate => ATTR_CERTIFICATE,
289            Attribute::Claim => ATTR_CLAIM,
290            Attribute::Class => ATTR_CLASS,
291            Attribute::ClassName => ATTR_CLASSNAME,
292            Attribute::Cn => ATTR_CN,
293            Attribute::CookiePrivateKey => ATTR_COOKIE_PRIVATE_KEY,
294            Attribute::CreatedAtCid => ATTR_CREATED_AT_CID,
295            Attribute::CredentialUpdateIntentToken => ATTR_CREDENTIAL_UPDATE_INTENT_TOKEN,
296            Attribute::CredentialTypeMinimum => ATTR_CREDENTIAL_TYPE_MINIMUM,
297            Attribute::DeniedName => ATTR_DENIED_NAME,
298            Attribute::Description => ATTR_DESCRIPTION,
299            Attribute::DirectMemberOf => ATTR_DIRECTMEMBEROF,
300            Attribute::DisplayName => ATTR_DISPLAYNAME,
301            Attribute::Dn => ATTR_DN,
302            Attribute::Domain => ATTR_DOMAIN,
303            Attribute::DomainAllowEasterEggs => ATTR_DOMAIN_ALLOW_EASTER_EGGS,
304            Attribute::DomainDevelopmentTaint => ATTR_DOMAIN_DEVELOPMENT_TAINT,
305            Attribute::DomainDisplayName => ATTR_DOMAIN_DISPLAY_NAME,
306            Attribute::DomainLdapBasedn => ATTR_DOMAIN_LDAP_BASEDN,
307            Attribute::DomainName => ATTR_DOMAIN_NAME,
308            Attribute::DomainSsid => ATTR_DOMAIN_SSID,
309            Attribute::DomainTokenKey => ATTR_DOMAIN_TOKEN_KEY,
310            Attribute::DomainUuid => ATTR_DOMAIN_UUID,
311            Attribute::DynGroup => ATTR_DYNGROUP,
312            Attribute::DynGroupFilter => ATTR_DYNGROUP_FILTER,
313            Attribute::DynMember => ATTR_DYNMEMBER,
314            Attribute::Email => ATTR_EMAIL,
315            Attribute::EmailAlternative => ATTR_EMAIL_ALTERNATIVE,
316            Attribute::EmailPrimary => ATTR_EMAIL_PRIMARY,
317            Attribute::EntryDn => ATTR_ENTRYDN,
318            Attribute::EntryManagedBy => ATTR_ENTRY_MANAGED_BY,
319            Attribute::EntryUuid => ATTR_ENTRYUUID,
320            Attribute::Es256PrivateKeyDer => ATTR_ES256_PRIVATE_KEY_DER,
321            Attribute::Excludes => ATTR_EXCLUDES,
322            Attribute::FernetPrivateKeyStr => ATTR_FERNET_PRIVATE_KEY_STR,
323            Attribute::Gecos => ATTR_GECOS,
324            Attribute::GidNumber => ATTR_GIDNUMBER,
325            Attribute::GrantUiHint => ATTR_GRANT_UI_HINT,
326            Attribute::Group => ATTR_GROUP,
327            Attribute::IdVerificationEcKey => ATTR_ID_VERIFICATION_ECKEY,
328            Attribute::Image => ATTR_IMAGE,
329            Attribute::Index => ATTR_INDEX,
330            Attribute::Indexed => ATTR_INDEXED,
331            Attribute::IpaNtHash => ATTR_IPANTHASH,
332            Attribute::IpaSshPubKey => ATTR_IPASSHPUBKEY,
333            Attribute::JwsEs256PrivateKey => ATTR_JWS_ES256_PRIVATE_KEY,
334            Attribute::KeyActionRotate => ATTR_KEY_ACTION_ROTATE,
335            Attribute::KeyActionRevoke => ATTR_KEY_ACTION_REVOKE,
336            Attribute::KeyActionImportJwsEs256 => ATTR_KEY_ACTION_IMPORT_JWS_ES256,
337            Attribute::KeyActionImportJwsRs256 => ATTR_KEY_ACTION_IMPORT_JWS_RS256,
338            Attribute::KeyInternalData => ATTR_KEY_INTERNAL_DATA,
339            Attribute::KeyProvider => ATTR_KEY_PROVIDER,
340            Attribute::LastModifiedCid => ATTR_LAST_MODIFIED_CID,
341            Attribute::LdapAllowUnixPwBind => ATTR_LDAP_ALLOW_UNIX_PW_BIND,
342            Attribute::LdapEmailAddress => ATTR_LDAP_EMAIL_ADDRESS,
343            Attribute::LdapKeys => ATTR_LDAP_KEYS,
344            Attribute::LdapMaxQueryableAttrs => ATTR_LDAP_MAX_QUERYABLE_ATTRS,
345            Attribute::LdapSshPublicKey => ATTR_LDAP_SSHPUBLICKEY,
346            Attribute::LegalName => ATTR_LEGALNAME,
347            Attribute::LimitSearchMaxResults => ATTR_LIMIT_SEARCH_MAX_RESULTS,
348            Attribute::LimitSearchMaxFilterTest => ATTR_LIMIT_SEARCH_MAX_FILTER_TEST,
349            Attribute::LinkedGroup => ATTR_LINKEDGROUP,
350            Attribute::LoginShell => ATTR_LOGINSHELL,
351            Attribute::Mail => ATTR_MAIL,
352            Attribute::May => ATTR_MAY,
353            Attribute::Member => ATTR_MEMBER,
354            Attribute::MemberOf => ATTR_MEMBEROF,
355            Attribute::MultiValue => ATTR_MULTIVALUE,
356            Attribute::Must => ATTR_MUST,
357            Attribute::Name => ATTR_NAME,
358            Attribute::NameHistory => ATTR_NAME_HISTORY,
359            Attribute::NoIndex => ATTR_NO_INDEX,
360            Attribute::NsUniqueId => ATTR_NSUNIQUEID,
361            Attribute::NsAccountLock => ATTR_NSACCOUNTLOCK,
362            Attribute::OAuth2AllowInsecureClientDisablePkce => {
363                ATTR_OAUTH2_ALLOW_INSECURE_CLIENT_DISABLE_PKCE
364            }
365            Attribute::OAuth2AllowLocalhostRedirect => ATTR_OAUTH2_ALLOW_LOCALHOST_REDIRECT,
366            Attribute::OAuth2ConsentScopeMap => ATTR_OAUTH2_CONSENT_SCOPE_MAP,
367            Attribute::OAuth2DeviceFlowEnable => ATTR_OAUTH2_DEVICE_FLOW_ENABLE,
368            Attribute::OAuth2JwtLegacyCryptoEnable => ATTR_OAUTH2_JWT_LEGACY_CRYPTO_ENABLE,
369            Attribute::OAuth2PreferShortUsername => ATTR_OAUTH2_PREFER_SHORT_USERNAME,
370            Attribute::OAuth2RsBasicSecret => ATTR_OAUTH2_RS_BASIC_SECRET,
371            Attribute::OAuth2RsClaimMap => ATTR_OAUTH2_RS_CLAIM_MAP,
372            Attribute::OAuth2RsImplicitScopes => ATTR_OAUTH2_RS_IMPLICIT_SCOPES,
373            Attribute::OAuth2RsName => ATTR_OAUTH2_RS_NAME,
374            Attribute::OAuth2RsOrigin => ATTR_OAUTH2_RS_ORIGIN,
375            Attribute::OAuth2RsOriginLanding => ATTR_OAUTH2_RS_ORIGIN_LANDING,
376            Attribute::OAuth2RsScopeMap => ATTR_OAUTH2_RS_SCOPE_MAP,
377            Attribute::OAuth2RsSupScopeMap => ATTR_OAUTH2_RS_SUP_SCOPE_MAP,
378            Attribute::OAuth2RsTokenKey => ATTR_OAUTH2_RS_TOKEN_KEY,
379            Attribute::OAuth2Session => ATTR_OAUTH2_SESSION,
380            Attribute::OAuth2StrictRedirectUri => ATTR_OAUTH2_STRICT_REDIRECT_URI,
381            Attribute::ObjectClass => ATTR_OBJECTCLASS,
382            Attribute::OtherNoIndex => ATTR_OTHER_NO_INDEX,
383            Attribute::PassKeys => ATTR_PASSKEYS,
384            Attribute::PasswordImport => ATTR_PASSWORD_IMPORT,
385            Attribute::PatchLevel => ATTR_PATCH_LEVEL,
386            Attribute::Phantom => ATTR_PHANTOM,
387            Attribute::PrimaryCredential => ATTR_PRIMARY_CREDENTIAL,
388            Attribute::PrivateCookieKey => ATTR_PRIVATE_COOKIE_KEY,
389            Attribute::PrivilegeExpiry => ATTR_PRIVILEGE_EXPIRY,
390            Attribute::RadiusSecret => ATTR_RADIUS_SECRET,
391            Attribute::RecycledDirectMemberOf => ATTR_RECYCLEDDIRECTMEMBEROF,
392            Attribute::Refers => ATTR_REFERS,
393            Attribute::Replicated => ATTR_REPLICATED,
394            Attribute::Rs256PrivateKeyDer => ATTR_RS256_PRIVATE_KEY_DER,
395            Attribute::Scope => ATTR_SCOPE,
396            Attribute::ScimSchemas => ATTR_SCIM_SCHEMAS,
397            Attribute::SourceUuid => ATTR_SOURCE_UUID,
398            Attribute::Spn => ATTR_SPN,
399            Attribute::SshPublicKey => ATTR_SSH_PUBLICKEY,
400            Attribute::SudoHost => ATTR_SUDOHOST,
401            Attribute::Supplements => ATTR_SUPPLEMENTS,
402            Attribute::SyncAllowed => ATTR_SYNC_ALLOWED,
403            Attribute::SyncClass => ATTR_SYNC_CLASS,
404            Attribute::SyncCookie => ATTR_SYNC_COOKIE,
405            Attribute::SyncCredentialPortal => ATTR_SYNC_CREDENTIAL_PORTAL,
406            Attribute::SyncExternalId => ATTR_SYNC_EXTERNAL_ID,
407            Attribute::SyncParentUuid => ATTR_SYNC_PARENT_UUID,
408            Attribute::SyncTokenSession => ATTR_SYNC_TOKEN_SESSION,
409            Attribute::SyncYieldAuthority => ATTR_SYNC_YIELD_AUTHORITY,
410            Attribute::Syntax => ATTR_SYNTAX,
411            Attribute::SystemExcludes => ATTR_SYSTEMEXCLUDES,
412            Attribute::SystemMay => ATTR_SYSTEMMAY,
413            Attribute::SystemMust => ATTR_SYSTEMMUST,
414            Attribute::SystemSupplements => ATTR_SYSTEMSUPPLEMENTS,
415            Attribute::Term => ATTR_TERM,
416            Attribute::TotpImport => ATTR_TOTP_IMPORT,
417            Attribute::Uid => ATTR_UID,
418            Attribute::UidNumber => ATTR_UIDNUMBER,
419            Attribute::Unique => ATTR_UNIQUE,
420            Attribute::UnixPassword => ATTR_UNIX_PASSWORD,
421            Attribute::UnixPasswordImport => ATTR_UNIX_PASSWORD_IMPORT,
422            Attribute::UserAuthTokenSession => ATTR_USER_AUTH_TOKEN_SESSION,
423            Attribute::UserId => ATTR_USERID,
424            Attribute::UserPassword => ATTR_USERPASSWORD,
425            Attribute::Uuid => ATTR_UUID,
426            Attribute::Version => ATTR_VERSION,
427            Attribute::WebauthnAttestationCaList => ATTR_WEBAUTHN_ATTESTATION_CA_LIST,
428            Attribute::AllowPrimaryCredFallback => ATTR_ALLOW_PRIMARY_CRED_FALLBACK,
429
430            #[cfg(any(debug_assertions, test, feature = "test"))]
431            Attribute::NonExist => TEST_ATTR_NON_EXIST,
432            #[cfg(any(debug_assertions, test, feature = "test"))]
433            Attribute::TestAttr => TEST_ATTR_TEST_ATTR,
434
435            #[cfg(test)]
436            Attribute::TestAttrA => TEST_ATTR_TEST_ATTR_A,
437            #[cfg(test)]
438            Attribute::TestAttrB => TEST_ATTR_TEST_ATTR_B,
439            #[cfg(test)]
440            Attribute::TestAttrC => TEST_ATTR_TEST_ATTR_C,
441            #[cfg(test)]
442            Attribute::TestAttrD => TEST_ATTR_TEST_ATTR_D,
443
444            #[cfg(any(debug_assertions, test, feature = "test"))]
445            Attribute::Extra => TEST_ATTR_EXTRA,
446            #[cfg(any(debug_assertions, test, feature = "test"))]
447            Attribute::TestNumber => TEST_ATTR_NUMBER,
448            #[cfg(any(debug_assertions, test, feature = "test"))]
449            Attribute::TestNotAllowed => TEST_ATTR_NOTALLOWED,
450
451            #[cfg(not(test))]
452            Attribute::Custom(value) => value.as_str(),
453        }
454    }
455
456    // We allow this because the standard lib from_str is fallible, and we want an infallible version.
457    #[allow(clippy::should_implement_trait)]
458    fn inner_from_str(value: &str) -> Self {
459        // Could this be something like heapless to save allocations? Also gives a way
460        // to limit length of str?
461        match value.to_lowercase().as_str() {
462            ATTR_ACCOUNT => Attribute::Account,
463            ATTR_ACCOUNT_EXPIRE => Attribute::AccountExpire,
464            ATTR_ACCOUNT_VALID_FROM => Attribute::AccountValidFrom,
465            ATTR_ACP_CREATE_ATTR => Attribute::AcpCreateAttr,
466            ATTR_ACP_CREATE_CLASS => Attribute::AcpCreateClass,
467            ATTR_ACP_ENABLE => Attribute::AcpEnable,
468            ATTR_ACP_MODIFY_CLASS => Attribute::AcpModifyClass,
469            ATTR_ACP_MODIFY_PRESENT_CLASS => Attribute::AcpModifyPresentClass,
470            ATTR_ACP_MODIFY_REMOVE_CLASS => Attribute::AcpModifyRemoveClass,
471            ATTR_ACP_MODIFY_PRESENTATTR => Attribute::AcpModifyPresentAttr,
472            ATTR_ACP_MODIFY_REMOVEDATTR => Attribute::AcpModifyRemovedAttr,
473            ATTR_ACP_RECEIVER => Attribute::AcpReceiver,
474            ATTR_ACP_RECEIVER_GROUP => Attribute::AcpReceiverGroup,
475            ATTR_ACP_SEARCH_ATTR => Attribute::AcpSearchAttr,
476            ATTR_ACP_TARGET_SCOPE => Attribute::AcpTargetScope,
477            ATTR_API_TOKEN_SESSION => Attribute::ApiTokenSession,
478            ATTR_APPLICATION_PASSWORD => Attribute::ApplicationPassword,
479            ATTR_APPLICATION_URL => Attribute::ApplicationUrl,
480            ATTR_ATTESTED_PASSKEYS => Attribute::AttestedPasskeys,
481            ATTR_ATTR => Attribute::Attr,
482            ATTR_ATTRIBUTENAME => Attribute::AttributeName,
483            ATTR_ATTRIBUTETYPE => Attribute::AttributeType,
484            ATTR_AUTH_SESSION_EXPIRY => Attribute::AuthSessionExpiry,
485            ATTR_AUTH_PASSWORD_MINIMUM_LENGTH => Attribute::AuthPasswordMinimumLength,
486            ATTR_BADLIST_PASSWORD => Attribute::BadlistPassword,
487            ATTR_CERTIFICATE => Attribute::Certificate,
488            ATTR_CLAIM => Attribute::Claim,
489            ATTR_CLASS => Attribute::Class,
490            ATTR_CLASSNAME => Attribute::ClassName,
491            ATTR_CN => Attribute::Cn,
492            ATTR_COOKIE_PRIVATE_KEY => Attribute::CookiePrivateKey,
493            ATTR_CREATED_AT_CID => Attribute::CreatedAtCid,
494            ATTR_CREDENTIAL_UPDATE_INTENT_TOKEN => Attribute::CredentialUpdateIntentToken,
495            ATTR_CREDENTIAL_TYPE_MINIMUM => Attribute::CredentialTypeMinimum,
496            ATTR_DENIED_NAME => Attribute::DeniedName,
497            ATTR_DESCRIPTION => Attribute::Description,
498            ATTR_DIRECTMEMBEROF => Attribute::DirectMemberOf,
499            ATTR_DISPLAYNAME => Attribute::DisplayName,
500            ATTR_DN => Attribute::Dn,
501            ATTR_DOMAIN => Attribute::Domain,
502            ATTR_DOMAIN_ALLOW_EASTER_EGGS => Attribute::DomainAllowEasterEggs,
503            ATTR_DOMAIN_DISPLAY_NAME => Attribute::DomainDisplayName,
504            ATTR_DOMAIN_DEVELOPMENT_TAINT => Attribute::DomainDevelopmentTaint,
505            ATTR_DOMAIN_LDAP_BASEDN => Attribute::DomainLdapBasedn,
506            ATTR_DOMAIN_NAME => Attribute::DomainName,
507            ATTR_DOMAIN_SSID => Attribute::DomainSsid,
508            ATTR_DOMAIN_TOKEN_KEY => Attribute::DomainTokenKey,
509            ATTR_DOMAIN_UUID => Attribute::DomainUuid,
510            ATTR_DYNGROUP => Attribute::DynGroup,
511            ATTR_DYNGROUP_FILTER => Attribute::DynGroupFilter,
512            ATTR_DYNMEMBER => Attribute::DynMember,
513            ATTR_EMAIL => Attribute::Email,
514            ATTR_EMAIL_ALTERNATIVE => Attribute::EmailAlternative,
515            ATTR_EMAIL_PRIMARY => Attribute::EmailPrimary,
516            ATTR_ENTRYDN => Attribute::EntryDn,
517            ATTR_ENTRY_MANAGED_BY => Attribute::EntryManagedBy,
518            ATTR_ENTRYUUID => Attribute::EntryUuid,
519            ATTR_ES256_PRIVATE_KEY_DER => Attribute::Es256PrivateKeyDer,
520            ATTR_EXCLUDES => Attribute::Excludes,
521            ATTR_FERNET_PRIVATE_KEY_STR => Attribute::FernetPrivateKeyStr,
522            ATTR_GECOS => Attribute::Gecos,
523            ATTR_GIDNUMBER => Attribute::GidNumber,
524            ATTR_GRANT_UI_HINT => Attribute::GrantUiHint,
525            ATTR_GROUP => Attribute::Group,
526            ATTR_ID_VERIFICATION_ECKEY => Attribute::IdVerificationEcKey,
527            ATTR_IMAGE => Attribute::Image,
528            ATTR_INDEX => Attribute::Index,
529            ATTR_INDEXED => Attribute::Indexed,
530            ATTR_IPANTHASH => Attribute::IpaNtHash,
531            ATTR_IPASSHPUBKEY => Attribute::IpaSshPubKey,
532            ATTR_JWS_ES256_PRIVATE_KEY => Attribute::JwsEs256PrivateKey,
533            ATTR_KEY_ACTION_ROTATE => Attribute::KeyActionRotate,
534            ATTR_KEY_ACTION_REVOKE => Attribute::KeyActionRevoke,
535            ATTR_KEY_ACTION_IMPORT_JWS_ES256 => Attribute::KeyActionImportJwsEs256,
536            ATTR_KEY_ACTION_IMPORT_JWS_RS256 => Attribute::KeyActionImportJwsRs256,
537            ATTR_KEY_INTERNAL_DATA => Attribute::KeyInternalData,
538            ATTR_KEY_PROVIDER => Attribute::KeyProvider,
539            ATTR_LAST_MODIFIED_CID => Attribute::LastModifiedCid,
540            ATTR_LDAP_ALLOW_UNIX_PW_BIND => Attribute::LdapAllowUnixPwBind,
541            ATTR_LDAP_EMAIL_ADDRESS => Attribute::LdapEmailAddress,
542            ATTR_LDAP_KEYS => Attribute::LdapKeys,
543            ATTR_LDAP_MAX_QUERYABLE_ATTRS => Attribute::LdapMaxQueryableAttrs,
544            ATTR_SSH_PUBLICKEY => Attribute::SshPublicKey,
545            ATTR_LEGALNAME => Attribute::LegalName,
546            ATTR_LINKEDGROUP => Attribute::LinkedGroup,
547            ATTR_LOGINSHELL => Attribute::LoginShell,
548            ATTR_LIMIT_SEARCH_MAX_RESULTS => Attribute::LimitSearchMaxResults,
549            ATTR_LIMIT_SEARCH_MAX_FILTER_TEST => Attribute::LimitSearchMaxFilterTest,
550            ATTR_MAIL => Attribute::Mail,
551            ATTR_MAY => Attribute::May,
552            ATTR_MEMBER => Attribute::Member,
553            ATTR_MEMBEROF => Attribute::MemberOf,
554            ATTR_MULTIVALUE => Attribute::MultiValue,
555            ATTR_MUST => Attribute::Must,
556            ATTR_NAME => Attribute::Name,
557            ATTR_NAME_HISTORY => Attribute::NameHistory,
558            ATTR_NO_INDEX => Attribute::NoIndex,
559            ATTR_NSUNIQUEID => Attribute::NsUniqueId,
560            ATTR_NSACCOUNTLOCK => Attribute::NsAccountLock,
561            ATTR_OAUTH2_ALLOW_INSECURE_CLIENT_DISABLE_PKCE => {
562                Attribute::OAuth2AllowInsecureClientDisablePkce
563            }
564            ATTR_OAUTH2_ALLOW_LOCALHOST_REDIRECT => Attribute::OAuth2AllowLocalhostRedirect,
565            ATTR_OAUTH2_CONSENT_SCOPE_MAP => Attribute::OAuth2ConsentScopeMap,
566            ATTR_OAUTH2_DEVICE_FLOW_ENABLE => Attribute::OAuth2DeviceFlowEnable,
567            ATTR_OAUTH2_JWT_LEGACY_CRYPTO_ENABLE => Attribute::OAuth2JwtLegacyCryptoEnable,
568            ATTR_OAUTH2_PREFER_SHORT_USERNAME => Attribute::OAuth2PreferShortUsername,
569            ATTR_OAUTH2_RS_BASIC_SECRET => Attribute::OAuth2RsBasicSecret,
570            ATTR_OAUTH2_RS_CLAIM_MAP => Attribute::OAuth2RsClaimMap,
571            ATTR_OAUTH2_RS_IMPLICIT_SCOPES => Attribute::OAuth2RsImplicitScopes,
572            ATTR_OAUTH2_RS_NAME => Attribute::OAuth2RsName,
573            ATTR_OAUTH2_RS_ORIGIN => Attribute::OAuth2RsOrigin,
574            ATTR_OAUTH2_RS_ORIGIN_LANDING => Attribute::OAuth2RsOriginLanding,
575            ATTR_OAUTH2_RS_SCOPE_MAP => Attribute::OAuth2RsScopeMap,
576            ATTR_OAUTH2_RS_SUP_SCOPE_MAP => Attribute::OAuth2RsSupScopeMap,
577            ATTR_OAUTH2_RS_TOKEN_KEY => Attribute::OAuth2RsTokenKey,
578            ATTR_OAUTH2_SESSION => Attribute::OAuth2Session,
579            ATTR_OAUTH2_STRICT_REDIRECT_URI => Attribute::OAuth2StrictRedirectUri,
580            ATTR_OBJECTCLASS => Attribute::ObjectClass,
581            ATTR_OTHER_NO_INDEX => Attribute::OtherNoIndex,
582            ATTR_PASSKEYS => Attribute::PassKeys,
583            ATTR_PASSWORD_IMPORT => Attribute::PasswordImport,
584            ATTR_PATCH_LEVEL => Attribute::PatchLevel,
585            ATTR_PHANTOM => Attribute::Phantom,
586            ATTR_PRIMARY_CREDENTIAL => Attribute::PrimaryCredential,
587            ATTR_PRIVATE_COOKIE_KEY => Attribute::PrivateCookieKey,
588            ATTR_PRIVILEGE_EXPIRY => Attribute::PrivilegeExpiry,
589            ATTR_RADIUS_SECRET => Attribute::RadiusSecret,
590            ATTR_RECYCLEDDIRECTMEMBEROF => Attribute::RecycledDirectMemberOf,
591            ATTR_REFERS => Attribute::Refers,
592            ATTR_REPLICATED => Attribute::Replicated,
593            ATTR_RS256_PRIVATE_KEY_DER => Attribute::Rs256PrivateKeyDer,
594            ATTR_SCIM_SCHEMAS => Attribute::ScimSchemas,
595            ATTR_SCOPE => Attribute::Scope,
596            ATTR_SOURCE_UUID => Attribute::SourceUuid,
597            ATTR_SPN => Attribute::Spn,
598            ATTR_LDAP_SSHPUBLICKEY => Attribute::LdapSshPublicKey,
599            ATTR_SUDOHOST => Attribute::SudoHost,
600            ATTR_SUPPLEMENTS => Attribute::Supplements,
601            ATTR_SYNC_ALLOWED => Attribute::SyncAllowed,
602            ATTR_SYNC_CLASS => Attribute::SyncClass,
603            ATTR_SYNC_COOKIE => Attribute::SyncCookie,
604            ATTR_SYNC_CREDENTIAL_PORTAL => Attribute::SyncCredentialPortal,
605            ATTR_SYNC_EXTERNAL_ID => Attribute::SyncExternalId,
606            ATTR_SYNC_PARENT_UUID => Attribute::SyncParentUuid,
607            ATTR_SYNC_TOKEN_SESSION => Attribute::SyncTokenSession,
608            ATTR_SYNC_YIELD_AUTHORITY => Attribute::SyncYieldAuthority,
609            ATTR_SYNTAX => Attribute::Syntax,
610            ATTR_SYSTEMEXCLUDES => Attribute::SystemExcludes,
611            ATTR_SYSTEMMAY => Attribute::SystemMay,
612            ATTR_SYSTEMMUST => Attribute::SystemMust,
613            ATTR_SYSTEMSUPPLEMENTS => Attribute::SystemSupplements,
614            ATTR_TERM => Attribute::Term,
615            ATTR_TOTP_IMPORT => Attribute::TotpImport,
616            ATTR_UID => Attribute::Uid,
617            ATTR_UIDNUMBER => Attribute::UidNumber,
618            ATTR_UNIQUE => Attribute::Unique,
619            ATTR_UNIX_PASSWORD => Attribute::UnixPassword,
620            ATTR_UNIX_PASSWORD_IMPORT => Attribute::UnixPasswordImport,
621            ATTR_USER_AUTH_TOKEN_SESSION => Attribute::UserAuthTokenSession,
622            ATTR_USERID => Attribute::UserId,
623            ATTR_USERPASSWORD => Attribute::UserPassword,
624            ATTR_UUID => Attribute::Uuid,
625            ATTR_VERSION => Attribute::Version,
626            ATTR_WEBAUTHN_ATTESTATION_CA_LIST => Attribute::WebauthnAttestationCaList,
627            ATTR_ALLOW_PRIMARY_CRED_FALLBACK => Attribute::AllowPrimaryCredFallback,
628
629            #[cfg(any(debug_assertions, test, feature = "test"))]
630            TEST_ATTR_NON_EXIST => Attribute::NonExist,
631            #[cfg(any(debug_assertions, test, feature = "test"))]
632            TEST_ATTR_TEST_ATTR => Attribute::TestAttr,
633
634            #[cfg(test)]
635            TEST_ATTR_TEST_ATTR_A => Attribute::TestAttrA,
636            #[cfg(test)]
637            TEST_ATTR_TEST_ATTR_B => Attribute::TestAttrB,
638            #[cfg(test)]
639            TEST_ATTR_TEST_ATTR_C => Attribute::TestAttrC,
640            #[cfg(test)]
641            TEST_ATTR_TEST_ATTR_D => Attribute::TestAttrD,
642
643            #[cfg(any(debug_assertions, test, feature = "test"))]
644            TEST_ATTR_EXTRA => Attribute::Extra,
645            #[cfg(any(debug_assertions, test, feature = "test"))]
646            TEST_ATTR_NUMBER => Attribute::TestNumber,
647            #[cfg(any(debug_assertions, test, feature = "test"))]
648            TEST_ATTR_NOTALLOWED => Attribute::TestNotAllowed,
649
650            #[cfg(not(test))]
651            _ => Attribute::Custom(AttrString::from(value)),
652            // Allowed only in tests
653            #[allow(clippy::unreachable)]
654            #[cfg(test)]
655            _ => {
656                unreachable!(
657                    "Check that you've implemented the Attribute conversion for {:?}",
658                    value
659                );
660            }
661        }
662    }
663}
664
665impl fmt::Display for Attribute {
666    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
667        write!(f, "{}", self.as_str())
668    }
669}
670
671impl From<Attribute> for String {
672    fn from(attr: Attribute) -> String {
673        attr.to_string()
674    }
675}
676
677/// Sub attributes are a component of SCIM, allowing tagged sub properties of a complex
678/// attribute to be accessed.
679#[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash)]
680#[serde(rename_all = "lowercase", try_from = "&str", into = "AttrString")]
681pub enum SubAttribute {
682    /// Denotes a primary value.
683    Primary,
684    /// The type of value
685    Type,
686    /// The data associated to a value
687    Value,
688
689    #[cfg(not(test))]
690    Custom(AttrString),
691}
692
693impl fmt::Display for SubAttribute {
694    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
695        write!(f, "{}", self.as_str())
696    }
697}
698
699impl From<SubAttribute> for AttrString {
700    fn from(val: SubAttribute) -> Self {
701        AttrString::from(val.as_str())
702    }
703}
704
705impl From<&str> for SubAttribute {
706    fn from(value: &str) -> Self {
707        Self::inner_from_str(value)
708    }
709}
710
711impl FromStr for SubAttribute {
712    type Err = Infallible;
713
714    fn from_str(value: &str) -> Result<Self, Self::Err> {
715        Ok(Self::inner_from_str(value))
716    }
717}
718
719impl SubAttribute {
720    pub fn as_str(&self) -> &str {
721        match self {
722            SubAttribute::Primary => SUB_ATTR_PRIMARY,
723            SubAttribute::Type => SUB_ATTR_TYPE,
724            SubAttribute::Value => SUB_ATTR_VALUE,
725            #[cfg(not(test))]
726            SubAttribute::Custom(s) => s,
727        }
728    }
729
730    // We allow this because the standard lib from_str is fallible, and we want an infallible version.
731    #[allow(clippy::should_implement_trait)]
732    fn inner_from_str(value: &str) -> Self {
733        // Could this be something like heapless to save allocations? Also gives a way
734        // to limit length of str?
735        match value.to_lowercase().as_str() {
736            SUB_ATTR_PRIMARY => SubAttribute::Primary,
737            SUB_ATTR_TYPE => SubAttribute::Type,
738            SUB_ATTR_VALUE => SubAttribute::Value,
739
740            #[cfg(not(test))]
741            _ => SubAttribute::Custom(AttrString::from(value)),
742
743            // Allowed only in tests
744            #[allow(clippy::unreachable)]
745            #[cfg(test)]
746            _ => {
747                unreachable!(
748                    "Check that you've implemented the SubAttribute conversion for {:?}",
749                    value
750                );
751            }
752        }
753    }
754}
755
756#[cfg(test)]
757mod test {
758    use super::Attribute;
759
760    #[test]
761    fn test_valueattribute_from_str() {
762        assert_eq!(Attribute::Uuid, Attribute::from("UUID"));
763        assert_eq!(Attribute::Uuid, Attribute::from("UuiD"));
764        assert_eq!(Attribute::Uuid, Attribute::from("uuid"));
765    }
766
767    #[test]
768    fn test_valueattribute_as_str() {
769        assert_eq!(Attribute::Class.as_str(), "class");
770        assert_eq!(Attribute::Class.to_string(), "class".to_string());
771    }
772
773    #[test]
774    // this ensures we cover both ends of the conversion to/from string-types
775    fn test_valueattribute_round_trip() {
776        use enum_iterator::all;
777        let the_list = all::<Attribute>().collect::<Vec<_>>();
778        for attr in the_list {
779            let attr2 = Attribute::from(attr.as_str());
780            assert!(
781                attr == attr2,
782                "Round-trip failed for {attr} <=> {attr2} check you've implemented a from and to string"
783            );
784        }
785    }
786}