001/* 002 * Copyright 2008-2024 Ping Identity Corporation 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright 2008-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) 2008-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 com.unboundid.asn1.ASN1Element; 041import com.unboundid.asn1.ASN1OctetString; 042import com.unboundid.asn1.ASN1Sequence; 043import com.unboundid.ldap.sdk.Control; 044import com.unboundid.ldap.sdk.ExtendedRequest; 045import com.unboundid.ldap.sdk.ExtendedResult; 046import com.unboundid.ldap.sdk.LDAPConnection; 047import com.unboundid.ldap.sdk.LDAPException; 048import com.unboundid.ldap.sdk.ResultCode; 049import com.unboundid.util.Debug; 050import com.unboundid.util.NotMutable; 051import com.unboundid.util.NotNull; 052import com.unboundid.util.Nullable; 053import com.unboundid.util.ThreadSafety; 054import com.unboundid.util.ThreadSafetyLevel; 055 056import static com.unboundid.ldap.sdk.unboundidds.extensions.ExtOpMessages.*; 057 058 059 060/** 061 * This class provides an implementation of the password policy state extended 062 * request as used in the Ping Identity, UnboundID, or Nokia/Alcatel-Lucent 8661 063 * Directory Server. It may be used to retrieve and/or alter password policy 064 * properties for a user account. See the documentation in the 065 * {@link PasswordPolicyStateOperation} class for information about the types of 066 * operations that can be performed. 067 * <BR> 068 * <BLOCKQUOTE> 069 * <B>NOTE:</B> This class, and other classes within the 070 * {@code com.unboundid.ldap.sdk.unboundidds} package structure, are only 071 * supported for use against Ping Identity, UnboundID, and 072 * Nokia/Alcatel-Lucent 8661 server products. These classes provide support 073 * for proprietary functionality or for external specifications that are not 074 * considered stable or mature enough to be guaranteed to work in an 075 * interoperable way with other types of LDAP servers. 076 * </BLOCKQUOTE> 077 * <BR> 078 * The extended request has an OID of 1.3.6.1.4.1.30221.1.6.1 and a value with 079 * the following encoding: 080 * <PRE> 081 * PasswordPolicyStateValue ::= SEQUENCE { 082 * targetUser LDAPDN 083 * operations SEQUENCE OF PasswordPolicyStateOperation OPTIONAL } 084 * 085 * PasswordPolicyStateOperation ::= SEQUENCE { 086 * opType ENUMERATED { 087 * getPasswordPolicyDN (0), 088 * getAccountDisabledState (1), 089 * setAccountDisabledState (2), 090 * clearAccountDisabledState (3), 091 * getAccountExpirationTime (4), 092 * setAccountExpirationTime (5), 093 * clearAccountExpirationTime (6), 094 * getSecondsUntilAccountExpiration (7), 095 * getPasswordChangedTime (8), 096 * setPasswordChangedTime (9), 097 * clearPasswordChangedTime (10), 098 * getPasswordExpirationWarnedTime (11), 099 * setPasswordExpirationWarnedTime (12), 100 * clearPasswordExpirationWarnedTime (13), 101 * getSecondsUntilPasswordExpiration (14), 102 * getSecondsUntilPasswordExpirationWarning (15), 103 * getAuthenticationFailureTimes (16), 104 * addAuthenticationFailureTime (17), 105 * setAuthenticationFailureTimes (18), 106 * clearAuthenticationFailureTimes (19), 107 * getSecondsUntilAuthenticationFailureUnlock (20), 108 * getRemainingAuthenticationFailureCount (21), 109 * getLastLoginTime (22), 110 * setLastLoginTime (23), 111 * clearLastLoginTime (24), 112 * getSecondsUntilIdleLockout (25), 113 * getPasswordResetState (26), 114 * setPasswordResetState (27), 115 * clearPasswordResetState (28), 116 * getSecondsUntilPasswordResetLockout (29), 117 * getGraceLoginUseTimes (30), 118 * addGraceLoginUseTime (31), 119 * setGraceLoginUseTimes (32), 120 * clearGraceLoginUseTimes (33), 121 * getRemainingGraceLoginCount (34), 122 * getPasswordChangedByRequiredTime (35), 123 * setPasswordChangedByRequiredTime (36), 124 * clearPasswordChangedByRequiredTime (37), 125 * getSecondsUntilRequiredChangeTime (38), 126 * getPasswordHistory (39), -- Deprecated 127 * clearPasswordHistory (40), 128 * hasRetiredPassword (41), 129 * getPasswordRetiredTime (42), 130 * getRetiredPasswordExpirationTime (43), 131 * purgeRetiredPassword (44), 132 * getAccountActivationTime (45), 133 * setAccountActivationTime (46), 134 * clearAccountActivationTime (47), 135 * getSecondsUntilAccountActivation (48), 136 * getLastLoginIPAddress (49), 137 * setLastLoginIPAddress (50), 138 * clearLastLoginIPAddress (51), 139 * getAccountUsabilityNotices (52), 140 * getAccountUsabilityWarnings (53), 141 * getAccountUsabilityErrors (54), 142 * getAccountIsUsable (55), 143 * getAccountIsNotYetActive (56), 144 * getAccountIsExpired (57), 145 * getPasswordExpirationTime (58), 146 * getAccountIsFailureLocked (59), 147 * setAccountIsFailureLocked (60), 148 * getFailureLockoutTime (61), 149 * getAccountIsIdleLocked (62), 150 * getIdleLockoutTime (63), 151 * getAccountIsResetLocked (64), 152 * getResetLockoutTime (65), 153 * getPasswordHistoryCount (66), 154 * getPasswordIsExpired (67), 155 * getAvailableSASLMechanisms (68), 156 * getAvailableOTPDeliveryMechanisms (69), 157 * getHasTOTPSharedSecret (70), 158 * getRegisteredYubiKeyPublicIDs (71), 159 * addRegisteredYubiKeyPublicID (72), 160 * removeRegisteredYubiKeyPublicID (73), 161 * setRegisteredYubiKeyPublicIDs (74), 162 * clearRegisteredYubiKeyPublicIDs (75), 163 * addTOTPSharedSecret (76), 164 * removeTOTPSharedSecret (77), 165 * setTOTPSharedSecrets (78), 166 * clearTOTPSharedSecrets (79), 167 * hasRegisteredYubiKeyPublicID (80), 168 * hasStaticPassword (81), 169 * getLastBindPasswordValidationTime (82), 170 * getSecondsSinceLastBindPasswordValidation (83), 171 * setLastBindPasswordValidationTime (84), 172 * clearLastBindPasswordValidationTime (85), 173 * getAccountIsValidationLocked (86), 174 * setAccountIsValidationLocked (87), 175 * getRecentLoginHistory (88), 176 * clearRecentLoginHistory (89), 177 * ... }, 178 * opValues SEQUENCE OF OCTET STRING OPTIONAL } 179 * </PRE> 180 * <BR> 181 * <H2>Example</H2> 182 * The following example demonstrates the use of the password policy state 183 * extended operation to administratively disable a user's account: 184 * <PRE> 185 * PasswordPolicyStateOperation disableOp = 186 * PasswordPolicyStateOperation.createSetAccountDisabledStateOperation( 187 * true); 188 * PasswordPolicyStateExtendedRequest pwpStateRequest = 189 * new PasswordPolicyStateExtendedRequest( 190 * "uid=john.doe,ou=People,dc=example,dc=com", disableOp); 191 * PasswordPolicyStateExtendedResult pwpStateResult = 192 * (PasswordPolicyStateExtendedResult) 193 * connection.processExtendedOperation(pwpStateRequest); 194 * 195 * // NOTE: The processExtendedOperation method will generally only throw an 196 * // exception if a problem occurs while trying to send the request or read 197 * // the response. It will not throw an exception because of a non-success 198 * // response. 199 * 200 * if (pwpStateResult.getResultCode() == ResultCode.SUCCESS) 201 * { 202 * boolean isDisabled = pwpStateResult.getBooleanValue( 203 * PasswordPolicyStateOperation.OP_TYPE_GET_ACCOUNT_DISABLED_STATE); 204 * if (isDisabled) 205 * { 206 * // The user account has been disabled. 207 * } 208 * else 209 * { 210 * // The user account is not disabled. 211 * } 212 * } 213 * </PRE> 214 */ 215@NotMutable() 216@ThreadSafety(level=ThreadSafetyLevel.NOT_THREADSAFE) 217public final class PasswordPolicyStateExtendedRequest 218 extends ExtendedRequest 219{ 220 /** 221 * The OID (1.3.6.1.4.1.30221.1.6.1) for the password policy state extended 222 * request. 223 */ 224 @NotNull public static final String PASSWORD_POLICY_STATE_REQUEST_OID = 225 "1.3.6.1.4.1.30221.1.6.1"; 226 227 228 229 /** 230 * The serial version UID for this serializable class. 231 */ 232 private static final long serialVersionUID = -1644137695182620213L; 233 234 235 236 // The set of password policy state operations to process. 237 @NotNull private final PasswordPolicyStateOperation[] operations; 238 239 // The DN of the user account on which to operate. 240 @NotNull private final String userDN; 241 242 243 244 /** 245 * Creates a new password policy state extended request with the provided user 246 * DN and optional set of operations. 247 * 248 * @param userDN The DN of the user account on which to operate. 249 * @param operations The set of password policy state operations to process. 250 * If no operations are provided, then the effect will be 251 * to retrieve the values of all available password policy 252 * state properties. 253 */ 254 public PasswordPolicyStateExtendedRequest(@NotNull final String userDN, 255 @NotNull final PasswordPolicyStateOperation... operations) 256 { 257 this(userDN, null, operations); 258 } 259 260 261 262 /** 263 * Creates a new password policy state extended request with the provided user 264 * DN, optional set of operations, and optional set of controls. 265 * 266 * @param userDN The DN of the user account on which to operate. 267 * @param controls The set of controls to include in the request. 268 * @param operations The set of password policy state operations to process. 269 * If no operations are provided, then the effect will be 270 * to retrieve the values of all available password policy 271 * state properties. 272 */ 273 public PasswordPolicyStateExtendedRequest(@NotNull final String userDN, 274 @Nullable final Control[] controls, 275 @NotNull final PasswordPolicyStateOperation... operations) 276 { 277 super(PASSWORD_POLICY_STATE_REQUEST_OID, encodeValue(userDN, operations), 278 controls); 279 280 this.userDN = userDN; 281 this.operations = operations; 282 } 283 284 285 286 /** 287 * Creates a new password policy state extended request from the provided 288 * generic extended request. 289 * 290 * @param extendedRequest The generic extended request to use to create this 291 * password policy state extended request. 292 * 293 * @throws LDAPException If a problem occurs while decoding the request. 294 */ 295 public PasswordPolicyStateExtendedRequest( 296 @NotNull final ExtendedRequest extendedRequest) 297 throws LDAPException 298 { 299 super(extendedRequest); 300 301 final ASN1OctetString value = extendedRequest.getValue(); 302 if (value == null) 303 { 304 throw new LDAPException(ResultCode.DECODING_ERROR, 305 ERR_PWP_STATE_REQUEST_NO_VALUE.get()); 306 } 307 308 final ASN1Element[] elements; 309 try 310 { 311 final ASN1Element valueElement = ASN1Element.decode(value.getValue()); 312 elements = ASN1Sequence.decodeAsSequence(valueElement).elements(); 313 } 314 catch (final Exception e) 315 { 316 Debug.debugException(e); 317 throw new LDAPException(ResultCode.DECODING_ERROR, 318 ERR_PWP_STATE_REQUEST_VALUE_NOT_SEQUENCE.get(e), 319 e); 320 } 321 322 if ((elements.length < 1) || (elements.length > 2)) 323 { 324 throw new LDAPException(ResultCode.DECODING_ERROR, 325 ERR_PWP_STATE_REQUEST_INVALID_ELEMENT_COUNT.get( 326 elements.length)); 327 } 328 329 userDN = ASN1OctetString.decodeAsOctetString(elements[0]).stringValue(); 330 331 if (elements.length == 1) 332 { 333 operations = new PasswordPolicyStateOperation[0]; 334 } 335 else 336 { 337 try 338 { 339 final ASN1Element[] opElements = 340 ASN1Sequence.decodeAsSequence(elements[1]).elements(); 341 operations = new PasswordPolicyStateOperation[opElements.length]; 342 for (int i=0; i < opElements.length; i++) 343 { 344 operations[i] = PasswordPolicyStateOperation.decode(opElements[i]); 345 } 346 } 347 catch (final Exception e) 348 { 349 Debug.debugException(e); 350 throw new LDAPException(ResultCode.DECODING_ERROR, 351 ERR_PWP_STATE_REQUEST_CANNOT_DECODE_OPS.get(e), 352 e); 353 } 354 } 355 } 356 357 358 359 /** 360 * Encodes the provided information into an ASN.1 octet string that may be 361 * used as the value for this extended request. 362 * 363 * @param userDN The DN of the user account on which to operate. 364 * @param operations The set of operations to be processed. 365 * 366 * @return An ASN.1 octet string containing the encoded value. 367 */ 368 @NotNull() 369 private static ASN1OctetString encodeValue(@NotNull final String userDN, 370 @Nullable final PasswordPolicyStateOperation[] operations) 371 { 372 final ASN1Element[] elements; 373 if ((operations == null) || (operations.length == 0)) 374 { 375 elements = new ASN1Element[] 376 { 377 new ASN1OctetString(userDN) 378 }; 379 } 380 else 381 { 382 final ASN1Element[] opElements = new ASN1Element[operations.length]; 383 for (int i=0; i < operations.length; i++) 384 { 385 opElements[i] = operations[i].encode(); 386 } 387 388 elements = new ASN1Element[] 389 { 390 new ASN1OctetString(userDN), 391 new ASN1Sequence(opElements) 392 }; 393 } 394 395 return new ASN1OctetString(new ASN1Sequence(elements).encode()); 396 } 397 398 399 400 /** 401 * Retrieves the DN of the user account on which to operate. 402 * 403 * @return The DN of the user account on which to operate. 404 */ 405 @NotNull() 406 public String getUserDN() 407 { 408 return userDN; 409 } 410 411 412 413 /** 414 * Retrieves the set of password policy state operations to be processed. 415 * 416 * @return The set of password policy state operations to be processed, or 417 * an empty list if the values of all password policy state 418 * properties should be retrieved. 419 */ 420 @NotNull() 421 public PasswordPolicyStateOperation[] getOperations() 422 { 423 return operations; 424 } 425 426 427 428 /** 429 * {@inheritDoc} 430 */ 431 @Override() 432 @NotNull() 433 public PasswordPolicyStateExtendedResult process( 434 @NotNull final LDAPConnection connection, final int depth) 435 throws LDAPException 436 { 437 final ExtendedResult extendedResponse = super.process(connection, depth); 438 return new PasswordPolicyStateExtendedResult(extendedResponse); 439 } 440 441 442 443 /** 444 * {@inheritDoc} 445 */ 446 @Override() 447 @NotNull() 448 public PasswordPolicyStateExtendedRequest duplicate() 449 { 450 return duplicate(getControls()); 451 } 452 453 454 455 /** 456 * {@inheritDoc} 457 */ 458 @Override() 459 @NotNull() 460 public PasswordPolicyStateExtendedRequest duplicate( 461 @Nullable final Control[] controls) 462 { 463 final PasswordPolicyStateExtendedRequest r = 464 new PasswordPolicyStateExtendedRequest(userDN, controls, operations); 465 r.setResponseTimeoutMillis(getResponseTimeoutMillis(null)); 466 r.setIntermediateResponseListener(getIntermediateResponseListener()); 467 r.setReferralDepth(getReferralDepth()); 468 r.setReferralConnector(getReferralConnectorInternal()); 469 return r; 470 } 471 472 473 474 /** 475 * {@inheritDoc} 476 */ 477 @Override() 478 @NotNull() 479 public String getExtendedRequestName() 480 { 481 return INFO_EXTENDED_REQUEST_NAME_PW_POLICY_STATE.get(); 482 } 483 484 485 486 /** 487 * {@inheritDoc} 488 */ 489 @Override() 490 public void toString(@NotNull final StringBuilder buffer) 491 { 492 buffer.append("PasswordPolicyStateExtendedRequest(userDN='"); 493 buffer.append(userDN); 494 495 if (operations.length > 0) 496 { 497 buffer.append("', operations={"); 498 for (int i=0; i < operations.length; i++) 499 { 500 if (i > 0) 501 { 502 buffer.append(", "); 503 } 504 505 operations[i].toString(buffer); 506 } 507 buffer.append('}'); 508 } 509 510 final Control[] controls = getControls(); 511 if (controls.length > 0) 512 { 513 buffer.append(", controls={"); 514 for (int i=0; i < controls.length; i++) 515 { 516 if (i > 0) 517 { 518 buffer.append(", "); 519 } 520 521 buffer.append(controls[i]); 522 } 523 buffer.append('}'); 524 } 525 526 buffer.append(')'); 527 } 528}