This demo, I want to understand AccessController.doPrivileged() better.In jetty-xml
module, the main()
methods has the following code:
AccessController.doPrivileged(new PrivilegedAction<Object>() {
@Override
public Object run() {
try {
Properties properties = null;
}
...
}
}
I think this is to ensure jetty-start
module can invoke jetty-xml
module successed.So I write a simple demo.But I have a new problem,now this problem has no relations with Jetty.
I had use google to search related issues,but most about rmi.Following diagram is the project structure, has two module, jetty-start
and jetty-xml
(I just simulate jetty module names):
The jetty-start
module Main
class, first invoke XmlConfiguration#readFile()
, then invoke XmlConfiguration#readFileWithPrivilegedAction()
by constructor a new classloader and reflect.In addition, run the Main
class, use the -Djava.security.policy=jetty-testXmlModulePrivileged.policy
vm args.
public class Main {
public static void main(String[] args) throws IOException, ReflectiveOperationException {
ClassLoader loader = getLoader();
Thread.currentThread().setContextClassLoader(loader);
Class<?> clazz = loader.loadClass("org.jetty.xml.XmlConfiguration");
System.setSecurityManager(new SecurityManager());
try {
System.out.println("invoke readFile().");
Method method = clazz.getMethod("readFile");
String lines = (String) method.invoke(null);
System.out.println("File Content: \n" + lines);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("/////////////////////////////////////////////////////////");
System.out.println();
try {
System.out.println("invoke readFileWithPrivilegedAction().");
Method method = clazz.getMethod("readFileWithPrivilegedAction");
String lines = (String) method.invoke(null);
System.out.println("File Content: \n" + lines);
} catch (Exception e) {
e.printStackTrace();
}
}
private static ClassLoader getLoader() throws IOException {
ClassLoader parent = Thread.currentThread().getContextClassLoader();
final String CLASSPATH_PATH = "E:\\Java\\workspace\\Test\\jetty-xml\\bin\\";
File bin = new File(CLASSPATH_PATH);
URL binUrl = bin.getCanonicalFile().toURI().toURL();
System.out.println("add classpath : " + binUrl);
URL[] urls = {binUrl};
ClassLoader loader = new StartClassLoader(urls, parent);
return loader;
}
private static class StartClassLoader extends URLClassLoader {
public StartClassLoader(URL[] urls, ClassLoader parent) {
super(urls, parent);
}
}
}
The jetty-xml
module XmlConfiguration
class,one method is normal method invoke, the other method use AccessController.doPrivileged
:
public class XmlConfiguration {
private final static String FOLDER_PATH = "E:\\Java\\workspace\\Test\\jetty-xml\\config\\";
private final static String FILENAME = "server.xml";
public static String readFile() throws IOException {
File fs = new File(FOLDER_PATH + FILENAME);
StringBuilder lines = new StringBuilder();
try (BufferedReader reader = new BufferedReader(new InputStreamReader(
new FileInputStream(fs)))) {
String line = null;
while ((line = reader.readLine()) != null) {
lines.append(line);
}
}
return lines.toString();
}
/**
*/
public static String readFileWithPrivilegedAction() throws IOException {
String lines = AccessController.doPrivileged(new PrivilegedAction<String>() {
@Override
public String run() {
File fs = new File(FOLDER_PATH + FILENAME);
StringBuilder lines = new StringBuilder();
try (BufferedReader reader = new BufferedReader(
new InputStreamReader(new FileInputStream(fs)))) {
String line = null;
while ((line = reader.readLine()) != null) {
lines.append(line);
}
} catch (IOException e) {
e.printStackTrace();
}
return lines.toString();
}
});
return lines;
}
}
The jetty-testXmlModulePrivileged.policy
is, give the jetty-xml
permission to read the server.xml
file.
grant codebase "file:/E:/Java/workspace/Test/jetty-xml/bin"
{
permission java.io.FilePermission "E:\\Java\\workspace\\Test\\jetty-xml\\config\\server.xml", "read,write";
};
Finally I run the Main
, the first exception I can understand, It has no permission(eg, invoke readFile()
method), and not run in AccessController.doPrivileged
, but the second exception, I was a little puzzled(eg. invoke readFileWithPrivilegedAction()
method):
invoke readFile().
java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.jetty.start.Main.main(Main.java:23)
Caused by: java.security.AccessControlException: access denied ("java.io.FilePermission" "E:\Java\workspace\Test\jetty-xml\config\server.xml" "read")
at java.security.AccessControlContext.checkPermission(AccessControlContext.java:372)
at java.security.AccessController.checkPermission(AccessController.java:559)
at java.lang.SecurityManager.checkPermission(SecurityManager.java:549)
at java.lang.SecurityManager.checkRead(SecurityManager.java:888)
at java.io.FileInputStream.<init>(FileInputStream.java:135)
at org.jetty.xml.XmlConfiguration.readFile(XmlConfiguration.java:19)
... 5 more
/////////////////////////////////////////////////////////
invoke readFileWithPrivilegedAction().
java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.jetty.start.Main.main(Main.java:35)
Caused by: java.lang.NoClassDefFoundError: org/jetty/xml/XmlConfiguration$1
at org.jetty.xml.XmlConfiguration.readFileWithPrivilegedAction(XmlConfiguration.java:34)
... 5 more
Caused by: java.lang.ClassNotFoundException: org.jetty.xml.XmlConfiguration$1
at java.net.URLClassLoader$1.run(URLClassLoader.java:366)
at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
at java.lang.ClassLoader.loadClass(ClassLoader.java:425)
at java.lang.ClassLoader.loadClass(ClassLoader.java:358)
... 6 more
I had constructor a new classloader, add the jetty-xml
bin classpath,then set the current thread classloader to this new classloader, I think this classloader can load org.jetty.xml.XmlConfiguration$1
.If I modify the Main
class,It's OK:
Class<?> clazz = loader.loadClass("org.jetty.xml.XmlConfiguration");
loader.loadClass("org.jetty.xml.XmlConfiguration$1");
This is similar to Tomcat's SecurityClassLoad
class.Preload some class.But here, why not throws AccessControlException
?