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