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