src/java.base/share/classes/sun/security/jca/ProviderConfig.java
Print this page
7191662: JCE providers should be located via ServiceLoader
@@ -1,7 +1,7 @@
/*
- * 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
@@ -25,18 +25,19 @@
package sun.security.jca;
import java.io.File;
import java.lang.reflect.*;
+import java.util.*;
import java.security.*;
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
* @since 1.5
*/
@@ -54,19 +55,14 @@
"${java.home}/conf/security/sunpkcs11-solaris.cfg";
// 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
private int tries;
@@ -170,10 +166,21 @@
return p;
}
if (shouldLoad() == false) {
return null;
}
+
+ // 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);
@@ -186,10 +193,11 @@
tries++;
p = doLoadProvider();
} finally {
isLoading = false;
}
+ }
provider = p;
return p;
}
/**
@@ -206,65 +214,39 @@
return AccessController.doPrivileged(new PrivilegedAction<Provider>() {
public Provider run() {
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);
+ Provider p = pl.load(className);
+ if (p != null) {
+ if (hasArgument()) {
+ p = p.configure(argument);
}
- Object obj;
- if (hasArgument() == false) {
- obj = provClass.newInstance();
- } else {
- Constructor<?> cons = provClass.getConstructor(CL_STRING);
- obj = cons.newInstance(argument);
- }
- if (obj instanceof Provider) {
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();
+ debug.println("Error loading " + className);
+ e.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) {
disableLoad();
- }
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;
}
}
});
}
@@ -287,6 +269,120 @@
}
}
});
}
+ // Inner class for loading security providers listed in java.security file
+ private static final class ProviderLoader {
+ ServiceLoader<Provider> 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<Provider> 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<Provider>() {
+ 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;
+ }
+ }
+ }
}