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 java.io.Serializable;
026import java.util.ArrayList;
027
028import com.unboundid.asn1.ASN1Boolean;
029import com.unboundid.asn1.ASN1Constants;
030import com.unboundid.asn1.ASN1Element;
031import com.unboundid.asn1.ASN1OctetString;
032import com.unboundid.asn1.ASN1Sequence;
033import com.unboundid.ldap.sdk.LDAPException;
034import com.unboundid.ldap.sdk.ResultCode;
035import com.unboundid.util.NotMutable;
036import com.unboundid.util.ThreadSafety;
037import com.unboundid.util.ThreadSafetyLevel;
038
039import static com.unboundid.ldap.sdk.unboundidds.controls.ControlMessages.*;
040import static com.unboundid.util.Debug.*;
041import static com.unboundid.util.StaticUtils.*;
042
043
044
045/**
046 * This class implements a data structure which encapsulates the value of an
047 * intermediate client request value.  It may recursively embed intermediate
048 * client request values from downstream clients.
049 * <BR>
050 * <BLOCKQUOTE>
051 *   <B>NOTE:</B>  This class, and other classes within the
052 *   {@code com.unboundid.ldap.sdk.unboundidds} package structure, are only
053 *   supported for use against Ping Identity, UnboundID, and Alcatel-Lucent 8661
054 *   server products.  These classes provide support for proprietary
055 *   functionality or for external specifications that are not considered stable
056 *   or mature enough to be guaranteed to work in an interoperable way with
057 *   other types of LDAP servers.
058 * </BLOCKQUOTE>
059 * <BR>
060 * See the documentation in the {@link IntermediateClientRequestControl} class
061 * for an example of using the intermediate client request and response
062 * controls.
063 */
064@NotMutable()
065@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
066public final class IntermediateClientRequestValue
067       implements Serializable
068{
069  /**
070   * The BER type for the downstreamRequest element.
071   */
072  private static final byte TYPE_DOWNSTREAM_REQUEST = (byte) 0xA0;
073
074
075
076  /**
077   * The BER type for the downstreamClientAddress element.
078   */
079  private static final byte TYPE_DOWNSTREAM_CLIENT_ADDRESS = (byte) 0x81;
080
081
082
083  /**
084   * The BER type for the downstreamClientSecure element.
085   */
086  private static final byte TYPE_DOWNSTREAM_CLIENT_SECURE = (byte) 0x82;
087
088
089
090  /**
091   * The BER type for the clientIdentity element.
092   */
093  private static final byte TYPE_CLIENT_IDENTITY = (byte) 0x83;
094
095
096
097  /**
098   * The BER type for the clientName element.
099   */
100  private static final byte TYPE_CLIENT_NAME = (byte) 0x84;
101
102
103
104  /**
105   * The BER type for the clientSessionID element.
106   */
107  private static final byte TYPE_CLIENT_SESSION_ID = (byte) 0x85;
108
109
110
111  /**
112   * The BER type for the clientRequestID element.
113   */
114  private static final byte TYPE_CLIENT_REQUEST_ID = (byte) 0x86;
115
116
117
118  /**
119   * The serial version UID for this serializable class.
120   */
121  private static final long serialVersionUID = -794887520013838259L;
122
123
124
125  // Indicates whether the communication with the downstream client is secure.
126  private final Boolean downstreamClientSecure;
127
128  // The downstream request value, if present.
129  private final IntermediateClientRequestValue downstreamRequest;
130
131  // The requested client authorization identity, if present.
132  private final String clientIdentity;
133
134  // The downstream client address, if present.
135  private final String downstreamClientAddress;
136
137  // The client name, which describes the client application, if present.
138  private final String clientName;
139
140  // The client request ID, if present.
141  private final String clientRequestID;
142
143  // The client session ID, if present.
144  private final String clientSessionID;
145
146
147
148  /**
149   * Creates a new intermediate client request value with the provided
150   * information.
151   *
152   * @param  downstreamRequest        A wrapped intermediate client request from
153   *                                  a downstream client.  It may be
154   *                                  {@code null} if there is no downstream
155   *                                  request.
156   * @param  downstreamClientAddress  The IP address or resolvable name of the
157   *                                  downstream client system.  It may be
158   *                                  {@code null} if there is no downstream
159   *                                  client or its address is not available.
160   * @param  downstreamClientSecure   Indicates whether communication with the
161   *                                  downstream client is secure.  It may be
162   *                                  {@code null} if there is no downstream
163   *                                  client or it is not known whether the
164   *                                  communication is secure.
165   * @param  clientIdentity           The requested client authorization
166   *                                  identity.  It may be {@code null} if there
167   *                                  is no requested authorization identity.
168   * @param  clientName               An identifier string that summarizes the
169   *                                  client application that created this
170   *                                  intermediate client request.  It may be
171   *                                  {@code null} if that information is not
172   *                                  available.
173   * @param  clientSessionID          A string that may be used to identify the
174   *                                  session in the client application.  It may
175   *                                  be {@code null} if there is no available
176   *                                  session identifier.
177   * @param  clientRequestID          A string that may be used to identify the
178   *                                  request in the client application.  It may
179   *                                  be {@code null} if there is no available
180   *                                  request identifier.
181   */
182  public IntermediateClientRequestValue(
183              final IntermediateClientRequestValue downstreamRequest,
184              final String downstreamClientAddress,
185              final Boolean downstreamClientSecure, final String clientIdentity,
186              final String clientName, final String clientSessionID,
187              final String clientRequestID)
188  {
189    this.downstreamRequest       = downstreamRequest;
190    this.downstreamClientAddress = downstreamClientAddress;
191    this.downstreamClientSecure  = downstreamClientSecure;
192    this.clientIdentity          = clientIdentity;
193    this.clientName              = clientName;
194    this.clientSessionID         = clientSessionID;
195    this.clientRequestID         = clientRequestID;
196  }
197
198
199
200  /**
201   * Retrieves the wrapped request from a downstream client, if available.
202   *
203   * @return  The wrapped request from a downstream client, or {@code null} if
204   *          there is none.
205   */
206  public IntermediateClientRequestValue getDownstreamRequest()
207  {
208    return downstreamRequest;
209  }
210
211
212
213  /**
214   * Retrieves the requested client authorization identity, if available.
215   *
216   * @return  The requested client authorization identity, or {@code null} if
217   *          there is none.
218   */
219  public String getClientIdentity()
220  {
221    return clientIdentity;
222  }
223
224
225
226  /**
227   * Retrieves the IP address or resolvable name of the downstream client
228   * system, if available.
229   *
230   * @return  The IP address or resolvable name of the downstream client system,
231   *          or {@code null} if there is no downstream client or its address is
232   *          not available.
233   */
234  public String getDownstreamClientAddress()
235  {
236    return downstreamClientAddress;
237  }
238
239
240
241  /**
242   * Indicates whether the communication with the communication with the
243   * downstream client is secure (i.e., whether communication between the
244   * client application and the downstream client is safe from interpretation or
245   * undetectable alteration by a third party observer or interceptor).
246   *
247   *
248   * @return  {@code Boolean.TRUE} if communication with the downstream client
249   *          is secure, {@code Boolean.FALSE} if it is not secure, or
250   *          {@code null} if there is no downstream client or it is not known
251   *          whether the communication is secure.
252   */
253  public Boolean downstreamClientSecure()
254  {
255    return downstreamClientSecure;
256  }
257
258
259
260  /**
261   * Retrieves a string that identifies the client application that created this
262   * intermediate client request value.
263   *
264   * @return  A string that may be used to identify the client application that
265   *          created this intermediate client request value.
266   */
267  public String getClientName()
268  {
269    return clientName;
270  }
271
272
273
274  /**
275   * Retrieves a string that may be used to identify the session in the client
276   * application.
277   *
278   * @return  A string that may be used to identify the session in the client
279   *          application, or {@code null} if there is none.
280   */
281  public String getClientSessionID()
282  {
283    return clientSessionID;
284  }
285
286
287
288  /**
289   * Retrieves a string that may be used to identify the request in the client
290   * application.
291   *
292   * @return  A string that may be used to identify the request in the client
293   *          application, or {@code null} if there is none.
294   */
295  public String getClientRequestID()
296  {
297    return clientRequestID;
298  }
299
300
301
302  /**
303   * Encodes this intermediate client request value to a form that may be
304   * included in the request control.
305   *
306   * @return  An ASN.1 octet string containing the encoded client request value.
307   */
308  public ASN1Sequence encode()
309  {
310    return encode(ASN1Constants.UNIVERSAL_SEQUENCE_TYPE);
311  }
312
313
314
315  /**
316   * Encodes this intermediate client request value to a form that may be
317   * included in the request control.
318   *
319   * @param  type  The BER type to use for this element.
320   *
321   * @return  An ASN.1 octet string containing the encoded client request value.
322   */
323  private ASN1Sequence encode(final byte type)
324  {
325    final ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(7);
326
327    if (downstreamRequest != null)
328    {
329      elements.add(downstreamRequest.encode(TYPE_DOWNSTREAM_REQUEST));
330    }
331
332    if (downstreamClientAddress != null)
333    {
334      elements.add(new ASN1OctetString(TYPE_DOWNSTREAM_CLIENT_ADDRESS,
335                                       downstreamClientAddress));
336    }
337
338    if (downstreamClientSecure != null)
339    {
340      elements.add(new ASN1Boolean(TYPE_DOWNSTREAM_CLIENT_SECURE,
341                                   downstreamClientSecure));
342    }
343
344    if (clientIdentity != null)
345    {
346      elements.add(new ASN1OctetString(TYPE_CLIENT_IDENTITY, clientIdentity));
347    }
348
349    if (clientName != null)
350    {
351      elements.add(new ASN1OctetString(TYPE_CLIENT_NAME,  clientName));
352    }
353
354    if (clientSessionID != null)
355    {
356      elements.add(new ASN1OctetString(TYPE_CLIENT_SESSION_ID,
357                                       clientSessionID));
358    }
359
360    if (clientRequestID != null)
361    {
362      elements.add(new ASN1OctetString(TYPE_CLIENT_REQUEST_ID,
363                                       clientRequestID));
364    }
365
366    return new ASN1Sequence(type, elements);
367  }
368
369
370
371  /**
372   * Decodes the provided ASN.1 sequence as an intermediate client request
373   * value.
374   *
375   * @param  sequence  The sequence to be decoded as an intermediate client
376   *                   request value.
377   *
378   * @return  The decoded intermediate client request value.
379   *
380   * @throws  LDAPException  If the provided sequence cannot be decoded as an
381   *                         intermediate client request value.
382   */
383  public static IntermediateClientRequestValue
384                     decode(final ASN1Sequence sequence)
385         throws LDAPException
386  {
387    Boolean                        downstreamClientSecure  = null;
388    IntermediateClientRequestValue downstreamRequest       = null;
389    String                         clientIdentity          = null;
390    String                         downstreamClientAddress = null;
391    String                         clientName              = null;
392    String                         clientRequestID         = null;
393    String                         clientSessionID         = null;
394
395    for (final ASN1Element element : sequence.elements())
396    {
397      switch (element.getType())
398      {
399        case TYPE_DOWNSTREAM_REQUEST:
400          try
401          {
402            final ASN1Sequence s = ASN1Sequence.decodeAsSequence(element);
403            downstreamRequest = decode(s);
404          }
405          catch (final LDAPException le)
406          {
407            debugException(le);
408            throw new LDAPException(ResultCode.DECODING_ERROR,
409                 ERR_ICREQ_CANNOT_DECODE_DOWNSTREAM_REQUEST.get(
410                      le.getMessage()), le);
411          }
412          catch (final Exception e)
413          {
414            debugException(e);
415            throw new LDAPException(ResultCode.DECODING_ERROR,
416                 ERR_ICREQ_CANNOT_DECODE_DOWNSTREAM_REQUEST.get(
417                      getExceptionMessage(e)),
418                 e);
419          }
420          break;
421
422        case TYPE_DOWNSTREAM_CLIENT_ADDRESS:
423          downstreamClientAddress =
424               ASN1OctetString.decodeAsOctetString(element).stringValue();
425          break;
426
427        case TYPE_DOWNSTREAM_CLIENT_SECURE:
428          try
429          {
430            downstreamClientSecure =
431                 ASN1Boolean.decodeAsBoolean(element).booleanValue();
432          }
433          catch (final Exception e)
434          {
435            debugException(e);
436            throw new LDAPException(ResultCode.DECODING_ERROR,
437                 ERR_ICREQ_CANNOT_DECODE_DOWNSTREAM_SECURE.get(
438                      getExceptionMessage(e)),
439                 e);
440          }
441          break;
442
443        case TYPE_CLIENT_IDENTITY:
444          clientIdentity =
445               ASN1OctetString.decodeAsOctetString(element).stringValue();
446          break;
447
448        case TYPE_CLIENT_NAME:
449          clientName =
450               ASN1OctetString.decodeAsOctetString(element).stringValue();
451          break;
452
453        case TYPE_CLIENT_SESSION_ID:
454          clientSessionID =
455               ASN1OctetString.decodeAsOctetString(element).stringValue();
456          break;
457
458        case TYPE_CLIENT_REQUEST_ID:
459          clientRequestID =
460               ASN1OctetString.decodeAsOctetString(element).stringValue();
461          break;
462
463        default:
464          throw new LDAPException(ResultCode.DECODING_ERROR,
465               ERR_ICREQ_INVALID_ELEMENT_TYPE.get(toHex(element.getType())));
466      }
467    }
468
469    return new IntermediateClientRequestValue(downstreamRequest,
470                                              downstreamClientAddress,
471                                              downstreamClientSecure,
472                                              clientIdentity, clientName,
473                                              clientSessionID, clientRequestID);
474  }
475
476
477
478  /**
479   * Generates a hash code for this intermediate client request value.
480   *
481   * @return  A hash code for this intermediate client request value.
482   */
483  @Override()
484  public int hashCode()
485  {
486    int hashCode = 0;
487
488    if (downstreamRequest != null)
489    {
490      hashCode += downstreamRequest.hashCode();
491    }
492
493    if (downstreamClientAddress != null)
494    {
495      hashCode += downstreamClientAddress.hashCode();
496    }
497
498    if (downstreamClientSecure != null)
499    {
500      hashCode += downstreamClientSecure.hashCode();
501    }
502
503    if (clientIdentity != null)
504    {
505      hashCode += clientIdentity.hashCode();
506    }
507
508    if (clientName != null)
509    {
510      hashCode += clientName.hashCode();
511    }
512
513    if (clientSessionID != null)
514    {
515      hashCode += clientSessionID.hashCode();
516    }
517
518    if (clientRequestID != null)
519    {
520      hashCode += clientRequestID.hashCode();
521    }
522
523    return hashCode;
524  }
525
526
527
528  /**
529   * Indicates whether the provided object is equal to this intermediate client
530   * request value.  It will only be considered equal if the provided object is
531   * also an intermediate client request value with all the same fields.
532   *
533   * @param  o  The object for which to make the determination.
534   *
535   * @return  {@code true} if the provided object is considered equal to this
536   *          intermediate client request value, or {@code false} if not.
537   */
538  @Override()
539  public boolean equals(final Object o)
540  {
541    if (o == this)
542    {
543      return true;
544    }
545    else if (o == null)
546    {
547      return false;
548    }
549    else if (! (o instanceof IntermediateClientRequestValue))
550    {
551      return false;
552    }
553
554    final IntermediateClientRequestValue v = (IntermediateClientRequestValue) o;
555
556    if (downstreamRequest == null)
557    {
558      if (v.downstreamRequest != null)
559      {
560        return false;
561      }
562    }
563    else
564    {
565      if (! downstreamRequest.equals(v.downstreamRequest))
566      {
567        return false;
568      }
569    }
570
571    if (downstreamClientAddress == null)
572    {
573      if (v.downstreamClientAddress != null)
574      {
575        return false;
576      }
577    }
578    else
579    {
580      if (! downstreamClientAddress.equals(v.downstreamClientAddress))
581      {
582        return false;
583      }
584    }
585
586    if (downstreamClientSecure == null)
587    {
588      if (v.downstreamClientSecure != null)
589      {
590        return false;
591      }
592    }
593    else
594    {
595      if (! downstreamClientSecure.equals(v.downstreamClientSecure))
596      {
597        return false;
598      }
599    }
600
601    if (clientIdentity == null)
602    {
603      if (v.clientIdentity != null)
604      {
605        return false;
606      }
607    }
608    else
609    {
610      if (! clientIdentity.equals(v.clientIdentity))
611      {
612        return false;
613      }
614    }
615
616    if (clientName == null)
617    {
618      if (v.clientName != null)
619      {
620        return false;
621      }
622    }
623    else
624    {
625      if (! clientName.equals(v.clientName))
626      {
627        return false;
628      }
629    }
630
631    if (clientSessionID == null)
632    {
633      if (v.clientSessionID != null)
634      {
635        return false;
636      }
637    }
638    else
639    {
640      if (! clientSessionID.equals(v.clientSessionID))
641      {
642        return false;
643      }
644    }
645
646    if (clientRequestID == null)
647    {
648      if (v.clientRequestID != null)
649      {
650        return false;
651      }
652    }
653    else
654    {
655      if (! clientRequestID.equals(v.clientRequestID))
656      {
657        return false;
658      }
659    }
660
661    return true;
662  }
663
664
665
666  /**
667   * Retrieves a string representation of this intermediate client request
668   * value.
669   *
670   * @return  A string representation of this intermediate client request value.
671   */
672  @Override()
673  public String toString()
674  {
675    final StringBuilder buffer = new StringBuilder();
676    toString(buffer);
677    return buffer.toString();
678  }
679
680
681
682  /**
683   * Appends a string representation of this intermediate client request value
684   * to the provided buffer.
685   *
686   * @param  buffer  The buffer to which the information is to be appended.
687   */
688  public void toString(final StringBuilder buffer)
689  {
690    buffer.append("IntermediateClientRequestValue(");
691
692    boolean added = false;
693    if (downstreamRequest != null)
694    {
695      buffer.append("downstreamRequest=");
696      downstreamRequest.toString(buffer);
697      added = true;
698    }
699
700    if (clientIdentity != null)
701    {
702      if (added)
703      {
704        buffer.append(", ");
705      }
706      else
707      {
708        added = true;
709      }
710
711      buffer.append("clientIdentity='");
712      buffer.append(clientIdentity);
713      buffer.append('\'');
714    }
715
716    if (downstreamClientAddress != null)
717    {
718      if (added)
719      {
720        buffer.append(", ");
721      }
722      else
723      {
724        added = true;
725      }
726
727      buffer.append("downstreamClientAddress='");
728      buffer.append(downstreamClientAddress);
729      buffer.append('\'');
730    }
731
732    if (downstreamClientSecure != null)
733    {
734      if (added)
735      {
736        buffer.append(", ");
737      }
738      else
739      {
740        added = true;
741      }
742
743      buffer.append("downstreamClientSecure='");
744      buffer.append(downstreamClientSecure);
745      buffer.append('\'');
746    }
747
748    if (clientName != null)
749    {
750      if (added)
751      {
752        buffer.append(", ");
753      }
754      else
755      {
756        added = true;
757      }
758
759      buffer.append("clientName='");
760      buffer.append(clientName);
761      buffer.append('\'');
762    }
763
764    if (clientSessionID != null)
765    {
766      if (added)
767      {
768        buffer.append(", ");
769      }
770      else
771      {
772        added = true;
773      }
774
775      buffer.append("clientSessionID='");
776      buffer.append(clientSessionID);
777      buffer.append('\'');
778    }
779
780    if (clientRequestID != null)
781    {
782      if (added)
783      {
784        buffer.append(", ");
785      }
786      else
787      {
788        added = true;
789      }
790
791      buffer.append("clientRequestID='");
792      buffer.append(clientRequestID);
793      buffer.append('\'');
794    }
795
796    buffer.append(')');
797  }
798}