KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > enterprise > security > provider > PolicyWrapper


1 /*
2  * The contents of this file are subject to the terms
3  * of the Common Development and Distribution License
4  * (the License). You may not use this file except in
5  * compliance with the License.
6  *
7  * You can obtain a copy of the license at
8  * https://glassfish.dev.java.net/public/CDDLv1.0.html or
9  * glassfish/bootstrap/legal/CDDLv1.0.txt.
10  * See the License for the specific language governing
11  * permissions and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL
14  * Header Notice in each file and include the License file
15  * at glassfish/bootstrap/legal/CDDLv1.0.txt.
16  * If applicable, add the following below the CDDL Header,
17  * with the fields enclosed by brackets [] replaced by
18  * you own identifying information:
19  * "Portions Copyrighted [year] [name of copyright owner]"
20  *
21  * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
22  */

23
24 /*
25  * PolicyWrapper.java
26  *
27  * @author Harpreet Singh (harpreet.singh@sun.com)
28  * @author Ron Monzillo
29  * @version
30 5B
31  * Created on May 23, 2002, 1:56 PM
32  */

33
34 package com.sun.enterprise.security.provider;
35
36 import sun.security.provider.PolicyFile;
37 import sun.security.util.PropertyExpander;
38 import java.security.*;
39 import javax.security.jacc.*;
40 import javax.management.MBeanPermission JavaDoc;
41 import java.io.File JavaDoc;
42 import java.net.URI JavaDoc;
43 import java.net.URL JavaDoc;
44 import java.util.Collection JavaDoc;
45 import java.util.Enumeration JavaDoc;
46 import java.util.Iterator JavaDoc;
47 import java.util.logging.*;
48 import java.lang.*;
49 import com.sun.logging.LogDomains;
50 import com.sun.enterprise.util.LocalStringManagerImpl;
51 /**
52  * This class is a wrapper around the default jdk policy file
53  * implementation. PolicyWrapper is installed as the JRE policy object
54  * It multiples policy decisions to the context specific instance of
55  * sun.security.provider.PolicyFile.
56  * Although this Policy provider is implemented using another Policy class,
57  * this class is not a "delegating Policy provider" as defined by JACC, and
58  * as such it SHOULD not be configured using the JACC system property
59  * javax.security.jacc.policy.provider.
60  * @author Harpreet Singh (harpreet.singh@sun.com)
61  * @author Jean-Francois Arcand
62  * @author Ron Monzillo
63  *
64  */

65 public final class PolicyWrapper extends java.security.Policy JavaDoc {
66
67     // this is the jdk policy file instance
68
private java.security.Policy JavaDoc policy = null;
69    
70     private static Logger logger = Logger.getLogger(LogDomains.SECURITY_LOGGER);
71     private static LocalStringManagerImpl localStrings =
72     new LocalStringManagerImpl(PolicyWrapper.class);
73
74     static String JavaDoc logMsg(Level level,String JavaDoc key,Object JavaDoc[] params,String JavaDoc defMsg){
75     String JavaDoc msg = (key == null ? defMsg : localStrings.getLocalString
76         (key,defMsg == null ? key : defMsg, params));
77     logger.log(level,msg);
78     return msg;
79     }
80
81     private static final String JavaDoc REUSE = "java.security.Policy.supportsReuse";
82     
83     /**
84      * Name of the system property to enable detecting and avoiding reentrancy.
85      * This property can be set using <jvm-options> in domain.xml. If not set
86      * or set to false, this class will detect or avoid reentrancy in policy
87      * evaluation. Note that if SecurityManager is turned off, this feature is
88      * always turned off.
89      * Another design approach is to name the property differently
90      * and use a list of context ids as its value, so that this feature may be
91      * enabled for selected contexts.
92      */

93     private static final String JavaDoc IGNORE_REENTRANCY_PROP_NAME =
94             "com.sun.enterprise.security.provider.PolicyWrapper.ignoreReentrancy";
95     
96     /**
97      * Flag to indicate if detecting and avoiding reentrancy is enabled.
98      * If SecurityManager is turned off, reentrancy is less likely to occur and
99      * this feature is always off; else if the system property IGNORE_REENTRANCY_PROP_NAME
100      * is not set, or set to false in domain.xml, this feature is on;
101      *
102      */

103     private static final boolean avoidReentrancy =
104             (!Boolean.getBoolean(IGNORE_REENTRANCY_PROP_NAME)) &&
105             (System.getSecurityManager() != null);
106     
107     /**
108      * ThreadLocal object to keep track of the reentrancy status of each thread.
109      * It contains a byte[] object whose single element is either 0 (initial
110      * value or no reentrancy), or 1 (current thread is reentrant). When a
111      * thread exists the implies method, byte[0] is alwasy reset to 0.
112      */

113     private static ThreadLocal JavaDoc reentrancyStatus;
114
115     static {
116         if(avoidReentrancy) {
117             reentrancyStatus = new ThreadLocal JavaDoc() {
118                 protected synchronized Object JavaDoc initialValue() {
119                     return new byte[]{0};
120                 }
121             };
122         }
123     }
124
125     /** Creates a new instance of PolicyWrapper */
126     public PolicyWrapper() {
127         // the jdk policy file implementation
128
policy = (java.security.Policy JavaDoc) new sun.security.provider.PolicyFile();
129     refreshTime = 0L;
130     // call the following routine to compute the actual refreshTime
131
defaultContextChanged();
132     }
133     
134     /**
135      * Evaluates the global policy and returns a
136      * PermissionCollection object specifying the set of
137      * permissions allowed for code from the specified
138      * code source.
139      *
140      * @param codesource the CodeSource associated with the caller.
141      * This encapsulates the original location of the code (where the code
142      * came from) and the public key(s) of its signer.
143      *
144      * @return the set of permissions allowed for code from <i>codesource</i>
145      * according to the policy.The returned set of permissions must be
146      * a new mutable instance and it must support heterogeneous
147      * Permission types.
148      *
149      */

150     public PermissionCollection getPermissions(CodeSource codesource) {
151     String JavaDoc contextId = PolicyContext.getContextID();
152     PolicyConfigurationImpl pci = getPolicyConfigForContext(contextId);
153     Policy appPolicy = getPolicy(pci);
154     PermissionCollection perms = appPolicy.getPermissions(codesource);
155     if (perms != null) {
156         perms = removeExcludedPermissions(pci,perms);
157     }
158     if (logger.isLoggable(Level.FINEST)){
159         logger.finest("JACC Policy Provider: PolicyWrapper.getPermissions(cs), context ("+contextId+") codesource ("+codesource+") permissions: "+perms);
160     }
161         return perms;
162     }
163
164     /**
165      * Evaluates the global policy and returns a
166      * PermissionCollection object specifying the set of
167      * permissions allowed given the characteristics of the
168      * protection domain.
169      *
170      * @param domain the ProtectionDomain associated with the caller.
171      *
172      * @return the set of permissions allowed for the <i>domain</i>
173      * according to the policy.The returned set of permissions must be
174      * a new mutable instance and it must support heterogeneous
175      * Permission types.
176      *
177      * @see java.security.ProtectionDomain
178      * @see java.security.SecureClassLoader
179      * @since 1.4
180      */

181     public PermissionCollection getPermissions(ProtectionDomain domain) {
182     String JavaDoc contextId = PolicyContext.getContextID();
183     PolicyConfigurationImpl pci = getPolicyConfigForContext(contextId);
184     Policy appPolicy = getPolicy(pci);
185     PermissionCollection perms = appPolicy.getPermissions(domain);
186     if (perms != null) {
187         perms = removeExcludedPermissions(pci,perms);
188     }
189     if (logger.isLoggable(Level.FINEST)){
190         logger.finest("JACC Policy Provider: PolicyWrapper.getPermissions(d), context ("+contextId+") permissions: "+perms);
191     }
192         return perms;
193     }
194     
195     /**
196      * Evaluates the global policy for the permissions granted to
197      * the ProtectionDomain and tests whether the permission is
198      * granted.
199      *
200      * @param domain the ProtectionDomain to test
201      * @param permission the Permission object to be tested for implication.
202      *
203      * @return true if "permission" is a proper subset of a permission
204      * granted to this ProtectionDomain.
205      *
206      * @see java.security.ProtectionDomain
207      * @since 1.4
208      */

209     public boolean implies(ProtectionDomain domain, Permission JavaDoc permission) {
210         if(avoidReentrancy) {
211             byte[] alreadyCalled = (byte[]) reentrancyStatus.get();
212             if(alreadyCalled[0] == 1) {
213                 return true;
214             } else {
215                 alreadyCalled[0] = 1;
216                 try {
217                     return doImplies(domain, permission);
218                 } finally {
219                     alreadyCalled[0] = 0;
220                 }
221             }
222         } else {
223             return doImplies(domain, permission);
224         }
225     }
226     
227     
228     /**
229      * Refreshes/reloads the policy configuration. The behavior of this method
230      * depends on the implementation. For example, calling <code>refresh</code>
231      * on a file-based policy will cause the file to be re-read.
232      *
233      */

234     public void refresh() {
235     if (logger.isLoggable(Level.FINE)){
236         logger.fine("JACC Policy Provider: Refreshing Policy files!");
237     }
238
239     // always refreshes default policy context, but refresh
240
// of application context depends on PolicyConfigurationImpl
241
// this could result in an inconsistency since default context is
242
// included in application contexts.
243
policy.refresh();
244
245     // try to determine if default policy context has changed.
246
// if so, force refresh of application contexts.
247
// if the following code is not robust enough to detect
248
// changes to the policy files read by the default context,
249
// then you can configure the provider to force on every refresh
250
// (see FORCE_APP_REFRESH_PROP_NAME).
251

252     boolean force = defaultContextChanged();
253
254     Collection JavaDoc c = PolicyConfigurationFactoryImpl.getPolicyConfigurationImpls();
255     if (c != null) {
256         Iterator JavaDoc it = c.iterator();
257         while (it.hasNext()) {
258         PolicyConfigurationImpl pci = (PolicyConfigurationImpl)it.next();
259         if (pci != null) {
260             // false means don't force refresh if no update since
261
// last refresh.
262
pci.refresh(force);
263         }
264         }
265     }
266         try {
267             if (PolicyContext.getHandlerKeys().contains(REUSE)) {
268                 PolicyContext.getContext(REUSE);
269             }
270         } catch(PolicyContextException pe) {
271             throw new IllegalStateException JavaDoc(pe.toString());
272         }
273     }
274
275     private static PolicyConfigurationImpl getPolicyConfigForContext(String JavaDoc contextId) {
276     PolicyConfigurationImpl pci = null;
277     if (contextId != null) {
278         pci = PolicyConfigurationFactoryImpl.getPolicyConfigurationImpl(contextId);
279     }
280     return pci;
281     }
282
283     private Policy getPolicy(PolicyConfigurationImpl pci) {
284     Policy result = null;
285     if (pci == null) {
286         result = policy;
287     } else {
288         result = pci.getPolicy();
289         if (result == null) {
290         // the pc is not in service so use the default context
291
result = policy;
292         }
293     }
294     return result;
295     }
296
297     private static Permissions getExcludedPolicy(PolicyConfigurationImpl pci) {
298     Permissions result = null;
299     if (pci != null) {
300         result = pci.getExcludedPolicy();
301     }
302     return result;
303     }
304
305     // should find a way to do this that preserves the argument PermissionCollection
306
// safe for now, becauuse on EJBMethodPermission, WebResourcePermission, and
307
// WebUserDatePermissions are excluded, and none of these classes implement a
308
// custom collection.
309
private static PermissionCollection removeExcludedPermissions
310     (PolicyConfigurationImpl pci, PermissionCollection perms) {
311     PermissionCollection result = perms;
312     boolean noneRemoved = true;
313     Permissions excluded = getExcludedPolicy(pci);
314     if (excluded != null && excluded.elements().hasMoreElements()) {
315         result = null;
316         Enumeration JavaDoc e = perms.elements();
317         while (e.hasMoreElements()) {
318         Permission JavaDoc granted = (Permission JavaDoc) e.nextElement();
319         if (!grantedIsExcluded(granted,excluded)) {
320             if (result == null) result = new Permissions();
321             result.add(granted);
322         } else {
323             noneRemoved = false;
324         }
325         }
326         if (noneRemoved) {
327         result = perms;
328         }
329     }
330     return result;
331     }
332
333     private static boolean grantedIsExcluded(Permission JavaDoc granted, Permissions excluded) {
334     boolean isExcluded = false;
335     if (excluded != null) {
336         if (!excluded.implies(granted)) {
337         Enumeration JavaDoc e = excluded.elements();
338         while (!isExcluded && e.hasMoreElements()) {
339             Permission JavaDoc excludedPerm = (Permission JavaDoc) e.nextElement();
340             if (granted.implies(excludedPerm)) {
341             isExcluded = true;
342             }
343         }
344         } else {
345         isExcluded = true;
346         }
347     }
348     if (logger.isLoggable(Level.FINEST)){
349         if (isExcluded) {
350         logger.finest("JACC Policy Provider: permission is excluded: "+granted);
351         }
352     }
353     return isExcluded;
354     }
355     
356     private boolean doImplies(ProtectionDomain domain, Permission JavaDoc permission) {
357     String JavaDoc contextId = PolicyContext.getContextID();
358     PolicyConfigurationImpl pci = getPolicyConfigForContext(contextId);
359     Policy appPolicy = getPolicy(pci);
360         
361     boolean result = appPolicy.implies(domain,permission);
362         
363         //log failures but skip failures that occurred prior to redirecting to
364
//login pages, and javax.management.MBeanPermission
365
if (!result) {
366             if(!(permission instanceof WebResourcePermission) &&
367                !(permission instanceof MBeanPermission JavaDoc)) {
368                 final String JavaDoc contextId2 = contextId;
369                 final Permission JavaDoc permission2 = permission;
370                 final ProtectionDomain domain2 = domain;
371                 AccessController.doPrivileged(new PrivilegedAction() {
372                     public Object JavaDoc run() {
373                         logger.info("JACC Policy Provider: PolicyWrapper.implies, context("
374                                 + contextId2
375                                 + ")- permission(" + permission2
376                                 + ") domain that failed(" +domain2 + ")");
377                         return null;
378                     }
379                 });
380             }
381         } else {
382         Permissions excluded = getExcludedPolicy(pci);
383         if (excluded != null) {
384         result = !grantedIsExcluded(permission,excluded);
385         }
386     }
387
388     // at FINEST: log only denies
389
if (!result && logger.isLoggable(Level.FINEST)){
390         logger.finest("JACC Policy Provider: PolicyWrapper.implies, context ("+
391             contextId+")- result was("+result+") permission ("
392             +permission+")");
393     }
394        
395         return result;
396     }
397
398     /**
399      * This method repeats the policy file loading algorithm of
400      * sun.security.provider.Policyfile to determine if the refresh
401      * resulted in a change to the loaded policy.
402      *
403      * Note:
404      * For backward compatibility with JAAS 1.0 it loads
405      * both java.auth.policy and java.policy. However it
406      * is recommended that java.auth.policy be not used
407      * and the java.policy contain all grant entries including
408      * that contain principal-based entries.
409      *
410      *
411      * <p> This object stores the policy for entire Java runtime,
412      * and is the amalgamation of multiple static policy
413      * configurations that resides in files.
414      * The algorithm for locating the policy file(s) and reading their
415      * information into this <code>Policy</code> object is:
416      *
417      * <ol>
418      * <li>
419      * Loop through the <code>java.security.Security</code> properties,
420      * <i>policy.url.1</i>, <i>policy.url.2</i>, ...,
421      * <i>policy.url.X</i>" and
422      * <i>auth.policy.url.1</i>, <i>auth.policy.url.2</i>, ...,
423      * <i>auth.policy.url.X</i>". These properties are set
424      * in the Java security properties file, which is located in the file named
425      * &lt;JAVA_HOME&gt;/lib/security/java.security, where &lt;JAVA_HOME&gt;
426      * refers to the directory where the JDK was installed.
427      * Each property value specifies a <code>URL</code> pointing to a
428      * policy file to be loaded. Read in and load each policy.
429      *
430      * <i>auth.policy.url</i> is supported only for backward compatibility.
431      *
432      * <li>
433      * The <code>java.lang.System</code> property <i>java.security.policy</i>
434      * may also be set to a <code>URL</code> pointing to another policy file
435      * (which is the case when a user uses the -D switch at runtime).
436      * If this property is defined, and its use is allowed by the
437      * security property file (the Security property,
438      * <i>policy.allowSystemProperty</i> is set to <i>true</i>),
439      * also load that policy.
440      *
441      * <li>
442      * The <code>java.lang.System</code> property
443      * <i>java.security.auth.policy</i> may also be set to a
444      * <code>URL</code> pointing to another policy file
445      * (which is the case when a user uses the -D switch at runtime).
446      * If this property is defined, and its use is allowed by the
447      * security property file (the Security property,
448      * <i>policy.allowSystemProperty</i> is set to <i>true</i>),
449      * also load that policy.
450      *
451      * <i>java.security.auth.policy</i> is supported only for backward
452      * compatibility.
453      *
454      * If the <i>java.security.policy</i> or
455      * <i>java.security.auth.policy</i> property is defined using
456      * "==" (rather than "="), then ignore all other specified
457      * policies and only load this policy.
458      * </ol>
459      */

460     private static final String JavaDoc POLICY = "java.security.policy";
461     private static final String JavaDoc POLICY_URL = "policy.url.";
462     private static final String JavaDoc AUTH_POLICY = "java.security.auth.policy";
463     private static final String JavaDoc AUTH_POLICY_URL = "auth.policy.url.";
464
465     /**
466      * Name of the system property that effects whether or not application
467      * policy objects are forced to refresh whenever the default context
468      * policy object is refreshed. Normally app policy objects only refresh
469      * when their app sepcifc policy files have changes. Since app policy
470      * objects alos include the rules of the default context; so they should
471      * be refreshed whenever the default context files are changed, but the
472      * algorithm by which a policy module finds its policy files is complex;
473      * and dependent on configuration; so this force switch is provided to
474      * ensure refresh of the app contexts (when the performace cost of doing
475      * so is acceptable). When this switch is not set, it may be necessary
476      * to restart the appserver to force changes in the various policy files to
477      * be in effect for specific applications.
478      */

479     private static final String JavaDoc FORCE_APP_REFRESH_PROP_NAME =
480         "com.sun.enterprise.security.provider.PolicyWrapper.force_app_refresh";
481
482     /**
483      * Flag to indicate if application specific policy objects are forced
484      * to refresh (independent of whether or not their app specific policy
485      * files have changed).
486      */

487     private static final boolean forceAppRefresh =
488             Boolean.getBoolean(FORCE_APP_REFRESH_PROP_NAME);
489     
490     private long refreshTime;
491
492     private synchronized boolean defaultContextChanged() {
493
494     if (forceAppRefresh) {
495         return true;
496     }
497
498     long newTime = getTimeStamp(POLICY,POLICY_URL);
499     newTime += getTimeStamp(AUTH_POLICY,AUTH_POLICY_URL);
500     boolean rvalue = refreshTime != newTime;
501     refreshTime = newTime;
502     return rvalue;
503     }
504
505     private static long
506     getTimeStamp(final String JavaDoc propname, final String JavaDoc urlname) {
507     Long JavaDoc l = (Long JavaDoc) AccessController.doPrivileged(new PrivilegedAction() {
508         public Long JavaDoc run() {
509         long sum = 0L;
510         boolean allowSystemProperties = "true".equalsIgnoreCase
511             (Security.getProperty("policy.allowSystemProperty"));
512         if (allowSystemProperties) {
513             String JavaDoc extra_policy = System.getProperty(propname);
514             if (extra_policy != null) {
515             boolean overrideAll = false;
516             if (extra_policy.startsWith("=")) {
517                 overrideAll = true;
518                 extra_policy = extra_policy.substring(1);
519             }
520             try {
521                 String JavaDoc path =PropertyExpander.expand(extra_policy);
522                 File policyFile = new File(path);
523                 boolean found = policyFile.exists();
524                 if (!found) {
525                 URL JavaDoc policy_url = new URL JavaDoc(path);
526                 if ("file".equals(policy_url.getProtocol())) {
527                     path = policy_url.getFile().
528                     replace('/', File.separatorChar);
529                     path = sun.net.www.ParseUtil.decode(path);
530                     policyFile = new File(path);
531                     found = policyFile.exists();
532                 }
533                 }
534                 if (found) {
535                 sum += policyFile.lastModified();
536                 if (logger.isLoggable(Level.FINE)) {
537                     logMsg(Level.FINE,"pc.file_refreshed",
538                      new Object JavaDoc[]{path},null);
539                 }
540                 } else {
541                 if (logger.isLoggable(Level.FINE)) {
542                     logMsg(Level.FINE,"pc.file_not_refreshed",
543                        new Object JavaDoc[]{path},null);
544                 }
545                 }
546             } catch (Exception JavaDoc e) {
547                 // ignore.
548
}
549             if (overrideAll) {
550                 return new Long JavaDoc(sum);
551             }
552             }
553         }
554         int n = 1;
555         String JavaDoc policy_uri;
556         while ((policy_uri = Security.getProperty(urlname+n)) != null){
557             try {
558             URL JavaDoc policy_url = null;
559             String JavaDoc expanded_uri = PropertyExpander.expand
560                 (policy_uri).replace(File.separatorChar, '/');
561             if (policy_uri.startsWith("file:${java.home}/") ||
562                 policy_uri.startsWith("file:${user.home}/")) {
563                 // this special case accommodates
564
// the situation java.home/user.home
565
// expand to a single slash, resulting in
566
// a file://foo URI
567
policy_url = new File
568                 (expanded_uri.substring(5)).toURI().toURL();
569             } else {
570                 policy_url = new URI JavaDoc(expanded_uri).toURL();
571             }
572             if ("file".equals(policy_url.getProtocol())) {
573                 String JavaDoc path = policy_url.getFile().
574                 replace('/', File.separatorChar);
575                 path = sun.net.www.ParseUtil.decode(path);
576                 File policyFile = new File(path);
577                 if (policyFile.exists()) {
578                 sum += policyFile.lastModified();
579                 if (logger.isLoggable(Level.FINE)) {
580                     logMsg(Level.FINE,"pc.file_refreshed",
581                        new Object JavaDoc[]{path},null);
582                 }
583                 } else {
584                 if (logger.isLoggable(Level.FINE)) {
585                     logMsg(Level.FINE,"pc.file_not_refreshed",
586                        new Object JavaDoc[]{path},null);
587                 }
588                 }
589             } else {
590                 if (logger.isLoggable(Level.FINE)) {
591                 logMsg(Level.FINE,"pc.file_not_refreshed",
592                        new Object JavaDoc[]{policy_url},null);
593                 }
594             }
595             } catch (Exception JavaDoc e) {
596             // ignore that policy
597
}
598             n++;
599         }
600         return new Long JavaDoc(sum);
601         }
602     });
603     return l.longValue();
604     }
605 }
606
Popular Tags