summaryrefslogtreecommitdiff
path: root/eaaf_modules/eaaf_module_auth_sl20/src
diff options
context:
space:
mode:
Diffstat (limited to 'eaaf_modules/eaaf_module_auth_sl20/src')
-rw-r--r--eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/AbstractSL20AuthenticationModulImpl.java10
-rw-r--r--eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/Constants.java36
-rw-r--r--eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/EventCodes.java2
-rw-r--r--eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/exceptions/SL20EidDataValidationException.java19
-rw-r--r--eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/exceptions/SL20Exception.java2
-rw-r--r--eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/tasks/AbstractCreateQualEidRequestTask.java160
-rw-r--r--eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/tasks/AbstractReceiveQualEidTask.java23
-rw-r--r--eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/utils/JoseUtils.java374
-rw-r--r--eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/utils/JsonSecurityUtils.java161
-rw-r--r--eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/utils/SL20Constants.java19
-rw-r--r--eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/utils/SL20HttpBindingUtils.java138
-rw-r--r--eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/utils/SL20JsonExtractorUtils.java84
-rw-r--r--eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/utils/SL20ResponseUtils.java14
-rw-r--r--eaaf_modules/eaaf_module_auth_sl20/src/test/java/at/gv/egiz/eaaf/modules/auth/sl20/utils/AbstractJsonSecurityUtilsTest.java394
-rw-r--r--eaaf_modules/eaaf_module_auth_sl20/src/test/java/at/gv/egiz/eaaf/modules/auth/sl20/utils/JoseUtilsTest.java83
-rw-r--r--eaaf_modules/eaaf_module_auth_sl20/src/test/java/at/gv/egiz/eaaf/modules/auth/sl20/utils/JsonSecurityUtilsHsmKeyTest.java86
-rw-r--r--eaaf_modules/eaaf_module_auth_sl20/src/test/java/at/gv/egiz/eaaf/modules/auth/sl20/utils/JsonSecurityUtilsSoftwareKeyTest.java110
-rw-r--r--eaaf_modules/eaaf_module_auth_sl20/src/test/resources/data/bindingAuth1.crt3
-rw-r--r--eaaf_modules/eaaf_module_auth_sl20/src/test/resources/data/bindingAuth1.jws1
-rw-r--r--eaaf_modules/eaaf_module_auth_sl20/src/test/resources/data/config1.properties19
-rw-r--r--eaaf_modules/eaaf_module_auth_sl20/src/test/resources/data/config2.properties19
-rw-r--r--eaaf_modules/eaaf_module_auth_sl20/src/test/resources/data/hsm_ec.crt3
-rw-r--r--eaaf_modules/eaaf_module_auth_sl20/src/test/resources/data/hsm_facade_trust_root.crt12
-rw-r--r--eaaf_modules/eaaf_module_auth_sl20/src/test/resources/data/hsm_rsa.crt3
-rw-r--r--eaaf_modules/eaaf_module_auth_sl20/src/test/resources/data/junit.jksbin0 -> 5738 bytes
-rw-r--r--eaaf_modules/eaaf_module_auth_sl20/src/test/resources/data/junit_no_rsa.jksbin0 -> 3510 bytes
-rw-r--r--eaaf_modules/eaaf_module_auth_sl20/src/test/resources/data/software_ec.crt3
-rw-r--r--eaaf_modules/eaaf_module_auth_sl20/src/test/resources/data/software_rsa.crt3
-rw-r--r--eaaf_modules/eaaf_module_auth_sl20/src/test/resources/data/test.crt3
-rw-r--r--eaaf_modules/eaaf_module_auth_sl20/src/test/resources/spring/test_eaaf_sl20.beans.xml24
-rw-r--r--eaaf_modules/eaaf_module_auth_sl20/src/test/resources/spring/test_eaaf_sl20_hsm.beans.xml24
31 files changed, 1531 insertions, 301 deletions
diff --git a/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/AbstractSL20AuthenticationModulImpl.java b/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/AbstractSL20AuthenticationModulImpl.java
index e9932ae8..d561a0bc 100644
--- a/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/AbstractSL20AuthenticationModulImpl.java
+++ b/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/AbstractSL20AuthenticationModulImpl.java
@@ -29,11 +29,9 @@ public abstract class AbstractSL20AuthenticationModulImpl implements AuthModule
private int priority = 3;
public static final List<String> VDA_TYPE_IDS = Arrays.asList("1", "2", "3", "4");
-
+
@Autowired(required = true)
protected IConfiguration authConfig;
- @Autowired(required = true)
- private AbstractAuthenticationManager authManager;
@Override
public int getPriority() {
@@ -51,9 +49,9 @@ public abstract class AbstractSL20AuthenticationModulImpl implements AuthModule
@PostConstruct
protected void initalSL20Authentication() {
- // parameter to whiteList
- authManager.addHeaderNameToWhiteList(SL20Constants.HTTP_HEADER_SL20_CLIENT_TYPE);
- authManager.addHeaderNameToWhiteList(SL20Constants.HTTP_HEADER_SL20_VDA_TYPE);
+ // parameter to whiteList
+ AbstractAuthenticationManager.addHeaderNameToWhiteList(SL20Constants.HTTP_HEADER_SL20_CLIENT_TYPE);
+ AbstractAuthenticationManager.addHeaderNameToWhiteList(SL20Constants.HTTP_HEADER_SL20_VDA_TYPE);
}
diff --git a/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/Constants.java b/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/Constants.java
index 11fd41fb..74d67d01 100644
--- a/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/Constants.java
+++ b/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/Constants.java
@@ -7,37 +7,41 @@ public class Constants {
public static final String CONFIG_PROP_VDA_AUTHBLOCK_TRANSFORMATION_ID = CONFIG_PROP_PREFIX
+ ".vda.authblock.transformation.id";
-
+
//KeyStore configuration
- public static final String CONFIG_PROP_SECURITY_KEYSTORE_TYPE =
+ public static final String CONFIG_PROP_SECURITY_KEYSTORE_TYPE =
CONFIG_PROP_PREFIX + ".security.keystore.type";
- public static final String CONFIG_PROP_SECURITY_KEYSTORE_NAME =
+ public static final String CONFIG_PROP_SECURITY_KEYSTORE_NAME =
CONFIG_PROP_PREFIX + ".security.keystore.name";
- public static final String CONFIG_PROP_SECURITY_KEYSTORE_PATH =
+ public static final String CONFIG_PROP_SECURITY_KEYSTORE_PATH =
CONFIG_PROP_PREFIX + ".security.keystore.path";
- public static final String CONFIG_PROP_SECURITY_KEYSTORE_PASSWORD =
+ public static final String CONFIG_PROP_SECURITY_KEYSTORE_PASSWORD =
CONFIG_PROP_PREFIX + ".security.keystore.password";
-
- public static final String CONFIG_PROP_SECURITY_KEYSTORE_KEY_SIGN_ALIAS =
+
+ public static final String CONFIG_PROP_SECURITY_KEYSTORE_KEY_SIGN_ALIAS =
CONFIG_PROP_PREFIX + ".security.sign.alias";
- public static final String CONFIG_PROP_SECURITY_KEYSTORE_KEY_SIGN_PASSWORD =
+ public static final String CONFIG_PROP_SECURITY_KEYSTORE_KEY_SIGN_PASSWORD =
CONFIG_PROP_PREFIX + ".security.sign.password";
- public static final String CONFIG_PROP_SECURITY_KEYSTORE_KEY_ENCRYPTION_ALIAS =
+ public static final String CONFIG_PROP_SECURITY_KEYSTORE_KEY_ENCRYPTION_ALIAS =
CONFIG_PROP_PREFIX + ".security.encryption.alias";
- public static final String CONFIG_PROP_SECURITY_KEYSTORE_KEY_ENCRYPTION_PASSWORD =
+ public static final String CONFIG_PROP_SECURITY_KEYSTORE_KEY_ENCRYPTION_PASSWORD =
CONFIG_PROP_PREFIX + ".security.encryption.password";
//TrustStore configuration
- public static final String CONFIG_PROP_SECURITY_TRUSTSTORE_TYPE =
+ public static final String CONFIG_PROP_SECURITY_TRUSTSTORE_TYPE =
CONFIG_PROP_PREFIX + ".security.truststore.type";
- public static final String CONFIG_PROP_SECURITY_TRUSTSTORE_NAME =
+ public static final String CONFIG_PROP_SECURITY_TRUSTSTORE_NAME =
CONFIG_PROP_PREFIX + ".security.truststore.name";
- public static final String CONFIG_PROP_SECURITY_TRUSTSTORE_PATH =
+ public static final String CONFIG_PROP_SECURITY_TRUSTSTORE_PATH =
CONFIG_PROP_PREFIX + ".security.truststore.path";
- public static final String CONFIG_PROP_SECURITY_TRUSTSTORE_PASSWORD =
+ public static final String CONFIG_PROP_SECURITY_TRUSTSTORE_PASSWORD =
CONFIG_PROP_PREFIX + ".security.truststore.password";
-
-
+
+ public static final String CONFIG_PROP_SECURITY_SIG_ALG_RSA =
+ CONFIG_PROP_PREFIX + ".security.sigalg.rsa";
+ public static final String CONFIG_PROP_SECURITY_SIG_ALG_ECC =
+ CONFIG_PROP_PREFIX + ".security.sigalg.ecc";
+
public static final String CONFIG_PROP_VDA_ENDPOINT_QUALeID_DEFAULT_ELEMENT = "default";
public static final String CONFIG_PROP_VDA_ENDPOINT_QUALeID_DEFAULT = CONFIG_PROP_VDA_ENDPOINT_QUALeID
+ CONFIG_PROP_VDA_ENDPOINT_QUALeID_DEFAULT_ELEMENT;
diff --git a/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/EventCodes.java b/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/EventCodes.java
index af155206..62779072 100644
--- a/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/EventCodes.java
+++ b/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/EventCodes.java
@@ -12,5 +12,5 @@ public class EventCodes {
public static final int AUTHPROCESS_SL20_ENDPOINT_URL = 4112;
public static final int AUTHPROCESS_SL20_DATAURL_IP = 4113;
- public static final int AUTHPROCESS_SL20_CONSENT_VALID = 4113;
+ public static final int AUTHPROCESS_SL20_CONSENT_VALID = 4114;
}
diff --git a/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/exceptions/SL20EidDataValidationException.java b/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/exceptions/SL20EidDataValidationException.java
index a14fbe9e..f0d993ca 100644
--- a/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/exceptions/SL20EidDataValidationException.java
+++ b/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/exceptions/SL20EidDataValidationException.java
@@ -1,15 +1,26 @@
package at.gv.egiz.eaaf.modules.auth.sl20.exceptions;
public class SL20EidDataValidationException extends SL20Exception {
- private static final long serialVersionUID = 1L;
+
+ private static final long serialVersionUID = -2604130523926584663L;
public SL20EidDataValidationException(final Object[] parameters) {
- super("sl20.07", parameters);
+ this("99", parameters);
}
-
+
public SL20EidDataValidationException(final Object[] parameters, final Throwable e) {
- super("sl20.07", parameters, e);
+ this("99", parameters, e);
+
+ }
+
+ public SL20EidDataValidationException(final String subErrorId, final Object[] parameters) {
+ super("sl20.07." + subErrorId, parameters);
+
+ }
+
+ public SL20EidDataValidationException(final String subErrorId, final Object[] parameters, final Throwable e) {
+ super("sl20.07." + subErrorId, parameters, e);
}
diff --git a/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/exceptions/SL20Exception.java b/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/exceptions/SL20Exception.java
index 12921ad6..08373a2d 100644
--- a/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/exceptions/SL20Exception.java
+++ b/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/exceptions/SL20Exception.java
@@ -4,7 +4,7 @@ import at.gv.egiz.eaaf.core.exceptions.EaafAuthenticationException;
public class SL20Exception extends EaafAuthenticationException {
- private static final long serialVersionUID = 1L;
+ private static final long serialVersionUID = -6716465236880571576L;
public SL20Exception(final String messageId, final Object[] parameters) {
super(messageId, parameters);
diff --git a/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/tasks/AbstractCreateQualEidRequestTask.java b/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/tasks/AbstractCreateQualEidRequestTask.java
index 6c11fa63..9dcfbe75 100644
--- a/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/tasks/AbstractCreateQualEidRequestTask.java
+++ b/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/tasks/AbstractCreateQualEidRequestTask.java
@@ -1,25 +1,29 @@
package at.gv.egiz.eaaf.modules.auth.sl20.tasks;
import java.io.Serializable;
+import java.net.SocketException;
+import java.net.SocketTimeoutException;
+import java.nio.charset.StandardCharsets;
import java.security.cert.CertificateEncodingException;
import java.util.ArrayList;
import java.util.List;
+import java.util.Locale;
import java.util.Map;
+import java.util.concurrent.TimeUnit;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.StringUtils;
-import org.apache.http.HttpResponse;
+import org.apache.commons.lang3.time.StopWatch;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.message.BasicNameValuePair;
import org.jose4j.base64url.Base64Url;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.i18n.LocaleContextHolder;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
@@ -33,7 +37,6 @@ import at.gv.egiz.eaaf.core.impl.http.IHttpClientFactory;
import at.gv.egiz.eaaf.core.impl.idp.auth.modules.AbstractAuthServletTask;
import at.gv.egiz.eaaf.core.impl.utils.KeyValueUtils;
import at.gv.egiz.eaaf.core.impl.utils.Random;
-import at.gv.egiz.eaaf.core.impl.utils.TransactionIdUtils;
import at.gv.egiz.eaaf.modules.auth.sl20.Constants;
import at.gv.egiz.eaaf.modules.auth.sl20.EventCodes;
import at.gv.egiz.eaaf.modules.auth.sl20.data.VerificationResult;
@@ -42,12 +45,16 @@ import at.gv.egiz.eaaf.modules.auth.sl20.exceptions.SlCommandoParserException;
import at.gv.egiz.eaaf.modules.auth.sl20.utils.SL20Constants;
import at.gv.egiz.eaaf.modules.auth.sl20.utils.SL20Constants.VdaAuthMethod;
import at.gv.egiz.eaaf.modules.auth.sl20.utils.SL20HttpBindingUtils;
+import at.gv.egiz.eaaf.modules.auth.sl20.utils.SL20HttpBindingUtils.Sl20ResponseHolder;
import at.gv.egiz.eaaf.modules.auth.sl20.utils.SL20JsonBuilderUtils;
import at.gv.egiz.eaaf.modules.auth.sl20.utils.SL20JsonExtractorUtils;
+import lombok.extern.slf4j.Slf4j;
+@Slf4j
public abstract class AbstractCreateQualEidRequestTask extends AbstractAuthServletTask {
- private static final Logger log = LoggerFactory.getLogger(AbstractCreateQualEidRequestTask.class);
+ private static final String FRIENDLYNAME_HTTP_CLIENT = "A-Trust Client";
+
@Autowired(required = true)
private IHttpClientFactory httpClientFactory;
@Autowired(required = true)
@@ -60,7 +67,8 @@ public abstract class AbstractCreateQualEidRequestTask extends AbstractAuthServl
log.debug("Starting SL2.0 authentication process .... ");
revisionsLogger.logEvent(pendingReq, EventCodes.AUTHPROCESS_SL20_SELECTED, "sl20auth");
-
+
+ String vdaQualEidDUrl = null;
try {
// get service-provider configuration
final ISpConfiguration oaConfig = pendingReq.getServiceProviderConfiguration();
@@ -72,7 +80,7 @@ public abstract class AbstractCreateQualEidRequestTask extends AbstractAuthServl
}
// get basic configuration parameters
- final String vdaQualEidDUrl = extractVdaUrlForSpecificOa(oaConfig, executionContext);
+ vdaQualEidDUrl = extractVdaUrlForSpecificOa(oaConfig, executionContext);
if (StringUtils.isEmpty(vdaQualEidDUrl)) {
log.error("NO VDA URL for qualified eID (" + Constants.CONFIG_PROP_VDA_ENDPOINT_QUALeID_DEFAULT + ")");
throw new SL20Exception("sl20.03", new Object[] { "NO VDA URL for qualified eID" });
@@ -89,55 +97,48 @@ public abstract class AbstractCreateQualEidRequestTask extends AbstractAuthServl
// build request container
final String qualEidReqId = Random.nextProcessReferenceValue();
- final ObjectNode sl20Req = SL20JsonBuilderUtils.createGenericRequest(qualEidReqId, null, null,
- signedQualEidCommand);
+ final ObjectNode sl20Req = SL20JsonBuilderUtils.createGenericRequest(qualEidReqId,
+ pendingReq.getUniqueTransactionIdentifier(), null, signedQualEidCommand);
// build http POST request
final HttpPost httpReq = new HttpPost(new URIBuilder(vdaQualEidDUrl).build());
final List<NameValuePair> parameters = new ArrayList<>();
parameters.add(new BasicNameValuePair(SL20Constants.PARAM_SL20_REQ_COMMAND_PARAM,
- Base64Url.encode(sl20Req.toString().getBytes("UTF-8"))));
-
- //set specific authentication method if it was selection by process step before
- VdaAuthMethod authMethod = getVdaAuthMethodFromContext(executionContext);
- if (authMethod != null) {
- log.debug("Request VDA with authType: {}", authMethod);
- parameters.add(new BasicNameValuePair(SL20Constants.PARAM_SL20_REQ_AUTH_METHOD_PARAM,
- authMethod.getAuthMethod()));
- }
+ Base64Url.encode(sl20Req.toString().getBytes(StandardCharsets.UTF_8))));
- //set VDA sessionId if it was available on context
- String vdaSessionId = getVdaSessionIdFromContext(executionContext);
- if (vdaSessionId != null) {
- log.trace("Request VDA with sessionId: {}", vdaSessionId);
- parameters.add(new BasicNameValuePair(
- SL20Constants.PARAM_SL20_REQ_AUTH_VDA_SESSIONID,
- vdaSessionId));
-
- }
-
-
-
- httpReq.setEntity(new UrlEncodedFormEntity(parameters));
+ //inject additional request parameters
+ injectAdditionalSL20RequestParams(parameters, executionContext, request);
- // build http GET request
- // URIBuilder sl20ReqUri = new URIBuilder(vdaQualeIDUrl);
- // sl20ReqUri.addParameter(SL20Constants.PARAM_SL20_REQ_COMMAND_PARAM,
- // Base64Url.encode(sl20Req.toString().getBytes()));
- // HttpGet httpReq = new HttpGet(sl20ReqUri.build());
+ httpReq.setEntity(new UrlEncodedFormEntity(parameters));
// set native client header
httpReq.addHeader(SL20Constants.HTTP_HEADER_SL20_CLIENT_TYPE, SL20Constants.HTTP_HEADER_VALUE_NATIVE);
- log.trace("Request VDA via SL20 with: " + Base64Url.encode(sl20Req.toString().getBytes("UTF-8")));
+ log.trace("Request VDA via SL20 with: {}",
+ Base64Url.encode(sl20Req.toString().getBytes(StandardCharsets.UTF_8)));
// request VDA
- final HttpResponse httpResp = httpClientFactory.getHttpClient(false).execute(httpReq);
-
- // parse response
- log.info("Receive response from VDA ... ");
- final JsonNode sl20Resp = SL20JsonExtractorUtils.getSL20ContainerFromResponse(httpResp);
- final VerificationResult respPayloadContainer = SL20JsonExtractorUtils.extractSL20PayLoad(sl20Resp, null, false);
+
+ final StopWatch watch = StopWatch.createStarted();
+ log.info("Requesting {} for authentication ... ", FRIENDLYNAME_HTTP_CLIENT);
+ final Sl20ResponseHolder httpResp = httpClientFactory.getHttpClient(false).execute(
+ httpReq, SL20HttpBindingUtils.sl20ResponseHandler());
+
+ watch.stop();
+ log.info("Respone from {} received after: {}[ms] with statusCode: {}", FRIENDLYNAME_HTTP_CLIENT,
+ watch.getTime(TimeUnit.MILLISECONDS), httpResp.getResponseStatus().getStatusCode());
+
+ //check on error on http channel
+ if (httpResp.getError() != null) {
+ log.info("Basic SL2.0 response processing has an error. HTTP-StatusCode: {} ErrorMsg: {}",
+ httpResp.getResponseStatus().getStatusCode(), httpResp.getError().getMessage());
+ throw httpResp.getError();
+
+ }
+
+ // parse response
+ final VerificationResult respPayloadContainer =
+ SL20JsonExtractorUtils.extractSL20PayLoad(httpResp.getResponseBody(), null, false);
if (respPayloadContainer.isValidSigned() == null) {
log.debug("Receive unsigned payLoad from VDA");
@@ -158,10 +159,10 @@ public abstract class AbstractCreateQualEidRequestTask extends AbstractAuthServl
SL20Constants.SL20_COMMAND_PARAM_GENERAL_REDIRECT_SIGNEDCOMMAND, false);
// create forward SL2.0 command
- final ObjectNode sl20Forward = sl20Resp.deepCopy();
+ final ObjectNode sl20Forward = httpResp.getResponseBody().deepCopy();
SL20JsonBuilderUtils.addOnlyOnceOfTwo(sl20Forward, SL20Constants.SL20_PAYLOAD, SL20Constants.SL20_SIGNEDPAYLOAD,
command.deepCopy(), signedCommand);
-
+
// store pending request
pendingReq.setRawDataToTransaction(Constants.PENDING_REQ_STORAGE_PREFIX + SL20Constants.SL20_REQID,
qualEidReqId);
@@ -201,21 +202,58 @@ public abstract class AbstractCreateQualEidRequestTask extends AbstractAuthServl
} catch (final EaafAuthenticationException e) {
throw new TaskExecutionException(pendingReq, "SL2.0 Authentication FAILED. Msg: " + e.getMessage(), e);
+ } catch (final SocketException | SocketTimeoutException e) {
+ log.error("SL2.0 Authentication has a VDA connector error. Endpoint: {}",
+ vdaQualEidDUrl, e);
+ throw new TaskExecutionException(pendingReq, e.getMessage(),
+ new SL20Exception("sl20.02", new Object[] { e.getMessage()}, e));
+
} catch (final Exception e) {
log.warn("SL2.0 Authentication FAILED with a generic error.", e);
throw new TaskExecutionException(pendingReq, e.getMessage(), e);
- } finally {
- TransactionIdUtils.removeTransactionId();
- TransactionIdUtils.removeSessionId();
+ }
+
+ }
+ protected void injectAdditionalSL20RequestParams(List<NameValuePair> parameters,
+ ExecutionContext executionContext, HttpServletRequest request) {
+ //set specific authentication method if it was selection by process step before
+ final VdaAuthMethod authMethod = getVdaAuthMethodFromContext(executionContext);
+ if (authMethod != null) {
+ log.debug("Request VDA with authType: {}", authMethod);
+ parameters.add(new BasicNameValuePair(SL20Constants.PARAM_SL20_REQ_AUTH_METHOD_PARAM,
+ authMethod.getAuthMethod()));
}
+ //set VDA sessionId if it was available on context
+ final String vdaSessionId = getVdaSessionIdFromContext(executionContext);
+ if (vdaSessionId != null) {
+ log.trace("Request VDA with sessionId: {}", vdaSessionId);
+ parameters.add(new BasicNameValuePair(
+ SL20Constants.PARAM_SL20_REQ_AUTH_VDA_SESSIONID,
+ vdaSessionId));
+
+ }
+
+ //set i18n language into VDA request
+ final Locale locale = LocaleContextHolder.getLocale();
+ final String language = locale.getLanguage();
+ if (StringUtils.isNotEmpty(language)) {
+ log.trace("Find i18n context). Inject locale: {} into VDA request", locale.getLanguage());
+ parameters.add(new BasicNameValuePair(
+ SL20Constants.PARAM_SL20_REQ_AUTH_VDA_LOCALE,
+ language.toUpperCase(locale)));
+
+ } else {
+ log.info("Find i18n context, but Language is UNKNOWN. It will be ignored");
+
+ }
}
/**
- * Get ExecutionContext parameter-key for VDA AuthMethod information.
- *
+ * Get ExecutionContext parameter-key for VDA AuthMethod information.
+ *
* @return Key to get AuthMethod from {@link ExecutionContext}
*/
protected abstract String getAuthMethodContextParamKey();
@@ -231,34 +269,34 @@ public abstract class AbstractCreateQualEidRequestTask extends AbstractAuthServl
*/
protected abstract String buildSignedQualifiedEidCommand() throws CertificateEncodingException, SL20Exception;
-
+
private VdaAuthMethod getVdaAuthMethodFromContext(ExecutionContext executionContext) {
- Serializable authMethodRaw = executionContext.get(getAuthMethodContextParamKey());
+ final Serializable authMethodRaw = executionContext.get(getAuthMethodContextParamKey());
if (authMethodRaw instanceof String) {
log.trace("Find authMethod parameter: {} on context", authMethodRaw);
return VdaAuthMethod.fromString((String) authMethodRaw);
-
+
}
-
+
return null;
}
-
+
private String getVdaSessionIdFromContext(ExecutionContext executionContext) {
- Serializable vdaSessionId = executionContext.get(
+ final Serializable vdaSessionId = executionContext.get(
SL20Constants.SL20_COMMAND_PARAM_GENERAL_RESPONSE_ERROR_VDASESSIONID);
- if (vdaSessionId instanceof String
+ if (vdaSessionId instanceof String
&& StringUtils.isNotEmpty((CharSequence) vdaSessionId)) {
executionContext.remove(
SL20Constants.SL20_COMMAND_PARAM_GENERAL_RESPONSE_ERROR_VDASESSIONID);
-
+
log.trace("Find vdaSessionId parameter: {} on context", vdaSessionId);
return (String) vdaSessionId;
-
+
}
-
+
return null;
}
-
+
private String extractVdaUrlForSpecificOa(final ISpConfiguration oaConfig, final ExecutionContext executionContext) {
// load SP specific config for development and testing purposes
diff --git a/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/tasks/AbstractReceiveQualEidTask.java b/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/tasks/AbstractReceiveQualEidTask.java
index 4786ff39..dfa05a89 100644
--- a/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/tasks/AbstractReceiveQualEidTask.java
+++ b/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/tasks/AbstractReceiveQualEidTask.java
@@ -8,8 +8,6 @@ import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.StringUtils;
import org.jose4j.base64url.Base64Url;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import com.fasterxml.jackson.core.JsonParseException;
@@ -22,7 +20,6 @@ import at.gv.egiz.eaaf.core.exceptions.TaskExecutionException;
import at.gv.egiz.eaaf.core.impl.idp.auth.modules.AbstractAuthServletTask;
import at.gv.egiz.eaaf.core.impl.utils.DataUrlBuilder;
import at.gv.egiz.eaaf.core.impl.utils.StreamUtils;
-import at.gv.egiz.eaaf.core.impl.utils.TransactionIdUtils;
import at.gv.egiz.eaaf.modules.auth.sl20.Constants;
import at.gv.egiz.eaaf.modules.auth.sl20.EventCodes;
import at.gv.egiz.eaaf.modules.auth.sl20.data.VerificationResult;
@@ -35,9 +32,10 @@ import at.gv.egiz.eaaf.modules.auth.sl20.utils.JsonMapper;
import at.gv.egiz.eaaf.modules.auth.sl20.utils.SL20Constants;
import at.gv.egiz.eaaf.modules.auth.sl20.utils.SL20JsonExtractorUtils;
import at.gv.egiz.eaaf.modules.auth.sl20.utils.SL20ResponseUtils;
+import lombok.extern.slf4j.Slf4j;
+@Slf4j
public abstract class AbstractReceiveQualEidTask extends AbstractAuthServletTask {
- private static final Logger log = LoggerFactory.getLogger(AbstractReceiveQualEidTask.class);
@Autowired(required = true)
private IJoseTools joseTools;
@@ -82,13 +80,14 @@ public abstract class AbstractReceiveQualEidTask extends AbstractAuthServletTask
sl20ReqObj = new JsonMapper().getMapper().readTree(Base64Url.decodeToUtf8String(sl20Result));
} catch (final JsonParseException e) {
- log.warn("SL2.0 command or result is NOT valid JSON.", e);
- log.debug("SL2.0 msg: " + sl20Result);
+ log.error("SL2.0 command or result is NOT valid JSON. Received msg: {}", sl20Result, e);
throw new SL20Exception("sl20.02", new Object[] { "SL2.0 command or result is NOT valid JSON." },
e);
}
+ log.info("Receive response from A-Trust. Starting response-message validation ... ");
+
// check on errorMessage
final VerificationResult payLoadContainerErrorCheck = SL20JsonExtractorUtils.extractSL20PayLoad(
sl20ReqObj,
@@ -117,7 +116,7 @@ public abstract class AbstractReceiveQualEidTask extends AbstractAuthServletTask
log.debug("VDA provides an optional sessionId. Inject it to internal error-holder ");
ex.setVdaSessionId(vdaSessionId);
- }
+ }
throw ex;
} else {
@@ -161,7 +160,6 @@ public abstract class AbstractReceiveQualEidTask extends AbstractAuthServletTask
}
} catch (final EaafAuthenticationException e) {
- log.warn("SL2.0 processing error:", e);
if (sl20Result != null) {
log.debug("Received SL2.0 result: " + sl20Result);
}
@@ -170,8 +168,8 @@ public abstract class AbstractReceiveQualEidTask extends AbstractAuthServletTask
new TaskExecutionException(pendingReq, "SL2.0 Authentication FAILED. Msg: " + e.getMessage(), e));
} catch (final Exception e) {
- log.warn("ERROR:", e);
- log.warn("SL2.0 Authentication FAILED with a generic error.", e);
+
+
if (sl20Result != null) {
log.debug("Received SL2.0 result: " + sl20Result);
}
@@ -212,11 +210,6 @@ public abstract class AbstractReceiveQualEidTask extends AbstractAuthServletTask
log.error("Can NOT send error message. SOMETHING IS REALY WRONG!", e);
}
-
- } finally {
- TransactionIdUtils.removeTransactionId();
- TransactionIdUtils.removeSessionId();
-
}
}
diff --git a/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/utils/JoseUtils.java b/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/utils/JoseUtils.java
new file mode 100644
index 00000000..5b221bbe
--- /dev/null
+++ b/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/utils/JoseUtils.java
@@ -0,0 +1,374 @@
+package at.gv.egiz.eaaf.modules.auth.sl20.utils;
+
+import java.io.IOException;
+import java.security.Key;
+import java.security.KeyFactory;
+import java.security.KeyStore;
+import java.security.NoSuchAlgorithmException;
+import java.security.Provider;
+import java.security.PublicKey;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.X509Certificate;
+import java.security.interfaces.ECPrivateKey;
+import java.security.interfaces.ECPublicKey;
+import java.security.interfaces.RSAPrivateKey;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import javax.annotation.Nonnull;
+
+import org.apache.commons.lang3.StringUtils;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.jose4j.jca.ProviderContext;
+import org.jose4j.jwa.AlgorithmConstraints;
+import org.jose4j.jws.AlgorithmIdentifiers;
+import org.jose4j.jws.JsonWebSignature;
+import org.jose4j.jwx.Headers;
+import org.jose4j.jwx.JsonWebStructure;
+import org.jose4j.keys.resolvers.X509VerificationKeyResolver;
+import org.jose4j.lang.JoseException;
+import org.springframework.util.Base64Utils;
+
+import at.gv.egiz.eaaf.core.exception.EaafKeyUsageException;
+import at.gv.egiz.eaaf.core.exceptions.EaafException;
+import at.gv.egiz.eaaf.core.impl.credential.EaafKeyStoreUtils;
+import at.gv.egiz.eaaf.core.impl.data.Pair;
+import at.gv.egiz.eaaf.core.impl.utils.X509Utils;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.extern.slf4j.Slf4j;
+
+/**
+ * {@link JoseUtils} provides static methods JWS and JWE processing.
+ *
+ * @author tlenz
+ *
+ */
+@Slf4j
+public class JoseUtils {
+
+ private static final Provider provider = new BouncyCastleProvider();
+
+ /**
+ * Create a JWS signature.
+ *
+ * <p>
+ * Use {@link org.jose4j.jws.AlgorithmIdentifiers.RSA_PSS_USING_SHA256} in case
+ * of a RSA based key and
+ * {@link org.jose4j.jws.AlgorithmIdentifiers.ECDSA_USING_P256_CURVE_AND_SHA256}
+ * in case of an ECC based key.
+ * </p>
+ *
+ * @param keyStore KeyStore that should be used
+ * @param keyAlias Alias of the private key
+ * @param keyPassword Password to access the key
+ * @param payLoad PayLoad to sign
+ * @param addFullCertChain If true the full certificate chain will be
+ * added, otherwise only the
+ * X509CertSha256Fingerprint is added into JOSE
+ * header
+ * @param friendlyNameForLogging FriendlyName for the used KeyStore for logging
+ * purposes only
+ * @return Signed PayLoad in serialized form
+ * @throws EaafException In case of a key-access or key-usage error
+ * @throws JoseException In case of a JOSE error
+ */
+ public static String createSignature(@Nonnull Pair<KeyStore, Provider> keyStore,
+ @Nonnull final String keyAlias, @Nonnull final char[] keyPassword,
+ @Nonnull final String payLoad, boolean addFullCertChain,
+ @Nonnull String friendlyNameForLogging) throws EaafException, JoseException {
+ return createSignature(keyStore, keyAlias, keyPassword, payLoad, addFullCertChain, Collections.emptyMap(),
+ AlgorithmIdentifiers.RSA_PSS_USING_SHA256, AlgorithmIdentifiers.ECDSA_USING_P256_CURVE_AND_SHA256,
+ friendlyNameForLogging);
+
+ }
+
+ /**
+ * Create a JWS signature.
+ *
+ * <p>
+ * Use {@link org.jose4j.jws.AlgorithmIdentifiers.RSA_PSS_USING_SHA256} in case
+ * of a RSA based key and
+ * {@link org.jose4j.jws.AlgorithmIdentifiers.ECDSA_USING_P256_CURVE_AND_SHA256}
+ * in case of an ECC based key.
+ * </p>
+ *
+ * @param keyStore KeyStore that should be used
+ * @param keyAlias Alias of the private key
+ * @param keyPassword Password to access the key
+ * @param payLoad PayLoad to sign
+ * @param addFullCertChain If true the full certificate chain will be
+ * added, otherwise only the
+ * X509CertSha256Fingerprint is added into JOSE
+ * header
+ * @param joseHeaders HeaderName and HeaderValue that should be set
+ * into JOSE header
+ * @param friendlyNameForLogging FriendlyName for the used KeyStore for logging
+ * purposes only
+ * @return Signed PayLoad in serialized form
+ * @throws EaafException In case of a key-access or key-usage error
+ * @throws JoseException In case of a JOSE error
+ */
+ public static String createSignature(@Nonnull Pair<KeyStore, Provider> keyStore,
+ @Nonnull final String keyAlias, @Nonnull final char[] keyPassword,
+ @Nonnull final String payLoad, boolean addFullCertChain,
+ @Nonnull final Map<String, String> joseHeaders,
+ @Nonnull String friendlyNameForLogging) throws EaafException, JoseException {
+ return createSignature(keyStore, keyAlias, keyPassword, payLoad, addFullCertChain, joseHeaders,
+ AlgorithmIdentifiers.RSA_PSS_USING_SHA256, AlgorithmIdentifiers.ECDSA_USING_P256_CURVE_AND_SHA256,
+ friendlyNameForLogging);
+
+ }
+
+ /**
+ * Create a JWS signature.
+ *
+ * @param keyStore KeyStore that should be used
+ * @param keyAlias Alias of the private key
+ * @param keyPassword Password to access the key
+ * @param payLoad PayLoad to sign
+ * @param addFullCertChain If true the full certificate chain will be
+ * added, otherwise only the
+ * X509CertSha256Fingerprint is added into JOSE
+ * header
+ * @param joseHeaders HeaderName and HeaderValue that should be set
+ * into JOSE header
+ * @param rsaAlgToUse Signing algorithm that should be used in case
+ * of a signing key based on RSA
+ * @param eccAlgToUse Signing algorithm that should be used in case
+ * of a signing key based on ECC
+ * @param friendlyNameForLogging FriendlyName for the used KeyStore for logging
+ * purposes only
+ * @return Signed PayLoad in serialized form
+ * @throws EaafException In case of a key-access or key-usage error
+ * @throws JoseException In case of a JOSE error
+ */
+ public static String createSignature(@Nonnull Pair<KeyStore, Provider> keyStore,
+ @Nonnull final String keyAlias, @Nonnull final char[] keyPassword,
+ @Nonnull final String payLoad, boolean addFullCertChain,
+ @Nonnull final Map<String, String> joseHeaders,
+ @Nonnull final String rsaAlgToUse, @Nonnull final String eccAlgToUse,
+ @Nonnull String friendlyNameForLogging) throws EaafException, JoseException {
+
+ final JsonWebSignature jws = new JsonWebSignature();
+
+ // set payload
+ jws.setPayload(payLoad);
+
+ // set JOSE headers
+ for (final Entry<String, String> el : joseHeaders.entrySet()) {
+ log.trace("Set JOSE header: {} with value: {} into JWS", el.getKey(), el.getValue());
+ jws.setHeader(el.getKey(), el.getValue());
+
+ }
+
+ // set signing information
+ final Pair<Key, X509Certificate[]> signingCred = EaafKeyStoreUtils.getPrivateKeyAndCertificates(
+ keyStore.getFirst(), keyAlias, keyPassword, true, friendlyNameForLogging);
+
+ // set verification key
+ jws.setKey(convertToBcKeyIfRequired(signingCred.getFirst()));
+
+ jws.setAlgorithmHeaderValue(getKeyOperationAlgorithmFromCredential(
+ jws.getKey(), rsaAlgToUse, eccAlgToUse, friendlyNameForLogging));
+
+ // set special provider if required
+ if (keyStore.getSecond() != null) {
+ log.trace("Injecting special Java Security Provider: {}", keyStore.getSecond().getName());
+ final ProviderContext providerCtx = new ProviderContext();
+ providerCtx.getSuppliedKeyProviderContext().setSignatureProvider(keyStore.getSecond().getName());
+ providerCtx.getGeneralProviderContext().setGeneralProvider(BouncyCastleProvider.PROVIDER_NAME);
+ jws.setProviderContext(providerCtx);
+
+ } else {
+ final ProviderContext providerCtx = new ProviderContext();
+ providerCtx.getGeneralProviderContext().setGeneralProvider(BouncyCastleProvider.PROVIDER_NAME);
+ jws.setProviderContext(providerCtx);
+
+ }
+
+ if (addFullCertChain) {
+ jws.setCertificateChainHeaderValue(signingCred.getSecond());
+
+ }
+
+ jws.setX509CertSha256ThumbprintHeaderValue(signingCred.getSecond()[0]);
+
+ return jws.getCompactSerialization();
+
+ }
+
+ /**
+ * Verify a JOSE signature.
+ *
+ * @param serializedContent Serialized content that should be verified
+ * @param trustedCerts Trusted certificates that should be used for
+ * verification
+ * @param constraints {@link AlgorithmConstraints} for verification
+ * @return {@link JwsResult} object
+ * @throws JoseException In case of a signature verification error
+ * @throws IOException In case of a general error
+ */
+ public static JwsResult validateSignature(@Nonnull final String serializedContent,
+ @Nonnull final List<X509Certificate> trustedCerts, @Nonnull final AlgorithmConstraints constraints)
+ throws JoseException, IOException {
+ final JsonWebSignature jws = new JsonWebSignature();
+ // set payload
+ jws.setCompactSerialization(serializedContent);
+
+ // set security constrains
+ jws.setAlgorithmConstraints(constraints);
+
+ // load signinc certs
+ Key selectedKey = null;
+ final List<X509Certificate> x5cCerts = jws.getCertificateChainHeaderValue();
+ final String x5t256 = jws.getX509CertSha256ThumbprintHeaderValue();
+ if (x5cCerts != null) {
+ log.debug("Found x509 certificate in JOSE header ... ");
+ log.trace("Sorting received X509 certificates ... ");
+ final List<X509Certificate> sortedX5cCerts = X509Utils.sortCertificates(x5cCerts);
+
+
+
+ if (trustedCerts.contains(sortedX5cCerts.get(0))) {
+ selectedKey = sortedX5cCerts.get(0).getPublicKey();
+
+ } else {
+ log.info("Can NOT find JOSE certificate in truststore.");
+ if (log.isDebugEnabled()) {
+ try {
+ log.debug("Cert: {}", Base64Utils.encodeToString(sortedX5cCerts.get(0).getEncoded()));
+
+ } catch (final CertificateEncodingException e) {
+ log.warn("Can not create DEBUG output", e);
+
+ }
+ }
+ }
+
+ } else if (StringUtils.isNotEmpty(x5t256)) {
+ log.debug("Found x5t256 fingerprint in JOSE header .... ");
+ final X509VerificationKeyResolver x509VerificationKeyResolver = new X509VerificationKeyResolver(
+ trustedCerts);
+ selectedKey = x509VerificationKeyResolver.resolveKey(jws, Collections.<JsonWebStructure>emptyList());
+
+ } else {
+ throw new JoseException("JWS contains NO signature certificate or NO certificate fingerprint");
+
+ }
+
+ if (selectedKey == null) {
+ throw new JoseException("Can NOT select verification key for JWS. Signature verification FAILED");
+
+ }
+
+ //set BouncyCastleProvider as default provider
+ final ProviderContext providerCtx = new ProviderContext();
+ providerCtx.getGeneralProviderContext().setGeneralProvider(BouncyCastleProvider.PROVIDER_NAME);
+ jws.setProviderContext(providerCtx);
+
+ // set verification key
+ jws.setKey(convertToBcKeyIfRequired(selectedKey));
+
+ // load payLoad
+ return new JwsResult(
+ jws.verifySignature(),
+ jws.getUnverifiedPayload(),
+ jws.getHeaders(),
+ x5cCerts);
+
+ }
+
+
+ /**
+ * Convert an ECC public-key into BouncyCastle implementation.
+ *
+ * <p> IAIK JCE / Eccelerate ECC Keys are not compatible to JWS impl.</p>
+ * @param input Key
+ * @return input Key, or BC ECC-Key in case of a ECC Key
+ */
+ public static Key convertToBcKeyIfRequired(Key input) {
+ try {
+ if (input instanceof ECPublicKey
+ && "iaik.security.ec.common.ECPublicKey".equals(input.getClass().getName())) {
+
+ //convert Key to BouncyCastle KeyImplemenation because there is an
+ //incompatibility with IAIK EC Keys and JWS signature-verfification implementation
+ PublicKey publicKey = KeyFactory.getInstance(
+ input.getAlgorithm(), provider).generatePublic(
+ new X509EncodedKeySpec(input.getEncoded()));
+ return publicKey;
+
+ } else if (input instanceof ECPrivateKey
+ && "iaik.security.ec.common.ECPrivateKey".equals(input.getClass().getName())) {
+ //convert Key to BouncyCastle KeyImplemenation because there is an
+ //incompatibility with IAIK EC Keys and JWS signature-creation implementation
+ Key privateKey = KeyFactory.getInstance(
+ input.getAlgorithm(), provider).generatePrivate(
+ new PKCS8EncodedKeySpec(input.getEncoded()));
+
+ return privateKey;
+
+ }
+
+ } catch (InvalidKeySpecException | NoSuchAlgorithmException e) {
+ log.warn("Can NOT convert {} to {}. The verification may FAIL.",
+ input.getClass().getName(), PublicKey.class.getName(), e);
+
+ }
+
+ return input;
+
+ }
+
+ /**
+ * Select signature algorithm for a given credential.
+ *
+ * @param key {@link X509Credential} that will be used for
+ * key operations
+ * @param rsaSigAlgorithm RSA based algorithm that should be used in case
+ * of RSA credential
+ * @param ecSigAlgorithm EC based algorithm that should be used in case
+ * of RSA credential
+ * @param friendlyNameForLogging KeyStore friendlyName for logging purposes
+ * @return either the RSA based algorithm or the EC based algorithm
+ * @throws EaafKeyUsageException In case of an unsupported private-key type
+ */
+ private static String getKeyOperationAlgorithmFromCredential(Key key,
+ String rsaSigAlgorithm, String ecSigAlgorithm, String friendlyNameForLogging)
+ throws EaafKeyUsageException {
+ if (key instanceof RSAPrivateKey) {
+ return rsaSigAlgorithm;
+
+ } else if (key instanceof ECPrivateKey) {
+ return ecSigAlgorithm;
+
+ } else {
+ log.warn("Could NOT select the cryptographic algorithm from Private-Key type");
+ throw new EaafKeyUsageException(EaafKeyUsageException.ERROR_CODE_01,
+ friendlyNameForLogging,
+ "Can not select cryptographic algorithm");
+
+ }
+
+ }
+
+ private JoseUtils() {
+
+ }
+
+ @Getter
+ @AllArgsConstructor
+ public static class JwsResult {
+ final boolean valid;
+ final String payLoad;
+ final Headers fullJoseHeader;
+ final List<X509Certificate> x5cCerts;
+
+ }
+}
diff --git a/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/utils/JsonSecurityUtils.java b/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/utils/JsonSecurityUtils.java
index 43c44647..58e3e41c 100644
--- a/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/utils/JsonSecurityUtils.java
+++ b/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/utils/JsonSecurityUtils.java
@@ -14,15 +14,14 @@ import javax.annotation.Nonnull;
import javax.annotation.PostConstruct;
import org.apache.commons.lang3.StringUtils;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.jose4j.jca.ProviderContext;
import org.jose4j.jwa.AlgorithmConstraints;
import org.jose4j.jwa.AlgorithmConstraints.ConstraintType;
import org.jose4j.jwe.JsonWebEncryption;
import org.jose4j.jws.AlgorithmIdentifiers;
-import org.jose4j.jws.JsonWebSignature;
-import org.jose4j.jwx.JsonWebStructure;
+import org.jose4j.jwx.HeaderParameterNames;
import org.jose4j.keys.X509Util;
-import org.jose4j.keys.resolvers.X509VerificationKeyResolver;
import org.jose4j.lang.JoseException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -37,6 +36,7 @@ import com.fasterxml.jackson.databind.JsonNode;
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.impl.credential.EaafKeyStoreFactory;
import at.gv.egiz.eaaf.core.impl.credential.EaafKeyStoreUtils;
import at.gv.egiz.eaaf.core.impl.credential.KeyStoreConfiguration;
@@ -49,6 +49,7 @@ import at.gv.egiz.eaaf.modules.auth.sl20.exceptions.SL20Exception;
import at.gv.egiz.eaaf.modules.auth.sl20.exceptions.SL20SecurityException;
import at.gv.egiz.eaaf.modules.auth.sl20.exceptions.SlCommandoBuildException;
import at.gv.egiz.eaaf.modules.auth.sl20.exceptions.SlCommandoParserException;
+import at.gv.egiz.eaaf.modules.auth.sl20.utils.JoseUtils.JwsResult;
@Service
public class JsonSecurityUtils implements IJoseTools {
@@ -125,40 +126,16 @@ public class JsonSecurityUtils implements IJoseTools {
@Override
public String createSignature(final String payLoad, boolean addFullCertChain) throws SlCommandoBuildException {
try {
- final JsonWebSignature jws = new JsonWebSignature();
-
- // set payload
- jws.setPayload(payLoad);
-
- // set basic header
- jws.setContentTypeHeaderValue(SL20Constants.SL20_CONTENTTYPE_SIGNED_COMMAND);
-
- // set signing information
- jws.setAlgorithmHeaderValue(AlgorithmIdentifiers.RSA_USING_SHA256);
- final Pair<Key, X509Certificate[]> signingCred = EaafKeyStoreUtils.getPrivateKeyAndCertificates(
- keyStore.getFirst(), getSigningKeyAlias(), getSigningKeyPassword(), true, FRIENDLYNAME_KEYSTORE);
- jws.setKey(signingCred.getFirst());
-
- // set special provider if required
- if (keyStore.getSecond() != null) {
- log.trace("Injecting special Java Security Provider: {}", keyStore.getSecond().getName());
- final ProviderContext providerCtx = new ProviderContext();
- providerCtx.getSuppliedKeyProviderContext().setSignatureProvider(
- keyStore.getSecond().getName());
- jws.setProviderContext(providerCtx);
-
- }
-
- if (addFullCertChain) {
- jws.setCertificateChainHeaderValue(signingCred.getSecond());
-
- }
-
- jws.setX509CertSha256ThumbprintHeaderValue(signingCred.getSecond()[0]);
-
- return jws.getCompactSerialization();
+ return JoseUtils.createSignature(keyStore, getSigningKeyAlias(), getSigningKeyPassword(),
+ payLoad, addFullCertChain,
+ Collections.singletonMap(
+ HeaderParameterNames.CONTENT_TYPE,
+ SL20Constants.SL20_CONTENTTYPE_SIGNED_COMMAND),
+ getRsaSigningAlgorithm(),
+ getEccSigningAlgorithm(),
+ FRIENDLYNAME_KEYSTORE);
- } catch (final JoseException | EaafKeyAccessException e) {
+ } catch (final JoseException | EaafException e) {
log.warn("Can NOT sign SL2.0 command.", e);
throw new SlCommandoBuildException("Can NOT sign SL2.0 command.", e);
@@ -179,61 +156,12 @@ public class JsonSecurityUtils implements IJoseTools {
public VerificationResult validateSignature(@Nonnull final String serializedContent,
@Nonnull final List<X509Certificate> trustedCerts, @Nonnull final AlgorithmConstraints constraints)
throws JoseException, IOException {
- final JsonWebSignature jws = new JsonWebSignature();
- // set payload
- jws.setCompactSerialization(serializedContent);
-
- // set security constrains
- jws.setAlgorithmConstraints(constraints);
-
- // load signinc certs
- Key selectedKey = null;
- final List<X509Certificate> x5cCerts = jws.getCertificateChainHeaderValue();
- final String x5t256 = jws.getX509CertSha256ThumbprintHeaderValue();
- if (x5cCerts != null) {
- log.debug("Found x509 certificate in JOSE header ... ");
- log.trace("Sorting received X509 certificates ... ");
- final List<X509Certificate> sortedX5cCerts = X509Utils.sortCertificates(x5cCerts);
-
- if (trustedCerts.contains(sortedX5cCerts.get(0))) {
- selectedKey = sortedX5cCerts.get(0).getPublicKey();
-
- } else {
- log.info("Can NOT find JOSE certificate in truststore.");
- try {
- log.debug("Cert: " + Base64Utils.encodeToString(sortedX5cCerts.get(0).getEncoded()));
-
- } catch (final CertificateEncodingException e) {
- e.printStackTrace();
- }
-
- }
-
- } else if (StringUtils.isNotEmpty(x5t256)) {
- log.debug("Found x5t256 fingerprint in JOSE header .... ");
- final X509VerificationKeyResolver x509VerificationKeyResolver = new X509VerificationKeyResolver(
- trustedCerts);
- selectedKey = x509VerificationKeyResolver.resolveKey(jws, Collections.<JsonWebStructure>emptyList());
-
- } else {
- throw new JoseException("JWS contains NO signature certificate or NO certificate fingerprint");
-
- }
-
- if (selectedKey == null) {
- throw new JoseException("Can NOT select verification key for JWS. Signature verification FAILED");
-
- }
-
- // set verification key
- jws.setKey(selectedKey);
-
- // load payLoad
+ final JwsResult result = JoseUtils.validateSignature(serializedContent, trustedCerts, constraints);
return new VerificationResult(
- mapper.getMapper().readTree(jws.getHeaders().getFullHeaderAsJsonString()),
- mapper.getMapper().readTree(jws.getPayload()),
- x5cCerts, jws.verifySignature());
+ mapper.getMapper().readTree(result.getFullJoseHeader().getFullHeaderAsJsonString()),
+ mapper.getMapper().readTree(result.getPayLoad()),
+ result.getX5cCerts(), result.isValid());
}
@@ -241,7 +169,7 @@ public class JsonSecurityUtils implements IJoseTools {
@Nonnull
public VerificationResult validateSignature(@Nonnull final String serializedContent) throws SL20Exception {
try {
- final AlgorithmConstraints algConstraints = new AlgorithmConstraints(ConstraintType.WHITELIST,
+ final AlgorithmConstraints algConstraints = new AlgorithmConstraints(ConstraintType.PERMIT,
SL20Constants.SL20_ALGORITHM_WHITELIST_SIGNING
.toArray(new String[SL20Constants.SL20_ALGORITHM_WHITELIST_SIGNING.size()]));
@@ -251,7 +179,7 @@ public class JsonSecurityUtils implements IJoseTools {
if (!result.isValidSigned()) {
log.info("JWS signature invalide. Stopping authentication process ...");
- log.debug("Received JWS msg: " + serializedContent);
+ log.debug("Received JWS msg: {}", serializedContent);
throw new SL20SecurityException("JWS signature invalide.");
}
@@ -278,11 +206,11 @@ public class JsonSecurityUtils implements IJoseTools {
// set security constrains
receiverJwe.setAlgorithmConstraints(
- new AlgorithmConstraints(ConstraintType.WHITELIST,
+ new AlgorithmConstraints(ConstraintType.PERMIT,
SL20Constants.SL20_ALGORITHM_WHITELIST_KEYENCRYPTION
.toArray(new String[SL20Constants.SL20_ALGORITHM_WHITELIST_KEYENCRYPTION.size()])));
receiverJwe.setContentEncryptionAlgorithmConstraints(
- new AlgorithmConstraints(ConstraintType.WHITELIST, SL20Constants.SL20_ALGORITHM_WHITELIST_ENCRYPTION
+ new AlgorithmConstraints(ConstraintType.PERMIT, SL20Constants.SL20_ALGORITHM_WHITELIST_ENCRYPTION
.toArray(new String[SL20Constants.SL20_ALGORITHM_WHITELIST_ENCRYPTION.size()])));
// set payload
@@ -292,6 +220,21 @@ public class JsonSecurityUtils implements IJoseTools {
keyStore.getFirst(), getEncryptionKeyAlias(), getEncryptionKeyPassword(), true,
FRIENDLYNAME_KEYSTORE);
+ // set special provider if required
+ if (keyStore.getSecond() != null) {
+ log.trace("Injecting special Java Security Provider: {}", keyStore.getSecond().getName());
+ final ProviderContext providerCtx = new ProviderContext();
+ providerCtx.getSuppliedKeyProviderContext().setGeneralProvider(keyStore.getSecond().getName());
+ providerCtx.getGeneralProviderContext().setGeneralProvider(BouncyCastleProvider.PROVIDER_NAME);
+ receiverJwe.setProviderContext(providerCtx);
+
+ } else {
+ final ProviderContext providerCtx = new ProviderContext();
+ providerCtx.getGeneralProviderContext().setGeneralProvider(BouncyCastleProvider.PROVIDER_NAME);
+ receiverJwe.setProviderContext(providerCtx);
+
+ }
+
// validate key from header against key from config
final List<X509Certificate> x5cCerts = receiverJwe.getCertificateChainHeaderValue();
final String x5t256 = receiverJwe.getX509CertSha256ThumbprintHeaderValue();
@@ -318,7 +261,7 @@ public class JsonSecurityUtils implements IJoseTools {
final String certFingerPrint = X509Util.x5tS256(encryptionCred.getSecond()[0]);
if (!certFingerPrint.equals(x5t256)) {
log.info("X5t256 from JOSE header does NOT match encryption certificate");
- log.debug("X5t256 from JOSE header: " + x5t256 + " Encrytption cert: " + certFingerPrint);
+ log.debug("X5t256 from JOSE header: {} Encrytption cert: {}", x5t256, certFingerPrint);
throw new SL20Exception("sl20.05",
new Object[] { "X5t256 from JOSE header does NOT match encryption certificate" });
@@ -332,7 +275,7 @@ public class JsonSecurityUtils implements IJoseTools {
}
// set key
- receiverJwe.setKey(encryptionCred.getFirst());
+ receiverJwe.setKey(JoseUtils.convertToBcKeyIfRequired(encryptionCred.getFirst()));
// decrypt payload
return mapper.getMapper().readTree(receiverJwe.getPlaintextString());
@@ -377,8 +320,7 @@ public class JsonSecurityUtils implements IJoseTools {
config.setFriendlyName(FRIENDLYNAME_KEYSTORE);
config.setKeyStoreType(authConfig.getBasicConfiguration(
- authConfig.getBasicConfiguration(Constants.CONFIG_PROP_SECURITY_KEYSTORE_TYPE),
- KeyStoreType.JKS.getKeyStoreType()));
+ Constants.CONFIG_PROP_SECURITY_KEYSTORE_TYPE, KeyStoreType.JKS.getKeyStoreType()));
config.setKeyStoreName(
authConfig.getBasicConfiguration(Constants.CONFIG_PROP_SECURITY_KEYSTORE_NAME));
config.setSoftKeyStoreFilePath(
@@ -398,8 +340,7 @@ public class JsonSecurityUtils implements IJoseTools {
config.setFriendlyName(FRIENDLYNAME_TRUSTSTORE);
config.setKeyStoreType(authConfig.getBasicConfiguration(
- authConfig.getBasicConfiguration(Constants.CONFIG_PROP_SECURITY_TRUSTSTORE_TYPE),
- KeyStoreType.JKS.getKeyStoreType()));
+ Constants.CONFIG_PROP_SECURITY_TRUSTSTORE_TYPE, KeyStoreType.JKS.getKeyStoreType()));
config.setKeyStoreName(
authConfig.getBasicConfiguration(Constants.CONFIG_PROP_SECURITY_TRUSTSTORE_NAME));
config.setSoftKeyStoreFilePath(
@@ -452,4 +393,26 @@ public class JsonSecurityUtils implements IJoseTools {
return null;
}
+ private String getRsaSigningAlgorithm() {
+ String value = authConfig.getBasicConfiguration(Constants.CONFIG_PROP_SECURITY_SIG_ALG_RSA,
+ AlgorithmIdentifiers.RSA_PSS_USING_SHA256);
+ if (value != null) {
+ value = value.trim();
+ }
+
+ return value;
+
+ }
+
+ private String getEccSigningAlgorithm() {
+ String value = authConfig.getBasicConfiguration(Constants.CONFIG_PROP_SECURITY_SIG_ALG_ECC,
+ AlgorithmIdentifiers.ECDSA_USING_P256_CURVE_AND_SHA256);
+ if (value != null) {
+ value = value.trim();
+ }
+
+ return value;
+
+ }
+
}
diff --git a/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/utils/SL20Constants.java b/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/utils/SL20Constants.java
index edf70cc8..c95bcc45 100644
--- a/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/utils/SL20Constants.java
+++ b/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/utils/SL20Constants.java
@@ -13,14 +13,15 @@ import org.jose4j.jws.AlgorithmIdentifiers;
public class SL20Constants {
public static final int CURRENT_SL20_VERSION = 10;
-
+
// http binding parameters
public static final String PARAM_SL20_REQ_COMMAND_PARAM = "slcommand";
public static final String PARAM_SL20_REQ_COMMAND_PARAM_OLD = "sl2command";
public static final String PARAM_SL20_REQ_AUTH_METHOD_PARAM = "authtype";
public static final String PARAM_SL20_REQ_AUTH_VDA_SESSIONID = "session";
-
+ public static final String PARAM_SL20_REQ_AUTH_VDA_LOCALE = "locale";
+
public enum VdaAuthMethod {
ANY("any"), MOBILEPHONE("handy"), CARD("card"), SMARTPHONE("smartphone");
@@ -51,7 +52,7 @@ public class SL20Constants {
} catch (IllegalArgumentException | NullPointerException e) {
return VdaAuthMethod.ANY;
-
+
}
}
@@ -59,9 +60,9 @@ public class SL20Constants {
public String toString() {
return getAuthMethod();
- }
+ }
}
-
+
public static final String PARAM_SL20_REQ_ICP_RETURN_URL_PARAM = "slIPCReturnUrl";
public static final String PARAM_SL20_REQ_TRANSACTIONID = "slTransactionID";
@@ -97,7 +98,11 @@ public class SL20Constants {
KeyManagementAlgorithmIdentifiers.RSA_OAEP_256;
public static final List<String> SL20_ALGORITHM_WHITELIST_KEYENCRYPTION = Collections
- .unmodifiableList(Arrays.asList(JSON_ALGORITHM_ENC_KEY_RSAOAEP, JSON_ALGORITHM_ENC_KEY_RSAOAEP256));
+ .unmodifiableList(Arrays.asList(
+ JSON_ALGORITHM_ENC_KEY_RSAOAEP,
+ JSON_ALGORITHM_ENC_KEY_RSAOAEP256,
+ KeyManagementAlgorithmIdentifiers.ECDH_ES_A128KW,
+ KeyManagementAlgorithmIdentifiers.ECDH_ES_A256KW));
public static final String JSON_ALGORITHM_ENC_PAYLOAD_A128CBCHS256 =
ContentEncryptionAlgorithmIdentifiers.AES_128_CBC_HMAC_SHA_256;
@@ -177,7 +182,7 @@ public class SL20Constants {
// error command
public static final String SL20_COMMAND_PARAM_GENERAL_RESPONSE_ERRORCODE = "errorCode";
public static final String SL20_COMMAND_PARAM_GENERAL_RESPONSE_ERRORMESSAGE = "errorMessage";
- public static final String SL20_COMMAND_PARAM_GENERAL_RESPONSE_ERROR_VDASESSIONID
+ public static final String SL20_COMMAND_PARAM_GENERAL_RESPONSE_ERROR_VDASESSIONID
= "handySignaturSession";
// qualified eID command
diff --git a/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/utils/SL20HttpBindingUtils.java b/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/utils/SL20HttpBindingUtils.java
index 1d7c9646..2b6ddb96 100644
--- a/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/utils/SL20HttpBindingUtils.java
+++ b/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/utils/SL20HttpBindingUtils.java
@@ -3,23 +3,133 @@ package at.gv.egiz.eaaf.modules.auth.sl20.utils;
import java.io.IOException;
import java.io.StringWriter;
import java.net.URISyntaxException;
+import java.text.MessageFormat;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
+import org.apache.http.Header;
+import org.apache.http.HttpEntity;
+import org.apache.http.ParseException;
+import org.apache.http.StatusLine;
+import org.apache.http.client.ResponseHandler;
import org.apache.http.client.utils.URIBuilder;
+import org.apache.http.entity.ContentType;
+import org.apache.http.util.EntityUtils;
import org.jose4j.base64url.Base64Url;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import com.fasterxml.jackson.databind.JsonNode;
+import at.gv.egiz.eaaf.modules.auth.sl20.exceptions.SlCommandoParserException;
+import lombok.Data;
+import lombok.Getter;
+
public class SL20HttpBindingUtils {
private static final Logger log = LoggerFactory.getLogger(SL20HttpBindingUtils.class);
+ private static JsonMapper mapper = new JsonMapper();
+
+ @Data
+ @Getter
+ public static class Sl20ResponseHolder {
+ private final JsonNode responseBody;
+ private final StatusLine responseStatus;
+ private SlCommandoParserException error;
+
+ }
+
+ /**
+ * Security-Layer 2.0 specific response-handler for Apache HTTP client.
+ *
+ * @return {@link Sl20ResponseHolder}
+ */
+ public static ResponseHandler<Sl20ResponseHolder> sl20ResponseHandler() {
+ return response -> {
+ try {
+ final int httpStatusCode = response.getStatusLine().getStatusCode();
+ if (httpStatusCode == HttpStatus.OK.value()) {
+ if (response.getEntity().getContentType() == null) {
+ throw new SlCommandoParserException("SL20 response contains NO ContentType");
+
+ }
+
+ final ContentType contentType = ContentType.getOrDefault(response.getEntity());
+ if (!ContentType.APPLICATION_JSON.getMimeType().equals(contentType.getMimeType())) {
+ log.error("SL20 response with statuscode: {} has wrong http ContentType: {}",
+ response.getStatusLine(), contentType);
+ throw new SlCommandoParserException(
+ "SL20 response with a wrong http ContentType: " + contentType);
+
+ }
+
+ //parse OK response from body
+ return new Sl20ResponseHolder(parseSL20ResultFromResponse(response.getEntity()),
+ response.getStatusLine());
+
+ } else if (httpStatusCode == HttpStatus.SEE_OTHER.value()
+ || httpStatusCode == HttpStatus.TEMPORARY_REDIRECT.value()) {
+ final Header[] locationHeader = response.getHeaders("Location");
+ if (locationHeader == null) {
+ throw new SlCommandoParserException("Find Redirect statuscode but not Location header");
+
+ }
+
+ final String sl20RespString = new URIBuilder(locationHeader[0].getValue()).getQueryParams().get(0).getValue();
+ return new Sl20ResponseHolder(mapper.getMapper().readTree(Base64Url.decode(sl20RespString)),
+ response.getStatusLine());
+
+ } else if (
+ httpStatusCode == HttpStatus.INTERNAL_SERVER_ERROR.value()
+ || httpStatusCode == HttpStatus.UNAUTHORIZED.value()
+ || httpStatusCode == HttpStatus.BAD_REQUEST.value()) {
+ log.info("SL20 response with http-code: {}. Search for error message", httpStatusCode);
+
+ String bodyMsg = "_EMPTY_";
+ try {
+ //extract JSON body from defined http error-codes
+ bodyMsg = EntityUtils.toString(response.getEntity());
+ log.info("SL20 response with http-code: {0} and errorMsg: {1}", httpStatusCode, bodyMsg);
+ Sl20ResponseHolder holder = new Sl20ResponseHolder(
+ mapper.getMapper().readTree(bodyMsg), response.getStatusLine());
+ return holder;
+
+ } catch (final IOException | ParseException e) {
+ log.warn("SL20 response contains no )valid JSON", e);
+ throw new SlCommandoParserException(MessageFormat.format(
+ "SL20 response with http-code: {0} with body: {1} and generic response-processing error: {2}",
+ httpStatusCode, bodyMsg, e.getMessage()));
+
+ }
+
+ } else {
+ //all other HTTP StatusCodes
+ throw new SlCommandoParserException(MessageFormat.format(
+ "SL20 response with http-code: {0} and errorMsg: {1}",
+ httpStatusCode, EntityUtils.toString(response.getEntity())));
+
+ }
+
+ } catch (SlCommandoParserException e) {
+ Sl20ResponseHolder holder = new Sl20ResponseHolder(null, response.getStatusLine());
+ holder.setError(e);
+ return holder;
+
+ } catch (final Exception e) {
+ Sl20ResponseHolder holder = new Sl20ResponseHolder(null, response.getStatusLine());
+ holder.setError(
+ new SlCommandoParserException("SL20 response parsing FAILED! Reason: " + e.getMessage(), e));
+ return holder;
+
+ }
+ };
+ }
+
/**
* Write SL2.0 response into http-response object
*
@@ -59,6 +169,34 @@ public class SL20HttpBindingUtils {
httpResp.setHeader("Location", clientRedirectUri.build().toString());
}
+ }
+
+ private static JsonNode parseSL20ResultFromResponse(final HttpEntity resp) throws Exception {
+ if (resp != null && resp.getContent() != null) {
+ final String rawSL20Resp = EntityUtils.toString(resp);
+ try {
+ final JsonNode sl20Resp = mapper.getMapper().readTree(rawSL20Resp);
+ if (sl20Resp != null) {
+ return sl20Resp;
+
+ } else {
+ log.error("SL2.0 can NOT parse to a JSON object from msg: {}", rawSL20Resp);
+ throw new SlCommandoParserException("SL2.0 can NOT parse to a JSON object");
+ }
+
+ } catch (SlCommandoParserException e) {
+ throw e;
+
+ } catch (Exception e) {
+ log.error("SL2.0 can NOT parse to a JSON object from msg: {}", rawSL20Resp);
+ throw new SlCommandoParserException("SL2.0 can NOT parse to a JSON object");
+
+ }
+
+ } else {
+ throw new SlCommandoParserException("Can NOT find any content in http response");
+
+ }
}
}
diff --git a/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/utils/SL20JsonExtractorUtils.java b/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/utils/SL20JsonExtractorUtils.java
index 40ea0430..bed25c0c 100644
--- a/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/utils/SL20JsonExtractorUtils.java
+++ b/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/utils/SL20JsonExtractorUtils.java
@@ -8,12 +8,6 @@ import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
-import org.apache.http.Header;
-import org.apache.http.HttpEntity;
-import org.apache.http.HttpResponse;
-import org.apache.http.client.utils.URIBuilder;
-import org.apache.http.util.EntityUtils;
-import org.jose4j.base64url.Base64Url;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -299,84 +293,6 @@ public class SL20JsonExtractorUtils {
}
- /**
- * Extract generic transport container from httpResponse.
- *
- * @param httpResp Http response object
- * @return JSON with SL2.0 response
- * @throws SlCommandoParserException In case of an error
- */
- public static JsonNode getSL20ContainerFromResponse(final HttpResponse httpResp) throws SlCommandoParserException {
- try {
- JsonNode sl20Resp = null;
- if (httpResp.getStatusLine().getStatusCode() == 303 || httpResp.getStatusLine().getStatusCode() == 307) {
- final Header[] locationHeader = httpResp.getHeaders("Location");
- if (locationHeader == null) {
- throw new SlCommandoParserException("Find Redirect statuscode but not Location header");
- }
-
- final String sl20RespString = new URIBuilder(locationHeader[0].getValue()).getQueryParams().get(0).getValue();
- sl20Resp = mapper.getMapper().readTree(Base64Url.decode(sl20RespString));
-
- } else if (httpResp.getStatusLine().getStatusCode() == 200) {
- if (httpResp.getEntity().getContentType() == null) {
- throw new SlCommandoParserException("SL20 response contains NO ContentType");
- }
-
- if (!httpResp.getEntity().getContentType().getValue().startsWith("application/json")) {
- throw new SlCommandoParserException(
- "SL20 response with a wrong ContentType: " + httpResp.getEntity().getContentType().getValue());
- }
- sl20Resp = parseSL20ResultFromResponse(httpResp.getEntity());
-
- } else if (httpResp.getStatusLine().getStatusCode() == 500 || httpResp.getStatusLine().getStatusCode() == 401
- || httpResp.getStatusLine().getStatusCode() == 400) {
- log.info(
- "SL20 response with http-code: " + httpResp.getStatusLine().getStatusCode() + ". Search for error message");
-
- try {
- sl20Resp = parseSL20ResultFromResponse(httpResp.getEntity());
-
- } catch (final Exception e) {
- log.warn("SL20 response contains no valid JSON", e);
- throw new SlCommandoParserException("SL20 response with http-code: "
- + httpResp.getStatusLine().getStatusCode() + " AND NO valid JSON errormsg", e);
-
- }
-
- } else {
- throw new SlCommandoParserException(
- "SL20 response with http-code: " + httpResp.getStatusLine().getStatusCode());
- }
-
- log.info("Find JSON object in http response");
- return sl20Resp;
-
- } catch (final Exception e) {
- throw new SlCommandoParserException("SL20 response parsing FAILED! Reason: " + e.getMessage(), e);
-
- }
- }
-
- private static JsonNode parseSL20ResultFromResponse(final HttpEntity resp) throws Exception {
- if (resp != null && resp.getContent() != null) {
- final String rawSL20Resp = EntityUtils.toString(resp);
- final JsonNode sl20Resp = mapper.getMapper().readTree(rawSL20Resp);
-
- // TODO: check sl20Resp type like && sl20Resp.isJsonObject()
- if (sl20Resp != null) {
- return sl20Resp;
-
- } else {
- throw new SlCommandoParserException("SL2.0 can NOT parse to a JSON object");
- }
-
- } else {
- throw new SlCommandoParserException("Can NOT find content in http response");
- }
-
- }
-
private static JsonNode getAndCheck(final JsonNode input, final String keyID, final boolean isRequired)
throws SlCommandoParserException {
final JsonNode internal = input.get(keyID);
diff --git a/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/utils/SL20ResponseUtils.java b/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/utils/SL20ResponseUtils.java
index 4bb91634..c3826087 100644
--- a/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/utils/SL20ResponseUtils.java
+++ b/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/utils/SL20ResponseUtils.java
@@ -11,17 +11,17 @@ import java.util.UUID;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
-import at.gv.egiz.eaaf.core.api.IRequest;
-import at.gv.egiz.eaaf.core.api.data.EaafConstants;
-import at.gv.egiz.eaaf.core.api.idp.IConfiguration;
-import at.gv.egiz.eaaf.modules.auth.sl20.Constants;
-import at.gv.egiz.eaaf.modules.auth.sl20.exceptions.SL20Exception;
-
import org.apache.commons.lang3.StringUtils;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.entity.ContentType;
import com.fasterxml.jackson.databind.node.ObjectNode;
+
+import at.gv.egiz.eaaf.core.api.IRequest;
+import at.gv.egiz.eaaf.core.api.data.EaafConstants;
+import at.gv.egiz.eaaf.core.api.idp.IConfiguration;
+import at.gv.egiz.eaaf.modules.auth.sl20.Constants;
+import at.gv.egiz.eaaf.modules.auth.sl20.exceptions.SL20Exception;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@@ -134,7 +134,7 @@ public class SL20ResponseUtils {
} else {
log.info("SL2.0 DataURL communication needs http header: '" + SL20Constants.HTTP_HEADER_SL20_CLIENT_TYPE + "'");
- log.debug("Client request containts is no native client ... ");
+ log.debug("Client request is no a native client. SL2.0 anwser will be a http redirect ... ");
final URIBuilder clientRedirectUri = new URIBuilder(fullRedirectUrl);
response.setStatus(Integer.parseInt(authConfig.getBasicConfiguration(Constants.CONFIG_PROP_HTTP_REDIRECT_CODE,
Constants.CONFIG_PROP_HTTP_REDIRECT_CODE_DEFAULT_VALUE)));
diff --git a/eaaf_modules/eaaf_module_auth_sl20/src/test/java/at/gv/egiz/eaaf/modules/auth/sl20/utils/AbstractJsonSecurityUtilsTest.java b/eaaf_modules/eaaf_module_auth_sl20/src/test/java/at/gv/egiz/eaaf/modules/auth/sl20/utils/AbstractJsonSecurityUtilsTest.java
new file mode 100644
index 00000000..ae4284d5
--- /dev/null
+++ b/eaaf_modules/eaaf_module_auth_sl20/src/test/java/at/gv/egiz/eaaf/modules/auth/sl20/utils/AbstractJsonSecurityUtilsTest.java
@@ -0,0 +1,394 @@
+package at.gv.egiz.eaaf.modules.auth.sl20.utils;
+
+import java.io.IOException;
+import java.security.Key;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.Provider;
+import java.security.Security;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.X509Certificate;
+
+import org.apache.commons.lang3.RandomStringUtils;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.jose4j.base64url.Base64Url;
+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.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+
+import com.fasterxml.jackson.databind.JsonNode;
+
+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.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.data.Pair;
+import at.gv.egiz.eaaf.core.test.dummy.DummyAuthConfigMap;
+import at.gv.egiz.eaaf.modules.auth.sl20.data.VerificationResult;
+import iaik.security.ec.provider.ECCelerate;
+import iaik.security.provider.IAIK;
+
+@RunWith(SpringJUnit4ClassRunner.class)
+@ContextConfiguration("/spring/test_eaaf_sl20_hsm.beans.xml")
+public abstract class AbstractJsonSecurityUtilsTest {
+
+ @Autowired protected DummyAuthConfigMap config;
+ @Autowired protected IJoseTools joseTools;
+ @Autowired protected EaafKeyStoreFactory keyStoreFactory;
+
+ /**
+ *jUnit test class initializer.
+ */
+ @BeforeClass
+ public static void classInitializer() {
+ IAIK.addAsProvider();
+ ECCelerate.addAsProvider();
+
+ Security.addProvider(new BouncyCastleProvider());
+ }
+
+ /**
+ * jUnit test class cleaner.
+ */
+ @AfterClass
+ public static final void classFinisher() {
+ Security.removeProvider(IAIK.getInstance().getName());
+ Security.removeProvider(ECCelerate.getInstance().getName());
+
+ }
+
+ protected abstract void setRsaSigningKey();
+
+ protected abstract void setEcSigningKey();
+
+ protected abstract void setRsaEncryptionKey();
+
+ protected abstract void setEcEncryptionKey();
+
+ protected abstract Pair<KeyStore, Provider> getEncryptionKeyStore() throws EaafException;
+
+ protected abstract String getRsaKeyAlias();
+
+ protected abstract String getRsaKeyPassword();
+
+ protected abstract String getEcKeyAlias();
+
+ protected abstract String getEcKeyPassword();
+
+
+ @Test
+ public void fullEncryptDecrypt() throws JoseException, EaafException {
+ final String payLoad = "{\"aac\":\"" + RandomStringUtils.randomAlphanumeric(100) + "\"}";
+
+ final JsonWebEncryption jwe = new JsonWebEncryption();
+ jwe.setAlgorithmHeaderValue(KeyManagementAlgorithmIdentifiers.ECDH_ES_A256KW);
+ jwe.setEncryptionMethodHeaderParameter(ContentEncryptionAlgorithmIdentifiers.AES_128_GCM);
+ jwe.setKey(JoseUtils.convertToBcKeyIfRequired(joseTools.getEncryptionCertificate().getPublicKey()));
+ jwe.setX509CertSha256ThumbprintHeaderValue(joseTools.getEncryptionCertificate());
+ jwe.setPayload(payLoad);
+
+ // set special provider if required
+ final Pair<KeyStore, Provider> rsaEncKeyStore = getEncryptionKeyStore();
+ if (rsaEncKeyStore.getSecond() != null) {
+ final ProviderContext providerCtx = new ProviderContext();
+ providerCtx.getSuppliedKeyProviderContext().setSignatureProvider(
+ rsaEncKeyStore.getSecond().getName());
+ providerCtx.getGeneralProviderContext().setGeneralProvider(BouncyCastleProvider.PROVIDER_NAME);
+ jwe.setProviderContext(providerCtx);
+
+ } else {
+ final ProviderContext providerCtx = new ProviderContext();
+ providerCtx.getGeneralProviderContext().setGeneralProvider(BouncyCastleProvider.PROVIDER_NAME);
+ jwe.setProviderContext(providerCtx);
+
+ }
+
+ final String encData = jwe.getCompactSerialization();
+ Assert.assertNotNull("JWE Encryption", encData);
+
+
+ final JsonNode decData = joseTools.decryptPayload(encData);
+ Assert.assertNotNull("JWE Decryption", decData);
+
+ }
+
+ @Test
+ public void encryptionRsa() throws JoseException, EaafException {
+ final String payLoad = "{\"aac\":\"" + RandomStringUtils.randomAlphanumeric(100) + "\"}";
+ final Pair<KeyStore, Provider> rsaEncKeyStore = getEncryptionKeyStore();
+ final Pair<Key, X509Certificate[]> key = EaafKeyStoreUtils.getPrivateKeyAndCertificates(
+ rsaEncKeyStore.getFirst(), getRsaKeyAlias(), getRsaKeyPassword().toCharArray(),
+ true, "jUnit RSA JWE");
+
+ final JsonWebEncryption jwe = new JsonWebEncryption();
+ jwe.setAlgorithmHeaderValue(KeyManagementAlgorithmIdentifiers.RSA_OAEP_256);
+ jwe.setEncryptionMethodHeaderParameter(ContentEncryptionAlgorithmIdentifiers.AES_128_GCM);
+ jwe.setKey(key.getSecond()[0].getPublicKey());
+ jwe.setPayload(payLoad);
+
+ // set special provider if required
+ if (rsaEncKeyStore.getSecond() != null) {
+ final ProviderContext providerCtx = new ProviderContext();
+ providerCtx.getSuppliedKeyProviderContext().setSignatureProvider(
+ rsaEncKeyStore.getSecond().getName());
+ jwe.setProviderContext(providerCtx);
+
+ }
+
+ final String encData = jwe.getCompactSerialization();
+ Assert.assertNotNull("JWE", encData);
+
+
+ //decrypt it again
+ final JsonWebEncryption jweDecrypt = new JsonWebEncryption();
+ jweDecrypt.setCompactSerialization(encData);
+ jweDecrypt.setKey(JoseUtils.convertToBcKeyIfRequired(key.getFirst()));
+
+
+ // set special provider if required
+ if (rsaEncKeyStore.getSecond() != null) {
+ final ProviderContext providerCtx = new ProviderContext();
+ providerCtx.getSuppliedKeyProviderContext().setGeneralProvider(rsaEncKeyStore.getSecond().getName());
+ providerCtx.getGeneralProviderContext().setGeneralProvider(BouncyCastleProvider.PROVIDER_NAME);
+ jweDecrypt.setProviderContext(providerCtx);
+
+ } else {
+ final ProviderContext providerCtx = new ProviderContext();
+ providerCtx.getGeneralProviderContext().setGeneralProvider(BouncyCastleProvider.PROVIDER_NAME);
+ jweDecrypt.setProviderContext(providerCtx);
+
+ }
+
+ String decPayload = jweDecrypt.getPayload();
+ Assert.assertNotNull("decrypted Payload", decPayload);
+ Assert.assertEquals("Decrypted message not match", payLoad, decPayload);
+
+ }
+
+ @Test
+ public void encryptionEc() throws JoseException, EaafException {
+ final String payLoad = "{\"aac\":\"" + RandomStringUtils.randomAlphanumeric(100) + "\"}";
+ final Pair<KeyStore, Provider> rsaEncKeyStore = getEncryptionKeyStore();
+ final Pair<Key, X509Certificate[]> key = EaafKeyStoreUtils.getPrivateKeyAndCertificates(
+ rsaEncKeyStore.getFirst(), getEcKeyAlias(), getEcKeyPassword().toCharArray(),
+ true, "jUnit RSA JWE");
+
+ final JsonWebEncryption jwe = new JsonWebEncryption();
+ jwe.setAlgorithmHeaderValue(KeyManagementAlgorithmIdentifiers.ECDH_ES_A256KW);
+ jwe.setEncryptionMethodHeaderParameter(ContentEncryptionAlgorithmIdentifiers.AES_128_GCM);
+ jwe.setKey(JoseUtils.convertToBcKeyIfRequired(key.getSecond()[0].getPublicKey()));
+ jwe.setPayload(payLoad);
+
+ // set special provider if required
+ if (rsaEncKeyStore.getSecond() != null) {
+ final ProviderContext providerCtx = new ProviderContext();
+ providerCtx.getSuppliedKeyProviderContext().setGeneralProvider(rsaEncKeyStore.getSecond().getName());
+ providerCtx.getGeneralProviderContext().setGeneralProvider(BouncyCastleProvider.PROVIDER_NAME);
+ jwe.setProviderContext(providerCtx);
+
+ } else {
+ final ProviderContext providerCtx = new ProviderContext();
+ providerCtx.getGeneralProviderContext().setGeneralProvider(BouncyCastleProvider.PROVIDER_NAME);
+ jwe.setProviderContext(providerCtx);
+
+ }
+
+ final String encData = jwe.getCompactSerialization();
+
+ Assert.assertNotNull("JWE", encData);
+
+
+ //decrypt it again
+ final JsonWebEncryption jweDecrypt = new JsonWebEncryption();
+ jweDecrypt.setCompactSerialization(encData);
+ jweDecrypt.setKey(JoseUtils.convertToBcKeyIfRequired(key.getFirst()));
+
+
+ // set special provider if required
+ if (rsaEncKeyStore.getSecond() != null) {
+ final ProviderContext providerCtx = new ProviderContext();
+ providerCtx.getSuppliedKeyProviderContext().setGeneralProvider(rsaEncKeyStore.getSecond().getName());
+ providerCtx.getGeneralProviderContext().setGeneralProvider(BouncyCastleProvider.PROVIDER_NAME);
+ jweDecrypt.setProviderContext(providerCtx);
+
+ } else {
+ final ProviderContext providerCtx = new ProviderContext();
+ providerCtx.getGeneralProviderContext().setGeneralProvider(BouncyCastleProvider.PROVIDER_NAME);
+ jweDecrypt.setProviderContext(providerCtx);
+
+ }
+
+ String decPayload = jweDecrypt.getPayload();
+ Assert.assertNotNull("decrypted Payload", decPayload);
+ Assert.assertEquals("Decrypted message not match", payLoad, decPayload);
+
+ }
+
+
+ @Test
+ public void noTrustedCert() throws CertificateEncodingException, KeyStoreException,
+ JoseException, IOException, EaafException {
+ setRsaSigningKey();
+ setRsaEncryptionKey();
+
+ final String payLoad = "{\"aac\":\"" + RandomStringUtils.randomAlphanumeric(100) + "\"}";
+
+ final String jws = joseTools.createSignature(payLoad);
+ Assert.assertNotNull("Signed msg", jws);
+
+ try {
+ joseTools.validateSignature(
+ jws,
+ keyStoreFactory.buildNewKeyStore(getSigTrustStoreConfigOnlyEc()).getFirst(),
+ getDefaultAlgorithmConstrains());
+ Assert.fail("Wrong JOSE Sig not detected");
+
+ } catch (final JoseException e) {
+ Assert.assertEquals("Wrong errorCode",
+ "Can NOT select verification key for JWS. Signature verification FAILED",
+ e.getMessage());
+
+ }
+ }
+
+ @Test
+ public void invalidSignature() throws CertificateEncodingException, KeyStoreException,
+ JoseException, IOException, EaafException {
+ setRsaSigningKey();
+ setRsaEncryptionKey();
+
+ final String payLoad = "{\"aac\":\"" + RandomStringUtils.randomAlphanumeric(100) + "\"}";
+
+ final String jws = joseTools.createSignature(payLoad);
+ Assert.assertNotNull("Signed msg", jws);
+
+ final String invalidJws = jws.substring(0, jws.indexOf("."))
+ + "."
+ + Base64Url.encodeUtf8ByteRepresentation("{\"aac\":\"" + RandomStringUtils.randomAlphabetic(25) + "\"}")
+ + "."
+ + jws.substring(jws.lastIndexOf(".") + 1);
+
+
+ final VerificationResult result = joseTools.validateSignature(
+ invalidJws,
+ keyStoreFactory.buildNewKeyStore(getSigTrustStoreConfigValid()).getFirst(),
+ getDefaultAlgorithmConstrains());
+
+ Assert.assertFalse("wrong sig. verification state", result.isValidSigned());
+
+ }
+
+ @Test
+ public void validSigningRsa() throws CertificateEncodingException, KeyStoreException,
+ JoseException, IOException, EaafException {
+ setRsaSigningKey();
+ setRsaEncryptionKey();
+
+ final String payLoad = "{\"aac\":\"" + RandomStringUtils.randomAlphanumeric(100) + "\"}";
+
+ final String jws = joseTools.createSignature(payLoad);
+ Assert.assertNotNull("Signed msg", jws);
+
+ final VerificationResult verify = joseTools.validateSignature(
+ jws,
+ keyStoreFactory.buildNewKeyStore(getSigTrustStoreConfigValid()).getFirst(),
+ getDefaultAlgorithmConstrains());
+ Assert.assertTrue("wrong verify state", verify.isValidSigned());
+ Assert.assertNotNull("JWS Header", verify.getJoseHeader());
+ Assert.assertNotNull("JWS Payload", verify.getPayload());
+ Assert.assertNotNull("CertChain", verify.getCertChain());
+
+
+ }
+
+ @Test
+ public void validSigningRsaPss() throws CertificateEncodingException, KeyStoreException,
+ JoseException, IOException, EaafException {
+
+ //
+ config.putConfigValue("modules.sl20.security.sigalg.rsa", "PS256");
+
+ setRsaSigningKey();
+ setRsaEncryptionKey();
+
+ final String payLoad = "{\"aac\":\"" + RandomStringUtils.randomAlphanumeric(100) + "\"}";
+
+ final String jws = joseTools.createSignature(payLoad);
+ Assert.assertNotNull("Signed msg", jws);
+
+ final VerificationResult verify = joseTools.validateSignature(
+ jws,
+ keyStoreFactory.buildNewKeyStore(getSigTrustStoreConfigValid()).getFirst(),
+ getDefaultAlgorithmConstrains());
+ Assert.assertTrue("wrong verify state", verify.isValidSigned());
+ Assert.assertNotNull("JWS Header", verify.getJoseHeader());
+ Assert.assertNotNull("JWS Payload", verify.getPayload());
+ Assert.assertNotNull("CertChain", verify.getCertChain());
+
+
+ }
+
+ @Test
+ public void validSigningEc() throws CertificateEncodingException, KeyStoreException,
+ JoseException, IOException, EaafException {
+ setEcSigningKey();
+ setEcEncryptionKey();
+
+ final String payLoad = "{\"aac\":\"" + RandomStringUtils.randomAlphanumeric(100) + "\"}";
+
+ final String jws = joseTools.createSignature(payLoad);
+ Assert.assertNotNull("Signed msg", jws);
+
+ final VerificationResult verify = joseTools.validateSignature(
+ jws,
+ keyStoreFactory.buildNewKeyStore(getSigTrustStoreConfigValid()).getFirst(),
+ getDefaultAlgorithmConstrains());
+ Assert.assertTrue("wrong verify state", verify.isValidSigned());
+ Assert.assertNotNull("JWS Header", verify.getJoseHeader());
+ Assert.assertNotNull("JWS Payload", verify.getPayload());
+ Assert.assertNotNull("CertChain", verify.getCertChain());
+
+ }
+
+ protected KeyStoreConfiguration getSigTrustStoreConfigValid() {
+ final KeyStoreConfiguration trustConfig = new KeyStoreConfiguration();
+ trustConfig.setFriendlyName("jUnit TrustStore");
+ trustConfig.setKeyStoreType(KeyStoreType.JKS);
+ trustConfig.setSoftKeyStoreFilePath("src/test/resources/data/junit.jks");
+ trustConfig.setSoftKeyStorePassword("password");
+
+ return trustConfig;
+
+ }
+
+ protected KeyStoreConfiguration getSigTrustStoreConfigOnlyEc() {
+ final KeyStoreConfiguration trustConfig = new KeyStoreConfiguration();
+ trustConfig.setFriendlyName("jUnit TrustStore");
+ trustConfig.setKeyStoreType(KeyStoreType.JKS);
+ trustConfig.setSoftKeyStoreFilePath("src/test/resources/data/junit_no_rsa.jks");
+ trustConfig.setSoftKeyStorePassword("password");
+
+ return trustConfig;
+
+ }
+
+ private AlgorithmConstraints getDefaultAlgorithmConstrains() {
+ return new AlgorithmConstraints(ConstraintType.WHITELIST,
+ SL20Constants.SL20_ALGORITHM_WHITELIST_SIGNING
+ .toArray(new String[SL20Constants.SL20_ALGORITHM_WHITELIST_SIGNING.size()]));
+ }
+
+}
diff --git a/eaaf_modules/eaaf_module_auth_sl20/src/test/java/at/gv/egiz/eaaf/modules/auth/sl20/utils/JoseUtilsTest.java b/eaaf_modules/eaaf_module_auth_sl20/src/test/java/at/gv/egiz/eaaf/modules/auth/sl20/utils/JoseUtilsTest.java
new file mode 100644
index 00000000..b5a7639e
--- /dev/null
+++ b/eaaf_modules/eaaf_module_auth_sl20/src/test/java/at/gv/egiz/eaaf/modules/auth/sl20/utils/JoseUtilsTest.java
@@ -0,0 +1,83 @@
+package at.gv.egiz.eaaf.modules.auth.sl20.utils;
+
+import java.io.IOException;
+import java.security.NoSuchProviderException;
+import java.security.Security;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.commons.io.IOUtils;
+import org.jose4j.jwa.AlgorithmConstraints;
+import org.jose4j.jwa.AlgorithmConstraints.ConstraintType;
+import org.jose4j.jws.AlgorithmIdentifiers;
+import org.jose4j.lang.JoseException;
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.BlockJUnit4ClassRunner;
+
+import at.gv.egiz.eaaf.modules.auth.sl20.utils.JoseUtils.JwsResult;
+import iaik.security.ec.provider.ECCelerate;
+import iaik.security.provider.IAIK;
+
+@RunWith(BlockJUnit4ClassRunner.class)
+public class JoseUtilsTest {
+
+ private static final List<String> BINDING_AUTH_ALGORITHM_WHITELIST_SIGNING = Collections.unmodifiableList(
+ Arrays.asList(
+ AlgorithmIdentifiers.ECDSA_USING_P256_CURVE_AND_SHA256,
+ AlgorithmIdentifiers.ECDSA_USING_P521_CURVE_AND_SHA512,
+ AlgorithmIdentifiers.RSA_PSS_USING_SHA256,
+ AlgorithmIdentifiers.RSA_PSS_USING_SHA512));
+
+ /**
+ *jUnit test class initializer.
+ */
+ @BeforeClass
+ public static final void classInitializer() {
+ IAIK.addAsProvider();
+ ECCelerate.addAsProvider();
+
+ }
+
+ /**
+ * jUnit test class cleaner.
+ */
+ @AfterClass
+ public static final void classFinisher() {
+ Security.removeProvider(IAIK.getInstance().getName());
+ Security.removeProvider(ECCelerate.getInstance().getName());
+
+ }
+
+ @Test
+ public void testBindingAuthBlock() throws JoseException, IOException, CertificateException, NoSuchProviderException {
+
+ final String serializedContent = IOUtils.toString(JoseUtils.class.getResourceAsStream(
+ "/data/bindingAuth1.jws"), "UTF-8");
+
+ final iaik.x509.X509Certificate trustedCert = new iaik.x509.X509Certificate(JoseUtils.class
+ .getResourceAsStream("/data/bindingAuth1.crt"));
+
+ final List<X509Certificate> trustedCerts = Arrays.asList(trustedCert);
+ final AlgorithmConstraints constraints = new AlgorithmConstraints(ConstraintType.PERMIT,
+ BINDING_AUTH_ALGORITHM_WHITELIST_SIGNING
+ .toArray(new String[BINDING_AUTH_ALGORITHM_WHITELIST_SIGNING.size()]));
+
+ final JwsResult result = JoseUtils.validateSignature(serializedContent, trustedCerts, constraints);
+
+ Assert.assertNotNull("JWS verify result", result);
+ Assert.assertTrue("JWS not valid", result.isValid());
+ Assert.assertNotNull("JWS payload", result.getPayLoad());
+ Assert.assertNotNull("JWS Headers", result.getFullJoseHeader());
+ Assert.assertNotNull("JWS Signercerts", result.getX5cCerts());
+ Assert.assertEquals("Signercerts size", 1, result.getX5cCerts().size());
+ Assert.assertArrayEquals("Signercerts", trustedCert.getEncoded(), result.getX5cCerts().get(0).getEncoded());
+
+ }
+}
diff --git a/eaaf_modules/eaaf_module_auth_sl20/src/test/java/at/gv/egiz/eaaf/modules/auth/sl20/utils/JsonSecurityUtilsHsmKeyTest.java b/eaaf_modules/eaaf_module_auth_sl20/src/test/java/at/gv/egiz/eaaf/modules/auth/sl20/utils/JsonSecurityUtilsHsmKeyTest.java
new file mode 100644
index 00000000..b01330d2
--- /dev/null
+++ b/eaaf_modules/eaaf_module_auth_sl20/src/test/java/at/gv/egiz/eaaf/modules/auth/sl20/utils/JsonSecurityUtilsHsmKeyTest.java
@@ -0,0 +1,86 @@
+package at.gv.egiz.eaaf.modules.auth.sl20.utils;
+
+import java.security.KeyStore;
+import java.security.Provider;
+
+import org.apache.commons.lang3.StringUtils;
+import org.junit.Before;
+import org.junit.runner.RunWith;
+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.KeyStoreConfiguration;
+import at.gv.egiz.eaaf.core.impl.credential.KeyStoreConfiguration.KeyStoreType;
+import at.gv.egiz.eaaf.core.impl.data.Pair;
+
+@RunWith(SpringJUnit4ClassRunner.class)
+@ContextConfiguration("/spring/test_eaaf_sl20_hsm.beans.xml")
+public class JsonSecurityUtilsHsmKeyTest extends AbstractJsonSecurityUtilsTest {
+
+ /**
+ * Initialize jUnit test.
+ */
+ @Before
+ public void initialize() {
+ config.putConfigValue("modules.sl20.security.sigalg.rsa", "RS256");
+ config.putConfigValue("modules.sl20.security.sigalg.ecc", "ES256");
+
+ }
+
+ @Override
+ protected void setRsaSigningKey() {
+ config.putConfigValue("modules.sl20.security.sign.alias", "rsa-key-1");
+
+ }
+
+ @Override
+ protected void setEcSigningKey() {
+ config.putConfigValue("modules.sl20.security.sign.alias", "ec-key-1");
+
+ }
+
+ @Override
+ protected void setRsaEncryptionKey() {
+ config.putConfigValue("modules.sl20.security.encryption.alias", "rsa-key-1");
+
+ }
+
+ @Override
+ protected void setEcEncryptionKey() {
+ config.putConfigValue("modules.sl20.security.encryption.alias", "ec-key-1");
+
+ }
+
+ @Override
+ protected Pair<KeyStore, Provider> getEncryptionKeyStore() throws EaafException {
+ final KeyStoreConfiguration keyConfig = new KeyStoreConfiguration();
+ keyConfig.setFriendlyName("Junit Enc Key Rsa");
+ keyConfig.setKeyStoreType(KeyStoreType.HSMFACADE);
+ keyConfig.setKeyStoreName("eid-junit");
+
+ return keyStoreFactory.buildNewKeyStore(keyConfig);
+ }
+
+ @Override
+ protected String getRsaKeyAlias() {
+ return "rsa-key-1";
+ }
+
+ @Override
+ protected String getRsaKeyPassword() {
+ return StringUtils.EMPTY;
+ }
+
+ @Override
+ protected String getEcKeyAlias() {
+ return "ec-key-1";
+ }
+
+ @Override
+ protected String getEcKeyPassword() {
+ return StringUtils.EMPTY;
+ }
+
+
+}
diff --git a/eaaf_modules/eaaf_module_auth_sl20/src/test/java/at/gv/egiz/eaaf/modules/auth/sl20/utils/JsonSecurityUtilsSoftwareKeyTest.java b/eaaf_modules/eaaf_module_auth_sl20/src/test/java/at/gv/egiz/eaaf/modules/auth/sl20/utils/JsonSecurityUtilsSoftwareKeyTest.java
new file mode 100644
index 00000000..d78bdbd7
--- /dev/null
+++ b/eaaf_modules/eaaf_module_auth_sl20/src/test/java/at/gv/egiz/eaaf/modules/auth/sl20/utils/JsonSecurityUtilsSoftwareKeyTest.java
@@ -0,0 +1,110 @@
+package at.gv.egiz.eaaf.modules.auth.sl20.utils;
+
+import java.security.KeyStore;
+import java.security.Provider;
+
+import org.apache.commons.lang3.RandomStringUtils;
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import org.springframework.util.Base64Utils;
+
+import at.gv.egiz.eaaf.core.exceptions.EaafException;
+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.modules.auth.sl20.exceptions.SL20Exception;
+
+
+@RunWith(SpringJUnit4ClassRunner.class)
+@ContextConfiguration("/spring/test_eaaf_sl20.beans.xml")
+public class JsonSecurityUtilsSoftwareKeyTest extends AbstractJsonSecurityUtilsTest {
+
+ @Test
+ public void invalidSignatureRandomString() {
+ try {
+ joseTools.validateSignature(RandomStringUtils.randomAlphabetic(10));
+ Assert.fail("Wrong JOSE Sig not detected");
+
+ } catch (SL20Exception e) {
+ Assert.assertEquals("Wrong errorCode", "sl20.05", e.getErrorId());
+ }
+
+ }
+
+ @Test
+ public void invalidSignatureRandomBase64UrlEncoded() {
+ String testValue = Base64Utils.encodeToUrlSafeString(RandomStringUtils.randomAlphanumeric(10).getBytes())
+ + "."
+ + Base64Utils.encodeToUrlSafeString(RandomStringUtils.randomAlphanumeric(10).getBytes())
+ + "."
+ + Base64Utils.encodeToUrlSafeString(RandomStringUtils.randomAlphanumeric(10).getBytes());
+
+ try {
+ joseTools.validateSignature(testValue);
+ Assert.fail("Wrong JOSE Sig not detected");
+
+ } catch (SL20Exception e) {
+ Assert.assertEquals("Wrong errorCode", "sl20.05", e.getErrorId());
+ }
+
+ }
+
+ @Override
+ protected void setRsaSigningKey() {
+ config.putConfigValue("modules.sl20.security.sign.alias", "meta");
+
+ }
+
+ @Override
+ protected void setEcSigningKey() {
+ config.putConfigValue("modules.sl20.security.sign.alias", "sig");
+
+ }
+
+ @Override
+ protected void setRsaEncryptionKey() {
+ config.putConfigValue("modules.sl20.security.encryption.alias", "meta");
+
+ }
+
+ @Override
+ protected void setEcEncryptionKey() {
+ config.putConfigValue("modules.sl20.security.encryption.alias", "sig");
+
+ }
+
+ @Override
+ protected Pair<KeyStore, Provider> getEncryptionKeyStore() throws EaafException {
+ KeyStoreConfiguration keyConfig = new KeyStoreConfiguration();
+ keyConfig.setFriendlyName("Junit Enc Key Rsa");
+ keyConfig.setKeyStoreType(KeyStoreType.JKS);
+ keyConfig.setSoftKeyStoreFilePath("src/test/resources/data/junit.jks");
+ keyConfig.setSoftKeyStorePassword("password");
+
+ return keyStoreFactory.buildNewKeyStore(keyConfig);
+ }
+
+ @Override
+ protected String getRsaKeyAlias() {
+ return "meta";
+ }
+
+ @Override
+ protected String getRsaKeyPassword() {
+ return "password";
+ }
+
+ @Override
+ protected String getEcKeyAlias() {
+ return "sig";
+ }
+
+ @Override
+ protected String getEcKeyPassword() {
+ return "password";
+ }
+
+}
diff --git a/eaaf_modules/eaaf_module_auth_sl20/src/test/resources/data/bindingAuth1.crt b/eaaf_modules/eaaf_module_auth_sl20/src/test/resources/data/bindingAuth1.crt
new file mode 100644
index 00000000..11c17e71
--- /dev/null
+++ b/eaaf_modules/eaaf_module_auth_sl20/src/test/resources/data/bindingAuth1.crt
@@ -0,0 +1,3 @@
+-----BEGIN CERTIFICATE-----
+MIIBXzCCAQWgAwIBAgIIPuBGtvo16nUwCgYIKoZIzj0EAwIwGjEYMBYGA1UEAwwPRHVtbXlQa2lTZXJ2aWNlMB4XDTIwMTAwNzEyMTAyMVoXDTIxMTAwNzEyMTAyMVowUTEpMCcGA1UEAwwgNWMzM2Q3MjdlY2YzZTAyYTE2NmYzYWI2NWZiYTEzOGExFDASBgNVBAoMC0VJRC1ERVYtUEtJMQ4wDAYDVQQLDAVULUVudjBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABACA6RBPYIX3i0+TqYq2gb3XAD0B1/tee3/lP8sPc+tt6GFDN0Vsos77VojhRQnGRndmoWi9OW7KS5uQe+5++W8wCgYIKoZIzj0EAwIDSAAwRQIhAO7NlM4YfnapZ9Vam/LF/5ASPGbN4SK0fK4bhGHQw8yIAiB77JHkZIaDtgCcv7CSPf/mvldSf5ViPelhuZBPSLRUsQ==
+-----END CERTIFICATE-----
diff --git a/eaaf_modules/eaaf_module_auth_sl20/src/test/resources/data/bindingAuth1.jws b/eaaf_modules/eaaf_module_auth_sl20/src/test/resources/data/bindingAuth1.jws
new file mode 100644
index 00000000..6ba84d97
--- /dev/null
+++ b/eaaf_modules/eaaf_module_auth_sl20/src/test/resources/data/bindingAuth1.jws
@@ -0,0 +1 @@
+eyJ4NWMiOlsiTUlJQlh6Q0NBUVdnQXdJQkFnSUlQdUJHdHZvMTZuVXdDZ1lJS29aSXpqMEVBd0l3R2pFWU1CWUdBMVVFQXd3UFJIVnRiWGxRYTJsVFpYSjJhV05sTUI0WERUSXdNVEF3TnpFeU1UQXlNVm9YRFRJeE1UQXdOekV5TVRBeU1Wb3dVVEVwTUNjR0ExVUVBd3dnTldNek0yUTNNamRsWTJZelpUQXlZVEUyTm1ZellXSTJOV1ppWVRFek9HRXhGREFTQmdOVkJBb01DMFZKUkMxRVJWWXRVRXRKTVE0d0RBWURWUVFMREFWVUxVVnVkakJaTUJNR0J5cUdTTTQ5QWdFR0NDcUdTTTQ5QXdFSEEwSUFCQUNBNlJCUFlJWDNpMCtUcVlxMmdiM1hBRDBCMVwvdGVlM1wvbFA4c1BjK3R0NkdGRE4wVnNvczc3Vm9qaFJRbkdSbmRtb1dpOU9XN0tTNXVRZSs1KytXOHdDZ1lJS29aSXpqMEVBd0lEU0FBd1JRSWhBTzdObE00WWZuYXBaOVZhbVwvTEZcLzVBU1BHYk40U0swZks0YmhHSFF3OHlJQWlCNzdKSGtaSWFEdGdDY3Y3Q1NQZlwvbXZsZFNmNVZpUGVsaHVaQlBTTFJVc1E9PSJdLCJ0eXAiOiJiaW5kaW5nQXV0aCIsImFsZyI6IkVTMjU2In0.MzIxZmVmYTQtODVkOC00YmE5LWE0MmUtYWY4MzM3YTEyNTA1.diiXXegwv3Gu6ezJRxf7F5BnRxNhTnBXJ0D5RX4OqDxs2QvfzSPA4mOkUed18_56aILMBLVL-XIMszNILfp7OA \ No newline at end of file
diff --git a/eaaf_modules/eaaf_module_auth_sl20/src/test/resources/data/config1.properties b/eaaf_modules/eaaf_module_auth_sl20/src/test/resources/data/config1.properties
new file mode 100644
index 00000000..f58e3da9
--- /dev/null
+++ b/eaaf_modules/eaaf_module_auth_sl20/src/test/resources/data/config1.properties
@@ -0,0 +1,19 @@
+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
+
+modules.sl20.security.keystore.type=jks
+modules.sl20.security.keystore.path=src/test/resources/data/junit.jks
+modules.sl20.security.keystore.password=password
+modules.sl20.security.keystore.name=
+modules.sl20.security.sign.alias=sig
+modules.sl20.security.sign.password=password
+modules.sl20.security.encryption.alias=meta
+modules.sl20.security.encryption.password=password
+
+modules.sl20.security.truststore.type=jks
+modules.sl20.security.truststore.path=src/test/resources/data/junit.jks
+modules.sl20.security.truststore.password=password
+modules.sl20.security.truststore.name= \ No newline at end of file
diff --git a/eaaf_modules/eaaf_module_auth_sl20/src/test/resources/data/config2.properties b/eaaf_modules/eaaf_module_auth_sl20/src/test/resources/data/config2.properties
new file mode 100644
index 00000000..ff99dcef
--- /dev/null
+++ b/eaaf_modules/eaaf_module_auth_sl20/src/test/resources/data/config2.properties
@@ -0,0 +1,19 @@
+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
+
+modules.sl20.security.keystore.type=hsmfacade
+modules.sl20.security.keystore.path=
+modules.sl20.security.keystore.password=
+modules.sl20.security.keystore.name=eid-junit
+modules.sl20.security.sign.alias=rsa-key-1
+modules.sl20.security.sign.password=
+modules.sl20.security.encryption.alias=ec-key-1
+modules.sl20.security.encryption.password=
+
+modules.sl20.security.truststore.type=hsmfacade
+modules.sl20.security.truststore.path=src/test/resources/data/junit.jks
+modules.sl20.security.truststore.password=
+modules.sl20.security.truststore.name=eid-junit \ No newline at end of file
diff --git a/eaaf_modules/eaaf_module_auth_sl20/src/test/resources/data/hsm_ec.crt b/eaaf_modules/eaaf_module_auth_sl20/src/test/resources/data/hsm_ec.crt
new file mode 100644
index 00000000..ad780a21
--- /dev/null
+++ b/eaaf_modules/eaaf_module_auth_sl20/src/test/resources/data/hsm_ec.crt
@@ -0,0 +1,3 @@
+-----BEGIN CERTIFICATE-----
+MIIBQTCB56ADAgECAghqWvzGZbotTjAKBggqhkjOPQQDAjASMRAwDgYDVQQDDAdFQy1Sb290MB4XDTIwMDYxODA3MzYwOVoXDTI1MDYxODA3MzYwOVowOzEaMBgGA1UEAwwRaW50LWVjLWtleS0xLTAwMDExETAPBgNVBAoMCHNvZnR3YXJlMQowCAYDVQQFEwExMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEMYva5n1ISLX4bZdG9ecGVNVId7OEY4Yjeu+4kk+nbppxNMj6JX5tO2iCCpgHlKC5WWTSJyxSQh3CoLzc8XLUmjAKBggqhkjOPQQDAgNJADBGAiEAiegmUzDThtinnuUwsHXwdr4Y/XUednOyIy7RBeClvyYCIQC/v5NZzg+H6FUrQ2nds2hlB6sD7z5cZPJcqm8+S0wYCw==
+-----END CERTIFICATE-----
diff --git a/eaaf_modules/eaaf_module_auth_sl20/src/test/resources/data/hsm_facade_trust_root.crt b/eaaf_modules/eaaf_module_auth_sl20/src/test/resources/data/hsm_facade_trust_root.crt
new file mode 100644
index 00000000..204ddccf
--- /dev/null
+++ b/eaaf_modules/eaaf_module_auth_sl20/src/test/resources/data/hsm_facade_trust_root.crt
@@ -0,0 +1,12 @@
+-----BEGIN CERTIFICATE-----
+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_modules/eaaf_module_auth_sl20/src/test/resources/data/hsm_rsa.crt b/eaaf_modules/eaaf_module_auth_sl20/src/test/resources/data/hsm_rsa.crt
new file mode 100644
index 00000000..aa83c8d9
--- /dev/null
+++ b/eaaf_modules/eaaf_module_auth_sl20/src/test/resources/data/hsm_rsa.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_modules/eaaf_module_auth_sl20/src/test/resources/data/junit.jks b/eaaf_modules/eaaf_module_auth_sl20/src/test/resources/data/junit.jks
new file mode 100644
index 00000000..a18df332
--- /dev/null
+++ b/eaaf_modules/eaaf_module_auth_sl20/src/test/resources/data/junit.jks
Binary files differ
diff --git a/eaaf_modules/eaaf_module_auth_sl20/src/test/resources/data/junit_no_rsa.jks b/eaaf_modules/eaaf_module_auth_sl20/src/test/resources/data/junit_no_rsa.jks
new file mode 100644
index 00000000..370cf19e
--- /dev/null
+++ b/eaaf_modules/eaaf_module_auth_sl20/src/test/resources/data/junit_no_rsa.jks
Binary files differ
diff --git a/eaaf_modules/eaaf_module_auth_sl20/src/test/resources/data/software_ec.crt b/eaaf_modules/eaaf_module_auth_sl20/src/test/resources/data/software_ec.crt
new file mode 100644
index 00000000..5311f3f1
--- /dev/null
+++ b/eaaf_modules/eaaf_module_auth_sl20/src/test/resources/data/software_ec.crt
@@ -0,0 +1,3 @@
+-----BEGIN CERTIFICATE-----
+MIIBbTCCARKgAwIBAgIEXjF+qTAKBggqhkjOPQQDAjA+MQswCQYDVQQGEwJBVDENMAsGA1UEBwwERUdJWjEOMAwGA1UECgwFalVuaXQxEDAOBgNVBAMMB3NpZ25pbmcwHhcNMjAwMTI5MTI0NjMzWhcNMjcwMTI4MTI0NjMzWjA+MQswCQYDVQQGEwJBVDENMAsGA1UEBwwERUdJWjEOMAwGA1UECgwFalVuaXQxEDAOBgNVBAMMB3NpZ25pbmcwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAASRt7gZRrr4rSEE7Q922oKQJF+mlkwCLZnv8ZzHtH54s4VdyQFIBjQF1PPf9PTn+5tid8QJehZPndcoeD7J8fPJMAoGCCqGSM49BAMCA0kAMEYCIQDFUO0owvqMVRO2FmD+vb8mqJBpWCE6Cl5pEHaygTa5LwIhANsmjI2azWiTSFjb7Ou5fnCfbeiJUP0s66m8qS4rYl9L
+-----END CERTIFICATE-----
diff --git a/eaaf_modules/eaaf_module_auth_sl20/src/test/resources/data/software_rsa.crt b/eaaf_modules/eaaf_module_auth_sl20/src/test/resources/data/software_rsa.crt
new file mode 100644
index 00000000..c70f5031
--- /dev/null
+++ b/eaaf_modules/eaaf_module_auth_sl20/src/test/resources/data/software_rsa.crt
@@ -0,0 +1,3 @@
+-----BEGIN CERTIFICATE-----
+MIIC+jCCAeKgAwIBAgIEXjF+fTANBgkqhkiG9w0BAQsFADA/MQswCQYDVQQGEwJBVDENMAsGA1UEBwwERUdJWjEOMAwGA1UECgwFalVuaXQxETAPBgNVBAMMCE1ldGFkYXRhMB4XDTIwMDEyOTEyNDU0OVoXDTI2MDEyODEyNDU0OVowPzELMAkGA1UEBhMCQVQxDTALBgNVBAcMBEVHSVoxDjAMBgNVBAoMBWpVbml0MREwDwYDVQQDDAhNZXRhZGF0YTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAK230G3dxNbNlSYAO5Kx/Js0aBAgxMt7q9m+dA35fK/dOvF/GjrqjWsMCnax+no9gLnq6x0gXiJclz6Hrp/YDOfLrJjMpNL/r0FWT947vbnEj7eT8TdY5d6Yi8AZulZmjiCI5nbZh2zwrP4+WqRroLoPhXQj8mDyp26M4xHBBUhLMRc2HV4S+XH4uNZ/vTmb8vBg31XGHCY33gl7/KA54JNGxJdN8Dxv6yHYsm91ZfVrX39W0iYLUNhUCkolwuQmjDVfrExM8BTLIONbf+erJoCm3A9ghZyDYRQ/e69/UEUqDa6XOzykr88INkQscEiAXCDS+EBPMpKo+t3lPIA9r7kCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAh/2mg4S03bdZy1OVtEAudBT9YZb9OF34hxPtNbkB/V04wSIg1d4TBr5KDhV7CdiUOxPZzHpS8LUCgfGX306FB6NXzh/b67uTOPaE72AB4VIT/Np0fsM7k5WhG9k9NoprIGiqCz2lXcfpZiT+LtSO1vWSYI87wR9KOSWjcw/5i5qZIAJuwvLCQj5JtUsmrhHK75222J3TJf4dS/gfN4xfY2rW9vcXtH6//8WdWp/zx9V7Z1ZsDb8TDKtBCEGuFDgVeU5ScKtVq8qRoUKD3Ve76cZipurO3KrRrVAuZP2EfLkZdHEHqe8GPigNnZ5kTn8V2VJ3iRAQ73hpJRR98tFd0A==
+-----END CERTIFICATE-----
diff --git a/eaaf_modules/eaaf_module_auth_sl20/src/test/resources/data/test.crt b/eaaf_modules/eaaf_module_auth_sl20/src/test/resources/data/test.crt
new file mode 100644
index 00000000..76c18361
--- /dev/null
+++ b/eaaf_modules/eaaf_module_auth_sl20/src/test/resources/data/test.crt
@@ -0,0 +1,3 @@
+-----BEGIN CERTIFICATE-----
+MIIEXDCCA0SgAwIBAgIEY4Qn3zANBgkqhkiG9w0BAQsFADCBpzELMAkGA1UEBhMCQVQxSDBGBgNVBAoMP0EtVHJ1c3QgR2VzLiBmLiBTaWNoZXJoZWl0c3N5c3RlbWUgaW0gZWxla3RyLiBEYXRlbnZlcmtlaHIgR21iSDEmMCQGA1UECwwdYS1zaWduLVRlc3QtUHJlbWl1bS1Nb2JpbGUtMDUxJjAkBgNVBAMMHWEtc2lnbi1UZXN0LVByZW1pdW0tTW9iaWxlLTA1MB4XDTE5MTIxMzEzNDg0N1oXDTI0MTIxMzEzNDg0N1owYDELMAkGA1UEBhMCQVQxFzAVBgNVBAMMDk1heCBNdXN0ZXJtYW5uMRMwEQYDVQQEDApNdXN0ZXJtYW5uMQwwCgYDVQQqDANNYXgxFTATBgNVBAUTDDgxNjkyMjY1ODM0ODBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABAUAVvbow4O/DMA5ZZoPHQXe0rtf86lvH8GLM/Crz1vvRYyQ5D4ESYRFy+s3zHdLqhE4l8I95i9jz2qTvof46mqjggGfMIIBmzCBggYIKwYBBQUHAQEEdjB0MEkGCCsGAQUFBzAChj1odHRwOi8vd3d3LmEtdHJ1c3QuYXQvY2VydHMvYS1zaWduLXRlc3QtcHJlbWl1bS1tb2JpbGUtMDUuY3J0MCcGCCsGAQUFBzABhhtodHRwOi8vb2NzcC5hLXRydXN0LmF0L29jc3AwEwYDVR0jBAwwCoAITuhoD/7N29AwEQYDVR0OBAoECEyqhgBwLul2MA4GA1UdDwEB/wQEAwIGwDAJBgNVHRMEAjAAMIGGBgNVHSAEfzB9MHsGBiooABEBBDBxMDgGCCsGAQUFBwICMCwaKkRpZXNlcyBaZXJ0aWZpa2F0IGRpZW50IG51ciB6dSBUZXN0endlY2tlbjA1BggrBgEFBQcCARYpaHR0cDovL3d3dy5hLXRydXN0LmF0L2RvY3MvY3AvYS1zaWduLVRFU1QwSAYDVR0fBEEwPzA9oDugOYY3aHR0cDovL2NybC5hLXRydXN0LmF0L2NybC9hLXNpZ24tdGVzdC1wcmVtaXVtLW1vYmlsZS0wNTANBgkqhkiG9w0BAQsFAAOCAQEATD4ZnrEV+xeT7PFI/idqHdElLZ1BVUO9G9qfQQn4oKNCWWHxMo/ZXSlvsOtTjFezCQFkcFO1eJtXNHCyqfr69jorzhZcicscNRMrDlJoB/sJr0l/Ekjlt/dgRaTuZ7NzWE/oTefI3M3xkkLd0ydAMrhrZx+9f82VE3k63I1fmT90kQ8PfDzAMMRmlwbZDA+2TB8iF7SQkOOL6H1j2L9qrhjlG2ekU4cyx6KMkRjLLbr1JVgS07qOzUkeQPR2KTJcWWR+/NQZWDKdOz97eVOulxeI+Y3y96arraGM7lIbV9ZrpkbUn/IxQ9TQTE5X02EipgnZdR7bZrwJ7hJ27vwnfQ==
+-----END CERTIFICATE-----
diff --git a/eaaf_modules/eaaf_module_auth_sl20/src/test/resources/spring/test_eaaf_sl20.beans.xml b/eaaf_modules/eaaf_module_auth_sl20/src/test/resources/spring/test_eaaf_sl20.beans.xml
new file mode 100644
index 00000000..e4002a8f
--- /dev/null
+++ b/eaaf_modules/eaaf_module_auth_sl20/src/test/resources/spring/test_eaaf_sl20.beans.xml
@@ -0,0 +1,24 @@
+<?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/config1.properties" />
+ </bean>
+
+ <bean id="jwsJweUtils"
+ class="at.gv.egiz.eaaf.modules.auth.sl20.utils.JsonSecurityUtils"/>
+
+ <import resource="classpath:/spring/eaaf_utils.beans.xml"/>
+
+</beans> \ No newline at end of file
diff --git a/eaaf_modules/eaaf_module_auth_sl20/src/test/resources/spring/test_eaaf_sl20_hsm.beans.xml b/eaaf_modules/eaaf_module_auth_sl20/src/test/resources/spring/test_eaaf_sl20_hsm.beans.xml
new file mode 100644
index 00000000..a9f5dc80
--- /dev/null
+++ b/eaaf_modules/eaaf_module_auth_sl20/src/test/resources/spring/test_eaaf_sl20_hsm.beans.xml
@@ -0,0 +1,24 @@
+<?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="jwsJweUtils"
+ class="at.gv.egiz.eaaf.modules.auth.sl20.utils.JsonSecurityUtils"/>
+
+ <import resource="classpath:/spring/eaaf_utils.beans.xml"/>
+
+</beans> \ No newline at end of file