blob: 76b5717dc4c75018c7be9c9c9112504d4db72dc0 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 1999-2006 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26package javax.security.sasl;
27
28import javax.security.auth.callback.CallbackHandler;
29
30import java.util.Enumeration;
31import java.util.Iterator;
32import java.util.Map;
33import java.util.Set;
34import java.util.HashSet;
35import java.util.Collections;
36import java.security.Provider;
37import java.security.Security;
38
39/**
40 * A static class for creating SASL clients and servers.
41 *<p>
42 * This class defines the policy of how to locate, load, and instantiate
43 * SASL clients and servers.
44 *<p>
45 * For example, an application or library gets a SASL client by doing
46 * something like:
47 *<blockquote><pre>
48 * SaslClient sc = Sasl.createSaslClient(mechanisms,
49 * authorizationId, protocol, serverName, props, callbackHandler);
50 *</pre></blockquote>
51 * It can then proceed to use the instance to create an authentication connection.
52 *<p>
53 * Similarly, a server gets a SASL server by using code that looks as follows:
54 *<blockquote><pre>
55 * SaslServer ss = Sasl.createSaslServer(mechanism,
56 * protocol, serverName, props, callbackHandler);
57 *</pre></blockquote>
58 *
59 * @since 1.5
60 *
61 * @author Rosanna Lee
62 * @author Rob Weltman
63 */
64public class Sasl {
65 // Cannot create one of these
66 private Sasl() {
67 }
68
69 /**
70 * The name of a property that specifies the quality-of-protection to use.
71 * The property contains a comma-separated, ordered list
72 * of quality-of-protection values that the
73 * client or server is willing to support. A qop value is one of
74 * <ul>
75 * <li><tt>"auth"</tt> - authentication only</li>
76 * <li><tt>"auth-int"</tt> - authentication plus integrity protection</li>
77 * <li><tt>"auth-conf"</tt> - authentication plus integrity and confidentiality
78 * protection</li>
79 * </ul>
80 *
81 * The order of the list specifies the preference order of the client or
82 * server. If this property is absent, the default qop is <tt>"auth"</tt>.
83 * The value of this constant is <tt>"javax.security.sasl.qop"</tt>.
84 */
85 public static final String QOP = "javax.security.sasl.qop";
86
87 /**
88 * The name of a property that specifies the cipher strength to use.
89 * The property contains a comma-separated, ordered list
90 * of cipher strength values that
91 * the client or server is willing to support. A strength value is one of
92 * <ul>
93 * <li><tt>"low"</tt></li>
94 * <li><tt>"medium"</tt></li>
95 * <li><tt>"high"</tt></li>
96 * </ul>
97 * The order of the list specifies the preference order of the client or
98 * server. An implementation should allow configuration of the meaning
99 * of these values. An application may use the Java Cryptography
100 * Extension (JCE) with JCE-aware mechanisms to control the selection of
101 * cipher suites that match the strength values.
102 * <BR>
103 * If this property is absent, the default strength is
104 * <tt>"high,medium,low"</tt>.
105 * The value of this constant is <tt>"javax.security.sasl.strength"</tt>.
106 */
107 public static final String STRENGTH = "javax.security.sasl.strength";
108
109 /**
110 * The name of a property that specifies whether the
111 * server must authenticate to the client. The property contains
112 * <tt>"true"</tt> if the server must
113 * authenticate the to client; <tt>"false"</tt> otherwise.
114 * The default is <tt>"false"</tt>.
115 * <br>The value of this constant is
116 * <tt>"javax.security.sasl.server.authentication"</tt>.
117 */
118 public static final String SERVER_AUTH =
119 "javax.security.sasl.server.authentication";
120
121 /**
122 * The name of a property that specifies the maximum size of the receive
123 * buffer in bytes of <tt>SaslClient</tt>/<tt>SaslServer</tt>.
124 * The property contains the string representation of an integer.
125 * <br>If this property is absent, the default size
126 * is defined by the mechanism.
127 * <br>The value of this constant is <tt>"javax.security.sasl.maxbuffer"</tt>.
128 */
129 public static final String MAX_BUFFER = "javax.security.sasl.maxbuffer";
130
131 /**
132 * The name of a property that specifies the maximum size of the raw send
133 * buffer in bytes of <tt>SaslClient</tt>/<tt>SaslServer</tt>.
134 * The property contains the string representation of an integer.
135 * The value of this property is negotiated between the client and server
136 * during the authentication exchange.
137 * <br>The value of this constant is <tt>"javax.security.sasl.rawsendsize"</tt>.
138 */
139 public static final String RAW_SEND_SIZE = "javax.security.sasl.rawsendsize";
140
141 /**
142 * The name of a property that specifies whether to reuse previously
143 * authenticated session information. The property contains "true" if the
144 * mechanism implementation may attempt to reuse previously authenticated
145 * session information; it contains "false" if the implementation must
146 * not reuse previously authenticated session information. A setting of
147 * "true" serves only as a hint: it does not necessarily entail actual
148 * reuse because reuse might not be possible due to a number of reasons,
149 * including, but not limited to, lack of mechanism support for reuse,
150 * expiration of reusable information, and the peer's refusal to support
151 * reuse.
152 *
153 * The property's default value is "false". The value of this constant
154 * is "javax.security.sasl.reuse".
155 *
156 * Note that all other parameters and properties required to create a
157 * SASL client/server instance must be provided regardless of whether
158 * this property has been supplied. That is, you cannot supply any less
159 * information in anticipation of reuse.
160 *
161 * Mechanism implementations that support reuse might allow customization
162 * of its implementation, for factors such as cache size, timeouts, and
163 * criteria for reuseability. Such customizations are
164 * implementation-dependent.
165 */
166 public static final String REUSE = "javax.security.sasl.reuse";
167
168 /**
169 * The name of a property that specifies
170 * whether mechanisms susceptible to simple plain passive attacks (e.g.,
171 * "PLAIN") are not permitted. The property
172 * contains <tt>"true"</tt> if such mechanisms are not permitted;
173 * <tt>"false"</tt> if such mechanisms are permitted.
174 * The default is <tt>"false"</tt>.
175 * <br>The value of this constant is
176 * <tt>"javax.security.sasl.policy.noplaintext"</tt>.
177 */
178 public static final String POLICY_NOPLAINTEXT =
179 "javax.security.sasl.policy.noplaintext";
180
181 /**
182 * The name of a property that specifies whether
183 * mechanisms susceptible to active (non-dictionary) attacks
184 * are not permitted.
185 * The property contains <tt>"true"</tt>
186 * if mechanisms susceptible to active attacks
187 * are not permitted; <tt>"false"</tt> if such mechanisms are permitted.
188 * The default is <tt>"false"</tt>.
189 * <br>The value of this constant is
190 * <tt>"javax.security.sasl.policy.noactive"</tt>.
191 */
192 public static final String POLICY_NOACTIVE =
193 "javax.security.sasl.policy.noactive";
194
195 /**
196 * The name of a property that specifies whether
197 * mechanisms susceptible to passive dictionary attacks are not permitted.
198 * The property contains <tt>"true"</tt>
199 * if mechanisms susceptible to dictionary attacks are not permitted;
200 * <tt>"false"</tt> if such mechanisms are permitted.
201 * The default is <tt>"false"</tt>.
202 *<br>
203 * The value of this constant is
204 * <tt>"javax.security.sasl.policy.nodictionary"</tt>.
205 */
206 public static final String POLICY_NODICTIONARY =
207 "javax.security.sasl.policy.nodictionary";
208
209 /**
210 * The name of a property that specifies whether mechanisms that accept
211 * anonymous login are not permitted. The property contains <tt>"true"</tt>
212 * if mechanisms that accept anonymous login are not permitted;
213 * <tt>"false"</tt>
214 * if such mechanisms are permitted. The default is <tt>"false"</tt>.
215 *<br>
216 * The value of this constant is
217 * <tt>"javax.security.sasl.policy.noanonymous"</tt>.
218 */
219 public static final String POLICY_NOANONYMOUS =
220 "javax.security.sasl.policy.noanonymous";
221
222 /**
223 * The name of a property that specifies whether mechanisms that implement
224 * forward secrecy between sessions are required. Forward secrecy
225 * means that breaking into one session will not automatically
226 * provide information for breaking into future sessions.
227 * The property
228 * contains <tt>"true"</tt> if mechanisms that implement forward secrecy
229 * between sessions are required; <tt>"false"</tt> if such mechanisms
230 * are not required. The default is <tt>"false"</tt>.
231 *<br>
232 * The value of this constant is
233 * <tt>"javax.security.sasl.policy.forward"</tt>.
234 */
235 public static final String POLICY_FORWARD_SECRECY =
236 "javax.security.sasl.policy.forward";
237
238 /**
239 * The name of a property that specifies whether
240 * mechanisms that pass client credentials are required. The property
241 * contains <tt>"true"</tt> if mechanisms that pass
242 * client credentials are required; <tt>"false"</tt>
243 * if such mechanisms are not required. The default is <tt>"false"</tt>.
244 *<br>
245 * The value of this constant is
246 * <tt>"javax.security.sasl.policy.credentials"</tt>.
247 */
248 public static final String POLICY_PASS_CREDENTIALS =
249 "javax.security.sasl.policy.credentials";
250
251 /**
252 * The name of a property that specifies the credentials to use.
253 * The property contains a mechanism-specific Java credential object.
254 * Mechanism implementations may examine the value of this property
255 * to determine whether it is a class that they support.
256 * The property may be used to supply credentials to a mechanism that
257 * supports delegated authentication.
258 *<br>
259 * The value of this constant is
260 * <tt>"javax.security.sasl.credentials"</tt>.
261 */
262 public static final String CREDENTIALS = "javax.security.sasl.credentials";
263
264 /**
265 * Creates a <tt>SaslClient</tt> using the parameters supplied.
266 *
267 * This method uses the
268<a href="{@docRoot}/../technotes/guides/security/crypto/CryptoSpec.html#Provider">JCA Security Provider Framework</a>, described in the
269 * "Java Cryptography Architecture API Specification & Reference", for
270 * locating and selecting a <tt>SaslClient</tt> implementation.
271 *
272 * First, it
273 * obtains an ordered list of <tt>SaslClientFactory</tt> instances from
274 * the registered security providers for the "SaslClientFactory" service
275 * and the specified SASL mechanism(s). It then invokes
276 * <tt>createSaslClient()</tt> on each factory instance on the list
277 * until one produces a non-null <tt>SaslClient</tt> instance. It returns
278 * the non-null <tt>SaslClient</tt> instance, or null if the search fails
279 * to produce a non-null <tt>SaslClient</tt> instance.
280 *<p>
281 * A security provider for SaslClientFactory registers with the
282 * JCA Security Provider Framework keys of the form <br>
283 * <tt>SaslClientFactory.<em>mechanism_name</em></tt>
284 * <br>
285 * and values that are class names of implementations of
286 * <tt>javax.security.sasl.SaslClientFactory</tt>.
287 *
288 * For example, a provider that contains a factory class,
289 * <tt>com.wiz.sasl.digest.ClientFactory</tt>, that supports the
290 * "DIGEST-MD5" mechanism would register the following entry with the JCA:
291 * <tt>SaslClientFactory.DIGEST-MD5 com.wiz.sasl.digest.ClientFactory</tt>
292 *<p>
293 * See the
294 * "Java Cryptography Architecture API Specification & Reference"
295 * for information about how to install and configure security service
296 * providers.
297 *
298 * @param mechanisms The non-null list of mechanism names to try. Each is the
299 * IANA-registered name of a SASL mechanism. (e.g. "GSSAPI", "CRAM-MD5").
300 * @param authorizationId The possibly null protocol-dependent
301 * identification to be used for authorization.
302 * If null or empty, the server derives an authorization
303 * ID from the client's authentication credentials.
304 * When the SASL authentication completes successfully,
305 * the specified entity is granted access.
306 *
307 * @param protocol The non-null string name of the protocol for which
308 * the authentication is being performed (e.g., "ldap").
309 *
310 * @param serverName The non-null fully-qualified host name of the server
311 * to authenticate to.
312 *
313 * @param props The possibly null set of properties used to
314 * select the SASL mechanism and to configure the authentication
315 * exchange of the selected mechanism.
316 * For example, if <tt>props</tt> contains the
317 * <code>Sasl.POLICY_NOPLAINTEXT</code> property with the value
318 * <tt>"true"</tt>, then the selected
319 * SASL mechanism must not be susceptible to simple plain passive attacks.
320 * In addition to the standard properties declared in this class,
321 * other, possibly mechanism-specific, properties can be included.
322 * Properties not relevant to the selected mechanism are ignored,
323 * including any map entries with non-String keys.
324 *
325 * @param cbh The possibly null callback handler to used by the SASL
326 * mechanisms to get further information from the application/library
327 * to complete the authentication. For example, a SASL mechanism might
328 * require the authentication ID, password and realm from the caller.
329 * The authentication ID is requested by using a <tt>NameCallback</tt>.
330 * The password is requested by using a <tt>PasswordCallback</tt>.
331 * The realm is requested by using a <tt>RealmChoiceCallback</tt> if there is a list
332 * of realms to choose from, and by using a <tt>RealmCallback</tt> if
333 * the realm must be entered.
334 *
335 *@return A possibly null <tt>SaslClient</tt> created using the parameters
336 * supplied. If null, cannot find a <tt>SaslClientFactory</tt>
337 * that will produce one.
338 *@exception SaslException If cannot create a <tt>SaslClient</tt> because
339 * of an error.
340 */
341 public static SaslClient createSaslClient(
342 String[] mechanisms,
343 String authorizationId,
344 String protocol,
345 String serverName,
346 Map<String,?> props,
347 CallbackHandler cbh) throws SaslException {
348
349 SaslClient mech = null;
350 SaslClientFactory fac;
351 String className;
352 String mechName;
353
354 for (int i = 0; i < mechanisms.length; i++) {
355 if ((mechName=mechanisms[i]) == null) {
356 throw new NullPointerException(
357 "Mechanism name cannot be null");
358 } else if (mechName.length() == 0) {
359 continue;
360 }
361 String mechFilter = "SaslClientFactory." + mechName;
362 Provider[] provs = Security.getProviders(mechFilter);
363 for (int j = 0; provs != null && j < provs.length; j++) {
364 className = provs[j].getProperty(mechFilter);
365 if (className == null) {
366 // Case is ignored
367 continue;
368 }
369
370 fac = (SaslClientFactory) loadFactory(provs[j], className);
371 if (fac != null) {
372 mech = fac.createSaslClient(
373 new String[]{mechanisms[i]}, authorizationId,
374 protocol, serverName, props, cbh);
375 if (mech != null) {
376 return mech;
377 }
378 }
379 }
380 }
381
382 return null;
383 }
384
385 private static Object loadFactory(Provider p, String className)
386 throws SaslException {
387 try {
388 /*
389 * Load the implementation class with the same class loader
390 * that was used to load the provider.
391 * In order to get the class loader of a class, the
392 * caller's class loader must be the same as or an ancestor of
393 * the class loader being returned. Otherwise, the caller must
394 * have "getClassLoader" permission, or a SecurityException
395 * will be thrown.
396 */
397 ClassLoader cl = p.getClass().getClassLoader();
398 Class implClass;
399 implClass = Class.forName(className, true, cl);
400 return implClass.newInstance();
401 } catch (ClassNotFoundException e) {
402 throw new SaslException("Cannot load class " + className, e);
403 } catch (InstantiationException e) {
404 throw new SaslException("Cannot instantiate class " + className, e);
405 } catch (IllegalAccessException e) {
406 throw new SaslException("Cannot access class " + className, e);
407 } catch (SecurityException e) {
408 throw new SaslException("Cannot access class " + className, e);
409 }
410 }
411
412
413 /**
414 * Creates a <tt>SaslServer</tt> for the specified mechanism.
415 *
416 * This method uses the
417<a href="{@docRoot}/../technotes/guides/security/crypto/CryptoSpec.html#Provider">JCA Security Provider Framework</a>,
418 * described in the
419 * "Java Cryptography Architecture API Specification & Reference", for
420 * locating and selecting a <tt>SaslServer</tt> implementation.
421 *
422 * First, it
423 * obtains an ordered list of <tt>SaslServerFactory</tt> instances from
424 * the registered security providers for the "SaslServerFactory" service
425 * and the specified mechanism. It then invokes
426 * <tt>createSaslServer()</tt> on each factory instance on the list
427 * until one produces a non-null <tt>SaslServer</tt> instance. It returns
428 * the non-null <tt>SaslServer</tt> instance, or null if the search fails
429 * to produce a non-null <tt>SaslServer</tt> instance.
430 *<p>
431 * A security provider for SaslServerFactory registers with the
432 * JCA Security Provider Framework keys of the form <br>
433 * <tt>SaslServerFactory.<em>mechanism_name</em></tt>
434 * <br>
435 * and values that are class names of implementations of
436 * <tt>javax.security.sasl.SaslServerFactory</tt>.
437 *
438 * For example, a provider that contains a factory class,
439 * <tt>com.wiz.sasl.digest.ServerFactory</tt>, that supports the
440 * "DIGEST-MD5" mechanism would register the following entry with the JCA:
441 * <tt>SaslServerFactory.DIGEST-MD5 com.wiz.sasl.digest.ServerFactory</tt>
442 *<p>
443 * See the
444 * "Java Cryptography Architecture API Specification & Reference"
445 * for information about how to install and configure security
446 * service providers.
447 *
448 * @param mechanism The non-null mechanism name. It must be an
449 * IANA-registered name of a SASL mechanism. (e.g. "GSSAPI", "CRAM-MD5").
450 * @param protocol The non-null string name of the protocol for which
451 * the authentication is being performed (e.g., "ldap").
452 * @param serverName The non-null fully qualified host name of the server.
453 * @param props The possibly null set of properties used to
454 * select the SASL mechanism and to configure the authentication
455 * exchange of the selected mechanism.
456 * For example, if <tt>props</tt> contains the
457 * <code>Sasl.POLICY_NOPLAINTEXT</code> property with the value
458 * <tt>"true"</tt>, then the selected
459 * SASL mechanism must not be susceptible to simple plain passive attacks.
460 * In addition to the standard properties declared in this class,
461 * other, possibly mechanism-specific, properties can be included.
462 * Properties not relevant to the selected mechanism are ignored,
463 * including any map entries with non-String keys.
464 *
465 * @param cbh The possibly null callback handler to used by the SASL
466 * mechanisms to get further information from the application/library
467 * to complete the authentication. For example, a SASL mechanism might
468 * require the authentication ID, password and realm from the caller.
469 * The authentication ID is requested by using a <tt>NameCallback</tt>.
470 * The password is requested by using a <tt>PasswordCallback</tt>.
471 * The realm is requested by using a <tt>RealmChoiceCallback</tt> if there is a list
472 * of realms to choose from, and by using a <tt>RealmCallback</tt> if
473 * the realm must be entered.
474 *
475 *@return A possibly null <tt>SaslServer</tt> created using the parameters
476 * supplied. If null, cannot find a <tt>SaslServerFactory</tt>
477 * that will produce one.
478 *@exception SaslException If cannot create a <tt>SaslServer</tt> because
479 * of an error.
480 **/
481 public static SaslServer
482 createSaslServer(String mechanism,
483 String protocol,
484 String serverName,
485 Map<String,?> props,
486 javax.security.auth.callback.CallbackHandler cbh)
487 throws SaslException {
488
489 SaslServer mech = null;
490 SaslServerFactory fac;
491 String className;
492
493 if (mechanism == null) {
494 throw new NullPointerException("Mechanism name cannot be null");
495 } else if (mechanism.length() == 0) {
496 return null;
497 }
498
499 String mechFilter = "SaslServerFactory." + mechanism;
500 Provider[] provs = Security.getProviders(mechFilter);
501 for (int j = 0; provs != null && j < provs.length; j++) {
502 className = provs[j].getProperty(mechFilter);
503 if (className == null) {
504 throw new SaslException("Provider does not support " +
505 mechFilter);
506 }
507 fac = (SaslServerFactory) loadFactory(provs[j], className);
508 if (fac != null) {
509 mech = fac.createSaslServer(
510 mechanism, protocol, serverName, props, cbh);
511 if (mech != null) {
512 return mech;
513 }
514 }
515 }
516
517 return null;
518 }
519
520 /**
521 * Gets an enumeration of known factories for producing <tt>SaslClient</tt>.
522 * This method uses the same algorithm for locating factories as
523 * <tt>createSaslClient()</tt>.
524 * @return A non-null enumeration of known factories for producing
525 * <tt>SaslClient</tt>.
526 * @see #createSaslClient
527 */
528 public static Enumeration<SaslClientFactory> getSaslClientFactories() {
529 Set<Object> facs = getFactories("SaslClientFactory");
530 final Iterator<Object> iter = facs.iterator();
531 return new Enumeration<SaslClientFactory>() {
532 public boolean hasMoreElements() {
533 return iter.hasNext();
534 }
535 public SaslClientFactory nextElement() {
536 return (SaslClientFactory)iter.next();
537 }
538 };
539 }
540
541 /**
542 * Gets an enumeration of known factories for producing <tt>SaslServer</tt>.
543 * This method uses the same algorithm for locating factories as
544 * <tt>createSaslServer()</tt>.
545 * @return A non-null enumeration of known factories for producing
546 * <tt>SaslServer</tt>.
547 * @see #createSaslServer
548 */
549 public static Enumeration<SaslServerFactory> getSaslServerFactories() {
550 Set<Object> facs = getFactories("SaslServerFactory");
551 final Iterator<Object> iter = facs.iterator();
552 return new Enumeration<SaslServerFactory>() {
553 public boolean hasMoreElements() {
554 return iter.hasNext();
555 }
556 public SaslServerFactory nextElement() {
557 return (SaslServerFactory)iter.next();
558 }
559 };
560 }
561
562 private static Set<Object> getFactories(String serviceName) {
563 HashSet<Object> result = new HashSet<Object>();
564
565 if ((serviceName == null) || (serviceName.length() == 0) ||
566 (serviceName.endsWith("."))) {
567 return result;
568 }
569
570
571 Provider[] providers = Security.getProviders();
572 HashSet<String> classes = new HashSet<String>();
573 Object fac;
574
575 for (int i = 0; i < providers.length; i++) {
576 classes.clear();
577
578 // Check the keys for each provider.
579 for (Enumeration e = providers[i].keys(); e.hasMoreElements(); ) {
580 String currentKey = (String)e.nextElement();
581 if (currentKey.startsWith(serviceName)) {
582 // We should skip the currentKey if it contains a
583 // whitespace. The reason is: such an entry in the
584 // provider property contains attributes for the
585 // implementation of an algorithm. We are only interested
586 // in entries which lead to the implementation
587 // classes.
588 if (currentKey.indexOf(" ") < 0) {
589 String className = providers[i].getProperty(currentKey);
590 if (!classes.contains(className)) {
591 classes.add(className);
592 try {
593 fac = loadFactory(providers[i], className);
594 if (fac != null) {
595 result.add(fac);
596 }
597 }catch (Exception ignore) {
598 }
599 }
600 }
601 }
602 }
603 }
604 return Collections.unmodifiableSet(result);
605 }
606}