kanidm_proto/
attribute.rs

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