source: java/net/deterlab/abac/Query.java @ 5cf72cc

abac0-leakabac0-meicompt_changesgec13mei-idmei-rt0-nmei_rt0mei_rt2mei_rt2_fix_1meiyap-rt1meiyap1rt2tvf-new-xml
Last change on this file since 5cf72cc was ac39e39, checked in by Mike Ryan <mikeryan@…>, 14 years ago

remove redundant new copy of role

  • Property mode set to 100644
File size: 9.8 KB
Line 
1package net.deterlab.abac;
2
3import org.apache.commons.collections15.*;
4
5import edu.uci.ics.jung.graph.*;
6import edu.uci.ics.jung.graph.util.*;
7
8import java.util.*;
9
10/**
11 * A class for making queries against the graph. It supports direct queries as
12 * well as reachability in either direction. See the run method for details.
13 */
14public class Query {
15    private Graph<Role,Credential> g;
16    private int vertex_count;
17
18    public Query(Graph<Role,Credential> g) {
19        this.g = g;
20    }
21
22    /**
23     * Run a query against the graph, returning a graph of the results. If the
24     * results are empty or the query fails, an empty graph is returned. When
25     * derived edges are involved, the subgraphs that imply those edges are
26     * included.
27     */
28    public Graph<Role,Credential> run(String attr, String prin) {
29        Role attribute = null, principal = null;;
30
31        if (!attr.isEmpty()) attribute = new Role(attr);
32        if (!prin.isEmpty()) principal = new Role(prin);
33
34        Graph<Role,Credential> ret =
35            Graphs.<Role,Credential>synchronizedDirectedGraph(
36                    new DirectedSparseGraph<Role,Credential>());
37
38        /* empty attribute, non-empty principal: find everywhere the principal can go */
39        if (attr.isEmpty() && !prin.isEmpty()) {
40            if (g.containsVertex(principal)) {
41                CollectReversePath collect = new CollectReversePath(ret);
42                forward_dfs(principal, collect);
43            }
44        }
45
46        /* otherwise we're going to do some kind of a reverse dfs */
47        else if (g.containsVertex(attribute)) { 
48            if ( prin == null || prin.isEmpty()) {
49                CollectQueryGraph  collect = new CollectQueryGraph(ret);
50                reverse_dfs(attribute, collect);
51            }
52            else {
53                if ( g.containsVertex(principal)) {
54                    CollectQueryPath  collect = new CollectQueryPath(ret, principal);
55                    reverse_dfs(attribute, collect);
56                }
57            }
58        }
59
60        vertex_count = ret.getVertexCount();
61
62        return ret;
63    }
64
65    /**
66     * Returns true after running a query that returns a non-empty set of
67     * vertices.
68     */
69    public boolean successful() {
70        return vertex_count > 0;
71    }
72
73    /**
74     * Returns a collection of principals reachable from a Role when
75     * traversing edges in the reverse direction.
76     */
77    public Set<Role> find_principals(Role n) {
78        Set<Role> principals = new HashSet<Role>();
79   
80        GetPrincipals f = new GetPrincipals(principals);
81        reverse_dfs(n, f);
82        return principals;
83    }
84
85
86    /**
87     * Interface to pass to the reverse_dfs class.  The node function gets
88     * called for every node visited by the dfs.
89     */
90    interface DfsFcn {
91        public void node(Role x);
92        public void node_after(Role x);
93    }
94
95    /**
96     * Class used to pull all the principals out of a reverse_dfs searched
97     * graph.  It takes a collection to the constructor and adds all principals
98     * it sees to that collection.  In no collection is passed in, it creates a
99     * local HashSet of vertices.  The collection is accessible via the p
100     * (i.e., principals) member.
101     */
102    private class GetPrincipals implements DfsFcn {
103        public Collection<Role> p;
104
105        public GetPrincipals(Collection<Role> vc) {
106            if ( vc != null) { p =vc;}
107            else { p = new HashSet<Role>(); }
108        }
109
110        public void node(Role r) {
111            if ( r.is_principal() ) p.add(r);
112        }
113        public void node_after(Role r) { }
114    }
115
116    /**
117     * Collect a subgraph. Add every node and outgoing arc we encounter, and
118     * pull in the linking node and intersection subtrees as well. Because it's
119     * possible that these subtrees have been encountered more than once, we're
120     * careful not to pull them in twice. The created graph is found in the
121     * public ng member.
122     */
123    private class CollectQueryGraph implements DfsFcn {
124        public Graph<Role, Credential> ng;
125        protected HashSet<Role> linking_roles_seen;
126        protected HashSet<Role> intersection_roles_seen;
127
128        public CollectQueryGraph(Graph<Role,Credential> g) {
129            ng = g;
130            linking_roles_seen = new HashSet<Role>();
131            intersection_roles_seen = new HashSet<Role>();
132        }
133
134        public void node(Role r) {
135            if (r.is_linking() && !linking_roles_seen.contains(r)) {
136                // Collect this linking role subgraph
137                reverse_dfs(new Role(r.principal_part()), this);
138                linking_roles_seen.add(r);
139            }
140
141            // collect subgraph for each intersection prereq
142            if (r.is_intersection() && !intersection_roles_seen.contains(r)) {
143                for (Role prereq : r.prereqs())
144                    reverse_dfs(prereq, this);
145                intersection_roles_seen.add(r);
146            }
147
148            // Add this node's children
149            for (Credential c : g.getInEdges(r) ) {
150                Role tail = g.getSource(c);
151                ng.addEdge(c, tail, r); // FIXME tail and r can come from c [?]
152            }
153        }
154        public void node_after(Role r) { }
155
156    }
157
158    /**
159     * Collect the path from one node to another. It only includes vertices that
160     * are traversed to reach the node. It also includes subgraphs that imply
161     * the linking/intersection edges traversed.
162     */
163    private class CollectQueryPath extends CollectQueryGraph {
164        HashSet<Role> onPath;     // Vertices on the path to the principal
165        public CollectQueryPath(Graph<Role,Credential> g, Role dest) {
166            super(g);
167            onPath = new HashSet<Role>();
168            onPath.add(dest);
169        }
170
171        public void node(Role r) { }
172
173        public void node_after(Role r) {
174            for (Credential c : g.getInEdges(r)) {
175                Role child = c.tail();
176
177                if (onPath.contains(child)) {
178                    Credential edge = g.findEdge(child, r);
179                    if (edge == null)
180                        throw new RuntimeException("Credential missing from parent graph, state is messed up");
181
182                    ng.addEdge(edge, child, r);
183                    onPath.add(r);
184
185                    // For linking roles, collect the whole subgraph of the
186                    // authorizer
187                    if (r.is_linking()) {
188                        CollectQueryPath link = new CollectQueryPath(ng, new Role(child.principal_part()));
189                        reverse_dfs(new Role(r.principal_part()), link);
190                    }
191
192                    // intersection: collect the subgraph of each prereq
193                    else if (r.is_intersection()) {
194                        CollectQueryPath prereq_finder = new CollectQueryPath(ng, child);
195                        for (Role prereq : r.prereqs())
196                            reverse_dfs(prereq, prereq_finder);
197                    }
198                }
199            }
200        }
201    }
202
203    /**
204     * Collect the path that a node can reach. It includes subgraphs that imply
205     * the linked/intersection edges traversed.
206     */
207    private class CollectReversePath extends CollectQueryGraph {
208        public CollectReversePath(Graph<Role,Credential> g) {
209            super(g);
210        }
211
212        /* add all of the node's parents */
213        public void node(Role r) {
214            for (Credential c : g.getOutEdges(r)) {
215                Role head = g.getDest(c);
216                Credential cred = g.findEdge(r, head);
217                if (cred == null)
218                    throw new RuntimeException("Credential missing from parent graph, state is messed up");
219
220                ng.addEdge(cred, r, head);
221            }
222        }
223
224        public void node_after(Role r) {
225            for (Credential c : g.getOutEdges(r)) {
226                Role parent = g.getDest(c);
227
228                // if any of the links we follow is from a linking node, copy
229                // the subgraph that implies said link
230                if (parent.is_linking()) {
231                    CollectQueryPath link = new CollectQueryPath(ng, new Role(r.principal_part()));
232                    reverse_dfs(new Role(parent.principal_part()), link);
233                }
234
235                // intersection roles do not need to be treated specially
236                // because the forward path from the principal will traverse all
237                // edges that imply the edge to the intersection node
238            }
239        }
240    }
241
242    /**
243     * Interface to the reverse_dfs member that does allocates the visited map
244     * so the user doesn't have to.
245     * */
246    private void reverse_dfs(Role r, DfsFcn f) {
247        reverse_dfs(r, new HashSet<Role>(), f);
248    }
249
250    /**
251     * Member function to walk the edges in reverse from a given Role.  Each
252     * Role is visited once and has the node() function of the dfs_fcn called
253     * on it.  Order is not guaranteed.
254     */
255    private void reverse_dfs(Role r, HashSet<Role> visited,
256            DfsFcn f) {
257        if (visited.contains(r)) return;
258
259        f.node(r);
260        visited.add(r);
261
262        for (Credential c : g.getInEdges(r)) 
263            reverse_dfs(g.getSource(c), visited, f);
264        f.node_after(r);
265    }
266
267    /**
268     * Interface to the forward_dfs member that allocates the visited map so
269     * the user doesn't have to.
270     */
271    private void forward_dfs(Role r, DfsFcn f) {
272        forward_dfs(r, new HashSet<Role>(), f);
273    }
274
275    /**
276     * Member function to walk the edges from a given Role. Each Role is
277     * visited once and has the node() function of the dfs_fcn called on it.
278     * Order is not guaranteed
279     */
280    private void forward_dfs(Role r, Set<Role> visited, DfsFcn f) {
281        if (visited.contains(r)) return;
282
283        f.node(r);
284        visited.add(r);
285
286        for (Credential c : g.getOutEdges(r))
287            forward_dfs(g.getDest(c), visited, f);
288        f.node_after(r);
289    }
290}
Note: See TracBrowser for help on using the repository browser.