kanidm_proto/
attribute.rs

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