diff options
author | Thomas Lenz <tlenz@iaik.tugraz.at> | 2018-05-30 14:36:39 +0200 |
---|---|---|
committer | Thomas Lenz <tlenz@iaik.tugraz.at> | 2018-05-30 14:36:39 +0200 |
commit | ecf9de84e76dde785ced8c1632c7909d1d57f94a (patch) | |
tree | ef32ed58461f520a790f53f1a049e566458482a0 /id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/tasks | |
parent | 52ad604e54cb91073503d708cd0c50ff0121174a (diff) | |
download | moa-id-spss-ecf9de84e76dde785ced8c1632c7909d1d57f94a.tar.gz moa-id-spss-ecf9de84e76dde785ced8c1632c7909d1d57f94a.tar.bz2 moa-id-spss-ecf9de84e76dde785ced8c1632c7909d1d57f94a.zip |
add error handling and some more validation to SL2.0 module
Diffstat (limited to 'id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/tasks')
3 files changed, 383 insertions, 153 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/CreateQualeIDRequestTask.java b/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/tasks/CreateQualeIDRequestTask.java index d9ff9d93c..763454639 100644 --- a/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/tasks/CreateQualeIDRequestTask.java +++ b/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/tasks/CreateQualeIDRequestTask.java @@ -5,7 +5,6 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; -import java.util.UUID; import javax.net.ssl.SSLSocketFactory; import javax.servlet.http.HttpServletRequest; @@ -30,6 +29,7 @@ import at.gv.egovernment.moa.id.auth.modules.TaskExecutionException; 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; +import at.gv.egovernment.moa.id.auth.modules.sl20_auth.exceptions.SLCommandoParserException; 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.SL20HttpBindingUtils; @@ -41,6 +41,7 @@ import at.gv.egovernment.moa.id.commons.api.exceptions.MOAIDException; import at.gv.egovernment.moa.id.commons.utils.HttpClientWithProxySupport; import at.gv.egovernment.moa.id.commons.utils.KeyValueUtils; import at.gv.egovernment.moa.id.process.api.ExecutionContext; +import at.gv.egovernment.moa.id.protocols.pvp2x.utils.SAML2Utils; import at.gv.egovernment.moa.id.util.SSLUtils; import at.gv.egovernment.moa.util.MiscUtil; import at.gv.egovernment.moaspss.logging.Logger; @@ -91,7 +92,8 @@ public class CreateQualeIDRequestTask extends AbstractAuthServletTask { qualifiedeIDParams, joseTools.getEncryptionCertificate()); - String qualeIDReqId = UUID.randomUUID().toString(); + //String qualeIDReqId = UUID.randomUUID().toString(); + String qualeIDReqId = SAML2Utils.getSecureIdentifier(); String signedQualeIDCommand = SL20JSONBuilderUtils.createSignedCommand(SL20Constants.SL20_COMMAND_IDENTIFIER_QUALIFIEDEID, qualeIDCommandParams, joseTools); JsonObject sl20Req = SL20JSONBuilderUtils.createGenericRequest(qualeIDReqId, null, null, signedQualeIDCommand); @@ -107,9 +109,16 @@ public class CreateQualeIDRequestTask extends AbstractAuthServletTask { HttpPost httpReq = new HttpPost(new URIBuilder(vdaQualeIDUrl).build()); httpReq.addHeader(SL20Constants.HTTP_HEADER_SL20_CLIENT_TYPE, SL20Constants.HTTP_HEADER_VALUE_NATIVE); List<NameValuePair> parameters = new ArrayList<NameValuePair>();; - parameters.add(new BasicNameValuePair(SL20Constants.PARAM_SL20_REQ_COMMAND_PARAM, sl20Req.toString())); + + //correct one + //parameters.add(new BasicNameValuePair(SL20Constants.PARAM_SL20_REQ_COMMAND_PARAM, Base64Url.encode(sl20Req.toString().getBytes()))); + + //A-Trust current version + parameters.add(new BasicNameValuePair(SL20Constants.PARAM_SL20_REQ_COMMAND_PARAM_OLD, sl20Req.toString())); httpReq.setEntity(new UrlEncodedFormEntity(parameters )); + + //request VDA HttpResponse httpResp = httpClient.execute(httpReq); @@ -147,10 +156,22 @@ public class CreateQualeIDRequestTask extends AbstractAuthServletTask { //TODO: maybe add SL2ClientType Header from execution context SL20HttpBindingUtils.writeIntoResponse(request, response, sl20Forward, redirectURL); + } else if (respPayload.get(SL20Constants.SL20_COMMAND_CONTAINER_NAME).getAsString() + .equals(SL20Constants.SL20_COMMAND_IDENTIFIER_ERROR)) { + JsonObject 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); + + Logger.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 Logger.warn("Received an unrecognized command: " + respPayload.get(SL20Constants.SL20_COMMAND_CONTAINER_NAME).getAsString()); - + throw new SLCommandoParserException("Received an unrecognized command: \" + respPayload.get(SL20Constants.SL20_COMMAND_CONTAINER_NAME).getAsString()"); } 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 90e19326e..b7fe579a3 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,7 +12,6 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.http.entity.ContentType; -import org.jose4j.keys.X509Util; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -35,18 +33,12 @@ 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.MOAIDAuthConstants; -import at.gv.egovernment.moa.id.commons.api.data.IIdentityLink; import at.gv.egovernment.moa.id.commons.api.exceptions.MOAIDException; import at.gv.egovernment.moa.id.process.api.ExecutionContext; -import at.gv.egovernment.moa.id.protocols.AbstractAuthProtocolModulController; -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; -import iaik.esi.sva.util.X509Utils; -import iaik.utils.Util; + @Component("ReceiveQualeIDTask") public class ReceiveQualeIDTask extends AbstractAuthServletTask { @@ -57,173 +49,210 @@ public class ReceiveQualeIDTask extends AbstractAuthServletTask { public void execute(ExecutionContext executionContext, HttpServletRequest request, HttpServletResponse response) throws TaskExecutionException { - 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); - - } - - - //parse SL2.0 command/result into JSON + Logger.debug("Receiving SL2.0 response process .... "); JsonObject sl20ReqObj = null; try { - JsonParser jsonParser = new JsonParser(); - JsonElement sl20Req = jsonParser.parse(sl20Result); - sl20ReqObj = sl20Req.getAsJsonObject(); + //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); + + } + + //parse SL2.0 command/result into JSON + try { + JsonParser jsonParser = new JsonParser(); + JsonElement sl20Req = jsonParser.parse(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."}); - } - - //TODO validate certificate - List<X509Certificate> sigCertChain = payLoadContainer.getCertChain(); - - - //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 .... "); - - //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); + //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."}); + + } + /*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(); - //TODO: validate results - IIdentityLink idl = new IdentityLinkAssertionParser(new ByteArrayInputStream(Base64Utils.decode(idlB64, false))).parseIdentityLink(); + //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 .... "); + + JsonElement qualeIDResult = SL20JSONExtractorUtils.extractSL20Result( + payLoad, joseTools, + authConfig.getBasicMOAIDConfigurationBoolean(Constants.CONFIG_PROP_DISABLE_EID_ENCRYPTION, true)); + + //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); + + //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"); + } - //add into session - defaultTaskInitialization(request, executionContext); - moasession.setIdentityLink(idl); - moasession.setBkuURL(ccsURL); - //TODO: from AuthBlock - moasession.setIssueInstant(DateTimeUtils.buildDateTimeUTC(Calendar.getInstance())); - moasession.setQAALevel(LoA); - //mark as authenticated - moasession.setAuthenticated(true); - pendingReq.setAuthenticated(true); - - //store pending request - requestStoreage.storePendingRequest(pendingReq); - - //create response - Map<String, String> reqParameters = new HashMap<String, String>(); - reqParameters.put(MOAIDAuthConstants.PARAM_TARGET_PENDINGREQUESTID, pendingReq.getRequestID()); - JsonObject callReqParams = SL20JSONBuilderUtils.createCallCommandParameters( - new DataURLBuilder().buildDataURL(pendingReq.getAuthURL(), AbstractAuthProtocolModulController.FINALIZEPROTOCOL_ENDPOINT, null), - SL20Constants.SL20_COMMAND_PARAM_GENERAL_CALL_METHOD_GET, - false, - reqParameters); - JsonObject callCommand = SL20JSONBuilderUtils.createCommand(SL20Constants.SL20_COMMAND_IDENTIFIER_CALL, callReqParams); + } catch (MOAIDException e) { + Logger.warn("SL2.0 processing error:", e); + pendingReq.setGenericDataToSession( + Constants.PENDING_REQ_STORAGE_PREFIX + SL20Constants.SL20_COMMAND_IDENTIFIER_ERROR, + new TaskExecutionException(pendingReq, "SL2.0 Authentication FAILED. Msg: " + e.getMessage(), e)); - //build first redirect command for app - JsonObject redirectOneParams = SL20JSONBuilderUtils.createRedirectCommandParameters("", callCommand, null, true); - JsonObject redirectOneCommand = SL20JSONBuilderUtils.createCommand(SL20Constants.SL20_COMMAND_IDENTIFIER_REDIRECT, redirectOneParams); - - //build second redirect command for IDP - JsonObject redirectTwoParams = SL20JSONBuilderUtils.createRedirectCommandParameters( - new DataURLBuilder().buildDataURL(pendingReq.getAuthURL(), AbstractAuthProtocolModulController.FINALIZEPROTOCOL_ENDPOINT, null), - redirectOneCommand, null, true); - JsonObject redirectTwoCommand = SL20JSONBuilderUtils.createCommand(SL20Constants.SL20_COMMAND_IDENTIFIER_REDIRECT, redirectTwoParams); + } catch (Exception e) { + Logger.warn("ERROR:", e); + Logger.warn("SL2.0 Authentication FAILED with a generic error.", e); + pendingReq.setGenericDataToSession( + Constants.PENDING_REQ_STORAGE_PREFIX + SL20Constants.SL20_COMMAND_IDENTIFIER_ERROR, + new TaskExecutionException(pendingReq, e.getMessage(), e)); - //build generic SL2.0 response container - String transactionId = SL20JSONExtractorUtils.getStringValue(sl20ReqObj, SL20Constants.SL20_TRANSACTIONID, false); - JsonObject respContainer = SL20JSONBuilderUtils.createGenericRequest( - UUID.randomUUID().toString(), - transactionId, - redirectTwoCommand, - null); + } finally { + //store pending request + requestStoreage.storePendingRequest(pendingReq); - 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 ... "); - 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); + //write SL2.0 response + if (sl20ReqObj != null) + buildResponse(request, response, sl20ReqObj); + else + buildErrorResponse(request, response, "2000", "General transport Binding error"); - - } else { - Logger.info("SL2.0 DataURL communication needs http header: '" + SL20Constants.HTTP_HEADER_SL20_CLIENT_TYPE + "'"); - throw new SL20Exception("sl20.06", - 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"); } - - - } 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); + //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); + try { + response.sendError(500, "Internal Server Error."); + + } catch (IOException e1) { + Logger.error("Can NOT send error message. SOMETHING IS REALY WRONG!", e); + + } - } finally { + } finally { TransactionIDUtils.removeTransactionId(); TransactionIDUtils.removeSessionId(); } } - - private JsonObject createRedirectCommand() { - + 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 ... "); + 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(MOAIDAuthConstants.PARAM_TARGET_PENDINGREQUESTID, pendingReq.getRequestID()); + JsonObject callReqParams = SL20JSONBuilderUtils.createCallCommandParameters( + new DataURLBuilder().buildDataURL(pendingReq.getAuthURL(), Constants.HTTP_ENDPOINT_RESUME, null), + SL20Constants.SL20_COMMAND_PARAM_GENERAL_CALL_METHOD_GET, + false, + reqParameters); + JsonObject callCommand = SL20JSONBuilderUtils.createCommand(SL20Constants.SL20_COMMAND_IDENTIFIER_CALL, callReqParams); - return null; + //build first redirect command for app + JsonObject redirectOneParams = SL20JSONBuilderUtils.createRedirectCommandParameters("", callCommand, null, true); + JsonObject redirectOneCommand = SL20JSONBuilderUtils.createCommand(SL20Constants.SL20_COMMAND_IDENTIFIER_REDIRECT, redirectOneParams); + + //build second redirect command for IDP + JsonObject redirectTwoParams = SL20JSONBuilderUtils.createRedirectCommandParameters( + new DataURLBuilder().buildDataURL(pendingReq.getAuthURL(), Constants.HTTP_ENDPOINT_RESUME, null), + redirectOneCommand, null, true); + JsonObject redirectTwoCommand = SL20JSONBuilderUtils.createCommand(SL20Constants.SL20_COMMAND_IDENTIFIER_REDIRECT, redirectTwoParams); + //build generic SL2.0 response container + String transactionId = SL20JSONExtractorUtils.getStringValue(sl20ReqObj, SL20Constants.SL20_TRANSACTIONID, false); + JsonObject 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)) { + Logger.debug("Client request containts 'native client' header ... "); + 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 { + Logger.info("SL2.0 DataURL communication needs http header: '" + SL20Constants.HTTP_HEADER_SL20_CLIENT_TYPE + "'"); + throw new SL20Exception("sl20.06", + new Object[] {"SL2.0 DataURL communication needs http header: '" + SL20Constants.HTTP_HEADER_SL20_CLIENT_TYPE + "'"}); + + } } + + } diff --git a/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/tasks/VerifyQualifiedeIDTask.java b/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/tasks/VerifyQualifiedeIDTask.java new file mode 100644 index 000000000..b5c84d315 --- /dev/null +++ b/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/tasks/VerifyQualifiedeIDTask.java @@ -0,0 +1,180 @@ +package at.gv.egovernment.moa.id.auth.modules.sl20_auth.tasks; + +import java.io.ByteArrayInputStream; +import java.util.Calendar; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.opensaml.Configuration; +import org.opensaml.saml2.core.Assertion; +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.io.Unmarshaller; +import org.opensaml.xml.io.UnmarshallerFactory; +import org.springframework.stereotype.Component; +import org.w3c.dom.Element; +import org.xml.sax.SAXException; + +import at.gv.egovernment.moa.id.advancedlogging.TransactionIDUtils; +import at.gv.egovernment.moa.id.auth.modules.AbstractAuthServletTask; +import at.gv.egovernment.moa.id.auth.modules.TaskExecutionException; +import at.gv.egovernment.moa.id.auth.modules.sl20_auth.Constants; +import at.gv.egovernment.moa.id.auth.modules.sl20_auth.exceptions.SL20eIDDataValidationException; +import at.gv.egovernment.moa.id.auth.modules.sl20_auth.sl20.SL20Constants; +import at.gv.egovernment.moa.id.auth.modules.sl20_auth.sl20.verifier.QualifiedeIDVerifier; +import at.gv.egovernment.moa.id.auth.parser.IdentityLinkAssertionParser; +import at.gv.egovernment.moa.id.commons.api.data.IIdentityLink; +import at.gv.egovernment.moa.id.commons.api.data.IVerifiyXMLSignatureResponse; +import at.gv.egovernment.moa.id.commons.api.exceptions.MOAIDException; +import at.gv.egovernment.moa.id.process.api.ExecutionContext; +import at.gv.egovernment.moa.id.protocols.pvp2x.utils.AssertionAttributeExtractor; +import at.gv.egovernment.moa.id.protocols.pvp2x.utils.SAML2Utils; +import at.gv.egovernment.moa.util.Base64Utils; +import at.gv.egovernment.moa.util.DOMUtils; +import at.gv.egovernment.moa.util.DateTimeUtils; +import at.gv.egovernment.moaspss.logging.Logger; + + +@Component("VerifyQualifiedeIDTask") +public class VerifyQualifiedeIDTask extends AbstractAuthServletTask { + + @Override + public void execute(ExecutionContext executionContext, HttpServletRequest request, HttpServletResponse response) + throws TaskExecutionException { + + Logger.debug("Verify qualified eID data from SL20 response .... "); + try { + //check if there was an error + TaskExecutionException sl20Error = pendingReq.getGenericData( + Constants.PENDING_REQ_STORAGE_PREFIX + SL20Constants.SL20_COMMAND_IDENTIFIER_ERROR, + TaskExecutionException.class); + if (sl20Error != null) { + Logger.info("Found SL2.0 error after redirect ... "); + throw sl20Error; + + } + + //get data from pending request + String sl20ReqId = pendingReq.getGenericData( + Constants.PENDING_REQ_STORAGE_PREFIX + SL20Constants.SL20_REQID, + String.class); + String idlB64 = pendingReq.getGenericData( + Constants.PENDING_REQ_STORAGE_PREFIX + SL20Constants.SL20_COMMAND_PARAM_EID_RESULT_IDL, + String.class); + String authBlockB64 = pendingReq.getGenericData( + Constants.PENDING_REQ_STORAGE_PREFIX + SL20Constants.SL20_COMMAND_PARAM_EID_RESULT_AUTHBLOCK, + String.class); + String ccsURL = pendingReq.getGenericData( + Constants.PENDING_REQ_STORAGE_PREFIX + SL20Constants.SL20_COMMAND_PARAM_EID_RESULT_CCSURL, + String.class); + String LoA = pendingReq.getGenericData( + Constants.PENDING_REQ_STORAGE_PREFIX + SL20Constants.SL20_COMMAND_PARAM_EID_RESULT_LOA, + String.class); + + //parse eID data + IIdentityLink idl = new IdentityLinkAssertionParser(new ByteArrayInputStream(Base64Utils.decode(idlB64, false))).parseIdentityLink(); + IVerifiyXMLSignatureResponse authBlockVerificationResult = null; + try { + Assertion authBlock = parseAuthBlockToSaml2Assertion(authBlockB64); + AssertionAttributeExtractor authBlockExtractor = new AssertionAttributeExtractor(authBlock); + + + //validate eID data + QualifiedeIDVerifier.verifyIdentityLink(idl, pendingReq.getOnlineApplicationConfiguration(), authConfig); + authBlockVerificationResult = QualifiedeIDVerifier.verifyAuthBlock( + authBlockB64, pendingReq.getOnlineApplicationConfiguration(), authConfig); + QualifiedeIDVerifier.checkConsistencyOfeIDData(sl20ReqId, idl, authBlockExtractor, authBlockVerificationResult); + + //TODO: add LoA verification + + } catch (SL20eIDDataValidationException e) { + if (authConfig.getBasicMOAIDConfigurationBoolean(Constants.CONFIG_PROP_DISABLE_EID_VALIDATION, false)) { + Logger.warn("SL20 eID data validation IS DISABLED!!"); + Logger.warn("SL20 eID data IS NOT VALID!!! Reason: " + e.getMessage(), e); + + } else + throw e; + + } + + //add into session + defaultTaskInitialization(request, executionContext); + moasession.setIdentityLink(idl); + moasession.setBkuURL(ccsURL); + //TODO: from AuthBlock + if (authBlockVerificationResult != null) + moasession.setIssueInstant(DateTimeUtils.buildDateTimeUTC(authBlockVerificationResult.getSigningDateTime())); + else + moasession.setIssueInstant(DateTimeUtils.buildDateTimeUTC(Calendar.getInstance())); + + moasession.setQAALevel(LoA); + + //store pending request + requestStoreage.storePendingRequest(pendingReq); + + } 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(); + + } + } + + private Assertion parseAuthBlockToSaml2Assertion(String authblockB64) throws SL20eIDDataValidationException { + try { + //parse authBlock into SAML2 Assertion + byte[] authBlockBytes = Base64Utils.decode(authblockB64, false); + Element authBlockDOM = DOMUtils.parseXmlValidating(new ByteArrayInputStream(authBlockBytes)); + UnmarshallerFactory unmarshallerFactory = Configuration.getUnmarshallerFactory(); + Unmarshaller unmarshaller = unmarshallerFactory.getUnmarshaller(authBlockDOM); + XMLObject samlAssertion = unmarshaller.unmarshall(authBlockDOM); + + //validate SAML2 Assertion + SAML2Utils.schemeValidation(samlAssertion); + + if (samlAssertion instanceof Assertion) + return (Assertion) samlAssertion; + else + throw new SL20eIDDataValidationException( + new Object[] { + SL20Constants.SL20_COMMAND_PARAM_EID_RESULT_AUTHBLOCK, + "AuthBlock is NOT of type SAML2 Assertion" + }); + + } catch (SL20eIDDataValidationException e) { + throw e; + + } catch (SAXException e) { + Logger.info("Scheme validation of SAML2 AuthBlock FAILED. Reason: " + e.getMessage()); + throw new SL20eIDDataValidationException( + new Object[] { + SL20Constants.SL20_COMMAND_PARAM_EID_RESULT_AUTHBLOCK, + e.getMessage() + }, + e); + + } catch (Exception e) { + Logger.info("Can not parse AuthBlock. Reason: " + e.getMessage()); + Logger.trace("FullAuthBlock: " + authblockB64); + throw new SL20eIDDataValidationException( + new Object[] { + SL20Constants.SL20_COMMAND_PARAM_EID_RESULT_AUTHBLOCK, + e.getMessage() + }, + e); + + } + + } + + + +} |