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 }
|