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