001/*
002 * Copyright 2015-2024 Ping Identity Corporation
003 * All Rights Reserved.
004 */
005/*
006 * Copyright 2015-2024 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) 2015-2024 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.unboundidds.extensions;
037
038
039
040import java.io.Serializable;
041import java.util.StringTokenizer;
042
043import com.unboundid.ldap.sdk.LDAPException;
044import com.unboundid.ldap.sdk.ResultCode;
045import com.unboundid.util.Debug;
046import com.unboundid.util.NotMutable;
047import com.unboundid.util.NotNull;
048import com.unboundid.util.Nullable;
049import com.unboundid.util.StaticUtils;
050import com.unboundid.util.ThreadSafety;
051import com.unboundid.util.ThreadSafetyLevel;
052import com.unboundid.util.Validator;
053
054import static com.unboundid.ldap.sdk.unboundidds.extensions.ExtOpMessages.*;
055
056
057
058/**
059 * This class defines a data structure that will provide information about
060 * notices pertaining to a user's password policy state (items that might be
061 * of interest, but do not necessarily represent a current or imminent problem
062 * with the account).  It includes a number of predefined notice types, but also
063 * allows for the possibility of additional notice types that have not been
064 * defined.
065 * <BR>
066 * <BLOCKQUOTE>
067 *   <B>NOTE:</B>  This class, and other classes within the
068 *   {@code com.unboundid.ldap.sdk.unboundidds} package structure, are only
069 *   supported for use against Ping Identity, UnboundID, and
070 *   Nokia/Alcatel-Lucent 8661 server products.  These classes provide support
071 *   for proprietary functionality or for external specifications that are not
072 *   considered stable or mature enough to be guaranteed to work in an
073 *   interoperable way with other types of LDAP servers.
074 * </BLOCKQUOTE>
075 */
076@NotMutable()
077@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
078public final class PasswordPolicyStateAccountUsabilityNotice
079       implements Serializable
080{
081  /**
082   * The numeric value for the notice type that indicates the user has a valid
083   * outstanding retired password.
084   */
085  public static final int NOTICE_TYPE_OUTSTANDING_RETIRED_PASSWORD = 1;
086
087
088
089  /**
090   * The name for the notice type that indicates the user user has a valid
091   * outstanding retired password.
092   */
093  @NotNull public static final String NOTICE_NAME_OUTSTANDING_RETIRED_PASSWORD =
094       "outstanding-retired-password";
095
096
097
098  /**
099   * The numeric value for the notice type that indicates the user has a valid
100   * outstanding one-time password.
101   */
102  public static final int NOTICE_TYPE_OUTSTANDING_ONE_TIME_PASSWORD = 2;
103
104
105
106  /**
107   * The name for the notice type that indicates the user has a valid
108   * outstanding one-time password.
109   */
110  @NotNull public static final String
111       NOTICE_NAME_OUTSTANDING_ONE_TIME_PASSWORD =
112            "outstanding-one-time-password";
113
114
115
116  /**
117   * The numeric value for the notice type that indicates the user has a valid
118   * outstanding password reset token.
119   */
120  public static final int NOTICE_TYPE_OUTSTANDING_PASSWORD_RESET_TOKEN = 3;
121
122
123
124  /**
125   * The name for the notice type that indicates the user has a valid
126   * outstanding password reset token that will expire in the near future.
127   */
128  @NotNull public static final String
129       NOTICE_NAME_OUTSTANDING_PASSWORD_RESET_TOKEN =
130            "outstanding-password-reset-token";
131
132
133
134  /**
135   * The numeric value for the notice type that indicates the user is not
136   * currently allowed to change his/her password because they are within the
137   * minimum password age.
138   */
139  public static final int NOTICE_TYPE_IN_MINIMUM_PASSWORD_AGE = 4;
140
141
142
143  /**
144   * The name for the notice type that indicates the user is not currently
145   * allowed to change his/her password because they are within the minimum
146   * password age.
147   */
148  @NotNull public static final String NOTICE_NAME_IN_MINIMUM_PASSWORD_AGE =
149       "in-minimum-password-age";
150
151
152
153  /**
154   * The numeric value for the notice type that indicates that the user does not
155   * have a static password.
156   */
157  public static final int NOTICE_TYPE_NO_STATIC_PASSWORD = 5;
158
159
160
161  /**
162   * The name for the notice type that indicates that the user does not have a
163   * static password.
164   */
165  @NotNull public static final  String NOTICE_NAME_NO_STATIC_PASSWORD =
166       "no-static-password";
167
168
169
170  /**
171   * The numeric value for the notice type that indicates that although the
172   * user's account should be locked as a result of too many outstanding
173   * failed authentication attempts, their password policy is configured with a
174   * failure lockout action that will not prevent them from authenticating, and
175   * should not otherwise have an effect on the usability of their account.
176   */
177  public static final int NOTICE_TYPE_TOO_MANY_OUTSTANDING_BIND_FAILURES = 6;
178
179
180
181  /**
182   * The name for the warning type that indicates that although the user's
183   * account should be locked as a result of too many outstanding failed
184   * authentication attempts, their password policy is configured with a failure
185   * lockout action that will not prevent them from authenticating, and should
186   * not otherwise have an effect on the usability of their account.
187   */
188  @NotNull public static final String
189       NOTICE_NAME_TOO_MANY_OUTSTANDING_BIND_FAILURES =
190            "too-many-outstanding-bind-failures";
191
192
193
194  /**
195   * The serial version UID for this serializable class.
196   */
197  private static final long serialVersionUID = 6147730018701385799L;
198
199
200
201  // The integer value for this account usability notice.
202  private final int intValue;
203
204  // A human-readable message that provides specific details about this account
205  // usability notice.
206  @Nullable private final String message;
207
208  // The name for this account usability notice.
209  @NotNull private final String name;
210
211  // The encoded string representation for this account usability notice.
212  @NotNull private final String stringRepresentation;
213
214
215
216  /**
217   * Creates a new account usability notice with the provided information.
218   *
219   * @param  intValue  The integer value for this account usability notice.
220   * @param  name      The name for this account usability notice.  It must not
221   *                   be {@code null}.
222   * @param  message   A human-readable message that provides specific details
223   *                   about this account usability notice.  It may be
224   *                   {@code null} if no message is available.
225   */
226  public PasswordPolicyStateAccountUsabilityNotice(final int intValue,
227              @NotNull final String name,
228              @Nullable final String message)
229  {
230    Validator.ensureNotNull(name);
231
232    this.intValue = intValue;
233    this.name = name;
234    this.message = message;
235
236    final StringBuilder buffer = new StringBuilder();
237    buffer.append("code=");
238    buffer.append(intValue);
239    buffer.append("\tname=");
240    buffer.append(name);
241
242    if (message != null)
243    {
244      buffer.append("\tmessage=");
245      buffer.append(message);
246    }
247
248    stringRepresentation = buffer.toString();
249  }
250
251
252
253  /**
254   * Creates a new account usability notice that is decoded from the provided
255   * string representation.
256   *
257   * @param  stringRepresentation  The string representation of the account
258   *                               usability notice to decode.  It must not be
259   *                               {@code null}.
260   *
261   * @throws LDAPException  If the provided string cannot be decoded as a valid
262   *                         account usability notice.
263   */
264  public PasswordPolicyStateAccountUsabilityNotice(
265              @NotNull final String stringRepresentation)
266         throws LDAPException
267  {
268    this.stringRepresentation = stringRepresentation;
269
270    try
271    {
272      Integer i = null;
273      String n = null;
274      String m = null;
275
276      final StringTokenizer tokenizer =
277           new StringTokenizer(stringRepresentation, "\t");
278      while (tokenizer.hasMoreTokens())
279      {
280        final String token = tokenizer.nextToken();
281        final int equalPos = token.indexOf('=');
282        final String fieldName = token.substring(0, equalPos);
283        final String fieldValue = token.substring(equalPos+1);
284        if (fieldName.equals("code"))
285        {
286          i = Integer.valueOf(fieldValue);
287        }
288        else if (fieldName.equals("name"))
289        {
290          n = fieldValue;
291        }
292        else if (fieldName.equals("message"))
293        {
294          m = fieldValue;
295        }
296      }
297
298      if (i == null)
299      {
300        throw new LDAPException(ResultCode.DECODING_ERROR,
301             ERR_PWP_STATE_ACCOUNT_USABILITY_NOTICE_CANNOT_DECODE.get(
302                  stringRepresentation,
303                  ERR_PWP_STATE_ACCOUNT_USABILITY_NOTICE_NO_CODE.get()));
304      }
305
306      if (n == null)
307      {
308        throw new LDAPException(ResultCode.DECODING_ERROR,
309             ERR_PWP_STATE_ACCOUNT_USABILITY_NOTICE_CANNOT_DECODE.get(
310                  stringRepresentation,
311                  ERR_PWP_STATE_ACCOUNT_USABILITY_NOTICE_NO_NAME.get()));
312      }
313
314      intValue = i;
315      name     = n;
316      message  = m;
317    }
318    catch (final LDAPException le)
319    {
320      Debug.debugException(le);
321
322      throw le;
323    }
324    catch (final Exception e)
325    {
326      Debug.debugException(e);
327
328      throw new LDAPException(ResultCode.DECODING_ERROR,
329           ERR_PWP_STATE_ACCOUNT_USABILITY_NOTICE_CANNOT_DECODE.get(
330                stringRepresentation, StaticUtils.getExceptionMessage(e)),
331           e);
332    }
333  }
334
335
336
337  /**
338   * Retrieves the integer value for this account usability notice.
339   *
340   * @return  The integer value for this account usability notice.
341   */
342  public int getIntValue()
343  {
344    return intValue;
345  }
346
347
348
349  /**
350   * Retrieves the name for this account usability notice.
351   *
352   * @return  The name for this account usability notice.
353   */
354  @NotNull()
355  public String getName()
356  {
357    return name;
358  }
359
360
361
362  /**
363   * Retrieves a human-readable message that provides specific details about
364   * this account usability notice.
365   *
366   * @return  A human-readable message that provides specific details about this
367   *          account usability notice, or {@code null} if no message is
368   *          available.
369   */
370  @Nullable()
371  public String getMessage()
372  {
373    return message;
374  }
375
376
377
378  /**
379   * Retrieves a string representation of this account usability notice.
380   *
381   * @return  A string representation of this account usability notice.
382   */
383  @Override()
384  @NotNull()
385  public String toString()
386  {
387    return stringRepresentation;
388  }
389}