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