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}