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><JAVA_HOME>/lib/security/java.security 82 * </code>, where <code><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