package com.nailabs.abac.process; import com.nailabs.abac.trust.*; import com.nailabs.abac.test.*; import com.nailabs.abac.credential.*; import edu.stanford.peer.rbtm.credential.*; import edu.stanford.peer.rbtm.engine.*; import edu.stanford.rt.credential.CredentialDomain; import edu.stanford.rt.credential.CredentialStore; import edu.stanford.rt.credential.RTContext; import edu.stanford.rt.parser.RTParser; import java.io.ByteArrayInputStream; import java.io.InputStream; import java.util.*; /** * A trust target graph (TTG) is used to represent the state of a trust * negotiation in process (one per graph). * @version $Id: TTG.java,v 1.50 2003/02/26 00:45:11 jjacobs Exp $ */ public class TTG extends Observable implements Observer { /** The top-level trust target the system is trying to solve. */ protected TargetNode root; /** An index of TTGNodes based on their trust targets */ protected Hashtable indexByTT = new Hashtable(); /** The old change list for this graph */ protected Message oldDelta = new Message(); /** The current change list for this graph */ protected Message newDelta = new Message(); /** A set of all previoussent credentials */ protected HashSet outCache = new HashSet(); /** A graph engine for storing remotely held credential */ protected GraphEngine oppoCreds = null; /** An RTML parser for de-serializing RTML evidence */ protected RTParser parser = null; /** An RTML context for incoming opponent's credentials */ protected RTContext rtc = null; /** A context for a single trust negotiation */ protected NegotiationContext context; /** Create a trust target graph for a specific negotiation */ public TTG(NegotiationContext context){ this.context = context; if(context.getFrontier() instanceof RtmlFrontier) { try { parser = new RTParser(); rtc = new RTContext(parser); oppoCreds = new RtmlEngine(new CredentialStore(parser)); } catch(Exception ex) { debug("rtml", ex.getMessage()); } } else { oppoCreds = new GraphEngine(); } } /** Propagates node state change information to a graph observer */ public void update(Observable o, Object arg) { //if(o instanceof TTGNode) { setChanged(); notifyObservers(arg); //} //else { //debug("update", "received unexpected observation from " + arg); //} } /** * This returns an internal list of all node in the trust target graph. * WARNING: this should be a privileged function for production use. Also, * any changes to the TTG will invalidate this iterator! */ public Iterator getNodes() { return indexByTT.values().iterator(); } public TTGNode getNode(Goal key) { TTGNode node = getNodeByHash(key); if(node == null) { node = TTGNode.createNode(key); putNodeByHash(node); debug("node", "initialized node for " + key); } else { debug("node", "found node for " + key); } return node; } /** Access a trust target node by the goal it represents */ public TTGNode getNodeByHash(Goal key) { return (TTGNode)indexByTT.get(key.toString()); } /** Entry point for global or local changes. */ public void putNodeByHash(TTGNode node) { indexByTT.put(node.getGoal().toString(), node); debug("node", "putting " + node.getGoal()); node.init(context); context.getStrategy().addToWorklist(node); context.getStrategy().addNewNode(node); setChanged(); notifyObservers((Object)node); } public void putRoot(TargetNode node) { debug("root", "putting root" + node); root = node; setChanged(); notifyObservers((Object)node); } /** A method to reset the change list at the end of a processing cycle */ public void reset() { //consolidate credentials Iterator i = newDelta.getEvidence(); while(i.hasNext()) { Object potential = i.next(); if(outCache.contains(potential)) { i.remove(); } else { outCache.add(potential); } } oldDelta = newDelta; // swap out the deltas newDelta = new Message(); setChanged(); // notify observers of the changed message notifyObservers((Object)oldDelta); } /** Accessor method for the change list on the graph and resets the list */ public Message getChanges() { return newDelta; } public boolean verifyEvidence(Operation op) { Entity self = context.getSelf(); if(op instanceof LinkingImplicationEdge) { return false; } if((op instanceof ImplicationEdge)) { Goal g = ((EdgeOperation)op).getParent(); debug("message", "verifying operation " + op); return(self.equals(g.getVerifier())); } debug("message", "not verifying operation " + op); return false; } /** boolean query to determine whether the sepcified goal needs evidence */ public boolean provideEvidence(Operation edge) { Goal g = ((EdgeOperation)edge).getParent(); Entity self = context.getSelf(); return (!self.equals(g.getVerifier())); } /** Update this graph with changes contained in the specified message */ public void update(Message msg) throws Exception { setChanged(); //notifyObservers("\n"); notifyObservers("location = remote"); Iterator ev = msg.getEvidence(); while(ev.hasNext()) { Object eObj = ev.next(); if(eObj instanceof String) { String xml = (String) eObj; InputStream in = new ByteArrayInputStream(xml.getBytes()); CredentialDomain domain = parser.parseCredentialDomain(in, rtc); ((RtmlEngine)oppoCreds).addDomain(domain); debug("message", "received evidence = " + domain); } else { StaticCredential credential = (StaticCredential)eObj; Debug.rbtmStart(); oppoCreds.addCredential(credential); Debug.rbtmStop(); debug("message", "received evidence = " + credential); } } Iterator operations = msg.getOperations(); while(operations.hasNext()) { Operation op = (Operation)operations.next(); debug("message", "performing op " + op); if(verifyEvidence(op)) { EdgeOperation edgeOp = (EdgeOperation)op; TrustTarget parent = (TrustTarget)edgeOp.getParent(); TrustTarget child = (TrustTarget)edgeOp.getChild(); HashSet evidence = null; //try { EntityExpression parentRole = parent.getTargetRole(); EntityExpression childRole = child.getTargetRole(); debug("message", "chain search from " + parentRole + " to " + childRole); Debug.rbtmStart(); oppoCreds.backwardSearch(parentRole); if(parentRole.equals(childRole)) { debug("message", "roles are equal bailing out now!"); } else { evidence = oppoCreds.getChain(parentRole, childRole); // } Debug.rbtmStop(); //} catch(Exception ex) { //ex.printStackTrace(); //throw(new java.rmi.RemoteException("Unjustified implication!!")); } edgeOp.setEvidence(evidence); debug("message", "evidence = " + evidence); } setChanged(); notifyObservers((Object)op); op.perform(this); } setChanged(); //notifyObservers("\n"); } /** * Accessor method for of root of graph. This is necessary to traverse * the graph. * @returns the root node which may be any TTGNode descendent. */ public TargetNode getRoot() { return root; } // Methods in this section are recorded in the delta list /** * Insert a new root node for this graph. * This is a global operation */ public void setRoot(TrustTarget target) { debug("root", "setting root = " + target); NodeOperation op = new NodeOperation (target, target.getInitialProcessingState(context), true); setChanged(); notifyObservers(op); op.perform(this); newDelta.addOperation(op); } /** * Mark a node in the graph as opponent processed. */ public void setOpponentProcessed(Goal id) { //TTGNode node = getNode(id); //ProcessingState state = node.getProcessingState(); //state.opponentProcess(state); setNode(id, new ProcessingState(false, true)); } /** * Mark a node in the graph as verifier processed. */ public void setVerifierProcessed(Goal id) { //TTGNode node = getNode(id); //ProcessingState state = node.getProcessingState(); //state.verifierProcess(); setNode(id, new ProcessingState(true, false)); } /** * Add a root or modify a node to this TTG and replicate the changes on * the opponent's TTG. * This is a global operation */ public void setNode(Goal id, ProcessingState state) { ProcessingState copy = new ProcessingState(); copy.update(state); NodeOperation nodeOp = new NodeOperation(id, copy); context.getStrategy().scheduleOperation(nodeOp); } /** actually performs the node operation on this graph */ public void performNode(NodeOperation nodeOp) { // This is slightly different than perform edge although they // could possibly be merged into a single performOperation method nodeOp.perform(this); newDelta.addOperation((Operation)nodeOp); setChanged(); notifyObservers((Object)nodeOp); } /** actually performs a previously scheduled edge operation */ public void performEdge(EdgeOperation edgeOp) { if(edgeOp instanceof LinkingImplicationEdge) { setChanged(); notifyObservers("location = async"); } setChanged(); notifyObservers((Object)edgeOp); edgeOp.perform(this); if(edgeOp instanceof ImplicationEdge && provideEvidence(edgeOp)) { debug("message", " %%%% adding evidence for " + edgeOp.toString()); newDelta.addOperation((Operation)edgeOp); } else { debug("message", " %%%% not adding evidence for" + edgeOp.toString()); newDelta.addOperationWithoutEvidence((Operation)edgeOp); } if(edgeOp instanceof LinkingImplicationEdge) { setChanged(); notifyObservers("location = sync"); } } /** * Add a new control edge to this TTG and replicate the changes on the * opponent's TTG. * This is a global operation */ public void addControlEdge(Goal parent, Goal child) { TTGNode cnode = getNodeByHash(child); ProcessingState state = (cnode == null)? child.getInitialProcessingState(context): null; EdgeOperation edgeOp = new ControlEdge(parent, child, state); context.getStrategy().scheduleOperation(edgeOp); } /** * Add a new implication edge to this TTG and replicate the changes on the * opponent's TTG. * This is a global operation */ public void addImplicationEdge(Goal parent, Goal child, HashSet creds) { TTGNode cnode = getNodeByHash(child); //debug("node", "implication cnode = " + cnode); ProcessingState state = (cnode == null)? child.getInitialProcessingState(context): null; ImplicationEdge edgeOp = new ImplicationEdge(parent, child, state, creds); context.getStrategy().scheduleOperation(edgeOp); } /** * Add a new intersection edge to this TTG and replicate the edge on the * opponent's TTG. This is a global operation */ public void addIntersectionEdge(TrustTarget parent, TrustTarget child) { TargetNode cnode = (TargetNode)getNodeByHash(child); debug("node", "implication cnode = " + cnode); ProcessingState state = (cnode == null)? child.getInitialProcessingState(context): null; IntersectionEdge edgeOp = new IntersectionEdge(parent, child, state); context.getStrategy().scheduleOperation(edgeOp); } public void addLinkingMonitorEdge(TrustTarget parent, LinkingGoal child) { TTGNode cnode = getNodeByHash(child); ProcessingState state = (cnode == null)? child.getInitialProcessingState(context): null; EdgeOperation edgeOp = new LinkingMonitorEdge(parent, child, state); context.getStrategy().scheduleOperation(edgeOp); } public void addLinkingSolutionEdge(LinkingGoal monitor, TrustTarget soln) { TTGNode cnode = getNodeByHash(soln); ProcessingState state = (cnode == null)? soln.getInitialProcessingState(context): null; EdgeOperation edgeOp = new LinkingSolutionEdge(monitor, soln, state); context.getStrategy().scheduleOperation(edgeOp); } public void addLinkingImplicationEdge(TrustTarget parent, TrustTarget child) { TTGNode cnode = getNodeByHash(child); ProcessingState state = (cnode == null)? child.getInitialProcessingState(context): null; EdgeOperation edgeOp = new LinkingImplicationEdge(parent, child, state); context.getStrategy().scheduleOperation(edgeOp); } /** Friendly debugging convenience method */ protected void debug(String level, String message) { StringBuffer buff = new StringBuffer("TTG["); buff.append(context.getSelf()).append("]: ").append(message); Debug.debug(level, buff.toString()); } public String toString() { StringBuffer buff = new StringBuffer("[TTG EntityID="); buff.append(context.getSelf().toString()).append("\n"); Iterator i = indexByTT.keySet().iterator(); while(i.hasNext()) { buff.append("\t").append(i.next()).append("\n"); } buff.append("]"); return buff.toString(); } }