KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > javax > security > auth > SubjectDomainCombiner


1 /*
2  * @(#)SubjectDomainCombiner.java 1.50 07/09/11
3  *
4  * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7
8 package javax.security.auth;
9
10 import java.security.AccessController JavaDoc;
11 import java.security.AccessControlContext JavaDoc;
12 import java.security.AllPermission JavaDoc;
13 import java.security.Permission JavaDoc;
14 import java.security.Permissions JavaDoc;
15 import java.security.PermissionCollection JavaDoc;
16 import java.security.Policy JavaDoc;
17 import java.security.Principal JavaDoc;
18 import java.security.PrivilegedAction JavaDoc;
19 import java.security.ProtectionDomain JavaDoc;
20 import java.lang.ClassLoader JavaDoc;
21 import java.security.Security JavaDoc;
22 import java.util.Set JavaDoc;
23 import java.util.Iterator JavaDoc;
24 import java.util.WeakHashMap JavaDoc;
25 import java.lang.ref.WeakReference JavaDoc;
26
27 /**
28  * A <code>SubjectDomainCombiner</code> updates ProtectionDomains
29  * with Principals from the <code>Subject</code> associated with this
30  * <code>SubjectDomainCombiner</code>.
31  *
32  * @version 1.48, 08/25/05
33  */

34 public class SubjectDomainCombiner implements java.security.DomainCombiner JavaDoc {
35
36     private Subject JavaDoc subject;
37     private WeakKeyValueMap<ProtectionDomain JavaDoc, ProtectionDomain JavaDoc> cachedPDs =
38         new WeakKeyValueMap<ProtectionDomain JavaDoc, ProtectionDomain JavaDoc>();
39     private Set JavaDoc principalSet;
40     private Principal JavaDoc[] principals;
41
42     private static final sun.security.util.Debug debug =
43     sun.security.util.Debug.getInstance("combiner",
44                     "\t[SubjectDomainCombiner]");
45
46     // Note: check only at classloading time, not dynamically during combine()
47
private static final boolean useJavaxPolicy = compatPolicy();
48
49     // Relevant only when useJavaxPolicy is true
50
private static final boolean allowCaching =
51                     (useJavaxPolicy && cachePolicy());
52
53     /**
54      * Associate the provided <code>Subject</code> with this
55      * <code>SubjectDomainCombiner</code>.
56      *
57      * <p>
58      *
59      * @param subject the <code>Subject</code> to be associated with
60      * with this <code>SubjectDomainCombiner</code>.
61      */

62     public SubjectDomainCombiner(Subject JavaDoc subject) {
63     this.subject = subject;
64
65     if (subject.isReadOnly()) {
66         principalSet = subject.getPrincipals();
67         principals = (Principal JavaDoc[])principalSet.toArray
68             (new Principal JavaDoc[principalSet.size()]);
69     }
70     }
71
72     /**
73      * Get the <code>Subject</code> associated with this
74      * <code>SubjectDomainCombiner</code>.
75      *
76      * <p>
77      *
78      * @return the <code>Subject</code> associated with this
79      * <code>SubjectDomainCombiner</code>, or <code>null</code>
80      * if no <code>Subject</code> is associated with this
81      * <code>SubjectDomainCombiner</code>.
82      *
83      * @exception SecurityException if the caller does not have permission
84      * to get the <code>Subject</code> associated with this
85      * <code>SubjectDomainCombiner</code>.
86      */

87     public Subject JavaDoc getSubject() {
88     java.lang.SecurityManager JavaDoc sm = System.getSecurityManager();
89     if (sm != null) {
90         sm.checkPermission(new AuthPermission JavaDoc
91         ("getSubjectFromDomainCombiner"));
92     }
93     return subject;
94     }
95
96     /**
97      * Update the relevant ProtectionDomains with the Principals
98      * from the <code>Subject</code> associated with this
99      * <code>SubjectDomainCombiner</code>.
100      *
101      * <p> A new <code>ProtectionDomain</code> instance is created
102      * for each <code>ProtectionDomain</code> in the
103      * <i>currentDomains</i> array. Each new <code>ProtectionDomain</code>
104      * instance is created using the <code>CodeSource</code>,
105      * <code>Permission</code>s and <code>ClassLoader</code>
106      * from the corresponding <code>ProtectionDomain</code> in
107      * <i>currentDomains</i>, as well as with the Principals from
108      * the <code>Subject</code> associated with this
109      * <code>SubjectDomainCombiner</code>.
110      *
111      * <p> All of the newly instantiated ProtectionDomains are
112      * combined into a new array. The ProtectionDomains from the
113      * <i>assignedDomains</i> array are appended to this new array,
114      * and the result is returned.
115      *
116      * <p> Note that optimizations such as the removal of duplicate
117      * ProtectionDomains may have occurred.
118      * In addition, caching of ProtectionDomains may be permitted.
119      *
120      * <p>
121      *
122      * @param currentDomains the ProtectionDomains associated with the
123      * current execution Thread, up to the most recent
124      * privileged <code>ProtectionDomain</code>.
125      * The ProtectionDomains are are listed in order of execution,
126      * with the most recently executing <code>ProtectionDomain</code>
127      * residing at the beginning of the array. This parameter may
128      * be <code>null</code> if the current execution Thread
129      * has no associated ProtectionDomains.<p>
130      *
131      * @param assignedDomains the ProtectionDomains inherited from the
132      * parent Thread, or the ProtectionDomains from the
133      * privileged <i>context</i>, if a call to
134      * AccessController.doPrivileged(..., <i>context</i>)
135      * had occurred This parameter may be <code>null</code>
136      * if there were no ProtectionDomains inherited from the
137      * parent Thread, or from the privileged <i>context</i>.
138      *
139      * @return a new array consisting of the updated ProtectionDomains,
140      * or <code>null</code>.
141      */

142     public ProtectionDomain JavaDoc[] combine(ProtectionDomain JavaDoc[] currentDomains,
143                 ProtectionDomain JavaDoc[] assignedDomains) {
144     if (debug != null) {
145         if (subject == null) {
146         debug.println("null subject");
147         } else {
148         final Subject JavaDoc s = subject;
149         AccessController.doPrivileged
150             (new java.security.PrivilegedAction JavaDoc() {
151             public Object JavaDoc run() {
152             debug.println(s.toString());
153             return null;
154             }
155         });
156         }
157         printInputDomains(currentDomains, assignedDomains);
158     }
159
160     if (currentDomains == null || currentDomains.length == 0) {
161         // No need to optimize assignedDomains because it should
162
// have been previously optimized (when it was set).
163

164         // Note that we are returning a direct reference
165
// to the input array - since ACC does not clone
166
// the arrays when it calls combiner.combine,
167
// multiple ACC instances may share the same
168
// array instance in this case
169

170         return assignedDomains;
171     }
172
173     // optimize currentDomains
174
//
175
// No need to optimize assignedDomains because it should
176
// have been previously optimized (when it was set).
177

178     currentDomains = optimize(currentDomains);
179     if (debug != null) {
180         debug.println("after optimize");
181         printInputDomains(currentDomains, assignedDomains);
182     }
183
184     if (currentDomains == null && assignedDomains == null) {
185         return null;
186     }
187
188     // maintain backwards compatibility for people who provide
189
// their own javax.security.auth.Policy implementations
190
if (useJavaxPolicy) {
191         return combineJavaxPolicy(currentDomains, assignedDomains);
192     }
193     
194     int cLen = (currentDomains == null ? 0 : currentDomains.length);
195     int aLen = (assignedDomains == null ? 0 : assignedDomains.length);
196
197     // the ProtectionDomains for the new AccessControlContext
198
// that we will return
199
ProtectionDomain JavaDoc[] newDomains = new ProtectionDomain JavaDoc[cLen + aLen];
200
201     boolean allNew = true;
202     synchronized(cachedPDs) {
203         if (!subject.isReadOnly() &&
204         !subject.getPrincipals().equals(principalSet)) {
205
206         // if the Subject was mutated, clear the PD cache
207
Set JavaDoc newSet = subject.getPrincipals();
208         synchronized(newSet) {
209             principalSet = new java.util.HashSet JavaDoc(newSet);
210         }
211         principals = (Principal JavaDoc[])principalSet.toArray
212             (new Principal JavaDoc[principalSet.size()]);
213         cachedPDs.clear();
214
215         if (debug != null) {
216             debug.println("Subject mutated - clearing cache");
217         }
218         }
219
220         ProtectionDomain JavaDoc subjectPd;
221         for (int i = 0; i < cLen; i++) {
222         ProtectionDomain JavaDoc pd = currentDomains[i];
223
224         subjectPd = cachedPDs.getValue(pd);
225
226         if (subjectPd == null) {
227             subjectPd = new ProtectionDomain JavaDoc(pd.getCodeSource(),
228                         pd.getPermissions(),
229                         pd.getClassLoader(),
230                         principals);
231             cachedPDs.putValue(pd, subjectPd);
232         } else {
233             allNew = false;
234         }
235         newDomains[i] = subjectPd;
236         }
237         }
238
239     if (debug != null) {
240         debug.println("updated current: ");
241         for (int i = 0; i < cLen; i++) {
242         debug.println("\tupdated[" + i + "] = " +
243                 printDomain(newDomains[i]));
244         }
245     }
246
247     // now add on the assigned domains
248
if (aLen > 0) {
249         System.arraycopy(assignedDomains, 0, newDomains, cLen, aLen);
250
251         // optimize the result (cached PDs might exist in assignedDomains)
252
if (!allNew) {
253         newDomains = optimize(newDomains);
254         }
255     }
256
257     // if aLen == 0 || allNew, no need to further optimize newDomains
258

259     if (debug != null) {
260         if (newDomains == null || newDomains.length == 0) {
261         debug.println("returning null");
262         } else {
263         debug.println("combinedDomains: ");
264         for (int i = 0; i < newDomains.length; i++) {
265             debug.println("newDomain " + i + ": " +
266                   printDomain(newDomains[i]));
267         }
268         }
269     }
270     
271     // return the new ProtectionDomains
272
if (newDomains == null || newDomains.length == 0) {
273         return null;
274     } else {
275         return newDomains;
276     }
277     }
278
279     /**
280      * Use the javax.security.auth.Policy implementation
281      */

282     private ProtectionDomain JavaDoc[] combineJavaxPolicy(
283     ProtectionDomain JavaDoc[] currentDomains,
284     ProtectionDomain JavaDoc[] assignedDomains) {
285
286     if (!allowCaching) {
287         java.security.AccessController.doPrivileged
288         (new PrivilegedAction JavaDoc() {
289             public Object JavaDoc run() {
290             // Call refresh only caching is disallowed
291
javax.security.auth.Policy.getPolicy().refresh();
292             return null;
293             }
294         });
295     }
296     
297     int cLen = (currentDomains == null ? 0 : currentDomains.length);
298     int aLen = (assignedDomains == null ? 0 : assignedDomains.length);
299
300     // the ProtectionDomains for the new AccessControlContext
301
// that we will return
302
ProtectionDomain JavaDoc[] newDomains = new ProtectionDomain JavaDoc[cLen + aLen];
303
304     synchronized(cachedPDs) {
305         if (!subject.isReadOnly() &&
306         !subject.getPrincipals().equals(principalSet)) {
307
308         // if the Subject was mutated, clear the PD cache
309
Set JavaDoc newSet = subject.getPrincipals();
310         synchronized(newSet) {
311             principalSet = new java.util.HashSet JavaDoc(newSet);
312         }
313         principals = (Principal JavaDoc[])principalSet.toArray
314             (new Principal JavaDoc[principalSet.size()]);
315         cachedPDs.clear();
316
317         if (debug != null) {
318             debug.println("Subject mutated - clearing cache");
319         }
320         }
321
322         for (int i = 0; i < cLen; i++) {
323         ProtectionDomain JavaDoc pd = currentDomains[i];
324         ProtectionDomain JavaDoc subjectPd = cachedPDs.getValue(pd);
325
326         if (subjectPd == null) {
327
328             // XXX
329
// we must first add the original permissions.
330
// that way when we later add the new JAAS permissions,
331
// any unresolved JAAS-related permissions will
332
// automatically get resolved.
333

334             // get the original perms
335
Permissions JavaDoc perms = new Permissions JavaDoc();
336             PermissionCollection JavaDoc coll = pd.getPermissions();
337             java.util.Enumeration JavaDoc e;
338                     if (coll != null) {
339                 synchronized (coll) {
340                 e = coll.elements();
341                 while (e.hasMoreElements()) {
342                     Permission JavaDoc newPerm =
343                                     (Permission JavaDoc)e.nextElement();
344                     perms.add(newPerm);
345                             }
346             }
347             }
348
349             // get perms from the policy
350

351             final java.security.CodeSource JavaDoc finalCs = pd.getCodeSource();
352             final Subject JavaDoc finalS = subject;
353             PermissionCollection JavaDoc newPerms = (PermissionCollection JavaDoc)
354             java.security.AccessController.doPrivileged
355             (new PrivilegedAction JavaDoc() {
356             public Object JavaDoc run() {
357               return
358               javax.security.auth.Policy.getPolicy().getPermissions
359                 (finalS, finalCs);
360             }
361             });
362             
363             // add the newly granted perms,
364
// avoiding duplicates
365
synchronized (newPerms) {
366             e = newPerms.elements();
367             while (e.hasMoreElements()) {
368                 Permission JavaDoc newPerm = (Permission JavaDoc)e.nextElement();
369                 if (!perms.implies(newPerm)) {
370                 perms.add(newPerm);
371                 if (debug != null)
372                     debug.println (
373                     "Adding perm " + newPerm + "\n");
374                 }
375             }
376             }
377                     subjectPd = new ProtectionDomain JavaDoc
378                         (finalCs, perms, pd.getClassLoader(), principals);
379
380             if (allowCaching)
381             cachedPDs.putValue(pd, subjectPd);
382         }
383         newDomains[i] = subjectPd;
384         }
385     }
386
387     if (debug != null) {
388         debug.println("updated current: ");
389         for (int i = 0; i < cLen; i++) {
390         debug.println("\tupdated[" + i + "] = " + newDomains[i]);
391         }
392     }
393
394     // now add on the assigned domains
395
if (aLen > 0) {
396         System.arraycopy(assignedDomains, 0, newDomains, cLen, aLen);
397     }
398
399     if (debug != null) {
400         if (newDomains == null || newDomains.length == 0) {
401         debug.println("returning null");
402         } else {
403         debug.println("combinedDomains: ");
404         for (int i = 0; i < newDomains.length; i++) {
405             debug.println("newDomain " + i + ": " +
406             newDomains[i].toString());
407         }
408         }
409     }
410
411     // return the new ProtectionDomains
412
if (newDomains == null || newDomains.length == 0) {
413         return null;
414     } else {
415         return newDomains;
416     }
417     }
418     
419     private static ProtectionDomain JavaDoc[] optimize(ProtectionDomain JavaDoc[] domains) {
420     if (domains == null || domains.length == 0)
421         return null;
422
423     ProtectionDomain JavaDoc[] optimized = new ProtectionDomain JavaDoc[domains.length];
424     ProtectionDomain JavaDoc pd;
425     int num = 0;
426     for (int i = 0; i < domains.length; i++) {
427
428         // skip domains with AllPermission
429
// XXX
430
//
431
// if (domains[i].implies(ALL_PERMISSION))
432
// continue;
433

434         // skip System Domains
435
if ((pd = domains[i]) != null) {
436
437         // remove duplicates
438
boolean found = false;
439         for (int j = 0; j < num && !found; j++) {
440             found = (optimized[j] == pd);
441         }
442         if (!found) {
443             optimized[num++] = pd;
444         }
445         }
446     }
447
448     // resize the array if necessary
449
if (num > 0 && num < domains.length) {
450         ProtectionDomain JavaDoc[] downSize = new ProtectionDomain JavaDoc[num];
451         System.arraycopy(optimized, 0, downSize, 0, downSize.length);
452         optimized = downSize;
453     }
454
455     return ((num == 0 || optimized.length == 0) ? null : optimized);
456     }
457
458     private static boolean cachePolicy() {
459     String JavaDoc s = (String JavaDoc)AccessController.doPrivileged
460         (new PrivilegedAction JavaDoc() {
461         public Object JavaDoc run() {
462         return java.security.Security.getProperty
463                     ("cache.auth.policy");
464         }
465     });
466     if (s != null) {
467         Boolean JavaDoc b = new Boolean JavaDoc(s);
468         return b.booleanValue();
469     }
470
471     // cache by default
472
return true;
473     }
474
475     // maintain backwards compatibility for people who provide
476
// their own javax.security.auth.Policy implementations
477
private static boolean compatPolicy() {
478     javax.security.auth.Policy JavaDoc javaxPolicy =
479         (javax.security.auth.Policy JavaDoc)AccessController.doPrivileged
480         (new PrivilegedAction JavaDoc() {
481         public Object JavaDoc run() {
482         return javax.security.auth.Policy.getPolicy();
483         }
484     });
485
486     if (!(javaxPolicy instanceof com.sun.security.auth.PolicyFile)) {
487         if (debug != null) {
488         debug.println("Providing backwards compatibility for " +
489             "javax.security.auth.policy implementation: " +
490             javaxPolicy.toString());
491         }
492
493         return true;
494     } else {
495         return false;
496     }
497     }
498
499     private static void printInputDomains(ProtectionDomain JavaDoc[] currentDomains,
500                 ProtectionDomain JavaDoc[] assignedDomains) {
501     if (currentDomains == null || currentDomains.length == 0) {
502         debug.println("currentDomains null or 0 length");
503     } else {
504         for (int i = 0; currentDomains != null &&
505             i < currentDomains.length; i++) {
506         if (currentDomains[i] == null) {
507             debug.println("currentDomain " + i + ": SystemDomain");
508         } else {
509             debug.println("currentDomain " + i + ": " +
510                 printDomain(currentDomains[i]));
511         }
512         }
513     }
514
515     if (assignedDomains == null || assignedDomains.length == 0) {
516         debug.println("assignedDomains null or 0 length");
517     } else {
518         debug.println("assignedDomains = ");
519         for (int i = 0; assignedDomains != null &&
520             i < assignedDomains.length; i++) {
521         if (assignedDomains[i] == null) {
522             debug.println("assignedDomain " + i + ": SystemDomain");
523         } else {
524             debug.println("assignedDomain " + i + ": " +
525                 printDomain(assignedDomains[i]));
526         }
527         }
528     }
529     }
530
531     private static String JavaDoc printDomain(final ProtectionDomain JavaDoc pd) {
532     if (pd == null) {
533         return "null";
534     }
535     return (String JavaDoc)AccessController.doPrivileged(new PrivilegedAction JavaDoc() {
536         public Object JavaDoc run() {
537         return pd.toString();
538         }
539     });
540     }
541
542     /**
543      * A HashMap that has weak keys and values.
544      *
545      * Key objects in this map are the "current" ProtectionDomain instances
546      * received via the combine method. Each "current" PD is mapped to a
547      * new PD instance that holds both the contents of the "current" PD,
548      * as well as the principals from the Subject associated with this combiner.
549      *
550      * The newly created "principal-based" PD values must be stored as
551      * WeakReferences since they contain strong references to the
552      * corresponding key object (the "current" non-principal-based PD),
553      * which will prevent the key from being GC'd. Specifically,
554      * a "principal-based" PD contains strong references to the CodeSource,
555      * signer certs, PermissionCollection and ClassLoader objects
556      * in the "current PD".
557      */

558     private static class WeakKeyValueMap<K,V> extends
559                     WeakHashMap JavaDoc<K,WeakReference JavaDoc<V>> {
560
561     public V getValue(K key) {
562         WeakReference JavaDoc<V> wr = super.get(key);
563         if (wr != null) {
564         return wr.get();
565         }
566         return null;
567     }
568
569     public V putValue(K key, V value) {
570         WeakReference JavaDoc<V> wr = super.put(key, new WeakReference JavaDoc<V>(value));
571         if (wr != null) {
572         return wr.get();
573         }
574         return null;
575     }
576     }
577 }
578
Popular Tags