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