diff options
author | Thomas Lenz <tlenz@iaik.tugraz.at> | 2018-05-16 09:29:09 +0200 |
---|---|---|
committer | Thomas Lenz <tlenz@iaik.tugraz.at> | 2018-05-16 09:29:09 +0200 |
commit | c61850c5607d066a3c322794c1220f26b31103a0 (patch) | |
tree | 8e91dbb441f5af6879c4314b38159b7ed9b4add4 /id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/tasks | |
parent | 44bce0049b598604cc1a30f419e936c6b5fc59cf (diff) | |
download | moa-id-spss-c61850c5607d066a3c322794c1220f26b31103a0.tar.gz moa-id-spss-c61850c5607d066a3c322794c1220f26b31103a0.tar.bz2 moa-id-spss-c61850c5607d066a3c322794c1220f26b31103a0.zip |
add initial version of Security-Layer 2.0 Authentication 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')
2 files changed, 404 insertions, 0 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 new file mode 100644 index 000000000..1e15e893e --- /dev/null +++ b/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/tasks/CreateQualeIDRequestTask.java @@ -0,0 +1,176 @@ +package at.gv.egovernment.moa.id.auth.modules.sl20_auth.tasks; + +import java.io.StringWriter; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +import javax.net.ssl.SSLSocketFactory; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +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.entity.ContentType; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.message.BasicNameValuePair; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import com.google.gson.JsonObject; + +import at.gv.egovernment.moa.id.advancedlogging.TransactionIDUtils; +import at.gv.egovernment.moa.id.auth.builder.DataURLBuilder; +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.data.VerificationResult; +import at.gv.egovernment.moa.id.auth.modules.sl20_auth.exceptions.SL20Exception; +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; +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.commons.api.AuthConfiguration; +import at.gv.egovernment.moa.id.commons.api.IOAAuthParameters; +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.process.api.ExecutionContext; +import at.gv.egovernment.moa.id.util.SSLUtils; +import at.gv.egovernment.moa.util.MiscUtil; +import at.gv.egovernment.moaspss.logging.Logger; + +@Component("CreateQualeIDRequestTask") +public class CreateQualeIDRequestTask extends AbstractAuthServletTask { + + @Autowired(required=true) private IJOSETools joseTools; + + @Override + public void execute(ExecutionContext executionContext, HttpServletRequest request, HttpServletResponse response) + throws TaskExecutionException { + + Logger.debug("Starting SL2.0 authentication process .... "); + + try { + //get service-provider configuration + IOAAuthParameters oaConfig = pendingReq.getOnlineApplicationConfiguration(); + + //get basic configuration parameters + String vdaQualeIDUrl = authConfig.getBasicMOAIDConfiguration(Constants.CONFIG_PROP_VDA_ENDPOINT_QUALeID); + if (MiscUtil.isEmpty(vdaQualeIDUrl)) { + Logger.error("NO VDA URL for qualified eID (" + Constants.CONFIG_PROP_VDA_ENDPOINT_QUALeID + ")"); + throw new SL20Exception("sl20.03", new Object[]{"NO VDA URL for qualified eID"}); + + } + + String authBlockId = authConfig.getBasicMOAIDConfiguration(Constants.CONFIG_PROP_VDA_AUTHBLOCK_ID); + if (MiscUtil.isEmpty(authBlockId)) { + Logger.error("NO AuthBlock Template identifier for qualified eID (" + Constants.CONFIG_PROP_VDA_AUTHBLOCK_ID + ")"); + throw new SL20Exception("sl20.03", new Object[]{"NO AuthBlock Template identifier for qualified eID"}); + + } + + //build DataURL for qualified eID response + String dataURL = new DataURLBuilder().buildDataURL( + pendingReq.getAuthURL(), Constants.HTTP_ENDPOINT_DATAURL, pendingReq.getRequestID()); +// String dataURL = new DataURLBuilder().buildDataURL( +// "http://labda.iaik.tugraz.at:8080/moa-id-auth/", Constants.HTTP_ENDPOINT_DATAURL, pendingReq.getRequestID()); + + //build qualifiedeID command + Map<String, String> qualifiedeIDParams = new HashMap<String, String>(); + qualifiedeIDParams.put(SL20Constants.SL20_COMMAND_PARAM_EID_ATTRIBUTES_SPUNIQUEID, oaConfig.getPublicURLPrefix()); + qualifiedeIDParams.put(SL20Constants.SL20_COMMAND_PARAM_EID_ATTRIBUTES_SPFRIENDLYNAME, oaConfig.getFriendlyName()); + //qualifiedeIDParams.put(SL20Constants.SL20_COMMAND_PARAM_EID_ATTRIBUTES_MANDATEREFVALUE, UUID.randomUUID().toString()); + + JsonObject qualeIDCommandParams = SL20JSONBuilderUtils.createQualifiedeIDCommandParameters( + authBlockId, + dataURL, + qualifiedeIDParams, + joseTools.getEncryptionCertificate()); + + String qualeIDReqId = UUID.randomUUID().toString(); + String signedQualeIDCommand = SL20JSONBuilderUtils.createSignedCommand(SL20Constants.SL20_COMMAND_IDENTIFIER_QUALIFIEDEID, qualeIDCommandParams, joseTools); + JsonObject sl20Req = SL20JSONBuilderUtils.createGenericRequest(qualeIDReqId, null, null, signedQualeIDCommand); + + //open http client + SSLSocketFactory sslFactory = SSLUtils.getSSLSocketFactory( + authConfig, + vdaQualeIDUrl); + CloseableHttpClient httpClient = HttpClientWithProxySupport.getHttpClient( + sslFactory, + authConfig.getBasicMOAIDConfigurationBoolean(AuthConfiguration.PROP_KEY_OVS_SSL_HOSTNAME_VALIDATION, true)); + + //build post request + 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())); + httpReq.setEntity(new UrlEncodedFormEntity(parameters )); + + //request VDA + HttpResponse httpResp = httpClient.execute(httpReq); + + //parse response + Logger.info("Receive response from VDA ... "); + JsonObject sl20Resp = SL20JSONExtractorUtils.getSL20ContainerFromResponse(httpResp); + VerificationResult respPayloadContainer = SL20JSONExtractorUtils.extractSL20PayLoad(sl20Resp, null, false); + + if (respPayloadContainer.isValidSigned() == null) { + Logger.debug("Receive unsigned payLoad from VDA"); + + } + + JsonObject respPayload = respPayloadContainer.getPayload(); + if (respPayload.get(SL20Constants.SL20_COMMAND_CONTAINER_NAME).getAsString() + .equals(SL20Constants.SL20_COMMAND_IDENTIFIER_REDIRECT)) { + Logger.debug("Find 'redirect' command in VDA response ... "); + JsonObject params = SL20JSONExtractorUtils.getJSONObjectValue(respPayload, SL20Constants.SL20_COMMAND_CONTAINER_PARAMS, true); + String redirectURL = SL20JSONExtractorUtils.getStringValue(params, SL20Constants.SL20_COMMAND_PARAM_GENERAL_REDIRECT_URL, true); + JsonObject 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 + JsonObject sl20Forward = sl20Resp.deepCopy().getAsJsonObject(); + SL20JSONBuilderUtils.addOnlyOnceOfTwo(sl20Forward, + SL20Constants.SL20_PAYLOAD, SL20Constants.SL20_SIGNEDPAYLOAD, + command, signedCommand); + + //store pending request + pendingReq.setGenericDataToSession(Constants.PENDING_REQ_STORAGE_PREFIX + SL20Constants.SL20_REQID, + qualeIDReqId); + requestStoreage.storePendingRequest(pendingReq); + + //forward SL2.0 command + SL20HttpBindingUtils.writeIntoResponse(request, response, sl20Forward, redirectURL); + + } else { + //TODO: update to add error handling + Logger.warn("Received an unrecognized command: " + respPayload.get(SL20Constants.SL20_COMMAND_CONTAINER_NAME).getAsString()); + + } + + + } catch (MOAIDException e) { + throw new TaskExecutionException(pendingReq, "SL2.0 Authentication FAILED. Msg: " + e.getMessage(), e); + + } catch (Exception e) { + Logger.warn("SL2.0 Authentication FAILED with a generic error.", e); + throw new TaskExecutionException(pendingReq, e.getMessage(), e); + + } finally { + TransactionIDUtils.removeTransactionId(); + TransactionIDUtils.removeSessionId(); + + } + + + + + } + +} 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 new file mode 100644 index 000000000..6d2163ff1 --- /dev/null +++ b/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/tasks/ReceiveQualeIDTask.java @@ -0,0 +1,228 @@ +package at.gv.egovernment.moa.id.auth.modules.sl20_auth.tasks; + +import java.io.ByteArrayInputStream; +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; +import java.util.UUID; + +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; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import com.google.gson.JsonSyntaxException; + +import at.gv.egovernment.moa.id.advancedlogging.TransactionIDUtils; +import at.gv.egovernment.moa.id.auth.builder.DataURLBuilder; +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.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.SL20SecurityException; +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.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.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 { + + @Autowired(required=true) private IJOSETools joseTools; + + @Override + 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 + JsonObject sl20ReqObj = null; + 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); + + } + + //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 + //TODO: + 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: add decryption + JsonElement qualeIDResult = SL20JSONExtractorUtils.extractSL20Result(payLoad, null, 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 + defaultTaskInitialization(request, executionContext); + 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); + + //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); + + //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); + + //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 + "'"}); + + } + + } 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); + + } finally { + TransactionIDUtils.removeTransactionId(); + TransactionIDUtils.removeSessionId(); + + } + } + + + private JsonObject createRedirectCommand() { + + + return null; + + + } + +} |