Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/sun/security/acl/AclImpl.java
38830 views
/*1* Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.security.acl;2627import java.io.*;28import java.util.*;29import java.security.Principal;30import java.security.acl.*;3132/**33* An Access Control List (ACL) is encapsulated by this class.34* @author Satish Dharmaraj35*/36public class AclImpl extends OwnerImpl implements Acl {37//38// Maintain four tables. one each for positive and negative39// ACLs. One each depending on whether the entity is a group40// or principal.41//42private Hashtable<Principal, AclEntry> allowedUsersTable =43new Hashtable<>(23);44private Hashtable<Principal, AclEntry> allowedGroupsTable =45new Hashtable<>(23);46private Hashtable<Principal, AclEntry> deniedUsersTable =47new Hashtable<>(23);48private Hashtable<Principal, AclEntry> deniedGroupsTable =49new Hashtable<>(23);50private String aclName = null;51private Vector<Permission> zeroSet = new Vector<>(1,1);525354/**55* Constructor for creating an empty ACL.56*/57public AclImpl(Principal owner, String name) {58super(owner);59try {60setName(owner, name);61} catch (Exception e) {}62}6364/**65* Sets the name of the ACL.66* @param caller the principal who is invoking this method.67* @param name the name of the ACL.68* @exception NotOwnerException if the caller principal is69* not on the owners list of the Acl.70*/71public void setName(Principal caller, String name)72throws NotOwnerException73{74if (!isOwner(caller))75throw new NotOwnerException();7677aclName = name;78}7980/**81* Returns the name of the ACL.82* @return the name of the ACL.83*/84public String getName() {85return aclName;86}8788/**89* Adds an ACL entry to this ACL. An entry associates a90* group or a principal with a set of permissions. Each91* user or group can have one positive ACL entry and one92* negative ACL entry. If there is one of the type (negative93* or positive) already in the table, a false value is returned.94* The caller principal must be a part of the owners list of95* the ACL in order to invoke this method.96* @param caller the principal who is invoking this method.97* @param entry the ACL entry that must be added to the ACL.98* @return true on success, false if the entry is already present.99* @exception NotOwnerException if the caller principal100* is not on the owners list of the Acl.101*/102public synchronized boolean addEntry(Principal caller, AclEntry entry)103throws NotOwnerException104{105if (!isOwner(caller))106throw new NotOwnerException();107108Hashtable<Principal, AclEntry> aclTable = findTable(entry);109Principal key = entry.getPrincipal();110111if (aclTable.get(key) != null)112return false;113114aclTable.put(key, entry);115return true;116}117118/**119* Removes an ACL entry from this ACL.120* The caller principal must be a part of the owners list of the ACL121* in order to invoke this method.122* @param caller the principal who is invoking this method.123* @param entry the ACL entry that must be removed from the ACL.124* @return true on success, false if the entry is not part of the ACL.125* @exception NotOwnerException if the caller principal is not126* the owners list of the Acl.127*/128public synchronized boolean removeEntry(Principal caller, AclEntry entry)129throws NotOwnerException130{131if (!isOwner(caller))132throw new NotOwnerException();133134Hashtable<Principal, AclEntry> aclTable = findTable(entry);135Principal key = entry.getPrincipal();136137AclEntry o = aclTable.remove(key);138return (o != null);139}140141/**142* This method returns the set of allowed permissions for the143* specified principal. This set of allowed permissions is calculated144* as follows:145*146* If there is no entry for a group or a principal an empty permission147* set is assumed.148*149* The group positive permission set is the union of all150* the positive permissions of each group that the individual belongs to.151* The group negative permission set is the union of all152* the negative permissions of each group that the individual belongs to.153* If there is a specific permission that occurs in both154* the postive permission set and the negative permission set,155* it is removed from both. The group positive and negatoive permission156* sets are calculated.157*158* The individial positive permission set and the individual negative159* permission set is then calculated. Again abscence of an entry means160* the empty set.161*162* The set of permissions granted to the principal is then calculated using163* the simple rule: Individual permissions always override the Group permissions.164* Specifically, individual negative permission set (specific165* denial of permissions) overrides the group positive permission set.166* And the individual positive permission set override the group negative167* permission set.168*169* @param user the principal for which the ACL entry is returned.170* @return The resulting permission set that the principal is allowed.171*/172public synchronized Enumeration<Permission> getPermissions(Principal user) {173174Enumeration<Permission> individualPositive;175Enumeration<Permission> individualNegative;176Enumeration<Permission> groupPositive;177Enumeration<Permission> groupNegative;178179//180// canonicalize the sets. That is remove common permissions from181// positive and negative sets.182//183groupPositive =184subtract(getGroupPositive(user), getGroupNegative(user));185groupNegative =186subtract(getGroupNegative(user), getGroupPositive(user));187individualPositive =188subtract(getIndividualPositive(user), getIndividualNegative(user));189individualNegative =190subtract(getIndividualNegative(user), getIndividualPositive(user));191192//193// net positive permissions is individual positive permissions194// plus (group positive - individual negative).195//196Enumeration<Permission> temp1 =197subtract(groupPositive, individualNegative);198Enumeration<Permission> netPositive =199union(individualPositive, temp1);200201// recalculate the enumeration since we lost it in performing the202// subtraction203//204individualPositive =205subtract(getIndividualPositive(user), getIndividualNegative(user));206individualNegative =207subtract(getIndividualNegative(user), getIndividualPositive(user));208209//210// net negative permissions is individual negative permissions211// plus (group negative - individual positive).212//213temp1 = subtract(groupNegative, individualPositive);214Enumeration<Permission> netNegative = union(individualNegative, temp1);215216return subtract(netPositive, netNegative);217}218219/**220* This method checks whether or not the specified principal221* has the required permission. If permission is denied222* permission false is returned, a true value is returned otherwise.223* This method does not authenticate the principal. It presumes that224* the principal is a valid authenticated principal.225* @param principal the name of the authenticated principal226* @param permission the permission that the principal must have.227* @return true of the principal has the permission desired, false228* otherwise.229*/230public boolean checkPermission(Principal principal, Permission permission)231{232Enumeration<Permission> permSet = getPermissions(principal);233while (permSet.hasMoreElements()) {234Permission p = permSet.nextElement();235if (p.equals(permission))236return true;237}238return false;239}240241/**242* returns an enumeration of the entries in this ACL.243*/244public synchronized Enumeration<AclEntry> entries() {245return new AclEnumerator(this,246allowedUsersTable, allowedGroupsTable,247deniedUsersTable, deniedGroupsTable);248}249250/**251* return a stringified version of the252* ACL.253*/254public String toString() {255StringBuffer sb = new StringBuffer();256Enumeration<AclEntry> entries = entries();257while (entries.hasMoreElements()) {258AclEntry entry = entries.nextElement();259sb.append(entry.toString().trim());260sb.append("\n");261}262263return sb.toString();264}265266//267// Find the table that this entry belongs to. There are 4268// tables that are maintained. One each for postive and269// negative ACLs and one each for groups and users.270// This method figures out which271// table is the one that this AclEntry belongs to.272//273private Hashtable<Principal, AclEntry> findTable(AclEntry entry) {274Hashtable<Principal, AclEntry> aclTable = null;275276Principal p = entry.getPrincipal();277if (p instanceof Group) {278if (entry.isNegative())279aclTable = deniedGroupsTable;280else281aclTable = allowedGroupsTable;282} else {283if (entry.isNegative())284aclTable = deniedUsersTable;285else286aclTable = allowedUsersTable;287}288return aclTable;289}290291//292// returns the set e1 U e2.293//294private static Enumeration<Permission> union(Enumeration<Permission> e1,295Enumeration<Permission> e2) {296Vector<Permission> v = new Vector<>(20, 20);297298while (e1.hasMoreElements())299v.addElement(e1.nextElement());300301while (e2.hasMoreElements()) {302Permission o = e2.nextElement();303if (!v.contains(o))304v.addElement(o);305}306307return v.elements();308}309310//311// returns the set e1 - e2.312//313private Enumeration<Permission> subtract(Enumeration<Permission> e1,314Enumeration<Permission> e2) {315Vector<Permission> v = new Vector<>(20, 20);316317while (e1.hasMoreElements())318v.addElement(e1.nextElement());319320while (e2.hasMoreElements()) {321Permission o = e2.nextElement();322if (v.contains(o))323v.removeElement(o);324}325326return v.elements();327}328329private Enumeration<Permission> getGroupPositive(Principal user) {330Enumeration<Permission> groupPositive = zeroSet.elements();331Enumeration<Principal> e = allowedGroupsTable.keys();332while (e.hasMoreElements()) {333Group g = (Group)e.nextElement();334if (g.isMember(user)) {335AclEntry ae = allowedGroupsTable.get(g);336groupPositive = union(ae.permissions(), groupPositive);337}338}339return groupPositive;340}341342private Enumeration<Permission> getGroupNegative(Principal user) {343Enumeration<Permission> groupNegative = zeroSet.elements();344Enumeration<Principal> e = deniedGroupsTable.keys();345while (e.hasMoreElements()) {346Group g = (Group)e.nextElement();347if (g.isMember(user)) {348AclEntry ae = deniedGroupsTable.get(g);349groupNegative = union(ae.permissions(), groupNegative);350}351}352return groupNegative;353}354355private Enumeration<Permission> getIndividualPositive(Principal user) {356Enumeration<Permission> individualPositive = zeroSet.elements();357AclEntry ae = allowedUsersTable.get(user);358if (ae != null)359individualPositive = ae.permissions();360return individualPositive;361}362363private Enumeration<Permission> getIndividualNegative(Principal user) {364Enumeration<Permission> individualNegative = zeroSet.elements();365AclEntry ae = deniedUsersTable.get(user);366if (ae != null)367individualNegative = ae.permissions();368return individualNegative;369}370}371372final class AclEnumerator implements Enumeration<AclEntry> {373Acl acl;374Enumeration<AclEntry> u1, u2, g1, g2;375376AclEnumerator(Acl acl, Hashtable<?,AclEntry> u1, Hashtable<?,AclEntry> g1,377Hashtable<?,AclEntry> u2, Hashtable<?,AclEntry> g2) {378this.acl = acl;379this.u1 = u1.elements();380this.u2 = u2.elements();381this.g1 = g1.elements();382this.g2 = g2.elements();383}384385public boolean hasMoreElements() {386return (u1.hasMoreElements() ||387u2.hasMoreElements() ||388g1.hasMoreElements() ||389g2.hasMoreElements());390}391392public AclEntry nextElement()393{394AclEntry o;395synchronized (acl) {396if (u1.hasMoreElements())397return u1.nextElement();398if (u2.hasMoreElements())399return u2.nextElement();400if (g1.hasMoreElements())401return g1.nextElement();402if (g2.hasMoreElements())403return g2.nextElement();404}405throw new NoSuchElementException("Acl Enumerator");406}407}408409410