1 /*
2 * Copyright (c) 1999, 2013, Oracle and/or its affiliates. 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. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package javax.security.sasl;
27
28 import javax.security.auth.callback.CallbackHandler;
29
30 import java.util.Enumeration;
31 import java.util.Iterator;
32 import java.util.Map;
33 import java.util.Set;
34 import java.util.HashSet;
35 import java.util.Collections;
36 import java.security.Provider;
37 import 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);
343 * The realm is requested by using a {@code RealmChoiceCallback} if there is a list
344 * of realms to choose from, and by using a {@code RealmCallback} if
345 * the realm must be entered.
346 *
347 *@return A possibly null {@code SaslClient} created using the parameters
348 * supplied. If null, cannot find a {@code SaslClientFactory}
349 * that will produce one.
350 *@exception SaslException If cannot create a {@code SaslClient} because
351 * of an error.
352 */
353 public static SaslClient createSaslClient(
354 String[] mechanisms,
355 String authorizationId,
356 String protocol,
357 String serverName,
358 Map<String,?> props,
359 CallbackHandler cbh) throws SaslException {
360
361 SaslClient mech = null;
362 SaslClientFactory fac;
363 String className;
364 String mechName;
365
366 for (int i = 0; i < mechanisms.length; i++) {
367 if ((mechName=mechanisms[i]) == null) {
368 throw new NullPointerException(
369 "Mechanism name cannot be null");
370 } else if (mechName.length() == 0) {
371 continue;
372 }
373 String mechFilter = "SaslClientFactory." + mechName;
374 Provider[] provs = Security.getProviders(mechFilter);
375 for (int j = 0; provs != null && j < provs.length; j++) {
376 className = provs[j].getProperty(mechFilter);
377 if (className == null) {
378 // Case is ignored
379 continue;
380 }
381
382 fac = (SaslClientFactory) loadFactory(provs[j], className);
383 if (fac != null) {
384 mech = fac.createSaslClient(
385 new String[]{mechanisms[i]}, authorizationId,
386 protocol, serverName, props, cbh);
387 if (mech != null) {
388 return mech;
389 }
390 }
391 }
392 }
393
394 return null;
395 }
396
397 private static Object loadFactory(Provider p, String className)
398 throws SaslException {
399 try {
400 /*
401 * Load the implementation class with the same class loader
402 * that was used to load the provider.
403 * In order to get the class loader of a class, the
404 * caller's class loader must be the same as or an ancestor of
405 * the class loader being returned. Otherwise, the caller must
406 * have "getClassLoader" permission, or a SecurityException
407 * will be thrown.
408 */
409 ClassLoader cl = p.getClass().getClassLoader();
410 Class<?> implClass;
411 implClass = Class.forName(className, true, cl);
412 return implClass.newInstance();
413 } catch (ClassNotFoundException e) {
414 throw new SaslException("Cannot load class " + className, e);
415 } catch (InstantiationException e) {
416 throw new SaslException("Cannot instantiate class " + className, e);
417 } catch (IllegalAccessException e) {
418 throw new SaslException("Cannot access class " + className, e);
419 } catch (SecurityException e) {
420 throw new SaslException("Cannot access class " + className, e);
421 }
422 }
423
424
425 /**
426 * Creates a {@code SaslServer} for the specified mechanism.
427 *
428 * This method uses the
429 <a href="{@docRoot}/../technotes/guides/security/crypto/CryptoSpec.html#Provider">JCA Security Provider Framework</a>,
430 * described in the
431 * "Java Cryptography Architecture API Specification & Reference", for
432 * locating and selecting a {@code SaslServer} implementation.
433 *
434 * First, it
435 * obtains an ordered list of {@code SaslServerFactory} instances from
436 * the registered security providers for the "SaslServerFactory" service
437 * and the specified mechanism. It then invokes
438 * {@code createSaslServer()} on each factory instance on the list
439 * until one produces a non-null {@code SaslServer} instance. It returns
440 * the non-null {@code SaslServer} instance, or null if the search fails
486 * The realm is requested by using a {@code RealmChoiceCallback} if there is a list
487 * of realms to choose from, and by using a {@code RealmCallback} if
488 * the realm must be entered.
489 *
490 *@return A possibly null {@code SaslServer} created using the parameters
491 * supplied. If null, cannot find a {@code SaslServerFactory}
492 * that will produce one.
493 *@exception SaslException If cannot create a {@code SaslServer} because
494 * of an error.
495 **/
496 public static SaslServer
497 createSaslServer(String mechanism,
498 String protocol,
499 String serverName,
500 Map<String,?> props,
501 javax.security.auth.callback.CallbackHandler cbh)
502 throws SaslException {
503
504 SaslServer mech = null;
505 SaslServerFactory fac;
506 String className;
507
508 if (mechanism == null) {
509 throw new NullPointerException("Mechanism name cannot be null");
510 } else if (mechanism.length() == 0) {
511 return null;
512 }
513
514 String mechFilter = "SaslServerFactory." + mechanism;
515 Provider[] provs = Security.getProviders(mechFilter);
516 for (int j = 0; provs != null && j < provs.length; j++) {
517 className = provs[j].getProperty(mechFilter);
518 if (className == null) {
519 throw new SaslException("Provider does not support " +
520 mechFilter);
521 }
522 fac = (SaslServerFactory) loadFactory(provs[j], className);
523 if (fac != null) {
524 mech = fac.createSaslServer(
525 mechanism, protocol, serverName, props, cbh);
526 if (mech != null) {
527 return mech;
528 }
529 }
530 }
531
532 return null;
533 }
534
535 /**
536 * Gets an enumeration of known factories for producing {@code SaslClient}.
537 * This method uses the same algorithm for locating factories as
538 * {@code createSaslClient()}.
539 * @return A non-null enumeration of known factories for producing
540 * {@code SaslClient}.
541 * @see #createSaslClient
542 */
543 public static Enumeration<SaslClientFactory> getSaslClientFactories() {
544 Set<Object> facs = getFactories("SaslClientFactory");
545 final Iterator<Object> iter = facs.iterator();
546 return new Enumeration<SaslClientFactory>() {
547 public boolean hasMoreElements() {
548 return iter.hasNext();
549 }
550 public SaslClientFactory nextElement() {
551 return (SaslClientFactory)iter.next();
565 Set<Object> facs = getFactories("SaslServerFactory");
566 final Iterator<Object> iter = facs.iterator();
567 return new Enumeration<SaslServerFactory>() {
568 public boolean hasMoreElements() {
569 return iter.hasNext();
570 }
571 public SaslServerFactory nextElement() {
572 return (SaslServerFactory)iter.next();
573 }
574 };
575 }
576
577 private static Set<Object> getFactories(String serviceName) {
578 HashSet<Object> result = new HashSet<Object>();
579
580 if ((serviceName == null) || (serviceName.length() == 0) ||
581 (serviceName.endsWith("."))) {
582 return result;
583 }
584
585
586 Provider[] providers = Security.getProviders();
587 HashSet<String> classes = new HashSet<String>();
588 Object fac;
589
590 for (int i = 0; i < providers.length; i++) {
591 classes.clear();
592
593 // Check the keys for each provider.
594 for (Enumeration<Object> e = providers[i].keys(); e.hasMoreElements(); ) {
595 String currentKey = (String)e.nextElement();
596 if (currentKey.startsWith(serviceName)) {
597 // We should skip the currentKey if it contains a
598 // whitespace. The reason is: such an entry in the
599 // provider property contains attributes for the
600 // implementation of an algorithm. We are only interested
601 // in entries which lead to the implementation
602 // classes.
603 if (currentKey.indexOf(' ') < 0) {
604 String className = providers[i].getProperty(currentKey);
605 if (!classes.contains(className)) {
606 classes.add(className);
607 try {
608 fac = loadFactory(providers[i], className);
609 if (fac != null) {
610 result.add(fac);
611 }
612 }catch (Exception ignore) {
613 }
614 }
615 }
616 }
617 }
618 }
619 return Collections.unmodifiableSet(result);
620 }
621 }
|
1 /*
2 * Copyright (c) 1999, 2015, Oracle and/or its affiliates. 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. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package javax.security.sasl;
27
28 import javax.security.auth.callback.CallbackHandler;
29
30 import java.util.Enumeration;
31 import java.util.Iterator;
32 import java.util.Map;
33 import java.util.Set;
34 import java.util.HashSet;
35 import java.util.Collections;
36 import java.security.InvalidParameterException;
37 import java.security.NoSuchAlgorithmException;
38 import java.security.Provider;
39 import java.security.Provider.Service;
40 import java.security.Security;
41
42 /**
43 * A static class for creating SASL clients and servers.
44 *<p>
45 * This class defines the policy of how to locate, load, and instantiate
46 * SASL clients and servers.
47 *<p>
48 * For example, an application or library gets a SASL client by doing
49 * something like:
50 *<blockquote><pre>
51 * SaslClient sc = Sasl.createSaslClient(mechanisms,
52 * authorizationId, protocol, serverName, props, callbackHandler);
53 *</pre></blockquote>
54 * It can then proceed to use the instance to create an authentication connection.
55 *<p>
56 * Similarly, a server gets a SASL server by using code that looks as follows:
57 *<blockquote><pre>
58 * SaslServer ss = Sasl.createSaslServer(mechanism,
59 * protocol, serverName, props, callbackHandler);
346 * The realm is requested by using a {@code RealmChoiceCallback} if there is a list
347 * of realms to choose from, and by using a {@code RealmCallback} if
348 * the realm must be entered.
349 *
350 *@return A possibly null {@code SaslClient} created using the parameters
351 * supplied. If null, cannot find a {@code SaslClientFactory}
352 * that will produce one.
353 *@exception SaslException If cannot create a {@code SaslClient} because
354 * of an error.
355 */
356 public static SaslClient createSaslClient(
357 String[] mechanisms,
358 String authorizationId,
359 String protocol,
360 String serverName,
361 Map<String,?> props,
362 CallbackHandler cbh) throws SaslException {
363
364 SaslClient mech = null;
365 SaslClientFactory fac;
366 Service service;
367 String mechName;
368
369 for (int i = 0; i < mechanisms.length; i++) {
370 if ((mechName=mechanisms[i]) == null) {
371 throw new NullPointerException(
372 "Mechanism name cannot be null");
373 } else if (mechName.length() == 0) {
374 continue;
375 }
376 String type = "SaslClientFactory";
377 Provider[] provs = Security.getProviders(type + "." + mechName);
378 if (provs != null) {
379 for (Provider p : provs) {
380 service = p.getService(type, mechName);
381 if (service == null) {
382 // no such service exists
383 continue;
384 }
385
386 fac = (SaslClientFactory) loadFactory(service);
387 if (fac != null) {
388 mech = fac.createSaslClient(
389 new String[]{mechanisms[i]}, authorizationId,
390 protocol, serverName, props, cbh);
391 if (mech != null) {
392 return mech;
393 }
394 }
395 }
396 }
397 }
398 return null;
399 }
400
401 private static Object loadFactory(Service service)
402 throws SaslException {
403 try {
404 /*
405 * Load the implementation class with the same class loader
406 * that was used to load the provider.
407 * In order to get the class loader of a class, the
408 * caller's class loader must be the same as or an ancestor of
409 * the class loader being returned. Otherwise, the caller must
410 * have "getClassLoader" permission, or a SecurityException
411 * will be thrown.
412 */
413 return service.newInstance(null);
414 } catch (InvalidParameterException | NoSuchAlgorithmException e) {
415 throw new SaslException("Cannot instantiate service " + service, e);
416 }
417 }
418
419
420 /**
421 * Creates a {@code SaslServer} for the specified mechanism.
422 *
423 * This method uses the
424 <a href="{@docRoot}/../technotes/guides/security/crypto/CryptoSpec.html#Provider">JCA Security Provider Framework</a>,
425 * described in the
426 * "Java Cryptography Architecture API Specification & Reference", for
427 * locating and selecting a {@code SaslServer} implementation.
428 *
429 * First, it
430 * obtains an ordered list of {@code SaslServerFactory} instances from
431 * the registered security providers for the "SaslServerFactory" service
432 * and the specified mechanism. It then invokes
433 * {@code createSaslServer()} on each factory instance on the list
434 * until one produces a non-null {@code SaslServer} instance. It returns
435 * the non-null {@code SaslServer} instance, or null if the search fails
481 * The realm is requested by using a {@code RealmChoiceCallback} if there is a list
482 * of realms to choose from, and by using a {@code RealmCallback} if
483 * the realm must be entered.
484 *
485 *@return A possibly null {@code SaslServer} created using the parameters
486 * supplied. If null, cannot find a {@code SaslServerFactory}
487 * that will produce one.
488 *@exception SaslException If cannot create a {@code SaslServer} because
489 * of an error.
490 **/
491 public static SaslServer
492 createSaslServer(String mechanism,
493 String protocol,
494 String serverName,
495 Map<String,?> props,
496 javax.security.auth.callback.CallbackHandler cbh)
497 throws SaslException {
498
499 SaslServer mech = null;
500 SaslServerFactory fac;
501 Service service;
502
503 if (mechanism == null) {
504 throw new NullPointerException("Mechanism name cannot be null");
505 } else if (mechanism.length() == 0) {
506 return null;
507 }
508
509 String type = "SaslServerFactory";
510 Provider[] provs = Security.getProviders(type + "." + mechanism);
511 if (provs != null) {
512 for (Provider p : provs) {
513 service = p.getService(type, mechanism);
514 if (service == null) {
515 throw new SaslException("Provider does not support " +
516 mechanism + " " + type);
517 }
518 fac = (SaslServerFactory) loadFactory(service);
519 if (fac != null) {
520 mech = fac.createSaslServer(
521 mechanism, protocol, serverName, props, cbh);
522 if (mech != null) {
523 return mech;
524 }
525 }
526 }
527 }
528 return null;
529 }
530
531 /**
532 * Gets an enumeration of known factories for producing {@code SaslClient}.
533 * This method uses the same algorithm for locating factories as
534 * {@code createSaslClient()}.
535 * @return A non-null enumeration of known factories for producing
536 * {@code SaslClient}.
537 * @see #createSaslClient
538 */
539 public static Enumeration<SaslClientFactory> getSaslClientFactories() {
540 Set<Object> facs = getFactories("SaslClientFactory");
541 final Iterator<Object> iter = facs.iterator();
542 return new Enumeration<SaslClientFactory>() {
543 public boolean hasMoreElements() {
544 return iter.hasNext();
545 }
546 public SaslClientFactory nextElement() {
547 return (SaslClientFactory)iter.next();
561 Set<Object> facs = getFactories("SaslServerFactory");
562 final Iterator<Object> iter = facs.iterator();
563 return new Enumeration<SaslServerFactory>() {
564 public boolean hasMoreElements() {
565 return iter.hasNext();
566 }
567 public SaslServerFactory nextElement() {
568 return (SaslServerFactory)iter.next();
569 }
570 };
571 }
572
573 private static Set<Object> getFactories(String serviceName) {
574 HashSet<Object> result = new HashSet<Object>();
575
576 if ((serviceName == null) || (serviceName.length() == 0) ||
577 (serviceName.endsWith("."))) {
578 return result;
579 }
580
581 Provider[] provs = Security.getProviders();
582 Object fac;
583
584 for (Provider p : provs) {
585
586 Iterator<Service> iter = p.getServices().iterator();
587 while (iter.hasNext()) {
588 Service s = iter.next();
589 if (s.getType().equals(serviceName)) {
590 try {
591 fac = loadFactory(s);
592 if (fac != null) {
593 result.add(fac);
594 }
595 } catch (Exception ignore) {
596 }
597 }
598 }
599 }
600 return Collections.unmodifiableSet(result);
601 }
602 }
|