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