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