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 * 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 DataObjects from the given * SingleSignatureInfo object. * *

* Only the following cases of DataObjects 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 DataObjects 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 The SingleSignatureInfo 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 DataObjects 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 XMLDataObjectAssociations * 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; } }