|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
|
|
package sun.security.provider; |
|
|
|
import java.io.*; |
|
import java.lang.reflect.*; |
|
import java.net.MalformedURLException; |
|
import java.net.URL; |
|
import java.net.URI; |
|
import java.nio.file.Files; |
|
import java.nio.file.Path; |
|
import java.util.*; |
|
import java.security.*; |
|
import java.security.cert.Certificate; |
|
import java.security.cert.X509Certificate; |
|
import javax.security.auth.Subject; |
|
import javax.security.auth.x500.X500Principal; |
|
import java.net.SocketPermission; |
|
import java.net.NetPermission; |
|
import java.util.concurrent.ConcurrentHashMap; |
|
import jdk.internal.access.JavaSecurityAccess; |
|
import jdk.internal.access.SharedSecrets; |
|
import jdk.internal.util.StaticProperty; |
|
import sun.nio.fs.DefaultFileSystemProvider; |
|
import sun.security.util.*; |
|
import sun.net.www.ParseUtil; |
|
|
|
import static java.nio.charset.StandardCharsets.UTF_8; |
|
import static jdk.internal.access.JavaSecurityAccess.ProtectionDomainCache; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
@SuppressWarnings("removal") |
|
public class PolicyFile extends java.security.Policy { |
|
|
|
private static final Debug debug = Debug.getInstance("policy"); |
|
|
|
private static final String SELF = "${{self}}"; |
|
private static final String X500PRINCIPAL = |
|
"javax.security.auth.x500.X500Principal"; |
|
private static final String POLICY = "java.security.policy"; |
|
private static final String POLICY_URL = "policy.url."; |
|
|
|
private static final int DEFAULT_CACHE_SIZE = 1; |
|
|
|
// contains the policy grant entries, PD cache, and alias mapping |
|
|
|
private volatile PolicyInfo policyInfo; |
|
|
|
private boolean expandProperties = true; |
|
private boolean allowSystemProperties = true; |
|
private boolean notUtf8 = false; |
|
private URL url; |
|
|
|
|
|
private static final Class<?>[] PARAMS0 = { }; |
|
private static final Class<?>[] PARAMS1 = { String.class }; |
|
private static final Class<?>[] PARAMS2 = { String.class, String.class }; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
private static Set<URL> badPolicyURLs = |
|
Collections.newSetFromMap(new ConcurrentHashMap<URL,Boolean>()); |
|
|
|
|
|
|
|
|
|
*/ |
|
private static final java.nio.file.FileSystem builtInFS = |
|
DefaultFileSystemProvider.theFileSystem(); |
|
|
|
|
|
|
|
|
|
*/ |
|
public PolicyFile() { |
|
init((URL)null); |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
public PolicyFile(URL url) { |
|
this.url = url; |
|
init(url); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
private void init(URL url) { |
|
// Properties are set once for each init(); ignore changes |
|
|
|
String numCacheStr = |
|
AccessController.doPrivileged(new PrivilegedAction<>() { |
|
@Override |
|
public String run() { |
|
expandProperties = "true".equalsIgnoreCase |
|
(Security.getProperty("policy.expandProperties")); |
|
allowSystemProperties = "true".equalsIgnoreCase |
|
(Security.getProperty("policy.allowSystemProperty")); |
|
notUtf8 = "false".equalsIgnoreCase |
|
(System.getProperty("sun.security.policy.utf8")); |
|
return System.getProperty("sun.security.policy.numcaches"); |
|
}}); |
|
|
|
int numCaches; |
|
if (numCacheStr != null) { |
|
try { |
|
numCaches = Integer.parseInt(numCacheStr); |
|
} catch (NumberFormatException e) { |
|
numCaches = DEFAULT_CACHE_SIZE; |
|
} |
|
} else { |
|
numCaches = DEFAULT_CACHE_SIZE; |
|
} |
|
PolicyInfo newInfo = new PolicyInfo(numCaches); |
|
initPolicyFile(newInfo, url); |
|
policyInfo = newInfo; |
|
} |
|
|
|
private void initPolicyFile(final PolicyInfo newInfo, final URL url) { |
|
|
|
|
|
AccessController.doPrivileged(new PrivilegedAction<>() { |
|
@Override |
|
public Void run() { |
|
initDefaultPolicy(newInfo); |
|
return null; |
|
} |
|
}); |
|
|
|
if (url != null) { |
|
|
|
/** |
|
* If the caller specified a URL via Policy.getInstance, |
|
* we only read from default.policy and that URL. |
|
*/ |
|
|
|
if (debug != null) { |
|
debug.println("reading " + url); |
|
} |
|
AccessController.doPrivileged(new PrivilegedAction<>() { |
|
@Override |
|
public Void run() { |
|
if (init(url, newInfo) == false) { |
|
|
|
initStaticPolicy(newInfo); |
|
} |
|
return null; |
|
} |
|
}); |
|
|
|
} else { |
|
|
|
/** |
|
* Caller did not specify URL via Policy.getInstance. |
|
* Read from URLs listed in the java.security properties file. |
|
*/ |
|
|
|
boolean loaded_one = initPolicyFile(POLICY, POLICY_URL, newInfo); |
|
// To maintain strict backward compatibility |
|
|
|
if (!loaded_one) { |
|
|
|
initStaticPolicy(newInfo); |
|
} |
|
} |
|
} |
|
|
|
private boolean initPolicyFile(final String propname, final String urlname, |
|
final PolicyInfo newInfo) { |
|
boolean loadedPolicy = |
|
AccessController.doPrivileged(new PrivilegedAction<>() { |
|
@Override |
|
public Boolean run() { |
|
boolean loaded_policy = false; |
|
|
|
if (allowSystemProperties) { |
|
String extra_policy = System.getProperty(propname); |
|
if (extra_policy != null) { |
|
boolean overrideAll = false; |
|
if (extra_policy.startsWith("=")) { |
|
overrideAll = true; |
|
extra_policy = extra_policy.substring(1); |
|
} |
|
try { |
|
extra_policy = |
|
PropertyExpander.expand(extra_policy); |
|
URL policyURL; |
|
|
|
File policyFile = new File(extra_policy); |
|
if (policyFile.exists()) { |
|
policyURL = ParseUtil.fileToEncodedURL |
|
(new File(policyFile.getCanonicalPath())); |
|
} else { |
|
policyURL = new URL(extra_policy); |
|
} |
|
if (debug != null) { |
|
debug.println("reading "+policyURL); |
|
} |
|
if (init(policyURL, newInfo)) { |
|
loaded_policy = true; |
|
} |
|
} catch (Exception e) { |
|
|
|
if (debug != null) { |
|
debug.println("caught exception: "+e); |
|
} |
|
} |
|
if (overrideAll) { |
|
if (debug != null) { |
|
debug.println("overriding other policies!"); |
|
} |
|
return Boolean.valueOf(loaded_policy); |
|
} |
|
} |
|
} |
|
|
|
int n = 1; |
|
String policy_uri; |
|
|
|
while ((policy_uri = Security.getProperty(urlname+n)) != null) { |
|
try { |
|
URL policy_url = null; |
|
String expanded_uri = PropertyExpander.expand |
|
(policy_uri).replace(File.separatorChar, '/'); |
|
|
|
if (policy_uri.startsWith("file:${java.home}/") || |
|
policy_uri.startsWith("file:${user.home}/")) { |
|
|
|
// this special case accommodates |
|
// the situation java.home/user.home |
|
// expand to a single slash, resulting in |
|
|
|
policy_url = new File |
|
(expanded_uri.substring(5)).toURI().toURL(); |
|
} else { |
|
policy_url = new URI(expanded_uri).toURL(); |
|
} |
|
|
|
if (debug != null) { |
|
debug.println("reading " + policy_url); |
|
} |
|
if (init(policy_url, newInfo)) { |
|
loaded_policy = true; |
|
} |
|
} catch (Exception e) { |
|
if (debug != null) { |
|
debug.println( |
|
"Debug info only. Error reading policy " +e); |
|
e.printStackTrace(); |
|
} |
|
// ignore that policy |
|
} |
|
n++; |
|
} |
|
return Boolean.valueOf(loaded_policy); |
|
} |
|
}); |
|
|
|
return loadedPolicy; |
|
} |
|
|
|
private void initDefaultPolicy(PolicyInfo newInfo) { |
|
Path defaultPolicy = builtInFS.getPath(StaticProperty.javaHome(), |
|
"lib", |
|
"security", |
|
"default.policy"); |
|
if (debug != null) { |
|
debug.println("reading " + defaultPolicy); |
|
} |
|
try (BufferedReader br = Files.newBufferedReader(defaultPolicy)) { |
|
|
|
PolicyParser pp = new PolicyParser(expandProperties); |
|
pp.read(br); |
|
|
|
Enumeration<PolicyParser.GrantEntry> enum_ = pp.grantElements(); |
|
while (enum_.hasMoreElements()) { |
|
PolicyParser.GrantEntry ge = enum_.nextElement(); |
|
addGrantEntry(ge, null, newInfo); |
|
} |
|
} catch (Exception e) { |
|
throw new InternalError("Failed to load default.policy", e); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
private boolean init(URL policy, PolicyInfo newInfo) { |
|
|
|
// skip parsing policy file if it has been previously parsed and |
|
|
|
if (badPolicyURLs.contains(policy)) { |
|
if (debug != null) { |
|
debug.println("skipping bad policy file: " + policy); |
|
} |
|
return false; |
|
} |
|
|
|
try (InputStreamReader isr = |
|
getInputStreamReader(PolicyUtil.getInputStream(policy))) { |
|
|
|
PolicyParser pp = new PolicyParser(expandProperties); |
|
pp.read(isr); |
|
|
|
KeyStore keyStore = null; |
|
try { |
|
keyStore = PolicyUtil.getKeyStore |
|
(policy, |
|
pp.getKeyStoreUrl(), |
|
pp.getKeyStoreType(), |
|
pp.getKeyStoreProvider(), |
|
pp.getStorePassURL(), |
|
debug); |
|
} catch (Exception e) { |
|
|
|
if (debug != null) { |
|
debug.println("Debug info only. Ignoring exception."); |
|
e.printStackTrace(); |
|
} |
|
} |
|
|
|
Enumeration<PolicyParser.GrantEntry> enum_ = pp.grantElements(); |
|
while (enum_.hasMoreElements()) { |
|
PolicyParser.GrantEntry ge = enum_.nextElement(); |
|
addGrantEntry(ge, keyStore, newInfo); |
|
} |
|
return true; |
|
} catch (PolicyParser.ParsingException pe) { |
|
|
|
badPolicyURLs.add(policy); |
|
Object[] source = {policy, pe.getNonlocalizedMessage()}; |
|
System.err.println(LocalizedMessage.getNonlocalized |
|
(POLICY + ".error.parsing.policy.message", source)); |
|
if (debug != null) { |
|
pe.printStackTrace(); |
|
} |
|
} catch (Exception e) { |
|
if (debug != null) { |
|
debug.println("error parsing "+policy); |
|
debug.println(e.toString()); |
|
e.printStackTrace(); |
|
} |
|
} |
|
|
|
return false; |
|
} |
|
|
|
private InputStreamReader getInputStreamReader(InputStream is) { |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
return (notUtf8) |
|
? new InputStreamReader(is) |
|
: new InputStreamReader(is, UTF_8); |
|
} |
|
|
|
private void initStaticPolicy(final PolicyInfo newInfo) { |
|
if (debug != null) { |
|
debug.println("Initializing with static permissions"); |
|
} |
|
AccessController.doPrivileged(new PrivilegedAction<>() { |
|
@Override |
|
public Void run() { |
|
PolicyEntry pe = new PolicyEntry(new CodeSource(null, |
|
(Certificate[]) null)); |
|
pe.add(SecurityConstants.LOCAL_LISTEN_PERMISSION); |
|
pe.add(new PropertyPermission("java.version", |
|
SecurityConstants.PROPERTY_READ_ACTION)); |
|
pe.add(new PropertyPermission("java.vendor", |
|
SecurityConstants.PROPERTY_READ_ACTION)); |
|
pe.add(new PropertyPermission("java.vendor.url", |
|
SecurityConstants.PROPERTY_READ_ACTION)); |
|
pe.add(new PropertyPermission("java.class.version", |
|
SecurityConstants.PROPERTY_READ_ACTION)); |
|
pe.add(new PropertyPermission("os.name", |
|
SecurityConstants.PROPERTY_READ_ACTION)); |
|
pe.add(new PropertyPermission("os.version", |
|
SecurityConstants.PROPERTY_READ_ACTION)); |
|
pe.add(new PropertyPermission("os.arch", |
|
SecurityConstants.PROPERTY_READ_ACTION)); |
|
pe.add(new PropertyPermission("file.separator", |
|
SecurityConstants.PROPERTY_READ_ACTION)); |
|
pe.add(new PropertyPermission("path.separator", |
|
SecurityConstants.PROPERTY_READ_ACTION)); |
|
pe.add(new PropertyPermission("line.separator", |
|
SecurityConstants.PROPERTY_READ_ACTION)); |
|
pe.add(new PropertyPermission |
|
("java.specification.version", |
|
SecurityConstants.PROPERTY_READ_ACTION)); |
|
pe.add(new PropertyPermission |
|
("java.specification.vendor", |
|
SecurityConstants.PROPERTY_READ_ACTION)); |
|
pe.add(new PropertyPermission |
|
("java.specification.name", |
|
SecurityConstants.PROPERTY_READ_ACTION)); |
|
pe.add(new PropertyPermission |
|
("java.vm.specification.version", |
|
SecurityConstants.PROPERTY_READ_ACTION)); |
|
pe.add(new PropertyPermission |
|
("java.vm.specification.vendor", |
|
SecurityConstants.PROPERTY_READ_ACTION)); |
|
pe.add(new PropertyPermission |
|
("java.vm.specification.name", |
|
SecurityConstants.PROPERTY_READ_ACTION)); |
|
pe.add(new PropertyPermission("java.vm.version", |
|
SecurityConstants.PROPERTY_READ_ACTION)); |
|
pe.add(new PropertyPermission("java.vm.vendor", |
|
SecurityConstants.PROPERTY_READ_ACTION)); |
|
pe.add(new PropertyPermission("java.vm.name", |
|
SecurityConstants.PROPERTY_READ_ACTION)); |
|
|
|
|
|
newInfo.policyEntries.add(pe); |
|
|
|
return null; |
|
} |
|
}); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
private CodeSource getCodeSource(PolicyParser.GrantEntry ge, KeyStore keyStore, |
|
PolicyInfo newInfo) throws java.net.MalformedURLException |
|
{ |
|
Certificate[] certs = null; |
|
if (ge.signedBy != null) { |
|
certs = getCertificates(keyStore, ge.signedBy, newInfo); |
|
if (certs == null) { |
|
// we don't have a key for this alias, |
|
|
|
if (debug != null) { |
|
debug.println(" -- No certs for alias '" + |
|
ge.signedBy + "' - ignoring entry"); |
|
} |
|
return null; |
|
} |
|
} |
|
|
|
URL location; |
|
|
|
if (ge.codeBase != null) |
|
location = new URL(ge.codeBase); |
|
else |
|
location = null; |
|
|
|
return (canonicalizeCodebase(new CodeSource(location, certs),false)); |
|
} |
|
|
|
|
|
|
|
*/ |
|
private void addGrantEntry(PolicyParser.GrantEntry ge, |
|
KeyStore keyStore, PolicyInfo newInfo) { |
|
|
|
if (debug != null) { |
|
debug.println("Adding policy entry: "); |
|
debug.println(" signedBy " + ge.signedBy); |
|
debug.println(" codeBase " + ge.codeBase); |
|
if (ge.principals != null) { |
|
for (PolicyParser.PrincipalEntry pppe : ge.principals) { |
|
debug.println(" " + pppe.toString()); |
|
} |
|
} |
|
} |
|
|
|
try { |
|
CodeSource codesource = getCodeSource(ge, keyStore, newInfo); |
|
|
|
if (codesource == null) return; |
|
|
|
// perform keystore alias principal replacement. |
|
// for example, if alias resolves to X509 certificate, |
|
// replace principal with: <X500Principal class> <SubjectDN> |
|
|
|
if (replacePrincipals(ge.principals, keyStore) == false) |
|
return; |
|
PolicyEntry entry = new PolicyEntry(codesource, ge.principals); |
|
Enumeration<PolicyParser.PermissionEntry> enum_ = |
|
ge.permissionElements(); |
|
while (enum_.hasMoreElements()) { |
|
PolicyParser.PermissionEntry pe = enum_.nextElement(); |
|
|
|
try { |
|
|
|
expandPermissionName(pe, keyStore); |
|
|
|
|
|
Permission perm; |
|
if (pe.permission.equals |
|
("javax.security.auth.PrivateCredentialPermission") && |
|
pe.name.endsWith(" self")) { |
|
pe.name = pe.name.substring(0, pe.name.indexOf("self")) |
|
+ SELF; |
|
} |
|
|
|
if (pe.name != null && pe.name.indexOf(SELF) != -1) { |
|
// Create a "SelfPermission" , it could be an |
|
// an unresolved permission which will be resolved |
|
// when implies is called |
|
|
|
Certificate[] certs; |
|
if (pe.signedBy != null) { |
|
certs = getCertificates(keyStore, |
|
pe.signedBy, |
|
newInfo); |
|
} else { |
|
certs = null; |
|
} |
|
perm = new SelfPermission(pe.permission, |
|
pe.name, |
|
pe.action, |
|
certs); |
|
} else { |
|
perm = getInstance(pe.permission, |
|
pe.name, |
|
pe.action); |
|
} |
|
entry.add(perm); |
|
if (debug != null) { |
|
debug.println(" "+perm); |
|
} |
|
} catch (ClassNotFoundException cnfe) { |
|
Certificate[] certs; |
|
if (pe.signedBy != null) { |
|
certs = getCertificates(keyStore, |
|
pe.signedBy, |
|
newInfo); |
|
} else { |
|
certs = null; |
|
} |
|
|
|
// only add if we had no signer or we had |
|
|
|
if (certs != null || pe.signedBy == null) { |
|
Permission perm = new UnresolvedPermission( |
|
pe.permission, |
|
pe.name, |
|
pe.action, |
|
certs); |
|
entry.add(perm); |
|
if (debug != null) { |
|
debug.println(" "+perm); |
|
} |
|
} |
|
} catch (java.lang.reflect.InvocationTargetException ite) { |
|
Object[] source = {pe.permission, |
|
ite.getCause().toString()}; |
|
System.err.println( |
|
LocalizedMessage.getNonlocalized( |
|
POLICY + ".error.adding.Permission.perm.message", |
|
source)); |
|
} catch (Exception e) { |
|
Object[] source = {pe.permission, |
|
e.toString()}; |
|
System.err.println( |
|
LocalizedMessage.getNonlocalized( |
|
POLICY + ".error.adding.Permission.perm.message", |
|
source)); |
|
} |
|
} |
|
|
|
|
|
newInfo.policyEntries.add(entry); |
|
} catch (Exception e) { |
|
Object[] source = {e.toString()}; |
|
System.err.println( |
|
LocalizedMessage.getNonlocalized( |
|
POLICY + ".error.adding.Entry.message", |
|
source)); |
|
} |
|
if (debug != null) |
|
debug.println(); |
|
} |
|
|
|
/** |
|
* Returns a new Permission object of the given Type. The Permission is |
|
* created by getting the |
|
* Class object using the <code>Class.forName</code> method, and using |
|
* the reflection API to invoke the (String name, String actions) |
|
* constructor on the |
|
* object. |
|
* |
|
* @param type the type of Permission being created. |
|
* @param name the name of the Permission being created. |
|
* @param actions the actions of the Permission being created. |
|
* |
|
* @exception ClassNotFoundException if the particular Permission |
|
* class could not be found. |
|
* |
|
* @exception IllegalAccessException if the class or initializer is |
|
* not accessible. |
|
* |
|
* @exception InstantiationException if getInstance tries to |
|
* instantiate an abstract class or an interface, or if the |
|
* instantiation fails for some other reason. |
|
* |
|
* @exception NoSuchMethodException if the (String, String) constructor |
|
* is not found. |
|
* |
|
* @exception InvocationTargetException if the underlying Permission |
|
* constructor throws an exception. |
|
* |
|
*/ |
|
|
|
private static final Permission getInstance(String type, |
|
String name, |
|
String actions) |
|
throws ClassNotFoundException, |
|
InstantiationException, |
|
IllegalAccessException, |
|
NoSuchMethodException, |
|
InvocationTargetException |
|
{ |
|
Class<?> pc = Class.forName(type, false, null); |
|
Permission answer = getKnownPermission(pc, name, actions); |
|
if (answer != null) { |
|
return answer; |
|
} |
|
if (!Permission.class.isAssignableFrom(pc)) { |
|
|
|
throw new ClassCastException(type + " is not a Permission"); |
|
} |
|
|
|
if (name == null && actions == null) { |
|
try { |
|
Constructor<?> c = pc.getConstructor(PARAMS0); |
|
return (Permission) c.newInstance(new Object[] {}); |
|
} catch (NoSuchMethodException ne) { |
|
try { |
|
Constructor<?> c = pc.getConstructor(PARAMS1); |
|
return (Permission) c.newInstance( |
|
new Object[] { name}); |
|
} catch (NoSuchMethodException ne1 ) { |
|
Constructor<?> c = pc.getConstructor(PARAMS2); |
|
return (Permission) c.newInstance( |
|
new Object[] { name, actions }); |
|
} |
|
} |
|
} else { |
|
if (name != null && actions == null) { |
|
try { |
|
Constructor<?> c = pc.getConstructor(PARAMS1); |
|
return (Permission) c.newInstance(new Object[] { name}); |
|
} catch (NoSuchMethodException ne) { |
|
Constructor<?> c = pc.getConstructor(PARAMS2); |
|
return (Permission) c.newInstance( |
|
new Object[] { name, actions }); |
|
} |
|
} else { |
|
Constructor<?> c = pc.getConstructor(PARAMS2); |
|
return (Permission) c.newInstance( |
|
new Object[] { name, actions }); |
|
} |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
private static Permission getKnownPermission(Class<?> claz, String name, |
|
String actions) { |
|
if (claz.equals(FilePermission.class)) { |
|
return new FilePermission(name, actions); |
|
} else if (claz.equals(SocketPermission.class)) { |
|
return new SocketPermission(name, actions); |
|
} else if (claz.equals(RuntimePermission.class)) { |
|
return new RuntimePermission(name, actions); |
|
} else if (claz.equals(PropertyPermission.class)) { |
|
return new PropertyPermission(name, actions); |
|
} else if (claz.equals(NetPermission.class)) { |
|
return new NetPermission(name, actions); |
|
} else if (claz.equals(AllPermission.class)) { |
|
return SecurityConstants.ALL_PERMISSION; |
|
} else if (claz.equals(SecurityPermission.class)) { |
|
return new SecurityPermission(name, actions); |
|
} else { |
|
return null; |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
private static Principal getKnownPrincipal(Class<?> claz, String name) { |
|
if (claz.equals(X500Principal.class)) { |
|
return new X500Principal(name); |
|
} else { |
|
return null; |
|
} |
|
} |
|
|
|
|
|
|
|
*/ |
|
private Certificate[] getCertificates |
|
(KeyStore keyStore, String aliases, PolicyInfo newInfo) { |
|
|
|
List<Certificate> vcerts = null; |
|
|
|
StringTokenizer st = new StringTokenizer(aliases, ","); |
|
int n = 0; |
|
|
|
while (st.hasMoreTokens()) { |
|
String alias = st.nextToken().trim(); |
|
n++; |
|
Certificate cert = null; |
|
|
|
synchronized (newInfo.aliasMapping) { |
|
cert = (Certificate)newInfo.aliasMapping.get(alias); |
|
|
|
if (cert == null && keyStore != null) { |
|
|
|
try { |
|
cert = keyStore.getCertificate(alias); |
|
} catch (KeyStoreException kse) { |
|
// never happens, because keystore has already been loaded |
|
// when we call this |
|
} |
|
if (cert != null) { |
|
newInfo.aliasMapping.put(alias, cert); |
|
newInfo.aliasMapping.put(cert, alias); |
|
} |
|
} |
|
} |
|
|
|
if (cert != null) { |
|
if (vcerts == null) |
|
vcerts = new ArrayList<>(); |
|
vcerts.add(cert); |
|
} |
|
} |
|
|
|
|
|
if (vcerts != null && n == vcerts.size()) { |
|
Certificate[] certs = new Certificate[vcerts.size()]; |
|
vcerts.toArray(certs); |
|
return certs; |
|
} else { |
|
return null; |
|
} |
|
} |
|
|
|
|
|
|
|
*/ |
|
@Override public void refresh() { |
|
init(url); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
@Override |
|
public boolean implies(ProtectionDomain pd, Permission p) { |
|
ProtectionDomainCache pdMap = policyInfo.getPdMapping(); |
|
PermissionCollection pc = pdMap.get(pd); |
|
|
|
if (pc != null) { |
|
return pc.implies(p); |
|
} |
|
|
|
pc = getPermissions(pd); |
|
if (pc == null) { |
|
return false; |
|
} |
|
|
|
|
|
pdMap.put(pd, pc); |
|
return pc.implies(p); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
@Override |
|
public PermissionCollection getPermissions(ProtectionDomain domain) { |
|
Permissions perms = new Permissions(); |
|
|
|
if (domain == null) |
|
return perms; |
|
|
|
|
|
getPermissions(perms, domain); |
|
|
|
// add static perms |
|
// - adding static perms after policy perms is necessary |
|
|
|
PermissionCollection pc = domain.getPermissions(); |
|
if (pc != null) { |
|
synchronized (pc) { |
|
Enumeration<Permission> e = pc.elements(); |
|
while (e.hasMoreElements()) { |
|
perms.add(FilePermCompat.newPermPlusAltPath(e.nextElement())); |
|
} |
|
} |
|
} |
|
|
|
return perms; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
@Override |
|
public PermissionCollection getPermissions(CodeSource codesource) { |
|
return getPermissions(new Permissions(), codesource); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
private PermissionCollection getPermissions(Permissions perms, |
|
ProtectionDomain pd ) { |
|
if (debug != null) { |
|
debug.println("getPermissions:\n\t" + printPD(pd)); |
|
} |
|
|
|
final CodeSource cs = pd.getCodeSource(); |
|
if (cs == null) |
|
return perms; |
|
|
|
CodeSource canonCodeSource = AccessController.doPrivileged( |
|
new java.security.PrivilegedAction<>(){ |
|
@Override |
|
public CodeSource run() { |
|
return canonicalizeCodebase(cs, true); |
|
} |
|
}); |
|
return getPermissions(perms, canonCodeSource, pd.getPrincipals()); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
private PermissionCollection getPermissions(Permissions perms, |
|
final CodeSource cs) { |
|
|
|
if (cs == null) |
|
return perms; |
|
|
|
CodeSource canonCodeSource = AccessController.doPrivileged( |
|
new PrivilegedAction<>(){ |
|
@Override |
|
public CodeSource run() { |
|
return canonicalizeCodebase(cs, true); |
|
} |
|
}); |
|
|
|
return getPermissions(perms, canonCodeSource, null); |
|
} |
|
|
|
private Permissions getPermissions(Permissions perms, |
|
final CodeSource cs, |
|
Principal[] principals) { |
|
for (PolicyEntry entry : policyInfo.policyEntries) { |
|
addPermissions(perms, cs, principals, entry); |
|
} |
|
|
|
return perms; |
|
} |
|
|
|
private void addPermissions(Permissions perms, |
|
final CodeSource cs, |
|
Principal[] principals, |
|
final PolicyEntry entry) { |
|
|
|
if (debug != null) { |
|
debug.println("evaluate codesources:\n" + |
|
"\tPolicy CodeSource: " + entry.getCodeSource() + "\n" + |
|
"\tActive CodeSource: " + cs); |
|
} |
|
|
|
|
|
Boolean imp = AccessController.doPrivileged |
|
(new PrivilegedAction<>() { |
|
@Override |
|
public Boolean run() { |
|
return entry.getCodeSource().implies(cs); |
|
} |
|
}); |
|
if (!imp.booleanValue()) { |
|
if (debug != null) { |
|
debug.println("evaluation (codesource) failed"); |
|
} |
|
|
|
|
|
return; |
|
} |
|
|
|
// check to see if the Principals imply |
|
|
|
List<PolicyParser.PrincipalEntry> entryPs = entry.getPrincipals(); |
|
if (debug != null) { |
|
List<PolicyParser.PrincipalEntry> accPs = new ArrayList<>(); |
|
if (principals != null) { |
|
for (int i = 0; i < principals.length; i++) { |
|
accPs.add(new PolicyParser.PrincipalEntry |
|
(principals[i].getClass().getName(), |
|
principals[i].getName())); |
|
} |
|
} |
|
debug.println("evaluate principals:\n" + |
|
"\tPolicy Principals: " + entryPs + "\n" + |
|
"\tActive Principals: " + accPs); |
|
} |
|
|
|
if (entryPs == null || entryPs.isEmpty()) { |
|
|
|
// policy entry has no principals - |
|
// add perms regardless of principals in current ACC |
|
|
|
addPerms(perms, principals, entry); |
|
if (debug != null) { |
|
debug.println("evaluation (codesource/principals) passed"); |
|
} |
|
return; |
|
|
|
} else if (principals == null || principals.length == 0) { |
|
|
|
// current thread has no principals but this policy entry |
|
// has principals - perms are not added |
|
|
|
if (debug != null) { |
|
debug.println("evaluation (principals) failed"); |
|
} |
|
return; |
|
} |
|
|
|
// current thread has principals and this policy entry |
|
// has principals. see if policy entry principals match |
|
// principals in current ACC |
|
|
|
for (PolicyParser.PrincipalEntry pppe : entryPs) { |
|
|
|
|
|
if (pppe.isWildcardClass()) { |
|
|
|
continue; |
|
} |
|
|
|
if (pppe.isWildcardName()) { |
|
|
|
if (wildcardPrincipalNameImplies(pppe.principalClass, |
|
principals)) { |
|
continue; |
|
} |
|
if (debug != null) { |
|
debug.println("evaluation (principal name wildcard) failed"); |
|
} |
|
// policy entry principal not in current ACC - |
|
|
|
return; |
|
} |
|
|
|
Set<Principal> pSet = new HashSet<>(Arrays.asList(principals)); |
|
Subject subject = new Subject(true, pSet, |
|
Collections.EMPTY_SET, |
|
Collections.EMPTY_SET); |
|
try { |
|
ClassLoader cl = Thread.currentThread().getContextClassLoader(); |
|
Class<?> pClass = Class.forName(pppe.principalClass, false, cl); |
|
Principal p = getKnownPrincipal(pClass, pppe.principalName); |
|
if (p == null) { |
|
if (!Principal.class.isAssignableFrom(pClass)) { |
|
|
|
throw new ClassCastException(pppe.principalClass + |
|
" is not a Principal"); |
|
} |
|
|
|
Constructor<?> c = pClass.getConstructor(PARAMS1); |
|
p = (Principal)c.newInstance(new Object[] { |
|
pppe.principalName }); |
|
|
|
} |
|
|
|
if (debug != null) { |
|
debug.println("found Principal " + p.getClass().getName()); |
|
} |
|
|
|
// check if the Principal implies the current |
|
|
|
if (!p.implies(subject)) { |
|
if (debug != null) { |
|
debug.println("evaluation (principal implies) failed"); |
|
} |
|
|
|
// policy principal does not imply the current Subject - |
|
|
|
return; |
|
} |
|
} catch (Exception e) { |
|
// fall back to default principal comparison. |
|
// see if policy entry principal is in current ACC |
|
|
|
if (debug != null) { |
|
e.printStackTrace(); |
|
} |
|
|
|
if (!pppe.implies(subject)) { |
|
if (debug != null) { |
|
debug.println("evaluation (default principal implies) failed"); |
|
} |
|
|
|
// policy entry principal not in current ACC - |
|
|
|
return; |
|
} |
|
} |
|
|
|
// either the principal information matched, |
|
// or the Principal.implies succeeded. |
|
// continue loop and test the next policy principal |
|
} |
|
|
|
// all policy entry principals were found in the current ACC - |
|
// grant the policy permissions |
|
|
|
if (debug != null) { |
|
debug.println("evaluation (codesource/principals) passed"); |
|
} |
|
addPerms(perms, principals, entry); |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
private static boolean wildcardPrincipalNameImplies(String principalClass, |
|
Principal[] principals) |
|
{ |
|
for (Principal p : principals) { |
|
if (principalClass.equals(p.getClass().getName())) { |
|
return true; |
|
} |
|
} |
|
return false; |
|
} |
|
|
|
private void addPerms(Permissions perms, |
|
Principal[] accPs, |
|
PolicyEntry entry) { |
|
for (int i = 0; i < entry.permissions.size(); i++) { |
|
Permission p = entry.permissions.get(i); |
|
if (debug != null) { |
|
debug.println(" granting " + p); |
|
} |
|
|
|
if (p instanceof SelfPermission) { |
|
|
|
expandSelf((SelfPermission)p, |
|
entry.getPrincipals(), |
|
accPs, |
|
perms); |
|
} else { |
|
perms.add(FilePermCompat.newPermPlusAltPath(p)); |
|
} |
|
} |
|
} |
|
|
|
/** |
|
* @param sp the SelfPermission that needs to be expanded. |
|
* |
|
* @param entryPs list of principals for the Policy entry. |
|
* |
|
* @param pdp Principal array from the current ProtectionDomain. |
|
* |
|
* @param perms the PermissionCollection where the individual |
|
* Permissions will be added after expansion. |
|
*/ |
|
|
|
private void expandSelf(SelfPermission sp, |
|
List<PolicyParser.PrincipalEntry> entryPs, |
|
Principal[] pdp, |
|
Permissions perms) { |
|
|
|
if (entryPs == null || entryPs.isEmpty()) { |
|
|
|
if (debug != null) { |
|
debug.println("Ignoring permission " |
|
+ sp.getSelfType() |
|
+ " with target name (" |
|
+ sp.getSelfName() + "). " |
|
+ "No Principal(s) specified " |
|
+ "in the grant clause. " |
|
+ "SELF-based target names are " |
|
+ "only valid in the context " |
|
+ "of a Principal-based grant entry." |
|
); |
|
} |
|
return; |
|
} |
|
int startIndex = 0; |
|
int v; |
|
StringBuilder sb = new StringBuilder(); |
|
while ((v = sp.getSelfName().indexOf(SELF, startIndex)) != -1) { |
|
|
|
|
|
sb.append(sp.getSelfName().substring(startIndex, v)); |
|
|
|
|
|
Iterator<PolicyParser.PrincipalEntry> pli = entryPs.iterator(); |
|
while (pli.hasNext()) { |
|
PolicyParser.PrincipalEntry pppe = pli.next(); |
|
String[][] principalInfo = getPrincipalInfo(pppe,pdp); |
|
for (int i = 0; i < principalInfo.length; i++) { |
|
if (i != 0) { |
|
sb.append(", "); |
|
} |
|
sb.append(principalInfo[i][0] + " " + |
|
"\"" + principalInfo[i][1] + "\""); |
|
} |
|
if (pli.hasNext()) { |
|
sb.append(", "); |
|
} |
|
} |
|
startIndex = v + SELF.length(); |
|
} |
|
|
|
sb.append(sp.getSelfName().substring(startIndex)); |
|
|
|
if (debug != null) { |
|
debug.println(" expanded:\n\t" + sp.getSelfName() |
|
+ "\n into:\n\t" + sb.toString()); |
|
} |
|
try { |
|
|
|
perms.add(FilePermCompat.newPermPlusAltPath(getInstance(sp.getSelfType(), |
|
sb.toString(), |
|
sp.getSelfActions()))); |
|
} catch (ClassNotFoundException cnfe) { |
|
// ok, the permission is not in the bootclasspath. |
|
// before we add an UnresolvedPermission, check to see |
|
// whether this perm already belongs to the collection. |
|
// if so, use that perm's ClassLoader to create a new |
|
|
|
Class<?> pc = null; |
|
synchronized (perms) { |
|
Enumeration<Permission> e = perms.elements(); |
|
while (e.hasMoreElements()) { |
|
Permission pElement = e.nextElement(); |
|
if (pElement.getClass().getName().equals(sp.getSelfType())) { |
|
pc = pElement.getClass(); |
|
break; |
|
} |
|
} |
|
} |
|
if (pc == null) { |
|
|
|
perms.add(new UnresolvedPermission(sp.getSelfType(), |
|
sb.toString(), |
|
sp.getSelfActions(), |
|
sp.getCerts())); |
|
} else { |
|
try { |
|
// we found an instantiated permission. |
|
|
|
Constructor<?> c; |
|
|
|
if (sp.getSelfActions() == null) { |
|
try { |
|
c = pc.getConstructor(PARAMS1); |
|
perms.add((Permission)c.newInstance |
|
(new Object[] {sb.toString()})); |
|
} catch (NoSuchMethodException ne) { |
|
c = pc.getConstructor(PARAMS2); |
|
perms.add((Permission)c.newInstance |
|
(new Object[] {sb.toString(), |
|
sp.getSelfActions() })); |
|
} |
|
} else { |
|
c = pc.getConstructor(PARAMS2); |
|
perms.add((Permission)c.newInstance |
|
(new Object[] {sb.toString(), |
|
sp.getSelfActions()})); |
|
} |
|
} catch (Exception nme) { |
|
if (debug != null) { |
|
debug.println("self entry expansion " + |
|
" instantiation failed: " |
|
+ nme.toString()); |
|
} |
|
} |
|
} |
|
} catch (Exception e) { |
|
if (debug != null) { |
|
debug.println(e.toString()); |
|
} |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
private String[][] getPrincipalInfo |
|
(PolicyParser.PrincipalEntry pe, Principal[] pdp) { |
|
|
|
// there are 3 possibilities: |
|
// 1) the entry's Principal class and name are not wildcarded |
|
// 2) the entry's Principal name is wildcarded only |
|
// 3) the entry's Principal class and name are wildcarded |
|
|
|
if (!pe.isWildcardClass() && !pe.isWildcardName()) { |
|
|
|
// build an info array for the principal |
|
|
|
String[][] info = new String[1][2]; |
|
info[0][0] = pe.principalClass; |
|
info[0][1] = pe.principalName; |
|
return info; |
|
|
|
} else if (!pe.isWildcardClass() && pe.isWildcardName()) { |
|
|
|
// build an info array for every principal |
|
// in the current domain which has a principal class |
|
|
|
List<Principal> plist = new ArrayList<>(); |
|
for (int i = 0; i < pdp.length; i++) { |
|
if (pe.principalClass.equals(pdp[i].getClass().getName())) |
|
plist.add(pdp[i]); |
|
} |
|
String[][] info = new String[plist.size()][2]; |
|
int i = 0; |
|
for (Principal p : plist) { |
|
info[i][0] = p.getClass().getName(); |
|
info[i][1] = p.getName(); |
|
i++; |
|
} |
|
return info; |
|
|
|
} else { |
|
|
|
// build an info array for every |
|
// one of the current Domain's principals |
|
|
|
String[][] info = new String[pdp.length][2]; |
|
|
|
for (int i = 0; i < pdp.length; i++) { |
|
info[i][0] = pdp[i].getClass().getName(); |
|
info[i][1] = pdp[i].getName(); |
|
} |
|
return info; |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
protected Certificate[] getSignerCertificates(CodeSource cs) { |
|
Certificate[] certs = null; |
|
if ((certs = cs.getCertificates()) == null) |
|
return null; |
|
for (int i=0; i<certs.length; i++) { |
|
if (!(certs[i] instanceof X509Certificate)) |
|
return cs.getCertificates(); |
|
} |
|
|
|
|
|
int i = 0; |
|
int count = 0; |
|
while (i < certs.length) { |
|
count++; |
|
while (((i+1) < certs.length) |
|
&& ((X509Certificate)certs[i]).getIssuerX500Principal().equals( |
|
((X509Certificate)certs[i+1]).getSubjectX500Principal())) { |
|
i++; |
|
} |
|
i++; |
|
} |
|
if (count == certs.length) |
|
|
|
return certs; |
|
|
|
List<Certificate> userCertList = new ArrayList<>(); |
|
i = 0; |
|
while (i < certs.length) { |
|
userCertList.add(certs[i]); |
|
while (((i+1) < certs.length) |
|
&& ((X509Certificate)certs[i]).getIssuerX500Principal().equals( |
|
((X509Certificate)certs[i+1]).getSubjectX500Principal())) { |
|
i++; |
|
} |
|
i++; |
|
} |
|
Certificate[] userCerts = new Certificate[userCertList.size()]; |
|
userCertList.toArray(userCerts); |
|
return userCerts; |
|
} |
|
|
|
private CodeSource canonicalizeCodebase(CodeSource cs, |
|
boolean extractSignerCerts) { |
|
|
|
String path = null; |
|
|
|
CodeSource canonCs = cs; |
|
URL u = cs.getLocation(); |
|
if (u != null) { |
|
if (u.getProtocol().equals("jar")) { |
|
|
|
String spec = u.getFile(); |
|
int separator = spec.indexOf("!/"); |
|
if (separator != -1) { |
|
try { |
|
u = new URL(spec.substring(0, separator)); |
|
} catch (MalformedURLException e) { |
|
// Fail silently. In this case, url stays what |
|
// it was above |
|
} |
|
} |
|
} |
|
if (u.getProtocol().equals("file")) { |
|
boolean isLocalFile = false; |
|
String host = u.getHost(); |
|
isLocalFile = (host == null || host.isEmpty() || |
|
host.equals("~") || host.equalsIgnoreCase("localhost")); |
|
|
|
if (isLocalFile) { |
|
path = u.getFile().replace('/', File.separatorChar); |
|
path = ParseUtil.decode(path); |
|
} |
|
} |
|
} |
|
|
|
if (path != null) { |
|
try { |
|
URL csUrl = null; |
|
path = canonPath(path); |
|
csUrl = ParseUtil.fileToEncodedURL(new File(path)); |
|
|
|
if (extractSignerCerts) { |
|
canonCs = new CodeSource(csUrl, |
|
getSignerCertificates(cs)); |
|
} else { |
|
canonCs = new CodeSource(csUrl, |
|
cs.getCertificates()); |
|
} |
|
} catch (IOException ioe) { |
|
// leave codesource as it is, unless we have to extract its |
|
|
|
if (extractSignerCerts) { |
|
canonCs = new CodeSource(cs.getLocation(), |
|
getSignerCertificates(cs)); |
|
} |
|
} |
|
} else { |
|
if (extractSignerCerts) { |
|
canonCs = new CodeSource(cs.getLocation(), |
|
getSignerCertificates(cs)); |
|
} |
|
} |
|
return canonCs; |
|
} |
|
|
|
// Wrapper to return a canonical path that avoids calling getCanonicalPath() |
|
|
|
private static String canonPath(String path) throws IOException { |
|
if (path.endsWith("*")) { |
|
path = path.substring(0, path.length()-1) + "-"; |
|
path = new File(path).getCanonicalPath(); |
|
return path.substring(0, path.length()-1) + "*"; |
|
} else { |
|
return new File(path).getCanonicalPath(); |
|
} |
|
} |
|
|
|
private String printPD(ProtectionDomain pd) { |
|
Principal[] principals = pd.getPrincipals(); |
|
String pals = "<no principals>"; |
|
if (principals != null && principals.length > 0) { |
|
StringBuilder palBuf = new StringBuilder("(principals "); |
|
for (int i = 0; i < principals.length; i++) { |
|
palBuf.append(principals[i].getClass().getName() + |
|
" \"" + principals[i].getName() + |
|
"\""); |
|
if (i < principals.length-1) |
|
palBuf.append(", "); |
|
else |
|
palBuf.append(")"); |
|
} |
|
pals = palBuf.toString(); |
|
} |
|
return "PD CodeSource: " |
|
+ pd.getCodeSource() |
|
+"\n\t" + "PD ClassLoader: " |
|
+ pd.getClassLoader() |
|
+"\n\t" + "PD Principals: " |
|
+ pals; |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
private boolean replacePrincipals( |
|
List<PolicyParser.PrincipalEntry> principals, KeyStore keystore) { |
|
|
|
if (principals == null || principals.isEmpty() || keystore == null) |
|
return true; |
|
|
|
for (PolicyParser.PrincipalEntry pppe : principals) { |
|
if (pppe.isReplaceName()) { |
|
|
|
// perform replacement |
|
|
|
String name; |
|
if ((name = getDN(pppe.principalName, keystore)) == null) { |
|
return false; |
|
} |
|
|
|
if (debug != null) { |
|
debug.println(" Replacing \"" + |
|
pppe.principalName + |
|
"\" with " + |
|
X500PRINCIPAL + "/\"" + |
|
name + |
|
"\""); |
|
} |
|
|
|
pppe.principalClass = X500PRINCIPAL; |
|
pppe.principalName = name; |
|
} |
|
} |
|
// return true if no replacement was performed, |
|
|
|
return true; |
|
} |
|
|
|
private void expandPermissionName(PolicyParser.PermissionEntry pe, |
|
KeyStore keystore) throws Exception { |
|
|
|
if (pe.name == null || pe.name.indexOf("${{", 0) == -1) { |
|
return; |
|
} |
|
|
|
int startIndex = 0; |
|
int b, e; |
|
StringBuilder sb = new StringBuilder(); |
|
while ((b = pe.name.indexOf("${{", startIndex)) != -1) { |
|
e = pe.name.indexOf("}}", b); |
|
if (e < 1) { |
|
break; |
|
} |
|
sb.append(pe.name.substring(startIndex, b)); |
|
|
|
|
|
String value = pe.name.substring(b+3, e); |
|
|
|
|
|
int colonIndex; |
|
String prefix = value; |
|
String suffix; |
|
if ((colonIndex = value.indexOf(':')) != -1) { |
|
prefix = value.substring(0, colonIndex); |
|
} |
|
|
|
|
|
if (prefix.equalsIgnoreCase("self")) { |
|
|
|
sb.append(pe.name.substring(b, e+2)); |
|
startIndex = e+2; |
|
continue; |
|
} else if (prefix.equalsIgnoreCase("alias")) { |
|
|
|
if (colonIndex == -1) { |
|
Object[] source = {pe.name}; |
|
throw new Exception( |
|
LocalizedMessage.getNonlocalized( |
|
"alias.name.not.provided.pe.name.", |
|
source)); |
|
} |
|
suffix = value.substring(colonIndex+1); |
|
if ((suffix = getDN(suffix, keystore)) == null) { |
|
Object[] source = {value.substring(colonIndex+1)}; |
|
throw new Exception( |
|
LocalizedMessage.getNonlocalized( |
|
"unable.to.perform.substitution.on.alias.suffix", |
|
source)); |
|
} |
|
|
|
sb.append(X500PRINCIPAL + " \"" + suffix + "\""); |
|
startIndex = e+2; |
|
} else { |
|
Object[] source = {prefix}; |
|
throw new Exception( |
|
LocalizedMessage.getNonlocalized( |
|
"substitution.value.prefix.unsupported", |
|
source)); |
|
} |
|
} |
|
|
|
|
|
sb.append(pe.name.substring(startIndex)); |
|
|
|
|
|
if (debug != null) { |
|
debug.println(" Permission name expanded from:\n\t" + |
|
pe.name + "\nto\n\t" + sb.toString()); |
|
} |
|
pe.name = sb.toString(); |
|
} |
|
|
|
private String getDN(String alias, KeyStore keystore) { |
|
Certificate cert = null; |
|
try { |
|
cert = keystore.getCertificate(alias); |
|
} catch (Exception e) { |
|
if (debug != null) { |
|
debug.println(" Error retrieving certificate for '" + |
|
alias + |
|
"': " + |
|
e.toString()); |
|
} |
|
return null; |
|
} |
|
|
|
if (cert == null || !(cert instanceof X509Certificate)) { |
|
if (debug != null) { |
|
debug.println(" -- No certificate for '" + |
|
alias + |
|
"' - ignoring entry"); |
|
} |
|
return null; |
|
} else { |
|
X509Certificate x509Cert = (X509Certificate)cert; |
|
|
|
// 4702543: X500 names with an EmailAddress |
|
// were encoded incorrectly. create new |
|
// X500Principal name with correct encoding |
|
|
|
X500Principal p = new X500Principal |
|
(x509Cert.getSubjectX500Principal().toString()); |
|
return p.getName(); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
private static class PolicyEntry { |
|
|
|
private final CodeSource codesource; |
|
final List<Permission> permissions; |
|
private final List<PolicyParser.PrincipalEntry> principals; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
PolicyEntry(CodeSource cs, List<PolicyParser.PrincipalEntry> principals) |
|
{ |
|
this.codesource = cs; |
|
this.permissions = new ArrayList<Permission>(); |
|
this.principals = principals; |
|
} |
|
|
|
PolicyEntry(CodeSource cs) |
|
{ |
|
this(cs, null); |
|
} |
|
|
|
List<PolicyParser.PrincipalEntry> getPrincipals() { |
|
return principals; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
void add(Permission p) { |
|
permissions.add(p); |
|
} |
|
|
|
|
|
|
|
*/ |
|
CodeSource getCodeSource() { |
|
return codesource; |
|
} |
|
|
|
@Override public String toString(){ |
|
StringBuilder sb = new StringBuilder(); |
|
sb.append(ResourcesMgr.getString("LPARAM")); |
|
sb.append(getCodeSource()); |
|
sb.append("\n"); |
|
for (int j = 0; j < permissions.size(); j++) { |
|
Permission p = permissions.get(j); |
|
sb.append(ResourcesMgr.getString("SPACE")); |
|
sb.append(ResourcesMgr.getString("SPACE")); |
|
sb.append(p); |
|
sb.append(ResourcesMgr.getString("NEWLINE")); |
|
} |
|
sb.append(ResourcesMgr.getString("RPARAM")); |
|
sb.append(ResourcesMgr.getString("NEWLINE")); |
|
return sb.toString(); |
|
} |
|
} |
|
|
|
private static class SelfPermission extends Permission { |
|
|
|
@java.io.Serial |
|
private static final long serialVersionUID = -8315562579967246806L; |
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
private String type; |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
private String name; |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
private String actions; |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
private Certificate[] certs; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public SelfPermission(String type, String name, String actions, |
|
Certificate[] certs) |
|
{ |
|
super(type); |
|
if (type == null) { |
|
throw new NullPointerException |
|
(LocalizedMessage.getNonlocalized("type.can.t.be.null")); |
|
} |
|
this.type = type; |
|
this.name = name; |
|
this.actions = actions; |
|
if (certs != null) { |
|
|
|
for (int i=0; i<certs.length; i++) { |
|
if (!(certs[i] instanceof X509Certificate)) { |
|
// there is no concept of signer certs, so we store the |
|
|
|
this.certs = certs.clone(); |
|
break; |
|
} |
|
} |
|
|
|
if (this.certs == null) { |
|
// Go through the list of certs and see if all the certs are |
|
|
|
int i = 0; |
|
int count = 0; |
|
while (i < certs.length) { |
|
count++; |
|
while (((i+1) < certs.length) && |
|
((X509Certificate)certs[i]).getIssuerX500Principal().equals( |
|
((X509Certificate)certs[i+1]).getSubjectX500Principal())) { |
|
i++; |
|
} |
|
i++; |
|
} |
|
if (count == certs.length) { |
|
// All the certs are signer certs, so we store the |
|
|
|
this.certs = certs.clone(); |
|
} |
|
|
|
if (this.certs == null) { |
|
|
|
List<Certificate> signerCerts = new ArrayList<>(); |
|
i = 0; |
|
while (i < certs.length) { |
|
signerCerts.add(certs[i]); |
|
while (((i+1) < certs.length) && |
|
((X509Certificate)certs[i]).getIssuerX500Principal().equals( |
|
((X509Certificate)certs[i+1]).getSubjectX500Principal())) { |
|
i++; |
|
} |
|
i++; |
|
} |
|
this.certs = new Certificate[signerCerts.size()]; |
|
signerCerts.toArray(this.certs); |
|
} |
|
} |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
@Override public boolean implies(Permission p) { |
|
return false; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
@Override public boolean equals(Object obj) { |
|
if (obj == this) |
|
return true; |
|
|
|
if (! (obj instanceof SelfPermission)) |
|
return false; |
|
SelfPermission that = (SelfPermission) obj; |
|
|
|
if (!(this.type.equals(that.type) && |
|
this.name.equals(that.name) && |
|
this.actions.equals(that.actions))) |
|
return false; |
|
|
|
if (this.certs.length != that.certs.length) |
|
return false; |
|
|
|
int i,j; |
|
boolean match; |
|
|
|
for (i = 0; i < this.certs.length; i++) { |
|
match = false; |
|
for (j = 0; j < that.certs.length; j++) { |
|
if (this.certs[i].equals(that.certs[j])) { |
|
match = true; |
|
break; |
|
} |
|
} |
|
if (!match) return false; |
|
} |
|
|
|
for (i = 0; i < that.certs.length; i++) { |
|
match = false; |
|
for (j = 0; j < this.certs.length; j++) { |
|
if (that.certs[i].equals(this.certs[j])) { |
|
match = true; |
|
break; |
|
} |
|
} |
|
if (!match) return false; |
|
} |
|
return true; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
@Override public int hashCode() { |
|
int hash = type.hashCode(); |
|
if (name != null) |
|
hash ^= name.hashCode(); |
|
if (actions != null) |
|
hash ^= actions.hashCode(); |
|
return hash; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
@Override public String getActions() { |
|
return ""; |
|
} |
|
|
|
public String getSelfType() { |
|
return type; |
|
} |
|
|
|
public String getSelfName() { |
|
return name; |
|
} |
|
|
|
public String getSelfActions() { |
|
return actions; |
|
} |
|
|
|
public Certificate[] getCerts() { |
|
return certs; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
@Override public String toString() { |
|
return "(SelfPermission " + type + " " + name + " " + actions + ")"; |
|
} |
|
} |
|
|
|
|
|
|
|
*/ |
|
private static class PolicyInfo { |
|
private static final boolean verbose = false; |
|
|
|
|
|
final List<PolicyEntry> policyEntries; |
|
|
|
|
|
final Map<Object, Object> aliasMapping; |
|
|
|
|
|
private final ProtectionDomainCache[] pdMapping; |
|
private java.util.Random random; |
|
|
|
PolicyInfo(int numCaches) { |
|
policyEntries = new ArrayList<>(); |
|
aliasMapping = Collections.synchronizedMap(new HashMap<>(11)); |
|
|
|
pdMapping = new ProtectionDomainCache[numCaches]; |
|
JavaSecurityAccess jspda |
|
= SharedSecrets.getJavaSecurityAccess(); |
|
for (int i = 0; i < numCaches; i++) { |
|
pdMapping[i] = jspda.getProtectionDomainCache(); |
|
} |
|
if (numCaches > 1) { |
|
random = new java.util.Random(); |
|
} |
|
} |
|
ProtectionDomainCache getPdMapping() { |
|
if (pdMapping.length == 1) { |
|
return pdMapping[0]; |
|
} else { |
|
int i = java.lang.Math.abs(random.nextInt() % pdMapping.length); |
|
return pdMapping[i]; |
|
} |
|
} |
|
} |
|
} |