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