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