001/*
002 * Copyright 2008-2017 Ping Identity Corporation
003 * All Rights Reserved.
004 */
005/*
006 * Copyright (C) 2015-2017 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                      String.valueOf(e)), e);
418          }
419          break;
420
421        case TYPE_DOWNSTREAM_CLIENT_ADDRESS:
422          downstreamClientAddress =
423               ASN1OctetString.decodeAsOctetString(element).stringValue();
424          break;
425
426        case TYPE_DOWNSTREAM_CLIENT_SECURE:
427          try
428          {
429            downstreamClientSecure =
430                 ASN1Boolean.decodeAsBoolean(element).booleanValue();
431          }
432          catch (final Exception e)
433          {
434            debugException(e);
435            throw new LDAPException(ResultCode.DECODING_ERROR,
436                 ERR_ICREQ_CANNOT_DECODE_DOWNSTREAM_SECURE.get(
437                      String.valueOf(e)), e);
438          }
439          break;
440
441        case TYPE_CLIENT_IDENTITY:
442          clientIdentity =
443               ASN1OctetString.decodeAsOctetString(element).stringValue();
444          break;
445
446        case TYPE_CLIENT_NAME:
447          clientName =
448               ASN1OctetString.decodeAsOctetString(element).stringValue();
449          break;
450
451        case TYPE_CLIENT_SESSION_ID:
452          clientSessionID =
453               ASN1OctetString.decodeAsOctetString(element).stringValue();
454          break;
455
456        case TYPE_CLIENT_REQUEST_ID:
457          clientRequestID =
458               ASN1OctetString.decodeAsOctetString(element).stringValue();
459          break;
460
461        default:
462          throw new LDAPException(ResultCode.DECODING_ERROR,
463               ERR_ICREQ_INVALID_ELEMENT_TYPE.get(toHex(element.getType())));
464      }
465    }
466
467    return new IntermediateClientRequestValue(downstreamRequest,
468                                              downstreamClientAddress,
469                                              downstreamClientSecure,
470                                              clientIdentity, clientName,
471                                              clientSessionID, clientRequestID);
472  }
473
474
475
476  /**
477   * Generates a hash code for this intermediate client request value.
478   *
479   * @return  A hash code for this intermediate client request value.
480   */
481  @Override()
482  public int hashCode()
483  {
484    int hashCode = 0;
485
486    if (downstreamRequest != null)
487    {
488      hashCode += downstreamRequest.hashCode();
489    }
490
491    if (downstreamClientAddress != null)
492    {
493      hashCode += downstreamClientAddress.hashCode();
494    }
495
496    if (downstreamClientSecure != null)
497    {
498      hashCode += downstreamClientSecure.hashCode();
499    }
500
501    if (clientIdentity != null)
502    {
503      hashCode += clientIdentity.hashCode();
504    }
505
506    if (clientName != null)
507    {
508      hashCode += clientName.hashCode();
509    }
510
511    if (clientSessionID != null)
512    {
513      hashCode += clientSessionID.hashCode();
514    }
515
516    if (clientRequestID != null)
517    {
518      hashCode += clientRequestID.hashCode();
519    }
520
521    return hashCode;
522  }
523
524
525
526  /**
527   * Indicates whether the provided object is equal to this intermediate client
528   * request value.  It will only be considered equal if the provided object is
529   * also an intermediate client request value with all the same fields.
530   *
531   * @param  o  The object for which to make the determination.
532   *
533   * @return  {@code true} if the provided object is considered equal to this
534   *          intermediate client request value, or {@code false} if not.
535   */
536  @Override()
537  public boolean equals(final Object o)
538  {
539    if (o == this)
540    {
541      return true;
542    }
543    else if (o == null)
544    {
545      return false;
546    }
547    else if (! (o instanceof IntermediateClientRequestValue))
548    {
549      return false;
550    }
551
552    final IntermediateClientRequestValue v = (IntermediateClientRequestValue) o;
553
554    if (downstreamRequest == null)
555    {
556      if (v.downstreamRequest != null)
557      {
558        return false;
559      }
560    }
561    else
562    {
563      if (! downstreamRequest.equals(v.downstreamRequest))
564      {
565        return false;
566      }
567    }
568
569    if (downstreamClientAddress == null)
570    {
571      if (v.downstreamClientAddress != null)
572      {
573        return false;
574      }
575    }
576    else
577    {
578      if (! downstreamClientAddress.equals(v.downstreamClientAddress))
579      {
580        return false;
581      }
582    }
583
584    if (downstreamClientSecure == null)
585    {
586      if (v.downstreamClientSecure != null)
587      {
588        return false;
589      }
590    }
591    else
592    {
593      if (! downstreamClientSecure.equals(v.downstreamClientSecure))
594      {
595        return false;
596      }
597    }
598
599    if (clientIdentity == null)
600    {
601      if (v.clientIdentity != null)
602      {
603        return false;
604      }
605    }
606    else
607    {
608      if (! clientIdentity.equals(v.clientIdentity))
609      {
610        return false;
611      }
612    }
613
614    if (clientName == null)
615    {
616      if (v.clientName != null)
617      {
618        return false;
619      }
620    }
621    else
622    {
623      if (! clientName.equals(v.clientName))
624      {
625        return false;
626      }
627    }
628
629    if (clientSessionID == null)
630    {
631      if (v.clientSessionID != null)
632      {
633        return false;
634      }
635    }
636    else
637    {
638      if (! clientSessionID.equals(v.clientSessionID))
639      {
640        return false;
641      }
642    }
643
644    if (clientRequestID == null)
645    {
646      if (v.clientRequestID != null)
647      {
648        return false;
649      }
650    }
651    else
652    {
653      if (! clientRequestID.equals(v.clientRequestID))
654      {
655        return false;
656      }
657    }
658
659    return true;
660  }
661
662
663
664  /**
665   * Retrieves a string representation of this intermediate client request
666   * value.
667   *
668   * @return  A string representation of this intermediate client request value.
669   */
670  @Override()
671  public String toString()
672  {
673    final StringBuilder buffer = new StringBuilder();
674    toString(buffer);
675    return buffer.toString();
676  }
677
678
679
680  /**
681   * Appends a string representation of this intermediate client request value
682   * to the provided buffer.
683   *
684   * @param  buffer  The buffer to which the information is to be appended.
685   */
686  public void toString(final StringBuilder buffer)
687  {
688    buffer.append("IntermediateClientRequestValue(");
689
690    boolean added = false;
691    if (downstreamRequest != null)
692    {
693      buffer.append("downstreamRequest=");
694      downstreamRequest.toString(buffer);
695      added = true;
696    }
697
698    if (clientIdentity != null)
699    {
700      if (added)
701      {
702        buffer.append(", ");
703      }
704      else
705      {
706        added = true;
707      }
708
709      buffer.append("clientIdentity='");
710      buffer.append(clientIdentity);
711      buffer.append('\'');
712    }
713
714    if (downstreamClientAddress != null)
715    {
716      if (added)
717      {
718        buffer.append(", ");
719      }
720      else
721      {
722        added = true;
723      }
724
725      buffer.append("downstreamClientAddress='");
726      buffer.append(downstreamClientAddress);
727      buffer.append('\'');
728    }
729
730    if (downstreamClientSecure != null)
731    {
732      if (added)
733      {
734        buffer.append(", ");
735      }
736      else
737      {
738        added = true;
739      }
740
741      buffer.append("downstreamClientSecure='");
742      buffer.append(downstreamClientSecure);
743      buffer.append('\'');
744    }
745
746    if (clientName != null)
747    {
748      if (added)
749      {
750        buffer.append(", ");
751      }
752      else
753      {
754        added = true;
755      }
756
757      buffer.append("clientName='");
758      buffer.append(clientName);
759      buffer.append('\'');
760    }
761
762    if (clientSessionID != null)
763    {
764      if (added)
765      {
766        buffer.append(", ");
767      }
768      else
769      {
770        added = true;
771      }
772
773      buffer.append("clientSessionID='");
774      buffer.append(clientSessionID);
775      buffer.append('\'');
776    }
777
778    if (clientRequestID != null)
779    {
780      if (added)
781      {
782        buffer.append(", ");
783      }
784      else
785      {
786        added = true;
787      }
788
789      buffer.append("clientRequestID='");
790      buffer.append(clientRequestID);
791      buffer.append('\'');
792    }
793
794    buffer.append(')');
795  }
796}