package won.cryptography.rdfsign;
import org.apache.jena.query.Dataset;
import org.apache.jena.rdf.model.Model;
import de.uni_koblenz.aggrimm.icp.crypto.sign.graph.*;
import de.uni_koblenz.aggrimm.icp.crypto.sign.ontology.Ontology;
import won.protocol.util.RdfUtils;
import won.protocol.util.WonRdfUtils;
import won.protocol.vocabulary.WONMSG;
import java.util.ArrayList;
import java.util.LinkedList;
/**
* Created by ypanchenko on 08.07.2014.
* <p/>
* A utility class for assembling the calculated signature inside the GraphCollection
* into the original Dataset; for removing signature graphs from a Dataset.
*/
public class WonAssembler
{
private static final String SIG_GRAPH_NAME_TEMP = "<http://localhost:8080/won/SIG-GRAPH-PLACEHOLDER-TEMP>";
private static final String SIG_BNODE_NAME = "_:sig-1";
/**
* Assumes that namedSignedGraph is GraphCollection containing exactly one named graph
* that is part of the Dataset graphOrigin, and that for this named graph the signature
* is already calculated inside the GraphCollection internally (i.e. an Algorithm's
* methods canonicalize(namedSignedGraph), postCanonicalize(namedSignedGraph),
* hash(namedSignedGraph, envHashAlgorithm), postHash(namedSignedGraph),
* sign(namedSignedGraph, privateKey) have already been applied.
*
* The method assembles the signature from provided GraphCollection into the origin Dataset
* by putting signature triples inside the default graph of the Dataset. Intended for the
* use by WonSigner.
*
* @param namedSignedGraph GraphCollection containing one named graph with its calculated signature
* @param graphOrigin Dataset that contains the graph that has was used to construct the namedSignedGraph
* @throws Exception
*/
@Deprecated
public static void assemble(GraphCollection namedSignedGraph,
Dataset graphOrigin)
throws Exception {
Ontology o = prepareSignatureOntology(namedSignedGraph);
verifyGraphCollectionContainsExactlyOneNamedGraph(namedSignedGraph);
addSignatureTriplesToOrigin(namedSignedGraph, o, graphOrigin);
}
/**
* Assumes that namedSignedGraph is GraphCollection containing exactly one named graph
* that is part of the Dataset graphOrigin, and that for this named graph the signature
* is already calculated inside the GraphCollection internally (i.e. an Algorithm's
* methods canonicalize(namedSignedGraph), postCanonicalize(namedSignedGraph),
* hash(namedSignedGraph, envHashAlgorithm), postHash(namedSignedGraph),
* sign(namedSignedGraph, privateKey) have already been applied.
*
* The method assembles the signature from provided GraphCollection into the origin Dataset
* by putting signature triples inside the named graph of the Dataset. Intended for the
* use by WonSigner.
*
* @param namedSignedGraph GraphCollection containing one named graph with its calculated signature
* @param graphOrigin Dataset that contains the graph that has was used to construct the namedSignedGraph
* @param sigGraphURI the name (URI) of the graph that should be assigned to the signature graph
* @throws Exception
*/
public static void assemble(GraphCollection namedSignedGraph,
Dataset graphOrigin,
String sigGraphURI)
throws Exception {
Ontology o = prepareSignatureOntology(namedSignedGraph);
verifyGraphCollectionContainsExactlyOneNamedGraph(namedSignedGraph);
addSignatureAsNamedGraphToOrigin(namedSignedGraph, o, graphOrigin, sigGraphURI);
}
/**
* Removes signature graphs from the Dataset. Can be useful to use after
* verification is done, when the signatures are no longer required for
* further actions on the signed data of the Dataset.
*
* @param dataset from which graphs representing signatures have to be removed
*/
public static void removeSignatureGraphs(Dataset dataset) {
for (String name : RdfUtils.getModelNames(dataset)) {
if (WonRdfUtils.SignatureUtils.isSignatureGraph(name, dataset.getNamedModel(name))) {
dataset.removeNamedModel(name);
}
}
}
private static void verifyGraphCollectionContainsExactlyOneNamedGraph(GraphCollection gc) {
LinkedList<NamedGraph> graphs = gc.getGraphs();
if (graphs.size() == 1 && !graphs.get(0).getName().isEmpty()) {
// it's OK
} else if (graphs.size() == 2
&& graphs.get(0).getName().isEmpty() || graphs.get(1).getName().isEmpty()) {
// it's OK
} else {
// it's not OK
throw new IllegalArgumentException(WonAssembler.class.getName() +
" expects exactly one named graph, found " + (graphs.size() - 1));
}
}
private static Ontology prepareSignatureOntology(GraphCollection gc) {
//Get Signature Data
SignatureData sigData = gc.getSignature();
//Prepare Ontology
Ontology o = new Ontology(sigData);
//Choose an unused prefix for signatures to avoid prefix collisions
//Add number to default prefix in case it is used in graph already with other IRI
String sigPrefix = o.getSigPrefix(); //Get signature prefix from Ontology
String sigIri = Ontology.getSigIri(); //Get signature IRI from Ontology
String sigPre = sigPrefix;
for (int prefixCounter = 2; true; prefixCounter++) {
//Find equal prefix with different IRI
boolean prefixUsed = false;
for (Prefix p : gc.getPrefixes()) {
if (p.getPrefix().equals(sigPre)) {
if (!p.getIri().equals("<" + sigIri + ">")) {
//Found!
prefixUsed = true;
break;
}
}
}
if (prefixUsed) {
//Prefix is used with different IRI! Try again with another one (add higher number)!
sigPre = sigPrefix + prefixCounter;
} else {
//Prefix is not used with a different IRI! Continue!
break;
}
}
o.setSigPrefix(sigPre);
return o;
}
private static NamedGraph getSignatureAsGraph(GraphCollection gc, Ontology o) {
gc.addPrefix(new Prefix(o.getSigPrefix() + ":", "<" + Ontology.getSigIri() + ">"));
String name = gc.getGraphs().get(0).getName();
if (name.isEmpty()) {
name = gc.getGraphs().get(1).getName();
}
NamedGraph sigGraph = new NamedGraph(SIG_GRAPH_NAME_TEMP, 0, null);
ArrayList<Triple> sigGraphTriples = sigGraph.getTriples();
// this graph is signed by the signature
sigGraphTriples.add(new Triple(SIG_BNODE_NAME, "<" + WONMSG.HAS_SIGNED_GRAPH_PROPERTY + ">", name));
for (Triple t : o.getTriples()) {
String subj = t.getSubject();
sigGraphTriples.add(new Triple(subj, t.getPredicate(), t.getObject()));
}
gc.addGraph(sigGraph);
return sigGraph;
}
private static NamedGraph getSignatureAsGraph(GraphCollection gc, String sigGraphURI, Ontology o) {
gc.addPrefix(new Prefix(o.getSigPrefix() + ":", "<" + Ontology.getSigIri() + ">"));
// the signed graph
String name = gc.getGraphs().get(0).getName();
if (name.isEmpty()) {
name = gc.getGraphs().get(1).getName();
}
NamedGraph sigGraph = new NamedGraph(SIG_GRAPH_NAME_TEMP, 0, null);
ArrayList<Triple> sigGraphTriples = sigGraph.getTriples();
// this graph is signed by the signature
sigGraphTriples.add(new Triple("<" + sigGraphURI + ">", "<" + WONMSG.HAS_SIGNED_GRAPH_PROPERTY + ">", name));
for (Triple t : o.getTriples()) {
String subj = t.getSubject();
if (subj.equals(SIG_BNODE_NAME)) {
// this graph represents the signature and contains the signature triples
subj = "<" + sigGraphURI + ">";
}
sigGraphTriples.add(new Triple(subj, t.getPredicate(), t.getObject()));
}
gc.addGraph(sigGraph);
return sigGraph;
}
private static void addSignatureAsNamedGraphToOrigin(
GraphCollection namedSignedGraph, Ontology o,
Dataset graphOrigin, String sigGraphURI) throws Exception {
NamedGraph signatureAsGraph = getSignatureAsGraph(namedSignedGraph, sigGraphURI, o);
Model signatureAsModel = ModelConverter.namedGraphToModel(signatureAsGraph.getName(), namedSignedGraph);
graphOrigin.addNamedModel(sigGraphURI, signatureAsModel);
addPrefixesToDefaultGraph(signatureAsModel, graphOrigin);
}
private static void addSignatureTriplesToOrigin(
GraphCollection namedSignedGraph, Ontology o,
Dataset graphOrigin) throws Exception {
NamedGraph signatureAsGraph = getSignatureAsGraph(namedSignedGraph, o);
Model signatureAsModel = ModelConverter.namedGraphToModel(signatureAsGraph.getName(), namedSignedGraph);
graphOrigin.getDefaultModel().add(signatureAsModel);
addPrefixesToDefaultGraph(signatureAsModel, graphOrigin);
}
private static void addPrefixesToDefaultGraph(final Model signatureAsModel, final Dataset graphOrigin) {
for (String prefix : signatureAsModel.getNsPrefixMap().keySet()) {
graphOrigin.getDefaultModel().setNsPrefix(prefix, signatureAsModel.getNsPrefixMap().get(prefix));
}
graphOrigin.getDefaultModel().getNsPrefixMap().putAll(signatureAsModel.getNsPrefixMap());
}
}