001    /*
002     * Copyright 2011-2014 UnboundID Corp.
003     * All Rights Reserved.
004     */
005    /*
006     * Copyright (C) 2011-2014 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     */
021    package com.unboundid.ldap.sdk;
022    
023    
024    
025    import java.io.Serializable;
026    import java.util.ArrayList;
027    import java.util.Arrays;
028    import java.util.Collections;
029    import java.util.List;
030    
031    import com.unboundid.asn1.ASN1OctetString;
032    import com.unboundid.util.Mutable;
033    import com.unboundid.util.StaticUtils;
034    import com.unboundid.util.ThreadSafety;
035    import com.unboundid.util.ThreadSafetyLevel;
036    import com.unboundid.util.Validator;
037    
038    
039    
040    /**
041     * This class provides a data structure that may be used to hold a number of
042     * properties that may be used during processing for a SASL GSSAPI bind
043     * operation.
044     */
045    @Mutable()
046    @ThreadSafety(level=ThreadSafetyLevel.NOT_THREADSAFE)
047    public final class GSSAPIBindRequestProperties
048           implements Serializable
049    {
050      /**
051       * The serial version UID for this serializable class.
052       */
053      private static final long serialVersionUID = 6872295509330315713L;
054    
055    
056    
057      // The password for the GSSAPI bind request.
058      private ASN1OctetString password;
059    
060      // Indicates whether to enable JVM-level debugging for GSSAPI processing.
061      private boolean enableGSSAPIDebugging;
062    
063      // Indicates whether to attempt to renew the client's existing ticket-granting
064      // ticket if authentication uses an existing Kerberos session.
065      private boolean renewTGT;
066    
067      // Indicates whether to require that the credentials be obtained from the
068      // ticket cache such that authentication will fail if the client does not have
069      // an existing Kerberos session.
070      private boolean requireCachedCredentials;
071    
072      // Indicates whether to enable the use of a ticket cache.
073      private boolean useTicketCache;
074    
075      // The SASL quality of protection value(s) allowed for the DIGEST-MD5 bind
076      // request.
077      private List<SASLQualityOfProtection> allowedQoP;
078    
079      // The authentication ID string for the GSSAPI bind request.
080      private String authenticationID;
081    
082      // The authorization ID string for the GSSAPI bind request, if available.
083      private String authorizationID;
084    
085      // The path to the JAAS configuration file to use for bind processing.
086      private String configFilePath;
087    
088      // The KDC address for the GSSAPI bind request, if available.
089      private String kdcAddress;
090    
091      // The realm for the GSSAPI bind request, if available.
092      private String realm;
093    
094      // The server name to use when creating the SASL client.
095      private String saslClientServerName;
096    
097      // The protocol that should be used in the Kerberos service principal for
098      // the server system.
099      private String servicePrincipalProtocol;
100    
101      // The path to the Kerberos ticket cache to use.
102      private String ticketCachePath;
103    
104    
105    
106      /**
107       * Creates a new set of GSSAPI bind request properties with the provided
108       * information.
109       *
110       * @param  authenticationID  The authentication ID for the GSSAPI bind
111       *                           request.  It may be {@code null} if an existing
112       *                           Kerberos session should be used.
113       * @param  password          The password for the GSSAPI bind request.  It may
114       *                           be {@code null} if an existing Kerberos session
115       *                           should be used.
116       */
117      public GSSAPIBindRequestProperties(final String authenticationID,
118                                         final String password)
119      {
120        this(authenticationID, null,
121             (password == null ? null : new ASN1OctetString(password)), null, null,
122             null);
123      }
124    
125    
126    
127      /**
128       * Creates a new set of GSSAPI bind request properties with the provided
129       * information.
130       *
131       * @param  authenticationID  The authentication ID for the GSSAPI bind
132       *                           request.  It may be {@code null} if an existing
133       *                           Kerberos session should be used.
134       * @param  password          The password for the GSSAPI bind request.  It may
135       *                           be {@code null} if an existing Kerberos session
136       *                           should be used.
137       */
138      public GSSAPIBindRequestProperties(final String authenticationID,
139                                         final byte[] password)
140      {
141        this(authenticationID, null,
142             (password == null ? null : new ASN1OctetString(password)), null, null,
143             null);
144      }
145    
146    
147    
148      /**
149       * Creates a new set of GSSAPI bind request properties with the provided
150       * information.
151       *
152       * @param  authenticationID  The authentication ID for the GSSAPI bind
153       *                           request.  It may be {@code null} if an existing
154       *                           Kerberos session should be used.
155       * @param  authorizationID   The authorization ID for the GSSAPI bind request.
156       *                           It may be {@code null} if the authorization ID
157       *                           should be the same as the authentication ID.
158       * @param  password          The password for the GSSAPI bind request.  It may
159       *                           be {@code null} if an existing Kerberos session
160       *                           should be used.
161       * @param  realm             The realm to use for the authentication.  It may
162       *                           be {@code null} to attempt to use the default
163       *                           realm from the system configuration.
164       * @param  kdcAddress        The address of the Kerberos key distribution
165       *                           center.  It may be {@code null} to attempt to use
166       *                           the default KDC from the system configuration.
167       * @param  configFilePath    The path to the JAAS configuration file to use
168       *                           for the authentication processing.  It may be
169       *                           {@code null} to use the default JAAS
170       *                           configuration.
171       */
172      GSSAPIBindRequestProperties(final String authenticationID,
173                                  final String authorizationID,
174                                  final ASN1OctetString password,
175                                  final String realm,
176                                  final String kdcAddress,
177                                  final String configFilePath)
178      {
179        this.authenticationID = authenticationID;
180        this.authorizationID  = authorizationID;
181        this.password         = password;
182        this.realm            = realm;
183        this.kdcAddress       = kdcAddress;
184        this.configFilePath   = configFilePath;
185    
186        servicePrincipalProtocol = "ldap";
187        enableGSSAPIDebugging    = false;
188        renewTGT                 = false;
189        useTicketCache           = true;
190        requireCachedCredentials = false;
191        saslClientServerName     = null;
192        ticketCachePath          = null;
193        allowedQoP               = Collections.unmodifiableList(Arrays.asList(
194             SASLQualityOfProtection.AUTH));
195      }
196    
197    
198    
199      /**
200       * Retrieves the authentication ID for the GSSAPI bind request, if defined.
201       *
202       * @return  The authentication ID for the GSSAPI bind request, or {@code null}
203       *          if an existing Kerberos session should be used.
204       */
205      public String getAuthenticationID()
206      {
207        return authenticationID;
208      }
209    
210    
211    
212      /**
213       * Sets the authentication ID for the GSSAPI bind request.
214       *
215       * @param  authenticationID  The authentication ID for the GSSAPI bind
216       *                           request.  It may be {@code null} if an existing
217       *                           Kerberos session should be used.
218       */
219      public void setAuthenticationID(final String authenticationID)
220      {
221        this.authenticationID = authenticationID;
222      }
223    
224    
225    
226      /**
227       * Retrieves the authorization ID for the GSSAPI bind request, if defined.
228       *
229       * @return  The authorizationID for the GSSAPI bind request, or {@code null}
230       *          if the authorization ID should be the same as the authentication
231       *          ID.
232       */
233      public String getAuthorizationID()
234      {
235        return authorizationID;
236      }
237    
238    
239    
240      /**
241       * Specifies the authorization ID for the GSSAPI bind request.
242       *
243       * @param  authorizationID  The authorization ID for the GSSAPI bind request.
244       *                          It may be {@code null} if the authorization ID
245       *                          should be the same as the authentication ID.
246       */
247      public void setAuthorizationID(final String authorizationID)
248      {
249        this.authorizationID = authorizationID;
250      }
251    
252    
253    
254      /**
255       * Retrieves the password that should be used for the GSSAPI bind request, if
256       * defined.
257       *
258       * @return  The password that should be used for the GSSAPI bind request, or
259       *          {@code null} if an existing Kerberos session should be used.
260       */
261      public ASN1OctetString getPassword()
262      {
263        return password;
264      }
265    
266    
267    
268      /**
269       * Specifies the password that should be used for the GSSAPI bind request.
270       *
271       * @param  password  The password that should be used for the GSSAPI bind
272       *                   request.  It may be {@code null} if an existing
273       *                   Kerberos session should be used.
274       */
275      public void setPassword(final String password)
276      {
277        if (password == null)
278        {
279          this.password = null;
280        }
281        else
282        {
283          this.password = new ASN1OctetString(password);
284        }
285      }
286    
287    
288    
289      /**
290       * Specifies the password that should be used for the GSSAPI bind request.
291       *
292       * @param  password  The password that should be used for the GSSAPI bind
293       *                   request.  It may be {@code null} if an existing
294       *                   Kerberos session should be used.
295       */
296      public void setPassword(final byte[] password)
297      {
298        if (password == null)
299        {
300          this.password = null;
301        }
302        else
303        {
304          this.password = new ASN1OctetString(password);
305        }
306      }
307    
308    
309    
310      /**
311       * Specifies the password that should be used for the GSSAPI bind request.
312       *
313       * @param  password  The password that should be used for the GSSAPI bind
314       *                   request.  It may be {@code null} if an existing
315       *                   Kerberos session should be used.
316       */
317      public void setPassword(final ASN1OctetString password)
318      {
319        this.password = password;
320      }
321    
322    
323    
324      /**
325       * Retrieves the realm to use for the GSSAPI bind request, if defined.
326       *
327       * @return  The realm to use for the GSSAPI bind request, or {@code null} if
328       *          the request should attempt to use the default realm from the
329       *          system configuration.
330       */
331      public String getRealm()
332      {
333        return realm;
334      }
335    
336    
337    
338      /**
339       * Specifies the realm to use for the GSSAPI bind request.
340       *
341       * @param  realm  The realm to use for the GSSAPI bind request.  It may be
342       *                {@code null} if the request should attempt to use the
343       *                default realm from the system configuration.
344       */
345      public void setRealm(final String realm)
346      {
347        this.realm = realm;
348      }
349    
350    
351    
352      /**
353       * Retrieves the list of allowed qualities of protection that may be used for
354       * communication that occurs on the connection after the authentication has
355       * completed, in order from most preferred to least preferred.
356       *
357       * @return  The list of allowed qualities of protection that may be used for
358       *          communication that occurs on the connection after the
359       *          authentication has completed, in order from most preferred to
360       *          least preferred.
361       */
362      public List<SASLQualityOfProtection> getAllowedQoP()
363      {
364        return allowedQoP;
365      }
366    
367    
368    
369      /**
370       * Specifies the list of allowed qualities of protection that may be used for
371       * communication that occurs on the connection after the authentication has
372       * completed, in order from most preferred to least preferred.
373       *
374       * @param  allowedQoP  The list of allowed qualities of protection that may be
375       *                     used for communication that occurs on the connection
376       *                     after the authentication has completed, in order from
377       *                     most preferred to least preferred.  If this is
378       *                     {@code null} or empty, then a list containing only the
379       *                     {@link SASLQualityOfProtection#AUTH} quality of
380       *                     protection value will be used.
381       */
382      public void setAllowedQoP(final List<SASLQualityOfProtection> allowedQoP)
383      {
384        if ((allowedQoP == null) || allowedQoP.isEmpty())
385        {
386          this.allowedQoP = Collections.unmodifiableList(Arrays.asList(
387               SASLQualityOfProtection.AUTH));
388        }
389        else
390        {
391          this.allowedQoP = Collections.unmodifiableList(
392               new ArrayList<SASLQualityOfProtection>(allowedQoP));
393        }
394      }
395    
396    
397    
398      /**
399       * Specifies the list of allowed qualities of protection that may be used for
400       * communication that occurs on the connection after the authentication has
401       * completed, in order from most preferred to least preferred.
402       *
403       * @param  allowedQoP  The list of allowed qualities of protection that may be
404       *                     used for communication that occurs on the connection
405       *                     after the authentication has completed, in order from
406       *                     most preferred to least preferred.  If this is
407       *                     {@code null} or empty, then a list containing only the
408       *                     {@link SASLQualityOfProtection#AUTH} quality of
409       *                     protection value will be used.
410       */
411      public void setAllowedQoP(final SASLQualityOfProtection... allowedQoP)
412      {
413        setAllowedQoP(StaticUtils.toList(allowedQoP));
414      }
415    
416    
417    
418      /**
419       * Retrieves the address to use for the Kerberos key distribution center,
420       * if defined.
421       *
422       * @return  The address to use for the Kerberos key distribution center, or
423       *          {@code null} if request should attempt to determine the KDC
424       *          address from the system configuration.
425       */
426      public String getKDCAddress()
427      {
428        return kdcAddress;
429      }
430    
431    
432    
433      /**
434       * Specifies the address to use for the Kerberos key distribution center.
435       *
436       * @param  kdcAddress  The address to use for the Kerberos key distribution
437       *                     center.  It may be {@code null} if the request should
438       *                     attempt to determine the KDC address from the system
439       *                     configuration.
440       */
441      public void setKDCAddress(final String kdcAddress)
442      {
443        this.kdcAddress = kdcAddress;
444      }
445    
446    
447    
448      /**
449       * Retrieves the path to a JAAS configuration file that should be used when
450       * processing the GSSAPI bind request, if defined.
451       *
452       * @return  The path to a JAAS configuration file that should be used when
453       *          processing the GSSAPI bind request, or {@code null} if a JAAS
454       *          configuration file should be automatically constructed for the
455       *          bind request.
456       */
457      public String getConfigFilePath()
458      {
459        return configFilePath;
460      }
461    
462    
463    
464      /**
465       * Specifies the path to a JAAS configuration file that should be used when
466       * processing the GSSAPI bind request.
467       *
468       * @param  configFilePath  The path to a JAAS configuration file that should
469       *                         be used when processing the GSSAPI bind request.
470       *                         It may be {@code null} if a configuration file
471       *                         should be automatically constructed for the bind
472       *                         request.
473       */
474      public void setConfigFilePath(final String configFilePath)
475      {
476        this.configFilePath = configFilePath;
477      }
478    
479    
480    
481      /**
482       * Retrieves the server name that should be used when creating the Java
483       * {@code SaslClient}, if one is defined.
484       *
485       * @return  The server name that should be used when creating the Java
486       *          {@code SaslClient}, or {@code null} if none is defined and the
487       *          {@code SaslClient} should use the address specified when
488       *          establishing the connection.
489       */
490      public String getSASLClientServerName()
491      {
492        return saslClientServerName;
493      }
494    
495    
496    
497      /**
498       * Specifies the server name that should be used when creating the Java
499       * {@code SaslClient}.
500       *
501       * @param  saslClientServerName  The server name that should be used when
502       *                               creating the Java {@code SaslClient}.  It may
503       *                               be {@code null} to indicate that the
504       *                               {@code SaslClient} should be created with the
505       *
506       */
507      public void setSASLClientServerName(final String saslClientServerName)
508      {
509        this.saslClientServerName = saslClientServerName;
510      }
511    
512    
513    
514      /**
515       * Retrieves the protocol specified in the service principal that the
516       * directory server uses for its communication with the KDC.  The service
517       * principal is usually something like "ldap/directory.example.com", where
518       * "ldap" is the protocol and "directory.example.com" is the fully-qualified
519       * address of the directory server system, but some servers may allow
520       * authentication with a service principal with a protocol other than "ldap".
521       *
522       * @return  The protocol specified in the service principal that the directory
523       *          server uses for its communication with the KDC.
524       */
525      public String getServicePrincipalProtocol()
526      {
527        return servicePrincipalProtocol;
528      }
529    
530    
531    
532      /**
533       * Specifies the protocol specified in the service principal that the
534       * directory server uses for its communication with the KDC.  This should
535       * generally be "ldap", but some servers may allow a service principal with a
536       * protocol other than "ldap".
537       *
538       * @param  servicePrincipalProtocol  The protocol specified in the service
539       *                                   principal that the directory server uses
540       *                                   for its communication with the KDC.
541       */
542      public void setServicePrincipalProtocol(final String servicePrincipalProtocol)
543      {
544        Validator.ensureNotNull(servicePrincipalProtocol);
545    
546        this.servicePrincipalProtocol = servicePrincipalProtocol;
547      }
548    
549    
550    
551      /**
552       * Indicates whether to enable the use of a ticket cache to to avoid the need
553       * to supply credentials if the client already has an existing Kerberos
554       * session.
555       *
556       * @return  {@code true} if a ticket cache may be used to take advantage of an
557       *          existing Kerberos session, or {@code false} if Kerberos
558       *          credentials should always be provided.
559       */
560      public boolean useTicketCache()
561      {
562        return useTicketCache;
563      }
564    
565    
566    
567      /**
568       * Specifies whether to enable the use of a ticket cache to to avoid the need
569       * to supply credentials if the client already has an existing Kerberos
570       * session.
571       *
572       * @param  useTicketCache  Indicates whether to enable the use of a ticket
573       *                         cache to to avoid the need to supply credentials if
574       *                         the client already has an existing Kerberos
575       *                         session.
576       */
577      public void setUseTicketCache(final boolean useTicketCache)
578      {
579        this.useTicketCache = useTicketCache;
580      }
581    
582    
583    
584      /**
585       * Indicates whether GSSAPI authentication should only occur using an existing
586       * Kerberos session.
587       *
588       * @return  {@code true} if GSSAPI authentication should only use an existing
589       *          Kerberos session and should fail if the client does not have an
590       *          existing session, or {@code false} if the client will be allowed
591       *          to create a new session if one does not already exist.
592       */
593      public boolean requireCachedCredentials()
594      {
595        return requireCachedCredentials;
596      }
597    
598    
599    
600      /**
601       * Specifies whether an GSSAPI authentication should only occur using an
602       * existing Kerberos session.
603       *
604       * @param  requireCachedCredentials  Indicates whether an existing Kerberos
605       *                                   session will be required for
606       *                                   authentication.  If {@code true}, then
607       *                                   authentication will fail if the client
608       *                                   does not already have an existing
609       *                                   Kerberos session.  This will be ignored
610       *                                   if {@code useTicketCache} is false.
611       */
612      public void setRequireCachedCredentials(
613                       final boolean requireCachedCredentials)
614      {
615        this.requireCachedCredentials = requireCachedCredentials;
616      }
617    
618    
619    
620      /**
621       * Retrieves the path to the Kerberos ticket cache file that should be used
622       * during authentication, if defined.
623       *
624       * @return  The path to the Kerberos ticket cache file that should be used
625       *          during authentication, or {@code null} if the default ticket cache
626       *          file should be used.
627       */
628      public String getTicketCachePath()
629      {
630        return ticketCachePath;
631      }
632    
633    
634    
635      /**
636       * Specifies the path to the Kerberos ticket cache file that should be used
637       * during authentication.
638       *
639       * @param  ticketCachePath  The path to the Kerberos ticket cache file that
640       *                          should be used during authentication.  It may be
641       *                          {@code null} if the default ticket cache file
642       *                          should be used.
643       */
644      public void setTicketCachePath(final String ticketCachePath)
645      {
646        this.ticketCachePath = ticketCachePath;
647      }
648    
649    
650    
651      /**
652       * Indicates whether to attempt to renew the client's ticket-granting ticket
653       * (TGT) if an existing Kerberos session is used to authenticate.
654       *
655       * @return  {@code true} if the client should attempt to renew its
656       *          ticket-granting ticket if the authentication is processed using an
657       *          existing Kerberos session, or {@code false} if not.
658       */
659      public boolean renewTGT()
660      {
661        return renewTGT;
662      }
663    
664    
665    
666      /**
667       * Specifies whether to attempt to renew the client's ticket-granting ticket
668       * (TGT) if an existing Kerberos session is used to authenticate.
669       *
670       * @param  renewTGT  Indicates whether to attempt to renew the client's
671       *                   ticket-granting ticket if an existing Kerberos session is
672       *                   used to authenticate.
673       */
674      public void setRenewTGT(final boolean renewTGT)
675      {
676        this.renewTGT = renewTGT;
677      }
678    
679    
680    
681      /**
682       * Indicates whether JVM-level debugging should be enabled for GSSAPI bind
683       * processing.  If this is enabled, then debug information may be written to
684       * standard error when performing GSSAPI processing that could be useful for
685       * debugging authentication problems.
686       *
687       * @return  {@code true} if JVM-level debugging should be enabled for GSSAPI
688       *          bind processing, or {@code false} if not.
689       */
690      public boolean enableGSSAPIDebugging()
691      {
692        return enableGSSAPIDebugging;
693      }
694    
695    
696    
697      /**
698       * Specifies whether JVM-level debugging should be enabled for GSSAPI bind
699       * processing.  If this is enabled, then debug information may be written to
700       * standard error when performing GSSAPI processing that could be useful for
701       * debugging authentication problems.
702       *
703       * @param  enableGSSAPIDebugging  Specifies whether JVM-level debugging should
704       *                                be enabled for GSSAPI bind processing.
705       */
706      public void setEnableGSSAPIDebugging(final boolean enableGSSAPIDebugging)
707      {
708        this.enableGSSAPIDebugging = enableGSSAPIDebugging;
709      }
710    
711    
712    
713      /**
714       * Retrieves a string representation of the GSSAPI bind request properties.
715       *
716       * @return  A string representation of the GSSAPI bind request properties.
717       */
718      @Override()
719      public String toString()
720      {
721        final StringBuilder buffer = new StringBuilder();
722        toString(buffer);
723        return buffer.toString();
724      }
725    
726    
727    
728      /**
729       * Appends a string representation of the GSSAPI bind request properties to
730       * the provided buffer.
731       *
732       * @param  buffer  The buffer to which the information should be appended.
733       */
734      public void toString(final StringBuilder buffer)
735      {
736        buffer.append("GSSAPIBindRequestProperties(");
737        if (authenticationID != null)
738        {
739          buffer.append("authenticationID='");
740          buffer.append(authenticationID);
741          buffer.append("', ");
742        }
743    
744        if (authorizationID != null)
745        {
746          buffer.append("authorizationID='");
747          buffer.append(authorizationID);
748          buffer.append("', ");
749        }
750    
751        if (realm != null)
752        {
753          buffer.append("realm='");
754          buffer.append(realm);
755          buffer.append("', ");
756        }
757    
758        buffer.append("qop='");
759        buffer.append(SASLQualityOfProtection.toString(allowedQoP));
760        buffer.append("', ");
761    
762        if (kdcAddress != null)
763        {
764          buffer.append("kdcAddress='");
765          buffer.append(kdcAddress);
766          buffer.append("', ");
767        }
768    
769        if (useTicketCache)
770        {
771          buffer.append("useTicketCache=true, requireCachedCredentials=");
772          buffer.append(requireCachedCredentials);
773          buffer.append(", renewTGT=");
774          buffer.append(renewTGT);
775          buffer.append(", ");
776    
777          if (ticketCachePath != null)
778          {
779            buffer.append("ticketCachePath='");
780            buffer.append(ticketCachePath);
781            buffer.append("', ");
782          }
783        }
784        else
785        {
786          buffer.append("useTicketCache=false, ");
787        }
788    
789        if (configFilePath != null)
790        {
791          buffer.append("configFilePath='");
792          buffer.append(configFilePath);
793          buffer.append("', ");
794        }
795    
796        if (saslClientServerName != null)
797        {
798          buffer.append("saslClientServerName='");
799          buffer.append(saslClientServerName);
800          buffer.append("', ");
801        }
802    
803        buffer.append("servicePrincipalProtocol='");
804        buffer.append(servicePrincipalProtocol);
805        buffer.append("', enableGSSAPIDebugging=");
806        buffer.append(enableGSSAPIDebugging);
807        buffer.append(')');
808      }
809    }