summaryrefslogtreecommitdiff
path: root/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/credential/inline/InlineKeyStoreParser.java
diff options
context:
space:
mode:
Diffstat (limited to 'eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/credential/inline/InlineKeyStoreParser.java')
-rw-r--r--eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/credential/inline/InlineKeyStoreParser.java149
1 files changed, 149 insertions, 0 deletions
diff --git a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/credential/inline/InlineKeyStoreParser.java b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/credential/inline/InlineKeyStoreParser.java
new file mode 100644
index 00000000..0ddc2680
--- /dev/null
+++ b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/credential/inline/InlineKeyStoreParser.java
@@ -0,0 +1,149 @@
+package at.gv.egiz.eaaf.core.impl.credential.inline;
+
+import java.io.IOException;
+import java.net.URI;
+import java.net.URL;
+import java.net.URLConnection;
+import java.net.URLDecoder;
+import java.net.URLStreamHandler;
+import java.nio.charset.StandardCharsets;
+import java.security.GeneralSecurityException;
+import java.security.KeyStore;
+import java.util.AbstractMap;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+import org.springframework.core.io.ResourceLoader;
+
+import at.gv.egiz.eaaf.core.exceptions.EaafConfigurationException;
+import lombok.extern.slf4j.Slf4j;
+
+/**
+ * Parse in-line keystore configuration in BRZ format.
+ *
+ * @author tlenz
+ *
+ */
+@Slf4j
+public class InlineKeyStoreParser extends URLStreamHandler {
+
+ @Override
+ protected URLConnection openConnection(URL u) throws IOException {
+ log.error("openConnection is not implemented by {}", InlineKeyStoreParser.class);
+ return null;
+
+ }
+
+ /**
+ * Build a {@link KeyStore} object from an in-line configuration {@link URL}.
+ *
+ * @param configUrl configuration URL
+ * @param configRootDirectory Root directory for configuration
+ * @param resourceLoader Spring ResourceLoader
+ * @return KeyStore created by configuration URL
+ * @throws IOException In case of a configuration read error
+ * @throws GeneralSecurityException In case of a KeyStore configuration error
+ * @throws EaafConfigurationException If keyfile can not be found
+ */
+ public static KeyStore buildKeyStore(URL configUrl, ResourceLoader resourceLoader, URI configRootDirectory)
+ throws IOException, GeneralSecurityException, EaafConfigurationException {
+ log.trace("Parsing keystore config from URL: {}", configUrl);
+ InlineKeyStoreBuilder keyStoreBuilder = new InlineKeyStoreBuilder(
+ configUrl.getProtocol(), resourceLoader, configRootDirectory);
+
+ // parse basis properties from URL
+ final Map<String, List<String>> queryParams = parseQuery(configUrl.getQuery());
+ final String[] certificateFiles = queryParams.getOrDefault("cert", Collections.emptyList())
+ .toArray(String[]::new);
+
+ if ("keystore".equalsIgnoreCase(configUrl.getPath())) {
+ parseKeyStore(keyStoreBuilder, queryParams, certificateFiles);
+
+ } else if ("truststore".equalsIgnoreCase(configUrl.getPath())) {
+ keyStoreBuilder.setCertificateEntries(certificateFiles);
+
+ } else {
+ throw new IllegalArgumentException("Unknown store type: " + configUrl.getPath());
+
+ }
+
+ return keyStoreBuilder.getKeyStore();
+ }
+
+ /**
+ * Takes the <i>queryParams</i> and builds based on them a {@link KeyStore} with
+ * secret and/or private key.
+ *
+ * @param keyStoreBuilder
+ *
+ * @param queryParams a map of all query params
+ * @param certificateFiles list of certificates
+ * @throws GeneralSecurityException if private or secret key cannot be parsed
+ * @throws IOException if private or secret key cannot be parsed
+ * @throws EaafConfigurationException if keyfile can not be found
+ */
+ private static void parseKeyStore(InlineKeyStoreBuilder keyStoreBuilder,
+ final Map<String, List<String>> queryParams, final String[] certificateFiles)
+ throws GeneralSecurityException, IOException, EaafConfigurationException {
+ final List<String> privateKeyList = queryParams.get("private");
+ final List<String> secretKeyList = queryParams.get("inlineSecret");
+
+ if (privateKeyList == null && secretKeyList == null) {
+ throw new IllegalArgumentException("Neither secret key nor private key are configured!");
+
+ }
+
+ if (privateKeyList != null) {
+ if (privateKeyList.size() == 1) {
+ final String privateKeyFile = queryParams.get("private").get(0);
+ keyStoreBuilder.setKeyEntry(privateKeyFile, certificateFiles);
+
+ } else {
+ throw new IllegalArgumentException("Exactly one private key must be specified!");
+
+ }
+ }
+
+ if (secretKeyList != null) {
+ if (secretKeyList.size() == 1) {
+ final String secret = URLDecoder.decode(secretKeyList.get(0), StandardCharsets.UTF_8);
+ keyStoreBuilder.setSecretEntry(secret);
+
+ } else {
+ throw new IllegalArgumentException("Exactly one secret key must be specified!");
+
+ }
+ }
+ }
+
+ private static Map<String, List<String>> parseQuery(String query) {
+ if (query != null) {
+ final Map<String, List<String>> queryParams = Arrays
+ .stream(query.split("&")) // generate a stream of key=value pairs
+ .map(keyValuePair -> keyValuePair.split("=")) // map key=value strings to arrays
+ .map(keyValuePair -> new AbstractMap.SimpleEntry<String, String>(keyValuePair[0],
+ keyValuePair[1])) // map arrays to Entry objects
+ .collect(Collectors
+ .groupingBy(AbstractMap.SimpleEntry::getKey)) // group entries with identical keys to a map of
+ // lists
+ .entrySet().stream() // stream the map again
+ .map(entry -> new AbstractMap.SimpleEntry<>(entry.getKey(),
+ entry.getValue().stream().map(AbstractMap.SimpleEntry::getValue).collect(Collectors
+ .toList()))) // map the lists of Entry objects to lists of Strings
+ .collect(Collectors.toMap(AbstractMap.SimpleEntry::getKey,
+ AbstractMap.SimpleEntry::getValue)); // collect the stream to a map
+
+ log.trace("Query map: {}", queryParams);
+ return queryParams;
+
+ } else {
+ log.warn("Empty query string");
+ return Collections.emptyMap();
+
+ }
+ }
+
+}