1. /*
  2. * @(#)ProtectionDomain.java 1.45 03/12/19
  3. *
  4. * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package java.security;
  8. import java.util.Enumeration;
  9. import java.util.List;
  10. import java.util.ArrayList;
  11. import sun.security.util.Debug;
  12. import sun.security.util.SecurityConstants;
  13. /**
  14. *
  15. *<p>
  16. * This ProtectionDomain class encapsulates the characteristics of a domain,
  17. * which encloses a set of classes whose instances are granted a set
  18. * of permissions when being executed on behalf of a given set of Principals.
  19. * <p>
  20. * A static set of permissions can be bound to a ProtectionDomain when it is
  21. * constructed; such permissions are granted to the domain regardless of the
  22. * Policy in force. However, to support dynamic security policies, a
  23. * ProtectionDomain can also be constructed such that it is dynamically
  24. * mapped to a set of permissions by the current Policy whenever a permission
  25. * is checked.
  26. * <p>
  27. *
  28. * @version 1.45, 12/19/03
  29. * @author Li Gong
  30. * @author Roland Schemers
  31. * @author Gary Ellison
  32. */
  33. public class ProtectionDomain {
  34. /* CodeSource */
  35. private CodeSource codesource ;
  36. /* ClassLoader the protection domain was consed from */
  37. private ClassLoader classloader;
  38. /* Principals running-as within this protection domain */
  39. private Principal[] principals;
  40. /* the rights this protection domain is granted */
  41. private PermissionCollection permissions;
  42. /* the PermissionCollection is static (pre 1.4 constructor)
  43. or dynamic (via a policy refresh) */
  44. private boolean staticPermissions;
  45. private static final Debug debug = Debug.getInstance("domain");
  46. /**
  47. * Creates a new ProtectionDomain with the given CodeSource and
  48. * Permissions. If the permissions object is not null, then
  49. * <code>setReadOnly())</code> will be called on the passed in
  50. * Permissions object. The only permissions granted to this domain
  51. * are the ones specified; the current Policy will not be consulted.
  52. *
  53. * @param codesource the codesource associated with this domain
  54. * @param permissions the permissions granted to this domain
  55. */
  56. public ProtectionDomain(CodeSource codesource,
  57. PermissionCollection permissions) {
  58. this.codesource = codesource;
  59. if (permissions != null) {
  60. this.permissions = permissions;
  61. this.permissions.setReadOnly();
  62. }
  63. this.classloader = null;
  64. this.principals = new Principal[0];
  65. staticPermissions = true;
  66. }
  67. /**
  68. * Creates a new ProtectionDomain qualified by the given CodeSource,
  69. * Permissions, ClassLoader and array of Principals. If the
  70. * permissions object is not null, then <code>setReadOnly()</code>
  71. * will be called on the passed in Permissions object.
  72. * The permissions granted to this domain are dynamic; they include
  73. * both the static permissions passed to this constructor, and any
  74. * permissions granted to this domain by the current Policy at the
  75. * time a permission is checked.
  76. * <p>
  77. * This constructor is typically used by
  78. * {@link SecureClassLoader ClassLoaders}
  79. * and {@link DomainCombiner DomainCombiners} which delegate to
  80. * <code>Policy</code> to actively associate the permissions granted to
  81. * this domain. This constructor affords the
  82. * Policy provider the opportunity to augment the supplied
  83. * PermissionCollection to reflect policy changes.
  84. * <p>
  85. *
  86. * @param codesource the CodeSource associated with this domain
  87. * @param permissions the permissions granted to this domain
  88. * @param classloader the ClassLoader associated with this domain
  89. * @param principals the array of Principals associated with this
  90. * domain. The contents of the array are copied to protect against
  91. * subsequent modification.
  92. * @see Policy#refresh
  93. * @see Policy#getPermissions(ProtectionDomain)
  94. * @since 1.4
  95. */
  96. public ProtectionDomain(CodeSource codesource,
  97. PermissionCollection permissions,
  98. ClassLoader classloader,
  99. Principal[] principals) {
  100. this.codesource = codesource;
  101. if (permissions != null) {
  102. this.permissions = permissions;
  103. this.permissions.setReadOnly();
  104. }
  105. this.classloader = classloader;
  106. this.principals = (principals != null ?
  107. (Principal[])principals.clone():
  108. new Principal[0]);
  109. staticPermissions = false;
  110. }
  111. /**
  112. * Returns the CodeSource of this domain.
  113. * @return the CodeSource of this domain which may be null.
  114. * @since 1.2
  115. */
  116. public final CodeSource getCodeSource() {
  117. return this.codesource;
  118. }
  119. /**
  120. * Returns the ClassLoader of this domain.
  121. * @return the ClassLoader of this domain which may be null.
  122. *
  123. * @since 1.4
  124. */
  125. public final ClassLoader getClassLoader() {
  126. return this.classloader;
  127. }
  128. /**
  129. * Returns an array of principals for this domain.
  130. * @return a non-null array of principals for this domain.
  131. * Returns a new array each time this method is called.
  132. *
  133. * @since 1.4
  134. */
  135. public final Principal[] getPrincipals() {
  136. return (Principal[])this.principals.clone();
  137. }
  138. /**
  139. * Returns the static permissions granted to this domain.
  140. *
  141. * @return the static set of permissions for this domain which may be null.
  142. * @see Policy#refresh
  143. * @see Policy#getPermissions(ProtectionDomain)
  144. */
  145. public final PermissionCollection getPermissions() {
  146. return permissions;
  147. }
  148. /**
  149. * Check and see if this ProtectionDomain implies the permissions
  150. * expressed in the Permission object.
  151. * <p>
  152. * The set of permissions evaluated is a function of whether the
  153. * ProtectionDomain was constructed with a static set of permissions
  154. * or it was bound to a dynamically mapped set of permissions.
  155. * <p>
  156. * If the ProtectionDomain was constructed to a
  157. * {@link #ProtectionDomain(CodeSource, PermissionCollection)
  158. * statically bound} PermissionCollection then the permission will
  159. * only be checked against the PermissionCollection supplied at
  160. * construction.
  161. * <p>
  162. * However, if the ProtectionDomain was constructed with
  163. * the constructor variant which supports
  164. * {@link #ProtectionDomain(CodeSource, PermissionCollection,
  165. * ClassLoader, java.security.Principal[]) dynamically binding}
  166. * permissions, then the permission will be checked against the
  167. * combination of the PermissionCollection supplied at construction and
  168. * the current Policy binding.
  169. * <p>
  170. *
  171. * @param permission the Permission object to check.
  172. *
  173. * @return true if "permission" is implicit to this ProtectionDomain.
  174. */
  175. public boolean implies(Permission permission) {
  176. if (!staticPermissions &&
  177. Policy.getPolicyNoCheck().implies(this, permission))
  178. return true;
  179. if (permissions != null)
  180. return permissions.implies(permission);
  181. return false;
  182. }
  183. /**
  184. * Convert a ProtectionDomain to a String.
  185. */
  186. public String toString() {
  187. String pals = "<no principals>";
  188. if (principals != null && principals.length > 0) {
  189. StringBuilder palBuf = new StringBuilder("(principals ");
  190. for (int i = 0; i < principals.length; i++) {
  191. palBuf.append(principals[i].getClass().getName() +
  192. " \"" + principals[i].getName() +
  193. "\"");
  194. if (i < principals.length-1)
  195. palBuf.append(",\n");
  196. else
  197. palBuf.append(")\n");
  198. }
  199. pals = palBuf.toString();
  200. }
  201. // Check if policy is set; we don't want to load
  202. // the policy prematurely here
  203. PermissionCollection pc = Policy.isSet() && seeAllp() ?
  204. mergePermissions():
  205. getPermissions();
  206. return "ProtectionDomain "+
  207. " "+codesource+"\n"+
  208. " "+classloader+"\n"+
  209. " "+pals+"\n"+
  210. " "+pc+"\n";
  211. }
  212. /**
  213. * Return true (merge policy permissions) in the following cases:
  214. *
  215. * . SecurityManager is null
  216. *
  217. * . SecurityManager is not null,
  218. * debug is not null,
  219. * SecurityManager impelmentation is in bootclasspath,
  220. * Policy implementation is in bootclasspath
  221. * (the bootclasspath restrictions avoid recursion)
  222. *
  223. * . SecurityManager is not null,
  224. * debug is null,
  225. * caller has Policy.getPolicy permission
  226. */
  227. private static boolean seeAllp() {
  228. SecurityManager sm = System.getSecurityManager();
  229. if (sm == null) {
  230. return true;
  231. } else {
  232. if (debug != null) {
  233. if (sm.getClass().getClassLoader() == null &&
  234. Policy.getPolicyNoCheck().getClass().getClassLoader()
  235. == null) {
  236. return true;
  237. }
  238. } else {
  239. try {
  240. sm.checkPermission(SecurityConstants.GET_POLICY_PERMISSION);
  241. return true;
  242. } catch (SecurityException se) {
  243. // fall thru and return false
  244. }
  245. }
  246. }
  247. return false;
  248. }
  249. private PermissionCollection mergePermissions() {
  250. if (staticPermissions)
  251. return permissions;
  252. PermissionCollection perms = (PermissionCollection)
  253. java.security.AccessController.doPrivileged
  254. (new java.security.PrivilegedAction() {
  255. public Object run() {
  256. Policy p = Policy.getPolicyNoCheck();
  257. return p.getPermissions(ProtectionDomain.this);
  258. }
  259. });
  260. Permissions mergedPerms = new Permissions();
  261. int swag = 32;
  262. int vcap = 8;
  263. Enumeration e;
  264. List pdVector = new ArrayList(vcap);
  265. List plVector = new ArrayList(swag);
  266. //
  267. // Build a vector of domain permissions for subsequent merge
  268. if (permissions != null) {
  269. synchronized (permissions) {
  270. e = permissions.elements();
  271. while (e.hasMoreElements()) {
  272. Permission p = (Permission)e.nextElement();
  273. pdVector.add(p);
  274. }
  275. }
  276. }
  277. //
  278. // Build a vector of Policy permissions for subsequent merge
  279. if (perms != null) {
  280. synchronized (perms) {
  281. e = perms.elements();
  282. while (e.hasMoreElements()) {
  283. plVector.add(e.nextElement());
  284. vcap++;
  285. }
  286. }
  287. }
  288. if (perms != null && permissions != null) {
  289. //
  290. // Weed out the duplicates from the policy. Unless a refresh
  291. // has occured since the pd was consed this should result in
  292. // an empty vector.
  293. synchronized (permissions) {
  294. e = permissions.elements(); // domain vs policy
  295. while (e.hasMoreElements()) {
  296. Permission pdp = (Permission)e.nextElement();
  297. Class pdpClass = pdp.getClass();
  298. String pdpActions = pdp.getActions();
  299. String pdpName = pdp.getName();
  300. for (int i = 0; i < plVector.size(); i++) {
  301. Permission pp = (Permission) plVector.get(i);
  302. if (pdpClass.isInstance(pp)) {
  303. // The equals() method on some permissions
  304. // have some side effects so this manual
  305. // comparison is sufficient.
  306. if (pdpName.equals(pp.getName()) &&
  307. pdpActions.equals(pp.getActions())) {
  308. plVector.remove(i);
  309. break;
  310. }
  311. }
  312. }
  313. }
  314. }
  315. }
  316. if (perms !=null) {
  317. // the order of adding to merged perms and permissions
  318. // needs to preserve the bugfix 4301064
  319. for (int i = plVector.size()-1; i >= 0; i--) {
  320. mergedPerms.add((Permission)plVector.get(i));
  321. }
  322. }
  323. if (permissions != null) {
  324. for (int i = pdVector.size()-1; i >= 0; i--) {
  325. mergedPerms.add((Permission)pdVector.get(i));
  326. }
  327. }
  328. return mergedPerms;
  329. }
  330. }