KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > javax > security > sasl > Sasl


1 /*
2  * @(#)Sasl.java 1.21 04/05/05
3  *
4  * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7
8 package javax.security.sasl;
9
10 import javax.security.auth.callback.CallbackHandler JavaDoc;
11
12 import java.util.Enumeration JavaDoc;
13 import java.util.Iterator JavaDoc;
14 import java.util.Map JavaDoc;
15 import java.util.Set JavaDoc;
16 import java.util.HashSet JavaDoc;
17 import java.util.Collections JavaDoc;
18 import java.security.Provider JavaDoc;
19 import java.security.Security JavaDoc;
20
21 /**
22  * A static class for creating SASL clients and servers.
23  *<p>
24  * This class defines the policy of how to locate, load, and instantiate
25  * SASL clients and servers.
26  *<p>
27  * For example, an application or library gets a SASL client by doing
28  * something like:
29  *<blockquote><pre>
30  * SaslClient sc = Sasl.createSaslClient(mechanisms,
31  * authorizationId, protocol, serverName, props, callbackHandler);
32  *</pre></blockquote>
33  * It can then proceed to use the instance to create an authentication connection.
34  *<p>
35  * Similarly, a server gets a SASL server by using code that looks as follows:
36  *<blockquote><pre>
37  * SaslServer ss = Sasl.createSaslServer(mechanism,
38  * protocol, serverName, props, callbackHandler);
39  *</pre></blockquote>
40  *
41  * @since 1.5
42  *
43  * @author Rosanna Lee
44  * @author Rob Weltman
45  */

46 public class Sasl {
47     // Cannot create one of these
48
private Sasl() {
49     }
50
51     /**
52      * The name of a property that specifies the quality-of-protection to use.
53      * The property contains a comma-separated, ordered list
54      * of quality-of-protection values that the
55      * client or server is willing to support. A qop value is one of
56      * <ul>
57      * <li><tt>"auth"</tt> - authentication only</li>
58      * <li><tt>"auth-int"</tt> - authentication plus integrity protection</li>
59      * <li><tt>"auth-conf"</tt> - authentication plus integrity and confidentiality
60      * protection</li>
61      * </ul>
62      *
63      * The order of the list specifies the preference order of the client or
64      * server. If this property is absent, the default qop is <tt>"auth"</tt>.
65      * The value of this constant is <tt>"javax.security.sasl.qop"</tt>.
66      */

67     public static final String JavaDoc QOP = "javax.security.sasl.qop";
68
69     /**
70      * The name of a property that specifies the cipher strength to use.
71      * The property contains a comma-separated, ordered list
72      * of cipher strength values that
73      * the client or server is willing to support. A strength value is one of
74      * <ul>
75      * <li><tt>"low"</tt></li>
76      * <li><tt>"medium"</tt></li>
77      * <li><tt>"high"</tt></li>
78      * </ul>
79      * The order of the list specifies the preference order of the client or
80      * server. An implementation should allow configuration of the meaning
81      * of these values. An application may use the Java Cryptography
82      * Extension (JCE) with JCE-aware mechanisms to control the selection of
83      *cipher suites that match the strength values.
84      * <BR>
85      * If this property is absent, the default strength is
86      * <tt>"high,medium,low"</tt>.
87      * The value of this constant is <tt>"javax.security.sasl.strength"</tt>.
88      */

89     public static final String JavaDoc STRENGTH = "javax.security.sasl.strength";
90
91     /**
92      * The name of a property that specifies whether the
93      * server must authenticate to the client. The property contains
94      * <tt>"true"</tt> if the server must
95      * authenticate the to client; <tt>"false"</tt> otherwise.
96      * The default is <tt>"false"</tt>.
97      * <br>The value of this constant is
98      * <tt>"javax.security.sasl.server.authentication"</tt>.
99      */

100     public static final String JavaDoc SERVER_AUTH =
101     "javax.security.sasl.server.authentication";
102
103     /**
104      * The name of a property that specifies the maximum size of the receive
105      * buffer in bytes of <tt>SaslClient</tt>/<tt>SaslServer</tt>.
106      * The property contains the string representation of an integer.
107      * <br>If this property is absent, the default size
108      * is defined by the mechanism.
109      * <br>The value of this constant is <tt>"javax.security.sasl.maxbuffer"</tt>.
110      */

111     public static final String JavaDoc MAX_BUFFER = "javax.security.sasl.maxbuffer";
112
113     /**
114      * The name of a property that specifies the maximum size of the raw send
115      * buffer in bytes of <tt>SaslClient</tt>/<tt>SaslServer</tt>.
116      * The property contains the string representation of an integer.
117      * The value of this property is negotiated between the client and server
118      * during the authentication exchange.
119      * <br>The value of this constant is <tt>"javax.security.sasl.rawsendsize"</tt>.
120      */

121     public static final String JavaDoc RAW_SEND_SIZE = "javax.security.sasl.rawsendsize";
122
123     /**
124      * The name of a property that specifies whether to reuse previously
125      * authenticated session information. The property contains "true" if the
126      * mechanism implementation may attempt to reuse previously authenticated
127      * session information; it contains "false" if the implementation must
128      * not reuse previously authenticated session information. A setting of
129      * "true" serves only as a hint: it does not necessarily entail actual
130      * reuse because reuse might not be possible due to a number of reasons,
131      * including, but not limited to, lack of mechanism support for reuse,
132      * expiration of reusable information, and the peer's refusal to support
133      * reuse.
134      *
135      * The property's default value is "false". The value of this constant
136      * is "javax.security.sasl.reuse".
137      *
138      * Note that all other parameters and properties required to create a
139      * SASL client/server instance must be provided regardless of whether
140      * this property has been supplied. That is, you cannot supply any less
141      * information in anticipation of reuse.
142      *
143      * Mechanism implementations that support reuse might allow customization
144      * of its implementation, for factors such as cache size, timeouts, and
145      * criteria for reuseability. Such customizations are
146      * implementation-dependent.
147      */

148      public static final String JavaDoc REUSE = "javax.security.sasl.reuse";
149
150     /**
151      * The name of a property that specifies
152      * whether mechanisms susceptible to simple plain passive attacks (e.g.,
153      * "PLAIN") are not permitted. The property
154      * contains <tt>"true"</tt> if such mechanisms are not permitted;
155      * <tt>"false"</tt> if such mechanisms are permitted.
156      * The default is <tt>"false"</tt>.
157      * <br>The value of this constant is
158      * <tt>"javax.security.sasl.policy.noplaintext"</tt>.
159      */

160     public static final String JavaDoc POLICY_NOPLAINTEXT =
161     "javax.security.sasl.policy.noplaintext";
162
163     /**
164      * The name of a property that specifies whether
165      * mechanisms susceptible to active (non-dictionary) attacks
166      * are not permitted.
167      * The property contains <tt>"true"</tt>
168      * if mechanisms susceptible to active attacks
169      * are not permitted; <tt>"false"</tt> if such mechanisms are permitted.
170      * The default is <tt>"false"</tt>.
171      * <br>The value of this constant is
172      * <tt>"javax.security.sasl.policy.noactive"</tt>.
173      */

174     public static final String JavaDoc POLICY_NOACTIVE =
175     "javax.security.sasl.policy.noactive";
176
177     /**
178      * The name of a property that specifies whether
179      * mechanisms susceptible to passive dictionary attacks are not permitted.
180      * The property contains <tt>"true"</tt>
181      * if mechanisms susceptible to dictionary attacks are not permitted;
182      * <tt>"false"</tt> if such mechanisms are permitted.
183      * The default is <tt>"false"</tt>.
184      *<br>
185      * The value of this constant is
186      * <tt>"javax.security.sasl.policy.nodictionary"</tt>.
187      */

188     public static final String JavaDoc POLICY_NODICTIONARY =
189     "javax.security.sasl.policy.nodictionary";
190
191     /**
192      * The name of a property that specifies whether mechanisms that accept
193      * anonymous login are not permitted. The property contains <tt>"true"</tt>
194      * if mechanisms that accept anonymous login are not permitted;
195      * <tt>"false"</tt>
196      * if such mechanisms are permitted. The default is <tt>"false"</tt>.
197      *<br>
198      * The value of this constant is
199      * <tt>"javax.security.sasl.policy.noanonymous"</tt>.
200      */

201     public static final String JavaDoc POLICY_NOANONYMOUS =
202     "javax.security.sasl.policy.noanonymous";
203
204      /**
205       * The name of a property that specifies whether mechanisms that implement
206       * forward secrecy between sessions are required. Forward secrecy
207       * means that breaking into one session will not automatically
208       * provide information for breaking into future sessions.
209       * The property
210       * contains <tt>"true"</tt> if mechanisms that implement forward secrecy
211       * between sessions are required; <tt>"false"</tt> if such mechanisms
212       * are not required. The default is <tt>"false"</tt>.
213       *<br>
214       * The value of this constant is
215       * <tt>"javax.security.sasl.policy.forward"</tt>.
216       */

217     public static final String JavaDoc POLICY_FORWARD_SECRECY =
218     "javax.security.sasl.policy.forward";
219
220     /**
221      * The name of a property that specifies whether
222      * mechanisms that pass client credentials are required. The property
223      * contains <tt>"true"</tt> if mechanisms that pass
224      * client credentials are required; <tt>"false"</tt>
225      * if such mechanisms are not required. The default is <tt>"false"</tt>.
226      *<br>
227      * The value of this constant is
228      * <tt>"javax.security.sasl.policy.credentials"</tt>.
229      */

230     public static final String JavaDoc POLICY_PASS_CREDENTIALS =
231     "javax.security.sasl.policy.credentials";
232
233
234     /**
235      * Creates a <tt>SaslClient</tt> using the parameters supplied.
236      *
237      * This method uses the
238 <a HREF="http://java.sun.com/j2se/1.4/docs/guide/security/CryptoSpec.html#Provider">JCA Security Provider Framework</a>, described in the
239      * "Java Cryptography Architecture API Specification & Reference", for
240      * locating and selecting a <tt>SaslClient</tt> implementation.
241      *
242      * First, it
243      * obtains an ordered list of <tt>SaslClientFactory</tt> instances from
244      * the registered security providers for the "SaslClientFactory" service
245      * and the specified SASL mechanism(s). It then invokes
246      * <tt>createSaslClient()</tt> on each factory instance on the list
247      * until one produces a non-null <tt>SaslClient</tt> instance. It returns
248      * the non-null <tt>SaslClient</tt> instance, or null if the search fails
249      * to produce a non-null <tt>SaslClient</tt> instance.
250      *<p>
251      * A security provider for SaslClientFactory registers with the
252      * JCA Security Provider Framework keys of the form <br>
253      * <tt>SaslClientFactory.<em>mechanism_name</em></tt>
254      * <br>
255      * and values that are class names of implementations of
256      * <tt>javax.security.sasl.SaslClientFactory</tt>.
257      *
258      * For example, a provider that contains a factory class,
259      * <tt>com.wiz.sasl.digest.ClientFactory</tt>, that supports the
260      * "DIGEST-MD5" mechanism would register the following entry with the JCA:
261      * <tt>SaslClientFactory.DIGEST-MD5 com.wiz.sasl.digest.ClientFactory</tt>
262      *<p>
263      * See the
264      * "Java Cryptography Architecture API Specification & Reference"
265      * for information about how to install and configure security service
266      * providers.
267      *
268      * @param mechanisms The non-null list of mechanism names to try. Each is the
269      * IANA-registered name of a SASL mechanism. (e.g. "GSSAPI", "CRAM-MD5").
270      * @param authorizationId The possibly null protocol-dependent
271      * identification to be used for authorization.
272      * If null or empty, the server derives an authorization
273      * ID from the client's authentication credentials.
274      * When the SASL authentication completes successfully,
275      * the specified entity is granted access.
276      *
277      * @param protocol The non-null string name of the protocol for which
278      * the authentication is being performed (e.g., "ldap").
279      *
280      * @param serverName The non-null fully-qualified host name of the server
281      * to authenticate to.
282      *
283      * @param props The possibly null set of properties used to
284      * select the SASL mechanism and to configure the authentication
285      * exchange of the selected mechanism.
286      * For example, if <tt>props</tt> contains the
287      * <code>Sasl.POLICY_NOPLAINTEXT</code> property with the value
288      * <tt>"true"</tt>, then the selected
289      * SASL mechanism must not be susceptible to simple plain passive attacks.
290      * In addition to the standard properties declared in this class,
291      * other, possibly mechanism-specific, properties can be included.
292      * Properties not relevant to the selected mechanism are ignored.
293      *
294      * @param cbh The possibly null callback handler to used by the SASL
295      * mechanisms to get further information from the application/library
296      * to complete the authentication. For example, a SASL mechanism might
297      * require the authentication ID, password and realm from the caller.
298      * The authentication ID is requested by using a <tt>NameCallback</tt>.
299      * The password is requested by using a <tt>PasswordCallback</tt>.
300      * The realm is requested by using a <tt>RealmChoiceCallback</tt> if there is a list
301      * of realms to choose from, and by using a <tt>RealmCallback</tt> if
302      * the realm must be entered.
303      *
304      *@return A possibly null <tt>SaslClient</tt> created using the parameters
305      * supplied. If null, cannot find a <tt>SaslClientFactory</tt>
306      * that will produce one.
307      *@exception SaslException If cannot create a <tt>SaslClient</tt> because
308      * of an error.
309      */

310     public static SaslClient JavaDoc createSaslClient(
311     String JavaDoc[] mechanisms,
312     String JavaDoc authorizationId,
313     String JavaDoc protocol,
314     String JavaDoc serverName,
315     Map JavaDoc<String JavaDoc,?> props,
316     CallbackHandler JavaDoc cbh) throws SaslException JavaDoc {
317         
318         SaslClient JavaDoc mech = null;
319     SaslClientFactory JavaDoc fac;
320     String JavaDoc className;
321     String JavaDoc mechName;
322
323     for (int i = 0; i < mechanisms.length; i++) {
324         if ((mechName=mechanisms[i]) == null) {
325         throw new NullPointerException JavaDoc(
326             "Mechanism name cannot be null");
327         } else if (mechName.length() == 0) {
328         continue;
329         }
330         String JavaDoc mechFilter = "SaslClientFactory." + mechName;
331         Provider JavaDoc[] provs = Security.getProviders(mechFilter);
332         for (int j = 0; provs != null && j < provs.length; j++) {
333         className = provs[j].getProperty(mechFilter);
334         if (className == null) {
335             // Case is ignored
336
continue;
337         }
338
339         fac = (SaslClientFactory JavaDoc) loadFactory(provs[j], className);
340         if (fac != null) {
341             mech = fac.createSaslClient(
342             new String JavaDoc[]{mechanisms[i]}, authorizationId,
343             protocol, serverName, props, cbh);
344             if (mech != null) {
345             return mech;
346             }
347         }
348         }
349     }
350
351     return null;
352     }
353
354     private static Object JavaDoc loadFactory(Provider JavaDoc p, String JavaDoc className)
355     throws SaslException JavaDoc {
356     try {
357         /*
358          * Load the implementation class with the same class loader
359          * that was used to load the provider.
360          * In order to get the class loader of a class, the
361          * caller's class loader must be the same as or an ancestor of
362          * the class loader being returned. Otherwise, the caller must
363          * have "getClassLoader" permission, or a SecurityException
364          * will be thrown.
365          */

366         ClassLoader JavaDoc cl = p.getClass().getClassLoader();
367         Class JavaDoc implClass;
368         implClass = Class.forName(className, true, cl);
369         return implClass.newInstance();
370     } catch (ClassNotFoundException JavaDoc e) {
371         throw new SaslException JavaDoc("Cannot load class " + className, e);
372     } catch (InstantiationException JavaDoc e) {
373         throw new SaslException JavaDoc("Cannot instantiate class " + className, e);
374     } catch (IllegalAccessException JavaDoc e) {
375         throw new SaslException JavaDoc("Cannot access class " + className, e);
376     } catch (SecurityException JavaDoc e) {
377         throw new SaslException JavaDoc("Cannot access class " + className, e);
378     }
379     }
380
381     
382     /**
383      * Creates a <tt>SaslServer</tt> for the specified mechanism.
384      *
385      * This method uses the
386 <a HREF="http://java.sun.com/j2se/1.4/docs/guide/security/CryptoSpec.html#Provider">JCA Security Provider Framework</a>,
387      * described in the
388      * "Java Cryptography Architecture API Specification & Reference", for
389      * locating and selecting a <tt>SaslServer</tt> implementation.
390      *
391      * First, it
392      * obtains an ordered list of <tt>SaslServerFactory</tt> instances from
393      * the registered security providers for the "SaslServerFactory" service
394      * and the specified mechanism. It then invokes
395      * <tt>createSaslServer()</tt> on each factory instance on the list
396      * until one produces a non-null <tt>SaslServer</tt> instance. It returns
397      * the non-null <tt>SaslServer</tt> instance, or null if the search fails
398      * to produce a non-null <tt>SaslServer</tt> instance.
399      *<p>
400      * A security provider for SaslServerFactory registers with the
401      * JCA Security Provider Framework keys of the form <br>
402      * <tt>SaslServerFactory.<em>mechanism_name</em></tt>
403      * <br>
404      * and values that are class names of implementations of
405      * <tt>javax.security.sasl.SaslServerFactory</tt>.
406      *
407      * For example, a provider that contains a factory class,
408      * <tt>com.wiz.sasl.digest.ServerFactory</tt>, that supports the
409      * "DIGEST-MD5" mechanism would register the following entry with the JCA:
410      * <tt>SaslServerFactory.DIGEST-MD5 com.wiz.sasl.digest.ServerFactory</tt>
411      *<p>
412      * See the
413      * "Java Cryptography Architecture API Specification & Reference"
414      * for information about how to install and configure security
415      * service providers.
416      *
417      * @param mechanism The non-null mechanism name. It must be an
418      * IANA-registered name of a SASL mechanism. (e.g. "GSSAPI", "CRAM-MD5").
419      * @param protocol The non-null string name of the protocol for which
420      * the authentication is being performed (e.g., "ldap").
421      * @param serverName The non-null fully qualified host name of the server.
422      * @param props The possibly null set of properties used to
423      * select the SASL mechanism and to configure the authentication
424      * exchange of the selected mechanism.
425      * For example, if <tt>props</tt> contains the
426      * <code>Sasl.POLICY_NOPLAINTEXT</code> property with the value
427      * <tt>"true"</tt>, then the selected
428      * SASL mechanism must not be susceptible to simple plain passive attacks.
429      * In addition to the standard properties declared in this class,
430      * other, possibly mechanism-specific, properties can be included.
431      * Properties not relevant to the selected mechanism are ignored.
432      *
433      * @param cbh The possibly null callback handler to used by the SASL
434      * mechanisms to get further information from the application/library
435      * to complete the authentication. For example, a SASL mechanism might
436      * require the authentication ID, password and realm from the caller.
437      * The authentication ID is requested by using a <tt>NameCallback</tt>.
438      * The password is requested by using a <tt>PasswordCallback</tt>.
439      * The realm is requested by using a <tt>RealmChoiceCallback</tt> if there is a list
440      * of realms to choose from, and by using a <tt>RealmCallback</tt> if
441      * the realm must be entered.
442      *
443      *@return A possibly null <tt>SaslServer</tt> created using the parameters
444      * supplied. If null, cannot find a <tt>SaslServerFactory</tt>
445      * that will produce one.
446      *@exception SaslException If cannot create a <tt>SaslServer</tt> because
447      * of an error.
448      **/

449     public static SaslServer JavaDoc
450     createSaslServer(String JavaDoc mechanism,
451                     String JavaDoc protocol,
452                     String JavaDoc serverName,
453                     Map JavaDoc<String JavaDoc,?> props,
454                     javax.security.auth.callback.CallbackHandler JavaDoc cbh)
455     throws SaslException JavaDoc {
456
457         SaslServer JavaDoc mech = null;
458     SaslServerFactory JavaDoc fac;
459     String JavaDoc className;
460
461     if (mechanism == null) {
462         throw new NullPointerException JavaDoc("Mechanism name cannot be null");
463     } else if (mechanism.length() == 0) {
464         return null;
465     }
466
467     String JavaDoc mechFilter = "SaslServerFactory." + mechanism;
468     Provider JavaDoc[] provs = Security.getProviders(mechFilter);
469     for (int j = 0; provs != null && j < provs.length; j++) {
470         className = provs[j].getProperty(mechFilter);
471         if (className == null) {
472         throw new SaslException JavaDoc("Provider does not support " +
473             mechFilter);
474         }
475         fac = (SaslServerFactory JavaDoc) loadFactory(provs[j], className);
476         if (fac != null) {
477         mech = fac.createSaslServer(
478             mechanism, protocol, serverName, props, cbh);
479         if (mech != null) {
480             return mech;
481         }
482         }
483     }
484
485     return null;
486     }
487
488     /**
489      * Gets an enumeration of known factories for producing <tt>SaslClient</tt>.
490      * This method uses the same algorithm for locating factories as
491      * <tt>createSaslClient()</tt>.
492      * @return A non-null enumeration of known factories for producing
493      * <tt>SaslClient</tt>.
494      * @see #createSaslClient
495      */

496     public static Enumeration JavaDoc<SaslClientFactory JavaDoc> getSaslClientFactories() {
497     Set JavaDoc facs = getFactories("SaslClientFactory");
498     final Iterator JavaDoc iter = facs.iterator();
499     return new Enumeration JavaDoc<SaslClientFactory JavaDoc>() {
500         public boolean hasMoreElements() {
501         return iter.hasNext();
502         }
503         public SaslClientFactory JavaDoc nextElement() {
504         return (SaslClientFactory JavaDoc)iter.next();
505         }
506     };
507     }
508
509     /**
510      * Gets an enumeration of known factories for producing <tt>SaslServer</tt>.
511      * This method uses the same algorithm for locating factories as
512      * <tt>createSaslServer()</tt>.
513      * @return A non-null enumeration of known factories for producing
514      * <tt>SaslServer</tt>.
515      * @see #createSaslServer
516      */

517     public static Enumeration JavaDoc<SaslServerFactory JavaDoc> getSaslServerFactories() {
518     Set JavaDoc facs = getFactories("SaslServerFactory");
519     final Iterator JavaDoc iter = facs.iterator();
520     return new Enumeration JavaDoc<SaslServerFactory JavaDoc>() {
521         public boolean hasMoreElements() {
522         return iter.hasNext();
523         }
524         public SaslServerFactory JavaDoc nextElement() {
525         return (SaslServerFactory JavaDoc)iter.next();
526         }
527     };
528     }
529
530     private static Set JavaDoc getFactories(String JavaDoc serviceName) {
531     HashSet JavaDoc result = new HashSet JavaDoc();
532
533     if ((serviceName == null) || (serviceName.length() == 0) ||
534         (serviceName.endsWith("."))) {
535         return result;
536     }
537
538
539     Provider JavaDoc[] providers = Security.getProviders();
540     HashSet JavaDoc classes = new HashSet JavaDoc();
541     Object JavaDoc fac;
542
543     for (int i = 0; i < providers.length; i++) {
544         classes.clear();
545
546         // Check the keys for each provider.
547
for (Enumeration JavaDoc e = providers[i].keys(); e.hasMoreElements(); ) {
548         String JavaDoc currentKey = (String JavaDoc)e.nextElement();
549         if (currentKey.startsWith(serviceName)) {
550             // We should skip the currentKey if it contains a
551
// whitespace. The reason is: such an entry in the
552
// provider property contains attributes for the
553
// implementation of an algorithm. We are only interested
554
// in entries which lead to the implementation
555
// classes.
556
if (currentKey.indexOf(" ") < 0) {
557             String JavaDoc className = providers[i].getProperty(currentKey);
558             if (!classes.contains(className)) {
559                 classes.add(className);
560                 try {
561                 fac = loadFactory(providers[i], className);
562                 if (fac != null) {
563                     result.add(fac);
564                 }
565                 }catch (Exception JavaDoc ignore) {
566                 }
567             }
568             }
569         }
570         }
571     }
572     return Collections.unmodifiableSet(result);
573     }
574 }
575
Popular Tags