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