aboutsummaryrefslogtreecommitdiff
path: root/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/GenerateAuthnRequestTask.java
diff options
context:
space:
mode:
Diffstat (limited to 'modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/GenerateAuthnRequestTask.java')
-rw-r--r--modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/GenerateAuthnRequestTask.java289
1 files changed, 159 insertions, 130 deletions
diff --git a/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/GenerateAuthnRequestTask.java b/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/GenerateAuthnRequestTask.java
index b6f028a4..774d27d6 100644
--- a/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/GenerateAuthnRequestTask.java
+++ b/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/GenerateAuthnRequestTask.java
@@ -19,10 +19,11 @@
* file for details on the various modules and licenses.
* The "NOTICE" text file is part of the distribution. Any derivative works
* that you distribute must include a readable copy of the "NOTICE" text file.
-*/
+ */
package at.asitplus.eidas.specific.modules.auth.eidas.v2.tasks;
+import java.io.IOException;
import java.util.UUID;
import javax.servlet.ServletException;
@@ -30,6 +31,7 @@ import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.StringUtils;
+import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
@@ -39,6 +41,7 @@ import at.asitplus.eidas.specific.core.MsConnectorEventCodes;
import at.asitplus.eidas.specific.core.MsEidasNodeConstants;
import at.asitplus.eidas.specific.core.gui.StaticGuiBuilderConfiguration;
import at.asitplus.eidas.specific.modules.auth.eidas.v2.Constants;
+import at.asitplus.eidas.specific.modules.auth.eidas.v2.exception.EidPostProcessingException;
import at.asitplus.eidas.specific.modules.auth.eidas.v2.exception.EidasSAuthenticationException;
import at.asitplus.eidas.specific.modules.auth.eidas.v2.service.ICcSpecificEidProcessingService;
import at.gv.egiz.eaaf.core.api.gui.ISpringMvcGuiFormBuilder;
@@ -47,6 +50,7 @@ import at.gv.egiz.eaaf.core.api.idp.process.ExecutionContext;
import at.gv.egiz.eaaf.core.api.storage.ITransactionStorage;
import at.gv.egiz.eaaf.core.exceptions.EaafConfigurationException;
import at.gv.egiz.eaaf.core.exceptions.EaafException;
+import at.gv.egiz.eaaf.core.exceptions.GuiBuildException;
import at.gv.egiz.eaaf.core.exceptions.TaskExecutionException;
import at.gv.egiz.eaaf.core.impl.idp.auth.modules.AbstractAuthServletTask;
import eu.eidas.auth.commons.EidasParameterKeys;
@@ -59,149 +63,169 @@ import eu.eidas.specificcommunication.exception.SpecificCommunicationException;
import eu.eidas.specificcommunication.protocol.SpecificCommunicationService;
import lombok.extern.slf4j.Slf4j;
+
/**
- * Authentication-process task that generates the Authn. Request to eIDAS Node.
- *
- * @author tlenz
+ * Generates the authn request to the eIDAS Node. This is the first task in the process.
+ * Input:
+ * <ul>
+ * <li>none</li>
+ * </ul>
+ * Output:
+ * <ul>
+ * <li>none</li>
+ * </ul>
+ * Transitions:
+ * <ul>
+ * <li>{@link at.asitplus.eidas.specific.modules.auth.eidas.v2.tasks.ReceiveAuthnResponseTask}
+ * to read the response from the eIDAS Node</li>
+ * </ul>
*
+ * @author tlenz
+ * @author ckollmann
*/
@Slf4j
-@Component("ConnecteIDASNodeTask")
+@Component("GenerateAuthnRequestTask")
public class GenerateAuthnRequestTask extends AbstractAuthServletTask {
+ @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection")
@Autowired
IConfiguration basicConfig;
+
@Autowired
ApplicationContext context;
+
+ @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection")
@Autowired
ITransactionStorage transactionStore;
+
+ @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection")
@Autowired
ISpringMvcGuiFormBuilder guiBuilder;
+
@Autowired
ICcSpecificEidProcessingService ccSpecificProcessing;
@Override
- public void execute(ExecutionContext executionContext,
- HttpServletRequest request, HttpServletResponse response)
+ public void execute(ExecutionContext executionContext, HttpServletRequest request, HttpServletResponse response)
throws TaskExecutionException {
-
try {
- // get target, environment and validate citizen countryCode
- final String citizenCountryCode = (String) executionContext.get(
- MsEidasNodeConstants.REQ_PARAM_SELECTED_COUNTRY);
- final String environment = (String) executionContext.get(
- MsEidasNodeConstants.REQ_PARAM_SELECTED_ENVIRONMENT);
-
- if (StringUtils.isEmpty(citizenCountryCode)) {
- // illegal state; task should not have been executed without a selected country
- throw new EidasSAuthenticationException("eidas.03", new Object[] { "" });
-
- }
-
- // TODO: maybe add countryCode validation before request ref. impl. eIDAS node
- log.info("Request eIDAS auth. for citizen of country: " + citizenCountryCode);
- revisionsLogger.logEvent(pendingReq, MsConnectorEventCodes.COUNTRY_SELECTED, citizenCountryCode);
-
- // build eIDAS AuthnRequest
- final LightRequest.Builder authnRequestBuilder = LightRequest.builder();
- authnRequestBuilder.id(UUID.randomUUID().toString());
-
- // set nameIDFormat
- authnRequestBuilder.nameIdFormat(
- authConfig.getBasicConfiguration(Constants.CONFIG_PROP_EIDAS_NODE_NAMEIDFORMAT));
-
- // set citizen country code for foreign uses
- authnRequestBuilder.citizenCountryCode(citizenCountryCode);
-
- //set Issuer
- final String issur = basicConfig.getBasicConfiguration(Constants.CONIG_PROPS_EIDAS_NODE_ENTITYID);
- if (StringUtils.isEmpty(issur)) {
- log.error("Found NO 'eIDAS node issuer' in configuration. Authentication NOT possible!");
- throw new EaafConfigurationException("config.27",
- new Object[] { "Application config containts NO " + Constants.CONIG_PROPS_EIDAS_NODE_ENTITYID });
-
- }
- authnRequestBuilder.issuer(issur);
-
+ final String citizenCountryCode = extractCitizenCountryCode(executionContext);
+ final String environment = (String) executionContext.get(MsEidasNodeConstants.REQ_PARAM_SELECTED_ENVIRONMENT);
+ final String issuer = loadIssuerFromConfig();
+
+ // inject MS-Connector staging parameters
+ injectStagingWorkaroundForMsConnector();
- // Add country-specific informations into eIDAS request
- ccSpecificProcessing.preProcess(citizenCountryCode, pendingReq, authnRequestBuilder);
-
- // build request
- final LightRequest lightAuthnReq = authnRequestBuilder.build();
-
- // put request into shared cache
+ final LightRequest lightAuthnReq = buildEidasAuthnRequest(citizenCountryCode, issuer);
+
final BinaryLightToken token = putRequestInCommunicationCache(lightAuthnReq);
final String tokenBase64 = BinaryLightTokenHelper.encodeBinaryLightTokenBase64(token);
-
- // Workaround for ms-connector staging
- injectStagingWorkaroundForMsConnector();
+ workaroundRelayState(lightAuthnReq);
+ final String forwardUrl = selectForwardUrl(environment);
- // Workaround, because eIDAS node ref. impl. does not return relayState
- if (basicConfig.getBasicConfigurationBoolean(
- Constants.CONIG_PROPS_EIDAS_NODE_WORKAROUND_USEREQUESTIDASTRANSACTIONIDENTIFIER,
- false)) {
- log.trace("Put lightRequestId into transactionstore as session-handling backup");
- transactionStore.put(lightAuthnReq.getId(), pendingReq.getPendingRequestId(), -1);
-
- }
-
- // select forward URL regarding the selected environment
- String forwardUrl = basicConfig.getBasicConfiguration(Constants.CONIG_PROPS_EIDAS_CONNECTOR_NODE_FORWARD_URL);
- if (StringUtils.isNotEmpty(environment)) {
- forwardUrl = selectedForwardUrlForEnvironment(environment);
- }
-
- if (StringUtils.isEmpty(forwardUrl)) {
- log.warn("NO ForwardURL defined in configuration. Can NOT forward to eIDAS node! Process stops");
- throw new EaafConfigurationException("config.08", new Object[] {
- environment == null ? Constants.CONIG_PROPS_EIDAS_CONNECTOR_NODE_FORWARD_URL
- : Constants.CONIG_PROPS_EIDAS_CONNECTOR_NODE_FORWARD_URL + "." + environment
- });
-
- }
- log.debug("ForwardURL: " + forwardUrl + " selected to forward eIDAS request");
-
- if (basicConfig.getBasicConfiguration(
- Constants.CONIG_PROPS_EIDAS_NODE_FORWARD_METHOD,
- Constants.FORWARD_METHOD_GET).equals(Constants.FORWARD_METHOD_GET)) {
-
- log.debug("Use http-redirect for eIDAS node forwarding ... ");
- // send redirect
- final UriComponentsBuilder redirectUrl = UriComponentsBuilder.fromHttpUrl(forwardUrl);
- redirectUrl.queryParam(EidasParameterKeys.TOKEN.toString(), tokenBase64);
- response.sendRedirect(redirectUrl.build().encode().toString());
+ String configValue = basicConfig.getBasicConfiguration(
+ Constants.CONIG_PROPS_EIDAS_NODE_FORWARD_METHOD, Constants.FORWARD_METHOD_GET);
+ boolean useHttpRedirect = configValue.equals(Constants.FORWARD_METHOD_GET);
+ if (useHttpRedirect) {
+ sendRedirect(response, tokenBase64, forwardUrl);
} else {
- log.debug("Use http-post for eIDAS node forwarding ... ");
- final StaticGuiBuilderConfiguration config = new StaticGuiBuilderConfiguration(
- basicConfig,
- pendingReq,
- Constants.TEMPLATE_POST_FORWARD_NAME,
- null,
- resourceLoader);
-
- config.putCustomParameter(null, Constants.TEMPLATE_POST_FORWARD_ENDPOINT, forwardUrl);
- config.putCustomParameter(null, Constants.TEMPLATE_POST_FORWARD_TOKEN_NAME,
- EidasParameterKeys.TOKEN.toString());
- config.putCustomParameter(null, Constants.TEMPLATE_POST_FORWARD_TOKEN_VALUE,
- tokenBase64);
-
- guiBuilder.build(request, response, config, "Forward to eIDASNode form");
-
+ sendPost(request, response, tokenBase64, forwardUrl);
}
revisionsLogger.logEvent(pendingReq, MsConnectorEventCodes.EIDAS_NODE_CONNECTED, lightAuthnReq.getId());
-
} catch (final EidasSAuthenticationException e) {
throw new TaskExecutionException(pendingReq, "eIDAS AuthnRequest generation FAILED.", e);
-
} catch (final Exception e) {
log.warn("eIDAS AuthnRequest generation FAILED.", e);
throw new TaskExecutionException(pendingReq, e.getMessage(), e);
+ }
+ }
+
+ @NotNull
+ private String extractCitizenCountryCode(ExecutionContext executionContext) throws EidasSAuthenticationException {
+ final String result = (String) executionContext.get(MsEidasNodeConstants.REQ_PARAM_SELECTED_COUNTRY);
+ // illegal state; task should not have been executed without a selected country
+ if (StringUtils.isEmpty(result)) {
+ throw new EidasSAuthenticationException("eidas.03", new Object[]{""});
+ }
+ // TODO: maybe add countryCode validation before request ref. impl. eIDAS node
+ log.info("Request eIDAS auth. for citizen of country: {}", result);
+ revisionsLogger.logEvent(pendingReq, MsConnectorEventCodes.COUNTRY_SELECTED, result);
+ return result;
+ }
+ @NotNull
+ private String loadIssuerFromConfig() throws EaafConfigurationException {
+ final String result = basicConfig.getBasicConfiguration(Constants.CONIG_PROPS_EIDAS_NODE_ENTITYID);
+ if (StringUtils.isEmpty(result)) {
+ log.error("Found NO 'eIDAS node issuer' in configuration. Authentication NOT possible!");
+ throw new EaafConfigurationException("config.27",
+ new Object[]{"Application config containts NO " + Constants.CONIG_PROPS_EIDAS_NODE_ENTITYID});
}
+ return result;
+ }
+
+ @NotNull
+ private LightRequest buildEidasAuthnRequest(String citizenCountryCode, String issuer)
+ throws EidPostProcessingException {
+ final LightRequest.Builder builder = LightRequest.builder();
+ builder.id(UUID.randomUUID().toString());
+
+ // set nameIDFormat
+ builder.nameIdFormat(
+ authConfig.getBasicConfiguration(Constants.CONFIG_PROP_EIDAS_NODE_NAMEIDFORMAT));
+
+ builder.citizenCountryCode(citizenCountryCode);
+ builder.issuer(issuer);
+ // Add country-specific information into eIDAS request
+ ccSpecificProcessing.preProcess(citizenCountryCode, pendingReq, builder);
+ return builder.build();
+ }
+
+ private BinaryLightToken putRequestInCommunicationCache(ILightRequest lightRequest)
+ throws ServletException {
+ final BinaryLightToken binaryLightToken;
+ try {
+ String beanName = SpecificCommunicationDefinitionBeanNames.SPECIFIC_CONNECTOR_COMMUNICATION_SERVICE.toString();
+ final SpecificCommunicationService service = (SpecificCommunicationService) context.getBean(beanName);
+ binaryLightToken = service.putRequest(lightRequest);
+ } catch (final SpecificCommunicationException e) {
+ log.error("Unable to process specific request");
+ throw new ServletException(e);
+ }
+
+ return binaryLightToken;
+ }
+
+ /**
+ * Workaround, because eIDAS node ref. impl. does not return relayState
+ */
+ private void workaroundRelayState(LightRequest lightAuthnReq) throws EaafException {
+ if (basicConfig.getBasicConfigurationBoolean(
+ Constants.CONIG_PROPS_EIDAS_NODE_WORKAROUND_USEREQUESTIDASTRANSACTIONIDENTIFIER,
+ false)) {
+ log.trace("Put lightRequestId into transactionstore as session-handling backup");
+ transactionStore.put(lightAuthnReq.getId(), pendingReq.getPendingRequestId(), -1);
+ }
+ }
+ @NotNull
+ private String selectForwardUrl(String environment) throws EaafConfigurationException {
+ String result = basicConfig.getBasicConfiguration(Constants.CONIG_PROPS_EIDAS_CONNECTOR_NODE_FORWARD_URL);
+ if (StringUtils.isNotEmpty(environment)) {
+ result = selectedForwardUrlForEnvironment(environment);
+ }
+ if (StringUtils.isEmpty(result)) {
+ log.warn("NO ForwardURL defined in configuration. Can NOT forward to eIDAS node! Process stops");
+ throw new EaafConfigurationException("config.08", new Object[]{
+ environment == null ? Constants.CONIG_PROPS_EIDAS_CONNECTOR_NODE_FORWARD_URL
+ : Constants.CONIG_PROPS_EIDAS_CONNECTOR_NODE_FORWARD_URL + "." + environment
+ });
+ }
+ log.debug("ForwardURL: {} selected to forward eIDAS request", result);
+ return result;
+
}
@@ -224,51 +248,56 @@ public class GenerateAuthnRequestTask extends AbstractAuthServletTask {
* <br>
* <b>Info: </b> This method is needed, because eIDAS Ref. Impl only supports
* one countrycode on each instance. In consequence, more than one eIDAS Ref.
- * Impl nodes are required to support producation, testing, or QS stages for one
+ * Impl nodes are required to support production, testing, or QS stages for one
* country by using one ms-specific eIDAS connector
- *
+ *
* @param environment Environment selector from CountrySlection page
- * @return
+ * @return the URL from the configuration
*/
private String selectedForwardUrlForEnvironment(String environment) {
- log.trace("Starting endpoint selection process for environment: " + environment + " ... ");
+ log.trace("Starting endpoint selection process for environment: {} ... ", environment);
if (environment.equalsIgnoreCase(MsEidasNodeConstants.REQ_PARAM_SELECTED_ENVIRONMENT_VALUE_PRODUCTION)) {
return basicConfig.getBasicConfiguration(Constants.CONIG_PROPS_EIDAS_CONNECTOR_NODE_FORWARD_URL);
+
} else if (environment.equalsIgnoreCase(MsEidasNodeConstants.REQ_PARAM_SELECTED_ENVIRONMENT_VALUE_QS)) {
return basicConfig.getBasicConfiguration(Constants.CONIG_PROPS_EIDAS_CONNECTOR_NODE_FORWARD_URL
+ "." + MsEidasNodeConstants.REQ_PARAM_SELECTED_ENVIRONMENT_VALUE_QS);
+
} else if (environment.equalsIgnoreCase(
MsEidasNodeConstants.REQ_PARAM_SELECTED_ENVIRONMENT_VALUE_TESTING)) {
return basicConfig.getBasicConfiguration(Constants.CONIG_PROPS_EIDAS_CONNECTOR_NODE_FORWARD_URL
+ "." + MsEidasNodeConstants.REQ_PARAM_SELECTED_ENVIRONMENT_VALUE_TESTING);
+
} else if (environment.equalsIgnoreCase(
MsEidasNodeConstants.REQ_PARAM_SELECTED_ENVIRONMENT_VALUE_DEVELOPMENT)) {
return basicConfig.getBasicConfiguration(Constants.CONIG_PROPS_EIDAS_CONNECTOR_NODE_FORWARD_URL
+ "." + MsEidasNodeConstants.REQ_PARAM_SELECTED_ENVIRONMENT_VALUE_DEVELOPMENT);
+
}
-
- log.info("Environment selector: " + environment + " is not supported");
+
+ log.info("Environment selector: {} is not supported", environment);
return null;
-
+
}
- private BinaryLightToken putRequestInCommunicationCache(ILightRequest lightRequest)
- throws ServletException {
- final BinaryLightToken binaryLightToken;
- try {
- final SpecificCommunicationService springManagedSpecificConnectorCommunicationService =
- (SpecificCommunicationService) context.getBean(
- SpecificCommunicationDefinitionBeanNames.SPECIFIC_CONNECTOR_COMMUNICATION_SERVICE.toString());
-
- binaryLightToken = springManagedSpecificConnectorCommunicationService.putRequest(lightRequest);
-
- } catch (final SpecificCommunicationException e) {
- log.error("Unable to process specific request");
- throw new ServletException(e);
-
- }
+ private void sendRedirect(HttpServletResponse response, String tokenBase64, String forwardUrl) throws IOException {
+ log.debug("Use http-redirect for eIDAS node forwarding ... ");
+ final UriComponentsBuilder redirectUrl = UriComponentsBuilder.fromHttpUrl(forwardUrl);
+ redirectUrl.queryParam(EidasParameterKeys.TOKEN.toString(), tokenBase64);
+ response.sendRedirect(redirectUrl.build().encode().toString());
+
+ }
- return binaryLightToken;
+ private void sendPost(HttpServletRequest request, HttpServletResponse response, String tokenBase64, String forwardUrl)
+ throws GuiBuildException {
+ log.debug("Use http-post for eIDAS node forwarding ... ");
+ final StaticGuiBuilderConfiguration config = new StaticGuiBuilderConfiguration(
+ basicConfig, pendingReq, Constants.TEMPLATE_POST_FORWARD_NAME, null, resourceLoader);
+ config.putCustomParameter(null, Constants.TEMPLATE_POST_FORWARD_ENDPOINT, forwardUrl);
+ String token = EidasParameterKeys.TOKEN.toString();
+ config.putCustomParameter(null, Constants.TEMPLATE_POST_FORWARD_TOKEN_NAME, token);
+ config.putCustomParameter(null, Constants.TEMPLATE_POST_FORWARD_TOKEN_VALUE, tokenBase64);
+ guiBuilder.build(request, response, config, "Forward to eIDASNode form");
}
}