summaryrefslogtreecommitdiff
path: root/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/tasks
diff options
context:
space:
mode:
authorThomas Lenz <thomas.lenz@egiz.gv.at>2019-12-04 19:43:32 +0100
committerThomas Lenz <thomas.lenz@egiz.gv.at>2019-12-04 19:43:32 +0100
commit759ac5f42c6aff901dbeede4fbf1a1d2e08cad0f (patch)
tree2132024fc058b1ef5338bf50df575a3244cc3f9f /eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/tasks
parent4f15bdc45b08724d20c66c9fd74ea6a43a03c32f (diff)
downloadEAAF-Components-759ac5f42c6aff901dbeede4fbf1a1d2e08cad0f.tar.gz
EAAF-Components-759ac5f42c6aff901dbeede4fbf1a1d2e08cad0f.tar.bz2
EAAF-Components-759ac5f42c6aff901dbeede4fbf1a1d2e08cad0f.zip
common EGIZ code-style refactoring
Diffstat (limited to 'eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/tasks')
-rw-r--r--eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/tasks/AbstractCreateQualEidRequestTask.java250
-rw-r--r--eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/tasks/AbstractCreateQualeIDRequestTask.java227
-rw-r--r--eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/tasks/AbstractReceiveQualEidTask.java344
-rw-r--r--eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/tasks/AbstractReceiveQualeIDTask.java321
4 files changed, 594 insertions, 548 deletions
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
new file mode 100644
index 00000000..251b516f
--- /dev/null
+++ b/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/tasks/AbstractCreateQualEidRequestTask.java
@@ -0,0 +1,250 @@
+package at.gv.egiz.eaaf.modules.auth.sl20.tasks;
+
+import java.security.cert.CertificateEncodingException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import at.gv.egiz.eaaf.core.api.idp.IConfigurationWithSP;
+import at.gv.egiz.eaaf.core.api.idp.IspConfiguration;
+import at.gv.egiz.eaaf.core.api.idp.process.ExecutionContext;
+import at.gv.egiz.eaaf.core.exceptions.EaafAuthenticationException;
+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.IHttpClientFactory;
+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;
+import at.gv.egiz.eaaf.modules.auth.sl20.exceptions.SL20Exception;
+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.SL20HttpBindingUtils;
+import at.gv.egiz.eaaf.modules.auth.sl20.utils.SL20JsonExtractorUtils;
+import at.gv.egiz.eaaf.modules.auth.sl20.utils.SL20JsonBuilderUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.http.HttpResponse;
+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 com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+
+public abstract class AbstractCreateQualEidRequestTask extends AbstractAuthServletTask {
+ private static final Logger log = LoggerFactory.getLogger(AbstractCreateQualEidRequestTask.class);
+
+ @Autowired(required = true)
+ private IHttpClientFactory httpClientFactory;
+ @Autowired(required = true)
+ protected IConfigurationWithSP authConfigWithSp;
+
+ @Override
+ public void execute(final ExecutionContext executionContext, final HttpServletRequest request,
+ final HttpServletResponse response) throws TaskExecutionException {
+
+ log.debug("Starting SL2.0 authentication process .... ");
+
+ revisionsLogger.logEvent(pendingReq, EventCodes.AUTHPROCESS_SL20_SELECTED, "sl20auth");
+
+ try {
+ // get service-provider configuration
+ final IspConfiguration oaConfig = pendingReq.getServiceProviderConfiguration();
+
+ if (oaConfig == null) {
+ log.warn("No SP configuration in pendingReq!");
+ throw new RuntimeException("Suspect state. NO SP CONFIGURATION IN PendingRequest!");
+
+ }
+
+ // get basic configuration parameters
+ final String 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"});
+
+ }
+
+ log.debug("Use {} as VDA end-point", vdaQualEidDUrl);
+ pendingReq.setRawDataToTransaction(
+ Constants.PENDING_REQ_STORAGE_PREFIX + SL20Constants.SL20_COMMAND_PARAM_EID_RESULT_CCSURL,
+ vdaQualEidDUrl);
+ revisionsLogger.logEvent(pendingReq, EventCodes.AUTHPROCESS_SL20_ENDPOINT_URL, vdaQualEidDUrl);
+
+ // create SL2.0 command for qualified eID
+ final String signedQualEidCommand = buildSignedQualifiedEidCommand();
+
+ // build request container
+ final String qualEidReqId = Random.nextProcessReferenceValue();
+ final ObjectNode sl20Req =
+ SL20JsonBuilderUtils.createGenericRequest(qualEidReqId, null, 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())));
+ httpReq.setEntity(new UrlEncodedFormEntity(parameters));
+
+ // 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());
+
+ // 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()));
+
+ // 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);
+
+ if (respPayloadContainer.isValidSigned() == null) {
+ log.debug("Receive unsigned payLoad from VDA");
+
+ }
+
+ final JsonNode respPayload = respPayloadContainer.getPayload();
+ if (respPayload.get(SL20Constants.SL20_COMMAND_CONTAINER_NAME).asText()
+ .equals(SL20Constants.SL20_COMMAND_IDENTIFIER_REDIRECT)) {
+ log.debug("Find 'redirect' command in VDA response ... ");
+ final JsonNode params = SL20JsonExtractorUtils.getJsonObjectValue(respPayload,
+ SL20Constants.SL20_COMMAND_CONTAINER_PARAMS, true);
+ final String redirectUrl = SL20JsonExtractorUtils.getStringValue(params,
+ SL20Constants.SL20_COMMAND_PARAM_GENERAL_REDIRECT_URL, true);
+ final JsonNode command = SL20JsonExtractorUtils.getJsonObjectValue(params,
+ SL20Constants.SL20_COMMAND_PARAM_GENERAL_REDIRECT_COMMAND, false);
+ final String signedCommand = SL20JsonExtractorUtils.getStringValue(params,
+ SL20Constants.SL20_COMMAND_PARAM_GENERAL_REDIRECT_SIGNEDCOMMAND, false);
+
+ // create forward SL2.0 command
+ final ObjectNode sl20Forward = sl20Resp.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);
+ requestStoreage.storePendingRequest(pendingReq);
+
+ // forward SL2.0 command
+ // TODO: maybe add SL2ClientType Header from execution context
+ SL20HttpBindingUtils.writeIntoResponse(request, response, sl20Forward, redirectUrl,
+ Integer
+ .parseInt(authConfig.getBasicConfiguration(Constants.CONFIG_PROP_HTTP_REDIRECT_CODE,
+ Constants.CONFIG_PROP_HTTP_REDIRECT_CODE_DEFAULT_VALUE)));
+
+ } else if (respPayload.get(SL20Constants.SL20_COMMAND_CONTAINER_NAME).asText()
+ .equals(SL20Constants.SL20_COMMAND_IDENTIFIER_ERROR)) {
+ JsonNode result = SL20JsonExtractorUtils.getJsonObjectValue(respPayload,
+ SL20Constants.SL20_COMMAND_CONTAINER_RESULT, false);
+ if (result == null) {
+ result = SL20JsonExtractorUtils.getJsonObjectValue(respPayload,
+ SL20Constants.SL20_COMMAND_CONTAINER_PARAMS, false);
+ }
+
+ final String errorCode = SL20JsonExtractorUtils.getStringValue(result,
+ SL20Constants.SL20_COMMAND_PARAM_GENERAL_RESPONSE_ERRORCODE, true);
+ final String errorMsg = SL20JsonExtractorUtils.getStringValue(result,
+ SL20Constants.SL20_COMMAND_PARAM_GENERAL_RESPONSE_ERRORMESSAGE, true);
+
+ log.info("Receive SL2.0 error. Code:" + errorCode + " Msg:" + errorMsg);
+ throw new SL20Exception("sl20.08", new Object[] {errorCode, errorMsg});
+
+ } else {
+ // TODO: update to add error handling
+ log.warn("Received an unrecognized command: "
+ + respPayload.get(SL20Constants.SL20_COMMAND_CONTAINER_NAME).asText());
+ throw new SlCommandoParserException(
+ "Received an unrecognized command: "
+ + respPayload.get(SL20Constants.SL20_COMMAND_CONTAINER_NAME).toString());
+ }
+
+
+ } catch (final EaafAuthenticationException e) {
+ throw new TaskExecutionException(pendingReq,
+ "SL2.0 Authentication FAILED. Msg: " + 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();
+
+ }
+
+ }
+
+ /**
+ * Create a implementation specific qualified eID SL2.0 command
+ *
+ * @param oaConfig
+ *
+ * @return signed JWT token as serialized {@link String}
+ * @throws CertificateEncodingException In case of certificate parsing error
+ * @throws SL20Exception In case of a SL2.0 error
+ */
+ protected abstract String buildSignedQualifiedEidCommand()
+ throws CertificateEncodingException, SL20Exception;
+
+
+ private String extractVdaUrlForSpecificOa(final IspConfiguration oaConfig,
+ final ExecutionContext executionContext) {
+
+ // load SP specific config for development and testing purposes
+ final String spSpecificVdaEndpoints =
+ oaConfig.getConfigurationValue(Constants.CONFIG_PROP_SP_SL20_ENDPOINT_LIST);
+
+ // load general configuration
+ final Map<String, String> endPointMap = authConfigWithSp
+ .getBasicConfigurationWithPrefix(Constants.CONFIG_PROP_VDA_ENDPOINT_QUALeID_LIST);
+ endPointMap.put(Constants.CONFIG_PROP_VDA_ENDPOINT_QUALeID_DEFAULT_ELEMENT,
+ authConfig.getBasicConfiguration(Constants.CONFIG_PROP_VDA_ENDPOINT_QUALeID_DEFAULT));
+ if (StringUtils.isNotEmpty(spSpecificVdaEndpoints)) {
+ endPointMap.putAll(KeyValueUtils.convertListToMap(KeyValueUtils
+ .getListOfCsvValues(KeyValueUtils.normalizeCsvValueString(spSpecificVdaEndpoints))));
+ log.debug("Find OA specific SL2.0 endpoints. Updating endPoint list ... ");
+
+ }
+
+ log.trace("Find #" + endPointMap.size() + " SL2.0 endpoints ... ");
+
+ // selection based on request Header
+ final String sl20VdaTypeHeader =
+ (String) executionContext.get(SL20Constants.HTTP_HEADER_SL20_VDA_TYPE.toLowerCase());
+ if (StringUtils.isNotEmpty(sl20VdaTypeHeader)) {
+ final String vdaUrl = endPointMap.get(sl20VdaTypeHeader);
+ if (StringUtils.isNotEmpty(vdaUrl)) {
+ return vdaUrl.trim();
+ } else {
+ log.info("Can NOT find VDA with Id: " + sl20VdaTypeHeader + ". Use default VDA");
+ }
+
+ }
+
+
+ log.info("NO specific VDA endpoint requested or found. Use default VDA");
+ return endPointMap.get(Constants.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/tasks/AbstractCreateQualeIDRequestTask.java b/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/tasks/AbstractCreateQualeIDRequestTask.java
deleted file mode 100644
index 85302d83..00000000
--- a/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/tasks/AbstractCreateQualeIDRequestTask.java
+++ /dev/null
@@ -1,227 +0,0 @@
-package at.gv.egiz.eaaf.modules.auth.sl20.tasks;
-
-import java.security.cert.CertificateEncodingException;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.apache.commons.lang3.StringUtils;
-import org.apache.http.HttpResponse;
-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 com.fasterxml.jackson.databind.JsonNode;
-import com.fasterxml.jackson.databind.node.ObjectNode;
-
-import at.gv.egiz.eaaf.core.api.idp.IConfigurationWithSP;
-import at.gv.egiz.eaaf.core.api.idp.ISPConfiguration;
-import at.gv.egiz.eaaf.core.api.idp.process.ExecutionContext;
-import at.gv.egiz.eaaf.core.exceptions.EAAFAuthenticationException;
-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.IHttpClientFactory;
-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;
-import at.gv.egiz.eaaf.modules.auth.sl20.exceptions.SL20Exception;
-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.SL20Constants;
-import at.gv.egiz.eaaf.modules.auth.sl20.utils.SL20HttpBindingUtils;
-import at.gv.egiz.eaaf.modules.auth.sl20.utils.SL20JSONBuilderUtils;
-import at.gv.egiz.eaaf.modules.auth.sl20.utils.SL20JSONExtractorUtils;
-
-public abstract class AbstractCreateQualeIDRequestTask extends AbstractAuthServletTask {
- private static final Logger log = LoggerFactory.getLogger(AbstractCreateQualeIDRequestTask.class);
-
- @Autowired(required=true) private IHttpClientFactory httpClientFactory;
- @Autowired(required=true) protected IConfigurationWithSP authConfigWithSp;
-
- @Override
- public void execute(ExecutionContext executionContext, HttpServletRequest request, HttpServletResponse response)
- throws TaskExecutionException {
-
- log.debug("Starting SL2.0 authentication process .... ");
-
- revisionsLogger.logEvent(pendingReq, EventCodes.AUTHPROCESS_SL20_SELECTED, "sl20auth");
-
- try {
- //get service-provider configuration
- final ISPConfiguration oaConfig = pendingReq.getServiceProviderConfiguration();
-
- if (oaConfig == null) {
- log.warn("No SP configuration in pendingReq!");
- throw new RuntimeException("Suspect state. NO SP CONFIGURATION IN PendingRequest!");
-
- }
-
- //get basic configuration parameters
- final String vdaQualeIDUrl = extractVDAURLForSpecificOA(oaConfig, executionContext);
- if (StringUtils.isEmpty(vdaQualeIDUrl)) {
- 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"});
-
- }
-
- log.debug("Use {} as VDA end-point", vdaQualeIDUrl) ;
- pendingReq.setRawDataToTransaction(
- Constants.PENDING_REQ_STORAGE_PREFIX + SL20Constants.SL20_COMMAND_PARAM_EID_RESULT_CCSURL,
- vdaQualeIDUrl);
- revisionsLogger.logEvent(pendingReq, EventCodes.AUTHPROCESS_SL20_ENDPOINT_URL, vdaQualeIDUrl);
-
- //create SL2.0 command for qualified eID
- final String signedQualeIDCommand = buildSignedQualifiedEIDCommand();
-
- //build request container
- final String qualeIDReqId = Random.nextProcessReferenceValue();
- final ObjectNode sl20Req = SL20JSONBuilderUtils.createGenericRequest(qualeIDReqId, null, null, signedQualeIDCommand);
-
- //build http POST request
- final HttpPost httpReq = new HttpPost(new URIBuilder(vdaQualeIDUrl).build());
- final List<NameValuePair> parameters = new ArrayList<NameValuePair>();;
- parameters.add(new BasicNameValuePair(SL20Constants.PARAM_SL20_REQ_COMMAND_PARAM, Base64Url.encode(sl20Req.toString().getBytes())));
- httpReq.setEntity(new UrlEncodedFormEntity(parameters ));
-
- //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());
-
- //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()));
-
- //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);
-
- if (respPayloadContainer.isValidSigned() == null) {
- log.debug("Receive unsigned payLoad from VDA");
-
- }
-
- final JsonNode respPayload = respPayloadContainer.getPayload();
- if (respPayload.get(SL20Constants.SL20_COMMAND_CONTAINER_NAME).asText()
- .equals(SL20Constants.SL20_COMMAND_IDENTIFIER_REDIRECT)) {
- log.debug("Find 'redirect' command in VDA response ... ");
- final JsonNode params = SL20JSONExtractorUtils.getJSONObjectValue(respPayload, SL20Constants.SL20_COMMAND_CONTAINER_PARAMS, true);
- final String redirectURL = SL20JSONExtractorUtils.getStringValue(params, SL20Constants.SL20_COMMAND_PARAM_GENERAL_REDIRECT_URL, true);
- final JsonNode command = SL20JSONExtractorUtils.getJSONObjectValue(params, SL20Constants.SL20_COMMAND_PARAM_GENERAL_REDIRECT_COMMAND, false);
- final String signedCommand = SL20JSONExtractorUtils.getStringValue(params, SL20Constants.SL20_COMMAND_PARAM_GENERAL_REDIRECT_SIGNEDCOMMAND, false);
-
- //create forward SL2.0 command
- final ObjectNode sl20Forward = sl20Resp.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);
- requestStoreage.storePendingRequest(pendingReq);
-
- //forward SL2.0 command
- //TODO: maybe add SL2ClientType Header from execution context
- SL20HttpBindingUtils.writeIntoResponse(request, response, sl20Forward, redirectURL,
- Integer.parseInt(authConfig.getBasicConfiguration(Constants.CONFIG_PROP_HTTP_REDIRECT_CODE, Constants.CONFIG_PROP_HTTP_REDIRECT_CODE_DEFAULT_VALUE)));
-
- } else if (respPayload.get(SL20Constants.SL20_COMMAND_CONTAINER_NAME).asText()
- .equals(SL20Constants.SL20_COMMAND_IDENTIFIER_ERROR)) {
- JsonNode result = SL20JSONExtractorUtils.getJSONObjectValue(respPayload, SL20Constants.SL20_COMMAND_CONTAINER_RESULT, false);
- if (result == null)
- result = SL20JSONExtractorUtils.getJSONObjectValue(respPayload, SL20Constants.SL20_COMMAND_CONTAINER_PARAMS, false);
-
- final String errorCode = SL20JSONExtractorUtils.getStringValue(result, SL20Constants.SL20_COMMAND_PARAM_GENERAL_RESPONSE_ERRORCODE, true);
- final String errorMsg = SL20JSONExtractorUtils.getStringValue(result, SL20Constants.SL20_COMMAND_PARAM_GENERAL_RESPONSE_ERRORMESSAGE, true);
-
- log.info("Receive SL2.0 error. Code:" + errorCode + " Msg:" + errorMsg);
- throw new SL20Exception("sl20.08", new Object[]{errorCode, errorMsg});
-
- } else {
- //TODO: update to add error handling
- log.warn("Received an unrecognized command: " + respPayload.get(SL20Constants.SL20_COMMAND_CONTAINER_NAME).asText());
- throw new SLCommandoParserException("Received an unrecognized command: \" + respPayload.get(SL20Constants.SL20_COMMAND_CONTAINER_NAME).getAsString()");
- }
-
-
- } catch (final EAAFAuthenticationException e) {
- throw new TaskExecutionException(pendingReq, "SL2.0 Authentication FAILED. Msg: " + 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();
-
- }
-
- }
-
- /**
- * Create a implementation specific qualified eID SL2.0 command
- * @param oaConfig
- *
- * @return signed JWT token as serialized {@link String}
- * @throws CertificateEncodingException
- * @throws SLCommandoBuildException
- * @throws SL20Exception
- */
- protected abstract String buildSignedQualifiedEIDCommand() throws CertificateEncodingException, SL20Exception;
-
-
- private String extractVDAURLForSpecificOA(ISPConfiguration oaConfig, ExecutionContext executionContext) {
-
- //load SP specific config for development and testing purposes
- final String spSpecificVDAEndpoints = oaConfig.getConfigurationValue(Constants.CONFIG_PROP_SP_SL20_ENDPOINT_LIST);
-
- //load general configuration
- final Map<String, String> endPointMap = authConfigWithSp.getBasicConfigurationWithPrefix(Constants.CONFIG_PROP_VDA_ENDPOINT_QUALeID_LIST);
- endPointMap.put(Constants.CONFIG_PROP_VDA_ENDPOINT_QUALeID_DEFAULT_ELEMENT, authConfig.getBasicConfiguration(Constants.CONFIG_PROP_VDA_ENDPOINT_QUALeID_DEFAULT));
- if (StringUtils.isNotEmpty(spSpecificVDAEndpoints)) {
- endPointMap.putAll(KeyValueUtils.convertListToMap(
- KeyValueUtils.getListOfCSVValues(
- KeyValueUtils.normalizeCSVValueString(spSpecificVDAEndpoints))));
- log.debug("Find OA specific SL2.0 endpoints. Updating endPoint list ... ");
-
- }
-
- log.trace("Find #" + endPointMap.size() + " SL2.0 endpoints ... ");
-
- //selection based on request Header
- final String sl20VDATypeHeader = (String) executionContext.get(SL20Constants.HTTP_HEADER_SL20_VDA_TYPE.toLowerCase());
- if (StringUtils.isNotEmpty(sl20VDATypeHeader)) {
- final String vdaURL = endPointMap.get(sl20VDATypeHeader);
- if (StringUtils.isNotEmpty(vdaURL))
- return vdaURL.trim();
- else
- log.info("Can NOT find VDA with Id: " + sl20VDATypeHeader + ". Use default VDA");
-
- }
-
-
- log.info("NO specific VDA endpoint requested or found. Use default VDA");
- return endPointMap.get(Constants.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/tasks/AbstractReceiveQualEidTask.java b/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/tasks/AbstractReceiveQualEidTask.java
new file mode 100644
index 00000000..39cfce05
--- /dev/null
+++ b/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/tasks/AbstractReceiveQualEidTask.java
@@ -0,0 +1,344 @@
+package at.gv.egiz.eaaf.modules.auth.sl20.tasks;
+
+import java.io.IOException;
+import java.io.StringWriter;
+import java.net.URISyntaxException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import at.gv.egiz.eaaf.core.api.data.EAAFConstants;
+import at.gv.egiz.eaaf.core.api.idp.process.ExecutionContext;
+import at.gv.egiz.eaaf.core.exceptions.EaafAuthenticationException;
+import at.gv.egiz.eaaf.core.exceptions.EaafStorageException;
+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;
+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.SlCommandoParserException;
+import at.gv.egiz.eaaf.modules.auth.sl20.utils.IJoseTools;
+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.SL20JsonBuilderUtils;
+import at.gv.egiz.eaaf.modules.auth.sl20.utils.SL20JsonExtractorUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.http.client.utils.URIBuilder;
+import org.apache.http.entity.ContentType;
+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;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+
+
+public abstract class AbstractReceiveQualEidTask extends AbstractAuthServletTask {
+ private static final Logger log = LoggerFactory.getLogger(AbstractReceiveQualEidTask.class);
+
+ private static final String PATTERN_PENDING_REQ_ID = "#PENDINGREQID#";
+
+ @Autowired(required = true)
+ private IJoseTools joseTools;
+
+ @Override
+ public void execute(final ExecutionContext executionContext, final HttpServletRequest request,
+ final HttpServletResponse response) throws TaskExecutionException {
+ String sl20Result = null;
+
+ try {
+ log.debug("Receiving SL2.0 response process .... ");
+ JsonNode sl20ReqObj = null;
+
+ // A-Trust does not SET http-header 'SL2ClientType' with value 'native'
+ // If A-trust sends an error, its maybe FrontChannel on DataURL
+ // boolean aTrustErrorWorkAround = false;
+
+ try {
+ // get SL2.0 command or result from HTTP request
+ final Map<String, String> reqParams = getParameters(request);
+ sl20Result = reqParams.get(SL20Constants.PARAM_SL20_REQ_COMMAND_PARAM);
+
+ if (StringUtils.isEmpty(sl20Result)) {
+ // Workaround for SIC Handy-Signature, because it sends result in InputStream
+ final String isReqInput = StreamUtils.readStream(request.getInputStream(), "UTF-8");
+ if (StringUtils.isNotEmpty(isReqInput)) {
+ log.info("Use SIC Handy-Signature work-around!");
+ sl20Result = isReqInput.substring("slcommand=".length());
+
+ } else {
+ log.info("NO SL2.0 commando or result FOUND.");
+ throw new SL20Exception("sl20.04", null);
+ }
+
+ }
+
+ log.trace("Received SL2.0 result: " + sl20Result);
+ revisionsLogger.logEvent(pendingReq, EventCodes.AUTHPROCESS_SL20_DATAURL_IP,
+ request.getRemoteAddr());
+
+ // parse SL2.0 command/result into JSON
+ try {
+ 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);
+ throw new SL20Exception("sl20.02",
+ new Object[] {"SL2.0 command or result is NOT valid JSON."}, e);
+
+ }
+
+ // check on errorMessage
+ final VerificationResult payLoadContainerErrorCheck =
+ SL20JsonExtractorUtils.extractSL20PayLoad(sl20ReqObj, joseTools, false);
+ if (SL20JsonExtractorUtils
+ .getStringValue(payLoadContainerErrorCheck.getPayload(),
+ SL20Constants.SL20_COMMAND_CONTAINER_NAME, true)
+ .equals(SL20Constants.SL20_COMMAND_IDENTIFIER_ERROR)) {
+ log.debug("Find " + SL20Constants.SL20_COMMAND_IDENTIFIER_ERROR + " result .... ");
+ final JsonNode errorResult = SL20JsonExtractorUtils
+ .extractSL20Result(payLoadContainerErrorCheck.getPayload(), joseTools, false);
+ final String errorCode = SL20JsonExtractorUtils.getStringValue(errorResult,
+ SL20Constants.SL20_COMMAND_PARAM_GENERAL_RESPONSE_ERRORCODE, true);
+ final String errorMsg = SL20JsonExtractorUtils.getStringValue(errorResult,
+ SL20Constants.SL20_COMMAND_PARAM_GENERAL_RESPONSE_ERRORMESSAGE, false);
+
+ log.info("Receiving errorcode: {} with msg: {} from VDA! Stopping auth-process ... ",
+ errorCode, errorMsg);
+ // aTrustErrorWorkAround = true;
+ throw new SL20Exception("sl20.08", new Object[] {errorCode, errorMsg});
+
+ } else {
+ // Receive no error - To request validation
+
+ // validate reqId with inResponseTo
+ final String sl20ReqId = pendingReq.getRawData(
+ Constants.PENDING_REQ_STORAGE_PREFIX + SL20Constants.SL20_REQID, String.class);
+ final String inRespTo =
+ SL20JsonExtractorUtils.getStringValue(sl20ReqObj, SL20Constants.SL20_INRESPTO, true);
+ if (sl20ReqId == null || !sl20ReqId.equals(inRespTo)) {
+ log.info(
+ "SL20 'reqId': " + sl20ReqId + " does NOT match to 'inResponseTo':" + inRespTo);
+ throw new SL20SecurityException(
+ "SL20 'reqId': " + sl20ReqId + " does NOT match to 'inResponseTo':" + inRespTo);
+ }
+
+
+ // validate signature
+ final VerificationResult payLoadContainer = SL20JsonExtractorUtils
+ .extractSL20PayLoad(sl20ReqObj, joseTools, authConfig.getBasicConfigurationBoolean(
+ Constants.CONFIG_PROP_FORCE_EID_SIGNED_RESULT, true));
+
+ if ((payLoadContainer.isValidSigned() == null || !payLoadContainer.isValidSigned())) {
+ if (authConfig.getBasicConfigurationBoolean(
+ Constants.CONFIG_PROP_FORCE_EID_SIGNED_RESULT, true)) {
+ log.info("SL20 result from VDA was not valid signed");
+ throw new SL20SecurityException(new Object[] {"Signature on SL20 result NOT valid."});
+
+ } else {
+ log.warn(
+ "SL20 result from VDA is NOT valid signed, but signatures-verification "
+ + "is DISABLED by configuration!");
+
+ }
+ }
+
+ payLoadContainer.getCertChain();
+
+
+ // extract payloaf
+ final JsonNode payLoad = payLoadContainer.getPayload();
+
+
+ // handle SL2.0 response payLoad
+ handleResponsePayLoad(payLoad);
+
+ }
+
+ } catch (final EaafAuthenticationException e) {
+ log.warn("SL2.0 processing error:", e);
+ if (sl20Result != null) {
+ log.debug("Received SL2.0 result: " + sl20Result);
+ }
+ pendingReq.setRawDataToTransaction(
+ Constants.PENDING_REQ_STORAGE_PREFIX + SL20Constants.SL20_COMMAND_IDENTIFIER_ERROR,
+ 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);
+ }
+ pendingReq.setRawDataToTransaction(
+ Constants.PENDING_REQ_STORAGE_PREFIX + SL20Constants.SL20_COMMAND_IDENTIFIER_ERROR,
+ new TaskExecutionException(pendingReq, e.getMessage(), e));
+
+ } finally {
+ // store pending request
+ requestStoreage.storePendingRequest(pendingReq);
+
+ // write SL2.0 response
+ if (sl20ReqObj != null) {
+ // buildResponse(request, response, sl20ReqObj, aTrustErrorWorkAround);
+ buildResponse(request, response, sl20ReqObj);
+ } else {
+ buildErrorResponse(request, response, "2000", "General transport Binding error");
+ }
+
+ }
+
+ } catch (final Exception e) {
+ // write internal server errror 500 according to SL2.0 specification, chapter https transport
+ // binding
+ log.warn("Can NOT build SL2.0 response. Reason: " + e.getMessage(), e);
+ if (sl20Result != null) {
+ log.debug("Received SL2.0 result: " + sl20Result);
+ }
+ try {
+ response.sendError(500, "Internal Server Error.");
+
+ } catch (final IOException e1) {
+ log.error("Can NOT send error message. SOMETHING IS REALY WRONG!", e);
+
+ }
+
+ } finally {
+ TransactionIdUtils.removeTransactionId();
+ TransactionIdUtils.removeSessionId();
+
+ }
+ }
+
+ protected abstract void handleResponsePayLoad(JsonNode payLoad)
+ throws SlCommandoParserException, SL20Exception, EaafStorageException;
+
+ protected abstract String getResumeEndPoint();
+
+ private void buildErrorResponse(final HttpServletRequest request,
+ final HttpServletResponse response, final String errorCode, final String errorMsg)
+ throws Exception {
+ final ObjectNode error = SL20JsonBuilderUtils.createErrorCommandResult(errorCode, errorMsg);
+ final ObjectNode errorCommand = SL20JsonBuilderUtils
+ .createCommandResponse(SL20Constants.SL20_COMMAND_IDENTIFIER_ERROR, error, null);
+
+
+ final ObjectNode respContainer = SL20JsonBuilderUtils
+ .createGenericResponse(UUID.randomUUID().toString(), null, null, errorCommand, null);
+
+ log.trace("SL20 response to VDA: " + respContainer);
+ final StringWriter writer = new StringWriter();
+ writer.write(respContainer.toString());
+ final byte[] content = writer.toString().getBytes("UTF-8");
+ response.setStatus(HttpServletResponse.SC_OK);
+ response.setContentLength(content.length);
+ response.setContentType(ContentType.APPLICATION_JSON.toString());
+ response.getOutputStream().write(content);
+
+ }
+
+ private void buildResponse(final HttpServletRequest request, final HttpServletResponse response,
+ final JsonNode sl20ReqObj) throws IOException, SL20Exception, URISyntaxException {
+ // create response
+ final Map<String, String> reqParameters = new HashMap<>();
+ reqParameters.put(EAAFConstants.PARAM_HTTP_TARGET_PENDINGREQUESTID,
+ pendingReq.getPendingRequestId());
+ final ObjectNode callReqParams = SL20JsonBuilderUtils.createCallCommandParameters(
+ new DataUrlBuilder().buildDataUrl(pendingReq.getAuthUrl(), getResumeEndPoint(), null),
+ SL20Constants.SL20_COMMAND_PARAM_GENERAL_CALL_METHOD_GET, false, reqParameters);
+ final ObjectNode callCommand = SL20JsonBuilderUtils
+ .createCommand(SL20Constants.SL20_COMMAND_IDENTIFIER_CALL, callReqParams);
+
+ // build first redirect command for app
+ final ObjectNode redirectOneParams = SL20JsonBuilderUtils.createRedirectCommandParameters(
+ generateIpcRedirectUrlForDebugging(), callCommand, null, true);
+ final ObjectNode redirectOneCommand = SL20JsonBuilderUtils
+ .createCommand(SL20Constants.SL20_COMMAND_IDENTIFIER_REDIRECT, redirectOneParams);
+
+ // build second redirect command for IDP
+ final ObjectNode redirectTwoParams = SL20JsonBuilderUtils.createRedirectCommandParameters(
+ new DataUrlBuilder().buildDataUrl(pendingReq.getAuthUrl(), getResumeEndPoint(),
+ pendingReq.getPendingRequestId()),
+ redirectOneCommand, null, false);
+ final ObjectNode redirectTwoCommand = SL20JsonBuilderUtils
+ .createCommand(SL20Constants.SL20_COMMAND_IDENTIFIER_REDIRECT, redirectTwoParams);
+
+ // build generic SL2.0 response container
+ final String transactionId =
+ SL20JsonExtractorUtils.getStringValue(sl20ReqObj, SL20Constants.SL20_TRANSACTIONID, false);
+ final ObjectNode respContainer = SL20JsonBuilderUtils.createGenericRequest(
+ UUID.randomUUID().toString(), transactionId, redirectTwoCommand, null);
+
+ if (request.getHeader(SL20Constants.HTTP_HEADER_SL20_CLIENT_TYPE) != null
+ && request.getHeader(SL20Constants.HTTP_HEADER_SL20_CLIENT_TYPE)
+ .equals(SL20Constants.HTTP_HEADER_VALUE_NATIVE)) {
+ log.debug("Client request containts 'native client' header ... ");
+ log.trace("SL20 response to VDA: " + respContainer);
+ final StringWriter writer = new StringWriter();
+ writer.write(respContainer.toString());
+ final byte[] content = writer.toString().getBytes("UTF-8");
+ response.setStatus(HttpServletResponse.SC_OK);
+ response.setContentLength(content.length);
+ response.setContentType(ContentType.APPLICATION_JSON.toString());
+ response.getOutputStream().write(content);
+
+
+ } 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 ... ");
+ final URIBuilder clientRedirectUri =
+ new URIBuilder(new DataUrlBuilder().buildDataUrl(pendingReq.getAuthUrl(),
+ getResumeEndPoint(), pendingReq.getPendingRequestId()));
+ response.setStatus(Integer
+ .parseInt(authConfig.getBasicConfiguration(Constants.CONFIG_PROP_HTTP_REDIRECT_CODE,
+ Constants.CONFIG_PROP_HTTP_REDIRECT_CODE_DEFAULT_VALUE)));
+ response.setHeader("Location", clientRedirectUri.build().toString());
+
+
+ // throw new SL20Exception("sl20.06",
+ // new Object[] {"SL2.0 DataURL communication needs http header: '" +
+ // SL20Constants.HTTP_HEADER_SL20_CLIENT_TYPE + "'"});
+
+ }
+ }
+
+ /**
+ * Generates a IPC redirect URL that is configured on IDP side.
+ *
+ * @return IPC ReturnURL, or null if no URL is configured
+ */
+ private String generateIpcRedirectUrlForDebugging() {
+
+
+ String ipcRedirectUrlConfig =
+ authConfig.getBasicConfiguration(Constants.CONFIG_PROP_IPC_RETURN_URL);
+ if (StringUtils.isNotEmpty(ipcRedirectUrlConfig)) {
+ if (ipcRedirectUrlConfig.contains(PATTERN_PENDING_REQ_ID)) {
+ log.trace("Find 'pendingReqId' pattern in IPC redirect URL. Update url ... ");
+ ipcRedirectUrlConfig = ipcRedirectUrlConfig.replaceAll("#PENDINGREQID#",
+ EAAFConstants.PARAM_HTTP_TARGET_PENDINGREQUESTID + "="
+ + pendingReq.getPendingRequestId());
+
+ }
+
+ return ipcRedirectUrlConfig;
+ }
+
+ return null;
+
+ }
+
+
+}
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
deleted file mode 100644
index b4039cf9..00000000
--- a/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/tasks/AbstractReceiveQualeIDTask.java
+++ /dev/null
@@ -1,321 +0,0 @@
-package at.gv.egiz.eaaf.modules.auth.sl20.tasks;
-
-import java.io.IOException;
-import java.io.StringWriter;
-import java.net.URISyntaxException;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.UUID;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.apache.commons.lang3.StringUtils;
-import org.apache.http.client.utils.URIBuilder;
-import org.apache.http.entity.ContentType;
-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;
-import com.fasterxml.jackson.databind.JsonNode;
-import com.fasterxml.jackson.databind.node.ObjectNode;
-
-import at.gv.egiz.eaaf.core.api.data.EAAFConstants;
-import at.gv.egiz.eaaf.core.api.idp.process.ExecutionContext;
-import at.gv.egiz.eaaf.core.exceptions.EAAFAuthenticationException;
-import at.gv.egiz.eaaf.core.exceptions.EAAFStorageException;
-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;
-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.SLCommandoParserException;
-import at.gv.egiz.eaaf.modules.auth.sl20.utils.IJOSETools;
-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.SL20JSONBuilderUtils;
-import at.gv.egiz.eaaf.modules.auth.sl20.utils.SL20JSONExtractorUtils;
-
-
-public abstract class AbstractReceiveQualeIDTask extends AbstractAuthServletTask {
- private static final Logger log = LoggerFactory.getLogger(AbstractReceiveQualeIDTask.class);
-
- @Autowired(required=true) private IJOSETools joseTools;
-
- @Override
- public void execute(ExecutionContext executionContext, HttpServletRequest request, HttpServletResponse response)
- throws TaskExecutionException {
- String sl20Result = null;
-
- try {
- log.debug("Receiving SL2.0 response process .... ");
- JsonNode sl20ReqObj = null;
-
- //A-Trust does not SET http-header 'SL2ClientType' with value 'native'
- //If A-trust sends an error, its maybe FrontChannel on DataURL
- //boolean aTrustErrorWorkAround = false;
-
- try {
- //get SL2.0 command or result from HTTP request
- final Map<String, String> reqParams = getParameters(request);
- sl20Result = reqParams.get(SL20Constants.PARAM_SL20_REQ_COMMAND_PARAM);
-
- if (StringUtils.isEmpty(sl20Result)) {
- //Workaround for SIC Handy-Signature, because it sends result in InputStream
- final String isReqInput = StreamUtils.readStream(request.getInputStream(), "UTF-8");
- if (StringUtils.isNotEmpty(isReqInput)) {
- log.info("Use SIC Handy-Signature work-around!");
- sl20Result = isReqInput.substring("slcommand=".length());
-
- } else {
- log.info("NO SL2.0 commando or result FOUND.");
- throw new SL20Exception("sl20.04", null);
- }
-
- }
-
- log.trace("Received SL2.0 result: " + sl20Result);
- revisionsLogger.logEvent(pendingReq, EventCodes.AUTHPROCESS_SL20_DATAURL_IP, request.getRemoteAddr());
-
- //parse SL2.0 command/result into JSON
- try {
- 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);
- throw new SL20Exception("sl20.02", new Object[]{"SL2.0 command or result is NOT valid JSON."}, e);
-
- }
-
- //check on errorMessage
- final VerificationResult payLoadContainerErrorCheck = SL20JSONExtractorUtils.extractSL20PayLoad(sl20ReqObj, joseTools, false);
- if (SL20JSONExtractorUtils.getStringValue(
- payLoadContainerErrorCheck.getPayload(), SL20Constants.SL20_COMMAND_CONTAINER_NAME, true)
- .equals(SL20Constants.SL20_COMMAND_IDENTIFIER_ERROR)) {
- log.debug("Find " + SL20Constants.SL20_COMMAND_IDENTIFIER_ERROR + " result .... ");
- final JsonNode errorResult = SL20JSONExtractorUtils.extractSL20Result(payLoadContainerErrorCheck.getPayload(), joseTools, false);
- final String errorCode = SL20JSONExtractorUtils.getStringValue(errorResult,
- SL20Constants.SL20_COMMAND_PARAM_GENERAL_RESPONSE_ERRORCODE, true);
- final String errorMsg = SL20JSONExtractorUtils.getStringValue(errorResult,
- SL20Constants.SL20_COMMAND_PARAM_GENERAL_RESPONSE_ERRORMESSAGE, false);
-
- log.info("Receiving errorcode: {} with msg: {} from VDA! Stopping auth-process ... ", errorCode, errorMsg);
- //aTrustErrorWorkAround = true;
- throw new SL20Exception("sl20.08", new Object[] {errorCode, errorMsg});
-
- } else {
- //Receive no error - To request validation
-
- //validate reqId with inResponseTo
- final String sl20ReqId = pendingReq.getRawData(Constants.PENDING_REQ_STORAGE_PREFIX + SL20Constants.SL20_REQID, String.class);
- final String inRespTo = SL20JSONExtractorUtils.getStringValue(sl20ReqObj, SL20Constants.SL20_INRESPTO, true);
- if (sl20ReqId == null || !sl20ReqId.equals(inRespTo)) {
- log.info("SL20 'reqId': " + sl20ReqId + " does NOT match to 'inResponseTo':" + inRespTo);
- throw new SL20SecurityException("SL20 'reqId': " + sl20ReqId + " does NOT match to 'inResponseTo':" + inRespTo);
- }
-
-
- //validate signature
- final VerificationResult payLoadContainer = SL20JSONExtractorUtils.extractSL20PayLoad(
- sl20ReqObj, joseTools,
- authConfig.getBasicConfigurationBoolean(Constants.CONFIG_PROP_FORCE_EID_SIGNED_RESULT, true));
-
- if ( (payLoadContainer.isValidSigned() == null || !payLoadContainer.isValidSigned())) {
- if (authConfig.getBasicConfigurationBoolean(Constants.CONFIG_PROP_FORCE_EID_SIGNED_RESULT, true)) {
- log.info("SL20 result from VDA was not valid signed");
- throw new SL20SecurityException(new Object[]{"Signature on SL20 result NOT valid."});
-
- } else {
- log.warn("SL20 result from VDA is NOT valid signed, but signatures-verification is DISABLED by configuration!");
-
- }
- }
-
- payLoadContainer.getCertChain();
-
-
- //extract payloaf
- final JsonNode payLoad = payLoadContainer.getPayload();
-
-
- //handle SL2.0 response payLoad
- handleResponsePayLoad(payLoad);
-
- }
-
- } catch (final EAAFAuthenticationException e) {
- log.warn("SL2.0 processing error:", e);
- if (sl20Result != null)
- log.debug("Received SL2.0 result: " + sl20Result);
- pendingReq.setRawDataToTransaction(
- Constants.PENDING_REQ_STORAGE_PREFIX + SL20Constants.SL20_COMMAND_IDENTIFIER_ERROR,
- 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);
- pendingReq.setRawDataToTransaction(
- Constants.PENDING_REQ_STORAGE_PREFIX + SL20Constants.SL20_COMMAND_IDENTIFIER_ERROR,
- new TaskExecutionException(pendingReq, e.getMessage(), e));
-
- } finally {
- //store pending request
- requestStoreage.storePendingRequest(pendingReq);
-
- //write SL2.0 response
- if (sl20ReqObj != null)
- //buildResponse(request, response, sl20ReqObj, aTrustErrorWorkAround);
- buildResponse(request, response, sl20ReqObj);
- else
- buildErrorResponse(request, response, "2000", "General transport Binding error");
-
- }
-
- } catch (final Exception e) {
- //write internal server errror 500 according to SL2.0 specification, chapter https transport binding
- log.warn("Can NOT build SL2.0 response. Reason: " + e.getMessage(), e);
- if (sl20Result != null)
- log.debug("Received SL2.0 result: " + sl20Result);
- try {
- response.sendError(500, "Internal Server Error.");
-
- } catch (final IOException e1) {
- log.error("Can NOT send error message. SOMETHING IS REALY WRONG!", e);
-
- }
-
- } finally {
- TransactionIDUtils.removeTransactionId();
- TransactionIDUtils.removeSessionId();
-
- }
- }
-
- protected abstract void handleResponsePayLoad(JsonNode payLoad) throws SLCommandoParserException, SL20Exception, EAAFStorageException;
-
- protected abstract String getResumeEndPoint();
-
- private void buildErrorResponse(HttpServletRequest request, HttpServletResponse response, String errorCode, String errorMsg) throws Exception {
- final ObjectNode error = SL20JSONBuilderUtils.createErrorCommandResult(errorCode, errorMsg);
- final ObjectNode errorCommand = SL20JSONBuilderUtils.createCommandResponse(SL20Constants.SL20_COMMAND_IDENTIFIER_ERROR, error, null);
-
-
- final ObjectNode respContainer = SL20JSONBuilderUtils.createGenericResponse(
- UUID.randomUUID().toString(),
- null,
- null,
- errorCommand ,
- null);
-
- log.trace("SL20 response to VDA: " + respContainer);
- final StringWriter writer = new StringWriter();
- writer.write(respContainer.toString());
- final byte[] content = writer.toString().getBytes("UTF-8");
- response.setStatus(HttpServletResponse.SC_OK);
- response.setContentLength(content.length);
- response.setContentType(ContentType.APPLICATION_JSON.toString());
- response.getOutputStream().write(content);
-
- }
-
- private void buildResponse(HttpServletRequest request, HttpServletResponse response, JsonNode sl20ReqObj) throws IOException, SL20Exception, URISyntaxException {
- //create response
- final Map<String, String> reqParameters = new HashMap<String, String>();
- reqParameters.put(EAAFConstants.PARAM_HTTP_TARGET_PENDINGREQUESTID, pendingReq.getPendingRequestId());
- final ObjectNode callReqParams = SL20JSONBuilderUtils.createCallCommandParameters(
- new DataURLBuilder().buildDataURL(pendingReq.getAuthURL(), getResumeEndPoint(), null),
- SL20Constants.SL20_COMMAND_PARAM_GENERAL_CALL_METHOD_GET,
- false,
- reqParameters);
- final ObjectNode callCommand = SL20JSONBuilderUtils.createCommand(SL20Constants.SL20_COMMAND_IDENTIFIER_CALL, callReqParams);
-
- //build first redirect command for app
- final ObjectNode redirectOneParams = SL20JSONBuilderUtils.createRedirectCommandParameters(
- generateICPRedirectURLForDebugging(),
- callCommand, null, true);
- final ObjectNode redirectOneCommand = SL20JSONBuilderUtils.createCommand(SL20Constants.SL20_COMMAND_IDENTIFIER_REDIRECT, redirectOneParams);
-
- //build second redirect command for IDP
- final ObjectNode redirectTwoParams = SL20JSONBuilderUtils.createRedirectCommandParameters(
- new DataURLBuilder().buildDataURL(pendingReq.getAuthURL(), getResumeEndPoint(), pendingReq.getPendingRequestId()),
- redirectOneCommand, null, false);
- final ObjectNode redirectTwoCommand = SL20JSONBuilderUtils.createCommand(SL20Constants.SL20_COMMAND_IDENTIFIER_REDIRECT, redirectTwoParams);
-
- //build generic SL2.0 response container
- final String transactionId = SL20JSONExtractorUtils.getStringValue(sl20ReqObj, SL20Constants.SL20_TRANSACTIONID, false);
- final ObjectNode respContainer = SL20JSONBuilderUtils.createGenericRequest(
- UUID.randomUUID().toString(),
- transactionId,
- redirectTwoCommand,
- null);
-
- if (request.getHeader(SL20Constants.HTTP_HEADER_SL20_CLIENT_TYPE) != null &&
- request.getHeader(SL20Constants.HTTP_HEADER_SL20_CLIENT_TYPE).equals(SL20Constants.HTTP_HEADER_VALUE_NATIVE)) {
- log.debug("Client request containts 'native client' header ... ");
- log.trace("SL20 response to VDA: " + respContainer);
- final StringWriter writer = new StringWriter();
- writer.write(respContainer.toString());
- final byte[] content = writer.toString().getBytes("UTF-8");
- response.setStatus(HttpServletResponse.SC_OK);
- response.setContentLength(content.length);
- response.setContentType(ContentType.APPLICATION_JSON.toString());
- response.getOutputStream().write(content);
-
-
- } 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 ... ");
- final URIBuilder clientRedirectURI = new URIBuilder(
- new DataURLBuilder().buildDataURL(
- pendingReq.getAuthURL(), getResumeEndPoint(), pendingReq.getPendingRequestId()));
- response.setStatus(Integer.parseInt(
- authConfig.getBasicConfiguration(
- Constants.CONFIG_PROP_HTTP_REDIRECT_CODE,
- Constants.CONFIG_PROP_HTTP_REDIRECT_CODE_DEFAULT_VALUE)));
- response.setHeader("Location", clientRedirectURI.build().toString());
-
-
-// throw new SL20Exception("sl20.06",
-// new Object[] {"SL2.0 DataURL communication needs http header: '" + SL20Constants.HTTP_HEADER_SL20_CLIENT_TYPE + "'"});
-
- }
- }
-
- /**
- * Generates a IPC redirect URL that is configured on IDP side
- *
- * @return IPC ReturnURL, or null if no URL is configured
- */
- private String generateICPRedirectURLForDebugging() {
- final String PATTERN_PENDING_REQ_ID = "#PENDINGREQID#";
-
- String ipcRedirectURLConfig = authConfig.getBasicConfiguration(Constants.CONFIG_PROP_IPC_RETURN_URL);
- if (StringUtils.isNotEmpty(ipcRedirectURLConfig)) {
- if (ipcRedirectURLConfig.contains(PATTERN_PENDING_REQ_ID)) {
- log.trace("Find 'pendingReqId' pattern in IPC redirect URL. Update url ... ");
- ipcRedirectURLConfig = ipcRedirectURLConfig.replaceAll(
- "#PENDINGREQID#",
- EAAFConstants.PARAM_HTTP_TARGET_PENDINGREQUESTID + "=" + pendingReq.getPendingRequestId());
-
- }
-
- return ipcRedirectURLConfig;
- }
-
- return null;
-
- }
-
-
-}