Skip to content

Commit

Permalink
add getAdjacentDescendants method to AccessQuery interface (#169)
Browse files Browse the repository at this point in the history
* add getAdjacentDescendants method to AccessQuery interface

* add check to root

* use pmadmin where pcs are used in access methods

* support node or attributes in user and target contexts

* update javadoc

* fix privilege checker when toCheck is empty

* updates

* - modify memory access evaluators to only perform one traversal
- remove access checks in the PDP AccessQueryAdjudicator
- removed computePolicyClassAccessRights as the functionality is copied in explain
  • Loading branch information
joshua-roberts authored Nov 14, 2024
1 parent 7f35068 commit dbff2d1
Show file tree
Hide file tree
Showing 154 changed files with 1,536 additions and 1,137 deletions.
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,8 @@ import gov.nist.csd.pm.pap.exception.PMException;
import gov.nist.csd.pm.pap.graph.relationship.AccessRightSet;
import gov.nist.csd.pm.pap.prohibition.ContainerCondition;
import gov.nist.csd.pm.pap.prohibition.ProhibitionSubject;
import gov.nist.csd.pm.pap.query.UserContext;
import gov.nist.csd.pm.pap.query.model.context.UserContext;
import gov.nist.csd.pm.pap.query.model.context.TargetContext;
import gov.nist.csd.pm.pdp.PDP;

import java.util.List;
Expand Down Expand Up @@ -156,7 +157,7 @@ public class Main {
pap.executePML(new UserContext("u1")), pml);
*/

AccessRightSet privileges = pap.query().access().computePrivileges(new UserContext("u1"), "o1");
AccessRightSet privileges = pap.query().access().computePrivileges(new UserContext("u1"), new TargetContext("o1"));
System.out.println(privileges);
// expected output: {associate, read, create_object_attribute, associate_to}

Expand Down
2 changes: 1 addition & 1 deletion src/main/java/gov/nist/csd/pm/epp/EPP.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import gov.nist.csd.pm.pap.PAP;
import gov.nist.csd.pm.pdp.PDP;
import gov.nist.csd.pm.pap.exception.PMException;
import gov.nist.csd.pm.pap.query.UserContext;
import gov.nist.csd.pm.pap.query.model.context.UserContext;
import gov.nist.csd.pm.pap.obligation.Obligation;
import gov.nist.csd.pm.pap.obligation.Response;
import gov.nist.csd.pm.pap.obligation.Rule;
Expand Down
679 changes: 0 additions & 679 deletions src/main/java/gov/nist/csd/pm/impl/memory/pap/MemoryAccessQuerier.java

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import gov.nist.csd.pm.impl.memory.pap.store.MemoryPolicyStore;
import gov.nist.csd.pm.pap.PAP;
import gov.nist.csd.pm.pap.PolicyQuerier;
import gov.nist.csd.pm.pap.store.PolicyStore;

public class MemoryPAP extends PAP {

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package gov.nist.csd.pm.impl.memory.pap;

import gov.nist.csd.pm.impl.memory.pap.access.MemoryAccessQuerier;
import gov.nist.csd.pm.pap.PolicyQuerier;
import gov.nist.csd.pm.pap.store.PolicyStore;

Expand All @@ -9,7 +10,7 @@ public class MemoryPolicyQuerier extends PolicyQuerier {

public MemoryPolicyQuerier(PolicyStore policyStore) {
super(policyStore);
this.accessQuerier = new MemoryAccessQuerier(policyStore, graph(), prohibitions());
this.accessQuerier = new MemoryAccessQuerier(policyStore);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,224 @@
package gov.nist.csd.pm.impl.memory.pap.access;

import gov.nist.csd.pm.pap.exception.PMException;
import gov.nist.csd.pm.pap.graph.dag.*;
import gov.nist.csd.pm.pap.graph.relationship.AccessRightSet;
import gov.nist.csd.pm.pap.AccessQuerier;
import gov.nist.csd.pm.pap.query.model.context.UserContext;
import gov.nist.csd.pm.pap.query.model.context.TargetContext;
import gov.nist.csd.pm.pap.query.model.explain.*;
import gov.nist.csd.pm.pap.query.model.subgraph.SubgraphPrivileges;
import gov.nist.csd.pm.pap.store.GraphStoreBFS;
import gov.nist.csd.pm.pap.store.PolicyStore;

import java.util.*;

import static gov.nist.csd.pm.pap.admin.AdminPolicyNode.PM_ADMIN_OBJECT;
import static gov.nist.csd.pm.pap.AccessRightResolver.*;
import static gov.nist.csd.pm.pap.graph.node.NodeType.U;
import static gov.nist.csd.pm.pap.graph.node.Properties.NO_PROPERTIES;

public class MemoryAccessQuerier extends AccessQuerier {

public MemoryAccessQuerier(PolicyStore memoryPolicyStore) {
super(memoryPolicyStore);
}

@Override
public AccessRightSet computePrivileges(UserContext userCtx, TargetContext targetCtx) throws PMException {
// traverse the user side of the graph to get the associations
MemoryUserEvaluator userEvaluator = new MemoryUserEvaluator(store);
UserDagResult userDagResult = userEvaluator.evaluate(userCtx);

// traverse the target side of the graph to get permissions per policy class
MemoryTargetEvaluator targetEvaluator = new MemoryTargetEvaluator(store);
TargetDagResult targetDagResult = targetEvaluator.evaluate(userDagResult, targetCtx);

// resolve the permissions
return resolvePrivileges(userDagResult, targetDagResult, store.operations().getResourceOperations());
}

@Override
public List<AccessRightSet> computePrivileges(UserContext userCtx, List<TargetContext> targetCtxs) throws PMException {
// traverse the user side of the graph to get the associations
MemoryUserEvaluator userEvaluator = new MemoryUserEvaluator(store);
UserDagResult userDagResult = userEvaluator.evaluate(userCtx);

// traverse the target side of the graph to get permissions per policy class
MemoryTargetEvaluator targetEvaluator = new MemoryTargetEvaluator(store);

List<AccessRightSet> accessRightSets = new ArrayList<>();
for (TargetContext targetCtx : targetCtxs) {
TargetDagResult targetDagResult = targetEvaluator.evaluate(userDagResult, targetCtx);
AccessRightSet privs = resolvePrivileges(userDagResult, targetDagResult, store.operations().getResourceOperations());

accessRightSets.add(privs);
}

return accessRightSets;
}

@Override
public AccessRightSet computeDeniedPrivileges(UserContext userCtx, TargetContext targetCtx) throws PMException {
AccessRightSet accessRights = new AccessRightSet();

// traverse the user side of the graph to get the associations
MemoryUserEvaluator userEvaluator = new MemoryUserEvaluator(store);
UserDagResult userDagResult = userEvaluator.evaluate(userCtx);
if (userDagResult.borderTargets().isEmpty()) {
return accessRights;
}

// traverse the target side of the graph to get permissions per policy class
MemoryTargetEvaluator targetEvaluator = new MemoryTargetEvaluator(store);
TargetDagResult targetDagResult = targetEvaluator.evaluate(userDagResult, targetCtx);

// resolve the permissions
return resolveDeniedAccessRights(userDagResult, targetDagResult);
}

@Override
public Map<String, AccessRightSet> computeCapabilityList(UserContext userCtx) throws PMException {
Map<String, AccessRightSet> results = new HashMap<>();

//get border nodes. Can be OA or UA. Return empty set if no attrs are reachable
MemoryUserEvaluator userEvaluator = new MemoryUserEvaluator(store);
UserDagResult userDagResult = userEvaluator.evaluate(userCtx);
if (userDagResult.borderTargets().isEmpty()) {
return results;
}

for(String borderTarget : userDagResult.borderTargets().keySet()) {
// compute permissions on the border attr
getAndStorePrivileges(results, userDagResult, borderTarget);

// compute decisions for the subgraph of the border attr
Set<String> descendants = getDescendants(borderTarget);
for (String descendant : descendants) {
if (results.containsKey(descendant)) {
continue;
}

getAndStorePrivileges(results, userDagResult, descendant);
}
}

// add policy classes
if (results.containsKey(PM_ADMIN_OBJECT.nodeName())) {
AccessRightSet arset = results.get(PM_ADMIN_OBJECT.nodeName());
for (String pc : store.graph().getPolicyClasses()) {
results.put(pc, arset);
}
}

return results;
}

@Override
public Map<String, AccessRightSet> computeACL(TargetContext targetCtx) throws PMException {
Map<String, AccessRightSet> acl = new HashMap<>();
Collection<String> search = store.graph().search(U, NO_PROPERTIES);
for (String user : search) {
AccessRightSet list = this.computePrivileges(new UserContext(user), targetCtx);
acl.put(user, list);
}

return acl;
}

@Override
public Map<String, AccessRightSet> computeDestinationAttributes(UserContext userCtx) throws PMException {
return new MemoryUserEvaluator(store)
.evaluate(userCtx)
.borderTargets();
}

@Override
public SubgraphPrivileges computeSubgraphPrivileges(UserContext userCtx, String root) throws PMException {
List<SubgraphPrivileges> subgraphs = new ArrayList<>();

Collection<String> adjacentAscendants = store.graph().getAdjacentAscendants(root);
for (String adjacent : adjacentAscendants) {
subgraphs.add(computeSubgraphPrivileges(userCtx, adjacent));
}

return new SubgraphPrivileges(root, computePrivileges(userCtx, new TargetContext(root)), subgraphs);
}

@Override
public Map<String, AccessRightSet> computeAdjacentAscendantPrivileges(UserContext userCtx, String root) throws PMException {
Map<String, AccessRightSet> ascendantPrivs = new HashMap<>();

Collection<String> adjacentAscendants = store.graph().getAdjacentAscendants(root);
for (String adjacentAscendant : adjacentAscendants) {
ascendantPrivs.put(adjacentAscendant, computePrivileges(userCtx, new TargetContext(adjacentAscendant)));
}

return ascendantPrivs;
}

@Override
public Map<String, AccessRightSet> computeAdjacentDescendantPrivileges(UserContext userCtx, String root) throws PMException {
Map<String, AccessRightSet> descendantPrivs = new HashMap<>();

Collection<String> adjacentDescendants = store.graph().getAdjacentDescendants(root);
for (String adjacentDescendant : adjacentDescendants) {
descendantPrivs.put(adjacentDescendant, computePrivileges(userCtx, new TargetContext(adjacentDescendant)));
}

return descendantPrivs;
}

@Override
public Explain explain(UserContext userCtx, TargetContext targetCtx) throws PMException {
return new MemoryExplainer(store)
.explain(userCtx, targetCtx);
}

@Override
public Map<String, AccessRightSet> computePersonalObjectSystem(UserContext userCtx) throws PMException {
Map<String, AccessRightSet> pos = new HashMap<>();

for (String pc : store.graph().getPolicyClasses()) {
new GraphStoreBFS(store.graph())
.withDirection(Direction.ASCENDANTS)
.withVisitor(n -> {
AccessRightSet privs = computePrivileges(userCtx, new TargetContext(n));
if (privs.isEmpty()) {
return;
}

pos.put(n, privs);
})
.withSinglePathShortCircuit(n -> {
return pos.containsKey(n);
})
.walk(pc);
}
return pos;
}

private void getAndStorePrivileges(Map<String, AccessRightSet> arsetMap, UserDagResult userDagResult, String target) throws PMException {
TargetDagResult result = new MemoryTargetEvaluator(store)
.evaluate(userDagResult, new TargetContext(target));
AccessRightSet privileges = resolvePrivileges(userDagResult, result, store.operations().getResourceOperations());
arsetMap.put(target, privileges);
}

private Set<String> getDescendants(String vNode) throws PMException {
Set<String> descendants = new HashSet<>();

Collection<String> ascendants = store.graph().getAdjacentAscendants(vNode);
if (ascendants.isEmpty()) {
return descendants;
}

descendants.addAll(ascendants);
for (String ascendant : ascendants) {
descendants.add(ascendant);
descendants.addAll(getDescendants(ascendant));
}

return descendants;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
package gov.nist.csd.pm.impl.memory.pap.access;

import gov.nist.csd.pm.pap.exception.PMException;
import gov.nist.csd.pm.pap.graph.dag.TargetDagResult;
import gov.nist.csd.pm.pap.graph.dag.UserDagResult;
import gov.nist.csd.pm.pap.graph.relationship.AccessRightSet;
import gov.nist.csd.pm.pap.graph.relationship.Association;
import gov.nist.csd.pm.pap.prohibition.Prohibition;
import gov.nist.csd.pm.pap.query.model.context.TargetContext;
import gov.nist.csd.pm.pap.query.model.context.UserContext;
import gov.nist.csd.pm.pap.query.model.explain.*;
import gov.nist.csd.pm.pap.store.PolicyStore;

import java.util.*;

import static gov.nist.csd.pm.pap.AccessRightResolver.*;

public class MemoryExplainer {

private PolicyStore policyStore;

public MemoryExplainer(PolicyStore policyStore) {
this.policyStore = policyStore;
}

public Explain explain(UserContext userCtx, TargetContext targetCtx) throws PMException {
// resolve paths from u to target
List<PolicyClassExplain> resolvedPaths = resolvePaths(userCtx, targetCtx);

// evaluate user
MemoryUserEvaluator userEvaluator = new MemoryUserEvaluator(policyStore);
UserDagResult userDagResult = userEvaluator.evaluate(userCtx);

// evaluate target
MemoryTargetEvaluator targetEvaluator = new MemoryTargetEvaluator(policyStore);
TargetDagResult targetDagResult = targetEvaluator.evaluate(userDagResult, targetCtx);

// resolve privs and prohibitions
AccessRightSet priv = resolvePrivileges(userDagResult, targetDagResult, policyStore.operations().getResourceOperations());
AccessRightSet deniedPriv = resolveDeniedAccessRights(userDagResult, targetDagResult);
List<Prohibition> prohibitions = computeSatisfiedProhibitions(userDagResult, targetDagResult);

return new Explain(priv, resolvedPaths, deniedPriv, prohibitions);
}

private List<PolicyClassExplain> resolvePaths(UserContext userCtx, TargetContext targetCtx) throws PMException {
MemoryUserExplainer userExplainer = new MemoryUserExplainer(policyStore);
MemoryTargetExplainer targetExplainer = new MemoryTargetExplainer(policyStore);
Map<String, Map<Path, List<Association>>> targetPaths = targetExplainer.explainTarget(targetCtx);
Map<String, Set<Path>> userPaths = userExplainer.explainIntersectionOfTargetPaths(userCtx, targetPaths);

List<PolicyClassExplain> result = new ArrayList<>();

for (Map.Entry<String, Map<Path, List<Association>>> targetPathEntry : targetPaths.entrySet()) {
String pc = targetPathEntry.getKey();
Map<Path, List<Association>> targetPathAssociations = targetPathEntry.getValue();

List<List<ExplainNode>> paths = getExplainNodePaths(targetPathAssociations, userPaths);
AccessRightSet arset = getArsetFromPaths(paths);

result.add(new PolicyClassExplain(pc, arset, paths));
}

return result;
}

private List<List<ExplainNode>> getExplainNodePaths(Map<Path, List<Association>> targetPathAssociations,
Map<String, Set<Path>> userPaths) {
List<List<ExplainNode>> paths = new ArrayList<>();

for (Map.Entry<Path, List<Association>> targetPathEntry : targetPathAssociations.entrySet()) {
Path path = targetPathEntry.getKey();
List<Association> pathAssocs = targetPathEntry.getValue();

List<ExplainNode> explainNodes = new ArrayList<>();
for (String node : path) {
List<ExplainAssociation> explainAssocs = new ArrayList<>();

for (Association pathAssoc : pathAssocs) {
String ua = pathAssoc.getSource();
String target = pathAssoc.getTarget();
if (!target.equals(node)) {
continue;
}

Set<Path> userPathsToAssoc = userPaths.getOrDefault(ua, new HashSet<>());

explainAssocs.add(new ExplainAssociation(
ua,
pathAssoc.getAccessRightSet(),
new ArrayList<>(userPathsToAssoc)
));
}

explainNodes.add(new ExplainNode(node, explainAssocs));
}

paths.add(explainNodes);
}

return paths;
}

private AccessRightSet getArsetFromPaths(List<List<ExplainNode>> paths) {
AccessRightSet accessRightSet = new AccessRightSet();
for (List<ExplainNode> path : paths) {
for (ExplainNode explainNode : path) {
List<ExplainAssociation> associations = explainNode.associations();
for (ExplainAssociation association : associations) {
if (association.userPaths().isEmpty()) {
continue;
}

accessRightSet.addAll(association.arset());
}
}
}

return accessRightSet;
}
}
Loading

0 comments on commit dbff2d1

Please sign in to comment.