001/* 002 * Copyright 2017-2020 Ping Identity Corporation 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright 2017-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) 2017-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.controls; 037 038 039 040import java.util.ArrayList; 041 042import com.unboundid.asn1.ASN1Boolean; 043import com.unboundid.asn1.ASN1Element; 044import com.unboundid.asn1.ASN1OctetString; 045import com.unboundid.asn1.ASN1Sequence; 046import com.unboundid.ldap.sdk.Control; 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.StaticUtils; 052import com.unboundid.util.ThreadSafety; 053import com.unboundid.util.ThreadSafetyLevel; 054 055import static com.unboundid.ldap.sdk.unboundidds.controls.ControlMessages.*; 056 057 058 059/** 060 * This class provides an implementation of a request control that can be 061 * included in an add request, modify request, or password modify extended 062 * request to control the way the server should behave when performing a 063 * password change. The requester must have the password-reset privilege. 064 * <BR> 065 * <BLOCKQUOTE> 066 * <B>NOTE:</B> This class, and other classes within the 067 * {@code com.unboundid.ldap.sdk.unboundidds} package structure, are only 068 * supported for use against Ping Identity, UnboundID, and 069 * Nokia/Alcatel-Lucent 8661 server products. These classes provide support 070 * for proprietary functionality or for external specifications that are not 071 * considered stable or mature enough to be guaranteed to work in an 072 * interoperable way with other types of LDAP servers. 073 * </BLOCKQUOTE> 074 * <BR> 075 * This request control has an OID of 1.3.6.1.4.1.30221.2.5.51. The criticality 076 * may be either true or false. It must have a value, and the value should have 077 * the following encoding: 078 * <PRE> 079 * PasswordUpdateBehaviorRequest ::= SEQUENCE { 080 * isSelfChange [0] BOOLEAN OPTIONAL, 081 * allowPreEncodedPassword [1] BOOLEAN OPTIONAL, 082 * skipPasswordValidation [2] BOOLEAN OPTIONAL, 083 * ignorePasswordHistory [3] BOOLEAN OPTIONAL, 084 * ignoreMinimumPasswordAge [4] BOOLEAN OPTIONAL, 085 * passwordStorageScheme [5] OCTET STRING OPTIONAL, 086 * mustChangePassword [6] BOOLEAN OPTIONAL, 087 * ... } 088 * </PRE> 089 * 090 * @see PasswordUpdateBehaviorRequestControlProperties 091 */ 092@NotMutable() 093@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE) 094public final class PasswordUpdateBehaviorRequestControl 095 extends Control 096{ 097 /** 098 * The OID (1.3.6.1.4.1.30221.2.5.51) for the password update behavior request 099 * control. 100 */ 101 public static final String PASSWORD_UPDATE_BEHAVIOR_REQUEST_OID = 102 "1.3.6.1.4.1.30221.2.5.51"; 103 104 105 106 /** 107 * The BER type to use for the {@code isSelfChange} element in the encoded 108 * request. 109 */ 110 private static final byte TYPE_IS_SELF_CHANGE = (byte) 0x80; 111 112 113 114 /** 115 * The BER type to use for the {@code allowPreEncodedPassword} element in the 116 * encoded request. 117 */ 118 private static final byte TYPE_ALLOW_PRE_ENCODED_PASSWORD = (byte) 0x81; 119 120 121 122 /** 123 * The BER type to use for the {@code skipPasswordValidation} element in the 124 * encoded request. 125 */ 126 private static final byte TYPE_SKIP_PASSWORD_VALIDATION = (byte) 0x82; 127 128 129 130 /** 131 * The BER type to use for the {@code ignorePasswordHistory} element in the 132 * encoded request. 133 */ 134 private static final byte TYPE_IGNORE_PASSWORD_HISTORY = (byte) 0x83; 135 136 137 138 /** 139 * The BER type to use for the {@code ignoreMinimumPasswordAge} element in the 140 * encoded request. 141 */ 142 private static final byte TYPE_IGNORE_MINIMUM_PASSWORD_AGE = (byte) 0x84; 143 144 145 146 /** 147 * The BER type to use for the {@code passwordStorageScheme} element in the 148 * encoded request. 149 */ 150 private static final byte TYPE_PASSWORD_STORAGE_SCHEME = (byte) 0x85; 151 152 153 154 /** 155 * The BER type to use for the {@code mustChangePassword} element in the 156 * encoded request. 157 */ 158 private static final byte TYPE_MUST_CHANGE_PASSWORD = (byte) 0x86; 159 160 161 162 /** 163 * The serial version UID for this serializable class. 164 */ 165 private static final long serialVersionUID = -1915608505128236450L; 166 167 168 169 // Indicates whether the requester should be allowed to provide a pre-encoded 170 // password. 171 private final Boolean allowPreEncodedPassword; 172 173 // Indicates whether to ignore any minimum password age configured in the 174 // password policy. 175 private final Boolean ignoreMinimumPasswordAge; 176 177 // Indicates whether to skip the process of checking whether the provided 178 // password matches the new current password or is in the password history. 179 private final Boolean ignorePasswordHistory; 180 181 // Indicates whether to treat the password change as a self change. 182 private final Boolean isSelfChange; 183 184 // Indicates whether to update the user's account to indicate that they must 185 // change their password the next time they authenticate. 186 private final Boolean mustChangePassword; 187 188 // Indicates whether to skip password validation for the new password. 189 private final Boolean skipPasswordValidation; 190 191 // Specifies the password storage scheme to use for the new password. 192 private final String passwordStorageScheme; 193 194 195 196 /** 197 * Creates a new password update behavior request control with the provided 198 * information. 199 * 200 * @param properties The set of properties to use for the request control. 201 * It must not be {@code null}. 202 * @param isCritical Indicates whether the control should be considered 203 * critical. 204 */ 205 public PasswordUpdateBehaviorRequestControl( 206 final PasswordUpdateBehaviorRequestControlProperties properties, 207 final boolean isCritical) 208 { 209 super(PASSWORD_UPDATE_BEHAVIOR_REQUEST_OID, isCritical, 210 encodeValue(properties)); 211 212 isSelfChange = properties.getIsSelfChange(); 213 allowPreEncodedPassword = properties.getAllowPreEncodedPassword(); 214 skipPasswordValidation = properties.getSkipPasswordValidation(); 215 ignorePasswordHistory = properties.getIgnorePasswordHistory(); 216 ignoreMinimumPasswordAge = properties.getIgnoreMinimumPasswordAge(); 217 passwordStorageScheme = properties.getPasswordStorageScheme(); 218 mustChangePassword = properties.getMustChangePassword(); 219 } 220 221 222 223 /** 224 * Creates a new password update behavior request control that is decoded from 225 * the provided generic control. 226 * 227 * @param control The control to be decoded as a password update behavior 228 * request control. It must not be {@code null}. 229 * 230 * @throws LDAPException If the provided control cannot be parsed as a 231 * password update behavior request control. 232 */ 233 public PasswordUpdateBehaviorRequestControl(final Control control) 234 throws LDAPException 235 { 236 super(control); 237 238 final ASN1OctetString value = control.getValue(); 239 if (value == null) 240 { 241 throw new LDAPException(ResultCode.DECODING_ERROR, 242 ERR_PW_UPDATE_BEHAVIOR_REQ_DECODE_NO_VALUE.get()); 243 } 244 245 try 246 { 247 Boolean allowPreEncoded = null; 248 Boolean ignoreAge = null; 249 Boolean ignoreHistory = null; 250 Boolean mustChange = null; 251 Boolean selfChange = null; 252 Boolean skipValidation = null; 253 String scheme = null; 254 for (final ASN1Element e : 255 ASN1Sequence.decodeAsSequence(value.getValue()).elements()) 256 { 257 switch (e.getType()) 258 { 259 case TYPE_IS_SELF_CHANGE: 260 selfChange = ASN1Boolean.decodeAsBoolean(e).booleanValue(); 261 break; 262 case TYPE_ALLOW_PRE_ENCODED_PASSWORD: 263 allowPreEncoded = ASN1Boolean.decodeAsBoolean(e).booleanValue(); 264 break; 265 case TYPE_SKIP_PASSWORD_VALIDATION: 266 skipValidation = ASN1Boolean.decodeAsBoolean(e).booleanValue(); 267 break; 268 case TYPE_IGNORE_PASSWORD_HISTORY: 269 ignoreHistory = ASN1Boolean.decodeAsBoolean(e).booleanValue(); 270 break; 271 case TYPE_IGNORE_MINIMUM_PASSWORD_AGE: 272 ignoreAge = ASN1Boolean.decodeAsBoolean(e).booleanValue(); 273 break; 274 case TYPE_PASSWORD_STORAGE_SCHEME: 275 scheme = ASN1OctetString.decodeAsOctetString(e).stringValue(); 276 break; 277 case TYPE_MUST_CHANGE_PASSWORD: 278 mustChange = ASN1Boolean.decodeAsBoolean(e).booleanValue(); 279 break; 280 default: 281 throw new LDAPException(ResultCode.DECODING_ERROR, 282 ERR_PW_UPDATE_BEHAVIOR_REQ_DECODE_UNRECOGNIZED_ELEMENT_TYPE. 283 get(StaticUtils.toHex(e.getType()))); 284 } 285 } 286 287 isSelfChange = selfChange; 288 allowPreEncodedPassword = allowPreEncoded; 289 skipPasswordValidation = skipValidation; 290 ignorePasswordHistory = ignoreHistory; 291 ignoreMinimumPasswordAge = ignoreAge; 292 passwordStorageScheme = scheme; 293 mustChangePassword = mustChange; 294 } 295 catch (final Exception e) 296 { 297 Debug.debugException(e); 298 throw new LDAPException(ResultCode.DECODING_ERROR, 299 ERR_PW_UPDATE_BEHAVIOR_REQ_DECODE_ERROR.get( 300 StaticUtils.getExceptionMessage(e)), 301 e); 302 } 303 } 304 305 306 307 /** 308 * Encodes the provided properties into a form that can be used as the value 309 * for this control. 310 * 311 * @param properties The properties to be encoded. 312 * 313 * @return An ASN.1 octet string that can be used as the request control 314 * value. 315 */ 316 private static ASN1OctetString encodeValue( 317 final PasswordUpdateBehaviorRequestControlProperties properties) 318 { 319 final ArrayList<ASN1Element> elements = new ArrayList<>(6); 320 321 if (properties.getIsSelfChange() != null) 322 { 323 elements.add(new ASN1Boolean(TYPE_IS_SELF_CHANGE, 324 properties.getIsSelfChange())); 325 } 326 327 if (properties.getAllowPreEncodedPassword() != null) 328 { 329 elements.add(new ASN1Boolean(TYPE_ALLOW_PRE_ENCODED_PASSWORD, 330 properties.getAllowPreEncodedPassword())); 331 } 332 333 if (properties.getSkipPasswordValidation() != null) 334 { 335 elements.add(new ASN1Boolean(TYPE_SKIP_PASSWORD_VALIDATION, 336 properties.getSkipPasswordValidation())); 337 } 338 339 if (properties.getIgnorePasswordHistory() != null) 340 { 341 elements.add(new ASN1Boolean(TYPE_IGNORE_PASSWORD_HISTORY, 342 properties.getIgnorePasswordHistory())); 343 } 344 345 if (properties.getIgnoreMinimumPasswordAge() != null) 346 { 347 elements.add(new ASN1Boolean(TYPE_IGNORE_MINIMUM_PASSWORD_AGE, 348 properties.getIgnoreMinimumPasswordAge())); 349 } 350 351 if (properties.getPasswordStorageScheme() != null) 352 { 353 elements.add(new ASN1OctetString(TYPE_PASSWORD_STORAGE_SCHEME, 354 properties.getPasswordStorageScheme())); 355 } 356 357 if (properties.getMustChangePassword() != null) 358 { 359 elements.add(new ASN1Boolean(TYPE_MUST_CHANGE_PASSWORD, 360 properties.getMustChangePassword())); 361 } 362 363 return new ASN1OctetString(new ASN1Sequence(elements).encode()); 364 } 365 366 367 368 /** 369 * Indicates whether this control should override the server's automatic 370 * classification of the password update as a self change or an administrative 371 * reset, and if so, what the overridden value should be. 372 * 373 * @return {@code Boolean.TRUE} if the server should treat the password 374 * update as a self change, {@code Boolean.FALSE} if the server 375 * should treat the password update as an administrative reset, or 376 * {@code null} if the server should automatically determine whether 377 * the password update is a self change or an administrative reset. 378 */ 379 public Boolean getIsSelfChange() 380 { 381 return isSelfChange; 382 } 383 384 385 386 /** 387 * Indicates whether this control should override the value of the 388 * {@code allow-pre-encoded-passwords} configuration property for the target 389 * user's password policy, and if so, what the overridden value should be. 390 * 391 * @return {@code Boolean.TRUE} if the server should accept a pre-encoded 392 * password in the password update even if the server's password 393 * policy configuration would normally not permit this, 394 * {@code Boolean.FALSE} if the server should reject a pre-encoded 395 * password in the password update even if the server's password 396 * policy configuration would normally accept it, or {@code null} if 397 * the password policy configuration should be used to determine 398 * whether to accept pre-encoded passwords. 399 */ 400 public Boolean getAllowPreEncodedPassword() 401 { 402 return allowPreEncodedPassword; 403 } 404 405 406 407 /** 408 * Indicates whether this control should override the server's normal behavior 409 * with regard to invoking password validators for any new passwords included 410 * in the password update, and if so, what the overridden behavior should be. 411 * 412 * @return {@code Boolean.TRUE} if the server should skip invoking the 413 * password validators configured in the target user's password 414 * policy validators for any new passwords included in the password 415 * update even if the server would normally perform password 416 * validation, {@code Boolean.FALSE} if the server should invoke the 417 * password validators even if it would normally skip them, or 418 * {@code null} if the password policy configuration should be used 419 * to determine whether to skip password validation. 420 */ 421 public Boolean getSkipPasswordValidation() 422 { 423 return skipPasswordValidation; 424 } 425 426 427 428 /** 429 * Indicates whether this control should override the server's normal behavior 430 * with regard to checking the password history for any new passwords included 431 * in the password update, and if so, what the overridden behavior should be. 432 * 433 * @return {@code Boolean.TRUE} if the server should not check to see whether 434 * any new password matches the current password or is in the user's 435 * password history even if it would normally perform that check, 436 * {@code Boolean.FALSE} if the server should check to see whether 437 * any new password matches the current or previous password even if 438 * it would normally not perform such a check, or {@code null} if the 439 * password policy configuration should be used to determine whether 440 * to ignore the password history. 441 */ 442 public Boolean getIgnorePasswordHistory() 443 { 444 return ignorePasswordHistory; 445 } 446 447 448 449 /** 450 * Indicates whether this control should override the server's normal behavior 451 * with regard to checking the minimum password age, and if so, what the 452 * overridden behavior should be. 453 * 454 * @return {@code Boolean.TRUE} if the server should accept the password 455 * change even if it has been less than the configured minimum 456 * password age since the password was last changed, 457 * {@code Boolean.FALSE} if the server should reject the password 458 * change if it has been less than teh configured minimum password 459 * age, or {@code null} if the password policy configuration should 460 * be used to determine the appropriate behavior. 461 */ 462 public Boolean getIgnoreMinimumPasswordAge() 463 { 464 return ignoreMinimumPasswordAge; 465 } 466 467 468 469 /** 470 * Indicates whether this control should override the server's normal behavior 471 * with regard to selecting the password storage scheme to use to encode new 472 * password values, and if so, which password storage scheme should be used. 473 * 474 * @return The name of the password storage scheme that should be used to 475 * encode any new password values, or {@code null} if the target 476 * user's password policy configuration should determine the 477 * appropriate schemes for encoding new passwords. 478 */ 479 public String getPasswordStorageScheme() 480 { 481 return passwordStorageScheme; 482 } 483 484 485 486 /** 487 * Indicates whether this control should override the server's normal behavior 488 * with regard to requiring a password change, and if so, what that behavior 489 * should be. 490 * 491 * @return {@code Boolean.TRUE} if the user will be required to change their 492 * password before being allowed to perform any other operation, 493 * {@code Boolean.FALSE} if the user will not be required to change 494 * their password before being allowed to perform any other 495 * operation, or {@code null} if the password policy configuration 496 * should be used to control this behavior. 497 */ 498 public Boolean getMustChangePassword() 499 { 500 return mustChangePassword; 501 } 502 503 504 505 /** 506 * {@inheritDoc} 507 */ 508 @Override() 509 public String getControlName() 510 { 511 return INFO_PW_UPDATE_BEHAVIOR_REQ_CONTROL_NAME.get(); 512 } 513 514 515 516 /** 517 * {@inheritDoc} 518 */ 519 @Override() 520 public void toString(final StringBuilder buffer) 521 { 522 buffer.append("PasswordUpdateBehaviorRequestControl(oid='"); 523 buffer.append(PASSWORD_UPDATE_BEHAVIOR_REQUEST_OID); 524 buffer.append("', isCritical="); 525 buffer.append(isCritical()); 526 buffer.append(", properties="); 527 new PasswordUpdateBehaviorRequestControlProperties(this).toString(buffer); 528 buffer.append(')'); 529 } 530}