diff options
| author | Thomas <> | 2023-08-21 15:17:36 +0200 | 
|---|---|---|
| committer | Thomas <> | 2023-08-21 15:17:36 +0200 | 
| commit | 958770eff456f5724e29166123c7e5c32391e3f4 (patch) | |
| tree | 1bf83690e8db0727faa4409551da9540e15973f4 /eaaf_modules/eaaf_module_auth_sl20 | |
| parent | 5d56b6b2d8cc654a13b9358c7bbe5459f24fb0c5 (diff) | |
| download | EAAF-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')
| -rw-r--r-- | eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/tasks/AbstractReceiveQualEidTask.java | 324 | 
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); + +  } +  } | 
