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 2006-2009 Sun Microsystems, Inc. 025 * Portions Copyright 2011-2015 ForgeRock AS 026 */ 027package org.opends.server.extensions; 028 029import java.io.IOException; 030import java.util.ArrayList; 031import java.util.LinkedHashSet; 032import java.util.List; 033 034import org.forgerock.i18n.LocalizableMessage; 035import org.forgerock.i18n.LocalizedIllegalArgumentException; 036import org.forgerock.i18n.slf4j.LocalizedLogger; 037import org.forgerock.opendj.config.server.ConfigException; 038import org.forgerock.opendj.io.ASN1; 039import org.forgerock.opendj.io.ASN1Reader; 040import org.forgerock.opendj.io.ASN1Writer; 041import org.forgerock.opendj.ldap.ByteString; 042import org.forgerock.opendj.ldap.ByteStringBuilder; 043import org.forgerock.opendj.ldap.GeneralizedTime; 044import org.forgerock.opendj.ldap.ResultCode; 045import org.forgerock.opendj.ldap.SearchScope; 046import org.opends.server.admin.std.server.PasswordPolicyStateExtendedOperationHandlerCfg; 047import org.opends.server.api.AuthenticationPolicy; 048import org.opends.server.api.ClientConnection; 049import org.opends.server.api.ExtendedOperationHandler; 050import org.opends.server.core.*; 051import org.opends.server.protocols.internal.InternalClientConnection; 052import org.opends.server.protocols.internal.InternalSearchOperation; 053import org.opends.server.protocols.internal.SearchRequest; 054import org.opends.server.schema.GeneralizedTimeSyntax; 055import org.opends.server.types.*; 056 057import static org.opends.messages.CoreMessages.*; 058import static org.opends.messages.ExtensionMessages.*; 059import static org.opends.server.protocols.internal.Requests.*; 060import static org.opends.server.util.CollectionUtils.*; 061import static org.opends.server.util.ServerConstants.*; 062import static org.opends.server.util.StaticUtils.*; 063 064/** 065 * This class implements an LDAP extended operation that can be used to query 066 * and update elements of the Directory Server password policy state for a given 067 * user. The ASN.1 definition for the value of the extended request is: 068 * <BR> 069 * <PRE> 070 * PasswordPolicyStateValue ::= SEQUENCE { 071 * targetUser LDAPDN 072 * operations SEQUENCE OF PasswordPolicyStateOperation OPTIONAL } 073 * 074 * PasswordPolicyStateOperation ::= SEQUENCE { 075 * opType ENUMERATED { 076 * getPasswordPolicyDN (0), 077 * getAccountDisabledState (1), 078 * setAccountDisabledState (2), 079 * clearAccountDisabledState (3), 080 * getAccountExpirationTime (4), 081 * setAccountExpirationTime (5), 082 * clearAccountExpirationTime (6), 083 * getSecondsUntilAccountExpiration (7), 084 * getPasswordChangedTime (8), 085 * setPasswordChangedTime (9), 086 * clearPasswordChangedTime (10), 087 * getPasswordExpirationWarnedTime (11), 088 * setPasswordExpirationWarnedTime (12), 089 * clearPasswordExpirationWarnedTime (13), 090 * getSecondsUntilPasswordExpiration (14), 091 * getSecondsUntilPasswordExpirationWarning (15), 092 * getAuthenticationFailureTimes (16), 093 * addAuthenticationFailureTime (17), 094 * setAuthenticationFailureTimes (18), 095 * clearAuthenticationFailureTimes (19), 096 * getSecondsUntilAuthenticationFailureUnlock (20), 097 * getRemainingAuthenticationFailureCount (21), 098 * getLastLoginTime (22), 099 * setLastLoginTime (23), 100 * clearLastLoginTime (24), 101 * getSecondsUntilIdleLockout (25), 102 * getPasswordResetState (26), 103 * setPasswordResetState (27), 104 * clearPasswordResetState (28), 105 * getSecondsUntilPasswordResetLockout (29), 106 * getGraceLoginUseTimes (30), 107 * addGraceLoginUseTime (31), 108 * setGraceLoginUseTimes (32), 109 * clearGraceLoginUseTimes (33), 110 * getRemainingGraceLoginCount (34), 111 * getPasswordChangedByRequiredTime (35), 112 * setPasswordChangedByRequiredTime (36), 113 * clearPasswordChangedByRequiredTime (37), 114 * getSecondsUntilRequiredChangeTime (38), 115 * getPasswordHistory (39), 116 * clearPasswordHistory (40), 117 * ... }, 118 * opValues SEQUENCE OF OCTET STRING OPTIONAL } 119 * </PRE> 120 * <BR> 121 * Both the request and response values use the same encoded form, and they both 122 * use the same OID of "1.3.6.1.4.1.26027.1.6.1". The response value will only 123 * include get* elements. If the request did not include any operations, then 124 * the response will include all get* elements; otherwise, the response will 125 * only include the get* elements that correspond to the state fields referenced 126 * in the request (regardless of whether that operation was included in a get*, 127 * set*, add*, remove*, or clear* operation). 128 */ 129public class PasswordPolicyStateExtendedOperation 130 extends ExtendedOperationHandler< 131 PasswordPolicyStateExtendedOperationHandlerCfg> 132{ 133 private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass(); 134 135 136 /** The enumerated value for the getPasswordPolicyDN operation. */ 137 public static final int OP_GET_PASSWORD_POLICY_DN = 0; 138 /** The enumerated value for the getAccountDisabledState operation. */ 139 public static final int OP_GET_ACCOUNT_DISABLED_STATE = 1; 140 /** The enumerated value for the setAccountDisabledState operation. */ 141 public static final int OP_SET_ACCOUNT_DISABLED_STATE = 2; 142 /** The enumerated value for the clearAccountDisabledState operation. */ 143 public static final int OP_CLEAR_ACCOUNT_DISABLED_STATE = 3; 144 /** The enumerated value for the getAccountExpirationTime operation. */ 145 public static final int OP_GET_ACCOUNT_EXPIRATION_TIME = 4; 146 /** The enumerated value for the setAccountExpirationTime operation. */ 147 public static final int OP_SET_ACCOUNT_EXPIRATION_TIME = 5; 148 /** The enumerated value for the clearAccountExpirationTime operation. */ 149 public static final int OP_CLEAR_ACCOUNT_EXPIRATION_TIME = 6; 150 /** 151 * The enumerated value for the getSecondsUntilAccountExpiration operation. 152 */ 153 public static final int OP_GET_SECONDS_UNTIL_ACCOUNT_EXPIRATION = 7; 154 /** The enumerated value for the getPasswordChangedTime operation. */ 155 public static final int OP_GET_PASSWORD_CHANGED_TIME = 8; 156 /** The enumerated value for the setPasswordChangedTime operation. */ 157 public static final int OP_SET_PASSWORD_CHANGED_TIME = 9; 158 /** The enumerated value for the clearPasswordChangedTime operation. */ 159 public static final int OP_CLEAR_PASSWORD_CHANGED_TIME = 10; 160 /** The enumerated value for the getPasswordExpirationWarnedTime operation. */ 161 public static final int OP_GET_PASSWORD_EXPIRATION_WARNED_TIME = 11; 162 /** The enumerated value for the setPasswordExpirationWarnedTime operation. */ 163 public static final int OP_SET_PASSWORD_EXPIRATION_WARNED_TIME = 12; 164 /** 165 * The enumerated value for the clearPasswordExpirationWarnedTime operation. 166 */ 167 public static final int OP_CLEAR_PASSWORD_EXPIRATION_WARNED_TIME = 13; 168 /** 169 * The enumerated value for the getSecondsUntilPasswordExpiration operation. 170 */ 171 public static final int OP_GET_SECONDS_UNTIL_PASSWORD_EXPIRATION = 14; 172 /** 173 * The enumerated value for the getSecondsUntilPasswordExpirationWarning 174 * operation. 175 */ 176 public static final int OP_GET_SECONDS_UNTIL_PASSWORD_EXPIRATION_WARNING = 15; 177 /** The enumerated value for the getAuthenticationFailureTimes operation. */ 178 public static final int OP_GET_AUTHENTICATION_FAILURE_TIMES = 16; 179 /** The enumerated value for the addAuthenticationFailureTime operation. */ 180 public static final int OP_ADD_AUTHENTICATION_FAILURE_TIME = 17; 181 /** The enumerated value for the setAuthenticationFailureTimes operation. */ 182 public static final int OP_SET_AUTHENTICATION_FAILURE_TIMES = 18; 183 /** The enumerated value for the clearAuthenticationFailureTimes operation. */ 184 public static final int OP_CLEAR_AUTHENTICATION_FAILURE_TIMES = 19; 185 /** 186 * The enumerated value for the getSecondsUntilAuthenticationFailureUnlock 187 * operation. 188 */ 189 public static final int OP_GET_SECONDS_UNTIL_AUTHENTICATION_FAILURE_UNLOCK = 190 20; 191 /** 192 * The enumerated value for the getRemainingAuthenticationFailureCount 193 * operation. 194 */ 195 public static final int OP_GET_REMAINING_AUTHENTICATION_FAILURE_COUNT = 21; 196 /** The enumerated value for the getLastLoginTime operation. */ 197 public static final int OP_GET_LAST_LOGIN_TIME = 22; 198 /** The enumerated value for the setLastLoginTime operation. */ 199 public static final int OP_SET_LAST_LOGIN_TIME = 23; 200 /** The enumerated value for the clearLastLoginTime operation. */ 201 public static final int OP_CLEAR_LAST_LOGIN_TIME = 24; 202 /** The enumerated value for the getSecondsUntilIdleLockout operation. */ 203 public static final int OP_GET_SECONDS_UNTIL_IDLE_LOCKOUT = 25; 204 /** The enumerated value for the getPasswordResetState operation. */ 205 public static final int OP_GET_PASSWORD_RESET_STATE = 26; 206 /** The enumerated value for the setPasswordResetState operation. */ 207 public static final int OP_SET_PASSWORD_RESET_STATE = 27; 208 /** The enumerated value for the clearPasswordResetState operation. */ 209 public static final int OP_CLEAR_PASSWORD_RESET_STATE = 28; 210 /** 211 * The enumerated value for the getSecondsUntilPasswordResetLockout operation. 212 */ 213 public static final int OP_GET_SECONDS_UNTIL_PASSWORD_RESET_LOCKOUT = 29; 214 /** The enumerated value for the getGraceLoginUseTimes operation. */ 215 public static final int OP_GET_GRACE_LOGIN_USE_TIMES = 30; 216 /** The enumerated value for the addGraceLoginUseTime operation. */ 217 public static final int OP_ADD_GRACE_LOGIN_USE_TIME = 31; 218 /** The enumerated value for the setGraceLoginUseTimes operation. */ 219 public static final int OP_SET_GRACE_LOGIN_USE_TIMES = 32; 220 /** The enumerated value for the clearGraceLoginUseTimes operation. */ 221 public static final int OP_CLEAR_GRACE_LOGIN_USE_TIMES = 33; 222 /** The enumerated value for the getRemainingGraceLoginCount operation. */ 223 public static final int OP_GET_REMAINING_GRACE_LOGIN_COUNT = 34; 224 /** 225 * The enumerated value for the getPasswordChangedByRequiredTime operation. 226 */ 227 public static final int OP_GET_PASSWORD_CHANGED_BY_REQUIRED_TIME = 35; 228 /** 229 * The enumerated value for the setPasswordChangedByRequiredTime operation. 230 */ 231 public static final int OP_SET_PASSWORD_CHANGED_BY_REQUIRED_TIME = 36; 232 /** 233 * The enumerated value for the clearPasswordChangedByRequiredTime operation. 234 */ 235 public static final int OP_CLEAR_PASSWORD_CHANGED_BY_REQUIRED_TIME = 37; 236 /** 237 * The enumerated value for the getSecondsUntilRequiredChangeTime operation. 238 */ 239 public static final int OP_GET_SECONDS_UNTIL_REQUIRED_CHANGE_TIME = 38; 240 /** The enumerated value for the getPasswordHistory operation. */ 241 public static final int OP_GET_PASSWORD_HISTORY = 39; 242 /** The enumerated value for the clearPasswordHistory operation. */ 243 public static final int OP_CLEAR_PASSWORD_HISTORY = 40; 244 245 246 /** The set of attributes to request when retrieving a user's entry. */ 247 private LinkedHashSet<String> requestAttributes; 248 249 /** The search filter that will be used to retrieve user entries. */ 250 private SearchFilter userFilter; 251 252 private boolean isAccountSetDisabled; 253 private boolean isAccountSetEnabled; 254 255 /** 256 * Create an instance of this password policy state extended operation. All 257 * initialization should be performed in the 258 * {@code initializeExtendedOperationHandler} method. 259 */ 260 public PasswordPolicyStateExtendedOperation() 261 { 262 super(); 263 } 264 265 266 /** 267 * Initializes this extended operation handler based on the information in the 268 * provided configuration entry. It should also register itself with the 269 * Directory Server for the particular kinds of extended operations that it 270 * will process. 271 * 272 * @param config The configuration that contains the information 273 * to use to initialize this extended operation handler. 274 * 275 * @throws ConfigException If an unrecoverable problem arises in the 276 * process of performing the initialization. 277 * 278 * @throws InitializationException If a problem occurs during initialization 279 * that is not related to the server 280 * configuration. 281 */ 282 @Override 283 public void initializeExtendedOperationHandler( 284 PasswordPolicyStateExtendedOperationHandlerCfg config) 285 throws ConfigException, InitializationException 286 { 287 userFilter = SearchFilter.objectClassPresent(); 288 requestAttributes = newLinkedHashSet("*", "+"); 289 290 DirectoryServer.registerSupportedExtension(OID_PASSWORD_POLICY_STATE_EXTOP, this); 291 // FIXME registerControlAndFeatures? 292 } 293 294 /** 295 * Processes the provided extended operation. 296 * 297 * @param operation The extended operation to be processed. 298 */ 299 @Override 300 public void processExtendedOperation(ExtendedOperation operation) 301 { 302 operation.setResultCode(ResultCode.UNDEFINED); 303 304 305 // The user must have the password-reset privilege in order to be able to do 306 // anything with this extended operation. 307 ClientConnection clientConnection = operation.getClientConnection(); 308 if (! clientConnection.hasPrivilege(Privilege.PASSWORD_RESET, operation)) 309 { 310 LocalizableMessage message = ERR_PWPSTATE_EXTOP_NO_PRIVILEGE.get(); 311 operation.appendErrorMessage(message); 312 operation.setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS); 313 return; 314 } 315 316 317 // There must be a request value, and it must be a sequence. Decode it 318 // into its components. 319 ByteString requestValue = operation.getRequestValue(); 320 if (requestValue == null) 321 { 322 LocalizableMessage message = ERR_PWPSTATE_EXTOP_NO_REQUEST_VALUE.get(); 323 operation.appendErrorMessage(message); 324 operation.setResultCode(ResultCode.PROTOCOL_ERROR); 325 return; 326 } 327 328 ByteString dnString; 329 ASN1Reader reader = ASN1.getReader(requestValue); 330 try 331 { 332 reader.readStartSequence(); 333 dnString = reader.readOctetString(); 334 } 335 catch (Exception e) 336 { 337 logger.traceException(e); 338 339 LocalizableMessage message = 340 ERR_PWPSTATE_EXTOP_DECODE_FAILURE.get(getExceptionMessage(e)); 341 operation.appendErrorMessage(message); 342 operation.setResultCode(ResultCode.PROTOCOL_ERROR); 343 return; 344 } 345 346 347 // Decode the DN and get the corresponding user entry. 348 DN targetDN; 349 try 350 { 351 targetDN = DN.decode(dnString); 352 } 353 catch (DirectoryException de) 354 { 355 logger.traceException(de); 356 357 operation.setResponseData(de); 358 return; 359 } 360 361 DN rootDN = DirectoryServer.getActualRootBindDN(targetDN); 362 if (rootDN != null) 363 { 364 targetDN = rootDN; 365 } 366 367 Entry userEntry; 368 InternalClientConnection conn = 369 new InternalClientConnection(clientConnection.getAuthenticationInfo()); 370 371 userEntry = searchUserEntry(conn, operation, targetDN); 372 373 if (userEntry == null) 374 { 375 return; 376 } 377 // Get the password policy state for the user entry. 378 PasswordPolicyState pwpState; 379 try 380 { 381 AuthenticationPolicy policy = AuthenticationPolicy.forUser(userEntry, 382 false); 383 if (!policy.isPasswordPolicy()) 384 { 385 operation.setResultCode(ResultCode.UNWILLING_TO_PERFORM); 386 operation.appendErrorMessage(ERR_EXTOP_PWPSTATE_ACCOUNT_NOT_LOCAL.get(userEntry)); 387 return; 388 } 389 pwpState = (PasswordPolicyState) policy 390 .createAuthenticationPolicyState(userEntry); 391 } 392 catch (DirectoryException de) 393 { 394 logger.traceException(de); 395 396 operation.setResponseData(de); 397 return; 398 } 399 400 PasswordPolicy policy = pwpState.getAuthenticationPolicy(); 401 isAccountSetDisabled = false; 402 isAccountSetEnabled = false; 403 // Create a hash set that will be used to hold the types of the return 404 // types that should be included in the response. 405 boolean returnAll; 406 LinkedHashSet<Integer> returnTypes = new LinkedHashSet<>(); 407 try 408 { 409 if (!reader.hasNextElement()) 410 { 411 // There is no operations sequence. 412 returnAll = true; 413 } 414 else if(reader.peekLength() <= 0) 415 { 416 // There is an operations sequence but its empty. 417 returnAll = true; 418 reader.readStartSequence(); 419 reader.readEndSequence(); 420 } 421 else 422 { 423 returnAll = false; 424 reader.readStartSequence(); 425 while(reader.hasNextElement()) 426 { 427 int opType; 428 ArrayList<String> opValues; 429 430 reader.readStartSequence(); 431 opType = (int)reader.readInteger(); 432 433 if (!reader.hasNextElement()) 434 { 435 // There is no values sequence 436 opValues = null; 437 } 438 else if(reader.peekLength() <= 0) 439 { 440 // There is a values sequence but its empty 441 opValues = null; 442 reader.readStartSequence(); 443 reader.readEndSequence(); 444 } 445 else 446 { 447 reader.readStartSequence(); 448 opValues = new ArrayList<>(); 449 while (reader.hasNextElement()) 450 { 451 opValues.add(reader.readOctetStringAsString()); 452 } 453 reader.readEndSequence(); 454 } 455 reader.readEndSequence(); 456 457 if(!processOp(opType, opValues, operation, 458 returnTypes, pwpState, policy)) 459 { 460 return; 461 } 462 } 463 reader.readEndSequence(); 464 } 465 reader.readEndSequence(); 466 467 468 // If there are any modifications that need to be made to the password 469 // policy state, then apply them now. 470 List<Modification> stateMods = pwpState.getModifications(); 471 if (stateMods != null && !stateMods.isEmpty()) 472 { 473 ModifyOperation modifyOperation = 474 conn.processModify(targetDN, stateMods); 475 if (modifyOperation.getResultCode() != ResultCode.SUCCESS) 476 { 477 operation.setResultCode(modifyOperation.getResultCode()); 478 operation.setErrorMessage(modifyOperation.getErrorMessage()); 479 operation.setMatchedDN(modifyOperation.getMatchedDN()); 480 operation.setReferralURLs(modifyOperation.getReferralURLs()); 481 return; 482 } 483 // Retrieve the updated entry 484 userEntry = searchUserEntry(conn, operation, targetDN); 485 if (userEntry == null) 486 { 487 return; 488 } 489 // And it's updated password policy state 490 try 491 { 492 // We should not need to re-fetch the password policy. 493 pwpState = (PasswordPolicyState) policy 494 .createAuthenticationPolicyState(userEntry); 495 } 496 catch (DirectoryException de) 497 { 498 logger.traceException(de); 499 500 operation.setResponseData(de); 501 return; 502 } 503 } 504 } 505 catch (Exception e) 506 { 507 logger.traceException(e); 508 509 LocalizableMessage message = ERR_PWPSTATE_EXTOP_INVALID_OP_ENCODING.get( 510 e.getLocalizedMessage()); 511 operation.appendErrorMessage(message); 512 operation.setResultCode(ResultCode.PROTOCOL_ERROR); 513 return; 514 } 515 516 try 517 { 518 // Construct the sequence of values to return. 519 ByteString responseValue = 520 encodeResponse(dnString, returnAll, returnTypes, pwpState, policy); 521 operation.setResponseOID(OID_PASSWORD_POLICY_STATE_EXTOP); 522 operation.setResponseValue(responseValue); 523 operation.setResultCode(ResultCode.SUCCESS); 524 } 525 catch(Exception e) 526 { 527 // TODO: Need a better message 528 LocalizableMessage message = ERR_PWPSTATE_EXTOP_INVALID_OP_ENCODING.get( 529 e.getLocalizedMessage()); 530 operation.appendErrorMessage(message); 531 operation.setResultCode(ResultCode.PROTOCOL_ERROR); 532 } 533 // Post AccountStatus Notifications if needed. 534 if (isAccountSetDisabled) 535 { 536 pwpState.generateAccountStatusNotification( 537 AccountStatusNotificationType.ACCOUNT_DISABLED, 538 userEntry, INFO_MODIFY_ACCOUNT_DISABLED.get(), 539 AccountStatusNotification.createProperties(pwpState, false, -1, 540 null, null)); 541 542 } 543 if (isAccountSetEnabled) 544 { 545 pwpState.generateAccountStatusNotification( 546 AccountStatusNotificationType.ACCOUNT_ENABLED, 547 userEntry, INFO_MODIFY_ACCOUNT_ENABLED.get(), 548 AccountStatusNotification.createProperties(pwpState, false, -1, 549 null, null)); 550 } 551 } 552 553 /** 554 * Searches and returns the entry referenced by targetDN. If there's not 555 * exactly one entry found, an error is reported for the operation. 556 * 557 * @param conn The internal connection used to issue the search 558 * @param operation The extended operation being processed 559 * @param targetDN The DN targeted by this operation 560 * 561 * @return the Entry if one and only one is found, null otherwise 562 */ 563 private Entry searchUserEntry (InternalClientConnection conn, 564 ExtendedOperation operation, 565 DN targetDN) 566 { 567 final SearchRequest request = newSearchRequest(targetDN, SearchScope.BASE_OBJECT, userFilter) 568 .setSizeLimit(1) 569 .addAttribute(requestAttributes); 570 InternalSearchOperation internalSearch = conn.processSearch(request); 571 if (internalSearch.getResultCode() != ResultCode.SUCCESS) 572 { 573 operation.setResultCode(internalSearch.getResultCode()); 574 operation.setErrorMessage(internalSearch.getErrorMessage()); 575 operation.setMatchedDN(internalSearch.getMatchedDN()); 576 operation.setReferralURLs(internalSearch.getReferralURLs()); 577 return null; 578 } 579 580 List<SearchResultEntry> matchingEntries = internalSearch.getSearchEntries(); 581 if (matchingEntries.isEmpty()) 582 { 583 operation.setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS); 584 return null; 585 } 586 else if (matchingEntries.size() > 1) 587 { 588 operation.appendErrorMessage(ERR_PWPSTATE_EXTOP_MULTIPLE_ENTRIES.get(targetDN)); 589 operation.setResultCode(ResultCode.CONSTRAINT_VIOLATION); 590 return null; 591 } 592 else 593 { 594 return matchingEntries.get(0); 595 } 596 } 597 598 /** 599 * Encodes the provided information in a form suitable for including in the 600 * response value. 601 * 602 * @param writer The ASN1Writer to use to encode. 603 * @param opType The operation type to use for the value. 604 * @param value The single value to include in the response. 605 * 606 * @throws IOException if an error occurs while encoding. 607 */ 608 public static void encode(ASN1Writer writer, int opType, String value) 609 throws IOException 610 { 611 writer.writeStartSequence(); 612 writer.writeEnumerated(opType); 613 614 if (value != null) 615 { 616 writer.writeStartSequence(); 617 writer.writeOctetString(value); 618 writer.writeEndSequence(); 619 } 620 621 writer.writeEndSequence(); 622 } 623 624 625 626 /** 627 * Encodes the provided information in a form suitable for including in the 628 * response value. 629 * 630 * @param writer The ASN1Writer to use to encode. 631 * @param opType The operation type to use for the value. 632 * @param values The set of string values to include in the response. 633 * 634 * @throws IOException if an error occurs while encoding. 635 */ 636 public static void encode(ASN1Writer writer, int opType, String[] values) 637 throws IOException 638 { 639 writer.writeStartSequence(); 640 writer.writeEnumerated(opType); 641 642 if (values != null && values.length > 0) 643 { 644 writer.writeStartSequence(); 645 for (String value : values) 646 { 647 writer.writeOctetString(value); 648 } 649 writer.writeEndSequence(); 650 } 651 652 writer.writeEndSequence(); 653 } 654 655 /** 656 * Encodes the provided information in a form suitable for including in the 657 * response value. 658 * 659 * @param writer The ASN1Writer to use to encode. 660 * @param opType The operation type to use for the value. 661 * @param values The set of timestamp values to include in the response. 662 * 663 * @throws IOException if an error occurs while encoding. 664 */ 665 public static void encode(ASN1Writer writer, int opType, List<Long> values) 666 throws IOException 667 { 668 writer.writeStartSequence(); 669 writer.writeEnumerated(opType); 670 671 if (values != null && !values.isEmpty()) 672 { 673 writer.writeStartSequence(); 674 for (long l : values) 675 { 676 writer.writeOctetString(GeneralizedTimeSyntax.format(l)); 677 } 678 writer.writeEndSequence(); 679 } 680 681 writer.writeEndSequence(); 682 } 683 684 private ByteString encodeResponse(ByteString dnString, boolean returnAll, 685 LinkedHashSet<Integer> returnTypes, 686 PasswordPolicyState pwpState, 687 PasswordPolicy policy) 688 throws IOException 689 { 690 ByteStringBuilder builder = new ByteStringBuilder(); 691 ASN1Writer writer = ASN1.getWriter(builder); 692 writer.writeStartSequence(); 693 writer.writeOctetString(dnString); 694 695 writer.writeStartSequence(); 696 if (returnAll || returnTypes.contains(OP_GET_PASSWORD_POLICY_DN)) 697 { 698 encode(writer, OP_GET_PASSWORD_POLICY_DN, 699 policy.getDN().toString()); 700 } 701 702 if (returnAll || returnTypes.contains(OP_GET_ACCOUNT_DISABLED_STATE)) 703 { 704 encode(writer, OP_GET_ACCOUNT_DISABLED_STATE, 705 String.valueOf(pwpState.isDisabled())); 706 } 707 708 if (returnAll || returnTypes.contains(OP_GET_ACCOUNT_EXPIRATION_TIME)) 709 { 710 String expTimeStr; 711 long expTime = pwpState.getAccountExpirationTime(); 712 if (expTime < 0) 713 { 714 expTimeStr = null; 715 } 716 else 717 { 718 expTimeStr = GeneralizedTimeSyntax.format(expTime); 719 } 720 721 encode(writer, OP_GET_ACCOUNT_EXPIRATION_TIME, expTimeStr); 722 } 723 724 if (returnAll || 725 returnTypes.contains(OP_GET_SECONDS_UNTIL_ACCOUNT_EXPIRATION)) 726 { 727 String secondsStr = null; 728 long expTime = pwpState.getAccountExpirationTime(); 729 if (expTime >= 0) 730 { 731 long seconds = (expTime - pwpState.getCurrentTime()) / 1000; 732 if (seconds > 0) 733 { 734 secondsStr = String.valueOf(seconds); 735 } 736 } 737 738 encode(writer, OP_GET_SECONDS_UNTIL_ACCOUNT_EXPIRATION, 739 secondsStr); 740 } 741 742 if (returnAll || returnTypes.contains(OP_GET_PASSWORD_CHANGED_TIME)) 743 { 744 String timeStr; 745 long changedTime = pwpState.getPasswordChangedTime(); 746 if (changedTime < 0) 747 { 748 timeStr = null; 749 } 750 else 751 { 752 timeStr = GeneralizedTimeSyntax.format(changedTime); 753 } 754 755 encode(writer, OP_GET_PASSWORD_CHANGED_TIME, timeStr); 756 } 757 758 if (returnAll || 759 returnTypes.contains(OP_GET_PASSWORD_EXPIRATION_WARNED_TIME)) 760 { 761 String timeStr; 762 long warnedTime = pwpState.getWarnedTime(); 763 if (warnedTime < 0) 764 { 765 timeStr = null; 766 } 767 else 768 { 769 timeStr = GeneralizedTimeSyntax.format(warnedTime); 770 } 771 772 encode(writer, OP_GET_PASSWORD_EXPIRATION_WARNED_TIME, timeStr); 773 } 774 775 if (returnAll || 776 returnTypes.contains(OP_GET_SECONDS_UNTIL_PASSWORD_EXPIRATION)) 777 { 778 String secondsStr; 779 int secondsUntilExp = pwpState.getSecondsUntilExpiration(); 780 if (secondsUntilExp < 0) 781 { 782 secondsStr = null; 783 } 784 else 785 { 786 secondsStr = String.valueOf(secondsUntilExp); 787 } 788 789 encode(writer, OP_GET_SECONDS_UNTIL_PASSWORD_EXPIRATION, 790 secondsStr); 791 } 792 793 if (returnAll || 794 returnTypes.contains(OP_GET_SECONDS_UNTIL_PASSWORD_EXPIRATION_WARNING)) 795 { 796 String secondsStr; 797 long secondsUntilExp = pwpState.getSecondsUntilExpiration(); 798 if (secondsUntilExp < 0) 799 { 800 secondsStr = null; 801 } 802 else 803 { 804 long secondsUntilWarning = secondsUntilExp 805 - policy.getPasswordExpirationWarningInterval(); 806 if (secondsUntilWarning <= 0) 807 { 808 secondsStr = "0"; 809 } 810 else 811 { 812 secondsStr = String.valueOf(secondsUntilWarning); 813 } 814 } 815 816 encode(writer, OP_GET_SECONDS_UNTIL_PASSWORD_EXPIRATION_WARNING, 817 secondsStr); 818 } 819 820 if (returnAll || returnTypes.contains(OP_GET_AUTHENTICATION_FAILURE_TIMES)) 821 { 822 encode(writer, OP_GET_AUTHENTICATION_FAILURE_TIMES, 823 pwpState.getAuthFailureTimes()); 824 } 825 826 if (returnAll || returnTypes.contains( 827 OP_GET_SECONDS_UNTIL_AUTHENTICATION_FAILURE_UNLOCK)) 828 { 829 // We have to check whether the account is locked due to failures before 830 // we can get the length of time until the account is unlocked. 831 String secondsStr; 832 if (pwpState.lockedDueToFailures()) 833 { 834 int seconds = pwpState.getSecondsUntilUnlock(); 835 if (seconds <= 0) 836 { 837 secondsStr = null; 838 } 839 else 840 { 841 secondsStr = String.valueOf(seconds); 842 } 843 } 844 else 845 { 846 secondsStr = null; 847 } 848 849 encode(writer, OP_GET_SECONDS_UNTIL_AUTHENTICATION_FAILURE_UNLOCK, 850 secondsStr); 851 } 852 853 if (returnAll || 854 returnTypes.contains(OP_GET_REMAINING_AUTHENTICATION_FAILURE_COUNT)) 855 { 856 String remainingFailuresStr; 857 int allowedFailureCount = policy.getLockoutFailureCount(); 858 if (allowedFailureCount > 0) 859 { 860 int remainingFailures = 861 allowedFailureCount - pwpState.getAuthFailureTimes().size(); 862 if (remainingFailures < 0) 863 { 864 remainingFailures = 0; 865 } 866 867 remainingFailuresStr = String.valueOf(remainingFailures); 868 } 869 else 870 { 871 remainingFailuresStr = null; 872 } 873 874 encode(writer, OP_GET_REMAINING_AUTHENTICATION_FAILURE_COUNT, 875 remainingFailuresStr); 876 } 877 878 if (returnAll || returnTypes.contains(OP_GET_LAST_LOGIN_TIME)) 879 { 880 String timeStr; 881 long lastLoginTime = pwpState.getLastLoginTime(); 882 if (lastLoginTime < 0) 883 { 884 timeStr = null; 885 } 886 else 887 { 888 timeStr = GeneralizedTimeSyntax.format(lastLoginTime); 889 } 890 891 encode(writer, OP_GET_LAST_LOGIN_TIME, timeStr); 892 } 893 894 if (returnAll || returnTypes.contains(OP_GET_SECONDS_UNTIL_IDLE_LOCKOUT)) 895 { 896 String secondsStr; 897 long lockoutInterval = policy.getIdleLockoutInterval(); 898 if (lockoutInterval > 0) 899 { 900 long lastLoginTime = pwpState.getLastLoginTime(); 901 if (lastLoginTime < 0) 902 { 903 secondsStr = "0"; 904 } 905 else 906 { 907 long lockoutTime = lastLoginTime + lockoutInterval*1000; 908 long currentTime = pwpState.getCurrentTime(); 909 int secondsUntilLockout = (int) ((lockoutTime - currentTime) / 1000L); 910 if (secondsUntilLockout <= 0) 911 { 912 secondsStr = "0"; 913 } 914 else 915 { 916 secondsStr = String.valueOf(secondsUntilLockout); 917 } 918 } 919 } 920 else 921 { 922 secondsStr = null; 923 } 924 925 encode(writer, OP_GET_SECONDS_UNTIL_IDLE_LOCKOUT, secondsStr); 926 } 927 928 if (returnAll || returnTypes.contains(OP_GET_PASSWORD_RESET_STATE)) 929 { 930 encode(writer, OP_GET_PASSWORD_RESET_STATE, 931 String.valueOf(pwpState.mustChangePassword())); 932 } 933 934 if (returnAll || 935 returnTypes.contains(OP_GET_SECONDS_UNTIL_PASSWORD_RESET_LOCKOUT)) 936 { 937 String secondsStr; 938 if (pwpState.mustChangePassword()) 939 { 940 long maxAge = policy.getMaxPasswordResetAge(); 941 if (maxAge > 0) 942 { 943 long currentTime = pwpState.getCurrentTime(); 944 long changedTime = pwpState.getPasswordChangedTime(); 945 int changeAge = (int) ((currentTime - changedTime) / 1000L); 946 long timeToLockout = maxAge - changeAge; 947 if (timeToLockout <= 0) 948 { 949 secondsStr = "0"; 950 } 951 else 952 { 953 secondsStr = String.valueOf(timeToLockout); 954 } 955 } 956 else 957 { 958 secondsStr = null; 959 } 960 } 961 else 962 { 963 secondsStr = null; 964 } 965 966 encode(writer, OP_GET_SECONDS_UNTIL_PASSWORD_RESET_LOCKOUT, 967 secondsStr); 968 } 969 970 if (returnAll || returnTypes.contains(OP_GET_GRACE_LOGIN_USE_TIMES)) 971 { 972 encode(writer, OP_GET_GRACE_LOGIN_USE_TIMES, 973 pwpState.getGraceLoginTimes()); 974 } 975 976 if (returnAll || returnTypes.contains(OP_GET_REMAINING_GRACE_LOGIN_COUNT)) 977 { 978 String remainingStr; 979 int remainingGraceLogins = pwpState.getGraceLoginsRemaining(); 980 if (remainingGraceLogins <= 0) 981 { 982 remainingStr = "0"; 983 } 984 else 985 { 986 remainingStr = String.valueOf(remainingGraceLogins); 987 } 988 989 encode(writer, OP_GET_REMAINING_GRACE_LOGIN_COUNT, remainingStr); 990 } 991 992 if (returnAll || 993 returnTypes.contains(OP_GET_PASSWORD_CHANGED_BY_REQUIRED_TIME)) 994 { 995 String timeStr; 996 long requiredChangeTime = pwpState.getRequiredChangeTime(); 997 if (requiredChangeTime < 0) 998 { 999 timeStr = null; 1000 } 1001 else 1002 { 1003 timeStr = GeneralizedTimeSyntax.format(requiredChangeTime); 1004 } 1005 1006 encode(writer, OP_GET_PASSWORD_CHANGED_BY_REQUIRED_TIME, timeStr); 1007 } 1008 1009 if (returnAll || 1010 returnTypes.contains(OP_GET_SECONDS_UNTIL_REQUIRED_CHANGE_TIME)) 1011 { 1012 String secondsStr; 1013 long policyRequiredChangeTime = policy.getRequireChangeByTime(); 1014 if (policyRequiredChangeTime > 0) 1015 { 1016 long accountRequiredChangeTime = pwpState.getRequiredChangeTime(); 1017 if (accountRequiredChangeTime >= policyRequiredChangeTime) 1018 { 1019 secondsStr = null; 1020 } 1021 else 1022 { 1023 long currentTime = pwpState.getCurrentTime(); 1024 if (currentTime >= policyRequiredChangeTime) 1025 { 1026 secondsStr = "0"; 1027 } 1028 else 1029 { 1030 secondsStr = 1031 String.valueOf((policyRequiredChangeTime-currentTime) / 1000); 1032 1033 } 1034 } 1035 } 1036 else 1037 { 1038 secondsStr = null; 1039 } 1040 1041 encode(writer, OP_GET_SECONDS_UNTIL_REQUIRED_CHANGE_TIME, 1042 secondsStr); 1043 } 1044 1045 if (returnAll || returnTypes.contains(OP_GET_PASSWORD_HISTORY)) 1046 { 1047 encode(writer, OP_GET_PASSWORD_HISTORY, 1048 pwpState.getPasswordHistoryValues()); 1049 } 1050 writer.writeEndSequence(); 1051 1052 writer.writeEndSequence(); 1053 1054 return builder.toByteString(); 1055 } 1056 1057 private boolean processOp(int opType, ArrayList<String> opValues, 1058 ExtendedOperation operation, 1059 LinkedHashSet<Integer> returnTypes, 1060 PasswordPolicyState pwpState, 1061 PasswordPolicy policy) 1062 { 1063 switch (opType) 1064 { 1065 case OP_GET_PASSWORD_POLICY_DN: 1066 returnTypes.add(OP_GET_PASSWORD_POLICY_DN); 1067 break; 1068 1069 case OP_GET_ACCOUNT_DISABLED_STATE: 1070 returnTypes.add(OP_GET_ACCOUNT_DISABLED_STATE); 1071 break; 1072 1073 case OP_SET_ACCOUNT_DISABLED_STATE: 1074 if (opValues == null) 1075 { 1076 operation.appendErrorMessage( 1077 ERR_PWPSTATE_EXTOP_NO_DISABLED_VALUE.get()); 1078 operation.setResultCode(ResultCode.CONSTRAINT_VIOLATION); 1079 return false; 1080 } 1081 else if (opValues.size() != 1) 1082 { 1083 operation.appendErrorMessage( 1084 ERR_PWPSTATE_EXTOP_BAD_DISABLED_VALUE_COUNT.get()); 1085 operation.setResultCode(ResultCode.CONSTRAINT_VIOLATION); 1086 return false; 1087 } 1088 else 1089 { 1090 String value = opValues.get(0); 1091 if ("true".equalsIgnoreCase(value)) 1092 { 1093 pwpState.setDisabled(true); 1094 isAccountSetDisabled = true; 1095 } 1096 else if ("false".equalsIgnoreCase(value)) 1097 { 1098 pwpState.setDisabled(false); 1099 isAccountSetEnabled = true; 1100 } 1101 else 1102 { 1103 operation.appendErrorMessage( 1104 ERR_PWPSTATE_EXTOP_BAD_DISABLED_VALUE.get()); 1105 operation.setResultCode(ResultCode.CONSTRAINT_VIOLATION); 1106 return false; 1107 } 1108 } 1109 1110 returnTypes.add(OP_GET_ACCOUNT_DISABLED_STATE); 1111 break; 1112 1113 case OP_CLEAR_ACCOUNT_DISABLED_STATE: 1114 pwpState.setDisabled(false); 1115 isAccountSetEnabled = true; 1116 returnTypes.add(OP_GET_ACCOUNT_DISABLED_STATE); 1117 break; 1118 1119 case OP_GET_ACCOUNT_EXPIRATION_TIME: 1120 returnTypes.add(OP_GET_ACCOUNT_EXPIRATION_TIME); 1121 break; 1122 1123 case OP_SET_ACCOUNT_EXPIRATION_TIME: 1124 if (opValues == null) 1125 { 1126 pwpState.setAccountExpirationTime(pwpState.getCurrentTime()); 1127 } 1128 else if (opValues.size() != 1) 1129 { 1130 operation.appendErrorMessage( 1131 ERR_PWPSTATE_EXTOP_BAD_ACCT_EXP_VALUE_COUNT.get()); 1132 operation.setResultCode(ResultCode.CONSTRAINT_VIOLATION); 1133 return false; 1134 } 1135 else 1136 { 1137 try 1138 { 1139 ByteString valueString = ByteString.valueOfUtf8(opValues.get(0)); 1140 long time = GeneralizedTime.valueOf(valueString.toString()).getTimeInMillis(); 1141 pwpState.setAccountExpirationTime(time); 1142 } 1143 catch (LocalizedIllegalArgumentException e) 1144 { 1145 operation.appendErrorMessage( 1146 ERR_PWPSTATE_EXTOP_BAD_ACCT_EXP_VALUE.get(opValues.get(0), e.getMessageObject())); 1147 operation.setResultCode(ResultCode.CONSTRAINT_VIOLATION); 1148 return false; 1149 } 1150 } 1151 1152 returnTypes.add(OP_GET_ACCOUNT_EXPIRATION_TIME); 1153 break; 1154 1155 case OP_CLEAR_ACCOUNT_EXPIRATION_TIME: 1156 pwpState.clearAccountExpirationTime(); 1157 returnTypes.add(OP_GET_ACCOUNT_EXPIRATION_TIME); 1158 break; 1159 1160 case OP_GET_SECONDS_UNTIL_ACCOUNT_EXPIRATION: 1161 returnTypes.add(OP_GET_SECONDS_UNTIL_ACCOUNT_EXPIRATION); 1162 break; 1163 1164 case OP_GET_PASSWORD_CHANGED_TIME: 1165 returnTypes.add(OP_GET_PASSWORD_CHANGED_TIME); 1166 break; 1167 1168 case OP_SET_PASSWORD_CHANGED_TIME: 1169 if (opValues == null) 1170 { 1171 pwpState.setPasswordChangedTime(); 1172 } 1173 else if (opValues.size() != 1) 1174 { 1175 operation.appendErrorMessage( 1176 ERR_PWPSTATE_EXTOP_BAD_PWCHANGETIME_VALUE_COUNT.get()); 1177 operation.setResultCode(ResultCode.CONSTRAINT_VIOLATION); 1178 return false; 1179 } 1180 else 1181 { 1182 try 1183 { 1184 ByteString valueString = ByteString.valueOfUtf8(opValues.get(0)); 1185 long time = GeneralizedTime.valueOf(valueString.toString()).getTimeInMillis(); 1186 pwpState.setPasswordChangedTime(time); 1187 } 1188 catch (LocalizedIllegalArgumentException e) 1189 { 1190 operation.appendErrorMessage( 1191 ERR_PWPSTATE_EXTOP_BAD_PWCHANGETIME_VALUE.get(opValues.get(0), e.getMessageObject())); 1192 operation.setResultCode(ResultCode.CONSTRAINT_VIOLATION); 1193 return false; 1194 } 1195 } 1196 1197 returnTypes.add(OP_GET_PASSWORD_CHANGED_TIME); 1198 break; 1199 1200 case OP_CLEAR_PASSWORD_CHANGED_TIME: 1201 pwpState.clearPasswordChangedTime(); 1202 returnTypes.add(OP_GET_PASSWORD_CHANGED_TIME); 1203 break; 1204 1205 case OP_GET_PASSWORD_EXPIRATION_WARNED_TIME: 1206 returnTypes.add(OP_GET_PASSWORD_EXPIRATION_WARNED_TIME); 1207 break; 1208 1209 case OP_SET_PASSWORD_EXPIRATION_WARNED_TIME: 1210 if (opValues == null) 1211 { 1212 pwpState.setWarnedTime(); 1213 } 1214 else if (opValues.size() != 1) 1215 { 1216 operation.appendErrorMessage( 1217 ERR_PWPSTATE_EXTOP_BAD_PWWARNEDTIME_VALUE_COUNT.get()); 1218 operation.setResultCode(ResultCode.CONSTRAINT_VIOLATION); 1219 return false; 1220 } 1221 else 1222 { 1223 try 1224 { 1225 ByteString valueString = ByteString.valueOfUtf8(opValues.get(0)); 1226 long time = GeneralizedTime.valueOf(valueString.toString()).getTimeInMillis(); 1227 pwpState.setWarnedTime(time); 1228 } 1229 catch (LocalizedIllegalArgumentException e) 1230 { 1231 operation.appendErrorMessage( 1232 ERR_PWPSTATE_EXTOP_BAD_PWWARNEDTIME_VALUE.get(opValues.get(0), e.getMessageObject())); 1233 operation.setResultCode(ResultCode.CONSTRAINT_VIOLATION); 1234 return false; 1235 } 1236 } 1237 1238 returnTypes.add(OP_GET_PASSWORD_EXPIRATION_WARNED_TIME); 1239 break; 1240 1241 case OP_CLEAR_PASSWORD_EXPIRATION_WARNED_TIME: 1242 pwpState.clearWarnedTime(); 1243 returnTypes.add(OP_GET_PASSWORD_EXPIRATION_WARNED_TIME); 1244 break; 1245 1246 case OP_GET_SECONDS_UNTIL_PASSWORD_EXPIRATION: 1247 returnTypes.add(OP_GET_SECONDS_UNTIL_PASSWORD_EXPIRATION); 1248 break; 1249 1250 case OP_GET_SECONDS_UNTIL_PASSWORD_EXPIRATION_WARNING: 1251 returnTypes.add(OP_GET_SECONDS_UNTIL_PASSWORD_EXPIRATION_WARNING); 1252 break; 1253 1254 case OP_GET_AUTHENTICATION_FAILURE_TIMES: 1255 returnTypes.add(OP_GET_AUTHENTICATION_FAILURE_TIMES); 1256 break; 1257 1258 case OP_ADD_AUTHENTICATION_FAILURE_TIME: 1259 if (opValues == null) 1260 { 1261 if (policy.getLockoutFailureCount() == 0) 1262 { 1263 returnTypes.add(OP_GET_AUTHENTICATION_FAILURE_TIMES); 1264 break; 1265 } 1266 1267 pwpState.updateAuthFailureTimes(); 1268 } 1269 else if (opValues.size() != 1) 1270 { 1271 operation.appendErrorMessage( 1272 ERR_PWPSTATE_EXTOP_BAD_ADD_FAILURE_TIME_COUNT.get()); 1273 operation.setResultCode(ResultCode.CONSTRAINT_VIOLATION); 1274 return false; 1275 } 1276 else 1277 { 1278 try 1279 { 1280 ByteString valueString = ByteString.valueOfUtf8(opValues.get(0)); 1281 long time = GeneralizedTime.valueOf(valueString.toString()).getTimeInMillis(); 1282 List<Long> authFailureTimes = pwpState.getAuthFailureTimes(); 1283 ArrayList<Long> newFailureTimes = new ArrayList<>(authFailureTimes.size()+1); 1284 newFailureTimes.addAll(authFailureTimes); 1285 newFailureTimes.add(time); 1286 pwpState.setAuthFailureTimes(newFailureTimes); 1287 } 1288 catch (LocalizedIllegalArgumentException e) 1289 { 1290 LocalizableMessage message = 1291 ERR_PWPSTATE_EXTOP_BAD_AUTH_FAILURE_TIME.get(opValues.get(0), e.getMessageObject()); 1292 operation.setResultCode(ResultCode.CONSTRAINT_VIOLATION); 1293 operation.appendErrorMessage(message); 1294 return false; 1295 } 1296 } 1297 1298 returnTypes.add(OP_GET_AUTHENTICATION_FAILURE_TIMES); 1299 break; 1300 1301 case OP_SET_AUTHENTICATION_FAILURE_TIMES: 1302 if (opValues == null) 1303 { 1304 pwpState.setAuthFailureTimes(newArrayList(pwpState.getCurrentTime())); 1305 } 1306 else 1307 { 1308 ArrayList<Long> valueList = new ArrayList<>(opValues.size()); 1309 for (String value : opValues) 1310 { 1311 try 1312 { 1313 valueList.add(GeneralizedTime.valueOf(value).getTimeInMillis()); 1314 } 1315 catch (LocalizedIllegalArgumentException e) 1316 { 1317 LocalizableMessage message = 1318 ERR_PWPSTATE_EXTOP_BAD_AUTH_FAILURE_TIME.get(value, e.getMessageObject()); 1319 operation.setResultCode(ResultCode.CONSTRAINT_VIOLATION); 1320 operation.appendErrorMessage(message); 1321 return false; 1322 } 1323 } 1324 pwpState.setAuthFailureTimes(valueList); 1325 } 1326 1327 returnTypes.add(OP_GET_AUTHENTICATION_FAILURE_TIMES); 1328 break; 1329 1330 case OP_CLEAR_AUTHENTICATION_FAILURE_TIMES: 1331 pwpState.clearFailureLockout(); 1332 returnTypes.add(OP_GET_AUTHENTICATION_FAILURE_TIMES); 1333 break; 1334 1335 case OP_GET_SECONDS_UNTIL_AUTHENTICATION_FAILURE_UNLOCK: 1336 returnTypes.add(OP_GET_SECONDS_UNTIL_AUTHENTICATION_FAILURE_UNLOCK); 1337 break; 1338 1339 case OP_GET_REMAINING_AUTHENTICATION_FAILURE_COUNT: 1340 returnTypes.add(OP_GET_REMAINING_AUTHENTICATION_FAILURE_COUNT); 1341 break; 1342 1343 case OP_GET_LAST_LOGIN_TIME: 1344 returnTypes.add(OP_GET_LAST_LOGIN_TIME); 1345 break; 1346 1347 case OP_SET_LAST_LOGIN_TIME: 1348 if (opValues == null) 1349 { 1350 pwpState.setLastLoginTime(); 1351 } 1352 else if (opValues.size() != 1) 1353 { 1354 operation.appendErrorMessage( 1355 ERR_PWPSTATE_EXTOP_BAD_LAST_LOGIN_TIME_COUNT.get()); 1356 operation.setResultCode(ResultCode.CONSTRAINT_VIOLATION); 1357 return false; 1358 } 1359 else 1360 { 1361 try 1362 { 1363 ByteString valueString = ByteString.valueOfUtf8(opValues.get(0)); 1364 long time = GeneralizedTime.valueOf(valueString.toString()).getTimeInMillis(); 1365 pwpState.setLastLoginTime(time); 1366 } 1367 catch (LocalizedIllegalArgumentException e) 1368 { 1369 operation.appendErrorMessage( 1370 ERR_PWPSTATE_EXTOP_BAD_LAST_LOGIN_TIME.get(opValues.get(0), e.getMessageObject())); 1371 operation.setResultCode(ResultCode.CONSTRAINT_VIOLATION); 1372 return false; 1373 } 1374 } 1375 1376 returnTypes.add(OP_GET_LAST_LOGIN_TIME); 1377 break; 1378 1379 case OP_CLEAR_LAST_LOGIN_TIME: 1380 pwpState.clearLastLoginTime(); 1381 returnTypes.add(OP_GET_LAST_LOGIN_TIME); 1382 break; 1383 1384 case OP_GET_SECONDS_UNTIL_IDLE_LOCKOUT: 1385 returnTypes.add(OP_GET_SECONDS_UNTIL_IDLE_LOCKOUT); 1386 break; 1387 1388 case OP_GET_PASSWORD_RESET_STATE: 1389 returnTypes.add(OP_GET_PASSWORD_RESET_STATE); 1390 break; 1391 1392 case OP_SET_PASSWORD_RESET_STATE: 1393 if (opValues == null) 1394 { 1395 operation.appendErrorMessage( 1396 ERR_PWPSTATE_EXTOP_NO_RESET_STATE_VALUE.get()); 1397 operation.setResultCode(ResultCode.CONSTRAINT_VIOLATION); 1398 return false; 1399 } 1400 else if (opValues.size() != 1) 1401 { 1402 operation.appendErrorMessage( 1403 ERR_PWPSTATE_EXTOP_BAD_RESET_STATE_VALUE_COUNT.get()); 1404 operation.setResultCode(ResultCode.CONSTRAINT_VIOLATION); 1405 return false; 1406 } 1407 else 1408 { 1409 String value = opValues.get(0); 1410 if ("true".equalsIgnoreCase(value)) 1411 { 1412 pwpState.setMustChangePassword(true); 1413 } 1414 else if ("false".equalsIgnoreCase(value)) 1415 { 1416 pwpState.setMustChangePassword(false); 1417 } 1418 else 1419 { 1420 operation.appendErrorMessage( 1421 ERR_PWPSTATE_EXTOP_BAD_RESET_STATE_VALUE.get()); 1422 operation.setResultCode(ResultCode.CONSTRAINT_VIOLATION); 1423 return false; 1424 } 1425 } 1426 1427 returnTypes.add(OP_GET_PASSWORD_RESET_STATE); 1428 break; 1429 1430 case OP_CLEAR_PASSWORD_RESET_STATE: 1431 pwpState.setMustChangePassword(false); 1432 returnTypes.add(OP_GET_PASSWORD_RESET_STATE); 1433 break; 1434 1435 case OP_GET_SECONDS_UNTIL_PASSWORD_RESET_LOCKOUT: 1436 returnTypes.add(OP_GET_SECONDS_UNTIL_PASSWORD_RESET_LOCKOUT); 1437 break; 1438 1439 case OP_GET_GRACE_LOGIN_USE_TIMES: 1440 returnTypes.add(OP_GET_GRACE_LOGIN_USE_TIMES); 1441 break; 1442 1443 case OP_ADD_GRACE_LOGIN_USE_TIME: 1444 if (opValues == null) 1445 { 1446 pwpState.updateGraceLoginTimes(); 1447 } 1448 else if (opValues.size() != 1) 1449 { 1450 operation.appendErrorMessage( 1451 ERR_PWPSTATE_EXTOP_BAD_ADD_GRACE_LOGIN_TIME_COUNT.get()); 1452 operation.setResultCode(ResultCode.CONSTRAINT_VIOLATION); 1453 return false; 1454 } 1455 else 1456 { 1457 try 1458 { 1459 ByteString valueString = ByteString.valueOfUtf8(opValues.get(0)); 1460 long time = GeneralizedTime.valueOf(valueString.toString()).getTimeInMillis(); 1461 List<Long> authFailureTimes = pwpState.getGraceLoginTimes(); 1462 ArrayList<Long> newGraceTimes = new ArrayList<>(authFailureTimes.size()+1); 1463 newGraceTimes.addAll(authFailureTimes); 1464 newGraceTimes.add(time); 1465 pwpState.setGraceLoginTimes(newGraceTimes); 1466 } 1467 catch (LocalizedIllegalArgumentException e) 1468 { 1469 LocalizableMessage message = 1470 ERR_PWPSTATE_EXTOP_BAD_GRACE_LOGIN_TIME.get(opValues.get(0), e.getMessageObject()); 1471 operation.setResultCode(ResultCode.CONSTRAINT_VIOLATION); 1472 operation.appendErrorMessage(message); 1473 return false; 1474 } 1475 } 1476 1477 returnTypes.add(OP_GET_GRACE_LOGIN_USE_TIMES); 1478 break; 1479 1480 case OP_SET_GRACE_LOGIN_USE_TIMES: 1481 if (opValues == null) 1482 { 1483 pwpState.setGraceLoginTimes(newArrayList(pwpState.getCurrentTime())); 1484 } 1485 else 1486 { 1487 ArrayList<Long> valueList = new ArrayList<>(opValues.size()); 1488 for (String s : opValues) 1489 { 1490 try 1491 { 1492 valueList.add(GeneralizedTime.valueOf(s).getTimeInMillis()); 1493 } 1494 catch (LocalizedIllegalArgumentException e) 1495 { 1496 LocalizableMessage message = ERR_PWPSTATE_EXTOP_BAD_GRACE_LOGIN_TIME.get( 1497 s, e.getMessageObject()); 1498 operation.setResultCode(ResultCode.CONSTRAINT_VIOLATION); 1499 operation.appendErrorMessage(message); 1500 return false; 1501 } 1502 } 1503 pwpState.setGraceLoginTimes(valueList); 1504 } 1505 1506 returnTypes.add(OP_GET_GRACE_LOGIN_USE_TIMES); 1507 break; 1508 1509 case OP_CLEAR_GRACE_LOGIN_USE_TIMES: 1510 pwpState.clearGraceLoginTimes(); 1511 returnTypes.add(OP_GET_GRACE_LOGIN_USE_TIMES); 1512 break; 1513 1514 case OP_GET_REMAINING_GRACE_LOGIN_COUNT: 1515 returnTypes.add(OP_GET_REMAINING_GRACE_LOGIN_COUNT); 1516 break; 1517 1518 case OP_GET_PASSWORD_CHANGED_BY_REQUIRED_TIME: 1519 returnTypes.add(OP_GET_PASSWORD_CHANGED_BY_REQUIRED_TIME); 1520 break; 1521 1522 case OP_SET_PASSWORD_CHANGED_BY_REQUIRED_TIME: 1523 if (opValues == null) 1524 { 1525 pwpState.setRequiredChangeTime(); 1526 } 1527 else if (opValues.size() != 1) 1528 { 1529 operation.appendErrorMessage( 1530 ERR_PWPSTATE_EXTOP_BAD_REQUIRED_CHANGE_TIME_COUNT.get()); 1531 operation.setResultCode(ResultCode.CONSTRAINT_VIOLATION); 1532 return false; 1533 } 1534 else 1535 { 1536 try 1537 { 1538 ByteString valueString = ByteString.valueOfUtf8(opValues.get(0)); 1539 long time = GeneralizedTime.valueOf(valueString.toString()).getTimeInMillis(); 1540 pwpState.setRequiredChangeTime(time); 1541 } 1542 catch (LocalizedIllegalArgumentException e) 1543 { 1544 operation.appendErrorMessage( 1545 ERR_PWPSTATE_EXTOP_BAD_REQUIRED_CHANGE_TIME.get( 1546 opValues.get(0), 1547 e.getMessageObject())); 1548 operation.setResultCode(ResultCode.CONSTRAINT_VIOLATION); 1549 return false; 1550 } 1551 } 1552 1553 returnTypes.add(OP_GET_PASSWORD_CHANGED_BY_REQUIRED_TIME); 1554 break; 1555 1556 case OP_CLEAR_PASSWORD_CHANGED_BY_REQUIRED_TIME: 1557 pwpState.clearRequiredChangeTime(); 1558 returnTypes.add(OP_GET_PASSWORD_CHANGED_BY_REQUIRED_TIME); 1559 break; 1560 1561 case OP_GET_SECONDS_UNTIL_REQUIRED_CHANGE_TIME: 1562 returnTypes.add(OP_GET_SECONDS_UNTIL_REQUIRED_CHANGE_TIME); 1563 break; 1564 1565 case OP_GET_PASSWORD_HISTORY: 1566 returnTypes.add(OP_GET_PASSWORD_HISTORY); 1567 break; 1568 1569 case OP_CLEAR_PASSWORD_HISTORY: 1570 pwpState.clearPasswordHistory(); 1571 returnTypes.add(OP_GET_PASSWORD_HISTORY); 1572 break; 1573 1574 default: 1575 operation.appendErrorMessage(ERR_PWPSTATE_EXTOP_UNKNOWN_OP_TYPE.get(opType)); 1576 operation.setResultCode(ResultCode.CONSTRAINT_VIOLATION); 1577 return false; 1578 } 1579 1580 return true; 1581 } 1582 1583 /** {@inheritDoc} */ 1584 @Override 1585 public String getExtendedOperationOID() 1586 { 1587 return OID_PASSWORD_POLICY_STATE_EXTOP; 1588 } 1589 1590 /** {@inheritDoc} */ 1591 @Override 1592 public String getExtendedOperationName() 1593 { 1594 return "Password Policy State"; 1595 } 1596}