001/* 002 * Copyright 2016-2024 Ping Identity Corporation 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright 2016-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) 2016-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.unboundidds; 037 038 039 040import java.util.ArrayList; 041import java.util.Collections; 042import java.util.Iterator; 043import java.util.LinkedHashMap; 044import java.util.List; 045import java.util.Map; 046 047import com.unboundid.asn1.ASN1Boolean; 048import com.unboundid.asn1.ASN1Element; 049import com.unboundid.asn1.ASN1OctetString; 050import com.unboundid.asn1.ASN1Sequence; 051import com.unboundid.ldap.sdk.BindResult; 052import com.unboundid.ldap.sdk.Control; 053import com.unboundid.ldap.sdk.InternalSDKHelper; 054import com.unboundid.ldap.sdk.LDAPConnection; 055import com.unboundid.ldap.sdk.LDAPException; 056import com.unboundid.ldap.sdk.ResultCode; 057import com.unboundid.ldap.sdk.SASLBindRequest; 058import com.unboundid.ldap.sdk.ToCodeArgHelper; 059import com.unboundid.ldap.sdk.ToCodeHelper; 060import com.unboundid.util.Debug; 061import com.unboundid.util.NotNull; 062import com.unboundid.util.Nullable; 063import com.unboundid.util.StaticUtils; 064import com.unboundid.util.ThreadSafety; 065import com.unboundid.util.ThreadSafetyLevel; 066import com.unboundid.util.Validator; 067 068import static com.unboundid.ldap.sdk.unboundidds.UnboundIDDSMessages.*; 069 070 071 072/** 073 * This class provides support for an UnboundID-proprietary SASL mechanism that 074 * may be used to indicate that a user has attempted authentication, whether 075 * successfully or not, through some mechanism that is external to the Directory 076 * Server. If this mechanism is supported in the server, then attempting to 077 * authenticate with it will not change the identity of the client connection, 078 * but will perform additional processing that would normally be completed 079 * during a more traditional authentication attempt. 080 * <BR> 081 * <BLOCKQUOTE> 082 * <B>NOTE:</B> This class, and other classes within the 083 * {@code com.unboundid.ldap.sdk.unboundidds} package structure, are only 084 * supported for use against Ping Identity, UnboundID, and 085 * Nokia/Alcatel-Lucent 8661 server products. These classes provide support 086 * for proprietary functionality or for external specifications that are not 087 * considered stable or mature enough to be guaranteed to work in an 088 * interoperable way with other types of LDAP servers. 089 * </BLOCKQUOTE> 090 * <BR> 091 * This SASL bind request has a mechanism of 092 * "UNBOUNDID-EXTERNALLY-PROCESSED-AUTHENTICATION" and must 093 * include SASL credentials with the following encoding: 094 * <PRE> 095 * ExternallyProcessedAuthenticationCredentials ::= SEQUENCE { 096 * authenticationID [0] OCTET STRING, 097 * externalMechanismName [1] OCTET STRING, 098 * externalAuthenticationWasSuccessful [2] BOOLEAN, 099 * externalAuthenticationFailureReason [3] OCTET STRING OPTIONAL, 100 * externalAuthenticationWasPasswordBased [4] BOOLEAN DEFAULT TRUE, 101 * externalAuthenticationWasSecure [5] BOOLEAN DEFAULT FALSE, 102 * endClientIPAddress [6] OCTET STRING OPTIONAL, 103 * additionalAccessLogProperties [7] SEQUENCE OF SEQUENCE { 104 * propertyName OCTET STRING, 105 * propertyValue OCTET STRING } OPTIONAL, 106 * ... } 107 * </PRE> 108 * <BR><BR> 109 * In the event that the external authentication was considered successful, the 110 * server will ensure that the target user's account is in a usable state and, 111 * if not, will return a failure response. If the external authentication was 112 * successful and the user's account is usable, then the server will make any 113 * appropriate password policy state updates (e.g., clearing previous 114 * authentication failures, updating the user's last login time and IP address, 115 * etc.) and return a success result. 116 * <BR><BR> 117 * In the event that the external authentication was not considered successful, 118 * the server may also make corresponding password policy state updates (e.g., 119 * incrementing the number of authentication failures and locking the account if 120 * appropriate) before returning a failure result. 121 */ 122@ThreadSafety(level=ThreadSafetyLevel.NOT_THREADSAFE) 123public final class UnboundIDExternallyProcessedAuthenticationBindRequest 124 extends SASLBindRequest 125{ 126 /** 127 * The name for the UnboundID externally-processed authentication SASL 128 * mechanism. 129 */ 130 @NotNull public static final String 131 UNBOUNDID_EXTERNALLY_PROCESSED_AUTH_MECHANISM_NAME = 132 "UNBOUNDID-EXTERNALLY-PROCESSED-AUTHENTICATION"; 133 134 135 136 /** 137 * The BER type for the authenticationID element of the bind request. 138 */ 139 private static final byte TYPE_AUTHENTICATION_ID = (byte) 0x80; 140 141 142 143 /** 144 * The BER type for the externalMechanismName element of the bind request. 145 */ 146 private static final byte TYPE_EXTERNAL_MECHANISM_NAME = (byte) 0x81; 147 148 149 150 /** 151 * The BER type for the externalAuthenticationWasSuccessful element of the 152 * bind request. 153 */ 154 private static final byte TYPE_EXTERNAL_AUTH_WAS_SUCCESSFUL = (byte) 0x82; 155 156 157 158 /** 159 * The BER type for the externalAuthenticationFailureReason element of the 160 * bind request. 161 */ 162 private static final byte TYPE_EXTERNAL_AUTH_FAILURE_REASON = (byte) 0x83; 163 164 165 166 /** 167 * The BER type for the externalAuthenticationWasPasswordBased element of the 168 * bind request. 169 */ 170 private static final byte TYPE_EXTERNAL_AUTH_WAS_PASSWORD_BASED = (byte) 0x84; 171 172 173 174 /** 175 * The BER type for the externalAuthenticationWasSecure element of the bind 176 * request. 177 */ 178 private static final byte TYPE_EXTERNAL_AUTH_WAS_SECURE = (byte) 0x85; 179 180 181 182 /** 183 * The BER type for the endClientIPAddress element of the bind request. 184 */ 185 private static final byte TYPE_END_CLIENT_IP_ADDRESS = (byte) 0x86; 186 187 188 189 /** 190 * The BER type for the additionalAccessLogProperties element of the bind 191 * request. 192 */ 193 private static final byte TYPE_ADDITIONAL_ACCESS_LOG_PROPERTIES = (byte) 0xA7; 194 195 196 197 /** 198 * The serial version UID for this serializable class. 199 */ 200 private static final long serialVersionUID = -4312237491980971019L; 201 202 203 204 // The encoded SASL credentials for this bind request. 205 @Nullable private volatile ASN1OctetString encodedCredentials; 206 207 // Indicates whether the external authentication processing involved a 208 // password. 209 private final boolean externalAuthWasPasswordBased; 210 211 // Indicates whether the external authentication processing is considered to 212 // have been secure. 213 private final boolean externalAuthWasSecure; 214 215 // Indicates whether the external authentication attempt is considered to have 216 // been successful. 217 private final boolean externalAuthWasSuccessful; 218 219 // The message ID from the last LDAP message sent from this request. 220 private volatile int messageID; 221 222 // A map of additional properties that should be recorded in the server's 223 // access log. 224 @NotNull private final Map<String,String> additionalAccessLogProperties; 225 226 // The authentication ID that identifies the user for whom the external 227 // authentication processing was performed. 228 @NotNull private final String authenticationID; 229 230 // The IPv4 or IPv6 address of the end client, if available. 231 @Nullable private final String endClientIPAddress; 232 233 // The reason that the external authentication attempt was considered a 234 // failure. 235 @Nullable private final String externalAuthFailureReason; 236 237 // The name of the mechanism used for the external authentication attempt. 238 @NotNull private final String externalMechanismName; 239 240 241 242 /** 243 * Creates a new UNBOUNDID-EXTERNALLY-PROCESSED-AUTHENTICATION bind request 244 * with the provided information. 245 * 246 * @param authenticationID The authentication ID that 247 * identifies the user for whom the 248 * external authentication processing 249 * was performed. This should be 250 * either "dn:" followed by the DN of 251 * the target user's entry, or "u:" 252 * followed by a username. This must 253 * not be {@code null}. 254 * @param externalMechanismName The name of the mechanism used for 255 * the external authentication attempt. 256 * This must not be {@code null}. 257 * @param externalAuthWasSuccessful Indicates whether the external 258 * authentication attempt is considered 259 * to have been successful. 260 * @param externalAuthFailureReason The reason that the external 261 * authentication attempt was 262 * considered a failure. This should 263 * be {@code null} if the external 264 * authentication attempt succeeded, 265 * and may be {@code null} if the 266 * external authentication attempt 267 * failed but no failure reason is 268 * available. 269 * @param externalAuthWasPasswordBased Indicates whether the external 270 * authentication processing involved a 271 * password. 272 * @param externalAuthWasSecure Indicates whether the external 273 * authentication processing was 274 * considered secure. A mechanism 275 * should only be considered secure if 276 * all credentials were protected in 277 * all communication. 278 * @param endClientIPAddress The IPv4 or IPv6 address of the end 279 * client involved in the external 280 * authentication processing. This may 281 * be {@code null} if the end client 282 * address is not available. 283 * @param additionalAccessLogProperties A map of additional properties that 284 * should be recorded in the server's 285 * access log for the external 286 * authentication attempt. This may be 287 * {@code null} or empty if no 288 * additional access log properties are 289 * required. 290 * @param controls The set of controls to include in 291 * the request. It may be {@code null} 292 * or empty if no request controls are 293 * needed. 294 */ 295 public UnboundIDExternallyProcessedAuthenticationBindRequest( 296 @NotNull final String authenticationID, 297 @NotNull final String externalMechanismName, 298 final boolean externalAuthWasSuccessful, 299 @Nullable final String externalAuthFailureReason, 300 final boolean externalAuthWasPasswordBased, 301 final boolean externalAuthWasSecure, 302 @Nullable final String endClientIPAddress, 303 @Nullable final Map<String,String> additionalAccessLogProperties, 304 @Nullable final Control... controls) 305 { 306 super(controls); 307 308 Validator.ensureNotNull(authenticationID); 309 Validator.ensureNotNull(externalMechanismName); 310 311 this.authenticationID = authenticationID; 312 this.externalMechanismName = externalMechanismName; 313 this.externalAuthWasSuccessful = externalAuthWasSuccessful; 314 this.externalAuthFailureReason = externalAuthFailureReason; 315 this.externalAuthWasPasswordBased = externalAuthWasPasswordBased; 316 this.externalAuthWasSecure = externalAuthWasSecure; 317 this.endClientIPAddress = endClientIPAddress; 318 319 if (additionalAccessLogProperties == null) 320 { 321 this.additionalAccessLogProperties = Collections.emptyMap(); 322 } 323 else 324 { 325 this.additionalAccessLogProperties = Collections.unmodifiableMap( 326 new LinkedHashMap<>(additionalAccessLogProperties)); 327 } 328 329 messageID = -1; 330 encodedCredentials = null; 331 } 332 333 334 335 /** 336 * Creates a new UNBOUNDID-EXTERNALLY-PROCESSED-AUTHENTICATION bind request 337 * decoded from the provided information. 338 * 339 * @param saslCredentials The encoded SASL credentials to be decoded. It 340 * must not be {@code null}. 341 * @param controls The set of controls to include in the request. It 342 * may be {@code null} or empty if no request 343 * controls are needed. 344 * 345 * @return The decoded UNBOUNDID-EXTERNALLY-PROCESSED-AUTHENTICATION bind 346 * request. 347 * 348 * @throws LDAPException If the provided SASL credentials are not valid for 349 * am UNBOUNDID-EXTERNALLY-PROCESSED-AUTHENTICATION 350 * bind request 351 */ 352 @NotNull() 353 public static UnboundIDExternallyProcessedAuthenticationBindRequest 354 decodeSASLCredentials( 355 @NotNull final ASN1OctetString saslCredentials, 356 @Nullable final Control... controls) 357 throws LDAPException 358 { 359 Validator.ensureNotNull(saslCredentials); 360 361 boolean passwordBased = true; 362 boolean secure = false; 363 Boolean successful = null; 364 String failureReason = null; 365 String ipAddress = null; 366 String mechanism = null; 367 String authID = null; 368 369 final LinkedHashMap<String,String> logProperties = 370 new LinkedHashMap<>(StaticUtils.computeMapCapacity(10)); 371 372 try 373 { 374 for (final ASN1Element e : 375 ASN1Sequence.decodeAsSequence(saslCredentials.getValue()).elements()) 376 { 377 switch (e.getType()) 378 { 379 case TYPE_AUTHENTICATION_ID: 380 authID = ASN1OctetString.decodeAsOctetString(e).stringValue(); 381 break; 382 case TYPE_EXTERNAL_MECHANISM_NAME: 383 mechanism = ASN1OctetString.decodeAsOctetString(e).stringValue(); 384 break; 385 case TYPE_EXTERNAL_AUTH_WAS_SUCCESSFUL: 386 successful = ASN1Boolean.decodeAsBoolean(e).booleanValue(); 387 break; 388 case TYPE_EXTERNAL_AUTH_FAILURE_REASON: 389 failureReason = 390 ASN1OctetString.decodeAsOctetString(e).stringValue(); 391 break; 392 case TYPE_EXTERNAL_AUTH_WAS_PASSWORD_BASED: 393 passwordBased = ASN1Boolean.decodeAsBoolean(e).booleanValue(); 394 break; 395 case TYPE_EXTERNAL_AUTH_WAS_SECURE: 396 secure = ASN1Boolean.decodeAsBoolean(e).booleanValue(); 397 break; 398 case TYPE_END_CLIENT_IP_ADDRESS: 399 ipAddress = ASN1OctetString.decodeAsOctetString(e).stringValue(); 400 break; 401 case TYPE_ADDITIONAL_ACCESS_LOG_PROPERTIES: 402 for (final ASN1Element propertiesElement : 403 ASN1Sequence.decodeAsSequence(e).elements()) 404 { 405 final ASN1Element[] logPairElements = 406 ASN1Sequence.decodeAsSequence(propertiesElement).elements(); 407 final String name = ASN1OctetString.decodeAsOctetString( 408 logPairElements[0]).stringValue(); 409 final String value = ASN1OctetString.decodeAsOctetString( 410 logPairElements[1]).stringValue(); 411 logProperties.put(name, value); 412 } 413 break; 414 } 415 } 416 } 417 catch (final Exception e) 418 { 419 Debug.debugException(e); 420 throw new LDAPException(ResultCode.DECODING_ERROR, 421 ERR_EXTERNALLY_PROCESSED_AUTH_CANNOT_DECODE_CREDS.get( 422 UNBOUNDID_EXTERNALLY_PROCESSED_AUTH_MECHANISM_NAME, 423 StaticUtils.getExceptionMessage(e)), 424 e); 425 } 426 427 if (authID == null) 428 { 429 throw new LDAPException(ResultCode.DECODING_ERROR, 430 ERR_EXTERNALLY_PROCESSED_AUTH_NO_AUTH_ID.get( 431 UNBOUNDID_EXTERNALLY_PROCESSED_AUTH_MECHANISM_NAME)); 432 } 433 434 if (mechanism == null) 435 { 436 throw new LDAPException(ResultCode.DECODING_ERROR, 437 ERR_EXTERNALLY_PROCESSED_AUTH_NO_MECH.get( 438 UNBOUNDID_EXTERNALLY_PROCESSED_AUTH_MECHANISM_NAME)); 439 } 440 441 if (successful == null) 442 { 443 throw new LDAPException(ResultCode.DECODING_ERROR, 444 ERR_EXTERNALLY_PROCESSED_AUTH_NO_WAS_SUCCESSFUL.get( 445 UNBOUNDID_EXTERNALLY_PROCESSED_AUTH_MECHANISM_NAME)); 446 } 447 448 final UnboundIDExternallyProcessedAuthenticationBindRequest bindRequest = 449 new UnboundIDExternallyProcessedAuthenticationBindRequest(authID, 450 mechanism, successful, failureReason, passwordBased, secure, 451 ipAddress, logProperties, controls); 452 bindRequest.encodedCredentials = saslCredentials; 453 454 return bindRequest; 455 } 456 457 458 459 /** 460 * Retrieves the authentication ID that identifies the user for whom the 461 * external authentication processing was performed. 462 * 463 * @return The authentication ID that identifies the user for whom the 464 * external authentication processing was performed. 465 */ 466 @NotNull() 467 public String getAuthenticationID() 468 { 469 return authenticationID; 470 } 471 472 473 474 /** 475 * Retrieves the name of the mechanism used for the external authentication 476 * attempt. 477 * 478 * @return The name of the mechanism used for the external authentication 479 * attempt. 480 */ 481 @NotNull() 482 public String getExternalMechanismName() 483 { 484 return externalMechanismName; 485 } 486 487 488 489 /** 490 * Indicates whether the external authentication attempt is considered to have 491 * been successful. 492 * 493 * @return {@code true} if the external authentication attempt was considered 494 * successful, or {@code false} if not. 495 */ 496 public boolean externalAuthenticationWasSuccessful() 497 { 498 return externalAuthWasSuccessful; 499 } 500 501 502 503 /** 504 * Retrieves the reason that the external authentication attempt was 505 * considered a failure, if available. 506 * 507 * @return The reason that the external authentication attempt was considered 508 * a failure, or {@code null} if no failure reason is available. 509 */ 510 @Nullable() 511 public String getExternalAuthenticationFailureReason() 512 { 513 return externalAuthFailureReason; 514 } 515 516 517 518 /** 519 * Indicates whether the external authentication processing involved a 520 * password. 521 * 522 * @return {@code true} if the external authentication processing involved a 523 * password, or {@code false} if not. 524 */ 525 public boolean externalAuthenticationWasPasswordBased() 526 { 527 return externalAuthWasPasswordBased; 528 } 529 530 531 532 /** 533 * Indicates whether the external authentication processing is considered to 534 * have been secure. 535 * 536 * @return {@code true} if the external authentication processing was 537 * considered secure, or {@code false} if not. 538 */ 539 public boolean externalAuthenticationWasSecure() 540 { 541 return externalAuthWasSecure; 542 } 543 544 545 546 /** 547 * Retrieves the IPv4 or IPv6 address of the end client involved in the 548 * external authentication processing, if available. 549 * 550 * @return The IPv4 or IPv6 address of the end client involved in the 551 * external authentication processing, or {@code null} if this is not 552 * available. 553 */ 554 @Nullable() 555 public String getEndClientIPAddress() 556 { 557 return endClientIPAddress; 558 } 559 560 561 562 /** 563 * Retrieves a map of additional properties that should be recorded in the 564 * server's access log for the external authentication attempt. 565 * 566 * @return A map of additional properties that should be recorded in the 567 * server's access log for the external authentication attempt, or an 568 * empty map if there are no additional log properties. 569 */ 570 @NotNull() 571 public Map<String,String> getAdditionalAccessLogProperties() 572 { 573 return additionalAccessLogProperties; 574 } 575 576 577 578 /** 579 * {@inheritDoc} 580 */ 581 @Override() 582 @NotNull() 583 public String getSASLMechanismName() 584 { 585 return UNBOUNDID_EXTERNALLY_PROCESSED_AUTH_MECHANISM_NAME; 586 } 587 588 589 590 /** 591 * Retrieves an encoded representation of the SASL credentials for this bind 592 * request. 593 * 594 * @return An encoded representation of the SASL credentials for this bind 595 * request. 596 */ 597 @NotNull() 598 public ASN1OctetString getEncodedCredentials() 599 { 600 if (encodedCredentials == null) 601 { 602 final ArrayList<ASN1Element> credElements = new ArrayList<>(8); 603 604 credElements.add(new ASN1OctetString(TYPE_AUTHENTICATION_ID, 605 authenticationID)); 606 credElements.add(new ASN1OctetString(TYPE_EXTERNAL_MECHANISM_NAME, 607 externalMechanismName)); 608 credElements.add(new ASN1Boolean(TYPE_EXTERNAL_AUTH_WAS_SUCCESSFUL, 609 externalAuthWasSuccessful)); 610 611 if (externalAuthFailureReason != null) 612 { 613 credElements.add(new ASN1OctetString(TYPE_EXTERNAL_AUTH_FAILURE_REASON, 614 externalAuthFailureReason)); 615 } 616 617 if (! externalAuthWasPasswordBased) 618 { 619 credElements.add(new ASN1Boolean(TYPE_EXTERNAL_AUTH_WAS_PASSWORD_BASED, 620 false)); 621 } 622 623 if (externalAuthWasSecure) 624 { 625 credElements.add(new ASN1Boolean(TYPE_EXTERNAL_AUTH_WAS_SECURE, true)); 626 } 627 628 if (endClientIPAddress != null) 629 { 630 credElements.add(new ASN1OctetString(TYPE_END_CLIENT_IP_ADDRESS, 631 endClientIPAddress)); 632 } 633 634 if (! additionalAccessLogProperties.isEmpty()) 635 { 636 final ArrayList<ASN1Element> logElements = 637 new ArrayList<>(additionalAccessLogProperties.size()); 638 for (final Map.Entry<String,String> e : 639 additionalAccessLogProperties.entrySet()) 640 { 641 logElements.add(new ASN1Sequence( 642 new ASN1OctetString(e.getKey()), 643 new ASN1OctetString(e.getValue()))); 644 } 645 646 credElements.add(new ASN1Sequence(TYPE_ADDITIONAL_ACCESS_LOG_PROPERTIES, 647 logElements)); 648 } 649 650 final ASN1Sequence credSequence = new ASN1Sequence(credElements); 651 encodedCredentials = new ASN1OctetString(credSequence.encode()); 652 } 653 654 return encodedCredentials; 655 } 656 657 658 659 /** 660 * {@inheritDoc} 661 */ 662 @Override() 663 @NotNull() 664 protected BindResult process(@NotNull final LDAPConnection connection, 665 final int depth) 666 throws LDAPException 667 { 668 setReferralDepth(depth); 669 670 messageID = InternalSDKHelper.nextMessageID(connection); 671 return sendBindRequest(connection, "", getEncodedCredentials(), 672 getControls(), getResponseTimeoutMillis(connection)); 673 } 674 675 676 677 /** 678 * {@inheritDoc} 679 */ 680 @Override() 681 public int getLastMessageID() 682 { 683 return messageID; 684 } 685 686 687 688 /** 689 * {@inheritDoc} 690 */ 691 @Override() 692 @NotNull() 693 public UnboundIDExternallyProcessedAuthenticationBindRequest duplicate() 694 { 695 return duplicate(getControls()); 696 } 697 698 699 700 /** 701 * {@inheritDoc} 702 */ 703 @Override() 704 @NotNull() 705 public UnboundIDExternallyProcessedAuthenticationBindRequest duplicate( 706 @Nullable final Control[] controls) 707 { 708 final UnboundIDExternallyProcessedAuthenticationBindRequest bindRequest = 709 new UnboundIDExternallyProcessedAuthenticationBindRequest( 710 authenticationID, externalMechanismName, 711 externalAuthWasSuccessful, externalAuthFailureReason, 712 externalAuthWasPasswordBased, externalAuthWasSecure, 713 endClientIPAddress, additionalAccessLogProperties, controls); 714 bindRequest.encodedCredentials = encodedCredentials; 715 716 bindRequest.setResponseTimeoutMillis(getResponseTimeoutMillis(null)); 717 bindRequest.setIntermediateResponseListener( 718 getIntermediateResponseListener()); 719 bindRequest.setReferralDepth(getReferralDepth()); 720 bindRequest.setReferralConnector(getReferralConnectorInternal()); 721 return bindRequest; 722 } 723 724 725 726 /** 727 * {@inheritDoc} 728 */ 729 @Override() 730 @NotNull() 731 public UnboundIDExternallyProcessedAuthenticationBindRequest getRebindRequest( 732 @NotNull final String host, final int port) 733 { 734 return duplicate(); 735 } 736 737 738 739 /** 740 * {@inheritDoc} 741 */ 742 @Override() 743 public void toString(@NotNull final StringBuilder buffer) 744 { 745 buffer.append("UnboundIDExternallyProcessedAuthenticationBindRequest(" + 746 "authenticationID='"); 747 buffer.append(authenticationID); 748 buffer.append("', externalMechanismName='"); 749 buffer.append(externalMechanismName); 750 buffer.append("', externalAuthenticationWasSuccessful="); 751 buffer.append(externalAuthWasSuccessful); 752 buffer.append('\''); 753 754 if (externalAuthFailureReason != null) 755 { 756 buffer.append(", externalAuthenticationFailureReason='"); 757 buffer.append(externalAuthFailureReason); 758 buffer.append('\''); 759 } 760 761 buffer.append(", externalAuthenticationWasPasswordBased="); 762 buffer.append(externalAuthWasPasswordBased); 763 buffer.append(", externalAuthenticationWasSecure="); 764 buffer.append(externalAuthWasSecure); 765 766 if (endClientIPAddress != null) 767 { 768 buffer.append(", endClientIPAddress='"); 769 buffer.append(endClientIPAddress); 770 buffer.append('\''); 771 } 772 773 if (! additionalAccessLogProperties.isEmpty()) 774 { 775 buffer.append(", additionalAccessLogProperties={"); 776 777 final Iterator<Map.Entry<String,String>> iterator = 778 additionalAccessLogProperties.entrySet().iterator(); 779 while (iterator.hasNext()) 780 { 781 final Map.Entry<String,String> e = iterator.next(); 782 783 buffer.append('\''); 784 buffer.append(e.getKey()); 785 buffer.append("'='"); 786 buffer.append(e.getValue()); 787 buffer.append('\''); 788 789 if (iterator.hasNext()) 790 { 791 buffer.append(", "); 792 } 793 } 794 795 buffer.append('}'); 796 } 797 798 799 final Control[] controls = getControls(); 800 if (controls.length > 0) 801 { 802 buffer.append(", controls={"); 803 for (int i=0; i < controls.length; i++) 804 { 805 if (i > 0) 806 { 807 buffer.append(", "); 808 } 809 810 buffer.append(controls[i]); 811 } 812 buffer.append('}'); 813 } 814 815 buffer.append(')'); 816 } 817 818 819 820 /** 821 * {@inheritDoc} 822 */ 823 @Override() 824 public void toCode(@NotNull final List<String> lineList, 825 @NotNull final String requestID, 826 final int indentSpaces, final boolean includeProcessing) 827 { 828 // Create the map of additional log properties. 829 final ArrayList<ToCodeArgHelper> mapConstructorArgs = new ArrayList<>(1); 830 mapConstructorArgs.add(ToCodeArgHelper.createInteger( 831 additionalAccessLogProperties.size(), "Initial Capacity")); 832 833 ToCodeHelper.generateMethodCall(lineList, indentSpaces, 834 "LinkedHashMap<String,String>", 835 requestID + "AdditionalAccessLogProperties", 836 "new LinkedHashMap<String,String>", 837 mapConstructorArgs); 838 839 840 // Create the method calls used to populate the map. 841 for (final Map.Entry<String,String> e : 842 additionalAccessLogProperties.entrySet()) 843 { 844 final ArrayList<ToCodeArgHelper> putArgs = new ArrayList<>(2); 845 putArgs.add(ToCodeArgHelper.createString(e.getKey(), 846 "Log Property Key")); 847 putArgs.add(ToCodeArgHelper.createString(e.getValue(), 848 "Log Property Value")); 849 850 ToCodeHelper.generateMethodCall(lineList, indentSpaces, null, null, 851 requestID + "AdditionalAccessLogProperties.put", putArgs); 852 } 853 854 855 // Create the request variable. 856 final ArrayList<ToCodeArgHelper> requestConstructorArgs = 857 new ArrayList<>(8); 858 requestConstructorArgs.add(ToCodeArgHelper.createString(authenticationID, 859 "Authentication ID")); 860 requestConstructorArgs.add(ToCodeArgHelper.createString( 861 externalMechanismName, "External Mechanism Name")); 862 requestConstructorArgs.add(ToCodeArgHelper.createBoolean( 863 externalAuthWasSuccessful, "External Authentication Was Successful")); 864 requestConstructorArgs.add(ToCodeArgHelper.createString( 865 externalAuthFailureReason, "External Authentication Failure Reason")); 866 requestConstructorArgs.add(ToCodeArgHelper.createBoolean( 867 externalAuthWasPasswordBased, 868 "External Authentication Was Password Based")); 869 requestConstructorArgs.add(ToCodeArgHelper.createBoolean( 870 externalAuthWasSecure, "External Authentication Was Secure")); 871 requestConstructorArgs.add(ToCodeArgHelper.createString(endClientIPAddress, 872 "End Client IP Address")); 873 requestConstructorArgs.add(ToCodeArgHelper.createRaw( 874 requestID + "AdditionalAccessLogProperties", 875 "Additional AccessLogProperties")); 876 877 final Control[] controls = getControls(); 878 if (controls.length > 0) 879 { 880 requestConstructorArgs.add(ToCodeArgHelper.createControlArray(controls, 881 "Bind Controls")); 882 } 883 884 lineList.add(""); 885 ToCodeHelper.generateMethodCall(lineList, indentSpaces, 886 "UnboundIDExternallyProcessedAuthenticationBindRequest", 887 requestID + "Request", 888 "new UnboundIDExternallyProcessedAuthenticationBindRequest", 889 requestConstructorArgs); 890 891 892 // Add lines for processing the request and obtaining the result. 893 if (includeProcessing) 894 { 895 // Generate a string with the appropriate indent. 896 final StringBuilder buffer = new StringBuilder(); 897 for (int i=0; i < indentSpaces; i++) 898 { 899 buffer.append(' '); 900 } 901 final String indent = buffer.toString(); 902 903 lineList.add(""); 904 lineList.add(indent + "try"); 905 lineList.add(indent + '{'); 906 lineList.add(indent + " BindResult " + requestID + 907 "Result = connection.bind(" + requestID + "Request);"); 908 lineList.add(indent + " // The bind was processed successfully."); 909 lineList.add(indent + '}'); 910 lineList.add(indent + "catch (LDAPException e)"); 911 lineList.add(indent + '{'); 912 lineList.add(indent + " // The bind failed. Maybe the following will " + 913 "help explain why."); 914 lineList.add(indent + " // Note that the connection is now likely in " + 915 "an unauthenticated state."); 916 lineList.add(indent + " ResultCode resultCode = e.getResultCode();"); 917 lineList.add(indent + " String message = e.getMessage();"); 918 lineList.add(indent + " String matchedDN = e.getMatchedDN();"); 919 lineList.add(indent + " String[] referralURLs = e.getReferralURLs();"); 920 lineList.add(indent + " Control[] responseControls = " + 921 "e.getResponseControls();"); 922 lineList.add(indent + '}'); 923 } 924 } 925}