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