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