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 com.unboundid.asn1.ASN1OctetString;
026    import com.unboundid.util.NotMutable;
027    import com.unboundid.util.ThreadSafety;
028    import com.unboundid.util.ThreadSafetyLevel;
029    
030    import static com.unboundid.util.StaticUtils.*;
031    import static com.unboundid.util.Validator.*;
032    
033    
034    
035    /**
036     * This class provides a SASL PLAIN bind request implementation as described in
037     * <A HREF="http://www.ietf.org/rfc/rfc4616.txt">RFC 4616</A>.  The SASL PLAIN
038     * mechanism allows the client to authenticate with an authentication ID and
039     * password, and optionally allows the client to provide an authorization ID for
040     * use in performing subsequent operations.
041     * <BR><BR>
042     * Elements included in a PLAIN bind request include:
043     * <UL>
044     *   <LI>Authentication ID -- A string which identifies the user that is
045     *       attempting to authenticate.  It should be an "authzId" value as
046     *       described in section 5.2.1.8 of
047     *       <A HREF="http://www.ietf.org/rfc/rfc4513.txt">RFC 4513</A>.  That is,
048     *       it should be either "dn:" followed by the distinguished name of the
049     *       target user, or "u:" followed by the username.  If the "u:" form is
050     *       used, then the mechanism used to resolve the provided username to an
051     *       entry may vary from server to server.</LI>
052     *   <LI>Authorization ID -- An optional string which specifies an alternate
053     *       authorization identity that should be used for subsequent operations
054     *       requested on the connection.  Like the authentication ID, the
055     *       authorization ID should use the "authzId" syntax.</LI>
056     *   <LI>Password -- The clear-text password for the target user.</LI>
057     * </UL>
058     * <H2>Example</H2>
059     * The following example demonstrates the process for performing a PLAIN bind
060     * against a directory server with a username of "test.user" and a password of
061     * "password":
062     * <PRE>
063     * PLAINBindRequest bindRequest =
064     *      new PLAINBindRequest("u:test.user", "password");
065     * BindResult bindResult;
066     * try
067     * {
068     *   bindResult = connection.bind(bindRequest);
069     *   // If we get here, then the bind was successful.
070     * }
071     * catch (LDAPException le)
072     * {
073     *   // The bind failed for some reason.
074     *   bindResult = new BindResult(le.toLDAPResult());
075     *   ResultCode resultCode = le.getResultCode();
076     *   String errorMessageFromServer = le.getDiagnosticMessage();
077     * }
078     * </PRE>
079     */
080    @NotMutable()
081    @ThreadSafety(level=ThreadSafetyLevel.NOT_THREADSAFE)
082    public final class PLAINBindRequest
083           extends SASLBindRequest
084    {
085      /**
086       * The name for the PLAIN SASL mechanism.
087       */
088      public static final String PLAIN_MECHANISM_NAME = "PLAIN";
089    
090    
091    
092      /**
093       * The serial version UID for this serializable class.
094       */
095      private static final long serialVersionUID = -5186140710317748684L;
096    
097    
098    
099      // The password for this bind request.
100      private final ASN1OctetString password;
101    
102      // The authentication ID string for this bind request.
103      private final String authenticationID;
104    
105      // The authorization ID string for this bind request, if available.
106      private final String authorizationID;
107    
108    
109    
110      /**
111       * Creates a new SASL PLAIN bind request with the provided authentication ID
112       * and password.  It will not include an authorization ID or set of controls.
113       *
114       * @param  authenticationID  The authentication ID for this bind request.  It
115       *                           must not be {@code null}.
116       * @param  password          The password for this bind request.  It must not
117       *                           be {@code null}.
118       */
119      public PLAINBindRequest(final String authenticationID, final String password)
120      {
121        this(authenticationID, null, new ASN1OctetString(password), NO_CONTROLS);
122    
123        ensureNotNull(password);
124      }
125    
126    
127    
128      /**
129       * Creates a new SASL PLAIN bind request with the provided authentication ID
130       * and password.  It will not include an authorization ID or set of controls.
131       *
132       * @param  authenticationID  The authentication ID for this bind request.  It
133       *                           must not be {@code null}.
134       * @param  password          The password for this bind request.  It must not
135       *                           be {@code null}.
136       */
137      public PLAINBindRequest(final String authenticationID, final byte[] password)
138      {
139        this(authenticationID, null, new ASN1OctetString(password), NO_CONTROLS);
140    
141        ensureNotNull(password);
142      }
143    
144    
145    
146      /**
147       * Creates a new SASL PLAIN bind request with the provided authentication ID
148       * and password.  It will not include an authorization ID or set of controls.
149       *
150       * @param  authenticationID  The authentication ID for this bind request.  It
151       *                           must not be {@code null}.
152       * @param  password          The password for this bind request.  It must not
153       *                           be {@code null}.
154       */
155      public PLAINBindRequest(final String authenticationID,
156                              final ASN1OctetString password)
157      {
158        this(authenticationID, null, password, NO_CONTROLS);
159      }
160    
161    
162    
163      /**
164       * Creates a new SASL PLAIN bind request with the provided authentication ID,
165       * authorization ID, and password.  It will not include a set of controls.
166       *
167       * @param  authenticationID  The authentication ID for this bind request.  It
168       *                           must not be {@code null}.
169       * @param  authorizationID   The authorization ID for this bind request, or
170       *                           {@code null} if there is to be no authorization
171       *                           ID.
172       * @param  password          The password for this bind request.  It must not
173       *                           be {@code null}.
174       */
175      public PLAINBindRequest(final String authenticationID,
176                              final String authorizationID, final String password)
177      {
178        this(authenticationID, authorizationID, new ASN1OctetString(password),
179             NO_CONTROLS);
180    
181        ensureNotNull(password);
182      }
183    
184    
185    
186      /**
187       * Creates a new SASL PLAIN bind request with the provided authentication ID,
188       * authorization ID, and password.  It will not include a set of controls.
189       *
190       * @param  authenticationID  The authentication ID for this bind request.  It
191       *                           must not be {@code null}.
192       * @param  authorizationID   The authorization ID for this bind request, or
193       *                           {@code null} if there is to be no authorization
194       *                           ID.
195       * @param  password          The password for this bind request.  It must not
196       *                           be {@code null}.
197       */
198      public PLAINBindRequest(final String authenticationID,
199                              final String authorizationID, final byte[] password)
200      {
201        this(authenticationID, authorizationID, new ASN1OctetString(password),
202             NO_CONTROLS);
203    
204        ensureNotNull(password);
205      }
206    
207    
208    
209      /**
210       * Creates a new SASL PLAIN bind request with the provided authentication ID,
211       * authorization ID, and password.  It will not include a set of controls.
212       *
213       * @param  authenticationID  The authentication ID for this bind request.  It
214       *                           must not be {@code null}.
215       * @param  authorizationID   The authorization ID for this bind request, or
216       *                           {@code null} if there is to be no authorization
217       *                           ID.
218       * @param  password          The password for this bind request.  It must not
219       *                           be {@code null}.
220       */
221      public PLAINBindRequest(final String authenticationID,
222                              final String authorizationID,
223                              final ASN1OctetString password)
224      {
225        this(authenticationID, authorizationID, password, NO_CONTROLS);
226      }
227    
228    
229    
230      /**
231       * Creates a new SASL PLAIN bind request with the provided authentication ID,
232       * password, and set of controls.  It will not include an authorization ID.
233       *
234       * @param  authenticationID  The authentication ID for this bind request.  It
235       *                           must not be {@code null}.
236       * @param  password          The password for this bind request.  It must not
237       *                           be {@code null}.
238       * @param  controls          The set of controls to include
239       */
240      public PLAINBindRequest(final String authenticationID, final String password,
241                              final Control... controls)
242      {
243        this(authenticationID, null, new ASN1OctetString(password), controls);
244    
245        ensureNotNull(password);
246      }
247    
248    
249    
250      /**
251       * Creates a new SASL PLAIN bind request with the provided authentication ID,
252       * password, and set of controls.  It will not include an authorization ID.
253       *
254       * @param  authenticationID  The authentication ID for this bind request.  It
255       *                           must not be {@code null}.
256       * @param  password          The password for this bind request.  It must not
257       *                           be {@code null}.
258       * @param  controls          The set of controls to include
259       */
260      public PLAINBindRequest(final String authenticationID, final byte[] password,
261                              final Control... controls)
262      {
263        this(authenticationID, null, new ASN1OctetString(password), controls);
264    
265        ensureNotNull(password);
266      }
267    
268    
269    
270      /**
271       * Creates a new SASL PLAIN bind request with the provided authentication ID,
272       * password, and set of controls.  It will not include an authorization ID.
273       *
274       * @param  authenticationID  The authentication ID for this bind request.  It
275       *                           must not be {@code null}.
276       * @param  password          The password for this bind request.  It must not
277       *                           be {@code null}.
278       * @param  controls          The set of controls to include
279       */
280      public PLAINBindRequest(final String authenticationID,
281                              final ASN1OctetString password,
282                              final Control... controls)
283      {
284        this(authenticationID, null, password, controls);
285      }
286    
287    
288    
289      /**
290       * Creates a new SASL PLAIN bind request with the provided information.
291       *
292       * @param  authenticationID  The authentication ID for this bind request.  It
293       *                           must not be {@code null}.
294       * @param  authorizationID   The authorization ID for this bind request, or
295       *                           {@code null} if there is to be no authorization
296       *                           ID.
297       * @param  password          The password for this bind request.  It must not
298       *                           be {@code null}.
299       * @param  controls          The set of controls to include
300       */
301      public PLAINBindRequest(final String authenticationID,
302                              final String authorizationID, final String password,
303                              final Control... controls)
304      {
305        this(authenticationID, authorizationID, new ASN1OctetString(password),
306             controls);
307    
308        ensureNotNull(password);
309      }
310    
311    
312    
313      /**
314       * Creates a new SASL PLAIN bind request with the provided information.
315       *
316       * @param  authenticationID  The authentication ID for this bind request.  It
317       *                           must not be {@code null}.
318       * @param  authorizationID   The authorization ID for this bind request, or
319       *                           {@code null} if there is to be no authorization
320       *                           ID.
321       * @param  password          The password for this bind request.  It must not
322       *                           be {@code null}.
323       * @param  controls          The set of controls to include
324       */
325      public PLAINBindRequest(final String authenticationID,
326                              final String authorizationID, final byte[] password,
327                              final Control... controls)
328      {
329        this(authenticationID, authorizationID, new ASN1OctetString(password),
330             controls);
331    
332        ensureNotNull(password);
333      }
334    
335    
336    
337      /**
338       * Creates a new SASL PLAIN bind request with the provided information.
339       *
340       * @param  authenticationID  The authentication ID for this bind request.  It
341       *                           must not be {@code null}.
342       * @param  authorizationID   The authorization ID for this bind request, or
343       *                           {@code null} if there is to be no authorization
344       *                           ID.
345       * @param  password          The password for this bind request.  It must not
346       *                           be {@code null}.
347       * @param  controls          The set of controls to include
348       */
349      public PLAINBindRequest(final String authenticationID,
350                              final String authorizationID,
351                              final ASN1OctetString password,
352                              final Control... controls)
353      {
354        super(controls);
355    
356        ensureNotNull(authenticationID, password);
357    
358        this.authenticationID = authenticationID;
359        this.authorizationID  = authorizationID;
360        this.password         = password;
361      }
362    
363    
364    
365      /**
366       * {@inheritDoc}
367       */
368      @Override()
369      public String getSASLMechanismName()
370      {
371        return PLAIN_MECHANISM_NAME;
372      }
373    
374    
375    
376      /**
377       * Retrieves the authentication ID for this bind request.
378       *
379       * @return  The authentication ID for this bind request.
380       */
381      public String getAuthenticationID()
382      {
383        return authenticationID;
384      }
385    
386    
387    
388      /**
389       * Retrieves the authorization ID for this bind request.
390       *
391       * @return  The authorization ID for this bind request, or {@code null} if
392       *          there is no authorization ID.
393       */
394      public String getAuthorizationID()
395      {
396        return authorizationID;
397      }
398    
399    
400    
401      /**
402       * Retrieves the string representation of the password for this bind request.
403       *
404       * @return  The string representation of the password for this bind request.
405       */
406      public String getPasswordString()
407      {
408        return password.stringValue();
409      }
410    
411    
412    
413      /**
414       * Retrieves the bytes that comprise the the password for this bind request.
415       *
416       * @return  The bytes that comprise the password for this bind request.
417       */
418      public byte[] getPasswordBytes()
419      {
420        return password.getValue();
421      }
422    
423    
424    
425      /**
426       * Sends this bind request to the target server over the provided connection
427       * and returns the corresponding response.
428       *
429       * @param  connection  The connection to use to send this bind request to the
430       *                     server and read the associated response.
431       * @param  depth       The current referral depth for this request.  It should
432       *                     always be one for the initial request, and should only
433       *                     be incremented when following referrals.
434       *
435       * @return  The bind response read from the server.
436       *
437       * @throws  LDAPException  If a problem occurs while sending the request or
438       *                         reading the response.
439       */
440      @Override()
441      protected BindResult process(final LDAPConnection connection, final int depth)
442                throws LDAPException
443      {
444        // Create the byte array that should comprise the credentials.
445        final byte[] authZIDBytes  = getBytes(authorizationID);
446        final byte[] authNIDBytes  = getBytes(authenticationID);
447        final byte[] passwordBytes = password.getValue();
448        final byte[] credBytes     = new byte[2 + authZIDBytes.length +
449                                        authNIDBytes.length + passwordBytes.length];
450    
451        System.arraycopy(authZIDBytes, 0, credBytes, 0, authZIDBytes.length);
452    
453        int pos = authZIDBytes.length + 1;
454        System.arraycopy(authNIDBytes, 0, credBytes, pos, authNIDBytes.length);
455    
456        pos += authNIDBytes.length + 1;
457        System.arraycopy(passwordBytes, 0, credBytes, pos, passwordBytes.length);
458    
459        return sendBindRequest(connection, "", new ASN1OctetString(credBytes),
460                               getControls(), getResponseTimeoutMillis(connection));
461      }
462    
463    
464    
465      /**
466       * {@inheritDoc}
467       */
468      @Override()
469      public PLAINBindRequest getRebindRequest(final String host, final int port)
470      {
471        return new PLAINBindRequest(authenticationID, authorizationID, password,
472                                    getControls());
473      }
474    
475    
476    
477      /**
478       * {@inheritDoc}
479       */
480      @Override()
481      public PLAINBindRequest duplicate()
482      {
483        return duplicate(getControls());
484      }
485    
486    
487    
488      /**
489       * {@inheritDoc}
490       */
491      @Override()
492      public PLAINBindRequest duplicate(final Control[] controls)
493      {
494        final PLAINBindRequest bindRequest = new PLAINBindRequest(authenticationID,
495             authorizationID, password, controls);
496        bindRequest.setResponseTimeoutMillis(getResponseTimeoutMillis(null));
497        return bindRequest;
498      }
499    
500    
501    
502      /**
503       * {@inheritDoc}
504       */
505      @Override()
506      public void toString(final StringBuilder buffer)
507      {
508        buffer.append("PLAINBindRequest(authenticationID='");
509        buffer.append(authenticationID);
510        buffer.append('\'');
511    
512        if (authorizationID != null)
513        {
514          buffer.append(", authorizationID='");
515          buffer.append(authorizationID);
516          buffer.append('\'');
517        }
518    
519        final Control[] controls = getControls();
520        if (controls.length > 0)
521        {
522          buffer.append(", controls={");
523          for (int i=0; i < controls.length; i++)
524          {
525            if (i > 0)
526            {
527              buffer.append(", ");
528            }
529    
530            buffer.append(controls[i]);
531          }
532          buffer.append('}');
533        }
534    
535        buffer.append(')');
536      }
537    }