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