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.controls; 037 038 039 040import java.util.LinkedHashMap; 041import java.util.List; 042import java.util.Map; 043 044import com.unboundid.asn1.ASN1Element; 045import com.unboundid.asn1.ASN1OctetString; 046import com.unboundid.asn1.ASN1Sequence; 047import com.unboundid.ldap.sdk.Control; 048import com.unboundid.ldap.sdk.JSONControlDecodeHelper; 049import com.unboundid.ldap.sdk.LDAPException; 050import com.unboundid.ldap.sdk.ResultCode; 051import com.unboundid.util.NotMutable; 052import com.unboundid.util.NotNull; 053import com.unboundid.util.Nullable; 054import com.unboundid.util.ThreadSafety; 055import com.unboundid.util.ThreadSafetyLevel; 056import com.unboundid.util.json.JSONBoolean; 057import com.unboundid.util.json.JSONField; 058import com.unboundid.util.json.JSONObject; 059import com.unboundid.util.json.JSONString; 060import com.unboundid.util.json.JSONValue; 061 062import static com.unboundid.ldap.sdk.unboundidds.controls.ControlMessages.*; 063 064 065 066/** 067 * This class defines an intermediate client request control, which can be used 068 * to provide a server with information about the client and any downstream 069 * clients that it may have. It can be used to help trace operations from the 070 * client to the directory server, potentially through any intermediate hops 071 * (like proxy servers) that may also support the intermediate client controls. 072 * <BR> 073 * <BLOCKQUOTE> 074 * <B>NOTE:</B> This class, and other classes within the 075 * {@code com.unboundid.ldap.sdk.unboundidds} package structure, are only 076 * supported for use against Ping Identity, UnboundID, and 077 * Nokia/Alcatel-Lucent 8661 server products. These classes provide support 078 * for proprietary functionality or for external specifications that are not 079 * considered stable or mature enough to be guaranteed to work in an 080 * interoperable way with other types of LDAP servers. 081 * </BLOCKQUOTE> 082 * <BR> 083 * This control is not based on any public standard. It was originally 084 * developed for use with the Ping Identity, UnboundID, and Nokia/Alcatel-Lucent 085 * 8661 Directory Server. The value of this control uses the following 086 * encoding: 087 * <BR><BR> 088 * <PRE> 089 * IntermediateClientRequest ::= SEQUENCE { 090 * downstreamRequest [0] IntermediateClientRequest OPTIONAL, 091 * downstreamClientAddress [1] OCTET STRING OPTIONAL, 092 * downstreamClientSecure [2] BOOLEAN DEFAULT FALSE, 093 * clientIdentity [3] authzId OPTIONAL, 094 * clientName [4] OCTET STRING OPTIONAL, 095 * clientSessionID [5] OCTET STRING OPTIONAL, 096 * clientRequestID [6] OCTET STRING OPTIONAL, 097 * ... } 098 * </PRE> 099 * <H2>Example</H2> 100 * The following example demonstrates the use of the intermediate client 101 * controls to perform a search operation in the directory server. The request 102 * will be from an application named "my client" with a session ID of 103 * "session123" and a request ID of "request456": 104 * <PRE> 105 * SearchRequest searchRequest = new SearchRequest("dc=example,dc=com", 106 * SearchScope.SUB, Filter.createEqualityFilter("uid", "john.doe")); 107 * searchRequest.addControl(new IntermediateClientRequestControl(null, null, 108 * null, null, "my client", "session123", "request456")); 109 * SearchResult searchResult = connection.search(searchRequest); 110 * 111 * IntermediateClientResponseControl c = 112 * IntermediateClientResponseControl.get(searchResult); 113 * if (c != null) 114 * { 115 * // There was an intermediate client response control. 116 * IntermediateClientResponseValue responseValue = c.getResponseValue(); 117 * } 118 * </PRE> 119 */ 120@NotMutable() 121@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE) 122public final class IntermediateClientRequestControl 123 extends Control 124{ 125 /** 126 * The OID (1.3.6.1.4.1.30221.2.5.2) for the intermediate client request 127 * control. 128 */ 129 @NotNull public static final String INTERMEDIATE_CLIENT_REQUEST_OID = 130 "1.3.6.1.4.1.30221.2.5.2"; 131 132 133 134 /** 135 * The name of the field used to hold the client identity in the JSON 136 * representation of this control. 137 */ 138 @NotNull private static final String JSON_FIELD_CLIENT_IDENTITY = 139 "client-identity"; 140 141 142 143 /** 144 * The name of the field used to hold the client name in the JSON 145 * representation of this control. 146 */ 147 @NotNull private static final String JSON_FIELD_CLIENT_NAME = "client-name"; 148 149 150 151 /** 152 * The name of the field used to hold the client request ID in the JSON 153 * representation of this control. 154 */ 155 @NotNull private static final String JSON_FIELD_CLIENT_REQUEST_ID = 156 "client-request-id"; 157 158 159 160 /** 161 * The name of the field used to hold the client session ID in the JSON 162 * representation of this control. 163 */ 164 @NotNull private static final String JSON_FIELD_CLIENT_SESSION_ID = 165 "client-session-id"; 166 167 168 169 /** 170 * The name of the field used to hold the downstream client address in the 171 * JSON representation of this control. 172 */ 173 @NotNull private static final String JSON_FIELD_DOWNSTREAM_CLIENT_ADDRESS = 174 "downstream-client-address"; 175 176 177 178 /** 179 * The name of the field used to hold the downstream client secure flag in the 180 * JSON representation of this control. 181 */ 182 @NotNull private static final String JSON_FIELD_DOWNSTREAM_CLIENT_SECURE = 183 "downstream-client-secure"; 184 185 186 187 /** 188 * The name of the field used to hold the downstream request in the JSON 189 * representation of this control. 190 */ 191 @NotNull private static final String JSON_FIELD_DOWNSTREAM_REQUEST = 192 "downstream-request"; 193 194 195 196 /** 197 * The serial version UID for this serializable class. 198 */ 199 private static final long serialVersionUID = 4883725840393001578L; 200 201 202 203 // The value for this intermediate client request control. 204 @NotNull private final IntermediateClientRequestValue value; 205 206 207 208 /** 209 * Creates a new intermediate client request control with the provided 210 * information. It will be marked critical. 211 * 212 * @param downstreamRequest A wrapped intermediate client request from 213 * a downstream client. It may be 214 * {@code null} if there is no downstream 215 * request. 216 * @param downstreamClientAddress The IP address or resolvable name of the 217 * downstream client system. It may be 218 * {@code null} if there is no downstream 219 * client or its address is not available. 220 * @param downstreamClientSecure Indicates whether communication with the 221 * downstream client is secure. It may be 222 * {@code null} if there is no downstream 223 * client or it is not known whether the 224 * communication is secure. 225 * @param clientIdentity The requested client authorization 226 * identity. It may be {@code null} if there 227 * is no requested authorization identity. 228 * @param clientName An identifier string that summarizes the 229 * client application that created this 230 * intermediate client request. It may be 231 * {@code null} if that information is not 232 * available. 233 * @param clientSessionID A string that may be used to identify the 234 * session in the client application. It may 235 * be {@code null} if there is no available 236 * session identifier. 237 * @param clientRequestID A string that may be used to identify the 238 * request in the client application. It may 239 * be {@code null} if there is no available 240 * request identifier. 241 */ 242 public IntermediateClientRequestControl( 243 @Nullable final IntermediateClientRequestValue downstreamRequest, 244 @Nullable final String downstreamClientAddress, 245 @Nullable final Boolean downstreamClientSecure, 246 @Nullable final String clientIdentity, 247 @Nullable final String clientName, 248 @Nullable final String clientSessionID, 249 @Nullable final String clientRequestID) 250 { 251 this(true, 252 new IntermediateClientRequestValue(downstreamRequest, 253 downstreamClientAddress, downstreamClientSecure, 254 clientIdentity, clientName, clientSessionID, 255 clientRequestID)); 256 } 257 258 259 260 /** 261 * Creates a new intermediate client request control with the provided value. 262 * It will be marked critical. 263 * 264 * @param value The value to use for this intermediate client request 265 * control. It must not be {@code null}. 266 */ 267 public IntermediateClientRequestControl( 268 @NotNull final IntermediateClientRequestValue value) 269 { 270 this(true, value); 271 } 272 273 274 275 /** 276 * Creates a new intermediate client request control with the provided value. 277 * 278 * @param isCritical Indicates whether the control should be marked 279 * critical. 280 * @param value The value to use for this intermediate client request 281 * control. It must not be {@code null}. 282 */ 283 public IntermediateClientRequestControl(final boolean isCritical, 284 @NotNull final IntermediateClientRequestValue value) 285 { 286 super(INTERMEDIATE_CLIENT_REQUEST_OID, isCritical, 287 new ASN1OctetString(value.encode().encode())); 288 289 this.value = value; 290 } 291 292 293 294 /** 295 * Creates a new intermediate client request control which is decoded from the 296 * provided generic control. 297 * 298 * @param control The generic control to be decoded as an intermediate 299 * client request control. 300 * 301 * @throws LDAPException If the provided control cannot be decoded as an 302 * intermediate client request control. 303 */ 304 public IntermediateClientRequestControl(@NotNull final Control control) 305 throws LDAPException 306 { 307 super(control); 308 309 final ASN1OctetString controlValue = control.getValue(); 310 if (controlValue == null) 311 { 312 throw new LDAPException(ResultCode.DECODING_ERROR, 313 ERR_ICREQ_CONTROL_NO_VALUE.get()); 314 } 315 316 final ASN1Sequence valueSequence; 317 try 318 { 319 final ASN1Element valueElement = 320 ASN1Element.decode(controlValue.getValue()); 321 valueSequence = ASN1Sequence.decodeAsSequence(valueElement); 322 } 323 catch (final Exception e) 324 { 325 throw new LDAPException(ResultCode.DECODING_ERROR, 326 ERR_ICREQ_CONTROL_VALUE_NOT_SEQUENCE.get(e), e); 327 } 328 329 value = IntermediateClientRequestValue.decode(valueSequence); 330 } 331 332 333 334 /** 335 * Retrieves the value for this intermediate client request. 336 * 337 * @return The value for this intermediate client request. 338 */ 339 @NotNull() 340 public IntermediateClientRequestValue getRequestValue() 341 { 342 return value; 343 } 344 345 346 347 /** 348 * Retrieves the wrapped request from a downstream client, if available. 349 * 350 * @return The wrapped request from a downstream client, or {@code null} if 351 * there is none. 352 */ 353 @Nullable() 354 public IntermediateClientRequestValue getDownstreamRequest() 355 { 356 return value.getDownstreamRequest(); 357 } 358 359 360 361 /** 362 * Retrieves the requested client authorization identity, if available. 363 * 364 * @return The requested client authorization identity, or {@code null} if 365 * there is none. 366 */ 367 @Nullable() 368 public String getClientIdentity() 369 { 370 return value.getClientIdentity(); 371 } 372 373 374 375 /** 376 * Retrieves the IP address or resolvable name of the downstream client 377 * system, if available. 378 * 379 * @return The IP address or resolvable name of the downstream client system, 380 * or {@code null} if there is no downstream client or its address is 381 * not available. 382 */ 383 @Nullable() 384 public String getDownstreamClientAddress() 385 { 386 return value.getDownstreamClientAddress(); 387 } 388 389 390 391 /** 392 * Indicates whether the communication with the communication with the 393 * downstream client is secure (i.e., whether communication between the 394 * client application and the downstream client is safe from interpretation or 395 * undetectable alteration by a third party observer or interceptor). 396 * 397 * 398 * @return {@code Boolean.TRUE} if communication with the downstream client 399 * is secure, {@code Boolean.FALSE} if it is not secure, or 400 * {@code null} if there is no downstream client or it is not known 401 * whether the communication is secure. 402 */ 403 @Nullable() 404 public Boolean downstreamClientSecure() 405 { 406 return value.downstreamClientSecure(); 407 } 408 409 410 411 /** 412 * Retrieves a string that identifies the client application that created this 413 * intermediate client request value. 414 * 415 * @return A string that may be used to identify the client application that 416 * created this intermediate client request value. 417 */ 418 @Nullable() 419 public String getClientName() 420 { 421 return value.getClientName(); 422 } 423 424 425 426 /** 427 * Retrieves a string that may be used to identify the session in the client 428 * application. 429 * 430 * @return A string that may be used to identify the session in the client 431 * application, or {@code null} if there is none. 432 */ 433 @Nullable() 434 public String getClientSessionID() 435 { 436 return value.getClientSessionID(); 437 } 438 439 440 441 /** 442 * Retrieves a string that may be used to identify the request in the client 443 * application. 444 * 445 * @return A string that may be used to identify the request in the client 446 * application, or {@code null} if there is none. 447 */ 448 @Nullable() 449 public String getClientRequestID() 450 { 451 return value.getClientRequestID(); 452 } 453 454 455 456 /** 457 * {@inheritDoc} 458 */ 459 @Override() 460 @NotNull() 461 public String getControlName() 462 { 463 return INFO_CONTROL_NAME_INTERMEDIATE_CLIENT_REQUEST.get(); 464 } 465 466 467 468 /** 469 * Retrieves a representation of this intermediate client request control as a 470 * JSON object. The JSON object uses the following fields: 471 * <UL> 472 * <LI> 473 * {@code oid} -- A mandatory string field whose value is the object 474 * identifier for this control. For the intermediate client request 475 * control, the OID is "1.3.6.1.4.1.30221.2.5.2". 476 * </LI> 477 * <LI> 478 * {@code control-name} -- An optional string field whose value is a 479 * human-readable name for this control. This field is only intended for 480 * descriptive purposes, and when decoding a control, the {@code oid} 481 * field should be used to identify the type of control. 482 * </LI> 483 * <LI> 484 * {@code criticality} -- A mandatory Boolean field used to indicate 485 * whether this control is considered critical. 486 * </LI> 487 * <LI> 488 * {@code value-base64} -- An optional string field whose value is a 489 * base64-encoded representation of the raw value for this intermediate 490 * client request control. Exactly one of the {@code value-base64} and 491 * {@code value-json} fields must be present. 492 * </LI> 493 * <LI> 494 * {@code value-json} -- An optional JSON object field whose value is a 495 * user-friendly representation of the value for this intermediate client 496 * request control. Exactly one of the {@code value-base64} and 497 * {@code value-json} fields must be present, and if the 498 * {@code value-json} field is used, then it will use the following 499 * fields: 500 * <UL> 501 * <LI> 502 * {@code downstream-request} -- An optional JSON object field whose 503 * content represents a downstream request value. If present, the 504 * fields of this object are the same as the fields that may be 505 * included in the top-level {@code value-json} object (optionally 506 * including a nested {@code downstream-request} field, if 507 * appropriate). 508 * </LI> 509 * <LI> 510 * {@code downstream-client-address} -- An optional string field whose 511 * value is the address of the immediate client from which the request 512 * was received. 513 * </LI> 514 * <LI> 515 * {@code downstream-client-secure} -- An optional Boolean field that 516 * indicates whether communication with the immediate client is using 517 * a secure channel. 518 * </LI> 519 * <LI> 520 * {@code client-identity} -- An optional string field whose value is 521 * the authorization identity of a user as whom the operation should 522 * be authorized. 523 * </LI> 524 * <LI> 525 * {@code client-name} -- An optional string field whose value is the 526 * name of the client application that generated this control. 527 * </LI> 528 * <LI> 529 * {@code client-session-id} -- An optional string field whose value 530 * is an identifier that the client is using to reference the current 531 * communication session with a downstream client. 532 * </LI> 533 * <LI> 534 * {@code client-request-id} -- An optional string field whose value 535 * is an identifier that the client is using to reference this request 536 * from a downstream client. 537 * </LI> 538 * </UL> 539 * </LI> 540 * </UL> 541 * 542 * @return A JSON object that contains a representation of this control. 543 */ 544 @Override() 545 @NotNull() 546 public JSONObject toJSONControl() 547 { 548 return new JSONObject( 549 new JSONField(JSONControlDecodeHelper.JSON_FIELD_OID, 550 INTERMEDIATE_CLIENT_REQUEST_OID), 551 new JSONField(JSONControlDecodeHelper.JSON_FIELD_CONTROL_NAME, 552 INFO_CONTROL_NAME_INTERMEDIATE_CLIENT_REQUEST.get()), 553 new JSONField(JSONControlDecodeHelper.JSON_FIELD_CRITICALITY, 554 isCritical()), 555 new JSONField(JSONControlDecodeHelper.JSON_FIELD_VALUE_JSON, 556 encodeRequestValueJSON(value))); 557 } 558 559 560 561 /** 562 * Encodes the provided intermediate client request value to a JSON object. 563 * 564 * @param value The intermediate client request value to be encoded. It 565 * must not be {@code null}. 566 * 567 * @return The JSON object containing the encoded intermediate client 568 * request value. 569 */ 570 @NotNull() 571 private static JSONObject encodeRequestValueJSON( 572 @NotNull final IntermediateClientRequestValue value) 573 { 574 final Map<String,JSONValue> fields = new LinkedHashMap<>(); 575 576 final IntermediateClientRequestValue downstreamRequest = 577 value.getDownstreamRequest(); 578 if (downstreamRequest != null) 579 { 580 fields.put(JSON_FIELD_DOWNSTREAM_REQUEST, 581 encodeRequestValueJSON(downstreamRequest)); 582 } 583 584 final String downstreamClientAddress = value.getDownstreamClientAddress(); 585 if (downstreamClientAddress != null) 586 { 587 fields.put(JSON_FIELD_DOWNSTREAM_CLIENT_ADDRESS, 588 new JSONString(downstreamClientAddress)); 589 } 590 591 final Boolean downstreamClientSecure = value.downstreamClientSecure(); 592 if (downstreamClientSecure != null) 593 { 594 fields.put(JSON_FIELD_DOWNSTREAM_CLIENT_SECURE, 595 new JSONBoolean(downstreamClientSecure)); 596 } 597 598 final String clientIdentity = value.getClientIdentity(); 599 if (clientIdentity != null) 600 { 601 fields.put(JSON_FIELD_CLIENT_IDENTITY, new JSONString(clientIdentity)); 602 } 603 604 final String clientName = value.getClientName(); 605 if (clientName != null) 606 { 607 fields.put(JSON_FIELD_CLIENT_NAME, new JSONString(clientName)); 608 } 609 610 final String clientSessionID = value.getClientSessionID(); 611 if (clientSessionID != null) 612 { 613 fields.put(JSON_FIELD_CLIENT_SESSION_ID, new JSONString(clientSessionID)); 614 } 615 616 final String clientRequestID = value.getClientRequestID(); 617 if (clientRequestID != null) 618 { 619 fields.put(JSON_FIELD_CLIENT_REQUEST_ID, new JSONString(clientRequestID)); 620 } 621 622 return new JSONObject(fields); 623 } 624 625 626 627 /** 628 * Attempts to decode the provided object as a JSON representation of an 629 * intermediate client request control. 630 * 631 * @param controlObject The JSON object to be decoded. It must not be 632 * {@code null}. 633 * @param strict Indicates whether to use strict mode when decoding 634 * the provided JSON object. If this is {@code true}, 635 * then this method will throw an exception if the 636 * provided JSON object contains any unrecognized 637 * fields. If this is {@code false}, then unrecognized 638 * fields will be ignored. 639 * 640 * @return The intermediate client request control that was decoded from 641 * the provided JSON object. 642 * 643 * @throws LDAPException If the provided JSON object cannot be parsed as a 644 * valid intermediate client request control. 645 */ 646 @NotNull() 647 public static IntermediateClientRequestControl decodeJSONControl( 648 @NotNull final JSONObject controlObject, 649 final boolean strict) 650 throws LDAPException 651 { 652 final JSONControlDecodeHelper jsonControl = new JSONControlDecodeHelper( 653 controlObject, strict, true, true); 654 655 final ASN1OctetString rawValue = jsonControl.getRawValue(); 656 if (rawValue != null) 657 { 658 return new IntermediateClientRequestControl(new Control( 659 jsonControl.getOID(), jsonControl.getCriticality(), rawValue)); 660 } 661 662 663 final IntermediateClientRequestValue value = 664 decodeIntermediateClientRequestValueJSON(controlObject, 665 jsonControl.getValueObject(), false, strict); 666 return new IntermediateClientRequestControl(jsonControl.getCriticality(), 667 value); 668 } 669 670 671 672 /** 673 * Decodes the provided JSON Object as an intermediate client request value. 674 * 675 * @param controlObject The JSON object that represents the entire 676 * intermediate client request control. It must 677 * not be {@code null}. 678 * @param valueObject The intermediate client request value to 679 * decode. It must not be {@code null}. 680 * @param isDownstreamRequest Indicates whether the provided JSON object 681 * represents a downstream request. 682 * @param strict Indicates whether to use strict mode when 683 * decoding the provided JSON object. If this is 684 * {@code true}, then this method will throw an 685 * exception if the provided JSON object contains 686 * any unrecognized fields. If this is 687 * {@code false}, then unrecognized fields will 688 * be ignored. 689 * 690 * @return The intermediate client request value that was decoded. 691 * 692 * @throws LDAPException If the provided JSON object cannot be decoded as an 693 * intermediate client request value. 694 */ 695 @NotNull() 696 private static IntermediateClientRequestValue 697 decodeIntermediateClientRequestValueJSON( 698 @NotNull final JSONObject controlObject, 699 @NotNull final JSONObject valueObject, 700 final boolean isDownstreamRequest, 701 final boolean strict) 702 throws LDAPException 703 { 704 final IntermediateClientRequestValue downstreamRequest; 705 final JSONObject downstreamRequestObject = 706 valueObject.getFieldAsObject(JSON_FIELD_DOWNSTREAM_REQUEST); 707 if (downstreamRequestObject == null) 708 { 709 downstreamRequest = null; 710 } 711 else 712 { 713 downstreamRequest = decodeIntermediateClientRequestValueJSON( 714 controlObject, downstreamRequestObject, true, strict); 715 } 716 717 final String downstreamClientAddress = 718 valueObject.getFieldAsString(JSON_FIELD_DOWNSTREAM_CLIENT_ADDRESS); 719 final Boolean downstreamClientSecure = 720 valueObject.getFieldAsBoolean(JSON_FIELD_DOWNSTREAM_CLIENT_SECURE); 721 final String clientIdentity = 722 valueObject.getFieldAsString(JSON_FIELD_CLIENT_IDENTITY); 723 final String clientName = 724 valueObject.getFieldAsString(JSON_FIELD_CLIENT_NAME); 725 final String clientSessionID = 726 valueObject.getFieldAsString(JSON_FIELD_CLIENT_SESSION_ID); 727 final String clientRequestID = 728 valueObject.getFieldAsString(JSON_FIELD_CLIENT_REQUEST_ID); 729 730 731 732 if (strict) 733 { 734 final List<String> unrecognizedFields = 735 JSONControlDecodeHelper.getControlObjectUnexpectedFields( 736 valueObject, JSON_FIELD_DOWNSTREAM_REQUEST, 737 JSON_FIELD_DOWNSTREAM_CLIENT_ADDRESS, 738 JSON_FIELD_DOWNSTREAM_CLIENT_SECURE, 739 JSON_FIELD_CLIENT_IDENTITY, 740 JSON_FIELD_CLIENT_NAME, 741 JSON_FIELD_CLIENT_SESSION_ID, 742 JSON_FIELD_CLIENT_REQUEST_ID); 743 if (! unrecognizedFields.isEmpty()) 744 { 745 if (isDownstreamRequest) 746 { 747 throw new LDAPException(ResultCode.DECODING_ERROR, 748 ERR_INTERMEDIATE_CLIENT_REQUEST_JSON_DS_VALUE_UNRECOGNIZED_FIELD. 749 get(controlObject.toSingleLineString(), 750 unrecognizedFields.get(0))); 751 } 752 else 753 { 754 throw new LDAPException(ResultCode.DECODING_ERROR, 755 ERR_INTERMEDIATE_CLIENT_REQUEST_JSON_VALUE_UNRECOGNIZED_FIELD. 756 get(controlObject.toSingleLineString(), 757 unrecognizedFields.get(0))); 758 } 759 } 760 } 761 762 763 return new IntermediateClientRequestValue(downstreamRequest, 764 downstreamClientAddress, downstreamClientSecure, clientIdentity, 765 clientName, clientSessionID, clientRequestID); 766 } 767 768 769 770 /** 771 * {@inheritDoc} 772 */ 773 @Override() 774 public void toString(@NotNull final StringBuilder buffer) 775 { 776 buffer.append("IntermediateClientRequestControl(isCritical="); 777 buffer.append(isCritical()); 778 buffer.append(", value="); 779 value.toString(buffer); 780 buffer.append(')'); 781 } 782}