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.controls;
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.controls.ControlMessages.*;
055
056
057
058/**
059 * This class defines a data structure that will provide information about
060 * errors that could cause an authentication attempt to fail.  It includes a
061 * number of predefined failure types, but also allows for the possibility of
062 * additional failure 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 AuthenticationFailureReason
077       implements Serializable
078{
079  /**
080   * The numeric value for the failure type that indicates the user's account
081   * is not in a usable state.  Examining the set of account usability errors
082   * should provide more specific information about the nature of the error.
083   */
084  public static final int FAILURE_TYPE_ACCOUNT_NOT_USABLE = 1;
085
086
087
088  /**
089   * The name for the failure type that indicates the user's account is not in a
090   * usable state.  Examining the set of account usability errors should provide
091   * more specific information about the nature of the error.
092   */
093  @NotNull public static final String FAILURE_NAME_ACCOUNT_NOT_USABLE =
094       "account-not-usable";
095
096
097
098  /**
099   * The numeric value for the failure type that indicates that the server was
100   * unable to assign a client connection policy for the user.
101   */
102  public static final int FAILURE_TYPE_CANNOT_ASSIGN_CLIENT_CONNECTION_POLICY =
103       3;
104
105
106
107  /**
108   * The name for the failure type that indicates that the server was unable to
109   * assign a client connection policy for the user.
110   */
111  @NotNull public static final String
112       FAILURE_NAME_CANNOT_ASSIGN_CLIENT_CONNECTION_POLICY =
113       "cannot-assign-client-connection-policy";
114
115
116
117  /**
118   * The numeric value for the failure type that indicates that the server was
119   * unable to identify the user specified as the authentication or
120   * authorization identity.
121   */
122  public static final int FAILURE_TYPE_CANNOT_IDENTIFY_USER = 4;
123
124
125
126  /**
127   * The numeric value for the failure type that indicates that the server was
128   * unable to identify the user specified as the authentication or
129   * authorization identity.
130   */
131  @NotNull public static final String FAILURE_NAME_CANNOT_IDENTIFY_USER =
132       "cannot-identify-user";
133
134
135
136  /**
137   * The numeric value for the failure type that indicates that bind was not
138   * permitted by some constraint defined in the server (password policy,
139   * client connection policy, operational attributes in the user entry, etc.).
140   */
141  public static final int FAILURE_TYPE_CONSTRAINT_VIOLATION = 5;
142
143
144
145  /**
146   * The name for the failure type that indicates that bind was not permitted by
147   * some constraint defined in the server (password policy, client connection
148   * policy, operational attributes in the user entry, etc.).
149   */
150  @NotNull public static final String FAILURE_NAME_CONSTRAINT_VIOLATION =
151       "constraint-violation";
152
153
154
155  /**
156   * The numeric value for the failure type that indicates that there was a
157   * problem with a control included in the bind request.
158   */
159  public static final int FAILURE_TYPE_CONTROL_PROBLEM = 6;
160
161
162
163  /**
164   * The name for the failure type that indicates that there was a problem with
165   * a control included in the bind request.
166   */
167  @NotNull public static final String FAILURE_NAME_CONTROL_PROBLEM =
168       "control-problem";
169
170
171
172  /**
173   * The numeric value for the failure type that indicates that there was a
174   * problem with the SASL credentials provided to the server (e.g., they were
175   * malformed, out of sequence, or otherwise invalid).
176   */
177  public static final int FAILURE_TYPE_IMPROPER_SASL_CREDENTIALS = 7;
178
179
180
181  /**
182   * The name for the failure type that indicates that there was a problem with
183   * the SASL credentials provided to the server (e.g., they were malformed, out
184   * of sequence, or otherwise invalid).
185   */
186  @NotNull public static final String FAILURE_NAME_IMPROPER_SASL_CREDENTIALS =
187       "improper-sasl-credentials";
188
189
190
191  /**
192   * The numeric value for the failure type that indicates that the bind was
193   * not permitted by the server's access control configuration.
194   */
195  public static final int FAILURE_TYPE_INSUFFICIENT_ACCESS_RIGHTS = 8;
196
197
198
199  /**
200   * The name for the failure type that indicates that the bind was not
201   * permitted by the server's access control configuration.
202   */
203  @NotNull public static final String FAILURE_NAME_INSUFFICIENT_ACCESS_RIGHTS =
204       "insufficient-access-rights";
205
206
207
208  /**
209   * The numeric value for the failure type that indicates that the user
210   * provided an incorrect password or other form of invalid credentials.
211   */
212  public static final int FAILURE_TYPE_INVALID_CREDENTIALS = 9;
213
214
215
216  /**
217   * The name for the failure type that indicates that the user provided an
218   * incorrect password or other form of invalid credentials.
219   */
220  @NotNull public static final String FAILURE_NAME_INVALID_CREDENTIALS =
221       "invalid-credentials";
222
223
224
225  /**
226   * The numeric value for the failure type that indicates that the server is in
227   * lockdown mode and will only permit authentication for a limited set of
228   * administrators.
229   */
230  public static final int FAILURE_TYPE_LOCKDOWN_MODE = 10;
231
232
233
234  /**
235   * The name for the failure type that indicates that the server is in lockdown
236   * mode and will only permit authentication for a limited set of
237   * administrators.
238   */
239  @NotNull public static final String FAILURE_NAME_LOCKDOWN_MODE =
240       "lockdown-mode";
241
242
243
244  /**
245   * The numeric value for the failure type that indicates that the user will
246   * only be permitted to authenticate in a secure manner.
247   */
248  public static final int FAILURE_TYPE_SECURE_AUTHENTICATION_REQUIRED = 11;
249
250
251
252  /**
253   * The name for the failure type that indicates that the user will only be
254   * permitted to authenticate in a secure manner.
255   */
256  @NotNull public static final String
257       FAILURE_NAME_SECURE_AUTHENTICATION_REQUIRED =
258            "secure-authentication-required";
259
260
261
262  /**
263   * The numeric value for the failure type that indicates that a server error
264   * occurred while processing the bind operation.
265   */
266  public static final int FAILURE_TYPE_SERVER_ERROR = 12;
267
268
269
270  /**
271   * The name for the failure type that indicates that a server error occurred
272   * while processing the bind operation.
273   */
274  @NotNull public static final String FAILURE_NAME_SERVER_ERROR =
275       "server-error";
276
277
278
279  /**
280   * The numeric value for the failure type that indicates that a third-party
281   * SASL mechanism handler failed to authenticate the user.
282   */
283  public static final int FAILURE_TYPE_THIRD_PARTY_SASL_AUTHENTICATION_FAILURE =
284       13;
285
286
287
288  /**
289   * The name for the failure type that indicates that a third-party SASL
290   * mechanism handler failed to authenticate the user.
291   */
292  @NotNull public static final String
293       FAILURE_NAME_THIRD_PARTY_SASL_AUTHENTICATION_FAILURE =
294            "third-party-sasl-authentication-failure";
295
296
297
298  /**
299   * The numeric value for the failure type that indicates that the attempted
300   * authentication type is not available for the target user.
301   */
302  public static final int FAILURE_TYPE_UNAVAILABLE_AUTHENTICATION_TYPE = 14;
303
304
305
306  /**
307   * The name for the failure type that indicates that the attempted
308   * authentication type is not available for the target user.
309   */
310  @NotNull public static final  String
311       FAILURE_NAME_UNAVAILABLE_AUTHENTICATION_TYPE =
312            "unavailable-authentication-type";
313
314
315
316  /**
317   * The numeric value for a failure type that does not fit into any other of
318   * the defined failure types.
319   */
320  public static final int FAILURE_TYPE_OTHER = 15;
321
322
323
324  /**
325   * The name for a failure type that does not fit into any other of the defined
326   * failure types.
327   */
328  @NotNull public static final String FAILURE_NAME_OTHER = "other";
329
330
331
332  /**
333   * The numeric value for the failure type that indicates that the bind request
334   * used a password that did not satisfy the configured set of password
335   * validators.
336   */
337  public static final int FAILURE_TYPE_PASSWORD_FAILED_VALIDATION = 16;
338
339
340
341  /**
342   * The name for the failure type that indicates that the bind request used a
343   * password that did not satisfy the configured set of password validators.
344   */
345  @NotNull public static final String FAILURE_NAME_PASSWORD_FAILED_VALIDATION =
346       "password-failed-validation";
347
348
349
350  /**
351   * The numeric value for the failure type that indicates that a
352   * security-related problem was encountered while processing the bind
353   * operation.
354   */
355  public static final int FAILURE_TYPE_SECURITY_PROBLEM = 17;
356
357
358
359  /**
360   * The name for the failure type that indicates that the bind request used a
361   * security-related problem was encountered while processing the bind
362   * operation.
363   */
364  @NotNull public static final String FAILURE_NAME_SECURITY_PROBLEM =
365       "security-problem";
366
367
368
369  /**
370   * The numeric value for the failure type that indicates that a pass-through
371   * authentication attempt failed.
372   */
373  public static final int FAILURE_TYPE_PASS_THROUGH_AUTH_FAILURE = 18;
374
375
376
377  /**
378   * The name for the failure type that indicates that a pass-through
379   * authentication attempt failed.
380   */
381  @NotNull public static final String FAILURE_NAME_PASS_THROUGH_AUTH_FAILURE =
382       "pass-through-authentication-failure";
383
384
385
386  /**
387   * The serial version UID for this serializable class.
388   */
389  private static final long serialVersionUID = 534691737103560809L;
390
391
392
393  // The integer value for this account usability error.
394  private final int intValue;
395
396  // A human-readable message that provides specific details about this account
397  // usability error.
398  @Nullable private final String message;
399
400  // The name for this account usability error.
401  @NotNull private final String name;
402
403  // The encoded string representation for this account usability error.
404  @NotNull private final String stringRepresentation;
405
406
407
408  /**
409   * Creates a new authentication failure reason with the provided information.
410   *
411   * @param  intValue  The integer value for this authentication failure reason.
412   * @param  name      The name for this authentication failure reason.  It must
413   *                   not be {@code null}.
414   * @param  message   A human-readable message that provides specific details
415   *                   about this account usability error.  It may be
416   *                   {@code null} if no message is available.
417   */
418  public AuthenticationFailureReason(final int intValue,
419                                     @NotNull final String name,
420                                     @Nullable final String message)
421  {
422    Validator.ensureNotNull(name);
423
424    this.intValue = intValue;
425    this.name = name;
426    this.message = message;
427
428    final StringBuilder buffer = new StringBuilder();
429    buffer.append("code=");
430    buffer.append(intValue);
431    buffer.append("\tname=");
432    buffer.append(name);
433
434    if (message != null)
435    {
436      buffer.append("\tmessage=");
437      buffer.append(message);
438    }
439
440    stringRepresentation = buffer.toString();
441  }
442
443
444
445  /**
446   * Creates a new authentication failure reason that is decoded from the
447   * provided string representation.
448   *
449   * @param  stringRepresentation  The string representation of the
450   *                               authentication failure reason to decode.  It
451   *                               must not be {@code null}.
452   *
453   * @throws LDAPException  If the provided string cannot be decoded as a valid
454   *                         authentication failure reason.
455   */
456  public AuthenticationFailureReason(@NotNull final String stringRepresentation)
457       throws LDAPException
458  {
459    this.stringRepresentation = stringRepresentation;
460
461    try
462    {
463      Integer i = null;
464      String n = null;
465      String m = null;
466
467      final StringTokenizer tokenizer =
468           new StringTokenizer(stringRepresentation, "\t");
469      while (tokenizer.hasMoreTokens())
470      {
471        final String token = tokenizer.nextToken();
472        final int equalPos = token.indexOf('=');
473        final String fieldName = token.substring(0, equalPos);
474        final String fieldValue = token.substring(equalPos+1);
475        if (fieldName.equals("code"))
476        {
477          i = Integer.valueOf(fieldValue);
478        }
479        else if (fieldName.equals("name"))
480        {
481          n = fieldValue;
482        }
483        else if (fieldName.equals("message"))
484        {
485          m = fieldValue;
486        }
487      }
488
489      if (i == null)
490      {
491        throw new LDAPException(ResultCode.DECODING_ERROR,
492             ERR_AUTH_FAILURE_REASON_CANNOT_DECODE.get(stringRepresentation,
493                  ERR_AUTH_FAILURE_REASON_NO_CODE.get()));
494      }
495
496      if (n == null)
497      {
498        throw new LDAPException(ResultCode.DECODING_ERROR,
499             ERR_AUTH_FAILURE_REASON_CANNOT_DECODE.get(stringRepresentation,
500                  ERR_AUTH_FAILURE_REASON_NO_NAME.get()));
501      }
502
503      intValue = i;
504      name     = n;
505      message  = m;
506    }
507    catch (final LDAPException le)
508    {
509      Debug.debugException(le);
510
511      throw le;
512    }
513    catch (final Exception e)
514    {
515      Debug.debugException(e);
516
517      throw new LDAPException(ResultCode.DECODING_ERROR,
518           ERR_AUTH_FAILURE_REASON_CANNOT_DECODE.get(stringRepresentation,
519                StaticUtils.getExceptionMessage(e)),
520           e);
521    }
522  }
523
524
525
526  /**
527   * Retrieves the integer value for this authentication failure reason.
528   *
529   * @return  The integer value for this authentication failure reason.
530   */
531  public int getIntValue()
532  {
533    return intValue;
534  }
535
536
537
538  /**
539   * Retrieves the name for this authentication failure reason.
540   *
541   * @return  The name for this authentication failure reason.
542   */
543  @NotNull()
544  public String getName()
545  {
546    return name;
547  }
548
549
550
551  /**
552   * Retrieves a human-readable message that provides specific details about
553   * this authentication failure reason.
554   *
555   * @return  A human-readable message that provides specific details about this
556   *          authentication failure reason, or {@code null} if no message is
557   *          available.
558   */
559  @Nullable()
560  public String getMessage()
561  {
562    return message;
563  }
564
565
566
567  /**
568   * Retrieves a string representation of this authentication failure reason.
569   *
570   * @return  A string representation of this authentication failure reason.
571   */
572  @Override()
573  @NotNull()
574  public String toString()
575  {
576    return stringRepresentation;
577  }
578}