001    /* PrivateCredentialPermission.java -- permissions governing private credentials.
002       Copyright (C) 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    
039    package javax.security.auth;
040    
041    import java.io.Serializable;
042    
043    import java.security.Permission;
044    import java.security.PermissionCollection;
045    
046    import java.util.HashSet;
047    import java.util.Iterator;
048    import java.util.Set;
049    import java.util.StringTokenizer;
050    
051    /**
052     * A permission governing access to a private credential. The action of this
053     * permission is always "read" -- meaning that the private credential
054     * information can be read from an object.
055     *
056     * <p>The target of this permission is formatted as follows:</p>
057     *
058     * <p><code>CredentialClassName ( PrinicpalClassName PrincipalName )*</code></p>
059     *
060     * <p><i>CredentialClassName</i> is either the name of a private credential
061     * class name, or a wildcard character (<code>'*'</code>).
062     * <i>PrinicpalClassName</i> is the class name of a principal object, and
063     * <i>PrincipalName</i> is a string representing the principal, or the
064     * wildcard character.</p>
065     */
066    public final class PrivateCredentialPermission extends Permission
067      implements Serializable
068    {
069      /**
070       * For compatability with Sun's JDK 1.4.2 rev. 5
071       */
072      private static final long serialVersionUID = 5284372143517237068L;
073    
074      // Fields.
075      // -------------------------------------------------------------------------
076    
077      /**
078       * @serial The credential class name.
079       */
080      private final String credentialClass;
081    
082      /**
083       * @serial The principals, a set of CredOwner objects (an undocumented
084       *  inner class of this class).
085       */
086      private final Set principals;
087    
088      /**
089       * @serial Who knows?
090       */
091      private final boolean testing;
092    
093      // Constructor.
094      // -------------------------------------------------------------------------
095    
096      /**
097       * Create a new private credential permission.
098       *
099       * @param name The permission target name.
100       * @param actions The list of actions, which, for this class, must be
101       *  <code>"read"</code>.
102       */
103      public PrivateCredentialPermission (final String name, String actions)
104      {
105        super(name);
106        actions = actions.trim().toLowerCase();
107        if (!"read".equals (actions))
108          {
109            throw new IllegalArgumentException("actions must be \"read\"");
110          }
111        StringTokenizer st = new StringTokenizer (name, " \"'");
112        principals = new HashSet();
113        if (st.countTokens() < 3 || (st.countTokens() & 1) == 0)
114          {
115            throw new IllegalArgumentException ("badly formed credential name");
116          }
117        credentialClass = st.nextToken();
118        while (st.hasMoreTokens())
119          {
120            principals.add (new CredOwner (st.nextToken(), st.nextToken()));
121          }
122        testing = false; // WTF ever.
123      }
124    
125      // Instance methods.
126      // -------------------------------------------------------------------------
127    
128      public boolean equals (Object o)
129      {
130        if (! (o instanceof PrivateCredentialPermission))
131          {
132            return false;
133          }
134        PrivateCredentialPermission that = (PrivateCredentialPermission) o;
135        if (!that.getActions().equals (getActions()))
136          {
137            return false;
138          }
139        if (!that.getCredentialClass().equals (getCredentialClass()))
140          {
141            return false;
142          }
143    
144        final String[][] principals = getPrincipals();
145        final String[][] that_principals = that.getPrincipals();
146        if (that_principals == null)
147          {
148            return false;
149          }
150        if (that_principals.length != principals.length)
151          {
152            return false;
153          }
154        for (int i = 0; i < principals.length; i++)
155          {
156            if (!principals[i][0].equals (that_principals[i][0]) ||
157                !principals[i][1].equals (that_principals[i][1]))
158              {
159                return false;
160              }
161          }
162        return true;
163      }
164    
165      /**
166       * Returns the actions this permission encompasses. For private credential
167       * permissions, this is always the string <code>"read"</code>.
168       *
169       * @return The list of actions.
170       */
171      public String getActions()
172      {
173        return "read";
174      }
175    
176      /**
177       * Returns the credential class name that was embedded in this permission's
178       * target name.
179       *
180       * @return The credential class name.
181       */
182      public String getCredentialClass()
183      {
184        return credentialClass;
185      }
186    
187      /**
188       * Returns the principal list that was embedded in this permission's target
189       * name.
190       *
191       * <p>Each element of the returned array is a pair; the first element is the
192       * principal class name, and the second is the principal name.
193       *
194       * @return The principal list.
195       */
196      public String[][] getPrincipals()
197      {
198        String[][] ret = new String[principals.size()][];
199        Iterator it = principals.iterator();
200        for (int i = 0; i < principals.size() && it.hasNext(); i++)
201          {
202            CredOwner co = (CredOwner) it.next();
203            ret[i] = new String[] { co.getPrincipalClass(), co.getPrincipalName() };
204          }
205        return ret;
206      }
207    
208      public int hashCode()
209      {
210        return credentialClass.hashCode() + principals.hashCode();
211      }
212    
213      /**
214       * Test if this permission implies another. This method returns true if:
215       *
216       * <ol>
217       * <li><i>p</i> is an instance of PrivateCredentialPermission</li>.
218       * <li>The credential class name of this instance matches that of <i>p</i>,
219       * and one of the principals of <i>p</i> is contained in the principals of
220       * this class. Thus,
221       *   <ul>
222       *   <li><code>[ * P "foo" ]  implies [ C P "foo" ]</code></li>
223       *   <li><code>[ C P1 "foo" ] implies [ C P1 "foo" P2 "bar" ]</code></li>
224       *   <li><code>[ C P1 "*" ]   implies [ C P1 "foo" ]</code></li>
225       *   </ul>
226       * </ol>
227       *
228       * @param p The permission to check.
229       * @return True if this permission implies <i>p</i>.
230       */
231      public boolean implies (Permission p)
232      {
233        if (! (p instanceof PrivateCredentialPermission))
234          {
235            return false;
236          }
237        PrivateCredentialPermission that = (PrivateCredentialPermission) p;
238        if (!credentialClass.equals ("*")
239            && !credentialClass.equals (that.getCredentialClass()))
240          {
241            return false;
242          }
243        String[][] principals = getPrincipals();
244        String[][] that_principals = that.getPrincipals();
245        if (that_principals == null)
246          {
247            return false;
248          }
249        for (int i = 0; i < principals.length; i++)
250          {
251            for (int j = 0; j < that_principals.length; j++)
252              {
253                if (principals[i][0].equals (that_principals[j][0]) &&
254                    (principals[i][1].equals ("*") ||
255                     principals[i][1].equals (that_principals[j][1])))
256                  {
257                    return true;
258                  }
259              }
260          }
261        return false;
262      }
263    
264      /**
265       * This method is not necessary for this class, thus it always returns null.
266       *
267       * @return null.
268       */
269      public PermissionCollection newPermissionCollection()
270      {
271        return null;
272      }
273    
274      // Inner class.
275      // -------------------------------------------------------------------------
276    
277      /**
278       * An undocumented inner class present for serialization compatibility.
279       */
280      private static class CredOwner implements Serializable
281      {
282    
283        // Fields.
284        // -----------------------------------------------------------------------
285    
286        private final String principalClass;
287        private final String principalName;
288    
289        // Constructor.
290        // -----------------------------------------------------------------------
291    
292        CredOwner (final String principalClass, final String principalName)
293        {
294          this.principalClass = principalClass;
295          this.principalName = principalName;
296        }
297    
298        // Instance methods.
299        // -----------------------------------------------------------------------
300    
301        public boolean equals (Object o)
302        {
303          if (!(o instanceof CredOwner))
304            {
305              return false;
306            }
307          return principalClass.equals (((CredOwner) o).getPrincipalClass()) &&
308            principalName.equals (((CredOwner) o).getPrincipalName());
309        }
310    
311        public int hashCode()
312        {
313          return principalClass.hashCode() + principalName.hashCode();
314        }
315    
316        public String getPrincipalClass()
317        {
318          return principalClass;
319        }
320    
321        public String getPrincipalName()
322        {
323          return principalName;
324        }
325      }
326    }