From 6f5ce93bab1c1ce6df0e71aa450f841f3d979bbc Mon Sep 17 00:00:00 2001
From: Andreas Tobler A static class for creating SASL clients and servers. This class defines the policy of how to locate, load, and instantiate SASL
+ * clients and servers. For example, an application or library gets a SASL client instance by
+ * doing something like: It can then proceed to use the instance to create an authenticated
+ * connection. Similarly, a server gets a SASL server instance by using code that looks
+ * as follows: 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: The order of the list specifies the preference order of the client or
+ * server. If this property is absent, the default qop is The value of this constant is 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: 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. If this property is absent, the default strength is
+ * The value of this constant is The name of a property that specifies whether the server must authenticate
+ * to the client. The property contains The value of this constant is
+ * 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. If this property is absent, the default size is defined by the
+ * mechanism. The value of this constant is 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. The value of this constant is The name of a property that specifies whether mechanisms susceptible
+ * to simple plain passive attacks (e.g., "PLAIN") are not permitted. The
+ * property contains The value of this constant is The name of a property that specifies whether mechanisms susceptible to
+ * active (non-dictionary) attacks are not permitted. The property contains
+ * The value of this constant is The name of a property that specifies whether mechanisms susceptible to
+ * passive dictionary attacks are not permitted. The property contains
+ * The value of this constant is The name of a property that specifies whether mechanisms that accept
+ * anonymous login are not permitted. The property contains The value of this constant is
+ *SaslClient sc =
+ * Sasl.createSaslClient(mechanisms, authorizationID, protocol,
+ * serverName, props, callbackHandler);
+ *
+ *
+ *
+ *SaslServer ss =
+ * Sasl.createSaslServer(mechanism, protocol, serverName, props,
+ * callbackHandler);
+ *
+ */
+public class Sasl
+{
+
+ // Constants and variables
+ // -------------------------------------------------------------------------
+
+ /**
+ *
+ *
+ *
+ * "auth"
- authentication only,"auth-int"
- authentication plus integrity
+ * protection,"auth-conf"
- authentication plus integrity and
+ * confidentiality protection."auth"
."javax.security.sasl.qop"
.
+ *
+ *
+ * "low"
,"medium"
,"high"
."high,medium,low"
."javax.security.sasl.strength"
.
+ * "true"
if the server
+ * must authenticate the to client; "false"
otherwise. The
+ * default is "false"
."javax.security.sasl.server.authentication"
."javax.security.sasl.maxbuffer"
.
+ * "javax.security.sasl.rawsendsize"
.
+ * "true"
if such mechanisms are not
+ * permitted; "false"
if such mechanisms are permitted. The
+ * default is "false"
."javax.security.sasl.policy.noplaintext"
.
+ * "true"
if mechanisms susceptible to active attacks are not
+ * permitted; "false"
if such mechanisms are permitted. The
+ * default is "false"
."javax.security.sasl.policy.noactive"
.
+ * "true"
if mechanisms susceptible to dictionary attacks are
+ * not permitted; "false"
if such mechanisms are permitted. The
+ * default is "false"
."javax.security.sasl.policy.nodictionary"
.
+ * "true"
+ * if mechanisms that accept anonymous login are not permitted; "false"
+ *
if such mechanisms are permitted. The default is "false"
.
+ * "javax.security.sasl.policy.noanonymous"
.
+ * "true"
+ * if mechanisms that implement forward secrecy between sessions are
+ * required; "false"
if such mechanisms are not required. The
+ * default is "false"
.
The value of this constant is "javax.security.sasl.policy.forward"
.
+ *
"true"
if
+ * mechanisms that pass client credentials are required; "false"
+ * if such mechanisms are not required. The default is "false"
.
+ *
+ *
+ * The value of this constant is "javax.security.sasl.policy.credentials"
.
+ *
The name of a property that specifies whether to reuse previously
+ * authenticated session information. The property contains "true"
+ * if the mechanism implementation may attempt to reuse previously
+ * authenticated session information; it contains "false"
if the
+ * implementation must not reuse previously authenticated session information.
+ * A setting of "true"
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 "false"
.
+ *
The value of this constant is "javax.security.sasl.reuse"
.
+ * 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.
Creates a {@link SaslClient} for the specified mechanism.
+ * + *This method uses the JCA Security Provider Framework, described in the + * "Java Cryptography Architecture API Specification & Reference", for + * locating and selecting a {@link SaslClient} implementation.
+ * + *First, it obtains an ordered list of {@link SaslClientFactory}
+ * instances from the registered security providers for the
+ * "SaslClientFactory"
service and the specified mechanism. It
+ * then invokes createSaslClient()
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 null
if
+ * the search fails to produce a non-null {@link SaslClient} instance.
A security provider for SaslClientFactory
registers with
+ * the JCA Security Provider Framework keys of the form:
+ * SaslClientFactory.mechanism_name + *+ * + *
and values that are class names of implementations of {@link + * SaslClientFactory}.
+ * + *For example, a provider that contains a factory class,
+ * com.wiz.sasl.digest.ClientFactory
, that supports the
+ * "DIGEST-MD5"
mechanism would register the following entry
+ * with the JCA:
+ * SaslClientFactory.DIGEST-MD5 com.wiz.sasl.digest.ClientFactory + *+ * + *
See the "Java Cryptography Architecture API Specification & + * Reference" for information about how to install and configure security + * service providers.
+ * + * @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 possiblynull
protocol-dependent
+ * identification to be used for authorization. If null
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 "true"
, 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 null
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 null
{@link SaslClient} created using the
+ * parameters supplied. If null
, 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 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 = null, 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
+ * createSaslClient()
.
+ *
+ * @return a non-null {@link Enumeration} of known factories for producing a
+ * {@link SaslClient} instance.
+ * @see #createSaslClient(String[],String,String,String,Map,CallbackHandler)
+ */
+ 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();
+ }
+
+ /**
+ * Creates a {@link SaslServer} for the specified mechanism.
+ * + *This method uses the JCA Security Provider Framework, described in the + * "Java Cryptography Architecture API Specification & Reference", for + * locating and selecting a SaslServer implementation.
+ * + *First, it obtains an ordered list of {@link SaslServerFactory}
+ * instances from the registered security providers for the
+ * "SaslServerFactory"
service and the specified mechanism. It
+ * then invokes createSaslServer()
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 null
if
+ * the search fails to produce a non-null {@link SaslServer} instance.
A security provider for {@link SaslServerFactory} registers with the + * JCA Security Provider Framework keys of the form:
+ * + *+ * SaslServerFactory.mechanism_name + *+ * + *
and values that are class names of implementations of {@link + * SaslServerFactory}.
+ * + *For example, a provider that contains a factory class,
+ * com.wiz.sasl.digest.ServerFactory
, that supports the
+ * "DIGEST-MD5"
mechanism would register the following entry
+ * with the JCA:
+ * SaslServerFactory.DIGEST-MD5 com.wiz.sasl.digest.ServerFactory + *+ * + *
See the "Java Cryptography Architecture API Specification & + * Reference" for information about how to install and configure security + * service providers.
+ * + * @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 possiblynull
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 "true"
, 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 null
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 null
{@link SaslServer} created using the
+ * parameters supplied. If null
, 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 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 = null, upper, alias = null;
+ 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
+ * createSaslServer()
.
+ *
+ * @return a non-null {@link Enumeration} of known factories for producing a
+ * {@link SaslServer} instance.
+ * @see #createSaslServer(String,String,String,Map,CallbackHandler)
+ */
+ 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();
+ }
+}
--
cgit v1.1