001    /*
002     * Copyright 2009-2012 UnboundID Corp.
003     * All Rights Reserved.
004     */
005    /*
006     * Copyright (C) 2009-2012 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.protocol;
022    
023    
024    
025    import com.unboundid.asn1.ASN1Buffer;
026    import com.unboundid.asn1.ASN1BufferSequence;
027    import com.unboundid.asn1.ASN1OctetString;
028    import com.unboundid.asn1.ASN1StreamReader;
029    import com.unboundid.asn1.ASN1StreamReaderSequence;
030    import com.unboundid.ldap.sdk.LDAPException;
031    import com.unboundid.ldap.sdk.ResultCode;
032    import com.unboundid.util.NotMutable;
033    import com.unboundid.util.InternalUseOnly;
034    import com.unboundid.util.ThreadSafety;
035    import com.unboundid.util.ThreadSafetyLevel;
036    
037    import static com.unboundid.ldap.protocol.ProtocolMessages.*;
038    import static com.unboundid.util.Debug.*;
039    import static com.unboundid.util.StaticUtils.*;
040    import static com.unboundid.util.Validator.*;
041    
042    
043    
044    /**
045     * This class provides an implementation of an LDAP bind request protocol op.
046     */
047    @InternalUseOnly()
048    @NotMutable()
049    @ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
050    public final class BindRequestProtocolOp
051           implements ProtocolOp
052    {
053      /**
054       * The credentials type for simple bind requests.
055       */
056      public static final byte CRED_TYPE_SIMPLE = (byte) 0x80;
057    
058    
059    
060      /**
061       * The credentials type for SASL bind requests.
062       */
063      public static final byte CRED_TYPE_SASL = (byte) 0xA3;
064    
065    
066    
067      /**
068       * The serial version UID for this serializable class.
069       */
070      private static final long serialVersionUID = 6661208657485444954L;
071    
072    
073    
074      // The credentials to use for SASL authentication.
075      private final ASN1OctetString saslCredentials;
076    
077      // The password to use for simple authentication.
078      private final ASN1OctetString simplePassword;
079    
080      // The credentials type for this bind request.
081      private final byte credentialsType;
082    
083      // The protocol version for this bind request.
084      private final int version;
085    
086      // The bind DN to use for this bind request.
087      private final String bindDN;
088    
089      // The name of the SASL mechanism.
090      private final String saslMechanism;
091    
092    
093    
094      /**
095       * Creates a new bind request protocol op for a simple bind.
096       *
097       * @param  bindDN    The DN for this bind request.
098       * @param  password  The password for this bind request.
099       */
100      public BindRequestProtocolOp(final String bindDN, final String password)
101      {
102        if (bindDN == null)
103        {
104          this.bindDN = "";
105        }
106        else
107        {
108          this.bindDN = bindDN;
109        }
110    
111        if (password == null)
112        {
113          simplePassword = new ASN1OctetString(CRED_TYPE_SIMPLE);
114        }
115        else
116        {
117          simplePassword = new ASN1OctetString(CRED_TYPE_SIMPLE, password);
118        }
119    
120        version         = 3;
121        credentialsType = CRED_TYPE_SIMPLE;
122        saslMechanism   = null;
123        saslCredentials = null;
124      }
125    
126    
127    
128      /**
129       * Creates a new bind request protocol op for a simple bind.
130       *
131       * @param  bindDN    The DN for this bind request.
132       * @param  password  The password for this bind request.
133       */
134      public BindRequestProtocolOp(final String bindDN, final byte[] password)
135      {
136        if (bindDN == null)
137        {
138          this.bindDN = "";
139        }
140        else
141        {
142          this.bindDN = bindDN;
143        }
144    
145        if (password == null)
146        {
147          simplePassword = new ASN1OctetString(CRED_TYPE_SIMPLE);
148        }
149        else
150        {
151          simplePassword = new ASN1OctetString(CRED_TYPE_SIMPLE, password);
152        }
153    
154        version         = 3;
155        credentialsType = CRED_TYPE_SIMPLE;
156        saslMechanism   = null;
157        saslCredentials = null;
158      }
159    
160    
161    
162      /**
163       * Creates a new bind request protocol op for a SASL bind.
164       *
165       * @param  bindDN           The DN for this bind request.
166       * @param  saslMechanism    The name of the SASL mechanism for this bind
167       *                          request.  It must not be {@code null}.
168       * @param  saslCredentials  The SASL credentials for this bind request, if
169       *                          any.
170       */
171      public BindRequestProtocolOp(final String bindDN, final String saslMechanism,
172                                   final ASN1OctetString saslCredentials)
173      {
174        this.saslMechanism   = saslMechanism;
175        this.saslCredentials = saslCredentials;
176    
177        if (bindDN == null)
178        {
179          this.bindDN = "";
180        }
181        else
182        {
183          this.bindDN = bindDN;
184        }
185    
186        version         = 3;
187        credentialsType = CRED_TYPE_SASL;
188        simplePassword  = null;
189      }
190    
191    
192    
193      /**
194       * Creates a new bind request protocol op read from the provided ASN.1 stream
195       * reader.
196       *
197       * @param  reader  The ASN.1 stream reader from which to read the bind request
198       *                 protocol op.
199       *
200       * @throws  LDAPException  If a problem occurs while reading or parsing the
201       *                         bind request.
202       */
203      BindRequestProtocolOp(final ASN1StreamReader reader)
204           throws LDAPException
205      {
206        try
207        {
208          reader.beginSequence();
209          version         = reader.readInteger();
210          bindDN          = reader.readString();
211          credentialsType = (byte) reader.peek();
212    
213          ensureNotNull(bindDN);
214    
215          switch (credentialsType)
216          {
217            case CRED_TYPE_SIMPLE:
218              simplePassword =
219                   new ASN1OctetString(credentialsType, reader.readBytes());
220              saslMechanism   = null;
221              saslCredentials = null;
222              ensureNotNull(bindDN);
223              break;
224    
225            case CRED_TYPE_SASL:
226              final ASN1StreamReaderSequence saslSequence = reader.beginSequence();
227              saslMechanism = reader.readString();
228              ensureNotNull(saslMechanism);
229              if (saslSequence.hasMoreElements())
230              {
231                saslCredentials = new ASN1OctetString(reader.readBytes());
232              }
233              else
234              {
235                saslCredentials = null;
236              }
237              simplePassword = null;
238              break;
239    
240            default:
241              throw new LDAPException(ResultCode.DECODING_ERROR,
242                   ERR_BIND_REQUEST_INVALID_CRED_TYPE.get(toHex(credentialsType)));
243          }
244        }
245        catch (LDAPException le)
246        {
247          debugException(le);
248          throw le;
249        }
250        catch (Exception e)
251        {
252          debugException(e);
253    
254          throw new LDAPException(ResultCode.DECODING_ERROR,
255               ERR_BIND_REQUEST_CANNOT_DECODE.get(getExceptionMessage(e)), e);
256        }
257      }
258    
259    
260    
261      /**
262       * Retrieves the protocol version for this bind request.
263       *
264       * @return  The protocol version for this bind request.
265       */
266      public int getVersion()
267      {
268        return version;
269      }
270    
271    
272    
273      /**
274       * Retrieves the bind DN for this bind request.
275       *
276       * @return  The bind DN for this bind request, or an empty string if none was
277       *          provided.
278       */
279      public String getBindDN()
280      {
281        return bindDN;
282      }
283    
284    
285    
286      /**
287       * Retrieves the credentials type for this bind request.  It will either be
288       * {@link #CRED_TYPE_SIMPLE} or {@link #CRED_TYPE_SASL}.
289       *
290       * @return  The credentials type for this bind request.
291       */
292      public byte getCredentialsType()
293      {
294        return credentialsType;
295      }
296    
297    
298    
299      /**
300       * Retrieves the password to use for simple authentication.
301       *
302       * @return  The password to use for simple authentication, or {@code null} if
303       *          SASL authentication will be used.
304       */
305      public ASN1OctetString getSimplePassword()
306      {
307        return simplePassword;
308      }
309    
310    
311    
312      /**
313       * Retrieves the name of the SASL mechanism for this bind request.
314       *
315       * @return  The name of the SASL mechanism for this bind request, or
316       *          {@code null} if simple authentication will be used.
317       */
318      public String getSASLMechanism()
319      {
320        return saslMechanism;
321      }
322    
323    
324    
325      /**
326       * Retrieves the credentials to use for SASL authentication, if any.
327       *
328       * @return  The credentials to use for SASL authentication, or {@code null} if
329       *          there are no SASL credentials or if simple authentication will be
330       *          used.
331       */
332      public ASN1OctetString getSASLCredentials()
333      {
334        return saslCredentials;
335      }
336    
337    
338    
339      /**
340       * {@inheritDoc}
341       */
342      public byte getProtocolOpType()
343      {
344        return LDAPMessage.PROTOCOL_OP_TYPE_BIND_REQUEST;
345      }
346    
347    
348    
349      /**
350       * {@inheritDoc}
351       */
352      public void writeTo(final ASN1Buffer buffer)
353      {
354        final ASN1BufferSequence opSequence =
355             buffer.beginSequence(LDAPMessage.PROTOCOL_OP_TYPE_BIND_REQUEST);
356        buffer.addInteger(version);
357        buffer.addOctetString(bindDN);
358    
359        if (credentialsType == CRED_TYPE_SIMPLE)
360        {
361          buffer.addElement(simplePassword);
362        }
363        else
364        {
365          final ASN1BufferSequence saslSequence =
366               buffer.beginSequence(CRED_TYPE_SASL);
367          buffer.addOctetString(saslMechanism);
368          if (saslCredentials != null)
369          {
370            buffer.addElement(saslCredentials);
371          }
372          saslSequence.end();
373        }
374        opSequence.end();
375        buffer.setZeroBufferOnClear();
376      }
377    
378    
379    
380      /**
381       * Retrieves a string representation of this protocol op.
382       *
383       * @return  A string representation of this protocol op.
384       */
385      @Override()
386      public String toString()
387      {
388        final StringBuilder buffer = new StringBuilder();
389        toString(buffer);
390        return buffer.toString();
391      }
392    
393    
394    
395      /**
396       * {@inheritDoc}
397       */
398      public void toString(final StringBuilder buffer)
399      {
400        buffer.append("BindRequestProtocolOp(version=");
401        buffer.append(version);
402        buffer.append(", bindDN='");
403        buffer.append(bindDN);
404        buffer.append("', type=");
405    
406        if (credentialsType == CRED_TYPE_SIMPLE)
407        {
408          buffer.append("simple");
409        }
410        else
411        {
412          buffer.append("SASL, mechanism=");
413          buffer.append(saslMechanism);
414        }
415    
416        buffer.append(')');
417      }
418    }