001/* 002 * Copyright 2008-2018 Ping Identity Corporation 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright (C) 2015-2018 Ping Identity Corporation 007 * 008 * This program is free software; you can redistribute it and/or modify 009 * it under the terms of the GNU General Public License (GPLv2 only) 010 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only) 011 * as published by the Free Software Foundation. 012 * 013 * This program is distributed in the hope that it will be useful, 014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 016 * GNU General Public License for more details. 017 * 018 * You should have received a copy of the GNU General Public License 019 * along with this program; if not, see <http://www.gnu.org/licenses>. 020 */ 021package com.unboundid.ldap.sdk.unboundidds.controls; 022 023 024 025import java.util.ArrayList; 026import java.util.Collections; 027import java.util.List; 028 029import com.unboundid.asn1.ASN1Boolean; 030import com.unboundid.asn1.ASN1Element; 031import com.unboundid.asn1.ASN1Integer; 032import com.unboundid.asn1.ASN1OctetString; 033import com.unboundid.asn1.ASN1Sequence; 034import com.unboundid.ldap.sdk.Control; 035import com.unboundid.ldap.sdk.DecodeableControl; 036import com.unboundid.ldap.sdk.LDAPException; 037import com.unboundid.ldap.sdk.ResultCode; 038import com.unboundid.ldap.sdk.SearchResultEntry; 039import com.unboundid.util.NotMutable; 040import com.unboundid.util.ThreadSafety; 041import com.unboundid.util.ThreadSafetyLevel; 042 043import static com.unboundid.ldap.sdk.unboundidds.controls.ControlMessages.*; 044import static com.unboundid.util.Debug.*; 045import static com.unboundid.util.StaticUtils.*; 046 047 048 049/** 050 * This class provides an implementation of the account usable response control, 051 * which may be returned with search result entries to provide information about 052 * the usability of the associated user accounts. 053 * <BR> 054 * <BLOCKQUOTE> 055 * <B>NOTE:</B> This class, and other classes within the 056 * {@code com.unboundid.ldap.sdk.unboundidds} package structure, are only 057 * supported for use against Ping Identity, UnboundID, and Alcatel-Lucent 8661 058 * server products. These classes provide support for proprietary 059 * functionality or for external specifications that are not considered stable 060 * or mature enough to be guaranteed to work in an interoperable way with 061 * other types of LDAP servers. 062 * </BLOCKQUOTE> 063 * <BR> 064 * Information that may be included in the account usable response control 065 * includes: 066 * <UL> 067 * <LI>{@code accountIsActive} -- Indicates that the account is active and may 068 * include the length of time in seconds until the password expires.</LI> 069 * <LI>{@code accountIsInactive} -- Indicates that the account has been locked 070 * or deactivated.</LI> 071 * <LI>{@code mustChangePassword} -- Indicates that the user must change his 072 * or her password before being allowed to perform any other 073 * operations.</LI> 074 * <LI>{@code passwordIsExpired} -- Indicates that the user's password has 075 * expired.</LI> 076 * <LI>{@code remainingGraceLogins} -- Indicates the number of grace logins 077 * remaining for the user.</LI> 078 * <LI>{@code secondsUntilUnlock} -- Indicates the length of time in seconds 079 * until the account will be automatically unlocked.</LI> 080 * </UL> 081 * See the {@link AccountUsableRequestControl} documentation for an example 082 * demonstrating the use of the account usable request and response controls. 083 * <BR><BR> 084 * This control was designed by Sun Microsystems and is not based on any RFC or 085 * Internet draft. The value of this control is encoded as follows: 086 * <BR><BR> 087 * <PRE> 088 * ACCOUNT_USABLE_RESPONSE ::= CHOICE { 089 * isUsable [0] INTEGER, -- Seconds until password expiration -- 090 * isNotUsable [1] MORE_INFO } 091 * 092 * MORE_INFO ::= SEQUENCE { 093 * accountIsInactive [0] BOOLEAN DEFAULT FALSE, 094 * mustChangePassword [1] BOOLEAN DEFAULT FALSE, 095 * passwordIsExpired [2] BOOLEAN DEFAULT FALSE, 096 * remainingGraceLogins [3] INTEGER OPTIONAL, 097 * secondsUntilUnlock [4] INTEGER OPTIONAL } 098 * </PRE> 099 */ 100@NotMutable() 101@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE) 102public final class AccountUsableResponseControl 103 extends Control 104 implements DecodeableControl 105{ 106 /** 107 * The OID (1.3.6.1.4.1.42.2.27.9.5.8) for the account usable response 108 * control. 109 */ 110 public static final String ACCOUNT_USABLE_RESPONSE_OID = 111 "1.3.6.1.4.1.42.2.27.9.5.8"; 112 113 114 115 /** 116 * The BER type that will be used for the element that indicates the account 117 * is usable and provides the number of seconds until expiration. 118 */ 119 private static final byte TYPE_SECONDS_UNTIL_EXPIRATION = (byte) 0x80; 120 121 122 123 /** 124 * The BER type that will be used for the element that indicates the account 125 * is not usable and provides additional information about the reason. 126 */ 127 private static final byte TYPE_MORE_INFO = (byte) 0xA1; 128 129 130 131 /** 132 * The BER type that will be used for the element that indicates whether the 133 * account is inactive. 134 */ 135 private static final byte TYPE_IS_INACTIVE = (byte) 0x80; 136 137 138 139 /** 140 * The BER type that will be used for the element that indicates whether the 141 * user must change their password. 142 */ 143 private static final byte TYPE_MUST_CHANGE = (byte) 0x81; 144 145 146 147 /** 148 * The BER type that will be used for the element that indicates whether the 149 * password is expired. 150 */ 151 private static final byte TYPE_IS_EXPIRED = (byte) 0x82; 152 153 154 155 /** 156 * The BER type that will be used for the element that provides the number of 157 * remaining grace logins. 158 */ 159 private static final byte TYPE_REMAINING_GRACE_LOGINS = (byte) 0x83; 160 161 162 163 /** 164 * The BER type that will be used for the element that provides the number of 165 * seconds until the account is unlocked. 166 */ 167 private static final byte TYPE_SECONDS_UNTIL_UNLOCK = (byte) 0x84; 168 169 170 171 /** 172 * The serial version UID for this serializable class. 173 */ 174 private static final long serialVersionUID = -9150988495337467770L; 175 176 177 178 // Indicates whether the account has been inactivated. 179 private final boolean isInactive; 180 181 // Indicates whether the account is usable. 182 private final boolean isUsable; 183 184 // Indicates whether the user's password must be changed before other 185 // operations will be allowed. 186 private final boolean mustChangePassword; 187 188 // Indicates whether the user's password is expired. 189 private final boolean passwordIsExpired; 190 191 // The list of reasons that this account may be considered unusable. 192 private final List<String> unusableReasons; 193 194 // The number of grace logins remaining. 195 private final int remainingGraceLogins; 196 197 // The length of time in seconds until the password expires. 198 private final int secondsUntilExpiration; 199 200 // The length of time in seconds until the account is unlocked. 201 private final int secondsUntilUnlock; 202 203 204 205 /** 206 * Creates a new empty control instance that is intended to be used only for 207 * decoding controls via the {@code DecodeableControl} interface. 208 */ 209 AccountUsableResponseControl() 210 { 211 isUsable = false; 212 secondsUntilExpiration = 0; 213 isInactive = false; 214 mustChangePassword = false; 215 passwordIsExpired = false; 216 remainingGraceLogins = 0; 217 secondsUntilUnlock = 0; 218 unusableReasons = Collections.emptyList(); 219 } 220 221 222 223 /** 224 * Creates a new account usable response control which indicates that the 225 * account is usable. 226 * 227 * @param secondsUntilExpiration The length of time in seconds until the 228 * user's password expires, or -1 if password 229 * expiration is not enabled for the user. 230 */ 231 public AccountUsableResponseControl(final int secondsUntilExpiration) 232 { 233 super(ACCOUNT_USABLE_RESPONSE_OID, false, 234 encodeValue(secondsUntilExpiration)); 235 236 isUsable = true; 237 this.secondsUntilExpiration = secondsUntilExpiration; 238 isInactive = false; 239 mustChangePassword = false; 240 passwordIsExpired = false; 241 remainingGraceLogins = -1; 242 secondsUntilUnlock = -1; 243 unusableReasons = Collections.emptyList(); 244 } 245 246 247 248 /** 249 * Creates a new account usable response control which indicates that the 250 * account is not usable. 251 * 252 * @param isInactive Indicates whether the user account has been 253 * inactivated. 254 * @param mustChangePassword Indicates whether the user is required to 255 * change his/her password before any other 256 * operations will be allowed. 257 * @param passwordIsExpired Indicates whether the user's password has 258 * expired. 259 * @param remainingGraceLogins The number of remaining grace logins for the 260 * user. 261 * @param secondsUntilUnlock The length of time in seconds until the 262 * user's account will be automatically 263 * unlocked. 264 */ 265 public AccountUsableResponseControl(final boolean isInactive, 266 final boolean mustChangePassword, 267 final boolean passwordIsExpired, 268 final int remainingGraceLogins, 269 final int secondsUntilUnlock) 270 { 271 super(ACCOUNT_USABLE_RESPONSE_OID, false, 272 encodeValue(isInactive, mustChangePassword, passwordIsExpired, 273 remainingGraceLogins, secondsUntilUnlock)); 274 275 isUsable = false; 276 secondsUntilExpiration = -1; 277 this.isInactive = isInactive; 278 this.mustChangePassword = mustChangePassword; 279 this.passwordIsExpired = passwordIsExpired; 280 this.remainingGraceLogins = remainingGraceLogins; 281 this.secondsUntilUnlock = secondsUntilUnlock; 282 283 final ArrayList<String> unusableList = new ArrayList<String>(5); 284 if (isInactive) 285 { 286 unusableList.add(ERR_ACCT_UNUSABLE_INACTIVE.get()); 287 } 288 289 if (mustChangePassword) 290 { 291 unusableList.add(ERR_ACCT_UNUSABLE_MUST_CHANGE_PW.get()); 292 } 293 294 if (passwordIsExpired) 295 { 296 unusableList.add(ERR_ACCT_UNUSABLE_PW_EXPIRED.get()); 297 } 298 299 if (remainingGraceLogins >= 0) 300 { 301 switch (remainingGraceLogins) 302 { 303 case 0: 304 unusableList.add(ERR_ACCT_UNUSABLE_REMAINING_GRACE_NONE.get()); 305 break; 306 case 1: 307 unusableList.add(ERR_ACCT_UNUSABLE_REMAINING_GRACE_ONE.get()); 308 break; 309 default: 310 unusableList.add(ERR_ACCT_UNUSABLE_REMAINING_GRACE_MULTIPLE.get( 311 remainingGraceLogins)); 312 break; 313 } 314 } 315 316 if (secondsUntilUnlock > 0) 317 { 318 unusableList.add( 319 ERR_ACCT_UNUSABLE_SECONDS_UNTIL_UNLOCK.get(secondsUntilUnlock)); 320 } 321 322 unusableReasons = Collections.unmodifiableList(unusableList); 323 } 324 325 326 327 /** 328 * Creates a new account usable response control with the provided 329 * information. 330 * 331 * @param oid The OID for the control. 332 * @param isCritical Indicates whether the control should be marked 333 * critical. 334 * @param value The encoded value for the control. This may be 335 * {@code null} if no value was provided. 336 * 337 * @throws LDAPException If the provided control cannot be decoded as an 338 * account usable response control. 339 */ 340 public AccountUsableResponseControl(final String oid, 341 final boolean isCritical, 342 final ASN1OctetString value) 343 throws LDAPException 344 { 345 super(oid, isCritical, value); 346 347 if (value == null) 348 { 349 throw new LDAPException(ResultCode.DECODING_ERROR, 350 ERR_ACCOUNT_USABLE_RESPONSE_NO_VALUE.get()); 351 } 352 353 final ASN1Element valueElement; 354 try 355 { 356 valueElement = ASN1Element.decode(value.getValue()); 357 } 358 catch (final Exception e) 359 { 360 debugException(e); 361 throw new LDAPException(ResultCode.DECODING_ERROR, 362 ERR_ACCOUNT_USABLE_RESPONSE_VALUE_NOT_ELEMENT.get(e), e); 363 } 364 365 366 final boolean decodedIsUsable; 367 boolean decodedIsInactive = false; 368 boolean decodedMustChangePassword = false; 369 boolean decodedPasswordIsExpired = false; 370 int decodedRemainingGraceLogins = -1; 371 int decodedSecondsUntilExpiration = -1; 372 int decodedSecondsUntilUnlock = -1; 373 374 final List<String> decodedUnusableReasons = new ArrayList<String>(5); 375 376 377 final byte type = valueElement.getType(); 378 if (type == TYPE_SECONDS_UNTIL_EXPIRATION) 379 { 380 decodedIsUsable = true; 381 382 try 383 { 384 decodedSecondsUntilExpiration = 385 ASN1Integer.decodeAsInteger(valueElement).intValue(); 386 if (decodedSecondsUntilExpiration < 0) 387 { 388 decodedSecondsUntilExpiration = -1; 389 } 390 } 391 catch (final Exception e) 392 { 393 debugException(e); 394 throw new LDAPException(ResultCode.DECODING_ERROR, 395 ERR_ACCOUNT_USABLE_RESPONSE_STE_NOT_INT.get(e), e); 396 } 397 } 398 else if (type == TYPE_MORE_INFO) 399 { 400 decodedIsUsable = false; 401 402 final ASN1Element[] elements; 403 try 404 { 405 elements = ASN1Sequence.decodeAsSequence(valueElement).elements(); 406 } 407 catch (final Exception e) 408 { 409 debugException(e); 410 throw new LDAPException(ResultCode.DECODING_ERROR, 411 ERR_ACCOUNT_USABLE_RESPONSE_VALUE_NOT_SEQUENCE.get(e), 412 e); 413 } 414 415 for (final ASN1Element element : elements) 416 { 417 switch (element.getType()) 418 { 419 case TYPE_IS_INACTIVE: 420 try 421 { 422 decodedIsInactive = 423 ASN1Boolean.decodeAsBoolean(element).booleanValue(); 424 decodedUnusableReasons.add(ERR_ACCT_UNUSABLE_INACTIVE.get()); 425 } 426 catch (final Exception e) 427 { 428 debugException(e); 429 throw new LDAPException(ResultCode.DECODING_ERROR, 430 ERR_ACCOUNT_USABLE_RESPONSE_INACTIVE_NOT_BOOLEAN.get(e), e); 431 } 432 break; 433 434 case TYPE_MUST_CHANGE: 435 try 436 { 437 decodedMustChangePassword = 438 ASN1Boolean.decodeAsBoolean(element).booleanValue(); 439 decodedUnusableReasons.add( 440 ERR_ACCT_UNUSABLE_MUST_CHANGE_PW.get()); 441 } 442 catch (final Exception e) 443 { 444 debugException(e); 445 throw new LDAPException(ResultCode.DECODING_ERROR, 446 ERR_ACCOUNT_USABLE_RESPONSE_MUST_CHANGE_NOT_BOOLEAN.get(e), 447 e); 448 } 449 break; 450 451 case TYPE_IS_EXPIRED: 452 try 453 { 454 decodedPasswordIsExpired = 455 ASN1Boolean.decodeAsBoolean(element).booleanValue(); 456 decodedUnusableReasons.add(ERR_ACCT_UNUSABLE_PW_EXPIRED.get()); 457 } 458 catch (final Exception e) 459 { 460 debugException(e); 461 throw new LDAPException(ResultCode.DECODING_ERROR, 462 ERR_ACCOUNT_USABLE_RESPONSE_IS_EXP_NOT_BOOLEAN.get(e), e); 463 } 464 break; 465 466 case TYPE_REMAINING_GRACE_LOGINS: 467 try 468 { 469 decodedRemainingGraceLogins = 470 ASN1Integer.decodeAsInteger(element).intValue(); 471 if (decodedRemainingGraceLogins < 0) 472 { 473 decodedRemainingGraceLogins = -1; 474 } 475 else 476 { 477 switch (decodedRemainingGraceLogins) 478 { 479 case 0: 480 decodedUnusableReasons.add( 481 ERR_ACCT_UNUSABLE_REMAINING_GRACE_NONE.get()); 482 break; 483 case 1: 484 decodedUnusableReasons.add( 485 ERR_ACCT_UNUSABLE_REMAINING_GRACE_ONE.get()); 486 break; 487 default: 488 decodedUnusableReasons.add( 489 ERR_ACCT_UNUSABLE_REMAINING_GRACE_MULTIPLE.get( 490 decodedRemainingGraceLogins)); 491 break; 492 } 493 } 494 } 495 catch (final Exception e) 496 { 497 debugException(e); 498 throw new LDAPException(ResultCode.DECODING_ERROR, 499 ERR_ACCOUNT_USABLE_RESPONSE_GRACE_LOGINS_NOT_INT.get(e), e); 500 } 501 break; 502 503 case TYPE_SECONDS_UNTIL_UNLOCK: 504 try 505 { 506 decodedSecondsUntilUnlock = 507 ASN1Integer.decodeAsInteger(element).intValue(); 508 if (decodedSecondsUntilUnlock < 0) 509 { 510 decodedSecondsUntilUnlock = -1; 511 } 512 else if (decodedSecondsUntilUnlock > 0) 513 { 514 decodedUnusableReasons.add( 515 ERR_ACCT_UNUSABLE_SECONDS_UNTIL_UNLOCK.get( 516 decodedSecondsUntilUnlock)); 517 } 518 } 519 catch (final Exception e) 520 { 521 debugException(e); 522 throw new LDAPException(ResultCode.DECODING_ERROR, 523 ERR_ACCOUNT_USABLE_RESPONSE_STU_NOT_INT.get(e), e); 524 } 525 break; 526 527 default: 528 throw new LDAPException(ResultCode.DECODING_ERROR, 529 ERR_ACCOUNT_USABLE_RESPONSE_MORE_INFO_INVALID_TYPE.get( 530 toHex(element.getType()))); 531 } 532 } 533 } 534 else 535 { 536 throw new LDAPException(ResultCode.DECODING_ERROR, 537 ERR_ACCOUNT_USABLE_RESPONSE_INVALID_TYPE.get( 538 toHex(type))); 539 } 540 541 isUsable = decodedIsUsable; 542 secondsUntilExpiration = decodedSecondsUntilExpiration; 543 isInactive = decodedIsInactive; 544 mustChangePassword = decodedMustChangePassword; 545 passwordIsExpired = decodedPasswordIsExpired; 546 remainingGraceLogins = decodedRemainingGraceLogins; 547 secondsUntilUnlock = decodedSecondsUntilUnlock; 548 unusableReasons = 549 Collections.unmodifiableList(decodedUnusableReasons); 550 } 551 552 553 554 /** 555 * Creates an ASN.1 octet string that may be used as the value of an account 556 * usable response control if the account is usable. 557 * 558 * @param secondsUntilExpiration The length of time in seconds until the 559 * user's password expires, or -1 if password 560 * expiration is not enabled for the user. 561 * 562 * @return The ASN.1 octet string that may be used as the control value. 563 */ 564 private static ASN1OctetString encodeValue(final int secondsUntilExpiration) 565 { 566 final ASN1Integer sueInteger = 567 new ASN1Integer(TYPE_SECONDS_UNTIL_EXPIRATION, secondsUntilExpiration); 568 569 return new ASN1OctetString(sueInteger.encode()); 570 } 571 572 573 574 /** 575 * Creates an ASN.1 octet string that may be used of the value of an account 576 * usable response control if the account is not usable. 577 * 578 * @param isInactive Indicates whether the user account has been 579 * inactivated. 580 * @param mustChangePassword Indicates whether the user is required to 581 * change his/her password before any other 582 * operations will be allowed. 583 * @param passwordIsExpired Indicates whether the user's password has 584 * expired. 585 * @param remainingGraceLogins The number of remaining grace logins for the 586 * user. 587 * @param secondsUntilUnlock The length of time in seconds until the 588 * user's account will be automatically 589 * unlocked. 590 * 591 * @return The ASN.1 octet string that may be used as the control value. 592 */ 593 private static ASN1OctetString encodeValue(final boolean isInactive, 594 final boolean mustChangePassword, 595 final boolean passwordIsExpired, 596 final int remainingGraceLogins, 597 final int secondsUntilUnlock) 598 { 599 final ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(5); 600 601 if (isInactive) 602 { 603 elements.add(new ASN1Boolean(TYPE_IS_INACTIVE, true)); 604 } 605 606 if (mustChangePassword) 607 { 608 elements.add(new ASN1Boolean(TYPE_MUST_CHANGE, true)); 609 } 610 611 if (passwordIsExpired) 612 { 613 elements.add(new ASN1Boolean(TYPE_IS_EXPIRED, true)); 614 } 615 616 if (remainingGraceLogins >= 0) 617 { 618 elements.add(new ASN1Integer(TYPE_REMAINING_GRACE_LOGINS, 619 remainingGraceLogins)); 620 } 621 622 if (secondsUntilUnlock >= 0) 623 { 624 elements.add(new ASN1Integer(TYPE_SECONDS_UNTIL_UNLOCK, 625 secondsUntilUnlock)); 626 } 627 628 final ASN1Sequence valueSequence = 629 new ASN1Sequence(TYPE_MORE_INFO, elements); 630 return new ASN1OctetString(valueSequence.encode()); 631 } 632 633 634 635 /** 636 * {@inheritDoc} 637 */ 638 @Override() 639 public AccountUsableResponseControl decodeControl(final String oid, 640 final boolean isCritical, 641 final ASN1OctetString value) 642 throws LDAPException 643 { 644 return new AccountUsableResponseControl(oid, isCritical, value); 645 } 646 647 648 649 /** 650 * Extracts an account usable response control from the provided search result 651 * entry. 652 * 653 * @param entry The search result entry from which to retrieve the account 654 * usable response control. 655 * 656 * @return The account usable response control contained in the provided 657 * search result entry, or {@code null} if the entry did not contain 658 * an account usable response control. 659 * 660 * @throws LDAPException If a problem is encountered while attempting to 661 * decode the account usable response control 662 * contained in the provided result. 663 */ 664 public static AccountUsableResponseControl get(final SearchResultEntry entry) 665 throws LDAPException 666 { 667 final Control c = entry.getControl(ACCOUNT_USABLE_RESPONSE_OID); 668 if (c == null) 669 { 670 return null; 671 } 672 673 if (c instanceof AccountUsableResponseControl) 674 { 675 return (AccountUsableResponseControl) c; 676 } 677 else 678 { 679 return new AccountUsableResponseControl(c.getOID(), c.isCritical(), 680 c.getValue()); 681 } 682 } 683 684 685 686 /** 687 * Indicates whether the associated user account is usable. 688 * 689 * @return {@code true} if the user account is usable, or {@code false} if 690 * not. 691 */ 692 public boolean isUsable() 693 { 694 return isUsable; 695 } 696 697 698 699 /** 700 * Retrieves the list of reasons that this account may be unusable. 701 * 702 * @return The list of reasons that this account may be unusable, or an empty 703 * list if the account is usable or no reasons are available. 704 */ 705 public List<String> getUnusableReasons() 706 { 707 return unusableReasons; 708 } 709 710 711 712 /** 713 * Retrieves the number of seconds until the user's password expires. This 714 * will only available if the account is usable. 715 * 716 * @return The number of seconds until the user's password expires, or -1 if 717 * the user account is not usable, or if password expiration is not 718 * enabled in the directory server. 719 */ 720 public int getSecondsUntilExpiration() 721 { 722 return secondsUntilExpiration; 723 } 724 725 726 727 /** 728 * Indicates whether the user account has been inactivated by a server 729 * administrator. 730 * 731 * @return {@code true} if the user account has been inactivated by a server 732 * administrator, or {@code false} if not. 733 */ 734 public boolean isInactive() 735 { 736 return isInactive; 737 } 738 739 740 741 /** 742 * Indicates whether the user must change his or her password before being 743 * allowed to perform any other operations. 744 * 745 * @return {@code true} if the user must change his or her password before 746 * being allowed to perform any other operations, or {@code false} if 747 * not. 748 */ 749 public boolean mustChangePassword() 750 { 751 return mustChangePassword; 752 } 753 754 755 756 /** 757 * Indicates whether the user's password is expired. 758 * 759 * @return {@code true} if the user's password is expired, or {@code false} 760 * if not. 761 */ 762 public boolean passwordIsExpired() 763 { 764 return passwordIsExpired; 765 } 766 767 768 769 /** 770 * Retrieves the number of remaining grace logins for the user. This will 771 * only be available if the user account is not usable. 772 * 773 * @return The number of remaining grace logins for the user, or -1 if this 774 * is not available (e.g., because the account is usable or grace 775 * login functionality is disabled on the server). 776 */ 777 public int getRemainingGraceLogins() 778 { 779 return remainingGraceLogins; 780 } 781 782 783 784 /** 785 * Retrieves the length of time in seconds until the user's account is 786 * automatically unlocked. This will only be available if the user account is 787 * not usable. 788 * 789 * @return The length of time in seconds until the user's account is 790 * automatically unlocked, or -1 if this is not available (e.g., 791 * because the account is usable, or because the account is not 792 * locked, or because automatic unlocking is disabled on the server). 793 */ 794 public int getSecondsUntilUnlock() 795 { 796 return secondsUntilUnlock; 797 } 798 799 800 801 /** 802 * {@inheritDoc} 803 */ 804 @Override() 805 public String getControlName() 806 { 807 return INFO_CONTROL_NAME_ACCOUNT_USABLE_RESPONSE.get(); 808 } 809 810 811 812 /** 813 * {@inheritDoc} 814 */ 815 @Override() 816 public void toString(final StringBuilder buffer) 817 { 818 buffer.append("AccountUsableResponseControl(isUsable="); 819 buffer.append(isUsable); 820 821 if (isUsable) 822 { 823 if (secondsUntilExpiration >= 0) 824 { 825 buffer.append(", secondsUntilExpiration="); 826 buffer.append(secondsUntilExpiration); 827 } 828 } 829 else 830 { 831 buffer.append(", isInactive="); 832 buffer.append(isInactive); 833 buffer.append(", mustChangePassword="); 834 buffer.append(mustChangePassword); 835 buffer.append(", passwordIsExpired="); 836 buffer.append(passwordIsExpired); 837 838 if (remainingGraceLogins >= 0) 839 { 840 buffer.append(", remainingGraceLogins="); 841 buffer.append(remainingGraceLogins); 842 } 843 844 if (secondsUntilUnlock >= 0) 845 { 846 buffer.append(", secondsUntilUnlock="); 847 buffer.append(secondsUntilUnlock); 848 } 849 } 850 851 buffer.append(')'); 852 } 853}