package org.dcache.namespace;
import javax.security.auth.Subject;
import java.util.Collections;
import java.util.EnumSet;
import java.util.Set;
import org.dcache.acl.ACL;
import org.dcache.acl.Owner;
import org.dcache.acl.Permission;
import org.dcache.acl.enums.AccessType;
import org.dcache.acl.mapper.AclMapper;
import org.dcache.acl.matcher.AclMatcher;
import org.dcache.auth.Origin;
import org.dcache.auth.Subjects;
import org.dcache.vehicles.FileAttributes;
import static org.dcache.acl.enums.AccessMask.*;
import static org.dcache.acl.enums.AccessType.*;
import static org.dcache.namespace.FileAttribute.*;
/**
* A PermissionHandler using the ACL module as a PDP.
*/
public class ACLPermissionHandler implements PermissionHandler
{
private static final Set<FileAttribute> REQUIRED_ATTRIBUTES =
Collections.unmodifiableSet(EnumSet.of(ACL, OWNER, OWNER_GROUP));
@Override
public Set<FileAttribute> getRequiredAttributes()
{
return REQUIRED_ATTRIBUTES;
}
private Permission getPermission(Subject subject, FileAttributes attr)
{
ACL acl = attr.getAcl();
Owner owner = new Owner(attr.getOwner(), attr.getGroup());
Origin origin = Subjects.getOrigin(subject);
return AclMapper.getPermission(subject, origin, owner, acl);
}
@Override
public AccessType canReadFile(Subject subject, FileAttributes attr)
{
Permission permission = getPermission(subject, attr);
return AclMatcher.isAllowed(permission, READ_DATA);
}
@Override
public AccessType canWriteFile(Subject subject, FileAttributes attr)
{
Permission permission = getPermission(subject, attr);
return AclMatcher.isAllowed(permission, WRITE_DATA);
}
@Override
public AccessType canCreateSubDir(Subject subject, FileAttributes parentAttr)
{
if (parentAttr == null) {
return ACCESS_DENIED;
}
Permission permission = getPermission(subject, parentAttr);
return AclMatcher.isAllowed(permission, ADD_SUBDIRECTORY);
}
@Override
public AccessType canCreateFile(Subject subject, FileAttributes parentAttr)
{
if (parentAttr == null) {
return ACCESS_DENIED;
}
Permission permission = getPermission(subject, parentAttr);
return AclMatcher.isAllowed(permission, ADD_FILE);
}
@Override
public AccessType canDeleteFile(Subject subject,
FileAttributes parentAttr,
FileAttributes childAttr)
{
if (parentAttr == null) {
return ACCESS_DENIED;
}
Permission permissionParent = getPermission(subject, parentAttr);
AccessType ofParent = AclMatcher.isAllowed(permissionParent,
DELETE_CHILD);
if ( ofParent == ACCESS_ALLOWED ) {
return ofParent;
}
Permission permissionChild = getPermission(subject, childAttr);
AccessType ofChild = AclMatcher.isAllowed(permissionChild,
DELETE);
if (ofChild == ACCESS_ALLOWED) {
return ofChild;
}
if (ofParent == ACCESS_DENIED
|| ofChild == ACCESS_DENIED) {
return ACCESS_DENIED;
}
return ACCESS_UNDEFINED;
}
@Override
public AccessType canDeleteDir(Subject subject,
FileAttributes parentAttr,
FileAttributes childAttr)
{
return canDeleteFile(subject, parentAttr, childAttr);
}
@Override
public AccessType canListDir(Subject subject, FileAttributes attr)
{
Permission permission = getPermission(subject, attr);
return AclMatcher.isAllowed(permission,
LIST_DIRECTORY);
}
@Override
public AccessType canLookup(Subject subject, FileAttributes attr)
{
Permission permission = getPermission(subject, attr);
return AclMatcher.isAllowed(permission,
EXECUTE);
}
@Override
public AccessType canRename(Subject subject,
FileAttributes parentAttr,
FileAttributes newParentAttr,
boolean isDirectory)
{
if (parentAttr == null || newParentAttr == null) {
return ACCESS_DENIED;
}
Permission permission1 = getPermission(subject, parentAttr);
Permission permission2 = getPermission(subject, newParentAttr);
AccessType ofSrcParent = AclMatcher.isAllowed(permission1, DELETE_CHILD);
AccessType ofDestParent = AclMatcher.isAllowed(permission2, ADD_FILE);
if (ofDestParent == ofSrcParent) {
return ofSrcParent;
}
if (ofSrcParent == ACCESS_DENIED ||
ofDestParent == ACCESS_DENIED) {
return ACCESS_DENIED;
}
return ACCESS_UNDEFINED;
}
@Override
public AccessType canSetAttributes(Subject subject,
FileAttributes attr,
Set<FileAttribute> attributes)
{
Permission permission = getPermission(subject, attr);
return canSetAttributes(permission, attributes);
}
@Override
public AccessType canGetAttributes(Subject subject,
FileAttributes attr,
Set<FileAttribute> attributes)
{
Permission permission = getPermission(subject, attr);
return canGetAttributes(permission, attributes);
}
/**
* Determines if the action is allowed on the get of file
* attributes. Returns ACCESS_DENIED if the action is denied for
* one or more of the attributes. Returns ACCESS_ALLOWED if the
* action is allowed for all attributes. Returns ACCESS_UNDEFINED
* otherwise.
*/
private AccessType canGetAttributes(Permission permission, Set<FileAttribute> attributes)
{
if (attributes.contains(ACL) ) {
return AclMatcher.isAllowed(permission, READ_ACL);
}
return AclMatcher.isAllowed(permission, READ_ATTRIBUTES);
}
/**
* Determines if the action is allowed on the set of file attributes.
* Returns ACCESS_DENIED if the action is denied for one or more of the
* attributes. Returns ACCESS_ALLOWED if the action is allowed for all
* attributes. Returns ACCESS_UNDEFINED otherwise.
*/
private AccessType canSetAttributes(Permission permission, Set<FileAttribute> attributes) {
if (attributes.contains(ACL)) {
return AclMatcher.isAllowed(permission, WRITE_ACL);
}
return AclMatcher.isAllowed(permission, WRITE_ATTRIBUTES);
}
}