001/*
002 * CDDL HEADER START
003 *
004 * The contents of this file are subject to the terms of the
005 * Common Development and Distribution License, Version 1.0 only
006 * (the "License").  You may not use this file except in compliance
007 * with the License.
008 *
009 * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt
010 * or http://forgerock.org/license/CDDLv1.0.html.
011 * See the License for the specific language governing permissions
012 * and limitations under the License.
013 *
014 * When distributing Covered Code, include this CDDL HEADER in each
015 * file and include the License file at legal-notices/CDDLv1_0.txt.
016 * If applicable, add the following below this CDDL HEADER, with the
017 * fields enclosed by brackets "[]" replaced with your own identifying
018 * information:
019 *      Portions Copyright [yyyy] [name of copyright owner]
020 *
021 * CDDL HEADER END
022 *
023 *
024 *      Copyright 2006-2009 Sun Microsystems, Inc.
025 *      Portions Copyright 2014-2015 ForgeRock AS
026 */
027package org.opends.server.controls;
028import org.forgerock.i18n.LocalizableMessage;
029
030
031import java.io.IOException;
032
033import org.forgerock.opendj.io.*;
034import org.opends.server.types.*;
035import org.forgerock.opendj.ldap.ResultCode;
036import org.forgerock.opendj.ldap.ByteString;
037import org.forgerock.i18n.slf4j.LocalizedLogger;
038import static org.opends.messages.ProtocolMessages.*;
039import static org.opends.server.util.ServerConstants.*;
040import static org.opends.server.util.StaticUtils.*;
041
042
043
044/**
045 * This class implements the account usable response control.  This is a
046 * Sun-defined control with OID 1.3.6.1.4.1.42.2.27.9.5.8.  The value of this
047 * control is composed according to the following BNF:
048 * <BR>
049 * <PRE>
050 * ACCOUNT_USABLE_RESPONSE ::= CHOICE {
051 *      is_available           [0] INTEGER, -- Seconds before expiration --
052 *      is_not_available       [1] MORE_INFO }
053 *
054 * MORE_INFO ::= SEQUENCE {
055 *      inactive               [0] BOOLEAN DEFAULT FALSE,
056 *      reset                  [1] BOOLEAN DEFAULT FALSE,
057 *      expired                [2] BOOLEAN DEFAULT_FALSE,
058 *      remaining_grace        [3] INTEGER OPTIONAL,
059 *      seconds_before_unlock  [4] INTEGER OPTIONAL }
060 * </PRE>
061 */
062public class AccountUsableResponseControl
063    extends Control
064{
065  /**
066   * ControlDecoder implementation to decode this control from a ByteString.
067   */
068  private static final class Decoder
069      implements ControlDecoder<AccountUsableResponseControl>
070  {
071    /** {@inheritDoc} */
072    public AccountUsableResponseControl decode(boolean isCritical,
073                                               ByteString value)
074        throws DirectoryException
075    {
076      if (value == null)
077      {
078        // The response control must always have a value.
079        LocalizableMessage message = ERR_ACCTUSABLERES_NO_CONTROL_VALUE.get();
080        throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message);
081      }
082
083
084      try
085      {
086        ASN1Reader reader = ASN1.getReader(value);
087        switch (reader.peekType())
088        {
089          case TYPE_SECONDS_BEFORE_EXPIRATION:
090            int secondsBeforeExpiration = (int)reader.readInteger();
091            return new AccountUsableResponseControl(isCritical,
092                secondsBeforeExpiration);
093          case TYPE_MORE_INFO:
094            boolean isInactive = false;
095            boolean isReset = false;
096            boolean isExpired = false;
097            boolean isLocked = false;
098            int     remainingGraceLogins = -1;
099            int     secondsBeforeUnlock = 0;
100
101            reader.readStartSequence();
102            if(reader.hasNextElement() &&
103                reader.peekType() == TYPE_INACTIVE)
104            {
105              isInactive = reader.readBoolean();
106            }
107            if(reader.hasNextElement() &&
108                reader.peekType() == TYPE_RESET)
109            {
110              isReset = reader.readBoolean();
111            }
112            if(reader.hasNextElement() &&
113                reader.peekType() == TYPE_EXPIRED)
114            {
115              isExpired = reader.readBoolean();
116            }
117            if(reader.hasNextElement() &&
118                reader.peekType() == TYPE_REMAINING_GRACE_LOGINS)
119            {
120              remainingGraceLogins = (int)reader.readInteger();
121            }
122            if(reader.hasNextElement() &&
123                reader.peekType() == TYPE_SECONDS_BEFORE_UNLOCK)
124            {
125              isLocked = true;
126              secondsBeforeUnlock = (int)reader.readInteger();
127            }
128            reader.readEndSequence();
129
130            return new AccountUsableResponseControl(isCritical,
131                isInactive, isReset,
132                isExpired,
133                remainingGraceLogins,
134                isLocked,
135                secondsBeforeUnlock);
136
137          default:
138            LocalizableMessage message = ERR_ACCTUSABLERES_UNKNOWN_VALUE_ELEMENT_TYPE.get(
139                byteToHex(reader.peekType()));
140            throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message);
141        }
142      }
143      catch (DirectoryException de)
144      {
145        throw de;
146      }
147      catch (Exception e)
148      {
149        logger.traceException(e);
150
151        LocalizableMessage message =
152            ERR_ACCTUSABLERES_DECODE_ERROR.get(getExceptionMessage(e));
153        throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message);
154      }
155    }
156
157    public String getOID()
158    {
159      return OID_ACCOUNT_USABLE_CONTROL;
160    }
161
162  }
163
164  /**
165   * The Control Decoder that can be used to decode this control.
166   */
167  public static final ControlDecoder<AccountUsableResponseControl> DECODER =
168    new Decoder();
169  private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
170
171
172
173
174  /**
175   * The BER type to use for the seconds before expiration when the account is
176   * available.
177   */
178  public static final byte TYPE_SECONDS_BEFORE_EXPIRATION = (byte) 0x80;
179
180
181
182  /**
183   * The BER type to use for the MORE_INFO sequence when the account is not
184   * available.
185   */
186  public static final byte TYPE_MORE_INFO = (byte) 0xA1;
187
188
189
190  /**
191   * The BER type to use for the MORE_INFO element that indicates that the
192   * account has been inactivated.
193   */
194  public static final byte TYPE_INACTIVE = (byte) 0x80;
195
196
197
198  /**
199   * The BER type to use for the MORE_INFO element that indicates that the
200   * password has been administratively reset.
201   */
202  public static final byte TYPE_RESET = (byte) 0x81;
203
204
205
206  /**
207   * The BER type to use for the MORE_INFO element that indicates that the
208   * user's password is expired.
209   */
210  public static final byte TYPE_EXPIRED = (byte) 0x82;
211
212
213
214  /**
215   * The BER type to use for the MORE_INFO element that provides the number of
216   * remaining grace logins.
217   */
218  public static final byte TYPE_REMAINING_GRACE_LOGINS = (byte) 0x83;
219
220
221
222  /**
223   * The BER type to use for the MORE_INFO element that indicates that the
224   * password has been administratively reset.
225   */
226  public static final byte TYPE_SECONDS_BEFORE_UNLOCK = (byte) 0x84;
227
228
229
230  /** Indicates whether the user's account is usable. */
231  private boolean isUsable;
232
233  /** Indicates whether the user's password is expired. */
234  private boolean isExpired;
235
236  /** Indicates whether the user's account is inactive. */
237  private boolean isInactive;
238
239  /** Indicates whether the user's account is currently locked. */
240  private boolean isLocked;
241
242  /**
243   * Indicates whether the user's password has been reset and must be changed
244   * before anything else can be done.
245   */
246  private boolean isReset;
247
248  /** The number of remaining grace logins, if available. */
249  private int remainingGraceLogins;
250
251  /**
252   * The length of time in seconds before the user's password expires, if
253   * available.
254   */
255  private int secondsBeforeExpiration;
256
257  /** The length of time before the user's account is unlocked, if available. */
258  private int secondsBeforeUnlock;
259
260
261
262  /**
263   * Creates a new account usability response control that may be used to
264   * indicate that the account is available and provide the number of seconds
265   * until expiration.  It will use the default OID and criticality.
266   *
267   * @param  secondsBeforeExpiration  The length of time in seconds until the
268   *                                  user's password expires, or -1 if the
269   *                                  user's password will not expire or the
270   *                                  expiration time is unknown.
271   */
272  public AccountUsableResponseControl(int secondsBeforeExpiration)
273  {
274    this(false, secondsBeforeExpiration);
275  }
276
277  /**
278   * Creates a new account usability response control that may be used to
279   * indicate that the account is available and provide the number of seconds
280   * until expiration.  It will use the default OID and criticality.
281   *
282   * @param  isCritical  Indicates whether this control should be
283   *                     considered critical in processing the
284   *                     request.
285   * @param  secondsBeforeExpiration  The length of time in seconds until the
286   *                                  user's password expires, or -1 if the
287   *                                  user's password will not expire or the
288   *                                  expiration time is unknown.
289   */
290  public AccountUsableResponseControl(boolean isCritical,
291                                      int secondsBeforeExpiration)
292  {
293    super(OID_ACCOUNT_USABLE_CONTROL, isCritical);
294
295
296    this.secondsBeforeExpiration = secondsBeforeExpiration;
297
298    isUsable             = true;
299    isInactive           = false;
300    isReset              = false;
301    isExpired            = false;
302    remainingGraceLogins = -1;
303    isLocked             = false;
304    secondsBeforeUnlock  = 0;
305  }
306
307
308
309  /**
310   * Creates a new account usability response control that may be used to
311   * indicate that the account is not available and provide information about
312   * the underlying reason.  It will use the default OID and criticality.
313   *
314   * @param  isCritical  Indicates whether this control should be
315   *                     considered critical in processing the
316   *                     request.
317   * @param  isInactive            Indicates whether the user's account has been
318   *                               inactivated by an administrator.
319   * @param  isReset               Indicates whether the user's password has
320   *                               been reset by an administrator.
321   * @param  isExpired             Indicates whether the user's password is
322   *                               expired.
323   * @param  remainingGraceLogins  The number of grace logins remaining.  A
324   *                               value of zero indicates that there are none
325   *                               remaining.  A value of -1 indicates that
326   *                               grace login functionality is not enabled.
327   * @param  isLocked              Indicates whether the user's account is
328   *                               currently locked out.
329   * @param  secondsBeforeUnlock   The length of time in seconds until the
330   *                               account is unlocked.  A value of -1 indicates
331   *                               that the account will not be automatically
332   *                               unlocked and must be reset by an
333   *                               administrator.
334   */
335  public AccountUsableResponseControl(boolean isCritical, boolean isInactive,
336                                      boolean isReset,
337                                      boolean isExpired,
338                                      int remainingGraceLogins,
339                                      boolean isLocked, int secondsBeforeUnlock)
340  {
341    super(OID_ACCOUNT_USABLE_CONTROL, isCritical);
342
343
344    this.isInactive           = isInactive;
345    this.isReset              = isReset;
346    this.isExpired            = isExpired;
347    this.remainingGraceLogins = remainingGraceLogins;
348    this.isLocked             = isLocked;
349    this.secondsBeforeUnlock  = secondsBeforeUnlock;
350
351    isUsable                = false;
352    secondsBeforeExpiration = -1;
353  }
354
355  /**
356   * Creates a new account usability response control that may be used to
357   * indicate that the account is not available and provide information about
358   * the underlying reason.  It will use the default OID and criticality.
359   *
360   * @param  isInactive            Indicates whether the user's account has been
361   *                               inactivated by an administrator.
362   * @param  isReset               Indicates whether the user's password has
363   *                               been reset by an administrator.
364   * @param  isExpired             Indicates whether the user's password is
365   *                               expired.
366   * @param  remainingGraceLogins  The number of grace logins remaining.  A
367   *                               value of zero indicates that there are none
368   *                               remaining.  A value of -1 indicates that
369   *                               grace login functionality is not enabled.
370   * @param  isLocked              Indicates whether the user's account is
371   *                               currently locked out.
372   * @param  secondsBeforeUnlock   The length of time in seconds until the
373   *                               account is unlocked.  A value of -1 indicates
374   *                               that the account will not be automatically
375   *                               unlocked and must be reset by an
376   *                               administrator.
377   */
378  public AccountUsableResponseControl(boolean isInactive, boolean isReset,
379                                      boolean isExpired,
380                                      int remainingGraceLogins,
381                                      boolean isLocked, int secondsBeforeUnlock)
382  {
383    this(false, isInactive, isReset, isExpired, remainingGraceLogins,
384        isLocked, secondsBeforeUnlock);
385  }
386
387  /**
388   * Writes this control's value to an ASN.1 writer. The value (if any) must be
389   * written as an ASN1OctetString.
390   *
391   * @param writer The ASN.1 output stream to write to.
392   * @throws IOException If a problem occurs while writing to the stream.
393   */
394  public void writeValue(ASN1Writer writer) throws IOException {
395    writer.writeStartSequence(ASN1.UNIVERSAL_OCTET_STRING_TYPE);
396
397    if(isUsable)
398    {
399      writer.writeInteger(TYPE_SECONDS_BEFORE_EXPIRATION,
400          secondsBeforeExpiration);
401    }
402    else
403    {
404      writer.writeStartSequence(TYPE_MORE_INFO);
405      if (isInactive)
406      {
407        writer.writeBoolean(TYPE_INACTIVE, true);
408      }
409
410      if (isReset)
411      {
412        writer.writeBoolean(TYPE_RESET, true);
413      }
414
415      if (isExpired)
416      {
417        writer.writeBoolean(TYPE_EXPIRED, true);
418
419        if (remainingGraceLogins >= 0)
420        {
421          writer.writeInteger(TYPE_REMAINING_GRACE_LOGINS,
422              remainingGraceLogins);
423        }
424      }
425
426      if (isLocked)
427      {
428        writer.writeInteger(TYPE_SECONDS_BEFORE_UNLOCK,
429            secondsBeforeUnlock);
430      }
431      writer.writeEndSequence();
432    }
433
434    writer.writeEndSequence();
435  }
436
437
438
439
440  /**
441   * Indicates whether the associated user account is available for use.
442   *
443   * @return  <CODE>true</CODE> if the associated user account is available, or
444   *          <CODE>false</CODE> if not.
445   */
446  public boolean isUsable()
447  {
448    return isUsable;
449  }
450
451
452
453  /**
454   * Retrieves the length of time in seconds before the user's password expires.
455   * This value is unreliable if the account is not available.
456   *
457   * @return  The length of time in seconds before the user's password expires,
458   *          or -1 if it is unknown or password expiration is not enabled for
459   *          the user.
460   */
461  public int getSecondsBeforeExpiration()
462  {
463    return secondsBeforeExpiration;
464  }
465
466
467
468  /**
469   * Indicates whether the user's account has been inactivated by an
470   * administrator.
471   *
472   * @return  <CODE>true</CODE> if the user's account has been inactivated by
473   *          an administrator, or <CODE>false</CODE> if not.
474   */
475  public boolean isInactive()
476  {
477    return isInactive;
478  }
479
480
481
482  /**
483   * Indicates whether the user's password has been administratively reset and
484   * the user must change that password before any other operations will be
485   * allowed.
486   *
487   * @return  <CODE>true</CODE> if the user's password has been administratively
488   *          reset, or <CODE>false</CODE> if not.
489   */
490  public boolean isReset()
491  {
492    return isReset;
493  }
494
495
496
497  /**
498   * Indicates whether the user's password is expired.
499   *
500   * @return  <CODE>true</CODE> if the user's password is expired, or
501   *          <CODE>false</CODE> if not.
502   */
503  public boolean isExpired()
504  {
505    return isExpired;
506  }
507
508
509
510  /**
511   * Retrieves the number of remaining grace logins for the user.  This value is
512   * unreliable if the user's password is not expired.
513   *
514   * @return  The number of remaining grace logins for the user, or -1 if the
515   *          grace logins feature is not enabled for the user.
516   */
517  public int getRemainingGraceLogins()
518  {
519    return remainingGraceLogins;
520  }
521
522
523
524  /**
525   * Indicates whether the user's account is locked for some reason.
526   *
527   * @return  <CODE>true</CODE> if the user's account is locked, or
528   *          <CODE>false</CODE> if it is not.
529   */
530  public boolean isLocked()
531  {
532    return isLocked;
533  }
534
535
536
537  /**
538   * Retrieves the length of time in seconds before the user's account is
539   * automatically unlocked.  This value is unreliable is the user's account is
540   * not locked.
541   *
542   * @return  The length of time in seconds before the user's account is
543   *          automatically unlocked, or -1 if it requires administrative action
544   *          to unlock the account.
545   */
546  public int getSecondsBeforeUnlock()
547  {
548    return secondsBeforeUnlock;
549  }
550
551
552
553  /**
554   * Appends a string representation of this password policy response control to
555   * the provided buffer.
556   *
557   * @param  buffer  The buffer to which the information should be appended.
558   */
559  public void toString(StringBuilder buffer)
560  {
561    buffer.append("AccountUsableResponseControl(isUsable=");
562    buffer.append(isUsable);
563
564    if (isUsable)
565    {
566      buffer.append(",secondsBeforeExpiration=");
567      buffer.append(secondsBeforeExpiration);
568    }
569    else
570    {
571      buffer.append(",isInactive=");
572      buffer.append(isInactive);
573      buffer.append(",isReset=");
574      buffer.append(isReset);
575      buffer.append(",isExpired=");
576      buffer.append(isExpired);
577      buffer.append(",remainingGraceLogins=");
578      buffer.append(remainingGraceLogins);
579      buffer.append(",isLocked=");
580      buffer.append(isLocked);
581      buffer.append(",secondsBeforeUnlock=");
582      buffer.append(secondsBeforeUnlock);
583    }
584
585    buffer.append(")");
586  }
587}
588