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