/* * Copyright 2011 Federal Chancellery Austria and * Graz University of Technology * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package at.gv.util.client.moaspss; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.util.ArrayList; import java.util.List; import java.util.Map; import javax.net.ssl.SSLContext; import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBElement; import javax.xml.bind.JAXBException; import javax.xml.namespace.QName; import javax.xml.transform.Source; import javax.xml.transform.TransformerException; import javax.xml.transform.stream.StreamSource; import javax.xml.ws.BindingProvider; import javax.xml.ws.Dispatch; import javax.xml.ws.Service; import javax.xml.ws.handler.Handler; import javax.xml.ws.soap.SOAPBinding; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.Document; import org.w3c.dom.Element; import at.gv.util.DOMUtils; import at.gv.util.LaxHostNameVerifier; import at.gv.util.LoggingHandler; import at.gv.util.MiscUtil; import at.gv.util.config.EgovUtilConfiguration; import at.gv.util.ex.EgovUtilException; import at.gv.util.wsdl.SignatureCreationService; import at.gv.util.wsdl.SignatureVerificationService; import at.gv.util.xsd.moaspss.CreateXMLSignatureRequest; import at.gv.util.xsd.moaspss.CreateXMLSignatureResponseType; import at.gv.util.xsd.moaspss.ErrorResponseType; import at.gv.util.xsd.moaspss.VerifyXMLSignatureRequestType; import at.gv.util.xsd.moaspss.VerifyXMLSignatureResponseType; import com.sun.org.apache.xpath.internal.XPathAPI; import com.sun.xml.ws.developer.JAXWSProperties; /** * MOA-SS client. * * @author Arne Tauber * */ public class MOASPSSClient { private static Logger log = LoggerFactory.getLogger(MOASPSSClient.class); private EgovUtilConfiguration config = null; public MOASPSSClient(EgovUtilConfiguration config) { if (config == null) { throw new NullPointerException("Argument 'config' must not be null."); } this.config = config; } public MOASPSSClient() { } @SuppressWarnings("unchecked") public Element sendSignatureCreationRequest(String serviceURL, InputStream signatureCreationRequest) throws MOASPSSClientException { log.debug("Creating XML signature using raw CreateXMLSignatureRequest."); // check for arguments if (serviceURL == null) { throw new NullPointerException("Argument 'serviceURL' must not be null."); } if (signatureCreationRequest == null) { throw new NullPointerException( "Argument 'signatureRequest' must not be null."); } try { log.trace("MOA-SS signature service URL: " + serviceURL); URL url = MOASPSSClient.class.getResource("/wsdl/MOA-SPSS-1.3.wsdl"); SignatureCreationService service = new SignatureCreationService( url, new QName( "http://reference.e-government.gv.at/namespace/moa/20020822#moa.wsdl", "SignatureCreationService")); QName qname = new QName( "http://localhost:8080/moa-spss/services/SignatureCreation", "CreateXMLSignatureRequest"); service.addPort(qname, SOAPBinding.SOAP11HTTP_BINDING, serviceURL); ByteArrayOutputStream bos = new ByteArrayOutputStream(); MiscUtil.copyStream(signatureCreationRequest, bos); Source source = new StreamSource(new ByteArrayInputStream( bos.toByteArray())); Dispatch dispatch = service.createDispatch(qname, Source.class, Service.Mode.PAYLOAD); BindingProvider bindingProvider = (BindingProvider) dispatch; log.trace("Adding JAX-WS request/response trace handler."); List handlerList = bindingProvider.getBinding() .getHandlerChain(); if (handlerList == null) { handlerList = new ArrayList(); } LoggingHandler loggingHandler = new LoggingHandler(); handlerList.add(loggingHandler); bindingProvider.getBinding().setHandlerChain(handlerList); // initialize ssl Map requestContext = bindingProvider.getRequestContext(); if (serviceURL.toLowerCase().startsWith("https")) { log.trace("Using ssl for MOA-SP request."); if (this.config == null) { throw new MOASPSSClientException( "SSL requires client to be configured."); } SSLContext sslContext = this.config.getMOASPSSsslConfiguration() .getSSLContext(false); if (sslContext == null) { throw new MOASPSSClientException( "SSL context from configuration is empty. Please configure an SSL context in the configuration first."); } requestContext.put(JAXWSProperties.SSL_SOCKET_FACTORY, sslContext.getSocketFactory()); // check for lax hostname if (this.config.getMOASPSSsslConfiguration().useLaxHostNameVerifier()) { log.trace("LaxHostnameVerifier enabled. This setting is not recommended to use."); requestContext.put(JAXWSProperties.HOSTNAME_VERIFIER, new LaxHostNameVerifier()); } } log.trace("Invoking MOA-SS signature creation service."); Source response = dispatch.invoke(source); log.trace("Parsing MOA-SS response."); byte[] moaResponse = MiscUtil.sourceToByteArray(response); JAXBContext ctx = JAXBContext.newInstance(CreateXMLSignatureRequest.class .getPackage().getName()); JAXBElement jaxbElement = (JAXBElement) ctx .createUnmarshaller() .unmarshal(new ByteArrayInputStream(moaResponse)); CreateXMLSignatureResponseType createXMLResponse = jaxbElement.getValue(); for (Object obj : createXMLResponse .getSignatureEnvironmentOrErrorResponse()) { if (obj instanceof ErrorResponseType) { ErrorResponseType errorResponse = (ErrorResponseType) obj; log.trace("Could not create signature: " + errorResponse.getErrorCode() + "/" + errorResponse.getInfo()); throw new MOASPSSClientException("MOA-SS signature error: " + errorResponse.getErrorCode() + "/" + errorResponse.getInfo()); } } log.trace(new String(moaResponse)); log.trace("Signature successfully created. Extracting from MOA-SS container."); // ok, we have success Document doc = MiscUtil.parseDocument(new ByteArrayInputStream( moaResponse)); String xpathExpression = "/moa:CreateXMLSignatureResponse/moa:SignatureEnvironment/child::*"; Element nsNode = doc.createElement("NsNode"); nsNode.setAttribute("xmlns:moa", doc.getDocumentElement() .getNamespaceURI()); log.trace("Selecting signed doc " + xpathExpression); Element documentNode = (Element) XPathAPI.selectSingleNode(doc, xpathExpression, nsNode); log.trace("Signed document: " + DOMUtils.serializeNode(documentNode)); return documentNode; } catch (TransformerException e) { throw new MOASPSSClientException(e); } catch (IOException e) { throw new MOASPSSClientException(e); } catch (JAXBException e) { throw new MOASPSSClientException(e); } catch (EgovUtilException e) { throw new MOASPSSClientException(e); } } @SuppressWarnings("unchecked") public VerifyXMLSignatureResponseType sendSignatureVerificationRequest( String serviceURL, InputStream signatureVerificationRequest) throws MOASPSSClientException { log.debug("Verifying XML signature using raw VerifyXMLSignatureRequest."); // check for arguments if (serviceURL == null) { throw new NullPointerException("Argument 'serviceURL' must not be null."); } if (signatureVerificationRequest == null) { throw new NullPointerException( "Argument 'signatureRequest' must not be null."); } try { log.trace("MOA-SP verification service URL: " + serviceURL); URL url = MOASPSSClient.class.getResource("/wsdl/MOA-SPSS-1.3.wsdl"); SignatureVerificationService service = new SignatureVerificationService( url, new QName( "http://reference.e-government.gv.at/namespace/moa/20020822#moa.wsdl", "SignatureCreationService")); QName qname = new QName( "http://localhost:8080/moa-spss/services/SignatureVerification", "VerifyXMLSignatureRequest"); service.addPort(qname, SOAPBinding.SOAP11HTTP_BINDING, serviceURL); ByteArrayOutputStream bos = new ByteArrayOutputStream(); MiscUtil.copyStream(signatureVerificationRequest, bos); Source source = new StreamSource(new ByteArrayInputStream( bos.toByteArray())); Dispatch dispatch = service.createDispatch(qname, Source.class, Service.Mode.PAYLOAD); BindingProvider bindingProvider = (BindingProvider) dispatch; log.trace("Adding JAX-WS request/response trace handler."); List handlerList = bindingProvider.getBinding() .getHandlerChain(); if (handlerList == null) { handlerList = new ArrayList(); } LoggingHandler loggingHandler = new LoggingHandler(); handlerList.add(loggingHandler); bindingProvider.getBinding().setHandlerChain(handlerList); // initialize ssl Map requestContext = bindingProvider.getRequestContext(); if (serviceURL.toLowerCase().startsWith("https")) { log.trace("Using ssl for MOA-SP request."); if (this.config == null) { throw new MOASPSSClientException( "SSL requires client to be configured."); } SSLContext sslContext = this.config.getMOASPSSsslConfiguration() .getSSLContext(false); if (sslContext == null) { throw new MOASPSSClientException( "SSL context from configuration is empty. Please configure an SSL context in the configuration first."); } requestContext.put(JAXWSProperties.SSL_SOCKET_FACTORY, sslContext.getSocketFactory()); // check for lax hostname if (this.config.getMOASPSSsslConfiguration().useLaxHostNameVerifier()) { log.trace("LaxHostnameVerifier enabled. This setting is not recommended to use."); requestContext.put(JAXWSProperties.HOSTNAME_VERIFIER, new LaxHostNameVerifier()); } } log.trace("Invoking MOA-SP signature verification service."); Source response = dispatch.invoke(source); log.trace("Parsing MOA-SP response."); byte[] moaResponse = MiscUtil.sourceToByteArray(response); JAXBContext ctx = JAXBContext .newInstance(VerifyXMLSignatureRequestType.class.getPackage() .getName()); JAXBElement jaxbElement = (JAXBElement) ctx .createUnmarshaller() .unmarshal(new ByteArrayInputStream(moaResponse)); VerifyXMLSignatureResponseType verifyXMLResponse = jaxbElement.getValue(); log.trace(new String(moaResponse)); return verifyXMLResponse; } catch (TransformerException e) { throw new MOASPSSClientException(e); } catch (IOException e) { throw new MOASPSSClientException(e); } catch (JAXBException e) { throw new MOASPSSClientException(e); } catch (EgovUtilException e) { throw new MOASPSSClientException(e); } } public static boolean isSuccess(VerifyXMLSignatureResponseType verifyResult) { if (verifyResult == null) { throw new NullPointerException( "Argument 'verifyResult' must not be null."); } log.trace("Checking for signature verification result."); int signatureCheckCode = verifyResult.getSignatureCheck().getCode() .intValue(); int signtaureManifestCheckCode = verifyResult.getSignatureManifestCheck() .getCode().intValue(); int certificateCheckCode = verifyResult.getCertificateCheck().getCode() .intValue(); log.trace("Signature check code: " + signatureCheckCode); log.trace("Signature manifest check code: " + signtaureManifestCheckCode); log.trace("Certificate check code: " + certificateCheckCode); return signatureCheckCode == 0 && signtaureManifestCheckCode == 0 && certificateCheckCode == 0; } }