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    }