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 com.unboundid.asn1.ASN1OctetString;
026import com.unboundid.util.NotMutable;
027import com.unboundid.util.ThreadSafety;
028import com.unboundid.util.ThreadSafetyLevel;
029
030import static com.unboundid.util.StaticUtils.*;
031import 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)
082public 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}