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