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