8168075: Custom system class loader + security manager + malformed policy file = recursive initialization
Reviewed-by: mchung, mullan
--- a/jdk/src/java.base/share/classes/sun/security/provider/PolicyFile.java Tue Jan 24 00:48:51 2017 -0800
+++ b/jdk/src/java.base/share/classes/sun/security/provider/PolicyFile.java Tue Jan 24 16:19:21 2017 -0500
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2017, 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
@@ -32,7 +32,6 @@
import java.net.URI;
import java.nio.file.Paths;
import java.util.*;
-import java.text.MessageFormat;
import java.security.*;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
@@ -579,10 +578,9 @@
k.add(policy);
return k;
});
- MessageFormat form = new MessageFormat(ResourcesMgr.getString
- (POLICY + ".error.parsing.policy.message"));
Object[] source = {policy, pe.getLocalizedMessage()};
- System.err.println(form.format(source));
+ System.err.println(LocalizedMessage.getMessage
+ (POLICY + ".error.parsing.policy.message", source));
if (debug != null) {
pe.printStackTrace();
}
@@ -805,32 +803,30 @@
}
}
} catch (java.lang.reflect.InvocationTargetException ite) {
- MessageFormat form = new MessageFormat
- (ResourcesMgr.getString
- (POLICY +
- ".error.adding.Permission.perm.message"));
Object[] source = {pe.permission,
ite.getTargetException().toString()};
- System.err.println(form.format(source));
+ System.err.println(
+ LocalizedMessage.getMessage(
+ POLICY + ".error.adding.Permission.perm.message",
+ source));
} catch (Exception e) {
- MessageFormat form = new MessageFormat
- (ResourcesMgr.getString
- (POLICY +
- ".error.adding.Permission.perm.message"));
Object[] source = {pe.permission,
e.toString()};
- System.err.println(form.format(source));
+ System.err.println(
+ LocalizedMessage.getMessage(
+ POLICY + ".error.adding.Permission.perm.message",
+ source));
}
}
// No need to sync because noone has access to newInfo yet
newInfo.policyEntries.add(entry);
} catch (Exception e) {
- MessageFormat form = new MessageFormat(ResourcesMgr.getString
- (POLICY
- + ".error.adding.Entry.message"));
Object[] source = {e.toString()};
- System.err.println(form.format(source));
+ System.err.println(
+ LocalizedMessage.getMessage(
+ POLICY + ".error.adding.Entry.message",
+ source));
}
if (debug != null)
debug.println();
@@ -1803,29 +1799,29 @@
} else if (prefix.equalsIgnoreCase("alias")) {
// get the suffix and perform keystore alias replacement
if (colonIndex == -1) {
- MessageFormat form = new MessageFormat
- (ResourcesMgr.getString
- ("alias.name.not.provided.pe.name."));
Object[] source = {pe.name};
- throw new Exception(form.format(source));
+ throw new Exception(
+ LocalizedMessage.getMessage(
+ "alias.name.not.provided.pe.name.",
+ source));
}
suffix = value.substring(colonIndex+1);
if ((suffix = getDN(suffix, keystore)) == null) {
- MessageFormat form = new MessageFormat
- (ResourcesMgr.getString
- ("unable.to.perform.substitution.on.alias.suffix"));
Object[] source = {value.substring(colonIndex+1)};
- throw new Exception(form.format(source));
+ throw new Exception(
+ LocalizedMessage.getMessage(
+ "unable.to.perform.substitution.on.alias.suffix",
+ source));
}
sb.append(X500PRINCIPAL + " \"" + suffix + "\"");
startIndex = e+2;
} else {
- MessageFormat form = new MessageFormat
- (ResourcesMgr.getString
- ("substitution.value.prefix.unsupported"));
Object[] source = {prefix};
- throw new Exception(form.format(source));
+ throw new Exception(
+ LocalizedMessage.getMessage(
+ "substitution.value.prefix.unsupported",
+ source));
}
}
@@ -2039,7 +2035,7 @@
super(type);
if (type == null) {
throw new NullPointerException
- (ResourcesMgr.getString("type.can.t.be.null"));
+ (LocalizedMessage.getMessage("type.can.t.be.null"));
}
this.type = type;
this.name = name;
--- a/jdk/src/java.base/share/classes/sun/security/provider/PolicyParser.java Tue Jan 24 00:48:51 2017 -0800
+++ b/jdk/src/java.base/share/classes/sun/security/provider/PolicyParser.java Tue Jan 24 16:19:21 2017 -0500
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2017, 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
@@ -26,18 +26,14 @@
package sun.security.provider;
import java.io.*;
-import java.lang.RuntimePermission;
-import java.net.SocketPermission;
-import java.net.URL;
import java.security.GeneralSecurityException;
import java.security.Principal;
-import java.text.MessageFormat;
import java.util.*;
import javax.security.auth.x500.X500Principal;
import sun.security.util.Debug;
import sun.security.util.PropertyExpander;
-import sun.security.util.ResourcesMgr;
+import sun.security.util.LocalizedMessage;
/**
* The policy for a Java runtime (specifying
@@ -209,13 +205,12 @@
if (!domainEntries.containsKey(domainName)) {
domainEntries.put(domainName, de);
} else {
- MessageFormat form =
- new MessageFormat(ResourcesMgr.getString(
- "duplicate.keystore.domain.name"));
+ LocalizedMessage localizedMsg =
+ new LocalizedMessage("duplicate.keystore.domain.name");
Object[] source = {domainName};
String msg = "duplicate keystore domain name: " +
domainName;
- throw new ParsingException(msg, form, source);
+ throw new ParsingException(msg, localizedMsg, source);
}
}
} else {
@@ -225,7 +220,7 @@
}
if (keyStoreUrlString == null && storePassURL != null) {
- throw new ParsingException(ResourcesMgr.getString
+ throw new ParsingException(LocalizedMessage.getMessage
("keystorePasswordURL.can.not.be.specified.without.also.specifying.keystore"));
}
}
@@ -367,7 +362,7 @@
keyStoreType = match("quoted string");
} else {
throw new ParsingException(st.lineno(),
- ResourcesMgr.getString("expected.keystore.type"));
+ LocalizedMessage.getMessage("expected.keystore.type"));
}
// parse keystore provider
@@ -380,7 +375,7 @@
keyStoreProvider = match("quoted string");
} else {
throw new ParsingException(st.lineno(),
- ResourcesMgr.getString("expected.keystore.provider"));
+ LocalizedMessage.getMessage("expected.keystore.provider"));
}
}
@@ -430,7 +425,7 @@
if (e.codeBase != null)
throw new ParsingException(
st.lineno(),
- ResourcesMgr.getString
+ LocalizedMessage.getMessage
("multiple.Codebase.expressions"));
e.codeBase = match("quoted string");
peekAndMatch(",");
@@ -438,8 +433,8 @@
if (e.signedBy != null)
throw new ParsingException(
st.lineno(),
- ResourcesMgr.getString(
- "multiple.SignedBy.expressions"));
+ LocalizedMessage.getMessage
+ ("multiple.SignedBy.expressions"));
e.signedBy = match("quoted string");
// verify syntax of the aliases
@@ -457,8 +452,8 @@
if (actr <= cctr)
throw new ParsingException(
st.lineno(),
- ResourcesMgr.getString(
- "SignedBy.has.empty.alias"));
+ LocalizedMessage.getMessage
+ ("SignedBy.has.empty.alias"));
peekAndMatch(",");
} else if (peekAndMatch("Principal")) {
@@ -500,7 +495,7 @@
}
throw new ParsingException
(st.lineno(),
- ResourcesMgr.getString
+ LocalizedMessage.getMessage
("can.not.specify.Principal.with.a.wildcard.class.without.a.wildcard.name"));
}
}
@@ -537,8 +532,8 @@
} else {
throw new ParsingException(st.lineno(),
- ResourcesMgr.getString(
- "expected.codeBase.or.SignedBy.or.Principal"));
+ LocalizedMessage.getMessage
+ ("expected.codeBase.or.SignedBy.or.Principal"));
}
}
@@ -561,8 +556,8 @@
} else {
throw new
ParsingException(st.lineno(),
- ResourcesMgr.getString(
- "expected.permission.entry"));
+ LocalizedMessage.getMessage
+ ("expected.permission.entry"));
}
}
match("}");
@@ -738,15 +733,14 @@
switch (lookahead) {
case StreamTokenizer.TT_NUMBER:
throw new ParsingException(st.lineno(), expect,
- ResourcesMgr.getString("number.") +
- String.valueOf(st.nval));
+ LocalizedMessage.getMessage("number.") +
+ String.valueOf(st.nval));
case StreamTokenizer.TT_EOF:
- MessageFormat form = new MessageFormat(
- ResourcesMgr.getString
- ("expected.expect.read.end.of.file."));
+ LocalizedMessage localizedMsg = new LocalizedMessage
+ ("expected.expect.read.end.of.file.");
Object[] source = {expect};
String msg = "expected [" + expect + "], read [end of file]";
- throw new ParsingException(msg, form, source);
+ throw new ParsingException(msg, localizedMsg, source);
case StreamTokenizer.TT_WORD:
if (expect.equalsIgnoreCase(st.sval)) {
lookahead = st.nextToken();
@@ -832,10 +826,10 @@
switch (lookahead) {
case StreamTokenizer.TT_NUMBER:
throw new ParsingException(st.lineno(), ";",
- ResourcesMgr.getString("number.") +
- String.valueOf(st.nval));
+ LocalizedMessage.getMessage("number.") +
+ String.valueOf(st.nval));
case StreamTokenizer.TT_EOF:
- throw new ParsingException(ResourcesMgr.getString
+ throw new ParsingException(LocalizedMessage.getMessage
("expected.read.end.of.file."));
default:
lookahead = st.nextToken();
@@ -993,8 +987,8 @@
*/
public PrincipalEntry(String principalClass, String principalName) {
if (principalClass == null || principalName == null)
- throw new NullPointerException(ResourcesMgr.getString(
- "null.principalClass.or.principalName"));
+ throw new NullPointerException(LocalizedMessage.getMessage
+ ("null.principalClass.or.principalName"));
this.principalClass = principalClass;
this.principalName = principalName;
}
@@ -1244,11 +1238,11 @@
if (!entries.containsKey(keystoreName)) {
entries.put(keystoreName, entry);
} else {
- MessageFormat form = new MessageFormat(ResourcesMgr.getString(
- "duplicate.keystore.name"));
+ LocalizedMessage localizedMsg = new LocalizedMessage
+ ("duplicate.keystore.name");
Object[] source = {keystoreName};
String msg = "duplicate keystore name: " + keystoreName;
- throw new ParsingException(msg, form, source);
+ throw new ParsingException(msg, localizedMsg, source);
}
}
@@ -1320,7 +1314,7 @@
private static final long serialVersionUID = -4330692689482574072L;
private String i18nMessage;
- private MessageFormat form;
+ private LocalizedMessage localizedMsg;
private Object[] source;
/**
@@ -1336,10 +1330,10 @@
i18nMessage = msg;
}
- public ParsingException(String msg, MessageFormat form,
+ public ParsingException(String msg, LocalizedMessage localizedMsg,
Object[] source) {
super(msg);
- this.form = form;
+ this.localizedMsg = localizedMsg;
this.source = source;
}
@@ -1347,7 +1341,7 @@
super("line " + line + ": " + msg);
// don't call form.format unless getLocalizedMessage is called
// to avoid unnecessary permission checks
- form = new MessageFormat(ResourcesMgr.getString("line.number.msg"));
+ localizedMsg = new LocalizedMessage("line.number.msg");
source = new Object[] {line, msg};
}
@@ -1356,14 +1350,14 @@
"], found [" + actual + "]");
// don't call form.format unless getLocalizedMessage is called
// to avoid unnecessary permission checks
- form = new MessageFormat(ResourcesMgr.getString
- ("line.number.expected.expect.found.actual."));
+ localizedMsg = new LocalizedMessage
+ ("line.number.expected.expect.found.actual.");
source = new Object[] {line, expect, actual};
}
@Override
public String getLocalizedMessage() {
- return i18nMessage != null ? i18nMessage : form.format(source);
+ return i18nMessage != null ? i18nMessage : localizedMsg.format(source);
}
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/share/classes/sun/security/util/LocalizedMessage.java Tue Jan 24 16:19:21 2017 -0500
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2017, 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.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.security.util;
+
+/**
+ * This class produces formatted and localized messages describing security
+ * issues. Some messages may be required when the VM is not fully booted. In
+ * this case, localization resources and classes used for message formatting
+ * may not be available. When the VM is not booted, the message will not be
+ * localized, and it will be formatted using simplified message formatting
+ * code that is contained in this class.
+ */
+
+/*
+ * Some of this code is executed before the VM is fully booted. Some import
+ * statements have been omitted to help prevent accidental use of classes that
+ * may not be available during boot.
+ */
+
+public class LocalizedMessage {
+
+ private static final Resources resources = new Resources();
+
+ private final String key;
+
+ /**
+ * A LocalizedMessage can be instantiated with a key and formatted with
+ * arguments later in the style of MessageFormat. This organization
+ * allows the actual formatting (and associated permission checks) to be
+ * avoided unless the resulting string is needed.
+ * @param key
+ */
+ public LocalizedMessage(String key) {
+ this.key = key;
+ }
+
+ /**
+ * Return a localized string corresponding to the key stored in this
+ * object, formatted with the provided arguments. When the VM is booted,
+ * this method will obtain the correct localized message and format it
+ * using java.text.MessageFormat. Otherwise, a non-localized string is
+ * returned, and the formatting is performed by simplified formatting code.
+ *
+ * @param arguments The arguments that should be placed in the message
+ * @return A formatted message string
+ */
+ public String format(Object... arguments) {
+ return getMessage(key, arguments);
+ }
+
+ /**
+ * Return a non-localized string corresponding to the provided key, and
+ * formatted with the provided arguments. All strings are obtained from
+ * sun.security.util.Resources, and the formatting only supports
+ * simple positional argument replacement (e.g. {1}).
+ *
+ * @param key The key of the desired string in Resources
+ * @param arguments The arguments that should be placed in the message
+ * @return A formatted message string
+ */
+ public static String getMessageUnbooted(String key,
+ Object... arguments) {
+
+ String value = resources.getString(key);
+ if (arguments == null || arguments.length == 0) {
+ return value;
+ }
+ // Classes like StringTokenizer may not be loaded, so parsing
+ // is performed with String methods
+ StringBuilder sb = new StringBuilder();
+ int nextBraceIndex;
+ while ((nextBraceIndex = value.indexOf('{')) >= 0) {
+
+ String firstPart = value.substring(0, nextBraceIndex);
+ sb.append(firstPart);
+ value = value.substring(nextBraceIndex + 1);
+
+ // look for closing brace and argument index
+ nextBraceIndex = value.indexOf('}');
+ if (nextBraceIndex < 0) {
+ // no closing brace
+ // MessageFormat would throw IllegalArgumentException, but
+ // that exception class may not be loaded yet
+ throw new RuntimeException("Unmatched braces");
+ }
+ String indexStr = value.substring(0, nextBraceIndex);
+ try {
+ int index = Integer.parseInt(indexStr);
+ sb.append(arguments[index]);
+ }
+ catch(NumberFormatException e) {
+ // argument index is not an integer
+ throw new RuntimeException("not an integer: " + indexStr);
+ }
+ value = value.substring(nextBraceIndex + 1);
+ }
+ sb.append(value);
+ return sb.toString();
+ }
+
+ /**
+ * Return a localized string corresponding to the provided key, and
+ * formatted with the provided arguments. When the VM is booted, this
+ * method will obtain the correct localized message and format it using
+ * java.text.MessageFormat. Otherwise, a non-localized string is returned,
+ * and the formatting is performed by simplified formatting code.
+ *
+ * @param key The key of the desired string in the security resource bundle
+ * @param arguments The arguments that should be placed in the message
+ * @return A formatted message string
+ */
+ public static String getMessage(String key,
+ Object... arguments) {
+
+ if (jdk.internal.misc.VM.isBooted()) {
+ // Localization and formatting resources are available
+ String value = ResourcesMgr.getString(key);
+ if (arguments == null) {
+ return value;
+ }
+ java.text.MessageFormat form = new java.text.MessageFormat(value);
+ return form.format(arguments);
+ } else {
+ return getMessageUnbooted(key, arguments);
+ }
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/security/util/Resources/customSysClassLoader/BootMessages.java Tue Jan 24 16:19:21 2017 -0500
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2017, 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.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8168075
+ * @summary Ensure that security messages can be formatted during system class
+ * loader initialization.
+ * @build CustomClassLoader
+ * @run main/othervm/java.security.policy=error.policy -Djava.security.manager -Djava.system.class.loader=CustomClassLoader BootMessages
+ */
+
+public class BootMessages {
+
+ public static void main(String[] args) throws Exception {
+
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/security/util/Resources/customSysClassLoader/CustomClassLoader.java Tue Jan 24 16:19:21 2017 -0500
@@ -0,0 +1,36 @@
+
+/*
+ * Copyright (c) 2017, 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
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * A class loader that can be used in tests that require a custom class
+ * loader. Its behavior is identical to ClassLoader.
+ */
+
+public class CustomClassLoader extends ClassLoader {
+ public CustomClassLoader(ClassLoader parent) {
+ super(parent);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/security/util/Resources/customSysClassLoader/MessageFormatting.java Tue Jan 24 16:19:21 2017 -0500
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2017, 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.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.util.*;
+import sun.security.util.Resources;
+import sun.security.util.LocalizedMessage;
+import java.text.MessageFormat;
+
+/*
+ * @test
+ * @bug 8168075
+ * @summary Ensure that security message formatting code is capable of
+ * displaying all messages.
+ * @modules java.base/sun.security.util
+ */
+
+public class MessageFormatting {
+
+ private static final Object[] MSG_ARGS = new Integer[]{0, 1, 2};
+
+ public static void main(String[] args) throws Exception {
+
+ Resources resources = new Resources();
+ Enumeration<String> keys = resources.getKeys();
+ while (keys.hasMoreElements()) {
+ String curKey = keys.nextElement();
+ String formattedString = LocalizedMessage.getMessageUnbooted(curKey, MSG_ARGS);
+ String msg = resources.getString(curKey);
+ String expectedString = formatIfNecessary(msg, MSG_ARGS);
+ if (!formattedString.equals(expectedString)) {
+ System.err.println("Expected string:");
+ System.err.println(expectedString);
+ System.err.println("Actual string:");
+ System.err.println(formattedString);
+ throw new Exception("Incorrect message string");
+ }
+ }
+ }
+
+ private static String formatIfNecessary(String str, Object[] args) {
+ // message formatting code only formats messages with arguments
+ if (str.indexOf('{') < 0) {
+ return str;
+ }
+ MessageFormat format = new MessageFormat(str);
+ return format.format(args);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/security/util/Resources/customSysClassLoader/error.policy Tue Jan 24 16:19:21 2017 -0500
@@ -0,0 +1,5 @@
+grant {
+ permission java.lang.RuntimePermission "createClassLoader";
+ permission java.lang.RuntimePermission "";
+};
+