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