diff options
Diffstat (limited to 'eidas_modules/authmodule-eIDAS-v2/src/main')
2 files changed, 203 insertions, 228 deletions
diff --git a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/GenerateMobilePhoneSignatureRequestTask.java b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/GenerateMobilePhoneSignatureRequestTask.java index 4d305c7d..e6484e63 100644 --- a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/GenerateMobilePhoneSignatureRequestTask.java +++ b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/GenerateMobilePhoneSignatureRequestTask.java @@ -23,16 +23,6 @@ package at.asitplus.eidas.specific.modules.auth.eidas.v2.tasks; -import java.text.MessageFormat; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.apache.commons.lang3.StringUtils; -import org.opensaml.saml.saml2.metadata.EntityDescriptor; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - import at.asitplus.eidas.specific.modules.auth.eidas.v2.Constants; import at.asitplus.eidas.specific.modules.auth.eidas.v2.idaustriaclient.IdAustriaClientAuthConstants; import at.asitplus.eidas.specific.modules.auth.eidas.v2.idaustriaclient.IdAustriaClientAuthRequestBuilderConfiguration; @@ -42,15 +32,28 @@ import at.gv.egiz.eaaf.core.api.idp.IConfiguration; 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.TaskExecutionException; import at.gv.egiz.eaaf.core.impl.idp.auth.modules.AbstractAuthServletTask; import at.gv.egiz.eaaf.core.impl.utils.Random; +import at.gv.egiz.eaaf.modules.pvp2.exception.CredentialsNotAvailableException; import at.gv.egiz.eaaf.modules.pvp2.sp.impl.PvpAuthnRequestBuilder; import lombok.extern.slf4j.Slf4j; +import net.shibboleth.utilities.java.support.resolver.ResolverException; import net.shibboleth.utilities.java.support.security.SecureRandomIdentifierGenerationStrategy; +import org.apache.commons.lang3.StringUtils; +import org.jetbrains.annotations.NotNull; +import org.opensaml.saml.saml2.metadata.EntityDescriptor; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.text.MessageFormat; /** * Generate a SAML2 AuthnRequest to authenticate the user at ID Austria system. + * This corresponds to Step 15A in the eIDAS Matching Concept. * * @author tlenz */ @@ -77,55 +80,66 @@ public class GenerateMobilePhoneSignatureRequestTask extends AbstractAuthServlet throws TaskExecutionException { try { log.trace("Starting GenerateMobilePhoneSignatureRequestTask"); - //step 15a - - // get entityID for ms-specific ID Austria node - final String msNodeEntityID = basicConfig.getBasicConfiguration( - IdAustriaClientAuthConstants.CONFIG_PROPS_ID_AUSTRIA_ENTITYID); - - if (StringUtils.isEmpty(msNodeEntityID)) { - log.warn("ID Austria authentication not possible -> NO EntityID for ID Austria System FOUND!"); - throw new EaafConfigurationException(Constants.ERRORCODE_00, - new Object[]{IdAustriaClientAuthConstants.CONFIG_PROPS_ID_AUSTRIA_ENTITYID}); - - } - - // load IDP SAML2 entitydescriptor - final EntityDescriptor entityDesc = metadataService.getEntityDescriptor(msNodeEntityID); - if (entityDesc == null) { - throw new EaafConfigurationException(IdAustriaClientAuthConstants.ERRORCODE_02, - new Object[]{MessageFormat.format(ERROR_MSG_1, msNodeEntityID)}); - - } + final String entityId = loadEntityId(); + final EntityDescriptor entityDesc = loadEntityDescriptor(entityId); + final IdAustriaClientAuthRequestBuilderConfiguration authnReqConfig = buildAuthnRequestConfig(entityDesc); + final String relayState = buildRelayState(); + authnReqBuilder.buildAuthnRequest(pendingReq, authnReqConfig, relayState, response); // also transmits! + } catch (final Exception e) { + throw new TaskExecutionException(pendingReq, "Generation of SAML2 AuthnRequest to ID Austria System FAILED", e); + } + } - // setup AuthnRequestBuilder configuration - final IdAustriaClientAuthRequestBuilderConfiguration authnReqConfig = - new IdAustriaClientAuthRequestBuilderConfiguration(); - final SecureRandomIdentifierGenerationStrategy gen = - new SecureRandomIdentifierGenerationStrategy(); - authnReqConfig.setRequestId(gen.generateIdentifier()); - authnReqConfig.setIdpEntity(entityDesc); - authnReqConfig.setPassive(false); - authnReqConfig.setSignCred(credential.getMessageSigningCredential()); - authnReqConfig.setSpEntityID( - pendingReq.getAuthUrlWithOutSlash() + IdAustriaClientAuthConstants.ENDPOINT_METADATA); - authnReqConfig.setRequestedLoA(authConfig.getBasicConfiguration( - IdAustriaClientAuthConstants.CONFIG_PROPS_REQUIRED_LOA, - IdAustriaClientAuthConstants.CONFIG_DEFAULT_LOA_EIDAS_LEVEL)); + @NotNull + private String loadEntityId() throws EaafConfigurationException { + final String msNodeEntityID = basicConfig.getBasicConfiguration( + IdAustriaClientAuthConstants.CONFIG_PROPS_ID_AUSTRIA_ENTITYID); + if (StringUtils.isEmpty(msNodeEntityID)) { + log.warn("ID Austria authentication not possible -> NO EntityID for ID Austria System FOUND!"); + throw new EaafConfigurationException(Constants.ERRORCODE_00, + new Object[]{IdAustriaClientAuthConstants.CONFIG_PROPS_ID_AUSTRIA_ENTITYID}); + } + return msNodeEntityID; + } - /*build relayState for session synchronization, because SAML2 only allows RelayState with 80 characters - * but encrypted PendingRequestId is much longer. - */ - String relayState = Random.nextProcessReferenceValue(); - transactionStorage.put(relayState, pendingReq.getPendingRequestId(), -1); + /** + * Build relayState for session synchronization, because SAML2 only allows RelayState with 80 characters + * but encrypted PendingRequestId is much longer. + */ + @NotNull + private String buildRelayState() throws EaafException { + String relayState = Random.nextProcessReferenceValue(); + transactionStorage.put(relayState, pendingReq.getPendingRequestId(), -1); + return relayState; + } - // build and transmit AuthnRequest - authnReqBuilder.buildAuthnRequest(pendingReq, authnReqConfig, relayState, response); + @NotNull + private EntityDescriptor loadEntityDescriptor(String msNodeEntityID) + throws ResolverException, EaafConfigurationException { + final EntityDescriptor entityDesc = metadataService.getEntityDescriptor(msNodeEntityID); + if (entityDesc == null) { + throw new EaafConfigurationException(IdAustriaClientAuthConstants.ERRORCODE_02, + new Object[]{MessageFormat.format(ERROR_MSG_1, msNodeEntityID)}); - } catch (final Exception e) { - throw new TaskExecutionException(pendingReq, - "Generation of SAML2 AuthnRequest to ID Austria System FAILED", e); - } + return entityDesc; + } + + @NotNull + private IdAustriaClientAuthRequestBuilderConfiguration buildAuthnRequestConfig(EntityDescriptor entityDesc) + throws CredentialsNotAvailableException { + final IdAustriaClientAuthRequestBuilderConfiguration authnReqConfig = + new IdAustriaClientAuthRequestBuilderConfiguration(); + final SecureRandomIdentifierGenerationStrategy gen = new SecureRandomIdentifierGenerationStrategy(); + authnReqConfig.setRequestId(gen.generateIdentifier()); + authnReqConfig.setIdpEntity(entityDesc); + authnReqConfig.setPassive(false); + authnReqConfig.setSignCred(credential.getMessageSigningCredential()); + authnReqConfig.setSpEntityID( + pendingReq.getAuthUrlWithOutSlash() + IdAustriaClientAuthConstants.ENDPOINT_METADATA); + authnReqConfig.setRequestedLoA(authConfig.getBasicConfiguration( + IdAustriaClientAuthConstants.CONFIG_PROPS_REQUIRED_LOA, + IdAustriaClientAuthConstants.CONFIG_DEFAULT_LOA_EIDAS_LEVEL)); + return authnReqConfig; } } diff --git a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/ReceiveMobilePhoneSignatureResponseAndSearchInRegistersTask.java b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/ReceiveMobilePhoneSignatureResponseAndSearchInRegistersTask.java index 09f2d54c..81be04b5 100644 --- a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/ReceiveMobilePhoneSignatureResponseAndSearchInRegistersTask.java +++ b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/ReceiveMobilePhoneSignatureResponseAndSearchInRegistersTask.java @@ -58,6 +58,7 @@ import at.gv.egiz.eaaf.modules.pvp2.sp.exception.AuthnResponseValidationExceptio import at.gv.egiz.eaaf.modules.pvp2.sp.impl.utils.AssertionAttributeExtractor; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; +import org.jetbrains.annotations.NotNull; import org.opensaml.core.xml.io.MarshallingException; import org.opensaml.messaging.decoder.MessageDecodingException; import org.opensaml.saml.saml2.core.Response; @@ -70,12 +71,16 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.xml.transform.TransformerException; import java.io.IOException; -import java.util.HashMap; import java.util.List; import java.util.Set; +import static at.asitplus.eidas.specific.modules.auth.eidas.v2.Constants.DATA_INITIAL_REGISTER_RESULT; +import static at.asitplus.eidas.specific.modules.auth.eidas.v2.Constants.DATA_SIMPLE_EIDAS; +import static at.asitplus.eidas.specific.modules.auth.eidas.v2.idaustriaclient.IdAustriaClientAuthConstants.MODULE_NAME_FOR_LOGGING; + /** * Task that receives the SAML2 response from ID Austria system. + * This corresponds to Step 15 in the eIDAS Matching Concept. * * @author tlenz */ @@ -89,7 +94,7 @@ public class ReceiveMobilePhoneSignatureResponseAndSearchInRegistersTask extends private RegisterSearchService registerSearchService; @Autowired private IdAustriaClientAuthCredentialProvider credentialProvider; - @Autowired(required = true) + @Autowired IdAustriaClientAuthMetadataProvider metadataProvider; private static final String ERROR_PVP_03 = "sp.pvp2.03"; @@ -100,208 +105,177 @@ public class ReceiveMobilePhoneSignatureResponseAndSearchInRegistersTask extends private static final String ERROR_PVP_11 = "sp.pvp2.11"; private static final String ERROR_PVP_12 = "sp.pvp2.12"; - private static final String ERROR_MSG_00 = - "Receive INVALID PVP Response from ID Austria system"; - private static final String ERROR_MSG_01 = - "Processing PVP response from 'ID Austria system' FAILED."; - private static final String ERROR_MSG_02 = - "PVP response decrytion FAILED. No credential found."; - private static final String ERROR_MSG_03 = - "PVP response validation FAILED."; + private static final String ERROR_MSG_00 = "Receive INVALID PVP Response from ID Austria system"; + private static final String ERROR_MSG_01 = "Processing PVP response from 'ID Austria system' FAILED."; + private static final String ERROR_MSG_02 = "PVP response decrytion FAILED. No credential found."; + private static final String ERROR_MSG_03 = "PVP response validation FAILED."; @Override public void execute(ExecutionContext executionContext, HttpServletRequest request, HttpServletResponse response) throws TaskExecutionException { try { - log.trace("Starting ReceiveMobilePhoneSignatureResponseTask");//Node 15 - InboundMessage msg = null; - IDecoder decoder = null; - EaafUriCompare comperator = null; - - // select Response Binding - if (request.getMethod().equalsIgnoreCase("POST")) { - decoder = new PostBinding(); - comperator = new EaafUriCompare(pendingReq.getAuthUrl() + IdAustriaClientAuthConstants.ENDPOINT_POST); - log.trace("Receive PVP Response from 'ID Austria system', by using POST-Binding."); - - } else if (request.getMethod().equalsIgnoreCase("GET")) { - decoder = new RedirectBinding(); - comperator = new EaafUriCompare(pendingReq.getAuthUrl() - + IdAustriaClientAuthConstants.ENDPOINT_REDIRECT); - log.trace("Receive PVP Response from 'ID Austria system', by using Redirect-Binding."); - - } else { - log.warn("Receive PVP Response, but Binding (" - + request.getMethod() + ") is not supported."); - throw new AuthnResponseValidationException(ERROR_PVP_03, new Object[]{ - IdAustriaClientAuthConstants.MODULE_NAME_FOR_LOGGING}); - - } - - // decode PVP response object - msg = (InboundMessage) decoder.decode( - request, response, metadataProvider, IDPSSODescriptor.DEFAULT_ELEMENT_NAME, - comperator); - - // validate response signature - if (!msg.isVerified()) { - samlVerificationEngine.verify(msg, TrustEngineFactory.getSignatureKnownKeysTrustEngine( - metadataProvider)); - msg.setVerified(true); - - } - - // validate assertion - final Pair<PvpSProfileResponse, Boolean> processedMsg = - preProcessAuthResponse((PvpSProfileResponse) msg); - - //check if SAML2 response contains user-stop decision + log.trace("Starting ReceiveMobilePhoneSignatureResponseTask"); + IDecoder decoder = loadDecoder(request); + EaafUriCompare comparator = loadComparator(request); + InboundMessage inboundMessage = decodeAndVerifyMessage(request, response, decoder, comparator); + final Pair<PvpSProfileResponse, Boolean> processedMsg = validateAssertion((PvpSProfileResponse) inboundMessage); if (processedMsg.getSecond()) { stopProcessFromUserDecision(executionContext, request, response); + return; + } - } else { - // validate entityId of response - final String msNodeEntityID = authConfig.getBasicConfiguration( - IdAustriaClientAuthConstants.CONFIG_PROPS_ID_AUSTRIA_ENTITYID); - final String respEntityId = msg.getEntityID(); - if (!msNodeEntityID.equals(respEntityId)) { - log.warn("Response Issuer is not from valid 'ID Austria IDP'. Stopping ID Austria authentication ..."); - throw new AuthnResponseValidationException(ERROR_PVP_08, - new Object[]{IdAustriaClientAuthConstants.MODULE_NAME_FOR_LOGGING, - msg.getEntityID()}); - - } - - // initialize Attribute extractor - final AssertionAttributeExtractor extractor = - new AssertionAttributeExtractor(processedMsg.getFirst().getResponse()); - - - - - /* - * SAML2 response ist bereits vollständig validiert und die Attribute können aus dem - * <AssertionAttributeExtractor extractor> ausgelesen werden. - * Die AttributeNamen sind entsprechend PVP Spezifikation, z.B. PvpAttributeDefinitions.GIVEN_NAME_NAME - * - * --------------------------------------------------------------------------------------------- - * - * TODO: ab hier müssen wir wohl was anpassen - * - */ - - //load additional search-data from pendingRequest - final AuthProcessDataWrapper authProcessData = pendingReq.getSessionData(AuthProcessDataWrapper.class); - MergedRegisterSearchResult initialSearchResult = - authProcessData.getGenericDataFromSession(Constants.DATA_INITIAL_REGISTER_RESULT, - MergedRegisterSearchResult.class); - SimpleEidasData eidData = authProcessData.getGenericDataFromSession(Constants.DATA_SIMPLE_EIDAS, - SimpleEidasData.class); - - - SimpleMobileSignatureData simpleMobileSignatureData = - getAuthDataFromInterfederation(extractor, authProcessData); - if (!simpleMobileSignatureData.equalsSimpleEidasData(eidData)) { - //User cheated? - throw new InvalidUserInputException();//TODO - } - String bpkzp = simpleMobileSignatureData.getBpk(); - - MergedRegisterSearchResult result = registerSearchService.searchWithBpkZp(bpkzp); - if (result.getResultCount() == 0) { - //go to step 16 - executionContext.put(Constants.TRANSITION_TO_GENERATE_GUI_QUERY_AUSTRIAN_RESIDENCE_TASK, true); - return; - } else if (result.getResultCount() == 1) { - String bpk = registerSearchService.step7aKittProcess(initialSearchResult, result, eidData, pendingReq); - authProcessData.setGenericDataToSession(Constants.DATA_RESULT_MATCHING_BPK, bpk); - //node 110 - } else if (result.getResultCount() > 1) { - throw new ManualFixNecessaryException("bpkzp:" + bpkzp);// node 108 - } - - // set NeedConsent to false, because user gives consont during authentication - pendingReq.setNeedUserConsent(false); - - log.info("Receive a valid assertion from IDP " + msg.getEntityID()); + validateEntityId(inboundMessage); + AssertionAttributeExtractor extractor = new AssertionAttributeExtractor(processedMsg.getFirst().getResponse()); + + /* + * SAML2 response ist bereits vollständig validiert und die Attribute können aus dem + * <AssertionAttributeExtractor extractor> ausgelesen werden. + * Die AttributeNamen sind entsprechend PVP Spezifikation, z.B. PvpAttributeDefinitions.GIVEN_NAME_NAME + * + * --------------------------------------------------------------------------------------------- + * + * TODO: ab hier müssen wir wohl was anpassen + * + */ + + final AuthProcessDataWrapper authProcessData = pendingReq.getSessionData(AuthProcessDataWrapper.class); + MergedRegisterSearchResult initialSearchResult = + authProcessData.getGenericDataFromSession(DATA_INITIAL_REGISTER_RESULT, MergedRegisterSearchResult.class); + SimpleEidasData eidasData = authProcessData.getGenericDataFromSession(DATA_SIMPLE_EIDAS, SimpleEidasData.class); + + SimpleMobileSignatureData simpleMobileSignatureData = getAuthDataFromInterfederation(extractor, authProcessData); + if (!simpleMobileSignatureData.equalsSimpleEidasData(eidasData)) { + //TODO User has cheated? + throw new InvalidUserInputException(); + } + String bpkZp = simpleMobileSignatureData.getBpk(); + MergedRegisterSearchResult result = registerSearchService.searchWithBpkZp(bpkZp); + if (result.getResultCount() == 0) { + //go to step 16 + executionContext.put(Constants.TRANSITION_TO_GENERATE_GUI_QUERY_AUSTRIAN_RESIDENCE_TASK, true); + return; + } else if (result.getResultCount() == 1) { + String bpk = registerSearchService.step7aKittProcess(initialSearchResult, result, eidasData, pendingReq); + authProcessData.setGenericDataToSession(Constants.DATA_RESULT_MATCHING_BPK, bpk); + return; + //node 110 + } else if (result.getResultCount() > 1) { + throw new ManualFixNecessaryException("bpkZp: " + bpkZp);// node 108 } + // set NeedConsent to false, because user gives consent during authentication + pendingReq.setNeedUserConsent(false); + log.info("Receive a valid assertion from IDP " + inboundMessage.getEntityID()); } catch (final AuthnResponseValidationException e) { throw new TaskExecutionException(pendingReq, ERROR_MSG_03, e); - } catch (MessageDecodingException | SecurityException | SamlSigningException e) { //final String samlRequest = request.getParameter("SAMLRequest"); //log.debug("Receive INVALID PVP Response from 'ms-specific eIDAS node': {}", // samlRequest, null, e); throw new TaskExecutionException(pendingReq, ERROR_MSG_00, - new AuthnResponseValidationException(ERROR_PVP_11, - new Object[]{IdAustriaClientAuthConstants.MODULE_NAME_FOR_LOGGING}, e)); - + new AuthnResponseValidationException(ERROR_PVP_11, new Object[]{MODULE_NAME_FOR_LOGGING}, e)); } catch (IOException | MarshallingException | TransformerException e) { log.debug("Processing PVP response from 'ms-specific eIDAS node' FAILED.", e); throw new TaskExecutionException(pendingReq, ERROR_MSG_01, - new AuthnResponseValidationException(ERROR_PVP_12, - new Object[]{IdAustriaClientAuthConstants.MODULE_NAME_FOR_LOGGING, e.getMessage()}, - e)); - + new AuthnResponseValidationException(ERROR_PVP_12, new Object[]{MODULE_NAME_FOR_LOGGING, e.getMessage()}, e)); } catch (final CredentialsNotAvailableException e) { log.debug("PVP response decrytion FAILED. No credential found.", e); throw new TaskExecutionException(pendingReq, ERROR_MSG_02, - new AuthnResponseValidationException(ERROR_PVP_10, - new Object[]{IdAustriaClientAuthConstants.MODULE_NAME_FOR_LOGGING}, e)); - + new AuthnResponseValidationException(ERROR_PVP_10, new Object[]{MODULE_NAME_FOR_LOGGING}, e)); } catch (final Exception e) { e.printStackTrace(); log.debug("PVP response validation FAILED. Msg:" + e.getMessage(), e); throw new TaskExecutionException(pendingReq, ERROR_MSG_03, - new AuthnResponseValidationException(ERROR_PVP_12, - new Object[]{IdAustriaClientAuthConstants.MODULE_NAME_FOR_LOGGING, e.getMessage()}, e)); + new AuthnResponseValidationException(ERROR_PVP_12, new Object[]{MODULE_NAME_FOR_LOGGING, e.getMessage()}, e)); + } + } + + @NotNull + private InboundMessage decodeAndVerifyMessage(HttpServletRequest request, HttpServletResponse response, + IDecoder decoder, EaafUriCompare comparator) throws Exception { + InboundMessage inboundMessage = (InboundMessage) decoder.decode(request, response, metadataProvider, + IDPSSODescriptor.DEFAULT_ELEMENT_NAME, comparator); + if (!inboundMessage.isVerified()) { + samlVerificationEngine.verify(inboundMessage, TrustEngineFactory.getSignatureKnownKeysTrustEngine( + metadataProvider)); + inboundMessage.setVerified(true); + } + return inboundMessage; + } + + private void validateEntityId(InboundMessage inboundMessage) throws AuthnResponseValidationException { + final String msNodeEntityID = authConfig + .getBasicConfiguration(IdAustriaClientAuthConstants.CONFIG_PROPS_ID_AUSTRIA_ENTITYID); + final String respEntityId = inboundMessage.getEntityID(); + if (!msNodeEntityID.equals(respEntityId)) { + log.warn("Response Issuer is not from valid 'ID Austria IDP'. Stopping ID Austria authentication ..."); + throw new AuthnResponseValidationException(ERROR_PVP_08, + new Object[]{MODULE_NAME_FOR_LOGGING, + inboundMessage.getEntityID()}); + } + } + + @NotNull + private EaafUriCompare loadComparator(HttpServletRequest request) throws AuthnResponseValidationException { + if (request.getMethod().equalsIgnoreCase("POST")) { + log.trace("Receive PVP Response from 'ID Austria system', by using POST-Binding."); + return new EaafUriCompare(pendingReq.getAuthUrl() + IdAustriaClientAuthConstants.ENDPOINT_POST); + } else if (request.getMethod().equalsIgnoreCase("GET")) { + log.trace("Receive PVP Response from 'ID Austria system', by using Redirect-Binding."); + return new EaafUriCompare(pendingReq.getAuthUrl() + IdAustriaClientAuthConstants.ENDPOINT_REDIRECT); + } else { + log.warn("Receive PVP Response from 'ID Austria system', but Binding {} is not supported.", request.getMethod()); + throw new AuthnResponseValidationException(ERROR_PVP_03, new Object[]{MODULE_NAME_FOR_LOGGING}); } + } + @NotNull + private IDecoder loadDecoder(HttpServletRequest request) throws AuthnResponseValidationException { + if (request.getMethod().equalsIgnoreCase("POST")) { + log.trace("Receive PVP Response from 'ID Austria system', by using POST-Binding."); + return new PostBinding(); + } else if (request.getMethod().equalsIgnoreCase("GET")) { + log.trace("Receive PVP Response from 'ID Austria system', by using Redirect-Binding."); + return new RedirectBinding(); + } else { + log.warn("Receive PVP Response from 'ID Austria system', but Binding {} is not supported.", request.getMethod()); + throw new AuthnResponseValidationException(ERROR_PVP_03, new Object[]{MODULE_NAME_FOR_LOGGING}); + } } - private Pair<PvpSProfileResponse, Boolean> preProcessAuthResponse(PvpSProfileResponse msg) + private Pair<PvpSProfileResponse, Boolean> validateAssertion(PvpSProfileResponse msg) throws IOException, MarshallingException, TransformerException, CredentialsNotAvailableException, AuthnResponseValidationException, SamlAssertionValidationExeption { log.debug("Start PVP21 assertion processing... "); - final Response samlResp = (Response) msg.getResponse(); - - // check SAML2 response status-code - if (samlResp.getStatus().getStatusCode().getValue().equals(StatusCode.SUCCESS)) { - // validate PVP 2.1 assertion - samlVerificationEngine.validateAssertion(samlResp, + final Response response = (Response) msg.getResponse(); + if (response.getStatus().getStatusCode().getValue().equals(StatusCode.SUCCESS)) { + samlVerificationEngine.validateAssertion(response, credentialProvider.getMessageEncryptionCredential(), pendingReq.getAuthUrl() + IdAustriaClientAuthConstants.ENDPOINT_METADATA, - IdAustriaClientAuthConstants.MODULE_NAME_FOR_LOGGING); - - msg.setSamlMessage(Saml2Utils.asDomDocument(samlResp).getDocumentElement()); + MODULE_NAME_FOR_LOGGING); + msg.setSamlMessage(Saml2Utils.asDomDocument(response).getDocumentElement()); revisionsLogger.logEvent(pendingReq, IdAustriaClientAuthEventConstants.AUTHPROCESS_ID_AUSTRIA_RESPONSE_RECEIVED, - samlResp.getID()); + response.getID()); return Pair.newInstance(msg, false); - } else { - log.info("Receive StatusCode {} from 'ms-specific eIDAS node'.", - samlResp.getStatus().getStatusCode().getValue()); - StatusCode subStatusCode = getSubStatusCode(samlResp); + log.info("Receive StatusCode {} from 'ms-specific eIDAS node'.", response.getStatus().getStatusCode().getValue()); + StatusCode subStatusCode = getSubStatusCode(response); if (subStatusCode != null && IdAustriaClientAuthConstants.SAML2_STATUSCODE_USERSTOP.equals(subStatusCode.getValue())) { log.info("Find 'User-Stop operation' in SAML2 response. Stopping authentication process ... "); return Pair.newInstance(msg, true); - } revisionsLogger.logEvent(pendingReq, IdAustriaClientAuthEventConstants.AUTHPROCESS_ID_AUSTRIA_RESPONSE_RECEIVED_ERROR); throw new AuthnResponseValidationException(ERROR_PVP_05, - new Object[]{IdAustriaClientAuthConstants.MODULE_NAME_FOR_LOGGING, - samlResp.getIssuer().getValue(), - samlResp.getStatus().getStatusCode().getValue(), - samlResp.getStatus().getStatusMessage().getMessage()}); - + new Object[]{MODULE_NAME_FOR_LOGGING, + response.getIssuer().getValue(), + response.getStatus().getStatusCode().getValue(), + response.getStatus().getStatusMessage().getMessage()}); } - } /** @@ -315,55 +289,42 @@ public class ReceiveMobilePhoneSignatureResponseAndSearchInRegistersTask extends && StringUtils.isNotEmpty(samlResp.getStatus().getStatusCode().getStatusCode().getValue())) { return samlResp.getStatus().getStatusCode().getStatusCode(); } - return null; } private SimpleMobileSignatureData getAuthDataFromInterfederation(AssertionAttributeExtractor extractor, AuthProcessDataWrapper authProcessData) throws EaafBuilderException { - List<String> requiredAttributes = IdAustriaClientAuthConstants.DEFAULT_REQUIRED_PVP_ATTRIBUTE_NAMES; - SimpleMobileSignatureData simpleMobileSignatureData = new SimpleMobileSignatureData(); + SimpleMobileSignatureData result = new SimpleMobileSignatureData(); try { - // check if all attributes are include if (!extractor.containsAllRequiredAttributes(requiredAttributes)) { log.warn("PVP Response from 'ID Austria node' contains not all requested attributes."); - throw new AssertionValidationExeption(ERROR_PVP_06, new Object[]{ - IdAustriaClientAuthConstants.MODULE_NAME_FOR_LOGGING}); - + throw new AssertionValidationExeption(ERROR_PVP_06, new Object[]{MODULE_NAME_FOR_LOGGING}); } - - HashMap<String, String> map = new HashMap<>(); final Set<String> includedAttrNames = extractor.getAllIncludeAttributeNames(); for (final String attrName : includedAttrNames) { - map.put(attrName, extractor.getSingleAttributeValue(attrName)); - if (PvpAttributeDefinitions.BPK_NAME.equals(attrName)) { - simpleMobileSignatureData.setBpk(extractor.getSingleAttributeValue(attrName)); + result.setBpk(extractor.getSingleAttributeValue(attrName)); } if (PvpAttributeDefinitions.GIVEN_NAME_NAME.equals(attrName)) { - simpleMobileSignatureData.setGivenName(extractor.getSingleAttributeValue(attrName)); + result.setGivenName(extractor.getSingleAttributeValue(attrName)); } if (PvpAttributeDefinitions.PRINCIPAL_NAME_NAME.equals(attrName)) { - simpleMobileSignatureData.setFamilyName(extractor.getSingleAttributeValue(attrName)); + result.setFamilyName(extractor.getSingleAttributeValue(attrName)); } if (PvpAttributeDefinitions.BIRTHDATE_NAME.equals(attrName)) { - simpleMobileSignatureData.setDateOfBirth(extractor.getSingleAttributeValue(attrName)); + result.setDateOfBirth(extractor.getSingleAttributeValue(attrName)); } if (PvpAttributeDefinitions.EID_CITIZEN_EIDAS_QAA_LEVEL_NAME.equals(attrName)) { authProcessData.setQaaLevel(extractor.getSingleAttributeValue(attrName)); } - } - authProcessData.setIssueInstant(extractor.getAssertionIssuingDate()); - } catch (final AssertionValidationExeption e) { throw new EaafBuilderException(ERROR_PVP_06, null, e.getMessage(), e); - } - return simpleMobileSignatureData; + return result; } |