/*
* Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.security.acl;
import java.io.*;
import java.util.*;
import java.security.Principal;
import java.security.acl.*;
An Access Control List (ACL) is encapsulated by this class.
Author: Satish Dharmaraj
/**
* An Access Control List (ACL) is encapsulated by this class.
* @author Satish Dharmaraj
*/
public class AclImpl extends OwnerImpl implements Acl {
//
// Maintain four tables. one each for positive and negative
// ACLs. One each depending on whether the entity is a group
// or principal.
//
private Hashtable<Principal, AclEntry> allowedUsersTable =
new Hashtable<>(23);
private Hashtable<Principal, AclEntry> allowedGroupsTable =
new Hashtable<>(23);
private Hashtable<Principal, AclEntry> deniedUsersTable =
new Hashtable<>(23);
private Hashtable<Principal, AclEntry> deniedGroupsTable =
new Hashtable<>(23);
private String aclName = null;
private Vector<Permission> zeroSet = new Vector<>(1,1);
Constructor for creating an empty ACL.
/**
* Constructor for creating an empty ACL.
*/
public AclImpl(Principal owner, String name) {
super(owner);
try {
setName(owner, name);
} catch (Exception e) {}
}
Sets the name of the ACL.
Params: - caller – the principal who is invoking this method.
- name – the name of the ACL.
Throws: - NotOwnerException – if the caller principal is
not on the owners list of the Acl.
/**
* Sets the name of the ACL.
* @param caller the principal who is invoking this method.
* @param name the name of the ACL.
* @exception NotOwnerException if the caller principal is
* not on the owners list of the Acl.
*/
public void setName(Principal caller, String name)
throws NotOwnerException
{
if (!isOwner(caller))
throw new NotOwnerException();
aclName = name;
}
Returns the name of the ACL.
Returns: the name of the ACL.
/**
* Returns the name of the ACL.
* @return the name of the ACL.
*/
public String getName() {
return aclName;
}
Adds an ACL entry to this ACL. An entry associates a
group or a principal with a set of permissions. Each
user or group can have one positive ACL entry and one
negative ACL entry. If there is one of the type (negative
or positive) already in the table, a false value is returned.
The caller principal must be a part of the owners list of
the ACL in order to invoke this method.
Params: - caller – the principal who is invoking this method.
- entry – the ACL entry that must be added to the ACL.
Throws: - NotOwnerException – if the caller principal
is not on the owners list of the Acl.
Returns: true on success, false if the entry is already present.
/**
* Adds an ACL entry to this ACL. An entry associates a
* group or a principal with a set of permissions. Each
* user or group can have one positive ACL entry and one
* negative ACL entry. If there is one of the type (negative
* or positive) already in the table, a false value is returned.
* The caller principal must be a part of the owners list of
* the ACL in order to invoke this method.
* @param caller the principal who is invoking this method.
* @param entry the ACL entry that must be added to the ACL.
* @return true on success, false if the entry is already present.
* @exception NotOwnerException if the caller principal
* is not on the owners list of the Acl.
*/
public synchronized boolean addEntry(Principal caller, AclEntry entry)
throws NotOwnerException
{
if (!isOwner(caller))
throw new NotOwnerException();
Hashtable<Principal, AclEntry> aclTable = findTable(entry);
Principal key = entry.getPrincipal();
if (aclTable.get(key) != null)
return false;
aclTable.put(key, entry);
return true;
}
Removes an ACL entry from this ACL.
The caller principal must be a part of the owners list of the ACL
in order to invoke this method.
Params: - caller – the principal who is invoking this method.
- entry – the ACL entry that must be removed from the ACL.
Throws: - NotOwnerException – if the caller principal is not
the owners list of the Acl.
Returns: true on success, false if the entry is not part of the ACL.
/**
* Removes an ACL entry from this ACL.
* The caller principal must be a part of the owners list of the ACL
* in order to invoke this method.
* @param caller the principal who is invoking this method.
* @param entry the ACL entry that must be removed from the ACL.
* @return true on success, false if the entry is not part of the ACL.
* @exception NotOwnerException if the caller principal is not
* the owners list of the Acl.
*/
public synchronized boolean removeEntry(Principal caller, AclEntry entry)
throws NotOwnerException
{
if (!isOwner(caller))
throw new NotOwnerException();
Hashtable<Principal, AclEntry> aclTable = findTable(entry);
Principal key = entry.getPrincipal();
AclEntry o = aclTable.remove(key);
return (o != null);
}
This method returns the set of allowed permissions for the
specified principal. This set of allowed permissions is calculated
as follows:
If there is no entry for a group or a principal an empty permission
set is assumed.
The group positive permission set is the union of all
the positive permissions of each group that the individual belongs to.
The group negative permission set is the union of all
the negative permissions of each group that the individual belongs to.
If there is a specific permission that occurs in both
the postive permission set and the negative permission set,
it is removed from both. The group positive and negatoive permission
sets are calculated.
The individial positive permission set and the individual negative
permission set is then calculated. Again abscence of an entry means
the empty set.
The set of permissions granted to the principal is then calculated using
the simple rule: Individual permissions always override the Group permissions.
Specifically, individual negative permission set (specific
denial of permissions) overrides the group positive permission set.
And the individual positive permission set override the group negative
permission set.
Params: - user – the principal for which the ACL entry is returned.
Returns: The resulting permission set that the principal is allowed.
/**
* This method returns the set of allowed permissions for the
* specified principal. This set of allowed permissions is calculated
* as follows:
*
* If there is no entry for a group or a principal an empty permission
* set is assumed.
*
* The group positive permission set is the union of all
* the positive permissions of each group that the individual belongs to.
* The group negative permission set is the union of all
* the negative permissions of each group that the individual belongs to.
* If there is a specific permission that occurs in both
* the postive permission set and the negative permission set,
* it is removed from both. The group positive and negatoive permission
* sets are calculated.
*
* The individial positive permission set and the individual negative
* permission set is then calculated. Again abscence of an entry means
* the empty set.
*
* The set of permissions granted to the principal is then calculated using
* the simple rule: Individual permissions always override the Group permissions.
* Specifically, individual negative permission set (specific
* denial of permissions) overrides the group positive permission set.
* And the individual positive permission set override the group negative
* permission set.
*
* @param user the principal for which the ACL entry is returned.
* @return The resulting permission set that the principal is allowed.
*/
public synchronized Enumeration<Permission> getPermissions(Principal user) {
Enumeration<Permission> individualPositive;
Enumeration<Permission> individualNegative;
Enumeration<Permission> groupPositive;
Enumeration<Permission> groupNegative;
//
// canonicalize the sets. That is remove common permissions from
// positive and negative sets.
//
groupPositive =
subtract(getGroupPositive(user), getGroupNegative(user));
groupNegative =
subtract(getGroupNegative(user), getGroupPositive(user));
individualPositive =
subtract(getIndividualPositive(user), getIndividualNegative(user));
individualNegative =
subtract(getIndividualNegative(user), getIndividualPositive(user));
//
// net positive permissions is individual positive permissions
// plus (group positive - individual negative).
//
Enumeration<Permission> temp1 =
subtract(groupPositive, individualNegative);
Enumeration<Permission> netPositive =
union(individualPositive, temp1);
// recalculate the enumeration since we lost it in performing the
// subtraction
//
individualPositive =
subtract(getIndividualPositive(user), getIndividualNegative(user));
individualNegative =
subtract(getIndividualNegative(user), getIndividualPositive(user));
//
// net negative permissions is individual negative permissions
// plus (group negative - individual positive).
//
temp1 = subtract(groupNegative, individualPositive);
Enumeration<Permission> netNegative = union(individualNegative, temp1);
return subtract(netPositive, netNegative);
}
This method checks whether or not the specified principal
has the required permission. If permission is denied
permission false is returned, a true value is returned otherwise.
This method does not authenticate the principal. It presumes that
the principal is a valid authenticated principal.
Params: - principal – the name of the authenticated principal
- permission – the permission that the principal must have.
Returns: true of the principal has the permission desired, false
otherwise.
/**
* This method checks whether or not the specified principal
* has the required permission. If permission is denied
* permission false is returned, a true value is returned otherwise.
* This method does not authenticate the principal. It presumes that
* the principal is a valid authenticated principal.
* @param principal the name of the authenticated principal
* @param permission the permission that the principal must have.
* @return true of the principal has the permission desired, false
* otherwise.
*/
public boolean checkPermission(Principal principal, Permission permission)
{
Enumeration<Permission> permSet = getPermissions(principal);
while (permSet.hasMoreElements()) {
Permission p = permSet.nextElement();
if (p.equals(permission))
return true;
}
return false;
}
returns an enumeration of the entries in this ACL.
/**
* returns an enumeration of the entries in this ACL.
*/
public synchronized Enumeration<AclEntry> entries() {
return new AclEnumerator(this,
allowedUsersTable, allowedGroupsTable,
deniedUsersTable, deniedGroupsTable);
}
return a stringified version of the
ACL.
/**
* return a stringified version of the
* ACL.
*/
public String toString() {
StringBuffer sb = new StringBuffer();
Enumeration<AclEntry> entries = entries();
while (entries.hasMoreElements()) {
AclEntry entry = entries.nextElement();
sb.append(entry.toString().trim());
sb.append("\n");
}
return sb.toString();
}
//
// Find the table that this entry belongs to. There are 4
// tables that are maintained. One each for postive and
// negative ACLs and one each for groups and users.
// This method figures out which
// table is the one that this AclEntry belongs to.
//
private Hashtable<Principal, AclEntry> findTable(AclEntry entry) {
Hashtable<Principal, AclEntry> aclTable = null;
Principal p = entry.getPrincipal();
if (p instanceof Group) {
if (entry.isNegative())
aclTable = deniedGroupsTable;
else
aclTable = allowedGroupsTable;
} else {
if (entry.isNegative())
aclTable = deniedUsersTable;
else
aclTable = allowedUsersTable;
}
return aclTable;
}
//
// returns the set e1 U e2.
//
private static Enumeration<Permission> union(Enumeration<Permission> e1,
Enumeration<Permission> e2) {
Vector<Permission> v = new Vector<>(20, 20);
while (e1.hasMoreElements())
v.addElement(e1.nextElement());
while (e2.hasMoreElements()) {
Permission o = e2.nextElement();
if (!v.contains(o))
v.addElement(o);
}
return v.elements();
}
//
// returns the set e1 - e2.
//
private Enumeration<Permission> subtract(Enumeration<Permission> e1,
Enumeration<Permission> e2) {
Vector<Permission> v = new Vector<>(20, 20);
while (e1.hasMoreElements())
v.addElement(e1.nextElement());
while (e2.hasMoreElements()) {
Permission o = e2.nextElement();
if (v.contains(o))
v.removeElement(o);
}
return v.elements();
}
private Enumeration<Permission> getGroupPositive(Principal user) {
Enumeration<Permission> groupPositive = zeroSet.elements();
Enumeration<Principal> e = allowedGroupsTable.keys();
while (e.hasMoreElements()) {
Group g = (Group)e.nextElement();
if (g.isMember(user)) {
AclEntry ae = allowedGroupsTable.get(g);
groupPositive = union(ae.permissions(), groupPositive);
}
}
return groupPositive;
}
private Enumeration<Permission> getGroupNegative(Principal user) {
Enumeration<Permission> groupNegative = zeroSet.elements();
Enumeration<Principal> e = deniedGroupsTable.keys();
while (e.hasMoreElements()) {
Group g = (Group)e.nextElement();
if (g.isMember(user)) {
AclEntry ae = deniedGroupsTable.get(g);
groupNegative = union(ae.permissions(), groupNegative);
}
}
return groupNegative;
}
private Enumeration<Permission> getIndividualPositive(Principal user) {
Enumeration<Permission> individualPositive = zeroSet.elements();
AclEntry ae = allowedUsersTable.get(user);
if (ae != null)
individualPositive = ae.permissions();
return individualPositive;
}
private Enumeration<Permission> getIndividualNegative(Principal user) {
Enumeration<Permission> individualNegative = zeroSet.elements();
AclEntry ae = deniedUsersTable.get(user);
if (ae != null)
individualNegative = ae.permissions();
return individualNegative;
}
}
final class AclEnumerator implements Enumeration<AclEntry> {
Acl acl;
Enumeration<AclEntry> u1, u2, g1, g2;
AclEnumerator(Acl acl, Hashtable<?,AclEntry> u1, Hashtable<?,AclEntry> g1,
Hashtable<?,AclEntry> u2, Hashtable<?,AclEntry> g2) {
this.acl = acl;
this.u1 = u1.elements();
this.u2 = u2.elements();
this.g1 = g1.elements();
this.g2 = g2.elements();
}
public boolean hasMoreElements() {
return (u1.hasMoreElements() ||
u2.hasMoreElements() ||
g1.hasMoreElements() ||
g2.hasMoreElements());
}
public AclEntry nextElement()
{
AclEntry o;
synchronized (acl) {
if (u1.hasMoreElements())
return u1.nextElement();
if (u2.hasMoreElements())
return u2.nextElement();
if (g1.hasMoreElements())
return g1.nextElement();
if (g2.hasMoreElements())
return g2.nextElement();
}
throw new NoSuchElementException("Acl Enumerator");
}
}