History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/java/security/AccessControlContext.java (1 of 18352 files). Show all

Unified · Split

java/pkg/java/security/AccessControlContext.java+598−0
@@ -0,0 +1,598 @@
1/*
2 * Copyright (c) 1997, 2011, Oracle and/or its affiliates. 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. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package java.security;
27
28import java.util.ArrayList;
29import java.util.List;
30import sun.security.util.Debug;
31import sun.security.util.SecurityConstants;
32import sun.misc.JavaSecurityAccess;
33import sun.misc.SharedSecrets;
34
35
36/**
37 * An AccessControlContext is used to make system resource access decisions
38 * based on the context it encapsulates.
39 *
40 * <p>More specifically, it encapsulates a context and
41 * has a single method, <code>checkPermission</code>,
42 * that is equivalent to the <code>checkPermission</code> method
43 * in the AccessController class, with one difference: The AccessControlContext
44 * <code>checkPermission</code> method makes access decisions based on the
45 * context it encapsulates,
46 * rather than that of the current execution thread.
47 *
48 * <p>Thus, the purpose of AccessControlContext is for those situations where
49 * a security check that should be made within a given context
50 * actually needs to be done from within a
51 * <i>different</i> context (for example, from within a worker thread).
52 *
53 * <p> An AccessControlContext is created by calling the
54 * <code>AccessController.getContext</code> method.
55 * The <code>getContext</code> method takes a "snapshot"
56 * of the current calling context, and places
57 * it in an AccessControlContext object, which it returns. A sample call is
58 * the following:
59 *
60 * <pre>
61 * AccessControlContext acc = AccessController.getContext()
62 * </pre>
63 *
64 * <p>
65 * Code within a different context can subsequently call the
66 * <code>checkPermission</code> method on the
67 * previously-saved AccessControlContext object. A sample call is the
68 * following:
69 *
70 * <pre>
71 * acc.checkPermission(permission)
72 * </pre>
73 *
74 * @see AccessController
75 *
76 * @author Roland Schemers
77 */
78
79public final class AccessControlContext {
80
81 private ProtectionDomain context[];
82 private boolean isPrivileged;
83
84 // Note: This field is directly used by the virtual machine
85 // native codes. Don't touch it.
86 private AccessControlContext privilegedContext;
87
88 private DomainCombiner combiner = null;
89
90 private static boolean debugInit = false;
91 private static Debug debug = null;
92
93 static Debug getDebug()
94 {
95 if (debugInit)
96 return debug;
97 else {
98 if (Policy.isSet()) {
99 debug = Debug.getInstance("access");
100 debugInit = true;
101 }
102 return debug;
103 }
104 }
105
106 /**
107 * Create an AccessControlContext with the given array of ProtectionDomains.
108 * Context must not be null. Duplicate domains will be removed from the
109 * context.
110 *
111 * @param context the ProtectionDomains associated with this context.
112 * The non-duplicate domains are copied from the array. Subsequent
113 * changes to the array will not affect this AccessControlContext.
114 * @throws NullPointerException if <code>context</code> is <code>null</code>
115 */
116 public AccessControlContext(ProtectionDomain context[])
117 {
118 if (context.length == 0) {
119 this.context = null;
120 } else if (context.length == 1) {
121 if (context[0] != null) {
122 this.context = context.clone();
123 } else {
124 this.context = null;
125 }
126 } else {
127 List<ProtectionDomain> v = new ArrayList<>(context.length);
128 for (int i =0; i< context.length; i++) {
129 if ((context[i] != null) && (!v.contains(context[i])))
130 v.add(context[i]);
131 }
132 if (!v.isEmpty()) {
133 this.context = new ProtectionDomain[v.size()];
134 this.context = v.toArray(this.context);
135 }
136 }
137 }
138
139 /**
140 * Create a new <code>AccessControlContext</code> with the given
141 * <code>AccessControlContext</code> and <code>DomainCombiner</code>.
142 * This constructor associates the provided
143 * <code>DomainCombiner</code> with the provided
144 * <code>AccessControlContext</code>.
145 *
146 * <p>
147 *
148 * @param acc the <code>AccessControlContext</code> associated
149 * with the provided <code>DomainCombiner</code>.
150 *
151 * @param combiner the <code>DomainCombiner</code> to be associated
152 * with the provided <code>AccessControlContext</code>.
153 *
154 * @exception NullPointerException if the provided
155 * <code>context</code> is <code>null</code>.
156 *
157 * @exception SecurityException if a security manager is installed and the
158 * caller does not have the "createAccessControlContext"
159 * {@link SecurityPermission}
160 * @since 1.3
161 */
162 public AccessControlContext(AccessControlContext acc,
163 DomainCombiner combiner) {
164
165 SecurityManager sm = System.getSecurityManager();
166 if (sm != null) {
167 sm.checkPermission(SecurityConstants.CREATE_ACC_PERMISSION);
168 }
169
170 this.context = acc.context;
171
172 // we do not need to run the combine method on the
173 // provided ACC. it was already "combined" when the
174 // context was originally retrieved.
175 //
176 // at this point in time, we simply throw away the old
177 // combiner and use the newly provided one.
178 this.combiner = combiner;
179 }
180
181 /**
182 * package private for AccessController
183 */
184 AccessControlContext(ProtectionDomain context[], DomainCombiner combiner) {
185 if (context != null) {
186 this.context = context.clone();
187 }
188 this.combiner = combiner;
189 }
190
191 /**
192 * package private constructor for AccessController.getContext()
193 */
194
195 AccessControlContext(ProtectionDomain context[],
196 boolean isPrivileged)
197 {
198 this.context = context;
199 this.isPrivileged = isPrivileged;
200 }
201
202 /**
203 * Constructor for JavaSecurityAccess.doIntersectionPrivilege()
204 */
205 AccessControlContext(ProtectionDomain[] context,
206 AccessControlContext privilegedContext)
207 {
208 this.context = context;
209 this.privilegedContext = privilegedContext;
210 this.isPrivileged = true;
211 }
212
213 /**
214 * Returns this context's context.
215 */
216 ProtectionDomain[] getContext() {
217 return context;
218 }
219
220 /**
221 * Returns true if this context is privileged.
222 */
223 boolean isPrivileged()
224 {
225 return isPrivileged;
226 }
227
228 /**
229 * get the assigned combiner from the privileged or inherited context
230 */
231 DomainCombiner getAssignedCombiner() {
232 AccessControlContext acc;
233 if (isPrivileged) {
234 acc = privilegedContext;
235 } else {
236 acc = AccessController.getInheritedAccessControlContext();
237 }
238 if (acc != null) {
239 return acc.combiner;
240 }
241 return null;
242 }
243
244 /**
245 * Get the <code>DomainCombiner</code> associated with this
246 * <code>AccessControlContext</code>.
247 *
248 * <p>
249 *
250 * @return the <code>DomainCombiner</code> associated with this
251 * <code>AccessControlContext</code>, or <code>null</code>
252 * if there is none.
253 *
254 * @exception SecurityException if a security manager is installed and
255 * the caller does not have the "getDomainCombiner"
256 * {@link SecurityPermission}
257 * @since 1.3
258 */
259 public DomainCombiner getDomainCombiner() {
260
261 SecurityManager sm = System.getSecurityManager();
262 if (sm != null) {
263 sm.checkPermission(SecurityConstants.GET_COMBINER_PERMISSION);
264 }
265 return combiner;
266 }
267
268 /**
269 * Determines whether the access request indicated by the
270 * specified permission should be allowed or denied, based on
271 * the security policy currently in effect, and the context in
272 * this object. The request is allowed only if every ProtectionDomain
273 * in the context implies the permission. Otherwise the request is
274 * denied.
275 *
276 * <p>
277 * This method quietly returns if the access request
278 * is permitted, or throws a suitable AccessControlException otherwise.
279 *
280 * @param perm the requested permission.
281 *
282 * @exception AccessControlException if the specified permission
283 * is not permitted, based on the current security policy and the
284 * context encapsulated by this object.
285 * @exception NullPointerException if the permission to check for is null.
286 */
287 public void checkPermission(Permission perm)
288 throws AccessControlException
289 {
290 boolean dumpDebug = false;
291
292 if (perm == null) {
293 throw new NullPointerException("permission can't be null");
294 }
295 if (getDebug() != null) {
296 // If "codebase" is not specified, we dump the info by default.
297 dumpDebug = !Debug.isOn("codebase=");
298 if (!dumpDebug) {
299 // If "codebase" is specified, only dump if the specified code
300 // value is in the stack.
301 for (int i = 0; context != null && i < context.length; i++) {
302 if (context[i].getCodeSource() != null &&
303 context[i].getCodeSource().getLocation() != null &&
304 Debug.isOn("codebase=" + context[i].getCodeSource().getLocation().toString())) {
305 dumpDebug = true;
306 break;
307 }
308 }
309 }
310
311 dumpDebug &= !Debug.isOn("permission=") ||
312 Debug.isOn("permission=" + perm.getClass().getCanonicalName());
313
314 if (dumpDebug && Debug.isOn("stack")) {
315 Thread.currentThread().dumpStack();
316 }
317
318 if (dumpDebug && Debug.isOn("domain")) {
319 if (context == null) {
320 debug.println("domain (context is null)");
321 } else {
322 for (int i=0; i< context.length; i++) {
323 debug.println("domain "+i+" "+context[i]);
324 }
325 }
326 }
327 }
328
329 /*
330 * iterate through the ProtectionDomains in the context.
331 * Stop at the first one that doesn't allow the
332 * requested permission (throwing an exception).
333 *
334 */
335
336 /* if ctxt is null, all we had on the stack were system domains,
337 or the first domain was a Privileged system domain. This
338 is to make the common case for system code very fast */
339
340 if (context == null)
341 return;
342
343 for (int i=0; i< context.length; i++) {
344 if (context[i] != null && !context[i].implies(perm)) {
345 if (dumpDebug) {
346 debug.println("access denied " + perm);
347 }
348
349 if (Debug.isOn("failure") && debug != null) {
350 // Want to make sure this is always displayed for failure,
351 // but do not want to display again if already displayed
352 // above.
353 if (!dumpDebug) {
354 debug.println("access denied " + perm);
355 }
356 Thread.currentThread().dumpStack();
357 final ProtectionDomain pd = context[i];
358 final Debug db = debug;
359 AccessController.doPrivileged (new PrivilegedAction<Void>() {
360 public Void run() {
361 db.println("domain that failed "+pd);
362 return null;
363 }
364 });
365 }
366 throw new AccessControlException("access denied "+perm, perm);
367 }
368 }
369
370 // allow if all of them allowed access
371 if (dumpDebug) {
372 debug.println("access allowed "+perm);
373 }
374
375 return;
376 }
377
378 /**
379 * Take the stack-based context (this) and combine it with the
380 * privileged or inherited context, if need be.
381 */
382 AccessControlContext optimize() {
383 // the assigned (privileged or inherited) context
384 AccessControlContext acc;
385 if (isPrivileged) {
386 acc = privilegedContext;
387 } else {
388 acc = AccessController.getInheritedAccessControlContext();
389 }
390
391 // this.context could be null if only system code is on the stack;
392 // in that case, ignore the stack context
393 boolean skipStack = (context == null);
394
395 // acc.context could be null if only system code was involved;
396 // in that case, ignore the assigned context
397 boolean skipAssigned = (acc == null || acc.context == null);
398
399 if (acc != null && acc.combiner != null) {
400 // let the assigned acc's combiner do its thing
401 return goCombiner(context, acc);
402 }
403
404 // optimization: if neither have contexts; return acc if possible
405 // rather than this, because acc might have a combiner
406 if (skipAssigned && skipStack) {
407 return this;
408 }
409
410 // optimization: if there is no stack context; there is no reason
411 // to compress the assigned context, it already is compressed
412 if (skipStack) {
413 return acc;
414 }
415
416 int slen = context.length;
417
418 // optimization: if there is no assigned context and the stack length
419 // is less then or equal to two; there is no reason to compress the
420 // stack context, it already is
421 if (skipAssigned && slen <= 2) {
422 return this;
423 }
424
425 // optimization: if there is a single stack domain and that domain
426 // is already in the assigned context; no need to combine
427 if ((slen == 1) && (context[0] == acc.context[0])) {
428 return acc;
429 }
430
431 int n = (skipAssigned) ? 0 : acc.context.length;
432
433 // now we combine both of them, and create a new context
434 ProtectionDomain pd[] = new ProtectionDomain[slen + n];
435
436 // first copy in the assigned context domains, no need to compress
437 if (!skipAssigned) {
438 System.arraycopy(acc.context, 0, pd, 0, n);
439 }
440
441 // now add the stack context domains, discarding nulls and duplicates
442 outer:
443 for (int i = 0; i < context.length; i++) {
444 ProtectionDomain sd = context[i];
445 if (sd != null) {
446 for (int j = 0; j < n; j++) {
447 if (sd == pd[j]) {
448 continue outer;
449 }
450 }
451 pd[n++] = sd;
452 }
453 }
454
455 // if length isn't equal, we need to shorten the array
456 if (n != pd.length) {
457 // optimization: if we didn't really combine anything
458 if (!skipAssigned && n == acc.context.length) {
459 return acc;
460 } else if (skipAssigned && n == slen) {
461 return this;
462 }
463 ProtectionDomain tmp[] = new ProtectionDomain[n];
464 System.arraycopy(pd, 0, tmp, 0, n);
465 pd = tmp;
466 }
467
468 // return new AccessControlContext(pd, false);
469
470 // Reuse existing ACC
471
472 this.context = pd;
473 this.combiner = null;
474 this.isPrivileged = false;
475
476 return this;
477 }
478
479 private AccessControlContext goCombiner(ProtectionDomain[] current,
480 AccessControlContext assigned) {
481
482 // the assigned ACC's combiner is not null --
483 // let the combiner do its thing
484
485 // XXX we could add optimizations to 'current' here ...
486
487 if (getDebug() != null) {
488 debug.println("AccessControlContext invoking the Combiner");
489 }
490
491 // No need to clone current and assigned.context
492 // combine() will not update them
493 ProtectionDomain[] combinedPds = assigned.combiner.combine(
494 current, assigned.context);
495
496 // return new AccessControlContext(combinedPds, assigned.combiner);
497
498 // Reuse existing ACC
499 this.context = combinedPds;
500 this.combiner = assigned.combiner;
501 this.isPrivileged = false;
502
503 return this;
504 }
505
506 /**
507 * Checks two AccessControlContext objects for equality.
508 * Checks that <i>obj</i> is
509 * an AccessControlContext and has the same set of ProtectionDomains
510 * as this context.
511 * <P>
512 * @param obj the object we are testing for equality with this object.
513 * @return true if <i>obj</i> is an AccessControlContext, and has the
514 * same set of ProtectionDomains as this context, false otherwise.
515 */
516 public boolean equals(Object obj) {
517 if (obj == this)
518 return true;
519
520 if (! (obj instanceof AccessControlContext))
521 return false;
522
523 AccessControlContext that = (AccessControlContext) obj;
524
525
526 if (context == null) {
527 return (that.context == null);
528 }
529
530 if (that.context == null)
531 return false;
532
533 if (!(this.containsAllPDs(that) && that.containsAllPDs(this)))
534 return false;
535
536 if (this.combiner == null)
537 return (that.combiner == null);
538
539 if (that.combiner == null)
540 return false;
541
542 if (!this.combiner.equals(that.combiner))
543 return false;
544
545 return true;
546 }
547
548 private boolean containsAllPDs(AccessControlContext that) {
549 boolean match = false;
550 //
551 // ProtectionDomains within an ACC currently cannot be null
552 // and this is enforced by the constructor and the various
553 // optimize methods. However, historically this logic made attempts
554 // to support the notion of a null PD and therefore this logic continues
555 // to support that notion.
556 ProtectionDomain thisPd;
557 for (int i = 0; i < context.length; i++) {
558 match = false;
559 if ((thisPd = context[i]) == null) {
560 for (int j = 0; (j < that.context.length) && !match; j++) {
561 match = (that.context[j] == null);
562 }
563 } else {
564 Class thisPdClass = thisPd.getClass();
565 ProtectionDomain thatPd;
566 for (int j = 0; (j < that.context.length) && !match; j++) {
567 thatPd = that.context[j];
568
569 // Class check required to avoid PD exposure (4285406)
570 match = (thatPd != null &&
571 thisPdClass == thatPd.getClass() && thisPd.equals(thatPd));
572 }
573 }
574 if (!match) return false;
575 }
576 return match;
577 }
578 /**
579 * Returns the hash code value for this context. The hash code
580 * is computed by exclusive or-ing the hash code of all the protection
581 * domains in the context together.
582 *
583 * @return a hash code value for this context.
584 */
585
586 public int hashCode() {
587 int hashCode = 0;
588
589 if (context == null)
590 return hashCode;
591
592 for (int i =0; i < context.length; i++) {
593 if (context[i] != null)
594 hashCode ^= context[i].hashCode();
595 }
596 return hashCode;
597 }
598}