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