Skip to main content

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