001/* 002 * Copyright 2008-2019 Ping Identity Corporation 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright (C) 2015-2019 Ping Identity Corporation 007 * 008 * This program is free software; you can redistribute it and/or modify 009 * it under the terms of the GNU General Public License (GPLv2 only) 010 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only) 011 * as published by the Free Software Foundation. 012 * 013 * This program is distributed in the hope that it will be useful, 014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 016 * GNU General Public License for more details. 017 * 018 * You should have received a copy of the GNU General Public License 019 * along with this program; if not, see <http://www.gnu.org/licenses>. 020 */ 021package com.unboundid.ldap.sdk.unboundidds.controls; 022 023 024 025import com.unboundid.asn1.ASN1Element; 026import com.unboundid.asn1.ASN1OctetString; 027import com.unboundid.asn1.ASN1Sequence; 028import com.unboundid.ldap.sdk.Control; 029import com.unboundid.ldap.sdk.LDAPException; 030import com.unboundid.ldap.sdk.ResultCode; 031import com.unboundid.util.NotMutable; 032import com.unboundid.util.ThreadSafety; 033import com.unboundid.util.ThreadSafetyLevel; 034 035import static com.unboundid.ldap.sdk.unboundidds.controls.ControlMessages.*; 036 037 038 039/** 040 * This class defines an intermediate client request control, which can be used 041 * to provide a server with information about the client and any downstream 042 * clients that it may have. It can be used to help trace operations from the 043 * client to the directory server, potentially through any intermediate hops 044 * (like proxy servers) that may also support the intermediate client controls. 045 * <BR> 046 * <BLOCKQUOTE> 047 * <B>NOTE:</B> This class, and other classes within the 048 * {@code com.unboundid.ldap.sdk.unboundidds} package structure, are only 049 * supported for use against Ping Identity, UnboundID, and 050 * Nokia/Alcatel-Lucent 8661 server products. These classes provide support 051 * for proprietary functionality or for external specifications that are not 052 * considered stable or mature enough to be guaranteed to work in an 053 * interoperable way with other types of LDAP servers. 054 * </BLOCKQUOTE> 055 * <BR> 056 * This control is not based on any public standard. It was originally 057 * developed for use with the Ping Identity, UnboundID, and Nokia/Alcatel-Lucent 058 * 8661 Directory Server. The value of this control uses the following 059 * encoding: 060 * <BR><BR> 061 * <PRE> 062 * IntermediateClientRequest ::= SEQUENCE { 063 * downstreamRequest [0] IntermediateClientRequest OPTIONAL, 064 * downstreamClientAddress [1] OCTET STRING OPTIONAL, 065 * downstreamClientSecure [2] BOOLEAN DEFAULT FALSE, 066 * clientIdentity [3] authzId OPTIONAL, 067 * clientName [4] OCTET STRING OPTIONAL, 068 * clientSessionID [5] OCTET STRING OPTIONAL, 069 * clientRequestID [6] OCTET STRING OPTIONAL, 070 * ... } 071 * </PRE> 072 * <H2>Example</H2> 073 * The following example demonstrates the use of the intermediate client 074 * controls to perform a search operation in the directory server. The request 075 * will be from an application named "my client" with a session ID of 076 * "session123" and a request ID of "request456": 077 * <PRE> 078 * SearchRequest searchRequest = new SearchRequest("dc=example,dc=com", 079 * SearchScope.SUB, Filter.createEqualityFilter("uid", "john.doe")); 080 * searchRequest.addControl(new IntermediateClientRequestControl(null, null, 081 * null, null, "my client", "session123", "request456")); 082 * SearchResult searchResult = connection.search(searchRequest); 083 * 084 * IntermediateClientResponseControl c = 085 * IntermediateClientResponseControl.get(searchResult); 086 * if (c != null) 087 * { 088 * // There was an intermediate client response control. 089 * IntermediateClientResponseValue responseValue = c.getResponseValue(); 090 * } 091 * </PRE> 092 */ 093@NotMutable() 094@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE) 095public final class IntermediateClientRequestControl 096 extends Control 097{ 098 /** 099 * The OID (1.3.6.1.4.1.30221.2.5.2) for the intermediate client request 100 * control. 101 */ 102 public static final String INTERMEDIATE_CLIENT_REQUEST_OID = 103 "1.3.6.1.4.1.30221.2.5.2"; 104 105 106 107 /** 108 * The serial version UID for this serializable class. 109 */ 110 private static final long serialVersionUID = 4883725840393001578L; 111 112 113 114 // The value for this intermediate client request control. 115 private final IntermediateClientRequestValue value; 116 117 118 119 /** 120 * Creates a new intermediate client request control with the provided 121 * information. It will be marked critical. 122 * 123 * @param downstreamRequest A wrapped intermediate client request from 124 * a downstream client. It may be 125 * {@code null} if there is no downstream 126 * request. 127 * @param downstreamClientAddress The IP address or resolvable name of the 128 * downstream client system. It may be 129 * {@code null} if there is no downstream 130 * client or its address is not available. 131 * @param downstreamClientSecure Indicates whether communication with the 132 * downstream client is secure. It may be 133 * {@code null} if there is no downstream 134 * client or it is not known whether the 135 * communication is secure. 136 * @param clientIdentity The requested client authorization 137 * identity. It may be {@code null} if there 138 * is no requested authorization identity. 139 * @param clientName An identifier string that summarizes the 140 * client application that created this 141 * intermediate client request. It may be 142 * {@code null} if that information is not 143 * available. 144 * @param clientSessionID A string that may be used to identify the 145 * session in the client application. It may 146 * be {@code null} if there is no available 147 * session identifier. 148 * @param clientRequestID A string that may be used to identify the 149 * request in the client application. It may 150 * be {@code null} if there is no available 151 * request identifier. 152 */ 153 public IntermediateClientRequestControl( 154 final IntermediateClientRequestValue downstreamRequest, 155 final String downstreamClientAddress, 156 final Boolean downstreamClientSecure, final String clientIdentity, 157 final String clientName, final String clientSessionID, 158 final String clientRequestID) 159 { 160 this(true, 161 new IntermediateClientRequestValue(downstreamRequest, 162 downstreamClientAddress, downstreamClientSecure, 163 clientIdentity, clientName, clientSessionID, 164 clientRequestID)); 165 } 166 167 168 169 /** 170 * Creates a new intermediate client request control with the provided value. 171 * It will be marked critical. 172 * 173 * @param value The value to use for this intermediate client request 174 * control. It must not be {@code null}. 175 */ 176 public IntermediateClientRequestControl( 177 final IntermediateClientRequestValue value) 178 { 179 this(true, value); 180 } 181 182 183 184 /** 185 * Creates a new intermediate client request control with the provided value. 186 * 187 * @param isCritical Indicates whether the control should be marked 188 * critical. 189 * @param value The value to use for this intermediate client request 190 * control. It must not be {@code null}. 191 */ 192 public IntermediateClientRequestControl(final boolean isCritical, 193 final IntermediateClientRequestValue value) 194 { 195 super(INTERMEDIATE_CLIENT_REQUEST_OID, isCritical, 196 new ASN1OctetString(value.encode().encode())); 197 198 this.value = value; 199 } 200 201 202 203 /** 204 * Creates a new intermediate client request control which is decoded from the 205 * provided generic control. 206 * 207 * @param control The generic control to be decoded as an intermediate 208 * client request control. 209 * 210 * @throws LDAPException If the provided control cannot be decoded as an 211 * intermediate client request control. 212 */ 213 public IntermediateClientRequestControl(final Control control) 214 throws LDAPException 215 { 216 super(control); 217 218 final ASN1OctetString controlValue = control.getValue(); 219 if (controlValue == null) 220 { 221 throw new LDAPException(ResultCode.DECODING_ERROR, 222 ERR_ICREQ_CONTROL_NO_VALUE.get()); 223 } 224 225 final ASN1Sequence valueSequence; 226 try 227 { 228 final ASN1Element valueElement = 229 ASN1Element.decode(controlValue.getValue()); 230 valueSequence = ASN1Sequence.decodeAsSequence(valueElement); 231 } 232 catch (final Exception e) 233 { 234 throw new LDAPException(ResultCode.DECODING_ERROR, 235 ERR_ICREQ_CONTROL_VALUE_NOT_SEQUENCE.get(e), e); 236 } 237 238 value = IntermediateClientRequestValue.decode(valueSequence); 239 } 240 241 242 243 /** 244 * Retrieves the value for this intermediate client request. 245 * 246 * @return The value for this intermediate client request. 247 */ 248 public IntermediateClientRequestValue getRequestValue() 249 { 250 return value; 251 } 252 253 254 255 /** 256 * Retrieves the wrapped request from a downstream client, if available. 257 * 258 * @return The wrapped request from a downstream client, or {@code null} if 259 * there is none. 260 */ 261 public IntermediateClientRequestValue getDownstreamRequest() 262 { 263 return value.getDownstreamRequest(); 264 } 265 266 267 268 /** 269 * Retrieves the requested client authorization identity, if available. 270 * 271 * @return The requested client authorization identity, or {@code null} if 272 * there is none. 273 */ 274 public String getClientIdentity() 275 { 276 return value.getClientIdentity(); 277 } 278 279 280 281 /** 282 * Retrieves the IP address or resolvable name of the downstream client 283 * system, if available. 284 * 285 * @return The IP address or resolvable name of the downstream client system, 286 * or {@code null} if there is no downstream client or its address is 287 * not available. 288 */ 289 public String getDownstreamClientAddress() 290 { 291 return value.getDownstreamClientAddress(); 292 } 293 294 295 296 /** 297 * Indicates whether the communication with the communication with the 298 * downstream client is secure (i.e., whether communication between the 299 * client application and the downstream client is safe from interpretation or 300 * undetectable alteration by a third party observer or interceptor). 301 * 302 * 303 * @return {@code Boolean.TRUE} if communication with the downstream client 304 * is secure, {@code Boolean.FALSE} if it is not secure, or 305 * {@code null} if there is no downstream client or it is not known 306 * whether the communication is secure. 307 */ 308 public Boolean downstreamClientSecure() 309 { 310 return value.downstreamClientSecure(); 311 } 312 313 314 315 /** 316 * Retrieves a string that identifies the client application that created this 317 * intermediate client request value. 318 * 319 * @return A string that may be used to identify the client application that 320 * created this intermediate client request value. 321 */ 322 public String getClientName() 323 { 324 return value.getClientName(); 325 } 326 327 328 329 /** 330 * Retrieves a string that may be used to identify the session in the client 331 * application. 332 * 333 * @return A string that may be used to identify the session in the client 334 * application, or {@code null} if there is none. 335 */ 336 public String getClientSessionID() 337 { 338 return value.getClientSessionID(); 339 } 340 341 342 343 /** 344 * Retrieves a string that may be used to identify the request in the client 345 * application. 346 * 347 * @return A string that may be used to identify the request in the client 348 * application, or {@code null} if there is none. 349 */ 350 public String getClientRequestID() 351 { 352 return value.getClientRequestID(); 353 } 354 355 356 357 /** 358 * {@inheritDoc} 359 */ 360 @Override() 361 public String getControlName() 362 { 363 return INFO_CONTROL_NAME_INTERMEDIATE_CLIENT_REQUEST.get(); 364 } 365 366 367 368 /** 369 * {@inheritDoc} 370 */ 371 @Override() 372 public void toString(final StringBuilder buffer) 373 { 374 buffer.append("IntermediateClientRequestControl(isCritical="); 375 buffer.append(isCritical()); 376 buffer.append(", value="); 377 value.toString(buffer); 378 buffer.append(')'); 379 } 380}