001/* 002 * Copyright 2007-2017 UnboundID Corp. 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright (C) 2008-2017 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 java.util.ArrayList; 026import java.util.List; 027 028import com.unboundid.asn1.ASN1OctetString; 029import com.unboundid.util.NotMutable; 030import com.unboundid.util.ThreadSafety; 031import com.unboundid.util.ThreadSafetyLevel; 032 033import static com.unboundid.util.StaticUtils.*; 034import 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) 085public 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}