package at.gv.egiz.moazs.client; import at.gv.egiz.moazs.preprocess.ConfigUtil; import at.gv.egiz.moazs.util.FileUtils; import at.gv.egiz.moazs.util.JAXBClassNotFoundFix; import at.gv.egiz.moazs.util.StoreSOAPBodyBinaryInRepositoryInterceptor; import at.gv.zustellung.app2mzs.xsd.ClientType; import at.gv.zustellung.app2mzs.xsd.KeyStoreType; import at.gv.zustellung.app2mzs.xsd.SSLType; import org.apache.cxf.configuration.jsse.TLSClientParameters; import org.apache.cxf.endpoint.Client; import org.apache.cxf.ext.logging.LoggingInInterceptor; import org.apache.cxf.ext.logging.LoggingOutInterceptor; import org.apache.cxf.frontend.ClientProxy; import org.apache.cxf.interceptor.Interceptor; import org.apache.cxf.jaxws.JaxWsClientFactoryBean; import org.apache.cxf.jaxws.JaxWsProxyFactoryBean; import org.apache.cxf.message.Message; import org.apache.cxf.transport.http.HTTPConduit; import org.apache.cxf.transports.http.configuration.HTTPClientPolicy; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import javax.annotation.Nullable; import javax.net.ssl.SSLContext; import javax.xml.ws.BindingProvider; import javax.xml.ws.soap.SOAPBinding; import static at.gv.zustellung.app2mzs.xsd.KeyStoreType.keyStoreTypeBuilder; @Component public class ClientFactory { private static final Logger log = LoggerFactory.getLogger(ClientFactory.class); private final StoreSOAPBodyBinaryInRepositoryInterceptor storeResponseInterceptor; private final SSLContextCreator sslContextCreator; private final FileUtils fileUtils; private final ConfigUtil configUtil; private static final Interceptor LOGGING_IN_INTERCEPTOR = new LoggingInInterceptor(); private static final Interceptor LOGGING_OUT_INTERCEPTOR = new LoggingOutInterceptor(); @Autowired public ClientFactory(StoreSOAPBodyBinaryInRepositoryInterceptor storeResponseInterceptor, SSLContextCreator creator, FileUtils fileUtils, ConfigUtil configUtil) { this.storeResponseInterceptor = storeResponseInterceptor; this.sslContextCreator = creator; this.fileUtils = fileUtils; this.configUtil = configUtil; } /** * Creates a client that communicates with a soap service. * * @param params for the client, such as service url and ssl parameters. * @return the client */ public T create(ClientType params, Class clazz) { return JAXBClassNotFoundFix.runInTheadWithClassClassLoader(() -> createClient(params, clazz)); } private T createClient(ClientType params, Class clazz) { log.info("Create client for service {}", params.getURL()); var factory = new JaxWsClientFactoryBean(); factory.setServiceClass(clazz); factory.setAddress(params.getURL()); factory.getInInterceptors().add(storeResponseInterceptor); setupLoggingInterceptors(factory); var proxy = new JaxWsProxyFactoryBean(factory).create(); Client client = ClientProxy.getClient(proxy); HTTPConduit http = (HTTPConduit) client.getConduit(); var bindingProvider = (BindingProvider) proxy; SOAPBinding binding = (SOAPBinding) bindingProvider.getBinding(); binding.setMTOMEnabled(true); var httpClientPolicy = new HTTPClientPolicy(); httpClientPolicy.setConnectionTimeout(params.getConnectionTimeout().longValueExact()); httpClientPolicy.setReceiveTimeout(params.getReceiveTimeout().longValueExact()); http.setClient(httpClientPolicy); var customHeaders = configUtil.convertHeadersToMap(params.getCustomHTTPHeader()); client.getRequestContext().put(Message.PROTOCOL_HEADERS, customHeaders); if (params.getURL().startsWith("https")) { TLSClientParameters tlsParams = setupTLSParams(params.getSSL()); http.setTlsClientParameters(tlsParams); log.info("SSLContext initialized. "); } return ((T)proxy); } private void setupLoggingInterceptors(JaxWsClientFactoryBean factory) { factory.getInInterceptors().add(LOGGING_IN_INTERCEPTOR); factory.getInFaultInterceptors().add(LOGGING_IN_INTERCEPTOR); factory.getOutInterceptors().add(LOGGING_OUT_INTERCEPTOR); factory.getOutFaultInterceptors().add(LOGGING_OUT_INTERCEPTOR); } private TLSClientParameters setupTLSParams(SSLType ssl) { var tlsParams = new TLSClientParameters(); var keystore = resolveKeyStorePath(ssl.getKeyStore()); SSLContext sslContext; if (ssl.isTrustAll()) { sslContext = sslContextCreator.createUnsafeSSLContext(keystore); } else { var truststore = resolveKeyStorePath(ssl.getTrustStore()); sslContext = sslContextCreator.createSSLContext(keystore, truststore); } tlsParams.setSSLSocketFactory(sslContext.getSocketFactory()); if (ssl.isLaxHostNameVerification()) { tlsParams.setDisableCNCheck(true); } return tlsParams; } private KeyStoreType resolveKeyStorePath(@Nullable KeyStoreType store) { if (store == null) return null; var resolvedURI = "file:" + fileUtils.determinePath(store.getFileName()); log.trace("Resolved key store path from {} to {}.", store.getFileName(), resolvedURI); return keyStoreTypeBuilder(store) .withFileName(resolvedURI) .build(); } }