001: /*
002: * Copyright 1997-2006 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004: *
005: * This code is free software; you can redistribute it and/or modify it
006: * under the terms of the GNU General Public License version 2 only, as
007: * published by the Free Software Foundation. Sun designates this
008: * particular file as subject to the "Classpath" exception as provided
009: * by Sun in the LICENSE file that accompanied this code.
010: *
011: * This code is distributed in the hope that it will be useful, but WITHOUT
012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014: * version 2 for more details (a copy is included in the LICENSE file that
015: * accompanied this code).
016: *
017: * You should have received a copy of the GNU General Public License version
018: * 2 along with this work; if not, write to the Free Software Foundation,
019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022: * CA 95054 USA or visit www.sun.com if you need additional information or
023: * have any questions.
024: */
025:
026: package java.security;
027:
028: import java.util.Enumeration;
029: import java.util.List;
030: import java.util.ArrayList;
031: import sun.security.util.Debug;
032: import sun.security.util.SecurityConstants;
033:
034: /**
035: *
036: *<p>
037: * This ProtectionDomain class encapsulates the characteristics of a domain,
038: * which encloses a set of classes whose instances are granted a set
039: * of permissions when being executed on behalf of a given set of Principals.
040: * <p>
041: * A static set of permissions can be bound to a ProtectionDomain when it is
042: * constructed; such permissions are granted to the domain regardless of the
043: * Policy in force. However, to support dynamic security policies, a
044: * ProtectionDomain can also be constructed such that it is dynamically
045: * mapped to a set of permissions by the current Policy whenever a permission
046: * is checked.
047: * <p>
048: *
049: * @version 1.54, 05/05/07
050: * @author Li Gong
051: * @author Roland Schemers
052: * @author Gary Ellison
053: */
054:
055: public class ProtectionDomain {
056:
057: /* CodeSource */
058: private CodeSource codesource;
059:
060: /* ClassLoader the protection domain was consed from */
061: private ClassLoader classloader;
062:
063: /* Principals running-as within this protection domain */
064: private Principal[] principals;
065:
066: /* the rights this protection domain is granted */
067: private PermissionCollection permissions;
068:
069: /* if the permissions object has AllPermission */
070: private boolean hasAllPerm = false;
071:
072: /* the PermissionCollection is static (pre 1.4 constructor)
073: or dynamic (via a policy refresh) */
074: private boolean staticPermissions;
075:
076: private static final Debug debug = Debug.getInstance("domain");
077:
078: /**
079: * Creates a new ProtectionDomain with the given CodeSource and
080: * Permissions. If the permissions object is not null, then
081: * <code>setReadOnly())</code> will be called on the passed in
082: * Permissions object. The only permissions granted to this domain
083: * are the ones specified; the current Policy will not be consulted.
084: *
085: * @param codesource the codesource associated with this domain
086: * @param permissions the permissions granted to this domain
087: */
088: public ProtectionDomain(CodeSource codesource,
089: PermissionCollection permissions) {
090: this .codesource = codesource;
091: if (permissions != null) {
092: this .permissions = permissions;
093: this .permissions.setReadOnly();
094: if (permissions instanceof Permissions
095: && ((Permissions) permissions).allPermission != null) {
096: hasAllPerm = true;
097: }
098: }
099: this .classloader = null;
100: this .principals = new Principal[0];
101: staticPermissions = true;
102: }
103:
104: /**
105: * Creates a new ProtectionDomain qualified by the given CodeSource,
106: * Permissions, ClassLoader and array of Principals. If the
107: * permissions object is not null, then <code>setReadOnly()</code>
108: * will be called on the passed in Permissions object.
109: * The permissions granted to this domain are dynamic; they include
110: * both the static permissions passed to this constructor, and any
111: * permissions granted to this domain by the current Policy at the
112: * time a permission is checked.
113: * <p>
114: * This constructor is typically used by
115: * {@link SecureClassLoader ClassLoaders}
116: * and {@link DomainCombiner DomainCombiners} which delegate to
117: * <code>Policy</code> to actively associate the permissions granted to
118: * this domain. This constructor affords the
119: * Policy provider the opportunity to augment the supplied
120: * PermissionCollection to reflect policy changes.
121: * <p>
122: *
123: * @param codesource the CodeSource associated with this domain
124: * @param permissions the permissions granted to this domain
125: * @param classloader the ClassLoader associated with this domain
126: * @param principals the array of Principals associated with this
127: * domain. The contents of the array are copied to protect against
128: * subsequent modification.
129: * @see Policy#refresh
130: * @see Policy#getPermissions(ProtectionDomain)
131: * @since 1.4
132: */
133: public ProtectionDomain(CodeSource codesource,
134: PermissionCollection permissions, ClassLoader classloader,
135: Principal[] principals) {
136: this .codesource = codesource;
137: if (permissions != null) {
138: this .permissions = permissions;
139: this .permissions.setReadOnly();
140: if (permissions instanceof Permissions
141: && ((Permissions) permissions).allPermission != null) {
142: hasAllPerm = true;
143: }
144: }
145: this .classloader = classloader;
146: this .principals = (principals != null ? (Principal[]) principals
147: .clone()
148: : new Principal[0]);
149: staticPermissions = false;
150: }
151:
152: /**
153: * Returns the CodeSource of this domain.
154: * @return the CodeSource of this domain which may be null.
155: * @since 1.2
156: */
157: public final CodeSource getCodeSource() {
158: return this .codesource;
159: }
160:
161: /**
162: * Returns the ClassLoader of this domain.
163: * @return the ClassLoader of this domain which may be null.
164: *
165: * @since 1.4
166: */
167: public final ClassLoader getClassLoader() {
168: return this .classloader;
169: }
170:
171: /**
172: * Returns an array of principals for this domain.
173: * @return a non-null array of principals for this domain.
174: * Returns a new array each time this method is called.
175: *
176: * @since 1.4
177: */
178: public final Principal[] getPrincipals() {
179: return (Principal[]) this .principals.clone();
180: }
181:
182: /**
183: * Returns the static permissions granted to this domain.
184: *
185: * @return the static set of permissions for this domain which may be null.
186: * @see Policy#refresh
187: * @see Policy#getPermissions(ProtectionDomain)
188: */
189: public final PermissionCollection getPermissions() {
190: return permissions;
191: }
192:
193: /**
194: * Check and see if this ProtectionDomain implies the permissions
195: * expressed in the Permission object.
196: * <p>
197: * The set of permissions evaluated is a function of whether the
198: * ProtectionDomain was constructed with a static set of permissions
199: * or it was bound to a dynamically mapped set of permissions.
200: * <p>
201: * If the ProtectionDomain was constructed to a
202: * {@link #ProtectionDomain(CodeSource, PermissionCollection)
203: * statically bound} PermissionCollection then the permission will
204: * only be checked against the PermissionCollection supplied at
205: * construction.
206: * <p>
207: * However, if the ProtectionDomain was constructed with
208: * the constructor variant which supports
209: * {@link #ProtectionDomain(CodeSource, PermissionCollection,
210: * ClassLoader, java.security.Principal[]) dynamically binding}
211: * permissions, then the permission will be checked against the
212: * combination of the PermissionCollection supplied at construction and
213: * the current Policy binding.
214: * <p>
215: *
216: * @param permission the Permission object to check.
217: *
218: * @return true if "permission" is implicit to this ProtectionDomain.
219: */
220: public boolean implies(Permission permission) {
221:
222: if (hasAllPerm) {
223: // internal permission collection already has AllPermission -
224: // no need to go to policy
225: return true;
226: }
227:
228: if (!staticPermissions
229: && Policy.getPolicyNoCheck().implies(this , permission))
230: return true;
231: if (permissions != null)
232: return permissions.implies(permission);
233:
234: return false;
235: }
236:
237: /**
238: * Convert a ProtectionDomain to a String.
239: */
240: public String toString() {
241: String pals = "<no principals>";
242: if (principals != null && principals.length > 0) {
243: StringBuilder palBuf = new StringBuilder("(principals ");
244:
245: for (int i = 0; i < principals.length; i++) {
246: palBuf.append(principals[i].getClass().getName()
247: + " \"" + principals[i].getName() + "\"");
248: if (i < principals.length - 1)
249: palBuf.append(",\n");
250: else
251: palBuf.append(")\n");
252: }
253: pals = palBuf.toString();
254: }
255:
256: // Check if policy is set; we don't want to load
257: // the policy prematurely here
258: PermissionCollection pc = Policy.isSet() && seeAllp() ? mergePermissions()
259: : getPermissions();
260:
261: return "ProtectionDomain " + " " + codesource + "\n" + " "
262: + classloader + "\n" + " " + pals + "\n" + " " + pc
263: + "\n";
264: }
265:
266: /**
267: * Return true (merge policy permissions) in the following cases:
268: *
269: * . SecurityManager is null
270: *
271: * . SecurityManager is not null,
272: * debug is not null,
273: * SecurityManager impelmentation is in bootclasspath,
274: * Policy implementation is in bootclasspath
275: * (the bootclasspath restrictions avoid recursion)
276: *
277: * . SecurityManager is not null,
278: * debug is null,
279: * caller has Policy.getPolicy permission
280: */
281: private static boolean seeAllp() {
282: SecurityManager sm = System.getSecurityManager();
283:
284: if (sm == null) {
285: return true;
286: } else {
287: if (debug != null) {
288: if (sm.getClass().getClassLoader() == null
289: && Policy.getPolicyNoCheck().getClass()
290: .getClassLoader() == null) {
291: return true;
292: }
293: } else {
294: try {
295: sm
296: .checkPermission(SecurityConstants.GET_POLICY_PERMISSION);
297: return true;
298: } catch (SecurityException se) {
299: // fall thru and return false
300: }
301: }
302: }
303:
304: return false;
305: }
306:
307: private PermissionCollection mergePermissions() {
308: if (staticPermissions)
309: return permissions;
310:
311: PermissionCollection perms = java.security.AccessController
312: .doPrivileged(new java.security.PrivilegedAction<PermissionCollection>() {
313: public PermissionCollection run() {
314: Policy p = Policy.getPolicyNoCheck();
315: return p.getPermissions(ProtectionDomain.this );
316: }
317: });
318:
319: Permissions mergedPerms = new Permissions();
320: int swag = 32;
321: int vcap = 8;
322: Enumeration<Permission> e;
323: List<Permission> pdVector = new ArrayList<Permission>(vcap);
324: List<Permission> plVector = new ArrayList<Permission>(swag);
325:
326: //
327: // Build a vector of domain permissions for subsequent merge
328: if (permissions != null) {
329: synchronized (permissions) {
330: e = permissions.elements();
331: while (e.hasMoreElements()) {
332: pdVector.add(e.nextElement());
333: }
334: }
335: }
336:
337: //
338: // Build a vector of Policy permissions for subsequent merge
339: if (perms != null) {
340: synchronized (perms) {
341: e = perms.elements();
342: while (e.hasMoreElements()) {
343: plVector.add(e.nextElement());
344: vcap++;
345: }
346: }
347: }
348:
349: if (perms != null && permissions != null) {
350: //
351: // Weed out the duplicates from the policy. Unless a refresh
352: // has occured since the pd was consed this should result in
353: // an empty vector.
354: synchronized (permissions) {
355: e = permissions.elements(); // domain vs policy
356: while (e.hasMoreElements()) {
357: Permission pdp = (Permission) e.nextElement();
358: Class pdpClass = pdp.getClass();
359: String pdpActions = pdp.getActions();
360: String pdpName = pdp.getName();
361: for (int i = 0; i < plVector.size(); i++) {
362: Permission pp = plVector.get(i);
363: if (pdpClass.isInstance(pp)) {
364: // The equals() method on some permissions
365: // have some side effects so this manual
366: // comparison is sufficient.
367: if (pdpName.equals(pp.getName())
368: && pdpActions.equals(pp
369: .getActions())) {
370: plVector.remove(i);
371: break;
372: }
373: }
374: }
375: }
376: }
377: }
378:
379: if (perms != null) {
380: // the order of adding to merged perms and permissions
381: // needs to preserve the bugfix 4301064
382:
383: for (int i = plVector.size() - 1; i >= 0; i--) {
384: mergedPerms.add(plVector.get(i));
385: }
386: }
387: if (permissions != null) {
388: for (int i = pdVector.size() - 1; i >= 0; i--) {
389: mergedPerms.add(pdVector.get(i));
390: }
391: }
392:
393: return mergedPerms;
394: }
395: }
|