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