package at.gv.egovernment.moa.spss.server.invoke;
import iaik.IAIKException;
import iaik.IAIKRuntimeException;
import iaik.server.modules.xml.DataObject;
import iaik.server.modules.xml.XMLDataObject;
import iaik.server.modules.xml.XMLSignature;
import iaik.server.modules.xmlsign.XMLSignatureCreationModule;
import iaik.server.modules.xmlsign.XMLSignatureCreationModuleFactory;
import iaik.server.modules.xmlsign.XMLSignatureCreationProfile;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import at.gv.egovernment.moa.logging.Logger;
import at.gv.egovernment.moa.logging.LoggingContext;
import at.gv.egovernment.moa.logging.LoggingContextManager;
import at.gv.egovernment.moa.spss.MOAApplicationException;
import at.gv.egovernment.moa.spss.MOAException;
import at.gv.egovernment.moa.spss.MOASystemException;
import at.gv.egovernment.moa.spss.api.common.Content;
import at.gv.egovernment.moa.spss.api.common.MetaInfo;
import at.gv.egovernment.moa.spss.api.xmlsign.CreateSignatureEnvironmentProfileExplicit;
import at.gv.egovernment.moa.spss.api.xmlsign.CreateSignatureInfo;
import at.gv.egovernment.moa.spss.api.xmlsign.CreateSignatureLocation;
import at.gv.egovernment.moa.spss.api.xmlsign.CreateTransformsInfoProfileExplicit;
import at.gv.egovernment.moa.spss.api.xmlsign.CreateXMLSignatureRequest;
import at.gv.egovernment.moa.spss.api.xmlsign.CreateXMLSignatureResponse;
import at.gv.egovernment.moa.spss.api.xmlsign.DataObjectInfo;
import at.gv.egovernment.moa.spss.api.xmlsign.SingleSignatureInfo;
import at.gv.egovernment.moa.spss.server.config.ConfigurationProvider;
import at.gv.egovernment.moa.spss.server.iaik.xml.XMLDataObjectImpl;
import at.gv.egovernment.moa.spss.server.logging.IaikLog;
import at.gv.egovernment.moa.spss.server.logging.TransactionId;
import at.gv.egovernment.moa.spss.server.transaction.TransactionContext;
import at.gv.egovernment.moa.spss.server.transaction.TransactionContextManager;
import at.gv.egovernment.moa.spss.server.util.IdGenerator;
import at.gv.egovernment.moa.util.Constants;
import at.gv.egovernment.moa.util.XPathUtils;
/**
* A class providing an API based interface to the
*
* Only the following cases of XMLSignatureCreationModule
.
*
* This class performs the invocation of the
* iaik.server.modules.xmlsign.XMLSignatureCreationModule
from a
* CreateXMLSignatureRequest
given as an API object. The result of
* the invocation is integrated into a CreateXMLSignatureResponse
* and returned.
*
* @author Patrick Peck
* @version $Id$
*/
public class XMLSignatureCreationInvoker {
/** The single instance of this class. */
private static XMLSignatureCreationInvoker instance = null;
/**
* Get the only instance of this class.
*
* @return The only instance of this class.
*/
public static synchronized XMLSignatureCreationInvoker getInstance() {
if (instance == null) {
instance = new XMLSignatureCreationInvoker();
}
return instance;
}
/**
* Create a new XMLSignatureCreationInvoker
.
*
* Protected to disallow multiple instances.
*/
protected XMLSignatureCreationInvoker() {
}
/**
* Process the CreateXMLSignatureRequest
message and invoke the
*
XMLSignatureCreationModule
for every
* SingleSignatureInfo
contained in the request.
*
* @param request A CreateXMLSignatureRequest
API object
* containing the information for creating the signature(s).
* @param reserved A
Set
of reserved object IDs.
*
* @return A CreateXMLSignatureResponse
API object containing
* the created signature(s). The response contains either a
* SignatureEnvironment
or a ErrorResponse
* for each SingleSignatureInfo
in the request.
* @throws MOAException An error occurred during signature creation.
*/
public CreateXMLSignatureResponse createXMLSignature(
CreateXMLSignatureRequest request,
Set reserved)
throws MOAException {
TransactionContext context =
TransactionContextManager.getInstance().getTransactionContext();
LoggingContext loggingCtx =
LoggingContextManager.getInstance().getLoggingContext();
reserved = new HashSet(reserved);
XMLSignatureCreationProfileFactory profileFactory =
new XMLSignatureCreationProfileFactory(request, reserved);
CreateXMLSignatureResponseBuilder responseBuilder =
new CreateXMLSignatureResponseBuilder();
int createCount = 1;
IdGenerator refIdGen;
XMLSignatureCreationModule module;
Iterator singleSignatureInfoIter;
// create the XMLSignatureCreationModule and configure it
module = XMLSignatureCreationModuleFactory.getInstance();
module.setLog(new IaikLog(loggingCtx.getNodeID()));
// select the SingleSignatureInfo elements
singleSignatureInfoIter = request.getSingleSignatureInfos().iterator();
// iterate over all the SingleSignatureInfo elements in the request
while (singleSignatureInfoIter.hasNext()) {
SingleSignatureInfo singleSignatureInfo =
(SingleSignatureInfo) singleSignatureInfoIter.next();
CreateSignatureInfo createSignatureInfo;
List dataObjectList;
XMLSignatureCreationProfile profile;
XMLDataObject signatureEnvironment;
XMLDataObject signatureParent;
XMLSignature signature;
List additionalSignedProperties;
Node signatureEnvironmentParent = null;
Element requestElement = null;
try {
// build the signature environment
createSignatureInfo = singleSignatureInfo.getCreateSignatureInfo();
if (createSignatureInfo != null) {
DataObjectFactory dataObjFactory = DataObjectFactory.getInstance();
signatureEnvironment =
dataObjFactory.createSignatureEnvironment(
createSignatureInfo.getCreateSignatureEnvironment(),
getCreateSignatureEnvironmentProfileSupplements(singleSignatureInfo));
} else {
signatureEnvironment = null;
}
HashSet sigInfoReservedIDs = new HashSet();
if (signatureEnvironment != null)
{
// Find Id attributes of existing XML signatures in signature environment
HashMap nSMap = new HashMap();
String dsp = Constants.DSIG_PREFIX;
nSMap.put(dsp, Constants.DSIG_NS_URI);
String xPathExpr = "//" + dsp + ":Signature/@Id | //" + dsp + ":Reference/@Id | //"
+ dsp + ":Object/@Id | //" + dsp + ":Manifest/@Id";
NodeList idAttrs = XPathUtils.selectNodeList(signatureEnvironment.getElement(), nSMap, xPathExpr);
// Add found Id attributes to set of reserved IDs
for (int i = 0; i < idAttrs.getLength(); i++) sigInfoReservedIDs.add(idAttrs.item(i).getNodeValue());
}
// create the reference id generator
HashSet allReservedIDs = new HashSet(reserved);
allReservedIDs.addAll(sigInfoReservedIDs);
refIdGen = new IdGenerator("reference-" + createCount++, allReservedIDs);
// build the list of DataObjects
List createTransformsProfiles = profileFactory.getCreateTransformsInfoProfiles(singleSignatureInfo);
dataObjectList =
buildDataObjectList(
singleSignatureInfo,
createTransformsProfiles,
signatureEnvironment,
refIdGen);
// build the XMLSignatureCreationProfile
profile = profileFactory.createProfile(singleSignatureInfo, sigInfoReservedIDs);
// build the additionalSignedProperties
additionalSignedProperties = buildAdditionalSignedProperties();
// build the signatureParentElement
if (signatureEnvironment != null) {
signatureParent =
buildSignatureParentElement(
signatureEnvironment.getElement(),
singleSignatureInfo);
} else {
signatureParent = null;
}
// make the signature environment the root of the document, if it is
// not a separate document anyway; this is done to assure that
// canonicalization of the signature environment contains the correct
// namespace declarations
if (signatureEnvironment != null) {
Document requestDoc =
signatureEnvironment.getElement().getOwnerDocument();
requestElement = requestDoc.getDocumentElement();
if (requestElement != signatureEnvironment.getElement()) {
signatureEnvironmentParent =
signatureEnvironment.getElement().getParentNode();
requestElement.getOwnerDocument().replaceChild(
signatureEnvironment.getElement(),
requestElement);
}
}
try {
// create the signature
signature =
module.createSignature(
dataObjectList,
profile,
additionalSignedProperties,
signatureParent,
new TransactionId(context.getTransactionID()));
// insert the result into the response
if (signatureParent != null) {
responseBuilder.addSignatureEnvironment(
signatureEnvironment.getElement());
} else {
responseBuilder.addSignatureEnvironment(signature.getElement());
}
} catch (IAIKException e) {
MOAException moaException = IaikExceptionMapper.getInstance().map(e);
responseBuilder.addError(
moaException.getMessageId(),
moaException.getMessage());
Logger.warn(moaException.getMessage(), e);
} catch (IAIKRuntimeException e) {
MOAException moaException = IaikExceptionMapper.getInstance().map(e);
responseBuilder.addError(
moaException.getMessageId(),
moaException.getMessage());
Logger.warn(moaException.getMessage(), e);
}
// swap back in the request as root document
if (signatureEnvironment != null) {
if (requestElement != signatureEnvironment.getElement()) {
requestElement.getOwnerDocument().replaceChild(
requestElement,
signatureEnvironment.getElement());
signatureEnvironmentParent.appendChild(
signatureEnvironment.getElement());
}
}
} catch (MOAException e) {
responseBuilder.addError(e.getMessageId(), e.getMessage());
Logger.warn(e.getMessage(), e);
}
}
return responseBuilder.getResponse();
}
/**
* Build the list of DataObject
s from the given
* SingleSignatureInfo
object.
*
* DataObject
s are
* valid in case of an enveloping signature:
*
*
*
* Reference == null && Content != null
: The
* Content
will be used in the DataObject
.Reference != null && Content == null
: Resolve the
* Reference
and use it as DataObject
.
* Set the Reference
in the DataObject
as well.
* Only the following cases of DataObject
s are valid in case
* of a detached signature:
*
*
Reference != null && Content == null
: Resolve the
* Reference
and use it as DataObject
.
* Set the Reference
in the DataObject
as well.Reference != null && Content != null
: The
* Content
will be used in the DataObject
.
* Set the Reference
in the DataObject
as well.* All other cases will lead to an error. *
* * @param singleSignatureInfo TheSingleSignatureInfo
object
* containing the DataObjectInfo
objects.
* @param createTransformsProfiles A list of objects of type {@link CreateTransformsInfoProfileExplicit},
* each representing the transforms info profile information for the corresponding DataObject
.
* @param signatureEnvironment The
* @param idGen The ID generator for DataObject
references.
* @return The List
of DataObject
s contained in the
* given singleSignatureInfo
.
* @throws MOASystemException A system error occurred building the data
* objects.
* @throws MOAApplicationException An error occurred building the data
* objects.
*/
private List buildDataObjectList(
SingleSignatureInfo singleSignatureInfo,
List createTransformsProfiles,
XMLDataObject signatureEnvironment,
IdGenerator idGen)
throws MOASystemException, MOAApplicationException {
List dataObjInfos = singleSignatureInfo.getDataObjectInfos();
List dataObjects = new ArrayList();
Iterator dtIter;
Iterator ctpIter = createTransformsProfiles.iterator();
for (dtIter = dataObjInfos.iterator(); dtIter.hasNext();)
{
DataObjectInfo dataObjInfo = (DataObjectInfo) dtIter.next();
String structure = dataObjInfo.getStructure();
CreateTransformsInfoProfileExplicit transformsProfile =
(CreateTransformsInfoProfileExplicit) ctpIter.next();
MetaInfo finalDataMetaInfo = transformsProfile.getCreateTransformsInfo().getFinalDataMetaInfo();
if (DataObjectInfo.STRUCTURE_ENVELOPING.equals(structure)) {
dataObjects.add(
buildEnvelopingDataObject(
dataObjInfo.getDataObject(),
finalDataMetaInfo,
idGen.uniqueId()));
} else if (DataObjectInfo.STRUCTURE_DETACHED.equals(structure)) {
dataObjects.add(
buildDetachedDataObject(
dataObjInfo.getDataObject(),
finalDataMetaInfo,
signatureEnvironment,
idGen.uniqueId()));
} else {
throw new MOAApplicationException("1103", new Object[] { structure });
}
}
return dataObjects;
}
/**
* Build a DataObject
to be used in an enveloping
* signature.
*
* @param content The Content
object containing the data object.
* ContentOptionalRefType
.
* @param finalDataMetaInfo The meta information corresponding with content
.
* @param referenceID The reference ID to use in the signature for the
* DataObject
created.
* @return The DataObject
representing the data contained in
* dataObjectElem
.
* @throws MOAApplicationException An error occurred during the creation of
* the DataObject
.
* @throws MOASystemException A system error occurred during the creation of
* the DataObject
.
*/
private DataObject buildEnvelopingDataObject(
Content content,
MetaInfo finalDataMetaInfo,
String referenceID)
throws MOASystemException, MOAApplicationException {
DataObjectFactory factory = DataObjectFactory.getInstance();
DataObject dataObject;
dataObject =
factory.createFromContentOptionalRefType(
content,
finalDataMetaInfo,
referenceID,
false,
false,
true,
false);
return dataObject;
}
/**
* Build a DataObject
to be used in a detached signature.
*
* @param content The Content
object containing an the data.
* @param finalDataMetaInfo The meta information corresponding with content
.
* @param signatureEnvironment The signature environment where the signature
* will be inserted.
* @param referenceID The reference ID to use in the signature for the
* DataObject
created.
* @return The DataObject
representing the data contained in
* dataObjectElem
.
* @throws MOAApplicationException An error occurred during the creation of
* the DataObject
.
* @throws MOASystemException A system error occurred during the creation of
* the DataObject
.
*/
private DataObject buildDetachedDataObject(
Content content,
MetaInfo finalDataMetaInfo,
XMLDataObject signatureEnvironment,
String referenceID)
throws MOASystemException, MOAApplicationException {
String reference = content.getReference();
DataObjectFactory factory = DataObjectFactory.getInstance();
DataObject dataObject;
if (reference == null) {
throw new MOAApplicationException("1102", null);
} else if ("".equals(reference) || reference.startsWith("#")) {
dataObject =
factory.createFromSignatureEnvironment(
signatureEnvironment.getElement(),
reference,
referenceID);
} else {
dataObject =
factory.createFromContentOptionalRefType(
content,
finalDataMetaInfo,
referenceID,
true,
false,
true,
false);
}
return dataObject;
}
/**
* Build the signature parent element.
*
* @param signatureEnvironment The signature environment containing the
* document in which to insert the signature.
* @param singleSignatureInfo The SingleSignatureInfo
* containing the signature parent element.
* @return An XMLDataObject
containing the signature parent
* element or null
, if the CreateSignatureInfo
is
* null
.
* @throws MOAApplicationException An error occurred during the creation of
* the signature parent.
*/
private XMLDataObject buildSignatureParentElement(
Element signatureEnvironment,
SingleSignatureInfo singleSignatureInfo)
throws MOAApplicationException {
CreateSignatureInfo createInfo =
singleSignatureInfo.getCreateSignatureInfo();
// evaluate the CreateSignatureLocation
if (createInfo != null) {
TransactionContext context =
TransactionContextManager.getInstance().getTransactionContext();
ConfigurationProvider config = context.getConfiguration();
CreateSignatureEnvironmentProfileExplicit createProfile =
ProfileMapper.mapCreateSignatureEnvironmentProfile(
createInfo.getCreateSignatureEnvironmentProfile(),
config);
CreateSignatureLocation location =
createProfile.getCreateSignatureLocation();
Element signatureParent =
InvokerUtils.evaluateSignatureLocation(signatureEnvironment, location);
return new XMLDataObjectImpl(signatureParent);
} else {
return null;
}
}
/**
* Get the supplements contained in the
* CreateSignatureEnvironmentProfile
of the given
* SingleSignatureInfo
.
*
* @param singleSigInfo The SingleSignatureInfo
from which
* to extract the supplements.
* @return A List
of XMLDataObjectAssociation
s
* or null
, if the singleSigInfo
does not contain
* supplements.
* @throws MOAApplicationException An error occurred parsing the
* CreateSignatureEnvironmentProfile
.
*/
private List getCreateSignatureEnvironmentProfileSupplements(SingleSignatureInfo singleSigInfo)
throws MOAApplicationException {
CreateSignatureInfo sigInfo = singleSigInfo.getCreateSignatureInfo();
if (sigInfo != null) {
TransactionContext context =
TransactionContextManager.getInstance().getTransactionContext();
ConfigurationProvider config = context.getConfiguration();
CreateSignatureEnvironmentProfileExplicit profile =
ProfileMapper.mapCreateSignatureEnvironmentProfile(
sigInfo.getCreateSignatureEnvironmentProfile(),
config);
List supplements = profile.getSupplements();
return supplements;
}
return null;
}
/**
* Build the list of additional signed properties.
*
* Based on the generic configuration setting
* ConfigurationProvider.TEST_SIGNING_TIME_PROPERTY
, a
* constant SigningTime
will be added to the properties.
*
* @return The List
of additional signed properties.
*/
private List buildAdditionalSignedProperties() {
TransactionContext context =
TransactionContextManager.getInstance().getTransactionContext();
ConfigurationProvider config = context.getConfiguration();
List additionalSignedProperties = Collections.EMPTY_LIST;
return additionalSignedProperties;
}
}