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