summaryrefslogtreecommitdiff
path: root/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/tasks/AbstractCreateQualeIDRequestTask.java
diff options
context:
space:
mode:
authorThomas Lenz <thomas.lenz@egiz.gv.at>2019-04-11 09:45:25 +0200
committerThomas Lenz <thomas.lenz@egiz.gv.at>2019-04-11 09:45:25 +0200
commitd781f0e89f16c650f70cc47d1ed5c4da2673b4d1 (patch)
treea6fc349c766cc7b095371dbbea7eb2e5765dacf8 /eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/tasks/AbstractCreateQualeIDRequestTask.java
parente19d3485c7ea0eb1cd877d52009e6efc932ce246 (diff)
downloadEAAF-Components-d781f0e89f16c650f70cc47d1ed5c4da2673b4d1.tar.gz
EAAF-Components-d781f0e89f16c650f70cc47d1ed5c4da2673b4d1.tar.bz2
EAAF-Components-d781f0e89f16c650f70cc47d1ed5c4da2673b4d1.zip
add EAAF module for authentication method based on Security-Layer 2.0 communication
Diffstat (limited to 'eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/tasks/AbstractCreateQualeIDRequestTask.java')
-rw-r--r--eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/tasks/AbstractCreateQualeIDRequestTask.java221
1 files changed, 221 insertions, 0 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..337002c5
--- /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,221 @@
+package at.gv.egiz.eaaf.modules.auth.sl20.tasks;
+
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.HashMap;
+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.IConfiguration;
+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.DataURLBuilder;
+import at.gv.egiz.eaaf.core.impl.utils.HttpClientFactory;
+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.IJOSETools;
+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 IJOSETools joseTools;
+ @Autowired(required=true) private IConfiguration basicConfig;
+ @Autowired(required=true) private HttpClientFactory httpClientFactory;
+
+ @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
+ ISPConfiguration oaConfig = pendingReq.getServiceProviderConfiguration();
+
+ //get basic configuration parameters
+ 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"});
+
+ }
+
+ revisionsLogger.logEvent(pendingReq, EventCodes.AUTHPROCESS_SL20_ENDPOINT_URL, vdaQualeIDUrl);
+
+ //create SL2.0 command for qualified eID
+ String signedQualeIDCommand = buildSignedQualifiedEIDCommand();
+
+ //build request container
+ String qualeIDReqId = Random.nextProcessReferenceValue();
+ ObjectNode sl20Req = SL20JSONBuilderUtils.createGenericRequest(qualeIDReqId, null, null, signedQualeIDCommand);
+
+ //build http POST request
+ HttpPost httpReq = new HttpPost(new URIBuilder(vdaQualeIDUrl).build());
+ 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
+ HttpResponse httpResp = httpClientFactory.getHttpClient().execute(httpReq);
+
+ //parse response
+ log.info("Receive response from VDA ... ");
+ JsonNode sl20Resp = SL20JSONExtractorUtils.getSL20ContainerFromResponse(httpResp);
+ VerificationResult respPayloadContainer = SL20JSONExtractorUtils.extractSL20PayLoad(sl20Resp, null, false);
+
+ if (respPayloadContainer.isValidSigned() == null) {
+ log.debug("Receive unsigned payLoad from VDA");
+
+ }
+
+ 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 ... ");
+ JsonNode params = SL20JSONExtractorUtils.getJSONObjectValue(respPayload, SL20Constants.SL20_COMMAND_CONTAINER_PARAMS, true);
+ String redirectURL = SL20JSONExtractorUtils.getStringValue(params, SL20Constants.SL20_COMMAND_PARAM_GENERAL_REDIRECT_URL, true);
+ JsonNode command = SL20JSONExtractorUtils.getJSONObjectValue(params, SL20Constants.SL20_COMMAND_PARAM_GENERAL_REDIRECT_COMMAND, false);
+ String signedCommand = SL20JSONExtractorUtils.getStringValue(params, SL20Constants.SL20_COMMAND_PARAM_GENERAL_REDIRECT_SIGNEDCOMMAND, false);
+
+ //create forward SL2.0 command
+ 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);
+
+ } 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);
+
+ String errorCode = SL20JSONExtractorUtils.getStringValue(result, SL20Constants.SL20_COMMAND_PARAM_GENERAL_RESPONSE_ERRORCODE, true);
+ 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 (EAAFAuthenticationException e) {
+ throw new TaskExecutionException(pendingReq, "SL2.0 Authentication FAILED. Msg: " + e.getMessage(), e);
+
+ } catch (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) {
+
+ //TODO: fully remove if not required any more
+ //String spSpecificVDAEndpoints = oaConfig.getConfigurationValue(MOAIDConfigurationConstants.SERVICE_AUTH_SL20_ENDPOINTS);
+ String spSpecificVDAEndpoints = null;
+
+ Map<String, String> endPointMap = authConfig.getBasicMOAIDConfigurationWithPrefix(Constants.CONFIG_PROP_VDA_ENDPOINT_QUALeID_LIST);
+ 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
+ String sl20VDATypeHeader = (String) executionContext.get(SL20Constants.HTTP_HEADER_SL20_VDA_TYPE.toLowerCase());
+ if (StringUtils.isNotEmpty(sl20VDATypeHeader)) {
+ 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 SP specific VDA endpoint found. Use default VDA");
+ return endPointMap.getOrDefault(Constants.CONFIG_PROP_VDA_ENDPOINT_QUALeID_DEFAULT,
+ Constants.CONFIG_PROP_VDA_ENDPOINT_QUALeID + Constants.CONFIG_PROP_VDA_ENDPOINT_QUALeID_DEFAULT);
+
+ }
+
+}