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}