001/*
002 * Copyright 2007-2022 Ping Identity Corporation
003 * All Rights Reserved.
004 */
005/*
006 * Copyright 2007-2022 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) 2007-2022 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.controls;
037
038
039
040import com.unboundid.asn1.ASN1OctetString;
041import com.unboundid.ldap.sdk.Control;
042import com.unboundid.ldap.sdk.DecodeableControl;
043import com.unboundid.ldap.sdk.LDAPException;
044import com.unboundid.ldap.sdk.LDAPResult;
045import com.unboundid.ldap.sdk.ResultCode;
046import com.unboundid.util.Debug;
047import com.unboundid.util.NotMutable;
048import com.unboundid.util.NotNull;
049import com.unboundid.util.Nullable;
050import com.unboundid.util.ThreadSafety;
051import com.unboundid.util.ThreadSafetyLevel;
052
053import static com.unboundid.ldap.sdk.controls.ControlMessages.*;
054
055
056
057/**
058 * This class provides an implementation of the expiring expiring control as
059 * described in draft-vchu-ldap-pwd-policy.  It may be used to indicate that the
060 * authenticated user's password will expire in the near future.  The value of
061 * this control includes the length of time in seconds until the user's
062 * password actually expires.
063 * <BR><BR>
064 * No request control is required to trigger the server to send the password
065 * expiring response control.  If the server supports the use of this control
066 * and the user's password will expire within a time frame that the server
067 * considers to be the near future, then it will be included in the bind
068 * response returned to the client.
069 * <BR><BR>
070 * See the documentation for the {@link PasswordExpiredControl} to see an
071 * example that demonstrates the use of both the password expiring and password
072 * expired controls.
073 */
074@NotMutable()
075@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
076public final class PasswordExpiringControl
077       extends Control
078       implements DecodeableControl
079{
080  /**
081   * The OID (2.16.840.1.113730.3.4.5) for the password expiring response
082   * control.
083   */
084  @NotNull public static final String PASSWORD_EXPIRING_OID =
085       "2.16.840.1.113730.3.4.5";
086
087
088
089  /**
090   * The serial version UID for this serializable class.
091   */
092  private static final long serialVersionUID = 1250220480854441338L;
093
094
095
096  // The length of time in seconds until the password expires.
097  private final int secondsUntilExpiration;
098
099
100
101  /**
102   * Creates a new empty control instance that is intended to be used only for
103   * decoding controls via the {@code DecodeableControl} interface.
104   */
105  PasswordExpiringControl()
106  {
107    secondsUntilExpiration = -1;
108  }
109
110
111
112  /**
113   * Creates a new password expiring control with the provided information.
114   *
115   * @param  secondsUntilExpiration  The length of time in seconds until the
116   *                                 password expires.
117   */
118  public PasswordExpiringControl(final int secondsUntilExpiration)
119  {
120    super(PASSWORD_EXPIRING_OID, false,
121          new ASN1OctetString(String.valueOf(secondsUntilExpiration)));
122
123    this.secondsUntilExpiration = secondsUntilExpiration;
124  }
125
126
127
128  /**
129   * Creates a new password expiring control with the provided information.
130   *
131   * @param  oid         The OID for the control.
132   * @param  isCritical  Indicates whether the control should be marked
133   *                     critical.
134   * @param  value       The encoded value for the control.  This may be
135   *                     {@code null} if no value was provided.
136   *
137   * @throws  LDAPException  If the provided control cannot be decoded as a
138   *                         password expiring response control.
139   */
140  public PasswordExpiringControl(@NotNull final String oid,
141                                 final boolean isCritical,
142                                 @Nullable final ASN1OctetString value)
143         throws LDAPException
144  {
145    super(oid, isCritical, value);
146
147    if (value == null)
148    {
149      throw new LDAPException(ResultCode.DECODING_ERROR,
150                              ERR_PW_EXPIRING_NO_VALUE.get());
151    }
152
153    try
154    {
155      secondsUntilExpiration = Integer.parseInt(value.stringValue());
156    }
157    catch (final NumberFormatException nfe)
158    {
159      Debug.debugException(nfe);
160      throw new LDAPException(ResultCode.DECODING_ERROR,
161                              ERR_PW_EXPIRING_VALUE_NOT_INTEGER.get(), nfe);
162    }
163  }
164
165
166
167  /**
168   * {@inheritDoc}
169   */
170  @Override()
171  @NotNull()
172  public PasswordExpiringControl decodeControl(
173              @NotNull final String oid, final boolean isCritical,
174              @Nullable final ASN1OctetString value)
175         throws LDAPException
176  {
177    return new PasswordExpiringControl(oid, isCritical, value);
178  }
179
180
181
182  /**
183   * Extracts a password expiring control from the provided result.
184   *
185   * @param  result  The result from which to retrieve the password expiring
186   *                 control.
187   *
188   * @return  The password expiring control contained in the provided result, or
189   *          {@code null} if the result did not contain a password expiring
190   *          control.
191   *
192   * @throws  LDAPException  If a problem is encountered while attempting to
193   *                         decode the password expiring control contained in
194   *                         the provided result.
195   */
196  @Nullable()
197  public static PasswordExpiringControl get(@NotNull final LDAPResult result)
198         throws LDAPException
199  {
200    final Control c = result.getResponseControl(PASSWORD_EXPIRING_OID);
201    if (c == null)
202    {
203      return null;
204    }
205
206    if (c instanceof PasswordExpiringControl)
207    {
208      return (PasswordExpiringControl) c;
209    }
210    else
211    {
212      return new PasswordExpiringControl(c.getOID(), c.isCritical(),
213           c.getValue());
214    }
215  }
216
217
218
219  /**
220   * Retrieves the length of time in seconds until the password expires.
221   *
222   * @return  The length of time in seconds until the password expires.
223   */
224  public int getSecondsUntilExpiration()
225  {
226    return secondsUntilExpiration;
227  }
228
229
230
231  /**
232   * {@inheritDoc}
233   */
234  @Override()
235  @NotNull()
236  public String getControlName()
237  {
238    return INFO_CONTROL_NAME_PW_EXPIRING.get();
239  }
240
241
242
243  /**
244   * {@inheritDoc}
245   */
246  @Override()
247  public void toString(@NotNull final StringBuilder buffer)
248  {
249    buffer.append("PasswordExpiringControl(secondsUntilExpiration=");
250    buffer.append(secondsUntilExpiration);
251    buffer.append(", isCritical=");
252    buffer.append(isCritical());
253    buffer.append(')');
254  }
255}