--- old/src/java.base/share/classes/sun/security/jca/ProviderConfig.java Wed May 27 22:51:49 2015 +++ new/src/java.base/share/classes/sun/security/jca/ProviderConfig.java Wed May 27 22:51:48 2015 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,6 +27,7 @@ import java.io.File; import java.lang.reflect.*; +import java.util.*; import java.security.*; @@ -33,8 +34,8 @@ import sun.security.util.PropertyExpander; /** - * Class representing a configured provider. Encapsulates configuration - * (className plus optional argument), the provider loading logic, and + * Class representing a configured provider which encapsulates configuration + * (className + optional argument), the provider loading logic, and * the loaded Provider object itself. * * @author Andreas Sterbenz @@ -56,15 +57,10 @@ // maximum number of times to try loading a provider before giving up private final static int MAX_LOAD_TRIES = 30; - // parameters for the Provider(String) constructor, - // use by doLoadProvider() - private final static Class[] CL_STRING = { String.class }; - // name of the provider class private final String className; - // argument to the provider constructor, - // empty string indicates no-arg constructor + // argument to the Provider.configure() call, never null private final String argument; // number of times we have already tried to load this provider @@ -172,22 +168,34 @@ if (shouldLoad() == false) { return null; } - if (isLoading) { - // because this method is synchronized, this can only - // happen if there is recursion. - if (debug != null) { - debug.println("Recursion loading provider: " + this); - new Exception("Call trace").printStackTrace(); + + // Create providers which are in java.base directly + if (className.equals("sun.security.provider.Sun")) { + p = new sun.security.provider.Sun(); + } else if (className.equals("sun.security.rsa.SunRsaSign")) { + p = new sun.security.rsa.SunRsaSign(); + } else if (className.equals("com.sun.crypto.provider.SunJCE")) { + p = new com.sun.crypto.provider.SunJCE(); + } else if (className.equals("com.sun.net.ssl.internal.ssl.Provider")) { + p = new com.sun.net.ssl.internal.ssl.Provider(); + } else { + if (isLoading) { + // because this method is synchronized, this can only + // happen if there is recursion. + if (debug != null) { + debug.println("Recursion loading provider: " + this); + new Exception("Call trace").printStackTrace(); + } + return null; } - return null; + try { + isLoading = true; + tries++; + p = doLoadProvider(); + } finally { + isLoading = false; + } } - try { - isLoading = true; - tries++; - p = doLoadProvider(); - } finally { - isLoading = false; - } provider = p; return p; } @@ -208,61 +216,35 @@ if (debug != null) { debug.println("Loading provider: " + ProviderConfig.this); } + ProviderLoader pl = new ProviderLoader(); try { - ClassLoader cl = ClassLoader.getSystemClassLoader(); - Class provClass; - if (cl != null) { - provClass = cl.loadClass(className); - } else { - provClass = Class.forName(className); - } - Object obj; - if (hasArgument() == false) { - obj = provClass.newInstance(); - } else { - Constructor cons = provClass.getConstructor(CL_STRING); - obj = cons.newInstance(argument); - } - if (obj instanceof Provider) { + Provider p = pl.load(className); + if (p != null) { + if (hasArgument()) { + p = p.configure(argument); + } if (debug != null) { - debug.println("Loaded provider " + obj); + debug.println("Loaded provider " + p.getName()); } - return (Provider)obj; } else { if (debug != null) { - debug.println(className + " is not a provider"); + debug.println("Error loading " + className); } disableLoad(); - return null; } + return p; } catch (Exception e) { - Throwable t; - if (e instanceof InvocationTargetException) { - t = ((InvocationTargetException)e).getCause(); + if (e instanceof ProviderException) { + // pass up + throw e; } else { - t = e; - } - if (debug != null) { - debug.println("Error loading provider " + ProviderConfig.this); - t.printStackTrace(); - } - // provider indicates fatal error, pass through exception - if (t instanceof ProviderException) { - throw (ProviderException)t; - } - // provider indicates that loading should not be retried - if (t instanceof UnsupportedOperationException) { + if (debug != null) { + debug.println("Error loading " + className); + e.printStackTrace(); + } disableLoad(); + return null; } - return null; - } catch (ExceptionInInitializerError err) { - // no sufficient permission to initialize provider class - if (debug != null) { - debug.println("Error loading provider " + ProviderConfig.this); - err.printStackTrace(); - } - disableLoad(); - return null; } } }); @@ -289,4 +271,118 @@ }); } + // Inner class for loading security providers listed in java.security file + private static final class ProviderLoader { + ServiceLoader services; + + ProviderLoader() { + // VM should already been booted at this point, if not + // - Only providers in java.base should be loaded, don't use + // ServiceLoader + // - ClassLoader.getSystemClassLoader() will throw InternalError + services = ServiceLoader.load(java.security.Provider.class, + ClassLoader.getSystemClassLoader()); + } + + /** + * Loads the provider with the specified class name. + * + * @param name the name of the provider class + * @return the Provider, or null if it cannot be found or loaded + * @throws ProviderException all other exceptions are ignored + */ + public Provider load(String classname) { + if (debug != null) { + debug.println("Attempt to load " + classname + " using SL"); + } + Iterator iter = services.iterator(); + while (iter.hasNext()) { + try { + Provider p = iter.next(); + if (debug != null) { + debug.println("Found SL Provider named " + p.getName()); + } + if (p.getClass().getName().equals(classname)) { + return p; + } + } catch (SecurityException | ServiceConfigurationError | + InvalidParameterException ex) { + // if provider loading fail due to security permission, + // log it and move on to next provider + if (debug != null) { + debug.println("Encountered " + ex + + " while iterating through SL, ignore and move on"); + ex.printStackTrace(); + } + } + } + // No success with ServiceLoader. Try loading provider the legacy, + // i.e. pre-module, way via reflection + try { + return legacyLoad(classname); + } catch (ProviderException pe) { + // pass through + throw pe; + } catch (Exception ex) { + // logged and ignored + if (debug != null) { + debug.println("Encountered " + ex + + " during legacy load of " + classname); + ex.printStackTrace(); + } + return null; + } + } + + private Provider legacyLoad(String classname) { + + if (debug != null) { + debug.println("Loading legacy provider: " + classname); + } + + try { + Class provClass = + ClassLoader.getSystemClassLoader().loadClass(classname); + + // only continue if the specified class extends Provider + if (!Provider.class.isAssignableFrom(provClass)) { + if (debug != null) { + debug.println(classname + " is not a provider"); + } + return null; + } + + Provider p = AccessController.doPrivileged + (new PrivilegedExceptionAction() { + public Provider run() throws Exception { + return (Provider) provClass.newInstance(); + } + }); + return p; + } catch (Exception e) { + Throwable t; + if (e instanceof InvocationTargetException) { + t = ((InvocationTargetException)e).getCause(); + } else { + t = e; + } + if (debug != null) { + debug.println("Error loading legacy provider " + classname); + t.printStackTrace(); + } + // provider indicates fatal error, pass through exception + if (t instanceof ProviderException) { + throw (ProviderException) t; + } + return null; + } catch (ExceptionInInitializerError | NoClassDefFoundError err) { + // no sufficient permission to access/initialize provider class + if (debug != null) { + debug.println("Error loading legacy provider " + classname); + err.printStackTrace(); + } + return null; + } + } + } }