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