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