001/* 002 * Copyright 2016-2018 Ping Identity Corporation 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright (C) 2016-2018 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 = new LinkedHashMap<>(10); 350 351 try 352 { 353 for (final ASN1Element e : 354 ASN1Sequence.decodeAsSequence(saslCredentials.getValue()).elements()) 355 { 356 switch (e.getType()) 357 { 358 case TYPE_AUTHENTICATION_ID: 359 authID = ASN1OctetString.decodeAsOctetString(e).stringValue(); 360 break; 361 case TYPE_EXTERNAL_MECHANISM_NAME: 362 mechanism = ASN1OctetString.decodeAsOctetString(e).stringValue(); 363 break; 364 case TYPE_EXTERNAL_AUTH_WAS_SUCCESSFUL: 365 successful = ASN1Boolean.decodeAsBoolean(e).booleanValue(); 366 break; 367 case TYPE_EXTERNAL_AUTH_FAILURE_REASON: 368 failureReason = 369 ASN1OctetString.decodeAsOctetString(e).stringValue(); 370 break; 371 case TYPE_EXTERNAL_AUTH_WAS_PASSWORD_BASED: 372 passwordBased = ASN1Boolean.decodeAsBoolean(e).booleanValue(); 373 break; 374 case TYPE_EXTERNAL_AUTH_WAS_SECURE: 375 secure = ASN1Boolean.decodeAsBoolean(e).booleanValue(); 376 break; 377 case TYPE_END_CLIENT_IP_ADDRESS: 378 ipAddress = ASN1OctetString.decodeAsOctetString(e).stringValue(); 379 break; 380 case TYPE_ADDITIONAL_ACCESS_LOG_PROPERTIES: 381 for (final ASN1Element propertiesElement : 382 ASN1Sequence.decodeAsSequence(e).elements()) 383 { 384 final ASN1Element[] logPairElements = 385 ASN1Sequence.decodeAsSequence(propertiesElement).elements(); 386 final String name = ASN1OctetString.decodeAsOctetString( 387 logPairElements[0]).stringValue(); 388 final String value = ASN1OctetString.decodeAsOctetString( 389 logPairElements[1]).stringValue(); 390 logProperties.put(name, value); 391 } 392 break; 393 } 394 } 395 } 396 catch (final Exception e) 397 { 398 Debug.debugException(e); 399 throw new LDAPException(ResultCode.DECODING_ERROR, 400 ERR_EXTERNALLY_PROCESSED_AUTH_CANNOT_DECODE_CREDS.get( 401 UNBOUNDID_EXTERNALLY_PROCESSED_AUTH_MECHANISM_NAME, 402 StaticUtils.getExceptionMessage(e)), 403 e); 404 } 405 406 if (authID == null) 407 { 408 throw new LDAPException(ResultCode.DECODING_ERROR, 409 ERR_EXTERNALLY_PROCESSED_AUTH_NO_AUTH_ID.get( 410 UNBOUNDID_EXTERNALLY_PROCESSED_AUTH_MECHANISM_NAME)); 411 } 412 413 if (mechanism == null) 414 { 415 throw new LDAPException(ResultCode.DECODING_ERROR, 416 ERR_EXTERNALLY_PROCESSED_AUTH_NO_MECH.get( 417 UNBOUNDID_EXTERNALLY_PROCESSED_AUTH_MECHANISM_NAME)); 418 } 419 420 if (successful == null) 421 { 422 throw new LDAPException(ResultCode.DECODING_ERROR, 423 ERR_EXTERNALLY_PROCESSED_AUTH_NO_WAS_SUCCESSFUL.get( 424 UNBOUNDID_EXTERNALLY_PROCESSED_AUTH_MECHANISM_NAME)); 425 } 426 427 final UnboundIDExternallyProcessedAuthenticationBindRequest bindRequest = 428 new UnboundIDExternallyProcessedAuthenticationBindRequest(authID, 429 mechanism, successful, failureReason, passwordBased, secure, 430 ipAddress, logProperties, controls); 431 bindRequest.encodedCredentials = saslCredentials; 432 433 return bindRequest; 434 } 435 436 437 438 /** 439 * Retrieves the authentication ID that identifies the user for whom the 440 * external authentication processing was performed. 441 * 442 * @return The authentication ID that identifies the user for whom the 443 * external authentication processing was performed. 444 */ 445 public String getAuthenticationID() 446 { 447 return authenticationID; 448 } 449 450 451 452 /** 453 * Retrieves the name of the mechanism used for the external authentication 454 * attempt. 455 * 456 * @return The name of the mechanism used for the external authentication 457 * attempt. 458 */ 459 public String getExternalMechanismName() 460 { 461 return externalMechanismName; 462 } 463 464 465 466 /** 467 * Indicates whether the external authentication attempt is considered to have 468 * been successful. 469 * 470 * @return {@code true} if the external authentication attempt was considered 471 * successful, or {@code false} if not. 472 */ 473 public boolean externalAuthenticationWasSuccessful() 474 { 475 return externalAuthWasSuccessful; 476 } 477 478 479 480 /** 481 * Retrieves the reason that the external authentication attempt was 482 * considered a failure, if available. 483 * 484 * @return The reason that the external authentication attempt was considered 485 * a failure, or {@code null} if no failure reason is available. 486 */ 487 public String getExternalAuthenticationFailureReason() 488 { 489 return externalAuthFailureReason; 490 } 491 492 493 494 /** 495 * Indicates whether the external authentication processing involved a 496 * password. 497 * 498 * @return {@code true} if the external authentication processing involved a 499 * password, or {@code false} if not. 500 */ 501 public boolean externalAuthenticationWasPasswordBased() 502 { 503 return externalAuthWasPasswordBased; 504 } 505 506 507 508 /** 509 * Indicates whether the external authentication processing is considered to 510 * have been secure. 511 * 512 * @return {@code true} if the external authentication processing was 513 * considered secure, or {@code false} if not. 514 */ 515 public boolean externalAuthenticationWasSecure() 516 { 517 return externalAuthWasSecure; 518 } 519 520 521 522 /** 523 * Retrieves the IPv4 or IPv6 address of the end client involved in the 524 * external authentication processing, if available. 525 * 526 * @return The IPv4 or IPv6 address of the end client involved in the 527 * external authentication processing, or {@code null} if this is not 528 * available. 529 */ 530 public String getEndClientIPAddress() 531 { 532 return endClientIPAddress; 533 } 534 535 536 537 /** 538 * Retrieves a map of additional properties that should be recorded in the 539 * server's access log for the external authentication attempt. 540 * 541 * @return A map of additional properties that should be recorded in the 542 * server's access log for the external authentication attempt, or an 543 * empty map if there are no additional log properties. 544 */ 545 public Map<String,String> getAdditionalAccessLogProperties() 546 { 547 return additionalAccessLogProperties; 548 } 549 550 551 552 /** 553 * {@inheritDoc} 554 */ 555 @Override() 556 public String getSASLMechanismName() 557 { 558 return UNBOUNDID_EXTERNALLY_PROCESSED_AUTH_MECHANISM_NAME; 559 } 560 561 562 563 /** 564 * Retrieves an encoded representation of the SASL credentials for this bind 565 * request. 566 * 567 * @return An encoded representation of the SASL credentials for this bind 568 * request. 569 */ 570 public ASN1OctetString getEncodedCredentials() 571 { 572 if (encodedCredentials == null) 573 { 574 final ArrayList<ASN1Element> credElements = new ArrayList<>(8); 575 576 credElements.add(new ASN1OctetString(TYPE_AUTHENTICATION_ID, 577 authenticationID)); 578 credElements.add(new ASN1OctetString(TYPE_EXTERNAL_MECHANISM_NAME, 579 externalMechanismName)); 580 credElements.add(new ASN1Boolean(TYPE_EXTERNAL_AUTH_WAS_SUCCESSFUL, 581 externalAuthWasSuccessful)); 582 583 if (externalAuthFailureReason != null) 584 { 585 credElements.add(new ASN1OctetString(TYPE_EXTERNAL_AUTH_FAILURE_REASON, 586 externalAuthFailureReason)); 587 } 588 589 if (! externalAuthWasPasswordBased) 590 { 591 credElements.add(new ASN1Boolean(TYPE_EXTERNAL_AUTH_WAS_PASSWORD_BASED, 592 false)); 593 } 594 595 if (externalAuthWasSecure) 596 { 597 credElements.add(new ASN1Boolean(TYPE_EXTERNAL_AUTH_WAS_SECURE, true)); 598 } 599 600 if (endClientIPAddress != null) 601 { 602 credElements.add(new ASN1OctetString(TYPE_END_CLIENT_IP_ADDRESS, 603 endClientIPAddress)); 604 } 605 606 if (! additionalAccessLogProperties.isEmpty()) 607 { 608 final ArrayList<ASN1Element> logElements = 609 new ArrayList<>(additionalAccessLogProperties.size()); 610 for (final Map.Entry<String,String> e : 611 additionalAccessLogProperties.entrySet()) 612 { 613 logElements.add(new ASN1Sequence( 614 new ASN1OctetString(e.getKey()), 615 new ASN1OctetString(e.getValue()))); 616 } 617 618 credElements.add(new ASN1Sequence(TYPE_ADDITIONAL_ACCESS_LOG_PROPERTIES, 619 logElements)); 620 } 621 622 final ASN1Sequence credSequence = new ASN1Sequence(credElements); 623 encodedCredentials = new ASN1OctetString(credSequence.encode()); 624 } 625 626 return encodedCredentials; 627 } 628 629 630 631 /** 632 * {@inheritDoc} 633 */ 634 @Override() 635 protected BindResult process(final LDAPConnection connection, final int depth) 636 throws LDAPException 637 { 638 messageID = InternalSDKHelper.nextMessageID(connection); 639 return sendBindRequest(connection, "", getEncodedCredentials(), 640 getControls(), getResponseTimeoutMillis(connection)); 641 } 642 643 644 645 /** 646 * {@inheritDoc} 647 */ 648 @Override() 649 public int getLastMessageID() 650 { 651 return messageID; 652 } 653 654 655 656 /** 657 * {@inheritDoc} 658 */ 659 @Override() 660 public UnboundIDExternallyProcessedAuthenticationBindRequest duplicate() 661 { 662 return duplicate(getControls()); 663 } 664 665 666 667 /** 668 * {@inheritDoc} 669 */ 670 @Override() 671 public UnboundIDExternallyProcessedAuthenticationBindRequest duplicate( 672 final Control[] controls) 673 { 674 final UnboundIDExternallyProcessedAuthenticationBindRequest bindRequest = 675 new UnboundIDExternallyProcessedAuthenticationBindRequest( 676 authenticationID, externalMechanismName, 677 externalAuthWasSuccessful, externalAuthFailureReason, 678 externalAuthWasPasswordBased, externalAuthWasSecure, 679 endClientIPAddress, additionalAccessLogProperties, controls); 680 bindRequest.encodedCredentials = encodedCredentials; 681 682 bindRequest.setResponseTimeoutMillis(getResponseTimeoutMillis(null)); 683 return bindRequest; 684 } 685 686 687 688 /** 689 * {@inheritDoc} 690 */ 691 @Override() 692 public UnboundIDExternallyProcessedAuthenticationBindRequest getRebindRequest( 693 final String host, final int port) 694 { 695 return duplicate(); 696 } 697 698 699 700 /** 701 * {@inheritDoc} 702 */ 703 @Override() 704 public void toString(final StringBuilder buffer) 705 { 706 buffer.append("UnboundIDExternallyProcessedAuthenticationBindRequest(" + 707 "authenticationID='"); 708 buffer.append(authenticationID); 709 buffer.append("', externalMechanismName='"); 710 buffer.append(externalMechanismName); 711 buffer.append("', externalAuthenticationWasSuccessful="); 712 buffer.append(externalAuthWasSuccessful); 713 buffer.append('\''); 714 715 if (externalAuthFailureReason != null) 716 { 717 buffer.append(", externalAuthenticationFailureReason='"); 718 buffer.append(externalAuthFailureReason); 719 buffer.append('\''); 720 } 721 722 buffer.append(", externalAuthenticationWasPasswordBased="); 723 buffer.append(externalAuthWasPasswordBased); 724 buffer.append(", externalAuthenticationWasSecure="); 725 buffer.append(externalAuthWasSecure); 726 727 if (endClientIPAddress != null) 728 { 729 buffer.append(", endClientIPAddress='"); 730 buffer.append(endClientIPAddress); 731 buffer.append('\''); 732 } 733 734 if (! additionalAccessLogProperties.isEmpty()) 735 { 736 buffer.append(", additionalAccessLogProperties={"); 737 738 final Iterator<Map.Entry<String,String>> iterator = 739 additionalAccessLogProperties.entrySet().iterator(); 740 while (iterator.hasNext()) 741 { 742 final Map.Entry<String,String> e = iterator.next(); 743 744 buffer.append('\''); 745 buffer.append(e.getKey()); 746 buffer.append("'='"); 747 buffer.append(e.getValue()); 748 buffer.append('\''); 749 750 if (iterator.hasNext()) 751 { 752 buffer.append(", "); 753 } 754 } 755 756 buffer.append('}'); 757 } 758 759 760 final Control[] controls = getControls(); 761 if (controls.length > 0) 762 { 763 buffer.append(", controls={"); 764 for (int i=0; i < controls.length; i++) 765 { 766 if (i > 0) 767 { 768 buffer.append(", "); 769 } 770 771 buffer.append(controls[i]); 772 } 773 buffer.append('}'); 774 } 775 776 buffer.append(')'); 777 } 778 779 780 781 /** 782 * {@inheritDoc} 783 */ 784 @Override() 785 public void toCode(final List<String> lineList, final String requestID, 786 final int indentSpaces, final boolean includeProcessing) 787 { 788 // Create the map of additional log properties. 789 final ArrayList<ToCodeArgHelper> mapConstructorArgs = new ArrayList<>(1); 790 mapConstructorArgs.add(ToCodeArgHelper.createInteger( 791 additionalAccessLogProperties.size(), "Initial Capacity")); 792 793 ToCodeHelper.generateMethodCall(lineList, indentSpaces, 794 "LinkedHashMap<String,String>", 795 requestID + "AdditionalAccessLogProperties", 796 "new LinkedHashMap<String,String>", 797 mapConstructorArgs); 798 799 800 // Create the method calls used to populate the map. 801 for (final Map.Entry<String,String> e : 802 additionalAccessLogProperties.entrySet()) 803 { 804 final ArrayList<ToCodeArgHelper> putArgs = new ArrayList<>(2); 805 putArgs.add(ToCodeArgHelper.createString(e.getKey(), 806 "Log Property Key")); 807 putArgs.add(ToCodeArgHelper.createString(e.getValue(), 808 "Log Property Value")); 809 810 ToCodeHelper.generateMethodCall(lineList, indentSpaces, null, null, 811 requestID + "AdditionalAccessLogProperties.put", putArgs); 812 } 813 814 815 // Create the request variable. 816 final ArrayList<ToCodeArgHelper> requestConstructorArgs = 817 new ArrayList<>(8); 818 requestConstructorArgs.add(ToCodeArgHelper.createString(authenticationID, 819 "Authentication ID")); 820 requestConstructorArgs.add(ToCodeArgHelper.createString( 821 externalMechanismName, "External Mechanism Name")); 822 requestConstructorArgs.add(ToCodeArgHelper.createBoolean( 823 externalAuthWasSuccessful, "External Authentication Was Successful")); 824 requestConstructorArgs.add(ToCodeArgHelper.createString( 825 externalAuthFailureReason, "External Authentication Failure Reason")); 826 requestConstructorArgs.add(ToCodeArgHelper.createBoolean( 827 externalAuthWasPasswordBased, 828 "External Authentication Was Password Based")); 829 requestConstructorArgs.add(ToCodeArgHelper.createBoolean( 830 externalAuthWasSecure, "External Authentication Was Secure")); 831 requestConstructorArgs.add(ToCodeArgHelper.createString(endClientIPAddress, 832 "End Client IP Address")); 833 requestConstructorArgs.add(ToCodeArgHelper.createRaw( 834 requestID + "AdditionalAccessLogProperties", 835 "Additional AccessLogProperties")); 836 837 final Control[] controls = getControls(); 838 if (controls.length > 0) 839 { 840 requestConstructorArgs.add(ToCodeArgHelper.createControlArray(controls, 841 "Bind Controls")); 842 } 843 844 lineList.add(""); 845 ToCodeHelper.generateMethodCall(lineList, indentSpaces, 846 "UnboundIDExternallyProcessedAuthenticationBindRequest", 847 requestID + "Request", 848 "new UnboundIDExternallyProcessedAuthenticationBindRequest", 849 requestConstructorArgs); 850 851 852 // Add lines for processing the request and obtaining the result. 853 if (includeProcessing) 854 { 855 // Generate a string with the appropriate indent. 856 final StringBuilder buffer = new StringBuilder(); 857 for (int i=0; i < indentSpaces; i++) 858 { 859 buffer.append(' '); 860 } 861 final String indent = buffer.toString(); 862 863 lineList.add(""); 864 lineList.add(indent + "try"); 865 lineList.add(indent + '{'); 866 lineList.add(indent + " BindResult " + requestID + 867 "Result = connection.bind(" + requestID + "Request);"); 868 lineList.add(indent + " // The bind was processed successfully."); 869 lineList.add(indent + '}'); 870 lineList.add(indent + "catch (LDAPException e)"); 871 lineList.add(indent + '{'); 872 lineList.add(indent + " // The bind failed. Maybe the following will " + 873 "help explain why."); 874 lineList.add(indent + " // Note that the connection is now likely in " + 875 "an unauthenticated state."); 876 lineList.add(indent + " ResultCode resultCode = e.getResultCode();"); 877 lineList.add(indent + " String message = e.getMessage();"); 878 lineList.add(indent + " String matchedDN = e.getMatchedDN();"); 879 lineList.add(indent + " String[] referralURLs = e.getReferralURLs();"); 880 lineList.add(indent + " Control[] responseControls = " + 881 "e.getResponseControls();"); 882 lineList.add(indent + '}'); 883 } 884 } 885}