001/* 002 * Copyright 2011-2024 Ping Identity Corporation 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright 2011-2024 Ping Identity Corporation 007 * 008 * Licensed under the Apache License, Version 2.0 (the "License"); 009 * you may not use this file except in compliance with the License. 010 * You may obtain a copy of the License at 011 * 012 * http://www.apache.org/licenses/LICENSE-2.0 013 * 014 * Unless required by applicable law or agreed to in writing, software 015 * distributed under the License is distributed on an "AS IS" BASIS, 016 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 017 * See the License for the specific language governing permissions and 018 * limitations under the License. 019 */ 020/* 021 * Copyright (C) 2011-2024 Ping Identity Corporation 022 * 023 * This program is free software; you can redistribute it and/or modify 024 * it under the terms of the GNU General Public License (GPLv2 only) 025 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only) 026 * as published by the Free Software Foundation. 027 * 028 * This program is distributed in the hope that it will be useful, 029 * but WITHOUT ANY WARRANTY; without even the implied warranty of 030 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 031 * GNU General Public License for more details. 032 * 033 * You should have received a copy of the GNU General Public License 034 * along with this program; if not, see <http://www.gnu.org/licenses>. 035 */ 036package com.unboundid.ldap.sdk; 037 038 039 040import java.io.Serializable; 041import java.util.ArrayList; 042import java.util.Collection; 043import java.util.Collections; 044import java.util.Iterator; 045import java.util.LinkedHashSet; 046import java.util.List; 047import java.util.Set; 048 049import com.unboundid.asn1.ASN1OctetString; 050import com.unboundid.util.CryptoHelper; 051import com.unboundid.util.Debug; 052import com.unboundid.util.Mutable; 053import com.unboundid.util.NotNull; 054import com.unboundid.util.Nullable; 055import com.unboundid.util.StaticUtils; 056import com.unboundid.util.ThreadSafety; 057import com.unboundid.util.ThreadSafetyLevel; 058import com.unboundid.util.Validator; 059import com.unboundid.util.json.JSONBuffer; 060 061import static com.unboundid.ldap.sdk.LDAPMessages.*; 062 063 064 065/** 066 * This class provides a data structure that may be used to hold a number of 067 * properties that may be used during processing for a SASL GSSAPI bind 068 * operation. 069 */ 070@Mutable() 071@ThreadSafety(level=ThreadSafetyLevel.NOT_THREADSAFE) 072public final class GSSAPIBindRequestProperties 073 implements Serializable 074{ 075 /** 076 * The serial version UID for this serializable class. 077 */ 078 private static final long serialVersionUID = 6872295509330315713L; 079 080 081 082 // The password for the GSSAPI bind request. 083 @Nullable private ASN1OctetString password; 084 085 // Indicates whether to enable JVM-level debugging for GSSAPI processing. 086 private boolean enableGSSAPIDebugging; 087 088 // Indicates whether the client should be considered the GSSAPI initiator or 089 // the acceptor. 090 @Nullable private Boolean isInitiator; 091 092 // Indicates whether to attempt to refresh the configuration before the JAAS 093 // login method is called. 094 private boolean refreshKrb5Config; 095 096 // Indicates whether to attempt to renew the client's existing ticket-granting 097 // ticket if authentication uses an existing Kerberos session. 098 private boolean renewTGT; 099 100 // Indicates whether to require that the credentials be obtained from the 101 // ticket cache such that authentication will fail if the client does not have 102 // an existing Kerberos session. 103 private boolean requireCachedCredentials; 104 105 // Indicates whether to allow the to obtain the credentials to be obtained 106 // from a keytab. 107 private boolean useKeyTab; 108 109 // Indicates whether to allow the client to use credentials that are outside 110 // of the current subject. 111 private boolean useSubjectCredentialsOnly; 112 113 // Indicates whether to enable the use of a ticket cache. 114 private boolean useTicketCache; 115 116 // A digest of the settings that are relevant to a JAAS configuration file. 117 @Nullable private byte[] configFileDigest; 118 119 // The type of channel binding to use for the bind request. 120 @NotNull private GSSAPIChannelBindingType channelBindingType; 121 122 // The SASL quality of protection value(s) allowed for the GSSAPI bind 123 // request. 124 @NotNull private List<SASLQualityOfProtection> allowedQoP; 125 126 // The names of any system properties that should not be altered by GSSAPI 127 // processing. 128 @NotNull private Set<String> suppressedSystemProperties; 129 130 // The authentication ID string for the GSSAPI bind request. 131 @Nullable private String authenticationID; 132 133 // The authorization ID string for the GSSAPI bind request, if available. 134 @Nullable private String authorizationID; 135 136 // The path to the JAAS configuration file to use for bind processing. 137 @Nullable private String configFilePath; 138 139 // The name that will be used to identify this client in the JAAS framework. 140 @NotNull private String jaasClientName; 141 142 // The KDC address for the GSSAPI bind request, if available. 143 @Nullable private String kdcAddress; 144 145 // The path to the keytab file to use if useKeyTab is true. 146 @Nullable private String keyTabPath; 147 148 // The realm for the GSSAPI bind request, if available. 149 @Nullable private String realm; 150 151 // The server name to use when creating the SASL client. 152 @Nullable private String saslClientServerName; 153 154 // The protocol that should be used in the Kerberos service principal for 155 // the server system. 156 @NotNull private String servicePrincipalProtocol; 157 158 // The path to the Kerberos ticket cache to use. 159 @Nullable private String ticketCachePath; 160 161 162 163 /** 164 * Creates a new set of GSSAPI bind request properties with the provided 165 * information. 166 * 167 * @param authenticationID The authentication ID for the GSSAPI bind 168 * request. It may be {@code null} if an existing 169 * Kerberos session should be used. 170 * @param password The password for the GSSAPI bind request. It may 171 * be {@code null} if an existing Kerberos session 172 * should be used. 173 */ 174 public GSSAPIBindRequestProperties(@Nullable final String authenticationID, 175 @Nullable final String password) 176 { 177 this(authenticationID, null, 178 (password == null ? null : new ASN1OctetString(password)), null, null, 179 null); 180 } 181 182 183 184 /** 185 * Creates a new set of GSSAPI bind request properties with the provided 186 * information. 187 * 188 * @param authenticationID The authentication ID for the GSSAPI bind 189 * request. It may be {@code null} if an existing 190 * Kerberos session should be used. 191 * @param password The password for the GSSAPI bind request. It may 192 * be {@code null} if an existing Kerberos session 193 * should be used. 194 */ 195 public GSSAPIBindRequestProperties(@Nullable final String authenticationID, 196 @Nullable final byte[] password) 197 { 198 this(authenticationID, null, 199 (password == null ? null : new ASN1OctetString(password)), null, null, 200 null); 201 } 202 203 204 205 /** 206 * Creates a new set of GSSAPI bind request properties with the provided 207 * information. 208 * 209 * @param authenticationID The authentication ID for the GSSAPI bind 210 * request. It may be {@code null} if an existing 211 * Kerberos session should be used. 212 * @param authorizationID The authorization ID for the GSSAPI bind request. 213 * It may be {@code null} if the authorization ID 214 * should be the same as the authentication ID. 215 * @param password The password for the GSSAPI bind request. It may 216 * be {@code null} if an existing Kerberos session 217 * should be used. 218 * @param realm The realm to use for the authentication. It may 219 * be {@code null} to attempt to use the default 220 * realm from the system configuration. 221 * @param kdcAddress The address of the Kerberos key distribution 222 * center. It may be {@code null} to attempt to use 223 * the default KDC from the system configuration. 224 * @param configFilePath The path to the JAAS configuration file to use 225 * for the authentication processing. It may be 226 * {@code null} to use the default JAAS 227 * configuration. 228 */ 229 GSSAPIBindRequestProperties(@Nullable final String authenticationID, 230 @Nullable final String authorizationID, 231 @Nullable final ASN1OctetString password, 232 @Nullable final String realm, 233 @Nullable final String kdcAddress, 234 @Nullable final String configFilePath) 235 { 236 this.authenticationID = authenticationID; 237 this.authorizationID = authorizationID; 238 this.password = password; 239 this.realm = realm; 240 this.kdcAddress = kdcAddress; 241 this.configFilePath = configFilePath; 242 243 servicePrincipalProtocol = "ldap"; 244 enableGSSAPIDebugging = false; 245 jaasClientName = "GSSAPIBindRequest"; 246 isInitiator = null; 247 refreshKrb5Config = false; 248 renewTGT = false; 249 useKeyTab = false; 250 useSubjectCredentialsOnly = true; 251 useTicketCache = true; 252 requireCachedCredentials = false; 253 saslClientServerName = null; 254 keyTabPath = null; 255 ticketCachePath = null; 256 suppressedSystemProperties = Collections.emptySet(); 257 allowedQoP = 258 Collections.singletonList(SASLQualityOfProtection.AUTH); 259 channelBindingType = GSSAPIChannelBindingType.NONE; 260 } 261 262 263 264 /** 265 * Retrieves the authentication ID for the GSSAPI bind request, if defined. 266 * 267 * @return The authentication ID for the GSSAPI bind request, or {@code null} 268 * if an existing Kerberos session should be used. 269 */ 270 @Nullable() 271 public String getAuthenticationID() 272 { 273 return authenticationID; 274 } 275 276 277 278 /** 279 * Sets the authentication ID for the GSSAPI bind request. 280 * 281 * @param authenticationID The authentication ID for the GSSAPI bind 282 * request. It may be {@code null} if an existing 283 * Kerberos session should be used. 284 */ 285 public void setAuthenticationID(@Nullable final String authenticationID) 286 { 287 this.authenticationID = authenticationID; 288 } 289 290 291 292 /** 293 * Retrieves the authorization ID for the GSSAPI bind request, if defined. 294 * 295 * @return The authorizationID for the GSSAPI bind request, or {@code null} 296 * if the authorization ID should be the same as the authentication 297 * ID. 298 */ 299 @Nullable() 300 public String getAuthorizationID() 301 { 302 return authorizationID; 303 } 304 305 306 307 /** 308 * Specifies the authorization ID for the GSSAPI bind request. 309 * 310 * @param authorizationID The authorization ID for the GSSAPI bind request. 311 * It may be {@code null} if the authorization ID 312 * should be the same as the authentication ID. 313 */ 314 public void setAuthorizationID(@Nullable final String authorizationID) 315 { 316 this.authorizationID = authorizationID; 317 } 318 319 320 321 /** 322 * Retrieves the password that should be used for the GSSAPI bind request, if 323 * defined. 324 * 325 * @return The password that should be used for the GSSAPI bind request, or 326 * {@code null} if an existing Kerberos session should be used. 327 */ 328 @Nullable() 329 public ASN1OctetString getPassword() 330 { 331 return password; 332 } 333 334 335 336 /** 337 * Specifies the password that should be used for the GSSAPI bind request. 338 * 339 * @param password The password that should be used for the GSSAPI bind 340 * request. It may be {@code null} if an existing 341 * Kerberos session should be used. 342 */ 343 public void setPassword(@Nullable final String password) 344 { 345 if (password == null) 346 { 347 this.password = null; 348 } 349 else 350 { 351 this.password = new ASN1OctetString(password); 352 } 353 } 354 355 356 357 /** 358 * Specifies the password that should be used for the GSSAPI bind request. 359 * 360 * @param password The password that should be used for the GSSAPI bind 361 * request. It may be {@code null} if an existing 362 * Kerberos session should be used. 363 */ 364 public void setPassword(@Nullable final byte[] password) 365 { 366 if (password == null) 367 { 368 this.password = null; 369 } 370 else 371 { 372 this.password = new ASN1OctetString(password); 373 } 374 } 375 376 377 378 /** 379 * Specifies the password that should be used for the GSSAPI bind request. 380 * 381 * @param password The password that should be used for the GSSAPI bind 382 * request. It may be {@code null} if an existing 383 * Kerberos session should be used. 384 */ 385 public void setPassword(@Nullable final ASN1OctetString password) 386 { 387 this.password = password; 388 } 389 390 391 392 /** 393 * Retrieves the realm to use for the GSSAPI bind request, if defined. 394 * 395 * @return The realm to use for the GSSAPI bind request, or {@code null} if 396 * the request should attempt to use the default realm from the 397 * system configuration. 398 */ 399 @Nullable() 400 public String getRealm() 401 { 402 return realm; 403 } 404 405 406 407 /** 408 * Specifies the realm to use for the GSSAPI bind request. 409 * 410 * @param realm The realm to use for the GSSAPI bind request. It may be 411 * {@code null} if the request should attempt to use the 412 * default realm from the system configuration. 413 */ 414 public void setRealm(@Nullable final String realm) 415 { 416 this.realm = realm; 417 } 418 419 420 421 /** 422 * Retrieves the list of allowed qualities of protection that may be used for 423 * communication that occurs on the connection after the authentication has 424 * completed, in order from most preferred to least preferred. 425 * 426 * @return The list of allowed qualities of protection that may be used for 427 * communication that occurs on the connection after the 428 * authentication has completed, in order from most preferred to 429 * least preferred. 430 */ 431 @NotNull() 432 public List<SASLQualityOfProtection> getAllowedQoP() 433 { 434 return allowedQoP; 435 } 436 437 438 439 /** 440 * Specifies the list of allowed qualities of protection that may be used for 441 * communication that occurs on the connection after the authentication has 442 * completed, in order from most preferred to least preferred. 443 * 444 * @param allowedQoP The list of allowed qualities of protection that may be 445 * used for communication that occurs on the connection 446 * after the authentication has completed, in order from 447 * most preferred to least preferred. If this is 448 * {@code null} or empty, then a list containing only the 449 * {@link SASLQualityOfProtection#AUTH} quality of 450 * protection value will be used. 451 */ 452 public void setAllowedQoP( 453 @Nullable final List<SASLQualityOfProtection> allowedQoP) 454 { 455 if ((allowedQoP == null) || allowedQoP.isEmpty()) 456 { 457 this.allowedQoP = Collections.singletonList(SASLQualityOfProtection.AUTH); 458 } 459 else 460 { 461 this.allowedQoP = 462 Collections.unmodifiableList(new ArrayList<>(allowedQoP)); 463 } 464 } 465 466 467 468 /** 469 * Specifies the list of allowed qualities of protection that may be used for 470 * communication that occurs on the connection after the authentication has 471 * completed, in order from most preferred to least preferred. 472 * 473 * @param allowedQoP The list of allowed qualities of protection that may be 474 * used for communication that occurs on the connection 475 * after the authentication has completed, in order from 476 * most preferred to least preferred. If this is 477 * {@code null} or empty, then a list containing only the 478 * {@link SASLQualityOfProtection#AUTH} quality of 479 * protection value will be used. 480 */ 481 public void setAllowedQoP( 482 @Nullable final SASLQualityOfProtection... allowedQoP) 483 { 484 setAllowedQoP(StaticUtils.toList(allowedQoP)); 485 } 486 487 488 489 /** 490 * Retrieves the address to use for the Kerberos key distribution center, 491 * if defined. 492 * 493 * @return The address to use for the Kerberos key distribution center, or 494 * {@code null} if request should attempt to determine the KDC 495 * address from the system configuration. 496 */ 497 @Nullable() 498 public String getKDCAddress() 499 { 500 return kdcAddress; 501 } 502 503 504 505 /** 506 * Specifies the address to use for the Kerberos key distribution center. 507 * 508 * @param kdcAddress The address to use for the Kerberos key distribution 509 * center. It may be {@code null} if the request should 510 * attempt to determine the KDC address from the system 511 * configuration. 512 */ 513 public void setKDCAddress(@Nullable final String kdcAddress) 514 { 515 this.kdcAddress = kdcAddress; 516 } 517 518 519 520 /** 521 * Retrieves the name that will be used to identify this client in the JAAS 522 * framework. 523 * 524 * @return The name that will be used to identify this client in the JAAS 525 * framework. 526 */ 527 @NotNull() 528 public String getJAASClientName() 529 { 530 return jaasClientName; 531 } 532 533 534 535 /** 536 * Specifies the name that will be used to identify this client in the JAAS 537 * framework. 538 * 539 * @param jaasClientName The name that will be used to identify this client 540 * in the JAAS framework. It must not be 541 * {@code null} or empty. 542 */ 543 public void setJAASClientName(@NotNull final String jaasClientName) 544 { 545 Validator.ensureNotNull(jaasClientName); 546 547 this.jaasClientName = jaasClientName; 548 configFileDigest = null; 549 } 550 551 552 553 /** 554 * Retrieves the path to a JAAS configuration file that should be used when 555 * processing the GSSAPI bind request, if defined. 556 * 557 * @return The path to a JAAS configuration file that should be used when 558 * processing the GSSAPI bind request, or {@code null} if a JAAS 559 * configuration file should be automatically constructed for the 560 * bind request. 561 */ 562 @Nullable() 563 public String getConfigFilePath() 564 { 565 return configFilePath; 566 } 567 568 569 570 /** 571 * Specifies the path to a JAAS configuration file that should be used when 572 * processing the GSSAPI bind request. 573 * 574 * @param configFilePath The path to a JAAS configuration file that should 575 * be used when processing the GSSAPI bind request. 576 * It may be {@code null} if a configuration file 577 * should be automatically constructed for the bind 578 * request. 579 */ 580 public void setConfigFilePath(@Nullable final String configFilePath) 581 { 582 this.configFilePath = configFilePath; 583 } 584 585 586 587 /** 588 * Retrieves the server name that should be used when creating the Java 589 * {@code SaslClient}, if one is defined. 590 * 591 * @return The server name that should be used when creating the Java 592 * {@code SaslClient}, or {@code null} if none is defined and the 593 * {@code SaslClient} should use the address specified when 594 * establishing the connection. 595 */ 596 @Nullable() 597 public String getSASLClientServerName() 598 { 599 return saslClientServerName; 600 } 601 602 603 604 /** 605 * Specifies the server name that should be used when creating the Java 606 * {@code SaslClient}. 607 * 608 * @param saslClientServerName The server name that should be used when 609 * creating the Java {@code SaslClient}. It may 610 * be {@code null} to indicate that the 611 * {@code SaslClient} should use the address 612 * specified when establishing the connection. 613 */ 614 public void setSASLClientServerName( 615 @Nullable final String saslClientServerName) 616 { 617 this.saslClientServerName = saslClientServerName; 618 } 619 620 621 622 /** 623 * Retrieves the protocol specified in the service principal that the 624 * directory server uses for its communication with the KDC. The service 625 * principal is usually something like "ldap/directory.example.com", where 626 * "ldap" is the protocol and "directory.example.com" is the fully-qualified 627 * address of the directory server system, but some servers may allow 628 * authentication with a service principal with a protocol other than "ldap". 629 * 630 * @return The protocol specified in the service principal that the directory 631 * server uses for its communication with the KDC. 632 */ 633 @NotNull() 634 public String getServicePrincipalProtocol() 635 { 636 return servicePrincipalProtocol; 637 } 638 639 640 641 /** 642 * Specifies the protocol specified in the service principal that the 643 * directory server uses for its communication with the KDC. This should 644 * generally be "ldap", but some servers may allow a service principal with a 645 * protocol other than "ldap". 646 * 647 * @param servicePrincipalProtocol The protocol specified in the service 648 * principal that the directory server uses 649 * for its communication with the KDC. 650 */ 651 public void setServicePrincipalProtocol( 652 @NotNull final String servicePrincipalProtocol) 653 { 654 Validator.ensureNotNull(servicePrincipalProtocol); 655 656 this.servicePrincipalProtocol = servicePrincipalProtocol; 657 } 658 659 660 661 /** 662 * Indicates whether to refresh the configuration before the JAAS 663 * {@code login} method is called. 664 * 665 * @return {@code true} if the GSSAPI implementation should refresh the 666 * configuration before the JAAS {@code login} method is called, or 667 * {@code false} if not. 668 */ 669 public boolean refreshKrb5Config() 670 { 671 return refreshKrb5Config; 672 } 673 674 675 676 /** 677 * Specifies whether to refresh the configuration before the JAAS 678 * {@code login} method is called. 679 * 680 * @param refreshKrb5Config Indicates whether to refresh the configuration 681 * before the JAAS {@code login} method is called. 682 */ 683 public void setRefreshKrb5Config(final boolean refreshKrb5Config) 684 { 685 this.refreshKrb5Config = refreshKrb5Config; 686 configFileDigest = null; 687 } 688 689 690 691 /** 692 * Indicates whether to allow the client to use credentials that are outside 693 * of the current subject, obtained via some system-specific mechanism. 694 * 695 * @return {@code true} if the client will only be allowed to use credentials 696 * that are within the current subject, or {@code false} if the 697 * client will be allowed to use credentials outside the current 698 * subject. 699 */ 700 public boolean useSubjectCredentialsOnly() 701 { 702 return useSubjectCredentialsOnly; 703 } 704 705 706 707 /** 708 * Specifies whether to allow the client to use credentials that are outside 709 * the current subject. If this is {@code false}, then a system-specific 710 * mechanism may be used in an attempt to obtain credentials from an 711 * existing session. 712 * 713 * @param useSubjectCredentialsOnly Indicates whether to allow the client to 714 * use credentials that are outside of the 715 * current subject. 716 */ 717 public void setUseSubjectCredentialsOnly( 718 final boolean useSubjectCredentialsOnly) 719 { 720 this.useSubjectCredentialsOnly = useSubjectCredentialsOnly; 721 } 722 723 724 725 /** 726 * Indicates whether to use a keytab to obtain the user credentials. 727 * 728 * @return {@code true} if the GSSAPI login attempt should use a keytab to 729 * obtain the user credentials, or {@code false} if not. 730 */ 731 public boolean useKeyTab() 732 { 733 return useKeyTab; 734 } 735 736 737 738 /** 739 * Specifies whether to use a keytab to obtain the user credentials. 740 * 741 * @param useKeyTab Indicates whether to use a keytab to obtain the user 742 * credentials. 743 */ 744 public void setUseKeyTab(final boolean useKeyTab) 745 { 746 this.useKeyTab = useKeyTab; 747 configFileDigest = null; 748 } 749 750 751 752 /** 753 * Retrieves the path to the keytab file from which to obtain the user 754 * credentials. This will only be used if {@link #useKeyTab} returns 755 * {@code true}. 756 * 757 * @return The path to the keytab file from which to obtain the user 758 * credentials, or {@code null} if the default keytab location should 759 * be used. 760 */ 761 @Nullable() 762 public String getKeyTabPath() 763 { 764 return keyTabPath; 765 } 766 767 768 769 /** 770 * Specifies the path to the keytab file from which to obtain the user 771 * credentials. 772 * 773 * @param keyTabPath The path to the keytab file from which to obtain the 774 * user credentials. It may be {@code null} if the 775 * default keytab location should be used. 776 */ 777 public void setKeyTabPath(@Nullable final String keyTabPath) 778 { 779 this.keyTabPath = keyTabPath; 780 configFileDigest = null; 781 } 782 783 784 785 /** 786 * Indicates whether to enable the use of a ticket cache to to avoid the need 787 * to supply credentials if the client already has an existing Kerberos 788 * session. 789 * 790 * @return {@code true} if a ticket cache may be used to take advantage of an 791 * existing Kerberos session, or {@code false} if Kerberos 792 * credentials should always be provided. 793 */ 794 public boolean useTicketCache() 795 { 796 return useTicketCache; 797 } 798 799 800 801 /** 802 * Specifies whether to enable the use of a ticket cache to to avoid the need 803 * to supply credentials if the client already has an existing Kerberos 804 * session. 805 * 806 * @param useTicketCache Indicates whether to enable the use of a ticket 807 * cache to to avoid the need to supply credentials if 808 * the client already has an existing Kerberos 809 * session. 810 */ 811 public void setUseTicketCache(final boolean useTicketCache) 812 { 813 this.useTicketCache = useTicketCache; 814 configFileDigest = null; 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 * Specifies whether an GSSAPI authentication should only occur using an 837 * existing Kerberos session. 838 * 839 * @param requireCachedCredentials Indicates whether an existing Kerberos 840 * session will be required for 841 * authentication. If {@code true}, then 842 * authentication will fail if the client 843 * does not already have an existing 844 * Kerberos session. This will be ignored 845 * if {@code useTicketCache} is false. 846 */ 847 public void setRequireCachedCredentials( 848 final boolean requireCachedCredentials) 849 { 850 this.requireCachedCredentials = requireCachedCredentials; 851 configFileDigest = null; 852 } 853 854 855 856 /** 857 * Retrieves the path to the Kerberos ticket cache file that should be used 858 * during authentication, if defined. 859 * 860 * @return The path to the Kerberos ticket cache file that should be used 861 * during authentication, or {@code null} if the default ticket cache 862 * file should be used. 863 */ 864 @Nullable() 865 public String getTicketCachePath() 866 { 867 return ticketCachePath; 868 } 869 870 871 872 /** 873 * Specifies the path to the Kerberos ticket cache file that should be used 874 * during authentication. 875 * 876 * @param ticketCachePath The path to the Kerberos ticket cache file that 877 * should be used during authentication. It may be 878 * {@code null} if the default ticket cache file 879 * should be used. 880 */ 881 public void setTicketCachePath(@Nullable final String ticketCachePath) 882 { 883 this.ticketCachePath = ticketCachePath; 884 configFileDigest = null; 885 } 886 887 888 889 /** 890 * Indicates whether to attempt to renew the client's ticket-granting ticket 891 * (TGT) if an existing Kerberos session is used to authenticate. 892 * 893 * @return {@code true} if the client should attempt to renew its 894 * ticket-granting ticket if the authentication is processed using an 895 * existing Kerberos session, or {@code false} if not. 896 */ 897 public boolean renewTGT() 898 { 899 return renewTGT; 900 } 901 902 903 904 /** 905 * Specifies whether to attempt to renew the client's ticket-granting ticket 906 * (TGT) if an existing Kerberos session is used to authenticate. 907 * 908 * @param renewTGT Indicates whether to attempt to renew the client's 909 * ticket-granting ticket if an existing Kerberos session is 910 * used to authenticate. 911 */ 912 public void setRenewTGT(final boolean renewTGT) 913 { 914 this.renewTGT = renewTGT; 915 configFileDigest = null; 916 } 917 918 919 920 /** 921 * Indicates whether the client should be configured so that it explicitly 922 * indicates whether it is the initiator or the acceptor. 923 * 924 * @return {@code Boolean.TRUE} if the client should explicitly indicate that 925 * it is the GSSAPI initiator, {@code Boolean.FALSE} if the client 926 * should explicitly indicate that it is the GSSAPI acceptor, or 927 * {@code null} if the client should not explicitly indicate either 928 * state (which is the default if the {@link #setIsInitiator} method 929 * has not been called). 930 */ 931 @Nullable() 932 public Boolean getIsInitiator() 933 { 934 return isInitiator; 935 } 936 937 938 939 /** 940 * Specifies whether the client should explicitly indicate whether it is the 941 * GSSAPI initiator or acceptor. 942 * 943 * @param isInitiator Indicates whether the client should be considered the 944 * GSSAPI initiator. A value of {@code Boolean.TRUE} 945 * means the client should explicitly indicate that it is 946 * the GSSAPI initiator. A value of 947 * {@code Boolean.FALSE} means the client should 948 * explicitly indicate that it is the GSSAPI acceptor. A 949 * value of {@code null} means that the client will not 950 * explicitly indicate one way or the other (although 951 * this behavior will only apply to Sun/Oracle-based 952 * implementations; on the IBM implementation, the client 953 * will always be the initiator unless explicitly 954 * configured otherwise). 955 */ 956 public void setIsInitiator(@Nullable final Boolean isInitiator) 957 { 958 this.isInitiator = isInitiator; 959 configFileDigest = null; 960 } 961 962 963 964 /** 965 * Retrieves the type of channel binding that should be used for the GSSAPI 966 * bind request. 967 * 968 * @return The type of channel binding that should be used for the GSSAPI 969 * bind request. 970 */ 971 @NotNull() 972 public GSSAPIChannelBindingType getChannelBindingType() 973 { 974 return channelBindingType; 975 } 976 977 978 979 /** 980 * Specifies the type of channel binding that should be used for the GSSAPI 981 * bind request. Note that channel binding support is dependent upon the 982 * underlying JVM and may not be available in all cases. 983 * 984 * @param channelBindingType The type of channel binding that should be used 985 * for the GSSAPI bind request. It may be 986 * {@code null} or {@code NONE} if no channel 987 * binding should be used. 988 */ 989 public void setChannelBindingType( 990 @Nullable final GSSAPIChannelBindingType channelBindingType) 991 { 992 if (channelBindingType == null) 993 { 994 this.channelBindingType = GSSAPIChannelBindingType.NONE; 995 } 996 else 997 { 998 this.channelBindingType = channelBindingType; 999 } 1000 } 1001 1002 1003 1004 /** 1005 * Retrieves a set of system properties that will not be altered by GSSAPI 1006 * processing. 1007 * 1008 * @return A set of system properties that will not be altered by GSSAPI 1009 * processing. 1010 */ 1011 @NotNull() 1012 public Set<String> getSuppressedSystemProperties() 1013 { 1014 return suppressedSystemProperties; 1015 } 1016 1017 1018 1019 /** 1020 * Specifies a set of system properties that will not be altered by GSSAPI 1021 * processing. This should generally only be used in cases in which the 1022 * specified system properties are known to already be set correctly for the 1023 * desired authentication processing. 1024 * 1025 * @param suppressedSystemProperties A set of system properties that will 1026 * not be altered by GSSAPI processing. 1027 * It may be {@code null} or empty to 1028 * indicate that no properties should be 1029 * suppressed. 1030 */ 1031 public void setSuppressedSystemProperties( 1032 @Nullable final Collection<String> suppressedSystemProperties) 1033 { 1034 if (suppressedSystemProperties == null) 1035 { 1036 this.suppressedSystemProperties = Collections.emptySet(); 1037 } 1038 else 1039 { 1040 this.suppressedSystemProperties = Collections.unmodifiableSet( 1041 new LinkedHashSet<>(suppressedSystemProperties)); 1042 } 1043 } 1044 1045 1046 1047 /** 1048 * Indicates whether JVM-level debugging should be enabled for GSSAPI bind 1049 * processing. If this is enabled, then debug information may be written to 1050 * standard error when performing GSSAPI processing that could be useful for 1051 * debugging authentication problems. 1052 * 1053 * @return {@code true} if JVM-level debugging should be enabled for GSSAPI 1054 * bind processing, or {@code false} if not. 1055 */ 1056 public boolean enableGSSAPIDebugging() 1057 { 1058 return enableGSSAPIDebugging; 1059 } 1060 1061 1062 1063 /** 1064 * Specifies whether JVM-level debugging should be enabled for GSSAPI bind 1065 * processing. If this is enabled, then debug information may be written to 1066 * standard error when performing GSSAPI processing that could be useful for 1067 * debugging authentication problems. 1068 * 1069 * @param enableGSSAPIDebugging Specifies whether JVM-level debugging should 1070 * be enabled for GSSAPI bind processing. 1071 */ 1072 public void setEnableGSSAPIDebugging(final boolean enableGSSAPIDebugging) 1073 { 1074 this.enableGSSAPIDebugging = enableGSSAPIDebugging; 1075 configFileDigest = null; 1076 } 1077 1078 1079 1080 /** 1081 * Retrieves a digest of the settings that are relevant to a JAAS 1082 * configuration file generated from these properties. 1083 * 1084 * @return A digest of the settings that are relevant to a JAAS configuration 1085 * file generated from these properties. 1086 * 1087 * @throws LDAPException If a problem occurs while attempting to generate 1088 * the digest. 1089 */ 1090 @NotNull() 1091 byte[] getConfigFileDigest() 1092 throws LDAPException 1093 { 1094 // If we have previously generated a digest from the current settings, then 1095 // just return that. 1096 if (configFileDigest != null) 1097 { 1098 return configFileDigest; 1099 } 1100 1101 1102 // Generate a JSON object from the relevant settings. 1103 final JSONBuffer buffer = new JSONBuffer(); 1104 buffer.beginObject(); 1105 buffer.appendString("jaasClientName", jaasClientName); 1106 1107 if (isInitiator != null) 1108 { 1109 buffer.appendBoolean("isInitiator", isInitiator); 1110 } 1111 1112 buffer.appendBoolean("refreshKrb5Config", refreshKrb5Config); 1113 buffer.appendBoolean("useKeyTab", useKeyTab); 1114 1115 if (keyTabPath != null) 1116 { 1117 buffer.appendString("keyTabPath", keyTabPath); 1118 } 1119 1120 buffer.appendBoolean("useTicketCache", useTicketCache); 1121 buffer.appendBoolean("renewTGT", renewTGT); 1122 buffer.appendBoolean("requireCachedCredentials", requireCachedCredentials); 1123 1124 if (ticketCachePath != null) 1125 { 1126 buffer.appendString("ticketCachePath", ticketCachePath); 1127 } 1128 1129 buffer.appendBoolean("enableGSSAPIDebugging", enableGSSAPIDebugging); 1130 buffer.endObject(); 1131 1132 1133 // Generate, cache, and return a 256-bit SHA digest of the JSON object. 1134 try 1135 { 1136 final byte[] bufferBytes = buffer.getBuffer().toByteArray(); 1137 configFileDigest = CryptoHelper.sha256(bufferBytes); 1138 return configFileDigest; 1139 } 1140 catch (final Exception e) 1141 { 1142 Debug.debugException(e); 1143 throw new LDAPException(ResultCode.LOCAL_ERROR, 1144 ERR_GSSAPI_PROPERTIES_CANNOT_COMPUTE_DIGEST.get( 1145 StaticUtils.getExceptionMessage(e)), 1146 e); 1147 1148 } 1149 } 1150 1151 1152 1153 /** 1154 * Retrieves a string representation of the GSSAPI bind request properties. 1155 * 1156 * @return A string representation of the GSSAPI bind request properties. 1157 */ 1158 @Override() 1159 @NotNull() 1160 public String toString() 1161 { 1162 final StringBuilder buffer = new StringBuilder(); 1163 toString(buffer); 1164 return buffer.toString(); 1165 } 1166 1167 1168 1169 /** 1170 * Appends a string representation of the GSSAPI bind request properties to 1171 * the provided buffer. 1172 * 1173 * @param buffer The buffer to which the information should be appended. 1174 */ 1175 public void toString(@NotNull final StringBuilder buffer) 1176 { 1177 buffer.append("GSSAPIBindRequestProperties("); 1178 if (authenticationID != null) 1179 { 1180 buffer.append("authenticationID='"); 1181 buffer.append(authenticationID); 1182 buffer.append("', "); 1183 } 1184 1185 if (authorizationID != null) 1186 { 1187 buffer.append("authorizationID='"); 1188 buffer.append(authorizationID); 1189 buffer.append("', "); 1190 } 1191 1192 if (realm != null) 1193 { 1194 buffer.append("realm='"); 1195 buffer.append(realm); 1196 buffer.append("', "); 1197 } 1198 1199 buffer.append("qop='"); 1200 buffer.append(SASLQualityOfProtection.toString(allowedQoP)); 1201 buffer.append("', "); 1202 1203 if (kdcAddress != null) 1204 { 1205 buffer.append("kdcAddress='"); 1206 buffer.append(kdcAddress); 1207 buffer.append("', "); 1208 } 1209 1210 buffer.append(", refreshKrb5Config="); 1211 buffer.append(refreshKrb5Config); 1212 buffer.append(", useSubjectCredentialsOnly="); 1213 buffer.append(useSubjectCredentialsOnly); 1214 buffer.append(", useKeyTab="); 1215 buffer.append(useKeyTab); 1216 buffer.append(", "); 1217 1218 if (keyTabPath != null) 1219 { 1220 buffer.append("keyTabPath='"); 1221 buffer.append(keyTabPath); 1222 buffer.append("', "); 1223 } 1224 1225 if (useTicketCache) 1226 { 1227 buffer.append("useTicketCache=true, requireCachedCredentials="); 1228 buffer.append(requireCachedCredentials); 1229 buffer.append(", renewTGT="); 1230 buffer.append(renewTGT); 1231 buffer.append(", "); 1232 1233 if (ticketCachePath != null) 1234 { 1235 buffer.append("ticketCachePath='"); 1236 buffer.append(ticketCachePath); 1237 buffer.append("', "); 1238 } 1239 } 1240 else 1241 { 1242 buffer.append("useTicketCache=false, "); 1243 } 1244 1245 if (isInitiator != null) 1246 { 1247 buffer.append("isInitiator="); 1248 buffer.append(isInitiator); 1249 buffer.append(", "); 1250 } 1251 1252 buffer.append("jaasClientName='"); 1253 buffer.append(jaasClientName); 1254 buffer.append("', "); 1255 1256 if (configFilePath != null) 1257 { 1258 buffer.append("configFilePath='"); 1259 buffer.append(configFilePath); 1260 buffer.append("', "); 1261 } 1262 1263 if (saslClientServerName != null) 1264 { 1265 buffer.append("saslClientServerName='"); 1266 buffer.append(saslClientServerName); 1267 buffer.append("', "); 1268 } 1269 1270 buffer.append("servicePrincipalProtocol='"); 1271 buffer.append(servicePrincipalProtocol); 1272 buffer.append("', channelBindingType='"); 1273 buffer.append(channelBindingType.getName()); 1274 buffer.append("', suppressedSystemProperties={"); 1275 1276 final Iterator<String> propIterator = suppressedSystemProperties.iterator(); 1277 while (propIterator.hasNext()) 1278 { 1279 buffer.append('\''); 1280 buffer.append(propIterator.next()); 1281 buffer.append('\''); 1282 1283 if (propIterator.hasNext()) 1284 { 1285 buffer.append(", "); 1286 } 1287 } 1288 1289 buffer.append("}, enableGSSAPIDebugging="); 1290 buffer.append(enableGSSAPIDebugging); 1291 buffer.append(')'); 1292 } 1293} 1294