001/* 002 * CDDL HEADER START 003 * 004 * The contents of this file are subject to the terms of the 005 * Common Development and Distribution License, Version 1.0 only 006 * (the "License"). You may not use this file except in compliance 007 * with the License. 008 * 009 * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt 010 * or http://forgerock.org/license/CDDLv1.0.html. 011 * See the License for the specific language governing permissions 012 * and limitations under the License. 013 * 014 * When distributing Covered Code, include this CDDL HEADER in each 015 * file and include the License file at legal-notices/CDDLv1_0.txt. 016 * If applicable, add the following below this CDDL HEADER, with the 017 * fields enclosed by brackets "[]" replaced with your own identifying 018 * information: 019 * Portions Copyright [yyyy] [name of copyright owner] 020 * 021 * CDDL HEADER END 022 * 023 * 024 * Copyright 2010 Sun Microsystems, Inc. 025 * Portions Copyright 2011-2015 ForgeRock AS. 026 */ 027package org.opends.server.core; 028 029import static org.opends.messages.ConfigMessages.*; 030import static org.opends.messages.CoreMessages.*; 031import static org.opends.server.schema.SchemaConstants.*; 032 033import java.util.*; 034import java.util.concurrent.atomic.AtomicBoolean; 035 036import org.forgerock.i18n.LocalizableMessage; 037import org.forgerock.i18n.LocalizableMessageBuilder; 038import org.opends.server.admin.std.meta.PasswordPolicyCfgDefn.*; 039import org.opends.server.admin.std.server.PasswordValidatorCfg; 040import org.opends.server.api.AccountStatusNotificationHandler; 041import org.opends.server.api.PasswordGenerator; 042import org.opends.server.api.PasswordStorageScheme; 043import org.opends.server.api.PasswordValidator; 044import org.forgerock.i18n.slf4j.LocalizedLogger; 045import org.forgerock.opendj.config.server.ConfigException; 046import org.opends.server.types.*; 047import org.forgerock.opendj.ldap.ResultCode; 048import org.forgerock.opendj.ldap.ByteString; 049 050/** 051 * This class represents subentry password policy based on Password Policy for 052 * LDAP Directories Internet-Draft. In order to represent subentry password 053 * policies as OpenDJ password policies it performs a mapping of Draft defined 054 * attributes to OpenDJ implementation specific attributes. Any missing 055 * attributes are inherited from server default password policy. This class is 056 * also responsible for any Draft attributes validation ie making sure that 057 * provided values are acceptable and within the predefined range. 058 */ 059public final class SubentryPasswordPolicy extends PasswordPolicy 060{ 061 private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass(); 062 063 // Password Policy Subentry draft attributes. 064 private static final String PWD_OC_POLICY = "pwdpolicy"; 065 private static final String PWD_ATTR_ATTRIBUTE = "pwdattribute"; 066 private static final String PWD_ATTR_MINAGE = "pwdminage"; 067 private static final String PWD_ATTR_MAXAGE = "pwdmaxage"; 068 private static final String PWD_ATTR_INHISTORY = "pwdinhistory"; 069 private static final String PWD_ATTR_CHECKQUALITY = "pwdcheckquality"; 070 private static final String PWD_ATTR_MINLENGTH = "pwdminlength"; 071 private static final String PWD_ATTR_EXPIREWARNING = "pwdexpirewarning"; 072 private static final String PWD_ATTR_GRACEAUTHNLIMIT = "pwdgraceauthnlimit"; 073 private static final String PWD_ATTR_LOCKOUT = "pwdlockout"; 074 private static final String PWD_ATTR_LOCKOUTDURATION = "pwdlockoutduration"; 075 private static final String PWD_ATTR_MAXFAILURE = "pwdmaxfailure"; 076 private static final String PWD_ATTR_MUSTCHANGE = "pwdmustchange"; 077 private static final String PWD_ATTR_ALLOWUSERCHANGE = "pwdallowuserchange"; 078 private static final String PWD_ATTR_SAFEMODIFY = "pwdsafemodify"; 079 private static final String PWD_ATTR_FAILURECOUNTINTERVAL = 080 "pwdfailurecountinterval"; 081 private static final String PWD_ATTR_VALIDATOR = "ds-cfg-password-validator"; 082 private static final String PWD_OC_VALIDATORPOLICY = "pwdvalidatorpolicy"; 083 084 /** Password Policy Subentry DN. */ 085 private final DN passwordPolicySubentryDN; 086 /** The value of the "allow-user-password-changes" property. */ 087 private final Boolean pAllowUserPasswordChanges; 088 /** The value of the "force-change-on-reset" property. */ 089 private final Boolean pForceChangeOnReset; 090 /** The value of the "grace-login-count" property. */ 091 private final Integer pGraceLoginCount; 092 /** The value of the "lockout-duration" property. */ 093 private final Long pLockoutDuration; 094 /** The value of the "lockout-failure-count" property. */ 095 private final Integer pLockoutFailureCount; 096 /** The value of the "lockout-failure-expiration-interval" property. */ 097 private final Long pLockoutFailureExpirationInterval; 098 /** The value of the "max-password-age" property. */ 099 private final Long pMaxPasswordAge; 100 /** The value of the "min-password-age" property. */ 101 private final Long pMinPasswordAge; 102 /** The value of the "password-attribute" property. */ 103 private final AttributeType pPasswordAttribute; 104 /** The value of the "password-change-requires-current-password" property. */ 105 private final Boolean pPasswordChangeRequiresCurrentPassword; 106 /** The value of the "password-expiration-warning-interval" property. */ 107 private final Long pPasswordExpirationWarningInterval; 108 /** The value of the "password-history-count" property. */ 109 private final Integer pPasswordHistoryCount; 110 /** Indicates if the password attribute uses auth password syntax. */ 111 private final Boolean pAuthPasswordSyntax; 112 /** The set of password validators if any. */ 113 private final Set<DN> pValidatorNames = new HashSet<>(); 114 /** Used when logging errors due to invalid validator reference. */ 115 private AtomicBoolean isAlreadyLogged = new AtomicBoolean(); 116 117 /** 118 * Returns the global default password policy which will be used for deriving 119 * the default properties of sub-entries. 120 */ 121 private PasswordPolicy getDefaultPasswordPolicy() 122 { 123 return DirectoryServer.getDefaultPasswordPolicy(); 124 } 125 126 /** 127 * Creates subentry password policy object from the subentry, parsing and 128 * evaluating subentry password policy attributes. 129 * 130 * @param subentry 131 * password policy subentry. 132 * @throws DirectoryException 133 * If a problem occurs while creating subentry password policy 134 * instance from given subentry. 135 */ 136 public SubentryPasswordPolicy(SubEntry subentry) throws DirectoryException 137 { 138 // Determine if this is a password policy subentry. 139 ObjectClass pwdPolicyOC = DirectoryServer.getObjectClass(PWD_OC_POLICY); 140 Entry entry = subentry.getEntry(); 141 Map<ObjectClass, String> objectClasses = entry.getObjectClasses(); 142 if (pwdPolicyOC == null) 143 { 144 // This should not happen -- The server doesn't 145 // have a pwdPolicy objectclass defined. 146 if (logger.isTraceEnabled()) 147 { 148 logger.trace("No %s objectclass is defined in the server schema.", 149 PWD_OC_POLICY); 150 } 151 for (String ocName : objectClasses.values()) 152 { 153 if (PWD_OC_POLICY.equalsIgnoreCase(ocName)) 154 { 155 break; 156 } 157 } 158 throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION, 159 ERR_PWPOLICY_NO_PWDPOLICY_OC.get(subentry.getDN())); 160 } 161 else if (!objectClasses.containsKey(pwdPolicyOC)) 162 { 163 throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION, 164 ERR_PWPOLICY_NO_PWDPOLICY_OC.get(subentry.getDN())); 165 } 166 167 // Subentry DN for this password policy. 168 this.passwordPolicySubentryDN = subentry.getDN(); 169 170 // Get known Password Policy draft attributes from the entry. 171 // If any given attribute is missing or empty set its value 172 // from default Password Policy configuration. 173 String value = getAttrValue(entry, PWD_ATTR_ATTRIBUTE); 174 if (value != null && value.length() > 0) 175 { 176 this.pPasswordAttribute = DirectoryServer.getAttributeType(value.toLowerCase()); 177 if (this.pPasswordAttribute == null) 178 { 179 throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, 180 ERR_PWPOLICY_UNDEFINED_PASSWORD_ATTRIBUTE.get(this.passwordPolicySubentryDN, value)); 181 } 182 183 // Check the syntax. 184 final String syntaxOID = pPasswordAttribute.getSyntax().getOID(); 185 if (SYNTAX_AUTH_PASSWORD_OID.equals(syntaxOID)) 186 { 187 pAuthPasswordSyntax = true; 188 } 189 else if (SYNTAX_USER_PASSWORD_OID.equals(syntaxOID)) 190 { 191 pAuthPasswordSyntax = false; 192 } 193 else 194 { 195 String syntax = pPasswordAttribute.getSyntax().getName(); 196 if (syntax == null || syntax.length() == 0) 197 { 198 syntax = syntaxOID; 199 } 200 201 LocalizableMessage message = ERR_PWPOLICY_INVALID_PASSWORD_ATTRIBUTE_SYNTAX.get( 202 passwordPolicySubentryDN, pPasswordAttribute.getNameOrOID(), syntax); 203 throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message); 204 } 205 } 206 else 207 { 208 this.pPasswordAttribute = null; 209 this.pAuthPasswordSyntax = null; 210 } 211 212 this.pMinPasswordAge = asLong(entry, PWD_ATTR_MINAGE); 213 this.pMaxPasswordAge = asLong(entry, PWD_ATTR_MAXAGE); 214 this.pPasswordHistoryCount = 215 asInteger(entry, PWD_ATTR_INHISTORY, Integer.MAX_VALUE); 216 217 // This one is managed via the password validator 218 // so only check if its value is acceptable. 219 asInteger(entry, PWD_ATTR_CHECKQUALITY, 2); 220 221 // This one is managed via the password validator 222 // so only check if its value is acceptable. 223 asInteger(entry, PWD_ATTR_MINLENGTH, Integer.MAX_VALUE); 224 225 // This one depends on lockout failure count value 226 // so only check if its value is acceptable. 227 asBoolean(entry, PWD_ATTR_LOCKOUT); 228 229 this.pPasswordExpirationWarningInterval = 230 asLong(entry, PWD_ATTR_EXPIREWARNING); 231 this.pGraceLoginCount = 232 asInteger(entry, PWD_ATTR_GRACEAUTHNLIMIT, Integer.MAX_VALUE); 233 this.pLockoutDuration = asLong(entry, PWD_ATTR_LOCKOUTDURATION); 234 this.pLockoutFailureCount = 235 asInteger(entry, PWD_ATTR_MAXFAILURE, Integer.MAX_VALUE); 236 this.pForceChangeOnReset = asBoolean(entry, PWD_ATTR_MUSTCHANGE); 237 this.pAllowUserPasswordChanges = asBoolean(entry, PWD_ATTR_ALLOWUSERCHANGE); 238 this.pPasswordChangeRequiresCurrentPassword = 239 asBoolean(entry, PWD_ATTR_SAFEMODIFY); 240 this.pLockoutFailureExpirationInterval = 241 asLong(entry, PWD_ATTR_FAILURECOUNTINTERVAL); 242 243 // Now check for the pwdValidatorPolicy OC and its attribute. 244 // Determine if this is a password validator policy object class. 245 ObjectClass pwdValidatorPolicyOC = 246 DirectoryServer.getObjectClass(PWD_OC_VALIDATORPOLICY); 247 if (pwdValidatorPolicyOC != null && 248 objectClasses.containsKey(pwdValidatorPolicyOC)) 249 { 250 AttributeType pwdAttrType = 251 DirectoryServer.getAttributeTypeOrDefault(PWD_ATTR_VALIDATOR); 252 List<Attribute> pwdAttrList = entry.getAttribute(pwdAttrType); 253 if (pwdAttrList != null && !pwdAttrList.isEmpty()) 254 { 255 for (Attribute attr : pwdAttrList) 256 { 257 for (ByteString val : attr) 258 { 259 DN validatorDN = DN.decode(val); 260 if (DirectoryServer.getPasswordValidator(validatorDN) == null) 261 { 262 throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION, 263 ERR_PWPOLICY_UNKNOWN_VALIDATOR.get(this.passwordPolicySubentryDN, validatorDN, PWD_ATTR_VALIDATOR)); 264 } 265 pValidatorNames.add(validatorDN); 266 } 267 } 268 } 269 } 270 } 271 272 private Boolean asBoolean(Entry entry, String attrName) 273 throws DirectoryException 274 { 275 final String value = getAttrValue(entry, attrName); 276 if (value != null && value.length() > 0) 277 { 278 if (value.equalsIgnoreCase(Boolean.TRUE.toString()) 279 || value.equalsIgnoreCase(Boolean.FALSE.toString())) 280 { 281 return Boolean.valueOf(value); 282 } 283 throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION, 284 ERR_CONFIG_ATTR_INVALID_BOOLEAN_VALUE.get(attrName, value)); 285 } 286 return null; 287 } 288 289 private Integer asInteger(Entry entry, String attrName, int upperBound) 290 throws DirectoryException 291 { 292 final String value = getAttrValue(entry, attrName); 293 if (value != null && value.length() > 0) 294 { 295 try 296 { 297 final Integer result = Integer.valueOf(value); 298 checkIntegerAttr(attrName, result, 0, upperBound); 299 return result; 300 } 301 catch (NumberFormatException ne) 302 { 303 throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION, 304 ERR_CONFIG_ATTR_INVALID_INT_VALUE.get(attrName, value, 305 ne.getLocalizedMessage())); 306 } 307 } 308 return null; 309 } 310 311 private Long asLong(Entry entry, String attrName) throws DirectoryException 312 { 313 final String value = getAttrValue(entry, attrName); 314 if (value != null && value.length() > 0) 315 { 316 try 317 { 318 final Long result = Long.valueOf(value); 319 checkIntegerAttr(attrName, result, 0, Integer.MAX_VALUE); 320 return result; 321 } 322 catch (NumberFormatException ne) 323 { 324 throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION, 325 ERR_CONFIG_ATTR_INVALID_INT_VALUE.get(attrName, value, 326 ne.getLocalizedMessage())); 327 } 328 } 329 return null; 330 } 331 332 333 334 /** 335 * Helper method to validate integer values. 336 * 337 * @param attrName 338 * integer attribute name. 339 * @param attrValue 340 * integer value to validate. 341 * @param lowerBound 342 * lowest acceptable value. 343 * @param upperBound 344 * highest acceptable value. 345 * @throws DirectoryException 346 * if the value is out of bounds. 347 */ 348 private void checkIntegerAttr(String attrName, long attrValue, 349 long lowerBound, long upperBound) throws DirectoryException 350 { 351 if (attrValue < lowerBound) 352 { 353 throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION, 354 ERR_CONFIG_ATTR_INT_BELOW_LOWER_BOUND.get(attrName, attrValue, 355 lowerBound)); 356 } 357 if (attrValue > upperBound) 358 { 359 throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION, 360 ERR_CONFIG_ATTR_INT_ABOVE_UPPER_BOUND.get(attrName, attrValue, 361 upperBound)); 362 } 363 } 364 365 366 367 /** 368 * Helper method to retrieve an attribute value from given entry. 369 * 370 * @param entry 371 * the entry to retrieve an attribute value from. 372 * @param pwdAttrName 373 * attribute name to retrieve the value for. 374 * @return <CODE>String</CODE> or <CODE>null</CODE>. 375 */ 376 private String getAttrValue(Entry entry, String pwdAttrName) 377 { 378 AttributeType pwdAttrType = DirectoryServer.getAttributeTypeOrDefault(pwdAttrName); 379 List<Attribute> pwdAttrList = entry.getAttribute(pwdAttrType); 380 if (pwdAttrList != null && !pwdAttrList.isEmpty()) 381 { 382 for (Attribute attr : pwdAttrList) 383 { 384 for (ByteString value : attr) 385 { 386 return value.toString(); 387 } 388 } 389 } 390 return null; 391 } 392 393 /** {@inheritDoc} */ 394 @Override 395 public boolean isAllowExpiredPasswordChanges() 396 { 397 return getDefaultPasswordPolicy().isAllowExpiredPasswordChanges(); 398 } 399 400 /** {@inheritDoc} */ 401 @Override 402 public boolean isAllowMultiplePasswordValues() 403 { 404 return getDefaultPasswordPolicy().isAllowMultiplePasswordValues(); 405 } 406 407 /** {@inheritDoc} */ 408 @Override 409 public boolean isAllowPreEncodedPasswords() 410 { 411 return getDefaultPasswordPolicy().isAllowPreEncodedPasswords(); 412 } 413 414 /** {@inheritDoc} */ 415 @Override 416 public boolean isAllowUserPasswordChanges() 417 { 418 return pAllowUserPasswordChanges != null ? pAllowUserPasswordChanges 419 : getDefaultPasswordPolicy().isAllowUserPasswordChanges(); 420 } 421 422 /** {@inheritDoc} */ 423 @Override 424 public boolean isExpirePasswordsWithoutWarning() 425 { 426 return getDefaultPasswordPolicy().isExpirePasswordsWithoutWarning(); 427 } 428 429 /** {@inheritDoc} */ 430 @Override 431 public boolean isForceChangeOnAdd() 432 { 433 // Don't use pwdMustChange since the password provided when the entry was 434 // added may have been provided by the user. See OPENDJ-341. 435 return getDefaultPasswordPolicy().isForceChangeOnAdd(); 436 } 437 438 /** {@inheritDoc} */ 439 @Override 440 public boolean isForceChangeOnReset() 441 { 442 return pForceChangeOnReset != null ? pForceChangeOnReset 443 : getDefaultPasswordPolicy().isForceChangeOnReset(); 444 } 445 446 /** {@inheritDoc} */ 447 @Override 448 public int getGraceLoginCount() 449 { 450 return pGraceLoginCount != null ? pGraceLoginCount 451 : getDefaultPasswordPolicy().getGraceLoginCount(); 452 } 453 454 /** {@inheritDoc} */ 455 @Override 456 public long getIdleLockoutInterval() 457 { 458 return getDefaultPasswordPolicy().getIdleLockoutInterval(); 459 } 460 461 /** {@inheritDoc} */ 462 @Override 463 public AttributeType getLastLoginTimeAttribute() 464 { 465 return getDefaultPasswordPolicy().getLastLoginTimeAttribute(); 466 } 467 468 /** {@inheritDoc} */ 469 @Override 470 public String getLastLoginTimeFormat() 471 { 472 return getDefaultPasswordPolicy().getLastLoginTimeFormat(); 473 } 474 475 /** {@inheritDoc} */ 476 @Override 477 public long getLockoutDuration() 478 { 479 return pLockoutDuration != null ? pLockoutDuration 480 : getDefaultPasswordPolicy().getLockoutDuration(); 481 } 482 483 /** {@inheritDoc} */ 484 @Override 485 public int getLockoutFailureCount() 486 { 487 return pLockoutFailureCount != null ? pLockoutFailureCount 488 : getDefaultPasswordPolicy().getLockoutFailureCount(); 489 } 490 491 /** {@inheritDoc} */ 492 @Override 493 public long getLockoutFailureExpirationInterval() 494 { 495 return pLockoutFailureExpirationInterval != null ? 496 pLockoutFailureExpirationInterval 497 : getDefaultPasswordPolicy().getLockoutFailureExpirationInterval(); 498 } 499 500 /** {@inheritDoc} */ 501 @Override 502 public long getMaxPasswordAge() 503 { 504 return pMaxPasswordAge != null ? pMaxPasswordAge 505 : getDefaultPasswordPolicy().getMaxPasswordAge(); 506 } 507 508 /** {@inheritDoc} */ 509 @Override 510 public long getMaxPasswordResetAge() 511 { 512 return getDefaultPasswordPolicy().getMaxPasswordResetAge(); 513 } 514 515 /** {@inheritDoc} */ 516 @Override 517 public long getMinPasswordAge() 518 { 519 return pMinPasswordAge != null ? pMinPasswordAge 520 : getDefaultPasswordPolicy().getMinPasswordAge(); 521 } 522 523 /** {@inheritDoc} */ 524 @Override 525 public AttributeType getPasswordAttribute() 526 { 527 return pPasswordAttribute != null ? pPasswordAttribute 528 : getDefaultPasswordPolicy().getPasswordAttribute(); 529 } 530 531 /** {@inheritDoc} */ 532 @Override 533 public boolean isPasswordChangeRequiresCurrentPassword() 534 { 535 return pPasswordChangeRequiresCurrentPassword != null ? 536 pPasswordChangeRequiresCurrentPassword 537 : getDefaultPasswordPolicy().isPasswordChangeRequiresCurrentPassword(); 538 } 539 540 /** {@inheritDoc} */ 541 @Override 542 public long getPasswordExpirationWarningInterval() 543 { 544 return pPasswordExpirationWarningInterval != null ? 545 pPasswordExpirationWarningInterval 546 : getDefaultPasswordPolicy().getPasswordExpirationWarningInterval(); 547 } 548 549 /** {@inheritDoc} */ 550 @Override 551 public int getPasswordHistoryCount() 552 { 553 return pPasswordHistoryCount != null ? pPasswordHistoryCount 554 : getDefaultPasswordPolicy().getPasswordHistoryCount(); 555 } 556 557 /** {@inheritDoc} */ 558 @Override 559 public long getPasswordHistoryDuration() 560 { 561 return getDefaultPasswordPolicy().getPasswordHistoryDuration(); 562 } 563 564 /** {@inheritDoc} */ 565 @Override 566 public SortedSet<String> getPreviousLastLoginTimeFormats() 567 { 568 return getDefaultPasswordPolicy().getPreviousLastLoginTimeFormats(); 569 } 570 571 /** {@inheritDoc} */ 572 @Override 573 public long getRequireChangeByTime() 574 { 575 return getDefaultPasswordPolicy().getRequireChangeByTime(); 576 } 577 578 /** {@inheritDoc} */ 579 @Override 580 public boolean isRequireSecureAuthentication() 581 { 582 return getDefaultPasswordPolicy().isRequireSecureAuthentication(); 583 } 584 585 /** {@inheritDoc} */ 586 @Override 587 public boolean isRequireSecurePasswordChanges() 588 { 589 return getDefaultPasswordPolicy().isRequireSecurePasswordChanges(); 590 } 591 592 /** {@inheritDoc} */ 593 @Override 594 public boolean isSkipValidationForAdministrators() 595 { 596 return getDefaultPasswordPolicy().isSkipValidationForAdministrators(); 597 } 598 599 /** {@inheritDoc} */ 600 @Override 601 public StateUpdateFailurePolicy getStateUpdateFailurePolicy() 602 { 603 return getDefaultPasswordPolicy().getStateUpdateFailurePolicy(); 604 } 605 606 /** {@inheritDoc} */ 607 @Override 608 public boolean isAuthPasswordSyntax() 609 { 610 return pAuthPasswordSyntax != null ? pAuthPasswordSyntax 611 : getDefaultPasswordPolicy().isAuthPasswordSyntax(); 612 } 613 614 /** {@inheritDoc} */ 615 @Override 616 public List<PasswordStorageScheme<?>> getDefaultPasswordStorageSchemes() 617 { 618 return getDefaultPasswordPolicy().getDefaultPasswordStorageSchemes(); 619 } 620 621 /** {@inheritDoc} */ 622 @Override 623 public Set<String> getDeprecatedPasswordStorageSchemes() 624 { 625 return getDefaultPasswordPolicy().getDeprecatedPasswordStorageSchemes(); 626 } 627 628 /** {@inheritDoc} */ 629 @Override 630 public DN getDN() 631 { 632 return passwordPolicySubentryDN; 633 } 634 635 /** {@inheritDoc} */ 636 @Override 637 public boolean isDefaultPasswordStorageScheme(String name) 638 { 639 return getDefaultPasswordPolicy().isDefaultPasswordStorageScheme(name); 640 } 641 642 /** {@inheritDoc} */ 643 @Override 644 public boolean isDeprecatedPasswordStorageScheme(String name) 645 { 646 return getDefaultPasswordPolicy().isDeprecatedPasswordStorageScheme(name); 647 } 648 649 /** {@inheritDoc} */ 650 @Override 651 public Collection<PasswordValidator<?>> getPasswordValidators() 652 { 653 if (!pValidatorNames.isEmpty()) 654 { 655 Collection<PasswordValidator<?>> values = new HashSet<>(); 656 for (DN validatorDN : pValidatorNames){ 657 PasswordValidator<?> validator = DirectoryServer.getPasswordValidator(validatorDN); 658 if (validator == null) { 659 PasswordValidator<?> errorValidator = new RejectPasswordValidator( 660 validatorDN.toString(), passwordPolicySubentryDN.toString()); 661 values.clear(); 662 values.add(errorValidator); 663 return values; 664 } 665 values.add(validator); 666 } 667 isAlreadyLogged.set(false); 668 return values; 669 } 670 return getDefaultPasswordPolicy().getPasswordValidators(); 671 } 672 673 674 /** 675 * Implementation of a specific Password Validator that reject all 676 * password due to mis-configured password policy subentry. 677 * This is only used when a subentry is referencing a password 678 * validator that is no longer configured. 679 */ 680 private final class RejectPasswordValidator extends 681 PasswordValidator<PasswordValidatorCfg> 682 { 683 private final String validatorName; 684 private final String pwPolicyName; 685 public RejectPasswordValidator(String name, String policyName) 686 { 687 super(); 688 validatorName = name; 689 pwPolicyName = policyName; 690 } 691 692 /** {@inheritDoc} */ 693 @Override 694 public void initializePasswordValidator(PasswordValidatorCfg configuration) 695 throws ConfigException, InitializationException 696 { 697 // do nothing 698 } 699 700 /** {@inheritDoc} */ 701 @Override 702 public boolean passwordIsAcceptable(ByteString newPassword, 703 Set<ByteString> currentPasswords, 704 Operation operation, Entry userEntry, 705 LocalizableMessageBuilder invalidReason) 706 { 707 invalidReason.append(ERR_PWPOLICY_REJECT_DUE_TO_UNKNOWN_VALIDATOR_REASON 708 .get()); 709 710 // Only log an error once, on first error 711 if (isAlreadyLogged.compareAndSet(false, true)) { 712 logger.error(ERR_PWPOLICY_REJECT_DUE_TO_UNKNOWN_VALIDATOR_LOG, 713 userEntry.getName(), pwPolicyName, validatorName); 714 } 715 return false; 716 } 717 } 718 719 /** {@inheritDoc} */ 720 @Override 721 public Collection<AccountStatusNotificationHandler<?>> 722 getAccountStatusNotificationHandlers() 723 { 724 return getDefaultPasswordPolicy().getAccountStatusNotificationHandlers(); 725 } 726 727 /** {@inheritDoc} */ 728 @Override 729 public PasswordGenerator<?> getPasswordGenerator() 730 { 731 return getDefaultPasswordPolicy().getPasswordGenerator(); 732 } 733 734}