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