summaryrefslogtreecommitdiff
path: root/eaaf_core_utils
diff options
context:
space:
mode:
Diffstat (limited to 'eaaf_core_utils')
-rw-r--r--eaaf_core_utils/checks/spotbugs-exclude.xml32
-rw-r--r--eaaf_core_utils/pom.xml107
-rw-r--r--eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/exception/EaafKeyUsageException.java21
-rw-r--r--eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/builder/BpkBuilder.java446
-rw-r--r--eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/credential/EaafKeyStoreFactory.java394
-rw-r--r--eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/credential/EaafKeyStoreUtils.java5
-rw-r--r--eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/credential/KeyStoreConfiguration.java9
-rw-r--r--eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/credential/SymmetricKeyConfiguration.java221
-rw-r--r--eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/http/EaafHttpRequestRetryHandler.java33
-rw-r--r--eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/http/EaafSslContextBuilder.java433
-rw-r--r--eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/http/EaafSslKeySelectionStrategy.java11
-rw-r--r--eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/http/HttpClientConfiguration.java22
-rw-r--r--eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/http/HttpClientFactory.java174
-rw-r--r--eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/http/HttpUtils.java194
-rw-r--r--eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/http/IHttpClientFactory.java4
-rw-r--r--eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/http/pvp/PvpRProfileHttpHeaders.java86
-rw-r--r--eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/idp/conf/SpConfigurationImpl.java28
-rw-r--r--eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/AuthenticatedEncryptionPendingRequestIdGenerationStrategy.java280
-rw-r--r--eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/EaafObjectInputStream.java39
-rw-r--r--eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/EaafSerializationUtils.java69
-rw-r--r--eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/KeyStoreUtils.java38
-rw-r--r--eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/KeyValueUtils.java44
-rw-r--r--eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/SecurePendingRequestIdGenerationStrategy.java123
-rw-r--r--eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/TransactionIdUtils.java19
-rw-r--r--eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/X509Utils.java14
-rw-r--r--eaaf_core_utils/src/main/resources/messages/eaaf_utils_message.properties16
-rw-r--r--eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/impl/logging/EaafUtilsMessageSourceTest.java6
-rw-r--r--eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/impl/utils/test/AuthenticatedEncryptionPendingRequestIdGenerationStrategyTest.java447
-rw-r--r--eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/impl/utils/test/AuthenticatedEncryptionPendingRequestIdGenerationStrategyWithHsmTest.java44
-rw-r--r--eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/impl/utils/test/KeyValueUtilsTest.java3
-rw-r--r--eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/test/builder/BpkBuilderTest.java562
-rw-r--r--eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/test/credentials/EaafKeyStoreFactoryTest.java293
-rw-r--r--eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/test/credentials/EncryptionTask.java156
-rw-r--r--eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/test/credentials/KeyOperationPerformanceTest.java155
-rw-r--r--eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/test/credentials/SymmetricKeyConfigurationTest.java162
-rw-r--r--eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/test/dummy/DummyAuthConfigMap.java2
-rw-r--r--eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/test/http/HttpClientFactoryProdHostTest.java98
-rw-r--r--eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/test/http/HttpClientFactoryTest.java369
-rw-r--r--eaaf_core_utils/src/test/resources/data/config1.properties15
-rw-r--r--eaaf_core_utils/src/test/resources/data/config2.properties15
-rw-r--r--eaaf_core_utils/src/test/resources/data/hsm_ee-RSA_rootcert.crt3
-rw-r--r--eaaf_core_utils/src/test/resources/data/hsm_ee_eecert.crt3
-rw-r--r--eaaf_core_utils/src/test/resources/data/hsm_ee_rootcert.crt3
-rw-r--r--eaaf_core_utils/src/test/resources/data/hsm_facade_trust_root.crt18
-rw-r--r--eaaf_core_utils/src/test/resources/data/server_host.crt18
-rw-r--r--eaaf_core_utils/src/test/resources/data/ssL_truststore.jksbin0 -> 799 bytes
-rw-r--r--eaaf_core_utils/src/test/resources/data/ssl_host.jksbin0 -> 2081 bytes
-rw-r--r--eaaf_core_utils/src/test/resources/spring/test_eaaf_pvp_lazy.beans.xml11
-rw-r--r--eaaf_core_utils/src/test/resources/spring/test_eaaf_pvp_not_lazy.beans.xml9
-rw-r--r--eaaf_core_utils/src/test/resources/spring/test_eaaf_pvp_not_lazy_with_hsm.beans.xml26
50 files changed, 4936 insertions, 344 deletions
diff --git a/eaaf_core_utils/checks/spotbugs-exclude.xml b/eaaf_core_utils/checks/spotbugs-exclude.xml
new file mode 100644
index 00000000..c1271f91
--- /dev/null
+++ b/eaaf_core_utils/checks/spotbugs-exclude.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<FindBugsFilter>
+ <Match>
+ <!-- bPK requires SHA1 from specification -->
+ <Class name="at.gv.egiz.eaaf.core.impl.builder.BpkBuilder" />
+ <OR>
+ <Bug pattern="WEAK_MESSAGE_DIGEST_SHA1" />
+ </OR>
+ </Match>
+ <Match>
+ <Class name="at.gv.egiz.eaaf.core.impl.utils.EaafSerializationUtils" />
+ <OR>
+ <Bug pattern="OBJECT_DESERIALIZATION" />
+ </OR>
+ </Match>
+ <Match>
+ <!-- Paths and URLs only loaded from configuration -->
+ <Class name="at.gv.egiz.eaaf.core.impl.utils.FileUtils" />
+ <OR>
+ <Bug pattern="URLCONNECTION_SSRF_FD" />
+ <Bug pattern="PATH_TRAVERSAL_IN" />
+ </OR>
+ </Match>
+ <Match>
+ <!-- Paths and URLs only loaded from configuration -->
+ <Class name="at.gv.egiz.eaaf.core.impl.utils.KeyStoreUtils" />
+ <OR>
+ <Bug pattern="URLCONNECTION_SSRF_FD" />
+ <Bug pattern="PATH_TRAVERSAL_IN" />
+ </OR>
+ </Match>
+</FindBugsFilter> \ No newline at end of file
diff --git a/eaaf_core_utils/pom.xml b/eaaf_core_utils/pom.xml
index ca735940..6ca82d9c 100644
--- a/eaaf_core_utils/pom.xml
+++ b/eaaf_core_utils/pom.xml
@@ -7,7 +7,7 @@
<parent>
<groupId>at.gv.egiz</groupId>
<artifactId>eaaf</artifactId>
- <version>1.1.3-SNAPSHOT</version>
+ <version>1.2.1-SNAPSHOT</version>
</parent>
<groupId>at.gv.egiz.eaaf</groupId>
<artifactId>eaaf_core_utils</artifactId>
@@ -39,22 +39,23 @@
<dependency>
<groupId>at.gv.egiz.eaaf</groupId>
<artifactId>eaaf_core_api</artifactId>
- </dependency>
+ </dependency>
<dependency>
<groupId>at.asitplus.hsmfacade</groupId>
<artifactId>provider</artifactId>
- </dependency>
+ <scope>provided</scope>
+ </dependency>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-core</artifactId>
- </dependency>
-
+ <scope>provided</scope>
+ </dependency>
<dependency>
- <groupId>org.springframework</groupId>
- <artifactId>spring-webmvc</artifactId>
+ <groupId>org.bouncycastle</groupId>
+ <artifactId>bctls-jdk15to18</artifactId>
</dependency>
-
+
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
@@ -80,7 +81,11 @@
<artifactId>joda-time</artifactId>
</dependency>
-
+ <dependency>
+ <groupId>org.bitbucket.b_c</groupId>
+ <artifactId>jose4j</artifactId>
+ <scope>provided</scope>
+ </dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
@@ -93,11 +98,6 @@
</dependency>
<dependency>
- <groupId>junit</groupId>
- <artifactId>junit</artifactId>
- <scope>test</scope>
- </dependency>
- <dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<scope>test</scope>
@@ -111,13 +111,44 @@
<groupId>com.squareup.okhttp3</groupId>
<artifactId>mockwebserver</artifactId>
<scope>test</scope>
+ <exclusions>
+ <exclusion>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ </exclusion>
+ </exclusions>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp-tls</artifactId>
<scope>test</scope>
+ <exclusions>
+ <exclusion>
+ <groupId>org.bouncycastle</groupId>
+ <artifactId>bctls-jdk15on</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>org.bouncycastle</groupId>
+ <artifactId>bcpkix-jdk15on</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ <dependency>
+ <groupId>ch.qos.logback</groupId>
+ <artifactId>logback-classic</artifactId>
+ <version>1.2.3</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.junit.vintage</groupId>
+ <artifactId>junit-vintage-engine</artifactId>
+ <version>${junit-jupiter-api.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.junit.jupiter</groupId>
+ <artifactId>junit-jupiter-migrationsupport</artifactId>
+ <version>${junit-jupiter-api.version}</version>
</dependency>
-
</dependencies>
<build>
@@ -131,49 +162,13 @@
<plugins>
<plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-compiler-plugin</artifactId>
- <version>3.7.0</version>
- <configuration>
- <source>1.8</source>
- <target>1.8</target>
- </configuration>
- <executions>
- <execution>
- <goals>
- <goal>compile</goal>
- <goal>testCompile</goal>
- </goals>
- </execution>
- </executions>
- </plugin>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-jar-plugin</artifactId>
- <version>3.1.0</version>
- <executions>
- <execution>
- <goals>
- <goal>test-jar</goal>
- </goals>
- </execution>
- </executions>
- </plugin>
-
- <!-- enable co-existence of testng and junit -->
- <plugin>
- <artifactId>maven-surefire-plugin</artifactId>
- <version>${surefire.version}</version>
+ <groupId>com.github.spotbugs</groupId>
+ <artifactId>spotbugs-maven-plugin</artifactId>
+ <version>${spotbugs-maven-plugin.version}</version>
<configuration>
- <threadCount>1</threadCount>
+ <failOnError>true</failOnError>
+ <excludeFilterFile>checks/spotbugs-exclude.xml</excludeFilterFile>
</configuration>
- <dependencies>
- <dependency>
- <groupId>org.apache.maven.surefire</groupId>
- <artifactId>surefire-junit47</artifactId>
- <version>${surefire.version}</version>
- </dependency>
- </dependencies>
</plugin>
</plugins>
diff --git a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/exception/EaafKeyUsageException.java b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/exception/EaafKeyUsageException.java
new file mode 100644
index 00000000..8b4e68a4
--- /dev/null
+++ b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/exception/EaafKeyUsageException.java
@@ -0,0 +1,21 @@
+package at.gv.egiz.eaaf.core.exception;
+
+import at.gv.egiz.eaaf.core.exceptions.EaafException;
+
+public class EaafKeyUsageException extends EaafException {
+
+ private static final long serialVersionUID = -2641273589744430903L;
+
+ public static final String ERROR_CODE_01 = "internal.key.01";
+
+ public EaafKeyUsageException(String errorCode, String... params) {
+ super(errorCode, new Object[] {params});
+
+ }
+
+ public EaafKeyUsageException(String errorCode, Throwable e, String... params) {
+ super(errorCode, new Object[] {params}, e);
+
+ }
+
+}
diff --git a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/builder/BpkBuilder.java b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/builder/BpkBuilder.java
new file mode 100644
index 00000000..903aa300
--- /dev/null
+++ b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/builder/BpkBuilder.java
@@ -0,0 +1,446 @@
+/*
+ * Copyright 2014 Federal Chancellery Austria MOA-ID has been developed in a cooperation between
+ * BRZ, the Federal Chancellery Austria - ICT staff unit, and Graz University of Technology.
+ *
+ * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by the European
+ * Commission - subsequent versions of the EUPL (the "Licence"); You may not use this work except in
+ * compliance with the Licence. You may obtain a copy of the Licence at: http://www.osor.eu/eupl/
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the Licence
+ * is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the Licence for the specific language governing permissions and limitations under
+ * the Licence.
+ *
+ * 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.gv.egiz.eaaf.core.impl.builder;
+
+import java.security.InvalidKeyException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Map.Entry;
+
+import javax.annotation.Nonnull;
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
+
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.lang.Nullable;
+import org.springframework.util.Assert;
+import org.springframework.util.Base64Utils;
+
+import at.gv.egiz.eaaf.core.api.data.EaafConstants;
+import at.gv.egiz.eaaf.core.exceptions.EaafBuilderException;
+import at.gv.egiz.eaaf.core.impl.data.Pair;
+import lombok.extern.slf4j.Slf4j;
+
+
+/**
+ * Builder for the bPK, as defined in
+ * <code>&quot;Ableitung f&uml;r die bereichsspezifische Personenkennzeichnung&quot;</code>
+ * version <code>1.0.1</code> from
+ * <code>&quot;reference.e-government.gv.at&quot;</code>.
+ *
+ */
+@Slf4j
+public class BpkBuilder {
+
+ private static final String ERROR_CODE_33 = "builder.33";
+
+ private static final String ERROR_MSG_WRONG_TARGET_FORMAT = "bPK-target format must be full URI";
+
+
+ /**
+ * Calculates an area specific unique person-identifier from a baseID.
+ *
+ * @param baseID baseId from user but never null
+ * @param targetIdentifier target identifier for area specific identifier
+ * calculation but never null
+ * @return Pair consists of (unique person identifier for this target,
+ * targetArea) but never null
+ * @throws EaafBuilderException if some input data are not valid
+ */
+ public static Pair<String, String> generateAreaSpecificPersonIdentifier(final String baseID,
+ final String targetIdentifier) throws EaafBuilderException {
+ return generateAreaSpecificPersonIdentifier(baseID, EaafConstants.URN_PREFIX_BASEID,
+ targetIdentifier);
+
+ }
+
+ /**
+ * Calculates an area specific unique person-identifier from an unique
+ * identifier with a specific type.
+ *
+ * @param baseID baseId from user but never null
+ * @param baseIdType Type of the baseID but never null
+ * @param targetIdentifier target identifier for area specific identifier
+ * calculation but never null
+ * @return Pair consists of (unique person identifier for this target,
+ * targetArea) but never null
+ * @throws EaafBuilderException if some input data are not valid
+ */
+ public static Pair<String, String> generateAreaSpecificPersonIdentifier(final String baseID,
+ final String baseIdType, final String targetIdentifier) throws EaafBuilderException {
+ if (StringUtils.isEmpty(baseID)) {
+ throw new EaafBuilderException(ERROR_CODE_33, new Object[] { "baseID is empty or null" },
+ "BaseId is empty or null");
+ }
+
+ if (StringUtils.isEmpty(baseIdType)) {
+ throw new EaafBuilderException(ERROR_CODE_33,
+ new Object[] { "the type of baseID is empty or null" }, "Type of baseId is empty or null");
+ }
+
+ if (StringUtils.isEmpty(targetIdentifier)) {
+ throw new EaafBuilderException(ERROR_CODE_33,
+ new Object[] { "SP specific target identifier is empty or null" },
+ "SP specific target identifier is empty or null");
+ }
+
+ if (baseIdType.startsWith(EaafConstants.URN_PREFIX_BASEID)) {
+ log.trace("Find baseID. Starting unique identifier caluclation for this target");
+
+ if (targetIdentifier.startsWith(EaafConstants.URN_PREFIX_CDID)) {
+ log.trace("Calculate bPK identifier for target: " + targetIdentifier);
+ return Pair.newInstance(calculatebPKwbPK(baseID + "+" + targetIdentifier),
+ targetIdentifier);
+
+ } else if (targetIdentifier.startsWith(EaafConstants.URN_PREFIX_WBPK)) {
+ log.trace("Calculate wbPK identifier for target: " + targetIdentifier);
+ String commonBpkTarget = normalizeBpkTargetIdentifierToCommonFormat(targetIdentifier);
+ return Pair.newInstance(calculatebPKwbPK(
+ baseID + "+" + normalizeBpkTargetIdentifierToBpkCalculationFormat(commonBpkTarget)),
+ commonBpkTarget);
+
+ } else if (targetIdentifier.startsWith(EaafConstants.URN_PREFIX_EIDAS)) {
+ log.trace("Calculate eIDAS identifier for target: " + targetIdentifier);
+ final String[] splittedTarget = targetIdentifier.split("\\+");
+ final String cititzenCountryCode = splittedTarget[1];
+ final String eidasOutboundCountry = splittedTarget[2];
+
+ if (cititzenCountryCode.equalsIgnoreCase(eidasOutboundCountry)) {
+ log.warn("Suspect configuration FOUND!!! CitizenCountry equals DestinationCountry");
+
+ }
+ return buildEidasIdentifer(baseID, baseIdType, cititzenCountryCode, eidasOutboundCountry);
+
+ } else {
+ throw new EaafBuilderException(ERROR_CODE_33,
+ new Object[] { "Target identifier: " + targetIdentifier + " is NOT allowed or unknown" },
+ "Target identifier: " + targetIdentifier + " is NOT allowed or unknown");
+ }
+
+ } else {
+ log.trace("BaseID is not of type " + EaafConstants.URN_PREFIX_BASEID
+ + ". Check type against requested target ...");
+ if (baseIdType.equals(targetIdentifier)) {
+ log.debug("Unique identifier is already area specific. Is nothing todo");
+ return Pair.newInstance(baseID, targetIdentifier);
+
+ } else {
+ log.warn("Get unique identifier for target: " + baseIdType + " but target: "
+ + targetIdentifier + " is required!");
+ throw new EaafBuilderException(ERROR_CODE_33,
+ new Object[] { "Get unique identifier for target: " + baseIdType + " but target: "
+ + targetIdentifier + " is required" },
+ "Get unique identifier for target: " + baseIdType + " but target: " + targetIdentifier
+ + " is required");
+
+ }
+ }
+ }
+
+
+
+ /**
+ * Create an encrypted bPK.
+ *
+ * @param bpk unencrypted bPK
+ * @param target bPK target in full form
+ * @param publicKey Public-Key used for encryption
+ * @return encrypted bPK
+ * @throws EaafBuilderException In case of an error
+ */
+ public static String encryptBpk(final String bpk, String target, final PublicKey publicKey)
+ throws EaafBuilderException {
+ final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
+
+ if (!target.startsWith(EaafConstants.URN_PREFIX_WITH_COLON)) {
+ throw new EaafBuilderException("builder.32",
+ null, ERROR_MSG_WRONG_TARGET_FORMAT);
+
+ }
+
+ target = normalizeBpkTargetIdentifierToBpkCalculationFormat(
+ normalizeBpkTargetIdentifierToCommonFormat(target));
+
+ final String input =
+ "V1::" + target + "::" + bpk + "::" + sdf.format(new Date());
+ // System.out.println(input);
+ byte[] result;
+ try {
+ final byte[] inputBytes = input.getBytes("ISO-8859-1");
+ result = encrypt(inputBytes, publicKey);
+ return new String(Base64Utils.encode(result), "ISO-8859-1").replaceAll("\r\n", "");
+ // return new String(Base64Utils.encode(result,
+ // "ISO-8859-1")).replaceAll("\r\n", "");
+
+ } catch (final Exception e) {
+ throw new EaafBuilderException("bPK encryption FAILED", null, e.getMessage(), e);
+
+ }
+ }
+
+ /**
+ * Decrypt an encrypted bPK.
+ *
+ * @param encryptedBpk encrypted bPK
+ * @param target bPK target in full form
+ * @param privateKey private-key for decryption
+ * @return bPK Pair consists of (unique person identifier for this target,
+ * targetArea) but never null
+ * @throws EaafBuilderException In case of an error
+ */
+ public static Pair<String, String> decryptBpk(final String encryptedBpk, String target,
+ final PrivateKey privateKey) throws EaafBuilderException {
+ String decryptedString;
+
+ if (!target.startsWith(EaafConstants.URN_PREFIX_WITH_COLON)) {
+ throw new EaafBuilderException("builder.32",
+ null, ERROR_MSG_WRONG_TARGET_FORMAT);
+
+ }
+
+ try {
+ final byte[] encryptedBytes = Base64Utils.decode(encryptedBpk.getBytes("ISO-8859-1"));
+ final byte[] decryptedBytes = decrypt(encryptedBytes, privateKey);
+ decryptedString = new String(decryptedBytes, "ISO-8859-1");
+
+ } catch (final Exception e) {
+ throw new EaafBuilderException("bPK decryption FAILED", null, e.getMessage(), e);
+
+ }
+
+ String[] parts = decryptedString.split("::");
+ if (parts.length != 4) {
+ log.trace("Encrypted bPK has value: {}", decryptedString);
+ throw new EaafBuilderException("builder.31", new Object[] {parts.length},
+ "encBpk has a suspect format");
+
+ }
+
+ final String sector = parts[1];
+ final String bPK = parts[2];
+
+ if (target.equals(normalizeBpkTargetIdentifierToCommonFormat(sector))) {
+ return Pair.newInstance(bPK, target);
+
+ } else {
+ throw new EaafBuilderException("builder.30", new Object[] {sector, target},
+ "Decrypted bPK-target does not match");
+
+ }
+ }
+
+ /**
+ * Normalize wbPK target identifier for FN, ZVR, and ERSB to XFN, XZVR, and XERSB.
+ *
+ * <p>If the target is not of this types the target will be returned as it is</p>
+ * @param targetIdentifier bPK input target
+ * @return XFN, XZVR, XERSB, or targetIdentfier if no normalization is required
+ */
+ @Nullable
+ public static String normalizeBpkTargetIdentifierToCommonFormat(@Nullable String targetIdentifier) {
+ if (targetIdentifier != null
+ && !targetIdentifier.startsWith(EaafConstants.URN_PREFIX_WBPK_TARGET_WITH_X)) {
+ for (Entry<String, String> mapper : EaafConstants.URN_WBPK_TARGET_X_TO_NONE_MAPPER.entrySet()) {
+ if (targetIdentifier.startsWith(mapper.getValue())) {
+ String wbpkTarget = mapper.getKey() + targetIdentifier.substring(mapper.getValue().length());
+ log.trace("Normalize wbPK target: {} to {}", targetIdentifier, wbpkTarget);
+ return wbpkTarget;
+
+ }
+ }
+ }
+
+ return targetIdentifier;
+ }
+
+ /**
+ * Normalize wbPK target identifier for XFN, XZVR, and XERSB to bPK non-X format like, FN, ZVR, and ERSB.
+ *
+ * <p>If the target is not of this types the target will be returned as it is</p>
+ *
+ * @param targetIdentifier bPK input target
+ * @return FN, ZVR, ERSB, or targetIdentfier if no normalization is required
+ */
+ @Nullable
+ public static String normalizeBpkTargetIdentifierToNonXFormat(@Nullable String targetIdentifier) {
+ if (targetIdentifier != null && targetIdentifier.startsWith(EaafConstants.URN_PREFIX_WBPK)) {
+ for (Entry<String, String> mapper : EaafConstants.URN_WBPK_TARGET_X_TO_NONE_MAPPER.entrySet()) {
+ if (targetIdentifier.startsWith(mapper.getKey())) {
+ String wbpkTarget = mapper.getValue() + targetIdentifier.substring(mapper.getKey().length());
+ log.trace("Find new wbPK target: {}. Replace it by: {}", targetIdentifier, wbpkTarget);
+ return wbpkTarget;
+
+ }
+ }
+ }
+
+ return targetIdentifier;
+ }
+
+ /**
+ * Normalize wbPK target identifier for XFN, XZVR, and XERSB to bPK calculation format like, FN, VR, and ERJ.
+ *
+ * <p>If the target is not of this types the target will be returned as it is</p>
+ *
+ * @param targetIdentifier bPK input target
+ * @return FN, VR, ERJ, or targetIdentfier if no normalization is required
+ */
+ @Nullable
+ public static String normalizeBpkTargetIdentifierToBpkCalculationFormat(@Nullable String targetIdentifier) {
+ if (targetIdentifier != null && targetIdentifier.startsWith(EaafConstants.URN_PREFIX_WBPK)) {
+ for (Entry<String, String> mapper : EaafConstants.URN_WBPK_TARGET_X_TO_CALC_TARGET_MAPPER.entrySet()) {
+ if (targetIdentifier.startsWith(mapper.getKey())) {
+ String wbpkTarget = mapper.getValue() + targetIdentifier.substring(mapper.getKey().length());
+ log.trace("Find new wbPK target: {}. Replace it by: {}", targetIdentifier, wbpkTarget);
+ return wbpkTarget;
+
+ }
+ }
+ }
+
+ return targetIdentifier;
+ }
+
+ /**
+ * Remove prefixes from bPK target identifier and get only the SP specific part.
+ *
+ * @param type full qualified bPK target with 'urn:publicid:gv.at:' prefix
+ * @return SP specific part, or full type if reduction is not supported
+ */
+ @Nonnull
+ public static String removeBpkTypePrefix(@Nonnull final String type) {
+ Assert.isTrue(type != null, "bPKType is 'NULL'");
+ if (type.startsWith(EaafConstants.URN_PREFIX_WBPK)) {
+ return type.substring(EaafConstants.URN_PREFIX_WBPK.length());
+
+ } else if (type.startsWith(EaafConstants.URN_PREFIX_CDID)) {
+ return type.substring(EaafConstants.URN_PREFIX_CDID.length());
+
+ } else if (type.startsWith(EaafConstants.URN_PREFIX_EIDAS)) {
+ return type.substring(EaafConstants.URN_PREFIX_EIDAS.length());
+
+ } else {
+ return type;
+
+ }
+ }
+
+ /**
+ * Builds the eIDAS from the given parameters.
+ *
+ * @param baseId baseID of the citizen
+ * @param baseIdType Type of the baseID
+ * @param sourceCountry CountryCode of that country, which build the eIDAs
+ * ID
+ * @param destinationCountry CountryCode of that country, which receives the
+ * eIDAs ID
+ *
+ * @return Pair eIDAs/bPKType in a BASE64 encoding
+ * @throws EaafBuilderException if some input data are not valid
+ */
+ private static Pair<String, String> buildEidasIdentifer(final String baseId,
+ final String baseIdType, final String sourceCountry, final String destinationCountry)
+ throws EaafBuilderException {
+ String bpk = null;
+ String bpkType = null;
+
+ // check if we have been called by public sector application
+ if (baseIdType.startsWith(EaafConstants.URN_PREFIX_BASEID)) {
+ bpkType = EaafConstants.URN_PREFIX_EIDAS + sourceCountry + "+" + destinationCountry;
+ log.debug("Building eIDAS identification from: [identValue]+" + bpkType);
+ bpk = calculatebPKwbPK(baseId + "+" + bpkType);
+
+ } else { // if not, sector identification value is already calculated by BKU
+ log.debug("eIDAS eIdentifier already provided by BKU");
+ bpk = baseId;
+ }
+
+ if (StringUtils.isEmpty(bpk) || StringUtils.isEmpty(sourceCountry)
+ || StringUtils.isEmpty(destinationCountry)) {
+ throw new EaafBuilderException("builder.00",
+ new Object[] { "eIDAS-ID",
+ "Unvollständige Parameterangaben: identificationValue=" + bpk + ", Zielland="
+ + destinationCountry + ", Ursprungsland=" + sourceCountry },
+ "eIDAS-ID: Unvollständige Parameterangaben: identificationValue=" + bpk + ", Zielland="
+ + destinationCountry + ", Ursprungsland=" + sourceCountry);
+ }
+
+ log.trace("eIDAS pseudonym generation finished. ");
+ final String eIdentifier = sourceCountry + "/" + destinationCountry + "/" + bpk;
+
+ return Pair.newInstance(eIdentifier, bpkType);
+ }
+
+ private static String calculatebPKwbPK(final String basisbegriff) throws EaafBuilderException {
+ try {
+ final MessageDigest md = MessageDigest.getInstance("SHA-1");
+ final byte[] hash = md.digest(basisbegriff.getBytes("ISO-8859-1"));
+ final String hashBase64 =
+ new String(Base64Utils.encode(hash), "ISO-8859-1").replaceAll("\r\n", ""); // Base64Utils.encode(hash);
+ return hashBase64;
+
+ } catch (final Exception ex) {
+ throw new EaafBuilderException(ERROR_CODE_33, new Object[] {ex.toString() },
+ ex.getMessage(), ex);
+
+ }
+
+ }
+
+ private static byte[] encrypt(final byte[] inputBytes, final PublicKey publicKey)
+ throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException,
+ IllegalBlockSizeException, BadPaddingException {
+ byte[] result;
+ Cipher cipher = null;
+ try {
+ cipher = Cipher.getInstance("RSA/ECB/OAEPPadding"); // try with bouncycastle
+
+ } catch (final NoSuchAlgorithmException e) {
+ cipher = Cipher.getInstance("RSA/ECB/OAEP"); // try with iaik provider
+ }
+ cipher.init(Cipher.ENCRYPT_MODE, publicKey);
+ result = cipher.doFinal(inputBytes);
+
+ return result;
+ }
+
+ private static byte[] decrypt(final byte[] encryptedBytes, final PrivateKey privateKey)
+ throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException,
+ IllegalBlockSizeException, BadPaddingException {
+ byte[] result;
+ Cipher cipher = null;
+ try {
+ cipher = Cipher.getInstance("RSA/ECB/OAEPPadding"); // try with bouncycastle
+
+ } catch (final NoSuchAlgorithmException e) {
+ cipher = Cipher.getInstance("RSA/ECB/OAEP"); // try with iaik provider
+
+ }
+ cipher.init(Cipher.DECRYPT_MODE, privateKey);
+ result = cipher.doFinal(encryptedBytes);
+ return result;
+
+ }
+}
diff --git a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/credential/EaafKeyStoreFactory.java b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/credential/EaafKeyStoreFactory.java
index e60c326c..623e9d2c 100644
--- a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/credential/EaafKeyStoreFactory.java
+++ b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/credential/EaafKeyStoreFactory.java
@@ -2,37 +2,46 @@ package at.gv.egiz.eaaf.core.impl.credential;
import java.io.IOException;
import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
import java.security.Key;
import java.security.KeyStore;
+import java.security.KeyStore.LoadStoreParameter;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.Provider;
import java.security.Security;
+import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.annotation.PostConstruct;
+import javax.crypto.SecretKey;
+import javax.crypto.SecretKeyFactory;
+import javax.crypto.spec.PBEKeySpec;
+
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.core.io.Resource;
+import org.springframework.core.io.ResourceLoader;
-import at.asitplus.hsmfacade.provider.HsmFacadeProvider;
-import at.asitplus.hsmfacade.provider.RemoteKeyStoreLoadParameter;
import at.gv.egiz.eaaf.core.api.idp.IConfiguration;
+import at.gv.egiz.eaaf.core.exception.EaafKeyAccessException;
import at.gv.egiz.eaaf.core.exceptions.EaafConfigurationException;
import at.gv.egiz.eaaf.core.exceptions.EaafException;
import at.gv.egiz.eaaf.core.exceptions.EaafFactoryException;
import at.gv.egiz.eaaf.core.impl.credential.KeyStoreConfiguration.KeyStoreType;
+import at.gv.egiz.eaaf.core.impl.credential.SymmetricKeyConfiguration.SymmetricKeyType;
import at.gv.egiz.eaaf.core.impl.data.Pair;
import at.gv.egiz.eaaf.core.impl.utils.FileUtils;
import at.gv.egiz.eaaf.core.impl.utils.KeyStoreUtils;
-
-import org.apache.commons.lang3.StringUtils;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.core.io.Resource;
-import org.springframework.core.io.ResourceLoader;
-
import lombok.extern.slf4j.Slf4j;
@Slf4j
@@ -43,6 +52,7 @@ public class EaafKeyStoreFactory {
public static final String CONFIG_PROP_HSM_FACADE_SSLTRUST = "security.hsmfacade.trustedsslcert";
public static final String CONFIG_PROP_HSM_FACADE_CLIENT_USERNAME = "security.hsmfacade.username";
public static final String CONFIG_PROP_HSM_FACADE_CLIENT_PASSWORD = "security.hsmfacade.password";
+ public static final String CONFIG_PROP_HSM_FACADE_GRPC_DEADLINE = "security.hsmfacade.grpc.deadline";
public static final String ERRORCODE_00 = "internal.keystore.00";
public static final String ERRORCODE_01 = "internal.keystore.01";
@@ -52,10 +62,26 @@ public class EaafKeyStoreFactory {
public static final String ERRORCODE_05 = "internal.keystore.05";
public static final String ERRORCODE_06 = "internal.keystore.06";
public static final String ERRORCODE_07 = "internal.keystore.07";
-
+ public static final String ERRORCODE_10 = "internal.keystore.10";
+ public static final String ERRORCODE_11 = "internal.keystore.11";
+
+ public static final String ERRORCODE_KEY_00 = "internal.key.00";
+
+ private static final String HSM_FACADE_PROVIDER_CLASS = "at.asitplus.hsmfacade.provider.HsmFacadeProvider";
+ private static final String HSM_FACADE_KEYSTORELOADPARAMETERS_CLASS
+ = "at.asitplus.hsmfacade.provider.RemoteKeyStoreLoadParameter";
+ private static final String HSM_FACADE_PROVIDER_METHOD_CONSTRUCT = "getInstance";
+ private static final String HSM_FACADE_PROVIDER_METHOD_INIT = "init";
+ private static final String HSM_FACADE_PROVIDER_METHOD_ISINITIALIZED = "isInitialized";
+ private static final String HSM_FACADE_PROVIDER_METHOD_HEALTHCHECK = "healthcheck";
+ private static final String HSM_FACADE_PROVIDER_INIT_ERROR_MSG
+ = "Has HSM-Facade class supported '{}' method: {}";
private static final String HSM_FACADE_PROVIDER = "HsmFacade";
private static final String HSM_FACADE_KEYSTORE_TYPE = "RemoteKeyStore";
-
+ private static final String HSM_FACADE_DEFAULT_DEADLINE = "30";
+
+ public enum HsmFacadeStatus { UP, DOWN, UNKNOWN }
+
@Autowired
private IConfiguration basicConfig;
@Autowired
@@ -64,6 +90,43 @@ public class EaafKeyStoreFactory {
private boolean isHsmFacadeInitialized = false;
/**
+ * Get a new symmetric key based on a {@link SymmetricKeyConfiguration} object.
+ *
+ * @param config Symmetric key configuration
+ * @return {@link Pair} of a new {@link SecretKey} instance and an optional {@link Provider}.
+ * The {@link SecretKey} is {@link Nonnull}. If the {@link Provider} is not <code>null</code>
+ * this {@link SecretKey} requires a specific {@link Provider} for {@link Key} operations.
+ * @throws EaafException In case of a KeyStore initialization error
+ */
+ @Nonnull
+ public Pair<SecretKey, Provider> buildNewSymmetricKey(SymmetricKeyConfiguration config) throws EaafException {
+ log.trace("Starting symmetric-key generation based on configuration object ... ");
+ if (SymmetricKeyType.PASSPHRASE.equals(config.getKeyType())) {
+ return generatePassPhraseBasedSymmetricKey(config);
+
+ } else if (SymmetricKeyType.HSMFACADE.equals(config.getKeyType())) {
+ if (isHsmFacadeInitialized) {
+ return getSymmetricKeyFromHsmFacade(config);
+
+ } else {
+ log.error("HSMFacade can NOT be used for symmetric Key: {} because {} is not initialized",
+ config.getFriendlyName());
+ throw new EaafConfigurationException(ERRORCODE_00,
+ new Object[] { config.getFriendlyName() });
+
+ }
+
+ } else {
+ log.warn("Symmetric KeyType: {} is unrecognized", config.getKeyType());
+ throw new EaafConfigurationException(ERRORCODE_01,
+ new Object[] { config.getFriendlyName() });
+
+ }
+
+
+ }
+
+ /**
* Get a new KeyStore based on a KeyStore configuration-object.
*
* @param config KeyStore configuration
@@ -113,45 +176,168 @@ public class EaafKeyStoreFactory {
return isHsmFacadeInitialized;
}
+
+ /**
+ * Get the current status for HSM-Facade interaction.
+ *
+ * @return {@link HsmFacadeStatus} to indicate the current status.
+ */
+ public HsmFacadeStatus checkHsmFacadeStatus() {
+ if (isHsmFacadeInitialized()) {
+ final Provider alreadyLoadedProvider = Security.getProvider(HSM_FACADE_PROVIDER);
+ if (alreadyLoadedProvider != null) {
+ try {
+ final Method healthCheck =
+ alreadyLoadedProvider.getClass().getMethod(HSM_FACADE_PROVIDER_METHOD_HEALTHCHECK, new Class[]{});
+ boolean currentHealthStatus = (boolean) healthCheck.invoke(alreadyLoadedProvider);
+ HsmFacadeStatus status = currentHealthStatus ? HsmFacadeStatus.UP : HsmFacadeStatus.DOWN;
+ log.trace("Current HSM-Facade status is: {}", status);
+ return status;
+
+ } catch (final Exception e) {
+ log.info("Can not determine state of alreay loaded HSM Facade: {} because HealthCheck not support",
+ alreadyLoadedProvider.getVersion());
+ log.debug("Full HSM-Facade health-check exception", e);
+ return HsmFacadeStatus.UNKNOWN;
+
+ }
+
+ } else {
+ log.warn("HSM-Facade is marked as 'initialized', but not load as Security-Provider");
+ return HsmFacadeStatus.DOWN;
+ }
+
+ } else {
+ log.trace("HSM-Facade is not initialized. Set status do 'unknown'");
+ return HsmFacadeStatus.UNKNOWN;
+
+ }
+ }
+
@PostConstruct
private void initialize() throws EaafException {
+ final Class<?> hsmProviderClazz = getHsmProviderClass();
+ if (hsmProviderClazz != null) {
+ final String hsmFacadeHost = basicConfig.getBasicConfiguration(CONFIG_PROP_HSM_FACADE_HOST);
+ final Provider alreadyLoadedProvider = Security.getProvider(HSM_FACADE_PROVIDER);
+ if (alreadyLoadedProvider != null
+ && alreadyLoadedProvider.getClass().isAssignableFrom(hsmProviderClazz)) {
+ log.info("Find already initialized Java SecurityProvider: {}", alreadyLoadedProvider.getName());
+ //mark it as initialized if the state can not be determined
+ boolean isAlreadyInitialized = true;
+ try {
+ final Method initializeCheck =
+ alreadyLoadedProvider.getClass().getMethod(HSM_FACADE_PROVIDER_METHOD_ISINITIALIZED, new Class[]{});
+ isAlreadyInitialized = (boolean) initializeCheck.invoke(alreadyLoadedProvider);
+
+ } catch (final Exception e) {
+ log.warn("Can not determine state of alreay loaded HSM Facade. Mark it as 'initialized'");
+ log.debug("HSM Facade check error: {}", e.getMessage());
+
+ }
+ isHsmFacadeInitialized = isAlreadyInitialized;
+
+ if (isHsmFacadeInitialized) {
+ log.info("HSM Facade is already initialized. {} can provide KeyStores based on remote HSM",
+ EaafKeyStoreFactory.class.getSimpleName());
+
+ } else {
+ log.info("HSM Facade is already loaded but not initialized. {} can NOT provide KeyStores based on remote HSM",
+ EaafKeyStoreFactory.class.getSimpleName());
+
+ }
+
+ } else if (StringUtils.isNotEmpty(hsmFacadeHost)) {
+ log.debug("Find host for HSMFacade. Starting crypto provider initialization ... ");
+ initializeHsmFacadeSecurityProvider(hsmProviderClazz, hsmFacadeHost);
- final String hsmFacadeHost = basicConfig.getBasicConfiguration(CONFIG_PROP_HSM_FACADE_HOST);
- if (StringUtils.isNotEmpty(hsmFacadeHost)) {
- log.debug("Find host for HSMFacade. Starting crypto provider initialization ... ");
- try {
- final int port = Integer.parseUnsignedInt(
- getConfigurationParameter(CONFIG_PROP_HSM_FACADE_PORT));
- final String clientUsername =
- getConfigurationParameter(CONFIG_PROP_HSM_FACADE_CLIENT_USERNAME);
- final String clientPassword =
- getConfigurationParameter(CONFIG_PROP_HSM_FACADE_CLIENT_PASSWORD);
-
- final HsmFacadeProvider provider = HsmFacadeProvider.Companion.getInstance();
- provider.init(getHsmFacadeTrustSslCertificate(), clientUsername, clientPassword, hsmFacadeHost, port);
- //Security.addProvider(provider);
- Security.insertProviderAt(provider, 0);
- isHsmFacadeInitialized = true;
- log.info("HSM Facade is initialized. {} can provide KeyStores based on remote HSM",
+ } else {
+ log.info("HSM Facade is on ClassPath but not configurated. {} can only provide software keystores",
EaafKeyStoreFactory.class.getSimpleName());
- } catch (final EaafException e) {
- throw e;
-
- } catch (final Exception e) {
- log.error("HSM Facade initialization FAILED with an generic error.", e);
- throw new EaafConfigurationException(ERRORCODE_03, new Object[] { e.getMessage() }, e);
}
} else {
- log.info("HSM Facade is not configurated. {} can only provide software keystores",
+ log.info("HSM Facade is not on ClassPath. {} can only provide software keystores",
EaafKeyStoreFactory.class.getSimpleName());
}
}
+ private void initializeHsmFacadeSecurityProvider(Class<?> hsmProviderClazz, String hsmFacadeHost)
+ throws EaafException {
+ try {
+ final int port = Integer.parseUnsignedInt(
+ getConfigurationParameter(CONFIG_PROP_HSM_FACADE_PORT));
+ final String clientUsername =
+ getConfigurationParameter(CONFIG_PROP_HSM_FACADE_CLIENT_USERNAME);
+ final String clientPassword =
+ getConfigurationParameter(CONFIG_PROP_HSM_FACADE_CLIENT_PASSWORD);
+ final long grpcDeadline = getConfigurationParameterLong(CONFIG_PROP_HSM_FACADE_GRPC_DEADLINE,
+ HSM_FACADE_DEFAULT_DEADLINE);
+
+
+ //initialize HSM-Facade by using JAVA Reflection, because in that case HSM-Facade
+ //has not be in ClassPath on every project
+ final Method constructor = hsmProviderClazz.getMethod(HSM_FACADE_PROVIDER_METHOD_CONSTRUCT, new Class[]{});
+ final Method initMethod = hsmProviderClazz.getMethod(HSM_FACADE_PROVIDER_METHOD_INIT,
+ X509Certificate.class, String.class, String.class, String.class, int.class, long.class);
+ if (initMethod != null && constructor != null) {
+ final Object rawProvider = constructor.invoke(hsmProviderClazz);
+ initMethod.invoke(
+ rawProvider, getHsmFacadeTrustSslCertificate(),
+ clientUsername, clientPassword, hsmFacadeHost, port, grpcDeadline);
+
+ if (rawProvider instanceof Provider) {
+ Security.addProvider((Provider) rawProvider);
+
+ isHsmFacadeInitialized = true;
+ log.info("HSM Facade is initialized. {} can provide KeyStores based on remote HSM",
+ EaafKeyStoreFactory.class.getSimpleName());
+
+ } else {
+ log.warn("Is HSM-Facade class type of 'java.security.Provider': {}",
+ rawProvider instanceof Provider);
+ throw new EaafException(ERRORCODE_10, new Object[] {HSM_FACADE_PROVIDER_CLASS});
+
+ }
+
+ } else {
+ log.warn(HSM_FACADE_PROVIDER_INIT_ERROR_MSG,
+ HSM_FACADE_PROVIDER_METHOD_CONSTRUCT, constructor != null);
+ log.warn(HSM_FACADE_PROVIDER_INIT_ERROR_MSG,
+ HSM_FACADE_PROVIDER_METHOD_INIT, initMethod != null);
+ throw new EaafException(ERRORCODE_10, new Object[] {HSM_FACADE_PROVIDER_CLASS});
+
+ }
+
+ //final HsmFacadeProvider provider = HsmFacadeProvider.Companion.getInstance();
+ //provider.init(getHsmFacadeTrustSslCertificate(), clientUsername, clientPassword, hsmFacadeHost, port);
+
+ } catch (final EaafException e) {
+ throw e;
+
+ } catch (final Exception e) {
+ log.error("HSM Facade initialization FAILED with an generic error.", e);
+ throw new EaafConfigurationException(ERRORCODE_03, new Object[] { e.getMessage() }, e);
+
+ }
+
+ }
+
+ private Class<?> getHsmProviderClass() {
+ try {
+ return Class.forName(HSM_FACADE_PROVIDER_CLASS);
+
+ } catch (final ClassNotFoundException e1) {
+ log.debug("No HSM-Facade implemenation in ClassPath. HSM-Facade will not be available");
+ return null;
+
+ }
+ }
+
@Nonnull
private Pair<KeyStore, Provider> getKeyStoreFromFileSystem(KeyStoreConfiguration config)
throws EaafConfigurationException, EaafFactoryException {
@@ -162,28 +348,41 @@ public class EaafKeyStoreFactory {
final String keyStorePassword = checkConfigurationParameter(config.getSoftKeyStorePassword(),
ERRORCODE_06, config.getFriendlyName(), "Software-KeyStore missing Password for KeyStore");
- final String absKeyStorePath = FileUtils.makeAbsoluteUrl(keyStorePath, basicConfig
- .getConfigurationRootDirectory());
- final Resource ressource = resourceLoader.getResource(absKeyStorePath);
+ Resource ressource;
+ if (config.isSkipMakeAbsolutPaths()) {
+ log.debug("Use filepath from config: {}", keyStorePath);
+ ressource = resourceLoader.getResource(keyStorePath);
+
+ } else {
+ final String absKeyStorePath = FileUtils.makeAbsoluteUrl(keyStorePath, basicConfig
+ .getConfigurationRootDirectory());
+ log.debug("Use filepath from config: {}", absKeyStorePath);
+
+ ressource = resourceLoader.getResource(absKeyStorePath);
+
+ }
+
if (!ressource.exists()) {
- throw new EaafConfigurationException(ERRORCODE_05,
+ throw new EaafConfigurationException(ERRORCODE_06,
new Object[] { config.getFriendlyName(),
- "File not found at: " + absKeyStorePath });
+ "RessourceLoader does NOT find File at: " + ressource.getURI() });
}
final InputStream is = ressource.getInputStream();
- final KeyStore keyStore = KeyStoreUtils.loadKeyStore(is, keyStorePassword);
+ final KeyStore keyStore = KeyStoreUtils.loadKeyStore(is, keyStorePassword, config.getKeyStoreType());
is.close();
- if (keyStore == null) {
- throw new EaafFactoryException(ERRORCODE_06,
- new Object[] { config.getFriendlyName(), "KeyStore not valid or password wrong" });
-
- }
return Pair.newInstance(keyStore, null);
- } catch (KeyStoreException | IOException e) {
+ } catch (final EaafException e) {
+ throw e;
+
+ } catch (final IOException e) {
+ throw new EaafFactoryException(ERRORCODE_06,
+ new Object[] { config.getFriendlyName(), "KeyStore not valid or password wrong" });
+
+ } catch (final Exception e) {
log.error("Software KeyStore initialization FAILED with an generic error.", e);
throw new EaafConfigurationException(ERRORCODE_03, new Object[] { e.getMessage() }, e);
@@ -193,24 +392,102 @@ public class EaafKeyStoreFactory {
@Nonnull
private Pair<KeyStore, Provider> getKeyStoreFromHsmFacade(KeyStoreConfiguration config)
throws EaafFactoryException, EaafConfigurationException {
- final String keyStoreName = checkConfigurationParameter(config.getKeyStoreName(),
- ERRORCODE_06, config.getFriendlyName(), "KeyStoreName missing for HSM Facade");
+ return getKeyStoreFromHsmFacade(config.getKeyStoreName(), config.getFriendlyName());
+
+ }
+
+ @Nonnull
+ private Pair<KeyStore, Provider> getKeyStoreFromHsmFacade(String keyStoreName, String friendlyName)
+ throws EaafFactoryException, EaafConfigurationException {
+ final String validatedKeyStoreName = checkConfigurationParameter(keyStoreName,
+ ERRORCODE_06, friendlyName, "KeyStoreName missing for HSM Fac)ade");
try {
final KeyStore keyStore = KeyStore.getInstance(HSM_FACADE_KEYSTORE_TYPE, HSM_FACADE_PROVIDER);
- keyStore.load(new RemoteKeyStoreLoadParameter(keyStoreName));
+ keyStore.load(getHsmFacadeKeyStoreParameter(validatedKeyStoreName));
return Pair.newInstance(keyStore, keyStore.getProvider());
} catch (NoSuchAlgorithmException | CertificateException | IOException | KeyStoreException
- | NoSuchProviderException e) {
+ | NoSuchProviderException | EaafException e) {
log.error("Can not initialize KeyStore: {} with reason: {}",
- config.getFriendlyName(), e.getMessage());
+ friendlyName, e.getMessage());
throw new EaafFactoryException(ERRORCODE_06,
- new Object[] { config.getFriendlyName(), e.getMessage() }, e);
+ new Object[] {friendlyName, e.getMessage() }, e);
}
}
+ private KeyStore.LoadStoreParameter getHsmFacadeKeyStoreParameter(String keyStoreName) throws EaafException {
+ try {
+ final Class<?> clazz = Class.forName(HSM_FACADE_KEYSTORELOADPARAMETERS_CLASS);
+ final Constructor<?> constructor = clazz.getConstructor(String.class);
+ final Object keyStoreParams = constructor.newInstance(keyStoreName);
+ return (LoadStoreParameter) keyStoreParams;
+
+ } catch (final Exception e) {
+ log.error("Can NOT build class: {} for HSM-Facade provider", HSM_FACADE_KEYSTORELOADPARAMETERS_CLASS, e);
+ throw new EaafException(ERRORCODE_10, new Object[] {HSM_FACADE_PROVIDER_CLASS}, e);
+
+ }
+
+ }
+
+ @Nonnull
+ private Pair<SecretKey, Provider> generatePassPhraseBasedSymmetricKey(SymmetricKeyConfiguration config)
+ throws EaafConfigurationException {
+ checkConfigurationParameter(config.getSoftKeyPassphrase(),
+ ERRORCODE_KEY_00, config.getFriendlyName(), "passphrase missing");
+ checkConfigurationParameter(config.getSoftKeySalt(),
+ ERRORCODE_KEY_00, config.getFriendlyName(), "salt missing");
+
+ try {
+ final SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBKDF2WITHHMACSHA256");
+ final KeySpec spec = new PBEKeySpec(
+ config.getSoftKeyPassphrase().toCharArray(),
+ config.getSoftKeySalt().getBytes("UTF-8"),
+ 10000, 128);
+ return Pair.newInstance(keyFactory.generateSecret(spec), null);
+
+ } catch (NoSuchAlgorithmException | InvalidKeySpecException | UnsupportedEncodingException e) {
+ log.error("Passphrase based symmetric-key generation FAILED", e);
+ throw new EaafConfigurationException(ERRORCODE_KEY_00,
+ new Object[] { config.getFriendlyName(), e.getMessage() },
+ e);
+
+ }
+ }
+
+ @Nonnull
+ private Pair<SecretKey, Provider> getSymmetricKeyFromHsmFacade(SymmetricKeyConfiguration config)
+ throws EaafFactoryException, EaafConfigurationException, EaafKeyAccessException {
+ final Pair<KeyStore, Provider> keyStore = getKeyStoreFromHsmFacade(
+ config.getKeyStoreName(), config.getFriendlyName());
+
+ checkConfigurationParameter(config.getKeyAlias(),
+ ERRORCODE_KEY_00, config.getFriendlyName(), "keyAlias missing");
+
+ try {
+ final SecretKey secretKey = (SecretKey) keyStore.getFirst().getKey(config.getKeyAlias(), null);
+ if (secretKey == null) {
+ throw new EaafKeyAccessException(EaafKeyAccessException.ERROR_CODE_09,
+ config.getFriendlyName(), config.getKeyAlias(), "No SecretKey with Alias ");
+
+ }
+
+ return Pair.newInstance(secretKey, keyStore.getSecond());
+
+ } catch (UnrecoverableKeyException | KeyStoreException | NoSuchAlgorithmException e) {
+ throw new EaafKeyAccessException(EaafKeyAccessException.ERROR_CODE_09, e,
+ config.getFriendlyName(), config.getKeyAlias(), e.getMessage());
+
+ } catch (final ClassCastException e) {
+ throw new EaafKeyAccessException(EaafKeyAccessException.ERROR_CODE_09,
+ config.getFriendlyName(), config.getKeyAlias(), "Wrong SecretKey type ");
+
+ }
+
+ }
+
private X509Certificate getHsmFacadeTrustSslCertificate() throws EaafConfigurationException {
try {
final String certFilePath = getConfigurationParameter(CONFIG_PROP_HSM_FACADE_SSLTRUST);
@@ -241,6 +518,19 @@ public class EaafKeyStoreFactory {
}
@Nonnull
+ private Long getConfigurationParameterLong(@Nonnull String configParamKey, String defaultValue)
+ throws EaafConfigurationException {
+ try {
+ return Long.valueOf(basicConfig.getBasicConfiguration(configParamKey, defaultValue));
+
+ } catch (NumberFormatException e) {
+ throw new EaafConfigurationException(ERRORCODE_05, new Object[] { configParamKey, e.getMessage()});
+
+ }
+
+ }
+
+ @Nonnull
private String getConfigurationParameter(@Nonnull String configParamKey)
throws EaafConfigurationException {
return checkConfigurationParameter(
diff --git a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/credential/EaafKeyStoreUtils.java b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/credential/EaafKeyStoreUtils.java
index b4b44724..12541222 100644
--- a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/credential/EaafKeyStoreUtils.java
+++ b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/credential/EaafKeyStoreUtils.java
@@ -24,13 +24,13 @@ import lombok.extern.slf4j.Slf4j;
public class EaafKeyStoreUtils {
private static final String ERROR_MSG_REASON = "Maybe 'Alias' is not valid";
private static final String ERROR_MSG_1 = "Can NOT access key: {} in KeyStore: {}. Reason: {}";
- private static final String ERROR_MSG_2 = "Key: {} will be NOT available";
+ private static final String ERROR_MSG_2 = "Key: {} will be NOT available";
/**
* Read all certificates from a {@link KeyStore}.
*
* @param keyStore KeyStore with certificates
- * @return {@link List} of {@link X509Certificate}, but never null
+ * @return Unmodifiable {@link List} of {@link X509Certificate}, but never null
* @throws KeyStoreException In case of an error during KeyStore operations
*/
@Nonnull
@@ -45,6 +45,7 @@ public class EaafKeyStoreUtils {
final Certificate cert = keyStore.getCertificate(el);
if (cert != null && cert instanceof X509Certificate) {
result.add((X509Certificate) cert);
+
} else {
log.info("Can not process entry: {}. Reason: {}", el, cert != null ? cert.getType() : "cert is null");
}
diff --git a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/credential/KeyStoreConfiguration.java b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/credential/KeyStoreConfiguration.java
index 970efd22..c1a1d917 100644
--- a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/credential/KeyStoreConfiguration.java
+++ b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/credential/KeyStoreConfiguration.java
@@ -4,10 +4,9 @@ import java.util.Map;
import javax.annotation.Nonnull;
-import at.gv.egiz.eaaf.core.exceptions.EaafConfigurationException;
-
import org.apache.commons.lang3.StringUtils;
+import at.gv.egiz.eaaf.core.exceptions.EaafConfigurationException;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
@@ -53,6 +52,12 @@ public class KeyStoreConfiguration {
*/
private String softKeyStorePassword;
+
+ /**
+ * Use filePaths as it is and does not make it absolut.
+ */
+ private boolean skipMakeAbsolutPaths = false;
+
/**
* Build a {@link KeyStoreConfiguration} from a configuration map. <br>
* <p>
diff --git a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/credential/SymmetricKeyConfiguration.java b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/credential/SymmetricKeyConfiguration.java
new file mode 100644
index 00000000..9477789c
--- /dev/null
+++ b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/credential/SymmetricKeyConfiguration.java
@@ -0,0 +1,221 @@
+package at.gv.egiz.eaaf.core.impl.credential;
+
+import java.util.Map;
+
+import javax.annotation.Nonnull;
+
+import org.apache.commons.lang3.StringUtils;
+
+import at.gv.egiz.eaaf.core.exceptions.EaafConfigurationException;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+@Getter
+@Setter
+public class SymmetricKeyConfiguration {
+
+ public static final String PROP_CONFIG_KEY_TYPE =
+ "key.type";
+
+ public static final String PROP_CONFIG_HSMFACADE_NAME =
+ "keystore.name";
+ public static final String PROP_CONFIG_HSM_KEY_ALIAS =
+ "key.alias";
+
+ public static final String PROP_CONFIG_SOFTWARE_KEY_PASSPHRASE =
+ "key.passphrase";
+ public static final String PROP_CONFIG_SOFTWARE_KEY_SALT =
+ "key.salt";
+
+ /**
+ * FriendlyName for this KeyStore. Mainly used for logging.
+ */
+ private String friendlyName;
+
+ /**
+ * General type of the KeyStore that should be generated.
+ */
+ private SymmetricKeyType keyType;
+
+ /**
+ * Name of the KeyStore in HSM Facade.
+ */
+ private String keyStoreName;
+
+ /**
+ * Alias of the Key in HSM Facade keystore.
+ */
+ private String keyAlias;
+
+ /**
+ * Software key passphrase.
+ */
+ private String softKeyPassphrase;
+
+ /**
+ * Software key salt.
+ */
+ private String softKeySalt;
+
+ /**
+ * Build a {@link SymmetricKeyConfiguration} from a configuration map. <br>
+ * <p>
+ * The configuration parameters defined in this class are used to load the
+ * configuration.
+ * </p>
+ *
+ * @param config Configuration
+ * @param friendlyName FriendlyName for this KeyStore
+ * @return Configuration object for {@link EaafKeyStoreFactory}
+ * @throws EaafConfigurationException In case of a configuration error.
+ */
+ public static SymmetricKeyConfiguration buildFromConfigurationMap(Map<String, String> config,
+ String friendlyName) throws EaafConfigurationException {
+
+ final SymmetricKeyConfiguration internalConfig = new SymmetricKeyConfiguration();
+ internalConfig.setFriendlyName(friendlyName);
+
+ final SymmetricKeyType internalKeyStoreType = SymmetricKeyType.fromString(
+ getConfigurationParameter(config, PROP_CONFIG_KEY_TYPE));
+ if (internalKeyStoreType != null) {
+ internalConfig.setKeyType(internalKeyStoreType);
+
+ } else {
+ log.error("Symmetric Key-configuration: {} sets an unknown Keytype: {}",
+ friendlyName, getConfigurationParameter(config, PROP_CONFIG_KEY_TYPE));
+ throw new EaafConfigurationException(EaafKeyStoreFactory.ERRORCODE_01,
+ new Object[] { friendlyName });
+
+ }
+
+ if (internalKeyStoreType.equals(SymmetricKeyType.HSMFACADE)) {
+ log.trace("Set-up HSM-Facade Symmentric-Key ... ");
+ internalConfig.setKeyStoreName(getConfigurationParameter(config, PROP_CONFIG_HSMFACADE_NAME));
+ internalConfig.setKeyAlias(getConfigurationParameter(config, PROP_CONFIG_HSM_KEY_ALIAS));
+
+ } else {
+ log.trace("Set-up software passphrase based symmetric key ... ");
+ internalConfig.setSoftKeyPassphrase(getConfigurationParameter(config, PROP_CONFIG_SOFTWARE_KEY_PASSPHRASE));
+ internalConfig.setSoftKeySalt(getConfigurationParameter(config, PROP_CONFIG_SOFTWARE_KEY_SALT));
+
+ }
+
+ return internalConfig;
+ }
+
+ /**
+ * Set the Type of the symmetric key based on String identifier.
+ *
+ * @param keyType String based KeyStore type
+ * @throws EaafConfigurationException In case of an unknown KeyStore type
+ */
+ public void setKeyType(@Nonnull String keyType) throws EaafConfigurationException {
+ final SymmetricKeyType internalKeyStoreType = SymmetricKeyType.fromString(keyType);
+ if (internalKeyStoreType != null) {
+ setKeyType(internalKeyStoreType);
+
+ } else {
+ log.error("KeyStore: {} sets an unknown KeyStore type: {}",
+ friendlyName, keyType);
+ throw new EaafConfigurationException(EaafKeyStoreFactory.ERRORCODE_01,
+ new Object[] { friendlyName });
+
+ }
+
+ }
+
+ /**
+ * Set the Type of the symmetric Key based on String identifier.
+ *
+ * @param type of tke symmetric key
+ */
+ public void setKeyType(@Nonnull SymmetricKeyType type) {
+ this.keyType = type;
+
+ }
+
+ /**
+ * Validate the internal state of this configuration object.
+ *
+ * @throws EaafConfigurationException In case of a configuration error
+ */
+ public void validate() throws EaafConfigurationException {
+ if (SymmetricKeyType.HSMFACADE.equals(keyType)) {
+ log.trace("Validate HSM-Facade symmetric key ... ");
+ checkConfigurationValue(keyStoreName, EaafKeyStoreFactory.ERRORCODE_07,
+ friendlyName, "Missing 'KeyStoreName' for HSM-Facade");
+ checkConfigurationValue(keyAlias, EaafKeyStoreFactory.ERRORCODE_07,
+ friendlyName, "Missing 'KeyAlias' for HSM-Facade");
+
+ } else {
+ log.trace("Validate passphrase based symmetric key ... ");
+ checkConfigurationValue(softKeyPassphrase, EaafKeyStoreFactory.ERRORCODE_07,
+ friendlyName, "Missing 'passphrase' for symmetric-key generation");
+ checkConfigurationValue(softKeySalt, EaafKeyStoreFactory.ERRORCODE_07,
+ friendlyName, "Missing 'salt' for symmetric-key generation");
+
+ }
+ }
+
+ public enum SymmetricKeyType {
+ PASSPHRASE("passphrase"), HSMFACADE("hsmfacade");
+
+ private final String keyType;
+
+ SymmetricKeyType(final String keyStoreType) {
+ this.keyType = keyStoreType;
+ }
+
+ /**
+ * Get Type of this Key.
+ *
+ * @return
+ */
+ public String getKeyType() {
+ return this.keyType;
+ }
+
+ /**
+ * Get KeyType from String representation.
+ *
+ * @param s Config parameter
+ * @return
+ */
+ public static SymmetricKeyType fromString(final String s) {
+ try {
+ return SymmetricKeyType.valueOf(s.toUpperCase());
+
+ } catch (IllegalArgumentException | NullPointerException e) {
+ return null;
+ }
+ }
+
+ @Override
+ public String toString() {
+ return getKeyType();
+
+ }
+ }
+
+ @Nonnull
+ private static String getConfigurationParameter(@Nonnull Map<String, String> config,
+ @Nonnull String configParamKey)
+ throws EaafConfigurationException {
+ final String configValue = config.get(configParamKey);
+ checkConfigurationValue(configValue, EaafKeyStoreFactory.ERRORCODE_04, configParamKey);
+ return configValue;
+
+ }
+
+ private static void checkConfigurationValue(String configValue, String errorCode, String... params)
+ throws EaafConfigurationException {
+ if (StringUtils.isEmpty(configValue)) {
+ throw new EaafConfigurationException(errorCode,
+ params);
+
+ }
+
+ }
+}
diff --git a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/http/EaafHttpRequestRetryHandler.java b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/http/EaafHttpRequestRetryHandler.java
new file mode 100644
index 00000000..3aa908e8
--- /dev/null
+++ b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/http/EaafHttpRequestRetryHandler.java
@@ -0,0 +1,33 @@
+package at.gv.egiz.eaaf.core.impl.http;
+
+import java.net.UnknownHostException;
+import java.util.Arrays;
+
+import javax.net.ssl.SSLException;
+
+import org.apache.http.client.HttpRequestRetryHandler;
+import org.apache.http.impl.client.DefaultHttpRequestRetryHandler;
+
+public class EaafHttpRequestRetryHandler extends DefaultHttpRequestRetryHandler implements
+ HttpRequestRetryHandler {
+
+ /**
+ * Create the request retry handler using the following list of non-retriable.
+ * IOException classes: <br>
+ * <ul>
+ * <li>UnknownHostException</li>
+ * <li>SSLException</li>
+ * </ul>
+ *
+ * @param retryCount how many times to retry; 0 means no retries
+ * @param requestSentRetryEnabled true if it's OK to retry non-idempotent
+ * requests that have been sent
+ */
+ public EaafHttpRequestRetryHandler(final int retryCount, final boolean requestSentRetryEnabled) {
+ super(retryCount, requestSentRetryEnabled, Arrays.asList(
+ UnknownHostException.class,
+ SSLException.class));
+
+ }
+
+}
diff --git a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/http/EaafSslContextBuilder.java b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/http/EaafSslContextBuilder.java
new file mode 100644
index 00000000..1cd739de
--- /dev/null
+++ b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/http/EaafSslContextBuilder.java
@@ -0,0 +1,433 @@
+package at.gv.egiz.eaaf.core.impl.http;
+
+import java.net.Socket;
+import java.security.KeyManagementException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.Principal;
+import java.security.PrivateKey;
+import java.security.Provider;
+import java.security.SecureRandom;
+import java.security.Security;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedHashSet;
+import java.util.Map;
+import java.util.Set;
+
+import javax.net.ssl.KeyManager;
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLEngine;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.TrustManagerFactory;
+import javax.net.ssl.X509ExtendedKeyManager;
+import javax.net.ssl.X509TrustManager;
+
+import org.apache.http.ssl.PrivateKeyDetails;
+import org.apache.http.ssl.PrivateKeyStrategy;
+import org.apache.http.ssl.SSLContextBuilder;
+import org.apache.http.ssl.TrustStrategy;
+import org.bouncycastle.jsse.provider.BouncyCastleJsseProvider;
+
+/**
+ * Fork of {@link SSLContextBuilder} that uses JSSE provider to get TrustManager.
+ *
+ * <p>This implementation fix an incompatibility between {@link BouncyCastleJsseProvider} and JAVA JDK >= v9</p>
+ *
+ * @author tlenz
+ *
+ */
+public class EaafSslContextBuilder {
+
+ static final String TLS = "TLS";
+
+ private String protocol;
+ private final Set<KeyManager> keyManagers;
+ private String keyManagerFactoryAlgorithm = KeyManagerFactory.getDefaultAlgorithm();
+ private String keyStoreType = KeyStore.getDefaultType();
+ private final Set<TrustManager> trustManagers;
+ private String trustManagerFactoryAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
+ private SecureRandom secureRandom;
+ private Provider provider;
+
+ public static EaafSslContextBuilder create() {
+ return new EaafSslContextBuilder();
+ }
+
+ /**
+ * Get a new SSLContext builder object.
+ */
+ public EaafSslContextBuilder() {
+ super();
+ this.keyManagers = new LinkedHashSet<>();
+ this.trustManagers = new LinkedHashSet<>();
+ }
+
+ /**
+ * Sets the SSLContext protocol algorithm name.
+ *
+ * @param protocol the SSLContext protocol algorithm name of the requested
+ * protocol. See the SSLContext section in the <a href=
+ * "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#SSLContext">Java
+ * Cryptography Architecture Standard Algorithm Name
+ * Documentation</a> for more information.
+ * @return this builder
+ * @see <a href=
+ * "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#SSLContext">Java
+ * Cryptography Architecture Standard Algorithm Name Documentation</a>
+ * @deprecated Use {@link #setProtocol(String)}.
+ */
+ @Deprecated
+ public EaafSslContextBuilder useProtocol(final String protocol) {
+ this.protocol = protocol;
+ return this;
+ }
+
+ /**
+ * Sets the SSLContext protocol algorithm name.
+ *
+ * @param protocol the SSLContext protocol algorithm name of the requested
+ * protocol. See the SSLContext section in the <a href=
+ * "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#SSLContext">Java
+ * Cryptography Architecture Standard Algorithm Name
+ * Documentation</a> for more information.
+ * @return this builder
+ * @see <a href=
+ * "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#SSLContext">Java
+ * Cryptography Architecture Standard Algorithm Name Documentation</a>
+ * @since 4.4.7
+ */
+ public EaafSslContextBuilder setProtocol(final String protocol) {
+ this.protocol = protocol;
+ return this;
+ }
+
+ public EaafSslContextBuilder setSecureRandom(final SecureRandom secureRandom) {
+ this.secureRandom = secureRandom;
+ return this;
+ }
+
+ public EaafSslContextBuilder setProvider(final Provider provider) {
+ this.provider = provider;
+ return this;
+ }
+
+ public EaafSslContextBuilder setProvider(final String name) {
+ this.provider = Security.getProvider(name);
+ return this;
+ }
+
+ /**
+ * Sets the key store type.
+ *
+ * @param keyStoreType the SSLkey store type. See the KeyStore section in the
+ * <a href=
+ * "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#KeyStore">Java
+ * Cryptography Architecture Standard Algorithm Name
+ * Documentation</a> for more information.
+ * @return this builder
+ * @see <a href=
+ * "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#KeyStore">Java
+ * Cryptography Architecture Standard Algorithm Name Documentation</a>
+ * @since 4.4.7
+ */
+ public EaafSslContextBuilder setKeyStoreType(final String keyStoreType) {
+ this.keyStoreType = keyStoreType;
+ return this;
+ }
+
+ /**
+ * Sets the key manager factory algorithm name.
+ *
+ * @param keyManagerFactoryAlgorithm the key manager factory algorithm name of
+ * the requested protocol. See the
+ * KeyManagerFactory section in the <a href=
+ * "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#KeyManagerFactory">Java
+ * Cryptography Architecture Standard
+ * Algorithm Name Documentation</a> for more
+ * information.
+ * @return this builder
+ * @see <a href=
+ * "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#KeyManagerFactory">Java
+ * Cryptography Architecture Standard Algorithm Name Documentation</a>
+ * @since 4.4.7
+ */
+ public EaafSslContextBuilder setKeyManagerFactoryAlgorithm(final String keyManagerFactoryAlgorithm) {
+ this.keyManagerFactoryAlgorithm = keyManagerFactoryAlgorithm;
+ return this;
+ }
+
+ /**
+ * Sets the trust manager factory algorithm name.
+ *
+ * @param trustManagerFactoryAlgorithm the trust manager algorithm name of the
+ * requested protocol. See the
+ * TrustManagerFactory section in the
+ * <a href=
+ * "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#TrustManagerFactory">Java
+ * Cryptography Architecture Standard
+ * Algorithm Name Documentation</a> for more
+ * information.
+ * @return this builder
+ * @see <a href=
+ * "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#TrustManagerFactory">Java
+ * Cryptography Architecture Standard Algorithm Name Documentation</a>
+ * @since 4.4.7
+ */
+ public EaafSslContextBuilder setTrustManagerFactoryAlgorithm(final String trustManagerFactoryAlgorithm) {
+ this.trustManagerFactoryAlgorithm = trustManagerFactoryAlgorithm;
+ return this;
+ }
+
+ /**
+ * Load custom truststore.
+ *
+ * @param truststore {@link KeyStore} if trusted certificates
+ * @param trustStrategy Trust validation strategy
+ * @return {@link EaafSslContextBuilder}
+ * @throws NoSuchAlgorithmException In case of an invalid TrustManager algorithm
+ * @throws KeyStoreException In case of an invalid KeyStore
+ */
+ public EaafSslContextBuilder loadTrustMaterial(
+ final KeyStore truststore,
+ final TrustStrategy trustStrategy) throws NoSuchAlgorithmException, KeyStoreException {
+
+ final String alg = trustManagerFactoryAlgorithm == null
+ ? TrustManagerFactory.getDefaultAlgorithm()
+ : trustManagerFactoryAlgorithm;
+
+ final TrustManagerFactory tmfactory = provider != null
+ ? TrustManagerFactory.getInstance(alg, provider)
+ : TrustManagerFactory.getInstance(alg);
+ tmfactory.init(truststore);
+ final TrustManager[] tms = tmfactory.getTrustManagers();
+ if (tms != null) {
+ if (trustStrategy != null) {
+ for (int i = 0; i < tms.length; i++) {
+ final TrustManager tm = tms[i];
+ if (tm instanceof X509TrustManager) {
+ tms[i] = new TrustManagerDelegate((X509TrustManager) tm, trustStrategy);
+ }
+ }
+ }
+ Collections.addAll(this.trustManagers, tms);
+ }
+ return this;
+ }
+
+ public EaafSslContextBuilder loadTrustMaterial(
+ final TrustStrategy trustStrategy) throws NoSuchAlgorithmException, KeyStoreException {
+ return loadTrustMaterial(null, trustStrategy);
+ }
+
+
+ /**
+ * Load SSL client-authentication key-material into SSL context.
+ *
+ * @param keystore {@link KeyStore} for SSL client-authentication
+ * @param keyPassword Password for this keystore
+ * @param aliasStrategy Stategy to select keys by alias
+ * @return {@link EaafSslContextBuilder}
+ * @throws NoSuchAlgorithmException In case of an invalid KeyManagerFactory algorithm
+ * @throws KeyStoreException In case of an invalid KeyStore
+ * @throws UnrecoverableKeyException In case of a invalid Key in this KeyStore
+ */
+ public EaafSslContextBuilder loadKeyMaterial(
+ final KeyStore keystore,
+ final char[] keyPassword,
+ final PrivateKeyStrategy aliasStrategy)
+ throws NoSuchAlgorithmException, KeyStoreException, UnrecoverableKeyException {
+ final KeyManagerFactory kmfactory = KeyManagerFactory
+ .getInstance(keyManagerFactoryAlgorithm == null ? KeyManagerFactory.getDefaultAlgorithm()
+ : keyManagerFactoryAlgorithm);
+ kmfactory.init(keystore, keyPassword);
+ final KeyManager[] kms = kmfactory.getKeyManagers();
+ if (kms != null) {
+ if (aliasStrategy != null) {
+ for (int i = 0; i < kms.length; i++) {
+ final KeyManager km = kms[i];
+ if (km instanceof X509ExtendedKeyManager) {
+ kms[i] = new KeyManagerDelegate((X509ExtendedKeyManager) km, aliasStrategy);
+ }
+ }
+ }
+ Collections.addAll(keyManagers, kms);
+ }
+ return this;
+ }
+
+ public EaafSslContextBuilder loadKeyMaterial(
+ final KeyStore keystore,
+ final char[] keyPassword) throws NoSuchAlgorithmException, KeyStoreException,
+ UnrecoverableKeyException {
+ return loadKeyMaterial(keystore, keyPassword, null);
+ }
+
+ protected void initSslContext(
+ final SSLContext sslContext,
+ final Collection<KeyManager> keyManagers,
+ final Collection<TrustManager> trustManagers,
+ final SecureRandom secureRandom) throws KeyManagementException {
+ sslContext.init(
+ !keyManagers.isEmpty() ? keyManagers.toArray(new KeyManager[keyManagers.size()]) : null,
+ !trustManagers.isEmpty() ? trustManagers.toArray(new TrustManager[trustManagers.size()]) : null,
+ secureRandom);
+ }
+
+ /**
+ * Build a {@link SSLContext} from this builder.
+ *
+ * @return new {@link SSLContext}
+ * @throws NoSuchAlgorithmException In case of an unknown SSL protocol
+ * @throws KeyManagementException In case of a key-access error
+ */
+ public SSLContext build() throws NoSuchAlgorithmException, KeyManagementException {
+ final SSLContext sslContext;
+ final String protocolStr = this.protocol != null ? this.protocol : TLS;
+ if (this.provider != null) {
+ sslContext = SSLContext.getInstance(protocolStr, this.provider);
+ } else {
+ sslContext = SSLContext.getInstance(protocolStr);
+ }
+ initSslContext(sslContext, keyManagers, trustManagers, secureRandom);
+ return sslContext;
+ }
+
+ static class TrustManagerDelegate implements X509TrustManager {
+
+ private final X509TrustManager trustManager;
+ private final TrustStrategy trustStrategy;
+
+ TrustManagerDelegate(final X509TrustManager trustManager, final TrustStrategy trustStrategy) {
+ super();
+ this.trustManager = trustManager;
+ this.trustStrategy = trustStrategy;
+ }
+
+ @Override
+ public void checkClientTrusted(
+ final X509Certificate[] chain, final String authType) throws CertificateException {
+ this.trustManager.checkClientTrusted(chain, authType);
+ }
+
+ @Override
+ public void checkServerTrusted(
+ final X509Certificate[] chain, final String authType) throws CertificateException {
+ if (!this.trustStrategy.isTrusted(chain, authType)) {
+ this.trustManager.checkServerTrusted(chain, authType);
+ }
+ }
+
+ @Override
+ public X509Certificate[] getAcceptedIssuers() {
+ return this.trustManager.getAcceptedIssuers();
+ }
+
+ }
+
+ static class KeyManagerDelegate extends X509ExtendedKeyManager {
+
+ private final X509ExtendedKeyManager keyManager;
+ private final PrivateKeyStrategy aliasStrategy;
+
+ KeyManagerDelegate(final X509ExtendedKeyManager keyManager, final PrivateKeyStrategy aliasStrategy) {
+ super();
+ this.keyManager = keyManager;
+ this.aliasStrategy = aliasStrategy;
+ }
+
+ @Override
+ public String[] getClientAliases(
+ final String keyType, final Principal[] issuers) {
+ return this.keyManager.getClientAliases(keyType, issuers);
+ }
+
+ public Map<String, PrivateKeyDetails> getClientAliasMap(
+ final String[] keyTypes, final Principal[] issuers) {
+ final Map<String, PrivateKeyDetails> validAliases = new HashMap<>();
+ for (final String keyType : keyTypes) {
+ final String[] aliases = this.keyManager.getClientAliases(keyType, issuers);
+ if (aliases != null) {
+ for (final String alias : aliases) {
+ validAliases.put(alias,
+ new PrivateKeyDetails(keyType, this.keyManager.getCertificateChain(alias)));
+ }
+ }
+ }
+ return validAliases;
+ }
+
+ public Map<String, PrivateKeyDetails> getServerAliasMap(
+ final String keyType, final Principal[] issuers) {
+ final Map<String, PrivateKeyDetails> validAliases = new HashMap<>();
+ final String[] aliases = this.keyManager.getServerAliases(keyType, issuers);
+ if (aliases != null) {
+ for (final String alias : aliases) {
+ validAliases.put(alias,
+ new PrivateKeyDetails(keyType, this.keyManager.getCertificateChain(alias)));
+ }
+ }
+ return validAliases;
+ }
+
+ @Override
+ public String chooseClientAlias(
+ final String[] keyTypes, final Principal[] issuers, final Socket socket) {
+ final Map<String, PrivateKeyDetails> validAliases = getClientAliasMap(keyTypes, issuers);
+ return this.aliasStrategy.chooseAlias(validAliases, socket);
+ }
+
+ @Override
+ public String[] getServerAliases(
+ final String keyType, final Principal[] issuers) {
+ return this.keyManager.getServerAliases(keyType, issuers);
+ }
+
+ @Override
+ public String chooseServerAlias(
+ final String keyType, final Principal[] issuers, final Socket socket) {
+ final Map<String, PrivateKeyDetails> validAliases = getServerAliasMap(keyType, issuers);
+ return this.aliasStrategy.chooseAlias(validAliases, socket);
+ }
+
+ @Override
+ public X509Certificate[] getCertificateChain(final String alias) {
+ return this.keyManager.getCertificateChain(alias);
+ }
+
+ @Override
+ public PrivateKey getPrivateKey(final String alias) {
+ return this.keyManager.getPrivateKey(alias);
+ }
+
+ @Override
+ public String chooseEngineClientAlias(
+ final String[] keyTypes, final Principal[] issuers, final SSLEngine sslEngine) {
+ final Map<String, PrivateKeyDetails> validAliases = getClientAliasMap(keyTypes, issuers);
+ return this.aliasStrategy.chooseAlias(validAliases, null);
+ }
+
+ @Override
+ public String chooseEngineServerAlias(
+ final String keyType, final Principal[] issuers, final SSLEngine sslEngine) {
+ final Map<String, PrivateKeyDetails> validAliases = getServerAliasMap(keyType, issuers);
+ return this.aliasStrategy.chooseAlias(validAliases, null);
+ }
+
+ }
+
+ @Override
+ public String toString() {
+ return "[provider=" + provider + ", protocol=" + protocol + ", keyStoreType=" + keyStoreType
+ + ", keyManagerFactoryAlgorithm=" + keyManagerFactoryAlgorithm + ", keyManagers=" + keyManagers
+ + ", trustManagerFactoryAlgorithm=" + trustManagerFactoryAlgorithm + ", trustManagers="
+ + trustManagers
+ + ", secureRandom=" + secureRandom + "]";
+ }
+}
diff --git a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/http/EaafSslKeySelectionStrategy.java b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/http/EaafSslKeySelectionStrategy.java
index 1e1e2137..d2377d69 100644
--- a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/http/EaafSslKeySelectionStrategy.java
+++ b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/http/EaafSslKeySelectionStrategy.java
@@ -33,18 +33,23 @@ public class EaafSslKeySelectionStrategy implements PrivateKeyStrategy {
@Override
public String chooseAlias(Map<String, PrivateKeyDetails> aliases, Socket socket) {
log.trace("Selection SSL client-auth key for alias: {}", keyAlias);
+ if (aliases.keySet().isEmpty()) {
+ log.debug("No Key with Alias: {} in empty KeyStore", keyAlias);
+ return null;
+
+ }
+
final PrivateKeyDetails selected = aliases.get(keyAlias);
if (selected != null) {
log.trace("Select SL client-auth key with type:", selected.getType());
return keyAlias;
- } else {
+ } else {
log.warn("KeyStore contains NO key with alias: {}. Using first key from keystore", keyAlias);
log.info("Available aliases: {}", StringUtils.join(aliases.keySet(), ", "));
return aliases.keySet().iterator().next();
-
+
}
-
}
}
diff --git a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/http/HttpClientConfiguration.java b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/http/HttpClientConfiguration.java
index 582ad545..9239d0c5 100644
--- a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/http/HttpClientConfiguration.java
+++ b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/http/HttpClientConfiguration.java
@@ -5,11 +5,12 @@ import java.util.UUID;
import javax.annotation.Nonnull;
-import at.gv.egiz.eaaf.core.exceptions.EaafConfigurationException;
-import at.gv.egiz.eaaf.core.impl.credential.KeyStoreConfiguration;
-
import org.apache.commons.lang3.StringUtils;
+import org.apache.http.client.ServiceUnavailableRetryStrategy;
+import at.gv.egiz.eaaf.core.exceptions.EaafConfigurationException;
+import at.gv.egiz.eaaf.core.impl.credential.KeyStoreConfiguration;
+import at.gv.egiz.eaaf.core.impl.credential.KeyStoreConfiguration.KeyStoreType;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
@@ -56,7 +57,17 @@ public class HttpClientConfiguration {
@Setter
private boolean followHttpRedirects = true;
+
+ @Setter
+ private int httpErrorRetryCount = 3;
+
+ @Setter
+ private boolean httpErrorRetryPost = false;
+ @Setter
+ private ServiceUnavailableRetryStrategy serviceUnavailStrategy = null;
+
+
/**
* Get a new HTTP-client configuration object.
*
@@ -117,7 +128,9 @@ public class HttpClientConfiguration {
}
- if (StringUtils.isEmpty(this.sslKeyPassword)) {
+ if (StringUtils.isEmpty(this.sslKeyPassword)
+ && (KeyStoreType.JKS.equals(keyStoreConfig.getKeyStoreType())
+ || KeyStoreType.PKCS12.equals(keyStoreConfig.getKeyStoreType()))) {
throw new EaafConfigurationException(ERROR_02, new Object[] {
this.friendlyName, this.keyStoreConfig.getFriendlyName()});
@@ -187,5 +200,4 @@ public class HttpClientConfiguration {
}
}
-
}
diff --git a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/http/HttpClientFactory.java b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/http/HttpClientFactory.java
index 00d5891a..07522b56 100644
--- a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/http/HttpClientFactory.java
+++ b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/http/HttpClientFactory.java
@@ -1,8 +1,11 @@
package at.gv.egiz.eaaf.core.impl.http;
import java.security.KeyStore;
+import java.security.Provider;
import java.util.HashMap;
import java.util.Map;
+import java.util.Map.Entry;
+import java.util.concurrent.TimeUnit;
import javax.annotation.Nonnull;
import javax.annotation.PostConstruct;
@@ -22,6 +25,7 @@ import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.config.SocketConfig;
+import org.apache.http.conn.HttpClientConnectionManager;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.LayeredConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
@@ -32,16 +36,19 @@ import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.DefaultRedirectStrategy;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
+import org.apache.http.impl.conn.BasicHttpClientConnectionManager;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.protocol.HttpContext;
import org.apache.http.ssl.SSLContexts;
import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.scheduling.annotation.Scheduled;
import at.gv.egiz.eaaf.core.api.idp.IConfiguration;
import at.gv.egiz.eaaf.core.exceptions.EaafConfigurationException;
import at.gv.egiz.eaaf.core.exceptions.EaafException;
import at.gv.egiz.eaaf.core.impl.credential.EaafKeyStoreFactory;
import at.gv.egiz.eaaf.core.impl.credential.KeyStoreConfiguration.KeyStoreType;
+import at.gv.egiz.eaaf.core.impl.data.Pair;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@@ -64,6 +71,10 @@ public class HttpClientFactory implements IHttpClientFactory {
"client.http.connection.timeout.connection";
public static final String PROP_CONFIG_CLIENT_HTTP_CONNECTION_TIMEOUT_REQUEST =
"client.http.connection.timeout.request";
+ public static final String PROP_CONFIG_CLIENT_HTTP_CONNECTION_RETRY_COUNT =
+ "client.http.connection.retry.count";
+ public static final String PROP_CONFIG_CLIENT_HTTP_CONNECTION_RETRY_POST =
+ "client.http.connection.retry.post";
public static final String PROP_CONFIG_CLIENT_HTTP_SSL_HOSTNAMEVERIFIER_TRUSTALL =
"client.http.ssl.hostnameverifier.trustall";
@@ -89,9 +100,16 @@ public class HttpClientFactory implements IHttpClientFactory {
public static final String DEFAULT_CONFIG_CLIENT_HTTP_CONNECTION_TIMEOUT_REQUEST = "30";
public static final String DEFAULT_CONFIG_CLIENT_HTTP_CONNECTION_POOL_MAXTOTAL = "500";
public static final String DEFAULT_CONFIG_CLIENT_HTTP_CONNECTION_POOL_MAXPERROUTE = "100";
+ public static final String DEFAULT_CONFIG_CLIENT_HTTP_CONNECTION_RETRY_COUNT = "3";
+ public static final String DEFAUTL_CONFIG_CLIENT_HTTP_CONNECTION_RETRY_POST = String.valueOf(false);
+ public static final int DEFAULT_CLEANUP_RUNNER_TIME = 30000;
+ public static final int DEFAULT_CLEANUP_IDLE_TIME = 60;
+
+
private String defaultConfigurationId = null;
- private final Map<String, HttpClientBuilder> availableBuilders = new HashMap<>();
+ private final Map<String, Pair<HttpClientBuilder, HttpClientConnectionManager>>
+ availableBuilders = new HashMap<>();
/*
* (non-Javadoc)
@@ -106,7 +124,7 @@ public class HttpClientFactory implements IHttpClientFactory {
@Override
public CloseableHttpClient getHttpClient(final boolean followRedirects) {
- return availableBuilders.get(defaultConfigurationId).setRedirectStrategy(
+ return availableBuilders.get(defaultConfigurationId).getFirst().setRedirectStrategy(
buildRedirectStrategy(followRedirects)).build();
}
@@ -116,27 +134,31 @@ public class HttpClientFactory implements IHttpClientFactory {
log.trace("Build http client for: {}", config.getFriendlyName());
HttpClientBuilder builder = null;
if (availableBuilders.containsKey(config.getUuid())) {
- builder = availableBuilders.get(config.getUuid());
+ builder = availableBuilders.get(config.getUuid()).getFirst();
} else {
log.debug("Initialize new http-client builder for: {}", config.getFriendlyName());
- //validate configuration object
+ // validate configuration object
config.validate();
builder = HttpClients.custom();
+
+ // inject request configuration
builder.setDefaultRequestConfig(buildDefaultRequestConfig());
+ injectInternalRetryHandler(builder, config);
- //inject basic authentication infos
+ // inject basic authentication infos
injectBasicAuthenticationIfRequired(builder, config);
- //inject authentication if required
+ // inject authentication if required
final LayeredConnectionSocketFactory sslConnectionFactory = getSslContext(config);
// set pool connection if required
- injectDefaultConnectionPoolIfRequired(builder, sslConnectionFactory);
+ HttpClientConnectionManager connectionManager
+ = injectConnectionManager(builder, sslConnectionFactory);
- availableBuilders.put(config.getUuid(), builder);
+ availableBuilders.put(config.getUuid(), Pair.newInstance(builder, connectionManager));
}
@@ -145,6 +167,47 @@ public class HttpClientFactory implements IHttpClientFactory {
}
+ /**
+ * Worker that closes expired connections or connections that in idle
+ * for more than DEFAULT_CLEANUP_IDLE_TIME seconds.
+ *
+ */
+ @Scheduled(fixedDelay = DEFAULT_CLEANUP_RUNNER_TIME)
+ private void httpConnectionPoolCleaner() {
+ log.trace("Starting http connection-pool eviction policy ... ");
+ for (final Entry<String, Pair<HttpClientBuilder, HttpClientConnectionManager>> el
+ : availableBuilders.entrySet()) {
+ log.trace("Checking connections of http-client: {}", el.getKey());
+ el.getValue().getSecond().closeExpiredConnections();
+ el.getValue().getSecond().closeIdleConnections(DEFAULT_CLEANUP_IDLE_TIME, TimeUnit.SECONDS);
+
+ }
+
+ }
+
+ private void injectInternalRetryHandler(HttpClientBuilder builder, HttpClientConfiguration config) {
+ if (config.getHttpErrorRetryCount() > 0) {
+ log.info("Set HTTP error-retry to {} for http-client: {}",
+ config.getHttpErrorRetryCount(), config.getFriendlyName());
+ builder.setRetryHandler(new EaafHttpRequestRetryHandler(
+ config.getHttpErrorRetryCount(),
+ config.isHttpErrorRetryPost()));
+
+ if (config.getServiceUnavailStrategy() != null) {
+ log.debug("HttpClient configuration: {} set custom ServiceUnavailableRetryStrategy: {}",
+ config.getFriendlyName(), config.getServiceUnavailStrategy().getClass().getName());
+ builder.setServiceUnavailableRetryStrategy(config.getServiceUnavailStrategy());
+
+ }
+
+ } else {
+ log.info("Disable HTTP error-retry for http-client: {}", config.getFriendlyName());
+ builder.disableAutomaticRetries();
+
+ }
+
+ }
+
@PostConstruct
private void initalize() throws EaafException {
final HttpClientConfiguration defaultHttpClientConfig = buildDefaultHttpClientConfiguration();
@@ -155,8 +218,9 @@ public class HttpClientFactory implements IHttpClientFactory {
// set default request configuration
defaultHttpClientBuilder.setDefaultRequestConfig(buildDefaultRequestConfig());
+ injectInternalRetryHandler(defaultHttpClientBuilder, defaultHttpClientConfig);
- //inject http basic authentication
+ // inject http basic authentication
injectBasicAuthenticationIfRequired(defaultHttpClientBuilder, defaultHttpClientConfig);
// inject authentication if required
@@ -164,11 +228,13 @@ public class HttpClientFactory implements IHttpClientFactory {
getSslContext(defaultHttpClientConfig);
// set pool connection if required
- injectDefaultConnectionPoolIfRequired(defaultHttpClientBuilder, sslConnectionFactory);
+ HttpClientConnectionManager connectionManager
+ = injectConnectionManager(defaultHttpClientBuilder, sslConnectionFactory);
- //set default http client builder
+ // set default http client builder
defaultConfigurationId = defaultHttpClientConfig.getUuid();
- availableBuilders.put(defaultConfigurationId, defaultHttpClientBuilder);
+ availableBuilders.put(defaultConfigurationId,
+ Pair.newInstance(defaultHttpClientBuilder, connectionManager));
}
@@ -203,6 +269,13 @@ public class HttpClientFactory implements IHttpClientFactory {
config.setDisableHostnameValidation(basicConfig.getBasicConfigurationBoolean(
PROP_CONFIG_CLIENT_HTTP_SSL_HOSTNAMEVERIFIER_TRUSTALL, false));
+ config.setHttpErrorRetryCount(Integer.parseInt(basicConfig.getBasicConfiguration(
+ PROP_CONFIG_CLIENT_HTTP_CONNECTION_RETRY_COUNT,
+ DEFAULT_CONFIG_CLIENT_HTTP_CONNECTION_RETRY_COUNT)));
+ config.setHttpErrorRetryPost(Boolean.parseBoolean(basicConfig.getBasicConfiguration(
+ PROP_CONFIG_CLIENT_HTTP_CONNECTION_RETRY_POST,
+ DEFAUTL_CONFIG_CLIENT_HTTP_CONNECTION_RETRY_POST)));
+
// validate configuration object
config.validate();
@@ -237,8 +310,8 @@ public class HttpClientFactory implements IHttpClientFactory {
SSLContext sslContext = null;
if (httpClientConfig.getAuthMode().equals(HttpClientConfiguration.ClientAuthMode.SSL)) {
log.debug("Open keyStore with type: {}", httpClientConfig.getKeyStoreConfig().getKeyStoreType());
- final KeyStore keyStore = keyStoreFactory.buildNewKeyStore(httpClientConfig.getKeyStoreConfig())
- .getFirst();
+ final Pair<KeyStore, Provider> keyStore = keyStoreFactory.buildNewKeyStore(httpClientConfig
+ .getKeyStoreConfig());
log.trace("Injecting SSL client-authentication into http client ... ");
sslContext = HttpUtils.buildSslContextWithSslClientAuthentication(keyStore,
@@ -248,7 +321,7 @@ public class HttpClientFactory implements IHttpClientFactory {
} else {
log.trace("Initializing default SSL Context ... ");
sslContext = SSLContexts.createDefault();
-
+
}
// set hostname verifier
@@ -266,48 +339,37 @@ public class HttpClientFactory implements IHttpClientFactory {
}
- private void injectDefaultConnectionPoolIfRequired(
+ @Nonnull
+ private HttpClientConnectionManager injectConnectionManager(
HttpClientBuilder builder, final LayeredConnectionSocketFactory sslConnectionFactory) {
if (basicConfig.getBasicConfigurationBoolean(PROP_CONFIG_CLIENT_HTTP_CONNECTION_POOL_USE,
true)) {
- PoolingHttpClientConnectionManager pool;
-
- // set socketFactoryRegistry if SSLConnectionFactory is Set
- if (sslConnectionFactory != null) {
- final Registry<ConnectionSocketFactory> socketFactoryRegistry =
- RegistryBuilder.<ConnectionSocketFactory>create()
- .register("http", PlainConnectionSocketFactory.getSocketFactory())
- .register("https", sslConnectionFactory).build();
- log.trace("Inject SSLSocketFactory into pooled connection");
- pool = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
-
- } else {
- pool = new PoolingHttpClientConnectionManager();
-
- }
-
- pool.setDefaultMaxPerRoute(Integer.parseInt(
+ PoolingHttpClientConnectionManager connectionPool
+ = new PoolingHttpClientConnectionManager(getDefaultRegistry(sslConnectionFactory));
+ connectionPool.setDefaultMaxPerRoute(Integer.parseInt(
basicConfig.getBasicConfiguration(PROP_CONFIG_CLIENT_HTTP_CONNECTION_POOL_MAXPERROUTE,
DEFAULT_CONFIG_CLIENT_HTTP_CONNECTION_POOL_MAXPERROUTE)));
- pool.setMaxTotal(Integer.parseInt(
+ connectionPool.setMaxTotal(Integer.parseInt(
basicConfig.getBasicConfiguration(PROP_CONFIG_CLIENT_HTTP_CONNECTION_POOL_MAXTOTAL,
DEFAULT_CONFIG_CLIENT_HTTP_CONNECTION_POOL_MAXTOTAL)));
-
- pool.setDefaultSocketConfig(SocketConfig.custom().setSoTimeout(Integer.parseInt(
+ connectionPool.setDefaultSocketConfig(SocketConfig.custom().setSoTimeout(Integer.parseInt(
basicConfig.getBasicConfiguration(PROP_CONFIG_CLIENT_HTTP_CONNECTION_TIMEOUT_SOCKET,
DEFAULT_CONFIG_CLIENT_HTTP_CONNECTION_TIMEOUT_SOCKET))
* 1000).build());
+ builder.setConnectionManager(connectionPool);
+ log.debug("Initalize http-client pool with, maxTotal: {} maxPerRoute: {}",
+ connectionPool.getMaxTotal(), connectionPool.getDefaultMaxPerRoute());
+ return connectionPool;
+
+ } else {
+ log.debug("Building http-client without Connection-Pool ... ");
+ final BasicHttpClientConnectionManager basicPool = new BasicHttpClientConnectionManager(
+ getDefaultRegistry(sslConnectionFactory));
+ builder.setConnectionManager(basicPool);
+ return basicPool;
- builder.setConnectionManager(pool);
- log.debug("Initalize http-client pool with, maxTotal: {} maxPerRoute: {}", pool.getMaxTotal(),
- pool.getDefaultMaxPerRoute());
-
- } else if (sslConnectionFactory != null) {
- log.trace("Inject SSLSocketFactory without connection pool");
- builder.setSSLSocketFactory(sslConnectionFactory);
-
}
-
+
}
private RequestConfig buildDefaultRequestConfig() {
@@ -323,7 +385,7 @@ public class HttpClientFactory implements IHttpClientFactory {
.setSocketTimeout(Integer.parseInt(
basicConfig.getBasicConfiguration(PROP_CONFIG_CLIENT_HTTP_CONNECTION_TIMEOUT_SOCKET,
DEFAULT_CONFIG_CLIENT_HTTP_CONNECTION_TIMEOUT_SOCKET))
- * 1000)
+ * 1000)
.build();
return requestConfig;
@@ -350,5 +412,25 @@ public class HttpClientFactory implements IHttpClientFactory {
return redirectStrategy;
}
+
+ private static Registry<ConnectionSocketFactory> getDefaultRegistry(
+ final LayeredConnectionSocketFactory sslConnectionFactory) {
+ final RegistryBuilder<ConnectionSocketFactory> builder =
+ RegistryBuilder.<ConnectionSocketFactory>create()
+ .register("http", PlainConnectionSocketFactory.getSocketFactory());
+
+ if (sslConnectionFactory != null) {
+ log.trace("Inject own SSLSocketFactory into pooled connection");
+ builder.register("https", sslConnectionFactory);
+
+ } else {
+ log.trace("Inject default SSLSocketFactory into pooled connection");
+ builder.register("https", SSLConnectionSocketFactory.getSocketFactory());
+
+ }
+
+ return builder.build();
+
+ }
}
diff --git a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/http/HttpUtils.java b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/http/HttpUtils.java
index 2d514912..dd6f69ee 100644
--- a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/http/HttpUtils.java
+++ b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/http/HttpUtils.java
@@ -18,10 +18,14 @@
package at.gv.egiz.eaaf.core.impl.http;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
+import java.security.Provider;
import java.security.UnrecoverableKeyException;
import javax.annotation.Nonnull;
@@ -29,22 +33,67 @@ import javax.annotation.Nullable;
import javax.net.ssl.SSLContext;
import javax.servlet.http.HttpServletRequest;
-import at.gv.egiz.eaaf.core.exceptions.EaafConfigurationException;
-import at.gv.egiz.eaaf.core.exceptions.EaafFactoryException;
-
import org.apache.commons.lang3.StringUtils;
+import org.apache.http.HttpRequest;
+import org.apache.http.HttpResponse;
+import org.apache.http.StatusLine;
+import org.apache.http.client.ClientProtocolException;
+import org.apache.http.client.ResponseHandler;
import org.apache.http.conn.ssl.TrustAllStrategy;
-import org.apache.http.ssl.SSLContextBuilder;
-import org.apache.http.ssl.SSLContexts;
+import org.apache.http.entity.ContentType;
import org.apache.http.ssl.TrustStrategy;
+import org.apache.http.util.EntityUtils;
+import org.bouncycastle.jsse.provider.BouncyCastleJsseProvider;
+import at.gv.egiz.eaaf.core.exceptions.EaafConfigurationException;
+import at.gv.egiz.eaaf.core.exceptions.EaafFactoryException;
+import at.gv.egiz.eaaf.core.impl.data.Pair;
+import at.gv.egiz.eaaf.core.impl.data.Triple;
+import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class HttpUtils {
private static final String ERROR_03 = "internal.httpclient.03";
+
+ /**
+ * Simple Http response-handler that only give http status-code as result.
+ *
+ * @return Status-Code of http response
+ */
+ public static ResponseHandler<StatusLine> simpleStatusCodeResponseHandler() {
+ return new ResponseHandler<StatusLine>() {
+ @Override
+ public StatusLine handleResponse(HttpResponse response) throws ClientProtocolException, IOException {
+ EntityUtils.consumeQuietly(response.getEntity());
+ return response.getStatusLine();
+ }
+ };
+ }
+
+ /**
+ * Http response-handler that gives a pair of http status-code,
+ * a copy of the full http-body as {@link InputStream} and the response {@link ContentType}.
+ *
+ * @return {@link Triple} of http response {@link StatusLine}, http body as {@link InputStream},
+ * and {@link ContentType}
+ */
+ public static ResponseHandler<Triple<StatusLine, ByteArrayInputStream, ContentType>>
+ bodyStatusCodeResponseHandler() {
+ return new ResponseHandler<Triple<StatusLine, ByteArrayInputStream, ContentType>>() {
+ @Override
+ public Triple<StatusLine, ByteArrayInputStream, ContentType> handleResponse(HttpResponse response)
+ throws ClientProtocolException, IOException {
+ byte[] bodyBytes = EntityUtils.toByteArray(response.getEntity());
+ return Triple.newInstance(response.getStatusLine(), new ByteArrayInputStream(bodyBytes),
+ ContentType.getOrDefault(response.getEntity()));
+
+ }
+ };
+ }
+
/**
* Helper method to retrieve server URL including context path.
*
@@ -124,7 +173,7 @@ public class HttpUtils {
* @param url URL
* @param paramname Name of the parameter.
* @param paramvalue Value of the parameter.
- * @return
+ * @return Url with parameter
*/
public static String addUrlParameter(final String url, final String paramname,
final String paramvalue) {
@@ -137,6 +186,23 @@ public class HttpUtils {
}
/**
+ * Inject HTTP header into http request.
+ *
+ * <p>The header is only set if HeaderValue is not null</p>
+ *
+ * @param req Http request object
+ * @param headerName HeaderName
+ * @param headerValue HeaderValue
+ */
+ public static void addHeaderIfNotEmpty(@NonNull HttpRequest req, @NonNull String headerName,
+ @Nullable String headerValue) {
+ if (StringUtils.isNotEmpty(headerValue)) {
+ req.addHeader(headerName, headerValue);
+
+ }
+ }
+
+ /**
* Initialize a {@link SSLContext} with a {@link KeyStore} that uses X509 Client
* authentication.
*
@@ -155,40 +221,114 @@ public class HttpUtils {
* @throws EaafFactoryException In case of a {@link SSLContext}
* initialization error
*/
- public static SSLContext buildSslContextWithSslClientAuthentication(@Nonnull final KeyStore keyStore,
+ public static SSLContext buildSslContextWithSslClientAuthentication(@Nonnull final Pair<KeyStore, Provider> keyStore,
@Nullable String keyAlias, @Nullable String keyPasswordString,
boolean trustAllServerCertificates, @Nonnull String friendlyName)
throws EaafConfigurationException, EaafFactoryException {
try {
- log.trace("Open SSL Client-Auth keystore with password: {}", keyPasswordString);
- final char[] keyPassword = keyPasswordString == null ? StringUtils.EMPTY.toCharArray()
- : keyPasswordString.toCharArray();
-
- SSLContextBuilder sslContextBuilder = SSLContexts.custom();
- if (StringUtils.isNotEmpty(keyAlias)) {
- sslContextBuilder = sslContextBuilder
- .loadKeyMaterial(keyStore, keyPassword, new EaafSslKeySelectionStrategy(keyAlias));
-
- } else {
- sslContextBuilder = sslContextBuilder
- .loadKeyMaterial(keyStore, keyPassword);
-
- }
-
- if (trustAllServerCertificates) {
- log.warn("Http-client:{} trusts ALL TLS server-certificates!");
- final TrustStrategy trustStrategy = new TrustAllStrategy();
- sslContextBuilder = sslContextBuilder.loadTrustMaterial(trustStrategy);
+ EaafSslContextBuilder sslContextBuilder = EaafSslContextBuilder.create();
+
+ injectKeyStore(sslContextBuilder, keyStore, keyAlias, keyPasswordString, friendlyName);
+
+ injectTrustStore(sslContextBuilder, null, trustAllServerCertificates, friendlyName);
+
+ return sslContextBuilder.build();
- }
+ } catch (NoSuchAlgorithmException | KeyManagementException | UnrecoverableKeyException
+ | KeyStoreException e) {
+ throw new EaafFactoryException(ERROR_03, new Object[] { friendlyName, e.getMessage() }, e);
+ }
+ }
+
+ /**
+ * Initialize a {@link SSLContext} with a {@link KeyStore} that uses X509 Client
+ * authentication and a custom TrustStore as {@link KeyStore}.
+ *
+ * @param keyStore KeyStore with private keys that should be
+ * used
+ * @param keyAlias Alias of the key that should be used. If
+ * the alias is null, than the first key that
+ * is found will be selected.
+ * @param keyPasswordString Password of the Key in this keystore
+ * @param trustStore TrustStore with trusted SSL certificates
+ * @param trustAllServerCertificates Deactivate SSL server-certificate
+ * validation
+ * @param friendlyName FriendlyName of the http client for logging
+ * purposes
+ * @return {@link SSLContext} with X509 client authentication
+ * @throws EaafConfigurationException In case of a configuration error
+ * @throws EaafFactoryException In case of a {@link SSLContext}
+ * initialization error
+ */
+ public static SSLContext buildSslContextWithSslClientAuthentication(@Nonnull final Pair<KeyStore, Provider> keyStore,
+ @Nullable String keyAlias, @Nullable String keyPasswordString,
+ @Nullable final Pair<KeyStore, Provider> trustStore, boolean trustAllServerCertificates,
+ @Nonnull String friendlyName)
+ throws EaafConfigurationException, EaafFactoryException {
+ try {
+ EaafSslContextBuilder sslContextBuilder = EaafSslContextBuilder.create();
+
+ injectKeyStore(sslContextBuilder, keyStore, keyAlias, keyPasswordString, friendlyName);
+
+ injectTrustStore(sslContextBuilder, trustStore, trustAllServerCertificates, friendlyName);
+
return sslContextBuilder.build();
} catch (NoSuchAlgorithmException | KeyManagementException | UnrecoverableKeyException
| KeyStoreException e) {
throw new EaafFactoryException(ERROR_03, new Object[] { friendlyName, e.getMessage() }, e);
+ }
+ }
+
+ private static void injectTrustStore(EaafSslContextBuilder sslContextBuilder,
+ Pair<KeyStore, Provider> trustStore, boolean trustAllServerCertificates, String friendlyName)
+ throws NoSuchAlgorithmException, KeyStoreException {
+
+ TrustStrategy trustStrategy = null;
+ if (trustAllServerCertificates) {
+ log.warn("Http-client:{} trusts ALL TLS server-certificates!", friendlyName);
+ trustStrategy = new TrustAllStrategy();
+
}
+
+ KeyStore trustStoreImpl = null;
+ if (trustStore != null) {
+ log.info("Http-client: {} uses custom TrustStore.", friendlyName);
+ trustStoreImpl = trustStore.getFirst();
+
+ }
+
+ sslContextBuilder.loadTrustMaterial(trustStoreImpl, trustStrategy);
+
}
+ private static void injectKeyStore(EaafSslContextBuilder sslContextBuilder, Pair<KeyStore, Provider> keyStore,
+ String keyAlias, String keyPasswordString, String friendlyName)
+ throws UnrecoverableKeyException, NoSuchAlgorithmException, KeyStoreException {
+
+ Provider provider;
+ if (keyStore.getSecond() != null) {
+ provider = new BouncyCastleJsseProvider(keyStore.getSecond());
+ log.debug("KeyStore: {} provide special security-provider. Inject: {} into SSLContext",
+ friendlyName, provider.getName());
+ sslContextBuilder.setProvider(provider);
+
+ }
+
+ log.trace("Open SSL Client-Auth keystore with password: {}", keyPasswordString);
+ final char[] keyPassword = keyPasswordString == null ? StringUtils.EMPTY.toCharArray()
+ : keyPasswordString.toCharArray();
+
+ if (StringUtils.isNotEmpty(keyAlias)) {
+ sslContextBuilder
+ .loadKeyMaterial(keyStore.getFirst(), keyPassword, new EaafSslKeySelectionStrategy(keyAlias));
+
+ } else {
+ sslContextBuilder.loadKeyMaterial(keyStore.getFirst(), keyPassword);
+
+ }
+
+ }
}
diff --git a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/http/IHttpClientFactory.java b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/http/IHttpClientFactory.java
index 7ec58d46..4e8374e1 100644
--- a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/http/IHttpClientFactory.java
+++ b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/http/IHttpClientFactory.java
@@ -2,10 +2,10 @@ package at.gv.egiz.eaaf.core.impl.http;
import javax.annotation.Nonnull;
-import at.gv.egiz.eaaf.core.exceptions.EaafException;
-
import org.apache.http.impl.client.CloseableHttpClient;
+import at.gv.egiz.eaaf.core.exceptions.EaafException;
+
public interface IHttpClientFactory {
/**
diff --git a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/http/pvp/PvpRProfileHttpHeaders.java b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/http/pvp/PvpRProfileHttpHeaders.java
new file mode 100644
index 00000000..cd6d7404
--- /dev/null
+++ b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/http/pvp/PvpRProfileHttpHeaders.java
@@ -0,0 +1,86 @@
+package at.gv.egiz.eaaf.core.impl.http.pvp;
+
+/**
+ * PVP2 R-Profile HTTP-Header definitions.
+ *
+ * @author tlenz
+ *
+ */
+public class PvpRProfileHttpHeaders {
+
+ //PVP 1.x headers
+ public static final String PVP_1X_VALUE_VERSION_PREFIX = "1.";
+
+ public static final String PVP_1X_PREFIX = "X-";
+ public static final String PVP_1X_VERSION_NAME = "Version";
+ public static final String PVP_1X_USERID_NAME = "AUTHENTICATE-UserID";
+ public static final String PVP_1X_GID_NAME = "AUTHENTICATE-GVGID";
+ public static final String PVP_1X_PARTICIPANT_ID_NAME = "AUTHENTICATE-PARTICIPANTID";
+ public static final String PVP_1X_GV_OU_ID_NAME = "AUTHENTICATE-GVOUID";
+ public static final String PVP_1X_OU_NAME = "AUTHENTICATE-OU";
+ public static final String PVP_1X_FUNCTION_NAME = "AUTHENTICATE-GVFUNCTION";
+ public static final String PVP_1X_SECCLASS_NAME = "AUTHENTICATE-gvSecClass";
+ public static final String PVP_1X_CN_NAME = "AUTHENTICATE-cn";
+ public static final String PVP_1X_COST_CENTER_ID_NAME = "ACCOUNTING-CostCenterId";
+ public static final String PVP_1X_INVOICE_RECPT_ID_NAME = "ACCOUNTING-InvoiceRecptId";
+ public static final String PVP_1X_ROLES_NAME = "AUTHORIZE-ROLES";
+ public static final String PVP_1X_GV_OU_OKZ_NAME = "AUTHENTICATE-GVOUOKZ";
+ public static final String PVP_1X_VERSION = PVP_1X_PREFIX + PVP_1X_VERSION_NAME;
+ public static final String PVP_1X_USERID = PVP_1X_PREFIX + PVP_1X_USERID_NAME;
+ public static final String PVP_1X_GID = PVP_1X_PREFIX + PVP_1X_GID_NAME;
+ public static final String PVP_1X_PARTICIPANT_ID = PVP_1X_PREFIX + PVP_1X_PARTICIPANT_ID_NAME;
+ public static final String PVP_1X_GV_OU_ID = PVP_1X_PREFIX + PVP_1X_GV_OU_ID_NAME;
+ public static final String PVP_1X_OU = PVP_1X_PREFIX + PVP_1X_OU_NAME;
+ public static final String PVP_1X_FUNCTION = PVP_1X_PREFIX + PVP_1X_FUNCTION_NAME;
+ public static final String PVP_1X_SECCLASS = PVP_1X_PREFIX + PVP_1X_SECCLASS_NAME;
+ public static final String PVP_1X_CN = PVP_1X_PREFIX + PVP_1X_CN_NAME;
+ public static final String PVP_1X_COST_CENTER_ID = PVP_1X_PREFIX + PVP_1X_COST_CENTER_ID_NAME;
+ public static final String PVP_1X_INVOICE_RECPT_ID = PVP_1X_PREFIX + PVP_1X_INVOICE_RECPT_ID_NAME;
+ public static final String PVP_1X_ROLES = PVP_1X_PREFIX + PVP_1X_ROLES_NAME;
+ public static final String PVP_1X_GV_OU_OKZ = PVP_1X_PREFIX + PVP_1X_GV_OU_OKZ_NAME;
+
+
+ //PVP 2.x headers
+ public static final String PVP_2X_VALUE_VERSION_PREFIX = "2.";
+
+ public static final String PVP_2X_VERSION = "X-PVP-VERSION";
+ public static final String PVP_2X_USERID = "X-PVP-USERID";
+ public static final String PVP_2X_GID = "X-PVP-GID";
+ public static final String PVP_2X_PARTICIPANT_ID = "X-PVP-PARTICIPANT-ID";
+ public static final String PVP_2X_GV_OU_ID = "X-PVP-OU-GV-OU-ID";
+ public static final String PVP_2X_OU = "X-PVP-OU";
+ public static final String PVP_2X_FUNCTION = "X-PVP-FUNCTION";
+ public static final String PVP_2X_SECCLASS = "X-PVP-SECCLASS";
+ public static final String PVP_2X_PRINCIPAL_NAME = "X-PVP-PRINCIPAL-NAME";
+ public static final String PVP_2X_BINDING = "X-PVP-BINDING";
+ public static final String PVP_2X_OU_OKZ = "X-PVP-OU-OKZ";
+ public static final String PVP_2X_COST_CENTER_ID = "X-PVP-COST-CENTER-ID";
+ public static final String PVP_2X_INVOICE_RECPT_ID = "X-PVP-INVOICE-RECPT-ID";
+ public static final String PVP_2X_ROLES = "X-PVP-ROLES";
+
+ public static final String PVP_ERROR_440_CODE = "440";
+ public static final String PVP_ERROR_440_MSG = "Mandatory PVP-Header {0} fehlt";
+ public static final String PVP_ERROR_441_CODE = "441";
+ public static final String PVP_ERROR_441_MSG = "Werte in X-PVP-ROLES haben ungültiges Format";
+ public static final String PVP_ERROR_442_CODE = "442";
+ public static final String PVP_ERROR_442_MSG = "Kein zulässiges Recht in X-PVP-ROLES";
+ public static final String PVP_ERROR_443_CODE = "443";
+ public static final String PVP_ERROR_443_MSG = "Die UserId ist am Anwendungsportal gesperrt";
+ public static final String PVP_ERROR_444_CODE = "444";
+ public static final String PVP_ERROR_444_MSG =
+ "Stammportal ist für Anfragen des angegebenen Participants nicht berechtigt";
+ public static final String PVP_ERROR_445_CODE = "445";
+ public static final String PVP_ERROR_445_MSG = "Participant am Anwendungsportal nicht registriert";
+ public static final String PVP_ERROR_490_CODE = "490";
+ public static final String PVP_ERROR_490_MSG = "Zertifikatsüberprüfung fehlgeschlagen. Grund: {0}";
+ public static final String PVP_ERROR_493_CODE = "493";
+ public static final String PVP_ERROR_493_MSG = "Keine Berechtigung für diese Anwendung im Stammportal";
+ public static final String PVP_ERROR_494_CODE = "494";
+ public static final String PVP_ERROR_494_MSG = "Die Authentifizierung des Stammportals ist fehlgeschlagen";
+ public static final String PVP_ERROR_511_CODE = "511";
+ public static final String PVP_ERROR_511_MSG = "PVP Version nicht unterstützt";
+
+ private PvpRProfileHttpHeaders() {
+
+ }
+}
diff --git a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/idp/conf/SpConfigurationImpl.java b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/idp/conf/SpConfigurationImpl.java
index de54d103..2f4e18fa 100644
--- a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/idp/conf/SpConfigurationImpl.java
+++ b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/idp/conf/SpConfigurationImpl.java
@@ -20,8 +20,10 @@
package at.gv.egiz.eaaf.core.impl.idp.conf;
import java.util.Collections;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
+import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -38,8 +40,8 @@ public class SpConfigurationImpl implements ISpConfiguration {
private static final Logger log = LoggerFactory.getLogger(SpConfigurationImpl.class);
private final Map<String, String> spConfiguration;
- private final List<String> targetAreasWithNoInteralBaseIdRestriction;
- private final List<String> targetAreasWithNoBaseIdTransmissionRestriction;
+ private final Set<String> targetAreasWithNoInteralBaseIdRestriction;
+ private final Set<String> targetAreasWithNoBaseIdTransmissionRestriction;
/**
* Service-provider configuration holder.
@@ -52,21 +54,19 @@ public class SpConfigurationImpl implements ISpConfiguration {
// set oa specific restrictions
targetAreasWithNoInteralBaseIdRestriction = Collections
- .unmodifiableList(KeyValueUtils.getListOfCsvValues(authConfig.getBasicConfiguration(
- CONFIG_KEY_RESTRICTIONS_BASEID_INTERNAL, EaafConstants.URN_PREFIX_CDID)));
+ .unmodifiableSet(new HashSet<String>(KeyValueUtils.getListOfCsvValues(authConfig.getBasicConfiguration(
+ CONFIG_KEY_RESTRICTIONS_BASEID_INTERNAL, EaafConstants.URN_PREFIX_CDID))));
targetAreasWithNoBaseIdTransmissionRestriction = Collections
- .unmodifiableList(KeyValueUtils.getListOfCsvValues(authConfig.getBasicConfiguration(
- CONFIG_KEY_RESTRICTIONS_BASEID_TRANSMISSION, EaafConstants.URN_PREFIX_CDID)));
+ .unmodifiableSet(new HashSet<String>(KeyValueUtils.getListOfCsvValues(authConfig.getBasicConfiguration(
+ CONFIG_KEY_RESTRICTIONS_BASEID_TRANSMISSION, EaafConstants.URN_PREFIX_CDID))));
if (log.isTraceEnabled()) {
log.trace("Internal policy for OA: " + getUniqueIdentifier());
- for (final String el : targetAreasWithNoInteralBaseIdRestriction) {
- log.trace(" Allow baseID processing for prefix " + el);
- }
- for (final String el : targetAreasWithNoBaseIdTransmissionRestriction) {
- log.trace(" Allow baseID transfer for prefix " + el);
- }
+ targetAreasWithNoInteralBaseIdRestriction.stream()
+ .forEach(el -> log.trace(" Allow baseID processing for prefix " + el));
+ targetAreasWithNoBaseIdTransmissionRestriction.stream()
+ .forEach(el -> log.trace(" Allow baseID transfer for prefix " + el));
}
}
@@ -143,12 +143,12 @@ public class SpConfigurationImpl implements ISpConfiguration {
}
@Override
- public final List<String> getTargetsWithNoBaseIdInternalProcessingRestriction() {
+ public final Set<String> getTargetsWithNoBaseIdInternalProcessingRestriction() {
return this.targetAreasWithNoInteralBaseIdRestriction;
}
@Override
- public final List<String> getTargetsWithNoBaseIdTransferRestriction() {
+ public final Set<String> getTargetsWithNoBaseIdTransferRestriction() {
return this.targetAreasWithNoBaseIdTransmissionRestriction;
}
diff --git a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/AuthenticatedEncryptionPendingRequestIdGenerationStrategy.java b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/AuthenticatedEncryptionPendingRequestIdGenerationStrategy.java
new file mode 100644
index 00000000..ca1db67d
--- /dev/null
+++ b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/AuthenticatedEncryptionPendingRequestIdGenerationStrategy.java
@@ -0,0 +1,280 @@
+package at.gv.egiz.eaaf.core.impl.utils;
+
+import java.nio.charset.StandardCharsets;
+import java.security.Provider;
+import java.util.Base64;
+
+import javax.annotation.Nonnull;
+import javax.annotation.PostConstruct;
+import javax.crypto.SecretKey;
+
+import org.apache.commons.lang3.StringUtils;
+import org.joda.time.DateTime;
+import org.joda.time.DurationFieldType;
+import org.joda.time.format.DateTimeFormat;
+import org.joda.time.format.DateTimeFormatter;
+import org.jose4j.jca.ProviderContext;
+import org.jose4j.jwa.AlgorithmConstraints;
+import org.jose4j.jwa.AlgorithmConstraints.ConstraintType;
+import org.jose4j.jwe.ContentEncryptionAlgorithmIdentifiers;
+import org.jose4j.jwe.JsonWebEncryption;
+import org.jose4j.jwe.KeyManagementAlgorithmIdentifiers;
+import org.jose4j.lang.JoseException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+
+import at.gv.egiz.eaaf.core.api.idp.IConfiguration;
+import at.gv.egiz.eaaf.core.api.utils.IPendingRequestIdGenerationStrategy;
+import at.gv.egiz.eaaf.core.exceptions.EaafConfigurationException;
+import at.gv.egiz.eaaf.core.exceptions.EaafException;
+import at.gv.egiz.eaaf.core.exceptions.PendingReqIdValidationException;
+import at.gv.egiz.eaaf.core.impl.credential.EaafKeyStoreFactory;
+import at.gv.egiz.eaaf.core.impl.credential.SymmetricKeyConfiguration;
+import at.gv.egiz.eaaf.core.impl.credential.SymmetricKeyConfiguration.SymmetricKeyType;
+import at.gv.egiz.eaaf.core.impl.data.Pair;
+
+/**
+ * PendingRequestId generation strategy based on signed tokens that facilitates
+ * extended token validation.
+ *
+ * @author tlenz
+ *
+ */
+public class AuthenticatedEncryptionPendingRequestIdGenerationStrategy
+ implements IPendingRequestIdGenerationStrategy {
+ private static final Logger log =
+ LoggerFactory.getLogger(AuthenticatedEncryptionPendingRequestIdGenerationStrategy.class);
+
+ @Autowired(required = true) IConfiguration baseConfig;
+ @Autowired EaafKeyStoreFactory keyStoreFactory;
+
+ private static final String FRIENDLYNAME = "pendingRequestId key";
+
+ public static final String CONFIG_PROP_PENDINGREQUESTID_DIGIST_TYPE =
+ "core.pendingrequestid.digist.type";
+ public static final String CONFIG_PROP_PENDINGREQUESTID_DIGIST_SECRET =
+ "core.pendingrequestid.digist.secret";
+
+ public static final String CONFIG_PROP_PENDINGREQUESTID_DIGIST_HSM_KEYSTORE =
+ "core.pendingrequestid.digist.keystore.name";
+ public static final String CONFIG_PROP_PENDINGREQUESTID_DIGIST_HSM_ALIAS =
+ "core.pendingrequestid.digist.key.alias";
+
+ public static final String CONFIG_PROP_PENDINGREQUESTID_MAX_LIFETIME =
+ "core.pendingrequestid.maxlifetime";
+
+ public static final String DEFAULT_PENDINGREQUESTID_DIGIST_ALGORITHM = "HmacSHA256";
+ public static final String DEFAULT_PENDINGREQUESTID_MAX_LIFETIME = "300";
+
+ private static final int ENCODED_TOKEN_PARTS = 2;
+ private static final String TOKEN_SEPARATOR = "|";
+ private static final DateTimeFormatter TOKEN_TEXTUAL_DATE_FORMAT =
+ DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss SSS ZZ").withZoneUTC();
+
+ private int maxPendingRequestIdLifeTime = 300;
+ private final int maxPendingReqIdSize = 1024;
+ private Pair<SecretKey, Provider> key = null;
+ private final String salt = "notRequiredInThisScenario";
+
+ @Override
+ public String generateExternalPendingRequestId() throws EaafException {
+ try {
+ final String toSign = buildInternalToken(Random.nextLongRandom(), DateTime.now());
+ JsonWebEncryption encToken = new JsonWebEncryption();
+ encToken.setAlgorithmHeaderValue(selectKeyWrappingAlgorithm(key.getFirst()));
+ encToken.setEncryptionMethodHeaderParameter(ContentEncryptionAlgorithmIdentifiers.AES_128_GCM);
+ encToken.setKey(key.getFirst());
+ encToken.setPayload(toSign);
+
+
+
+ if (key.getSecond() != null) {
+ final ProviderContext providerCtx = new ProviderContext();
+ providerCtx.getSuppliedKeyProviderContext().setSignatureProvider(
+ key.getSecond().getName());
+ encToken.setProviderContext(providerCtx);
+
+ }
+
+ return Base64.getUrlEncoder()
+ .encodeToString(encToken.getCompactSerialization().getBytes(StandardCharsets.UTF_8));
+
+ } catch (final JoseException e) {
+ throw new EaafException("internal.pendingreqid.02", new Object[] { e.getMessage() }, e);
+
+ }
+
+ }
+
+ @Override
+ public String getPendingRequestIdWithOutChecks(final String externalPendingReqId)
+ throws PendingReqIdValidationException {
+ try {
+ String stringToken = getDecryptedExternalPendingRequestId(externalPendingReqId);
+ log.debug("Token decryption successful");
+
+ if (!(StringUtils.countMatches(stringToken, TOKEN_SEPARATOR) == ENCODED_TOKEN_PARTS - 1)) {
+ log.warn("PendingRequestId has an unvalid format");
+ log.debug("PendingRequestId: {}", stringToken);
+ throw new PendingReqIdValidationException(null, "internal.pendingreqid.01");
+
+ }
+
+ final String[] tokenElements =
+ StringUtils.split(stringToken, TOKEN_SEPARATOR, ENCODED_TOKEN_PARTS);
+ return tokenElements[1];
+
+ } catch (JoseException e) {
+ log.warn("Token is NOT a valid String. Msg: {}", e.getMessage());
+ log.debug("TokenValue: {}", externalPendingReqId);
+ throw new PendingReqIdValidationException(null, "internal.pendingreqid.05", e);
+
+ }
+ }
+
+ @Override
+ public String validateAndGetPendingRequestId(final String externalPendingReqId)
+ throws PendingReqIdValidationException {
+ try {
+ String stringToken = getDecryptedExternalPendingRequestId(externalPendingReqId);
+ log.debug("Token decryption successful");
+
+ if (!(StringUtils.countMatches(stringToken, TOKEN_SEPARATOR) == ENCODED_TOKEN_PARTS - 1)) {
+ log.info("PendingRequestId: {}", stringToken);
+ throw new PendingReqIdValidationException(null, "internal.pendingreqid.01");
+
+ }
+
+ final String[] tokenElements =
+ StringUtils.split(stringToken, TOKEN_SEPARATOR, ENCODED_TOKEN_PARTS);
+ final String internalPendingReqId = tokenElements[1];
+ final DateTime timeStamp = TOKEN_TEXTUAL_DATE_FORMAT.parseDateTime(tokenElements[0]);
+
+ log.trace("Checking valid period ... ");
+ final DateTime now = DateTime.now();
+ if (timeStamp.withFieldAdded(DurationFieldType.seconds(), maxPendingRequestIdLifeTime)
+ .isBefore(now)) {
+ log.info("Token exceeds the valid period. Token: {} | Now: {}", timeStamp, now);
+ throw new PendingReqIdValidationException(internalPendingReqId,
+ "internal.pendingreqid.06");
+
+ }
+ log.debug("Token valid-period check successful");
+
+ return internalPendingReqId;
+
+ } catch (JoseException e) {
+ log.warn("Token is NOT a valid encrypt. Msg: {}", e.getMessage());
+ log.debug("TokenValue: {}", externalPendingReqId);
+ throw new PendingReqIdValidationException(null, "internal.pendingreqid.04", e);
+
+ } catch (final IllegalArgumentException e) {
+ log.warn("Token is NOT a valid String. Msg: {}", e.getMessage());
+ log.debug("TokenValue: {}", externalPendingReqId);
+ throw new PendingReqIdValidationException(null, "internal.pendingreqid.05", e);
+
+ }
+ }
+
+ @Nonnull
+ private String getDecryptedExternalPendingRequestId(String externalPendingReqId)
+ throws JoseException, PendingReqIdValidationException {
+ if (StringUtils.isEmpty(externalPendingReqId)) {
+ log.info("PendingReqId is 'null' or empty");
+ throw new PendingReqIdValidationException(null, "internal.pendingreqid.00");
+
+ }
+
+ log.trace("RAW external pendingReqId: {}", externalPendingReqId);
+ final byte[] externalPendingReqIdBytes = Base64.getUrlDecoder().decode(externalPendingReqId);
+
+ if (externalPendingReqIdBytes.length > maxPendingReqIdSize) {
+ log.warn("pendingReqId size exceeds {}", maxPendingReqIdSize);
+ throw new PendingReqIdValidationException(null, "internal.pendingreqid.03");
+
+ }
+
+
+ JsonWebEncryption encToken = new JsonWebEncryption();
+ encToken.setContentEncryptionAlgorithmConstraints(new AlgorithmConstraints(
+ ConstraintType.WHITELIST, ContentEncryptionAlgorithmIdentifiers.AES_128_GCM));
+ encToken.setAlgorithmConstraints(new AlgorithmConstraints(
+ ConstraintType.WHITELIST,
+ KeyManagementAlgorithmIdentifiers.DIRECT,
+ KeyManagementAlgorithmIdentifiers.A128GCMKW
+ ));
+ encToken.setKey(key.getFirst());
+
+ if (key.getSecond() != null) {
+ final ProviderContext providerCtx = new ProviderContext();
+ providerCtx.getSuppliedKeyProviderContext().setSignatureProvider(
+ key.getSecond().getName());
+ encToken.setProviderContext(providerCtx);
+
+ }
+
+ encToken.setCompactSerialization(new String(externalPendingReqIdBytes, StandardCharsets.UTF_8));
+ return encToken.getPayload();
+
+ }
+
+ private String selectKeyWrappingAlgorithm(SecretKey first) {
+ if ("AES".equals(first.getAlgorithm())) {
+ return KeyManagementAlgorithmIdentifiers.A128GCMKW;
+
+ } else {
+ return KeyManagementAlgorithmIdentifiers.DIRECT;
+
+ }
+ }
+
+ @PostConstruct
+ private void initialize() throws EaafConfigurationException {
+ log.debug("Initializing " + this.getClass().getName() + " ... ");
+
+ maxPendingRequestIdLifeTime =
+ Integer.parseInt(baseConfig.getBasicConfiguration(CONFIG_PROP_PENDINGREQUESTID_MAX_LIFETIME,
+ DEFAULT_PENDINGREQUESTID_MAX_LIFETIME));
+
+
+ SymmetricKeyConfiguration secretKeyConfig = new SymmetricKeyConfiguration();
+ secretKeyConfig.setFriendlyName(FRIENDLYNAME);
+ secretKeyConfig.setKeyType(
+ baseConfig.getBasicConfiguration(CONFIG_PROP_PENDINGREQUESTID_DIGIST_TYPE,
+ SymmetricKeyType.PASSPHRASE.name()));
+
+ secretKeyConfig.setSoftKeyPassphrase(
+ baseConfig.getBasicConfiguration(CONFIG_PROP_PENDINGREQUESTID_DIGIST_SECRET));
+ secretKeyConfig.setSoftKeySalt(salt);
+
+ secretKeyConfig.setKeyStoreName(
+ baseConfig.getBasicConfiguration(CONFIG_PROP_PENDINGREQUESTID_DIGIST_HSM_KEYSTORE));
+ secretKeyConfig.setKeyAlias(
+ baseConfig.getBasicConfiguration(CONFIG_PROP_PENDINGREQUESTID_DIGIST_HSM_ALIAS));
+
+ //validate symmetric-key configuration
+ secretKeyConfig.validate();
+
+ try {
+ key = keyStoreFactory.buildNewSymmetricKey(secretKeyConfig);
+
+ } catch (EaafException e) {
+ log.error("Can NOT initialize TokenService with configuration object", e);
+ throw new EaafConfigurationException("config.09",
+ new Object[] { CONFIG_PROP_PENDINGREQUESTID_DIGIST_SECRET, "Can NOT generate HMAC key" },
+ e);
+
+ }
+
+ log.info(this.getClass().getName() + " initialized with Alg: {} and maxLifeTime: {}",
+ ContentEncryptionAlgorithmIdentifiers.AES_128_GCM, maxPendingRequestIdLifeTime);
+
+ }
+
+ private String buildInternalToken(final String internalPendingReqId, final DateTime now) {
+ return new StringBuilder().append(TOKEN_TEXTUAL_DATE_FORMAT.print(now)).append(TOKEN_SEPARATOR)
+ .append(internalPendingReqId).toString();
+ }
+
+}
diff --git a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/EaafObjectInputStream.java b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/EaafObjectInputStream.java
new file mode 100644
index 00000000..e15c7a37
--- /dev/null
+++ b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/EaafObjectInputStream.java
@@ -0,0 +1,39 @@
+package at.gv.egiz.eaaf.core.impl.utils;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InvalidClassException;
+import java.io.ObjectInputStream;
+import java.io.ObjectStreamClass;
+import java.util.List;
+
+import javax.annotation.Nonnull;
+
+public class EaafObjectInputStream extends ObjectInputStream {
+
+ private List<String> allowedClassNames;
+
+ /**
+ * Object input-stream with internal class validation.
+ *
+ * @param is Inputstream to deserialize.
+ * @param classNames Whitelisted classnames
+ * @throws IOException In case of an error
+ */
+ public EaafObjectInputStream(@Nonnull InputStream is, @Nonnull List<String> classNames) throws IOException {
+ super(is);
+ this.allowedClassNames = classNames;
+
+ }
+
+ //Only deserialize instances of our expected class
+ @Override
+ protected Class<?> resolveClass(ObjectStreamClass desc)
+ throws IOException, ClassNotFoundException {
+ if (!allowedClassNames.contains(desc.getName())) {
+ throw new InvalidClassException("Unauthorized deserialization attempt: {}",desc.getName());
+
+ }
+ return super.resolveClass(desc);
+ }
+}
diff --git a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/EaafSerializationUtils.java b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/EaafSerializationUtils.java
new file mode 100644
index 00000000..e15c6800
--- /dev/null
+++ b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/EaafSerializationUtils.java
@@ -0,0 +1,69 @@
+package at.gv.egiz.eaaf.core.impl.utils;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.util.List;
+
+import org.springframework.lang.Nullable;
+
+public class EaafSerializationUtils {
+
+ private EaafSerializationUtils() {
+
+ }
+
+ /**
+ * Serialize a given Java object into a byte array.
+ *
+ * @param object Java object to serialize.
+ * @return Serialized Java object
+ */
+ @Nullable
+ public static byte[] serialize(@Nullable Object object) {
+ if (object == null) {
+ return null;
+
+ }
+
+ final ByteArrayOutputStream baos = new ByteArrayOutputStream(1024);
+ try (ObjectOutputStream oos = new ObjectOutputStream(baos)) {
+ oos.writeObject(object);
+ oos.flush();
+
+ } catch (final IOException ex) {
+ throw new IllegalArgumentException("Failed to serialize object of type: " + object.getClass(), ex);
+
+ }
+
+ return baos.toByteArray();
+ }
+
+ /**
+ * Deserialize the byte array into an object.
+ *
+ * @param bytes a serialized object
+ * @param allowedClassName List of classnames that are allowed for deserialization
+ * @return the result of deserializing the bytes
+ */
+ @Nullable
+ public static Object deserialize(@Nullable byte[] bytes, List<String> allowedClassName) {
+ if (bytes == null) {
+ return null;
+
+ }
+
+ try (ObjectInputStream ois = new EaafObjectInputStream(new ByteArrayInputStream(bytes), allowedClassName)) {
+ return ois.readObject();
+
+ } catch (final IOException ex) {
+ throw new IllegalArgumentException("Failed to deserialize object", ex);
+
+ } catch (final ClassNotFoundException ex) {
+ throw new IllegalStateException("Failed to deserialize object type", ex);
+
+ }
+ }
+}
diff --git a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/KeyStoreUtils.java b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/KeyStoreUtils.java
index 99b87819..be51426c 100644
--- a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/KeyStoreUtils.java
+++ b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/KeyStoreUtils.java
@@ -30,12 +30,16 @@ import java.security.KeyStoreException;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
+import at.gv.egiz.eaaf.core.impl.credential.KeyStoreConfiguration.KeyStoreType;
+import lombok.extern.slf4j.Slf4j;
+
/**
* Utility for creating and loading key stores.
*
* @author Paul Ivancsics
* @version $Id$
*/
+@Slf4j
public class KeyStoreUtils {
/**
@@ -110,6 +114,32 @@ public class KeyStoreUtils {
}
/**
+ * Loads a keyStore with known keyStore type.
+ *
+ * @param is input stream
+ * @param password Password protecting the keyStore
+ * @param keyStoreType Type of the KeyStore
+ * @return loaded KeyStore
+ * @throws IOException In case of a general error
+ * @throws GeneralSecurityException In case of a KeyStore access error
+ */
+ public static KeyStore loadKeyStore(final InputStream is, final String password, KeyStoreType keyStoreType)
+ throws IOException, GeneralSecurityException {
+ String internalType = KEYSTORE_TYPE_PKCS12;
+ if (keyStoreType.equals(KeyStoreType.JKS)) {
+ internalType = KEYSTORE_TYPE_JKS;
+
+ } else if (keyStoreType.equals(KeyStoreType.PKCS12)) {
+ internalType = KEYSTORE_TYPE_PKCS12;
+
+ }
+
+ return loadKeyStore(internalType, is, password);
+
+ }
+
+
+ /**
* Loads a keyStore without knowing the keyStore type.
*
* @param is input stream
@@ -125,14 +155,18 @@ public class KeyStoreUtils {
try {
try {
ks = loadKeyStore(KEYSTORE_TYPE_PKCS12, is, password);
+
} catch (final IOException e2) {
is.reset();
ks = loadKeyStore(KEYSTORE_TYPE_JKS, is, password);
+
}
+
} catch (final Exception e) {
- e.printStackTrace();
-
+ log.warn("Can not load keystore", e);
+
}
+
return ks;
}
diff --git a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/KeyValueUtils.java b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/KeyValueUtils.java
index 0c5eeb40..b0a91e74 100644
--- a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/KeyValueUtils.java
+++ b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/KeyValueUtils.java
@@ -28,13 +28,12 @@ import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.Set;
+import java.util.stream.Collectors;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import org.apache.commons.lang3.StringUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
/**
* Utils to operate on Key/Value based configurations.
@@ -43,8 +42,7 @@ import org.slf4j.LoggerFactory;
*
*/
public class KeyValueUtils {
- private static final Logger log = LoggerFactory.getLogger(KeyValueUtils.class);
-
+
public static final String KEY_DELIMITER = ".";
public static final String CSV_DELIMITER = ",";
public static final String KEYVVALUEDELIMITER = "=";
@@ -154,18 +152,14 @@ public class KeyValueUtils {
* null
*/
public static Map<String, String> removePrefixFromKeys(final Map<String, String> keys,
- final String prefix) {
- final Map<String, String> result = new HashMap<>();
- final Iterator<Entry<String, String>> interator = keys.entrySet().iterator();
- while (interator.hasNext()) {
- final Entry<String, String> el = interator.next();
- final String newKey = removePrefixFromKey(el.getKey(), prefix);
- if (StringUtils.isNotEmpty(newKey)) {
- result.put(newKey, el.getValue());
- }
- }
-
- return result;
+ final String prefix) {
+ return keys.entrySet().stream()
+ .filter(el -> StringUtils.isNotEmpty(removePrefixFromKey(el.getKey(), prefix)))
+ .collect(Collectors.toMap(
+ el -> removePrefixFromKey(el.getKey(), prefix),
+ el -> el.getValue()));
+
+
}
/**
@@ -351,19 +345,13 @@ public class KeyValueUtils {
* @return Map of Key / Value pairs, but never null
*/
public static Map<String, String> convertListToMap(final List<String> elements) {
- final Map<String, String> map = new HashMap<>();
- for (final String el : elements) {
- if (el.contains(KEYVVALUEDELIMITER)) {
- final String[] split = el.split(KEYVVALUEDELIMITER);
- map.put(split[0], split[1]);
-
- } else {
- log.debug("Key/Value Mapper: '" + el + "' contains NO '='. Ignore it.");
- }
-
- }
+ return elements.stream()
+ .filter(el -> el.contains(KEYVVALUEDELIMITER))
+ .map(el -> el.split(KEYVVALUEDELIMITER))
+ .collect(Collectors.toMap(
+ el -> el[0],
+ el -> el[1]));
- return map;
}
/**
diff --git a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/SecurePendingRequestIdGenerationStrategy.java b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/SecurePendingRequestIdGenerationStrategy.java
index bc770a8c..5cac4cb0 100644
--- a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/SecurePendingRequestIdGenerationStrategy.java
+++ b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/SecurePendingRequestIdGenerationStrategy.java
@@ -1,19 +1,14 @@
package at.gv.egiz.eaaf.core.impl.utils;
-import java.io.UnsupportedEncodingException;
-import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
+import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
-import java.security.spec.InvalidKeySpecException;
-import java.security.spec.KeySpec;
-import java.util.Arrays;
import java.util.Base64;
import javax.annotation.PostConstruct;
import javax.crypto.Mac;
import javax.crypto.SecretKey;
-import javax.crypto.SecretKeyFactory;
-import javax.crypto.spec.PBEKeySpec;
import org.apache.commons.lang3.StringUtils;
import org.joda.time.DateTime;
@@ -32,6 +27,9 @@ import at.gv.egiz.eaaf.core.exceptions.EaafConfigurationException;
import at.gv.egiz.eaaf.core.exceptions.EaafException;
import at.gv.egiz.eaaf.core.exceptions.EaafIllegalStateException;
import at.gv.egiz.eaaf.core.exceptions.PendingReqIdValidationException;
+import at.gv.egiz.eaaf.core.impl.credential.EaafKeyStoreFactory;
+import at.gv.egiz.eaaf.core.impl.credential.SymmetricKeyConfiguration;
+import at.gv.egiz.eaaf.core.impl.credential.SymmetricKeyConfiguration.SymmetricKeyType;
/**
* PendingRequestId generation strategy based on signed tokens that facilitates
@@ -45,11 +43,22 @@ public class SecurePendingRequestIdGenerationStrategy
private static final Logger log =
LoggerFactory.getLogger(SecurePendingRequestIdGenerationStrategy.class);
- @Autowired(required = true)
- IConfiguration baseConfig;
+ @Autowired(required = true) IConfiguration baseConfig;
+ @Autowired EaafKeyStoreFactory keyStoreFactory;
+ private static final String FRIENDLYNAME = "pendingRequestId key";
+
+ public static final String CONFIG_PROP_PENDINGREQUESTID_DIGIST_TYPE =
+ "core.pendingrequestid.digist.type";
public static final String CONFIG_PROP_PENDINGREQUESTID_DIGIST_SECRET =
"core.pendingrequestid.digist.secret";
+
+ public static final String CONFIG_PROP_PENDINGREQUESTID_DIGIST_HSM_KEYSTORE =
+ "core.pendingrequestid.digist.keystore.name";
+ public static final String CONFIG_PROP_PENDINGREQUESTID_DIGIST_HSM_ALIAS =
+ "core.pendingrequestid.digist.key.alias";
+
+
public static final String CONFIG_PROP_PENDINGREQUESTID_DIGIST_ALGORITHM =
"core.pendingrequestid.digist.algorithm";
public static final String CONFIG_PROP_PENDINGREQUESTID_MAX_LIFETIME =
@@ -61,43 +70,32 @@ public class SecurePendingRequestIdGenerationStrategy
private static final int ENCODED_TOKEN_PARTS = 3;
private static final String TOKEN_SEPARATOR = "|";
private static final DateTimeFormatter TOKEN_TEXTUAL_DATE_FORMAT =
- DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss SSS");
+ DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss SSS ZZ").withZoneUTC();
private int maxPendingRequestIdLifeTime = 300;
private final int maxPendingReqIdSize = 1024;
private String digistAlgorithm = null;
private SecretKey key = null;
- private final byte[] salt = "notRequiredInThisScenario".getBytes(Charset.defaultCharset());
+ private final String salt = "notRequiredInThisScenario";
@Override
public String generateExternalPendingRequestId() throws EaafException {
- try {
- final String toSign = buildInternalToken(Random.nextLongRandom(), DateTime.now());
- final StringBuilder externalPendingRequestId = new StringBuilder();
- externalPendingRequestId.append(toSign);
- externalPendingRequestId.append(TOKEN_SEPARATOR);
- externalPendingRequestId.append(Base64.getEncoder().encodeToString(calculateHmac(toSign)));
- return Base64.getUrlEncoder()
- .encodeToString(externalPendingRequestId.toString().getBytes("UTF-8"));
-
- } catch (final UnsupportedEncodingException e) {
- throw new EaafException("internal.99", new Object[] { e.getMessage() }, e);
-
- }
+ final String toSign = buildInternalToken(Random.nextLongRandom(), DateTime.now());
+ final StringBuilder externalPendingRequestId = new StringBuilder();
+ externalPendingRequestId.append(toSign);
+ externalPendingRequestId.append(TOKEN_SEPARATOR);
+ externalPendingRequestId.append(Base64.getEncoder().encodeToString(calculateHmac(toSign)));
+ return Base64.getUrlEncoder()
+ .encodeToString(externalPendingRequestId.toString().getBytes(StandardCharsets.UTF_8));
}
@Override
public String getPendingRequestIdWithOutChecks(final String externalPendingReqId)
throws PendingReqIdValidationException {
- try {
- final String[] tokenElements = extractTokens(externalPendingReqId);
- return tokenElements[1];
-
- } catch (final UnsupportedEncodingException e) {
- throw new RuntimeException(e);
-
- }
+ final String[] tokenElements = extractTokens(externalPendingReqId);
+ return tokenElements[1];
+
}
@Override
@@ -111,11 +109,11 @@ public class SecurePendingRequestIdGenerationStrategy
log.trace("Checking HMAC from externalPendingReqId ... ");
final byte[] tokenDigest = Base64.getDecoder().decode(tokenElements[2]);
final byte[] refDigist = calculateHmac(buildInternalToken(internalPendingReqId, timeStamp));
- if (!Arrays.equals(tokenDigest, refDigist)) {
+
+ if (!MessageDigest.isEqual(refDigist,tokenDigest)) {
log.warn("Digest of Token does NOT match");
log.debug("Token: {} | Ref: {}", tokenDigest, refDigist);
- throw new PendingReqIdValidationException(null,
- "Digest of pendingRequestId does NOT match");
+ throw new PendingReqIdValidationException(null, "internal.pendingreqid.04");
}
log.debug("PendingRequestId HMAC digest check successful");
@@ -126,8 +124,7 @@ public class SecurePendingRequestIdGenerationStrategy
.isBefore(now)) {
log.warn("Token exceeds the valid period");
log.debug("Token: {} | Now: {}", timeStamp, now);
- throw new PendingReqIdValidationException(internalPendingReqId,
- "PendingRequestId exceeds the valid period");
+ throw new PendingReqIdValidationException(internalPendingReqId, "internal.pendingreqid.06");
}
log.debug("Token valid-period check successful");
@@ -137,20 +134,17 @@ public class SecurePendingRequestIdGenerationStrategy
} catch (final IllegalArgumentException | EaafIllegalStateException e) {
log.warn("Token is NOT a valid String. Msg: {}", e.getMessage());
log.debug("TokenValue: {}", externalPendingReqId);
- throw new PendingReqIdValidationException(null, "PendingReqId is NOT a valid String", e);
-
- } catch (final UnsupportedEncodingException e) {
- throw new RuntimeException(e);
+ throw new PendingReqIdValidationException(null, "internal.pendingreqid.06", e);
}
}
@NonNull
private String[] extractTokens(@Nullable final String externalPendingReqId)
- throws PendingReqIdValidationException, UnsupportedEncodingException {
+ throws PendingReqIdValidationException {
if (StringUtils.isEmpty(externalPendingReqId)) {
log.info("PendingReqId is 'null' or empty");
- throw new PendingReqIdValidationException(null, "PendingReqId is 'null' or empty");
+ throw new PendingReqIdValidationException(null, "internal.pendingreqid.00");
}
@@ -159,12 +153,11 @@ public class SecurePendingRequestIdGenerationStrategy
if (externalPendingReqIdBytes.length > maxPendingReqIdSize) {
log.warn("pendingReqId size exceeds {}", maxPendingReqIdSize);
- throw new PendingReqIdValidationException(null,
- "pendingReqId exceeds max.size: " + maxPendingReqIdSize);
+ throw new PendingReqIdValidationException(null, "internal.pendingreqid.03");
}
- final String stringToken = new String(externalPendingReqIdBytes, "UTF-8");
+ final String stringToken = new String(externalPendingReqIdBytes, StandardCharsets.UTF_8);
if (StringUtils.countMatches(stringToken, TOKEN_SEPARATOR) == ENCODED_TOKEN_PARTS - 1) {
final String[] tokenElements =
StringUtils.split(stringToken, TOKEN_SEPARATOR, ENCODED_TOKEN_PARTS);
@@ -173,7 +166,7 @@ public class SecurePendingRequestIdGenerationStrategy
} else {
log.warn("PendingRequestId has an unvalid format");
log.debug("PendingRequestId: {}", stringToken);
- throw new PendingReqIdValidationException(null, "PendingReqId has an unvalid format");
+ throw new PendingReqIdValidationException(null, "internal.pendingreqid.01");
}
@@ -183,13 +176,6 @@ public class SecurePendingRequestIdGenerationStrategy
private void initialize() throws EaafConfigurationException {
log.debug("Initializing " + this.getClass().getName() + " ... ");
- final String pendingReqIdDigistSecret =
- baseConfig.getBasicConfiguration(CONFIG_PROP_PENDINGREQUESTID_DIGIST_SECRET);
- if (StringUtils.isEmpty(pendingReqIdDigistSecret)) {
- throw new EaafConfigurationException("config.08",
- new Object[] { CONFIG_PROP_PENDINGREQUESTID_DIGIST_SECRET });
- }
-
digistAlgorithm = baseConfig.getBasicConfiguration(
CONFIG_PROP_PENDINGREQUESTID_DIGIST_ALGORITHM, DEFAULT_PENDINGREQUESTID_DIGIST_ALGORITHM);
@@ -197,12 +183,29 @@ public class SecurePendingRequestIdGenerationStrategy
Integer.parseInt(baseConfig.getBasicConfiguration(CONFIG_PROP_PENDINGREQUESTID_MAX_LIFETIME,
DEFAULT_PENDINGREQUESTID_MAX_LIFETIME));
+
+ SymmetricKeyConfiguration secretKeyConfig = new SymmetricKeyConfiguration();
+ secretKeyConfig.setFriendlyName(FRIENDLYNAME);
+ secretKeyConfig.setKeyType(
+ baseConfig.getBasicConfiguration(CONFIG_PROP_PENDINGREQUESTID_DIGIST_TYPE,
+ SymmetricKeyType.PASSPHRASE.name()));
+
+ secretKeyConfig.setSoftKeyPassphrase(
+ baseConfig.getBasicConfiguration(CONFIG_PROP_PENDINGREQUESTID_DIGIST_SECRET));
+ secretKeyConfig.setSoftKeySalt(salt);
+
+ secretKeyConfig.setKeyStoreName(
+ baseConfig.getBasicConfiguration(CONFIG_PROP_PENDINGREQUESTID_DIGIST_HSM_KEYSTORE));
+ secretKeyConfig.setKeyAlias(
+ baseConfig.getBasicConfiguration(CONFIG_PROP_PENDINGREQUESTID_DIGIST_HSM_ALIAS));
+
+ //validate symmetric-key configuration
+ secretKeyConfig.validate();
+
try {
- final SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBKDF2WITHHMACSHA256");
- final KeySpec spec = new PBEKeySpec(pendingReqIdDigistSecret.toCharArray(), salt, 10000, 128);
- key = keyFactory.generateSecret(spec);
+ key = keyStoreFactory.buildNewSymmetricKey(secretKeyConfig).getFirst();
- } catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
+ } catch (EaafException e) {
log.error("Can NOT initialize TokenService with configuration object", e);
throw new EaafConfigurationException("config.09",
new Object[] { CONFIG_PROP_PENDINGREQUESTID_DIGIST_SECRET, "Can NOT generate HMAC key" },
@@ -224,9 +227,9 @@ public class SecurePendingRequestIdGenerationStrategy
try {
final Mac mac = Mac.getInstance(digistAlgorithm);
mac.init(key);
- return mac.doFinal(toSign.getBytes("UTF-8"));
+ return mac.doFinal(toSign.getBytes(StandardCharsets.UTF_8));
- } catch (UnsupportedEncodingException | NoSuchAlgorithmException | InvalidKeyException e) {
+ } catch (NoSuchAlgorithmException | InvalidKeyException e) {
log.error("Can NOT generate secure pendingRequestId", e);
throw new EaafIllegalStateException(
new Object[] { "Can NOT caluclate digist for secure pendingRequestId" }, e);
diff --git a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/TransactionIdUtils.java b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/TransactionIdUtils.java
index 4c1601c0..212460d7 100644
--- a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/TransactionIdUtils.java
+++ b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/TransactionIdUtils.java
@@ -21,7 +21,10 @@ package at.gv.egiz.eaaf.core.impl.utils;
import java.util.UUID;
+import javax.annotation.Nullable;
+
import at.gv.egiz.eaaf.core.api.IRequest;
+import lombok.extern.slf4j.Slf4j;
/**
* Transaction Identifier Utils.
@@ -29,6 +32,7 @@ import at.gv.egiz.eaaf.core.api.IRequest;
* @author tlenz
*
*/
+@Slf4j
public class TransactionIdUtils {
/**
@@ -58,11 +62,16 @@ public class TransactionIdUtils {
*
* @param pendingRequest Http request object
*/
- public static void setAllLoggingVariables(final IRequest pendingRequest) {
- setTransactionId(pendingRequest.getUniqueTransactionIdentifier());
- setSessionId(pendingRequest.getUniqueSessionIdentifier());
- setServiceProviderId(pendingRequest.getServiceProviderConfiguration().getUniqueIdentifier());
-
+ public static void setAllLoggingVariables(@Nullable final IRequest pendingRequest) {
+ if (pendingRequest != null) {
+ setTransactionId(pendingRequest.getUniqueTransactionIdentifier());
+ setSessionId(pendingRequest.getUniqueSessionIdentifier());
+ setServiceProviderId(pendingRequest.getServiceProviderConfiguration().getUniqueIdentifier());
+
+ } else {
+ log.info("Can NOT set MDC variables from pendingRequest because it is 'null'");
+
+ }
}
/**
diff --git a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/X509Utils.java b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/X509Utils.java
index 72c183bf..4d872ebe 100644
--- a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/X509Utils.java
+++ b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/X509Utils.java
@@ -1,6 +1,7 @@
package at.gv.egiz.eaaf.core.impl.utils;
import java.security.cert.X509Certificate;
+import java.util.Arrays;
import java.util.List;
import javax.security.auth.x500.X500Principal;
@@ -11,6 +12,18 @@ public class X509Utils {
* Sorts the Certificate Chain by IssuerDN and SubjectDN. The [0]-Element should
* be the Hostname, the last Element should be the Root Certificate.
*
+ * @param certChain The first element must be the correct one.
+ * @return sorted Certificate Chain
+ */
+ public static List<X509Certificate> sortCertificates(X509Certificate[] certChain) {
+ return sortCertificates(Arrays.asList(certChain));
+
+ }
+
+ /**
+ * Sorts the Certificate Chain by IssuerDN and SubjectDN. The [0]-Element should
+ * be the Hostname, the last Element should be the Root Certificate.
+ *
* @param certs The first element must be the correct one.
* @return sorted Certificate Chain
*/
@@ -48,4 +61,5 @@ public class X509Utils {
return certs;
}
+
}
diff --git a/eaaf_core_utils/src/main/resources/messages/eaaf_utils_message.properties b/eaaf_core_utils/src/main/resources/messages/eaaf_utils_message.properties
index b20c5f63..79f82af8 100644
--- a/eaaf_core_utils/src/main/resources/messages/eaaf_utils_message.properties
+++ b/eaaf_core_utils/src/main/resources/messages/eaaf_utils_message.properties
@@ -11,8 +11,22 @@ internal.keystore.06=KeyStore: {0} initialization failed. Reason: {1}
internal.keystore.07=Validation of KeyStore: {0} failed. Reason: {1}
internal.keystore.08=Can not access Key: {1} in KeyStore: {0}
internal.keystore.09=Can not access Key: {1} in KeyStore: {0} Reason: {2}
+internal.keystore.10=HSM-Facade NOT INITIALIZED. Find HSM-Facade class: {0} put that looks WRONG.
+internal.keystore.11=KeyStore: {0} has a wrong configuration. Property: {0} Reason:{1}
+
+internal.key.00=Can not generate passphrase based symmetric-key: {0} Reason: {1}
+internal.key.01=Can not use key from Keystore: {0} Reason: {1}
internal.httpclient.00=HttpClient:{0} uses http Basic-Auth, but 'Username' is NOT set
internal.httpclient.01=HttpClient:{0} uses X509 client-auth, but 'KeyStoreConfig' is NOT set
internal.httpclient.02=HttpClient:{0} uses KeyStore:{1}, but 'keyPassword' is NOT set
-internal.httpclient.03=Can not initialize SSLContext for HttpClient:{0} Reason:{1} \ No newline at end of file
+internal.httpclient.03=Can not initialize SSLContext for HttpClient:{0} Reason:{1}
+
+internal.pendingreqid.00=Process Token is 'null' or 'empty'
+internal.pendingreqid.01=Process Token is NOT valid because it has an invalid format
+internal.pendingreqid.02=Can not create process Token
+internal.pendingreqid.03=Process Token is NOT valid because it reached maximum size
+internal.pendingreqid.04=Process Token is NOT valid because it is cryptographically invalid
+internal.pendingreqid.05=Process Token is NOT valid because it has an invalid encoding
+internal.pendingreqid.06=Process Token is NOT valid because it exceeds the valid period
+
diff --git a/eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/impl/logging/EaafUtilsMessageSourceTest.java b/eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/impl/logging/EaafUtilsMessageSourceTest.java
index 53ea54dc..125dcb09 100644
--- a/eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/impl/logging/EaafUtilsMessageSourceTest.java
+++ b/eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/impl/logging/EaafUtilsMessageSourceTest.java
@@ -2,19 +2,21 @@ package at.gv.egiz.eaaf.core.impl.logging;
import java.util.List;
-import at.gv.egiz.eaaf.core.api.logging.IMessageSourceLocation;
-
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
+import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import at.gv.egiz.eaaf.core.api.logging.IMessageSourceLocation;
+
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("/spring/test_eaaf_pvp_not_lazy.beans.xml")
+@DirtiesContext
public class EaafUtilsMessageSourceTest {
@Autowired
diff --git a/eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/impl/utils/test/AuthenticatedEncryptionPendingRequestIdGenerationStrategyTest.java b/eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/impl/utils/test/AuthenticatedEncryptionPendingRequestIdGenerationStrategyTest.java
new file mode 100644
index 00000000..93ef17b9
--- /dev/null
+++ b/eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/impl/utils/test/AuthenticatedEncryptionPendingRequestIdGenerationStrategyTest.java
@@ -0,0 +1,447 @@
+package at.gv.egiz.eaaf.core.impl.utils.test;
+
+import java.io.UnsupportedEncodingException;
+import java.security.Provider;
+import java.util.Base64;
+
+import javax.crypto.SecretKey;
+
+import org.apache.commons.lang3.RandomStringUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.joda.time.DateTime;
+import org.joda.time.ReadableInstant;
+import org.joda.time.format.DateTimeFormat;
+import org.jose4j.jwe.ContentEncryptionAlgorithmIdentifiers;
+import org.jose4j.jwe.JsonWebEncryption;
+import org.jose4j.jwe.KeyManagementAlgorithmIdentifiers;
+import org.jose4j.lang.JoseException;
+import org.junit.Assert;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.test.annotation.DirtiesContext;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+
+import at.gv.egiz.eaaf.core.exceptions.EaafException;
+import at.gv.egiz.eaaf.core.exceptions.PendingReqIdValidationException;
+import at.gv.egiz.eaaf.core.impl.credential.EaafKeyStoreFactory;
+import at.gv.egiz.eaaf.core.impl.credential.SymmetricKeyConfiguration;
+import at.gv.egiz.eaaf.core.impl.credential.SymmetricKeyConfiguration.SymmetricKeyType;
+import at.gv.egiz.eaaf.core.impl.data.Pair;
+import at.gv.egiz.eaaf.core.impl.utils.AuthenticatedEncryptionPendingRequestIdGenerationStrategy;
+
+@RunWith(SpringJUnit4ClassRunner.class)
+@ContextConfiguration("/spring/test_eaaf_pvp_not_lazy.beans.xml")
+@DirtiesContext
+public class AuthenticatedEncryptionPendingRequestIdGenerationStrategyTest {
+
+ @Autowired private EaafKeyStoreFactory keyStoreFactory;
+ @Autowired private AuthenticatedEncryptionPendingRequestIdGenerationStrategy pendingIdStrategy;
+
+
+ @Test
+ public void generatePendingRequestId() throws EaafException {
+ String pendingId = pendingIdStrategy.generateExternalPendingRequestId();
+ Assert.assertNotNull("pendingId", pendingId);
+
+ }
+
+ @Test
+ public void validatePendingRequestId() throws EaafException {
+ String extPendingId = pendingIdStrategy.generateExternalPendingRequestId();
+ Assert.assertNotNull("external pendingId", extPendingId);
+
+
+ String pendingId = pendingIdStrategy.validateAndGetPendingRequestId(extPendingId);
+ Assert.assertNotNull("internal pendingId", pendingId);
+
+ String pendingId2 = pendingIdStrategy.getPendingRequestIdWithOutChecks(extPendingId);
+ Assert.assertNotNull("internal pendingId", pendingId2);
+
+ Assert.assertEquals("pendingId not match", pendingId, pendingId2);
+
+ }
+
+ @Test
+ public void nullPendingRequestId() {
+ try {
+ pendingIdStrategy.validateAndGetPendingRequestId(null);
+ Assert.fail("Wrong pendingId not detected");
+
+ } catch (PendingReqIdValidationException e) {
+ Assert.assertNull("internal pendingReqId", e.getInvalidInternalPendingReqId());
+ Assert.assertNull("internal pendingReq", e.getInvalidPendingReq());
+ Assert.assertEquals("Wrong errorId", "internal.pendingreqid.00", e.getErrorId());
+
+ }
+ }
+
+ @Test
+ public void emptyPendingRequestId() {
+ try {
+ pendingIdStrategy.validateAndGetPendingRequestId(StringUtils.EMPTY);
+ Assert.fail("Wrong pendingId not detected");
+
+ } catch (PendingReqIdValidationException e) {
+ Assert.assertNull("internal pendingReqId", e.getInvalidInternalPendingReqId());
+ Assert.assertNull("internal pendingReq", e.getInvalidPendingReq());
+ Assert.assertEquals("Wrong errorId", "internal.pendingreqid.00", e.getErrorId());
+
+ }
+ }
+
+ @Test
+ public void noBase64UrlPendingRequestId() {
+ try {
+ pendingIdStrategy.validateAndGetPendingRequestId(RandomStringUtils.randomAlphanumeric(25));
+ Assert.fail("Wrong pendingId not detected");
+
+ } catch (PendingReqIdValidationException e) {
+ Assert.assertNull("internal pendingReqId", e.getInvalidInternalPendingReqId());
+ Assert.assertNull("internal pendingReq", e.getInvalidPendingReq());
+ Assert.assertEquals("Wrong errorId", "internal.pendingreqid.05", e.getErrorId());
+
+ }
+ }
+
+ @Test
+ public void toLongBase64UrlPendingRequestId() {
+ try {
+ pendingIdStrategy.validateAndGetPendingRequestId(Base64.getUrlEncoder()
+ .encodeToString(RandomStringUtils.randomAlphanumeric(1100).getBytes()));
+ Assert.fail("Wrong pendingId not detected");
+
+ } catch (PendingReqIdValidationException e) {
+ Assert.assertNull("internal pendingReqId", e.getInvalidInternalPendingReqId());
+ Assert.assertNull("internal pendingReq", e.getInvalidPendingReq());
+ Assert.assertEquals("Wrong errorId", "internal.pendingreqid.03", e.getErrorId());
+
+ }
+ }
+
+ @Test
+ public void wrongFormat() throws EaafException, JoseException, UnsupportedEncodingException {
+ String payLoad = RandomStringUtils.randomAlphanumeric(25);
+
+ String extPendingId = generateEncryptedPendingId(payLoad,
+ KeyManagementAlgorithmIdentifiers.DIRECT,
+ ContentEncryptionAlgorithmIdentifiers.AES_128_GCM,
+ "pendingReqIdSecret");
+
+ try {
+ pendingIdStrategy.validateAndGetPendingRequestId(Base64.getUrlEncoder()
+ .encodeToString(extPendingId.getBytes()));
+ Assert.fail("Wrong pendingId not detected");
+
+ } catch (PendingReqIdValidationException e) {
+ Assert.assertNull("internal pendingReqId", e.getInvalidInternalPendingReqId());
+ Assert.assertNull("internal pendingReq", e.getInvalidPendingReq());
+ Assert.assertEquals("Wrong errorId", "internal.pendingreqid.01", e.getErrorId());
+
+ }
+ }
+
+ @Test
+ public void wrongFormatToLong() throws EaafException, JoseException, UnsupportedEncodingException {
+ String payLoad = RandomStringUtils.randomAlphanumeric(25) + "|"
+ + RandomStringUtils.randomAlphanumeric(25) + "|" + "aabbcc";
+
+ String extPendingId = generateEncryptedPendingId(payLoad,
+ KeyManagementAlgorithmIdentifiers.DIRECT,
+ ContentEncryptionAlgorithmIdentifiers.AES_128_GCM,
+ "pendingReqIdSecret");
+
+ try {
+ pendingIdStrategy.validateAndGetPendingRequestId(Base64.getUrlEncoder()
+ .encodeToString(extPendingId.getBytes()));
+ Assert.fail("Wrong pendingId not detected");
+
+ } catch (PendingReqIdValidationException e) {
+ Assert.assertNull("internal pendingReqId", e.getInvalidInternalPendingReqId());
+ Assert.assertNull("internal pendingReq", e.getInvalidPendingReq());
+ Assert.assertEquals("Wrong errorId", "internal.pendingreqid.01", e.getErrorId());
+
+ }
+ }
+
+ @Test
+ public void wrongFormatNoDate() throws EaafException, JoseException, UnsupportedEncodingException {
+ String payLoad = RandomStringUtils.randomAlphanumeric(25) + "|"
+ + RandomStringUtils.randomAlphanumeric(25);
+
+ String extPendingId = generateEncryptedPendingId(payLoad,
+ KeyManagementAlgorithmIdentifiers.DIRECT,
+ ContentEncryptionAlgorithmIdentifiers.AES_128_GCM,
+ "pendingReqIdSecret");
+
+ try {
+ pendingIdStrategy.validateAndGetPendingRequestId(Base64.getUrlEncoder()
+ .encodeToString(extPendingId.getBytes()));
+ Assert.fail("Wrong pendingId not detected");
+
+ } catch (PendingReqIdValidationException e) {
+ Assert.assertNull("internal pendingReqId", e.getInvalidInternalPendingReqId());
+ Assert.assertNull("internal pendingReq", e.getInvalidPendingReq());
+ Assert.assertEquals("Wrong errorId", "internal.pendingreqid.05", e.getErrorId());
+
+ }
+ }
+
+ @Test
+ public void wrongFormatWrongDate() throws EaafException, JoseException, UnsupportedEncodingException {
+ String payLoad = "2020-01-01 12:01:55 111 +00:00" + "|"
+ + RandomStringUtils.randomAlphanumeric(25);
+
+ String extPendingId = generateEncryptedPendingId(payLoad,
+ KeyManagementAlgorithmIdentifiers.DIRECT,
+ ContentEncryptionAlgorithmIdentifiers.AES_128_GCM,
+ "pendingReqIdSecret");
+
+ try {
+ pendingIdStrategy.validateAndGetPendingRequestId(Base64.getUrlEncoder()
+ .encodeToString(extPendingId.getBytes()));
+ Assert.fail("Wrong pendingId not detected");
+
+ } catch (PendingReqIdValidationException e) {
+ Assert.assertNotNull("internal pendingReqId", e.getInvalidInternalPendingReqId());
+ Assert.assertNull("internal pendingReq", e.getInvalidPendingReq());
+ Assert.assertEquals("Wrong errorId", "internal.pendingreqid.06", e.getErrorId());
+
+ }
+ }
+
+ @Test
+ public void wrongFormatNotValidation() throws EaafException, JoseException, UnsupportedEncodingException {
+ String payLoad = RandomStringUtils.randomAlphanumeric(25);
+
+ String extPendingId = generateEncryptedPendingId(payLoad,
+ KeyManagementAlgorithmIdentifiers.DIRECT,
+ ContentEncryptionAlgorithmIdentifiers.AES_128_GCM,
+ "pendingReqIdSecret");
+
+ try {
+ pendingIdStrategy.getPendingRequestIdWithOutChecks(Base64.getUrlEncoder()
+ .encodeToString(extPendingId.getBytes()));
+ Assert.fail("Wrong pendingId not detected");
+
+ } catch (PendingReqIdValidationException e) {
+ Assert.assertNull("internal pendingReqId", e.getInvalidInternalPendingReqId());
+ Assert.assertNull("internal pendingReq", e.getInvalidPendingReq());
+ Assert.assertEquals("Wrong errorId", "internal.pendingreqid.01", e.getErrorId());
+
+ }
+ }
+
+ @Test
+ public void wrongFormatToLongNotValidation() throws EaafException, JoseException, UnsupportedEncodingException {
+ String payLoad = RandomStringUtils.randomAlphanumeric(25) + "|"
+ + RandomStringUtils.randomAlphanumeric(25) + "|" + "aabbcc";
+
+ String extPendingId = generateEncryptedPendingId(payLoad,
+ KeyManagementAlgorithmIdentifiers.DIRECT,
+ ContentEncryptionAlgorithmIdentifiers.AES_128_GCM,
+ "pendingReqIdSecret");
+
+ try {
+ pendingIdStrategy.getPendingRequestIdWithOutChecks(Base64.getUrlEncoder()
+ .encodeToString(extPendingId.getBytes()));
+ Assert.fail("Wrong pendingId not detected");
+
+ } catch (PendingReqIdValidationException e) {
+ Assert.assertNull("internal pendingReqId", e.getInvalidInternalPendingReqId());
+ Assert.assertNull("internal pendingReq", e.getInvalidPendingReq());
+ Assert.assertEquals("Wrong errorId", "internal.pendingreqid.01", e.getErrorId());
+
+ }
+ }
+
+ @Test
+ public void wrongFormatNoDateNotValidation() throws EaafException, JoseException, UnsupportedEncodingException {
+ String payLoad = RandomStringUtils.randomAlphanumeric(25) + "|"
+ + RandomStringUtils.randomAlphanumeric(25);
+
+ String extPendingId = generateEncryptedPendingId(payLoad,
+ KeyManagementAlgorithmIdentifiers.DIRECT,
+ ContentEncryptionAlgorithmIdentifiers.AES_128_GCM,
+ "pendingReqIdSecret");
+
+
+ String intPendingId = pendingIdStrategy.getPendingRequestIdWithOutChecks(Base64.getUrlEncoder()
+ .encodeToString(extPendingId.getBytes()));
+ Assert.assertNotNull("Int PendingId", intPendingId);
+
+ }
+
+ @Test
+ public void wrongFormatWrongDateNotValidation() throws EaafException, JoseException, UnsupportedEncodingException {
+ String payLoad = "2020-01-01 12:01:55 111" + "|"
+ + RandomStringUtils.randomAlphanumeric(25);
+
+ String extPendingId = generateEncryptedPendingId(payLoad,
+ KeyManagementAlgorithmIdentifiers.DIRECT,
+ ContentEncryptionAlgorithmIdentifiers.AES_128_GCM,
+ "pendingReqIdSecret");
+
+
+ String intPendingId = pendingIdStrategy.getPendingRequestIdWithOutChecks(Base64.getUrlEncoder()
+ .encodeToString(extPendingId.getBytes()));
+ Assert.assertNotNull("Int PendingId", intPendingId);
+
+
+ }
+
+ @Test
+ public void validFormat() throws EaafException, JoseException, UnsupportedEncodingException {
+ String intId = RandomStringUtils.randomAlphanumeric(25);
+ ReadableInstant now = DateTime.now();
+ String payLoad = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss SSS").print(now)
+ + "|" + intId;
+
+ String extPendingId = generateEncryptedPendingId(payLoad,
+ KeyManagementAlgorithmIdentifiers.DIRECT,
+ ContentEncryptionAlgorithmIdentifiers.AES_128_GCM,
+ "pendingReqIdSecret");
+
+
+ String intPendingId = pendingIdStrategy.getPendingRequestIdWithOutChecks(Base64.getUrlEncoder()
+ .encodeToString(extPendingId.getBytes()));
+ Assert.assertNotNull("Int PendingId", intPendingId);
+ Assert.assertEquals("pendingId not match", intId, intPendingId);
+
+ }
+
+ @Test
+ public void validFormatNotValidation() throws EaafException, JoseException, UnsupportedEncodingException {
+ String intId = RandomStringUtils.randomAlphanumeric(25);
+ String payLoad = "2020-01-01 12:01:55 111"
+ + "|" + intId;
+
+ String extPendingId = generateEncryptedPendingId(payLoad,
+ KeyManagementAlgorithmIdentifiers.DIRECT,
+ ContentEncryptionAlgorithmIdentifiers.AES_128_GCM,
+ "pendingReqIdSecret");
+
+ String intPendingId = pendingIdStrategy.getPendingRequestIdWithOutChecks(Base64.getUrlEncoder()
+ .encodeToString(extPendingId.getBytes()));
+ Assert.assertNotNull("Int PendingId", intPendingId);
+
+ }
+
+ @Test
+ public void validFormatWrongDateNotValidation() throws EaafException, JoseException, UnsupportedEncodingException {
+ String intId = RandomStringUtils.randomAlphanumeric(25);
+ String payLoad = "2020-01-01 12:01:55 111" + "|"
+ + intId;
+
+ String extPendingId = generateEncryptedPendingId(payLoad,
+ KeyManagementAlgorithmIdentifiers.DIRECT,
+ ContentEncryptionAlgorithmIdentifiers.AES_128_GCM,
+ "pendingReqIdSecret");
+
+
+ String intPendingId = pendingIdStrategy.getPendingRequestIdWithOutChecks(Base64.getUrlEncoder()
+ .encodeToString(extPendingId.getBytes()));
+ Assert.assertNotNull("Int PendingId", intPendingId);
+ Assert.assertEquals("pendingId not match", intId, intPendingId);
+
+
+ }
+
+ @Test
+ public void wrongEncrypted() throws EaafException, JoseException, UnsupportedEncodingException {
+ String payLoad = RandomStringUtils.randomAlphanumeric(25);
+
+ String extPendingId = generateEncryptedPendingId(payLoad,
+ KeyManagementAlgorithmIdentifiers.DIRECT,
+ ContentEncryptionAlgorithmIdentifiers.AES_128_GCM,
+ "wrongPassword");
+
+ try {
+ pendingIdStrategy.validateAndGetPendingRequestId(Base64.getUrlEncoder()
+ .encodeToString(extPendingId.getBytes()));
+ Assert.fail("Wrong pendingId not detected");
+
+ } catch (PendingReqIdValidationException e) {
+ Assert.assertNull("internal pendingReqId", e.getInvalidInternalPendingReqId());
+ Assert.assertNull("internal pendingReq", e.getInvalidPendingReq());
+ Assert.assertEquals("Wrong errorId", "internal.pendingreqid.04", e.getErrorId());
+
+ }
+ }
+
+ @Ignore
+ @Test
+ public void wrongEncryptionAlg() throws EaafException, JoseException, UnsupportedEncodingException {
+ String payLoad = RandomStringUtils.randomAlphanumeric(25);
+
+ String extPendingId = generateEncryptedPendingId(payLoad,
+ KeyManagementAlgorithmIdentifiers.A256KW,
+ ContentEncryptionAlgorithmIdentifiers.AES_128_CBC_HMAC_SHA_256,
+ "pendingReqIdSecret");
+
+ try {
+ pendingIdStrategy.validateAndGetPendingRequestId(Base64.getUrlEncoder()
+ .encodeToString(extPendingId.getBytes()));
+ Assert.fail("Wrong pendingId not detected");
+
+ } catch (PendingReqIdValidationException e) {
+ Assert.assertNull("internal pendingReqId", e.getInvalidInternalPendingReqId());
+ Assert.assertNull("internal pendingReq", e.getInvalidPendingReq());
+ Assert.assertEquals("Wrong errorId", "process.99", e.getErrorId());
+ Assert.assertEquals("Wrong errorMsg",
+ "No StatusMessager-Backend available! StatusCode:process.99 Params:[null, "
+ + "PendingReqId has an unvalid format]",
+ e.getMessage());
+
+ }
+ }
+
+ @Ignore
+ @Test
+ public void wrongKeyEncAlg() throws EaafException, JoseException, UnsupportedEncodingException {
+ String payLoad = RandomStringUtils.randomAlphanumeric(25);
+
+ String extPendingId = generateEncryptedPendingId(payLoad,
+ KeyManagementAlgorithmIdentifiers.A128KW,
+ ContentEncryptionAlgorithmIdentifiers.AES_128_CBC_HMAC_SHA_256,
+ "pendingReqIdSecret");
+
+ try {
+ pendingIdStrategy.validateAndGetPendingRequestId(Base64.getUrlEncoder()
+ .encodeToString(extPendingId.getBytes()));
+ Assert.fail("Wrong pendingId not detected");
+
+ } catch (PendingReqIdValidationException e) {
+ Assert.assertNull("internal pendingReqId", e.getInvalidInternalPendingReqId());
+ Assert.assertNull("internal pendingReq", e.getInvalidPendingReq());
+ Assert.assertEquals("Wrong errorId", "process.99", e.getErrorId());
+ Assert.assertEquals("Wrong errorMsg",
+ "No StatusMessager-Backend available! StatusCode:process.99 Params:[null, "
+ + "PendingReqId is NOT a valid String]",
+ e.getMessage());
+
+ }
+ }
+
+ private String generateEncryptedPendingId(String payLoad, String direct, String aes128Gcm, String softKeyPassphrase)
+ throws EaafException, JoseException, UnsupportedEncodingException {
+ SymmetricKeyConfiguration config = new SymmetricKeyConfiguration();
+ config.setFriendlyName("jUnit");
+ config.setKeyType(SymmetricKeyType.PASSPHRASE);
+ config.setSoftKeySalt("notRequiredInThisScenario");
+ config.setSoftKeyPassphrase(softKeyPassphrase);
+ Pair<SecretKey, Provider> key = keyStoreFactory.buildNewSymmetricKey(config);
+
+ JsonWebEncryption encToken = new JsonWebEncryption();
+ encToken.setAlgorithmHeaderValue(direct);
+ encToken.setEncryptionMethodHeaderParameter(aes128Gcm);
+ encToken.setKey(key.getFirst());
+ encToken.setPayload(payLoad);
+
+ return encToken.getCompactSerialization();
+
+ }
+
+}
diff --git a/eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/impl/utils/test/AuthenticatedEncryptionPendingRequestIdGenerationStrategyWithHsmTest.java b/eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/impl/utils/test/AuthenticatedEncryptionPendingRequestIdGenerationStrategyWithHsmTest.java
new file mode 100644
index 00000000..b588bb3a
--- /dev/null
+++ b/eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/impl/utils/test/AuthenticatedEncryptionPendingRequestIdGenerationStrategyWithHsmTest.java
@@ -0,0 +1,44 @@
+package at.gv.egiz.eaaf.core.impl.utils.test;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.test.annotation.DirtiesContext;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+
+import at.gv.egiz.eaaf.core.exceptions.EaafException;
+import at.gv.egiz.eaaf.core.impl.utils.AuthenticatedEncryptionPendingRequestIdGenerationStrategy;
+
+@RunWith(SpringJUnit4ClassRunner.class)
+@ContextConfiguration("/spring/test_eaaf_pvp_not_lazy_with_hsm.beans.xml")
+@DirtiesContext
+public class AuthenticatedEncryptionPendingRequestIdGenerationStrategyWithHsmTest {
+
+ @Autowired private AuthenticatedEncryptionPendingRequestIdGenerationStrategy pendingIdStrategy;
+
+ @Test
+ public void generatePendingRequestId() throws EaafException {
+ String pendingId = pendingIdStrategy.generateExternalPendingRequestId();
+ Assert.assertNotNull("pendingId", pendingId);
+
+ }
+
+ @Test
+ public void validatePendingRequestId() throws EaafException {
+ String extPendingId = pendingIdStrategy.generateExternalPendingRequestId();
+ Assert.assertNotNull("external pendingId", extPendingId);
+
+
+ String pendingId = pendingIdStrategy.validateAndGetPendingRequestId(extPendingId);
+ Assert.assertNotNull("internal pendingId", pendingId);
+
+ String pendingId2 = pendingIdStrategy.getPendingRequestIdWithOutChecks(extPendingId);
+ Assert.assertNotNull("internal pendingId", pendingId2);
+
+ Assert.assertEquals("pendingId not match", pendingId, pendingId2);
+
+ }
+
+}
diff --git a/eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/impl/utils/test/KeyValueUtilsTest.java b/eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/impl/utils/test/KeyValueUtilsTest.java
index 58788392..ca90f05b 100644
--- a/eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/impl/utils/test/KeyValueUtilsTest.java
+++ b/eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/impl/utils/test/KeyValueUtilsTest.java
@@ -153,7 +153,8 @@ public class KeyValueUtilsTest {
+ RandomStringUtils.randomAlphabetic(6) + KeyValueUtils.KEY_DELIMITER
+ RandomStringUtils.randomAlphabetic(5);
final Map<String, String> testMap = generateTestMap(testPrefix, 5, 5);
-
+ testMap.put(testPrefix, RandomStringUtils.randomAlphabetic(10));
+
final Map<String, String> result = KeyValueUtils.removePrefixFromKeys(testMap, testPrefix);
Assert.assertNotNull("Result is null", result);
Assert.assertFalse("Result is empty", result.isEmpty());
diff --git a/eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/test/builder/BpkBuilderTest.java b/eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/test/builder/BpkBuilderTest.java
new file mode 100644
index 00000000..bccab09f
--- /dev/null
+++ b/eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/test/builder/BpkBuilderTest.java
@@ -0,0 +1,562 @@
+package at.gv.egiz.eaaf.core.test.builder;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.spec.ECGenParameterSpec;
+
+import org.apache.commons.lang3.RandomStringUtils;
+import org.jose4j.jwe.ContentEncryptionAlgorithmIdentifiers;
+import org.jose4j.jwe.JsonWebEncryption;
+import org.jose4j.jwe.KeyManagementAlgorithmIdentifiers;
+import org.jose4j.lang.JoseException;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.BlockJUnit4ClassRunner;
+
+import at.gv.egiz.eaaf.core.api.data.EaafConstants;
+import at.gv.egiz.eaaf.core.exceptions.EaafBuilderException;
+import at.gv.egiz.eaaf.core.impl.builder.BpkBuilder;
+import at.gv.egiz.eaaf.core.impl.data.Pair;
+
+@RunWith(BlockJUnit4ClassRunner.class)
+public class BpkBuilderTest {
+
+ private static final String BASEID = "RUxHQVRlc3RQQjBYWFjFkHpnw7xyX1hYWFTDvHpla8OnaQ==";
+
+ private KeyPair keyPair;
+
+
+ /**
+ * jUnit test initializer.
+ * @throws NoSuchProviderException In case of an error
+ * @throws NoSuchAlgorithmException In case of an error
+ */
+ @Before
+ public void initialize() throws NoSuchAlgorithmException, NoSuchProviderException {
+ KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
+ keyGen.initialize(2048);
+ keyPair = keyGen.generateKeyPair();
+
+ }
+
+ @Test
+ public void encBpkTextualLength() throws EaafBuilderException, InvalidKeyException, NoSuchAlgorithmException,
+ NoSuchProviderException, InvalidAlgorithmParameterException, JoseException {
+ String bpk = "MDEyMzQ1Njc4OWFiY2RIZg+CU";
+ String target = EaafConstants.URN_PREFIX_CDID + "AA";
+
+ printResult("Legacy RSA 1024:", BpkBuilder.encryptBpk(bpk, target, generateRsaPubKey(1024)));
+ printResult("Legacy RSA 2048:", BpkBuilder.encryptBpk(bpk, target, generateRsaPubKey(2048)));
+ printResult("Legacy RSA 3072:", BpkBuilder.encryptBpk(bpk, target, generateRsaPubKey(3072)));
+ printResult("Legacy RSA 4096:", BpkBuilder.encryptBpk(bpk, target, generateRsaPubKey(4096)));
+
+
+ bpk = "V1::urn:publicid:gv.at:cdid+BW::MDEyMzQ1Njc 4OW FiY2RIZg+CU&g=::2004-01-22T20:57:12";
+
+ printResult("RSA 2048:", createJsonEnc(generateRsaPubKey(2048), bpk, target,
+ KeyManagementAlgorithmIdentifiers.RSA_OAEP_256));
+ printResult("RSA 3072:", createJsonEnc(generateRsaPubKey(3072), bpk, target,
+ KeyManagementAlgorithmIdentifiers.RSA_OAEP_256));
+ printResult("RSA 4096:", createJsonEnc(generateRsaPubKey(4048), bpk, target,
+ KeyManagementAlgorithmIdentifiers.RSA_OAEP_256));
+
+ printResult("ECC 256:", createJsonEnc(generateEcPubKey("secp256r1"), bpk, target,
+ KeyManagementAlgorithmIdentifiers.ECDH_ES_A128KW));
+ printResult("ECC 384:", createJsonEnc(generateEcPubKey("secp384r1"), bpk, target,
+ KeyManagementAlgorithmIdentifiers.ECDH_ES_A128KW));
+ printResult("ECC 521:", createJsonEnc(generateEcPubKey("secp521r1"), bpk, target,
+ KeyManagementAlgorithmIdentifiers.ECDH_ES_A128KW));
+
+ System.out.println("Finished!");
+ }
+
+ private void printResult(String prefix, String body) {
+ System.out.println(prefix + " " + body.length() + " full:" + body);
+
+ }
+
+ private String createJsonEnc(PublicKey pubKey, String bpk, String target, String keyWrapAlg) throws JoseException {
+ JsonWebEncryption enc = new JsonWebEncryption();
+ enc.setKey(pubKey);
+ enc.setPayload(bpk);
+ enc.setAlgorithmHeaderValue(keyWrapAlg);
+ enc.setEncryptionMethodHeaderParameter(ContentEncryptionAlgorithmIdentifiers.AES_128_GCM);
+ enc.setKeyIdHeaderValue("myFirstKey");
+ enc.setContentTypeHeaderValue(target);
+ return enc.getCompactSerialization();
+
+ }
+
+ private PublicKey generateRsaPubKey(int size) throws NoSuchAlgorithmException {
+ KeyPairGenerator keyGen3 = KeyPairGenerator.getInstance("RSA");
+ keyGen3.initialize(size);
+ return keyGen3.generateKeyPair().getPublic();
+
+ }
+
+ private PublicKey generateEcPubKey(String curve) throws NoSuchAlgorithmException,
+ NoSuchProviderException, InvalidAlgorithmParameterException {
+ KeyPairGenerator generator = KeyPairGenerator.getInstance("EC");
+ ECGenParameterSpec ecSpec = new ECGenParameterSpec(curve);
+ generator.initialize(ecSpec, new SecureRandom());
+ return generator.generateKeyPair().getPublic();
+
+ }
+
+ @Test
+ public void encBpkWrongTarget() throws InvalidKeyException {
+ String bpk = RandomStringUtils.randomAlphanumeric(25);
+ String target = RandomStringUtils.randomAlphanumeric(25);
+
+ try {
+ BpkBuilder.encryptBpk(bpk, target, keyPair.getPublic());
+ Assert.fail("Wrong parameters not detected");
+
+ } catch (EaafBuilderException e) {
+ Assert.assertEquals("Wrong errorMsg", "builder.32", e.getErrorId());
+
+ }
+ }
+
+ @Test
+ public void decBpkWrongTarget() throws InvalidKeyException {
+ String bpk = RandomStringUtils.randomAlphanumeric(25);
+ String target = RandomStringUtils.randomAlphanumeric(25);
+
+ try {
+ BpkBuilder.decryptBpk(bpk, target, keyPair.getPrivate());
+ Assert.fail("Wrong parameters not detected");
+
+ } catch (EaafBuilderException e) {
+ Assert.assertEquals("Wrong errorMsg", "builder.32", e.getErrorId());
+
+ }
+ }
+
+ @Test
+ public void decBpkWrongTargetInEncBpk() throws InvalidKeyException, EaafBuilderException {
+ String bpk = RandomStringUtils.randomAlphanumeric(25);
+ String target = EaafConstants.URN_PREFIX_CDID + "AA";
+
+ String encBpk = BpkBuilder.encryptBpk(bpk, target, keyPair.getPublic());
+ try {
+ BpkBuilder.decryptBpk(encBpk,
+ EaafConstants.URN_PREFIX_CDID + "BB", keyPair.getPrivate());
+ Assert.fail("Wrong parameters not detected");
+
+ } catch (EaafBuilderException e) {
+ Assert.assertEquals("Wrong errorMsg", "builder.30", e.getErrorId());
+
+ }
+ }
+
+ @Test
+ public void encBpkSuccess() throws EaafBuilderException, InvalidKeyException {
+ String bpk = RandomStringUtils.randomAlphanumeric(25);
+ String target = EaafConstants.URN_PREFIX_CDID + "AA";
+
+ String encBpk = BpkBuilder.encryptBpk(bpk, target, keyPair.getPublic());
+
+ Assert.assertNotNull("encBpk", encBpk);
+
+ Pair<String, String> decBpk = BpkBuilder.decryptBpk(encBpk, target, keyPair.getPrivate());
+
+ Assert.assertEquals("wrong bBK", bpk, decBpk.getFirst());
+ Assert.assertEquals("wrong bBK-Target", target, decBpk.getSecond());
+
+ }
+
+ @Test
+ public void encWbpkSuccess() throws EaafBuilderException, InvalidKeyException {
+ String bpk = RandomStringUtils.randomAlphanumeric(25);
+ String target = EaafConstants.URN_PREFIX_WBPK + "XFN+123456i";
+
+ String encBpk = BpkBuilder.encryptBpk(bpk, target, keyPair.getPublic());
+
+ Assert.assertNotNull("encBpk", encBpk);
+
+ Pair<String, String> decBpk = BpkBuilder.decryptBpk(encBpk, target, keyPair.getPrivate());
+
+ Assert.assertEquals("wrong bBK", bpk, decBpk.getFirst());
+ Assert.assertEquals("wrong bBK-Target", target, decBpk.getSecond());
+
+ }
+
+ @Test
+ public void encWbpkSuccessSecond() throws EaafBuilderException, InvalidKeyException {
+ String bpk = RandomStringUtils.randomAlphanumeric(25);
+ String target = EaafConstants.URN_PREFIX_WBPK + "FN+123456i";
+
+ String encBpk = BpkBuilder.encryptBpk(bpk, target, keyPair.getPublic());
+
+ Assert.assertNotNull("encBpk", encBpk);
+
+ Pair<String, String> decBpk = BpkBuilder.decryptBpk(encBpk,
+ EaafConstants.URN_PREFIX_WBPK + "XFN+123456i", keyPair.getPrivate());
+
+ Assert.assertEquals("wrong bBK", bpk, decBpk.getFirst());
+ Assert.assertEquals("wrong bBK-Target",
+ EaafConstants.URN_PREFIX_WBPK + "XFN+123456i", decBpk.getSecond());
+
+ }
+
+
+ @Test
+ public void noBaseId() {
+ try {
+ BpkBuilder.generateAreaSpecificPersonIdentifier(null, EaafConstants.URN_PREFIX_CDID + "AA");
+
+ } catch (EaafBuilderException e) {
+ Assert.assertEquals("Wrong errorCode", "builder.33", e.getErrorId());
+ }
+ }
+
+ @Test
+ public void noTarget() {
+ try {
+ BpkBuilder.generateAreaSpecificPersonIdentifier(BASEID, null);
+
+ } catch (EaafBuilderException e) {
+ Assert.assertEquals("Wrong errorCode", "builder.33", e.getErrorId());
+ }
+ }
+
+ @Test
+ public void noBaseIdType() {
+ try {
+ BpkBuilder.generateAreaSpecificPersonIdentifier(BASEID,
+ null, EaafConstants.URN_PREFIX_CDID + "AA");
+
+ } catch (EaafBuilderException e) {
+ Assert.assertEquals("Wrong errorCode", "builder.33", e.getErrorId());
+ }
+ }
+
+ @Test
+ public void wrongBaseIdType() {
+ try {
+ BpkBuilder.generateAreaSpecificPersonIdentifier(BASEID,
+ EaafConstants.URN_PREFIX_CDID + "BB", EaafConstants.URN_PREFIX_CDID + "AA");
+
+ } catch (EaafBuilderException e) {
+ Assert.assertEquals("Wrong errorCode", "builder.33", e.getErrorId());
+ }
+ }
+
+ @Test
+ public void baseIdTypeEqualsTarget() throws EaafBuilderException {
+ Pair<String, String> result1 = BpkBuilder.generateAreaSpecificPersonIdentifier(BASEID,
+ EaafConstants.URN_PREFIX_CDID + "AA", EaafConstants.URN_PREFIX_CDID + "AA");
+
+ Assert.assertEquals("first bPK", BASEID,
+ result1.getFirst());
+ Assert.assertEquals("first bPK", "urn:publicid:gv.at:cdid+AA",
+ result1.getSecond());
+
+ }
+
+ @Test
+ public void buildBpk() throws EaafBuilderException {
+
+ Pair<String, String> result1 = BpkBuilder.generateAreaSpecificPersonIdentifier(
+ BASEID, EaafConstants.URN_PREFIX_CDID + "AA");
+ Pair<String, String> result2 = BpkBuilder.generateAreaSpecificPersonIdentifier(
+ BASEID, EaafConstants.URN_PREFIX_CDID + "BB");
+
+ Assert.assertEquals("first bPK", "b1Ip610zZq/Or/uCqgb51lnAdZM=",
+ result1.getFirst());
+ Assert.assertEquals("first bPK", "urn:publicid:gv.at:cdid+AA",
+ result1.getSecond());
+
+ Assert.assertEquals("second bPK", "uYst6hjKJvyp7s/ezD8zsnkcj9k=",
+ result2.getFirst());
+ Assert.assertEquals("second bPK", "urn:publicid:gv.at:cdid+BB",
+ result2.getSecond());
+
+ }
+
+ @Test
+ public void buildWbpkFn() throws EaafBuilderException {
+
+ Pair<String, String> result1 = BpkBuilder.generateAreaSpecificPersonIdentifier(
+ BASEID, EaafConstants.URN_PREFIX_WBPK + "FN+123456i");
+
+ Assert.assertEquals("wbPK", "k65HRxpVcoZ2OPZHo3j2LEn/JQE=",
+ result1.getFirst());
+ Assert.assertEquals("wbPK", "urn:publicid:gv.at:wbpk+XFN+123456i",
+ result1.getSecond());
+
+ }
+
+ @Test
+ public void buildWbpkZvr() throws EaafBuilderException {
+
+ Pair<String, String> result1 = BpkBuilder.generateAreaSpecificPersonIdentifier(
+ BASEID, EaafConstants.URN_PREFIX_WBPK + "ZVR+123456");
+
+ Assert.assertEquals("wbPK", "1WvaBLiTxcc3kVzfB71Zh2sCtvA=",
+ result1.getFirst());
+ Assert.assertEquals("wbPK", "urn:publicid:gv.at:wbpk+XZVR+123456",
+ result1.getSecond());
+
+ }
+
+ @Test
+ public void buildWbpkErsb() throws EaafBuilderException {
+
+ Pair<String, String> result1 = BpkBuilder.generateAreaSpecificPersonIdentifier(
+ BASEID, EaafConstants.URN_PREFIX_WBPK + "ERSB+123456");
+
+ Assert.assertEquals("wbPK", "xtAWGAiblvhYJiCpUB3dwdRFPpg=",
+ result1.getFirst());
+ Assert.assertEquals("wbPK", "urn:publicid:gv.at:wbpk+XERSB+123456",
+ result1.getSecond());
+
+ }
+
+ @Test
+ public void buildWbpkXFn() throws EaafBuilderException {
+
+ Pair<String, String> result1 = BpkBuilder.generateAreaSpecificPersonIdentifier(
+ BASEID, EaafConstants.URN_PREFIX_WBPK + "XFN+123456i");
+
+ Assert.assertEquals("wbPK", "k65HRxpVcoZ2OPZHo3j2LEn/JQE=",
+ result1.getFirst());
+ Assert.assertEquals("wbPK", "urn:publicid:gv.at:wbpk+XFN+123456i",
+ result1.getSecond());
+
+ }
+
+ @Test
+ public void buildWbpkXZvr() throws EaafBuilderException {
+
+ Pair<String, String> result1 = BpkBuilder.generateAreaSpecificPersonIdentifier(
+ BASEID, EaafConstants.URN_PREFIX_WBPK + "XZVR+123456");
+
+ Assert.assertEquals("wbPK", "1WvaBLiTxcc3kVzfB71Zh2sCtvA=",
+ result1.getFirst());
+ Assert.assertEquals("wbPK", "urn:publicid:gv.at:wbpk+XZVR+123456",
+ result1.getSecond());
+
+ }
+
+ @Test
+ public void buildWbpkXErsb() throws EaafBuilderException {
+
+ Pair<String, String> result1 = BpkBuilder.generateAreaSpecificPersonIdentifier(
+ BASEID, EaafConstants.URN_PREFIX_WBPK + "XERSB+123456");
+
+ Assert.assertEquals("wbPK", "xtAWGAiblvhYJiCpUB3dwdRFPpg=",
+ result1.getFirst());
+ Assert.assertEquals("wbPK", "urn:publicid:gv.at:wbpk+XERSB+123456",
+ result1.getSecond());
+
+ }
+
+ @Test
+ public void buildWbpkOthers() throws EaafBuilderException {
+
+ Pair<String, String> result1 = BpkBuilder.generateAreaSpecificPersonIdentifier(
+ BASEID, EaafConstants.URN_PREFIX_WBPK + "XABC+123456");
+
+ Assert.assertEquals("wbPK", "wv96/xKUyi6YoYGv7IcIlFTsJIk=",
+ result1.getFirst());
+ Assert.assertEquals("wbPK", "urn:publicid:gv.at:wbpk+XABC+123456",
+ result1.getSecond());
+
+ }
+
+ @Test
+ public void buildEidasId() throws EaafBuilderException {
+
+ Pair<String, String> result1 = BpkBuilder.generateAreaSpecificPersonIdentifier(
+ BASEID, EaafConstants.URN_PREFIX_EIDAS + "AT+ES");
+
+ Assert.assertEquals("eidas", "AT/ES/7AuLZNKsiRr97yvLsQ16SZ6r0q0=",
+ result1.getFirst());
+ Assert.assertEquals("wbPK", "urn:publicid:gv.at:eidasid+AT+ES",
+ result1.getSecond());
+
+ }
+
+ @Test
+ public void normalizeNullTarget() {
+ Assert.assertNull("Wrong normalized target",
+ BpkBuilder.normalizeBpkTargetIdentifierToCommonFormat(null));
+
+ }
+
+ @Test
+ public void normalizeBpkTarget() {
+ String target = EaafConstants.URN_PREFIX_CDID + RandomStringUtils.randomAlphabetic(2);
+ Assert.assertEquals("Wrong normalized target",
+ target,
+ BpkBuilder.normalizeBpkTargetIdentifierToCommonFormat(target));
+
+ }
+
+ @Test
+ public void normalizeWbpkTargetWithX() {
+ String target = EaafConstants.URN_PREFIX_WBPK_TARGET_WITH_X + RandomStringUtils.randomAlphabetic(2);
+ Assert.assertEquals("Wrong normalized target",
+ target,
+ BpkBuilder.normalizeBpkTargetIdentifierToCommonFormat(target));
+
+ }
+
+ @Test
+ public void normalizeWbpkTargetWithOutXNoMapping() {
+ String target = EaafConstants.URN_PREFIX_WBPK + RandomStringUtils.randomAlphabetic(2);
+ Assert.assertEquals("Wrong normalized target",
+ target,
+ BpkBuilder.normalizeBpkTargetIdentifierToCommonFormat(target));
+
+ }
+
+ @Test
+ public void normalizeWbpkTargetWithOutXMappingFn() {
+ Assert.assertEquals("Wrong normalized target",
+ EaafConstants.URN_PREFIX_WBPK + "XFN+123456i",
+ BpkBuilder.normalizeBpkTargetIdentifierToCommonFormat(EaafConstants.URN_PREFIX_WBPK + "FN+123456i"));
+
+ }
+
+ @Test
+ public void normalizeWbpkTargetWithOutXMappingZvr() {
+ Assert.assertEquals("Wrong normalized target",
+ EaafConstants.URN_PREFIX_WBPK + "XZVR+1122334455",
+ BpkBuilder.normalizeBpkTargetIdentifierToCommonFormat(EaafConstants.URN_PREFIX_WBPK + "ZVR+1122334455"));
+
+ }
+
+ @Test
+ public void normalizeWbpkTargetWithOutXMappingErsb() {
+ Assert.assertEquals("Wrong normalized target",
+ EaafConstants.URN_PREFIX_WBPK + "XERSB+998877665544",
+ BpkBuilder.normalizeBpkTargetIdentifierToCommonFormat(EaafConstants.URN_PREFIX_WBPK + "ERSB+998877665544"));
+
+ }
+
+ @Test
+ public void normalizeEidasTarget() {
+ String target = EaafConstants.URN_PREFIX_EIDAS + RandomStringUtils.randomAlphabetic(2)
+ + "+" + RandomStringUtils.randomAlphabetic(2);
+ Assert.assertEquals("Wrong normalized target",
+ target,
+ BpkBuilder.normalizeBpkTargetIdentifierToCommonFormat(target));
+
+ }
+
+ @Test
+ public void calcNormalizeNullTarget() {
+ Assert.assertNull("Wrong normalized target",
+ BpkBuilder.normalizeBpkTargetIdentifierToNonXFormat(null));
+
+ }
+
+ @Test
+ public void calcNormalizeBpkTarget() {
+ String target = EaafConstants.URN_PREFIX_CDID + RandomStringUtils.randomAlphabetic(2);
+ Assert.assertEquals("Wrong normalized target",
+ target,
+ BpkBuilder.normalizeBpkTargetIdentifierToNonXFormat(target));
+
+ }
+
+ @Test
+ public void calcNormalizeWbpkTargetWithoutX() {
+
+ Assert.assertEquals("Wrong normalized target",
+ EaafConstants.URN_PREFIX_WBPK + "FN+123456i",
+ BpkBuilder.normalizeBpkTargetIdentifierToNonXFormat(EaafConstants.URN_PREFIX_WBPK + "FN+123456i"));
+
+ }
+
+ @Test
+ public void calcNormalizeWbpkTargetWithOutXNoMapping() {
+ String target = EaafConstants.URN_PREFIX_WBPK + RandomStringUtils.randomAlphabetic(2);
+ Assert.assertEquals("Wrong normalized target",
+ target,
+ BpkBuilder.normalizeBpkTargetIdentifierToNonXFormat(target));
+
+ }
+
+ @Test
+ public void calcNormalizeWbpkTargetWithXMappingFn() {
+ Assert.assertEquals("Wrong normalized target",
+ EaafConstants.URN_PREFIX_WBPK + "FN+123456i",
+ BpkBuilder.normalizeBpkTargetIdentifierToNonXFormat(EaafConstants.URN_PREFIX_WBPK + "XFN+123456i"));
+
+ }
+
+ @Test
+ public void calcNormalizeWbpkTargetWithXMappingZvr() {
+ Assert.assertEquals("Wrong normalized target",
+ EaafConstants.URN_PREFIX_WBPK + "ZVR+1122334455",
+ BpkBuilder.normalizeBpkTargetIdentifierToNonXFormat(EaafConstants.URN_PREFIX_WBPK + "XZVR+1122334455"));
+
+ }
+
+ @Test
+ public void calcNormalizeWbpkTargetWithXMappingErsb() {
+ Assert.assertEquals("Wrong normalized target",
+ EaafConstants.URN_PREFIX_WBPK + "ERSB+998877665544",
+ BpkBuilder.normalizeBpkTargetIdentifierToNonXFormat(
+ EaafConstants.URN_PREFIX_WBPK + "XERSB+998877665544"));
+
+ }
+
+ @Test
+ public void calcNormalizeEidasTarget() {
+ String target = EaafConstants.URN_PREFIX_EIDAS + RandomStringUtils.randomAlphabetic(2)
+ + "+" + RandomStringUtils.randomAlphabetic(2);
+ Assert.assertEquals("Wrong normalized target",
+ target,
+ BpkBuilder.normalizeBpkTargetIdentifierToNonXFormat(target));
+
+ }
+
+ @Test
+ public void removeBpkPrefix() {
+ String spTarget = RandomStringUtils.randomAlphabetic(2);
+ Assert.assertEquals("Wrong SP target without prefix",
+ spTarget,
+ BpkBuilder.removeBpkTypePrefix(EaafConstants.URN_PREFIX_CDID + spTarget));
+
+ }
+
+ @Test
+ public void removeWpbkPrefix() {
+ String spTarget = RandomStringUtils.randomAlphabetic(10);
+ Assert.assertEquals("Wrong SP target without prefix",
+ spTarget,
+ BpkBuilder.removeBpkTypePrefix(EaafConstants.URN_PREFIX_WBPK + spTarget));
+
+ }
+
+ @Test
+ public void removeEidasPbkPrefix() {
+ String spTarget = RandomStringUtils.randomAlphabetic(2) + "+" + RandomStringUtils.randomAlphabetic(2);
+ Assert.assertEquals("Wrong SP target without prefix",
+ spTarget,
+ BpkBuilder.removeBpkTypePrefix(EaafConstants.URN_PREFIX_EIDAS + spTarget));
+
+ }
+
+ @Test
+ public void removeUnknownPbkPrefix() {
+ String spTarget = RandomStringUtils.randomAlphabetic(10);
+ Assert.assertEquals("Wrong SP target without prefix",
+ EaafConstants.URN_PREFIX_BASEID + spTarget,
+ BpkBuilder.removeBpkTypePrefix(EaafConstants.URN_PREFIX_BASEID + spTarget));
+
+ }
+}
diff --git a/eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/test/credentials/EaafKeyStoreFactoryTest.java b/eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/test/credentials/EaafKeyStoreFactoryTest.java
index cefb1e7e..3e82c510 100644
--- a/eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/test/credentials/EaafKeyStoreFactoryTest.java
+++ b/eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/test/credentials/EaafKeyStoreFactoryTest.java
@@ -4,18 +4,23 @@ import java.security.Key;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.Provider;
+import java.security.Security;
import java.security.cert.X509Certificate;
import java.util.List;
+import javax.crypto.SecretKey;
+
import org.apache.commons.lang3.RandomStringUtils;
import org.junit.Assert;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.test.annotation.DirtiesContext;
+import org.springframework.test.annotation.DirtiesContext.ClassMode;
import org.springframework.test.annotation.DirtiesContext.MethodMode;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@@ -25,6 +30,7 @@ import com.google.common.base.Predicates;
import com.google.common.base.Throwables;
import com.google.common.collect.FluentIterable;
+import at.asitplus.hsmfacade.provider.HsmFacadeProvider;
import at.gv.egiz.eaaf.core.exception.EaafKeyAccessException;
import at.gv.egiz.eaaf.core.exceptions.EaafConfigurationException;
import at.gv.egiz.eaaf.core.exceptions.EaafException;
@@ -33,13 +39,15 @@ import at.gv.egiz.eaaf.core.impl.credential.EaafKeyStoreFactory;
import at.gv.egiz.eaaf.core.impl.credential.EaafKeyStoreUtils;
import at.gv.egiz.eaaf.core.impl.credential.KeyStoreConfiguration;
import at.gv.egiz.eaaf.core.impl.credential.KeyStoreConfiguration.KeyStoreType;
+import at.gv.egiz.eaaf.core.impl.credential.SymmetricKeyConfiguration;
+import at.gv.egiz.eaaf.core.impl.credential.SymmetricKeyConfiguration.SymmetricKeyType;
import at.gv.egiz.eaaf.core.impl.data.Pair;
import at.gv.egiz.eaaf.core.test.dummy.DummyAuthConfigMap;
import io.grpc.StatusRuntimeException;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("/spring/test_eaaf_pvp_lazy.beans.xml")
-@DirtiesContext(methodMode = MethodMode.BEFORE_METHOD)
+@DirtiesContext(classMode = ClassMode.BEFORE_EACH_TEST_METHOD)
public class EaafKeyStoreFactoryTest {
private static final String HSM_FACASE_HOST = "eid.a-sit.at";
@@ -66,14 +74,15 @@ public class EaafKeyStoreFactoryTest {
/**
* jUnit test set-up.
*/
- @Before
+ @Before
public void testSetup() {
mapConfig.clearAllConfig();
-
+ Security.removeProvider(HsmFacadeProvider.getInstance().getName());
+
}
@Test
- @DirtiesContext
+ @DirtiesContext(methodMode = MethodMode.BEFORE_METHOD)
public void startWithoutConfigHsmFacadeConfig() {
final EaafKeyStoreFactory keyStoreFactory = context.getBean(EaafKeyStoreFactory.class);
Assert.assertFalse("HSM Facade state wrong", keyStoreFactory.isHsmFacadeInitialized());
@@ -81,7 +90,7 @@ public class EaafKeyStoreFactoryTest {
}
@Test
- @DirtiesContext
+ @DirtiesContext(methodMode = MethodMode.BEFORE_METHOD)
public void buildyStoreWithOutConfig() {
final EaafKeyStoreFactory keyStoreFactory = context.getBean(EaafKeyStoreFactory.class);
Assert.assertFalse("HSM Facade state wrong", keyStoreFactory.isHsmFacadeInitialized());
@@ -99,7 +108,7 @@ public class EaafKeyStoreFactoryTest {
}
@Test
- @DirtiesContext
+ @DirtiesContext(methodMode = MethodMode.BEFORE_METHOD)
public void buildyStoreWithPkcs11() {
final EaafKeyStoreFactory keyStoreFactory = context.getBean(EaafKeyStoreFactory.class);
Assert.assertFalse("HSM Facade state wrong", keyStoreFactory.isHsmFacadeInitialized());
@@ -118,7 +127,7 @@ public class EaafKeyStoreFactoryTest {
}
@Test
- @DirtiesContext
+ @DirtiesContext(methodMode = MethodMode.BEFORE_METHOD)
public void softwareKeyStoreWithoutConfig() {
final EaafKeyStoreFactory keyStoreFactory = context.getBean(EaafKeyStoreFactory.class);
Assert.assertFalse("HSM Facade state wrong", keyStoreFactory.isHsmFacadeInitialized());
@@ -137,7 +146,7 @@ public class EaafKeyStoreFactoryTest {
}
@Test
- @DirtiesContext
+ @DirtiesContext(methodMode = MethodMode.BEFORE_METHOD)
public void softwareKeyStoreWithoutConfigSecond() {
final EaafKeyStoreFactory keyStoreFactory = context.getBean(EaafKeyStoreFactory.class);
Assert.assertFalse("HSM Facade state wrong", keyStoreFactory.isHsmFacadeInitialized());
@@ -156,7 +165,7 @@ public class EaafKeyStoreFactoryTest {
}
@Test
- @DirtiesContext
+ @DirtiesContext(methodMode = MethodMode.BEFORE_METHOD)
public void softwareKeyStoreWithoutPassword() {
final EaafKeyStoreFactory keyStoreFactory = context.getBean(EaafKeyStoreFactory.class);
Assert.assertFalse("HSM Facade state wrong", keyStoreFactory.isHsmFacadeInitialized());
@@ -177,7 +186,7 @@ public class EaafKeyStoreFactoryTest {
}
@Test
- @DirtiesContext
+ @DirtiesContext(methodMode = MethodMode.BEFORE_METHOD)
public void softwareKeyStoreWithoutPath() {
final EaafKeyStoreFactory keyStoreFactory = context.getBean(EaafKeyStoreFactory.class);
Assert.assertFalse("HSM Facade state wrong", keyStoreFactory.isHsmFacadeInitialized());
@@ -199,7 +208,7 @@ public class EaafKeyStoreFactoryTest {
}
@Test
- @DirtiesContext
+ @DirtiesContext(methodMode = MethodMode.BEFORE_METHOD)
public void softwareKeyStoreWithoutType() throws EaafException {
final EaafKeyStoreFactory keyStoreFactory = context.getBean(EaafKeyStoreFactory.class);
Assert.assertFalse("HSM Facade state wrong", keyStoreFactory.isHsmFacadeInitialized());
@@ -217,7 +226,7 @@ public class EaafKeyStoreFactoryTest {
}
@Test
- @DirtiesContext
+ @DirtiesContext(methodMode = MethodMode.BEFORE_METHOD)
public void softwareKeyStoreWithWrongPath() {
final EaafKeyStoreFactory keyStoreFactory = context.getBean(EaafKeyStoreFactory.class);
Assert.assertFalse("HSM Facade state wrong", keyStoreFactory.isHsmFacadeInitialized());
@@ -234,13 +243,13 @@ public class EaafKeyStoreFactoryTest {
} catch (final EaafException e) {
org.springframework.util.Assert.isInstanceOf(EaafConfigurationException.class, e, "Wong ExceptionType");
- Assert.assertEquals("wrong errorCode", "internal.keystore.05", e.getErrorId());
+ Assert.assertEquals("wrong errorCode", "internal.keystore.06", e.getErrorId());
}
}
@Test
- @DirtiesContext
+ @DirtiesContext(methodMode = MethodMode.BEFORE_METHOD)
public void softwareKeyStoreWithWrongPassword() {
final EaafKeyStoreFactory keyStoreFactory = context.getBean(EaafKeyStoreFactory.class);
Assert.assertFalse("HSM Facade state wrong", keyStoreFactory.isHsmFacadeInitialized());
@@ -263,7 +272,7 @@ public class EaafKeyStoreFactoryTest {
}
@Test
- @DirtiesContext
+ @DirtiesContext(methodMode = MethodMode.BEFORE_METHOD)
public void softwareKeyStoreSuccessJks() throws EaafException {
final EaafKeyStoreFactory keyStoreFactory = context.getBean(EaafKeyStoreFactory.class);
Assert.assertFalse("HSM Facade state wrong", keyStoreFactory.isHsmFacadeInitialized());
@@ -280,10 +289,13 @@ public class EaafKeyStoreFactoryTest {
Assert.assertNotNull("KeyStore is null", keyStore.getFirst());
Assert.assertNull("KeyStore is null", keyStore.getSecond());
+ Assert.assertEquals("Wrong HSM-Facade state", EaafKeyStoreFactory.HsmFacadeStatus.UNKNOWN,
+ keyStoreFactory.checkHsmFacadeStatus());
+
}
@Test
- @DirtiesContext
+ @DirtiesContext(methodMode = MethodMode.BEFORE_METHOD)
public void softwareKeyStoreAccessOperations() throws EaafException, KeyStoreException {
final EaafKeyStoreFactory keyStoreFactory = context.getBean(EaafKeyStoreFactory.class);
Assert.assertFalse("HSM Facade state wrong", keyStoreFactory.isHsmFacadeInitialized());
@@ -352,7 +364,7 @@ public class EaafKeyStoreFactoryTest {
}
@Test
- @DirtiesContext
+ @DirtiesContext(methodMode = MethodMode.BEFORE_METHOD)
public void softwareKeyStoreSuccessPkcs12() throws EaafException {
final EaafKeyStoreFactory keyStoreFactory = context.getBean(EaafKeyStoreFactory.class);
Assert.assertFalse("HSM Facade state wrong", keyStoreFactory.isHsmFacadeInitialized());
@@ -372,6 +384,75 @@ public class EaafKeyStoreFactoryTest {
}
@Test
+ @DirtiesContext(methodMode = MethodMode.BEFORE_METHOD)
+ public void symmetricSoftwareKeyWithOutConfig() {
+ final EaafKeyStoreFactory keyStoreFactory = context.getBean(EaafKeyStoreFactory.class);
+ Assert.assertFalse("HSM Facade state wrong", keyStoreFactory.isHsmFacadeInitialized());
+
+ SymmetricKeyConfiguration keyConfig = new SymmetricKeyConfiguration();
+ keyConfig.setFriendlyName("jUnit test");
+ keyConfig.setKeyType(SymmetricKeyType.PASSPHRASE);
+ try {
+ keyStoreFactory.buildNewSymmetricKey(keyConfig);
+ Assert.fail("Wrong config not detected");
+
+ } catch (final EaafException e) {
+ org.springframework.util.Assert.isInstanceOf(EaafConfigurationException.class, e, "Wong ExceptionType");
+ Assert.assertEquals("wrong errorCode", "internal.key.00", e.getErrorId());
+
+ }
+ }
+
+ @Test
+ @DirtiesContext(methodMode = MethodMode.BEFORE_METHOD)
+ public void symmetricSoftwareKeyWithOutSalt() {
+ final EaafKeyStoreFactory keyStoreFactory = context.getBean(EaafKeyStoreFactory.class);
+ Assert.assertFalse("HSM Facade state wrong", keyStoreFactory.isHsmFacadeInitialized());
+
+ SymmetricKeyConfiguration keyConfig = new SymmetricKeyConfiguration();
+ keyConfig.setFriendlyName("jUnit test");
+ keyConfig.setKeyType(SymmetricKeyType.PASSPHRASE);
+ keyConfig.setSoftKeyPassphrase(RandomStringUtils.randomAlphanumeric(10));
+ try {
+ keyStoreFactory.buildNewSymmetricKey(keyConfig);
+ Assert.fail("Wrong config not detected");
+
+ } catch (final EaafException e) {
+ org.springframework.util.Assert.isInstanceOf(EaafConfigurationException.class, e, "Wong ExceptionType");
+ Assert.assertEquals("wrong errorCode", "internal.key.00", e.getErrorId());
+
+ }
+ }
+
+ @Test
+ @DirtiesContext(methodMode = MethodMode.BEFORE_METHOD)
+ public void symmetricSoftwareKeyValid() throws EaafException {
+ final EaafKeyStoreFactory keyStoreFactory = context.getBean(EaafKeyStoreFactory.class);
+ Assert.assertFalse("HSM Facade state wrong", keyStoreFactory.isHsmFacadeInitialized());
+
+ SymmetricKeyConfiguration keyConfig = new SymmetricKeyConfiguration();
+ keyConfig.setFriendlyName("jUnit test");
+ keyConfig.setKeyType(SymmetricKeyType.PASSPHRASE);
+ keyConfig.setSoftKeyPassphrase(RandomStringUtils.randomAlphanumeric(10));
+ keyConfig.setSoftKeySalt(RandomStringUtils.randomAlphanumeric(10));
+
+ Pair<SecretKey, Provider> key = keyStoreFactory.buildNewSymmetricKey(keyConfig);
+ Assert.assertNotNull("Key container is null", key);
+ Assert.assertNotNull("Key is null", key.getFirst());
+ Assert.assertNull("Provider is not null", key.getSecond());
+
+ }
+
+ @Test
+ @DirtiesContext(methodMode = MethodMode.BEFORE_METHOD)
+ public void hsmFacadeNoHostConfig() {
+ context.getBean(EaafKeyStoreFactory.class);
+
+ }
+
+
+ @Test
+ @DirtiesContext(methodMode = MethodMode.BEFORE_METHOD)
public void hsmFacadeOnlyHostConfig() {
mapConfig.putConfigValue(EaafKeyStoreFactory.CONFIG_PROP_HSM_FACADE_HOST,
RandomStringUtils.randomNumeric(10));
@@ -386,6 +467,7 @@ public class EaafKeyStoreFactoryTest {
}
@Test
+ @DirtiesContext(methodMode = MethodMode.BEFORE_METHOD)
public void hsmFacadeMissingPort() {
mapConfig.putConfigValue(EaafKeyStoreFactory.CONFIG_PROP_HSM_FACADE_HOST,
RandomStringUtils.randomNumeric(10));
@@ -405,6 +487,7 @@ public class EaafKeyStoreFactoryTest {
}
@Test
+ @DirtiesContext(methodMode = MethodMode.BEFORE_METHOD)
public void hsmFacadeMissingUsername() {
mapConfig.putConfigValue(EaafKeyStoreFactory.CONFIG_PROP_HSM_FACADE_HOST,
RandomStringUtils.randomNumeric(10));
@@ -423,6 +506,7 @@ public class EaafKeyStoreFactoryTest {
}
@Test
+ @DirtiesContext(methodMode = MethodMode.BEFORE_METHOD)
public void hsmFacadeMissingPassword() {
mapConfig.putConfigValue(EaafKeyStoreFactory.CONFIG_PROP_HSM_FACADE_HOST,
RandomStringUtils.randomNumeric(10));
@@ -442,6 +526,7 @@ public class EaafKeyStoreFactoryTest {
}
@Test
+ @DirtiesContext(methodMode = MethodMode.BEFORE_METHOD)
public void hsmFacadeMissingTrustedCertificate() {
mapConfig.putConfigValue(EaafKeyStoreFactory.CONFIG_PROP_HSM_FACADE_HOST,
RandomStringUtils.randomNumeric(10));
@@ -463,6 +548,7 @@ public class EaafKeyStoreFactoryTest {
}
@Test
+ @DirtiesContext(methodMode = MethodMode.BEFORE_METHOD)
public void hsmFacadeMissingTrustedCertificateFile() {
mapConfig.putConfigValue(EaafKeyStoreFactory.CONFIG_PROP_HSM_FACADE_HOST,
RandomStringUtils.randomNumeric(10));
@@ -485,7 +571,8 @@ public class EaafKeyStoreFactoryTest {
}
}
- @Test
+ @Test
+ @DirtiesContext(methodMode = MethodMode.BEFORE_METHOD)
public void hsmFacadeMissingWrongTrustedCertificate() {
mapConfig.putConfigValue(EaafKeyStoreFactory.CONFIG_PROP_HSM_FACADE_HOST,
RandomStringUtils.randomNumeric(10));
@@ -508,8 +595,35 @@ public class EaafKeyStoreFactoryTest {
}
}
+ @Test
+ @DirtiesContext(methodMode = MethodMode.BEFORE_METHOD)
+ public void hsmFacadeWrongGrpcDeadlineParameter() {
+ mapConfig.putConfigValue(EaafKeyStoreFactory.CONFIG_PROP_HSM_FACADE_HOST,
+ RandomStringUtils.randomNumeric(10));
+ mapConfig.putConfigValue(EaafKeyStoreFactory.CONFIG_PROP_HSM_FACADE_PORT,
+ RandomStringUtils.randomNumeric(4));
+ mapConfig.putConfigValue(EaafKeyStoreFactory.CONFIG_PROP_HSM_FACADE_CLIENT_USERNAME,
+ RandomStringUtils.randomNumeric(10));
+ mapConfig.putConfigValue(EaafKeyStoreFactory.CONFIG_PROP_HSM_FACADE_CLIENT_PASSWORD,
+ RandomStringUtils.randomAlphanumeric(10));
+ mapConfig.putConfigValue(EaafKeyStoreFactory.CONFIG_PROP_HSM_FACADE_SSLTRUST,
+ "src/test/resources/spring/test_eaaf_pvp_lazy.beans.xml");
+ mapConfig.putConfigValue(EaafKeyStoreFactory.CONFIG_PROP_HSM_FACADE_GRPC_DEADLINE,
+ RandomStringUtils.randomAlphabetic(5));
+
+ try {
+ context.getBean(EaafKeyStoreFactory.class);
+ Assert.fail("Missing HSM Facade not detected");
+
+ } catch (final BeansException e) {
+ checkMissingConfigException(e, "internal.keystore.05");
+
+ }
+ }
+
+ @Ignore
@Test
- @DirtiesContext
+ @DirtiesContext(methodMode = MethodMode.BEFORE_METHOD)
public void hsmFacadeInitialized() {
mapConfig.putConfigValue(EaafKeyStoreFactory.CONFIG_PROP_HSM_FACADE_HOST,
RandomStringUtils.randomNumeric(10));
@@ -521,14 +635,54 @@ public class EaafKeyStoreFactoryTest {
RandomStringUtils.randomAlphanumeric(10));
mapConfig.putConfigValue(EaafKeyStoreFactory.CONFIG_PROP_HSM_FACADE_SSLTRUST,
PATH_TO_HSM_FACADE_TRUST_CERT);
+ mapConfig.putConfigValue(EaafKeyStoreFactory.CONFIG_PROP_HSM_FACADE_GRPC_DEADLINE,
+ RandomStringUtils.randomNumeric(2));
+
+ final EaafKeyStoreFactory keyStoreFactory = context.getBean(EaafKeyStoreFactory.class);
+ Assert.assertTrue("HSM Facade state wrong", keyStoreFactory.isHsmFacadeInitialized());
+ Assert.assertEquals("Wrong HSM-Facade state", EaafKeyStoreFactory.HsmFacadeStatus.UP,
+ keyStoreFactory.checkHsmFacadeStatus());
+
+ }
+
+ @Test
+ @DirtiesContext(methodMode = MethodMode.BEFORE_METHOD)
+ public void hsmFacadeHealthCheckNoProvider() {
+ mapConfig.putConfigValue(EaafKeyStoreFactory.CONFIG_PROP_HSM_FACADE_HOST,
+ RandomStringUtils.randomNumeric(10));
+ mapConfig.putConfigValue(EaafKeyStoreFactory.CONFIG_PROP_HSM_FACADE_PORT,
+ RandomStringUtils.randomNumeric(4));
+ mapConfig.putConfigValue(EaafKeyStoreFactory.CONFIG_PROP_HSM_FACADE_CLIENT_USERNAME,
+ RandomStringUtils.randomNumeric(10));
+ mapConfig.putConfigValue(EaafKeyStoreFactory.CONFIG_PROP_HSM_FACADE_CLIENT_PASSWORD,
+ RandomStringUtils.randomAlphanumeric(10));
+ mapConfig.putConfigValue(EaafKeyStoreFactory.CONFIG_PROP_HSM_FACADE_SSLTRUST,
+ PATH_TO_HSM_FACADE_TRUST_CERT);
final EaafKeyStoreFactory keyStoreFactory = context.getBean(EaafKeyStoreFactory.class);
Assert.assertTrue("HSM Facade state wrong", keyStoreFactory.isHsmFacadeInitialized());
+
+ Security.removeProvider("HsmFacade");
+ Assert.assertEquals("Wrong HSM-Facade state", EaafKeyStoreFactory.HsmFacadeStatus.DOWN,
+ keyStoreFactory.checkHsmFacadeStatus());
}
+
+ @Test
+ @DirtiesContext(methodMode = MethodMode.BEFORE_METHOD)
+ public void hsmFacadeAlreadLoaded() {
+ HsmFacadeProvider provider = HsmFacadeProvider.getInstance();
+ Security.addProvider(provider);
+
+ final EaafKeyStoreFactory keyStoreFactory = context.getBean(EaafKeyStoreFactory.class);
+ Assert.assertTrue("HSM Facade state wrong", keyStoreFactory.isHsmFacadeInitialized());
+ Assert.assertEquals("Wrong HSM-Facade state", EaafKeyStoreFactory.HsmFacadeStatus.UP,
+ keyStoreFactory.checkHsmFacadeStatus());
+ }
+
@Test
- @DirtiesContext
+ @DirtiesContext(methodMode = MethodMode.BEFORE_METHOD)
public void hsmFacadeKeyStoreNoKeyStoreName() {
configureHsmFacade();
@@ -550,7 +704,7 @@ public class EaafKeyStoreFactoryTest {
}
@Test
- @DirtiesContext
+ @DirtiesContext(methodMode = MethodMode.BEFORE_METHOD)
public void hsmFacadeKeyStoreSuccess() throws EaafException {
configureHsmFacade();
@@ -578,13 +732,106 @@ public class EaafKeyStoreFactoryTest {
}
@Test
- @DirtiesContext
- public void hsmFacadeKeyStoreSuccessASitTestFacade() throws EaafException, KeyStoreException {
+ @DirtiesContext(methodMode = MethodMode.BEFORE_METHOD)
+ public void symmetricHsmFacadeKeyWithOutConfig() {
configureHsmFacade();
+
+ final EaafKeyStoreFactory keyStoreFactory = context.getBean(EaafKeyStoreFactory.class);
+ Assert.assertTrue("HSM Facade state wrong", keyStoreFactory.isHsmFacadeInitialized());
+ SymmetricKeyConfiguration keyConfig = new SymmetricKeyConfiguration();
+ keyConfig.setFriendlyName("jUnit test");
+ keyConfig.setKeyType(SymmetricKeyType.HSMFACADE);
+ try {
+ keyStoreFactory.buildNewSymmetricKey(keyConfig);
+ Assert.fail("Wrong config not detected");
+
+ } catch (final EaafException e) {
+ org.springframework.util.Assert.isInstanceOf(EaafConfigurationException.class, e, "Wong ExceptionType");
+ Assert.assertEquals("wrong errorCode", "internal.keystore.06", e.getErrorId());
+
+ }
+ }
+
+ @Test
+ @DirtiesContext(methodMode = MethodMode.BEFORE_METHOD)
+ public void symmetricHsmFacadeKeyWithOutKeyAlias() {
+ configureHsmFacade();
+
final EaafKeyStoreFactory keyStoreFactory = context.getBean(EaafKeyStoreFactory.class);
Assert.assertTrue("HSM Facade state wrong", keyStoreFactory.isHsmFacadeInitialized());
+ SymmetricKeyConfiguration keyConfig = new SymmetricKeyConfiguration();
+ keyConfig.setFriendlyName("jUnit test");
+ keyConfig.setKeyType(SymmetricKeyType.HSMFACADE);
+ keyConfig.setKeyStoreName("authhandler");
+ try {
+ keyStoreFactory.buildNewSymmetricKey(keyConfig);
+ Assert.fail("Wrong config not detected");
+
+ } catch (final EaafException e) {
+ org.springframework.util.Assert.isInstanceOf(EaafConfigurationException.class, e, "Wong ExceptionType");
+ Assert.assertEquals("wrong errorCode", "internal.key.00", e.getErrorId());
+
+ }
+ }
+
+ @Test
+ @DirtiesContext(methodMode = MethodMode.BEFORE_METHOD)
+ public void symmetricHsmFacadeKeyWrongKeyAlias() {
+ configureHsmFacade();
+
+ final EaafKeyStoreFactory keyStoreFactory = context.getBean(EaafKeyStoreFactory.class);
+ Assert.assertTrue("HSM Facade state wrong", keyStoreFactory.isHsmFacadeInitialized());
+
+ SymmetricKeyConfiguration keyConfig = new SymmetricKeyConfiguration();
+ keyConfig.setFriendlyName("jUnit test");
+ keyConfig.setKeyType(SymmetricKeyType.HSMFACADE);
+ keyConfig.setKeyStoreName("authhandler");
+ keyConfig.setKeyAlias("notExist");
+
+ try {
+ keyStoreFactory.buildNewSymmetricKey(keyConfig);
+ Assert.fail("Wrong config not detected");
+
+ } catch (final EaafException e) {
+ org.springframework.util.Assert.isInstanceOf(EaafKeyAccessException.class, e, "Wong ExceptionType");
+ Assert.assertEquals("wrong errorCode", "internal.keystore.09", e.getErrorId());
+
+ }
+ }
+
+ @Test
+ @DirtiesContext(methodMode = MethodMode.BEFORE_METHOD)
+ public void symmetricHsmFacadeKeyValid() throws EaafException {
+ configureHsmFacade();
+
+ final EaafKeyStoreFactory keyStoreFactory = context.getBean(EaafKeyStoreFactory.class);
+ Assert.assertTrue("HSM Facade state wrong", keyStoreFactory.isHsmFacadeInitialized());
+
+ SymmetricKeyConfiguration keyConfig = new SymmetricKeyConfiguration();
+ keyConfig.setFriendlyName("jUnit test");
+ keyConfig.setKeyType(SymmetricKeyType.HSMFACADE);
+ keyConfig.setKeyStoreName("authhandler");
+ keyConfig.setKeyAlias("aes-key-1");
+
+ Pair<SecretKey, Provider> key = keyStoreFactory.buildNewSymmetricKey(keyConfig);
+ Assert.assertNotNull("Key container is null", key);
+ Assert.assertNotNull("Key is null", key.getFirst());
+ Assert.assertNotNull("Provider is null", key.getFirst());
+
+ }
+
+ @Test
+ @DirtiesContext(methodMode = MethodMode.BEFORE_METHOD)
+ public void hsmFacadeKeyStoreSuccessASitTestFacade() throws EaafException, KeyStoreException {
+ configureHsmFacade();
+
+ final EaafKeyStoreFactory keyStoreFactory = context.getBean(EaafKeyStoreFactory.class);
+ Assert.assertTrue("HSM Facade state wrong", keyStoreFactory.isHsmFacadeInitialized());
+ Assert.assertEquals("Wrong HSM-Facade state", EaafKeyStoreFactory.HsmFacadeStatus.UP,
+ keyStoreFactory.checkHsmFacadeStatus());
+
final KeyStoreConfiguration keyStoreConfig = new KeyStoreConfiguration();
keyStoreConfig.setKeyStoreType(KeyStoreType.HSMFACADE);
keyStoreConfig.setKeyStoreName("authhandler");
diff --git a/eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/test/credentials/EncryptionTask.java b/eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/test/credentials/EncryptionTask.java
new file mode 100644
index 00000000..ac456c13
--- /dev/null
+++ b/eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/test/credentials/EncryptionTask.java
@@ -0,0 +1,156 @@
+package at.gv.egiz.eaaf.core.test.credentials;
+
+import static org.junit.Assert.assertArrayEquals;
+
+import java.security.Provider;
+import java.util.concurrent.CompletableFuture;
+
+import javax.crypto.Cipher;
+import javax.crypto.SecretKey;
+import javax.crypto.spec.GCMParameterSpec;
+
+import org.apache.commons.lang3.RandomStringUtils;
+import org.junit.Assert;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.ApplicationContext;
+import org.springframework.scheduling.annotation.Async;
+import org.springframework.scheduling.annotation.AsyncResult;
+
+import at.gv.egiz.eaaf.core.exceptions.EaafException;
+import at.gv.egiz.eaaf.core.impl.credential.EaafKeyStoreFactory;
+import at.gv.egiz.eaaf.core.impl.credential.SymmetricKeyConfiguration;
+import at.gv.egiz.eaaf.core.impl.credential.SymmetricKeyConfiguration.SymmetricKeyType;
+import at.gv.egiz.eaaf.core.impl.data.Pair;
+import at.gv.egiz.eaaf.core.impl.utils.Random;
+import at.gv.egiz.eaaf.core.test.dummy.DummyAuthConfigMap;
+import lombok.Getter;
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+@Getter
+public class EncryptionTask implements Runnable {
+
+ private static final String HSM_FACASE_HOST = "eid.a-sit.at";
+ private static final String HSM_FACASE_PORT = "9050";
+ private static final String HSM_FACASE_SSL_TRUST = "src/test/resources/data/hsm_facade_trust_root.crt";
+ private static final String HSM_FACASE_USERNAME = "authhandler-junit";
+ private static final String HSM_FACASE_PASSWORD = "supersecret123";
+ private static final String PATH_TO_SOFTWARE_KEYSTORE_JKS_WITH_TRUSTED_CERTS =
+ "src/test/resources/data/junit.jks";
+ private static final String PATH_TO_SOFTWARE_KEYSTORE_JKS =
+ "src/test/resources/data/junit_without_trustcerts.jks";
+ private static final String PATH_TO_SOFTWARE_KEYSTORE_PKCS12 =
+ "src/test/resources/data/junit_without_trustcerts.p12";
+ private static final String SOFTWARE_KEYSTORE_PASSWORD = "password";
+
+ private static final String HSM_FACADE_KEY_ALIAS = "authhandler-sign";
+
+ private static final String CIPHER_MODE = "AES/GCM/NoPadding";
+ private static final int GCM_NONCE_LENGTH = 12; // in bytes
+ private static final int GCM_TAG_LENGTH = 16; // in bytes
+
+ protected static final String KEYNAME = "AES";
+
+ @Autowired
+ private DummyAuthConfigMap mapConfig;
+ @Autowired
+ private ApplicationContext context;
+
+ String keyName;
+ int rounds;
+ private Exception error;
+
+ public EncryptionTask(ApplicationContext context2, DummyAuthConfigMap mapConfig2,
+ String keyName, int rounds) {
+ this.context = context2;
+ this.mapConfig = mapConfig2;
+
+ this.keyName = keyName;
+ this.rounds = rounds;
+
+ }
+
+ @Override
+ public void run() {
+ run(this.keyName, this.rounds);
+
+ }
+
+ @Async
+ public CompletableFuture<String> run(String keyName, int rounds) {
+ try {
+ Pair<SecretKey, Provider> key = loadSymmetricKey(keyName);
+ Assert.assertNotNull("Key container is null", key);
+
+ for(int i = 0; i < rounds; i++) {
+
+ log.info("Starting threat: {} Round: {}", Thread.currentThread().getName(), i);
+
+ byte[] data = RandomStringUtils.randomAlphanumeric(1024*64).getBytes();
+ Pair<byte[], byte[]> enc = encryptData(key.getFirst(), data);
+
+ byte[] checkData = decryptData(enc, key.getFirst());
+ log.info("Finishing threat: {} Round: {}", Thread.currentThread().getName(), i);
+
+
+ assertArrayEquals("plaintext not match", data, checkData);
+
+
+
+ }
+
+ } catch (Exception e) {
+ this.error = e;
+ throw new RuntimeException(e);
+
+ }
+
+ return new AsyncResult<>("finished").completable();
+
+ }
+
+ private byte[] decryptData(Pair<byte[], byte[]> enc, SecretKey secret) throws Exception {
+ final GCMParameterSpec iv = new GCMParameterSpec(GCM_TAG_LENGTH * 8, enc.getSecond());
+ final Cipher cipher = Cipher.getInstance(CIPHER_MODE);
+ cipher.init(Cipher.DECRYPT_MODE, secret, iv);
+ return cipher.doFinal(enc.getFirst());
+
+ }
+
+
+
+ private Pair<byte[], byte[]> encryptData(SecretKey secret, byte[] toEncrypt) throws Exception {
+ final byte[] nonce = Random.nextBytes(GCM_NONCE_LENGTH);
+ final GCMParameterSpec spec = new GCMParameterSpec(GCM_TAG_LENGTH * 8, nonce);
+ final Cipher cipher = Cipher.getInstance(CIPHER_MODE);
+ cipher.init(Cipher.ENCRYPT_MODE, secret, spec);
+
+ final byte[] encdata = cipher.doFinal(toEncrypt);
+ final byte[] iv = cipher.getIV();
+
+ return Pair.newInstance(encdata, iv);
+
+ }
+
+ private Pair<SecretKey, Provider> loadSymmetricKey(String keyName) throws EaafException {
+ mapConfig.putConfigValue(EaafKeyStoreFactory.CONFIG_PROP_HSM_FACADE_HOST, HSM_FACASE_HOST);
+ mapConfig.putConfigValue(EaafKeyStoreFactory.CONFIG_PROP_HSM_FACADE_PORT, HSM_FACASE_PORT);
+ mapConfig.putConfigValue(EaafKeyStoreFactory.CONFIG_PROP_HSM_FACADE_SSLTRUST, HSM_FACASE_SSL_TRUST);
+ mapConfig.putConfigValue(EaafKeyStoreFactory.CONFIG_PROP_HSM_FACADE_CLIENT_USERNAME, HSM_FACASE_USERNAME);
+ mapConfig.putConfigValue(EaafKeyStoreFactory.CONFIG_PROP_HSM_FACADE_CLIENT_PASSWORD, HSM_FACASE_PASSWORD);
+
+ final EaafKeyStoreFactory keyStoreFactory = context.getBean(EaafKeyStoreFactory.class);
+ Assert.assertTrue("HSM Facade state wrong", keyStoreFactory.isHsmFacadeInitialized());
+
+ SymmetricKeyConfiguration keyConfig = new SymmetricKeyConfiguration();
+ keyConfig.setFriendlyName("jUnit test");
+ keyConfig.setKeyType(SymmetricKeyType.HSMFACADE);
+ keyConfig.setKeyStoreName("authhandler");
+ keyConfig.setKeyAlias(keyName);
+
+ return keyStoreFactory.buildNewSymmetricKey(keyConfig);
+ }
+
+
+
+}
diff --git a/eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/test/credentials/KeyOperationPerformanceTest.java b/eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/test/credentials/KeyOperationPerformanceTest.java
new file mode 100644
index 00000000..90d878b9
--- /dev/null
+++ b/eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/test/credentials/KeyOperationPerformanceTest.java
@@ -0,0 +1,155 @@
+package at.gv.egiz.eaaf.core.test.credentials;
+
+import static org.junit.Assert.assertFalse;
+
+import java.security.Provider;
+import java.security.Security;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import javax.crypto.SecretKey;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.ApplicationContext;
+import org.springframework.test.annotation.DirtiesContext;
+import org.springframework.test.annotation.DirtiesContext.ClassMode;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+
+import at.asitplus.hsmfacade.provider.HsmFacadeProvider;
+import at.gv.egiz.eaaf.core.exceptions.EaafException;
+import at.gv.egiz.eaaf.core.impl.credential.EaafKeyStoreFactory;
+import at.gv.egiz.eaaf.core.impl.credential.SymmetricKeyConfiguration;
+import at.gv.egiz.eaaf.core.impl.credential.SymmetricKeyConfiguration.SymmetricKeyType;
+import at.gv.egiz.eaaf.core.impl.data.Pair;
+import at.gv.egiz.eaaf.core.test.dummy.DummyAuthConfigMap;
+import lombok.extern.slf4j.Slf4j;
+
+@Ignore
+@RunWith(SpringJUnit4ClassRunner.class)
+@ContextConfiguration("/spring/test_eaaf_pvp_lazy.beans.xml")
+@DirtiesContext(classMode = ClassMode.BEFORE_EACH_TEST_METHOD)
+@Slf4j
+public class KeyOperationPerformanceTest {
+
+ private static final String HSM_FACASE_HOST = "eid.a-sit.at";
+ private static final String HSM_FACASE_PORT = "9050";
+ private static final String HSM_FACASE_SSL_TRUST = "src/test/resources/data/hsm_facade_trust_root.crt";
+ private static final String HSM_FACASE_USERNAME = "authhandler-junit";
+ private static final String HSM_FACASE_PASSWORD = "supersecret123";
+ private static final String PATH_TO_SOFTWARE_KEYSTORE_JKS_WITH_TRUSTED_CERTS =
+ "src/test/resources/data/junit.jks";
+ private static final String PATH_TO_SOFTWARE_KEYSTORE_JKS =
+ "src/test/resources/data/junit_without_trustcerts.jks";
+ private static final String PATH_TO_SOFTWARE_KEYSTORE_PKCS12 =
+ "src/test/resources/data/junit_without_trustcerts.p12";
+ private static final String SOFTWARE_KEYSTORE_PASSWORD = "password";
+
+ private static final String HSM_FACADE_KEY_ALIAS = "authhandler-sign";
+
+ private static final String CIPHER_MODE = "AES/GCM/NoPadding";
+ private static final int GCM_NONCE_LENGTH = 12; // in bytes
+ private static final int GCM_TAG_LENGTH = 16; // in bytes
+
+ protected static final String KEYNAME = "AES";
+
+
+ private static final String AES_KEY_1 = "aes-key-1";
+ private static final String AES_KEY_2 = "aes-key-2";
+
+ private static final List<String> ALL_AES_KEYS = Arrays.asList(AES_KEY_1, AES_KEY_2);
+
+ @Autowired
+ private DummyAuthConfigMap mapConfig;
+ @Autowired
+ private ApplicationContext context;
+
+ /**
+ * jUnit test set-up.
+ */
+ @Before
+ public void testSetup() {
+ mapConfig.clearAllConfig();
+ Security.removeProvider(HsmFacadeProvider.getInstance().getName());
+
+ }
+
+ @Ignore
+ @Test
+ public void symmetricHsmFacadeKeyLoad() throws EaafException {
+ Pair<SecretKey, Provider> key = loadSymmetricKey(AES_KEY_1);
+ Assert.assertNotNull("Key container is null", key);
+ Assert.assertNotNull("Key is null", key.getFirst());
+ Assert.assertNotNull("Provider is null", key.getFirst());
+
+ }
+
+
+ @Ignore
+ @Test
+ public void symmetricHsmFacadeKeyOperations() throws Exception {
+ Pair<SecretKey, Provider> key = loadSymmetricKey(AES_KEY_1);
+ Assert.assertNotNull("Key container is null", key);
+ new EncryptionTask(context, mapConfig, AES_KEY_2, 15).run(AES_KEY_2, 15);
+
+ }
+
+ @Test
+ public void symmetricHsmFacadeMultithreatKeyOperations() throws Exception {
+ Pair<SecretKey, Provider> key = loadSymmetricKey(AES_KEY_1);
+ Assert.assertNotNull("Key container is null", key);
+
+ int threads = 30;
+
+ ArrayList<EncryptionTask> taskList = new ArrayList<EncryptionTask>();
+ ArrayList<Thread> threadList = new ArrayList<Thread>();
+ for(int i=0; i < threads; i++){
+ EncryptionTask task = new EncryptionTask(context, mapConfig, ALL_AES_KEYS.get(i % 2), 20);
+ taskList.add(task);
+ Thread t = new Thread(task);
+ threadList.add(t);
+ t.start();
+ }
+
+ // wait until they are all done
+ log.trace("Wait for mandate sources .... ");
+ for(int i=0; i<threadList.size(); i++){
+ threadList.get(i).join();
+ }
+ log.trace("Mandate sources collection finished ");
+
+
+ assertFalse("Find Thread with error", taskList.stream()
+ .filter(el -> el.getError() != null)
+ .findFirst()
+ .isPresent());
+
+
+ }
+
+ private Pair<SecretKey, Provider> loadSymmetricKey(String keyName) throws EaafException {
+ mapConfig.putConfigValue(EaafKeyStoreFactory.CONFIG_PROP_HSM_FACADE_HOST, HSM_FACASE_HOST);
+ mapConfig.putConfigValue(EaafKeyStoreFactory.CONFIG_PROP_HSM_FACADE_PORT, HSM_FACASE_PORT);
+ mapConfig.putConfigValue(EaafKeyStoreFactory.CONFIG_PROP_HSM_FACADE_SSLTRUST, HSM_FACASE_SSL_TRUST);
+ mapConfig.putConfigValue(EaafKeyStoreFactory.CONFIG_PROP_HSM_FACADE_CLIENT_USERNAME, HSM_FACASE_USERNAME);
+ mapConfig.putConfigValue(EaafKeyStoreFactory.CONFIG_PROP_HSM_FACADE_CLIENT_PASSWORD, HSM_FACASE_PASSWORD);
+
+ final EaafKeyStoreFactory keyStoreFactory = context.getBean(EaafKeyStoreFactory.class);
+ Assert.assertTrue("HSM Facade state wrong", keyStoreFactory.isHsmFacadeInitialized());
+
+ SymmetricKeyConfiguration keyConfig = new SymmetricKeyConfiguration();
+ keyConfig.setFriendlyName("jUnit test");
+ keyConfig.setKeyType(SymmetricKeyType.HSMFACADE);
+ keyConfig.setKeyStoreName("authhandler");
+ keyConfig.setKeyAlias(keyName);
+
+ return keyStoreFactory.buildNewSymmetricKey(keyConfig);
+ }
+
+}
diff --git a/eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/test/credentials/SymmetricKeyConfigurationTest.java b/eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/test/credentials/SymmetricKeyConfigurationTest.java
new file mode 100644
index 00000000..eb4eb212
--- /dev/null
+++ b/eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/test/credentials/SymmetricKeyConfigurationTest.java
@@ -0,0 +1,162 @@
+package at.gv.egiz.eaaf.core.test.credentials;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.commons.lang3.RandomStringUtils;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.BlockJUnit4ClassRunner;
+
+import at.gv.egiz.eaaf.core.exceptions.EaafConfigurationException;
+import at.gv.egiz.eaaf.core.impl.credential.SymmetricKeyConfiguration;
+import at.gv.egiz.eaaf.core.impl.credential.SymmetricKeyConfiguration.SymmetricKeyType;
+
+@RunWith(BlockJUnit4ClassRunner.class)
+public class SymmetricKeyConfigurationTest {
+
+ private Map<String, String> config;
+
+ @Before
+ public void testSetup() {
+ config = new HashMap<>();
+
+ }
+
+ @Test
+ public void emptyConfigMap() {
+ try {
+ SymmetricKeyConfiguration.buildFromConfigurationMap(config, "jUnitTest");
+ Assert.fail("Wrong config not detected");
+
+ } catch (final EaafConfigurationException e) {
+ Assert.assertEquals("wrong errorCode", "internal.keystore.04", e.getErrorId());
+ }
+ }
+
+ @Test
+ public void emptyKeyType() {
+ try {
+ config.put("key.type", "");
+
+ SymmetricKeyConfiguration.buildFromConfigurationMap(config, "jUnitTest");
+ Assert.fail("Wrong config not detected");
+
+ } catch (final EaafConfigurationException e) {
+ Assert.assertEquals("wrong errorCode", "internal.keystore.04", e.getErrorId());
+ }
+ }
+
+ @Test
+ public void unknownKeyType() {
+ try {
+ config.put("key.type", "test");
+
+ SymmetricKeyConfiguration.buildFromConfigurationMap(config, "jUnitTest");
+ Assert.fail("Wrong config not detected");
+
+ } catch (final EaafConfigurationException e) {
+ Assert.assertEquals("wrong errorCode", "internal.keystore.01", e.getErrorId());
+ }
+ }
+
+ @Test
+ public void hsmFacadeKeyTypeMissingName() {
+ try {
+ config.put("key.type", "hsmfacade");
+
+ SymmetricKeyConfiguration.buildFromConfigurationMap(config, "jUnitTest");
+ Assert.fail("Wrong config not detected");
+
+ } catch (final EaafConfigurationException e) {
+ Assert.assertEquals("wrong errorCode", "internal.keystore.04", e.getErrorId());
+ }
+ }
+
+ @Test
+ public void hsmFacadeKeyTypeMissingAlias() {
+ try {
+ final String keyStoreName = RandomStringUtils.randomAlphabetic(5);
+ config.put("key.type", "hsmfacade");
+ config.put("keystore.name", keyStoreName);
+
+ SymmetricKeyConfiguration.buildFromConfigurationMap(config, "jUnitTest");
+ Assert.fail("Wrong config not detected");
+
+ } catch (final EaafConfigurationException e) {
+ Assert.assertEquals("wrong errorCode", "internal.keystore.04", e.getErrorId());
+ }
+ }
+
+ @Test
+ public void hsmFacadeKeyTypeSucces() throws EaafConfigurationException {
+ final String keyStoreName = RandomStringUtils.randomAlphabetic(5);
+ final String keyAlias = RandomStringUtils.randomAlphabetic(5);
+ config.put("key.type", "hsmfacade");
+ config.put("keystore.name", keyStoreName);
+ config.put("key.alias", keyAlias);
+
+ final SymmetricKeyConfiguration keyStoreConfig = SymmetricKeyConfiguration.buildFromConfigurationMap(config,
+ "jUnitTest");
+
+ Assert.assertNotNull("KeyStore config object", keyStoreConfig);
+ Assert.assertEquals("Wrong Type", SymmetricKeyType.HSMFACADE, keyStoreConfig.getKeyType());
+ Assert.assertEquals("Wrong KeyStoreName", keyStoreName, keyStoreConfig.getKeyStoreName());
+ Assert.assertEquals("Wrong KeyStoreName", keyAlias, keyStoreConfig.getKeyAlias());
+
+
+ keyStoreConfig.validate();
+
+ }
+
+ @Test
+ public void passphraseKeyTypeMissingPassphrase() {
+ try {
+ config.put("key.type", "passphrase");
+
+ SymmetricKeyConfiguration.buildFromConfigurationMap(config, "jUnitTest");
+ Assert.fail("Wrong config not detected");
+
+ } catch (final EaafConfigurationException e) {
+ Assert.assertEquals("wrong errorCode", "internal.keystore.04", e.getErrorId());
+ }
+ }
+
+ @Test
+ public void passphraseKeyTypeMissingSalt() {
+ try {
+ final String passphrase = RandomStringUtils.randomAlphabetic(5);
+ config.put("key.type", "passphrase");
+ config.put("key.passphrase", passphrase);
+
+ SymmetricKeyConfiguration.buildFromConfigurationMap(config, "jUnitTest");
+ Assert.fail("Wrong config not detected");
+
+ } catch (final EaafConfigurationException e) {
+ Assert.assertEquals("wrong errorCode", "internal.keystore.04", e.getErrorId());
+ }
+ }
+
+ @Test
+ public void passphraseKeyTypeSucces() throws EaafConfigurationException {
+ final String passphrase = RandomStringUtils.randomAlphabetic(5);
+ final String salt = RandomStringUtils.randomAlphabetic(5);
+ config.put("key.type", "passphrase");
+ config.put("key.passphrase", passphrase);
+ config.put("key.salt", salt);
+
+ final SymmetricKeyConfiguration keyStoreConfig = SymmetricKeyConfiguration.buildFromConfigurationMap(config,
+ "jUnitTest");
+
+ Assert.assertNotNull("KeyStore config object", keyStoreConfig);
+ Assert.assertEquals("Wrong Type", SymmetricKeyType.PASSPHRASE, keyStoreConfig.getKeyType());
+ Assert.assertEquals("Wrong KeyStoreName", passphrase, keyStoreConfig.getSoftKeyPassphrase());
+ Assert.assertEquals("Wrong KeyStoreName", salt, keyStoreConfig.getSoftKeySalt());
+
+ keyStoreConfig.validate();
+
+ }
+}
+
diff --git a/eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/test/dummy/DummyAuthConfigMap.java b/eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/test/dummy/DummyAuthConfigMap.java
index bf1dfd03..09301f57 100644
--- a/eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/test/dummy/DummyAuthConfigMap.java
+++ b/eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/test/dummy/DummyAuthConfigMap.java
@@ -123,7 +123,7 @@ public class DummyAuthConfigMap implements IConfigurationWithSP {
@Override
public String validateIdpUrl(final URL authReqUrl) throws EaafException {
- return null;
+ return authReqUrl.toExternalForm();
}
public void putConfigValue(final String key, final String value) {
diff --git a/eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/test/http/HttpClientFactoryProdHostTest.java b/eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/test/http/HttpClientFactoryProdHostTest.java
new file mode 100644
index 00000000..55c17ee8
--- /dev/null
+++ b/eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/test/http/HttpClientFactoryProdHostTest.java
@@ -0,0 +1,98 @@
+package at.gv.egiz.eaaf.core.test.http;
+
+import java.io.IOException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.Provider;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.X509Certificate;
+import java.util.Base64;
+
+import org.apache.http.client.ClientProtocolException;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpUriRequest;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.test.annotation.DirtiesContext;
+import org.springframework.test.annotation.DirtiesContext.MethodMode;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+
+import at.gv.egiz.eaaf.core.exceptions.EaafException;
+import at.gv.egiz.eaaf.core.impl.credential.EaafKeyStoreFactory;
+import at.gv.egiz.eaaf.core.impl.data.Pair;
+import at.gv.egiz.eaaf.core.impl.http.HttpClientConfiguration;
+import at.gv.egiz.eaaf.core.impl.http.IHttpClientFactory;
+import ch.qos.logback.classic.Level;
+import ch.qos.logback.classic.Logger;
+
+@RunWith(SpringJUnit4ClassRunner.class)
+@ContextConfiguration("/spring/test_eaaf_pvp_not_lazy.beans.xml")
+@DirtiesContext
+public class HttpClientFactoryProdHostTest {
+
+ @Autowired private IHttpClientFactory httpClientFactory;
+ @Autowired private EaafKeyStoreFactory keyStoreFactory;
+
+ /**
+ * Initialize full class.
+ */
+ @BeforeClass
+ public static void classInitializer() {
+ final Logger logger = (Logger) LoggerFactory.getLogger("org.bouncycastle.jsse");
+ logger.setLevel(Level.TRACE);
+
+ }
+
+ /**
+ * JUnit test set-up.
+ *
+ */
+ @Before
+ public void setup() {
+
+ }
+
+ @Test
+ @DirtiesContext(methodMode = MethodMode.BEFORE_METHOD)
+ public void getCustomClientX509AuthWithHsmFacadeTrustStore() throws EaafException, ClientProtocolException,
+ IOException, KeyStoreException, UnrecoverableKeyException, NoSuchAlgorithmException,
+ CertificateEncodingException {
+ System.setProperty("javax.net.debug", "ssl:handshake");
+
+ final HttpClientConfiguration clientConfig = new HttpClientConfiguration("jUnit-client");
+ clientConfig.setAuthMode("ssl");
+ //clientConfig.buildKeyStoreConfig("hsmfacade", null, null, "eid-junit");
+ //clientConfig.setSslKeyAlias("rsa-key-1");
+ clientConfig.buildKeyStoreConfig("hsmfacade", null, null, "authhandler");
+ clientConfig.setSslKeyAlias("authhandler-sign");
+ clientConfig.setDisableTlsHostCertificateValidation(false);
+
+ final CloseableHttpClient client = httpClientFactory.getHttpClient(clientConfig);
+ Assert.assertNotNull("httpClient", client);
+
+ final Pair<KeyStore, Provider> sslClientKeyStore =
+ keyStoreFactory.buildNewKeyStore(clientConfig.getKeyStoreConfig());
+ final X509Certificate clientRootCert = (X509Certificate) sslClientKeyStore.getFirst()
+ .getCertificateChain(clientConfig.getSslKeyAlias())[1];
+ final X509Certificate clientEeCert = (X509Certificate) sslClientKeyStore.getFirst()
+ .getCertificateChain(clientConfig.getSslKeyAlias())[0];
+ Base64.getEncoder().encodeToString(clientEeCert.getEncoded());
+
+ //perform test request
+ final HttpUriRequest httpGet2 = new HttpGet("https://apps.egiz.gv.at//sslclientcertdemo/");
+ final CloseableHttpResponse httpResp2 = client.execute(httpGet2);
+ Assert.assertEquals("http statusCode", 200, httpResp2.getStatusLine().getStatusCode());
+
+ }
+
+}
diff --git a/eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/test/http/HttpClientFactoryTest.java b/eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/test/http/HttpClientFactoryTest.java
index 25bd3008..c71d8352 100644
--- a/eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/test/http/HttpClientFactoryTest.java
+++ b/eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/test/http/HttpClientFactoryTest.java
@@ -1,42 +1,66 @@
package at.gv.egiz.eaaf.core.test.http;
+import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.InetAddress;
+import java.net.SocketTimeoutException;
+import java.security.Key;
+import java.security.KeyPair;
import java.security.KeyStore;
import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
import java.security.Provider;
+import java.security.UnrecoverableKeyException;
import java.security.cert.X509Certificate;
import org.apache.commons.lang3.RandomStringUtils;
+import org.apache.http.StatusLine;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpUriRequest;
+import org.apache.http.entity.ContentType;
import org.apache.http.impl.client.CloseableHttpClient;
import org.junit.After;
+import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.Before;
+import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.test.annotation.DirtiesContext;
+import org.springframework.test.annotation.DirtiesContext.MethodMode;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import at.gv.egiz.eaaf.core.exceptions.EaafException;
import at.gv.egiz.eaaf.core.impl.credential.EaafKeyStoreFactory;
+import at.gv.egiz.eaaf.core.impl.credential.KeyStoreConfiguration;
+import at.gv.egiz.eaaf.core.impl.credential.KeyStoreConfiguration.KeyStoreType;
import at.gv.egiz.eaaf.core.impl.data.Pair;
+import at.gv.egiz.eaaf.core.impl.data.Triple;
import at.gv.egiz.eaaf.core.impl.http.HttpClientConfiguration;
+import at.gv.egiz.eaaf.core.impl.http.HttpUtils;
import at.gv.egiz.eaaf.core.impl.http.IHttpClientFactory;
+import at.gv.egiz.eaaf.core.impl.utils.StreamUtils;
+import ch.qos.logback.classic.Level;
+import ch.qos.logback.classic.Logger;
import okhttp3.HttpUrl;
import okhttp3.mockwebserver.MockResponse;
import okhttp3.mockwebserver.MockWebServer;
import okhttp3.mockwebserver.RecordedRequest;
+import okhttp3.mockwebserver.SocketPolicy;
import okhttp3.tls.HandshakeCertificates;
import okhttp3.tls.HeldCertificate;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("/spring/test_eaaf_pvp_not_lazy.beans.xml")
+@DirtiesContext
public class HttpClientFactoryTest {
@Autowired private EaafKeyStoreFactory keyStoreFactory;
@@ -46,6 +70,27 @@ public class HttpClientFactoryTest {
private HttpUrl mockServerUrl;
/**
+ * Initialize full class.
+ */
+ @BeforeClass
+ public static void classInitializer() {
+ final Logger logger = (Logger) LoggerFactory.getLogger("org.bouncycastle.jsse");
+ logger.setLevel(Level.TRACE);
+
+ }
+
+ /**
+ * Reset test environment.
+ */
+ @AfterClass
+ public static void classReset() {
+ System.clearProperty("javax.net.ssl.trustStoreType");
+ System.clearProperty("javax.net.ssl.trustStore");
+ System.clearProperty("javax.net.ssl.trustStorePassword");
+
+ }
+
+ /**
* JUnit test set-up.
*
*/
@@ -84,6 +129,27 @@ public class HttpClientFactoryTest {
}
@Test
+ public void defaultHttpClientRetryOneTime() throws EaafException, InterruptedException,
+ ClientProtocolException, IOException {
+ final CloseableHttpClient client = httpClientFactory.getHttpClient();
+ Assert.assertNotNull("No httpClient", client);
+
+ mockWebServer = new MockWebServer();
+ mockServerUrl = mockWebServer.url("/sp/junit");
+ mockWebServer.enqueue(new MockResponse()
+ .setSocketPolicy(SocketPolicy.NO_RESPONSE)
+ .setResponseCode(HttpURLConnection.HTTP_NO_CONTENT));
+ mockWebServer.enqueue(new MockResponse().setResponseCode(200)
+ .setBody("GetData"));
+
+ //request webservice
+ final HttpUriRequest httpGet1 = new HttpGet(mockServerUrl.url().toString());
+ final CloseableHttpResponse httpResp1 = client.execute(httpGet1);
+ Assert.assertEquals("http statusCode", 200, httpResp1.getStatusLine().getStatusCode());
+
+ }
+
+ @Test
public void getCustomClientsDefault() throws EaafException {
final HttpClientConfiguration config = new HttpClientConfiguration("jUnit");
Assert.assertFalse("Wrong default config - Hostnamevalidation",
@@ -109,7 +175,7 @@ public class HttpClientFactoryTest {
}
@Test
- public void getCustomClientBasicAuth() throws EaafException, ClientProtocolException,
+ public void getCustomClientBasicAuth() throws EaafException, ClientProtocolException,
IOException, InterruptedException {
final HttpClientConfiguration config = new HttpClientConfiguration("jUnit");
config.setAuthMode("password");
@@ -157,6 +223,193 @@ public class HttpClientFactoryTest {
}
@Test
+ public void httpPostRetryNotAllowed() throws EaafException, InterruptedException,
+ ClientProtocolException, IOException {
+ final HttpClientConfiguration config =
+ new HttpClientConfiguration("jUnit_retry_" + RandomStringUtils.randomAlphabetic(3));
+ config.setHttpErrorRetryCount(2);
+ config.setHttpErrorRetryPost(false);
+
+ final CloseableHttpClient client = httpClientFactory.getHttpClient(config);
+ Assert.assertNotNull("No httpClient", client);
+
+
+ mockWebServer = new MockWebServer();
+ mockServerUrl = mockWebServer.url("/sp/junit");
+ mockWebServer.enqueue(new MockResponse()
+ .setSocketPolicy(SocketPolicy.NO_RESPONSE)
+ .setResponseCode(HttpURLConnection.HTTP_NO_CONTENT));
+ mockWebServer.enqueue(new MockResponse().setResponseCode(200)
+ .setBody("GetData"));
+
+ //request webservice
+ final HttpUriRequest httpGet1 = new HttpPost(mockServerUrl.url().toString());
+ try {
+ client.execute(httpGet1);
+ Assert.fail("HTTP POST retry not allowed");
+
+ } catch (final SocketTimeoutException e) {
+ Assert.assertNotNull("No errorMsg", e.getMessage());
+
+ }
+
+ }
+
+ @Test
+ public void httpPostRetryOneTime() throws EaafException, InterruptedException,
+ ClientProtocolException, IOException {
+ final HttpClientConfiguration config =
+ new HttpClientConfiguration("jUnit_retry_" + RandomStringUtils.randomAlphabetic(3));
+ config.setHttpErrorRetryCount(2);
+ config.setHttpErrorRetryPost(true);
+
+ final CloseableHttpClient client = httpClientFactory.getHttpClient(config);
+ Assert.assertNotNull("No httpClient", client);
+
+
+ mockWebServer = new MockWebServer();
+ mockServerUrl = mockWebServer.url("/sp/junit");
+ mockWebServer.enqueue(new MockResponse()
+ .setSocketPolicy(SocketPolicy.NO_RESPONSE)
+ .setResponseCode(HttpURLConnection.HTTP_NO_CONTENT));
+ mockWebServer.enqueue(new MockResponse().setResponseCode(200)
+ .setBody("GetData"));
+
+ //request webservice
+ final HttpUriRequest httpGet1 = new HttpPost(mockServerUrl.url().toString());
+ final StatusLine httpResp1 = client.execute(httpGet1,
+ HttpUtils.simpleStatusCodeResponseHandler());
+ Assert.assertEquals("http statusCode", 200, httpResp1.getStatusCode());
+
+ }
+
+ @Test
+ public void testHttpClientRetryOneTime() throws EaafException, InterruptedException,
+ ClientProtocolException, IOException {
+ final HttpClientConfiguration config =
+ new HttpClientConfiguration("jUnit_retry_" + RandomStringUtils.randomAlphabetic(3));
+ config.setHttpErrorRetryCount(2);
+
+ final CloseableHttpClient client = httpClientFactory.getHttpClient(config);
+ Assert.assertNotNull("No httpClient", client);
+
+
+ mockWebServer = new MockWebServer();
+ mockServerUrl = mockWebServer.url("/sp/junit");
+ mockWebServer.enqueue(new MockResponse()
+ .setSocketPolicy(SocketPolicy.NO_RESPONSE)
+ .setResponseCode(HttpURLConnection.HTTP_NO_CONTENT));
+
+ String bodyData = RandomStringUtils.randomAlphanumeric(10);
+ mockWebServer.enqueue(new MockResponse().setResponseCode(200)
+ .setBody(bodyData));
+
+ //request webservice
+ final HttpUriRequest httpGet1 = new HttpGet(mockServerUrl.url().toString());
+ final Triple<StatusLine, ByteArrayInputStream, ContentType> httpResp1 = client.execute(httpGet1,
+ HttpUtils.bodyStatusCodeResponseHandler());
+ Assert.assertEquals("http statusCode", 200, httpResp1.getFirst().getStatusCode());
+ Assert.assertEquals("http statusCode", bodyData, new String(StreamUtils.readStream(httpResp1.getSecond())));
+
+
+ }
+
+ @Test
+ public void testHttpClientRetryTwoTime() throws EaafException, InterruptedException,
+ ClientProtocolException, IOException {
+ final HttpClientConfiguration config =
+ new HttpClientConfiguration("jUnit_retry_" + RandomStringUtils.randomAlphabetic(3));
+ config.setHttpErrorRetryCount(2);
+
+ final CloseableHttpClient client = httpClientFactory.getHttpClient(config);
+ Assert.assertNotNull("No httpClient", client);
+
+
+ mockWebServer = new MockWebServer();
+ mockServerUrl = mockWebServer.url("/sp/junit");
+ mockWebServer.enqueue(new MockResponse()
+ .setSocketPolicy(SocketPolicy.NO_RESPONSE)
+ .setResponseCode(HttpURLConnection.HTTP_NO_CONTENT));
+ mockWebServer.enqueue(new MockResponse()
+ .setSocketPolicy(SocketPolicy.NO_RESPONSE)
+ .setResponseCode(HttpURLConnection.HTTP_NO_CONTENT));
+ mockWebServer.enqueue(new MockResponse().setResponseCode(200)
+ .setBody("GetData"));
+
+ //request webservice
+ final HttpUriRequest httpGet1 = new HttpGet(mockServerUrl.url().toString());
+ final CloseableHttpResponse httpResp1 = client.execute(httpGet1);
+ Assert.assertEquals("http statusCode", 200, httpResp1.getStatusLine().getStatusCode());
+
+ }
+
+ @Test
+ public void testHttpClientRetryMaxReached() throws EaafException, InterruptedException,
+ ClientProtocolException, IOException {
+ final HttpClientConfiguration config =
+ new HttpClientConfiguration("jUnit_retry_" + RandomStringUtils.randomAlphabetic(3));
+ config.setHttpErrorRetryCount(2);
+
+ final CloseableHttpClient client = httpClientFactory.getHttpClient(config);
+ Assert.assertNotNull("No httpClient", client);
+
+ mockWebServer = new MockWebServer();
+ mockServerUrl = mockWebServer.url("/sp/junit");
+ mockWebServer.enqueue(new MockResponse()
+ .setSocketPolicy(SocketPolicy.NO_RESPONSE)
+ .setResponseCode(HttpURLConnection.HTTP_NO_CONTENT));
+ mockWebServer.enqueue(new MockResponse()
+ .setSocketPolicy(SocketPolicy.NO_RESPONSE)
+ .setResponseCode(HttpURLConnection.HTTP_NO_CONTENT));
+ mockWebServer.enqueue(new MockResponse()
+ .setSocketPolicy(SocketPolicy.NO_RESPONSE)
+ .setResponseCode(HttpURLConnection.HTTP_NO_CONTENT));
+ mockWebServer.enqueue(new MockResponse().setResponseCode(200)
+ .setBody("GetData"));
+
+ //request webservice
+ final HttpUriRequest httpGet1 = new HttpGet(mockServerUrl.url().toString());
+ try {
+ client.execute(httpGet1);
+ Assert.fail("Max retry failed");
+
+ } catch (final SocketTimeoutException e) {
+ Assert.assertNotNull("No errorMsg", e.getMessage());
+
+ }
+ }
+
+ @Test
+ public void testHttpClientNoRetry() throws EaafException, InterruptedException,
+ ClientProtocolException, IOException {
+ final HttpClientConfiguration config =
+ new HttpClientConfiguration("jUnit_retry_" + RandomStringUtils.randomAlphabetic(3));
+ config.setHttpErrorRetryCount(0);
+
+ final CloseableHttpClient client = httpClientFactory.getHttpClient(config);
+ Assert.assertNotNull("No httpClient", client);
+
+ mockWebServer = new MockWebServer();
+ mockServerUrl = mockWebServer.url("/sp/junit");
+ mockWebServer.enqueue(new MockResponse()
+ .setSocketPolicy(SocketPolicy.NO_RESPONSE)
+ .setResponseCode(HttpURLConnection.HTTP_NO_CONTENT));
+ mockWebServer.enqueue(new MockResponse().setResponseCode(200)
+ .setBody("GetData"));
+
+ //request webservice
+ final HttpUriRequest httpGet1 = new HttpGet(mockServerUrl.url().toString());
+ try {
+ client.execute(httpGet1);
+ Assert.fail("Max retry failed");
+
+ } catch (final SocketTimeoutException e) {
+ Assert.assertNotNull("No errorMsg", e.getMessage());
+
+ }
+ }
+
+ @Test
public void getCustomClientBasicAuthNoPassword() throws EaafException {
final HttpClientConfiguration config = new HttpClientConfiguration("jUnit");
config.setAuthMode("password");
@@ -283,7 +536,7 @@ public class HttpClientFactoryTest {
}
@Test
- public void getCustomClientX509AuthWithWrongAlias() throws EaafException, KeyStoreException,
+ public void getCustomClientX509AuthWithWrongAlias() throws EaafException, KeyStoreException,
ClientProtocolException, IOException {
final HttpClientConfiguration config = new HttpClientConfiguration("jUnit");
config.setAuthMode("ssl");
@@ -311,9 +564,120 @@ public class HttpClientFactoryTest {
final HandshakeCertificates serverCertificates = new HandshakeCertificates.Builder()
.addTrustedCertificate(
(X509Certificate) sslClientKeyStore.getFirst().getCertificate("meta"))
+ .addTrustedCertificate(
+ (X509Certificate) sslClientKeyStore.getFirst().getCertificate("sig"))
+ .heldCertificate(localhostCertificate)
+ .build();
+ mockWebServer = new MockWebServer();
+ mockWebServer.useHttps(serverCertificates.sslSocketFactory(), false);
+ mockWebServer.requireClientAuth();
+ mockWebServer.enqueue(new MockResponse().setResponseCode(200)
+ .setBody("Successful auth!"));
+ mockServerUrl = mockWebServer.url("/sp/junit");
+
+ //perform test request
+ final HttpUriRequest httpGet2 = new HttpGet(mockServerUrl.url().toString());
+ final CloseableHttpResponse httpResp2 = client.execute(httpGet2);
+ Assert.assertEquals("http statusCode", 200, httpResp2.getStatusLine().getStatusCode());
+
+ }
+
+ @Test
+ @DirtiesContext(methodMode = MethodMode.BEFORE_METHOD)
+ public void getCustomClientX509AuthWithHsmFacade() throws EaafException, ClientProtocolException,
+ IOException, KeyStoreException {
+ final HttpClientConfiguration clientConfig = new HttpClientConfiguration("jUnit-client");
+ clientConfig.setAuthMode("ssl");
+ clientConfig.buildKeyStoreConfig("hsmfacade", null, null, "authhandler");
+ clientConfig.setSslKeyAlias("authhandler-sign");
+ clientConfig.setDisableTlsHostCertificateValidation(true);
+
+
+
+ final CloseableHttpClient client = httpClientFactory.getHttpClient(clientConfig);
+ Assert.assertNotNull("httpClient", client);
+
+ //set-up mock-up web-server with SSL client authentication
+ final Pair<KeyStore, Provider> sslClientKeyStore =
+ keyStoreFactory.buildNewKeyStore(clientConfig.getKeyStoreConfig());
+ final X509Certificate clientRootCert = (X509Certificate) sslClientKeyStore.getFirst()
+ .getCertificateChain(clientConfig.getSslKeyAlias())[1];
+ final X509Certificate clientEeCert = (X509Certificate) sslClientKeyStore.getFirst()
+ .getCertificateChain(clientConfig.getSslKeyAlias())[0];
+
+ final String localhost = InetAddress.getByName("localhost").getCanonicalHostName();
+ final HeldCertificate localhostCertificate = new HeldCertificate.Builder()
+ .addSubjectAlternativeName(localhost)
+ .build();
+ final HandshakeCertificates serverCertificates = new HandshakeCertificates.Builder()
+ .addTrustedCertificate(clientEeCert)
+ .addTrustedCertificate(clientRootCert)
+ .heldCertificate(localhostCertificate)
+ .build();
+ mockWebServer = new MockWebServer();
+ mockWebServer.useHttps(serverCertificates.sslSocketFactory(), false);
+ mockWebServer.requireClientAuth();
+ mockWebServer.enqueue(new MockResponse().setResponseCode(200)
+ .setBody("Successful auth!"));
+ mockServerUrl = mockWebServer.url("/sp/junit");
+
+ //perform test request
+ final HttpUriRequest httpGet2 = new HttpGet(mockServerUrl.url().toString());
+ final CloseableHttpResponse httpResp2 = client.execute(httpGet2);
+ Assert.assertEquals("http statusCode", 200, httpResp2.getStatusLine().getStatusCode());
+
+ }
+
+ @Test
+ @DirtiesContext(methodMode = MethodMode.BEFORE_METHOD)
+ public void getCustomClientX509AuthWithHsmFacadeTrustStore() throws EaafException, ClientProtocolException,
+ IOException, KeyStoreException, UnrecoverableKeyException, NoSuchAlgorithmException {
+
+ final String current = new java.io.File(".").getCanonicalPath();
+ System.setProperty("javax.net.ssl.trustStoreType", "jks");
+ System.setProperty("javax.net.ssl.trustStore",
+ current + "/src/test/resources/data/ssL_truststore.jks");
+ System.setProperty("javax.net.ssl.trustStorePassword",
+ "password");
+
+ final KeyStoreConfiguration sslServerCertConfig = new KeyStoreConfiguration();
+ sslServerCertConfig.setKeyStoreType(KeyStoreType.JKS);
+ sslServerCertConfig.setFriendlyName("SSL host cert");
+ sslServerCertConfig.setSoftKeyStoreFilePath("src/test/resources/data/ssl_host.jks");
+ sslServerCertConfig.setSoftKeyStorePassword("password");
+
+ Pair<KeyStore, Provider> sslServerHostKeyStore =
+ keyStoreFactory.buildNewKeyStore(sslServerCertConfig);
+
+
+ final HttpClientConfiguration clientConfig = new HttpClientConfiguration("jUnit-client");
+ clientConfig.setAuthMode("ssl");
+ clientConfig.buildKeyStoreConfig("hsmfacade", null, null, "authhandler");
+ clientConfig.setSslKeyAlias("authhandler-sign");
+ clientConfig.setDisableTlsHostCertificateValidation(false);
+
+ final CloseableHttpClient client = httpClientFactory.getHttpClient(clientConfig);
+ Assert.assertNotNull("httpClient", client);
+
+ //set-up mock-up web-server with SSL client authentication
+ final Pair<KeyStore, Provider> sslClientKeyStore =
+ keyStoreFactory.buildNewKeyStore(clientConfig.getKeyStoreConfig());
+ final X509Certificate clientRootCert = (X509Certificate) sslClientKeyStore.getFirst()
+ .getCertificateChain(clientConfig.getSslKeyAlias())[1];
+ final X509Certificate clientEeCert = (X509Certificate) sslClientKeyStore.getFirst()
+ .getCertificateChain(clientConfig.getSslKeyAlias())[0];
+
+ Key sslKey = sslServerHostKeyStore.getFirst().getKey("ssl", "password".toCharArray());
+ X509Certificate sslCert = (X509Certificate) sslServerHostKeyStore.getFirst().getCertificate("ssl");
+ KeyPair keyPair = new KeyPair(sslCert.getPublicKey(), (PrivateKey) sslKey);
+ HeldCertificate localhostCertificate = new HeldCertificate(keyPair, sslCert);
+ final HandshakeCertificates serverCertificates = new HandshakeCertificates.Builder()
+ .addTrustedCertificate(clientEeCert)
+ .addTrustedCertificate(clientRootCert)
.heldCertificate(localhostCertificate)
.build();
mockWebServer = new MockWebServer();
+
mockWebServer.useHttps(serverCertificates.sslSocketFactory(), false);
mockWebServer.requireClientAuth();
mockWebServer.enqueue(new MockResponse().setResponseCode(200)
@@ -326,4 +690,5 @@ public class HttpClientFactoryTest {
Assert.assertEquals("http statusCode", 200, httpResp2.getStatusLine().getStatusCode());
}
+
}
diff --git a/eaaf_core_utils/src/test/resources/data/config1.properties b/eaaf_core_utils/src/test/resources/data/config1.properties
new file mode 100644
index 00000000..12209d21
--- /dev/null
+++ b/eaaf_core_utils/src/test/resources/data/config1.properties
@@ -0,0 +1,15 @@
+security.hsmfacade.host=eid.a-sit.at
+security.hsmfacade.port=9050
+security.hsmfacade.trustedsslcert=src/test/resources/data/hsm_facade_trust_root.crt
+security.hsmfacade.username=authhandler-junit
+security.hsmfacade.password=supersecret123
+
+client.http.connection.timeout.socket=2
+client.http.connection.timeout.connection=2
+client.http.connection.timeout.request=2
+
+core.pendingrequestid.maxlifetime=180
+core.pendingrequestid.digist.type=passphrase
+core.pendingrequestid.digist.secret=pendingReqIdSecret
+core.pendingrequestid.digist.keystore.name=
+core.pendingrequestid.digist.key.alias= \ No newline at end of file
diff --git a/eaaf_core_utils/src/test/resources/data/config2.properties b/eaaf_core_utils/src/test/resources/data/config2.properties
new file mode 100644
index 00000000..3a1194b4
--- /dev/null
+++ b/eaaf_core_utils/src/test/resources/data/config2.properties
@@ -0,0 +1,15 @@
+security.hsmfacade.host=eid.a-sit.at
+security.hsmfacade.port=9050
+security.hsmfacade.trustedsslcert=src/test/resources/data/hsm_facade_trust_root.crt
+security.hsmfacade.username=authhandler-junit
+security.hsmfacade.password=supersecret123
+
+client.http.connection.timeout.socket=2
+client.http.connection.timeout.connection=2
+client.http.connection.timeout.request=2
+
+core.pendingrequestid.maxlifetime=180
+core.pendingrequestid.digist.type=hsmfacade
+core.pendingrequestid.digist.secret=pendingReqIdSecret
+core.pendingrequestid.digist.keystore.name=authhandler
+core.pendingrequestid.digist.key.alias=aes-key-1 \ No newline at end of file
diff --git a/eaaf_core_utils/src/test/resources/data/hsm_ee-RSA_rootcert.crt b/eaaf_core_utils/src/test/resources/data/hsm_ee-RSA_rootcert.crt
new file mode 100644
index 00000000..aa83c8d9
--- /dev/null
+++ b/eaaf_core_utils/src/test/resources/data/hsm_ee-RSA_rootcert.crt
@@ -0,0 +1,3 @@
+-----BEGIN CERTIFICATE-----
+MIICDTCCAbOgAwIBAgIIVLxIFI8kRpkwCgYIKoZIzj0EAwIwEjEQMA4GA1UEAwwHRUMtUm9vdDAeFw0yMDA2MTgwNzM2MTBaFw0yNTA2MTgwNzM2MTBaMDwxGzAZBgNVBAMMEmludC1yc2Eta2V5LTEtMDAwMTERMA8GA1UECgwIc29mdHdhcmUxCjAIBgNVBAUTATEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDrM1ocQqtch95Dm21JHi0V35nlWZibsjLqR+g8ERdD1qFgun/X0I/Rbft+KxB8QsDX7UmIjXGdavNcEjY/XcbiJxUcpv7vn/2+x3JxZO6Iye/ut001okICt3OGIqP93ZEnIaTTNhDsK7OnvD/eUjlmuHiTaFq1dZLKYDQlz9jl/9F4axfrz1V7oo60iqFIW+7tlUeh8VGDUPjQpHghzjHXTJv/OIAt752K31Tn8KR3kvkn6WTPo8eOWVaPQ480Dik0e2afTPPJNZJ7BW111IwqBAOKp586yVsQ4XVEF8H64Cq+s+b4/HBboo9TDJKTJvo2yQmcTsahbH+Rlm20ifUTAgMBAAEwCgYIKoZIzj0EAwIDSAAwRQIhANKN/N2Atb5fbeHSB2Myv/JcNf9JonxFe92AOu4f62NNAiBjOEeg4OyJZKPiDl6aqYVtz1Qroo6xzUC9UVA4qNe4LA==
+-----END CERTIFICATE-----
diff --git a/eaaf_core_utils/src/test/resources/data/hsm_ee_eecert.crt b/eaaf_core_utils/src/test/resources/data/hsm_ee_eecert.crt
new file mode 100644
index 00000000..b4c47c78
--- /dev/null
+++ b/eaaf_core_utils/src/test/resources/data/hsm_ee_eecert.crt
@@ -0,0 +1,3 @@
+-----BEGIN CERTIFICATE-----
+MIIDEzCCArqgAwIBAgIIMrAOP6EqywMwCgYIKoZIzj0EAwIwEjEQMA4GA1UEAwwHRUMtUm9vdDAeFw0yMDA2MTgwNzM2MDlaFw0yNTA2MTgwNzM2MDlaMEMxIjAgBgNVBAMMGWludC1hdXRoaGFuZGxlci1zaWduLTAwMDExETAPBgNVBAoMCHNvZnR3YXJlMQowCAYDVQQFEwExMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA5j2vR8ZV88fOJzFHmLuPizHXk+aiE0fX8Bu63FqCNa2Vy343u2k+4HVQBWpAtyRej8nL7JQuhFa11YRtVF+Vos9cyUDk482sUlYA2LdAFIuHJP6iTRrrHYdiTskc3FQUm9m9KorVFwnfzqJ40wjn9hD0xKCE0odk9IHA5aLTul0mSMcHQ+MMu2cbelK2TWTEC0wcGum2NrTWukhf0E4/e4SuqMgEUPdHSEaNZLGKZU0kyVtXKK0HCtWF8OKGay4V504dk3qnmRHHO8ik3oyPk2yLipQAPL0bUGMZ7tlRLo5VxJvkZSsJfAzvYn1JzcQIt6bXszQGU/JS6dw7Jq99Ckzox/vk8p1YUPd4tCuUJPXzhFhI7CedHKGItwk7mQf5llgeVJy40sVrFwHLDPufY5mlm9C+gVBs71+ibT/sJ96gCueWqduzDX8fHzeaNVj2NFEx2pT46D5cbRWZBow3+Rx+hpge6SDMzaebpbkgLPX+35D952bMLjm+9T0DulGk1tLL2k4YK+1WWUprlo+rm65OA5FxnO5YxNmGk2Uizu3tSoZMxmXwEWoFfYaMsTt5Not3+CLPjfs6pE4ML9ifAOxW+pPsmanDiNaMiL0/aSddvvkv3lSMRiU9nYh3DuOu6sGIMaPdyYF0V/9Fua2SDZV3QKIbzPbJfEsXFKtjtzUCAwEAATAKBggqhkjOPQQDAgNHADBEAiBHsK819KfxVn91KAmjRjb7zx8TLLBApyaZHXi5HVrYUwIgQbF6u6bXziAWdijlJC0IOWdBuTLWmTvFqBH7uX1HL9c=
+-----END CERTIFICATE-----
diff --git a/eaaf_core_utils/src/test/resources/data/hsm_ee_rootcert.crt b/eaaf_core_utils/src/test/resources/data/hsm_ee_rootcert.crt
new file mode 100644
index 00000000..fa7b132f
--- /dev/null
+++ b/eaaf_core_utils/src/test/resources/data/hsm_ee_rootcert.crt
@@ -0,0 +1,3 @@
+-----BEGIN CERTIFICATE-----
+MIIBPDCB46ADAgECAghZ0/gtbA6FrjAKBggqhkjOPQQDAjASMRAwDgYDVQQDDAdFQy1Sb290MB4XDTIwMDYxODA3MzU1M1oXDTMwMDYxODA3MzU1M1owEjEQMA4GA1UEAwwHRUMtUm9vdDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABIjgL+6qiE9oj2yWCkVm6s7AaYkbDhTptYXTW92MhASiTqxL6g8tr28MlRA2P8HPrNSK9payeMe5QW9Kxn+EMPejIzAhMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgWgMAoGCCqGSM49BAMCA0gAMEUCIDq2f4xjYD8pzr+mdzuT8wzePRnj/EatjmimGnvNt3FjAiEArezudh6G+wE+ds6S0dnFxG0o/BrbR0fiRNTQwiZA9ec=
+-----END CERTIFICATE-----
diff --git a/eaaf_core_utils/src/test/resources/data/hsm_facade_trust_root.crt b/eaaf_core_utils/src/test/resources/data/hsm_facade_trust_root.crt
index 01be3821..204ddccf 100644
--- a/eaaf_core_utils/src/test/resources/data/hsm_facade_trust_root.crt
+++ b/eaaf_core_utils/src/test/resources/data/hsm_facade_trust_root.crt
@@ -1,10 +1,12 @@
-----BEGIN CERTIFICATE-----
-MIIBdDCCARqgAwIBAgIEXkz1yjAKBggqhkjOPQQDAjARMQ8wDQYDVQQDDAZlY3Jv
-b3QwHhcNMjAwMjE5MDg0NjAyWhcNMjEwMjE4MDg0NjAyWjARMQ8wDQYDVQQDDAZl
-Y3Jvb3QwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAS8yvpVIWbPj4E7Lr87hwQR
-T9DZf9WY5LMV7gF6NKpnJ5JkEql/s7fqBVbrh8aSNo6gmfmSk4VYGhPJ+DCMzzQj
-o2AwXjAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFOXafzYpIOlu6BgNU+Ee
-JWuJobgWMB0GA1UdDgQWBBTl2n82KSDpbugYDVPhHiVriaG4FjALBgNVHQ8EBAMC
-AQYwCgYIKoZIzj0EAwIDSAAwRQIgRt/51PKL/bATuLCdib95Ika+h845Jo0G+Sbn
-bzNwJAcCIQCVD1cxEBuUkKaiaLbTiNVsEjvQb6ti0TFbbQUH66jCGA==
+MIIByzCCAXGgAwIBAgIEYC5cIjAKBggqhkjOPQQDAjA7MRMwEQYDVQQKDApBLVNJ
+VCBQbHVzMRIwEAYDVQQLDAlIc21GYWNhZGUxEDAOBgNVBAMMB0VDIFJvb3QwHhcN
+MjEwMjE4MTIyMjU4WhcNMzEwMjE4MTIyMjU4WjA7MRMwEQYDVQQKDApBLVNJVCBQ
+bHVzMRIwEAYDVQQLDAlIc21GYWNhZGUxEDAOBgNVBAMMB0VDIFJvb3QwWTATBgcq
+hkjOPQIBBggqhkjOPQMBBwNCAARK1UAE+T3xYsoI0VkRcP20jPwTd2MePMkXRsSR
+lpqPMQ6dPMlxPmAzWK33DWPFAFMY8+ecF0J8t2D+5RiJSSB+o2MwYTAPBgNVHRMB
+Af8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAfBgNVHSMEGDAWgBT1v6FCAwJIM8kv
+JD7gVjdGXqhcYjAdBgNVHQ4EFgQU9b+hQgMCSDPJLyQ+4FY3Rl6oXGIwCgYIKoZI
+zj0EAwIDSAAwRQIhAI+5lHyNCQfyj8c0pdBDVWY3fkCOj9ZTJ/hqgW+6TIQBAiBS
+jn7uIj7tGm+f0RgXMbhcgtQhYgVwf0x8OnRwmDOwaw==
-----END CERTIFICATE-----
diff --git a/eaaf_core_utils/src/test/resources/data/server_host.crt b/eaaf_core_utils/src/test/resources/data/server_host.crt
new file mode 100644
index 00000000..21d3a1e4
--- /dev/null
+++ b/eaaf_core_utils/src/test/resources/data/server_host.crt
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC2TCCAcECBGB5WpEwDQYJKoZIhvcNAQELBQAwMTELMAkGA1UEBhMCQVQxDjAM
+BgNVBAsMBWpVbml0MRIwEAYDVQQDDAlsb2NhbGhvc3QwHhcNMjEwNDE2MDkzNjE3
+WhcNMjQwMTEwMDkzNjE3WjAxMQswCQYDVQQGEwJBVDEOMAwGA1UECwwFalVuaXQx
+EjAQBgNVBAMMCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
+ggEBAJVYLzPzq7oBGS5Wer0++rHbp+DWI7srAV1lGHdq8ST6APh/7fEVWpdZDpMY
+bOXl6uIiVmMsx/jUhQwOu4rFXThiQlwyQOv57SO7WHqNPqbRs/EUVnzW35aXU/DB
+CmkqKyjK/+vuq7tIahlpqrppCzBVC9/Z15U+RMTdnATrohALNJovydH3VSkdkKX0
+5BDx779/8malTgyWTUgl+p3F/91iIIl4ZvIngo2ZYQCFm1nV6jmpErGFkG6YVrO7
+oe3OlGKFiXtqCmq+NSFeXsv/SaXWNUw82pYKuK/5EFSLX49HLBBDI14eOCuVLnGA
+H/kG3tGteYMBNzSMmC/kcKgRDnUCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAAJn2
+a/VbtXGmHe9wmtu8K3noyECfG5fbu9URUjXhCBlXGcdjfz1gzrOHcmaBndk0a566
+R2W0fLvjLpjWChrj7r34EpNYGPMLV2gp3ZkiSGl9kv8mf9iChK6+ga3SlyHJuXXu
+gw6eOIAxBrE/vLw+pZtCEV9yPrIydkt19jjejf1wjs5y2G7m5r5pBIh6Wlmmc4f2
+3M6l6Dge78WVdUaU5AeAHjgGgXwULxmLGxi6yiS5HsSeb79oGz9psHbq1EAvwOVY
+sLepTbDQvX/VAAG7HOJXhdGM0fRIkM7HFA5+6joTHvAKhuMlFIJ8Y4QIG2QaIBAh
+eBBh91x/aB2xOKs+Kg==
+-----END CERTIFICATE-----
diff --git a/eaaf_core_utils/src/test/resources/data/ssL_truststore.jks b/eaaf_core_utils/src/test/resources/data/ssL_truststore.jks
new file mode 100644
index 00000000..4d7bc2f3
--- /dev/null
+++ b/eaaf_core_utils/src/test/resources/data/ssL_truststore.jks
Binary files differ
diff --git a/eaaf_core_utils/src/test/resources/data/ssl_host.jks b/eaaf_core_utils/src/test/resources/data/ssl_host.jks
new file mode 100644
index 00000000..4ca07595
--- /dev/null
+++ b/eaaf_core_utils/src/test/resources/data/ssl_host.jks
Binary files differ
diff --git a/eaaf_core_utils/src/test/resources/spring/test_eaaf_pvp_lazy.beans.xml b/eaaf_core_utils/src/test/resources/spring/test_eaaf_pvp_lazy.beans.xml
index 210b88be..672efe5d 100644
--- a/eaaf_core_utils/src/test/resources/spring/test_eaaf_pvp_lazy.beans.xml
+++ b/eaaf_core_utils/src/test/resources/spring/test_eaaf_pvp_lazy.beans.xml
@@ -13,11 +13,20 @@
<bean id="dummyAuthConfigMap"
class="at.gv.egiz.eaaf.core.test.dummy.DummyAuthConfigMap" />
-
+
<bean id="eaafKeyStoreFactory"
class="at.gv.egiz.eaaf.core.impl.credential.EaafKeyStoreFactory" />
<bean id="eaafUtilsMessageSource"
class="at.gv.egiz.eaaf.core.impl.logging.EaafUtilsMessageSource" />
+ <bean class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
+ <property name="corePoolSize" value="5" />
+ <property name="maxPoolSize" value="25" />
+ <property name="queueCapacity" value="100" />
+ </bean>
+
+ <bean class="at.gv.egiz.eaaf.core.test.credentials.EncryptionTask"
+ scope="prototype"/>
+
</beans> \ No newline at end of file
diff --git a/eaaf_core_utils/src/test/resources/spring/test_eaaf_pvp_not_lazy.beans.xml b/eaaf_core_utils/src/test/resources/spring/test_eaaf_pvp_not_lazy.beans.xml
index 402e07f9..92dd5928 100644
--- a/eaaf_core_utils/src/test/resources/spring/test_eaaf_pvp_not_lazy.beans.xml
+++ b/eaaf_core_utils/src/test/resources/spring/test_eaaf_pvp_not_lazy.beans.xml
@@ -12,7 +12,14 @@
default-lazy-init="true">
<bean id="dummyAuthConfigMap"
- class="at.gv.egiz.eaaf.core.test.dummy.DummyAuthConfigMap" />
+ class="at.gv.egiz.eaaf.core.test.dummy.DummyAuthConfigMap">
+ <constructor-arg value="/data/config1.properties" />
+ </bean>
+
+ <bean id="encrytedTokenGenerationStrategy"
+ class="at.gv.egiz.eaaf.core.impl.utils.AuthenticatedEncryptionPendingRequestIdGenerationStrategy" />
+
+
<import resource="classpath:/spring/eaaf_utils.beans.xml"/>
diff --git a/eaaf_core_utils/src/test/resources/spring/test_eaaf_pvp_not_lazy_with_hsm.beans.xml b/eaaf_core_utils/src/test/resources/spring/test_eaaf_pvp_not_lazy_with_hsm.beans.xml
new file mode 100644
index 00000000..0f235e29
--- /dev/null
+++ b/eaaf_core_utils/src/test/resources/spring/test_eaaf_pvp_not_lazy_with_hsm.beans.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<beans xmlns="http://www.springframework.org/schema/beans"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:context="http://www.springframework.org/schema/context"
+ xmlns:tx="http://www.springframework.org/schema/tx"
+ xmlns:aop="http://www.springframework.org/schema/aop"
+ xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
+ http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
+ http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
+ http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd"
+ default-lazy-init="true">
+
+ <bean id="dummyAuthConfigMap"
+ class="at.gv.egiz.eaaf.core.test.dummy.DummyAuthConfigMap">
+ <constructor-arg value="/data/config2.properties" />
+ </bean>
+
+ <bean id="encrytedTokenGenerationStrategy"
+ class="at.gv.egiz.eaaf.core.impl.utils.AuthenticatedEncryptionPendingRequestIdGenerationStrategy" />
+
+
+
+ <import resource="classpath:/spring/eaaf_utils.beans.xml"/>
+
+</beans> \ No newline at end of file