|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
|
|
package java.security; |
|
|
|
import java.util.ArrayList; |
|
import java.util.Collections; |
|
import java.util.Enumeration; |
|
import java.util.List; |
|
import java.util.Map; |
|
import java.util.Objects; |
|
import java.util.WeakHashMap; |
|
import jdk.internal.misc.JavaSecurityAccess; |
|
import jdk.internal.misc.SharedSecrets; |
|
import sun.security.action.GetPropertyAction; |
|
import sun.security.provider.PolicyFile; |
|
import sun.security.util.Debug; |
|
import sun.security.util.FilePermCompat; |
|
import sun.security.util.SecurityConstants; |
|
|
|
/** |
|
* The ProtectionDomain class encapsulates the characteristics of a domain, |
|
* which encloses a set of classes whose instances are granted a set |
|
* of permissions when being executed on behalf of a given set of Principals. |
|
* <p> |
|
* A static set of permissions can be bound to a ProtectionDomain when it is |
|
* constructed; such permissions are granted to the domain regardless of the |
|
* Policy in force. However, to support dynamic security policies, a |
|
* ProtectionDomain can also be constructed such that it is dynamically |
|
* mapped to a set of permissions by the current Policy whenever a permission |
|
* is checked. |
|
* |
|
* @author Li Gong |
|
* @author Roland Schemers |
|
* @author Gary Ellison |
|
* @since 1.2 |
|
*/ |
|
|
|
public class ProtectionDomain { |
|
|
|
|
|
|
|
|
|
*/ |
|
private static final boolean filePermCompatInPD = |
|
"true".equals(GetPropertyAction.privilegedGetProperty( |
|
"jdk.security.filePermCompat")); |
|
|
|
private static class JavaSecurityAccessImpl implements JavaSecurityAccess { |
|
|
|
private JavaSecurityAccessImpl() { |
|
} |
|
|
|
@Override |
|
public <T> T doIntersectionPrivilege( |
|
PrivilegedAction<T> action, |
|
final AccessControlContext stack, |
|
final AccessControlContext context) { |
|
if (action == null) { |
|
throw new NullPointerException(); |
|
} |
|
|
|
return AccessController.doPrivileged( |
|
action, |
|
getCombinedACC(context, stack) |
|
); |
|
} |
|
|
|
@Override |
|
public <T> T doIntersectionPrivilege( |
|
PrivilegedAction<T> action, |
|
AccessControlContext context) { |
|
return doIntersectionPrivilege(action, |
|
AccessController.getContext(), context); |
|
} |
|
|
|
@Override |
|
public ProtectionDomain[] getProtectDomains(AccessControlContext context) { |
|
return context.getContext(); |
|
} |
|
|
|
private static AccessControlContext getCombinedACC( |
|
AccessControlContext context, AccessControlContext stack) { |
|
AccessControlContext acc = |
|
new AccessControlContext(context, stack.getCombiner(), true); |
|
|
|
return new AccessControlContext(stack.getContext(), acc).optimize(); |
|
} |
|
|
|
@Override |
|
public ProtectionDomainCache getProtectionDomainCache() { |
|
return new ProtectionDomainCache() { |
|
private final Map<Key, PermissionCollection> map = |
|
Collections.synchronizedMap(new WeakHashMap<>()); |
|
public void put(ProtectionDomain pd, |
|
PermissionCollection pc) { |
|
map.put((pd == null ? null : pd.key), pc); |
|
} |
|
public PermissionCollection get(ProtectionDomain pd) { |
|
return pd == null ? map.get(null) : map.get(pd.key); |
|
} |
|
}; |
|
} |
|
} |
|
|
|
static { |
|
|
|
SharedSecrets.setJavaSecurityAccess(new JavaSecurityAccessImpl()); |
|
} |
|
|
|
|
|
private CodeSource codesource ; |
|
|
|
|
|
private ClassLoader classloader; |
|
|
|
|
|
private Principal[] principals; |
|
|
|
|
|
private PermissionCollection permissions; |
|
|
|
|
|
private boolean hasAllPerm = false; |
|
|
|
|
|
or dynamic (via a policy refresh) */ |
|
private final boolean staticPermissions; |
|
|
|
|
|
|
|
*/ |
|
final Key key = new Key(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public ProtectionDomain(CodeSource codesource, |
|
PermissionCollection permissions) { |
|
this.codesource = codesource; |
|
if (permissions != null) { |
|
this.permissions = permissions; |
|
this.permissions.setReadOnly(); |
|
if (permissions instanceof Permissions && |
|
((Permissions)permissions).allPermission != null) { |
|
hasAllPerm = true; |
|
} |
|
} |
|
this.classloader = null; |
|
this.principals = new Principal[0]; |
|
staticPermissions = true; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public ProtectionDomain(CodeSource codesource, |
|
PermissionCollection permissions, |
|
ClassLoader classloader, |
|
Principal[] principals) { |
|
this.codesource = codesource; |
|
if (permissions != null) { |
|
this.permissions = permissions; |
|
this.permissions.setReadOnly(); |
|
if (permissions instanceof Permissions && |
|
((Permissions)permissions).allPermission != null) { |
|
hasAllPerm = true; |
|
} |
|
} |
|
this.classloader = classloader; |
|
this.principals = (principals != null ? principals.clone(): |
|
new Principal[0]); |
|
staticPermissions = false; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public final CodeSource getCodeSource() { |
|
return this.codesource; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public final ClassLoader getClassLoader() { |
|
return this.classloader; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public final Principal[] getPrincipals() { |
|
return this.principals.clone(); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public final PermissionCollection getPermissions() { |
|
return permissions; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public final boolean staticPermissionsOnly() { |
|
return this.staticPermissions; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public boolean implies(Permission perm) { |
|
|
|
if (hasAllPerm) { |
|
// internal permission collection already has AllPermission - |
|
|
|
return true; |
|
} |
|
|
|
if (!staticPermissions && |
|
Policy.getPolicyNoCheck().implies(this, perm)) { |
|
return true; |
|
} |
|
if (permissions != null) { |
|
return permissions.implies(perm); |
|
} |
|
|
|
return false; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
boolean impliesWithAltFilePerm(Permission perm) { |
|
|
|
// If FilePermCompat.compat is set (default value), FilePermission |
|
// checking compatibility should be considered. |
|
|
|
// If filePermCompatInPD is set, this method checks for alternative |
|
// FilePermission to keep compatibility for any Policy implementation. |
|
// When set to false (default value), implies() is called since |
|
// the PolicyFile implementation already supports compatibility. |
|
|
|
// If this is a subclass of ProtectionDomain, call implies() |
|
// because most likely user has overridden it. |
|
|
|
if (!filePermCompatInPD || !FilePermCompat.compat || |
|
getClass() != ProtectionDomain.class) { |
|
return implies(perm); |
|
} |
|
|
|
if (hasAllPerm) { |
|
// internal permission collection already has AllPermission - |
|
|
|
return true; |
|
} |
|
|
|
Permission p2 = null; |
|
boolean p2Calculated = false; |
|
|
|
if (!staticPermissions) { |
|
Policy policy = Policy.getPolicyNoCheck(); |
|
if (policy instanceof PolicyFile) { |
|
// The PolicyFile implementation supports compatibility |
|
|
|
return policy.implies(this, perm); |
|
} else { |
|
if (policy.implies(this, perm)) { |
|
return true; |
|
} |
|
p2 = FilePermCompat.newPermUsingAltPath(perm); |
|
p2Calculated = true; |
|
if (p2 != null && policy.implies(this, p2)) { |
|
return true; |
|
} |
|
} |
|
} |
|
if (permissions != null) { |
|
if (permissions.implies(perm)) { |
|
return true; |
|
} else { |
|
if (!p2Calculated) { |
|
p2 = FilePermCompat.newPermUsingAltPath(perm); |
|
} |
|
if (p2 != null) { |
|
return permissions.implies(p2); |
|
} |
|
} |
|
} |
|
return false; |
|
} |
|
|
|
|
|
boolean impliesCreateAccessControlContext() { |
|
return implies(SecurityConstants.CREATE_ACC_PERMISSION); |
|
} |
|
|
|
|
|
|
|
*/ |
|
@Override public String toString() { |
|
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(",\n"); |
|
else |
|
palBuf.append(")\n"); |
|
} |
|
pals = palBuf.toString(); |
|
} |
|
|
|
// Check if policy is set; we don't want to load |
|
|
|
PermissionCollection pc = Policy.isSet() && seeAllp() ? |
|
mergePermissions(): |
|
getPermissions(); |
|
|
|
return "ProtectionDomain "+ |
|
" "+codesource+"\n"+ |
|
" "+classloader+"\n"+ |
|
" "+pals+"\n"+ |
|
" "+pc+"\n"; |
|
} |
|
|
|
|
|
|
|
*/ |
|
private static class DebugHolder { |
|
private static final Debug debug = Debug.getInstance("domain"); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
private static boolean seeAllp() { |
|
SecurityManager sm = System.getSecurityManager(); |
|
|
|
if (sm == null) { |
|
return true; |
|
} else { |
|
if (DebugHolder.debug != null) { |
|
if (sm.getClass().getClassLoader() == null && |
|
Policy.getPolicyNoCheck().getClass().getClassLoader() |
|
== null) { |
|
return true; |
|
} |
|
} else { |
|
try { |
|
sm.checkPermission(SecurityConstants.GET_POLICY_PERMISSION); |
|
return true; |
|
} catch (SecurityException se) { |
|
// fall thru and return false |
|
} |
|
} |
|
} |
|
|
|
return false; |
|
} |
|
|
|
private PermissionCollection mergePermissions() { |
|
if (staticPermissions) |
|
return permissions; |
|
|
|
PermissionCollection perms = |
|
java.security.AccessController.doPrivileged |
|
(new java.security.PrivilegedAction<>() { |
|
public PermissionCollection run() { |
|
Policy p = Policy.getPolicyNoCheck(); |
|
return p.getPermissions(ProtectionDomain.this); |
|
} |
|
}); |
|
|
|
Permissions mergedPerms = new Permissions(); |
|
int swag = 32; |
|
int vcap = 8; |
|
Enumeration<Permission> e; |
|
List<Permission> pdVector = new ArrayList<>(vcap); |
|
List<Permission> plVector = new ArrayList<>(swag); |
|
|
|
// |
|
|
|
if (permissions != null) { |
|
synchronized (permissions) { |
|
e = permissions.elements(); |
|
while (e.hasMoreElements()) { |
|
pdVector.add(e.nextElement()); |
|
} |
|
} |
|
} |
|
|
|
// |
|
|
|
if (perms != null) { |
|
synchronized (perms) { |
|
e = perms.elements(); |
|
while (e.hasMoreElements()) { |
|
plVector.add(e.nextElement()); |
|
vcap++; |
|
} |
|
} |
|
} |
|
|
|
if (perms != null && permissions != null) { |
|
// |
|
// Weed out the duplicates from the policy. Unless a refresh |
|
// has occurred since the pd was consed this should result in |
|
|
|
synchronized (permissions) { |
|
e = permissions.elements(); |
|
while (e.hasMoreElements()) { |
|
Permission pdp = e.nextElement(); |
|
Class<?> pdpClass = pdp.getClass(); |
|
String pdpActions = pdp.getActions(); |
|
String pdpName = pdp.getName(); |
|
for (int i = 0; i < plVector.size(); i++) { |
|
Permission pp = plVector.get(i); |
|
if (pdpClass.isInstance(pp)) { |
|
// The equals() method on some permissions |
|
// have some side effects so this manual |
|
|
|
if (pdpName.equals(pp.getName()) && |
|
Objects.equals(pdpActions, pp.getActions())) { |
|
plVector.remove(i); |
|
break; |
|
} |
|
} |
|
} |
|
} |
|
} |
|
} |
|
|
|
if (perms !=null) { |
|
// the order of adding to merged perms and permissions |
|
// needs to preserve the bugfix 4301064 |
|
|
|
for (int i = plVector.size()-1; i >= 0; i--) { |
|
mergedPerms.add(plVector.get(i)); |
|
} |
|
} |
|
if (permissions != null) { |
|
for (int i = pdVector.size()-1; i >= 0; i--) { |
|
mergedPerms.add(pdVector.get(i)); |
|
} |
|
} |
|
|
|
return mergedPerms; |
|
} |
|
|
|
|
|
|
|
*/ |
|
final class Key {} |
|
|
|
} |