001/* AccessControlContext.java --- Access Control Context Class
002   Copyright (C) 1999, 2004 Free Software Foundation, Inc.
003
004This file is part of GNU Classpath.
005
006GNU Classpath is free software; you can redistribute it and/or modify
007it under the terms of the GNU General Public License as published by
008the Free Software Foundation; either version 2, or (at your option)
009any later version.
010
011GNU Classpath is distributed in the hope that it will be useful, but
012WITHOUT ANY WARRANTY; without even the implied warranty of
013MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014General Public License for more details.
015
016You should have received a copy of the GNU General Public License
017along with GNU Classpath; see the file COPYING.  If not, write to the
018Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
01902110-1301 USA.
020
021Linking this library statically or dynamically with other modules is
022making a combined work based on this library.  Thus, the terms and
023conditions of the GNU General Public License cover the whole
024combination.
025
026As a special exception, the copyright holders of this library give you
027permission to link this library with independent modules to produce an
028executable, regardless of the license terms of these independent
029modules, and to copy and distribute the resulting executable under
030terms of your choice, provided that you also meet, for each linked
031independent module, the terms and conditions of the license of that
032module.  An independent module is a module which is not derived from
033or based on this library.  If you modify this library, you may extend
034this exception to your version of the library, but you are not
035obligated to do so.  If you do not wish to do so, delete this
036exception statement from your version. */
037
038package java.security;
039
040import java.util.HashSet;
041
042/**
043 * AccessControlContext makes system resource access decsion 
044 * based on permission rights.  
045 *
046 * It is used for a specific context and has only one method
047 * checkPermission. It is similar to AccessController except
048 * that it makes decsions based on the current context instead
049 * of the the current thread.
050 *
051 * It is created by call AccessController.getContext method.
052 *
053 * @author Mark Benvenuto
054 * @since 1.2
055 */
056public final class AccessControlContext
057{
058  private final ProtectionDomain[] protectionDomains;
059  private final DomainCombiner combiner;
060
061  /**
062   * Construct a new AccessControlContext with the specified
063   * ProtectionDomains. <code>context</code> must not be 
064   * null and duplicates will be removed.
065   *
066   * @param context The ProtectionDomains to use
067   */
068  public AccessControlContext(ProtectionDomain[] context)
069  {
070    HashSet domains = new HashSet (context.length);
071    for (int i = 0; i < context.length; i++)
072      domains.add (context[i]);
073    protectionDomains = (ProtectionDomain[])
074      domains.toArray (new ProtectionDomain[domains.size()]);
075    combiner = null;
076  }
077
078  /**
079   * Construct a new AccessControlContext with the specified
080   * {@link ProtectionDomain}s and {@link DomainCombiner}.
081   *
082   * <p>Code calling this constructor must have a {@link
083   * SecurityPermission} of <i>createAccessControlContext</i>.</p>
084   *
085   * @throws SecurityException If the caller does not have permission
086   * to create an access control context.
087   * @since 1.3
088   */
089  public AccessControlContext(AccessControlContext acc,
090                              DomainCombiner combiner)
091  {
092    AccessControlContext acc2 = null;
093    SecurityManager sm = System.getSecurityManager ();
094    if (sm != null)
095      {
096        Permission perm =
097          new SecurityPermission ("createAccessControlContext");
098
099        // The default SecurityManager.checkPermission(perm) just calls 
100        // AccessController.checkPermission(perm) which in turn just
101        // calls AccessController.getContext().checkPermission(perm).
102        // This means AccessController.getContext() is called twice,
103        // once for the security check and once by us.  It's a very
104        // expensive call (on gcj at least) so if we're using the
105        // default security manager we avoid this duplication.
106        if (sm.getClass() == SecurityManager.class)
107          {
108            acc2 = AccessController.getContext ();
109            acc2.checkPermission (perm);
110          }
111        else
112          sm.checkPermission (perm);
113      }
114    if (acc2 == null)
115      acc2 = AccessController.getContext ();
116    protectionDomains = combiner.combine (acc2.protectionDomains,
117                                          acc.protectionDomains);
118    this.combiner = combiner;
119  }
120
121  AccessControlContext (ProtectionDomain[] domains, AccessControlContext acc,
122                        DomainCombiner combiner)
123  {
124    protectionDomains = combiner.combine (domains, acc.protectionDomains);
125    this.combiner = combiner;
126  }
127
128  /**
129   * Returns the Domain Combiner associated with the AccessControlContext
130   *
131   * @return the DomainCombiner
132   */
133  public DomainCombiner getDomainCombiner()
134  {
135    return combiner;
136  }
137
138  /**
139   * Determines whether or not the specific permission is granted
140   * depending on the context it is within. 
141   *
142   * @param perm a permission to check
143   *
144   * @throws AccessControlException if the permssion is not permitted
145   */
146  public void checkPermission(Permission perm) throws AccessControlException
147  {
148    if (protectionDomains.length == 0)
149      throw new AccessControlException ("permission " 
150                                        + perm 
151                                        + " not granted: no protection domains");
152
153    for (int i = 0; i < protectionDomains.length; i++)
154      {
155        final ProtectionDomain domain = protectionDomains[i];
156        if (!domain.implies(perm))
157          throw new AccessControlException ("permission " 
158                                            + perm 
159                                            + " not granted: " 
160                                            + domain 
161                                            + " does not imply it.");
162      }
163  }
164
165  /**
166   * Checks if two AccessControlContexts are equal.
167   *
168   * It first checks if obj is an AccessControlContext class, and
169   * then checks if each ProtectionDomain matches.
170   *
171   * @param obj The object to compare this class to
172   *
173   * @return true if equal, false otherwise
174   */
175  public boolean equals(Object obj)
176  {
177    if (obj instanceof AccessControlContext)
178      {
179        AccessControlContext acc = (AccessControlContext) obj;
180
181        if (acc.protectionDomains.length != protectionDomains.length)
182          return false;
183
184        int i, j;
185        for (i = 0; i < protectionDomains.length; i++)
186          {
187            for (j = 0; j < acc.protectionDomains.length; j++)
188              {
189                if (acc.protectionDomains[j].equals (protectionDomains[i]))
190                  break;
191              }
192            if (j == acc.protectionDomains.length)
193              return false;
194          }
195        return true;
196      }
197    return false;
198  }
199
200  /**
201   * Computes a hash code of this class
202   *
203   * @return a hash code representing this class
204   */
205  public int hashCode()
206  {
207    int h = 0;
208    for (int i = 0; i < protectionDomains.length; i++)
209      h ^= protectionDomains[i].hashCode();
210
211    return h;
212  }
213
214  ProtectionDomain[] getProtectionDomains ()
215  {
216    return protectionDomains;
217  }
218}