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 2006-2008 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.*; 021import static org.opends.server.schema.SchemaConstants.*; 022import static org.opends.server.util.ServerConstants.*; 023import static org.opends.server.util.StaticUtils.*; 024 025import java.text.SimpleDateFormat; 026import java.util.*; 027 028import org.forgerock.i18n.LocalizableMessage; 029import org.forgerock.i18n.slf4j.LocalizedLogger; 030import org.forgerock.opendj.config.server.ConfigChangeResult; 031import org.forgerock.opendj.config.server.ConfigException; 032import org.forgerock.opendj.ldap.ByteString; 033import org.forgerock.opendj.ldap.DN; 034import org.forgerock.opendj.ldap.GeneralizedTime; 035import org.forgerock.opendj.ldap.ResultCode; 036import org.opends.server.admin.server.ConfigurationChangeListener; 037import org.opends.server.admin.std.meta.PasswordPolicyCfgDefn.StateUpdateFailurePolicy; 038import org.opends.server.admin.std.server.PasswordPolicyCfg; 039import org.opends.server.api.*; 040import org.forgerock.opendj.ldap.schema.AttributeType; 041import org.opends.server.types.*; 042 043/** 044 * This class is the interface between the password policy configurable 045 * component and a password policy state object. When a password policy entry is 046 * added to the configuration, an instance of this class is created and 047 * registered to manage subsequent modification to that configuration entry, 048 * including validating any proposed modification and applying an accepted 049 * modification. 050 */ 051public final class PasswordPolicyFactory implements 052 AuthenticationPolicyFactory<PasswordPolicyCfg> 053{ 054 private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass(); 055 056 057 058 /** 059 * Password policy implementation. 060 */ 061 private static final class PasswordPolicyImpl extends PasswordPolicy 062 implements ConfigurationChangeListener<PasswordPolicyCfg> 063 { 064 private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass(); 065 066 /** Current configuration. */ 067 private PasswordPolicyCfg configuration; 068 069 /** Indicates whether the attribute type uses the authPassword syntax. */ 070 private boolean authPasswordSyntax; 071 072 /** The set of account status notification handlers for this password policy. */ 073 private Map<DN, AccountStatusNotificationHandler<?>> notificationHandlers; 074 075 /** 076 * The set of password validators that will be used with this 077 * password policy. 078 */ 079 private Map<DN, PasswordValidator<?>> passwordValidators; 080 081 /** 082 * The set of default password storage schemes for this password policy. 083 */ 084 private List<PasswordStorageScheme<?>> defaultStorageSchemes; 085 086 /** 087 * The names of the deprecated password storage schemes for this password 088 * policy. 089 */ 090 private Set<String> deprecatedStorageSchemes; 091 092 /** The password generator for use with this password policy. */ 093 private PasswordGenerator<?> passwordGenerator; 094 095 /** 096 * The the time by which all users will be required to change their 097 * passwords. 098 */ 099 private long requireChangeByTime; 100 101 private final ServerContext serverContext; 102 103 /** {@inheritDoc} */ 104 @Override 105 public void finalizeAuthenticationPolicy() 106 { 107 configuration.removePasswordPolicyChangeListener(this); 108 } 109 110 /** {@inheritDoc} */ 111 @Override 112 public ConfigChangeResult applyConfigurationChange(PasswordPolicyCfg configuration) 113 { 114 final ConfigChangeResult ccr = new ConfigChangeResult(); 115 try 116 { 117 updateConfiguration(configuration, true); 118 } 119 catch (ConfigException ce) 120 { 121 ccr.setResultCode(ResultCode.CONSTRAINT_VIOLATION); 122 ccr.addMessage(ERR_CONFIG_PWPOLICY_INVALID_POLICY_CONFIG.get(configuration.dn(), ce.getMessage())); 123 } 124 catch (InitializationException ie) 125 { 126 ccr.addMessage(ERR_CONFIG_PWPOLICY_INVALID_POLICY_CONFIG.get( 127 configuration.dn(), ie.getMessage())); 128 ccr.setResultCode(DirectoryServer.getServerErrorResultCode()); 129 } 130 catch (Exception e) 131 { 132 ccr.addMessage(ERR_CONFIG_PWPOLICY_INVALID_POLICY_CONFIG.get( 133 configuration.dn(), stackTraceToSingleLineString(e))); 134 ccr.setResultCode(DirectoryServer.getServerErrorResultCode()); 135 } 136 return ccr; 137 } 138 139 /** {@inheritDoc} */ 140 @Override 141 public boolean isConfigurationChangeAcceptable( 142 PasswordPolicyCfg configuration, List<LocalizableMessage> unacceptableReasons) 143 { 144 try 145 { 146 updateConfiguration(configuration, false); 147 } 148 catch (ConfigException | InitializationException e) 149 { 150 LocalizableMessage message = ERR_CONFIG_PWPOLICY_INVALID_POLICY_CONFIG.get( 151 configuration.dn(), e.getMessage()); 152 unacceptableReasons.add(message); 153 return false; 154 } 155 catch (Exception e) 156 { 157 LocalizableMessage message = ERR_CONFIG_PWPOLICY_INVALID_POLICY_CONFIG 158 .get(configuration.dn(), stackTraceToSingleLineString(e)); 159 unacceptableReasons.add(message); 160 return false; 161 } 162 163 // If we've gotten here, then it is acceptable. 164 return true; 165 } 166 167 168 169 /** 170 * Creates a new password policy based on the configuration contained in the 171 * provided configuration entry. Any parameters not included in the provided 172 * configuration entry will be assigned server-wide default values. 173 * @param serverContext TODO 174 * @param configuration 175 * The configuration with the information to use to initialize this 176 * password policy. 177 * 178 * @throws ConfigException 179 * If the provided entry does not contain a valid password policy 180 * configuration. 181 * @throws InitializationException 182 * If an error occurs while initializing the password policy that 183 * is not related to the server configuration. 184 */ 185 private PasswordPolicyImpl(ServerContext serverContext, PasswordPolicyCfg configuration) 186 throws ConfigException, InitializationException 187 { 188 this.serverContext = serverContext; 189 updateConfiguration(configuration, true); 190 } 191 192 193 194 private void updateConfiguration(PasswordPolicyCfg configuration, 195 boolean applyChanges) throws ConfigException, 196 InitializationException 197 { 198 final DN configEntryDN = configuration.dn(); 199 200 // Get the password attribute. If specified, it must have either the 201 // user password or auth password syntax. 202 final AttributeType passwordAttribute = configuration 203 .getPasswordAttribute(); 204 final String syntaxOID = passwordAttribute.getSyntax().getOID(); 205 final boolean authPasswordSyntax; 206 if (syntaxOID.equals(SYNTAX_AUTH_PASSWORD_OID)) 207 { 208 authPasswordSyntax = true; 209 } 210 else if (syntaxOID.equals(SYNTAX_USER_PASSWORD_OID)) 211 { 212 authPasswordSyntax = false; 213 } 214 else 215 { 216 String syntax = passwordAttribute.getSyntax().getName(); 217 if (syntax == null || syntax.length() == 0) 218 { 219 syntax = syntaxOID; 220 } 221 222 throw new ConfigException(ERR_PWPOLICY_INVALID_PASSWORD_ATTRIBUTE_SYNTAX.get( 223 configEntryDN, passwordAttribute.getNameOrOID(), syntax)); 224 } 225 226 // Get the default storage schemes. They must all reference valid storage 227 // schemes that support the syntax for the specified password attribute. 228 List<PasswordStorageScheme<?>> defaultStorageSchemes = new LinkedList<>(); 229 for (DN schemeDN : configuration.getDefaultPasswordStorageSchemeDNs()) 230 { 231 PasswordStorageScheme<?> scheme = DirectoryServer 232 .getPasswordStorageScheme(schemeDN); 233 234 if (authPasswordSyntax && !scheme.supportsAuthPasswordSyntax()) 235 { 236 throw new ConfigException(ERR_PWPOLICY_SCHEME_DOESNT_SUPPORT_AUTH.get( 237 schemeDN, passwordAttribute.getNameOrOID())); 238 } 239 240 defaultStorageSchemes.add(scheme); 241 } 242 243 // Get the names of the deprecated storage schemes. 244 Set<String> deprecatedStorageSchemes = new LinkedHashSet<>(); 245 for (DN schemeDN : configuration.getDeprecatedPasswordStorageSchemeDNs()) 246 { 247 PasswordStorageScheme<?> scheme = DirectoryServer 248 .getPasswordStorageScheme(schemeDN); 249 if (authPasswordSyntax) 250 { 251 if (scheme.supportsAuthPasswordSyntax()) 252 { 253 deprecatedStorageSchemes.add(toLowerCase(scheme 254 .getAuthPasswordSchemeName())); 255 } 256 else 257 { 258 throw new ConfigException(ERR_PWPOLICY_DEPRECATED_SCHEME_NOT_AUTH.get( 259 configEntryDN, schemeDN)); 260 } 261 } 262 else 263 { 264 deprecatedStorageSchemes.add(toLowerCase(scheme.getStorageSchemeName())); 265 } 266 } 267 268 // Get the password validators. 269 Map<DN, PasswordValidator<?>> passwordValidators = new HashMap<>(); 270 for (DN validatorDN : configuration.getPasswordValidatorDNs()) 271 { 272 passwordValidators.put(validatorDN, 273 DirectoryServer.getPasswordValidator(validatorDN)); 274 } 275 276 // Get the status notification handlers. 277 Map<DN, AccountStatusNotificationHandler<?>> notificationHandlers = new HashMap<>(); 278 for (DN handlerDN : configuration.getAccountStatusNotificationHandlerDNs()) 279 { 280 AccountStatusNotificationHandler<?> handler = DirectoryServer 281 .getAccountStatusNotificationHandler(handlerDN); 282 notificationHandlers.put(handlerDN, handler); 283 } 284 285 // Get the password generator. 286 PasswordGenerator<?> passwordGenerator = null; 287 DN passGenDN = configuration.getPasswordGeneratorDN(); 288 if (passGenDN != null) 289 { 290 passwordGenerator = DirectoryServer.getPasswordGenerator(passGenDN); 291 } 292 293 // If the expire without warning option is disabled, then there must be a 294 // warning interval. 295 if (!configuration.isExpirePasswordsWithoutWarning() 296 && configuration.getPasswordExpirationWarningInterval() <= 0) 297 { 298 LocalizableMessage message = 299 ERR_PWPOLICY_MUST_HAVE_WARNING_IF_NOT_EXPIRE_WITHOUT_WARNING.get(configEntryDN); 300 throw new ConfigException(message); 301 } 302 303 // Get the required change time. 304 String requireChangeBy = configuration.getRequireChangeByTime(); 305 long requireChangeByTime = 0L; 306 try 307 { 308 if (requireChangeBy != null) 309 { 310 ByteString valueString = ByteString.valueOfUtf8(requireChangeBy); 311 requireChangeByTime = GeneralizedTime.valueOf(valueString.toString()).getTimeInMillis(); 312 } 313 } 314 catch (Exception e) 315 { 316 logger.traceException(e); 317 318 LocalizableMessage message = ERR_PWPOLICY_CANNOT_DETERMINE_REQUIRE_CHANGE_BY_TIME 319 .get(configEntryDN, getExceptionMessage(e)); 320 throw new InitializationException(message, e); 321 } 322 323 // Get the last login time format. If specified, it must be a valid format 324 // string. 325 String formatString = configuration.getLastLoginTimeFormat(); 326 if (formatString != null) 327 { 328 try 329 { 330 new SimpleDateFormat(formatString); 331 } 332 catch (Exception e) 333 { 334 logger.traceException(e); 335 336 LocalizableMessage message = ERR_PWPOLICY_INVALID_LAST_LOGIN_TIME_FORMAT.get(configEntryDN, formatString); 337 throw new ConfigException(message); 338 } 339 } 340 341 // Get the previous last login time formats. If specified, they must all 342 // be valid format strings. 343 SortedSet<String> formatStrings = configuration 344 .getPreviousLastLoginTimeFormat(); 345 if (formatStrings != null) 346 { 347 for (String s : formatStrings) 348 { 349 try 350 { 351 new SimpleDateFormat(s); 352 } 353 catch (Exception e) 354 { 355 logger.traceException(e); 356 357 LocalizableMessage message = 358 ERR_PWPOLICY_INVALID_PREVIOUS_LAST_LOGIN_TIME_FORMAT.get(configEntryDN, s); 359 throw new ConfigException(message); 360 } 361 } 362 } 363 364 // If both a maximum password age and a warning interval are provided, 365 // then 366 // ensure that the warning interval is less than the maximum age. Further, 367 // if a minimum age is specified, then the sum of the minimum age and the 368 // warning interval should be less than the maximum age. 369 if (configuration.getMaxPasswordAge() > 0) 370 { 371 long warnInterval = Math.max(0L, 372 configuration.getPasswordExpirationWarningInterval()); 373 if (configuration.getMinPasswordAge() > 0) 374 { 375 if (warnInterval + configuration.getMinPasswordAge() >= configuration.getMaxPasswordAge()) 376 { 377 LocalizableMessage message = 378 ERR_PWPOLICY_MIN_AGE_PLUS_WARNING_GREATER_THAN_MAX_AGE.get(configEntryDN); 379 throw new ConfigException(message); 380 } 381 } 382 else if (warnInterval >= configuration.getMaxPasswordAge()) 383 { 384 LocalizableMessage message = ERR_PWPOLICY_WARNING_INTERVAL_LARGER_THAN_MAX_AGE.get(configEntryDN); 385 throw new ConfigException(message); 386 } 387 } 388 389 // If we've got this far then the configuration is good and we can commit 390 // the changes if required. 391 if (applyChanges) 392 { 393 this.configuration = configuration; 394 this.authPasswordSyntax = authPasswordSyntax; 395 this.defaultStorageSchemes = defaultStorageSchemes; 396 this.deprecatedStorageSchemes = deprecatedStorageSchemes; 397 this.notificationHandlers = notificationHandlers; 398 this.passwordGenerator = passwordGenerator; 399 this.passwordValidators = passwordValidators; 400 this.requireChangeByTime = requireChangeByTime; 401 } 402 } 403 404 /** {@inheritDoc} */ 405 @Override 406 public boolean isAuthPasswordSyntax() 407 { 408 return authPasswordSyntax; 409 } 410 411 /** {@inheritDoc} */ 412 @Override 413 public List<PasswordStorageScheme<?>> getDefaultPasswordStorageSchemes() 414 { 415 return defaultStorageSchemes; 416 } 417 418 /** {@inheritDoc} */ 419 @Override 420 public Set<String> getDeprecatedPasswordStorageSchemes() 421 { 422 return deprecatedStorageSchemes; 423 } 424 425 /** {@inheritDoc} */ 426 @Override 427 public DN getDN() 428 { 429 return configuration.dn(); 430 } 431 432 /** {@inheritDoc} */ 433 @Override 434 public boolean isDefaultPasswordStorageScheme(String name) 435 { 436 for (PasswordStorageScheme<?> s : defaultStorageSchemes) 437 { 438 if (authPasswordSyntax) 439 { 440 if (s.getAuthPasswordSchemeName().equalsIgnoreCase(name)) 441 { 442 return true; 443 } 444 } 445 else 446 { 447 if (s.getStorageSchemeName().equalsIgnoreCase(name)) 448 { 449 return true; 450 } 451 } 452 } 453 454 return false; 455 } 456 457 /** {@inheritDoc} */ 458 @Override 459 public boolean isDeprecatedPasswordStorageScheme(String name) 460 { 461 return deprecatedStorageSchemes.contains(toLowerCase(name)); 462 } 463 464 /** {@inheritDoc} */ 465 @Override 466 public Collection<PasswordValidator<?>> getPasswordValidators() 467 { 468 return passwordValidators.values(); 469 } 470 471 /** {@inheritDoc} */ 472 @Override 473 public Collection<AccountStatusNotificationHandler<?>> 474 getAccountStatusNotificationHandlers() 475 { 476 return notificationHandlers.values(); 477 } 478 479 /** {@inheritDoc} */ 480 @Override 481 public PasswordGenerator<?> getPasswordGenerator() 482 { 483 return passwordGenerator; 484 } 485 486 /** {@inheritDoc} */ 487 @Override 488 public long getRequireChangeByTime() 489 { 490 return requireChangeByTime; 491 } 492 493 494 495 /** 496 * Retrieves a string representation of this password policy. 497 * 498 * @return A string representation of this password policy. 499 */ 500 @Override 501 public String toString() 502 { 503 StringBuilder buffer = new StringBuilder(); 504 toString(buffer); 505 return buffer.toString(); 506 } 507 508 509 510 /** 511 * Appends a string representation of this password policy to the provided 512 * buffer. 513 * 514 * @param buffer 515 * The buffer to which the information should be appended. 516 */ 517 public void toString(StringBuilder buffer) 518 { 519 buffer.append("Password Attribute: "); 520 buffer.append(configuration.getPasswordAttribute().getNameOrOID()); 521 buffer.append(EOL); 522 523 buffer.append("Default Password Storage Schemes: "); 524 if (defaultStorageSchemes == null || defaultStorageSchemes.isEmpty()) 525 { 526 buffer.append("{none specified}"); 527 buffer.append(EOL); 528 } 529 else 530 { 531 Iterator<PasswordStorageScheme<?>> iterator = defaultStorageSchemes 532 .iterator(); 533 buffer.append(iterator.next().getStorageSchemeName()); 534 buffer.append(EOL); 535 536 while (iterator.hasNext()) 537 { 538 buffer.append(" "); 539 buffer.append(iterator.next().getStorageSchemeName()); 540 buffer.append(EOL); 541 } 542 } 543 544 buffer.append("Deprecated Password Storage Schemes: "); 545 if (deprecatedStorageSchemes == null || deprecatedStorageSchemes.isEmpty()) 546 { 547 buffer.append("{none specified}"); 548 buffer.append(EOL); 549 } 550 else 551 { 552 Iterator<String> iterator = deprecatedStorageSchemes.iterator(); 553 buffer.append(iterator.next()); 554 buffer.append(EOL); 555 556 while (iterator.hasNext()) 557 { 558 buffer.append(" "); 559 buffer.append(iterator.next()); 560 buffer.append(EOL); 561 } 562 } 563 564 buffer.append("Allow Multiple Password Values: "); 565 buffer.append(configuration.isAllowMultiplePasswordValues()); 566 buffer.append(EOL); 567 568 buffer.append("Allow Pre-Encoded Passwords: "); 569 buffer.append(configuration.isAllowPreEncodedPasswords()); 570 buffer.append(EOL); 571 572 buffer.append("Allow User Password Changes: "); 573 buffer.append(configuration.isAllowUserPasswordChanges()); 574 buffer.append(EOL); 575 576 buffer.append("Force Password Change on Add: "); 577 buffer.append(configuration.isForceChangeOnAdd()); 578 buffer.append(EOL); 579 580 buffer.append("Force Password Change on Admin Reset: "); 581 buffer.append(configuration.isForceChangeOnReset()); 582 buffer.append(EOL); 583 584 buffer.append("Require Current Password: "); 585 buffer.append(configuration.isPasswordChangeRequiresCurrentPassword()); 586 buffer.append(EOL); 587 588 buffer.append("Require Secure Authentication: "); 589 buffer.append(configuration.isRequireSecureAuthentication()); 590 buffer.append(EOL); 591 592 buffer.append("Require Secure Password Changes: "); 593 buffer.append(configuration.isRequireSecurePasswordChanges()); 594 buffer.append(EOL); 595 596 buffer.append("Lockout Failure Expiration Interval: "); 597 buffer.append(configuration.getLockoutFailureExpirationInterval()); 598 buffer.append(" seconds"); 599 buffer.append(EOL); 600 601 buffer.append("Password Validators: "); 602 if (passwordValidators == null || passwordValidators.isEmpty()) 603 { 604 buffer.append("{none specified}"); 605 buffer.append(EOL); 606 } 607 else 608 { 609 Iterator<DN> iterator = passwordValidators.keySet().iterator(); 610 buffer.append(iterator.next()); 611 buffer.append(EOL); 612 613 while (iterator.hasNext()) 614 { 615 buffer.append(" "); 616 buffer.append(iterator.next()); 617 buffer.append(EOL); 618 } 619 } 620 621 buffer.append("Skip Validation for Administrators: "); 622 buffer.append(configuration.isSkipValidationForAdministrators()); 623 buffer.append(EOL); 624 625 buffer.append("Password Generator: "); 626 if (passwordGenerator == null) 627 { 628 buffer.append("{none specified}"); 629 } 630 else 631 { 632 buffer.append(configuration.getPasswordGeneratorDN()); 633 } 634 buffer.append(EOL); 635 636 buffer.append("Account Status Notification Handlers: "); 637 if (notificationHandlers == null || notificationHandlers.isEmpty()) 638 { 639 buffer.append("{none specified}"); 640 buffer.append(EOL); 641 } 642 else 643 { 644 Iterator<DN> iterator = notificationHandlers.keySet().iterator(); 645 buffer.append(iterator.next()); 646 buffer.append(EOL); 647 648 while (iterator.hasNext()) 649 { 650 buffer.append(" "); 651 buffer.append(iterator.next()); 652 buffer.append(EOL); 653 } 654 } 655 656 buffer.append("Minimum Password Age: "); 657 buffer.append(configuration.getMinPasswordAge()); 658 buffer.append(" seconds"); 659 buffer.append(EOL); 660 661 buffer.append("Maximum Password Age: "); 662 buffer.append(configuration.getMaxPasswordAge()); 663 buffer.append(" seconds"); 664 buffer.append(EOL); 665 666 buffer.append("Maximum Password Reset Age: "); 667 buffer.append(configuration.getMaxPasswordResetAge()); 668 buffer.append(" seconds"); 669 buffer.append(EOL); 670 671 buffer.append("Expiration Warning Interval: "); 672 buffer.append(configuration.getPasswordExpirationWarningInterval()); 673 buffer.append(" seconds"); 674 buffer.append(EOL); 675 676 buffer.append("Expire Passwords Without Warning: "); 677 buffer.append(configuration.isExpirePasswordsWithoutWarning()); 678 buffer.append(EOL); 679 680 buffer.append("Allow Expired Password Changes: "); 681 buffer.append(configuration.isAllowExpiredPasswordChanges()); 682 buffer.append(EOL); 683 684 buffer.append("Grace Login Count: "); 685 buffer.append(configuration.getGraceLoginCount()); 686 buffer.append(EOL); 687 688 buffer.append("Lockout Failure Count: "); 689 buffer.append(configuration.getLockoutFailureCount()); 690 buffer.append(EOL); 691 692 buffer.append("Lockout Duration: "); 693 buffer.append(configuration.getLockoutDuration()); 694 buffer.append(" seconds"); 695 buffer.append(EOL); 696 697 buffer.append("Lockout Count Expiration Interval: "); 698 buffer.append(configuration.getLockoutFailureExpirationInterval()); 699 buffer.append(" seconds"); 700 buffer.append(EOL); 701 702 buffer.append("Required Password Change By Time: "); 703 if (requireChangeByTime <= 0) 704 { 705 buffer.append("{none specified}"); 706 } 707 else 708 { 709 SimpleDateFormat dateFormat = new SimpleDateFormat( 710 DATE_FORMAT_GENERALIZED_TIME); 711 dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); 712 buffer.append(dateFormat.format(new Date(requireChangeByTime))); 713 } 714 buffer.append(EOL); 715 716 buffer.append("Last Login Time Attribute: "); 717 if (configuration.getLastLoginTimeAttribute() == null) 718 { 719 buffer.append("{none specified}"); 720 } 721 else 722 { 723 buffer.append(configuration.getLastLoginTimeAttribute().getNameOrOID()); 724 } 725 buffer.append(EOL); 726 727 buffer.append("Last Login Time Format: "); 728 if (configuration.getLastLoginTimeFormat() == null) 729 { 730 buffer.append("{none specified}"); 731 } 732 else 733 { 734 buffer.append(configuration.getLastLoginTimeFormat()); 735 } 736 buffer.append(EOL); 737 738 buffer.append("Previous Last Login Time Formats: "); 739 if (configuration.getPreviousLastLoginTimeFormat().isEmpty()) 740 { 741 buffer.append("{none specified}"); 742 buffer.append(EOL); 743 } 744 else 745 { 746 Iterator<String> iterator = configuration 747 .getPreviousLastLoginTimeFormat().iterator(); 748 749 buffer.append(iterator.next()); 750 buffer.append(EOL); 751 752 while (iterator.hasNext()) 753 { 754 buffer.append(" "); 755 buffer.append(iterator.next()); 756 buffer.append(EOL); 757 } 758 } 759 760 buffer.append("Idle Lockout Interval: "); 761 buffer.append(configuration.getIdleLockoutInterval()); 762 buffer.append(" seconds"); 763 buffer.append(EOL); 764 765 buffer.append("History Count: "); 766 buffer.append(configuration.getPasswordHistoryCount()); 767 buffer.append(EOL); 768 769 buffer.append("Update Failure Policy: "); 770 buffer.append(configuration.getStateUpdateFailurePolicy()); 771 buffer.append(EOL); 772 } 773 774 /** {@inheritDoc} */ 775 @Override 776 public boolean isAllowExpiredPasswordChanges() 777 { 778 return configuration.isAllowExpiredPasswordChanges(); 779 } 780 781 /** {@inheritDoc} */ 782 @Override 783 public boolean isAllowMultiplePasswordValues() 784 { 785 return configuration.isAllowMultiplePasswordValues(); 786 } 787 788 /** {@inheritDoc} */ 789 @Override 790 public boolean isAllowPreEncodedPasswords() 791 { 792 return configuration.isAllowPreEncodedPasswords(); 793 } 794 795 /** {@inheritDoc} */ 796 @Override 797 public boolean isAllowUserPasswordChanges() 798 { 799 return configuration.isAllowUserPasswordChanges(); 800 } 801 802 /** {@inheritDoc} */ 803 @Override 804 public boolean isExpirePasswordsWithoutWarning() 805 { 806 return configuration.isExpirePasswordsWithoutWarning(); 807 } 808 809 /** {@inheritDoc} */ 810 @Override 811 public boolean isForceChangeOnAdd() 812 { 813 return configuration.isForceChangeOnAdd(); 814 } 815 816 /** {@inheritDoc} */ 817 @Override 818 public boolean isForceChangeOnReset() 819 { 820 return configuration.isForceChangeOnReset(); 821 } 822 823 /** {@inheritDoc} */ 824 @Override 825 public int getGraceLoginCount() 826 { 827 return configuration.getGraceLoginCount(); 828 } 829 830 /** {@inheritDoc} */ 831 @Override 832 public long getIdleLockoutInterval() 833 { 834 return configuration.getIdleLockoutInterval(); 835 } 836 837 /** {@inheritDoc} */ 838 @Override 839 public AttributeType getLastLoginTimeAttribute() 840 { 841 return configuration.getLastLoginTimeAttribute(); 842 } 843 844 /** {@inheritDoc} */ 845 @Override 846 public String getLastLoginTimeFormat() 847 { 848 return configuration.getLastLoginTimeFormat(); 849 } 850 851 /** {@inheritDoc} */ 852 @Override 853 public long getLockoutDuration() 854 { 855 return configuration.getLockoutDuration(); 856 } 857 858 /** {@inheritDoc} */ 859 @Override 860 public int getLockoutFailureCount() 861 { 862 return configuration.getLockoutFailureCount(); 863 } 864 865 /** {@inheritDoc} */ 866 @Override 867 public long getLockoutFailureExpirationInterval() 868 { 869 return configuration.getLockoutFailureExpirationInterval(); 870 } 871 872 /** {@inheritDoc} */ 873 @Override 874 public long getMaxPasswordAge() 875 { 876 return configuration.getMaxPasswordAge(); 877 } 878 879 /** {@inheritDoc} */ 880 @Override 881 public long getMaxPasswordResetAge() 882 { 883 return configuration.getMaxPasswordResetAge(); 884 } 885 886 /** {@inheritDoc} */ 887 @Override 888 public long getMinPasswordAge() 889 { 890 return configuration.getMinPasswordAge(); 891 } 892 893 /** {@inheritDoc} */ 894 @Override 895 public AttributeType getPasswordAttribute() 896 { 897 return configuration.getPasswordAttribute(); 898 } 899 900 /** {@inheritDoc} */ 901 @Override 902 public boolean isPasswordChangeRequiresCurrentPassword() 903 { 904 return configuration.isPasswordChangeRequiresCurrentPassword(); 905 } 906 907 /** {@inheritDoc} */ 908 @Override 909 public long getPasswordExpirationWarningInterval() 910 { 911 return configuration.getPasswordExpirationWarningInterval(); 912 } 913 914 /** {@inheritDoc} */ 915 @Override 916 public int getPasswordHistoryCount() 917 { 918 return configuration.getPasswordHistoryCount(); 919 } 920 921 /** {@inheritDoc} */ 922 @Override 923 public long getPasswordHistoryDuration() 924 { 925 return configuration.getPasswordHistoryDuration(); 926 } 927 928 /** {@inheritDoc} */ 929 @Override 930 public SortedSet<String> getPreviousLastLoginTimeFormats() 931 { 932 return configuration.getPreviousLastLoginTimeFormat(); 933 } 934 935 /** {@inheritDoc} */ 936 @Override 937 public boolean isRequireSecureAuthentication() 938 { 939 return configuration.isRequireSecureAuthentication(); 940 } 941 942 /** {@inheritDoc} */ 943 @Override 944 public boolean isRequireSecurePasswordChanges() 945 { 946 return configuration.isRequireSecurePasswordChanges(); 947 } 948 949 /** {@inheritDoc} */ 950 @Override 951 public boolean isSkipValidationForAdministrators() 952 { 953 return configuration.isSkipValidationForAdministrators(); 954 } 955 956 /** {@inheritDoc} */ 957 @Override 958 public StateUpdateFailurePolicy getStateUpdateFailurePolicy() 959 { 960 return configuration.getStateUpdateFailurePolicy(); 961 } 962 963 } 964 965 private ServerContext serverContext; 966 967 /** 968 * Default constructor instantiated from authentication policy config manager. 969 */ 970 public PasswordPolicyFactory() 971 { 972 // Nothing to do . 973 } 974 975 /** 976 * Sets the server context. 977 * 978 * @param serverContext 979 * The server context. 980 */ 981 @Override 982 public void setServerContext(final ServerContext serverContext) { 983 this.serverContext = serverContext; 984 } 985 986 /** {@inheritDoc} */ 987 @Override 988 public PasswordPolicy createAuthenticationPolicy( 989 final PasswordPolicyCfg configuration) throws ConfigException, 990 InitializationException 991 { 992 PasswordPolicyImpl policy = new PasswordPolicyImpl(serverContext, configuration); 993 configuration.addPasswordPolicyChangeListener(policy); 994 return policy; 995 } 996 997 /** {@inheritDoc} */ 998 @Override 999 public boolean isConfigurationAcceptable( 1000 final PasswordPolicyCfg configuration, 1001 final List<LocalizableMessage> unacceptableReasons) 1002 { 1003 try 1004 { 1005 new PasswordPolicyImpl(null, configuration); 1006 } 1007 catch (final ConfigException | InitializationException ie) 1008 { 1009 logger.traceException(ie); 1010 1011 unacceptableReasons.add(ie.getMessageObject()); 1012 return false; 1013 } 1014 1015 // If we made it here, then the configuration is acceptable. 1016 return true; 1017 } 1018 1019}