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