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