001/*
002 * Copyright 2015-2018 Ping Identity Corporation
003 * All Rights Reserved.
004 */
005/*
006 * Copyright (C) 2015-2018 Ping Identity Corporation
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 */
021package com.unboundid.ldap.sdk.unboundidds.extensions;
022
023
024
025import java.io.Serializable;
026import java.util.StringTokenizer;
027
028import com.unboundid.ldap.sdk.LDAPException;
029import com.unboundid.ldap.sdk.ResultCode;
030import com.unboundid.util.Debug;
031import com.unboundid.util.NotMutable;
032import com.unboundid.util.StaticUtils;
033import com.unboundid.util.ThreadSafety;
034import com.unboundid.util.ThreadSafetyLevel;
035import com.unboundid.util.Validator;
036
037import static com.unboundid.ldap.sdk.unboundidds.extensions.ExtOpMessages.*;
038
039
040
041/**
042 * This class defines a data structure that will provide information about
043 * errors that may affect an account's usability.  It includes a number of
044 * predefined error types, but also allows for the possibility of additional
045 * error types that have not been defined.
046 * <BR>
047 * <BLOCKQUOTE>
048 *   <B>NOTE:</B>  This class, and other classes within the
049 *   {@code com.unboundid.ldap.sdk.unboundidds} package structure, are only
050 *   supported for use against Ping Identity, UnboundID, and
051 *   Nokia/Alcatel-Lucent 8661 server products.  These classes provide support
052 *   for proprietary functionality or for external specifications that are not
053 *   considered stable or mature enough to be guaranteed to work in an
054 *   interoperable way with other types of LDAP servers.
055 * </BLOCKQUOTE>
056 */
057@NotMutable()
058@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
059public final class PasswordPolicyStateAccountUsabilityError
060       implements Serializable
061{
062  /**
063   * The numeric value for the error type that indicates the user's account is
064   * disabled.
065   */
066  public static final int ERROR_TYPE_ACCOUNT_DISABLED = 1;
067
068
069
070  /**
071   * The name for the error type that indicates the user's account is disabled.
072   */
073  public static final String ERROR_NAME_ACCOUNT_DISABLED = "account-disabled";
074
075
076
077  /**
078   * The numeric value for the error type that indicates the user's account is
079   * not yet active.
080   */
081  public static final int ERROR_TYPE_ACCOUNT_NOT_YET_ACTIVE = 2;
082
083
084
085  /**
086   * The name for the error type that indicates the user's account is not yet
087   * valid.
088   */
089  public static final String ERROR_NAME_ACCOUNT_NOT_YET_ACTIVE =
090       "account-not-yet-active";
091
092
093
094  /**
095   * The numeric value for the error type that indicates the user's account is
096   * expired.
097   */
098  public static final int ERROR_TYPE_ACCOUNT_EXPIRED = 3;
099
100
101
102  /**
103   * The name for the error type that indicates the user's account is expired.
104   */
105  public static final String ERROR_NAME_ACCOUNT_EXPIRED = "account-expired";
106
107
108
109  /**
110   * The numeric value for the error type that indicates the user's account is
111   * permanently locked (until the password is reset by an administrator) as a
112   * result of too many failed authentication attempts.
113   */
114  public static final int
115       ERROR_TYPE_ACCOUNT_PERMANENTLY_LOCKED_DUE_TO_BIND_FAILURES = 4;
116
117
118
119  /**
120   * The name for the error type that indicates the user's account is
121   * permanently locked (until the password is reset by an administrator) as a
122   * result of too many failed authentication attempts.
123   */
124  public static final String
125       ERROR_NAME_ACCOUNT_PERMANENTLY_LOCKED_DUE_TO_BIND_FAILURES =
126       "account-permanently-locked-due-to-bind-failures";
127
128
129
130  /**
131   * The numeric value for the error type that indicates the user's account is
132   * temporarily locked (until the lockout period elapses or the password is
133   * reset by an administrator) as a result of too many failed authentication
134   * attempts.
135   */
136  public static final int
137       ERROR_TYPE_ACCOUNT_TEMPORARILY_LOCKED_DUE_TO_BIND_FAILURES = 5;
138
139
140
141  /**
142   * The name for the error type that indicates the user's account is
143   * temporarily locked (until the lockout period elapses or the password is
144   * reset by an administrator) as a result of too many failed authentication
145   * attempts.
146   */
147  public static final String
148       ERROR_NAME_ACCOUNT_TEMPORARILY_LOCKED_DUE_TO_BIND_FAILURES =
149       "account-temporarily-locked-due-to-bind-failures";
150
151
152
153  /**
154   * The numeric value for the error type that indicates the user's account is
155   * locked (until the password is reset by an administrator) as a result of
156   * remaining idle for too long (i.e., it has been too long since the user last
157   * authenticated).
158   */
159  public static final int ERROR_TYPE_ACCOUNT_IDLE_LOCKED = 6;
160
161
162
163  /**
164   * The name for the error type that indicates the user's account is locked
165   * (until the password is reset by an administrator) as a result of remaining
166   * idle for too long (i.e., it has been too long since the user last
167   * authenticated).
168   */
169  public static final String ERROR_NAME_ACCOUNT_IDLE_LOCKED =
170       "account-idle-locked";
171
172
173
174  /**
175   * The numeric value for the error type that indicates the user's account is
176   * locked (until the password is reset by an administrator) as a result of
177   * failing to change the password in a timely manner after it was reset by an
178   * administrator.
179   */
180  public static final int ERROR_TYPE_ACCOUNT_RESET_LOCKED = 7;
181
182
183
184  /**
185   * The name for the error type that indicates the user's account is locked
186   * (until the password is reset by an administrator) as a result of failing to
187   * change the password in a timely manner after it was reset by an
188   * administrator.
189   */
190  public static final String ERROR_NAME_ACCOUNT_RESET_LOCKED =
191       "account-reset-locked";
192
193
194
195  /**
196   * The numeric value for the error type that indicates the user's password
197   * is expired.
198   */
199  public static final int ERROR_TYPE_PASSWORD_EXPIRED = 8;
200
201
202
203  /**
204   * The name for the error type that indicates the user's password is expired.
205   */
206  public static final String ERROR_NAME_PASSWORD_EXPIRED = "password-expired";
207
208
209
210  /**
211   * The numeric value for the error type that indicates the user's account is
212   * locked (until the password is reset by an administrator) as a result of
213   * failing to change the password by a required time.
214   */
215  public static final int ERROR_TYPE_PASSWORD_NOT_CHANGED_BY_REQUIRED_TIME = 9;
216
217
218
219  /**
220   * The name for the error type that indicates the user's account is locked
221   * (until the password is reset by an administrator) as a result of failing to
222   * change the password by a required time.
223   */
224  public static final  String ERROR_NAME_PASSWORD_NOT_CHANGED_BY_REQUIRED_TIME =
225       "password-not-changed-by-required-time";
226
227
228
229  /**
230   * The numeric value for the warning type that indicates the user's password
231   * has expired, but the user has one or more grace logins remaining.  The
232   * user may still authenticate with a grace login, but will not be permitted
233   * to submit any other requests until changing the password.
234   */
235  public static final int ERROR_TYPE_PASSWORD_EXPIRED_WITH_GRACE_LOGINS = 10;
236
237
238
239  /**
240   * The name for the warning type that indicates the user's password has
241   * expired, but the user has one or more grace logins remaining.  The user may
242   * still authenticate with a grace login, but will not be permitted to submit
243   * any other requests until changing the password.
244   */
245  public static final String ERROR_NAME_PASSWORD_EXPIRED_WITH_GRACE_LOGINS =
246       "password-expired-with-grace-logins";
247
248
249
250  /**
251   * The numeric value for the warning type that indicates the user must change
252   * their password after an administrative reset (or for a newly-created
253   * account) before they will be submit any requests.  The user's account may
254   * be locked if they do not change their password in a timely manner.
255   */
256  public static final int ERROR_TYPE_MUST_CHANGE_PASSWORD = 11;
257
258
259
260  /**
261   * The name for the warning type that indicates the user must change their
262   * password after an administrative reset (or for a newly-created account)
263   * before they will be submit any requests.  The user's account may be locked
264   * if they do not change their password in a timely manner.
265   */
266  public static final String ERROR_NAME_MUST_CHANGE_PASSWORD =
267       "must-change-password";
268
269
270
271  /**
272   * The serial version UID for this serializable class.
273   */
274  private static final long serialVersionUID = -2482863468368980580L;
275
276
277
278  // The integer value for this account usability error.
279  private final int intValue;
280
281  // A human-readable message that provides specific details about this account
282  // usability error.
283  private final String message;
284
285  // The name for this account usability error.
286  private final String name;
287
288  // The encoded string representation for this account usability error.
289  private final String stringRepresentation;
290
291
292
293  /**
294   * Creates a new account usability error with the provided information.
295   *
296   * @param  intValue  The integer value for this account usability error.
297   * @param  name      The name for this account usability error.  It must not
298   *                   be {@code null}.
299   * @param  message   A human-readable message that provides specific details
300   *                   about this account usability error.  It may be
301   *                   {@code null} if no message is available.
302   */
303  public PasswordPolicyStateAccountUsabilityError(final int intValue,
304                                                  final String name,
305                                                  final String message)
306  {
307    Validator.ensureNotNull(name);
308
309    this.intValue = intValue;
310    this.name = name;
311    this.message = message;
312
313    final StringBuilder buffer = new StringBuilder();
314    buffer.append("code=");
315    buffer.append(intValue);
316    buffer.append("\tname=");
317    buffer.append(name);
318
319    if (message != null)
320    {
321      buffer.append("\tmessage=");
322      buffer.append(message);
323    }
324
325    stringRepresentation = buffer.toString();
326  }
327
328
329
330  /**
331   * Creates a new account usability error that is decoded from the provided
332   * string representation.
333   *
334   * @param  stringRepresentation  The string representation of the account
335   *                               usability error to decode.  It must not be
336   *                               {@code null}.
337   *
338   * @throws  LDAPException  If the provided string cannot be decoded as a valid
339   *                         account usability error.
340   */
341  public PasswordPolicyStateAccountUsabilityError(
342              final String stringRepresentation)
343         throws LDAPException
344  {
345    this.stringRepresentation = stringRepresentation;
346
347    try
348    {
349      Integer i = null;
350      String  n = null;
351      String  m = null;
352
353      final StringTokenizer tokenizer =
354           new StringTokenizer(stringRepresentation, "\t");
355      while (tokenizer.hasMoreTokens())
356      {
357        final String token = tokenizer.nextToken();
358        final int equalPos = token.indexOf('=');
359        final String fieldName = token.substring(0, equalPos);
360        final String fieldValue = token.substring(equalPos+1);
361        if (fieldName.equals("code"))
362        {
363          i = Integer.valueOf(fieldValue);
364        }
365        else if (fieldName.equals("name"))
366        {
367          n = fieldValue;
368        }
369        else if (fieldName.equals("message"))
370        {
371          m = fieldValue;
372        }
373      }
374
375      if (i == null)
376      {
377        throw new LDAPException(ResultCode.DECODING_ERROR,
378             ERR_PWP_STATE_ACCOUNT_USABILITY_ERROR_CANNOT_DECODE.get(
379                  stringRepresentation,
380                  ERR_PWP_STATE_ACCOUNT_USABILITY_ERROR_NO_CODE.get()));
381      }
382
383      if (n == null)
384      {
385        throw new LDAPException(ResultCode.DECODING_ERROR,
386             ERR_PWP_STATE_ACCOUNT_USABILITY_ERROR_CANNOT_DECODE.get(
387                  stringRepresentation,
388                  ERR_PWP_STATE_ACCOUNT_USABILITY_ERROR_NO_NAME.get()));
389      }
390
391      intValue = i;
392      name     = n;
393      message  = m;
394    }
395    catch (final LDAPException le)
396    {
397      Debug.debugException(le);
398
399      throw le;
400    }
401    catch (final Exception e)
402    {
403      Debug.debugException(e);
404
405      throw new LDAPException(ResultCode.DECODING_ERROR,
406           ERR_PWP_STATE_ACCOUNT_USABILITY_ERROR_CANNOT_DECODE.get(
407                stringRepresentation, StaticUtils.getExceptionMessage(e)),
408           e);
409    }
410  }
411
412
413
414  /**
415   * Retrieves the integer value for this account usability error.
416   *
417   * @return  The integer value for this account usability error.
418   */
419  public int getIntValue()
420  {
421    return intValue;
422  }
423
424
425
426  /**
427   * Retrieves the name for this account usability error.
428   *
429   * @return  The name for this account usability error.
430   */
431  public String getName()
432  {
433    return name;
434  }
435
436
437
438  /**
439   * Retrieves a human-readable message that provides specific details about
440   * this account usability error.
441   *
442   * @return  A human-readable message that provides specific details about this
443   *          account usability error, or {@code null} if no message is
444   *          available.
445   */
446  public String getMessage()
447  {
448    return message;
449  }
450
451
452
453  /**
454   * Retrieves a string representation of this account usability error.
455   *
456   * @return  A string representation of this account usability error.
457   */
458  @Override()
459  public String toString()
460  {
461    return stringRepresentation;
462  }
463}