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