Logo Search packages:      
Sourcecode: libgnucrypto-java version File versions  Download package

Sasl.java

package javax.security.sasl;

// ----------------------------------------------------------------------------
// $Id: Sasl.java,v 1.1 2003/05/10 18:45:12 raif Exp $
//
// Copyright (C) 2003, Free Software Foundation, Inc.
//
// This file is part of GNU Crypto.
//
// GNU Crypto is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2, or (at your option)
// any later version.
//
// GNU Crypto is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; see the file COPYING.  If not, write to the
//
//    Free Software Foundation Inc.,
//    59 Temple Place - Suite 330,
//    Boston, MA 02111-1307
//    USA
//
// Linking this library statically or dynamically with other modules is
// making a combined work based on this library.  Thus, the terms and
// conditions of the GNU General Public License cover the whole
// combination.
//
// As a special exception, the copyright holders of this library give
// you permission to link this library with independent modules to
// produce an executable, regardless of the license terms of these
// independent modules, and to copy and distribute the resulting
// executable under terms of your choice, provided that you also meet,
// for each linked independent module, the terms and conditions of the
// license of that module.  An independent module is a module which is
// not derived from or based on this library.  If you modify this
// library, you may extend this exception to your version of the
// library, but you are not obligated to do so.  If you do not wish to
// do so, delete this exception statement from your version.
// ----------------------------------------------------------------------------

import java.util.Enumeration;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Vector;
import java.security.Security;
import java.security.Provider;

import javax.security.auth.callback.CallbackHandler;

/**
 * <p>A static class for creating SASL clients and servers.</p>
 *
 * <p>This class defines the policy of how to locate, load, and instantiate SASL
 * clients and servers.</p>
 *
 * <p>For example, an application or library gets a SASL client instance by
 * doing something like:</p>
 *
 * <pre>
 *SaslClient sc =
 *      Sasl.createSaslClient(mechanisms, authorizationID, protocol,
 *                            serverName, props, callbackHandler);
 * </pre>
 *
 * <p>It can then proceed to use the instance to create an authenticated
 * connection.</p>
 *
 * <p>Similarly, a server gets a SASL server instance by using code that looks
 * as follows:</p>
 *
 * <pre>
 *SaslServer ss =
 *      Sasl.createSaslServer(mechanism, protocol, serverName, props,
 *                            callbackHandler);
 * </pre>
 *
 * @version $Revision: 1.1 $
 */
00085 public class Sasl {

   // Constants and variables
   // -------------------------------------------------------------------------

   /**
    * <p>The name of a property that specifies the quality-of-protection to use.
    * The property contains a comma-separated, ordered list of quality-of-
    * protection values that the client or server is willing to support. A qop
    * value is one of:</p>
    *
    * <ul>
    *    <li><code>"auth"</code> - authentication only,</li>
    *    <li><code>"auth-int"</code> - authentication plus integrity
    *    protection,</li>
    *    <li><code>"auth-conf"</code> - authentication plus integrity and
    *    confidentiality protection.</li>
    * </ul>
    *
    * <p>The order of the list specifies the preference order of the client or
    * server.</p>
    *
    * <p>If this property is absent, the default qop is <code>"auth"</code>.</p>
    *
    * <p>The value of this constant is <code>"javax.security.sasl.qop"</code>.</p>
    */
00111    public static final String QOP = "javax.security.sasl.qop";

   /**
    * <p>The name of a property that specifies the cipher strength to use. The
    * property contains a comma-separated, ordered list of cipher strength
    * values that the client or server is willing to support. A strength value
    * is one of:</p>
    *
    * <ul>
    *    <li><code>"low"</code>,</li>
    *    <li><code>"medium"</code>,</li>
    *    <li><code>"high"</code>.</li>
    * </ul>
    *
    * <p>The order of the list specifies the preference order of the client or
    * server. An implementation should allow configuration of the meaning of
    * these values. An application may use the Java Cryptography Extension (JCE)
    * with JCE-aware mechanisms to control the selection of cipher suites that
    * match the strength values.</p>
    *
    * <p>If this property is absent, the default strength is
    * <code>"high,medium,low"</code>.</p>
    *
    * <p>The value of this constant is <code>"javax.security.sasl.strength"</code>.
    * </p>
    */
00137    public static final String STRENGTH = "javax.security.sasl.strength";

   /**
    * <p>The name of a property that specifies whether the server must authenticate
    * to the client. The property contains <code>"true"</code> if the server
    * must authenticate the to client; <code>"false"</code> otherwise. The
    * default is <code>"false"</code>.</p>
    *
    * <p>The value of this constant is
    * <code>"javax.security.sasl.server.authentication"</code>.</p>
    */
00148    public static final String SERVER_AUTH = "javax.security.sasl.server.authentication";

   /**
    * <p>The name of a property that specifies the maximum size of the receive
    * buffer in bytes of {@link SaslClient}/{@link SaslServer}. The property
    * contains the string representation of an integer.</p>
    *
    * <p>If this property is absent, the default size is defined by the
    * mechanism.</p>
    *
    * <p>The value of this constant is <code>"javax.security.sasl.maxbuffer"</code>.
    * </p>
    */
00161    public static final String MAX_BUFFER = "javax.security.sasl.maxbuffer";

   /**
    * <p>The name of a property that specifies the maximum size of the raw send
    * buffer in bytes of {@link SaslClient}/{@link SaslServer}. The property
    * contains the string representation of an integer. The value of this
    * property is negotiated between the client and server during the
    * authentication exchange.</p>
    *
    * <p>The value of this constant is <code>"javax.security.sasl.rawsendsize"</code>.
    * </p>
    */
00173    public static final String RAW_SEND_SIZE = "javax.security.sasl.rawsendsize";

   /**
    * <p>The name of a property that specifies whether mechanisms susceptible
    * to simple plain passive attacks (e.g., "PLAIN") are not permitted. The
    * property contains <code>"true"</code> if such mechanisms are not
    * permitted; <code>"false"</code> if such mechanisms are permitted. The
    * default is <code>"false"</code>.</p>
    *
    * <p>The value of this constant is <code>"javax.security.sasl.policy.noplaintext"</code>.
    * </p>
    */
00185    public static final String POLICY_NOPLAINTEXT = "javax.security.sasl.policy.noplaintext";

   /**
    * <p>The name of a property that specifies whether mechanisms susceptible to
    * active (non-dictionary) attacks are not permitted. The property contains
    * <code>"true"</code> if mechanisms susceptible to active attacks are not
    * permitted; <code>"false"</code> if such mechanisms are permitted. The
    * default is <code>"false"</code>.</p>
    *
    * <p>The value of this constant is <code>"javax.security.sasl.policy.noactive"</code>.
    * </p>
    */
00197    public static final String POLICY_NOACTIVE = "javax.security.sasl.policy.noactive";

   /**
    * <p>The name of a property that specifies whether mechanisms susceptible to
    * passive dictionary attacks are not permitted. The property contains
    * <code>"true"</code> if mechanisms susceptible to dictionary attacks are
    * not permitted; <code>"false"</code> if such mechanisms are permitted. The
    * default is <code>"false"</code>.</p>
    *
    * <p>The value of this constant is <code>"javax.security.sasl.policy.nodictionary"</code>.
    * </p>
    */
00209    public static final String POLICY_NODICTIONARY = "javax.security.sasl.policy.nodictionary";

   /**
    * <p>The name of a property that specifies whether mechanisms that accept
    * anonymous login are not permitted. The property contains <code>"true"</code>
    * if mechanisms that accept anonymous login are not permitted; <code>"false"
    * </code> if such mechanisms are permitted. The default is <code>"false"</code>.
    * </p>
    *
    * <p>The value of this constant is <code>"javax.security.sasl.policy.noanonymous"</code>.
    * </p>
    */
00221    public static final String POLICY_NOANONYMOUS = "javax.security.sasl.policy.noanonymous";

   /**
    * The name of a property that specifies whether mechanisms that implement
    * forward secrecy between sessions are required. Forward secrecy means that
    * breaking into one session will not automatically provide information for
    * breaking into future sessions. The property contains <code>"true"</code>
    * if mechanisms that implement forward secrecy between sessions are
    * required; <code>"false"</code> if such mechanisms are not required. The
    * default is <code>"false"</code>.</p>
    *
    * <p>The value of this constant is <code>"javax.security.sasl.policy.forward"</code>.
    * </p>
    */
00235    public static final String POLICY_FORWARD_SECRECY = "javax.security.sasl.policy.forward";

   /**
    * The name of a property that specifies whether mechanisms that pass client
    * credentials are required. The property contains <code>"true"</code> if
    * mechanisms that pass client credentials are required; <code>"false"</code>
    * if such mechanisms are not required. The default is <code>"false"</code>.
    * </p>
    *
    * <p>The value of this constant is <code>"javax.security.sasl.policy.credentials"</code>.
    * </p>
    */
00247    public static final String POLICY_PASS_CREDENTIALS = "javax.security.sasl.policy.credentials";

   /**
    * <p>The name of a property that specifies whether to reuse previously
    * authenticated session information. The property contains <code>"true"</code>
    * if the mechanism implementation may attempt to reuse previously
    * authenticated session information; it contains <code>"false"</code> if the
    * implementation must not reuse previously authenticated session information.
    * A setting of <code>"true"</code> serves only as a hint; it does not
    * necessarily entail actual reuse because reuse might not be possible due to
    * a number of reasons, including, but not limited to, lack of mechanism
    * support for reuse, expiration of reusable information, and the peer's
    * refusal to support reuse. The property's default value is <code>"false"</code>.
    * </p>
    *
    * <p>The value of this constant is <code>"javax.security.sasl.reuse"</code>.
    * Note that all other parameters and properties required to create a SASL
    * client/server instance must be provided regardless of whether this
    * property has been supplied. That is, you cannot supply any less
    * information in anticipation of reuse. Mechanism implementations that
    * support reuse might allow customization of its implementation for factors
    * such as cache size, timeouts, and criteria for reuseability. Such
    * customizations are implementation-dependent.</p>
    */
00271    public static final String REUSE = "javax.security.sasl.reuse";

   private static final String CLIENT_FACTORY_SVC = "SaslClientFactory.";
   private static final String SERVER_FACTORY_SVC = "SaslServerFactory.";
   private static final String ALIAS = "Alg.Alias.";

   // Constructor(s)
   // -------------------------------------------------------------------------

   private Sasl() {
      super();
   }

   // Class methods
   // -------------------------------------------------------------------------

   /**
    * <p>Creates a {@link SaslClient} for the specified mechanism.</p>
    *
    * <p>This method uses the JCA Security Provider Framework, described in the
    * "Java Cryptography Architecture API Specification &amp; Reference", for
    * locating and selecting a {@link SaslClient} implementation.</p>
    *
    * <p>First, it obtains an ordered list of {@link SaslClientFactory}
    * instances from the registered security providers for the
    * <code>"SaslClientFactory"</code> service and the specified mechanism. It
    * then invokes <code>createSaslClient()</code> on each factory instance on
    * the list until one produces a non-null {@link SaslClient} instance. It
    * returns the non-null {@link SaslClient} instance, or <code>null</code> if
    * the search fails to produce a non-null {@link SaslClient} instance.</p>
    *
    * <p>A security provider for <code>SaslClientFactory</code> registers with
    * the JCA Security Provider Framework keys of the form:</p>
    *
    * <pre>
    *    SaslClientFactory.mechanism_name
    * </pre>
    *
    * <p>and values that are class names of implementations of {@link
    * SaslClientFactory}.</p>
    *
    * <p>For example, a provider that contains a factory class,
    * <code>com.wiz.sasl.digest.ClientFactory</code>, that supports the
    * <code>"DIGEST-MD5"</code> mechanism would register the following entry
    * with the JCA:</p>
    *
    * <pre>
    *    SaslClientFactory.DIGEST-MD5     com.wiz.sasl.digest.ClientFactory
    * </pre>
    *
    * <p>See the "Java Cryptography Architecture API Specification &amp;
    * Reference" for information about how to install and configure security
    * service providers.</p>
    *
    * @param mechanisms the non-null list of mechanism names to try. Each is the
    * IANA-registered name of a SASL mechanism. (e.g. "GSSAPI", "CRAM-MD5").
    * @param authorizationID the possibly <code>null</code> protocol-dependent
    * identification to be used for authorization. If <code>null</code> or
    * empty, the server derives an authorization ID from the client's
    * authentication credentials. When the SASL authentication completes
    * successfully, the specified entity is granted access.
    * @param protocol the non-null string name of the protocol for which the
    * authentication is being performed (e.g. "ldap").
    * @param serverName the non-null fully-qualified host name of the server to
    * authenticate to.
    * @param props the possibly null set of properties used to select the SASL
    * mechanism and to configure the authentication exchange of the selected
    * mechanism. For example, if props contains the {@link Sasl#POLICY_NOPLAINTEXT}
    * property with the value <code>"true"</code>, then the selected SASL
    * mechanism must not be susceptible to simple plain passive attacks. In
    * addition to the standard properties declared in this class, other,
    * possibly mechanism-specific, properties can be included. Properties not
    * relevant to the selected mechanism are ignored.
    * @param cbh the possibly <code>null</code> callback handler to used by the
    * SASL mechanisms to get further information from the application/library to
    * complete the authentication. For example, a SASL mechanism might require
    * the authentication ID, password and realm from the caller. The
    * authentication ID is requested by using a
    * {@link javax.security.auth.callback.NameCallback}. The password is
    * requested by using a {@link javax.security.auth.callback.PasswordCallback}.
    * The realm is requested by using a {@link RealmChoiceCallback} if there is
    * a list of realms to choose from, and by using a {@link RealmCallback} if
    * the realm must be entered.
    * @return a possibly <code>null</code> {@link SaslClient} created using the
    * parameters supplied. If <code>null</code>, the method could not find a
    * {@link SaslClientFactory} that will produce one.
    * @throws SaslException if a {@link SaslClient} cannot be created because
    * of an error.
    */
   public static SaslClient
00361    createSaslClient(String[] mechanisms, String authorizationID, String protocol,
                    String serverName, Map props, CallbackHandler cbh)
   throws SaslException {
      if (mechanisms == null) {
         return null;
      }
      Provider[] providers = Security.getProviders();
      if (providers == null || providers.length == 0) {
         return null;
      }

      SaslClient result = null;
      SaslClientFactory factory = null;
      String m, clazz, upper, alias;
      int j;
      Provider p;
      for (int i = 0; i < mechanisms.length; i++) {
         m = mechanisms[i];
         if (m == null) {
            continue;
         }
         for (j = 0; j < providers.length; j++) {
            p = providers[j];
            if (p != null) {
               // try the name as is
               clazz = p.getProperty(CLIENT_FACTORY_SVC + m);
               if (clazz == null) { // try all uppercase
                  upper = m.toUpperCase();
                  clazz = p.getProperty(CLIENT_FACTORY_SVC + upper);
                  if (clazz == null) { // try if it's an alias
                     alias = p.getProperty(ALIAS + CLIENT_FACTORY_SVC + m);
                     if (alias == null) { // try all-uppercase alias name
                        alias = p.getProperty(ALIAS + CLIENT_FACTORY_SVC + upper);
                        if (alias == null) { // spit the dummy
                           continue;
                        }
                     }
                     clazz = p.getProperty(CLIENT_FACTORY_SVC + alias);
                  }
               }
               if (clazz == null) {
                  continue;
               } else {
                  clazz = clazz.trim();
               }

               try {
                  result = null;
                  factory = (SaslClientFactory) Class.forName(clazz).newInstance();
                  result = factory.createSaslClient(
                        mechanisms, authorizationID, protocol, serverName, props, cbh);
               } catch (ClassCastException ignored) { // ignore instantiation exceptions
               } catch (ClassNotFoundException ignored) {
               } catch (InstantiationException ignored) {
               } catch (IllegalAccessException ignored) {
               }
               if (result != null) {
                  return result;
               }
            }
         }
      }
      return null;
   }

   /**
    * Gets an enumeration of known factories for producing a {@link SaslClient}
    * instance. This method uses the same sources for locating factories as
    * <code>createSaslClient()</code>.
    *
    * @return a non-null {@link Enumeration} of known factories for producing a
    * {@link SaslClient} instance.
    * @see #createSaslClient(String[],String,String,String,Map,CallbackHandler)
    */
00435    public static Enumeration getSaslClientFactories() {
      Vector result = new Vector();
      HashSet names = new HashSet();
      Provider[] providers = Security.getProviders();
      Iterator it;
      if (providers == null) {
         Provider p;
         String key;
         for (int i = 0; i < providers.length; i++) {
            p = providers[i];
            for (it = p.keySet().iterator(); it.hasNext(); ) {
               key = (String) it.next();
               // add key's binding (a) it is a class of a client factory,
               // and (b) the key does not include blanks
               if (key.startsWith(CLIENT_FACTORY_SVC) && key.indexOf(" ") == -1) {
                  names.add(p.getProperty(key));
                  break;
               }
            }
         }
      }
      // we have the factory class names in names; instantiate and enumerate
      String c;
      for (it = names.iterator(); it.hasNext(); ) {
         c = (String) it.next();
         try {
            SaslClientFactory f = (SaslClientFactory) Class.forName(c).newInstance();
            if (f != null) {
               result.add(f);
            }
         } catch (ClassCastException ignored) { // ignore instantiation exceptions
         } catch (ClassNotFoundException ignored) {
         } catch (InstantiationException ignored) {
         } catch (IllegalAccessException ignored) {
         }
      }

      return result.elements();
   }

   /**
    * <p>Creates a {@link SaslServer} for the specified mechanism.</p>
    *
    * <p>This method uses the JCA Security Provider Framework, described in the
    * "Java Cryptography Architecture API Specification &amp; Reference", for
    * locating and selecting a SaslServer implementation.</p>
    *
    * <p>First, it obtains an ordered list of {@link SaslServerFactory}
    * instances from the registered security providers for the
    * <code>"SaslServerFactory"</code> service and the specified mechanism. It
    * then invokes <code>createSaslServer()</code> on each factory instance on
    * the list until one produces a non-null {@link SaslServer} instance. It
    * returns the non-null {@link SaslServer} instance, or <code>null</code> if
    * the search fails to produce a non-null {@link SaslServer} instance.</p>
    *
    * <p>A security provider for {@link SaslServerFactory} registers with the
    * JCA Security Provider Framework keys of the form:</p>
    *
    * <pre>
    *    SaslServerFactory.mechanism_name
    * </pre>
    *
    * <p>and values that are class names of implementations of {@link
    * SaslServerFactory}.</p>
    *
    * <p>For example, a provider that contains a factory class,
    * <code>com.wiz.sasl.digest.ServerFactory</code>, that supports the
    * <code>"DIGEST-MD5"</code> mechanism would register the following entry
    * with the JCA:</p>
    *
    * <pre>
    *    SaslServerFactory.DIGEST-MD5     com.wiz.sasl.digest.ServerFactory
    * </pre></p>
    *
    * <p>See the "Java Cryptography Architecture API Specification &amp;
    * Reference" for information about how to install and configure security
    * service providers.</p>
    *
    * @param mechanism the non-null mechanism name. It must be an
    * IANA-registered name of a SASL mechanism. (e.g. "GSSAPI", "CRAM-MD5").
    * @param protocol the non-null string name of the protocol for which the
    * authentication is being performed (e.g. "ldap").
    * @param serverName the non-null fully qualified host name of the server.
    * @param props the possibly <code>null</code> set of properties used to
    * select the SASL mechanism and to configure the authentication exchange of
    * the selected mechanism. For example, if props contains the {@link
    * Sasl#POLICY_NOPLAINTEXT} property with the value <code>"true"</code>, then
    * the selected SASL mechanism must not be susceptible to simple plain
    * passive attacks. In addition to the standard properties declared in this
    * class, other, possibly mechanism-specific, properties can be included.
    * Properties not relevant to the selected mechanism are ignored.
    * @param cbh the possibly <code>null</code> callback handler to used by the
    * SASL mechanisms to get further information from the application/library to
    * complete the authentication. For example, a SASL mechanism might require
    * the authentication ID, password and realm from the caller. The
    * authentication ID is requested by using a
    * {@link javax.security.auth.callback.NameCallback}. The password is
    * requested by using a {@link javax.security.auth.callback.PasswordCallback}.
    * The realm is requested by using a {@link RealmChoiceCallback} if there is
    * a list of realms to choose from, and by using a {@link RealmCallback} if
    * the realm must be entered.
    * @return a possibly <code>null</code> {@link SaslServer} created using the
    * parameters supplied. If <code>null</code>, the method cannot find a
    * {@link SaslServerFactory} instance that will produce one.
    * @throws SaslException if a {@link SaslServer} instance cannot be created
    * because of an error.
    */
   public static SaslServer
00543    createSaslServer(String mechanism, String protocol, String serverName,
                    Map props, CallbackHandler cbh)
   throws SaslException {
      if (mechanism == null) {
         return null;
      }
      Provider[] providers = Security.getProviders();
      if (providers == null || providers.length == 0) {
         return null;
      }

      SaslServer result = null;
      SaslServerFactory factory = null;
      String clazz, upper, alias;
      int j;
      Provider p;
      for (j = 0; j < providers.length; j++) {
         p = providers[j];
         if (p != null) {
            // try the name as is
            clazz = p.getProperty(SERVER_FACTORY_SVC + mechanism);
            if (clazz == null) { // try all uppercase
               upper = mechanism.toUpperCase();
               clazz = p.getProperty(SERVER_FACTORY_SVC + upper);
               if (clazz == null) { // try if it's an alias
                  alias = p.getProperty(ALIAS + SERVER_FACTORY_SVC + mechanism);
                  if (alias == null) { // try all-uppercase alias name
                     alias = p.getProperty(ALIAS + SERVER_FACTORY_SVC + upper);
                     if (alias == null) { // spit the dummy
                        continue;
                     }
                  }
                  clazz = p.getProperty(SERVER_FACTORY_SVC + alias);
               }
            }
            if (clazz == null) {
               continue;
            } else {
               clazz = clazz.trim();
            }

            try {
               result = null;
               factory = (SaslServerFactory) Class.forName(clazz).newInstance();
               result = factory.createSaslServer(
                     mechanism, protocol, serverName, props, cbh);
            } catch (ClassCastException ignored) { // ignore instantiation exceptions
            } catch (ClassNotFoundException ignored) {
            } catch (InstantiationException ignored) {
            } catch (IllegalAccessException ignored) {
            }
            if (result != null) {
               return result;
            }
         }
      }
      return null;
   }

   /**
    * Gets an enumeration of known factories for producing a {@link SaslServer}
    * instance. This method uses the same sources for locating factories as
    * <code>createSaslServer()</code>.
    *
    * @return a non-null {@link Enumeration} of known factories for producing a
    * {@link SaslServer} instance.
    * @see #createSaslServer(String,String,String,Map,CallbackHandler)
    */
00611    public static Enumeration getSaslServerFactories() {
      Vector result = new Vector();
      HashSet names = new HashSet();
      Provider[] providers = Security.getProviders();
      Iterator it;
      if (providers == null) {
         Provider p;
         String key;
         for (int i = 0; i < providers.length; i++) {
            p = providers[i];
            for (it = p.keySet().iterator(); it.hasNext(); ) {
               key = (String) it.next();
               // add key's binding (a) it is a class of a server factory,
               // and (b) the key does not include blanks
               if (key.startsWith(SERVER_FACTORY_SVC) && key.indexOf(" ") == -1) {
                  names.add(p.getProperty(key));
                  break;
               }
            }
         }
      }
      // we have the factory class names in names; instantiate and enumerate
      String c;
      for (it = names.iterator(); it.hasNext(); ) {
         c = (String) it.next();
         try {
            SaslServerFactory f = (SaslServerFactory) Class.forName(c).newInstance();
            if (f != null) {
               result.add(f);
            }
         } catch (ClassCastException ignored) { // ignore instantiation exceptions
         } catch (ClassNotFoundException ignored) {
         } catch (InstantiationException ignored) {
         } catch (IllegalAccessException ignored) {
         }
      }

      return result.elements();
   }
}

Generated by  Doxygen 1.6.0   Back to index