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