[31b67d5] | 1 | package net.deterlab.abac; |
---|
| 2 | |
---|
| 3 | import org.apache.commons.collections15.*; |
---|
| 4 | import org.apache.commons.collections15.functors.*; |
---|
| 5 | |
---|
| 6 | import edu.uci.ics.jung.graph.*; |
---|
| 7 | import edu.uci.ics.jung.graph.event.*; |
---|
| 8 | import edu.uci.ics.jung.graph.util.*; |
---|
| 9 | |
---|
| 10 | import java.awt.geom.Point2D; |
---|
| 11 | import java.io.*; |
---|
| 12 | import java.util.*; |
---|
| 13 | |
---|
| 14 | /** |
---|
| 15 | * Represents a global graph of credentials in the form of principals and |
---|
| 16 | * attributes. |
---|
| 17 | */ |
---|
| 18 | public class CredentialGraph { |
---|
[a2a1555] | 19 | protected Graph<Role,Credential> g = null; |
---|
| 20 | protected java.util.Set<Credential> derived_edges = new HashSet<Credential>(); |
---|
| 21 | protected Query pq; |
---|
| 22 | protected boolean m_dirty; |
---|
[31b67d5] | 23 | |
---|
| 24 | public CredentialGraph() { |
---|
| 25 | /* create the graph */ |
---|
[a624bd1] | 26 | g = Graphs.<Role,Credential>synchronizedDirectedGraph( |
---|
| 27 | new DirectedSparseGraph<Role,Credential>()); |
---|
[31b67d5] | 28 | pq = new Query(g); |
---|
| 29 | } |
---|
| 30 | |
---|
| 31 | /** |
---|
[5bf874d] | 32 | * Returns a Query object which can be used to query the graph. This object |
---|
| 33 | * becomes invalid if the graph is modified. |
---|
[31b67d5] | 34 | */ |
---|
| 35 | public Query querier() { |
---|
[cac4c76] | 36 | derive_implied_edges(); |
---|
[31b67d5] | 37 | return new Query(g); |
---|
| 38 | } |
---|
| 39 | |
---|
| 40 | /** |
---|
| 41 | * Add a credential to the graph. |
---|
| 42 | */ |
---|
| 43 | public void add_credential(Credential cred) { |
---|
| 44 | Role tail = cred.tail(); |
---|
| 45 | Role head = cred.head(); |
---|
| 46 | |
---|
| 47 | /* explicitly add the vertices, otherwise get a null pointer exception */ |
---|
| 48 | g.addVertex(tail); |
---|
| 49 | g.addVertex(head); |
---|
| 50 | |
---|
| 51 | g.addEdge(cred, tail, head); |
---|
[cac4c76] | 52 | |
---|
| 53 | // add the prereqs of an intersection to the graph |
---|
| 54 | if (tail.is_intersection()) |
---|
| 55 | for (Role prereq : tail.prereqs()) |
---|
| 56 | g.addVertex(prereq); |
---|
[5bf874d] | 57 | |
---|
| 58 | m_dirty = true; |
---|
[31b67d5] | 59 | } |
---|
| 60 | |
---|
| 61 | /** |
---|
| 62 | * Remove a credential from the graph. |
---|
| 63 | */ |
---|
| 64 | public void remove_credential(Credential cred) { |
---|
[622bdbc] | 65 | if (g.containsEdge(cred)) |
---|
| 66 | g.removeEdge(cred); |
---|
[5bf874d] | 67 | m_dirty = true; |
---|
[31b67d5] | 68 | } |
---|
| 69 | |
---|
| 70 | /** |
---|
| 71 | * Returns a collection of the credentials in the graph. |
---|
| 72 | */ |
---|
| 73 | public Collection<Credential> credentials() { |
---|
| 74 | Collection<Credential> creds = new HashSet<Credential>(); |
---|
| 75 | |
---|
[90f939f] | 76 | // only return creds with a cert: all others are derived edges |
---|
| 77 | for (Credential cred : g.getEdges()) |
---|
| 78 | if (cred.cert() != null) |
---|
[31b67d5] | 79 | creds.add(cred); |
---|
[90f939f] | 80 | |
---|
[31b67d5] | 81 | return creds; |
---|
| 82 | } |
---|
| 83 | |
---|
| 84 | /** |
---|
[cac4c76] | 85 | * Derive the implied edges in the graph, according to RT0 derivation rules. |
---|
| 86 | * They are added to this graph. See "Distributed Credential Chain Discovery |
---|
| 87 | * in Trust Management" by Ninghui Li et al. for details. Note that a |
---|
| 88 | * derived linking edge can imply a new intersection edge and vice versa. |
---|
| 89 | * Therefore we iteratively derive edges, giving up when an iteration |
---|
| 90 | * produces 0 new edges. |
---|
| 91 | */ |
---|
[a2a1555] | 92 | protected synchronized void derive_implied_edges() { |
---|
[5bf874d] | 93 | // nothing to do on a clean graph |
---|
| 94 | if (!m_dirty) |
---|
| 95 | return; |
---|
| 96 | |
---|
| 97 | clear_old_edges(); |
---|
[cac4c76] | 98 | |
---|
| 99 | // iteratively derive links. continue as long as new links are added |
---|
| 100 | while (derive_links_iter() > 0) |
---|
| 101 | ; |
---|
[5bf874d] | 102 | m_dirty = false; |
---|
[cac4c76] | 103 | } |
---|
| 104 | |
---|
| 105 | /** |
---|
| 106 | * Single iteration of deriving implied edges. Returns the number of new |
---|
| 107 | * links added. |
---|
[31b67d5] | 108 | */ |
---|
[a2a1555] | 109 | protected int derive_links_iter() { |
---|
[cac4c76] | 110 | int count = 0; |
---|
[31b67d5] | 111 | |
---|
| 112 | /* for every node in the graph.. */ |
---|
[cac4c76] | 113 | for (Role vertex : g.getVertices()) { |
---|
| 114 | if (vertex.is_intersection()) { |
---|
| 115 | // for each prereq edge: |
---|
| 116 | // find set of principals that have the prereq |
---|
| 117 | // find the intersection of all sets (i.e., principals that satisfy all prereqs) |
---|
| 118 | // for each principal in intersection: |
---|
| 119 | // add derived edge |
---|
| 120 | |
---|
| 121 | Set<Role> principals = null; |
---|
| 122 | |
---|
| 123 | for (Role prereq : vertex.prereqs()) { |
---|
| 124 | Set<Role> cur_principals = pq.find_principals(prereq); |
---|
| 125 | |
---|
| 126 | if (principals == null) |
---|
| 127 | principals = cur_principals; |
---|
| 128 | else |
---|
| 129 | // no, they couldn't just call it "intersection" |
---|
| 130 | principals.retainAll(cur_principals); |
---|
| 131 | |
---|
| 132 | if (principals.size() == 0) |
---|
| 133 | break; |
---|
| 134 | } |
---|
| 135 | |
---|
| 136 | // add em |
---|
| 137 | for (Role principal : principals) |
---|
| 138 | if (add_derived_edge(vertex, principal)) |
---|
| 139 | ++count; |
---|
| 140 | } |
---|
| 141 | |
---|
| 142 | else if (vertex.is_linking()) { |
---|
| 143 | // make the rest of the code a bit clearer |
---|
| 144 | Role A_r1_r2 = vertex; |
---|
[31b67d5] | 145 | |
---|
[cac4c76] | 146 | Role A_r1 = new Role(A_r1_r2.A_r1()); |
---|
| 147 | String r2 = A_r1_r2.r2(); |
---|
[31b67d5] | 148 | |
---|
[cac4c76] | 149 | /* locate the node A.r1 */ |
---|
| 150 | if (!g.containsVertex(A_r1)) continue; /* boring: nothing of the form A.r1 */ |
---|
[31b67d5] | 151 | |
---|
[cac4c76] | 152 | /* for each B that satisfies A_r1 */ |
---|
| 153 | for (Role principal : pq.find_principals(A_r1)) { |
---|
| 154 | Role B_r2 = new Role(principal + "." + r2); |
---|
| 155 | if (!g.containsVertex(B_r2)) continue; |
---|
[31b67d5] | 156 | |
---|
[cac4c76] | 157 | if (add_derived_edge(A_r1_r2, B_r2)) |
---|
| 158 | ++count; |
---|
| 159 | } |
---|
[31b67d5] | 160 | } |
---|
| 161 | } |
---|
[cac4c76] | 162 | |
---|
| 163 | return count; |
---|
| 164 | } |
---|
| 165 | |
---|
| 166 | /** |
---|
| 167 | * Add a derived edge in the graph. Returns true only if the edge does not |
---|
| 168 | * exist. |
---|
| 169 | */ |
---|
[a2a1555] | 170 | protected boolean add_derived_edge(Role head, Role tail) { |
---|
[cac4c76] | 171 | // edge exists: return false |
---|
| 172 | if (g.findEdge(tail, head) != null) |
---|
| 173 | return false; |
---|
| 174 | |
---|
| 175 | // add the new edge |
---|
| 176 | Credential derived_edge = new Credential(head, tail); |
---|
| 177 | derived_edges.add(derived_edge); |
---|
| 178 | g.addEdge(derived_edge, tail, head); |
---|
| 179 | |
---|
| 180 | return true; |
---|
[31b67d5] | 181 | } |
---|
| 182 | |
---|
| 183 | /** |
---|
| 184 | * Clear the derived edges that currently exist in the graph. This is done |
---|
| 185 | * before the edges are rederived. The derived edges in filtered graphs are |
---|
| 186 | * also cleared. |
---|
| 187 | */ |
---|
[622bdbc] | 188 | protected void clear_old_edges() { |
---|
| 189 | for (Credential i: derived_edges) |
---|
[31b67d5] | 190 | g.removeEdge(i); |
---|
| 191 | derived_edges = new HashSet<Credential>(); |
---|
| 192 | } |
---|
| 193 | } |
---|