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.Arrays; 042import java.util.List; 043import java.util.concurrent.LinkedBlockingQueue; 044import java.util.concurrent.TimeUnit; 045import java.util.logging.Level; 046 047import com.unboundid.asn1.ASN1Buffer; 048import com.unboundid.asn1.ASN1BufferSequence; 049import com.unboundid.asn1.ASN1Element; 050import com.unboundid.asn1.ASN1Integer; 051import com.unboundid.asn1.ASN1OctetString; 052import com.unboundid.asn1.ASN1Sequence; 053import com.unboundid.ldap.protocol.LDAPMessage; 054import com.unboundid.ldap.protocol.LDAPResponse; 055import com.unboundid.ldap.protocol.ProtocolOp; 056import com.unboundid.util.Debug; 057import com.unboundid.util.InternalUseOnly; 058import com.unboundid.util.LDAPSDKUsageException; 059import com.unboundid.util.NotMutable; 060import com.unboundid.util.NotNull; 061import com.unboundid.util.Nullable; 062import com.unboundid.util.StaticUtils; 063import com.unboundid.util.ThreadSafety; 064import com.unboundid.util.ThreadSafetyLevel; 065 066import static com.unboundid.ldap.sdk.LDAPMessages.*; 067 068 069 070/** 071 * This class implements the processing necessary to perform an LDAPv3 simple 072 * bind operation, which authenticates using a bind DN and password. 073 */ 074@NotMutable() 075@ThreadSafety(level=ThreadSafetyLevel.NOT_THREADSAFE) 076public final class SimpleBindRequest 077 extends BindRequest 078 implements ResponseAcceptor, ProtocolOp 079{ 080 /** 081 * The BER type to use for the credentials element in a simple bind request 082 * protocol op. 083 */ 084 private static final byte CRED_TYPE_SIMPLE = (byte) 0x80; 085 086 087 088 /** 089 * The ASN.1 octet string that will be used for the bind DN if none was 090 * provided. 091 */ 092 @NotNull private static final ASN1OctetString NO_BIND_DN = 093 new ASN1OctetString(); 094 095 096 097 /** 098 * The ASN.1 octet string that will be used for the bind password if none was 099 * provided. 100 */ 101 @NotNull private static final ASN1OctetString NO_PASSWORD = 102 new ASN1OctetString(CRED_TYPE_SIMPLE); 103 104 105 106 /** 107 * The serial version UID for this serializable class. 108 */ 109 private static final long serialVersionUID = 4725871243149974407L; 110 111 112 113 // The message ID from the last LDAP message sent from this request. 114 private int messageID = -1; 115 116 // The bind DN for this simple bind request. 117 @NotNull private final ASN1OctetString bindDN; 118 119 // The password for this simple bind request. 120 @Nullable private final ASN1OctetString password; 121 122 // The queue that will be used to receive response messages from the server. 123 @NotNull private final LinkedBlockingQueue<LDAPResponse> responseQueue = 124 new LinkedBlockingQueue<>(); 125 126 // The password provider that should be used to obtain the password for this 127 // simple bind request. 128 @Nullable private final PasswordProvider passwordProvider; 129 130 131 132 /** 133 * Creates a new simple bind request that may be used to perform an anonymous 134 * bind to the directory server (i.e., with a zero-length bind DN and a 135 * zero-length password). 136 */ 137 public SimpleBindRequest() 138 { 139 this(NO_BIND_DN, NO_PASSWORD, null, NO_CONTROLS); 140 } 141 142 143 144 /** 145 * Creates a new simple bind request with the provided bind DN and password. 146 * 147 * @param bindDN The bind DN for this simple bind request. 148 * @param password The password for this simple bind request. 149 */ 150 public SimpleBindRequest(@Nullable final String bindDN, 151 @Nullable final String password) 152 { 153 this(bindDN, password, NO_CONTROLS); 154 } 155 156 157 158 /** 159 * Creates a new simple bind request with the provided bind DN and password. 160 * 161 * @param bindDN The bind DN for this simple bind request. 162 * @param password The password for this simple bind request. 163 */ 164 public SimpleBindRequest(@Nullable final String bindDN, 165 @Nullable final byte[] password) 166 { 167 this(bindDN, password, NO_CONTROLS); 168 } 169 170 171 172 /** 173 * Creates a new simple bind request with the provided bind DN and password. 174 * 175 * @param bindDN The bind DN for this simple bind request. 176 * @param password The password for this simple bind request. 177 */ 178 public SimpleBindRequest(@Nullable final DN bindDN, 179 @Nullable final String password) 180 { 181 this(bindDN, password, NO_CONTROLS); 182 } 183 184 185 186 /** 187 * Creates a new simple bind request with the provided bind DN and password. 188 * 189 * @param bindDN The bind DN for this simple bind request. 190 * @param password The password for this simple bind request. 191 */ 192 public SimpleBindRequest(@Nullable final DN bindDN, 193 @Nullable final byte[] password) 194 { 195 this(bindDN, password, NO_CONTROLS); 196 } 197 198 199 200 /** 201 * Creates a new simple bind request with the provided bind DN and password. 202 * 203 * @param bindDN The bind DN for this simple bind request. 204 * @param password The password for this simple bind request. 205 * @param controls The set of controls for this simple bind request. 206 */ 207 public SimpleBindRequest(@Nullable final String bindDN, 208 @Nullable final String password, 209 @Nullable final Control... controls) 210 { 211 super(controls); 212 213 if (bindDN == null) 214 { 215 this.bindDN = NO_BIND_DN; 216 } 217 else 218 { 219 this.bindDN = new ASN1OctetString(bindDN); 220 } 221 222 if (password == null) 223 { 224 this.password = NO_PASSWORD; 225 } 226 else 227 { 228 this.password = new ASN1OctetString(CRED_TYPE_SIMPLE, password); 229 } 230 231 passwordProvider = null; 232 } 233 234 235 236 /** 237 * Creates a new simple bind request with the provided bind DN and password. 238 * 239 * @param bindDN The bind DN for this simple bind request. 240 * @param password The password for this simple bind request. 241 * @param controls The set of controls for this simple bind request. 242 */ 243 public SimpleBindRequest(@Nullable final String bindDN, 244 @Nullable final byte[] password, 245 @Nullable final Control... controls) 246 { 247 super(controls); 248 249 if (bindDN == null) 250 { 251 this.bindDN = NO_BIND_DN; 252 } 253 else 254 { 255 this.bindDN = new ASN1OctetString(bindDN); 256 } 257 258 if (password == null) 259 { 260 this.password = NO_PASSWORD; 261 } 262 else 263 { 264 this.password = new ASN1OctetString(CRED_TYPE_SIMPLE, password); 265 } 266 267 passwordProvider = null; 268 } 269 270 271 272 /** 273 * Creates a new simple bind request with the provided bind DN and password. 274 * 275 * @param bindDN The bind DN for this simple bind request. 276 * @param password The password for this simple bind request. 277 * @param controls The set of controls for this simple bind request. 278 */ 279 public SimpleBindRequest(@Nullable final DN bindDN, 280 @Nullable final String password, 281 @Nullable final Control... controls) 282 { 283 super(controls); 284 285 if (bindDN == null) 286 { 287 this.bindDN = NO_BIND_DN; 288 } 289 else 290 { 291 this.bindDN = new ASN1OctetString(bindDN.toString()); 292 } 293 294 if (password == null) 295 { 296 this.password = NO_PASSWORD; 297 } 298 else 299 { 300 this.password = new ASN1OctetString(CRED_TYPE_SIMPLE, password); 301 } 302 303 passwordProvider = null; 304 } 305 306 307 308 /** 309 * Creates a new simple bind request with the provided bind DN and password. 310 * 311 * @param bindDN The bind DN for this simple bind request. 312 * @param password The password for this simple bind request. 313 * @param controls The set of controls for this simple bind request. 314 */ 315 public SimpleBindRequest(@Nullable final DN bindDN, 316 @Nullable final byte[] password, 317 @Nullable final Control... controls) 318 { 319 super(controls); 320 321 if (bindDN == null) 322 { 323 this.bindDN = NO_BIND_DN; 324 } 325 else 326 { 327 this.bindDN = new ASN1OctetString(bindDN.toString()); 328 } 329 330 if (password == null) 331 { 332 this.password = NO_PASSWORD; 333 } 334 else 335 { 336 this.password = new ASN1OctetString(CRED_TYPE_SIMPLE, password); 337 } 338 339 passwordProvider = null; 340 } 341 342 343 344 /** 345 * Creates a new simple bind request with the provided bind DN and that will 346 * use a password provider in order to obtain the bind password. 347 * 348 * @param bindDN The bind DN for this simple bind request. It 349 * must not be {@code null}. 350 * @param passwordProvider The password provider that will be used to obtain 351 * the password for this simple bind request. It 352 * must not be {@code null}. 353 * @param controls The set of controls for this simple bind request. 354 */ 355 public SimpleBindRequest(@NotNull final String bindDN, 356 @NotNull final PasswordProvider passwordProvider, 357 @Nullable final Control... controls) 358 { 359 super(controls); 360 361 this.bindDN = new ASN1OctetString(bindDN); 362 this.passwordProvider = passwordProvider; 363 364 password = null; 365 } 366 367 368 369 /** 370 * Creates a new simple bind request with the provided bind DN and that will 371 * use a password provider in order to obtain the bind password. 372 * 373 * @param bindDN The bind DN for this simple bind request. It 374 * must not be {@code null}. 375 * @param passwordProvider The password provider that will be used to obtain 376 * the password for this simple bind request. It 377 * must not be {@code null}. 378 * @param controls The set of controls for this simple bind request. 379 */ 380 public SimpleBindRequest(@NotNull final DN bindDN, 381 @NotNull final PasswordProvider passwordProvider, 382 @Nullable final Control... controls) 383 { 384 super(controls); 385 386 this.bindDN = new ASN1OctetString(bindDN.toString()); 387 this.passwordProvider = passwordProvider; 388 389 password = null; 390 } 391 392 393 394 /** 395 * Creates a new simple bind request with the provided bind DN and password. 396 * 397 * @param bindDN The bind DN for this simple bind request. 398 * @param password The password for this simple bind request. 399 * @param passwordProvider The password provider that will be used to obtain 400 * the password to use for the bind request. 401 * @param controls The set of controls for this simple bind request. 402 */ 403 private SimpleBindRequest(@Nullable final ASN1OctetString bindDN, 404 @Nullable final ASN1OctetString password, 405 @Nullable final PasswordProvider passwordProvider, 406 @Nullable final Control... controls) 407 { 408 super(controls); 409 410 this.bindDN = bindDN; 411 this.password = password; 412 this.passwordProvider = passwordProvider; 413 } 414 415 416 417 /** 418 * Retrieves the bind DN for this simple bind request. 419 * 420 * @return The bind DN for this simple bind request. 421 */ 422 @NotNull() 423 public String getBindDN() 424 { 425 return bindDN.stringValue(); 426 } 427 428 429 430 /** 431 * Retrieves the password for this simple bind request, if no password 432 * provider has been configured. 433 * 434 * @return The password for this simple bind request, or {@code null} if a 435 * password provider will be used to obtain the password. 436 */ 437 @Nullable() 438 public ASN1OctetString getPassword() 439 { 440 return password; 441 } 442 443 444 445 /** 446 * Retrieves the password provider for this simple bind request, if defined. 447 * 448 * @return The password provider for this simple bind request, or 449 * {@code null} if this bind request was created with an explicit 450 * password rather than a password provider. 451 */ 452 @Nullable() 453 public PasswordProvider getPasswordProvider() 454 { 455 return passwordProvider; 456 } 457 458 459 460 /** 461 * {@inheritDoc} 462 */ 463 @Override() 464 public byte getProtocolOpType() 465 { 466 return LDAPMessage.PROTOCOL_OP_TYPE_BIND_REQUEST; 467 } 468 469 470 471 /** 472 * {@inheritDoc} 473 */ 474 @Override() 475 public void writeTo(@NotNull final ASN1Buffer buffer) 476 { 477 final ASN1BufferSequence requestSequence = 478 buffer.beginSequence(LDAPMessage.PROTOCOL_OP_TYPE_BIND_REQUEST); 479 buffer.addElement(VERSION_ELEMENT); 480 buffer.addElement(bindDN); 481 482 if (passwordProvider == null) 483 { 484 buffer.addElement(password); 485 } 486 else 487 { 488 final byte[] pwBytes; 489 try 490 { 491 pwBytes = passwordProvider.getPasswordBytes(); 492 } 493 catch (final LDAPException le) 494 { 495 Debug.debugException(le); 496 throw new LDAPRuntimeException(le); 497 } 498 499 final ASN1OctetString pw = new ASN1OctetString(CRED_TYPE_SIMPLE, pwBytes); 500 buffer.addElement(pw); 501 buffer.setZeroBufferOnClear(); 502 Arrays.fill(pwBytes, (byte) 0x00); 503 } 504 505 requestSequence.end(); 506 } 507 508 509 510 /** 511 * {@inheritDoc} 512 * Use of this method is only supported if the bind request was created with a 513 * static password. It is not allowed if the password will be obtained 514 * through a password provider. 515 * 516 * @throws LDAPSDKUsageException If this bind request was created with a 517 * password provider rather than a static 518 * password. 519 */ 520 @Override() 521 @NotNull() 522 public ASN1Element encodeProtocolOp() 523 throws LDAPSDKUsageException 524 { 525 if (password == null) 526 { 527 throw new LDAPSDKUsageException( 528 ERR_SIMPLE_BIND_ENCODE_PROTOCOL_OP_WITH_PROVIDER.get()); 529 } 530 531 return new ASN1Sequence(LDAPMessage.PROTOCOL_OP_TYPE_BIND_REQUEST, 532 new ASN1Integer(3), 533 bindDN, 534 password); 535 } 536 537 538 539 /** 540 * {@inheritDoc} 541 */ 542 @Override() 543 @NotNull() 544 protected BindResult process(@NotNull final LDAPConnection connection, 545 final int depth) 546 throws LDAPException 547 { 548 // See if a bind DN was provided without a password. If that is the case 549 // and this should not be allowed, then throw an exception. 550 if (password != null) 551 { 552 if ((bindDN.getValue().length > 0) && (password.getValue().length == 0) && 553 connection.getConnectionOptions().bindWithDNRequiresPassword()) 554 { 555 final LDAPException le = new LDAPException(ResultCode.PARAM_ERROR, 556 ERR_SIMPLE_BIND_DN_WITHOUT_PASSWORD.get()); 557 Debug.debugCodingError(le); 558 throw le; 559 } 560 } 561 562 563 if (connection.synchronousMode()) 564 { 565 @SuppressWarnings("deprecation") 566 final boolean autoReconnect = 567 connection.getConnectionOptions().autoReconnect(); 568 return processSync(connection, autoReconnect); 569 } 570 571 // Create the LDAP message. 572 messageID = connection.nextMessageID(); 573 final LDAPMessage message = new LDAPMessage(messageID, this, getControls()); 574 575 576 // Register with the connection reader to be notified of responses for the 577 // request that we've created. 578 connection.registerResponseAcceptor(messageID, this); 579 580 581 try 582 { 583 // Send the request to the server. 584 final long responseTimeout = getResponseTimeoutMillis(connection); 585 Debug.debugLDAPRequest(Level.INFO, this, messageID, connection); 586 587 final LDAPConnectionLogger logger = 588 connection.getConnectionOptions().getConnectionLogger(); 589 if (logger != null) 590 { 591 logger.logBindRequest(connection, messageID, this); 592 } 593 594 final long requestTime = System.nanoTime(); 595 connection.getConnectionStatistics().incrementNumBindRequests(); 596 connection.sendMessage(message, responseTimeout); 597 598 // Wait for and process the response. 599 final LDAPResponse response; 600 try 601 { 602 if (responseTimeout > 0) 603 { 604 response = responseQueue.poll(responseTimeout, TimeUnit.MILLISECONDS); 605 } 606 else 607 { 608 response = responseQueue.take(); 609 } 610 } 611 catch (final InterruptedException ie) 612 { 613 Debug.debugException(ie); 614 Thread.currentThread().interrupt(); 615 throw new LDAPException(ResultCode.LOCAL_ERROR, 616 ERR_BIND_INTERRUPTED.get(connection.getHostPort()), ie); 617 } 618 619 return handleResponse(connection, response, requestTime, false); 620 } 621 finally 622 { 623 connection.deregisterResponseAcceptor(messageID); 624 } 625 } 626 627 628 629 /** 630 * Processes this bind operation in synchronous mode, in which the same 631 * thread will send the request and read the response. 632 * 633 * @param connection The connection to use to communicate with the directory 634 * server. 635 * @param allowRetry Indicates whether the request may be re-tried on a 636 * re-established connection if the initial attempt fails 637 * in a way that indicates the connection is no longer 638 * valid and autoReconnect is true. 639 * 640 * @return An LDAP result object that provides information about the result 641 * of the bind processing. 642 * 643 * @throws LDAPException If a problem occurs while sending the request or 644 * reading the response. 645 */ 646 @NotNull() 647 private BindResult processSync(@NotNull final LDAPConnection connection, 648 final boolean allowRetry) 649 throws LDAPException 650 { 651 // Create the LDAP message. 652 messageID = connection.nextMessageID(); 653 final LDAPMessage message = 654 new LDAPMessage(messageID, this, getControls()); 655 656 657 // Send the request to the server. 658 final long requestTime = System.nanoTime(); 659 Debug.debugLDAPRequest(Level.INFO, this, messageID, connection); 660 661 final LDAPConnectionLogger logger = 662 connection.getConnectionOptions().getConnectionLogger(); 663 if (logger != null) 664 { 665 logger.logBindRequest(connection, messageID, this); 666 } 667 668 connection.getConnectionStatistics().incrementNumBindRequests(); 669 try 670 { 671 connection.sendMessage(message, getResponseTimeoutMillis(connection)); 672 } 673 catch (final LDAPException le) 674 { 675 Debug.debugException(le); 676 677 if (allowRetry) 678 { 679 final BindResult bindResult = reconnectAndRetry(connection, 680 le.getResultCode()); 681 if (bindResult != null) 682 { 683 return bindResult; 684 } 685 } 686 687 throw le; 688 } 689 690 while (true) 691 { 692 final LDAPResponse response = connection.readResponse(messageID); 693 if (response instanceof IntermediateResponse) 694 { 695 final IntermediateResponseListener listener = 696 getIntermediateResponseListener(); 697 if (listener != null) 698 { 699 listener.intermediateResponseReturned( 700 (IntermediateResponse) response); 701 } 702 } 703 else 704 { 705 return handleResponse(connection, response, requestTime, allowRetry); 706 } 707 } 708 } 709 710 711 712 /** 713 * Performs the necessary processing for handling a response. 714 * 715 * @param connection The connection used to read the response. 716 * @param response The response to be processed. 717 * @param requestTime The time the request was sent to the server. 718 * @param allowRetry Indicates whether the request may be re-tried on a 719 * re-established connection if the initial attempt fails 720 * in a way that indicates the connection is no longer 721 * valid and autoReconnect is true. 722 * 723 * @return The bind result. 724 * 725 * @throws LDAPException If a problem occurs. 726 */ 727 @NotNull() 728 private BindResult handleResponse(@NotNull final LDAPConnection connection, 729 @Nullable final LDAPResponse response, 730 final long requestTime, 731 final boolean allowRetry) 732 throws LDAPException 733 { 734 if (response == null) 735 { 736 final long waitTime = 737 StaticUtils.nanosToMillis(System.nanoTime() - requestTime); 738 throw new LDAPException(ResultCode.TIMEOUT, 739 ERR_SIMPLE_BIND_CLIENT_TIMEOUT.get(waitTime, messageID, 740 bindDN.stringValue(), connection.getHostPort())); 741 } 742 743 connection.getConnectionStatistics().incrementNumBindResponses( 744 System.nanoTime() - requestTime); 745 if (response instanceof ConnectionClosedResponse) 746 { 747 // The connection was closed while waiting for the response. 748 if (allowRetry) 749 { 750 final BindResult retryResult = reconnectAndRetry(connection, 751 ResultCode.SERVER_DOWN); 752 if (retryResult != null) 753 { 754 return retryResult; 755 } 756 } 757 758 final ConnectionClosedResponse ccr = (ConnectionClosedResponse) response; 759 final String message = ccr.getMessage(); 760 if (message == null) 761 { 762 throw new LDAPException(ccr.getResultCode(), 763 ERR_CONN_CLOSED_WAITING_FOR_BIND_RESPONSE.get( 764 connection.getHostPort(), toString())); 765 } 766 else 767 { 768 throw new LDAPException(ccr.getResultCode(), 769 ERR_CONN_CLOSED_WAITING_FOR_BIND_RESPONSE_WITH_MESSAGE.get( 770 connection.getHostPort(), toString(), message)); 771 } 772 } 773 774 final BindResult bindResult = (BindResult) response; 775 if (allowRetry) 776 { 777 final BindResult retryResult = reconnectAndRetry(connection, 778 bindResult.getResultCode()); 779 if (retryResult != null) 780 { 781 return retryResult; 782 } 783 } 784 785 return bindResult; 786 } 787 788 789 790 /** 791 * Attempts to re-establish the connection and retry processing this request 792 * on it. 793 * 794 * @param connection The connection to be re-established. 795 * @param resultCode The result code for the previous operation attempt. 796 * 797 * @return The result from re-trying the bind, or {@code null} if it could 798 * not be re-tried. 799 */ 800 @Nullable() 801 private BindResult reconnectAndRetry(@NotNull final LDAPConnection connection, 802 @NotNull final ResultCode resultCode) 803 { 804 try 805 { 806 // We will only want to retry for certain result codes that indicate a 807 // connection problem. 808 switch (resultCode.intValue()) 809 { 810 case ResultCode.SERVER_DOWN_INT_VALUE: 811 case ResultCode.DECODING_ERROR_INT_VALUE: 812 case ResultCode.CONNECT_ERROR_INT_VALUE: 813 connection.reconnect(); 814 return processSync(connection, false); 815 } 816 } 817 catch (final Exception e) 818 { 819 Debug.debugException(e); 820 } 821 822 return null; 823 } 824 825 826 827 /** 828 * {@inheritDoc} 829 */ 830 @Override() 831 @NotNull() 832 public SimpleBindRequest getRebindRequest(@NotNull final String host, 833 final int port) 834 { 835 return new SimpleBindRequest(bindDN, password, passwordProvider, 836 getControls()); 837 } 838 839 840 841 /** 842 * {@inheritDoc} 843 */ 844 @InternalUseOnly() 845 @Override() 846 public void responseReceived(@NotNull final LDAPResponse response) 847 throws LDAPException 848 { 849 try 850 { 851 responseQueue.put(response); 852 } 853 catch (final Exception e) 854 { 855 Debug.debugException(e); 856 857 if (e instanceof InterruptedException) 858 { 859 Thread.currentThread().interrupt(); 860 } 861 862 throw new LDAPException(ResultCode.LOCAL_ERROR, 863 ERR_EXCEPTION_HANDLING_RESPONSE.get( 864 StaticUtils.getExceptionMessage(e)), 865 e); 866 } 867 } 868 869 870 871 /** 872 * {@inheritDoc} 873 */ 874 @Override() 875 @NotNull() 876 public String getBindType() 877 { 878 return "SIMPLE"; 879 } 880 881 882 883 /** 884 * {@inheritDoc} 885 */ 886 @Override() 887 public int getLastMessageID() 888 { 889 return messageID; 890 } 891 892 893 894 /** 895 * {@inheritDoc} 896 */ 897 @Override() 898 @NotNull() 899 public SimpleBindRequest duplicate() 900 { 901 return duplicate(getControls()); 902 } 903 904 905 906 /** 907 * {@inheritDoc} 908 */ 909 @Override() 910 @NotNull() 911 public SimpleBindRequest duplicate(@Nullable final Control[] controls) 912 { 913 final SimpleBindRequest bindRequest = 914 new SimpleBindRequest(bindDN, password, passwordProvider, controls); 915 bindRequest.setResponseTimeoutMillis(getResponseTimeoutMillis(null)); 916 return bindRequest; 917 } 918 919 920 921 /** 922 * {@inheritDoc} 923 */ 924 @Override() 925 public void toString(@NotNull final StringBuilder buffer) 926 { 927 buffer.append("SimpleBindRequest(dn='"); 928 buffer.append(bindDN); 929 buffer.append('\''); 930 931 final Control[] controls = getControls(); 932 if (controls.length > 0) 933 { 934 buffer.append(", controls={"); 935 for (int i=0; i < controls.length; i++) 936 { 937 if (i > 0) 938 { 939 buffer.append(", "); 940 } 941 942 buffer.append(controls[i]); 943 } 944 buffer.append('}'); 945 } 946 947 buffer.append(')'); 948 } 949 950 951 952 /** 953 * {@inheritDoc} 954 */ 955 @Override() 956 public void toCode(@NotNull final List<String> lineList, 957 @NotNull final String requestID, 958 final int indentSpaces, final boolean includeProcessing) 959 { 960 // Create the request variable. 961 final ArrayList<ToCodeArgHelper> constructorArgs = new ArrayList<>(3); 962 constructorArgs.add(ToCodeArgHelper.createString(bindDN.stringValue(), 963 "Bind DN")); 964 constructorArgs.add(ToCodeArgHelper.createString("---redacted-password---", 965 "Bind Password")); 966 967 final Control[] controls = getControls(); 968 if (controls.length > 0) 969 { 970 constructorArgs.add(ToCodeArgHelper.createControlArray(controls, 971 "Bind Controls")); 972 } 973 974 ToCodeHelper.generateMethodCall(lineList, indentSpaces, "SimpleBindRequest", 975 requestID + "Request", "new SimpleBindRequest", constructorArgs); 976 977 978 // Add lines for processing the request and obtaining the result. 979 if (includeProcessing) 980 { 981 // Generate a string with the appropriate indent. 982 final StringBuilder buffer = new StringBuilder(); 983 for (int i=0; i < indentSpaces; i++) 984 { 985 buffer.append(' '); 986 } 987 final String indent = buffer.toString(); 988 989 lineList.add(""); 990 lineList.add(indent + "try"); 991 lineList.add(indent + '{'); 992 lineList.add(indent + " BindResult " + requestID + 993 "Result = connection.bind(" + requestID + "Request);"); 994 lineList.add(indent + " // The bind was processed successfully."); 995 lineList.add(indent + '}'); 996 lineList.add(indent + "catch (LDAPException e)"); 997 lineList.add(indent + '{'); 998 lineList.add(indent + " // The bind failed. Maybe the following will " + 999 "help explain why."); 1000 lineList.add(indent + " // Note that the connection is now likely in " + 1001 "an unauthenticated state."); 1002 lineList.add(indent + " ResultCode resultCode = e.getResultCode();"); 1003 lineList.add(indent + " String message = e.getMessage();"); 1004 lineList.add(indent + " String matchedDN = e.getMatchedDN();"); 1005 lineList.add(indent + " String[] referralURLs = e.getReferralURLs();"); 1006 lineList.add(indent + " Control[] responseControls = " + 1007 "e.getResponseControls();"); 1008 lineList.add(indent + '}'); 1009 } 1010 } 1011}