001/* 002 * Copyright 2009-2019 Ping Identity Corporation 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright (C) 2009-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; 022 023 024 025import java.io.File; 026import java.io.FileWriter; 027import java.io.PrintWriter; 028import java.security.PrivilegedExceptionAction; 029import java.util.ArrayList; 030import java.util.HashMap; 031import java.util.List; 032import java.util.Set; 033import java.util.concurrent.atomic.AtomicReference; 034import java.util.logging.Level; 035import javax.security.auth.Subject; 036import javax.security.auth.callback.Callback; 037import javax.security.auth.callback.CallbackHandler; 038import javax.security.auth.callback.NameCallback; 039import javax.security.auth.callback.PasswordCallback; 040import javax.security.auth.callback.UnsupportedCallbackException; 041import javax.security.auth.login.LoginContext; 042import javax.security.sasl.RealmCallback; 043import javax.security.sasl.Sasl; 044import javax.security.sasl.SaslClient; 045 046import com.unboundid.asn1.ASN1OctetString; 047import com.unboundid.util.Debug; 048import com.unboundid.util.DebugType; 049import com.unboundid.util.InternalUseOnly; 050import com.unboundid.util.NotMutable; 051import com.unboundid.util.StaticUtils; 052import com.unboundid.util.ThreadSafety; 053import com.unboundid.util.ThreadSafetyLevel; 054import com.unboundid.util.Validator; 055 056import static com.unboundid.ldap.sdk.LDAPMessages.*; 057 058 059 060/** 061 * This class provides a SASL GSSAPI bind request implementation as described in 062 * <A HREF="http://www.ietf.org/rfc/rfc4752.txt">RFC 4752</A>. It provides the 063 * ability to authenticate to a directory server using Kerberos V, which can 064 * serve as a kind of single sign-on mechanism that may be shared across 065 * client applications that support Kerberos. 066 * <BR><BR> 067 * This class uses the Java Authentication and Authorization Service (JAAS) 068 * behind the scenes to perform all Kerberos processing. This framework 069 * requires a configuration file to indicate the underlying mechanism to be 070 * used. It is possible for clients to explicitly specify the path to the 071 * configuration file that should be used, but if none is given then a default 072 * file will be created and used. This default file should be sufficient for 073 * Sun-provided JVMs, but a custom file may be required for JVMs provided by 074 * other vendors. 075 * <BR><BR> 076 * Elements included in a GSSAPI bind request include: 077 * <UL> 078 * <LI>Authentication ID -- A string which identifies the user that is 079 * attempting to authenticate. It should be the user's Kerberos 080 * principal.</LI> 081 * <LI>Authorization ID -- An optional string which specifies an alternate 082 * authorization identity that should be used for subsequent operations 083 * requested on the connection. Like the authentication ID, the 084 * authorization ID should be a Kerberos principal.</LI> 085 * <LI>KDC Address -- An optional string which specifies the IP address or 086 * resolvable name for the Kerberos key distribution center. If this is 087 * not provided, an attempt will be made to determine the appropriate 088 * value from the system configuration.</LI> 089 * <LI>Realm -- An optional string which specifies the realm into which the 090 * user should authenticate. If this is not provided, an attempt will be 091 * made to determine the appropriate value from the system 092 * configuration</LI> 093 * <LI>Password -- The clear-text password for the target user in the Kerberos 094 * realm.</LI> 095 * </UL> 096 * <H2>Example</H2> 097 * The following example demonstrates the process for performing a GSSAPI bind 098 * against a directory server with a username of "john.doe" and a password 099 * of "password": 100 * <PRE> 101 * GSSAPIBindRequestProperties gssapiProperties = 102 * new GSSAPIBindRequestProperties("john.doe@EXAMPLE.COM", "password"); 103 * gssapiProperties.setKDCAddress("kdc.example.com"); 104 * gssapiProperties.setRealm("EXAMPLE.COM"); 105 * 106 * GSSAPIBindRequest bindRequest = 107 * new GSSAPIBindRequest(gssapiProperties); 108 * BindResult bindResult; 109 * try 110 * { 111 * bindResult = connection.bind(bindRequest); 112 * // If we get here, then the bind was successful. 113 * } 114 * catch (LDAPException le) 115 * { 116 * // The bind failed for some reason. 117 * bindResult = new BindResult(le.toLDAPResult()); 118 * ResultCode resultCode = le.getResultCode(); 119 * String errorMessageFromServer = le.getDiagnosticMessage(); 120 * } 121 * </PRE> 122 */ 123@NotMutable() 124@ThreadSafety(level=ThreadSafetyLevel.NOT_THREADSAFE) 125public final class GSSAPIBindRequest 126 extends SASLBindRequest 127 implements CallbackHandler, PrivilegedExceptionAction<Object> 128{ 129 /** 130 * The name for the GSSAPI SASL mechanism. 131 */ 132 public static final String GSSAPI_MECHANISM_NAME = "GSSAPI"; 133 134 135 136 /** 137 * The name of the configuration property used to specify the address of the 138 * Kerberos key distribution center. 139 */ 140 private static final String PROPERTY_KDC_ADDRESS = "java.security.krb5.kdc"; 141 142 143 144 /** 145 * The name of the configuration property used to specify the Kerberos realm. 146 */ 147 private static final String PROPERTY_REALM = "java.security.krb5.realm"; 148 149 150 151 /** 152 * The name of the configuration property used to specify the path to the JAAS 153 * configuration file. 154 */ 155 private static final String PROPERTY_CONFIG_FILE = 156 "java.security.auth.login.config"; 157 158 159 160 /** 161 * The name of the configuration property used to indicate whether credentials 162 * can come from somewhere other than the location specified in the JAAS 163 * configuration file. 164 */ 165 private static final String PROPERTY_SUBJECT_CREDS_ONLY = 166 "javax.security.auth.useSubjectCredsOnly"; 167 168 169 170 /** 171 * The value for the java.security.auth.login.config property at the time that 172 * this class was loaded. If this is set, then it will be used in place of 173 * an automatically-generated config file. 174 */ 175 private static final String DEFAULT_CONFIG_FILE = 176 System.getProperty(PROPERTY_CONFIG_FILE); 177 178 179 180 /** 181 * The default KDC address that will be used if none is explicitly configured. 182 */ 183 private static final String DEFAULT_KDC_ADDRESS = 184 System.getProperty(PROPERTY_KDC_ADDRESS); 185 186 187 188 /** 189 * The default realm that will be used if none is explicitly configured. 190 */ 191 private static final String DEFAULT_REALM = 192 System.getProperty(PROPERTY_REALM); 193 194 195 196 /** 197 * The serial version UID for this serializable class. 198 */ 199 private static final long serialVersionUID = 2511890818146955112L; 200 201 202 203 // The password for the GSSAPI bind request. 204 private final ASN1OctetString password; 205 206 // A reference to the connection to use for bind processing. 207 private final AtomicReference<LDAPConnection> conn; 208 209 // Indicates whether to enable JVM-level debugging for GSSAPI processing. 210 private final boolean enableGSSAPIDebugging; 211 212 // Indicates whether the client should act as the GSSAPI initiator or the 213 // acceptor. 214 private final Boolean isInitiator; 215 216 // Indicates whether to attempt to refresh the configuration before the JAAS 217 // login method is called. 218 private final boolean refreshKrb5Config; 219 220 // Indicates whether to attempt to renew the client's existing ticket-granting 221 // ticket if authentication uses an existing Kerberos session. 222 private final boolean renewTGT; 223 224 // Indicates whether to require that the credentials be obtained from the 225 // ticket cache such that authentication will fail if the client does not have 226 // an existing Kerberos session. 227 private final boolean requireCachedCredentials; 228 229 // Indicates whether to allow the to obtain the credentials to be obtained 230 // from a keytab. 231 private final boolean useKeyTab; 232 233 // Indicates whether to allow the client to use credentials that are outside 234 // of the current subject. 235 private final boolean useSubjectCredentialsOnly; 236 237 // Indicates whether to enable the use pf a ticket cache. 238 private final boolean useTicketCache; 239 240 // The message ID from the last LDAP message sent from this request. 241 private int messageID; 242 243 // The SASL quality of protection value(s) allowed for the DIGEST-MD5 bind 244 // request. 245 private final List<SASLQualityOfProtection> allowedQoP; 246 247 // A list that will be updated with messages about any unhandled callbacks 248 // encountered during processing. 249 private final List<String> unhandledCallbackMessages; 250 251 // The names of any system properties that should not be altered by GSSAPI 252 // processing. 253 private Set<String> suppressedSystemProperties; 254 255 // The authentication ID string for the GSSAPI bind request. 256 private final String authenticationID; 257 258 // The authorization ID string for the GSSAPI bind request, if available. 259 private final String authorizationID; 260 261 // The path to the JAAS configuration file to use for bind processing. 262 private final String configFilePath; 263 264 // The name that will be used to identify this client in the JAAS framework. 265 private final String jaasClientName; 266 267 // The KDC address for the GSSAPI bind request, if available. 268 private final String kdcAddress; 269 270 // The path to the keytab file to use if useKeyTab is true. 271 private final String keyTabPath; 272 273 // The realm for the GSSAPI bind request, if available. 274 private final String realm; 275 276 // The server name that should be used when creating the Java SaslClient, if 277 // defined. 278 private final String saslClientServerName; 279 280 // The protocol that should be used in the Kerberos service principal for 281 // the server system. 282 private final String servicePrincipalProtocol; 283 284 // The path to the Kerberos ticket cache to use. 285 private final String ticketCachePath; 286 287 288 289 /** 290 * Creates a new SASL GSSAPI bind request with the provided authentication ID 291 * and password. 292 * 293 * @param authenticationID The authentication ID for this bind request. It 294 * must not be {@code null}. 295 * @param password The password for this bind request. It must not 296 * be {@code null}. 297 * 298 * @throws LDAPException If a problem occurs while creating the JAAS 299 * configuration file to use during authentication 300 * processing. 301 */ 302 public GSSAPIBindRequest(final String authenticationID, final String password) 303 throws LDAPException 304 { 305 this(new GSSAPIBindRequestProperties(authenticationID, password)); 306 } 307 308 309 310 /** 311 * Creates a new SASL GSSAPI bind request with the provided authentication ID 312 * and password. 313 * 314 * @param authenticationID The authentication ID for this bind request. It 315 * must not be {@code null}. 316 * @param password The password for this bind request. It must not 317 * be {@code null}. 318 * 319 * @throws LDAPException If a problem occurs while creating the JAAS 320 * configuration file to use during authentication 321 * processing. 322 */ 323 public GSSAPIBindRequest(final String authenticationID, final byte[] password) 324 throws LDAPException 325 { 326 this(new GSSAPIBindRequestProperties(authenticationID, password)); 327 } 328 329 330 331 /** 332 * Creates a new SASL GSSAPI bind request with the provided authentication ID 333 * and password. 334 * 335 * @param authenticationID The authentication ID for this bind request. It 336 * must not be {@code null}. 337 * @param password The password for this bind request. It must not 338 * be {@code null}. 339 * @param controls The set of controls to include in the request. 340 * 341 * @throws LDAPException If a problem occurs while creating the JAAS 342 * configuration file to use during authentication 343 * processing. 344 */ 345 public GSSAPIBindRequest(final String authenticationID, final String password, 346 final Control[] controls) 347 throws LDAPException 348 { 349 this(new GSSAPIBindRequestProperties(authenticationID, password), controls); 350 } 351 352 353 354 /** 355 * Creates a new SASL GSSAPI bind request with the provided authentication ID 356 * and password. 357 * 358 * @param authenticationID The authentication ID for this bind request. It 359 * must not be {@code null}. 360 * @param password The password for this bind request. It must not 361 * be {@code null}. 362 * @param controls The set of controls to include in the request. 363 * 364 * @throws LDAPException If a problem occurs while creating the JAAS 365 * configuration file to use during authentication 366 * processing. 367 */ 368 public GSSAPIBindRequest(final String authenticationID, final byte[] password, 369 final Control[] controls) 370 throws LDAPException 371 { 372 this(new GSSAPIBindRequestProperties(authenticationID, password), controls); 373 } 374 375 376 377 /** 378 * Creates a new SASL GSSAPI bind request with the provided information. 379 * 380 * @param authenticationID The authentication ID for this bind request. It 381 * must not be {@code null}. 382 * @param authorizationID The authorization ID for this bind request. It 383 * may be {@code null} if no alternate authorization 384 * ID should be used. 385 * @param password The password for this bind request. It must not 386 * be {@code null}. 387 * @param realm The realm to use for the authentication. It may 388 * be {@code null} to attempt to use the default 389 * realm from the system configuration. 390 * @param kdcAddress The address of the Kerberos key distribution 391 * center. It may be {@code null} to attempt to use 392 * the default KDC from the system configuration. 393 * @param configFilePath The path to the JAAS configuration file to use 394 * for the authentication processing. It may be 395 * {@code null} to use the default JAAS 396 * configuration. 397 * 398 * @throws LDAPException If a problem occurs while creating the JAAS 399 * configuration file to use during authentication 400 * processing. 401 */ 402 public GSSAPIBindRequest(final String authenticationID, 403 final String authorizationID, final String password, 404 final String realm, final String kdcAddress, 405 final String configFilePath) 406 throws LDAPException 407 { 408 this(new GSSAPIBindRequestProperties(authenticationID, authorizationID, 409 new ASN1OctetString(password), realm, kdcAddress, configFilePath)); 410 } 411 412 413 414 /** 415 * Creates a new SASL GSSAPI bind request with the provided information. 416 * 417 * @param authenticationID The authentication ID for this bind request. It 418 * must not be {@code null}. 419 * @param authorizationID The authorization ID for this bind request. It 420 * may be {@code null} if no alternate authorization 421 * ID should be used. 422 * @param password The password for this bind request. It must not 423 * be {@code null}. 424 * @param realm The realm to use for the authentication. It may 425 * be {@code null} to attempt to use the default 426 * realm from the system configuration. 427 * @param kdcAddress The address of the Kerberos key distribution 428 * center. It may be {@code null} to attempt to use 429 * the default KDC from the system configuration. 430 * @param configFilePath The path to the JAAS configuration file to use 431 * for the authentication processing. It may be 432 * {@code null} to use the default JAAS 433 * configuration. 434 * 435 * @throws LDAPException If a problem occurs while creating the JAAS 436 * configuration file to use during authentication 437 * processing. 438 */ 439 public GSSAPIBindRequest(final String authenticationID, 440 final String authorizationID, final byte[] password, 441 final String realm, final String kdcAddress, 442 final String configFilePath) 443 throws LDAPException 444 { 445 this(new GSSAPIBindRequestProperties(authenticationID, authorizationID, 446 new ASN1OctetString(password), realm, kdcAddress, configFilePath)); 447 } 448 449 450 451 /** 452 * Creates a new SASL GSSAPI bind request with the provided information. 453 * 454 * @param authenticationID The authentication ID for this bind request. It 455 * must not be {@code null}. 456 * @param authorizationID The authorization ID for this bind request. It 457 * may be {@code null} if no alternate authorization 458 * ID should be used. 459 * @param password The password for this bind request. It must not 460 * be {@code null}. 461 * @param realm The realm to use for the authentication. It may 462 * be {@code null} to attempt to use the default 463 * realm from the system configuration. 464 * @param kdcAddress The address of the Kerberos key distribution 465 * center. It may be {@code null} to attempt to use 466 * the default KDC from the system configuration. 467 * @param configFilePath The path to the JAAS configuration file to use 468 * for the authentication processing. It may be 469 * {@code null} to use the default JAAS 470 * configuration. 471 * @param controls The set of controls to include in the request. 472 * 473 * @throws LDAPException If a problem occurs while creating the JAAS 474 * configuration file to use during authentication 475 * processing. 476 */ 477 public GSSAPIBindRequest(final String authenticationID, 478 final String authorizationID, final String password, 479 final String realm, final String kdcAddress, 480 final String configFilePath, 481 final Control[] controls) 482 throws LDAPException 483 { 484 this(new GSSAPIBindRequestProperties(authenticationID, authorizationID, 485 new ASN1OctetString(password), realm, kdcAddress, configFilePath), 486 controls); 487 } 488 489 490 491 /** 492 * Creates a new SASL GSSAPI bind request with the provided information. 493 * 494 * @param authenticationID The authentication ID for this bind request. It 495 * must not be {@code null}. 496 * @param authorizationID The authorization ID for this bind request. It 497 * may be {@code null} if no alternate authorization 498 * ID should be used. 499 * @param password The password for this bind request. It must not 500 * be {@code null}. 501 * @param realm The realm to use for the authentication. It may 502 * be {@code null} to attempt to use the default 503 * realm from the system configuration. 504 * @param kdcAddress The address of the Kerberos key distribution 505 * center. It may be {@code null} to attempt to use 506 * the default KDC from the system configuration. 507 * @param configFilePath The path to the JAAS configuration file to use 508 * for the authentication processing. It may be 509 * {@code null} to use the default JAAS 510 * configuration. 511 * @param controls The set of controls to include in the request. 512 * 513 * @throws LDAPException If a problem occurs while creating the JAAS 514 * configuration file to use during authentication 515 * processing. 516 */ 517 public GSSAPIBindRequest(final String authenticationID, 518 final String authorizationID, final byte[] password, 519 final String realm, final String kdcAddress, 520 final String configFilePath, 521 final Control[] controls) 522 throws LDAPException 523 { 524 this(new GSSAPIBindRequestProperties(authenticationID, authorizationID, 525 new ASN1OctetString(password), realm, kdcAddress, configFilePath), 526 controls); 527 } 528 529 530 531 /** 532 * Creates a new SASL GSSAPI bind request with the provided set of properties. 533 * 534 * @param gssapiProperties The set of properties that should be used for 535 * the GSSAPI bind request. It must not be 536 * {@code null}. 537 * @param controls The set of controls to include in the request. 538 * 539 * @throws LDAPException If a problem occurs while creating the JAAS 540 * configuration file to use during authentication 541 * processing. 542 */ 543 public GSSAPIBindRequest(final GSSAPIBindRequestProperties gssapiProperties, 544 final Control... controls) 545 throws LDAPException 546 { 547 super(controls); 548 549 Validator.ensureNotNull(gssapiProperties); 550 551 authenticationID = gssapiProperties.getAuthenticationID(); 552 password = gssapiProperties.getPassword(); 553 realm = gssapiProperties.getRealm(); 554 allowedQoP = gssapiProperties.getAllowedQoP(); 555 kdcAddress = gssapiProperties.getKDCAddress(); 556 jaasClientName = gssapiProperties.getJAASClientName(); 557 saslClientServerName = gssapiProperties.getSASLClientServerName(); 558 servicePrincipalProtocol = gssapiProperties.getServicePrincipalProtocol(); 559 enableGSSAPIDebugging = gssapiProperties.enableGSSAPIDebugging(); 560 useKeyTab = gssapiProperties.useKeyTab(); 561 useSubjectCredentialsOnly = gssapiProperties.useSubjectCredentialsOnly(); 562 useTicketCache = gssapiProperties.useTicketCache(); 563 requireCachedCredentials = gssapiProperties.requireCachedCredentials(); 564 refreshKrb5Config = gssapiProperties.refreshKrb5Config(); 565 renewTGT = gssapiProperties.renewTGT(); 566 keyTabPath = gssapiProperties.getKeyTabPath(); 567 ticketCachePath = gssapiProperties.getTicketCachePath(); 568 isInitiator = gssapiProperties.getIsInitiator(); 569 suppressedSystemProperties = 570 gssapiProperties.getSuppressedSystemProperties(); 571 572 unhandledCallbackMessages = new ArrayList<>(5); 573 574 conn = new AtomicReference<>(); 575 messageID = -1; 576 577 final String authzID = gssapiProperties.getAuthorizationID(); 578 if (authzID == null) 579 { 580 authorizationID = null; 581 } 582 else 583 { 584 authorizationID = authzID; 585 } 586 587 final String cfgPath = gssapiProperties.getConfigFilePath(); 588 if (cfgPath == null) 589 { 590 if (DEFAULT_CONFIG_FILE == null) 591 { 592 configFilePath = getConfigFilePath(gssapiProperties); 593 } 594 else 595 { 596 configFilePath = DEFAULT_CONFIG_FILE; 597 } 598 } 599 else 600 { 601 configFilePath = cfgPath; 602 } 603 } 604 605 606 607 /** 608 * {@inheritDoc} 609 */ 610 @Override() 611 public String getSASLMechanismName() 612 { 613 return GSSAPI_MECHANISM_NAME; 614 } 615 616 617 618 /** 619 * Retrieves the authentication ID for the GSSAPI bind request, if defined. 620 * 621 * @return The authentication ID for the GSSAPI bind request, or {@code null} 622 * if an existing Kerberos session should be used. 623 */ 624 public String getAuthenticationID() 625 { 626 return authenticationID; 627 } 628 629 630 631 /** 632 * Retrieves the authorization ID for this bind request, if any. 633 * 634 * @return The authorization ID for this bind request, or {@code null} if 635 * there should not be a separate authorization identity. 636 */ 637 public String getAuthorizationID() 638 { 639 return authorizationID; 640 } 641 642 643 644 /** 645 * Retrieves the string representation of the password for this bind request, 646 * if defined. 647 * 648 * @return The string representation of the password for this bind request, 649 * or {@code null} if an existing Kerberos session should be used. 650 */ 651 public String getPasswordString() 652 { 653 if (password == null) 654 { 655 return null; 656 } 657 else 658 { 659 return password.stringValue(); 660 } 661 } 662 663 664 665 /** 666 * Retrieves the bytes that comprise the the password for this bind request, 667 * if defined. 668 * 669 * @return The bytes that comprise the password for this bind request, or 670 * {@code null} if an existing Kerberos session should be used. 671 */ 672 public byte[] getPasswordBytes() 673 { 674 if (password == null) 675 { 676 return null; 677 } 678 else 679 { 680 return password.getValue(); 681 } 682 } 683 684 685 686 /** 687 * Retrieves the realm for this bind request, if any. 688 * 689 * @return The realm for this bind request, or {@code null} if none was 690 * defined and the client should attempt to determine the realm from 691 * the system configuration. 692 */ 693 public String getRealm() 694 { 695 return realm; 696 } 697 698 699 700 /** 701 * Retrieves the list of allowed qualities of protection that may be used for 702 * communication that occurs on the connection after the authentication has 703 * completed, in order from most preferred to least preferred. 704 * 705 * @return The list of allowed qualities of protection that may be used for 706 * communication that occurs on the connection after the 707 * authentication has completed, in order from most preferred to 708 * least preferred. 709 */ 710 public List<SASLQualityOfProtection> getAllowedQoP() 711 { 712 return allowedQoP; 713 } 714 715 716 717 /** 718 * Retrieves the address of the Kerberos key distribution center. 719 * 720 * @return The address of the Kerberos key distribution center, or 721 * {@code null} if none was defined and the client should attempt to 722 * determine the KDC address from the system configuration. 723 */ 724 public String getKDCAddress() 725 { 726 return kdcAddress; 727 } 728 729 730 731 /** 732 * Retrieves the path to the JAAS configuration file that will be used during 733 * authentication processing. 734 * 735 * @return The path to the JAAS configuration file that will be used during 736 * authentication processing. 737 */ 738 public String getConfigFilePath() 739 { 740 return configFilePath; 741 } 742 743 744 745 /** 746 * Retrieves the protocol specified in the service principal that the 747 * directory server uses for its communication with the KDC. 748 * 749 * @return The protocol specified in the service principal that the directory 750 * server uses for its communication with the KDC. 751 */ 752 public String getServicePrincipalProtocol() 753 { 754 return servicePrincipalProtocol; 755 } 756 757 758 759 /** 760 * Indicates whether to refresh the configuration before the JAAS 761 * {@code login} method is called. 762 * 763 * @return {@code true} if the GSSAPI implementation should refresh the 764 * configuration before the JAAS {@code login} method is called, or 765 * {@code false} if not. 766 */ 767 public boolean refreshKrb5Config() 768 { 769 return refreshKrb5Config; 770 } 771 772 773 774 /** 775 * Indicates whether to use a keytab to obtain the user credentials. 776 * 777 * @return {@code true} if the GSSAPI login attempt should use a keytab to 778 * obtain the user credentials, or {@code false} if not. 779 */ 780 public boolean useKeyTab() 781 { 782 return useKeyTab; 783 } 784 785 786 787 /** 788 * Retrieves the path to the keytab file from which to obtain the user 789 * credentials. This will only be used if {@link #useKeyTab} returns 790 * {@code true}. 791 * 792 * @return The path to the keytab file from which to obtain the user 793 * credentials, or {@code null} if the default keytab location should 794 * be used. 795 */ 796 public String getKeyTabPath() 797 { 798 return keyTabPath; 799 } 800 801 802 803 /** 804 * Indicates whether to enable the use of a ticket cache to to avoid the need 805 * to supply credentials if the client already has an existing Kerberos 806 * session. 807 * 808 * @return {@code true} if a ticket cache may be used to take advantage of an 809 * existing Kerberos session, or {@code false} if Kerberos 810 * credentials should always be provided. 811 */ 812 public boolean useTicketCache() 813 { 814 return useTicketCache; 815 } 816 817 818 819 /** 820 * Indicates whether GSSAPI authentication should only occur using an existing 821 * Kerberos session. 822 * 823 * @return {@code true} if GSSAPI authentication should only use an existing 824 * Kerberos session and should fail if the client does not have an 825 * existing session, or {@code false} if the client will be allowed 826 * to create a new session if one does not already exist. 827 */ 828 public boolean requireCachedCredentials() 829 { 830 return requireCachedCredentials; 831 } 832 833 834 835 /** 836 * Retrieves the path to the Kerberos ticket cache file that should be used 837 * during authentication, if defined. 838 * 839 * @return The path to the Kerberos ticket cache file that should be used 840 * during authentication, or {@code null} if the default ticket cache 841 * file should be used. 842 */ 843 public String getTicketCachePath() 844 { 845 return ticketCachePath; 846 } 847 848 849 850 /** 851 * Indicates whether to attempt to renew the client's ticket-granting ticket 852 * (TGT) if an existing Kerberos session is used to authenticate. 853 * 854 * @return {@code true} if the client should attempt to renew its 855 * ticket-granting ticket if the authentication is processed using an 856 * existing Kerberos session, or {@code false} if not. 857 */ 858 public boolean renewTGT() 859 { 860 return renewTGT; 861 } 862 863 864 865 /** 866 * Indicates whether to allow the client to use credentials that are outside 867 * of the current subject, obtained via some system-specific mechanism. 868 * 869 * @return {@code true} if the client will only be allowed to use credentials 870 * that are within the current subject, or {@code false} if the 871 * client will be allowed to use credentials outside the current 872 * subject. 873 */ 874 public boolean useSubjectCredentialsOnly() 875 { 876 return useSubjectCredentialsOnly; 877 } 878 879 880 881 /** 882 * Indicates whether the client should be configured so that it explicitly 883 * indicates whether it is the initiator or the acceptor. 884 * 885 * @return {@code Boolean.TRUE} if the client should explicitly indicate that 886 * it is the GSSAPI initiator, {@code Boolean.FALSE} if the client 887 * should explicitly indicate that it is the GSSAPI acceptor, or 888 * {@code null} if the client should not explicitly indicate either 889 * state (which is the default behavior unless the 890 * {@link GSSAPIBindRequestProperties#setIsInitiator} method has 891 * been used to explicitly specify a value). 892 */ 893 public Boolean getIsInitiator() 894 { 895 return isInitiator; 896 } 897 898 899 900 /** 901 * Retrieves a set of system properties that will not be altered by GSSAPI 902 * processing. 903 * 904 * @return A set of system properties that will not be altered by GSSAPI 905 * processing. 906 */ 907 public Set<String> getSuppressedSystemProperties() 908 { 909 return suppressedSystemProperties; 910 } 911 912 913 914 /** 915 * Indicates whether JVM-level debugging should be enabled for GSSAPI bind 916 * processing. 917 * 918 * @return {@code true} if JVM-level debugging should be enabled for GSSAPI 919 * bind processing, or {@code false} if not. 920 */ 921 public boolean enableGSSAPIDebugging() 922 { 923 return enableGSSAPIDebugging; 924 } 925 926 927 928 /** 929 * Retrieves the path to the default JAAS configuration file that will be used 930 * if no file was explicitly provided. A new file may be created if 931 * necessary. 932 * 933 * @param properties The GSSAPI properties that should be used for 934 * authentication. 935 * 936 * @return The path to the default JAAS configuration file that will be used 937 * if no file was explicitly provided. 938 * 939 * @throws LDAPException If an error occurs while attempting to create the 940 * configuration file. 941 */ 942 private static String getConfigFilePath( 943 final GSSAPIBindRequestProperties properties) 944 throws LDAPException 945 { 946 try 947 { 948 final File f = 949 File.createTempFile("GSSAPIBindRequest-JAAS-Config-", ".conf"); 950 f.deleteOnExit(); 951 final PrintWriter w = new PrintWriter(new FileWriter(f)); 952 953 try 954 { 955 // The JAAS configuration file may vary based on the JVM that we're 956 // using. For Sun-based JVMs, the module will be 957 // "com.sun.security.auth.module.Krb5LoginModule". 958 try 959 { 960 final Class<?> sunModuleClass = 961 Class.forName("com.sun.security.auth.module.Krb5LoginModule"); 962 if (sunModuleClass != null) 963 { 964 writeSunJAASConfig(w, properties); 965 return f.getAbsolutePath(); 966 } 967 } 968 catch (final ClassNotFoundException cnfe) 969 { 970 // This is fine. 971 Debug.debugException(cnfe); 972 } 973 974 975 // For the IBM JVMs, the module will be 976 // "com.ibm.security.auth.module.Krb5LoginModule". 977 try 978 { 979 final Class<?> ibmModuleClass = 980 Class.forName("com.ibm.security.auth.module.Krb5LoginModule"); 981 if (ibmModuleClass != null) 982 { 983 writeIBMJAASConfig(w, properties); 984 return f.getAbsolutePath(); 985 } 986 } 987 catch (final ClassNotFoundException cnfe) 988 { 989 // This is fine. 990 Debug.debugException(cnfe); 991 } 992 993 994 // If we've gotten here, then we can't generate an appropriate 995 // configuration. 996 throw new LDAPException(ResultCode.LOCAL_ERROR, 997 ERR_GSSAPI_CANNOT_CREATE_JAAS_CONFIG.get( 998 ERR_GSSAPI_NO_SUPPORTED_JAAS_MODULE.get())); 999 } 1000 finally 1001 { 1002 w.close(); 1003 } 1004 } 1005 catch (final LDAPException le) 1006 { 1007 Debug.debugException(le); 1008 throw le; 1009 } 1010 catch (final Exception e) 1011 { 1012 Debug.debugException(e); 1013 1014 throw new LDAPException(ResultCode.LOCAL_ERROR, 1015 ERR_GSSAPI_CANNOT_CREATE_JAAS_CONFIG.get( 1016 StaticUtils.getExceptionMessage(e)), 1017 e); 1018 } 1019 } 1020 1021 1022 1023 /** 1024 * Writes a JAAS configuration file in a form appropriate for Sun VMs. 1025 * 1026 * @param w The writer to use to create the config file. 1027 * @param p The properties to use for GSSAPI authentication. 1028 */ 1029 private static void writeSunJAASConfig(final PrintWriter w, 1030 final GSSAPIBindRequestProperties p) 1031 { 1032 w.println(p.getJAASClientName() + " {"); 1033 w.println(" com.sun.security.auth.module.Krb5LoginModule required"); 1034 w.println(" client=true"); 1035 1036 if (p.getIsInitiator() != null) 1037 { 1038 w.println(" isInitiator=" + p.getIsInitiator()); 1039 } 1040 1041 if (p.refreshKrb5Config()) 1042 { 1043 w.println(" refreshKrb5Config=true"); 1044 } 1045 1046 if (p.useKeyTab()) 1047 { 1048 w.println(" useKeyTab=true"); 1049 if (p.getKeyTabPath() != null) 1050 { 1051 w.println(" keyTab=\"" + p.getKeyTabPath() + '"'); 1052 } 1053 } 1054 1055 if (p.useTicketCache()) 1056 { 1057 w.println(" useTicketCache=true"); 1058 w.println(" renewTGT=" + p.renewTGT()); 1059 w.println(" doNotPrompt=" + p.requireCachedCredentials()); 1060 1061 final String ticketCachePath = p.getTicketCachePath(); 1062 if (ticketCachePath != null) 1063 { 1064 w.println(" ticketCache=\"" + ticketCachePath + '"'); 1065 } 1066 } 1067 else 1068 { 1069 w.println(" useTicketCache=false"); 1070 } 1071 1072 if (p.enableGSSAPIDebugging()) 1073 { 1074 w.println(" debug=true"); 1075 } 1076 1077 w.println(" ;"); 1078 w.println("};"); 1079 } 1080 1081 1082 1083 /** 1084 * Writes a JAAS configuration file in a form appropriate for IBM VMs. 1085 * 1086 * @param w The writer to use to create the config file. 1087 * @param p The properties to use for GSSAPI authentication. 1088 */ 1089 private static void writeIBMJAASConfig(final PrintWriter w, 1090 final GSSAPIBindRequestProperties p) 1091 { 1092 // NOTE: It does not appear that the IBM GSSAPI implementation has any 1093 // analog for the renewTGT property, so it will be ignored. 1094 w.println(p.getJAASClientName() + " {"); 1095 w.println(" com.ibm.security.auth.module.Krb5LoginModule required"); 1096 if ((p.getIsInitiator() == null) || p.getIsInitiator().booleanValue()) 1097 { 1098 w.println(" credsType=initiator"); 1099 } 1100 else 1101 { 1102 w.println(" credsType=acceptor"); 1103 } 1104 1105 if (p.refreshKrb5Config()) 1106 { 1107 w.println(" refreshKrb5Config=true"); 1108 } 1109 1110 if (p.useKeyTab()) 1111 { 1112 w.println(" useKeyTab=true"); 1113 if (p.getKeyTabPath() != null) 1114 { 1115 w.println(" keyTab=\"" + p.getKeyTabPath() + '"'); 1116 } 1117 } 1118 1119 if (p.useTicketCache()) 1120 { 1121 final String ticketCachePath = p.getTicketCachePath(); 1122 if (ticketCachePath == null) 1123 { 1124 if (p.requireCachedCredentials()) 1125 { 1126 w.println(" useDefaultCcache=true"); 1127 } 1128 } 1129 else 1130 { 1131 final File f = new File(ticketCachePath); 1132 final String path = f.getAbsolutePath().replace('\\', '/'); 1133 w.println(" useCcache=\"file://" + path + '"'); 1134 } 1135 } 1136 else 1137 { 1138 w.println(" useDefaultCcache=false"); 1139 } 1140 1141 if (p.enableGSSAPIDebugging()) 1142 { 1143 w.println(" debug=true"); 1144 } 1145 1146 w.println(" ;"); 1147 w.println("};"); 1148 } 1149 1150 1151 1152 /** 1153 * Sends this bind request to the target server over the provided connection 1154 * and returns the corresponding response. 1155 * 1156 * @param connection The connection to use to send this bind request to the 1157 * server and read the associated response. 1158 * @param depth The current referral depth for this request. It should 1159 * always be one for the initial request, and should only 1160 * be incremented when following referrals. 1161 * 1162 * @return The bind response read from the server. 1163 * 1164 * @throws LDAPException If a problem occurs while sending the request or 1165 * reading the response. 1166 */ 1167 @Override() 1168 protected BindResult process(final LDAPConnection connection, final int depth) 1169 throws LDAPException 1170 { 1171 if (! conn.compareAndSet(null, connection)) 1172 { 1173 throw new LDAPException(ResultCode.LOCAL_ERROR, 1174 ERR_GSSAPI_MULTIPLE_CONCURRENT_REQUESTS.get()); 1175 } 1176 1177 setProperty(PROPERTY_CONFIG_FILE, configFilePath); 1178 setProperty(PROPERTY_SUBJECT_CREDS_ONLY, 1179 String.valueOf(useSubjectCredentialsOnly)); 1180 if (Debug.debugEnabled(DebugType.LDAP)) 1181 { 1182 Debug.debug(Level.CONFIG, DebugType.LDAP, 1183 "Using config file property " + PROPERTY_CONFIG_FILE + " = '" + 1184 configFilePath + "'."); 1185 Debug.debug(Level.CONFIG, DebugType.LDAP, 1186 "Using subject creds only property " + PROPERTY_SUBJECT_CREDS_ONLY + 1187 " = '" + useSubjectCredentialsOnly + "'."); 1188 } 1189 1190 if (kdcAddress == null) 1191 { 1192 if (DEFAULT_KDC_ADDRESS == null) 1193 { 1194 clearProperty(PROPERTY_KDC_ADDRESS); 1195 if (Debug.debugEnabled(DebugType.LDAP)) 1196 { 1197 Debug.debug(Level.CONFIG, DebugType.LDAP, 1198 "Clearing kdcAddress property '" + PROPERTY_KDC_ADDRESS + "'."); 1199 } 1200 } 1201 else 1202 { 1203 setProperty(PROPERTY_KDC_ADDRESS, DEFAULT_KDC_ADDRESS); 1204 if (Debug.debugEnabled(DebugType.LDAP)) 1205 { 1206 Debug.debug(Level.CONFIG, DebugType.LDAP, 1207 "Using default kdcAddress property " + PROPERTY_KDC_ADDRESS + 1208 " = '" + DEFAULT_KDC_ADDRESS + "'."); 1209 } 1210 } 1211 } 1212 else 1213 { 1214 setProperty(PROPERTY_KDC_ADDRESS, kdcAddress); 1215 if (Debug.debugEnabled(DebugType.LDAP)) 1216 { 1217 Debug.debug(Level.CONFIG, DebugType.LDAP, 1218 "Using kdcAddress property " + PROPERTY_KDC_ADDRESS + " = '" + 1219 kdcAddress + "'."); 1220 } 1221 } 1222 1223 if (realm == null) 1224 { 1225 if (DEFAULT_REALM == null) 1226 { 1227 clearProperty(PROPERTY_REALM); 1228 if (Debug.debugEnabled(DebugType.LDAP)) 1229 { 1230 Debug.debug(Level.CONFIG, DebugType.LDAP, 1231 "Clearing realm property '" + PROPERTY_REALM + "'."); 1232 } 1233 } 1234 else 1235 { 1236 setProperty(PROPERTY_REALM, DEFAULT_REALM); 1237 if (Debug.debugEnabled(DebugType.LDAP)) 1238 { 1239 Debug.debug(Level.CONFIG, DebugType.LDAP, 1240 "Using default realm property " + PROPERTY_REALM + " = '" + 1241 DEFAULT_REALM + "'."); 1242 } 1243 } 1244 } 1245 else 1246 { 1247 setProperty(PROPERTY_REALM, realm); 1248 if (Debug.debugEnabled(DebugType.LDAP)) 1249 { 1250 Debug.debug(Level.CONFIG, DebugType.LDAP, 1251 "Using realm property " + PROPERTY_REALM + " = '" + realm + "'."); 1252 } 1253 } 1254 1255 try 1256 { 1257 final LoginContext context; 1258 try 1259 { 1260 context = new LoginContext(jaasClientName, this); 1261 context.login(); 1262 } 1263 catch (final Exception e) 1264 { 1265 Debug.debugException(e); 1266 1267 throw new LDAPException(ResultCode.LOCAL_ERROR, 1268 ERR_GSSAPI_CANNOT_INITIALIZE_JAAS_CONTEXT.get( 1269 StaticUtils.getExceptionMessage(e)), 1270 e); 1271 } 1272 1273 try 1274 { 1275 return (BindResult) Subject.doAs(context.getSubject(), this); 1276 } 1277 catch (final Exception e) 1278 { 1279 Debug.debugException(e); 1280 if (e instanceof LDAPException) 1281 { 1282 throw (LDAPException) e; 1283 } 1284 else 1285 { 1286 throw new LDAPException(ResultCode.LOCAL_ERROR, 1287 ERR_GSSAPI_AUTHENTICATION_FAILED.get( 1288 StaticUtils.getExceptionMessage(e)), 1289 e); 1290 } 1291 } 1292 } 1293 finally 1294 { 1295 conn.set(null); 1296 } 1297 } 1298 1299 1300 1301 /** 1302 * Perform the privileged portion of the authentication processing. 1303 * 1304 * @return {@code null}, since no return value is actually needed. 1305 * 1306 * @throws LDAPException If a problem occurs during processing. 1307 */ 1308 @InternalUseOnly() 1309 @Override() 1310 public Object run() 1311 throws LDAPException 1312 { 1313 unhandledCallbackMessages.clear(); 1314 1315 final LDAPConnection connection = conn.get(); 1316 1317 1318 final HashMap<String,Object> saslProperties = 1319 new HashMap<>(StaticUtils.computeMapCapacity(2)); 1320 saslProperties.put(Sasl.QOP, SASLQualityOfProtection.toString(allowedQoP)); 1321 saslProperties.put(Sasl.SERVER_AUTH, "true"); 1322 1323 final SaslClient saslClient; 1324 try 1325 { 1326 String serverName = saslClientServerName; 1327 if (serverName == null) 1328 { 1329 serverName = connection.getConnectedAddress(); 1330 } 1331 1332 final String[] mechanisms = { GSSAPI_MECHANISM_NAME }; 1333 saslClient = Sasl.createSaslClient(mechanisms, authorizationID, 1334 servicePrincipalProtocol, serverName, saslProperties, this); 1335 } 1336 catch (final Exception e) 1337 { 1338 Debug.debugException(e); 1339 throw new LDAPException(ResultCode.LOCAL_ERROR, 1340 ERR_GSSAPI_CANNOT_CREATE_SASL_CLIENT.get( 1341 StaticUtils.getExceptionMessage(e)), 1342 e); 1343 } 1344 1345 final SASLHelper helper = new SASLHelper(this, connection, 1346 GSSAPI_MECHANISM_NAME, saslClient, getControls(), 1347 getResponseTimeoutMillis(connection), unhandledCallbackMessages); 1348 1349 try 1350 { 1351 return helper.processSASLBind(); 1352 } 1353 finally 1354 { 1355 messageID = helper.getMessageID(); 1356 } 1357 } 1358 1359 1360 1361 /** 1362 * {@inheritDoc} 1363 */ 1364 @Override() 1365 public GSSAPIBindRequest getRebindRequest(final String host, final int port) 1366 { 1367 try 1368 { 1369 final GSSAPIBindRequestProperties gssapiProperties = 1370 new GSSAPIBindRequestProperties(authenticationID, authorizationID, 1371 password, realm, kdcAddress, configFilePath); 1372 gssapiProperties.setAllowedQoP(allowedQoP); 1373 gssapiProperties.setServicePrincipalProtocol(servicePrincipalProtocol); 1374 gssapiProperties.setUseTicketCache(useTicketCache); 1375 gssapiProperties.setRequireCachedCredentials(requireCachedCredentials); 1376 gssapiProperties.setRenewTGT(renewTGT); 1377 gssapiProperties.setUseSubjectCredentialsOnly(useSubjectCredentialsOnly); 1378 gssapiProperties.setTicketCachePath(ticketCachePath); 1379 gssapiProperties.setEnableGSSAPIDebugging(enableGSSAPIDebugging); 1380 gssapiProperties.setJAASClientName(jaasClientName); 1381 gssapiProperties.setSASLClientServerName(saslClientServerName); 1382 gssapiProperties.setSuppressedSystemProperties( 1383 suppressedSystemProperties); 1384 1385 return new GSSAPIBindRequest(gssapiProperties, getControls()); 1386 } 1387 catch (final Exception e) 1388 { 1389 // This should never happen. 1390 Debug.debugException(e); 1391 return null; 1392 } 1393 } 1394 1395 1396 1397 /** 1398 * Handles any necessary callbacks required for SASL authentication. 1399 * 1400 * @param callbacks The set of callbacks to be handled. 1401 * 1402 * @throws UnsupportedCallbackException If an unsupported type of callback 1403 * was received. 1404 */ 1405 @InternalUseOnly() 1406 @Override() 1407 public void handle(final Callback[] callbacks) 1408 throws UnsupportedCallbackException 1409 { 1410 for (final Callback callback : callbacks) 1411 { 1412 if (callback instanceof NameCallback) 1413 { 1414 ((NameCallback) callback).setName(authenticationID); 1415 } 1416 else if (callback instanceof PasswordCallback) 1417 { 1418 if (password == null) 1419 { 1420 throw new UnsupportedCallbackException(callback, 1421 ERR_GSSAPI_NO_PASSWORD_AVAILABLE.get()); 1422 } 1423 else 1424 { 1425 ((PasswordCallback) callback).setPassword( 1426 password.stringValue().toCharArray()); 1427 } 1428 } 1429 else if (callback instanceof RealmCallback) 1430 { 1431 final RealmCallback rc = (RealmCallback) callback; 1432 if (realm == null) 1433 { 1434 unhandledCallbackMessages.add( 1435 ERR_GSSAPI_REALM_REQUIRED_BUT_NONE_PROVIDED.get(rc.getPrompt())); 1436 } 1437 else 1438 { 1439 rc.setText(realm); 1440 } 1441 } 1442 else 1443 { 1444 // This is an unexpected callback. 1445 if (Debug.debugEnabled(DebugType.LDAP)) 1446 { 1447 Debug.debug(Level.WARNING, DebugType.LDAP, 1448 "Unexpected GSSAPI SASL callback of type " + 1449 callback.getClass().getName()); 1450 } 1451 1452 unhandledCallbackMessages.add(ERR_GSSAPI_UNEXPECTED_CALLBACK.get( 1453 callback.getClass().getName())); 1454 } 1455 } 1456 } 1457 1458 1459 1460 /** 1461 * {@inheritDoc} 1462 */ 1463 @Override() 1464 public int getLastMessageID() 1465 { 1466 return messageID; 1467 } 1468 1469 1470 1471 /** 1472 * {@inheritDoc} 1473 */ 1474 @Override() 1475 public GSSAPIBindRequest duplicate() 1476 { 1477 return duplicate(getControls()); 1478 } 1479 1480 1481 1482 /** 1483 * {@inheritDoc} 1484 */ 1485 @Override() 1486 public GSSAPIBindRequest duplicate(final Control[] controls) 1487 { 1488 try 1489 { 1490 final GSSAPIBindRequestProperties gssapiProperties = 1491 new GSSAPIBindRequestProperties(authenticationID, authorizationID, 1492 password, realm, kdcAddress, configFilePath); 1493 gssapiProperties.setAllowedQoP(allowedQoP); 1494 gssapiProperties.setServicePrincipalProtocol(servicePrincipalProtocol); 1495 gssapiProperties.setUseTicketCache(useTicketCache); 1496 gssapiProperties.setRequireCachedCredentials(requireCachedCredentials); 1497 gssapiProperties.setRenewTGT(renewTGT); 1498 gssapiProperties.setRefreshKrb5Config(refreshKrb5Config); 1499 gssapiProperties.setUseKeyTab(useKeyTab); 1500 gssapiProperties.setKeyTabPath(keyTabPath); 1501 gssapiProperties.setUseSubjectCredentialsOnly(useSubjectCredentialsOnly); 1502 gssapiProperties.setTicketCachePath(ticketCachePath); 1503 gssapiProperties.setEnableGSSAPIDebugging(enableGSSAPIDebugging); 1504 gssapiProperties.setJAASClientName(jaasClientName); 1505 gssapiProperties.setSASLClientServerName(saslClientServerName); 1506 gssapiProperties.setIsInitiator(isInitiator); 1507 gssapiProperties.setSuppressedSystemProperties( 1508 suppressedSystemProperties); 1509 1510 final GSSAPIBindRequest bindRequest = 1511 new GSSAPIBindRequest(gssapiProperties, controls); 1512 bindRequest.setResponseTimeoutMillis(getResponseTimeoutMillis(null)); 1513 return bindRequest; 1514 } 1515 catch (final Exception e) 1516 { 1517 // This should never happen. 1518 Debug.debugException(e); 1519 return null; 1520 } 1521 } 1522 1523 1524 1525 /** 1526 * Clears the specified system property, unless it is one that is configured 1527 * to be suppressed. 1528 * 1529 * @param name The name of the property to be suppressed. 1530 */ 1531 private void clearProperty(final String name) 1532 { 1533 if (! suppressedSystemProperties.contains(name)) 1534 { 1535 System.clearProperty(name); 1536 } 1537 } 1538 1539 1540 1541 /** 1542 * Sets the specified system property, unless it is one that is configured to 1543 * be suppressed. 1544 * 1545 * @param name The name of the property to be suppressed. 1546 * @param value The value of the property to be suppressed. 1547 */ 1548 private void setProperty(final String name, final String value) 1549 { 1550 if (! suppressedSystemProperties.contains(name)) 1551 { 1552 System.setProperty(name, value); 1553 } 1554 } 1555 1556 1557 1558 /** 1559 * {@inheritDoc} 1560 */ 1561 @Override() 1562 public void toString(final StringBuilder buffer) 1563 { 1564 buffer.append("GSSAPIBindRequest(authenticationID='"); 1565 buffer.append(authenticationID); 1566 buffer.append('\''); 1567 1568 if (authorizationID != null) 1569 { 1570 buffer.append(", authorizationID='"); 1571 buffer.append(authorizationID); 1572 buffer.append('\''); 1573 } 1574 1575 if (realm != null) 1576 { 1577 buffer.append(", realm='"); 1578 buffer.append(realm); 1579 buffer.append('\''); 1580 } 1581 1582 buffer.append(", qop='"); 1583 buffer.append(SASLQualityOfProtection.toString(allowedQoP)); 1584 buffer.append('\''); 1585 1586 if (kdcAddress != null) 1587 { 1588 buffer.append(", kdcAddress='"); 1589 buffer.append(kdcAddress); 1590 buffer.append('\''); 1591 } 1592 1593 if (isInitiator != null) 1594 { 1595 buffer.append(", isInitiator="); 1596 buffer.append(isInitiator); 1597 } 1598 1599 buffer.append(", jaasClientName='"); 1600 buffer.append(jaasClientName); 1601 buffer.append("', configFilePath='"); 1602 buffer.append(configFilePath); 1603 buffer.append("', servicePrincipalProtocol='"); 1604 buffer.append(servicePrincipalProtocol); 1605 buffer.append("', enableGSSAPIDebugging="); 1606 buffer.append(enableGSSAPIDebugging); 1607 1608 final Control[] controls = getControls(); 1609 if (controls.length > 0) 1610 { 1611 buffer.append(", controls={"); 1612 for (int i=0; i < controls.length; i++) 1613 { 1614 if (i > 0) 1615 { 1616 buffer.append(", "); 1617 } 1618 1619 buffer.append(controls[i]); 1620 } 1621 buffer.append('}'); 1622 } 1623 1624 buffer.append(')'); 1625 } 1626 1627 1628 1629 /** 1630 * {@inheritDoc} 1631 */ 1632 @Override() 1633 public void toCode(final List<String> lineList, final String requestID, 1634 final int indentSpaces, final boolean includeProcessing) 1635 { 1636 // Create and update the bind request properties object. 1637 ToCodeHelper.generateMethodCall(lineList, indentSpaces, 1638 "GSSAPIBindRequestProperties", requestID + "RequestProperties", 1639 "new GSSAPIBindRequestProperties", 1640 ToCodeArgHelper.createString(authenticationID, "Authentication ID"), 1641 ToCodeArgHelper.createString("---redacted-password---", "Password")); 1642 1643 if (authorizationID != null) 1644 { 1645 ToCodeHelper.generateMethodCall(lineList, indentSpaces, null, null, 1646 requestID + "RequestProperties.setAuthorizationID", 1647 ToCodeArgHelper.createString(authorizationID, null)); 1648 } 1649 1650 if (realm != null) 1651 { 1652 ToCodeHelper.generateMethodCall(lineList, indentSpaces, null, null, 1653 requestID + "RequestProperties.setRealm", 1654 ToCodeArgHelper.createString(realm, null)); 1655 } 1656 1657 final ArrayList<String> qopValues = new ArrayList<>(3); 1658 for (final SASLQualityOfProtection qop : allowedQoP) 1659 { 1660 qopValues.add("SASLQualityOfProtection." + qop.name()); 1661 } 1662 ToCodeHelper.generateMethodCall(lineList, indentSpaces, null, null, 1663 requestID + "RequestProperties.setAllowedQoP", 1664 ToCodeArgHelper.createRaw(qopValues, null)); 1665 1666 if (kdcAddress != null) 1667 { 1668 ToCodeHelper.generateMethodCall(lineList, indentSpaces, null, null, 1669 requestID + "RequestProperties.setKDCAddress", 1670 ToCodeArgHelper.createString(kdcAddress, null)); 1671 } 1672 1673 if (jaasClientName != null) 1674 { 1675 ToCodeHelper.generateMethodCall(lineList, indentSpaces, null, null, 1676 requestID + "RequestProperties.setJAASClientName", 1677 ToCodeArgHelper.createString(jaasClientName, null)); 1678 } 1679 1680 if (configFilePath != null) 1681 { 1682 ToCodeHelper.generateMethodCall(lineList, indentSpaces, null, null, 1683 requestID + "RequestProperties.setConfigFilePath", 1684 ToCodeArgHelper.createString(configFilePath, null)); 1685 } 1686 1687 if (saslClientServerName != null) 1688 { 1689 ToCodeHelper.generateMethodCall(lineList, indentSpaces, null, null, 1690 requestID + "RequestProperties.setSASLClientServerName", 1691 ToCodeArgHelper.createString(saslClientServerName, null)); 1692 } 1693 1694 if (servicePrincipalProtocol != null) 1695 { 1696 ToCodeHelper.generateMethodCall(lineList, indentSpaces, null, null, 1697 requestID + "RequestProperties.setServicePrincipalProtocol", 1698 ToCodeArgHelper.createString(servicePrincipalProtocol, null)); 1699 } 1700 1701 ToCodeHelper.generateMethodCall(lineList, indentSpaces, null, null, 1702 requestID + "RequestProperties.setRefreshKrb5Config", 1703 ToCodeArgHelper.createBoolean(refreshKrb5Config, null)); 1704 1705 ToCodeHelper.generateMethodCall(lineList, indentSpaces, null, null, 1706 requestID + "RequestProperties.setUseKeyTab", 1707 ToCodeArgHelper.createBoolean(useKeyTab, null)); 1708 1709 if (keyTabPath != null) 1710 { 1711 ToCodeHelper.generateMethodCall(lineList, indentSpaces, null, null, 1712 requestID + "RequestProperties.setKeyTabPath", 1713 ToCodeArgHelper.createString(keyTabPath, null)); 1714 } 1715 1716 ToCodeHelper.generateMethodCall(lineList, indentSpaces, null, null, 1717 requestID + "RequestProperties.setUseSubjectCredentialsOnly", 1718 ToCodeArgHelper.createBoolean(useSubjectCredentialsOnly, null)); 1719 1720 ToCodeHelper.generateMethodCall(lineList, indentSpaces, null, null, 1721 requestID + "RequestProperties.setUseTicketCache", 1722 ToCodeArgHelper.createBoolean(useTicketCache, null)); 1723 1724 ToCodeHelper.generateMethodCall(lineList, indentSpaces, null, null, 1725 requestID + "RequestProperties.setRequireCachedCredentials", 1726 ToCodeArgHelper.createBoolean(requireCachedCredentials, null)); 1727 1728 if (ticketCachePath != null) 1729 { 1730 ToCodeHelper.generateMethodCall(lineList, indentSpaces, null, null, 1731 requestID + "RequestProperties.setTicketCachePath", 1732 ToCodeArgHelper.createString(ticketCachePath, null)); 1733 } 1734 1735 ToCodeHelper.generateMethodCall(lineList, indentSpaces, null, null, 1736 requestID + "RequestProperties.setRenewTGT", 1737 ToCodeArgHelper.createBoolean(renewTGT, null)); 1738 1739 if (isInitiator != null) 1740 { 1741 ToCodeHelper.generateMethodCall(lineList, indentSpaces, null, null, 1742 requestID + "RequestProperties.setIsInitiator", 1743 ToCodeArgHelper.createBoolean(isInitiator, null)); 1744 } 1745 1746 if ((suppressedSystemProperties != null) && 1747 (! suppressedSystemProperties.isEmpty())) 1748 { 1749 final ArrayList<ToCodeArgHelper> suppressedArgs = 1750 new ArrayList<>(suppressedSystemProperties.size()); 1751 for (final String s : suppressedSystemProperties) 1752 { 1753 suppressedArgs.add(ToCodeArgHelper.createString(s, null)); 1754 } 1755 1756 ToCodeHelper.generateMethodCall(lineList, indentSpaces, "List<String>", 1757 requestID + "SuppressedProperties", "Arrays.asList", suppressedArgs); 1758 1759 ToCodeHelper.generateMethodCall(lineList, indentSpaces, null, null, 1760 requestID + "RequestProperties.setSuppressedSystemProperties", 1761 ToCodeArgHelper.createRaw(requestID + "SuppressedProperties", null)); 1762 } 1763 1764 ToCodeHelper.generateMethodCall(lineList, indentSpaces, null, null, 1765 requestID + "RequestProperties.setEnableGSSAPIDebugging", 1766 ToCodeArgHelper.createBoolean(enableGSSAPIDebugging, null)); 1767 1768 1769 // Create the request variable. 1770 final ArrayList<ToCodeArgHelper> constructorArgs = new ArrayList<>(2); 1771 constructorArgs.add( 1772 ToCodeArgHelper.createRaw(requestID + "RequestProperties", null)); 1773 1774 final Control[] controls = getControls(); 1775 if (controls.length > 0) 1776 { 1777 constructorArgs.add(ToCodeArgHelper.createControlArray(controls, 1778 "Bind Controls")); 1779 } 1780 1781 ToCodeHelper.generateMethodCall(lineList, indentSpaces, "GSSAPIBindRequest", 1782 requestID + "Request", "new GSSAPIBindRequest", constructorArgs); 1783 1784 1785 // Add lines for processing the request and obtaining the result. 1786 if (includeProcessing) 1787 { 1788 // Generate a string with the appropriate indent. 1789 final StringBuilder buffer = new StringBuilder(); 1790 for (int i=0; i < indentSpaces; i++) 1791 { 1792 buffer.append(' '); 1793 } 1794 final String indent = buffer.toString(); 1795 1796 lineList.add(""); 1797 lineList.add(indent + "try"); 1798 lineList.add(indent + '{'); 1799 lineList.add(indent + " BindResult " + requestID + 1800 "Result = connection.bind(" + requestID + "Request);"); 1801 lineList.add(indent + " // The bind was processed successfully."); 1802 lineList.add(indent + '}'); 1803 lineList.add(indent + "catch (LDAPException e)"); 1804 lineList.add(indent + '{'); 1805 lineList.add(indent + " // The bind failed. Maybe the following will " + 1806 "help explain why."); 1807 lineList.add(indent + " // Note that the connection is now likely in " + 1808 "an unauthenticated state."); 1809 lineList.add(indent + " ResultCode resultCode = e.getResultCode();"); 1810 lineList.add(indent + " String message = e.getMessage();"); 1811 lineList.add(indent + " String matchedDN = e.getMatchedDN();"); 1812 lineList.add(indent + " String[] referralURLs = e.getReferralURLs();"); 1813 lineList.add(indent + " Control[] responseControls = " + 1814 "e.getResponseControls();"); 1815 lineList.add(indent + '}'); 1816 } 1817 } 1818}