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