001    /* AccessControlContext.java --- Access Control Context Class
002       Copyright (C) 1999, 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.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     */
056    public 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    }