001    /*
002     * Copyright 2007-2015 UnboundID Corp.
003     * All Rights Reserved.
004     */
005    /*
006     * Copyright (C) 2008-2015 UnboundID Corp.
007     *
008     * This program is free software; you can redistribute it and/or modify
009     * it under the terms of the GNU General Public License (GPLv2 only)
010     * or the terms of the GNU Lesser General Public License (LGPLv2.1 only)
011     * as published by the Free Software Foundation.
012     *
013     * This program is distributed in the hope that it will be useful,
014     * but WITHOUT ANY WARRANTY; without even the implied warranty of
015     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
016     * GNU General Public License for more details.
017     *
018     * You should have received a copy of the GNU General Public License
019     * along with this program; if not, see <http://www.gnu.org/licenses>.
020     */
021    package com.unboundid.ldap.sdk.controls;
022    
023    
024    
025    import com.unboundid.asn1.ASN1OctetString;
026    import com.unboundid.ldap.sdk.Control;
027    import com.unboundid.ldap.sdk.DecodeableControl;
028    import com.unboundid.ldap.sdk.LDAPException;
029    import com.unboundid.ldap.sdk.LDAPResult;
030    import com.unboundid.ldap.sdk.ResultCode;
031    import com.unboundid.util.NotMutable;
032    import com.unboundid.util.ThreadSafety;
033    import com.unboundid.util.ThreadSafetyLevel;
034    
035    import static com.unboundid.ldap.sdk.controls.ControlMessages.*;
036    import static com.unboundid.util.Debug.*;
037    
038    
039    
040    /**
041     * This class provides an implementation of the expiring expiring control as
042     * described in draft-vchu-ldap-pwd-policy.  It may be used to indicate that the
043     * authenticated user's password will expire in the near future.  The value of
044     * this control includes the length of time in seconds until the user's
045     * password actually expires.
046     * <BR><BR>
047     * No request control is required to trigger the server to send the password
048     * expiring response control.  If the server supports the use of this control
049     * and the user's password will expire within a time frame that the server
050     * considers to be the near future, then it will be included in the bind
051     * response returned to the client.
052     * <BR><BR>
053     * See the documentation for the {@link PasswordExpiredControl} to see an
054     * example that demonstrates the use of both the password expiring and password
055     * expired controls.
056     */
057    @NotMutable()
058    @ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
059    public final class PasswordExpiringControl
060           extends Control
061           implements DecodeableControl
062    {
063      /**
064       * The OID (2.16.840.1.113730.3.4.5) for the password expiring response
065       * control.
066       */
067      public static final String PASSWORD_EXPIRING_OID = "2.16.840.1.113730.3.4.5";
068    
069    
070    
071      /**
072       * The serial version UID for this serializable class.
073       */
074      private static final long serialVersionUID = 1250220480854441338L;
075    
076    
077    
078      // The length of time in seconds until the password expires.
079      private final int secondsUntilExpiration;
080    
081    
082    
083      /**
084       * Creates a new empty control instance that is intended to be used only for
085       * decoding controls via the {@code DecodeableControl} interface.
086       */
087      PasswordExpiringControl()
088      {
089        secondsUntilExpiration = -1;
090      }
091    
092    
093    
094      /**
095       * Creates a new password expiring control with the provided information.
096       *
097       * @param  secondsUntilExpiration  The length of time in seconds until the
098       *                                 password expires.
099       */
100      public PasswordExpiringControl(final int secondsUntilExpiration)
101      {
102        super(PASSWORD_EXPIRING_OID, false,
103              new ASN1OctetString(String.valueOf(secondsUntilExpiration)));
104    
105        this.secondsUntilExpiration = secondsUntilExpiration;
106      }
107    
108    
109    
110      /**
111       * Creates a new password expiring control with the provided information.
112       *
113       * @param  oid         The OID for the control.
114       * @param  isCritical  Indicates whether the control should be marked
115       *                     critical.
116       * @param  value       The encoded value for the control.  This may be
117       *                     {@code null} if no value was provided.
118       *
119       * @throws  LDAPException  If the provided control cannot be decoded as a
120       *                         password expiring response control.
121       */
122      public PasswordExpiringControl(final String oid, final boolean isCritical,
123                                     final ASN1OctetString value)
124             throws LDAPException
125      {
126        super(oid, isCritical, value);
127    
128        if (value == null)
129        {
130          throw new LDAPException(ResultCode.DECODING_ERROR,
131                                  ERR_PW_EXPIRING_NO_VALUE.get());
132        }
133    
134        try
135        {
136          secondsUntilExpiration = Integer.parseInt(value.stringValue());
137        }
138        catch (NumberFormatException nfe)
139        {
140          debugException(nfe);
141          throw new LDAPException(ResultCode.DECODING_ERROR,
142                                  ERR_PW_EXPIRING_VALUE_NOT_INTEGER.get(), nfe);
143        }
144      }
145    
146    
147    
148      /**
149       * {@inheritDoc}
150       */
151      public PasswordExpiringControl
152                  decodeControl(final String oid, final boolean isCritical,
153                                final ASN1OctetString value)
154             throws LDAPException
155      {
156        return new PasswordExpiringControl(oid, isCritical, value);
157      }
158    
159    
160    
161      /**
162       * Extracts a password expiring control from the provided result.
163       *
164       * @param  result  The result from which to retrieve the password expiring
165       *                 control.
166       *
167       * @return  The password expiring control contained in the provided result, or
168       *          {@code null} if the result did not contain a password expiring
169       *          control.
170       *
171       * @throws  LDAPException  If a problem is encountered while attempting to
172       *                         decode the password expiring control contained in
173       *                         the provided result.
174       */
175      public static PasswordExpiringControl get(final LDAPResult result)
176             throws LDAPException
177      {
178        final Control c = result.getResponseControl(PASSWORD_EXPIRING_OID);
179        if (c == null)
180        {
181          return null;
182        }
183    
184        if (c instanceof PasswordExpiringControl)
185        {
186          return (PasswordExpiringControl) c;
187        }
188        else
189        {
190          return new PasswordExpiringControl(c.getOID(), c.isCritical(),
191               c.getValue());
192        }
193      }
194    
195    
196    
197      /**
198       * Retrieves the length of time in seconds until the password expires.
199       *
200       * @return  The length of time in seconds until the password expires.
201       */
202      public int getSecondsUntilExpiration()
203      {
204        return secondsUntilExpiration;
205      }
206    
207    
208    
209      /**
210       * {@inheritDoc}
211       */
212      @Override()
213      public String getControlName()
214      {
215        return INFO_CONTROL_NAME_PW_EXPIRING.get();
216      }
217    
218    
219    
220      /**
221       * {@inheritDoc}
222       */
223      @Override()
224      public void toString(final StringBuilder buffer)
225      {
226        buffer.append("PasswordExpiringControl(secondsUntilExpiration=");
227        buffer.append(secondsUntilExpiration);
228        buffer.append(", isCritical=");
229        buffer.append(isCritical());
230        buffer.append(')');
231      }
232    }