| /* Sasl.java -- |
| Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc. |
| |
| This file is part of GNU Classpath. |
| |
| GNU Classpath 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 Classpath 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 GNU Classpath; see the file COPYING. If not, write to the |
| Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
| 02110-1301 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. */ |
| |
| |
| package javax.security.sasl; |
| |
| import java.security.Provider; |
| import java.security.Security; |
| import java.util.Enumeration; |
| import java.util.HashSet; |
| import java.util.Iterator; |
| import java.util.Map; |
| import java.util.Vector; |
| |
| 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> |
| * |
| * @since 1.5 |
| */ |
| 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> |
| */ |
| 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> |
| */ |
| 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> |
| */ |
| 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> |
| */ |
| 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> |
| */ |
| 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> |
| */ |
| 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> |
| */ |
| 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> |
| */ |
| 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> |
| */ |
| 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>The value of this constant is <code>"javax.security.sasl.policy.forward"</code>. |
| * </p> |
| */ |
| 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>The value of this constant is <code>"javax.security.sasl.policy.credentials"</code>. |
| * </p> |
| */ |
| 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> |
| */ |
| public static final String REUSE = "javax.security.sasl.reuse"; |
| |
| /** |
| * <p>The name of a property which specifies the credentials to use. |
| * The value of the property is a mechanism-specific object which can |
| * be used to supply credentials to a mechanism which provides delegated |
| * authentication.</p> |
| * |
| * <p>The value of this constant is <code>"javax.security.sasl.credentials"</code>.</p> |
| */ |
| public static final String CREDENTIALS = "javax.security.sasl.credentials"; |
| |
| 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 |
| // ------------------------------------------------------------------------- |
| |
| /** |
| * Creates a {@link SaslClient} for the specified mechanism. |
| * |
| * <p>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.</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 & |
| * 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 createSaslClient(String[] mechanisms, |
| String authorizationID, |
| String protocol, |
| String serverName, |
| Map<String, ?> 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 |
| * <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) |
| */ |
| public static Enumeration<SaslClientFactory> 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. |
| * |
| * <p>This method uses the JCA Security Provider Framework, described in the |
| * "Java Cryptography Architecture API Specification & 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>See the "Java Cryptography Architecture API Specification & |
| * 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 createSaslServer(String mechanism, String protocol, |
| String serverName, |
| Map<String, ?> 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 |
| * <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) |
| */ |
| public static Enumeration<SaslServerFactory> 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(); |
| } |
| } |