jdk/src/java.base/share/classes/sun/security/acl/AclImpl.java
changeset 29100 56267f38f743
parent 29099 766801b4d95d
child 29101 55f7a91aaa32
equal deleted inserted replaced
29099:766801b4d95d 29100:56267f38f743
     1 /*
       
     2  * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.  Oracle designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     9  * by Oracle in the LICENSE file that accompanied this code.
       
    10  *
       
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    14  * version 2 for more details (a copy is included in the LICENSE file that
       
    15  * accompanied this code).
       
    16  *
       
    17  * You should have received a copy of the GNU General Public License version
       
    18  * 2 along with this work; if not, write to the Free Software Foundation,
       
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    20  *
       
    21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
       
    22  * or visit www.oracle.com if you need additional information or have any
       
    23  * questions.
       
    24  */
       
    25 
       
    26 package sun.security.acl;
       
    27 
       
    28 import java.io.*;
       
    29 import java.util.*;
       
    30 import java.security.Principal;
       
    31 import java.security.acl.*;
       
    32 
       
    33 /**
       
    34  * An Access Control List (ACL) is encapsulated by this class.
       
    35  * @author      Satish Dharmaraj
       
    36  */
       
    37 public class AclImpl extends OwnerImpl implements Acl {
       
    38     //
       
    39     // Maintain four tables. one each for positive and negative
       
    40     // ACLs. One each depending on whether the entity is a group
       
    41     // or principal.
       
    42     //
       
    43     private Hashtable<Principal, AclEntry> allowedUsersTable =
       
    44                                         new Hashtable<>(23);
       
    45     private Hashtable<Principal, AclEntry> allowedGroupsTable =
       
    46                                         new Hashtable<>(23);
       
    47     private Hashtable<Principal, AclEntry> deniedUsersTable =
       
    48                                         new Hashtable<>(23);
       
    49     private Hashtable<Principal, AclEntry> deniedGroupsTable =
       
    50                                         new Hashtable<>(23);
       
    51     private String aclName = null;
       
    52     private Vector<Permission> zeroSet = new Vector<>(1,1);
       
    53 
       
    54 
       
    55     /**
       
    56      * Constructor for creating an empty ACL.
       
    57      */
       
    58     public AclImpl(Principal owner, String name) {
       
    59         super(owner);
       
    60         try {
       
    61             setName(owner, name);
       
    62         } catch (Exception e) {}
       
    63     }
       
    64 
       
    65     /**
       
    66      * Sets the name of the ACL.
       
    67      * @param caller the principal who is invoking this method.
       
    68      * @param name the name of the ACL.
       
    69      * @exception NotOwnerException if the caller principal is
       
    70      * not on the owners list of the Acl.
       
    71      */
       
    72     public void setName(Principal caller, String name)
       
    73       throws NotOwnerException
       
    74     {
       
    75         if (!isOwner(caller))
       
    76             throw new NotOwnerException();
       
    77 
       
    78         aclName = name;
       
    79     }
       
    80 
       
    81     /**
       
    82      * Returns the name of the ACL.
       
    83      * @return the name of the ACL.
       
    84      */
       
    85     public String getName() {
       
    86         return aclName;
       
    87     }
       
    88 
       
    89     /**
       
    90      * Adds an ACL entry to this ACL. An entry associates a
       
    91      * group or a principal with a set of permissions. Each
       
    92      * user or group can have one positive ACL entry and one
       
    93      * negative ACL entry. If there is one of the type (negative
       
    94      * or positive) already in the table, a false value is returned.
       
    95      * The caller principal must be a part of the owners list of
       
    96      * the ACL in order to invoke this method.
       
    97      * @param caller the principal who is invoking this method.
       
    98      * @param entry the ACL entry that must be added to the ACL.
       
    99      * @return true on success, false if the entry is already present.
       
   100      * @exception NotOwnerException if the caller principal
       
   101      * is not on the owners list of the Acl.
       
   102      */
       
   103     public synchronized boolean addEntry(Principal caller, AclEntry entry)
       
   104       throws NotOwnerException
       
   105     {
       
   106         if (!isOwner(caller))
       
   107             throw new NotOwnerException();
       
   108 
       
   109         Hashtable<Principal, AclEntry> aclTable = findTable(entry);
       
   110         Principal key = entry.getPrincipal();
       
   111 
       
   112         if (aclTable.get(key) != null)
       
   113             return false;
       
   114 
       
   115         aclTable.put(key, entry);
       
   116         return true;
       
   117     }
       
   118 
       
   119     /**
       
   120      * Removes an ACL entry from this ACL.
       
   121      * The caller principal must be a part of the owners list of the ACL
       
   122      * in order to invoke this method.
       
   123      * @param caller the principal who is invoking this method.
       
   124      * @param entry the ACL entry that must be removed from the ACL.
       
   125      * @return true on success, false if the entry is not part of the ACL.
       
   126      * @exception NotOwnerException if the caller principal is not
       
   127      * the owners list of the Acl.
       
   128      */
       
   129     public synchronized boolean removeEntry(Principal caller, AclEntry entry)
       
   130       throws NotOwnerException
       
   131     {
       
   132         if (!isOwner(caller))
       
   133             throw new NotOwnerException();
       
   134 
       
   135         Hashtable<Principal, AclEntry> aclTable = findTable(entry);
       
   136         Principal key = entry.getPrincipal();
       
   137 
       
   138         AclEntry o = aclTable.remove(key);
       
   139         return (o != null);
       
   140     }
       
   141 
       
   142     /**
       
   143      * This method returns the set of allowed permissions for the
       
   144      * specified principal. This set of allowed permissions is calculated
       
   145      * as follows:
       
   146      *
       
   147      * If there is no entry for a group or a principal an empty permission
       
   148      * set is assumed.
       
   149      *
       
   150      * The group positive permission set is the union of all
       
   151      * the positive permissions of each group that the individual belongs to.
       
   152      * The group negative permission set is the union of all
       
   153      * the negative permissions of each group that the individual belongs to.
       
   154      * If there is a specific permission that occurs in both
       
   155      * the postive permission set and the negative permission set,
       
   156      * it is removed from both. The group positive and negatoive permission
       
   157      * sets are calculated.
       
   158      *
       
   159      * The individial positive permission set and the individual negative
       
   160      * permission set is then calculated. Again abscence of an entry means
       
   161      * the empty set.
       
   162      *
       
   163      * The set of permissions granted to the principal is then calculated using
       
   164      * the simple rule: Individual permissions always override the Group permissions.
       
   165      * Specifically, individual negative permission set (specific
       
   166      * denial of permissions) overrides the group positive permission set.
       
   167      * And the individual positive permission set override the group negative
       
   168      * permission set.
       
   169      *
       
   170      * @param user the principal for which the ACL entry is returned.
       
   171      * @return The resulting permission set that the principal is allowed.
       
   172      */
       
   173     public synchronized Enumeration<Permission> getPermissions(Principal user) {
       
   174 
       
   175         Enumeration<Permission> individualPositive;
       
   176         Enumeration<Permission> individualNegative;
       
   177         Enumeration<Permission> groupPositive;
       
   178         Enumeration<Permission> groupNegative;
       
   179 
       
   180         //
       
   181         // canonicalize the sets. That is remove common permissions from
       
   182         // positive and negative sets.
       
   183         //
       
   184         groupPositive =
       
   185             subtract(getGroupPositive(user), getGroupNegative(user));
       
   186         groupNegative  =
       
   187             subtract(getGroupNegative(user), getGroupPositive(user));
       
   188         individualPositive =
       
   189             subtract(getIndividualPositive(user), getIndividualNegative(user));
       
   190         individualNegative =
       
   191             subtract(getIndividualNegative(user), getIndividualPositive(user));
       
   192 
       
   193         //
       
   194         // net positive permissions is individual positive permissions
       
   195         // plus (group positive - individual negative).
       
   196         //
       
   197         Enumeration<Permission> temp1 =
       
   198             subtract(groupPositive, individualNegative);
       
   199         Enumeration<Permission> netPositive =
       
   200             union(individualPositive, temp1);
       
   201 
       
   202         // recalculate the enumeration since we lost it in performing the
       
   203         // subtraction
       
   204         //
       
   205         individualPositive =
       
   206             subtract(getIndividualPositive(user), getIndividualNegative(user));
       
   207         individualNegative =
       
   208             subtract(getIndividualNegative(user), getIndividualPositive(user));
       
   209 
       
   210         //
       
   211         // net negative permissions is individual negative permissions
       
   212         // plus (group negative - individual positive).
       
   213         //
       
   214         temp1 = subtract(groupNegative, individualPositive);
       
   215         Enumeration<Permission> netNegative = union(individualNegative, temp1);
       
   216 
       
   217         return subtract(netPositive, netNegative);
       
   218     }
       
   219 
       
   220     /**
       
   221      * This method checks whether or not the specified principal
       
   222      * has the required permission. If permission is denied
       
   223      * permission false is returned, a true value is returned otherwise.
       
   224      * This method does not authenticate the principal. It presumes that
       
   225      * the principal is a valid authenticated principal.
       
   226      * @param principal the name of the authenticated principal
       
   227      * @param permission the permission that the principal must have.
       
   228      * @return true of the principal has the permission desired, false
       
   229      * otherwise.
       
   230      */
       
   231     public boolean checkPermission(Principal principal, Permission permission)
       
   232     {
       
   233         Enumeration<Permission> permSet = getPermissions(principal);
       
   234         while (permSet.hasMoreElements()) {
       
   235             Permission p = permSet.nextElement();
       
   236             if (p.equals(permission))
       
   237               return true;
       
   238         }
       
   239         return false;
       
   240     }
       
   241 
       
   242     /**
       
   243      * returns an enumeration of the entries in this ACL.
       
   244      */
       
   245     public synchronized Enumeration<AclEntry> entries() {
       
   246         return new AclEnumerator(this,
       
   247                                  allowedUsersTable, allowedGroupsTable,
       
   248                                  deniedUsersTable, deniedGroupsTable);
       
   249     }
       
   250 
       
   251     /**
       
   252      * return a stringified version of the
       
   253      * ACL.
       
   254      */
       
   255     public String toString() {
       
   256         StringBuilder sb = new StringBuilder();
       
   257         Enumeration<AclEntry> entries = entries();
       
   258         while (entries.hasMoreElements()) {
       
   259             AclEntry entry = entries.nextElement();
       
   260             sb.append(entry.toString().trim());
       
   261             sb.append("\n");
       
   262         }
       
   263 
       
   264         return sb.toString();
       
   265     }
       
   266 
       
   267     //
       
   268     // Find the table that this entry belongs to. There are 4
       
   269     // tables that are maintained. One each for postive and
       
   270     // negative ACLs and one each for groups and users.
       
   271     // This method figures out which
       
   272     // table is the one that this AclEntry belongs to.
       
   273     //
       
   274     private Hashtable<Principal, AclEntry> findTable(AclEntry entry) {
       
   275         Hashtable<Principal, AclEntry> aclTable = null;
       
   276 
       
   277         Principal p = entry.getPrincipal();
       
   278         if (p instanceof Group) {
       
   279             if (entry.isNegative())
       
   280                 aclTable = deniedGroupsTable;
       
   281             else
       
   282                 aclTable = allowedGroupsTable;
       
   283         } else {
       
   284             if (entry.isNegative())
       
   285                 aclTable = deniedUsersTable;
       
   286             else
       
   287                 aclTable = allowedUsersTable;
       
   288         }
       
   289         return aclTable;
       
   290     }
       
   291 
       
   292     //
       
   293     // returns the set e1 U e2.
       
   294     //
       
   295     private static Enumeration<Permission> union(Enumeration<Permission> e1,
       
   296                 Enumeration<Permission> e2) {
       
   297         Vector<Permission> v = new Vector<>(20, 20);
       
   298 
       
   299         while (e1.hasMoreElements())
       
   300             v.addElement(e1.nextElement());
       
   301 
       
   302         while (e2.hasMoreElements()) {
       
   303             Permission o = e2.nextElement();
       
   304             if (!v.contains(o))
       
   305                 v.addElement(o);
       
   306         }
       
   307 
       
   308         return v.elements();
       
   309     }
       
   310 
       
   311     //
       
   312     // returns the set e1 - e2.
       
   313     //
       
   314     private Enumeration<Permission> subtract(Enumeration<Permission> e1,
       
   315                 Enumeration<Permission> e2) {
       
   316         Vector<Permission> v = new Vector<>(20, 20);
       
   317 
       
   318         while (e1.hasMoreElements())
       
   319             v.addElement(e1.nextElement());
       
   320 
       
   321         while (e2.hasMoreElements()) {
       
   322             Permission o = e2.nextElement();
       
   323             if (v.contains(o))
       
   324                 v.removeElement(o);
       
   325         }
       
   326 
       
   327         return v.elements();
       
   328     }
       
   329 
       
   330     private Enumeration<Permission> getGroupPositive(Principal user) {
       
   331         Enumeration<Permission> groupPositive = zeroSet.elements();
       
   332         Enumeration<Principal> e = allowedGroupsTable.keys();
       
   333         while (e.hasMoreElements()) {
       
   334             Group g = (Group)e.nextElement();
       
   335             if (g.isMember(user)) {
       
   336                 AclEntry ae = allowedGroupsTable.get(g);
       
   337                 groupPositive = union(ae.permissions(), groupPositive);
       
   338             }
       
   339         }
       
   340         return groupPositive;
       
   341     }
       
   342 
       
   343     private Enumeration<Permission> getGroupNegative(Principal user) {
       
   344         Enumeration<Permission> groupNegative = zeroSet.elements();
       
   345         Enumeration<Principal> e = deniedGroupsTable.keys();
       
   346         while (e.hasMoreElements()) {
       
   347             Group g = (Group)e.nextElement();
       
   348             if (g.isMember(user)) {
       
   349                 AclEntry ae = deniedGroupsTable.get(g);
       
   350                 groupNegative = union(ae.permissions(), groupNegative);
       
   351             }
       
   352         }
       
   353         return groupNegative;
       
   354     }
       
   355 
       
   356     private Enumeration<Permission> getIndividualPositive(Principal user) {
       
   357         Enumeration<Permission> individualPositive = zeroSet.elements();
       
   358         AclEntry ae = allowedUsersTable.get(user);
       
   359         if (ae != null)
       
   360             individualPositive = ae.permissions();
       
   361         return individualPositive;
       
   362     }
       
   363 
       
   364     private Enumeration<Permission> getIndividualNegative(Principal user) {
       
   365         Enumeration<Permission> individualNegative = zeroSet.elements();
       
   366         AclEntry ae  = deniedUsersTable.get(user);
       
   367         if (ae != null)
       
   368             individualNegative = ae.permissions();
       
   369         return individualNegative;
       
   370     }
       
   371 }
       
   372 
       
   373 final class AclEnumerator implements Enumeration<AclEntry> {
       
   374     Acl acl;
       
   375     Enumeration<AclEntry> u1, u2, g1, g2;
       
   376 
       
   377     AclEnumerator(Acl acl, Hashtable<?,AclEntry> u1, Hashtable<?,AclEntry> g1,
       
   378                   Hashtable<?,AclEntry> u2, Hashtable<?,AclEntry> g2) {
       
   379         this.acl = acl;
       
   380         this.u1 = u1.elements();
       
   381         this.u2 = u2.elements();
       
   382         this.g1 = g1.elements();
       
   383         this.g2 = g2.elements();
       
   384     }
       
   385 
       
   386     public boolean hasMoreElements() {
       
   387         return (u1.hasMoreElements() ||
       
   388                 u2.hasMoreElements() ||
       
   389                 g1.hasMoreElements() ||
       
   390                 g2.hasMoreElements());
       
   391     }
       
   392 
       
   393     public AclEntry nextElement()
       
   394     {
       
   395         AclEntry o;
       
   396         synchronized (acl) {
       
   397             if (u1.hasMoreElements())
       
   398                 return u1.nextElement();
       
   399             if (u2.hasMoreElements())
       
   400                 return u2.nextElement();
       
   401             if (g1.hasMoreElements())
       
   402                 return g1.nextElement();
       
   403             if (g2.hasMoreElements())
       
   404                 return g2.nextElement();
       
   405         }
       
   406         throw new NoSuchElementException("Acl Enumerator");
       
   407     }
       
   408 }