diff options
Diffstat (limited to 'id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/tasks/ReceiveQualeIDTask.java')
-rw-r--r-- | id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/tasks/ReceiveQualeIDTask.java | 309 |
1 files changed, 204 insertions, 105 deletions
diff --git a/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/tasks/ReceiveQualeIDTask.java b/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/tasks/ReceiveQualeIDTask.java index 8791da429..a3175713a 100644 --- a/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/tasks/ReceiveQualeIDTask.java +++ b/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/tasks/ReceiveQualeIDTask.java @@ -1,9 +1,8 @@ package at.gv.egovernment.moa.id.auth.modules.sl20_auth.tasks; -import java.io.ByteArrayInputStream; +import java.io.IOException; import java.io.StringWriter; import java.security.cert.X509Certificate; -import java.util.Calendar; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -13,6 +12,7 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.http.entity.ContentType; +import org.jose4j.base64url.Base64Url; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -27,8 +27,9 @@ 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.idp.controller.AbstractAuthProtocolModulController; 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.egovernment.moa.id.auth.data.AuthenticationSessionWrapper; +import at.gv.egovernment.moa.id.advancedlogging.MOAIDEventConstants; import at.gv.egovernment.moa.id.auth.modules.sl20_auth.Constants; import at.gv.egovernment.moa.id.auth.modules.sl20_auth.data.VerificationResult; import at.gv.egovernment.moa.id.auth.modules.sl20_auth.exceptions.SL20Exception; @@ -38,13 +39,11 @@ import at.gv.egovernment.moa.id.auth.modules.sl20_auth.sl20.IJOSETools; import at.gv.egovernment.moa.id.auth.modules.sl20_auth.sl20.SL20Constants; import at.gv.egovernment.moa.id.auth.modules.sl20_auth.sl20.SL20JSONBuilderUtils; import at.gv.egovernment.moa.id.auth.modules.sl20_auth.sl20.SL20JSONExtractorUtils; -import at.gv.egovernment.moa.id.auth.parser.IdentityLinkAssertionParser; import at.gv.egovernment.moa.id.commons.api.exceptions.MOAIDException; -import at.gv.egovernment.moa.util.Base64Utils; -import at.gv.egovernment.moa.util.DateTimeUtils; import at.gv.egovernment.moa.util.MiscUtil; import at.gv.egovernment.moaspss.logging.Logger; + @Component("ReceiveQualeIDTask") public class ReceiveQualeIDTask extends AbstractAuthServletTask { @@ -52,98 +51,197 @@ public class ReceiveQualeIDTask extends AbstractAuthServletTask { @Override public void execute(ExecutionContext executionContext, HttpServletRequest request, HttpServletResponse response) - throws TaskExecutionException { + throws TaskExecutionException { + String sl20Result = null; - Logger.debug("Receiving SL2.0 response process .... "); try { - //get SL2.0 command or result from HTTP request - Map<String, String> reqParams = getParameters(request); - String sl20Result = reqParams.get(SL20Constants.PARAM_SL20_REQ_COMMAND_PARAM); - if (MiscUtil.isEmpty(sl20Result)) { - Logger.info("NO SL2.0 commando or result FOUND."); - throw new SL20Exception("sl20.04", null); + Logger.debug("Receiving SL2.0 response process .... "); + JsonObject sl20ReqObj = null; + try { + //get SL2.0 command or result from HTTP request + Map<String, String> reqParams = getParameters(request); + sl20Result = reqParams.get(SL20Constants.PARAM_SL20_REQ_COMMAND_PARAM); - } - + if (MiscUtil.isEmpty(sl20Result)) { + //Workaround for SIC Handy-Signature, because it sends result in InputStream + String isReqInput = StreamUtils.readStream(request.getInputStream(), "UTF-8"); + if (MiscUtil.isNotEmpty(isReqInput)) { + Logger.info("Use SIC Handy-Signature work-around!"); + sl20Result = isReqInput.substring("slcommand=".length()); + + } else { + Logger.info("NO SL2.0 commando or result FOUND."); + throw new SL20Exception("sl20.04", null); + } + + } + + Logger.trace("Received SL2.0 result: " + sl20Result); + revisionsLogger.logEvent(pendingReq, MOAIDEventConstants.AUTHPROCESS_BKU_DATAURL_IP, request.getRemoteAddr()); - //parse SL2.0 command/result into JSON - JsonObject sl20ReqObj = null; - try { - JsonParser jsonParser = new JsonParser(); - JsonElement sl20Req = jsonParser.parse(sl20Result); - sl20ReqObj = sl20Req.getAsJsonObject(); + //parse SL2.0 command/result into JSON + try { + JsonParser jsonParser = new JsonParser(); + JsonElement sl20Req = jsonParser.parse(Base64Url.decodeToUtf8String(sl20Result)); + sl20ReqObj = sl20Req.getAsJsonObject(); - } catch (JsonSyntaxException e) { - Logger.warn("SL2.0 command or result is NOT valid JSON.", e); - Logger.debug("SL2.0 msg: " + sl20Result); - throw new SL20Exception("sl20.02", new Object[]{"SL2.0 command or result is NOT valid JSON."}, e); + } catch (JsonSyntaxException e) { + Logger.warn("SL2.0 command or result is NOT valid JSON.", e); + Logger.debug("SL2.0 msg: " + sl20Result); + throw new SL20Exception("sl20.02", new Object[]{"SL2.0 command or result is NOT valid JSON."}, e); - } + } - //validate reqId with inResponseTo - String sl20ReqId = pendingReq.getGenericData(Constants.PENDING_REQ_STORAGE_PREFIX + SL20Constants.SL20_REQID, String.class); - String inRespTo = SL20JSONExtractorUtils.getStringValue(sl20ReqObj, SL20Constants.SL20_INRESPTO, true); - if (sl20ReqId == null || !sl20ReqId.equals(inRespTo)) { - Logger.info("SL20 'reqId': " + sl20ReqId + " does NOT match to 'inResponseTo':" + inRespTo); - throw new SL20SecurityException("SL20 'reqId': " + sl20ReqId + " does NOT match to 'inResponseTo':" + inRespTo); - } + //validate reqId with inResponseTo + String sl20ReqId = pendingReq.getGenericData(Constants.PENDING_REQ_STORAGE_PREFIX + SL20Constants.SL20_REQID, String.class); + String inRespTo = SL20JSONExtractorUtils.getStringValue(sl20ReqObj, SL20Constants.SL20_INRESPTO, true); + if (sl20ReqId == null || !sl20ReqId.equals(inRespTo)) { + Logger.info("SL20 'reqId': " + sl20ReqId + " does NOT match to 'inResponseTo':" + inRespTo); + throw new SL20SecurityException("SL20 'reqId': " + sl20ReqId + " does NOT match to 'inResponseTo':" + inRespTo); + } - //validate signature - VerificationResult payLoadContainer = SL20JSONExtractorUtils.extractSL20PayLoad(sl20ReqObj, joseTools, true); - if (payLoadContainer.isValidSigned() == null || - !payLoadContainer.isValidSigned()) { - Logger.info("SL20 result from VDA was not valid signed"); - throw new SL20SecurityException(new Object[]{"Signature on SL20 result NOT valid."}); + //validate signature + VerificationResult payLoadContainer = SL20JSONExtractorUtils.extractSL20PayLoad( + sl20ReqObj, joseTools, + authConfig.getBasicMOAIDConfigurationBoolean(Constants.CONFIG_PROP_FORCE_EID_SIGNED_RESULT, true)); - } - - //TODO validate certificate - List<X509Certificate> sigCertChain = payLoadContainer.getCertChain(); + if ( (payLoadContainer.isValidSigned() == null || !payLoadContainer.isValidSigned())) { + if (authConfig.getBasicMOAIDConfigurationBoolean(Constants.CONFIG_PROP_FORCE_EID_SIGNED_RESULT, true)) { + Logger.info("SL20 result from VDA was not valid signed"); + throw new SL20SecurityException(new Object[]{"Signature on SL20 result NOT valid."}); + + } else { + Logger.warn("SL20 result from VDA is NOT valid signed, but signatures-verification is DISABLED by configuration!"); + + } + } + + /*TODO validate certificate by using MOA-SPSS + * currently, the certificate is validated in IJOSETools by using a pkcs12 or jks keystore + */ + List<X509Certificate> sigCertChain = payLoadContainer.getCertChain(); - //extract payloaf - JsonObject payLoad = payLoadContainer.getPayload(); + //extract payloaf + JsonObject payLoad = payLoadContainer.getPayload(); - //check response type - if (SL20JSONExtractorUtils.getStringValue( - payLoad, SL20Constants.SL20_COMMAND_CONTAINER_NAME, true) - .equals(SL20Constants.SL20_COMMAND_IDENTIFIER_QUALIFIEDEID)) { - Logger.debug("Find " + SL20Constants.SL20_COMMAND_IDENTIFIER_QUALIFIEDEID + " result .... "); + //check response type + if (SL20JSONExtractorUtils.getStringValue( + payLoad, SL20Constants.SL20_COMMAND_CONTAINER_NAME, true) + .equals(SL20Constants.SL20_COMMAND_IDENTIFIER_QUALIFIEDEID)) { + Logger.debug("Find " + SL20Constants.SL20_COMMAND_IDENTIFIER_QUALIFIEDEID + " result .... "); - //TODO: activate decryption in 'SL20JSONExtractorUtils.extractSL20Result' - JsonElement qualeIDResult = SL20JSONExtractorUtils.extractSL20Result(payLoad, joseTools, false); - - //extract attributes from result - String idlB64 = SL20JSONExtractorUtils.getStringValue(qualeIDResult.getAsJsonObject(), - SL20Constants.SL20_COMMAND_PARAM_EID_RESULT_IDL, true); - String authBlockB64 = SL20JSONExtractorUtils.getStringValue(qualeIDResult.getAsJsonObject(), - SL20Constants.SL20_COMMAND_PARAM_EID_RESULT_AUTHBLOCK, true); - String ccsURL = SL20JSONExtractorUtils.getStringValue(qualeIDResult.getAsJsonObject(), - SL20Constants.SL20_COMMAND_PARAM_EID_RESULT_CCSURL, true); - String LoA = SL20JSONExtractorUtils.getStringValue(qualeIDResult.getAsJsonObject(), - SL20Constants.SL20_COMMAND_PARAM_EID_RESULT_LOA, true); - - - //TODO: validate results - - - //add into session - AuthenticationSessionWrapper moasession = new AuthenticationSessionWrapper(pendingReq.genericFullDataStorage()); - moasession.setIdentityLink(new IdentityLinkAssertionParser(new ByteArrayInputStream(Base64Utils.decode(idlB64, false))).parseIdentityLink()); - moasession.setBkuURL(ccsURL); - //TODO: from AuthBlock - moasession.setIssueInstant(DateTimeUtils.buildDateTimeUTC(Calendar.getInstance())); - moasession.setQAALevel(LoA); - - //mark as authenticated - moasession.setAuthenticated(true); - pendingReq.setAuthenticated(true); + JsonElement qualeIDResult = SL20JSONExtractorUtils.extractSL20Result( + payLoad, joseTools, + authConfig.getBasicMOAIDConfigurationBoolean(Constants.CONFIG_PROP_FORCE_EID_ENCRYPTION, true)); + + //extract attributes from result + Map<String, String> eIDData = SL20JSONExtractorUtils.getMapOfStringElements(qualeIDResult); + String idlB64 = eIDData.get(SL20Constants.SL20_COMMAND_PARAM_EID_RESULT_IDL); + String authBlockB64 = eIDData.get(SL20Constants.SL20_COMMAND_PARAM_EID_RESULT_AUTHBLOCK); + String ccsURL = eIDData.get(SL20Constants.SL20_COMMAND_PARAM_EID_RESULT_CCSURL); + String LoA = eIDData.get(SL20Constants.SL20_COMMAND_PARAM_EID_RESULT_LOA); + + + + if (MiscUtil.isEmpty(idlB64) || MiscUtil.isEmpty(authBlockB64) + || MiscUtil.isEmpty(LoA) || MiscUtil.isEmpty(ccsURL)) { + Logger.info("SL20 'qualifiedeID' result does NOT contain all required attributes."); + throw new SLCommandoParserException("SL20 'qualifiedeID' result does NOT contain all required attributes."); + + } + + //cache qualified eID data into pending request + pendingReq.setGenericDataToSession( + Constants.PENDING_REQ_STORAGE_PREFIX + SL20Constants.SL20_COMMAND_PARAM_EID_RESULT_IDL, + idlB64); + pendingReq.setGenericDataToSession( + Constants.PENDING_REQ_STORAGE_PREFIX + SL20Constants.SL20_COMMAND_PARAM_EID_RESULT_AUTHBLOCK, + authBlockB64); + pendingReq.setGenericDataToSession( + Constants.PENDING_REQ_STORAGE_PREFIX + SL20Constants.SL20_COMMAND_PARAM_EID_RESULT_CCSURL, + ccsURL); + pendingReq.setGenericDataToSession( + Constants.PENDING_REQ_STORAGE_PREFIX + SL20Constants.SL20_COMMAND_PARAM_EID_RESULT_LOA, + LoA); + } else { + Logger.info("SL20 response is NOT a " + SL20Constants.SL20_COMMAND_IDENTIFIER_QUALIFIEDEID + " result"); + throw new SLCommandoParserException("SL20 response is NOT a " + SL20Constants.SL20_COMMAND_IDENTIFIER_QUALIFIEDEID + " result"); + } + + + } catch (MOAIDException e) { + Logger.warn("SL2.0 processing error:", e); + if (sl20Result != null) + Logger.debug("Received SL2.0 result: " + sl20Result); + pendingReq.setGenericDataToSession( + Constants.PENDING_REQ_STORAGE_PREFIX + SL20Constants.SL20_COMMAND_IDENTIFIER_ERROR, + new TaskExecutionException(pendingReq, "SL2.0 Authentication FAILED. Msg: " + e.getMessage(), e)); + + } catch (Exception e) { + Logger.warn("ERROR:", e); + Logger.warn("SL2.0 Authentication FAILED with a generic error.", e); + if (sl20Result != null) + Logger.debug("Received SL2.0 result: " + sl20Result); + pendingReq.setGenericDataToSession( + Constants.PENDING_REQ_STORAGE_PREFIX + SL20Constants.SL20_COMMAND_IDENTIFIER_ERROR, + new TaskExecutionException(pendingReq, e.getMessage(), e)); + + } finally { //store pending request - pendingReq.setGenericDataToSession(moasession.getKeyValueRepresentationFromAuthSession()); requestStoreage.storePendingRequest(pendingReq); + //write SL2.0 response + if (sl20ReqObj != null) + buildResponse(request, response, sl20ReqObj); + else + buildErrorResponse(request, response, "2000", "General transport Binding error"); + + } + + } catch (Exception e) { + //write internal server errror 500 according to SL2.0 specification, chapter https transport binding + Logger.warn("Can NOT build SL2.0 response. Reason: " + e.getMessage(), e); + if (sl20Result != null) + Logger.debug("Received SL2.0 result: " + sl20Result); + try { + response.sendError(500, "Internal Server Error."); + + } catch (IOException e1) { + Logger.error("Can NOT send error message. SOMETHING IS REALY WRONG!", e); + + } + + } finally { + TransactionIDUtils.removeTransactionId(); + TransactionIDUtils.removeSessionId(); + + } + } + + private void buildErrorResponse(HttpServletRequest request, HttpServletResponse response, String errorCode, String errorMsg) throws Exception { + JsonObject error = SL20JSONBuilderUtils.createErrorCommandResult(errorCode, errorMsg); + JsonObject respContainer = SL20JSONBuilderUtils.createGenericRequest( + UUID.randomUUID().toString(), + null, + error , + null); + + Logger.debug("Client request containts 'native client' header ... "); + Logger.trace("SL20 response to VDA: " + respContainer); + 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, JsonObject sl20ReqObj) throws IOException, SL20Exception { //create response Map<String, String> reqParameters = new HashMap<String, String>(); reqParameters.put(EAAFConstants.PARAM_HTTP_TARGET_PENDINGREQUESTID, pendingReq.getPendingRequestId()); @@ -155,7 +253,9 @@ public class ReceiveQualeIDTask extends AbstractAuthServletTask { JsonObject callCommand = SL20JSONBuilderUtils.createCommand(SL20Constants.SL20_COMMAND_IDENTIFIER_CALL, callReqParams); //build first redirect command for app - JsonObject redirectOneParams = SL20JSONBuilderUtils.createRedirectCommandParameters("", callCommand, null, true); + JsonObject redirectOneParams = SL20JSONBuilderUtils.createRedirectCommandParameters( + generateICPRedirectURLForDebugging(), + callCommand, null, true); JsonObject redirectOneCommand = SL20JSONBuilderUtils.createCommand(SL20Constants.SL20_COMMAND_IDENTIFIER_REDIRECT, redirectOneParams); //build second redirect command for IDP @@ -172,9 +272,12 @@ public class ReceiveQualeIDTask extends AbstractAuthServletTask { redirectTwoCommand, null); + //workaround for A-Trust if (request.getHeader(SL20Constants.HTTP_HEADER_SL20_CLIENT_TYPE) != null && - request.getHeader(SL20Constants.HTTP_HEADER_SL20_CLIENT_TYPE).equals(SL20Constants.HTTP_HEADER_VALUE_NATIVE)) { - Logger.debug("Client request containts 'native client' header ... "); + request.getHeader(SL20Constants.HTTP_HEADER_SL20_CLIENT_TYPE).equals(SL20Constants.HTTP_HEADER_VALUE_NATIVE) + || true) { + Logger.debug("Client request containts 'native client' header ... "); + Logger.trace("SL20 response to VDA: " + respContainer); StringWriter writer = new StringWriter(); writer.write(respContainer.toString()); final byte[] content = writer.toString().getBytes("UTF-8"); @@ -190,36 +293,32 @@ public class ReceiveQualeIDTask extends AbstractAuthServletTask { new Object[] {"SL2.0 DataURL communication needs http header: '" + SL20Constants.HTTP_HEADER_SL20_CLIENT_TYPE + "'"}); } - - } else { - Logger.info("SL20 response is NOT a " + SL20Constants.SL20_COMMAND_IDENTIFIER_QUALIFIEDEID + " result"); - throw new SLCommandoParserException("SL20 response is NOT a " + SL20Constants.SL20_COMMAND_IDENTIFIER_QUALIFIEDEID + " result"); } + + /** + * 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 (MiscUtil.isNotEmpty(ipcRedirectURLConfig)) { + if (ipcRedirectURLConfig.contains(PATTERN_PENDING_REQ_ID)) { + Logger.trace("Find 'pendingReqId' pattern in IPC redirect URL. Update url ... "); + ipcRedirectURLConfig = ipcRedirectURLConfig.replaceAll( + "#PENDINGREQID#", + EAAFConstants.PARAM_HTTP_TARGET_PENDINGREQUESTID + "=" + pendingReq.getPendingRequestId()); - } catch (MOAIDException e) { - Logger.warn("ERROR:", e); - throw new TaskExecutionException(pendingReq, "SL2.0 Authentication FAILED. Msg: " + e.getMessage(), e); - - } catch (Exception e) { - Logger.warn("ERROR:", e); - Logger.warn("SL2.0 Authentication FAILED with a generic error.", e); - throw new TaskExecutionException(pendingReq, e.getMessage(), e); - - } finally { - TransactionIDUtils.removeTransactionId(); - TransactionIDUtils.removeSessionId(); + } + return ipcRedirectURLConfig; } - } - - private JsonObject createRedirectCommand() { - - return null; - } + } |