blob: 313fa5a55f90e5cc7457f90211f5daf1054741ad [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 1997-2006 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26package java.security;
27
28import java.util.Enumeration;
29import java.util.List;
30import java.util.ArrayList;
31import sun.security.util.Debug;
32import sun.security.util.SecurityConstants;
33
34/**
35 *
36 *<p>
37 * This ProtectionDomain class encapsulates the characteristics of a domain,
38 * which encloses a set of classes whose instances are granted a set
39 * of permissions when being executed on behalf of a given set of Principals.
40 * <p>
41 * A static set of permissions can be bound to a ProtectionDomain when it is
42 * constructed; such permissions are granted to the domain regardless of the
43 * Policy in force. However, to support dynamic security policies, a
44 * ProtectionDomain can also be constructed such that it is dynamically
45 * mapped to a set of permissions by the current Policy whenever a permission
46 * is checked.
47 * <p>
48 *
49 * @author Li Gong
50 * @author Roland Schemers
51 * @author Gary Ellison
52 */
53
54public class ProtectionDomain {
55
56 /* CodeSource */
57 private CodeSource codesource ;
58
59 /* ClassLoader the protection domain was consed from */
60 private ClassLoader classloader;
61
62 /* Principals running-as within this protection domain */
63 private Principal[] principals;
64
65 /* the rights this protection domain is granted */
66 private PermissionCollection permissions;
67
68 /* if the permissions object has AllPermission */
69 private boolean hasAllPerm = false;
70
71 /* the PermissionCollection is static (pre 1.4 constructor)
72 or dynamic (via a policy refresh) */
73 private boolean staticPermissions;
74
75 private static final Debug debug = Debug.getInstance("domain");
76
77 /**
78 * Creates a new ProtectionDomain with the given CodeSource and
79 * Permissions. If the permissions object is not null, then
80 * <code>setReadOnly())</code> will be called on the passed in
81 * Permissions object. The only permissions granted to this domain
82 * are the ones specified; the current Policy will not be consulted.
83 *
84 * @param codesource the codesource associated with this domain
85 * @param permissions the permissions granted to this domain
86 */
87 public ProtectionDomain(CodeSource codesource,
88 PermissionCollection permissions) {
89 this.codesource = codesource;
90 if (permissions != null) {
91 this.permissions = permissions;
92 this.permissions.setReadOnly();
93 if (permissions instanceof Permissions &&
94 ((Permissions)permissions).allPermission != null) {
95 hasAllPerm = true;
96 }
97 }
98 this.classloader = null;
99 this.principals = new Principal[0];
100 staticPermissions = true;
101 }
102
103 /**
104 * Creates a new ProtectionDomain qualified by the given CodeSource,
105 * Permissions, ClassLoader and array of Principals. If the
106 * permissions object is not null, then <code>setReadOnly()</code>
107 * will be called on the passed in Permissions object.
108 * The permissions granted to this domain are dynamic; they include
109 * both the static permissions passed to this constructor, and any
110 * permissions granted to this domain by the current Policy at the
111 * time a permission is checked.
112 * <p>
113 * This constructor is typically used by
114 * {@link SecureClassLoader ClassLoaders}
115 * and {@link DomainCombiner DomainCombiners} which delegate to
116 * <code>Policy</code> to actively associate the permissions granted to
117 * this domain. This constructor affords the
118 * Policy provider the opportunity to augment the supplied
119 * PermissionCollection to reflect policy changes.
120 * <p>
121 *
122 * @param codesource the CodeSource associated with this domain
123 * @param permissions the permissions granted to this domain
124 * @param classloader the ClassLoader associated with this domain
125 * @param principals the array of Principals associated with this
126 * domain. The contents of the array are copied to protect against
127 * subsequent modification.
128 * @see Policy#refresh
129 * @see Policy#getPermissions(ProtectionDomain)
130 * @since 1.4
131 */
132 public ProtectionDomain(CodeSource codesource,
133 PermissionCollection permissions,
134 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 ? principals.clone():
147 new Principal[0]);
148 staticPermissions = false;
149 }
150
151 /**
152 * Returns the CodeSource of this domain.
153 * @return the CodeSource of this domain which may be null.
154 * @since 1.2
155 */
156 public final CodeSource getCodeSource() {
157 return this.codesource;
158 }
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 /**
173 * Returns an array of principals for this domain.
174 * @return a non-null array of principals for this domain.
175 * Returns a new array each time this method is called.
176 *
177 * @since 1.4
178 */
179 public final Principal[] getPrincipals() {
180 return this.principals.clone();
181 }
182
183 /**
184 * Returns the static permissions granted to this domain.
185 *
186 * @return the static set of permissions for this domain which may be null.
187 * @see Policy#refresh
188 * @see Policy#getPermissions(ProtectionDomain)
189 */
190 public final PermissionCollection getPermissions() {
191 return permissions;
192 }
193
194 /**
195 * Check and see if this ProtectionDomain implies the permissions
196 * expressed in the Permission object.
197 * <p>
198 * The set of permissions evaluated is a function of whether the
199 * ProtectionDomain was constructed with a static set of permissions
200 * or it was bound to a dynamically mapped set of permissions.
201 * <p>
202 * If the ProtectionDomain was constructed to a
203 * {@link #ProtectionDomain(CodeSource, PermissionCollection)
204 * statically bound} PermissionCollection then the permission will
205 * only be checked against the PermissionCollection supplied at
206 * construction.
207 * <p>
208 * However, if the ProtectionDomain was constructed with
209 * the constructor variant which supports
210 * {@link #ProtectionDomain(CodeSource, PermissionCollection,
211 * ClassLoader, java.security.Principal[]) dynamically binding}
212 * permissions, then the permission will be checked against the
213 * combination of the PermissionCollection supplied at construction and
214 * the current Policy binding.
215 * <p>
216 *
217 * @param permission the Permission object to check.
218 *
219 * @return true if "permission" is implicit to this ProtectionDomain.
220 */
221 public boolean implies(Permission permission) {
222
223 if (hasAllPerm) {
224 // internal permission collection already has AllPermission -
225 // no need to go to policy
226 return true;
227 }
228
229 if (!staticPermissions &&
230 Policy.getPolicyNoCheck().implies(this, permission))
231 return true;
232 if (permissions != null)
233 return permissions.implies(permission);
234
235 return false;
236 }
237
238 /**
239 * Convert a ProtectionDomain to a String.
240 */
241 public String toString() {
242 String pals = "<no principals>";
243 if (principals != null && principals.length > 0) {
244 StringBuilder palBuf = new StringBuilder("(principals ");
245
246 for (int i = 0; i < principals.length; i++) {
247 palBuf.append(principals[i].getClass().getName() +
248 " \"" + principals[i].getName() +
249 "\"");
250 if (i < principals.length-1)
251 palBuf.append(",\n");
252 else
253 palBuf.append(")\n");
254 }
255 pals = palBuf.toString();
256 }
257
258 // Check if policy is set; we don't want to load
259 // the policy prematurely here
260 PermissionCollection pc = Policy.isSet() && seeAllp() ?
261 mergePermissions():
262 getPermissions();
263
264 return "ProtectionDomain "+
265 " "+codesource+"\n"+
266 " "+classloader+"\n"+
267 " "+pals+"\n"+
268 " "+pc+"\n";
269 }
270
271 /**
272 * Return true (merge policy permissions) in the following cases:
273 *
274 * . SecurityManager is null
275 *
276 * . SecurityManager is not null,
277 * debug is not null,
278 * SecurityManager impelmentation is in bootclasspath,
279 * Policy implementation is in bootclasspath
280 * (the bootclasspath restrictions avoid recursion)
281 *
282 * . SecurityManager is not null,
283 * debug is null,
284 * caller has Policy.getPolicy permission
285 */
286 private static boolean seeAllp() {
287 SecurityManager sm = System.getSecurityManager();
288
289 if (sm == null) {
290 return true;
291 } else {
292 if (debug != null) {
293 if (sm.getClass().getClassLoader() == null &&
294 Policy.getPolicyNoCheck().getClass().getClassLoader()
295 == null) {
296 return true;
297 }
298 } else {
299 try {
300 sm.checkPermission(SecurityConstants.GET_POLICY_PERMISSION);
301 return true;
302 } catch (SecurityException se) {
303 // fall thru and return false
304 }
305 }
306 }
307
308 return false;
309 }
310
311 private PermissionCollection mergePermissions() {
312 if (staticPermissions)
313 return permissions;
314
315 PermissionCollection perms =
316 java.security.AccessController.doPrivileged
317 (new java.security.PrivilegedAction<PermissionCollection>() {
318 public PermissionCollection run() {
319 Policy p = Policy.getPolicyNoCheck();
320 return p.getPermissions(ProtectionDomain.this);
321 }
322 });
323
324 Permissions mergedPerms = new Permissions();
325 int swag = 32;
326 int vcap = 8;
327 Enumeration<Permission> e;
328 List<Permission> pdVector = new ArrayList<Permission>(vcap);
329 List<Permission> plVector = new ArrayList<Permission>(swag);
330
331 //
332 // Build a vector of domain permissions for subsequent merge
333 if (permissions != null) {
334 synchronized (permissions) {
335 e = permissions.elements();
336 while (e.hasMoreElements()) {
337 pdVector.add(e.nextElement());
338 }
339 }
340 }
341
342 //
343 // Build a vector of Policy permissions for subsequent merge
344 if (perms != null) {
345 synchronized (perms) {
346 e = perms.elements();
347 while (e.hasMoreElements()) {
348 plVector.add(e.nextElement());
349 vcap++;
350 }
351 }
352 }
353
354 if (perms != null && permissions != null) {
355 //
356 // Weed out the duplicates from the policy. Unless a refresh
357 // has occured since the pd was consed this should result in
358 // an empty vector.
359 synchronized (permissions) {
360 e = permissions.elements(); // domain vs policy
361 while (e.hasMoreElements()) {
362 Permission pdp = e.nextElement();
363 Class pdpClass = pdp.getClass();
364 String pdpActions = pdp.getActions();
365 String pdpName = pdp.getName();
366 for (int i = 0; i < plVector.size(); i++) {
367 Permission pp = plVector.get(i);
368 if (pdpClass.isInstance(pp)) {
369 // The equals() method on some permissions
370 // have some side effects so this manual
371 // comparison is sufficient.
372 if (pdpName.equals(pp.getName()) &&
373 pdpActions.equals(pp.getActions())) {
374 plVector.remove(i);
375 break;
376 }
377 }
378 }
379 }
380 }
381 }
382
383 if (perms !=null) {
384 // the order of adding to merged perms and permissions
385 // needs to preserve the bugfix 4301064
386
387 for (int i = plVector.size()-1; i >= 0; i--) {
388 mergedPerms.add(plVector.get(i));
389 }
390 }
391 if (permissions != null) {
392 for (int i = pdVector.size()-1; i >= 0; i--) {
393 mergedPerms.add(pdVector.get(i));
394 }
395 }
396
397 return mergedPerms;
398 }
399}