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