001/*
002 * Copyright 2007-2014 UnboundID Corp.
003 * All Rights Reserved.
004 */
005/*
006 * Copyright (C) 2008-2014 UnboundID Corp.
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;
022
023
024
025import java.util.ArrayList;
026
027import com.unboundid.asn1.ASN1OctetString;
028import com.unboundid.asn1.ASN1StreamReader;
029import com.unboundid.asn1.ASN1StreamReaderSequence;
030import com.unboundid.util.Extensible;
031import com.unboundid.util.NotMutable;
032import com.unboundid.util.ThreadSafety;
033import com.unboundid.util.ThreadSafetyLevel;
034
035import static com.unboundid.ldap.sdk.LDAPMessages.*;
036import static com.unboundid.util.Debug.*;
037import static com.unboundid.util.StaticUtils.*;
038
039
040
041/**
042 * This class provides a data structure for holding information about the result
043 * of processing a bind operation.  It provides generic bind response elements
044 * as described in the {@link LDAPResult} class, but may be overridden to
045 * provide more detailed information for specific types of bind requests.
046 */
047@Extensible()
048@NotMutable()
049@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
050public class BindResult
051       extends LDAPResult
052{
053  /**
054   * The BER type for the server SASL credentials element in the bind result.
055   */
056  private static final byte TYPE_SERVER_SASL_CREDENTIALS = (byte) 0x87;
057
058
059
060  /**
061   * The serial version UID for this serializable class.
062   */
063  private static final long serialVersionUID = 2211625049303605730L;
064
065
066
067  // The server SASL credentials from the response, if available.
068  private final ASN1OctetString serverSASLCredentials;
069
070
071
072  /**
073   * Creates a new bind result with the provided information.
074   *
075   * @param  messageID          The message ID for the LDAP message that is
076   *                            associated with this bind result.
077   * @param  resultCode         The result code from the response.
078   * @param  diagnosticMessage  The diagnostic message from the response, if
079   *                            available.
080   * @param  matchedDN          The matched DN from the response, if available.
081   * @param  referralURLs       The set of referral URLs from the response, if
082   *                            available.
083   * @param  responseControls   The set of controls from the response, if
084   *                            available.
085   */
086  public BindResult(final int messageID, final ResultCode resultCode,
087                    final String diagnosticMessage, final String matchedDN,
088                    final String[] referralURLs,
089                    final Control[] responseControls)
090  {
091    this(messageID, resultCode, diagnosticMessage, matchedDN, referralURLs,
092         responseControls, null);
093  }
094
095
096
097  /**
098   * Creates a new bind result with the provided information.
099   *
100   * @param  messageID              The message ID for the LDAP message that is
101   *                                associated with this bind result.
102   * @param  resultCode             The result code from the response.
103   * @param  diagnosticMessage      The diagnostic message from the response, if
104   *                                available.
105   * @param  matchedDN              The matched DN from the response, if
106   *                                available.
107   * @param  referralURLs           The set of referral URLs from the response,
108   *                                if available.
109   * @param  responseControls       The set of controls from the response, if
110   *                                available.
111   * @param  serverSASLCredentials  The server SASL credentials from the
112   *                                response, if available.
113   */
114  public BindResult(final int messageID, final ResultCode resultCode,
115                    final String diagnosticMessage, final String matchedDN,
116                    final String[] referralURLs,
117                    final Control[] responseControls,
118                    final ASN1OctetString serverSASLCredentials)
119  {
120    super(messageID, resultCode, diagnosticMessage, matchedDN, referralURLs,
121          responseControls);
122
123    this.serverSASLCredentials = serverSASLCredentials;
124  }
125
126
127
128  /**
129   * Creates a new bind result from the provided generic LDAP result.
130   *
131   * @param  ldapResult  The LDAP result to use to create this bind result.
132   */
133  public BindResult(final LDAPResult ldapResult)
134  {
135    super(ldapResult);
136
137    serverSASLCredentials = null;
138  }
139
140
141
142  /**
143   * Creates a new bind result from the provided {@code LDAPException}.
144   *
145   * @param  exception  The {@code LDAPException} to use to create this bind
146   *                    result.
147   */
148  public BindResult(final LDAPException exception)
149  {
150    super(exception.toLDAPResult());
151
152    serverSASLCredentials = null;
153  }
154
155
156
157  /**
158   * Creates a new bind result from the provided bind result.  This constructor
159   * may be used in creating custom subclasses.
160   *
161   * @param  bindResult  The bind result to use to create this bind result.
162   */
163  protected BindResult(final BindResult bindResult)
164  {
165    super(bindResult);
166
167    serverSASLCredentials = bindResult.serverSASLCredentials;
168  }
169
170
171
172  /**
173   * Creates a new bind result object with the provided message ID and with the
174   * protocol op and controls read from the given ASN.1 stream reader.
175   *
176   * @param  messageID        The LDAP message ID for the LDAP message that is
177   *                          associated with this bind result.
178   * @param  messageSequence  The ASN.1 stream reader sequence used in the
179   *                          course of reading the LDAP message elements.
180   * @param  reader           The ASN.1 stream reader from which to read the
181   *                          protocol op and controls.
182   *
183   * @return  The decoded bind result.
184   *
185   * @throws  LDAPException  If a problem occurs while reading or decoding data
186   *                         from the ASN.1 stream reader.
187   */
188  static BindResult readBindResultFrom(final int messageID,
189                         final ASN1StreamReaderSequence messageSequence,
190                         final ASN1StreamReader reader)
191         throws LDAPException
192  {
193    try
194    {
195      final ASN1StreamReaderSequence protocolOpSequence =
196           reader.beginSequence();
197      final ResultCode resultCode = ResultCode.valueOf(reader.readEnumerated());
198
199      String matchedDN = reader.readString();
200      if (matchedDN.length() == 0)
201      {
202        matchedDN = null;
203      }
204
205      String diagnosticMessage = reader.readString();
206      if (diagnosticMessage.length() == 0)
207      {
208        diagnosticMessage = null;
209      }
210
211      String[] referralURLs = null;
212      ASN1OctetString serverSASLCredentials = null;
213      while (protocolOpSequence.hasMoreElements())
214      {
215        final byte type = (byte) reader.peek();
216        switch (type)
217        {
218          case TYPE_REFERRAL_URLS:
219            final ArrayList<String> refList = new ArrayList<String>(1);
220            final ASN1StreamReaderSequence refSequence = reader.beginSequence();
221            while (refSequence.hasMoreElements())
222            {
223              refList.add(reader.readString());
224            }
225            referralURLs = new String[refList.size()];
226            refList.toArray(referralURLs);
227            break;
228
229          case TYPE_SERVER_SASL_CREDENTIALS:
230            serverSASLCredentials =
231                 new ASN1OctetString(type, reader.readBytes());
232            break;
233
234          default:
235            throw new LDAPException(ResultCode.DECODING_ERROR,
236                 ERR_BIND_RESULT_INVALID_ELEMENT.get(toHex(type)));
237        }
238      }
239
240      Control[] controls = NO_CONTROLS;
241      if (messageSequence.hasMoreElements())
242      {
243        final ArrayList<Control> controlList = new ArrayList<Control>(1);
244        final ASN1StreamReaderSequence controlSequence = reader.beginSequence();
245        while (controlSequence.hasMoreElements())
246        {
247          controlList.add(Control.readFrom(reader));
248        }
249
250        controls = new Control[controlList.size()];
251        controlList.toArray(controls);
252      }
253
254      return new BindResult(messageID, resultCode, diagnosticMessage, matchedDN,
255                            referralURLs, controls, serverSASLCredentials);
256    }
257    catch (LDAPException le)
258    {
259      debugException(le);
260      throw le;
261    }
262    catch (Exception e)
263    {
264      debugException(e);
265      throw new LDAPException(ResultCode.DECODING_ERROR,
266           ERR_BIND_RESULT_CANNOT_DECODE.get(getExceptionMessage(e)), e);
267    }
268  }
269
270
271
272  /**
273   * Retrieves the server SASL credentials from the bind result, if available.
274   *
275   * @return  The server SASL credentials from the bind response, or
276   *          {@code null} if none were provided.
277   */
278  public ASN1OctetString getServerSASLCredentials()
279  {
280    return serverSASLCredentials;
281  }
282}