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/CreateQualeIDRequestTask.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/CreateQualeIDRequestTask.java | 243 |
1 files changed, 243 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..3408cf538 --- /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,243 @@ +package at.gv.egovernment.moa.id.auth.modules.sl20_auth.tasks; + +import java.security.cert.X509Certificate; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +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.impl.client.CloseableHttpClient; +import org.apache.http.message.BasicNameValuePair; +import org.jose4j.base64url.Base64Url; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import com.google.gson.JsonObject; + +import at.gv.egiz.eaaf.core.api.idp.ISPConfiguration; +import at.gv.egiz.eaaf.core.api.idp.process.ExecutionContext; +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.utils.DataURLBuilder; +import at.gv.egiz.eaaf.core.impl.utils.KeyValueUtils; +import at.gv.egiz.eaaf.core.impl.utils.TransactionIDUtils; +import at.gv.egiz.eaaf.modules.pvp2.impl.utils.SAML2Utils; +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; +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; +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.exceptions.MOAIDException; +import at.gv.egovernment.moa.id.commons.config.MOAIDConfigurationConstants; +import at.gv.egovernment.moa.id.commons.utils.HttpClientWithProxySupport; +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; + @Autowired private AuthConfiguration moaAuthConfig; + + @Override + public void execute(ExecutionContext executionContext, HttpServletRequest request, HttpServletResponse response) + throws TaskExecutionException { + + Logger.debug("Starting SL2.0 authentication process .... "); + + revisionsLogger.logEvent(pendingReq, MOAIDEventConstants.AUTHPROCESS_BKUTYPE_SELECTED, "sl20auth"); + + try { + //get service-provider configuration + ISPConfiguration oaConfig = pendingReq.getServiceProviderConfiguration(); + + //get basic configuration parameters + String vdaQualeIDUrl = extractVDAURLForSpecificOA(oaConfig, executionContext); + if (MiscUtil.isEmpty(vdaQualeIDUrl)) { + Logger.error("NO VDA URL for qualified eID (" + Constants.CONFIG_PROP_VDA_ENDPOINT_QUALeID_DEFAULT + ")"); + throw new SL20Exception("sl20.03", new Object[]{"NO VDA URL for qualified eID"}); + + } + revisionsLogger.logEvent(pendingReq, MOAIDEventConstants.AUTHPROCESS_BKU_URL, vdaQualeIDUrl); + + + String authBlockId = authConfig.getBasicConfiguration(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.getPendingRequestId()); + + //build qualifiedeID command + Map<String, String> qualifiedeIDParams = new HashMap<String, String>(); + qualifiedeIDParams.put(SL20Constants.SL20_COMMAND_PARAM_EID_ATTRIBUTES_SPUNIQUEID, oaConfig.getUniqueIdentifier()); + qualifiedeIDParams.put(SL20Constants.SL20_COMMAND_PARAM_EID_ATTRIBUTES_SPFRIENDLYNAME, oaConfig.getFriendlyName()); + qualifiedeIDParams.put(SL20Constants.SL20_COMMAND_PARAM_EID_ATTRIBUTES_SPCOUNTRYCODE, "AT"); + //qualifiedeIDParams.put(SL20Constants.SL20_COMMAND_PARAM_EID_ATTRIBUTES_MANDATEREFVALUE, UUID.randomUUID().toString()); + + + X509Certificate encCert = null; + if (authConfig.getBasicMOAIDConfigurationBoolean(Constants.CONFIG_PROP_ENABLE_EID_ENCRYPTION, true)) + encCert = joseTools.getEncryptionCertificate(); + else + Logger.info("eID data encryption is disabled by configuration"); + + JsonObject qualeIDCommandParams = SL20JSONBuilderUtils.createQualifiedeIDCommandParameters( + authBlockId, + dataURL, + qualifiedeIDParams, + encCert + ); + + //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); + + //open http client + SSLSocketFactory sslFactory = SSLUtils.getSSLSocketFactory( + moaAuthConfig, + vdaQualeIDUrl); + CloseableHttpClient httpClient = HttpClientWithProxySupport.getHttpClient( + sslFactory, + moaAuthConfig.getBasicMOAIDConfigurationBoolean(AuthConfiguration.PROP_KEY_OVS_SSL_HOSTNAME_VALIDATION, true)); + + //build http POST request + HttpPost httpReq = new HttpPost(new URIBuilder(vdaQualeIDUrl).build()); + List<NameValuePair> parameters = new ArrayList<NameValuePair>();; + parameters.add(new BasicNameValuePair(SL20Constants.PARAM_SL20_REQ_COMMAND_PARAM, Base64Url.encode(sl20Req.toString().getBytes()))); + httpReq.setEntity(new UrlEncodedFormEntity(parameters )); + + //build http GET request +// URIBuilder sl20ReqUri = new URIBuilder(vdaQualeIDUrl); +// sl20ReqUri.addParameter(SL20Constants.PARAM_SL20_REQ_COMMAND_PARAM, Base64Url.encode(sl20Req.toString().getBytes())); +// HttpGet httpReq = new HttpGet(sl20ReqUri.build()); + + //set native client header + httpReq.addHeader(SL20Constants.HTTP_HEADER_SL20_CLIENT_TYPE, SL20Constants.HTTP_HEADER_VALUE_NATIVE); + + Logger.trace("Request VDA via SL20 with: " + Base64Url.encode(sl20Req.toString().getBytes())); + + //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.setRawDataToTransaction(Constants.PENDING_REQ_STORAGE_PREFIX + SL20Constants.SL20_REQID, + qualeIDReqId); + requestStoreage.storePendingRequest(pendingReq); + + //forward SL2.0 command + //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()"); + } + + + } 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(); + + } + + } + + private String extractVDAURLForSpecificOA(ISPConfiguration oaConfig, ExecutionContext executionContext) { + String spSpecificVDAEndpoints = oaConfig.getConfigurationValue(MOAIDConfigurationConstants.SERVICE_AUTH_SL20_ENDPOINTS); + Map<String, String> endPointMap = authConfig.getBasicMOAIDConfigurationWithPrefix(Constants.CONFIG_PROP_VDA_ENDPOINT_QUALeID_LIST); + if (MiscUtil.isNotEmpty(spSpecificVDAEndpoints)) { + endPointMap.putAll(KeyValueUtils.convertListToMap( + KeyValueUtils.getListOfCSVValues( + KeyValueUtils.normalizeCSVValueString(spSpecificVDAEndpoints)))); + Logger.debug("Find OA specific SL2.0 endpoints. Updating endPoint list ... "); + + } + + Logger.trace("Find #" + endPointMap.size() + " SL2.0 endpoints ... "); + + //selection based on request Header + String sl20VDATypeHeader = (String) executionContext.get(SL20Constants.HTTP_HEADER_SL20_VDA_TYPE.toLowerCase()); + if (MiscUtil.isNotEmpty(sl20VDATypeHeader)) { + String vdaURL = endPointMap.get(sl20VDATypeHeader); + if (MiscUtil.isNotEmpty(vdaURL)) + return vdaURL.trim(); + + else + Logger.info("Can NOT find VDA with Id: " + sl20VDATypeHeader + ". Use default VDA"); + + } + + Logger.info("NO SP specific VDA endpoint found. Use default VDA"); + return endPointMap.getOrDefault(Constants.CONFIG_PROP_VDA_ENDPOINT_QUALeID_DEFAULT, + Constants.CONFIG_PROP_VDA_ENDPOINT_QUALeID + Constants.CONFIG_PROP_VDA_ENDPOINT_QUALeID_DEFAULT); + + } + +} |