be.fedict.eid.dss.ws.DigitalSignatureServicePortImpl.java Source code

Java tutorial

Introduction

Here is the source code for be.fedict.eid.dss.ws.DigitalSignatureServicePortImpl.java

Source

/*
 * eID Digital Signature Service Project.
 * Copyright (C) 2009-2010 FedICT.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License version
 * 3.0 as published by the Free Software Foundation.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, see 
 * http://www.gnu.org/licenses/.
 */

package be.fedict.eid.dss.ws;

import java.util.LinkedList;
import java.util.List;
import java.util.UUID;

import javax.ejb.EJB;
import javax.jws.WebService;
import javax.xml.bind.JAXBException;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.joda.time.DateTime;
import org.w3c.dom.Element;

import be.fedict.eid.dss.entity.DocumentEntity;
import be.fedict.eid.dss.model.DocumentService;
import be.fedict.eid.dss.model.SignatureVerificationService;
import be.fedict.eid.dss.model.exception.DocumentFormatException;
import be.fedict.eid.dss.model.exception.InvalidSignatureException;
import be.fedict.eid.dss.spi.SignatureInfo;
import be.fedict.eid.dss.ws.jaxb.dss.AnyType;
import be.fedict.eid.dss.ws.jaxb.dss.Base64Data;
import be.fedict.eid.dss.ws.jaxb.dss.DocumentType;
import be.fedict.eid.dss.ws.jaxb.dss.DocumentWithSignature;
import be.fedict.eid.dss.ws.jaxb.dss.InputDocuments;
import be.fedict.eid.dss.ws.jaxb.dss.ObjectFactory;
import be.fedict.eid.dss.ws.jaxb.dss.ResponseBaseType;
import be.fedict.eid.dss.ws.jaxb.dss.Result;
import be.fedict.eid.dss.ws.jaxb.dss.SignRequest;
import be.fedict.eid.dss.ws.jaxb.dss.SignResponse;
import be.fedict.eid.dss.ws.jaxb.dss.VerifyRequest;
import be.fedict.eid.dss.ws.profile.artifact.jaxb.ReturnStoredDocument;
import be.fedict.eid.dss.ws.profile.artifact.jaxb.StorageInfo;
import be.fedict.eid.dss.ws.profile.artifact.jaxb.ValidityType;

import com.sun.xml.ws.developer.UsesJAXBContext;

/**
 * Implementation of the DSS verification web service JAX-WS endpoint.
 * <p/>
 * TODO: we can use this directly as servlet in web.xml. Before doing so we
 * should activate the Metro JBossWS.
 * 
 * @author Frank Cornelis
 */
@WebService(endpointInterface = "be.fedict.eid.dss.ws.DigitalSignatureServicePortType")
@ServiceConsumer
@UsesJAXBContext(DSSJAXBContextFactory.class)
public class DigitalSignatureServicePortImpl implements DigitalSignatureServicePortType {

    private static final Log LOG = LogFactory.getLog(DigitalSignatureServicePortImpl.class);

    @EJB
    private SignatureVerificationService signatureVerificationService;

    @EJB
    private DocumentService documentService;

    @Override
    public ResponseBaseType verify(VerifyRequest verifyRequest) {

        LOG.debug("verify");

        /*
         * Parse the request.
         */
        String requestId = verifyRequest.getRequestID();
        LOG.debug("request Id: " + requestId);
        List<DocumentDO> documents = getDocuments(verifyRequest.getInputDocuments());

        if (documents.isEmpty()) {
            return DSSUtil.createRequestorErrorResponse(requestId, null, "No valid document found to validate.");
        }
        if (documents.size() != 1) {
            return DSSUtil.createRequestorErrorResponse(requestId, null, "Can validate only one document.");
        }
        byte[] data = documents.get(0).getDocumentData();
        String mimeType = documents.get(0).getContentType();

        byte[] originalData = null;
        boolean returnVerificationReport = false;
        AnyType optionalInput = verifyRequest.getOptionalInputs();
        if (null != optionalInput) {
            List<Object> anyObjects = optionalInput.getAny();
            for (Object anyObject : anyObjects) {
                if (anyObject instanceof Element) {
                    Element element = (Element) anyObject;
                    if (DSSConstants.VR_NAMESPACE.equals(element.getNamespaceURI())
                            && "ReturnVerificationReport".equals(element.getLocalName())) {
                        /*
                         * We could check for supported ReturnVerificationReport
                         * input, but then again, who cares?
                         */
                        returnVerificationReport = true;
                    }
                    if (DSSConstants.ORIGINAL_DOCUMENT_NAMESPACE.equals(element.getNamespaceURI())
                            && DSSConstants.ORIGINAL_DOCUMENT_ELEMENT.equals(element.getLocalName())) {
                        try {
                            originalData = DSSUtil.getOriginalDocument(element);
                        } catch (JAXBException e) {
                            return DSSUtil.createRequestorErrorResponse(requestId,
                                    DSSConstants.RESULT_MINOR_NOT_PARSEABLE_XML_DOCUMENT);
                        }
                    }
                }
            }
        }

        /*
         * Invoke the underlying DSS verification service.
         */
        List<SignatureInfo> signatureInfos;
        try {
            signatureInfos = this.signatureVerificationService.verify(data, mimeType, originalData);
        } catch (DocumentFormatException e) {
            return DSSUtil.createRequestorErrorResponse(requestId,
                    DSSConstants.RESULT_MINOR_NOT_PARSEABLE_XML_DOCUMENT);
        } catch (InvalidSignatureException e) {
            return DSSUtil.createRequestorErrorResponse(requestId);
        }

        /*
         * Construct the DSS response.
         */
        ObjectFactory dssObjectFactory = new ObjectFactory();

        ResponseBaseType responseBase = dssObjectFactory.createResponseBaseType();
        responseBase.setRequestID(requestId);
        Result result = dssObjectFactory.createResult();
        result.setResultMajor(DSSConstants.RESULT_MAJOR_SUCCESS);
        AnyType optionalOutput = dssObjectFactory.createAnyType();
        if (signatureInfos.size() > 1) {
            result.setResultMinor(DSSConstants.RESULT_MINOR_VALID_MULTI_SIGNATURES);
        } else if (1 == signatureInfos.size()) {
            result.setResultMinor(DSSConstants.RESULT_MINOR_VALID_SIGNATURE);
        } else {
            result.setResultMinor(DSSConstants.RESULT_MINOR_INVALID_SIGNATURE);
        }

        if (returnVerificationReport) {
            DSSUtil.addVerificationReport(optionalOutput, signatureInfos);
        }

        if (!optionalOutput.getAny().isEmpty()) {
            responseBase.setOptionalOutputs(optionalOutput);
        }

        responseBase.setResult(result);
        return responseBase;
    }

    @Override
    public SignResponse sign(SignRequest signRequest) {

        LOG.debug("sign");

        // parse request
        String requestId = signRequest.getRequestID();
        LOG.debug("request Id: " + requestId);

        // verify profile
        String profile = signRequest.getProfile();
        LOG.debug("signRequest.profile: " + profile);
        if (!profile.equals(DSSConstants.ARTIFACT_NAMESPACE)) {
            return DSSUtil.createRequestorSignErrorResponse(requestId, DSSConstants.RESULT_MINOR_NOT_SUPPORTED,
                    "Profile not supported.");
        }

        // parse OptionalInput's
        boolean returnStorageInfo = false;
        String documentId = null;

        AnyType optionalInputs = signRequest.getOptionalInputs();
        if (null == optionalInputs) {
            return DSSUtil.createRequestorSignErrorResponse(requestId, DSSConstants.RESULT_MINOR_NOT_SUPPORTED,
                    "Expecting Artifact Binding OptionalInputs...");
        }
        for (Object optionalInputObject : optionalInputs.getAny()) {

            if (optionalInputObject instanceof Element) {

                Element element = (Element) optionalInputObject;

                if (DSSConstants.ARTIFACT_NAMESPACE.equals(element.getNamespaceURI())
                        && DSSConstants.RETURN_STORAGE_INFO.equals(element.getLocalName())) {

                    returnStorageInfo = true;

                } else if (DSSConstants.ARTIFACT_NAMESPACE.equals(element.getNamespaceURI())
                        && DSSConstants.RETURN_STORED_DOCUMENT.equals(element.getLocalName())) {

                    try {
                        ReturnStoredDocument returnStoredDocument = DSSUtil.getReturnStoredDocument(element);
                        documentId = returnStoredDocument.getIdentifier();
                    } catch (JAXBException e) {

                        return DSSUtil.createRequestorSignErrorResponse(requestId,
                                DSSConstants.RESULT_MINOR_NOT_SUPPORTED,
                                "Failed to unmarshall \"ReturnStoredDocument\"" + " element.");
                    }

                } else {

                    return DSSUtil.createRequestorSignErrorResponse(requestId,
                            DSSConstants.RESULT_MINOR_NOT_SUPPORTED,
                            "Unexpected OptionalInput: \"" + element.getLocalName() + "\"");

                }
            }
        }

        if (!returnStorageInfo && null == documentId || returnStorageInfo && null != documentId) {

            return DSSUtil.createRequestorSignErrorResponse(requestId, DSSConstants.RESULT_MINOR_NOT_SUPPORTED,
                    "Missing Artifact Binding OptionalInputs...");
        }

        if (returnStorageInfo) {

            return storageInfoResponse(signRequest);
        } else {

            return storedDocumentResponse(signRequest, documentId);
        }
    }

    private SignResponse storedDocumentResponse(SignRequest signRequest, String documentId) {

        // construct response
        ObjectFactory dssObjectFactory = new ObjectFactory();

        SignResponse signResponse = dssObjectFactory.createSignResponse();
        signResponse.setRequestID(signRequest.getRequestID());
        signResponse.setProfile(DSSConstants.ARTIFACT_NAMESPACE);

        Result result = dssObjectFactory.createResult();
        signResponse.setResult(result);
        result.setResultMajor(DSSConstants.RESULT_MAJOR_SUCCESS);

        // add signed document
        DocumentEntity documentEntity = this.documentService.retrieve(documentId);
        if (null == documentEntity) {
            return DSSUtil.createRequestorSignErrorResponse(signRequest.getRequestID(),
                    DSSConstants.RESULT_MINOR_NOT_SUPPORTED, "Document not found or expired...");
        }
        String mimeType = documentEntity.getContentType();

        DocumentWithSignature documentWithSignature = dssObjectFactory.createDocumentWithSignature();
        DocumentType document = dssObjectFactory.createDocumentType();
        documentWithSignature.setDocument(document);
        if (null == mimeType || "text/xml".equals(mimeType)) {
            document.setBase64XML(documentEntity.getData());
        } else {
            Base64Data base64Data = dssObjectFactory.createBase64Data();
            base64Data.setValue(documentEntity.getData());
            base64Data.setMimeType(mimeType);
            document.setBase64Data(base64Data);
        }
        AnyType optionalOutputs = dssObjectFactory.createAnyType();
        signResponse.setOptionalOutputs(optionalOutputs);
        optionalOutputs.getAny().add(documentWithSignature);

        return signResponse;
    }

    private SignResponse storageInfoResponse(SignRequest signRequest) {

        List<DocumentDO> documents = getDocuments(signRequest.getInputDocuments());

        if (documents.isEmpty()) {
            return DSSUtil.createRequestorSignErrorResponse(signRequest.getRequestID(), null,
                    "No valid document found to validate.");
        }
        if (documents.size() != 1) {
            return DSSUtil.createRequestorSignErrorResponse(signRequest.getRequestID(), null,
                    "Can validate only one document.");
        }

        // store artifact
        String documentId = UUID.randomUUID().toString();

        DateTime expiration = this.documentService.store(documentId, documents.get(0).getDocumentData(),
                documents.get(0).getContentType());

        // construct response
        ObjectFactory dssObjectFactory = new ObjectFactory();
        be.fedict.eid.dss.ws.profile.artifact.jaxb.ObjectFactory artifactObjectFactory = new be.fedict.eid.dss.ws.profile.artifact.jaxb.ObjectFactory();

        SignResponse signResponse = dssObjectFactory.createSignResponse();
        signResponse.setRequestID(signRequest.getRequestID());
        signResponse.setProfile(DSSConstants.ARTIFACT_NAMESPACE);

        Result result = dssObjectFactory.createResult();
        signResponse.setResult(result);

        result.setResultMajor(DSSConstants.RESULT_MAJOR_SUCCESS);

        AnyType optionalOutputs = dssObjectFactory.createAnyType();
        signResponse.setOptionalOutputs(optionalOutputs);

        StorageInfo storageInfo = artifactObjectFactory.createStorageInfo();
        storageInfo.setIdentifier(documentId);
        ValidityType validity = artifactObjectFactory.createValidityType();
        validity.setNotBefore(DSSUtil.toXML(new DateTime()));
        validity.setNotAfter(DSSUtil.toXML(expiration));
        storageInfo.setValidity(validity);

        optionalOutputs.getAny().add(DSSUtil.getStorageInfoElement(storageInfo));

        return signResponse;
    }

    class DocumentDO {

        private final byte[] documentData;
        private final String contentType;

        public DocumentDO(byte[] documentData, String contentType) {
            this.documentData = documentData;
            this.contentType = contentType;
        }

        public byte[] getDocumentData() {
            return documentData;
        }

        public String getContentType() {
            return contentType;
        }
    }

    private List<DocumentDO> getDocuments(InputDocuments inputDocuments) {

        List<DocumentDO> documents = new LinkedList<DocumentDO>();
        List<Object> documentObjects = inputDocuments.getDocumentOrTransformedDataOrDocumentHash();

        for (Object documentObject : documentObjects) {

            if (!(documentObject instanceof DocumentType)) {
                continue;
            }
            DocumentType document = (DocumentType) documentObject;
            Base64Data base64Data = document.getBase64Data();
            byte[] data;
            String mimeType;
            if (null != base64Data) {
                data = base64Data.getValue();
                mimeType = base64Data.getMimeType();
            } else {
                data = document.getBase64XML();
                mimeType = "text/xml";
            }
            if (null == data || null == mimeType) {
                continue;
            }
            documents.add(new DocumentDO(data, mimeType));
        }
        return documents;
    }
}