1 /* Policy.java --- Policy Manager Class
2    Copyright (C) 1999, 2003, Free Software Foundation, Inc.
3 
4 This file is part of GNU Classpath.
5 
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10 
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 General Public License for more details.
15 
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING.  If not, write to the
18 Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19 02111-1307 USA.
20 
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library.  Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
25 
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module.  An independent module is a module which is not derived from
33 or based on this library.  If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so.  If you do not wish to do so, delete this
36 exception statement from your version. */
37 
38 package java.security;
39 
40 import java.util.Collections;
41 import java.util.Enumeration;
42 import java.util.LinkedHashMap;
43 import java.util.Map;
44 
45 /**
46  * <p>This is an abstract class for representing the system security policy for
47  * a Java application environment (specifying which permissions are available
48  * for code from various sources). That is, the security policy is represented
49  * by a <code>Policy</code> subclass providing an implementation of the abstract
50  * methods in this <code>Policy</code> class.</p>
51  *
52  * <p>There is only one <code>Policy</code> object in effect at any given time.
53  * </p>
54  *
55  * <p>The source location for the policy information utilized by the
56  * <code>Policy</code> object is up to the <code>Policy</code> implementation.
57  * The policy configuration may be stored, for example, as a flat ASCII file, as
58  * a serialized binary file of the <code>Policy</code> class, or as a database.
59  * </p>
60  *
61  * <p>The currently-installed <code>Policy</code> object can be obtained by
62  * calling the <code>getPolicy()</code> method, and it can be changed by a call
63  * to the <code>setPolicy()</code> method (by code with permission to reset the
64  * <code>Policy</code>).</p>
65  *
66  * <p>The <code>refresh()</code> method causes the policy object to refresh /
67  * reload its current configuration.</p>
68  *
69  * <p>This is implementation-dependent. For example, if the policy object stores
70  * its policy in configuration files, calling <code>refresh()</code> will cause
71  * it to re-read the configuration policy files. The refreshed policy may not
72  * have an effect on classes in a particular {@link ProtectionDomain}. This is
73  * dependent on the <code>Policy</code> provider's implementation of the
74  * <code>implies()</code> method and the {@link PermissionCollection} caching
75  * strategy.</p>
76  *
77  * <p>The default <code>Policy</code> implementation can be changed by setting
78  * the value of the <code>"policy.provider"</code> security property (in the
79  * Java security properties file) to the fully qualified name of the desired
80  * <code>Policy</code> implementation class. The Java security properties file
81  * is located in the file named <code>&lt;JAVA_HOME>/lib/security/java.security
82  * </code>, where <code>&lt;JAVA_HOME></code> refers to the directory where the
83  * SDK was installed.</p>
84  *
85  * <p><b>IMPLEMENTATION NOTE:</b> This implementation attempts to read the
86  * System property named <code>policy.provider</code> to find the concrete
87  * implementation of the <code>Policy</code>. If/when this fails, it falls back
88  * to a default implementation, which <b>allows everything</b>.
89  *
90  * @author Mark Benvenuto
91  * @see CodeSource
92  * @see PermissionCollection
93  * @see SecureClassLoader
94  * @since 1.2
95  */
96 public abstract class Policy
97 {
98   static private Policy currentPolicy = null;
99 
100   /** Map of ProtectionDomains to PermissionCollections for this instance. */
101   private Map pd2pc = null;
102 
103   /** Constructs a new <code>Policy</code> object. */
Policy()104   public Policy()
105   {
106   }
107 
108   /**
109    * Returns the installed <code>Policy</code> object. This value should not be
110    * cached, as it may be changed by a call to <code>setPolicy()</code>. This
111    * method first calls {@link SecurityManager#checkPermission(Permission)} with
112    * a <code>SecurityPermission("getPolicy")</code> permission to ensure it's ok
113    * to get the <code>Policy</code> object.
114    *
115    * @return the installed <code>Policy</code>.
116    * @throws SecurityException if a security manager exists and its
117    * <code>checkPermission()</code> method doesn't allow getting the
118    * <code>Policy</code> object.
119    * @see SecurityManager#checkPermission(Permission)
120    * @see #setPolicy(Policy)
121    */
getPolicy()122   public static Policy getPolicy()
123   {
124     SecurityManager sm = System.getSecurityManager();
125     if (sm != null)
126       sm.checkPermission(new SecurityPermission("getPolicy"));
127 
128     return getCurrentPolicy();
129   }
130 
131   /**
132    * Sets the system-wide <code>Policy</code> object. This method first calls
133    * {@link SecurityManager#checkPermission(Permission)} with a
134    * <code>SecurityPermission("setPolicy")</code> permission to ensure it's ok
135    * to set the <code>Policy</code>.
136    *
137    * @param policy the new system <code>Policy</code> object.
138    * @throws SecurityException if a security manager exists and its
139    * <code>checkPermission()</code> method doesn't allow setting the
140    * <code>Policy</code>.
141    * @see SecurityManager#checkPermission(Permission)
142    * @see #getPolicy()
143    */
setPolicy(Policy policy)144   public static void setPolicy(Policy policy)
145   {
146     SecurityManager sm = System.getSecurityManager();
147     if (sm != null)
148       sm.checkPermission(new SecurityPermission("setPolicy"));
149 
150     setup(policy);
151     currentPolicy = policy;
152   }
153 
setup(final Policy policy)154   private static void setup(final Policy policy)
155   {
156     if (policy.pd2pc == null)
157       policy.pd2pc = Collections.synchronizedMap(new LinkedHashMap());
158 
159     ProtectionDomain pd = policy.getClass().getProtectionDomain();
160     if (pd.getCodeSource() != null)
161       {
162         PermissionCollection pc = null;
163         if (currentPolicy != null)
164           pc = currentPolicy.getPermissions(pd);
165 
166         if (pc == null) // assume it has all
167           {
168             pc = new Permissions();
169             pc.add(new AllPermission());
170           }
171 
172         policy.pd2pc.put(pd, pc); // add the mapping pd -> pc
173       }
174   }
175 
176   /**
177    * Ensures/forces loading of the configured policy provider, while bypassing
178    * the {@link SecurityManager} checks for <code>"getPolicy"</code> security
179    * permission.  Needed by {@link ProtectionDomain}.
180    */
getCurrentPolicy()181   static Policy getCurrentPolicy()
182   {
183     // FIXME: The class name of the Policy provider should really be sourced
184     // from the "java.security" configuration file. For now, just hard-code
185     // a stub implementation.
186     if (currentPolicy == null)
187       {
188         String pp = System.getProperty ("policy.provider");
189         if (pp != null)
190           try
191             {
192               currentPolicy = (Policy) Class.forName(pp).newInstance();
193             }
194           catch (Exception ignored) {}
195 
196         if (currentPolicy == null)
197           currentPolicy = new gnu.java.security.provider.DefaultPolicy();
198       }
199     return currentPolicy;
200   }
201 
202   /**
203    * Tests if <code>currentPolicy</code> is not <code>null</code>,
204    * thus allowing clients to not force loading of any policy
205    * provider; needed by {@link ProtectionDomain}.
206    */
isLoaded()207   static boolean isLoaded()
208   {
209     return currentPolicy != null;
210   }
211 
212   /**
213    * Evaluates the global policy and returns a {@link PermissionCollection}
214    * object specifying the set of permissions allowed for code from the
215    * specified code source.
216    *
217    * @param codesource the {@link CodeSource} associated with the caller. This
218    * encapsulates the original location of the code (where the code came from)
219    * and the public key(s) of its signer.
220    * @return the set of permissions allowed for code from codesource according
221    * to the policy. The returned set of permissions must be a new mutable
222    * instance and it must support heterogeneous {@link Permission} types.
223    */
getPermissions(CodeSource codesource)224   public abstract PermissionCollection getPermissions(CodeSource codesource);
225 
226   /**
227    * Evaluates the global policy and returns a {@link PermissionCollection}
228    * object specifying the set of permissions allowed given the characteristics
229    * of the protection domain.
230    *
231    * @param domain the {@link ProtectionDomain} associated with the caller.
232    * @return the set of permissions allowed for the domain according to the
233    * policy. The returned set of permissions must be a new mutable instance and
234    * it must support heterogeneous {@link Permission} types.
235    * @since 1.4
236    * @see ProtectionDomain
237    * @see SecureClassLoader
238    */
getPermissions(ProtectionDomain domain)239   public PermissionCollection getPermissions(ProtectionDomain domain)
240   {
241     if (domain == null)
242       return new Permissions();
243 
244     if (pd2pc == null)
245       setup(this);
246 
247     PermissionCollection result = (PermissionCollection) pd2pc.get(domain);
248     if (result != null)
249       {
250         Permissions realResult = new Permissions();
251         for (Enumeration e = result.elements(); e.hasMoreElements(); )
252           realResult.add((Permission) e.nextElement());
253 
254         return realResult;
255       }
256 
257     result = getPermissions(domain.getCodeSource());
258     if (result == null)
259       result = new Permissions();
260 
261     PermissionCollection pc = domain.getPermissions();
262     if (pc != null)
263       for (Enumeration e = pc.elements(); e.hasMoreElements(); )
264         result.add((Permission) e.nextElement());
265 
266     return result;
267   }
268 
269   /**
270    * Evaluates the global policy for the permissions granted to the {@link
271    * ProtectionDomain} and tests whether the <code>permission</code> is granted.
272    *
273    * @param domain the {@link ProtectionDomain} to test.
274    * @param permission the {@link Permission} object to be tested for
275    * implication.
276    * @return <code>true</code> if <code>permission</code> is a proper subset of
277    * a permission granted to this {@link ProtectionDomain}.
278    * @since 1.4
279    * @see ProtectionDomain
280    */
implies(ProtectionDomain domain, Permission permission)281   public boolean implies(ProtectionDomain domain, Permission permission)
282   {
283     if (pd2pc == null)
284       setup(this);
285 
286     PermissionCollection pc = (PermissionCollection) pd2pc.get(domain);
287     if (pc != null)
288       return pc.implies(permission);
289 
290     boolean result = false;
291     pc = getPermissions(domain);
292     if (pc != null)
293       {
294         result = pc.implies(permission);
295         pd2pc.put(domain, pc);
296       }
297 
298     return result;
299   }
300 
301   /**
302    * Refreshes/reloads the policy configuration. The behavior of this method
303    * depends on the implementation. For example, calling refresh on a file-based
304    * policy will cause the file to be re-read.
305    */
refresh()306   public abstract void refresh();
307 }
308