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 * warnings that may affect an account's usability.  It includes a number of
061 * predefined warning types, but also allows for the possibility of additional
062 * warning types that have not been defined.
063 * <BR>
064 * <BLOCKQUOTE>
065 *   <B>NOTE:</B>  This class, and other classes within the
066 *   {@code com.unboundid.ldap.sdk.unboundidds} package structure, are only
067 *   supported for use against Ping Identity, UnboundID, and
068 *   Nokia/Alcatel-Lucent 8661 server products.  These classes provide support
069 *   for proprietary functionality or for external specifications that are not
070 *   considered stable or mature enough to be guaranteed to work in an
071 *   interoperable way with other types of LDAP servers.
072 * </BLOCKQUOTE>
073 */
074@NotMutable()
075@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
076public final class PasswordPolicyStateAccountUsabilityWarning
077       implements Serializable
078{
079  /**
080   * The numeric value for the warning type that indicates the user's account is
081   * about to expire.
082   */
083  public static final int WARNING_TYPE_ACCOUNT_EXPIRING = 1;
084
085
086
087  /**
088   * The name for the warning type that indicates the user's account is about
089   * to expire.
090   */
091  @NotNull public static final String WARNING_NAME_ACCOUNT_EXPIRING =
092       "account-expiring";
093
094
095
096  /**
097   * The numeric value for the warning type that indicates the user's password
098   * is about to expire.
099   */
100  public static final int WARNING_TYPE_PASSWORD_EXPIRING = 2;
101
102
103
104  /**
105   * The name for the warning type that indicates the user's password is about
106   * to expire.
107   */
108  @NotNull public static final String WARNING_NAME_PASSWORD_EXPIRING =
109       "password-expiring";
110
111
112
113  /**
114   * The numeric value for the warning type that indicates the user has one or
115   * more failed authentication attempts since the last successful bind, and
116   * that the account may be locked if there are too many more failures.
117   */
118  public static final int WARNING_TYPE_OUTSTANDING_BIND_FAILURES = 3;
119
120
121
122  /**
123   * The name for the warning type that indicates the user has one or more
124   * failed authentication attempts since the last successful bind, and that the
125   * account may be locked if there are too many more failures.
126   */
127  @NotNull public static final String WARNING_NAME_OUTSTANDING_BIND_FAILURES =
128       "outstanding-bind-failures";
129
130
131
132  /**
133   * The numeric value for the warning type that indicates the user has not
134   * authenticated in some time, and the account may be locked in the near
135   * future if it remains idle.
136   */
137  public static final int WARNING_TYPE_ACCOUNT_IDLE = 4;
138
139
140
141  /**
142   * The name for the warning type that indicates the user has not authenticated
143   * in some time, and the account may be locked in the near future if it
144   * remains idle.
145   */
146  @NotNull public static final String WARNING_NAME_ACCOUNT_IDLE =
147       "account-idle";
148
149
150
151  /**
152   * The numeric value for the warning type that indicates the user will be
153   * required to change his/her password by a specific time because the password
154   * policy requires all users to change their passwords by that time.
155   */
156  public static final int WARNING_TYPE_REQUIRE_PASSWORD_CHANGE_BY_TIME = 5;
157
158
159
160  /**
161   * The name for the warning type that indicates the user user will be required
162   * to change his/her password by a specific time because the password policy
163   * requires all users to change their passwords by that time.
164   */
165  @NotNull public static final String
166       WARNING_NAME_REQUIRE_PASSWORD_CHANGE_BY_TIME =
167            "require-password-change-by-time";
168
169
170
171  /**
172   * The numeric value for the warning type that indicates that although the
173   * user's account should be locked as a result of too many outstanding
174   * failed authentication attempts, their password policy is configured with a
175   * failure lockout action that will not prevent them from authenticating
176   * (although it may still have an effect on their account's usability).
177   */
178  public static final int WARNING_TYPE_TOO_MANY_OUTSTANDING_BIND_FAILURES = 6;
179
180
181
182  /**
183   * The name for the warning type that indicates that although the user's
184   * account should be locked as a result of too many outstanding failed
185   * authentication attempts, their password policy is configured with a failure
186   * lockout action that will not prevent them from authenticating (although it
187   * may still have an effect on their account's usability).
188   */
189  @NotNull public static final String
190       WARNING_NAME_TOO_MANY_OUTSTANDING_BIND_FAILURES =
191            "too-many-outstanding-bind-failures";
192
193
194
195  /**
196   * The numeric value for the warning type that indicates that the user's
197   * account has a password that is encoded with a deprecated password storage
198   * scheme.
199   */
200  public static final int WARNING_TYPE_DEPRECATED_PASSWORD_STORAGE_SCHEME = 7;
201
202
203
204  /**
205   * The numeric value for the warning type that indicates that the user's
206   * account has a password that is encoded with a deprecated password storage
207   * scheme.
208   */
209  @NotNull public static final String
210       WARNING_NAME_DEPRECATED_PASSWORD_STORAGE_SCHEME =
211            "deprecated-password-storage-scheme";
212
213
214
215  /**
216   * The serial version UID for this serializable class.
217   */
218  private static final long serialVersionUID = -8585936121537239716L;
219
220
221
222  // The integer value for this account usability warning.
223  private final int intValue;
224
225  // A human-readable message that provides specific details about this account
226  // usability warning.
227  @Nullable private final String message;
228
229  // The name for this account usability warning.
230  @NotNull private final String name;
231
232  // The encoded string representation for this account usability warning.
233  @NotNull private final String stringRepresentation;
234
235
236
237  /**
238   * Creates a new account usability warning with the provided information.
239   *
240   * @param  intValue  The integer value for this account usability warning.
241   * @param  name      The name for this account usability warning.  It must not
242   *                   be {@code null}.
243   * @param  message   A human-readable message that provides specific details
244   *                   about this account usability warning.  It may be
245   *                   {@code null} if no message is available.
246   */
247  public PasswordPolicyStateAccountUsabilityWarning(final int intValue,
248              @NotNull final String name,
249              @Nullable final String message)
250  {
251    Validator.ensureNotNull(name);
252
253    this.intValue = intValue;
254    this.name = name;
255    this.message = message;
256
257    final StringBuilder buffer = new StringBuilder();
258    buffer.append("code=");
259    buffer.append(intValue);
260    buffer.append("\tname=");
261    buffer.append(name);
262
263    if (message != null)
264    {
265      buffer.append("\tmessage=");
266      buffer.append(message);
267    }
268
269    stringRepresentation = buffer.toString();
270  }
271
272
273
274  /**
275   * Creates a new account usability warning that is decoded from the provided
276   * string representation.
277   *
278   * @param  stringRepresentation  The string representation of the account
279   *                               usability warning to decode.  It must not be
280   *                               {@code null}.
281   *
282   * @throws  LDAPException  If the provided string cannot be decoded as a valid
283   *                         account usability warning.
284   */
285  public PasswordPolicyStateAccountUsabilityWarning(
286              @NotNull final String stringRepresentation)
287         throws LDAPException
288  {
289    this.stringRepresentation = stringRepresentation;
290
291    try
292    {
293      Integer i = null;
294      String  n = null;
295      String  m = null;
296
297      final StringTokenizer tokenizer =
298           new StringTokenizer(stringRepresentation, "\t");
299      while (tokenizer.hasMoreTokens())
300      {
301        final String token = tokenizer.nextToken();
302        final int equalPos = token.indexOf('=');
303        final String fieldName = token.substring(0, equalPos);
304        final String fieldValue = token.substring(equalPos+1);
305        if (fieldName.equals("code"))
306        {
307          i = Integer.valueOf(fieldValue);
308        }
309        else if (fieldName.equals("name"))
310        {
311          n = fieldValue;
312        }
313        else if (fieldName.equals("message"))
314        {
315          m = fieldValue;
316        }
317      }
318
319      if (i == null)
320      {
321        throw new LDAPException(ResultCode.DECODING_ERROR,
322             ERR_PWP_STATE_ACCOUNT_USABILITY_WARNING_CANNOT_DECODE.get(
323                  stringRepresentation,
324                  ERR_PWP_STATE_ACCOUNT_USABILITY_WARNING_NO_CODE.get()));
325      }
326
327      if (n == null)
328      {
329        throw new LDAPException(ResultCode.DECODING_ERROR,
330             ERR_PWP_STATE_ACCOUNT_USABILITY_WARNING_CANNOT_DECODE.get(
331                  stringRepresentation,
332                  ERR_PWP_STATE_ACCOUNT_USABILITY_WARNING_NO_NAME.get()));
333      }
334
335      intValue = i;
336      name     = n;
337      message  = m;
338    }
339    catch (final LDAPException le)
340    {
341      Debug.debugException(le);
342
343      throw le;
344    }
345    catch (final Exception e)
346    {
347      Debug.debugException(e);
348
349      throw new LDAPException(ResultCode.DECODING_ERROR,
350           ERR_PWP_STATE_ACCOUNT_USABILITY_WARNING_CANNOT_DECODE.get(
351                stringRepresentation, StaticUtils.getExceptionMessage(e)),
352           e);
353    }
354  }
355
356
357
358  /**
359   * Retrieves the integer value for this account usability warning.
360   *
361   * @return  The integer value for this account usability warning.
362   */
363  public int getIntValue()
364  {
365    return intValue;
366  }
367
368
369
370  /**
371   * Retrieves the name for this account usability warning.
372   *
373   * @return  The name for this account usability warning.
374   */
375  @NotNull()
376  public String getName()
377  {
378    return name;
379  }
380
381
382
383  /**
384   * Retrieves a human-readable message that provides specific details about
385   * this account usability warning.
386   *
387   * @return  A human-readable message that provides specific details about this
388   *          account usability warning, or {@code null} if no message is
389   *          available.
390   */
391  @Nullable()
392  public String getMessage()
393  {
394    return message;
395  }
396
397
398
399  /**
400   * Retrieves a string representation of this account usability warning.
401   *
402   * @return  A string representation of this account usability warning.
403   */
404  @Override()
405  @NotNull()
406  public String toString()
407  {
408    return stringRepresentation;
409  }
410}