001/* 002 * Copyright 2017-2024 Ping Identity Corporation 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright 2017-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) 2017-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.util.ArrayList; 041import java.util.LinkedHashMap; 042import java.util.List; 043import java.util.Map; 044 045import com.unboundid.asn1.ASN1Boolean; 046import com.unboundid.asn1.ASN1Element; 047import com.unboundid.asn1.ASN1OctetString; 048import com.unboundid.asn1.ASN1Sequence; 049import com.unboundid.ldap.sdk.Control; 050import com.unboundid.ldap.sdk.JSONControlDecodeHelper; 051import com.unboundid.ldap.sdk.LDAPException; 052import com.unboundid.ldap.sdk.ResultCode; 053import com.unboundid.util.Debug; 054import com.unboundid.util.NotMutable; 055import com.unboundid.util.NotNull; 056import com.unboundid.util.Nullable; 057import com.unboundid.util.StaticUtils; 058import com.unboundid.util.ThreadSafety; 059import com.unboundid.util.ThreadSafetyLevel; 060import com.unboundid.util.json.JSONBoolean; 061import com.unboundid.util.json.JSONField; 062import com.unboundid.util.json.JSONObject; 063import com.unboundid.util.json.JSONString; 064import com.unboundid.util.json.JSONValue; 065 066import static com.unboundid.ldap.sdk.unboundidds.controls.ControlMessages.*; 067 068 069 070/** 071 * This class provides an implementation of a request control that can be 072 * included in an add request, modify request, or password modify extended 073 * request to control the way the server should behave when performing a 074 * password change. The requester must have the password-reset privilege. 075 * <BR> 076 * <BLOCKQUOTE> 077 * <B>NOTE:</B> This class, and other classes within the 078 * {@code com.unboundid.ldap.sdk.unboundidds} package structure, are only 079 * supported for use against Ping Identity, UnboundID, and 080 * Nokia/Alcatel-Lucent 8661 server products. These classes provide support 081 * for proprietary functionality or for external specifications that are not 082 * considered stable or mature enough to be guaranteed to work in an 083 * interoperable way with other types of LDAP servers. 084 * </BLOCKQUOTE> 085 * <BR> 086 * This request control has an OID of 1.3.6.1.4.1.30221.2.5.51. The criticality 087 * may be either true or false. It must have a value, and the value should have 088 * the following encoding: 089 * <PRE> 090 * PasswordUpdateBehaviorRequest ::= SEQUENCE { 091 * isSelfChange [0] BOOLEAN OPTIONAL, 092 * allowPreEncodedPassword [1] BOOLEAN OPTIONAL, 093 * skipPasswordValidation [2] BOOLEAN OPTIONAL, 094 * ignorePasswordHistory [3] BOOLEAN OPTIONAL, 095 * ignoreMinimumPasswordAge [4] BOOLEAN OPTIONAL, 096 * passwordStorageScheme [5] OCTET STRING OPTIONAL, 097 * mustChangePassword [6] BOOLEAN OPTIONAL, 098 * ... } 099 * </PRE> 100 * 101 * @see PasswordUpdateBehaviorRequestControlProperties 102 */ 103@NotMutable() 104@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE) 105public final class PasswordUpdateBehaviorRequestControl 106 extends Control 107{ 108 /** 109 * The OID (1.3.6.1.4.1.30221.2.5.51) for the password update behavior request 110 * control. 111 */ 112 @NotNull public static final String PASSWORD_UPDATE_BEHAVIOR_REQUEST_OID = 113 "1.3.6.1.4.1.30221.2.5.51"; 114 115 116 117 /** 118 * The BER type to use for the {@code isSelfChange} element in the encoded 119 * request. 120 */ 121 private static final byte TYPE_IS_SELF_CHANGE = (byte) 0x80; 122 123 124 125 /** 126 * The BER type to use for the {@code allowPreEncodedPassword} element in the 127 * encoded request. 128 */ 129 private static final byte TYPE_ALLOW_PRE_ENCODED_PASSWORD = (byte) 0x81; 130 131 132 133 /** 134 * The BER type to use for the {@code skipPasswordValidation} element in the 135 * encoded request. 136 */ 137 private static final byte TYPE_SKIP_PASSWORD_VALIDATION = (byte) 0x82; 138 139 140 141 /** 142 * The BER type to use for the {@code ignorePasswordHistory} element in the 143 * encoded request. 144 */ 145 private static final byte TYPE_IGNORE_PASSWORD_HISTORY = (byte) 0x83; 146 147 148 149 /** 150 * The BER type to use for the {@code ignoreMinimumPasswordAge} element in the 151 * encoded request. 152 */ 153 private static final byte TYPE_IGNORE_MINIMUM_PASSWORD_AGE = (byte) 0x84; 154 155 156 157 /** 158 * The BER type to use for the {@code passwordStorageScheme} element in the 159 * encoded request. 160 */ 161 private static final byte TYPE_PASSWORD_STORAGE_SCHEME = (byte) 0x85; 162 163 164 165 /** 166 * The BER type to use for the {@code mustChangePassword} element in the 167 * encoded request. 168 */ 169 private static final byte TYPE_MUST_CHANGE_PASSWORD = (byte) 0x86; 170 171 172 173 /** 174 * The name of the field used to hold the allow-pre-encoded-password value in 175 * the JSON representation of this control. 176 */ 177 @NotNull private static final String JSON_FIELD_ALLOW_PRE_ENCODED_PASSWORD = 178 "allow-pre-encoded-password"; 179 180 181 182 /** 183 * The name of the field used to hold the ignore-minimum-password-age value in 184 * the JSON representation of this control. 185 */ 186 @NotNull private static final String JSON_FIELD_IGNORE_MINIMUM_PASSWORD_AGE = 187 "ignore-minimum-password-age"; 188 189 190 191 /** 192 * The name of the field used to hold the ignore-password-history value in the 193 * JSON representation of this control. 194 */ 195 @NotNull private static final String JSON_FIELD_IGNORE_PASSWORD_HISTORY = 196 "ignore-password-history"; 197 198 199 200 /** 201 * The name of the field used to hold the is-self-change value in the JSON 202 * representation of this control. 203 */ 204 @NotNull private static final String JSON_FIELD_IS_SELF_CHANGE = 205 "is-self-change"; 206 207 208 209 /** 210 * The name of the field used to hold the must-change-password value in the 211 * JSON representation of this control. 212 */ 213 @NotNull private static final String JSON_FIELD_MUST_CHANGE_PASSWORD = 214 "must-change-password"; 215 216 217 218 /** 219 * The name of the field used to hold the password-storage-scheme value in the 220 * JSON representation of this control. 221 */ 222 @NotNull private static final String JSON_FIELD_PASSWORD_STORAGE_SCHEME = 223 "password-storage-scheme"; 224 225 226 227 /** 228 * The name of the field used to hold the skip-password-validation value in 229 * the JSON representation of this control. 230 */ 231 @NotNull private static final String JSON_FIELD_SKIP_PASSWORD_VALIDATION = 232 "skip-password-validation"; 233 234 235 236 /** 237 * The serial version UID for this serializable class. 238 */ 239 private static final long serialVersionUID = -1915608505128236450L; 240 241 242 243 // Indicates whether the requester should be allowed to provide a pre-encoded 244 // password. 245 @Nullable private final Boolean allowPreEncodedPassword; 246 247 // Indicates whether to ignore any minimum password age configured in the 248 // password policy. 249 @Nullable private final Boolean ignoreMinimumPasswordAge; 250 251 // Indicates whether to skip the process of checking whether the provided 252 // password matches the new current password or is in the password history. 253 @Nullable private final Boolean ignorePasswordHistory; 254 255 // Indicates whether to treat the password change as a self change. 256 @Nullable private final Boolean isSelfChange; 257 258 // Indicates whether to update the user's account to indicate that they must 259 // change their password the next time they authenticate. 260 @Nullable private final Boolean mustChangePassword; 261 262 // Indicates whether to skip password validation for the new password. 263 @Nullable private final Boolean skipPasswordValidation; 264 265 // Specifies the password storage scheme to use for the new password. 266 @Nullable private final String passwordStorageScheme; 267 268 269 270 /** 271 * Creates a new password update behavior request control with the provided 272 * information. 273 * 274 * @param properties The set of properties to use for the request control. 275 * It must not be {@code null}. 276 * @param isCritical Indicates whether the control should be considered 277 * critical. 278 */ 279 public PasswordUpdateBehaviorRequestControl( 280 @NotNull final PasswordUpdateBehaviorRequestControlProperties properties, 281 final boolean isCritical) 282 { 283 super(PASSWORD_UPDATE_BEHAVIOR_REQUEST_OID, isCritical, 284 encodeValue(properties)); 285 286 isSelfChange = properties.getIsSelfChange(); 287 allowPreEncodedPassword = properties.getAllowPreEncodedPassword(); 288 skipPasswordValidation = properties.getSkipPasswordValidation(); 289 ignorePasswordHistory = properties.getIgnorePasswordHistory(); 290 ignoreMinimumPasswordAge = properties.getIgnoreMinimumPasswordAge(); 291 passwordStorageScheme = properties.getPasswordStorageScheme(); 292 mustChangePassword = properties.getMustChangePassword(); 293 } 294 295 296 297 /** 298 * Creates a new password update behavior request control that is decoded from 299 * the provided generic control. 300 * 301 * @param control The control to be decoded as a password update behavior 302 * request control. It must not be {@code null}. 303 * 304 * @throws LDAPException If the provided control cannot be parsed as a 305 * password update behavior request control. 306 */ 307 public PasswordUpdateBehaviorRequestControl(@NotNull final Control control) 308 throws LDAPException 309 { 310 super(control); 311 312 final ASN1OctetString value = control.getValue(); 313 if (value == null) 314 { 315 throw new LDAPException(ResultCode.DECODING_ERROR, 316 ERR_PW_UPDATE_BEHAVIOR_REQ_DECODE_NO_VALUE.get()); 317 } 318 319 try 320 { 321 Boolean allowPreEncoded = null; 322 Boolean ignoreAge = null; 323 Boolean ignoreHistory = null; 324 Boolean mustChange = null; 325 Boolean selfChange = null; 326 Boolean skipValidation = null; 327 String scheme = null; 328 for (final ASN1Element e : 329 ASN1Sequence.decodeAsSequence(value.getValue()).elements()) 330 { 331 switch (e.getType()) 332 { 333 case TYPE_IS_SELF_CHANGE: 334 selfChange = ASN1Boolean.decodeAsBoolean(e).booleanValue(); 335 break; 336 case TYPE_ALLOW_PRE_ENCODED_PASSWORD: 337 allowPreEncoded = ASN1Boolean.decodeAsBoolean(e).booleanValue(); 338 break; 339 case TYPE_SKIP_PASSWORD_VALIDATION: 340 skipValidation = ASN1Boolean.decodeAsBoolean(e).booleanValue(); 341 break; 342 case TYPE_IGNORE_PASSWORD_HISTORY: 343 ignoreHistory = ASN1Boolean.decodeAsBoolean(e).booleanValue(); 344 break; 345 case TYPE_IGNORE_MINIMUM_PASSWORD_AGE: 346 ignoreAge = ASN1Boolean.decodeAsBoolean(e).booleanValue(); 347 break; 348 case TYPE_PASSWORD_STORAGE_SCHEME: 349 scheme = ASN1OctetString.decodeAsOctetString(e).stringValue(); 350 break; 351 case TYPE_MUST_CHANGE_PASSWORD: 352 mustChange = ASN1Boolean.decodeAsBoolean(e).booleanValue(); 353 break; 354 default: 355 throw new LDAPException(ResultCode.DECODING_ERROR, 356 ERR_PW_UPDATE_BEHAVIOR_REQ_DECODE_UNRECOGNIZED_ELEMENT_TYPE. 357 get(StaticUtils.toHex(e.getType()))); 358 } 359 } 360 361 isSelfChange = selfChange; 362 allowPreEncodedPassword = allowPreEncoded; 363 skipPasswordValidation = skipValidation; 364 ignorePasswordHistory = ignoreHistory; 365 ignoreMinimumPasswordAge = ignoreAge; 366 passwordStorageScheme = scheme; 367 mustChangePassword = mustChange; 368 } 369 catch (final Exception e) 370 { 371 Debug.debugException(e); 372 throw new LDAPException(ResultCode.DECODING_ERROR, 373 ERR_PW_UPDATE_BEHAVIOR_REQ_DECODE_ERROR.get( 374 StaticUtils.getExceptionMessage(e)), 375 e); 376 } 377 } 378 379 380 381 /** 382 * Encodes the provided properties into a form that can be used as the value 383 * for this control. 384 * 385 * @param properties The properties to be encoded. 386 * 387 * @return An ASN.1 octet string that can be used as the request control 388 * value. 389 */ 390 @NotNull() 391 private static ASN1OctetString encodeValue( 392 @NotNull final PasswordUpdateBehaviorRequestControlProperties properties) 393 { 394 final ArrayList<ASN1Element> elements = new ArrayList<>(6); 395 396 if (properties.getIsSelfChange() != null) 397 { 398 elements.add(new ASN1Boolean(TYPE_IS_SELF_CHANGE, 399 properties.getIsSelfChange())); 400 } 401 402 if (properties.getAllowPreEncodedPassword() != null) 403 { 404 elements.add(new ASN1Boolean(TYPE_ALLOW_PRE_ENCODED_PASSWORD, 405 properties.getAllowPreEncodedPassword())); 406 } 407 408 if (properties.getSkipPasswordValidation() != null) 409 { 410 elements.add(new ASN1Boolean(TYPE_SKIP_PASSWORD_VALIDATION, 411 properties.getSkipPasswordValidation())); 412 } 413 414 if (properties.getIgnorePasswordHistory() != null) 415 { 416 elements.add(new ASN1Boolean(TYPE_IGNORE_PASSWORD_HISTORY, 417 properties.getIgnorePasswordHistory())); 418 } 419 420 if (properties.getIgnoreMinimumPasswordAge() != null) 421 { 422 elements.add(new ASN1Boolean(TYPE_IGNORE_MINIMUM_PASSWORD_AGE, 423 properties.getIgnoreMinimumPasswordAge())); 424 } 425 426 if (properties.getPasswordStorageScheme() != null) 427 { 428 elements.add(new ASN1OctetString(TYPE_PASSWORD_STORAGE_SCHEME, 429 properties.getPasswordStorageScheme())); 430 } 431 432 if (properties.getMustChangePassword() != null) 433 { 434 elements.add(new ASN1Boolean(TYPE_MUST_CHANGE_PASSWORD, 435 properties.getMustChangePassword())); 436 } 437 438 return new ASN1OctetString(new ASN1Sequence(elements).encode()); 439 } 440 441 442 443 /** 444 * Indicates whether this control should override the server's automatic 445 * classification of the password update as a self change or an administrative 446 * reset, and if so, what the overridden value should be. 447 * 448 * @return {@code Boolean.TRUE} if the server should treat the password 449 * update as a self change, {@code Boolean.FALSE} if the server 450 * should treat the password update as an administrative reset, or 451 * {@code null} if the server should automatically determine whether 452 * the password update is a self change or an administrative reset. 453 */ 454 @Nullable() 455 public Boolean getIsSelfChange() 456 { 457 return isSelfChange; 458 } 459 460 461 462 /** 463 * Indicates whether this control should override the value of the 464 * {@code allow-pre-encoded-passwords} configuration property for the target 465 * user's password policy, and if so, what the overridden value should be. 466 * 467 * @return {@code Boolean.TRUE} if the server should accept a pre-encoded 468 * password in the password update even if the server's password 469 * policy configuration would normally not permit this, 470 * {@code Boolean.FALSE} if the server should reject a pre-encoded 471 * password in the password update even if the server's password 472 * policy configuration would normally accept it, or {@code null} if 473 * the password policy configuration should be used to determine 474 * whether to accept pre-encoded passwords. 475 */ 476 @Nullable() 477 public Boolean getAllowPreEncodedPassword() 478 { 479 return allowPreEncodedPassword; 480 } 481 482 483 484 /** 485 * Indicates whether this control should override the server's normal behavior 486 * with regard to invoking password validators for any new passwords included 487 * in the password update, and if so, what the overridden behavior should be. 488 * 489 * @return {@code Boolean.TRUE} if the server should skip invoking the 490 * password validators configured in the target user's password 491 * policy validators for any new passwords included in the password 492 * update even if the server would normally perform password 493 * validation, {@code Boolean.FALSE} if the server should invoke the 494 * password validators even if it would normally skip them, or 495 * {@code null} if the password policy configuration should be used 496 * to determine whether to skip password validation. 497 */ 498 @Nullable() 499 public Boolean getSkipPasswordValidation() 500 { 501 return skipPasswordValidation; 502 } 503 504 505 506 /** 507 * Indicates whether this control should override the server's normal behavior 508 * with regard to checking the password history for any new passwords included 509 * in the password update, and if so, what the overridden behavior should be. 510 * 511 * @return {@code Boolean.TRUE} if the server should not check to see whether 512 * any new password matches the current password or is in the user's 513 * password history even if it would normally perform that check, 514 * {@code Boolean.FALSE} if the server should check to see whether 515 * any new password matches the current or previous password even if 516 * it would normally not perform such a check, or {@code null} if the 517 * password policy configuration should be used to determine whether 518 * to ignore the password history. 519 */ 520 @Nullable() 521 public Boolean getIgnorePasswordHistory() 522 { 523 return ignorePasswordHistory; 524 } 525 526 527 528 /** 529 * Indicates whether this control should override the server's normal behavior 530 * with regard to checking the minimum password age, and if so, what the 531 * overridden behavior should be. 532 * 533 * @return {@code Boolean.TRUE} if the server should accept the password 534 * change even if it has been less than the configured minimum 535 * password age since the password was last changed, 536 * {@code Boolean.FALSE} if the server should reject the password 537 * change if it has been less than teh configured minimum password 538 * age, or {@code null} if the password policy configuration should 539 * be used to determine the appropriate behavior. 540 */ 541 @Nullable() 542 public Boolean getIgnoreMinimumPasswordAge() 543 { 544 return ignoreMinimumPasswordAge; 545 } 546 547 548 549 /** 550 * Indicates whether this control should override the server's normal behavior 551 * with regard to selecting the password storage scheme to use to encode new 552 * password values, and if so, which password storage scheme should be used. 553 * 554 * @return The name of the password storage scheme that should be used to 555 * encode any new password values, or {@code null} if the target 556 * user's password policy configuration should determine the 557 * appropriate schemes for encoding new passwords. 558 */ 559 @Nullable() 560 public String getPasswordStorageScheme() 561 { 562 return passwordStorageScheme; 563 } 564 565 566 567 /** 568 * Indicates whether this control should override the server's normal behavior 569 * with regard to requiring a password change, and if so, what that behavior 570 * should be. 571 * 572 * @return {@code Boolean.TRUE} if the user will be required to change their 573 * password before being allowed to perform any other operation, 574 * {@code Boolean.FALSE} if the user will not be required to change 575 * their password before being allowed to perform any other 576 * operation, or {@code null} if the password policy configuration 577 * should be used to control this behavior. 578 */ 579 @Nullable() 580 public Boolean getMustChangePassword() 581 { 582 return mustChangePassword; 583 } 584 585 586 587 /** 588 * {@inheritDoc} 589 */ 590 @Override() 591 @NotNull() 592 public String getControlName() 593 { 594 return INFO_PW_UPDATE_BEHAVIOR_REQ_CONTROL_NAME.get(); 595 } 596 597 598 599 /** 600 * Retrieves a representation of this password update behavior request control 601 * as a JSON object. The JSON object uses the following fields: 602 * <UL> 603 * <LI> 604 * {@code oid} -- A mandatory string field whose value is the object 605 * identifier for this control. For the password update behavior request 606 * control, the OID is "1.3.6.1.4.1.30221.2.5.51". 607 * </LI> 608 * <LI> 609 * {@code control-name} -- An optional string field whose value is a 610 * human-readable name for this control. This field is only intended for 611 * descriptive purposes, and when decoding a control, the {@code oid} 612 * field should be used to identify the type of control. 613 * </LI> 614 * <LI> 615 * {@code criticality} -- A mandatory Boolean field used to indicate 616 * whether this control is considered critical. 617 * </LI> 618 * <LI> 619 * {@code value-base64} -- An optional string field whose value is a 620 * base64-encoded representation of the raw value for this password update 621 * behavior request control. Exactly one of the {@code value-base64} and 622 * {@code value-json} fields must be present. 623 * </LI> 624 * <LI> 625 * {@code value-json} -- An optional JSON object field whose value is a 626 * user-friendly representation of the value for this password update 627 * behavior request control. Exactly one of the {@code value-base64} and 628 * {@code value-json} fields must be present, and if the 629 * {@code value-json} field is used, then it will use the following 630 * fields: 631 * <UL> 632 * <LI> 633 * {@code is-self-change} -- An optional Boolean field that may be 634 * used to explicitly indicate whether the server should treat the 635 * password update as a self change or an administrative reset. 636 * </LI> 637 * <LI> 638 * {@code allow-pre-encoded-password} -- An optional Boolean field 639 * that may be used to explicitly indicate whether the server should 640 * allow the new password to be provided in pre-encoded form. 641 * </LI> 642 * <LI> 643 * {@code skip-password-validation} -- An optional Boolean field that 644 * may be used to explicitly indicate whether the server should skip 645 * the password validation processing that it may otherwise perform 646 * for the new password. 647 * </LI> 648 * <LI> 649 * {@code ignore-password-history} -- An optional Boolean field that 650 * may be used to explicitly indicate whether the server should ignore 651 * the user's password history when determining whether to accept the 652 * new password. 653 * </LI> 654 * <LI> 655 * {@code ignore-minimum-password-age} -- An optional Boolean field 656 * that may be used to explicitly indicate whether the server should 657 * ignore any minimum password age constraints that may otherwise be 658 * in place for the user. 659 * </LI> 660 * <LI> 661 * {@code password-storage-scheme} -- An optional string field whose 662 * value is the name of the password storage scheme that the server 663 * should use when encoding the new password. 664 * </LI> 665 * <LI> 666 * {@code must-change-password} -- An optional Boolean field that may 667 * be used to explicitly indicate whether the server should require 668 * the user to change their password before they will be allowed to 669 * request any other operations. 670 * </LI> 671 * </UL> 672 * </LI> 673 * </UL> 674 * 675 * @return A JSON object that contains a representation of this control. 676 */ 677 @Override() 678 @NotNull() 679 public JSONObject toJSONControl() 680 { 681 final Map<String,JSONValue> valueFields = new LinkedHashMap<>(); 682 683 if (isSelfChange != null) 684 { 685 valueFields.put(JSON_FIELD_IS_SELF_CHANGE, new JSONBoolean(isSelfChange)); 686 } 687 688 if (allowPreEncodedPassword != null) 689 { 690 valueFields.put(JSON_FIELD_ALLOW_PRE_ENCODED_PASSWORD, 691 new JSONBoolean(allowPreEncodedPassword)); 692 } 693 694 if (skipPasswordValidation != null) 695 { 696 valueFields.put(JSON_FIELD_SKIP_PASSWORD_VALIDATION, 697 new JSONBoolean(skipPasswordValidation)); 698 } 699 700 if (ignorePasswordHistory != null) 701 { 702 valueFields.put(JSON_FIELD_IGNORE_PASSWORD_HISTORY, 703 new JSONBoolean(ignorePasswordHistory)); 704 } 705 706 if (ignoreMinimumPasswordAge != null) 707 { 708 valueFields.put(JSON_FIELD_IGNORE_MINIMUM_PASSWORD_AGE, 709 new JSONBoolean(ignoreMinimumPasswordAge)); 710 } 711 712 if (passwordStorageScheme != null) 713 { 714 valueFields.put(JSON_FIELD_PASSWORD_STORAGE_SCHEME, 715 new JSONString(passwordStorageScheme)); 716 } 717 718 if (mustChangePassword != null) 719 { 720 valueFields.put(JSON_FIELD_MUST_CHANGE_PASSWORD, 721 new JSONBoolean(mustChangePassword)); 722 } 723 724 return new JSONObject( 725 new JSONField(JSONControlDecodeHelper.JSON_FIELD_OID, 726 PASSWORD_UPDATE_BEHAVIOR_REQUEST_OID), 727 new JSONField(JSONControlDecodeHelper.JSON_FIELD_CONTROL_NAME, 728 INFO_PW_UPDATE_BEHAVIOR_REQ_CONTROL_NAME.get()), 729 new JSONField(JSONControlDecodeHelper.JSON_FIELD_CRITICALITY, 730 isCritical()), 731 new JSONField(JSONControlDecodeHelper.JSON_FIELD_VALUE_JSON, 732 new JSONObject(valueFields))); 733 } 734 735 736 737 /** 738 * Attempts to decode the provided object as a JSON representation of a 739 * password update behavior control. 740 * 741 * @param controlObject The JSON object to be decoded. It must not be 742 * {@code null}. 743 * @param strict Indicates whether to use strict mode when decoding 744 * the provided JSON object. If this is {@code true}, 745 * then this method will throw an exception if the 746 * provided JSON object contains any unrecognized 747 * fields. If this is {@code false}, then unrecognized 748 * fields will be ignored. 749 * 750 * @return The password update behavior request control that was decoded from 751 * the provided JSON object. 752 * 753 * @throws LDAPException If the provided JSON object cannot be parsed as a 754 * valid password update behavior request control. 755 */ 756 @NotNull() 757 public static PasswordUpdateBehaviorRequestControl decodeJSONControl( 758 @NotNull final JSONObject controlObject, 759 final boolean strict) 760 throws LDAPException 761 { 762 final JSONControlDecodeHelper jsonControl = new JSONControlDecodeHelper( 763 controlObject, strict, true, true); 764 765 final ASN1OctetString rawValue = jsonControl.getRawValue(); 766 if (rawValue != null) 767 { 768 return new PasswordUpdateBehaviorRequestControl(new Control( 769 jsonControl.getOID(), jsonControl.getCriticality(), rawValue)); 770 } 771 772 773 final PasswordUpdateBehaviorRequestControlProperties properties = 774 new PasswordUpdateBehaviorRequestControlProperties(); 775 final JSONObject valueObject = jsonControl.getValueObject(); 776 777 final Boolean isSelfChange = 778 valueObject.getFieldAsBoolean(JSON_FIELD_IS_SELF_CHANGE); 779 if (isSelfChange != null) 780 { 781 properties.setIsSelfChange(isSelfChange); 782 } 783 784 final Boolean allowPreEncodedPassword = 785 valueObject.getFieldAsBoolean(JSON_FIELD_ALLOW_PRE_ENCODED_PASSWORD); 786 if (allowPreEncodedPassword != null) 787 { 788 properties.setAllowPreEncodedPassword(allowPreEncodedPassword); 789 } 790 791 final Boolean skipPasswordValidation = 792 valueObject.getFieldAsBoolean(JSON_FIELD_SKIP_PASSWORD_VALIDATION); 793 if (skipPasswordValidation != null) 794 { 795 properties.setSkipPasswordValidation(skipPasswordValidation); 796 } 797 798 final Boolean ignorePasswordHistory = 799 valueObject.getFieldAsBoolean(JSON_FIELD_IGNORE_PASSWORD_HISTORY); 800 if (ignorePasswordHistory != null) 801 { 802 properties.setIgnorePasswordHistory(ignorePasswordHistory); 803 } 804 805 final Boolean ignoreMinimumPasswordAge = 806 valueObject.getFieldAsBoolean(JSON_FIELD_IGNORE_MINIMUM_PASSWORD_AGE); 807 if (ignoreMinimumPasswordAge != null) 808 { 809 properties.setIgnoreMinimumPasswordAge(ignoreMinimumPasswordAge); 810 } 811 812 final String passwordStorageScheme = 813 valueObject.getFieldAsString(JSON_FIELD_PASSWORD_STORAGE_SCHEME); 814 if (passwordStorageScheme != null) 815 { 816 properties.setPasswordStorageScheme(passwordStorageScheme); 817 } 818 819 final Boolean mustChangePassword = 820 valueObject.getFieldAsBoolean(JSON_FIELD_MUST_CHANGE_PASSWORD); 821 if (mustChangePassword != null) 822 { 823 properties.setMustChangePassword(mustChangePassword); 824 } 825 826 827 if (strict) 828 { 829 final List<String> unrecognizedFields = 830 JSONControlDecodeHelper.getControlObjectUnexpectedFields( 831 valueObject, JSON_FIELD_IS_SELF_CHANGE, 832 JSON_FIELD_ALLOW_PRE_ENCODED_PASSWORD, 833 JSON_FIELD_SKIP_PASSWORD_VALIDATION, 834 JSON_FIELD_IGNORE_PASSWORD_HISTORY, 835 JSON_FIELD_IGNORE_MINIMUM_PASSWORD_AGE, 836 JSON_FIELD_PASSWORD_STORAGE_SCHEME, 837 JSON_FIELD_MUST_CHANGE_PASSWORD); 838 if (! unrecognizedFields.isEmpty()) 839 { 840 throw new LDAPException(ResultCode.DECODING_ERROR, 841 ERR_PW_UPDATE_BEHAVIOR_REQ_JSON_UNRECOGNIZED_FIELD.get( 842 controlObject.toSingleLineString(), 843 unrecognizedFields.get(0))); 844 } 845 } 846 847 848 return new PasswordUpdateBehaviorRequestControl(properties, 849 jsonControl.getCriticality()); 850 } 851 852 853 854 /** 855 * {@inheritDoc} 856 */ 857 @Override() 858 public void toString(@NotNull final StringBuilder buffer) 859 { 860 buffer.append("PasswordUpdateBehaviorRequestControl(oid='"); 861 buffer.append(PASSWORD_UPDATE_BEHAVIOR_REQUEST_OID); 862 buffer.append("', isCritical="); 863 buffer.append(isCritical()); 864 buffer.append(", properties="); 865 new PasswordUpdateBehaviorRequestControlProperties(this).toString(buffer); 866 buffer.append(')'); 867 } 868}