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
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}