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 }