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 }