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