package org.dcache.namespace; import javax.security.auth.Subject; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.EnumSet; import java.util.List; import java.util.Set; import org.dcache.acl.enums.AccessType; import org.dcache.vehicles.FileAttributes; import static org.dcache.acl.enums.AccessType.*; /** * PermissionHandler which delegates calls to a chain of permission * handler. For each policy decision, the permission handler delegates * the call to each chained permission handler until the first one * which returns a result different from ACCESS_UNDEFINED. That result * will be returned. If all chained permission handlers return * ACCESS_UNDEFINED, then this permission handler also returns * ACCESS_UNDEFINED. */ public class ChainedPermissionHandler implements PermissionHandler { private final List<PermissionHandler> _chain = new ArrayList<>(); public ChainedPermissionHandler() { } public ChainedPermissionHandler(List<PermissionHandler> chain) { _chain.addAll(chain); } public ChainedPermissionHandler(PermissionHandler ... chain) { _chain.addAll(Arrays.asList(chain)); } public void setChain(List<PermissionHandler> chain) { _chain.clear(); _chain.addAll(chain); } @Override public Set<FileAttribute> getRequiredAttributes() { Set<FileAttribute> attributes = EnumSet.noneOf(FileAttribute.class); for (PermissionHandler handler: _chain) { attributes.addAll(handler.getRequiredAttributes()); } return attributes; } @Override public AccessType canReadFile(Subject subject, FileAttributes attr) { for (PermissionHandler handler: _chain) { AccessType res = handler.canReadFile(subject, attr); if (res != AccessType.ACCESS_UNDEFINED) { return res; } } return AccessType.ACCESS_UNDEFINED; } @Override public AccessType canWriteFile(Subject subject, FileAttributes attr) { for (PermissionHandler handler: _chain) { AccessType res = handler.canWriteFile(subject, attr); if (res != AccessType.ACCESS_UNDEFINED) { return res; } } return AccessType.ACCESS_UNDEFINED; } @Override public AccessType canCreateSubDir(Subject subject, FileAttributes parentAttr) { for (PermissionHandler handler: _chain) { AccessType res = handler.canCreateSubDir(subject, parentAttr); if (res != AccessType.ACCESS_UNDEFINED) { return res; } } return AccessType.ACCESS_UNDEFINED; } @Override public AccessType canCreateFile(Subject subject, FileAttributes parentAttr) { for (PermissionHandler handler: _chain) { AccessType res = handler.canCreateFile(subject, parentAttr); if (res != AccessType.ACCESS_UNDEFINED) { return res; } } return AccessType.ACCESS_UNDEFINED; } @Override public AccessType canDeleteFile(Subject subject, FileAttributes parentAttr, FileAttributes childAttr) { for (PermissionHandler handler: _chain) { AccessType res = handler.canDeleteFile(subject, parentAttr, childAttr); if (res != AccessType.ACCESS_UNDEFINED) { return res; } } return AccessType.ACCESS_UNDEFINED; } @Override public AccessType canDeleteDir(Subject subject, FileAttributes parentAttr, FileAttributes childAttr) { for (PermissionHandler handler: _chain) { AccessType res = handler.canDeleteDir(subject, parentAttr, childAttr); if (res != AccessType.ACCESS_UNDEFINED) { return res; } } return AccessType.ACCESS_UNDEFINED; } @Override public AccessType canRename(Subject subject, FileAttributes existingParentAttr, FileAttributes newParentAttr, boolean isDirectory) { for (PermissionHandler handler: _chain) { AccessType res = handler.canRename(subject, existingParentAttr, newParentAttr, isDirectory); if (res != AccessType.ACCESS_UNDEFINED) { return res; } } return AccessType.ACCESS_UNDEFINED; } @Override public AccessType canListDir(Subject subject, FileAttributes attr) { for (PermissionHandler handler: _chain) { AccessType res = handler.canListDir(subject, attr); if (res != AccessType.ACCESS_UNDEFINED) { return res; } } return AccessType.ACCESS_UNDEFINED; } @Override public AccessType canLookup(Subject subject, FileAttributes attr) { for (PermissionHandler handler: _chain) { AccessType res = handler.canLookup(subject, attr); if (res != AccessType.ACCESS_UNDEFINED) { return res; } } return AccessType.ACCESS_UNDEFINED; } private AccessType canSetAttribute(Subject subject, FileAttributes attrs, FileAttribute attribute) { Set<FileAttribute> set = Collections.singleton(attribute); for (PermissionHandler handler: _chain) { AccessType res = handler.canSetAttributes(subject, attrs, set); switch (res) { case ACCESS_DENIED: return ACCESS_DENIED; case ACCESS_ALLOWED: return ACCESS_ALLOWED; case ACCESS_UNDEFINED: break; } } return ACCESS_UNDEFINED; } private AccessType canGetAttribute(Subject subject, FileAttributes attrs, FileAttribute attribute) { Set<FileAttribute> set = Collections.singleton(attribute); for (PermissionHandler handler: _chain) { AccessType res = handler.canGetAttributes(subject, attrs, set); switch (res) { case ACCESS_DENIED: return ACCESS_DENIED; case ACCESS_ALLOWED: return ACCESS_ALLOWED; case ACCESS_UNDEFINED: break; } } return ACCESS_UNDEFINED; } @Override public AccessType canSetAttributes(Subject subject, FileAttributes attrs, Set<FileAttribute> attributes) { boolean allAllowed = true; for (FileAttribute attribute: attributes) { AccessType res = canSetAttribute(subject, attrs, attribute); switch (res) { case ACCESS_DENIED: return ACCESS_DENIED; case ACCESS_UNDEFINED: allAllowed = false; break; case ACCESS_ALLOWED: break; } } return allAllowed ? ACCESS_ALLOWED : ACCESS_UNDEFINED; } @Override public AccessType canGetAttributes(Subject subject, FileAttributes attrs, Set<FileAttribute> attributes) { boolean allAllowed = true; for (FileAttribute attribute: attributes) { AccessType res = canGetAttribute(subject, attrs, attribute); switch (res) { case ACCESS_DENIED: return ACCESS_DENIED; case ACCESS_UNDEFINED: allAllowed = false; break; case ACCESS_ALLOWED: break; } } return allAllowed ? ACCESS_ALLOWED : ACCESS_UNDEFINED; } }