aboutsummaryrefslogtreecommitdiff
path: root/src/main
diff options
context:
space:
mode:
Diffstat (limited to 'src/main')
-rw-r--r--src/main/java/at/gv/egiz/moazs/MoaZSException.java6
-rw-r--r--src/main/java/at/gv/egiz/moazs/config/MoaSigConfig.java19
-rw-r--r--src/main/java/at/gv/egiz/moazs/msg/MsgClient.java64
-rw-r--r--src/main/java/at/gv/egiz/moazs/msg/MsgClientFactory.java51
-rw-r--r--src/main/java/at/gv/egiz/moazs/pipeline/SameThreadDeliveryPipeline.java4
-rw-r--r--src/main/java/at/gv/egiz/moazs/preprocess/ConfigProfileGenerator.java19
-rw-r--r--src/main/java/at/gv/egiz/moazs/preprocess/ConfigUtil.java183
-rw-r--r--src/main/java/at/gv/egiz/moazs/preprocess/DeliveryRequestAugmenter.java6
-rw-r--r--src/main/java/at/gv/egiz/moazs/util/FileUtils.java22
-rw-r--r--src/main/java/at/gv/egiz/moazs/util/SSLContextCreator.java82
-rw-r--r--src/main/java/at/gv/egiz/moazs/util/StringUtils.java17
-rw-r--r--src/main/resources/application.yaml29
-rw-r--r--src/main/resources/mzs/app2mzs.xsd34
13 files changed, 441 insertions, 95 deletions
diff --git a/src/main/java/at/gv/egiz/moazs/MoaZSException.java b/src/main/java/at/gv/egiz/moazs/MoaZSException.java
index db04241..847d9c1 100644
--- a/src/main/java/at/gv/egiz/moazs/MoaZSException.java
+++ b/src/main/java/at/gv/egiz/moazs/MoaZSException.java
@@ -32,6 +32,10 @@ public class MoaZSException extends RuntimeException {
this.mzsRequest = mzsRequest;
}
+ public static MoaZSException moaZSException(String message, Throwable cause) {
+ return moaZSExceptionBuilder(message).withCause(cause).build();
+ }
+
public static MoaZSException moaZSException(String formatString, Object... objects) {
return moaZSExceptionBuilder(formatString, objects).build();
}
@@ -73,7 +77,7 @@ public class MoaZSException extends RuntimeException {
return msgRequest;
}
- public static class Builder extends Throwable {
+ public static class Builder {
private String message;
private Throwable cause;
diff --git a/src/main/java/at/gv/egiz/moazs/config/MoaSigConfig.java b/src/main/java/at/gv/egiz/moazs/config/MoaSigConfig.java
index 05ecac1..0b7bdc7 100644
--- a/src/main/java/at/gv/egiz/moazs/config/MoaSigConfig.java
+++ b/src/main/java/at/gv/egiz/moazs/config/MoaSigConfig.java
@@ -2,10 +2,12 @@ package at.gv.egiz.moazs.config;
import at.gv.egiz.eid.authhandler.modules.sigverify.moasig.api.ISignatureVerificationService;
import at.gv.egiz.eid.authhandler.modules.sigverify.moasig.impl.SignatureVerificationService;
+import at.gv.egiz.moazs.util.FileUtils;
import at.gv.egiz.moazs.verify.MoaSPSSSignatureVerifier;
import at.gv.egiz.moazs.verify.SignatureVerifier;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@@ -28,15 +30,18 @@ public class MoaSigConfig {
private final String keyStoreType;
private final String defaultTrustProfile;
private final String spssConfigFilePath;
+ private final FileUtils fileUtils;
public MoaSigConfig(@Value("${javax.net.ssl.trustStoreType}") String trustStoreType,
@Value("${javax.net.ssl.keyStoreType}") String keyStoreType,
@Value("${moa.spss.server.default-trustprofile}") String defaultTrustProfile,
- @Value("${moa.spss.server.configuration}") String spssConfigFilePath) throws FileNotFoundException {
+ @Value("${moa.spss.server.configuration}") String spssConfigFilePath,
+ @Autowired FileUtils fileUtils) throws FileNotFoundException {
this.trustStoreType = trustStoreType;
this.keyStoreType = keyStoreType;
this.defaultTrustProfile = defaultTrustProfile;
this.spssConfigFilePath = spssConfigFilePath;
+ this.fileUtils = fileUtils;
fallBackToSpringEnvForMoaSPSSConfigProperty();
fallBackToSpringEnvForJavaxNetSSLStoreTypeProperty();
}
@@ -45,7 +50,7 @@ public class MoaSigConfig {
log.info("value of spssConfigFilePath is {}", spssConfigFilePath);
if(System.getProperty(MOA_SPSS_CONFIG_FILE_PROPERTY) == null) {
- var realPath = determinePath(spssConfigFilePath);
+ var realPath = fileUtils.determinePath(spssConfigFilePath);
var realFile = new File(realPath);
if(realFile.exists() && realFile.canRead()) {
@@ -57,15 +62,7 @@ public class MoaSigConfig {
}
}
- private String determinePath(String abstractPath) {
- if (new File(abstractPath).isAbsolute()) {
- return abstractPath;
- } else {
- //resolve relative path as classpath resource
- //java.lang.Class needs relative resources to start with "/"
- return this.getClass().getResource("/" + abstractPath).getFile();
- }
- }
+
private void fallBackToSpringEnvForJavaxNetSSLStoreTypeProperty() {
if (System.getProperty(JAVAX_SSL_TRUSTSTORE_TYPE_PROPERTY) == null) {
diff --git a/src/main/java/at/gv/egiz/moazs/msg/MsgClient.java b/src/main/java/at/gv/egiz/moazs/msg/MsgClient.java
index 82f172d..84a7801 100644
--- a/src/main/java/at/gv/egiz/moazs/msg/MsgClient.java
+++ b/src/main/java/at/gv/egiz/moazs/msg/MsgClient.java
@@ -1,46 +1,80 @@
package at.gv.egiz.moazs.msg;
-import at.gv.zustellung.app2mzs.xsd.ConfigType;
import at.gv.zustellung.msg.xsd.App2ZusePort;
+import at.gv.zustellung.msg.xsd.App2ZusePortService;
import at.gv.zustellung.msg.xsd.DeliveryRequestStatusType;
import at.gv.zustellung.msg.xsd.DeliveryRequestType;
+import org.apache.cxf.configuration.jsse.TLSClientParameters;
+import org.apache.cxf.endpoint.Client;
+import org.apache.cxf.frontend.ClientProxy;
import org.apache.cxf.jaxws.JaxWsClientFactoryBean;
import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
import org.apache.cxf.message.Message;
import org.apache.cxf.phase.PhaseInterceptor;
+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.lang.Nullable;
+import javax.net.ssl.SSLContext;
+
+//TODO: Rethink design. could this entire class be replaced?
+// Because everything the send() method does could be initialized in
+// the MsgClientFactory as well.
public class MsgClient {
- private final DeliveryRequestType msgRequest;
- private final ConfigType config;
+ private static final Logger log = LoggerFactory.getLogger(MsgClient.class);
+
private final PhaseInterceptor<? extends Message> interceptor;
- public MsgClient(DeliveryRequestType msgRequest, ConfigType config, PhaseInterceptor<? extends Message> interceptor) {
- this.msgRequest = msgRequest;
- this.config = config;
+ private final String address;
+
+ //TODO: make configurable
+ private final int connectionTimeout = 60;
+ private final int receiveTimeout = 60;
+
+ @Nullable
+ private final SSLContext sslContext;
+
+ public MsgClient(PhaseInterceptor<? extends Message> interceptor,
+ String address,
+ @Nullable SSLContext sslContext) {
this.interceptor = interceptor;
+ this.address = address;
+ this.sslContext = sslContext;
}
/**
* Send {@code msgRequest} to {@code Config/Server/ZUSEUrlID} and run {@code interceptor} on response.
* @return
*/
- public DeliveryRequestStatusType send() {
- var proxy = connect(config);
- return proxy.delivery(msgRequest);
- }
-
- private App2ZusePort connect(ConfigType config) {
-
- var address = config.getServer().getZUSEUrlID();
+ public DeliveryRequestStatusType send(DeliveryRequestType msgRequest) {
var factory = new JaxWsClientFactoryBean();
+
factory.setServiceClass(App2ZusePort.class);
factory.setAddress(address);
factory.getInInterceptors().add(interceptor);
var proxy = new JaxWsProxyFactoryBean(factory).create();
- return (App2ZusePort) proxy;
+ Client client = ClientProxy.getClient(proxy);
+ HTTPConduit http = (HTTPConduit) client.getConduit();
+
+ var httpClientPolicy = new HTTPClientPolicy();
+ httpClientPolicy.setConnectionTimeout(connectionTimeout);
+ httpClientPolicy.setReceiveTimeout(receiveTimeout);
+ http.setClient(httpClientPolicy);
+
+ if (sslContext != null) {
+ var tlsParams = new TLSClientParameters();
+ tlsParams.setSSLSocketFactory(sslContext.getSocketFactory());
+ http.setTlsClientParameters(tlsParams);
+ log.info("SSLContext initialized. ");
+ }
+
+ return ((App2ZusePort)proxy).delivery(msgRequest);
}
+
}
diff --git a/src/main/java/at/gv/egiz/moazs/msg/MsgClientFactory.java b/src/main/java/at/gv/egiz/moazs/msg/MsgClientFactory.java
index c2cf34f..d4cc9f1 100644
--- a/src/main/java/at/gv/egiz/moazs/msg/MsgClientFactory.java
+++ b/src/main/java/at/gv/egiz/moazs/msg/MsgClientFactory.java
@@ -1,14 +1,57 @@
package at.gv.egiz.moazs.msg;
-import at.gv.zustellung.app2mzs.xsd.ConfigType;
-import at.gv.zustellung.msg.xsd.DeliveryRequestType;
+import at.gv.egiz.moazs.util.FileUtils;
+import at.gv.egiz.moazs.util.SSLContextCreator;
+import at.gv.zustellung.app2mzs.xsd.ClientType;
+import at.gv.zustellung.app2mzs.xsd.KeyStoreType;
+import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
+import javax.net.ssl.SSLContext;
+
+import static at.gv.zustellung.app2mzs.xsd.KeyStoreType.keyStoreTypeBuilder;
+
@Component
public class MsgClientFactory {
- public MsgClient create(DeliveryRequestType msgRequest, ConfigType config, StoreSOAPBodyBinaryInRepositoryInterceptor storeResponseInterceptor) {
- return new MsgClient(msgRequest, config, storeResponseInterceptor);
+ private final StoreSOAPBodyBinaryInRepositoryInterceptor storeResponseInterceptor;
+ private final SSLContextCreator sslContextCreator;
+ private final FileUtils fileUtils;
+
+
+ @Autowired
+ public MsgClientFactory(StoreSOAPBodyBinaryInRepositoryInterceptor storeResponseInterceptor, SSLContextCreator creator, FileUtils fileUtils) {
+ this.storeResponseInterceptor = storeResponseInterceptor;
+ this.sslContextCreator = creator;
+ this.fileUtils = fileUtils;
+ }
+
+
+ /**
+ * Creates a client that communicates with a msg service.
+ *
+ * @param params for the client, such as service url and ssl parameters.
+ * @return the msg client
+ */
+ //TODO evaluate and honor laxhostnameverification and trustall parameter!
+ public MsgClient create(ClientType params) {
+
+ SSLContext sslContext = null;
+
+ if (params.getURL().startsWith("https")) {
+ var keystore = resolveKeyStorePath(params.getSSL().getKeyStore());
+ var truststore = resolveKeyStorePath(params.getSSL().getTrustStore());
+ sslContext = sslContextCreator.createSSLContext(keystore, truststore);
+ }
+
+ return new MsgClient(storeResponseInterceptor, params.getURL(), sslContext);
+ }
+
+ private KeyStoreType resolveKeyStorePath(KeyStoreType store) {
+ return store == null ? null
+ : keyStoreTypeBuilder(store)
+ .withFileName(fileUtils.determinePath(store.getFileName()))
+ .build();
}
}
diff --git a/src/main/java/at/gv/egiz/moazs/pipeline/SameThreadDeliveryPipeline.java b/src/main/java/at/gv/egiz/moazs/pipeline/SameThreadDeliveryPipeline.java
index ae8286f..20320c4 100644
--- a/src/main/java/at/gv/egiz/moazs/pipeline/SameThreadDeliveryPipeline.java
+++ b/src/main/java/at/gv/egiz/moazs/pipeline/SameThreadDeliveryPipeline.java
@@ -80,7 +80,7 @@ public class SameThreadDeliveryPipeline implements DeliveryPipeline {
exceptionBuilder.withMsgRequest(msgRequest);
- var status = msgClientFactory.create(msgRequest, mzsRequest.getConfig(), interceptor).send();
+ var status = msgClientFactory.create(mzsRequest.getConfig().getMSGClient()).send(msgRequest);
exceptionBuilder.withMsgResult(status);
verifySignedStatus(appDeliveryId, exceptionBuilder);
@@ -128,7 +128,7 @@ public class SameThreadDeliveryPipeline implements DeliveryPipeline {
.withAppDeliveryID(appDeliveryId);
if (exception.getMzsRequest() != null) {
- errorBuilder.withDeliverySystem(exception.getMzsRequest().getConfig().getServer().getZUSEUrlID());
+ errorBuilder.withDeliverySystem(exception.getMzsRequest().getConfig().getMSGClient().getURL());
}
if (exception.getTnvzResult() != null && exception.getTnvzResult().getError() != null) {
diff --git a/src/main/java/at/gv/egiz/moazs/preprocess/ConfigProfileGenerator.java b/src/main/java/at/gv/egiz/moazs/preprocess/ConfigProfileGenerator.java
index be14852..fa1ccd6 100644
--- a/src/main/java/at/gv/egiz/moazs/preprocess/ConfigProfileGenerator.java
+++ b/src/main/java/at/gv/egiz/moazs/preprocess/ConfigProfileGenerator.java
@@ -1,6 +1,7 @@
package at.gv.egiz.moazs.preprocess;
import at.gv.egiz.moazs.MoaZSException;
+import at.gv.egiz.moazs.util.StringUtils;
import at.gv.zustellung.app2mzs.xsd.ConfigType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -58,9 +59,9 @@ public class ConfigProfileGenerator {
var groupedKeys = properties.getPropertyNames()
.filter(this::isConfigurationProfileProperty)
- .map(this::removePrefix)
- .filter(this::hasPrefix)
- .collect(groupingBy(this::keepPrefix, mapping(this::removePrefix, toSet())));
+ .map(StringUtils::removePrefix)
+ .filter(StringUtils::hasPrefix)
+ .collect(groupingBy(StringUtils::keepPrefix, mapping(StringUtils::removePrefix, toSet())));
var profiles = groupedKeys.entrySet().stream()
.collect(toUnmodifiableMap(Entry::getKey, this::createConfigFromEnv));
@@ -78,22 +79,10 @@ public class ConfigProfileGenerator {
return defaultProfile == null ? profiles : mergeProfiles(profiles, defaultProfile);
}
- private boolean hasPrefix(String name) {
- return name.indexOf('.') != -1;
- }
-
private boolean isConfigurationProfileProperty(String propName) {
return propName.startsWith(profilePrefix + ".");
}
- private String keepPrefix(String name) {
- return name.substring(0, name.indexOf('.'));
- }
-
- private String removePrefix(String name) {
- return name.substring(name.indexOf('.') + 1);
- }
-
private ConfigType createConfigFromEnv(Entry<String, Set<String>> entry) {
var profile = entry.getKey();
diff --git a/src/main/java/at/gv/egiz/moazs/preprocess/ConfigUtil.java b/src/main/java/at/gv/egiz/moazs/preprocess/ConfigUtil.java
index 3fef4bd..1befd1d 100644
--- a/src/main/java/at/gv/egiz/moazs/preprocess/ConfigUtil.java
+++ b/src/main/java/at/gv/egiz/moazs/preprocess/ConfigUtil.java
@@ -1,20 +1,37 @@
package at.gv.egiz.moazs.preprocess;
+import at.gv.egiz.moazs.util.StringUtils;
+import at.gv.zustellung.app2mzs.xsd.ClientType;
import at.gv.zustellung.app2mzs.xsd.ConfigType;
-import at.gv.zustellung.app2mzs.xsd.ServerType;
+import at.gv.zustellung.app2mzs.xsd.KeyStoreType;
+import at.gv.zustellung.app2mzs.xsd.SSLType;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Component;
import java.util.Map;
+import static at.gv.zustellung.app2mzs.xsd.ClientType.clientTypeBuilder;
import static at.gv.zustellung.app2mzs.xsd.ConfigType.configTypeBuilder;
-import static at.gv.zustellung.app2mzs.xsd.ServerType.serverTypeBuilder;
+import static at.gv.zustellung.app2mzs.xsd.KeyStoreType.keyStoreTypeBuilder;
+import static at.gv.zustellung.app2mzs.xsd.SSLType.SSLTypeBuilder;
+import static java.util.stream.Collectors.toMap;
@Component
public class ConfigUtil {
- private static final String TNVZ_REQUEST_KEY = "perform-query-person-request";
- private static final String MSG_URL_KEY = "msg.url";
+ public static final String TNVZ_REQUEST_KEY = "perform-query-person-request";
+ public static final String MSG_CLIENT_KEY = "msg-client";
+ public static final String TNVZ_CLIENT_KEY = "tnvz-client";
+ public static final String URL_KEY = "url";
+ public static final String SSL_KEY = "ssl";
+ public static final String TRUST_ALL_KEY = "trust-all";
+ public static final String LAX_HOSTNAME_VERIFICATION_KEY = "lax-hostname-verification";
+ public static final String KEYSTORE_KEY = "keystore";
+ public static final String TRUSTSTORE_KEY = "truststore";
+ public static final String FILENAME_KEY = "filename";
+ public static final String FILETYPE_KEY = "filetype";
+ public static final String PASSWORD_KEY = "password";
+
/**
* Convert a map into a Config object.
@@ -23,16 +40,74 @@ public class ConfigUtil {
* @return Config
*/
public ConfigType convert(Map<String, String> values) {
- var server = serverTypeBuilder()
- .withZUSEUrlID(values.get(MSG_URL_KEY))
- .build();
-
Boolean performQueryPersonRequest = values.get(TNVZ_REQUEST_KEY) == null
? null : Boolean.getBoolean(values.get(TNVZ_REQUEST_KEY));
+ var msgClientParams = filterMapByPrefix(values, MSG_CLIENT_KEY);
+ ClientType msgClient = msgClientParams.isEmpty()
+ ? null : buildClient(msgClientParams);
+
+ var tnvzClientParams = filterMapByPrefix(values, TNVZ_CLIENT_KEY);
+ ClientType tnvzClient = tnvzClientParams.isEmpty()
+ ? null : buildClient(tnvzClientParams);
+
return ConfigType.configTypeBuilder()
.withPerformQueryPersonRequest(performQueryPersonRequest)
- .withServer(server)
+ .withMSGClient(msgClient)
+ .withTNVZClient(tnvzClient)
+ .build();
+ }
+
+ private Map<String, String> filterMapByPrefix(Map<String, String> values, String prefix) {
+ return values.entrySet().stream()
+ .filter(entry -> entry.getKey().startsWith(prefix))
+ .collect(toMap(e -> StringUtils.removePrefix(e.getKey()), Map.Entry::getValue));
+ }
+
+
+ private ClientType buildClient(Map<String, String> clientParams) {
+
+ var url = clientParams.get(URL_KEY);
+
+ var sslParams = filterMapByPrefix(clientParams, SSL_KEY);
+ SSLType ssl = sslParams.isEmpty()
+ ? null : buildSSL(sslParams);
+
+ return clientTypeBuilder().withURL(url).withSSL(ssl).build();
+
+ }
+
+ private SSLType buildSSL(Map<String, String> sslParams) {
+
+ var keyStoreParams = filterMapByPrefix(sslParams, KEYSTORE_KEY);
+ KeyStoreType keyStore = keyStoreParams.isEmpty()
+ ? null : buildKeyStore(keyStoreParams);
+
+ var trustStoreParams = filterMapByPrefix(sslParams, TRUSTSTORE_KEY);
+ KeyStoreType trustStore = trustStoreParams.isEmpty()
+ ? null : buildKeyStore(trustStoreParams);
+
+ var trustAll = sslParams.get(TRUST_ALL_KEY) == null
+ ? null : Boolean.getBoolean(sslParams.get(TRUST_ALL_KEY));
+
+ var laxHostNameVerification = sslParams.get(LAX_HOSTNAME_VERIFICATION_KEY) == null
+ ? null : Boolean.getBoolean(sslParams.get(LAX_HOSTNAME_VERIFICATION_KEY));
+
+ return SSLTypeBuilder()
+ .withKeyStore(keyStore)
+ .withTrustStore(trustStore)
+ .withTrustAll(trustAll)
+ .withLaxHostNameVerification(laxHostNameVerification)
+ .build();
+
+ }
+
+ private KeyStoreType buildKeyStore(Map<String, String> params) {
+
+ return keyStoreTypeBuilder()
+ .withFileName(params.get(FILENAME_KEY))
+ .withFileType(params.get(FILETYPE_KEY))
+ .withPassword(params.get(PASSWORD_KEY))
.build();
}
@@ -47,32 +122,65 @@ public class ConfigUtil {
var builder = configTypeBuilder(fallback);
- if(primary.getServer() != null) {
- builder.withServer(merge(primary.getServer(), fallback.getServer()));
+ if (primary.isPerformQueryPersonRequest() != null) {
+ builder.withPerformQueryPersonRequest(primary.isPerformQueryPersonRequest());
}
- if(primary.isPerformQueryPersonRequest() != null) {
- builder.withPerformQueryPersonRequest(primary.isPerformQueryPersonRequest());
+ if (primary.getMSGClient() != null) {
+ builder.withMSGClient(merge(primary.getMSGClient(), fallback.getMSGClient()));
+ }
+
+ if (primary.getTNVZClient() != null) {
+ builder.withMSGClient(merge(primary.getTNVZClient(), fallback.getTNVZClient()));
}
return builder.build();
+ }
+
+ private ClientType merge(ClientType primary, ClientType fallback) {
+ var builder = clientTypeBuilder(fallback);
+
+ if (primary.getURL() != null) {
+ builder.withURL(primary.getURL());
+ }
+
+ if (primary.getSSL() != null) {
+ builder.withSSL(merge(primary.getSSL(), fallback.getSSL()));
+ }
+ return builder.build();
}
- private ServerType merge(ServerType primary, ServerType fallback) {
+ private SSLType merge(SSLType primary, SSLType fallback) {
+ var builder = SSLTypeBuilder(fallback);
- if (fallback == null) {
- return primary;
+ if (primary.getKeyStore() != null) {
+ builder.withKeyStore(merge(primary.getKeyStore(), fallback.getKeyStore()));
}
- var builder = serverTypeBuilder(fallback);
+ if (primary.getTrustStore() != null) {
+ builder.withKeyStore(merge(primary.getTrustStore(), fallback.getTrustStore()));
+ }
- if (primary.getX509() != null) builder.withX509 (primary.getX509() );
- if (primary.getZUSEUrlID() != null) builder.withZUSEUrlID(primary.getZUSEUrlID());
+ if (primary.isLaxHostNameVerification() != null) {
+ builder.withLaxHostNameVerification(primary.isLaxHostNameVerification());
+ }
+ if (primary.isTrustAll() != null) {
+ builder.withLaxHostNameVerification(primary.isTrustAll());
+ }
return builder.build();
}
+ private KeyStoreType merge(KeyStoreType primary, KeyStoreType fallback) {
+
+ if (primary.getFileName() != null && primary.getFileType() != null && primary.getPassword() != null)
+ return primary;
+
+ return fallback;
+
+ }
+
/**
* Check if all mandatory fields are set.
*
@@ -80,11 +188,42 @@ public class ConfigUtil {
* @return true if all mandatory fields are set
*/
public boolean isComplete(@Nullable ConfigType profile) {
- //TODO: add check fo x509 certificate
return profile != null
&& profile.isPerformQueryPersonRequest() != null
- && profile.getServer() != null
- && profile.getServer().getZUSEUrlID() != null;
+ && isTVNZClientConfigured(profile.getTNVZClient(), profile.isPerformQueryPersonRequest())
+ && isMSGClientConfigured(profile.getMSGClient());
+ }
+
+ private boolean isTVNZClientConfigured(ClientType tnvzClient, Boolean isPerformQueryPersonRequest) {
+ return (tnvzClient != null
+ && tnvzClient.getURL() != null
+ && isSSLConfigured(tnvzClient))
+ || isPerformQueryPersonRequest == false;
}
+ private boolean isMSGClientConfigured(ClientType msgClient) {
+ return msgClient != null
+ && msgClient.getURL() != null
+ && isSSLConfigured(msgClient);
+ }
+
+ private boolean isSSLConfigured(ClientType params) {
+ return (params.getURL().startsWith("https")
+ && params.getSSL() != null
+ && params.getSSL().isTrustAll() != null
+ && params.getSSL().isLaxHostNameVerification() != null
+ && isKeyStoreConfigured(params.getSSL().getKeyStore())
+ && isKeyStoreConfigured(params.getSSL().getTrustStore()))
+ || !params.getURL().startsWith("https");
+ }
+
+ private boolean isKeyStoreConfigured(KeyStoreType keyStore) {
+ return (keyStore != null
+ && keyStore.getPassword() != null
+ && keyStore.getFileType() != null
+ && keyStore.getFileName() != null)
+ || keyStore == null;
+ }
+
+
}
diff --git a/src/main/java/at/gv/egiz/moazs/preprocess/DeliveryRequestAugmenter.java b/src/main/java/at/gv/egiz/moazs/preprocess/DeliveryRequestAugmenter.java
index 057c3d4..d3891e4 100644
--- a/src/main/java/at/gv/egiz/moazs/preprocess/DeliveryRequestAugmenter.java
+++ b/src/main/java/at/gv/egiz/moazs/preprocess/DeliveryRequestAugmenter.java
@@ -37,8 +37,8 @@ public class DeliveryRequestAugmenter {
public DeliveryRequestType augment(DeliveryRequestType request) {
var requestConfig = request.getConfig();
- var profileId = determineProfileIdFrom(requestConfig);
- var fallbackConfig = configs.get(profileId);
+ var fallbackProfileId = determineProfileIdFrom(requestConfig);
+ var fallbackConfig = configs.get(fallbackProfileId);
if (fallbackConfig == null) {
@@ -58,7 +58,7 @@ public class DeliveryRequestAugmenter {
.withConfig(mergedConfig)
.build();
} else {
- throw moaZSException(INCOMPLETE_MERGED_CONFIG_ERROR_MESSAGE, profileId);
+ throw moaZSException(INCOMPLETE_MERGED_CONFIG_ERROR_MESSAGE, fallbackProfileId);
}
}
}
diff --git a/src/main/java/at/gv/egiz/moazs/util/FileUtils.java b/src/main/java/at/gv/egiz/moazs/util/FileUtils.java
new file mode 100644
index 0000000..7e7723d
--- /dev/null
+++ b/src/main/java/at/gv/egiz/moazs/util/FileUtils.java
@@ -0,0 +1,22 @@
+package at.gv.egiz.moazs.util;
+
+import org.springframework.stereotype.Component;
+
+import java.io.File;
+
+@Component
+public class FileUtils {
+
+ /**
+ * If path is relative, resolve path as classpath resource. If path is absolute,
+ * leave as-is.
+ */
+ public String determinePath(String abstractPath) {
+ if (new File(abstractPath).isAbsolute()) {
+ return abstractPath;
+ } else {
+ //java.lang.Class needs relative resources to start with "/"
+ return this.getClass().getResource("/" + abstractPath).getFile();
+ }
+ }
+}
diff --git a/src/main/java/at/gv/egiz/moazs/util/SSLContextCreator.java b/src/main/java/at/gv/egiz/moazs/util/SSLContextCreator.java
new file mode 100644
index 0000000..b4d66d1
--- /dev/null
+++ b/src/main/java/at/gv/egiz/moazs/util/SSLContextCreator.java
@@ -0,0 +1,82 @@
+package at.gv.egiz.moazs.util;
+
+import at.gv.egiz.eaaf.core.impl.utils.KeyStoreUtils;
+import at.gv.zustellung.app2mzs.xsd.KeyStoreType;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.lang.Nullable;
+import org.springframework.stereotype.Component;
+
+import javax.net.ssl.*;
+import java.io.IOException;
+import java.security.*;
+
+import static at.gv.egiz.moazs.MoaZSException.moaZSException;
+import static java.lang.String.format;
+
+@Component
+public class SSLContextCreator {
+
+ private static final Logger log = LoggerFactory.getLogger(SSLContextCreator.class);
+
+ /**
+ * Creates an SSL Context.
+ * Adapted from at.asitplus.eidas.specific.modules.authmodule_eIDASv2.szr.SZRClient
+ *
+ * @param keystore (if null, use no key store)
+ * @param truststore (if null, use default trust store)
+ * @throws at.gv.egiz.moazs.MoaZSException
+ */
+ public SSLContext createSSLContext(@Nullable KeyStoreType keystore, @Nullable KeyStoreType truststore) {
+ try {
+ SSLContext context = SSLContext.getInstance("TLS");
+ KeyManager[] keyManager = initKeyManager(keystore);
+ TrustManager[] trustManager = initTrustManager(truststore);
+ context.init(keyManager, trustManager, new SecureRandom());
+ return context;
+ } catch (NoSuchAlgorithmException | KeyManagementException e) {
+ throw moaZSException("SSLContext initialization FAILED.", e);
+ }
+ }
+
+ private KeyManager[] initKeyManager(KeyStoreType keystore) {
+ if (keystore == null) {
+ log.trace("No keystore path provided. NOT using SSL client authentication. ");
+ return null;
+ } else {
+ log.trace("Find keystore path: {}. Injecting SSL client certificate... ", keystore.getFileName());
+ try {
+ KeyStore keyStore = KeyStoreUtils.loadKeyStore(
+ keystore.getFileType(), keystore.getFileName(), keystore.getPassword());
+ KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
+ kmf.init(keyStore, keystore.getPassword().toCharArray());
+ log.trace("SSL client certificate injected.");
+ return kmf.getKeyManagers();
+ } catch (IOException | GeneralSecurityException e) {
+ throw moaZSException(format("Can NOT load SSL client certificate from path: %s.",
+ keystore.getFileName()), e);
+ }
+ }
+ }
+
+ private TrustManager[] initTrustManager(KeyStoreType truststore) {
+ if (truststore == null) {
+ log.trace("Using default truststore. ");
+ return null;
+ } else {
+ log.trace("Find truststore path: {}. Injecting SSL truststore... ", truststore.getFileName());
+ try {
+ KeyStore trustStore = KeyStoreUtils.loadKeyStore(
+ truststore.getFileType(), truststore.getFileName(), truststore.getPassword());
+ TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
+ tmf.init(trustStore);
+ log.trace("SSL TrustStore injected to client. ");
+ return tmf.getTrustManagers();
+ } catch (GeneralSecurityException | IOException e) {
+ throw moaZSException(format("Can NOT open SSL TrustStore from path: %s.",
+ truststore.getFileName()), e);
+ }
+ }
+ }
+
+}
diff --git a/src/main/java/at/gv/egiz/moazs/util/StringUtils.java b/src/main/java/at/gv/egiz/moazs/util/StringUtils.java
new file mode 100644
index 0000000..fd40f6e
--- /dev/null
+++ b/src/main/java/at/gv/egiz/moazs/util/StringUtils.java
@@ -0,0 +1,17 @@
+package at.gv.egiz.moazs.util;
+
+public class StringUtils {
+
+ public static boolean hasPrefix(String name) {
+ return name.indexOf('.') != -1;
+ }
+
+ public static String keepPrefix(String name) {
+ return name.substring(0, name.indexOf('.'));
+ }
+
+ public static String removePrefix(String name) {
+ return name.substring(name.indexOf('.') + 1);
+ }
+
+}
diff --git a/src/main/resources/application.yaml b/src/main/resources/application.yaml
index 9ce1158..a0040ca 100644
--- a/src/main/resources/application.yaml
+++ b/src/main/resources/application.yaml
@@ -13,32 +13,34 @@ spring:
# Order: DeliveryRequest/Config > [chosen-profile] > default
delivery-request-configuration-profiles:
default:
+
+ perform-query-person-request: false
+
## All parameters for MSG client.
- msg:
+ msg-client:
- ## How to reach
url: http://localhost:8081/services/DeliveryRequest
+
ssl:
+ ## Boolean; if true, app will trust all server certificates;
+ ## if false, server certificate needs to be in truststore.
+ trust-all: false
+
+ ## Boolean; if true, app ignores mismatches between server's host name and
+ ## Certificate's common name / alternative subject name.
+ lax-hostname-verification: false
+
## Parameters for ssl client auth
keystore:
## Absolute path to file
- filename:
+ filename: ssl/client.jks
## Password to unlock key store.
password: 1233
## JKS or PKCS12
type: JKS
- ## Boolean; if true, app will trust all server certificates;
- ## if false, server certificate needs to be in truststore.
- trustall: false
- ## Boolean; if true, app ignores mismatches between server's host name and
- ## Certificate's common name / alternative subject name.
- laxhostnameverification: false
-
-
- perform-query-person-request: false
app-profile-1:
msg:
@@ -49,9 +51,6 @@ delivery-request-configuration-profiles:
msg:
url: https://msg-url2.com
-key-store-profiles:
- msg-key-store:
-
## If set to false, moa zs ignores an incomplete default DeliveryRequest-configuration
## profile and continues startup. See 'delivery-request-configuration-profiles'.
## Default value: true
diff --git a/src/main/resources/mzs/app2mzs.xsd b/src/main/resources/mzs/app2mzs.xsd
index 05a9ea4..956cd31 100644
--- a/src/main/resources/mzs/app2mzs.xsd
+++ b/src/main/resources/mzs/app2mzs.xsd
@@ -81,19 +81,39 @@
<xs:complexType name="ConfigType">
<xs:sequence>
<xs:element name="ProfileID" type="xs:token" minOccurs="0"></xs:element>
- <xs:element ref="Server" minOccurs="0"></xs:element>
<xs:element name="PerformQueryPersonRequest" type="xs:boolean" minOccurs="0" />
+ <xs:element ref="MSGClient" minOccurs="0" />
+ <xs:element ref="TNVZClient" minOccurs="0" />
</xs:sequence>
</xs:complexType>
- <xs:element name="Server" type="ServerType" />
- <xs:complexType name="ServerType">
+ <xs:element name="MSGClient" type="ClientType" />
+ <xs:element name="TNVZClient" type="ClientType" />
+ <xs:complexType name="ClientType">
<xs:sequence>
- <xs:element name="ZUSEUrlID" type="xs:anyURI" minOccurs="0"/>
- <xs:element name="X509" type="xs:base64Binary" minOccurs="0"/>
+ <xs:element name="URL" type="xs:anyURI" />
+ <xs:element ref="SSL" minOccurs="0"/>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:element name="SSL" type="SSLType" />
+ <xs:complexType name="SSLType">
+ <xs:sequence>
+ <xs:element name="TrustAll" minOccurs="0" type="xs:boolean" />
+ <xs:element name="LaxHostNameVerification" minOccurs="0" type="xs:boolean" />
+ <xs:element ref="KeyStore" minOccurs="0" />
+ <xs:element ref="TrustStore" minOccurs="0"/>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:element name="TrustStore" type="KeyStoreType" />
+ <xs:element name="KeyStore" type="KeyStoreType" />
+ <xs:complexType name="KeyStoreType">
+ <xs:sequence>
+ <xs:element name="FileName" type="xs:string" minOccurs="0"/>
+ <xs:element name="Password" type="xs:string" minOccurs="0"/>
+ <xs:element name="FileType" type="xs:string" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
<xs:element name="DeliveryResponse" type="DeliveryResponseType"/>
- <xs:complexType name="DeliveryResponseType">
+ <xs:complexType name="DeliveryResponseType">
<xs:choice>
<xs:element ref="PartialSuccess"/>
<xs:element ref="Success"/>
@@ -179,7 +199,7 @@
<xs:element ref="msg:DeliverySystem"/>
<xs:element ref="msg:ZSDeliveryID" />
<xs:element ref="msg:GZ" minOccurs="0"/>
- <xs:element name="SignedDeliveryRequestStatus" type="xs:base64Binary" minOccurs="0"/>
+ <xs:element name="SignedDeliveryRequestStatus" type="xs:base64Binary" minOccurs="0"/>
</xs:sequence>
</xs:complexType>