FileSystemResource.java
package com.goldencode.p2j.security;
import com.goldencode.p2j.concurrent.*;
import com.goldencode.p2j.directory.*;
import com.goldencode.p2j.util.logging.*;
import java.nio.file.*;
import java.util.function.*;
import java.util.logging.*;
/**
* Implements the "FileSystemResource" resource. Access to such resources have rights which can
* be represented by a small set of flags:
* <ul>
* <li> create - a runtime instance of the resource can be created
* <li> delete - an existing runtime instance can be destroyed
* <li> read - the state or data associated with an existing runtime instance can be accessed
* <li> write - the state or data associated with an existing runtime instance can be modified
* <li> execute - the runtime instance can be executed
* <li> denied - no access is allowed (overrides any other access flags)
* </ul>
* <p>
* Rights objects for this resource are made of one bitfield with 8 bits. The first four bits
* correspond to the create, delete, read and write respectively. There are 2 reserved bits.
* The last bit is for explicit denial of access. When printed, they are shown as
* {@code CDRWE}
* <p>
* Resource names will be namespaced using the subclass' resource type name. The naming approach
* is {@code /resource_type_name/instance_name}. Each different instance of a particular
* resource type will share the same type name but must have a unique, non-empty instance name.
*/
public class FileSystemResource
extends BitFlagsResource
{
/** Logger */
private static CentralLogger LOG = CentralLogger.get(FileSystemResource.class);
/** EXECUTE permissions bit for the bitflags resource. */
public static final int BIT_EXECUTE_ACCESS = 4;
/** Resource type name */
public static final String TYPE_NAME = "file-system";
/**
* Returns the plugin resource type name as a string.
*
* @return plugin resource type name
*/
@Override
public String getTypeName()
{
return TYPE_NAME;
}
/**
* Override the method to provide extended bit names to augment the default set of bits.
* The method must return either {@code null} for no extended bits or an array of length 1, 2, 3.
* An array of length 1 will carry name of bit 4, length 2 bits 4 and 5, and length 3 bits 4, 5 and 6.
*
* @return See above.
*/
@Override
public String[] getExtendedBits()
{
return new String[] {"execute"};
}
/**
* Instantiates a plugin's class that implements the <code>Rights</code> interface, using
* the array of objects representing a set of access rights fields.
*
* @param rights
* The objects needed to create an access rights instance.
*
* @return The newly created rights instance.
*/
public Rights getRightsInstance(Object[] rights)
{
return new FileSystemRights(BitSetHelper.fromBitField((BitField)rights[0]));
}
/**
* Checks whether a given string is a syntactically valid resource name
* for this resource type.
*
* @param resource
* string naming a resource
*
* @return <code>true</code> if the name is syntactically correct
*/
@Override
public boolean isInstanceNameValid(String resource)
{
if (resource == null)
{
return false;
}
// validate the glob pattern
try
{
FileSystems.getDefault().getPathMatcher("glob:" + resource);
return true;
}
catch (Exception ex)
{
LOG.log(Level.WARNING, "Resource instance " + resource + " is invalid.", ex);
return false;
}
}
/**
* Returns a bi-predicate allowing to match ACLs based on a supplied resource instance name.
*
* @return A valid bi-predicate.
*/
@Override
public BiPredicate<AccessControlList, String> getACLMatcher()
{
return (acl, resInst) ->
{
// the glob pattern should always be valid, it is validated in isInstanceNameValid
PathMatcher matcher = FileSystems.getDefault().getPathMatcher("glob:" + acl.getInstanceName());
Path input = Paths.get(resInst);
return matcher.matches(input);
};
}
/**
* Reports if EXECUTE is allowed for the given resource name.
*
* @param name
* Resource instance name.
*
* @return <code>true</code> if access is allowed.
*/
public boolean canExecute(String name)
{
return accessWorker(name, BIT_EXECUTE_ACCESS);
}
}