001/* 002 * Copyright 2007-2024 Ping Identity Corporation 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright 2007-2024 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-2024 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 setReferralDepth(depth); 549 550 // See if a bind DN was provided without a password. If that is the case 551 // and this should not be allowed, then throw an exception. 552 if (password != null) 553 { 554 if ((bindDN.getValue().length > 0) && (password.getValue().length == 0) && 555 connection.getConnectionOptions().bindWithDNRequiresPassword()) 556 { 557 final LDAPException le = new LDAPException(ResultCode.PARAM_ERROR, 558 ERR_SIMPLE_BIND_DN_WITHOUT_PASSWORD.get()); 559 Debug.debugCodingError(le); 560 throw le; 561 } 562 } 563 564 565 if (connection.synchronousMode()) 566 { 567 @SuppressWarnings("deprecation") 568 final boolean autoReconnect = 569 connection.getConnectionOptions().autoReconnect(); 570 return processSync(connection, autoReconnect); 571 } 572 573 // Create the LDAP message. 574 messageID = connection.nextMessageID(); 575 final LDAPMessage message = new LDAPMessage(messageID, this, getControls()); 576 577 578 // Register with the connection reader to be notified of responses for the 579 // request that we've created. 580 connection.registerResponseAcceptor(messageID, this); 581 582 583 try 584 { 585 // Send the request to the server. 586 final long responseTimeout = getResponseTimeoutMillis(connection); 587 Debug.debugLDAPRequest(Level.INFO, this, messageID, connection); 588 589 final LDAPConnectionLogger logger = 590 connection.getConnectionOptions().getConnectionLogger(); 591 if (logger != null) 592 { 593 logger.logBindRequest(connection, messageID, this); 594 } 595 596 final long requestTime = System.nanoTime(); 597 connection.getConnectionStatistics().incrementNumBindRequests(); 598 connection.sendMessage(message, responseTimeout); 599 600 // Wait for and process the response. 601 final LDAPResponse response; 602 try 603 { 604 if (responseTimeout > 0) 605 { 606 response = responseQueue.poll(responseTimeout, TimeUnit.MILLISECONDS); 607 } 608 else 609 { 610 response = responseQueue.take(); 611 } 612 } 613 catch (final InterruptedException ie) 614 { 615 Debug.debugException(ie); 616 Thread.currentThread().interrupt(); 617 throw new LDAPException(ResultCode.LOCAL_ERROR, 618 ERR_BIND_INTERRUPTED.get(connection.getHostPort()), ie); 619 } 620 621 return handleResponse(connection, response, requestTime, false); 622 } 623 finally 624 { 625 connection.deregisterResponseAcceptor(messageID); 626 } 627 } 628 629 630 631 /** 632 * Processes this bind operation in synchronous mode, in which the same 633 * thread will send the request and read the response. 634 * 635 * @param connection The connection to use to communicate with the directory 636 * server. 637 * @param allowRetry Indicates whether the request may be re-tried on a 638 * re-established connection if the initial attempt fails 639 * in a way that indicates the connection is no longer 640 * valid and autoReconnect is true. 641 * 642 * @return An LDAP result object that provides information about the result 643 * of the bind processing. 644 * 645 * @throws LDAPException If a problem occurs while sending the request or 646 * reading the response. 647 */ 648 @NotNull() 649 private BindResult processSync(@NotNull final LDAPConnection connection, 650 final boolean allowRetry) 651 throws LDAPException 652 { 653 // Create the LDAP message. 654 messageID = connection.nextMessageID(); 655 final LDAPMessage message = 656 new LDAPMessage(messageID, this, getControls()); 657 658 659 // Send the request to the server. 660 final long requestTime = System.nanoTime(); 661 Debug.debugLDAPRequest(Level.INFO, this, messageID, connection); 662 663 final LDAPConnectionLogger logger = 664 connection.getConnectionOptions().getConnectionLogger(); 665 if (logger != null) 666 { 667 logger.logBindRequest(connection, messageID, this); 668 } 669 670 connection.getConnectionStatistics().incrementNumBindRequests(); 671 try 672 { 673 connection.sendMessage(message, getResponseTimeoutMillis(connection)); 674 } 675 catch (final LDAPException le) 676 { 677 Debug.debugException(le); 678 679 if (allowRetry) 680 { 681 final BindResult bindResult = reconnectAndRetry(connection, 682 le.getResultCode()); 683 if (bindResult != null) 684 { 685 return bindResult; 686 } 687 } 688 689 throw le; 690 } 691 692 while (true) 693 { 694 final LDAPResponse response = connection.readResponse(messageID); 695 if (response instanceof IntermediateResponse) 696 { 697 final IntermediateResponseListener listener = 698 getIntermediateResponseListener(); 699 if (listener != null) 700 { 701 listener.intermediateResponseReturned( 702 (IntermediateResponse) response); 703 } 704 } 705 else 706 { 707 return handleResponse(connection, response, requestTime, allowRetry); 708 } 709 } 710 } 711 712 713 714 /** 715 * Performs the necessary processing for handling a response. 716 * 717 * @param connection The connection used to read the response. 718 * @param response The response to be processed. 719 * @param requestTime The time the request was sent to the server. 720 * @param allowRetry Indicates whether the request may be re-tried on a 721 * re-established connection if the initial attempt fails 722 * in a way that indicates the connection is no longer 723 * valid and autoReconnect is true. 724 * 725 * @return The bind result. 726 * 727 * @throws LDAPException If a problem occurs. 728 */ 729 @NotNull() 730 private BindResult handleResponse(@NotNull final LDAPConnection connection, 731 @Nullable final LDAPResponse response, 732 final long requestTime, 733 final boolean allowRetry) 734 throws LDAPException 735 { 736 if (response == null) 737 { 738 final long waitTime = 739 StaticUtils.nanosToMillis(System.nanoTime() - requestTime); 740 throw new LDAPException(ResultCode.TIMEOUT, 741 ERR_SIMPLE_BIND_CLIENT_TIMEOUT.get(waitTime, messageID, 742 bindDN.stringValue(), connection.getHostPort())); 743 } 744 745 connection.getConnectionStatistics().incrementNumBindResponses( 746 System.nanoTime() - requestTime); 747 if (response instanceof ConnectionClosedResponse) 748 { 749 // The connection was closed while waiting for the response. 750 if (allowRetry) 751 { 752 final BindResult retryResult = reconnectAndRetry(connection, 753 ResultCode.SERVER_DOWN); 754 if (retryResult != null) 755 { 756 return retryResult; 757 } 758 } 759 760 final ConnectionClosedResponse ccr = (ConnectionClosedResponse) response; 761 final String message = ccr.getMessage(); 762 if (message == null) 763 { 764 throw new LDAPException(ccr.getResultCode(), 765 ERR_CONN_CLOSED_WAITING_FOR_BIND_RESPONSE.get( 766 connection.getHostPort(), toString())); 767 } 768 else 769 { 770 throw new LDAPException(ccr.getResultCode(), 771 ERR_CONN_CLOSED_WAITING_FOR_BIND_RESPONSE_WITH_MESSAGE.get( 772 connection.getHostPort(), toString(), message)); 773 } 774 } 775 776 final BindResult bindResult = (BindResult) response; 777 if (allowRetry) 778 { 779 final BindResult retryResult = reconnectAndRetry(connection, 780 bindResult.getResultCode()); 781 if (retryResult != null) 782 { 783 return retryResult; 784 } 785 } 786 787 return bindResult; 788 } 789 790 791 792 /** 793 * Attempts to re-establish the connection and retry processing this request 794 * on it. 795 * 796 * @param connection The connection to be re-established. 797 * @param resultCode The result code for the previous operation attempt. 798 * 799 * @return The result from re-trying the bind, or {@code null} if it could 800 * not be re-tried. 801 */ 802 @Nullable() 803 private BindResult reconnectAndRetry(@NotNull final LDAPConnection connection, 804 @NotNull final ResultCode resultCode) 805 { 806 try 807 { 808 // We will only want to retry for certain result codes that indicate a 809 // connection problem. 810 switch (resultCode.intValue()) 811 { 812 case ResultCode.SERVER_DOWN_INT_VALUE: 813 case ResultCode.DECODING_ERROR_INT_VALUE: 814 case ResultCode.CONNECT_ERROR_INT_VALUE: 815 connection.reconnect(); 816 return processSync(connection, false); 817 } 818 } 819 catch (final Exception e) 820 { 821 Debug.debugException(e); 822 } 823 824 return null; 825 } 826 827 828 829 /** 830 * {@inheritDoc} 831 */ 832 @Override() 833 @NotNull() 834 public SimpleBindRequest getRebindRequest(@NotNull final String host, 835 final int port) 836 { 837 return new SimpleBindRequest(bindDN, password, passwordProvider, 838 getControls()); 839 } 840 841 842 843 /** 844 * {@inheritDoc} 845 */ 846 @InternalUseOnly() 847 @Override() 848 public void responseReceived(@NotNull final LDAPResponse response) 849 throws LDAPException 850 { 851 try 852 { 853 responseQueue.put(response); 854 } 855 catch (final Exception e) 856 { 857 Debug.debugException(e); 858 859 if (e instanceof InterruptedException) 860 { 861 Thread.currentThread().interrupt(); 862 } 863 864 throw new LDAPException(ResultCode.LOCAL_ERROR, 865 ERR_EXCEPTION_HANDLING_RESPONSE.get( 866 StaticUtils.getExceptionMessage(e)), 867 e); 868 } 869 } 870 871 872 873 /** 874 * {@inheritDoc} 875 */ 876 @Override() 877 @NotNull() 878 public String getBindType() 879 { 880 return "SIMPLE"; 881 } 882 883 884 885 /** 886 * {@inheritDoc} 887 */ 888 @Override() 889 public int getLastMessageID() 890 { 891 return messageID; 892 } 893 894 895 896 /** 897 * {@inheritDoc} 898 */ 899 @Override() 900 @NotNull() 901 public SimpleBindRequest duplicate() 902 { 903 return duplicate(getControls()); 904 } 905 906 907 908 /** 909 * {@inheritDoc} 910 */ 911 @Override() 912 @NotNull() 913 public SimpleBindRequest duplicate(@Nullable final Control[] controls) 914 { 915 final SimpleBindRequest bindRequest = 916 new SimpleBindRequest(bindDN, password, passwordProvider, controls); 917 bindRequest.setResponseTimeoutMillis(getResponseTimeoutMillis(null)); 918 bindRequest.setIntermediateResponseListener( 919 getIntermediateResponseListener()); 920 bindRequest.setReferralDepth(getReferralDepth()); 921 bindRequest.setReferralConnector(getReferralConnectorInternal()); 922 return bindRequest; 923 } 924 925 926 927 /** 928 * {@inheritDoc} 929 */ 930 @Override() 931 public void toString(@NotNull final StringBuilder buffer) 932 { 933 buffer.append("SimpleBindRequest(dn='"); 934 buffer.append(bindDN); 935 buffer.append('\''); 936 937 final Control[] controls = getControls(); 938 if (controls.length > 0) 939 { 940 buffer.append(", controls={"); 941 for (int i=0; i < controls.length; i++) 942 { 943 if (i > 0) 944 { 945 buffer.append(", "); 946 } 947 948 buffer.append(controls[i]); 949 } 950 buffer.append('}'); 951 } 952 953 buffer.append(')'); 954 } 955 956 957 958 /** 959 * {@inheritDoc} 960 */ 961 @Override() 962 public void toCode(@NotNull final List<String> lineList, 963 @NotNull final String requestID, 964 final int indentSpaces, final boolean includeProcessing) 965 { 966 // Create the request variable. 967 final ArrayList<ToCodeArgHelper> constructorArgs = new ArrayList<>(3); 968 constructorArgs.add(ToCodeArgHelper.createString(bindDN.stringValue(), 969 "Bind DN")); 970 constructorArgs.add(ToCodeArgHelper.createString("---redacted-password---", 971 "Bind Password")); 972 973 final Control[] controls = getControls(); 974 if (controls.length > 0) 975 { 976 constructorArgs.add(ToCodeArgHelper.createControlArray(controls, 977 "Bind Controls")); 978 } 979 980 ToCodeHelper.generateMethodCall(lineList, indentSpaces, "SimpleBindRequest", 981 requestID + "Request", "new SimpleBindRequest", constructorArgs); 982 983 984 // Add lines for processing the request and obtaining the result. 985 if (includeProcessing) 986 { 987 // Generate a string with the appropriate indent. 988 final StringBuilder buffer = new StringBuilder(); 989 for (int i=0; i < indentSpaces; i++) 990 { 991 buffer.append(' '); 992 } 993 final String indent = buffer.toString(); 994 995 lineList.add(""); 996 lineList.add(indent + "try"); 997 lineList.add(indent + '{'); 998 lineList.add(indent + " BindResult " + requestID + 999 "Result = connection.bind(" + requestID + "Request);"); 1000 lineList.add(indent + " // The bind was processed successfully."); 1001 lineList.add(indent + '}'); 1002 lineList.add(indent + "catch (LDAPException e)"); 1003 lineList.add(indent + '{'); 1004 lineList.add(indent + " // The bind failed. Maybe the following will " + 1005 "help explain why."); 1006 lineList.add(indent + " // Note that the connection is now likely in " + 1007 "an unauthenticated state."); 1008 lineList.add(indent + " ResultCode resultCode = e.getResultCode();"); 1009 lineList.add(indent + " String message = e.getMessage();"); 1010 lineList.add(indent + " String matchedDN = e.getMatchedDN();"); 1011 lineList.add(indent + " String[] referralURLs = e.getReferralURLs();"); 1012 lineList.add(indent + " Control[] responseControls = " + 1013 "e.getResponseControls();"); 1014 lineList.add(indent + '}'); 1015 } 1016 } 1017}