aboutsummaryrefslogtreecommitdiff
path: root/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/szr/SzrClient.java
diff options
context:
space:
mode:
Diffstat (limited to 'eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/szr/SzrClient.java')
-rw-r--r--eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/szr/SzrClient.java408
1 files changed, 408 insertions, 0 deletions
diff --git a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/szr/SzrClient.java b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/szr/SzrClient.java
new file mode 100644
index 00000000..763d8dab
--- /dev/null
+++ b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/szr/SzrClient.java
@@ -0,0 +1,408 @@
+/*
+ * Copyright 2018 A-SIT Plus GmbH
+ * AT-specific eIDAS Connector has been developed in a cooperation between EGIZ,
+ * A-SIT Plus GmbH, A-SIT, and Graz University of Technology.
+ *
+ * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by
+ * the European Commission - subsequent versions of the EUPL (the "License");
+ * You may not use this work except in compliance with the License.
+ * You may obtain a copy of the License at:
+ * https://joinup.ec.europa.eu/news/understanding-eupl-v12
+ *
+ * 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.
+ *
+ * This product combines work with different licenses. See the "NOTICE" text
+ * file for details on the various modules and licenses.
+ * The "NOTICE" text file is part of the distribution. Any derivative works
+ * that you distribute must include a readable copy of the "NOTICE" text file.
+ */
+
+package at.asitplus.eidas.specific.modules.auth.eidas.v2.szr;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.net.URL;
+import java.security.KeyManagementException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.security.UnrecoverableKeyException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import javax.annotation.PostConstruct;
+import javax.net.ssl.KeyManager;
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.TrustManagerFactory;
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.Marshaller;
+import javax.xml.namespace.QName;
+import javax.xml.transform.Source;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.stream.StreamResult;
+import javax.xml.transform.stream.StreamSource;
+import javax.xml.ws.BindingProvider;
+import javax.xml.ws.Dispatch;
+import javax.xml.ws.handler.Handler;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.cxf.configuration.jsse.TLSClientParameters;
+import org.apache.cxf.endpoint.Client;
+import org.apache.cxf.frontend.ClientProxy;
+import org.apache.cxf.jaxws.DispatchImpl;
+import org.apache.cxf.transport.http.HTTPConduit;
+import org.apache.cxf.transports.http.configuration.HTTPClientPolicy;
+import org.apache.xpath.XPathAPI;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+import at.asitplus.eidas.specific.modules.auth.eidas.v2.Constants;
+import at.asitplus.eidas.specific.modules.auth.eidas.v2.exception.SzrCommunicationException;
+import at.asitplus.eidas.specific.modules.auth.eidas.v2.utils.LoggingHandler;
+import at.gv.egiz.eaaf.core.api.data.XmlNamespaceConstants;
+import at.gv.egiz.eaaf.core.api.idp.IConfiguration;
+import at.gv.egiz.eaaf.core.impl.utils.DomUtils;
+import at.gv.egiz.eaaf.core.impl.utils.FileUtils;
+import at.gv.egiz.eaaf.core.impl.utils.KeyStoreUtils;
+import szrservices.GetBPK;
+import szrservices.GetBPKResponse;
+import szrservices.GetIdentityLinkEidas;
+import szrservices.GetIdentityLinkEidasResponse;
+import szrservices.IdentityLinkType;
+import szrservices.ObjectFactory;
+import szrservices.PersonInfoType;
+import szrservices.SZR;
+import szrservices.SZRException_Exception;
+
+@Service("SZRClientForeIDAS")
+public class SzrClient {
+ private static final Logger log = LoggerFactory.getLogger(SzrClient.class);
+
+ private static final String CLIENT_DEFAULT = "DefaultClient";
+ private static final String CLIENT_RAW = "RawClient";
+
+ @Autowired
+ private IConfiguration basicConfig;
+
+ // client for anything, without identitylink
+ private SZR szr = null;
+
+ // RAW client is needed for identitylink
+ private Dispatch<Source> dispatch = null;
+
+ private SzrService szrService = null;
+ private String szrUrl = null;
+ private QName qname = null;
+
+ /**
+ * Get IdentityLink of a person.
+ *
+ * @param personInfo Person identification information
+ * @return IdentityLink
+ * @throws SzrCommunicationException In case of a SZR error
+ */
+ public IdentityLinkType getIdentityLinkInRawMode(PersonInfoType personInfo)
+ throws SzrCommunicationException {
+ try {
+ final GetIdentityLinkEidas getIdl = new GetIdentityLinkEidas();
+ getIdl.setPersonInfo(personInfo);
+
+ final JAXBContext jaxbContext = JAXBContext.newInstance(ObjectFactory.class);
+ final Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
+
+ final ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+ jaxbMarshaller.marshal(getIdl, outputStream);
+ outputStream.flush();
+
+ final Source source = new StreamSource(new ByteArrayInputStream(outputStream.toByteArray()));
+ outputStream.close();
+
+ log.trace("Requesting SZR ... ");
+ final Source response = dispatch.invoke(source);
+ log.trace("Receive RAW response from SZR");
+
+ final byte[] szrResponse = sourceToByteArray(response);
+ final GetIdentityLinkEidasResponse jaxbElement = (GetIdentityLinkEidasResponse) jaxbContext
+ .createUnmarshaller().unmarshal(new ByteArrayInputStream(szrResponse));
+
+ // build response
+ log.trace(new String(szrResponse, "UTF-8"));
+
+ // ok, we have success
+ final Document doc = DomUtils.parseDocument(
+ new ByteArrayInputStream(szrResponse),
+ true,
+ XmlNamespaceConstants.ALL_SCHEMA_LOCATIONS + " " + Constants.SZR_SCHEMA_LOCATIONS,
+ null, null);
+ final String xpathExpression = "//saml:Assertion";
+ final Element nsNode = doc.createElementNS("urn:oasis:names:tc:SAML:1.0:assertion", "saml:NSNode");
+
+ log.trace("Selecting signed doc " + xpathExpression);
+ final Element documentNode = (Element) XPathAPI.selectSingleNode(doc,
+ xpathExpression, nsNode);
+ log.trace("Signed document: " + DomUtils.serializeNode(documentNode));
+
+ final IdentityLinkType idl = new IdentityLinkType();
+ idl.setAssertion(documentNode);
+ idl.setPersonInfo(jaxbElement.getGetIdentityLinkReturn().getPersonInfo());
+
+ return idl;
+
+ } catch (final Exception e) {
+ log.warn("SZR communication FAILED. Reason: " + e.getMessage(), e);
+ throw new SzrCommunicationException("ernb.02", new Object[] { e.getMessage() }, e);
+
+ }
+
+ }
+
+ /**
+ * Get bPK of person.
+ *
+ * @param personInfo Person identification information
+ * @param target requested bPK target
+ * @param vkz Verfahrenskennzeichen
+ * @return bPK for this person
+ * @throws SzrCommunicationException In case of a SZR error
+ */
+ public String getBpk(PersonInfoType personInfo, String target, String vkz)
+ throws SzrCommunicationException {
+ try {
+ final GetBPK parameters = new GetBPK();
+ parameters.setPersonInfo(personInfo);
+ parameters.setBereichsKennung(target);
+ parameters.setVKZ(vkz);
+ final GetBPKResponse result = this.szr.getBPK(parameters);
+
+ return result.getGetBPKReturn();
+
+ } catch (final SZRException_Exception e) {
+ log.warn("SZR communication FAILED. Reason: " + e.getMessage(), e);
+ throw new SzrCommunicationException("ernb.02", new Object[] { e.getMessage() }, e);
+
+ }
+
+ }
+
+ @PostConstruct
+ private void initialize() {
+ log.info("Starting SZR-Client initialization .... ");
+ final URL url = SzrClient.class.getResource("/szr_client/SZR-1.1.WSDL");
+
+ final boolean useTestSzr = basicConfig.getBasicConfigurationBoolean(
+ Constants.CONIG_PROPS_EIDAS_SZRCLIENT_USETESTSERVICE,
+ true);
+
+ if (useTestSzr) {
+ log.debug("Initializing SZR test environment configuration.");
+ qname = SzrService.SZRTestumgebung;
+ szrService = new SzrService(url, new QName("urn:SZRServices", "SZRService"));
+ szr = szrService.getSzrTestumgebung();
+ szrUrl = basicConfig.getBasicConfiguration(Constants.CONIG_PROPS_EIDAS_SZRCLIENT_ENDPOINT_TEST);
+
+ } else {
+ log.debug("Initializing SZR productive configuration.");
+ qname = SzrService.SZRProduktionsumgebung;
+ szrService = new SzrService(url, new QName("urn:SZRServices", "SZRService"));
+ szr = szrService.getSzrProduktionsumgebung();
+ szrUrl = basicConfig.getBasicConfiguration(Constants.CONIG_PROPS_EIDAS_SZRCLIENT_ENDPOINT_PROD);
+
+ }
+
+ // create raw client;
+ dispatch = szrService.createDispatch(qname, Source.class, javax.xml.ws.Service.Mode.PAYLOAD);
+
+ if (StringUtils.isEmpty(szrUrl)) {
+ log.error("No SZR service-URL found. SZR-Client initalisiation failed.");
+ throw new RuntimeException("No SZR service URL found. SZR-Client initalisiation failed.");
+
+ }
+
+ // check if Clients can be initialized
+ if (szr == null) {
+ log.error("SZR " + CLIENT_DEFAULT + " is 'NULL'. Something goes wrong");
+ throw new RuntimeException("SZR " + CLIENT_DEFAULT + " is 'NULL'. Something goes wrong");
+
+ }
+ if (dispatch == null) {
+ log.error("SZR " + CLIENT_RAW + " is 'NULL'. Something goes wrong");
+ throw new RuntimeException("SZR " + CLIENT_RAW + " is 'NULL'. Something goes wrong");
+
+ }
+
+ // inject handler
+ log.info("Use SZR service-URL: " + szrUrl);
+ injectBindingProvider((BindingProvider) szr, CLIENT_DEFAULT);
+ injectBindingProvider(dispatch, CLIENT_RAW);
+
+ // inject http parameters and SSL context
+ log.debug("Inject HTTP client settings ... ");
+ injectHttpClient(szr, CLIENT_DEFAULT);
+ injectHttpClient(dispatch, CLIENT_RAW);
+
+ log.info("SZR-Client initialization successfull");
+ }
+
+ private void injectHttpClient(Object raw, String clientType) {
+ // extract client from implementation
+ Client client = null;
+ if (raw instanceof DispatchImpl<?>) {
+ client = ((DispatchImpl<?>) raw).getClient();
+ } else if (raw instanceof Client) {
+ client = ClientProxy.getClient(raw);
+ } else {
+ throw new RuntimeException("SOAP Client for SZR connection is of UNSUPPORTED type: " + raw.getClass()
+ .getName());
+ }
+
+ // set basic connection policies
+ final HTTPConduit http = (HTTPConduit) client.getConduit();
+
+ // set timeout policy
+ final HTTPClientPolicy httpClientPolicy = new HTTPClientPolicy();
+ httpClientPolicy.setConnectionTimeout(
+ Integer.parseInt(basicConfig.getBasicConfiguration(
+ Constants.CONIG_PROPS_EIDAS_SZRCLIENT_TIMEOUT_CONNECTION,
+ Constants.HTTP_CLIENT_DEFAULT_TIMEOUT_CONNECTION)) * 1000);
+ httpClientPolicy.setReceiveTimeout(
+ Integer.parseInt(basicConfig.getBasicConfiguration(
+ Constants.CONIG_PROPS_EIDAS_SZRCLIENT_TIMEOUT_RESPONSE,
+ Constants.HTTP_CLIENT_DEFAULT_TIMEOUT_RESPONSE)) * 1000);
+ http.setClient(httpClientPolicy);
+
+ // inject SSL context in case of https
+ if (szrUrl.toLowerCase().startsWith("https")) {
+ log.debug("Adding SSLContext to client: " + clientType + " ... ");
+ final TLSClientParameters tlsParams = new TLSClientParameters();
+ tlsParams.setSSLSocketFactory(createSslContext(clientType).getSocketFactory());
+ http.setTlsClientParameters(tlsParams);
+ log.info("SSLContext initialized for client: " + clientType);
+
+ }
+
+ }
+
+ private void injectBindingProvider(BindingProvider bindingProvider, String clientType) {
+ final Map<String, Object> requestContext = bindingProvider.getRequestContext();
+ requestContext.put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, szrUrl);
+
+ log.trace("Adding JAX-WS request/response trace handler to client: " + clientType);
+ List<Handler> handlerList = bindingProvider.getBinding().getHandlerChain();
+ if (handlerList == null) {
+ handlerList = new ArrayList<>();
+ bindingProvider.getBinding().setHandlerChain(handlerList);
+
+ }
+
+ // add logging handler to trace messages if required
+ if (basicConfig.getBasicConfigurationBoolean(
+ Constants.CONIG_PROPS_EIDAS_SZRCLIENT_DEBUG_TRACEMESSAGES,
+ false)) {
+ final LoggingHandler loggingHandler = new LoggingHandler();
+ handlerList.add(loggingHandler);
+
+ }
+ bindingProvider.getBinding().setHandlerChain(handlerList);
+ }
+
+ private SSLContext createSslContext(String clientType) {
+ try {
+ final SSLContext context = SSLContext.getInstance("TLS");
+
+ // initialize key-mangager for SSL client-authentication
+ KeyManager[] keyManager = null;
+ final String keyStorePath = basicConfig.getBasicConfiguration(
+ Constants.CONIG_PROPS_EIDAS_SZRCLIENT_SSL_KEYSTORE_PATH);
+ final String keyStorePassword = basicConfig.getBasicConfiguration(
+ Constants.CONIG_PROPS_EIDAS_SZRCLIENT_SSL_KEYSTORE_PASSWORD);
+ if (StringUtils.isNotEmpty(keyStorePath)) {
+ log.trace("Find keyStore path: " + keyStorePath + " Injecting SSL client certificate ... ");
+ try {
+ final KeyStore keyStore = KeyStoreUtils.loadKeyStore(
+ FileUtils.makeAbsoluteUrl(keyStorePath, basicConfig.getConfigurationRootDirectory()),
+ keyStorePassword);
+
+ final KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
+ kmf.init(keyStore, keyStorePassword.toCharArray());
+ keyManager = kmf.getKeyManagers();
+ log.debug("SSL client certificate injected to client: " + clientType);
+
+ } catch (KeyStoreException | IOException | UnrecoverableKeyException e) {
+ log.error("Can NOT load SSL client certificate from path: " + keyStorePath);
+ throw new RuntimeException("Can NOT load SSL client certificate from path: " + keyStorePath, e);
+
+ }
+ } else {
+ log.debug(
+ "No KeyStore for SSL Client Auth. found. Initializing SSLContext without authentication ... ");
+
+ }
+
+ // initialize SSL TrustStore
+ TrustManager[] trustManager = null;
+ final String trustStorePath = basicConfig.getBasicConfiguration(
+ Constants.CONIG_PROPS_EIDAS_SZRCLIENT_SSL_TRUSTSTORE_PATH);
+ final String trustStorePassword = basicConfig.getBasicConfiguration(
+ Constants.CONIG_PROPS_EIDAS_SZRCLIENT_SSL_TRUSTSTORE_PASSWORD);
+ if (StringUtils.isNotEmpty(trustStorePath)) {
+ log.trace("Find trustStore path: " + trustStorePath + " Injecting SSL TrustStore ... ");
+ try {
+ final KeyStore trustStore = KeyStoreUtils.loadKeyStore(
+ FileUtils.makeAbsoluteUrl(trustStorePath, basicConfig.getConfigurationRootDirectory()),
+ trustStorePassword);
+
+ final TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
+ tmf.init(trustStore);
+ trustManager = tmf.getTrustManagers();
+ log.debug("SSL TrustStore injected to client: " + clientType);
+
+ } catch (KeyStoreException | IOException e) {
+ log.error("Can NOT open SSL TrustStore from path: " + trustStorePath);
+ throw new RuntimeException("Can NOT open SSL TrustStore from path: " + trustStorePath, e);
+
+ }
+
+ } else {
+ log.debug("No custom SSL TrustStore found. Initializing SSLContext with JVM default truststore ... ");
+
+ }
+
+ context.init(keyManager, trustManager, new SecureRandom());
+ return context;
+
+ } catch (NoSuchAlgorithmException | KeyManagementException e) {
+ log.error("SSLContext initialization FAILED.", e);
+ throw new RuntimeException("SSLContext initialization FAILED.", e);
+
+ }
+
+ }
+
+ private byte[] sourceToByteArray(Source result) throws TransformerException {
+ final TransformerFactory factory = TransformerFactory.newInstance();
+ final Transformer transformer = factory.newTransformer();
+ transformer.setOutputProperty("omit-xml-declaration", "yes");
+ transformer.setOutputProperty("method", "xml");
+ final ByteArrayOutputStream out = new ByteArrayOutputStream();
+ final StreamResult streamResult = new StreamResult();
+ streamResult.setOutputStream(out);
+ transformer.transform(result, streamResult);
+ return out.toByteArray();
+ }
+
+}