001 /* Policy.java --- Policy Manager Class
002 Copyright (C) 1999, 2003, 2004 Free Software Foundation, Inc.
003
004 This file is part of GNU Classpath.
005
006 GNU Classpath is free software; you can redistribute it and/or modify
007 it under the terms of the GNU General Public License as published by
008 the Free Software Foundation; either version 2, or (at your option)
009 any later version.
010
011 GNU Classpath is distributed in the hope that it will be useful, but
012 WITHOUT ANY WARRANTY; without even the implied warranty of
013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014 General Public License for more details.
015
016 You should have received a copy of the GNU General Public License
017 along with GNU Classpath; see the file COPYING. If not, write to the
018 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
019 02110-1301 USA.
020
021 Linking this library statically or dynamically with other modules is
022 making a combined work based on this library. Thus, the terms and
023 conditions of the GNU General Public License cover the whole
024 combination.
025
026 As a special exception, the copyright holders of this library give you
027 permission to link this library with independent modules to produce an
028 executable, regardless of the license terms of these independent
029 modules, and to copy and distribute the resulting executable under
030 terms of your choice, provided that you also meet, for each linked
031 independent module, the terms and conditions of the license of that
032 module. An independent module is a module which is not derived from
033 or based on this library. If you modify this library, you may extend
034 this exception to your version of the library, but you are not
035 obligated to do so. If you do not wish to do so, delete this
036 exception statement from your version. */
037
038 package java.security;
039
040 import java.util.Collections;
041 import java.util.Enumeration;
042 import java.util.LinkedHashMap;
043 import java.util.Map;
044
045 /**
046 * <code>Policy</code> is an abstract class for managing the system security
047 * policy for the Java application environment. It specifies which permissions
048 * are available for code from various sources. The security policy is
049 * represented through a subclass of <code>Policy</code>.
050 *
051 * <p>Only one <code>Policy</code> is in effect at any time. A
052 * {@link ProtectionDomain} initializes itself with information from this class
053 * on the set of permssions to grant.</p>
054 *
055 * <p>The location for the actual <code>Policy</code> could be anywhere in any
056 * form because it depends on the Policy implementation. The default system is
057 * in a flat ASCII file or it could be in a database.</p>
058 *
059 * <p>The current installed <code>Policy</code> can be accessed with
060 * {@link #getPolicy()} and changed with {@link #setPolicy(Policy)} if the code
061 * has the correct permissions.</p>
062 *
063 * <p>The {@link #refresh()} method causes the <code>Policy</code> instance to
064 * refresh/reload its configuration. The method used to refresh depends on the
065 * <code>Policy</code> implementation.</p>
066 *
067 * <p>When a protection domain initializes its permissions, it uses code like
068 * the following:</p>
069 *
070 * <code>
071 * policy = Policy.getPolicy();
072 * PermissionCollection perms = policy.getPermissions(myCodeSource);
073 * </code>
074 *
075 * <p>The protection domain passes the <code>Policy</code> handler a
076 * {@link CodeSource} instance which contains the codebase URL and a public key.
077 * The <code>Policy</code> implementation then returns the proper set of
078 * permissions for that {@link CodeSource}.</p>
079 *
080 * <p>The default <code>Policy</code> implementation can be changed by setting
081 * the "policy.provider" security provider in the "java.security" file to the
082 * correct <code>Policy</code> implementation class.</p>
083 *
084 * @author Mark Benvenuto
085 * @see CodeSource
086 * @see PermissionCollection
087 * @see SecureClassLoader
088 * @since 1.2
089 */
090 public abstract class Policy
091 {
092 private static Policy currentPolicy;
093
094 /** Map of ProtectionDomains to PermissionCollections for this instance. */
095 private Map pd2pc = null;
096
097 /** Constructs a new <code>Policy</code> object. */
098 public Policy()
099 {
100 }
101
102 /**
103 * Returns the currently installed <code>Policy</code> handler. The value
104 * should not be cached as it can be changed any time by
105 * {@link #setPolicy(Policy)}.
106 *
107 * @return the current <code>Policy</code>.
108 * @throws SecurityException
109 * if a {@link SecurityManager} is installed which disallows this
110 * operation.
111 */
112 public static Policy getPolicy()
113 {
114 SecurityManager sm = System.getSecurityManager();
115 if (sm != null)
116 sm.checkPermission(new SecurityPermission("getPolicy"));
117
118 return getCurrentPolicy();
119 }
120
121 /**
122 * Sets the <code>Policy</code> handler to a new value.
123 *
124 * @param policy
125 * the new <code>Policy</code> to use.
126 * @throws SecurityException
127 * if a {@link SecurityManager} is installed which disallows this
128 * operation.
129 */
130 public static void setPolicy(Policy policy)
131 {
132 SecurityManager sm = System.getSecurityManager();
133 if (sm != null)
134 sm.checkPermission(new SecurityPermission("setPolicy"));
135
136 setup(policy);
137 currentPolicy = policy;
138 }
139
140 private static void setup(final Policy policy)
141 {
142 if (policy.pd2pc == null)
143 policy.pd2pc = Collections.synchronizedMap(new LinkedHashMap());
144
145 ProtectionDomain pd = policy.getClass().getProtectionDomain();
146 if (pd.getCodeSource() != null)
147 {
148 PermissionCollection pc = null;
149 if (currentPolicy != null)
150 pc = currentPolicy.getPermissions(pd);
151
152 if (pc == null) // assume it has all
153 {
154 pc = new Permissions();
155 pc.add(new AllPermission());
156 }
157
158 policy.pd2pc.put(pd, pc); // add the mapping pd -> pc
159 }
160 }
161
162 /**
163 * Ensures/forces loading of the configured policy provider, while bypassing
164 * the {@link SecurityManager} checks for <code>"getPolicy"</code> security
165 * permission. Needed by {@link ProtectionDomain}.
166 */
167 static Policy getCurrentPolicy()
168 {
169 // FIXME: The class name of the Policy provider should really be sourced
170 // from the "java.security" configuration file. For now, just hard-code
171 // a stub implementation.
172 if (currentPolicy == null)
173 {
174 String pp = System.getProperty ("policy.provider");
175 if (pp != null)
176 try
177 {
178 currentPolicy = (Policy) Class.forName(pp).newInstance();
179 }
180 catch (Exception e)
181 {
182 // Ignored.
183 }
184
185 if (currentPolicy == null)
186 currentPolicy = new gnu.java.security.provider.DefaultPolicy();
187 }
188 return currentPolicy;
189 }
190
191 /**
192 * Tests if <code>currentPolicy</code> is not <code>null</code>,
193 * thus allowing clients to not force loading of any policy
194 * provider; needed by {@link ProtectionDomain}.
195 */
196 static boolean isLoaded()
197 {
198 return currentPolicy != null;
199 }
200
201 /**
202 * Returns the set of Permissions allowed for a given {@link CodeSource}.
203 *
204 * @param codesource
205 * the {@link CodeSource} for which, the caller needs to find the
206 * set of granted permissions.
207 * @return a set of permissions for {@link CodeSource} specified by the
208 * current <code>Policy</code>.
209 * @throws SecurityException
210 * if a {@link SecurityManager} is installed which disallows this
211 * operation.
212 */
213 public abstract PermissionCollection getPermissions(CodeSource codesource);
214
215 /**
216 * Returns the set of Permissions allowed for a given {@link ProtectionDomain}.
217 *
218 * @param domain
219 * the {@link ProtectionDomain} for which, the caller needs to find
220 * the set of granted permissions.
221 * @return a set of permissions for {@link ProtectionDomain} specified by the
222 * current <code>Policy.</code>.
223 * @since 1.4
224 * @see ProtectionDomain
225 * @see SecureClassLoader
226 */
227 public PermissionCollection getPermissions(ProtectionDomain domain)
228 {
229 if (domain == null)
230 return new Permissions();
231
232 if (pd2pc == null)
233 setup(this);
234
235 PermissionCollection result = (PermissionCollection) pd2pc.get(domain);
236 if (result != null)
237 {
238 Permissions realResult = new Permissions();
239 for (Enumeration e = result.elements(); e.hasMoreElements(); )
240 realResult.add((Permission) e.nextElement());
241
242 return realResult;
243 }
244
245 result = getPermissions(domain.getCodeSource());
246 if (result == null)
247 result = new Permissions();
248
249 PermissionCollection pc = domain.getPermissions();
250 if (pc != null)
251 for (Enumeration e = pc.elements(); e.hasMoreElements(); )
252 result.add((Permission) e.nextElement());
253
254 return result;
255 }
256
257 /**
258 * Checks if the designated {@link Permission} is granted to a designated
259 * {@link ProtectionDomain}.
260 *
261 * @param domain
262 * the {@link ProtectionDomain} to test.
263 * @param permission
264 * the {@link Permission} to check.
265 * @return <code>true</code> if <code>permission</code> is implied by a
266 * permission granted to this {@link ProtectionDomain}. Returns
267 * <code>false</code> otherwise.
268 * @since 1.4
269 * @see ProtectionDomain
270 */
271 public boolean implies(ProtectionDomain domain, Permission permission)
272 {
273 if (pd2pc == null)
274 setup(this);
275
276 PermissionCollection pc = (PermissionCollection) pd2pc.get(domain);
277 if (pc != null)
278 return pc.implies(permission);
279
280 boolean result = false;
281 pc = getPermissions(domain);
282 if (pc != null)
283 {
284 result = pc.implies(permission);
285 pd2pc.put(domain, pc);
286 }
287
288 return result;
289 }
290
291 /**
292 * Causes this <code>Policy</code> instance to refresh / reload its
293 * configuration. The method used to refresh depends on the concrete
294 * implementation.
295 */
296 public abstract void refresh();
297 }