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.controls; 037 038 039 040import java.io.Serializable; 041import java.util.ArrayList; 042 043import com.unboundid.asn1.ASN1Boolean; 044import com.unboundid.asn1.ASN1Constants; 045import com.unboundid.asn1.ASN1Element; 046import com.unboundid.asn1.ASN1OctetString; 047import com.unboundid.asn1.ASN1Sequence; 048import com.unboundid.ldap.sdk.LDAPException; 049import com.unboundid.ldap.sdk.ResultCode; 050import com.unboundid.util.Debug; 051import com.unboundid.util.NotMutable; 052import com.unboundid.util.StaticUtils; 053import com.unboundid.util.ThreadSafety; 054import com.unboundid.util.ThreadSafetyLevel; 055 056import static com.unboundid.ldap.sdk.unboundidds.controls.ControlMessages.*; 057 058 059 060/** 061 * This class implements a data structure which encapsulates the value of an 062 * intermediate client response value. It may recursively embed intermediate 063 * client response values from upstream servers. 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 * See the documentation in the {@link IntermediateClientRequestControl} class 076 * for an example of using the intermediate client request and response 077 * controls. 078 */ 079@NotMutable() 080@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE) 081public final class IntermediateClientResponseValue 082 implements Serializable 083{ 084 /** 085 * The BER type for the upstreamResponse element. 086 */ 087 private static final byte TYPE_UPSTREAM_RESPONSE = (byte) 0xA0; 088 089 090 091 /** 092 * The BER type for the upstreamServerAddress element. 093 */ 094 private static final byte TYPE_UPSTREAM_SERVER_ADDRESS = (byte) 0x81; 095 096 097 098 /** 099 * The BER type for the upstreamServerSecure element. 100 */ 101 private static final byte TYPE_UPSTREAM_SERVER_SECURE = (byte) 0x82; 102 103 104 105 /** 106 * The BER type for the serverName element. 107 */ 108 private static final byte TYPE_SERVER_NAME = (byte) 0x83; 109 110 111 112 /** 113 * The BER type for the serverSessionID element. 114 */ 115 private static final byte TYPE_SERVER_SESSION_ID = (byte) 0x84; 116 117 118 119 /** 120 * The BER type for the serverResponseID element. 121 */ 122 private static final byte TYPE_SERVER_RESPONSE_ID = (byte) 0x85; 123 124 125 126 /** 127 * The serial version UID for this serializable class. 128 */ 129 private static final long serialVersionUID = 5165171788442351399L; 130 131 132 133 // Indicates whether communication with the upstream server is secure. 134 private final Boolean upstreamServerSecure; 135 136 // The upstream response, if available. 137 private final IntermediateClientResponseValue upstreamResponse; 138 139 // The server name, which describes the server application, if present. 140 private final String serverName; 141 142 // The server response ID, if present. 143 private final String serverResponseID; 144 145 // The server session ID, if present. 146 private final String serverSessionID; 147 148 // The address of the upstream server, if available. 149 private final String upstreamServerAddress; 150 151 152 153 /** 154 * Creates a new intermediate client response value with the provided 155 * information. 156 * 157 * @param upstreamResponse A wrapped intermediate client response from 158 * an upstream server. It may be {@code null} 159 * if there is no wrapped upstream response. 160 * @param upstreamServerAddress The IP address or resolvable name of the 161 * upstream server system. It may be 162 * {@code null} if there is no upstream server 163 * or its address is not available. 164 * @param upstreamServerSecure Indicates whether communication with the 165 * upstream server is secure. It may be 166 * {@code null} if there is no upstream server 167 * or it is not known whether the communication 168 * is secure. 169 * @param serverName An identifier string that summarizes the 170 * server application that created this 171 * intermediate client response. It may be 172 * {@code null} if that information is not 173 * available. 174 * @param serverSessionID A string that may be used to identify the 175 * session in the server application. It may 176 * be {@code null} if there is no available 177 * session identifier. 178 * @param serverResponseID A string that may be used to identify the 179 * response in the server application. It may 180 * be {@code null} if there is no available 181 * response identifier. 182 */ 183 public IntermediateClientResponseValue( 184 final IntermediateClientResponseValue upstreamResponse, 185 final String upstreamServerAddress, 186 final Boolean upstreamServerSecure, final String serverName, 187 final String serverSessionID, final String serverResponseID) 188 { 189 this.upstreamResponse = upstreamResponse; 190 this.upstreamServerAddress = upstreamServerAddress; 191 this.upstreamServerSecure = upstreamServerSecure; 192 this.serverName = serverName; 193 this.serverSessionID = serverSessionID; 194 this.serverResponseID = serverResponseID; 195 } 196 197 198 199 /** 200 * Retrieves the wrapped response from an upstream server, if available. 201 * 202 * @return The wrapped response from an upstream server, or {@code null} if 203 * there is none. 204 */ 205 public IntermediateClientResponseValue getUpstreamResponse() 206 { 207 return upstreamResponse; 208 } 209 210 211 212 /** 213 * Retrieves the IP address or resolvable name of the upstream server system, 214 * if available. 215 * 216 * @return The IP address or resolvable name of the upstream server system, 217 * {@code null} if there is no upstream server or its address is not 218 * available. 219 */ 220 public String getUpstreamServerAddress() 221 { 222 return upstreamServerAddress; 223 } 224 225 226 227 /** 228 * Indicates whether the communication with the communication with the 229 * upstream server is secure (i.e., whether communication between the 230 * server application and the upstream server is safe from interpretation or 231 * undetectable alteration by a third party observer or interceptor). 232 * 233 * 234 * @return {@code Boolean.TRUE} if communication with the upstream server is 235 * secure, {@code Boolean.FALSE} if it is not secure, or 236 * {@code null} if there is no upstream server or it is not known 237 * whether the communication is secure. 238 */ 239 public Boolean upstreamServerSecure() 240 { 241 return upstreamServerSecure; 242 } 243 244 245 246 /** 247 * Retrieves a string that identifies the server application that created this 248 * intermediate client response value. 249 * 250 * @return A string that may be used to identify the server application that 251 * created this intermediate client response value. 252 */ 253 public String getServerName() 254 { 255 return serverName; 256 } 257 258 259 260 /** 261 * Retrieves a string that may be used to identify the session in the server 262 * application. 263 * 264 * @return A string that may be used to identify the session in the server 265 * application, or {@code null} if there is none. 266 */ 267 public String getServerSessionID() 268 { 269 return serverSessionID; 270 } 271 272 273 274 /** 275 * Retrieves a string that may be used to identify the response in the server 276 * application. 277 * 278 * @return A string that may be used to identify the response in the server 279 * application, or {@code null} if there is none. 280 */ 281 public String getServerResponseID() 282 { 283 return serverResponseID; 284 } 285 286 287 288 /** 289 * Encodes this intermediate client response value to a form that may be 290 * included in the response control. 291 * 292 * @return An ASN.1 octet string containing the encoded client response 293 * value. 294 */ 295 public ASN1Sequence encode() 296 { 297 return encode(ASN1Constants.UNIVERSAL_SEQUENCE_TYPE); 298 } 299 300 301 302 /** 303 * Encodes this intermediate client response value to a form that may be 304 * included in the response control. 305 * 306 * @param type The BER type to use for this element. 307 * 308 * @return An ASN.1 octet string containing the encoded client response 309 * value. 310 */ 311 private ASN1Sequence encode(final byte type) 312 { 313 final ArrayList<ASN1Element> elements = new ArrayList<>(6); 314 315 if (upstreamResponse != null) 316 { 317 elements.add(upstreamResponse.encode(TYPE_UPSTREAM_RESPONSE)); 318 } 319 320 if (upstreamServerAddress != null) 321 { 322 elements.add(new ASN1OctetString(TYPE_UPSTREAM_SERVER_ADDRESS, 323 upstreamServerAddress)); 324 } 325 326 if (upstreamServerSecure != null) 327 { 328 elements.add(new ASN1Boolean(TYPE_UPSTREAM_SERVER_SECURE, 329 upstreamServerSecure)); 330 } 331 332 if (serverName != null) 333 { 334 elements.add(new ASN1OctetString(TYPE_SERVER_NAME, serverName)); 335 } 336 337 if (serverSessionID != null) 338 { 339 elements.add(new ASN1OctetString(TYPE_SERVER_SESSION_ID, 340 serverSessionID)); 341 } 342 343 if (serverResponseID != null) 344 { 345 elements.add(new ASN1OctetString(TYPE_SERVER_RESPONSE_ID, 346 serverResponseID)); 347 } 348 349 return new ASN1Sequence(type, elements); 350 } 351 352 353 354 /** 355 * Decodes the provided ASN.1 sequence as an intermediate client response 356 * value. 357 * 358 * @param sequence The sequence to be decoded as an intermediate client 359 * response value. 360 * 361 * @return The decoded intermediate client response value. 362 * 363 * @throws LDAPException If the provided sequence cannot be decoded as an 364 * intermediate client response value. 365 */ 366 public static IntermediateClientResponseValue 367 decode(final ASN1Sequence sequence) 368 throws LDAPException 369 { 370 Boolean upstreamServerSecure = null; 371 IntermediateClientResponseValue upstreamResponse = null; 372 String upstreamServerAddress = null; 373 String serverName = null; 374 String serverResponseID = null; 375 String serverSessionID = null; 376 377 for (final ASN1Element element : sequence.elements()) 378 { 379 switch (element.getType()) 380 { 381 case TYPE_UPSTREAM_RESPONSE: 382 try 383 { 384 final ASN1Sequence s = ASN1Sequence.decodeAsSequence(element); 385 upstreamResponse = decode(s); 386 } 387 catch (final LDAPException le) 388 { 389 Debug.debugException(le); 390 throw new LDAPException(ResultCode.DECODING_ERROR, 391 ERR_ICRESP_CANNOT_DECODE_UPSTREAM_RESPONSE.get( 392 le.getMessage()), le); 393 } 394 catch (final Exception e) 395 { 396 Debug.debugException(e); 397 throw new LDAPException(ResultCode.DECODING_ERROR, 398 ERR_ICRESP_CANNOT_DECODE_UPSTREAM_RESPONSE.get( 399 StaticUtils.getExceptionMessage(e)), 400 e); 401 } 402 break; 403 404 case TYPE_UPSTREAM_SERVER_ADDRESS: 405 upstreamServerAddress = 406 ASN1OctetString.decodeAsOctetString(element).stringValue(); 407 break; 408 409 case TYPE_UPSTREAM_SERVER_SECURE: 410 try 411 { 412 upstreamServerSecure = 413 ASN1Boolean.decodeAsBoolean(element).booleanValue(); 414 } 415 catch (final Exception e) 416 { 417 Debug.debugException(e); 418 throw new LDAPException(ResultCode.DECODING_ERROR, 419 ERR_ICRESP_CANNOT_DECODE_UPSTREAM_SECURE.get( 420 StaticUtils.getExceptionMessage(e)), 421 e); 422 } 423 break; 424 425 case TYPE_SERVER_NAME: 426 serverName = 427 ASN1OctetString.decodeAsOctetString(element).stringValue(); 428 break; 429 430 case TYPE_SERVER_SESSION_ID: 431 serverSessionID = 432 ASN1OctetString.decodeAsOctetString(element).stringValue(); 433 break; 434 435 case TYPE_SERVER_RESPONSE_ID: 436 serverResponseID = 437 ASN1OctetString.decodeAsOctetString(element).stringValue(); 438 break; 439 440 default: 441 throw new LDAPException(ResultCode.DECODING_ERROR, 442 ERR_ICRESP_INVALID_ELEMENT_TYPE.get( 443 StaticUtils.toHex(element.getType()))); 444 } 445 } 446 447 return new IntermediateClientResponseValue(upstreamResponse, 448 upstreamServerAddress, 449 upstreamServerSecure, 450 serverName, serverSessionID, 451 serverResponseID); 452 } 453 454 455 456 /** 457 * Generates a hash code for this intermediate client response value. 458 * 459 * @return A hash code for this intermediate client response value. 460 */ 461 @Override() 462 public int hashCode() 463 { 464 int hashCode = 0; 465 466 if (upstreamResponse != null) 467 { 468 hashCode += upstreamResponse.hashCode(); 469 } 470 471 if (upstreamServerAddress != null) 472 { 473 hashCode += upstreamServerAddress.hashCode(); 474 } 475 476 if (upstreamServerSecure != null) 477 { 478 hashCode += upstreamServerSecure.hashCode(); 479 } 480 481 if (serverName != null) 482 { 483 hashCode += serverName.hashCode(); 484 } 485 486 if (serverSessionID != null) 487 { 488 hashCode += serverSessionID.hashCode(); 489 } 490 491 if (serverResponseID != null) 492 { 493 hashCode += serverResponseID.hashCode(); 494 } 495 496 return hashCode; 497 } 498 499 500 501 /** 502 * Indicates whether the provided object is equal to this intermediate client 503 * response value. It will only be considered equal if the provided object is 504 * also an intermediate client response value with all the same fields. 505 * 506 * @param o The object for which to make the determination. 507 * 508 * @return {@code true} if the provided object is considered equal to this 509 * intermediate client response value, or {@code false} if not. 510 */ 511 @Override() 512 public boolean equals(final Object o) 513 { 514 if (o == this) 515 { 516 return true; 517 } 518 else if (o == null) 519 { 520 return false; 521 } 522 else if (! (o instanceof IntermediateClientResponseValue)) 523 { 524 return false; 525 } 526 527 final IntermediateClientResponseValue v = 528 (IntermediateClientResponseValue) o; 529 530 if (upstreamResponse == null) 531 { 532 if (v.upstreamResponse != null) 533 { 534 return false; 535 } 536 } 537 else 538 { 539 if (! upstreamResponse.equals(v.upstreamResponse)) 540 { 541 return false; 542 } 543 } 544 545 if (upstreamServerAddress == null) 546 { 547 if (v.upstreamServerAddress != null) 548 { 549 return false; 550 } 551 } 552 else 553 { 554 if (! upstreamServerAddress.equals(v.upstreamServerAddress)) 555 { 556 return false; 557 } 558 } 559 560 if (upstreamServerSecure == null) 561 { 562 if (v.upstreamServerSecure != null) 563 { 564 return false; 565 } 566 } 567 else 568 { 569 if (! upstreamServerSecure.equals(v.upstreamServerSecure)) 570 { 571 return false; 572 } 573 } 574 575 if (serverName == null) 576 { 577 if (v.serverName != null) 578 { 579 return false; 580 } 581 } 582 else 583 { 584 if (! serverName.equals(v.serverName)) 585 { 586 return false; 587 } 588 } 589 590 if (serverSessionID == null) 591 { 592 if (v.serverSessionID != null) 593 { 594 return false; 595 } 596 } 597 else 598 { 599 if (! serverSessionID.equals(v.serverSessionID)) 600 { 601 return false; 602 } 603 } 604 605 if (serverResponseID == null) 606 { 607 if (v.serverResponseID != null) 608 { 609 return false; 610 } 611 } 612 else 613 { 614 if (! serverResponseID.equals(v.serverResponseID)) 615 { 616 return false; 617 } 618 } 619 620 return true; 621 } 622 623 624 625 /** 626 * Retrieves a string representation of this intermediate client response 627 * value. 628 * 629 * @return A string representation of this intermediate client response 630 * value. 631 */ 632 @Override() 633 public String toString() 634 { 635 final StringBuilder buffer = new StringBuilder(); 636 toString(buffer); 637 return buffer.toString(); 638 } 639 640 641 642 /** 643 * Appends a string representation of this intermediate client response value 644 * to the provided buffer. 645 * 646 * @param buffer The buffer to which the information is to be appended. 647 */ 648 public void toString(final StringBuilder buffer) 649 { 650 buffer.append("IntermediateClientResponseValue("); 651 652 boolean added = false; 653 if (upstreamResponse != null) 654 { 655 buffer.append("upstreamResponse="); 656 upstreamResponse.toString(buffer); 657 added = true; 658 } 659 660 if (upstreamServerAddress != null) 661 { 662 if (added) 663 { 664 buffer.append(", "); 665 } 666 else 667 { 668 added = true; 669 } 670 671 buffer.append("upstreamServerAddress='"); 672 buffer.append(upstreamServerAddress); 673 buffer.append('\''); 674 } 675 676 if (upstreamServerSecure != null) 677 { 678 if (added) 679 { 680 buffer.append(", "); 681 } 682 else 683 { 684 added = true; 685 } 686 687 buffer.append("upstreamServerSecure='"); 688 buffer.append(upstreamServerSecure); 689 buffer.append('\''); 690 } 691 692 if (serverName != null) 693 { 694 if (added) 695 { 696 buffer.append(", "); 697 } 698 else 699 { 700 added = true; 701 } 702 703 buffer.append("serverName='"); 704 buffer.append(serverName); 705 buffer.append('\''); 706 } 707 708 if (serverSessionID != null) 709 { 710 if (added) 711 { 712 buffer.append(", "); 713 } 714 else 715 { 716 added = true; 717 } 718 719 buffer.append("serverSessionID='"); 720 buffer.append(serverSessionID); 721 buffer.append('\''); 722 } 723 724 if (serverResponseID != null) 725 { 726 if (added) 727 { 728 buffer.append(", "); 729 } 730 else 731 { 732 added = true; 733 } 734 735 buffer.append("serverResponseID='"); 736 buffer.append(serverResponseID); 737 buffer.append('\''); 738 } 739 740 buffer.append(')'); 741 } 742}