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 Alcatel-Lucent 8661 068 * server products. These classes provide support for proprietary 069 * functionality or for external specifications that are not considered stable 070 * or mature enough to be guaranteed to work in an interoperable way with 071 * 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<String,String>(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<String,String>(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 /** 555 * {@inheritDoc} 556 */ 557 @Override() 558 public String getSASLMechanismName() 559 { 560 return UNBOUNDID_EXTERNALLY_PROCESSED_AUTH_MECHANISM_NAME; 561 } 562 563 564 565 /** 566 * Retrieves an encoded representation of the SASL credentials for this bind 567 * request. 568 * 569 * @return An encoded representation of the SASL credentials for this bind 570 * request. 571 */ 572 public ASN1OctetString getEncodedCredentials() 573 { 574 if (encodedCredentials == null) 575 { 576 final ArrayList<ASN1Element> credElements = new ArrayList<ASN1Element>(8); 577 578 credElements.add(new ASN1OctetString(TYPE_AUTHENTICATION_ID, 579 authenticationID)); 580 credElements.add(new ASN1OctetString(TYPE_EXTERNAL_MECHANISM_NAME, 581 externalMechanismName)); 582 credElements.add(new ASN1Boolean(TYPE_EXTERNAL_AUTH_WAS_SUCCESSFUL, 583 externalAuthWasSuccessful)); 584 585 if (externalAuthFailureReason != null) 586 { 587 credElements.add(new ASN1OctetString(TYPE_EXTERNAL_AUTH_FAILURE_REASON, 588 externalAuthFailureReason)); 589 } 590 591 if (! externalAuthWasPasswordBased) 592 { 593 credElements.add(new ASN1Boolean(TYPE_EXTERNAL_AUTH_WAS_PASSWORD_BASED, 594 false)); 595 } 596 597 if (externalAuthWasSecure) 598 { 599 credElements.add(new ASN1Boolean(TYPE_EXTERNAL_AUTH_WAS_SECURE, true)); 600 } 601 602 if (endClientIPAddress != null) 603 { 604 credElements.add(new ASN1OctetString(TYPE_END_CLIENT_IP_ADDRESS, 605 endClientIPAddress)); 606 } 607 608 if (! additionalAccessLogProperties.isEmpty()) 609 { 610 final ArrayList<ASN1Element> logElements = 611 new ArrayList<ASN1Element>(additionalAccessLogProperties.size()); 612 for (final Map.Entry<String,String> e : 613 additionalAccessLogProperties.entrySet()) 614 { 615 logElements.add(new ASN1Sequence( 616 new ASN1OctetString(e.getKey()), 617 new ASN1OctetString(e.getValue()))); 618 } 619 620 credElements.add(new ASN1Sequence(TYPE_ADDITIONAL_ACCESS_LOG_PROPERTIES, 621 logElements)); 622 } 623 624 final ASN1Sequence credSequence = new ASN1Sequence(credElements); 625 encodedCredentials = new ASN1OctetString(credSequence.encode()); 626 } 627 628 return encodedCredentials; 629 } 630 631 632 633 /** 634 * {@inheritDoc} 635 */ 636 @Override() 637 protected BindResult process(final LDAPConnection connection, final int depth) 638 throws LDAPException 639 { 640 messageID = InternalSDKHelper.nextMessageID(connection); 641 return sendBindRequest(connection, "", getEncodedCredentials(), 642 getControls(), getResponseTimeoutMillis(connection)); 643 } 644 645 646 647 /** 648 * {@inheritDoc} 649 */ 650 @Override() 651 public int getLastMessageID() 652 { 653 return messageID; 654 } 655 656 657 658 /** 659 * {@inheritDoc} 660 */ 661 @Override() 662 public UnboundIDExternallyProcessedAuthenticationBindRequest duplicate() 663 { 664 return duplicate(getControls()); 665 } 666 667 668 669 /** 670 * {@inheritDoc} 671 */ 672 @Override() 673 public UnboundIDExternallyProcessedAuthenticationBindRequest duplicate( 674 final Control[] controls) 675 { 676 final UnboundIDExternallyProcessedAuthenticationBindRequest bindRequest = 677 new UnboundIDExternallyProcessedAuthenticationBindRequest( 678 authenticationID, externalMechanismName, 679 externalAuthWasSuccessful, externalAuthFailureReason, 680 externalAuthWasPasswordBased, externalAuthWasSecure, 681 endClientIPAddress, additionalAccessLogProperties, controls); 682 bindRequest.encodedCredentials = encodedCredentials; 683 684 bindRequest.setResponseTimeoutMillis(getResponseTimeoutMillis(null)); 685 return bindRequest; 686 } 687 688 689 690 /** 691 * {@inheritDoc} 692 */ 693 @Override() 694 public UnboundIDExternallyProcessedAuthenticationBindRequest getRebindRequest( 695 final String host, final int port) 696 { 697 return duplicate(); 698 } 699 700 701 702 /** 703 * {@inheritDoc} 704 */ 705 @Override() 706 public void toString(final StringBuilder buffer) 707 { 708 buffer.append("UnboundIDExternallyProcessedAuthenticationBindRequest(" + 709 "authenticationID='"); 710 buffer.append(authenticationID); 711 buffer.append("', externalMechanismName='"); 712 buffer.append(externalMechanismName); 713 buffer.append("', externalAuthenticationWasSuccessful="); 714 buffer.append(externalAuthWasSuccessful); 715 buffer.append('\''); 716 717 if (externalAuthFailureReason != null) 718 { 719 buffer.append(", externalAuthenticationFailureReason='"); 720 buffer.append(externalAuthFailureReason); 721 buffer.append('\''); 722 } 723 724 buffer.append(", externalAuthenticationWasPasswordBased="); 725 buffer.append(externalAuthWasPasswordBased); 726 buffer.append(", externalAuthenticationWasSecure="); 727 buffer.append(externalAuthWasSecure); 728 729 if (endClientIPAddress != null) 730 { 731 buffer.append(", endClientIPAddress='"); 732 buffer.append(endClientIPAddress); 733 buffer.append('\''); 734 } 735 736 if (! additionalAccessLogProperties.isEmpty()) 737 { 738 buffer.append(", additionalAccessLogProperties={"); 739 740 final Iterator<Map.Entry<String,String>> iterator = 741 additionalAccessLogProperties.entrySet().iterator(); 742 while (iterator.hasNext()) 743 { 744 final Map.Entry<String,String> e = iterator.next(); 745 746 buffer.append('\''); 747 buffer.append(e.getKey()); 748 buffer.append("'='"); 749 buffer.append(e.getValue()); 750 buffer.append('\''); 751 752 if (iterator.hasNext()) 753 { 754 buffer.append(", "); 755 } 756 } 757 758 buffer.append('}'); 759 } 760 761 762 final Control[] controls = getControls(); 763 if (controls.length > 0) 764 { 765 buffer.append(", controls={"); 766 for (int i=0; i < controls.length; i++) 767 { 768 if (i > 0) 769 { 770 buffer.append(", "); 771 } 772 773 buffer.append(controls[i]); 774 } 775 buffer.append('}'); 776 } 777 778 buffer.append(')'); 779 } 780 781 782 783 /** 784 * {@inheritDoc} 785 */ 786 @Override() 787 public void toCode(final List<String> lineList, final String requestID, 788 final int indentSpaces, final boolean includeProcessing) 789 { 790 // Create the map of additional log properties. 791 final ArrayList<ToCodeArgHelper> mapConstructorArgs = 792 new ArrayList<ToCodeArgHelper>(1); 793 mapConstructorArgs.add(ToCodeArgHelper.createInteger( 794 additionalAccessLogProperties.size(), "Initial Capacity")); 795 796 ToCodeHelper.generateMethodCall(lineList, indentSpaces, 797 "LinkedHashMap<String,String>", 798 requestID + "AdditionalAccessLogProperties", 799 "new LinkedHashMap<String,String>", 800 mapConstructorArgs); 801 802 803 // Create the method calls used to populate the map. 804 for (final Map.Entry<String,String> e : 805 additionalAccessLogProperties.entrySet()) 806 { 807 final ArrayList<ToCodeArgHelper> putArgs = 808 new ArrayList<ToCodeArgHelper>(2); 809 putArgs.add(ToCodeArgHelper.createString(e.getKey(), 810 "Log Property Key")); 811 putArgs.add(ToCodeArgHelper.createString(e.getValue(), 812 "Log Property Value")); 813 814 ToCodeHelper.generateMethodCall(lineList, indentSpaces, null, null, 815 requestID + "AdditionalAccessLogProperties.put", putArgs); 816 } 817 818 819 // Create the request variable. 820 final ArrayList<ToCodeArgHelper> requestConstructorArgs = 821 new ArrayList<ToCodeArgHelper>(8); 822 requestConstructorArgs.add(ToCodeArgHelper.createString(authenticationID, 823 "Authentication ID")); 824 requestConstructorArgs.add(ToCodeArgHelper.createString( 825 externalMechanismName, "External Mechanism Name")); 826 requestConstructorArgs.add(ToCodeArgHelper.createBoolean( 827 externalAuthWasSuccessful, "External Authentication Was Successful")); 828 requestConstructorArgs.add(ToCodeArgHelper.createString( 829 externalAuthFailureReason, "External Authentication Failure Reason")); 830 requestConstructorArgs.add(ToCodeArgHelper.createBoolean( 831 externalAuthWasPasswordBased, 832 "External Authentication Was Password Based")); 833 requestConstructorArgs.add(ToCodeArgHelper.createBoolean( 834 externalAuthWasSecure, "External Authentication Was Secure")); 835 requestConstructorArgs.add(ToCodeArgHelper.createString(endClientIPAddress, 836 "End Client IP Address")); 837 requestConstructorArgs.add(ToCodeArgHelper.createRaw( 838 requestID + "AdditionalAccessLogProperties", 839 "Additional AccessLogProperties")); 840 841 final Control[] controls = getControls(); 842 if (controls.length > 0) 843 { 844 requestConstructorArgs.add(ToCodeArgHelper.createControlArray(controls, 845 "Bind Controls")); 846 } 847 848 lineList.add(""); 849 ToCodeHelper.generateMethodCall(lineList, indentSpaces, 850 "UnboundIDExternallyProcessedAuthenticationBindRequest", 851 requestID + "Request", 852 "new UnboundIDExternallyProcessedAuthenticationBindRequest", 853 requestConstructorArgs); 854 855 856 // Add lines for processing the request and obtaining the result. 857 if (includeProcessing) 858 { 859 // Generate a string with the appropriate indent. 860 final StringBuilder buffer = new StringBuilder(); 861 for (int i=0; i < indentSpaces; i++) 862 { 863 buffer.append(' '); 864 } 865 final String indent = buffer.toString(); 866 867 lineList.add(""); 868 lineList.add(indent + "try"); 869 lineList.add(indent + '{'); 870 lineList.add(indent + " BindResult " + requestID + 871 "Result = connection.bind(" + requestID + "Request);"); 872 lineList.add(indent + " // The bind was processed successfully."); 873 lineList.add(indent + '}'); 874 lineList.add(indent + "catch (LDAPException e)"); 875 lineList.add(indent + '{'); 876 lineList.add(indent + " // The bind failed. Maybe the following will " + 877 "help explain why."); 878 lineList.add(indent + " // Note that the connection is now likely in " + 879 "an unauthenticated state."); 880 lineList.add(indent + " ResultCode resultCode = e.getResultCode();"); 881 lineList.add(indent + " String message = e.getMessage();"); 882 lineList.add(indent + " String matchedDN = e.getMatchedDN();"); 883 lineList.add(indent + " String[] referralURLs = e.getReferralURLs();"); 884 lineList.add(indent + " Control[] responseControls = " + 885 "e.getResponseControls();"); 886 lineList.add(indent + '}'); 887 } 888 } 889}