src/java.security.sasl/share/classes/javax/security/sasl/Sasl.java

Print this page
7191662: JCE providers should be located via ServiceLoader
   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 &amp; 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 &amp; 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 }