summaryrefslogtreecommitdiff
path: root/eaaf_modules/eaaf_module_auth_sl20/src/main
diff options
context:
space:
mode:
authorThomas <>2023-08-21 15:17:36 +0200
committerThomas <>2023-08-21 15:17:36 +0200
commit958770eff456f5724e29166123c7e5c32391e3f4 (patch)
tree1bf83690e8db0727faa4409551da9540e15973f4 /eaaf_modules/eaaf_module_auth_sl20/src/main
parent5d56b6b2d8cc654a13b9358c7bbe5459f24fb0c5 (diff)
downloadEAAF-Components-958770eff456f5724e29166123c7e5c32391e3f4.tar.gz
EAAF-Components-958770eff456f5724e29166123c7e5c32391e3f4.tar.bz2
EAAF-Components-958770eff456f5724e29166123c7e5c32391e3f4.zip
refact(sl20): clean-up SL20 response handler
Diffstat (limited to 'eaaf_modules/eaaf_module_auth_sl20/src/main')
-rw-r--r--eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/tasks/AbstractReceiveQualEidTask.java324
1 files changed, 177 insertions, 147 deletions
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 f95d4adc..a12fb36f 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
@@ -6,11 +6,14 @@ import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
+import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.lang3.StringUtils;
import org.jose4j.base64url.Base64Url;
import org.springframework.beans.factory.annotation.Autowired;
import com.fasterxml.jackson.core.JsonParseException;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.JsonNode;
import at.gv.egiz.eaaf.core.api.idp.process.ExecutionContext;
@@ -48,155 +51,12 @@ public abstract class AbstractReceiveQualEidTask extends AbstractAuthServletTask
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;
+ // get SL2.0 command or result from HTTP request
+ sl20Result = getSl20OperationFromHttp(request);
+ revisionsLogger.logEvent(pendingReq, EventCodes.AUTHPROCESS_SL20_DATAURL_IP, request.getRemoteAddr());
- 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 = JsonMapper.getMapper().readTree(Base64Url.decodeToUtf8String(sl20Result));
-
- } catch (final JsonParseException e) {
- 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,
- 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);
-
- final SL20VdaResponseException ex = new SL20VdaResponseException("sl20.08", new Object[] {
- errorCode, errorMsg }, errorCode);
- log.info("Receiving errorcode: {} with msg: {} from VDA! Stopping auth-process ... ", errorCode,
- errorMsg);
-
- final String vdaSessionId = SL20JsonExtractorUtils.getStringValue(errorResult,
- SL20Constants.SL20_COMMAND_PARAM_GENERAL_RESPONSE_ERROR_VDASESSIONID, false);
- if (StringUtils.isNotEmpty(vdaSessionId)) {
- log.debug("VDA provides an optional sessionId. Inject it to internal error-holder ");
- ex.setVdaSessionId(vdaSessionId);
-
- }
- throw ex;
-
- } 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!");
-
- }
- }
-
- // extract payloaf
- final JsonNode payLoad = payLoadContainer.getPayload();
-
- // handle SL2.0 response payLoad
- handleResponsePayLoad(payLoad);
-
- }
-
- } catch (final EaafAuthenticationException e) {
- if (sl20Result != null) {
- log.debug("Received SL2.0 result: " + sl20Result);
- }
-
- pendingReq.setRawDataToTransaction(
- Constants.PENDING_REQ_STORAGE_PREFIX + SL20Constants.SL20_COMMAND_IDENTIFIER_ERROR,
- new ExceptionContainer(null,
- new TaskExecutionException(pendingReq, "SL2.0 Authentication FAILED. Msg: " + e.getMessage(),
- e)));
-
- } catch (final Exception e) {
- if (sl20Result != null) {
- log.debug("Received SL2.0 result: " + sl20Result);
- }
-
- pendingReq.setRawDataToTransaction(
- Constants.PENDING_REQ_STORAGE_PREFIX + SL20Constants.SL20_COMMAND_IDENTIFIER_ERROR,
- new ExceptionContainer(null, new TaskExecutionException(pendingReq, e.getMessage(), e)));
-
- } finally {
- // store pending request
- requestStoreage.storePendingRequest(pendingReq);
-
- // write SL2.0 response
- if (sl20ReqObj != null) {
- final String resumeEndpoint = new DataUrlBuilder().buildDataUrl(pendingReq.getAuthUrl(),
- getResumeEndPoint(), pendingReq.getPendingRequestId());
- SL20ResponseUtils.buildResponse(request, response, pendingReq, resumeEndpoint,
- SL20JsonExtractorUtils.getStringValue(sl20ReqObj, SL20Constants.SL20_TRANSACTIONID, false),
- authConfig);
-
- } else {
- SL20ResponseUtils.buildErrorResponse(response, "2000", "General transport Binding error");
- }
-
- }
+ internalExecute(request, response, sl20Result);
} catch (final Exception e) {
// write internal server errror 500 according to SL2.0 specification, chapter
@@ -221,4 +81,174 @@ public abstract class AbstractReceiveQualEidTask extends AbstractAuthServletTask
protected abstract String getResumeEndPoint();
+ private void internalExecute(HttpServletRequest request, HttpServletResponse response, String sl20Result)
+ throws Exception {
+ JsonNode sl20ReqObj = null;
+ try {
+ // parse SL2.0 command/result into JSON
+ sl20ReqObj = decodeSl20Request(sl20Result);
+ log.info("Receive response from A-Trust. Starting response-message validation ... ");
+
+ // 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)) {
+ handleSl20Error(payLoadContainerErrorCheck);
+
+ } else {
+ // Receive no error - To request validation
+ handleSl20Operation(sl20ReqObj);
+
+ }
+
+ } catch (final EaafAuthenticationException e) {
+ if (sl20Result != null) {
+ log.debug("Received SL2.0 result: " + sl20Result);
+ }
+
+ pendingReq.setRawDataToTransaction(
+ Constants.PENDING_REQ_STORAGE_PREFIX + SL20Constants.SL20_COMMAND_IDENTIFIER_ERROR,
+ new ExceptionContainer(null,
+ new TaskExecutionException(pendingReq, "SL2.0 Authentication FAILED. Msg: " + e.getMessage(),
+ e)));
+
+ } catch (final Exception e) {
+ if (sl20Result != null) {
+ log.debug("Received SL2.0 result: " + sl20Result);
+ }
+
+ pendingReq.setRawDataToTransaction(
+ Constants.PENDING_REQ_STORAGE_PREFIX + SL20Constants.SL20_COMMAND_IDENTIFIER_ERROR,
+ new ExceptionContainer(null, new TaskExecutionException(pendingReq, e.getMessage(), e)));
+
+ } finally {
+ // store pending request
+ requestStoreage.storePendingRequest(pendingReq);
+
+ // write SL2.0 response
+ if (sl20ReqObj != null) {
+ final String resumeEndpoint = new DataUrlBuilder().buildDataUrl(pendingReq.getAuthUrl(),
+ getResumeEndPoint(), pendingReq.getPendingRequestId());
+ SL20ResponseUtils.buildResponse(request, response, pendingReq, resumeEndpoint,
+ SL20JsonExtractorUtils.getStringValue(sl20ReqObj, SL20Constants.SL20_TRANSACTIONID, false),
+ authConfig);
+
+ } else {
+ SL20ResponseUtils.buildErrorResponse(response, "2000", "General transport Binding error");
+
+ }
+ }
+ }
+
+ private String getSl20OperationFromHttp(HttpServletRequest request)
+ throws SL20Exception, IOException, FileUploadException {
+ // 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;
+ String sl20Result = getSl20OperationFromHttp(request);
+
+ // 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);
+ return sl20Result;
+
+ }
+
+ private JsonNode decodeSl20Request(String sl20Result)
+ throws JsonMappingException, JsonProcessingException, SL20Exception {
+ try {
+ return JsonMapper.getMapper().readTree(Base64Url.decodeToUtf8String(sl20Result));
+
+ } catch (final JsonParseException e) {
+ 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);
+
+ }
+ }
+
+ private void handleSl20Error(VerificationResult payLoadContainerErrorCheck) throws SL20Exception {
+ 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);
+
+ final SL20VdaResponseException ex = new SL20VdaResponseException("sl20.08", new Object[] {
+ errorCode, errorMsg }, errorCode);
+ log.info("Receiving errorcode: {} with msg: {} from VDA! Stopping auth-process ... ", errorCode,
+ errorMsg);
+
+ final String vdaSessionId = SL20JsonExtractorUtils.getStringValue(errorResult,
+ SL20Constants.SL20_COMMAND_PARAM_GENERAL_RESPONSE_ERROR_VDASESSIONID, false);
+ if (StringUtils.isNotEmpty(vdaSessionId)) {
+ log.debug("VDA provides an optional sessionId. Inject it to internal error-holder ");
+ ex.setVdaSessionId(vdaSessionId);
+
+ }
+ throw ex;
+
+ }
+
+ private void handleSl20Operation(JsonNode sl20ReqObj) throws SlCommandoParserException, SL20Exception,
+ EaafStorageException {
+ // 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!");
+
+ }
+ }
+
+ // extract payloaf
+ final JsonNode payLoad = payLoadContainer.getPayload();
+
+ // handle SL2.0 response payLoad
+ handleResponsePayLoad(payLoad);
+
+ }
+
}