From 4b6fd327b29ff84f61914f33b6361fa31441c92e Mon Sep 17 00:00:00 2001 From: Thomas Knall Date: Wed, 4 Feb 2015 11:31:43 +0100 Subject: Create separate module STORK (MOAID-67) - Add new maven module moa-id-modules and sub module moa-id-module-stork. - Move stork relates processes and task to module moa-id-module-stork. - Move module registration to modules package. --- .../id/auth/modules/stork/STORKAuthModuleImpl.java | 39 ++ .../stork/STORKWebApplicationInitializer.java | 37 ++ .../AbstractPepsConnectorWithLocalSigningTask.java | 223 ++++++++ .../tasks/CreateStorkAuthRequestFormTask.java | 112 ++++ .../PepsConnectorHandleLocalSignResponseTask.java | 216 ++++++++ ...onnectorHandleResponseWithoutSignatureTask.java | 439 ++++++++++++++++ .../modules/stork/tasks/PepsConnectorTask.java | 566 +++++++++++++++++++++ .../auth/modules/stork/STORK.authmodule.beans.xml | 14 + .../modules/stork/STORKAuthentication.process.xml | 29 ++ 9 files changed, 1675 insertions(+) create mode 100644 id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/STORKAuthModuleImpl.java create mode 100644 id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/STORKWebApplicationInitializer.java create mode 100644 id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/tasks/AbstractPepsConnectorWithLocalSigningTask.java create mode 100644 id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/tasks/CreateStorkAuthRequestFormTask.java create mode 100644 id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/tasks/PepsConnectorHandleLocalSignResponseTask.java create mode 100644 id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/tasks/PepsConnectorHandleResponseWithoutSignatureTask.java create mode 100644 id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/tasks/PepsConnectorTask.java create mode 100644 id/server/modules/module-stork/src/main/resources/at/gv/egovernment/moa/id/auth/modules/stork/STORK.authmodule.beans.xml create mode 100644 id/server/modules/module-stork/src/main/resources/at/gv/egovernment/moa/id/auth/modules/stork/STORKAuthentication.process.xml (limited to 'id/server/modules/module-stork/src/main') diff --git a/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/STORKAuthModuleImpl.java b/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/STORKAuthModuleImpl.java new file mode 100644 index 000000000..41384690e --- /dev/null +++ b/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/STORKAuthModuleImpl.java @@ -0,0 +1,39 @@ +package at.gv.egovernment.moa.id.auth.modules.stork; + +import org.apache.commons.lang3.StringUtils; + +import at.gv.egovernment.moa.id.auth.modules.AuthModule; +import at.gv.egovernment.moa.id.process.api.ExecutionContext; + +/** + * Module descriptor for an auth module providing stork authentication related processes. + * @author tknall + */ +public class STORKAuthModuleImpl implements AuthModule { + + private int priority = 0; + + @Override + public int getPriority() { + return priority; + } + + /** + * Sets the priority of this module. Default value is {@code 0}. + * @param priority The priority. + */ + public void setPriority(int priority) { + this.priority = priority; + } + + @Override + public String selectProcess(ExecutionContext context) { + return StringUtils.isNotBlank((String) context.get("ccc")) ? "STORKAuthentication" : null; + } + + @Override + public String[] getProcessDefinitions() { + return new String[] { "classpath:at/gv/egovernment/moa/id/auth/modules/stork/STORKAuthentication.process.xml" }; + } + +} diff --git a/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/STORKWebApplicationInitializer.java b/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/STORKWebApplicationInitializer.java new file mode 100644 index 000000000..7478a57c3 --- /dev/null +++ b/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/STORKWebApplicationInitializer.java @@ -0,0 +1,37 @@ +package at.gv.egovernment.moa.id.auth.modules.stork; + +import javax.servlet.ServletContext; +import javax.servlet.ServletException; +import javax.servlet.ServletRegistration; + +import org.springframework.web.WebApplicationInitializer; + +import at.gv.egovernment.moa.id.auth.servlet.ProcessEngineSignalServlet; + +/** + * Spring automatically discovers {@link WebApplicationInitializer} implementations at startup.
+ * This STORK webapp initializer adds the required servlet mappings: + * + * for the {@linkplain ProcessEngineSignalServlet process engine servlet} (named {@code ProcessEngineSignal}) that wakes + * up a process in order to execute asynchronous tasks. Therefore the servlet mappings mentioned above do not need to be + * declared in {@code web.xml}. + * + * @author tknall + * @see ProcessEngineSignalServlet + */ +public class STORKWebApplicationInitializer implements WebApplicationInitializer { + + @Override + public void onStartup(ServletContext servletContext) throws ServletException { + ServletRegistration servletRegistration = servletContext.getServletRegistration("ProcessEngineSignal"); + if (servletRegistration == null) { + throw new IllegalStateException("Servlet 'ProcessEngineSignal' expected to be registered."); + } + servletRegistration.addMapping("/PEPSConnectorWithLocalSigning"); + servletRegistration.addMapping("/PEPSConnector"); + } + +} diff --git a/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/tasks/AbstractPepsConnectorWithLocalSigningTask.java b/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/tasks/AbstractPepsConnectorWithLocalSigningTask.java new file mode 100644 index 000000000..702e62fa0 --- /dev/null +++ b/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/tasks/AbstractPepsConnectorWithLocalSigningTask.java @@ -0,0 +1,223 @@ +package at.gv.egovernment.moa.id.auth.modules.stork.tasks; + +import iaik.x509.X509Certificate; + +import java.io.IOException; +import java.io.InputStream; +import java.io.UnsupportedEncodingException; +import java.security.cert.CertificateException; +import java.util.HashMap; + +import javax.activation.DataSource; +import javax.xml.bind.JAXBContext; +import javax.xml.bind.JAXBElement; +import javax.xml.bind.JAXBException; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.transform.TransformerConfigurationException; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactoryConfigurationError; + +import org.apache.commons.io.IOUtils; +import org.xml.sax.SAXException; + +import at.gv.egovernment.moa.id.auth.data.AuthenticationSession; +import at.gv.egovernment.moa.id.auth.data.IdentityLink; +import at.gv.egovernment.moa.id.auth.exception.AuthenticationException; +import at.gv.egovernment.moa.id.auth.exception.BKUException; +import at.gv.egovernment.moa.id.auth.exception.BuildException; +import at.gv.egovernment.moa.id.auth.exception.MOAIDException; +import at.gv.egovernment.moa.id.auth.exception.ParseException; +import at.gv.egovernment.moa.id.auth.exception.ServiceException; +import at.gv.egovernment.moa.id.auth.modules.AbstractAuthServletTask; +import at.gv.egovernment.moa.id.auth.stork.STORKException; +import at.gv.egovernment.moa.id.auth.stork.STORKResponseProcessor; +import at.gv.egovernment.moa.id.config.ConfigurationException; +import at.gv.egovernment.moa.id.config.auth.AuthConfigurationProvider; +import at.gv.egovernment.moa.id.config.auth.OAAuthParameter; +import at.gv.egovernment.moa.id.protocols.pvp2x.PVPConstants; +import at.gv.egovernment.moa.logging.Logger; +import at.gv.egovernment.moa.spss.MOAException; +import at.gv.egovernment.moa.spss.api.SPSSFactory; +import at.gv.egovernment.moa.spss.api.SignatureVerificationService; +import at.gv.egovernment.moa.spss.api.common.Content; +import at.gv.egovernment.moa.spss.api.xmlverify.VerifySignatureInfo; +import at.gv.egovernment.moa.spss.api.xmlverify.VerifySignatureLocation; +import at.gv.egovernment.moa.spss.api.xmlverify.VerifyXMLSignatureRequest; +import at.gv.egovernment.moa.spss.api.xmlverify.VerifyXMLSignatureResponse; +import at.gv.util.xsd.xmldsig.SignatureType; +import at.gv.util.xsd.xmldsig.X509DataType; +import eu.stork.oasisdss.api.LightweightSourceResolver; +import eu.stork.oasisdss.api.exceptions.ApiUtilsException; +import eu.stork.oasisdss.api.exceptions.UtilsException; +import eu.stork.oasisdss.profile.SignResponse; +import eu.stork.peps.auth.commons.IPersonalAttributeList; + +public abstract class AbstractPepsConnectorWithLocalSigningTask extends AbstractAuthServletTask { + + String getCitizienSignatureFromSignResponse(SignResponse dssSignResponse) throws IllegalArgumentException, + TransformerConfigurationException, UtilsException, TransformerException, + TransformerFactoryConfigurationError, IOException, ApiUtilsException { + // fetch signed doc + DataSource ds = LightweightSourceResolver.getDataSource(dssSignResponse); + if (ds == null) { + throw new ApiUtilsException("No datasource found in response"); + } + + InputStream incoming = ds.getInputStream(); + String citizenSignature = IOUtils.toString(incoming); + incoming.close(); + + return citizenSignature; + } + + void SZRGInsertion(AuthenticationSession moaSession, IPersonalAttributeList personalAttributeList, + String authnContextClassRef, String citizenSignature) throws STORKException, MOAIDException { + Logger.debug("Foregin Citizen signature successfully extracted from STORK Assertion (signedDoc)"); + Logger.debug("Citizen signature will be verified by SZR Gateway!"); + + Logger.debug("fetching OAParameters from database"); + + OAAuthParameter oaParam = AuthConfigurationProvider.getInstance().getOnlineApplicationParameter( + moaSession.getPublicOAURLPrefix()); + if (oaParam == null) + throw new AuthenticationException("auth.00", new Object[] { moaSession.getPublicOAURLPrefix() }); + + // retrieve target + // TODO: check in case of SSO!!! + String targetType = null; + if (oaParam.getBusinessService()) { + String id = oaParam.getIdentityLinkDomainIdentifier(); + if (id.startsWith(AuthenticationSession.REGISTERANDORDNR_PREFIX_)) + targetType = id; + else + targetType = AuthenticationSession.REGISTERANDORDNR_PREFIX_ + moaSession.getDomainIdentifier(); + } else { + targetType = AuthenticationSession.TARGET_PREFIX_ + oaParam.getTarget(); + } + + Logger.debug("Starting connecting SZR Gateway"); + // contact SZR Gateway + IdentityLink identityLink = null; + + identityLink = STORKResponseProcessor.connectToSZRGateway(personalAttributeList, oaParam.getFriendlyName(), + targetType, null, oaParam.getMandateProfiles(), citizenSignature); + Logger.debug("SZR communication was successfull"); + + if (identityLink == null) { + Logger.error("SZR Gateway did not return an identity link."); + throw new MOAIDException("stork.10", null); + } + Logger.info("Received Identity Link from SZR Gateway"); + moaSession.setIdentityLink(identityLink); + + Logger.debug("Adding addtional STORK attributes to MOA session"); + moaSession.setStorkAttributes(personalAttributeList); + + // We don't have BKUURL, setting from null to "Not applicable" + moaSession.setBkuURL("Not applicable (STORK Authentication)"); + + // free for single use + moaSession.setAuthenticatedUsed(false); + + // stork did the authentication step + moaSession.setAuthenticated(true); + + // TODO: found better solution, but QAA Level in response could be not supported yet + try { + if (authnContextClassRef == null) + authnContextClassRef = PVPConstants.STORK_QAA_PREFIX + oaParam.getQaaLevel(); + moaSession.setQAALevel(authnContextClassRef); + + } catch (Throwable e) { + Logger.warn("STORK QAA-Level is not found in AuthnResponse. Set QAA Level to requested level"); + moaSession.setQAALevel(PVPConstants.STORK_QAA_PREFIX + oaParam.getQaaLevel()); + + } + + } + + X509Certificate getSignerCertificate(String citizenSignature) throws CertificateException, JAXBException, + UnsupportedEncodingException { + JAXBContext ctx = JAXBContext.newInstance(SignatureType.class.getPackage().getName()); + SignatureType root = ((JAXBElement) ctx.createUnmarshaller().unmarshal( + IOUtils.toInputStream(citizenSignature))).getValue(); + + // extract certificate + for (Object current : root.getKeyInfo().getContent()) + if (((JAXBElement) current).getValue() instanceof X509DataType) { + for (Object currentX509Data : ((JAXBElement) current).getValue() + .getX509IssuerSerialOrX509SKIOrX509SubjectName()) { + JAXBElement casted = ((JAXBElement) currentX509Data); + if (casted.getName().getLocalPart().equals("X509Certificate")) { + return new X509Certificate(((String) casted.getValue()).getBytes("UTF-8")); + } + } + } + return null; + } + + VerifyXMLSignatureResponse verifyXMLSignature(String signature) throws AuthenticationException, ParseException, + BKUException, BuildException, ConfigurationException, ServiceException, UnsupportedEncodingException, + SAXException, IOException, ParserConfigurationException, MOAException { + // Based on MOA demo client + // Factory und Service instanzieren + SPSSFactory spssFac = SPSSFactory.getInstance(); + SignatureVerificationService sigVerifyService = SignatureVerificationService.getInstance(); + + Content sigDocContent1 = spssFac.createContent(IOUtils.toInputStream(signature, "UTF-8"), null); + + // Position der zu prüfenden Signatur im Dokument angeben + // (Nachdem im XPath-Ausdruck ein NS-Präfix verwendet wird, muss in einer Lookup-Tabelle + // der damit bezeichnete Namenraum mitgegeben werden) + HashMap nSMap = new HashMap(); + nSMap.put("dsig", "http://www.w3.org/2000/09/xmldsig#"); + VerifySignatureLocation sigLocation = spssFac.createVerifySignatureLocation("//dsig:Signature", nSMap); + + // Zu prüfendes Dokument und Signaturposition zusammenfassen + + VerifySignatureInfo sigInfo = spssFac.createVerifySignatureInfo(sigDocContent1, sigLocation); + + // Prüfrequest zusammenstellen + VerifyXMLSignatureRequest verifyRequest = spssFac.createVerifyXMLSignatureRequest(null, // Wird Prüfzeit nicht + // angegeben, wird + // aktuelle Zeit + // verwendet + sigInfo, null, // Keine Ergänzungsobjekte notwendig + null, // Signaturmanifest-Prüfung soll nicht durchgeführt werden + false, // Hash-Inputdaten, d.h. tatsächlich signierte Daten werden nicht zurückgeliefert + "MOAIDBuergerkartePersonenbindungMitTestkarten");// TODO load from config + // "Test-Signaturdienste"); // ID des verwendeten Vertrauensprofils + + VerifyXMLSignatureResponse verifyResponse = null; + try { + // Aufruf der Signaturprüfung + verifyResponse = sigVerifyService.verifyXMLSignature(verifyRequest); + } catch (MOAException e) { + // Service liefert Fehler + System.err.println("Die Signaturprüfung hat folgenden Fehler geliefert:"); + System.err.println("Fehlercode: " + e.getMessageId()); + System.err.println("Fehlernachricht: " + e.getMessage()); + throw e; + } + + return verifyResponse; + } + + at.gv.egovernment.moa.id.auth.data.VerifyXMLSignatureResponse convert( + VerifyXMLSignatureResponse xMLVerifySignatureResponse) { + at.gv.egovernment.moa.id.auth.data.VerifyXMLSignatureResponse response = new at.gv.egovernment.moa.id.auth.data.VerifyXMLSignatureResponse(); + response.setCertificateCheckCode(xMLVerifySignatureResponse.getCertificateCheck().getCode()); + response.setPublicAuthority(xMLVerifySignatureResponse.getSignerInfo().isPublicAuthority()); + // response.setPublicAuthorityCode(publicAuthorityCode) + response.setQualifiedCertificate(xMLVerifySignatureResponse.getSignerInfo().isQualifiedCertificate()); + response.setSignatureCheckCode(xMLVerifySignatureResponse.getSignatureCheck().getCode()); + response.setSignatureManifestCheckCode(xMLVerifySignatureResponse.getSignatureManifestCheck().getCode()); + // response.setSigningDateTime() + // response.setX509certificate(x509certificate) + response.setXmlDSIGManifestCheckCode(xMLVerifySignatureResponse.getSignatureManifestCheck().getCode()); + // response.setXmlDSIGManigest(xMLVerifySignatureResponse.getSignatureManifestCheck()) + // response.setXmlDsigSubjectName(xmlDsigSubjectName) + return response; + } + +} diff --git a/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/tasks/CreateStorkAuthRequestFormTask.java b/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/tasks/CreateStorkAuthRequestFormTask.java new file mode 100644 index 000000000..f8cc17b93 --- /dev/null +++ b/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/tasks/CreateStorkAuthRequestFormTask.java @@ -0,0 +1,112 @@ +package at.gv.egovernment.moa.id.auth.modules.stork.tasks; + +import static at.gv.egovernment.moa.id.auth.MOAIDAuthConstants.*; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.commons.lang.StringEscapeUtils; +import org.apache.commons.lang3.StringUtils; + +import at.gv.egovernment.moa.id.auth.AuthenticationServer; +import at.gv.egovernment.moa.id.auth.builder.StartAuthenticationBuilder; +import at.gv.egovernment.moa.id.auth.data.AuthenticationSession; +import at.gv.egovernment.moa.id.auth.exception.AuthenticationException; +import at.gv.egovernment.moa.id.auth.exception.MOAIDException; +import at.gv.egovernment.moa.id.auth.exception.WrongParametersException; +import at.gv.egovernment.moa.id.auth.modules.AbstractAuthServletTask; +import at.gv.egovernment.moa.id.commons.db.ConfigurationDBUtils; +import at.gv.egovernment.moa.id.config.auth.AuthConfigurationProvider; +import at.gv.egovernment.moa.id.config.stork.CPEPS; +import at.gv.egovernment.moa.id.config.stork.STORKConfig; +import at.gv.egovernment.moa.id.process.api.ExecutionContext; +import at.gv.egovernment.moa.id.storage.AuthenticationSessionStoreage; +import at.gv.egovernment.moa.id.util.ParamValidatorUtils; +import at.gv.egovernment.moa.logging.Logger; + +/** + * Creates a SAML2 STORK authentication request, embeds it in a form (in order to satisfy saml post binging) and returns the form withing the HttpServletResponse.

+ * In detail: + *

    + *
  • Validates the stork configuration in order to make sure the selected country is supported.
  • + *
  • Puts a flag ({@link #PROCESS_CTX_KEY_CPEPS_ISXMLSIGSUPPORTED}) into the ExecutionContext reflecting the capability of the C-PEPS to create xml signatures.
  • + *
  • Invokes {@link AuthenticationServer#startSTORKAuthentication(HttpServletRequest, HttpServletResponse, AuthenticationSession)} which
  • + *
      + *
    • Creates and signs a SAML2 stork authentication request.
    • + *
    • Creates a signature request for auth block signature (either to be performed by the C-PEPS or locally).
    • + *
    • Using the velocity template engine in order to create a form with the embedded stork request.
    • + *
    • Writes the form to the response output stream.
    • + *
    + *
+ * Expects: + *
    + *
  • HttpServletRequest parameter {@linkplain at.gv.egovernment.moa.id.auth.MOAIDAuthConstants#PARAM_SESSIONID PARAM_SESSIONID}
  • + *
  • Property {@code ccc} set within the moa session.
  • + *
+ * Result: + *
    + *
  • Form containing a SAML2 Stork authentication request and an action url pointing to the selected C-PEPS.
  • + *
  • Assertion consumer URL for C-PEPS set either to {@code /PEPSConnector} in case of a C-PEPS supporting xml signatures or {@code /PEPSConnectorWithLocalSigning} if the selected C-PEPS does not support xml signatures.
  • + *
  • In case of a C-PEPS not supporting xml signature: moasession with set signedDoc property (containing the signature request for local signing).
  • + *
  • ExecutionContext contains the boolean flag {@link #PROCESS_CTX_KEY_CPEPS_ISXMLSIGSUPPORTED}. + *
+ * Code taken from {@link StartAuthenticationBuilder#build(AuthenticationSession, HttpServletRequest, HttpServletResponse)}.
+ * Using {@link AuthenticationServer#startSTORKAuthentication(HttpServletRequest, HttpServletResponse, AuthenticationSession)} + * @see #execute(ExecutionContext, HttpServletRequest, HttpServletResponse) + */ +public class CreateStorkAuthRequestFormTask extends AbstractAuthServletTask { + + /** + * Boolean value reflecting the capability of the selected c-peps of creating xml signatures. + */ + public static final String PROCESS_CTX_KEY_CPEPS_ISXMLSIGSUPPORTED = "C-PEPS:XMLSignatureSupported"; + + @Override + public void execute(ExecutionContext executionContext, HttpServletRequest req, HttpServletResponse resp) + throws Exception { + + String pendingRequestID = null; + String sessionID = null; + try { + setNoCachingHeaders(resp); + + sessionID = StringEscapeUtils.escapeHtml(req.getParameter(PARAM_SESSIONID)); + // check parameter + if (!ParamValidatorUtils.isValidSessionID(sessionID)) { + throw new WrongParametersException("CreateStorkAuthRequestFormTask", PARAM_SESSIONID, "auth.12"); + } + AuthenticationSession moasession = AuthenticationServer.getSession(sessionID); + pendingRequestID = AuthenticationSessionStoreage.getPendingRequestID(sessionID); + + if (StringUtils.isEmpty(moasession.getCcc())) { + // illegal state; task should not have been executed without a selected country + throw new AuthenticationException("stork.22", new Object[] { sessionID }); + } + STORKConfig storkConfig = AuthConfigurationProvider.getInstance().getStorkConfig(); + if (!storkConfig.isSTORKAuthentication(moasession.getCcc())) { + throw new AuthenticationException("stork.23", new Object[] { moasession.getCcc(), sessionID }); + } + + // STORK authentication + // cpeps cannot be null + CPEPS cpeps = storkConfig.getCPEPS(moasession.getCcc()); + Logger.debug("Found C-PEPS configuration for citizen of country: " + moasession.getCcc()); + executionContext.put(PROCESS_CTX_KEY_CPEPS_ISXMLSIGSUPPORTED, cpeps.isXMLSignatureSupported()); + + Logger.info("Starting STORK authentication for a citizen of country: " + moasession.getCcc()); + AuthenticationServer.startSTORKAuthentication(req, resp, moasession); + + } catch (MOAIDException ex) { + handleError(null, ex, req, resp, pendingRequestID); + + } catch (Exception e) { + Logger.error("CreateStorkAuthRequestFormTask has an interal Error.", e); + throw new MOAIDException("Internal error.", new Object[] { sessionID }, e); + } + + finally { + ConfigurationDBUtils.closeSession(); + } + } + +} diff --git a/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/tasks/PepsConnectorHandleLocalSignResponseTask.java b/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/tasks/PepsConnectorHandleLocalSignResponseTask.java new file mode 100644 index 000000000..077bb2dee --- /dev/null +++ b/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/tasks/PepsConnectorHandleLocalSignResponseTask.java @@ -0,0 +1,216 @@ +package at.gv.egovernment.moa.id.auth.modules.stork.tasks; + +import iaik.x509.X509Certificate; + +import java.io.IOException; +import java.io.StringWriter; +import java.util.ArrayList; +import java.util.List; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.xml.transform.Source; +import javax.xml.transform.stream.StreamSource; + +import org.apache.commons.codec.binary.Base64; +import org.apache.velocity.Template; +import org.apache.velocity.VelocityContext; +import org.apache.velocity.app.VelocityEngine; + +import at.gv.egovernment.moa.id.auth.AuthenticationServer; +import at.gv.egovernment.moa.id.auth.builder.DataURLBuilder; +import at.gv.egovernment.moa.id.auth.data.AuthenticationSession; +import at.gv.egovernment.moa.id.auth.exception.AuthenticationException; +import at.gv.egovernment.moa.id.auth.exception.MOAIDException; +import at.gv.egovernment.moa.id.auth.stork.STORKException; +import at.gv.egovernment.moa.id.commons.db.ConfigurationDBUtils; +import at.gv.egovernment.moa.id.moduls.ModulUtils; +import at.gv.egovernment.moa.id.process.api.ExecutionContext; +import at.gv.egovernment.moa.id.storage.AuthenticationSessionStoreage; +import at.gv.egovernment.moa.id.util.VelocityProvider; +import at.gv.egovernment.moa.logging.Logger; +import at.gv.egovernment.moa.spss.api.xmlverify.VerifyXMLSignatureResponse; +import eu.stork.oasisdss.api.ApiUtils; +import eu.stork.oasisdss.profile.SignResponse; +import eu.stork.peps.auth.commons.IPersonalAttributeList; +import eu.stork.peps.auth.commons.PersonalAttribute; + +/** + * Processes the citizen's signature, creates identity link using szr gateway and finalizes authentication. + *

+ * In detail: + *

    + *
  • Changes moa session id.
  • + *
  • Decodes and validates the sign response, extracting the citizen's signature.
  • + *
  • Verifies the citizen's signature.
  • + *
  • Create {@code signedDoc} attribute.
  • + *
  • Retrieve identity link from SZR gateway using the citizen's signature.
  • + *
  • If the S-PEPS did not provide any gender information, the szr gateway will not be able to issue an identity link. + * Therefore a form is presented asking for the subject's gender. The form finally submits the user back to the + * {@code /PepsConnectorWithLocalSigning} servlet (this task).
  • + *
  • The moa session is updated with authentication information.
  • + *
  • Change moa session id.
  • + *
  • Redirects back to {@code /dispatcher} in order to finalize the authentication.
  • + *
+ * Expects: + *
    + *
  • HttpServletRequest parameter {@code moaSessionID}
  • + *
  • HttpServletRequest parameter {@code signresponse}
  • + *
+ * Result: + *
    + *
  • Updated moa id session (signed auth block, signer certificate etc.)
  • + *
  • Redirect to {@code /dispatcher}.
  • + *
  • {@link ExecutionContext} contains boolean flag {@code identityLinkAvailable} indicating if an identitylink has been successfully creates or not.
  • + *
+ * Possible branches: + *
    + *
  • In case the szr gateway throws exception due to missing gender information: + *
      + *
    • Returns a form for gender selection with action url back to this servlet/task.
    • + *
    + *
  • + *
+ * Code taken from {@link at.gv.egovernment.moa.id.auth.servlet.PEPSConnectorWithLocalSigningServlet}.
+ * + * @see #execute(ExecutionContext, HttpServletRequest, HttpServletResponse) + */ +public class PepsConnectorHandleLocalSignResponseTask extends AbstractPepsConnectorWithLocalSigningTask { + + @Override + public void execute(ExecutionContext executionContext, HttpServletRequest request, HttpServletResponse response) + throws Exception { + String moaSessionID = request.getParameter("moaSessionID"); + String signResponse = request.getParameter("signresponse"); + Logger.info("moaSessionID:" + moaSessionID); + Logger.info("signResponse:" + signResponse); + + if (moaSessionID != null && signResponse != null) { + // redirect from oasis with signresponse + handleSignResponse(executionContext, request, response); + } else { + // should not occur + throw new IOException("should not occur"); + } + return; + } + + private void handleSignResponse(ExecutionContext executionContext, HttpServletRequest request, + HttpServletResponse response) { + Logger.info("handleSignResponse started"); + String moaSessionID = request.getParameter("moaSessionID"); + String signResponse = request.getParameter("signresponse"); + Logger.info("moaSessionID:" + moaSessionID); + Logger.info("signResponse:" + signResponse); + String pendingRequestID = null; + try { + + // load MOASession from database + AuthenticationSession moaSession = AuthenticationServer.getSession(moaSessionID); + // change MOASessionID + moaSessionID = AuthenticationSessionStoreage.changeSessionID(moaSession); + + pendingRequestID = AuthenticationSessionStoreage.getPendingRequestID(moaSessionID); + Logger.info("pendingRequestID:" + pendingRequestID); + String signResponseString = new String(Base64.decodeBase64(signResponse), "UTF8"); + Logger.info("RECEIVED signresponse:" + signResponseString); + // create SignResponse object + Source response1 = new StreamSource(new java.io.StringReader(signResponseString)); + SignResponse dssSignResponse = ApiUtils.unmarshal(response1, SignResponse.class); + + // SignResponse dssSignResponse = (SignResponse) ApiUtils.unmarshal(new StreamSource(new + // java.io.StringReader(Base64.signResponse))); + + String citizenSignature = getCitizienSignatureFromSignResponse(dssSignResponse); + + // memorize signature into authblock + moaSession.setAuthBlock(citizenSignature); + + X509Certificate cert = getSignerCertificate(citizenSignature); + moaSession.setSignerCertificate(cert); + VerifyXMLSignatureResponse xMLVerifySignatureResponse = verifyXMLSignature(citizenSignature); + at.gv.egovernment.moa.id.auth.data.VerifyXMLSignatureResponse tmp = convert(xMLVerifySignatureResponse); + + moaSession.setXMLVerifySignatureResponse(tmp); + executionContext.put("identityLinkAvailable", false); + try { + IPersonalAttributeList personalAttributeList = moaSession.getAuthnResponseGetPersonalAttributeList(); + // Add SignResponse TODO Add signature (extracted from signResponse)? + List values = new ArrayList(); + values.add(signResponseString); + // values.add(citizenSignature); + Logger.debug("Assembling signedDoc attribute"); + PersonalAttribute signedDocAttribute = new PersonalAttribute("signedDoc", false, values, "Available"); + personalAttributeList.add(signedDocAttribute); + + String authnContextClassRef = moaSession.getAuthnContextClassRef(); + SZRGInsertion(moaSession, personalAttributeList, authnContextClassRef, citizenSignature); + executionContext.put("identityLinkAvailable", true); + } catch (STORKException e) { + // this is really nasty but we work against the system here. We are supposed to get the gender attribute + // from + // stork. If we do not, we cannot register the person in the ERnP - we have to have the + // gender for the represented person. So here comes the dirty hack. + if (e.getCause() instanceof STORKException + && e.getCause().getMessage().equals("gender not found in response")) { + try { + Logger.trace("Initialize VelocityEngine..."); + + VelocityEngine velocityEngine = VelocityProvider.getClassPathVelocityEngine(); + Template template = velocityEngine.getTemplate("/resources/templates/fetchGender.html"); + VelocityContext context = new VelocityContext(); + context.put("SAMLResponse", request.getParameter("SAMLResponse")); + context.put("action", request.getRequestURL()); + + StringWriter writer = new StringWriter(); + template.merge(context, writer); + response.getOutputStream().write(writer.toString().getBytes("UTF-8")); + } catch (Exception e1) { + Logger.error("Error sending gender retrival form.", e1); + // httpSession.invalidate(); + throw new MOAIDException("stork.10", null); + } + + return; + } + + Logger.error("Error connecting SZR Gateway", e); + throw new MOAIDException("stork.10", null); + } + + Logger.debug("Add full STORK AuthnResponse to MOA session"); + moaSession.setStorkAuthnResponse(request.getParameter("SAMLResponse"));// TODO ask Florian/Thomas + // authnResponse? + moaSession.setForeigner(true); + + // session is implicit stored in changeSessionID!!!! + String newMOASessionID = AuthenticationSessionStoreage.changeSessionID(moaSession); + + Logger.info("Changed MOASession " + moaSessionID + " to Session " + newMOASessionID); + + // redirect + String redirectURL = null; + redirectURL = new DataURLBuilder().buildDataURL(moaSession.getAuthURL(), + ModulUtils.buildAuthURL(moaSession.getModul(), moaSession.getAction(), pendingRequestID), + newMOASessionID); + redirectURL = response.encodeRedirectURL(redirectURL); + + response.sendRedirect(redirectURL); + Logger.info("REDIRECT TO: " + redirectURL); + + } catch (AuthenticationException e) { + handleError(null, e, request, response, pendingRequestID); + + } catch (MOAIDException e) { + handleError(null, e, request, response, pendingRequestID); + + } catch (Exception e) { + Logger.error("PEPSConnector has an interal Error.", e); + } + + finally { + ConfigurationDBUtils.closeSession(); + } + } + +} diff --git a/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/tasks/PepsConnectorHandleResponseWithoutSignatureTask.java b/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/tasks/PepsConnectorHandleResponseWithoutSignatureTask.java new file mode 100644 index 000000000..3338804b4 --- /dev/null +++ b/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/tasks/PepsConnectorHandleResponseWithoutSignatureTask.java @@ -0,0 +1,439 @@ +package at.gv.egovernment.moa.id.auth.modules.stork.tasks; + +import iaik.x509.X509Certificate; + +import java.io.IOException; +import java.io.StringWriter; +import java.util.ArrayList; +import java.util.List; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.xml.transform.Source; +import javax.xml.transform.stream.StreamSource; + +import org.apache.commons.codec.binary.Base64; +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang.StringEscapeUtils; +import org.apache.velocity.Template; +import org.apache.velocity.VelocityContext; +import org.apache.velocity.app.VelocityEngine; +import org.opensaml.saml2.core.StatusCode; + +import at.gv.egovernment.moa.id.auth.AuthenticationServer; +import at.gv.egovernment.moa.id.auth.builder.DataURLBuilder; +import at.gv.egovernment.moa.id.auth.data.AuthenticationSession; +import at.gv.egovernment.moa.id.auth.exception.AuthenticationException; +import at.gv.egovernment.moa.id.auth.exception.MOAIDException; +import at.gv.egovernment.moa.id.auth.servlet.PEPSConnectorWithLocalSigningServlet; +import at.gv.egovernment.moa.id.auth.stork.STORKException; +import at.gv.egovernment.moa.id.auth.stork.STORKResponseProcessor; +import at.gv.egovernment.moa.id.commons.db.ConfigurationDBUtils; +import at.gv.egovernment.moa.id.commons.db.dao.config.AttributeProviderPlugin; +import at.gv.egovernment.moa.id.config.auth.AuthConfigurationProvider; +import at.gv.egovernment.moa.id.moduls.ModulUtils; +import at.gv.egovernment.moa.id.process.api.ExecutionContext; +import at.gv.egovernment.moa.id.storage.AuthenticationSessionStoreage; +import at.gv.egovernment.moa.id.util.HTTPUtils; +import at.gv.egovernment.moa.id.util.VelocityProvider; +import at.gv.egovernment.moa.logging.Logger; +import at.gv.egovernment.moa.util.StringUtils; +import eu.stork.oasisdss.api.ApiUtils; +import eu.stork.oasisdss.profile.SignRequest; +import eu.stork.oasisdss.profile.SignResponse; +import eu.stork.peps.auth.commons.IPersonalAttributeList; +import eu.stork.peps.auth.commons.PEPSUtil; +import eu.stork.peps.auth.commons.PersonalAttribute; +import eu.stork.peps.auth.commons.STORKAuthnRequest; +import eu.stork.peps.auth.commons.STORKAuthnResponse; +import eu.stork.peps.auth.engine.STORKSAMLEngine; +import eu.stork.peps.exceptions.STORKSAMLEngineException; + +/** + * Validates the SAML response from C-PEPS. + *

+ * In detail: + *

    + *
  • Decodes and validates SAML response from C-PEPS.
  • + *
  • Retrieves the moa session using the session id provided by HttpServletRequest parameter {@code RelayState} or by {@code inResponseTo} attribute of the saml response.
  • + *
  • Store saml response in moa session.
  • + *
  • Change moa session id.
  • + *
  • Redirect to {@code /PEPSConnectorWithLocalSigning}, with providing the moa session id as request parameter.
  • + *
+ * Expects: + *
    + *
  • HttpServletRequest parameter {@code moaSessionID} to be {@code null}
  • + *
  • HttpServletRequest parameter {@code signresponse} to be {@code null}
  • + *
  • HttpServletRequest parameter {@code SAMLResponse}
  • + *
  • Either HttpServletRequest parameter {@code RelayState} or {@code inResponseTo} attribute within the saml response, both reflecting the moa session id.
  • + *
+ * Result: + *
    + *
  • Updated moa session (with saml response).
  • + *
  • Redirect to {@code /PEPSConnectorWithLocalSigning}, with providing the moa session id as request parameter.
  • + *
+ * Code taken from {@link at.gv.egovernment.moa.id.auth.servlet.PEPSConnectorWithLocalSigningServlet}.
+ * + * @see #execute(ExecutionContext, HttpServletRequest, HttpServletResponse) + */ +public class PepsConnectorHandleResponseWithoutSignatureTask extends AbstractPepsConnectorWithLocalSigningTask { + + private String oasisDssWebFormURL = "https://testvidp.buergerkarte.at/oasis-dss/DSSWebFormServlet"; + // load from config below + + @Override + public void execute(ExecutionContext executionContext, HttpServletRequest request, HttpServletResponse response) + throws Exception { + String moaSessionID = request.getParameter("moaSessionID"); + String signResponse = request.getParameter("signresponse"); + Logger.info("moaSessionID:" + moaSessionID); + Logger.info("signResponse:" + signResponse); + + if (moaSessionID == null && signResponse == null) { + // normal saml response + handleSAMLResponse(executionContext, request, response); + + } else { + // should not occur + throw new IOException("should not occur"); + } + return; + } + + private void handleSAMLResponse(ExecutionContext executionContext, HttpServletRequest request, + HttpServletResponse response) { + Logger.info("handleSAMLResponse started"); + String pendingRequestID = null; + + setNoCachingHeaders(response); + try { + Logger.info("PEPSConnector Servlet invoked, expecting C-PEPS message."); + Logger.debug("This ACS endpoint is: " + HTTPUtils.getBaseURL(request)); + + Logger.trace("No Caching headers set for HTTP response"); + + // check if https or only http + super.checkIfHTTPisAllowed(request.getRequestURL().toString()); + + Logger.debug("Beginning to extract SAMLResponse out of HTTP Request"); + + // extract STORK Response from HTTP Request + // Decodes SAML Response + byte[] decSamlToken; + try { + decSamlToken = PEPSUtil.decodeSAMLToken(request.getParameter("SAMLResponse")); + Logger.debug("SAMLResponse: " + new String(decSamlToken)); + + } catch (NullPointerException e) { + Logger.error("Unable to retrieve STORK Response", e); + throw new MOAIDException("stork.04", null); + } + + // Get SAMLEngine instance + STORKSAMLEngine engine = STORKSAMLEngine.getInstance("outgoing"); + + STORKAuthnResponse authnResponse = null; + try { + // validate SAML Token + Logger.debug("Starting validation of SAML response"); + authnResponse = engine.validateSTORKAuthnResponse(decSamlToken, (String) request.getRemoteHost()); + Logger.info("SAML response succesfully verified!"); + } catch (STORKSAMLEngineException e) { + Logger.error("Failed to verify STORK SAML Response", e); + throw new MOAIDException("stork.05", null); + } + + Logger.info("STORK SAML Response message succesfully extracted"); + Logger.debug("STORK response: "); + Logger.debug(authnResponse.toString()); + + Logger.debug("Trying to find MOA Session-ID ..."); + // String moaSessionID = request.getParameter(PARAM_SESSIONID); + // first use SAML2 relayState + String moaSessionID = request.getParameter("RelayState"); + + // escape parameter strings + moaSessionID = StringEscapeUtils.escapeHtml(moaSessionID); + + // check if SAML2 relaystate includes a MOA sessionID + if (StringUtils.isEmpty(moaSessionID)) { + // if relaystate is emtpty, use SAML response -> inResponseTo element as session identifier + + moaSessionID = authnResponse.getInResponseTo(); + moaSessionID = StringEscapeUtils.escapeHtml(moaSessionID); + + if (StringUtils.isEmpty(moaSessionID)) { + // No authentication session has been started before + Logger.error("MOA-SessionID was not found, no previous AuthnRequest had been started"); + Logger.debug("PEPSConnectorURL was: " + request.getRequestURL()); + throw new AuthenticationException("auth.02", new Object[] { moaSessionID }); + + } else + Logger.trace("Use MOA SessionID " + moaSessionID + " from AuthnResponse->inResponseTo attribute."); + + } else + // Logger.trace("MOA SessionID " + moaSessionID + " is found in http GET parameter."); + Logger.trace("MOA SessionID " + moaSessionID + " is found in SAML2 relayState."); + + /* + * INFO!!!! SAML message IDs has an different format then MOASessionIDs This is only a workaround because + * many PEPS does not support SAML2 relayState or MOASessionID as AttributConsumerServiceURL GET parameter + */ + // if (!ParamValidatorUtils.isValidSessionID(moaSessionID)) + // throw new WrongParametersException("VerifyAuthenticationBlock", PARAM_SESSIONID, "auth.12"); + + pendingRequestID = AuthenticationSessionStoreage.getPendingRequestID(moaSessionID); + + // load MOASession from database + AuthenticationSession moaSession = AuthenticationServer.getSession(moaSessionID); + // change MOASessionID + moaSessionID = AuthenticationSessionStoreage.changeSessionID(moaSession); + + Logger.info("Found MOA sessionID: " + moaSessionID); + + String statusCodeValue = authnResponse.getStatusCode(); + + if (!statusCodeValue.equals(StatusCode.SUCCESS_URI)) { + Logger.error("Received ErrorResponse from PEPS: " + statusCodeValue); + throw new MOAIDException("stork.06", new Object[] { statusCodeValue }); + } + + Logger.info("Got SAML response with authentication success message."); + + Logger.debug("MOA session is still valid"); + + STORKAuthnRequest storkAuthnRequest = moaSession.getStorkAuthnRequest(); + + if (storkAuthnRequest == null) { + Logger.error("Could not find any preceeding STORK AuthnRequest to this MOA session: " + moaSessionID); + throw new MOAIDException("stork.07", null); + } + + Logger.debug("Found a preceeding STORK AuthnRequest to this MOA session: " + moaSessionID); + + // //////////// incorporate gender from parameters if not in stork response + + IPersonalAttributeList attributeList = authnResponse.getPersonalAttributeList(); + + // but first, check if we have a representation case + if (STORKResponseProcessor.hasAttribute("mandateContent", attributeList) + || STORKResponseProcessor.hasAttribute("representative", attributeList) + || STORKResponseProcessor.hasAttribute("represented", attributeList)) { + // in a representation case... + moaSession.setUseMandate("true"); + + // and check if we have the gender value + PersonalAttribute gender = attributeList.get("gender"); + if (null == gender) { + String gendervalue = (String) request.getParameter("gender"); + if (null != gendervalue) { + gender = new PersonalAttribute(); + gender.setName("gender"); + ArrayList tmp = new ArrayList(); + tmp.add(gendervalue); + gender.setValue(tmp); + + authnResponse.getPersonalAttributeList().add(gender); + } + } + } + + + + // //////////////////////////////////////////////////////////////////////// + + Logger.debug("Starting extraction of signedDoc attribute"); + // extract signed doc element and citizen signature + String citizenSignature = null; + try { + PersonalAttribute signedDoc = authnResponse.getPersonalAttributeList().get("signedDoc"); + String signatureInfo = null; + // FIXME: Remove nonsense code (signedDoc attribute... (throw Exception for "should not occur" situations)), adjust error messages in order to reflect the true problem... + if (signedDoc != null) { + signatureInfo = signedDoc.getValue().get(0); + // should not occur + } else { + + // store SAMLResponse + moaSession.setSAMLResponse(request.getParameter("SAMLResponse")); + // store authnResponse + + // moaSession.setAuthnResponse(authnResponse);//not serializable + moaSession.setAuthnResponseGetPersonalAttributeList(authnResponse.getPersonalAttributeList()); + + String authnContextClassRef = null; + try { + authnContextClassRef = authnResponse.getAssertions().get(0).getAuthnStatements().get(0) + .getAuthnContext().getAuthnContextClassRef().getAuthnContextClassRef(); + } catch (Throwable e) { + Logger.warn("STORK QAA-Level is not found in AuthnResponse. Set QAA Level to requested level"); + } + + moaSession.setAuthnContextClassRef(authnContextClassRef); + moaSession.setReturnURL(request.getRequestURL()); + + // load signedDoc + String signRequest = moaSession.getSignedDoc(); + + // session is implicit stored in changeSessionID!!!! + String newMOASessionID = AuthenticationSessionStoreage.changeSessionID(moaSession); + + // set return url to PEPSConnectorWithLocalSigningServlet and add newMOASessionID + // signRequest + + String issuerValue = AuthConfigurationProvider.getInstance().getPublicURLPrefix(); + String acsURL = issuerValue + + PEPSConnectorWithLocalSigningServlet.PEPSCONNECTOR_SERVLET_URL_PATTERN; + + String url = acsURL + "?moaSessionID=" + newMOASessionID; + // redirect to OASIS module and sign there + + boolean found = false; + try { + List aps = AuthConfigurationProvider.getInstance() + .getOnlineApplicationParameter(moaSession.getPublicOAURLPrefix()).getStorkAPs(); + Logger.info("Found AttributeProviderPlugins:" + aps.size()); + for (AttributeProviderPlugin ap : aps) { + Logger.info("Found AttributeProviderPlugin attribute:" + ap.getAttributes()); + if (ap.getAttributes().equalsIgnoreCase("signedDoc")) { + // FIXME: A servlet's class field is not thread safe!!! + oasisDssWebFormURL = ap.getUrl(); + found = true; + Logger.info("Loaded signedDoc attribute provider url from config:" + oasisDssWebFormURL); + break; + } + } + } catch (Exception e) { + e.printStackTrace(); + Logger.error("Loading the signedDoc attribute provider url from config failed"); + } + if (!found) { + Logger.error("Failed to load the signedDoc attribute provider url from config"); + } + performRedirect(url, request, response, signRequest); + + return; + } + + // FIXME: This servlet/task is intended to handle peps responses without signature, so why do we try to process that signature here? + SignResponse dssSignResponse = (SignResponse) ApiUtils.unmarshal(new StreamSource( + new java.io.StringReader(signatureInfo))); + + citizenSignature = getCitizienSignatureFromSignResponse(dssSignResponse); + + // memorize signature into authblock + moaSession.setAuthBlock(citizenSignature); + + X509Certificate cert = getSignerCertificate(citizenSignature); + moaSession.setSignerCertificate(cert); + moaSession.setForeigner(true); + + } catch (Throwable e) { + Logger.error("Could not extract citizen signature from C-PEPS", e); + throw new MOAIDException("stork.09", null); + } + + // FIXME: Same here; we do not have the citizen's signature, so this code might be regarded as dead code. + try { + SZRGInsertion(moaSession, authnResponse.getPersonalAttributeList(), authnResponse.getAssertions() + .get(0).getAuthnStatements().get(0).getAuthnContext().getAuthnContextClassRef() + .getAuthnContextClassRef(), citizenSignature); + } catch (STORKException e) { + // this is really nasty but we work against the system here. We are supposed to get the gender attribute + // from + // stork. If we do not, we cannot register the person in the ERnP - we have to have the + // gender for the represented person. So here comes the dirty hack. + if (e.getCause() instanceof STORKException + && e.getCause().getMessage().equals("gender not found in response")) { + try { + Logger.trace("Initialize VelocityEngine..."); + + VelocityEngine velocityEngine = VelocityProvider.getClassPathVelocityEngine(); + Template template = velocityEngine.getTemplate("/resources/templates/fetchGender.html"); + VelocityContext context = new VelocityContext(); + context.put("SAMLResponse", request.getParameter("SAMLResponse")); + context.put("action", request.getRequestURL()); + + StringWriter writer = new StringWriter(); + template.merge(context, writer); + + response.getOutputStream().write(writer.toString().getBytes("UTF-8")); + } catch (Exception e1) { + Logger.error("Error sending gender retrival form.", e1); + // httpSession.invalidate(); + throw new MOAIDException("stork.10", null); + } + + return; + } + + Logger.error("Error connecting SZR Gateway", e); + throw new MOAIDException("stork.10", null); + } + + Logger.debug("Add full STORK AuthnResponse to MOA session"); + moaSession.setStorkAuthnResponse(request.getParameter("SAMLResponse"));// TODO ask Florian/Thomas + // authnResponse? + + // session is implicit stored in changeSessionID!!!! + String newMOASessionID = AuthenticationSessionStoreage.changeSessionID(moaSession); + + Logger.info("Changed MOASession " + moaSessionID + " to Session " + newMOASessionID); + + // redirect + String redirectURL = null; + redirectURL = new DataURLBuilder().buildDataURL(moaSession.getAuthURL(), + ModulUtils.buildAuthURL(moaSession.getModul(), moaSession.getAction(), pendingRequestID), + newMOASessionID); + redirectURL = response.encodeRedirectURL(redirectURL); + + response.setContentType("text/html"); + response.setStatus(302); + response.addHeader("Location", redirectURL); + Logger.info("REDIRECT TO: " + redirectURL); + + } catch (AuthenticationException e) { + handleError(null, e, request, response, pendingRequestID); + + } catch (MOAIDException e) { + handleError(null, e, request, response, pendingRequestID); + + } catch (Exception e) { + Logger.error("PEPSConnector has an interal Error.", e); + } + + finally { + ConfigurationDBUtils.closeSession(); + } + + } + + private void performRedirect(String url, HttpServletRequest req, HttpServletResponse resp, String signRequestString) + throws MOAIDException { + + try { + Logger.trace("Initialize VelocityEngine..."); + + VelocityEngine velocityEngine = VelocityProvider.getClassPathVelocityEngine(); + Template template = velocityEngine.getTemplate("/resources/templates/oasis_dss_webform_binding.vm"); + VelocityContext context = new VelocityContext(); + + Logger.debug("performRedirect, signrequest:" + signRequestString); + Source signDoc = new StreamSource(new java.io.StringReader(signRequestString)); + SignRequest signRequest = ApiUtils.unmarshal(signDoc, SignRequest.class); + signRequest.setReturnURL("TODO"); + signRequestString = IOUtils.toString(ApiUtils.marshalToInputStream(signRequest)); + context.put("signrequest", Base64.encodeBase64String(signRequestString.getBytes("UTF8"))); + context.put("clienturl", url); + context.put("action", oasisDssWebFormURL); + + StringWriter writer = new StringWriter(); + template.merge(context, writer); + + resp.getOutputStream().write(writer.toString().getBytes("UTF-8")); + } catch (Exception e) { + Logger.error("Error sending DSS signrequest.", e); + throw new MOAIDException("stork.11", null); + } + } +} diff --git a/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/tasks/PepsConnectorTask.java b/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/tasks/PepsConnectorTask.java new file mode 100644 index 000000000..94017e9f6 --- /dev/null +++ b/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/tasks/PepsConnectorTask.java @@ -0,0 +1,566 @@ +package at.gv.egovernment.moa.id.auth.modules.stork.tasks; + +import iaik.x509.X509Certificate; + +import java.io.IOException; +import java.io.InputStream; +import java.io.StringWriter; +import java.net.URL; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Properties; + +import javax.activation.DataSource; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.xml.bind.JAXBContext; +import javax.xml.bind.JAXBElement; +import javax.xml.namespace.QName; +import javax.xml.transform.stream.StreamSource; +import javax.xml.ws.BindingProvider; +import javax.xml.ws.Service; +import javax.xml.ws.soap.SOAPBinding; + +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang.StringEscapeUtils; +import org.apache.velocity.Template; +import org.apache.velocity.VelocityContext; +import org.apache.velocity.app.VelocityEngine; +import org.opensaml.saml2.core.StatusCode; + +import at.gv.egovernment.moa.id.auth.AuthenticationServer; +import at.gv.egovernment.moa.id.auth.builder.DataURLBuilder; +import at.gv.egovernment.moa.id.auth.data.AuthenticationSession; +import at.gv.egovernment.moa.id.auth.data.IdentityLink; +import at.gv.egovernment.moa.id.auth.exception.AuthenticationException; +import at.gv.egovernment.moa.id.auth.exception.MOAIDException; +import at.gv.egovernment.moa.id.auth.modules.AbstractAuthServletTask; +import at.gv.egovernment.moa.id.auth.stork.STORKException; +import at.gv.egovernment.moa.id.auth.stork.STORKResponseProcessor; +import at.gv.egovernment.moa.id.commons.db.ConfigurationDBUtils; +import at.gv.egovernment.moa.id.config.auth.AuthConfigurationProvider; +import at.gv.egovernment.moa.id.config.auth.OAAuthParameter; +import at.gv.egovernment.moa.id.moduls.ModulUtils; +import at.gv.egovernment.moa.id.process.api.ExecutionContext; +import at.gv.egovernment.moa.id.protocols.pvp2x.PVPConstants; +import at.gv.egovernment.moa.id.storage.AuthenticationSessionStoreage; +import at.gv.egovernment.moa.id.util.HTTPUtils; +import at.gv.egovernment.moa.id.util.VelocityProvider; +import at.gv.egovernment.moa.logging.Logger; +import at.gv.egovernment.moa.util.StringUtils; +import at.gv.util.xsd.xmldsig.SignatureType; +import at.gv.util.xsd.xmldsig.X509DataType; +import eu.stork.documentservice.DocumentService; +import eu.stork.documentservice.data.DatabaseConnectorMySQLImpl; +import eu.stork.oasisdss.api.ApiUtils; +import eu.stork.oasisdss.api.LightweightSourceResolver; +import eu.stork.oasisdss.api.exceptions.ApiUtilsException; +import eu.stork.oasisdss.profile.DocumentType; +import eu.stork.oasisdss.profile.DocumentWithSignature; +import eu.stork.oasisdss.profile.SignResponse; +import eu.stork.peps.auth.commons.IPersonalAttributeList; +import eu.stork.peps.auth.commons.PEPSUtil; +import eu.stork.peps.auth.commons.PersonalAttribute; +import eu.stork.peps.auth.commons.PersonalAttributeList; +import eu.stork.peps.auth.commons.STORKAttrQueryRequest; +import eu.stork.peps.auth.commons.STORKAuthnRequest; +import eu.stork.peps.auth.commons.STORKAuthnResponse; +import eu.stork.peps.auth.engine.STORKSAMLEngine; +import eu.stork.peps.exceptions.STORKSAMLEngineException; + +/** + * Evaluates the SAML response from the C-PEPS and authenticates the user. + *

+ * In detail: + *

    + *
  • Decodes and validates the SAML response from the C-PEPS.
  • + *
  • Change moa session id.
  • + *
  • Extracts the subject's gender from request parameter {@code gender} if not available from the saml response.
  • + *
  • Extracts the {@code signedDoc} attribute from the response, get signed doc payload using stork attribute query request.
  • + *
  • Request SZR gateway for verification of the citizen's signature and for creating of an identity link.
  • + *
  • In case of mandate mode: If the S-PEPS did not provide any gender information, the szr gateway will not be able to issue an identity link. Therefore a form is presented asking for the subject's gender. The form submits the user back to the {@code /PepsConnector} servlet (this task).
  • + *
  • The moa session is updated with authentication information.
  • + *
  • Change moa session id.
  • + *
  • Redirects back to {@code /dispatcher} in order to finalize the authentication.
  • + *
+ * Expects: + *
    + *
  • HttpServletRequest parameter {@code SAMLResponse}
  • + *
  • Either HttpServletRequest parameter {@code RelayState} or {@code inResponseTo} attribute from the SAML response (both depicting the moa session id)
  • + *
  • HttpServletRequest parameter {@code gender} in case the request comes from the gender selection form
  • + *
  • {@code signedDoc} attribute within the SAML response.
  • + *
+ * Result: + *
    + *
  • Updated moa id session (identity link, stork attributes...)
  • + *
  • {@link ExecutionContext} contains boolean flag {@code identityLinkAvailable} indicating if an identitylink has been successfully creates or not.
  • + *
  • Redirect to {@code /dispatcher}.
  • + *
+ * Possible branches: + *
    + *
  • In case the szr gateway throws exception due to missing gender information: + *
      + *
    • Returns a form for gender selection with action url back to this servlet/task.
    • + *
    + *
  • + *
+ * Code taken from {@link at.gv.egovernment.moa.id.auth.servlet.PEPSConnectorServlet}.
+ * + * @see #execute(ExecutionContext, HttpServletRequest, HttpServletResponse) + */ +public class PepsConnectorTask extends AbstractAuthServletTask { + + private String dtlUrl = null; + + public PepsConnectorTask() { + super(); + Properties props = new Properties(); + try { + props.load(DatabaseConnectorMySQLImpl.class.getResourceAsStream("docservice.properties")); + dtlUrl = props.getProperty("docservice.url"); + } catch (IOException e) { + dtlUrl = "http://testvidp.buergerkarte.at/DocumentService/DocumentService"; + Logger.error("Loading DTL config failed, using default value:" + dtlUrl); + e.printStackTrace(); + } + } + + @Override + public void execute(ExecutionContext executionContext, HttpServletRequest request, HttpServletResponse response) + throws Exception { + String pendingRequestID = null; + + setNoCachingHeaders(response); + + try { + + Logger.info("PEPSConnector Servlet invoked, expecting C-PEPS message."); + Logger.debug("This ACS endpoint is: " + HTTPUtils.getBaseURL(request)); + + // check if https or only http + super.checkIfHTTPisAllowed(request.getRequestURL().toString()); + + Logger.debug("Beginning to extract SAMLResponse out of HTTP Request"); + + // extract STORK Response from HTTP Request + // Decodes SAML Response + byte[] decSamlToken; + try { + decSamlToken = PEPSUtil.decodeSAMLToken(request.getParameter("SAMLResponse")); + Logger.debug("SAMLResponse: " + new String(decSamlToken)); + + } catch (NullPointerException e) { + Logger.error("Unable to retrieve STORK Response", e); + throw new MOAIDException("stork.04", null); + } + + // Get SAMLEngine instance + STORKSAMLEngine engine = STORKSAMLEngine.getInstance("outgoing"); + + STORKAuthnResponse authnResponse = null; + try { + // validate SAML Token + Logger.debug("Starting validation of SAML response"); + authnResponse = engine.validateSTORKAuthnResponse(decSamlToken, (String) request.getRemoteHost()); + Logger.info("SAML response succesfully verified!"); + } catch (STORKSAMLEngineException e) { + Logger.error("Failed to verify STORK SAML Response", e); + throw new MOAIDException("stork.05", null); + } + + Logger.info("STORK SAML Response message succesfully extracted"); + Logger.debug("STORK response: "); + Logger.debug(authnResponse.toString()); + + Logger.debug("Trying to find MOA Session-ID ..."); + // String moaSessionID = request.getParameter(PARAM_SESSIONID); + // first use SAML2 relayState + String moaSessionID = request.getParameter("RelayState"); + + // escape parameter strings + moaSessionID = StringEscapeUtils.escapeHtml(moaSessionID); + + // check if SAML2 relaystate includes a MOA sessionID + if (StringUtils.isEmpty(moaSessionID)) { + // if relaystate is emtpty, use SAML response -> inResponseTo element as session identifier + + moaSessionID = authnResponse.getInResponseTo(); + moaSessionID = StringEscapeUtils.escapeHtml(moaSessionID); + + if (StringUtils.isEmpty(moaSessionID)) { + // No authentication session has been started before + Logger.error("MOA-SessionID was not found, no previous AuthnRequest had been started"); + Logger.debug("PEPSConnectorURL was: " + request.getRequestURL()); + throw new AuthenticationException("auth.02", new Object[] { moaSessionID }); + + } else + Logger.trace("Use MOA SessionID " + moaSessionID + " from AuthnResponse->inResponseTo attribute."); + + } else + // Logger.trace("MOA SessionID " + moaSessionID + " is found in http GET parameter."); + Logger.trace("MOA SessionID " + moaSessionID + " is found in SAML2 relayState."); + + /* + * INFO!!!! SAML message IDs has an different format then MOASessionIDs This is only a workaround because + * many PEPS does not support SAML2 relayState or MOASessionID as AttributConsumerServiceURL GET parameter + */ + // if (!ParamValidatorUtils.isValidSessionID(moaSessionID)) + // throw new WrongParametersException("VerifyAuthenticationBlock", PARAM_SESSIONID, "auth.12"); + + pendingRequestID = AuthenticationSessionStoreage.getPendingRequestID(moaSessionID); + + // load MOASession from database + AuthenticationSession moaSession = AuthenticationServer.getSession(moaSessionID); + // change MOASessionID + moaSessionID = AuthenticationSessionStoreage.changeSessionID(moaSession); + + Logger.info("Found MOA sessionID: " + moaSessionID); + + String statusCodeValue = authnResponse.getStatusCode(); + + if (!statusCodeValue.equals(StatusCode.SUCCESS_URI)) { + Logger.error("Received ErrorResponse from PEPS: " + statusCodeValue); + throw new MOAIDException("stork.06", new Object[] { statusCodeValue }); + } + + Logger.info("Got SAML response with authentication success message."); + + Logger.debug("MOA session is still valid"); + + STORKAuthnRequest storkAuthnRequest = moaSession.getStorkAuthnRequest(); + + if (storkAuthnRequest == null) { + Logger.error("Could not find any preceeding STORK AuthnRequest to this MOA session: " + moaSessionID); + throw new MOAIDException("stork.07", null); + } + + Logger.debug("Found a preceeding STORK AuthnRequest to this MOA session: " + moaSessionID); + + // //////////// incorporate gender from parameters if not in stork response + + IPersonalAttributeList attributeList = authnResponse.getPersonalAttributeList(); + + // but first, check if we have a representation case + if (STORKResponseProcessor.hasAttribute("mandateContent", attributeList) + || STORKResponseProcessor.hasAttribute("representative", attributeList) + || STORKResponseProcessor.hasAttribute("represented", attributeList)) { + // in a representation case... + moaSession.setUseMandate("true"); + + // and check if we have the gender value + PersonalAttribute gender = attributeList.get("gender"); // TODO Do we need to check gender value if + // there is no representation case? + if (null == gender) { + String gendervalue = (String) request.getParameter("gender"); + if (null != gendervalue) { + gender = new PersonalAttribute(); + gender.setName("gender"); + ArrayList tmp = new ArrayList(); + tmp.add(gendervalue); + gender.setValue(tmp); + + authnResponse.getPersonalAttributeList().add(gender); + } + } + } + + // //////////////////////////////////////////////////////////////////////// + + Logger.debug("Starting extraction of signedDoc attribute"); + // extract signed doc element and citizen signature + String citizenSignature = null; + try { + String signatureInfo = authnResponse.getPersonalAttributeList().get("signedDoc").getValue().get(0); // TODO ERROR HANDLING + + Logger.debug("signatureInfo:" + signatureInfo); + + SignResponse dssSignResponse = (SignResponse) ApiUtils.unmarshal(new StreamSource( + new java.io.StringReader(signatureInfo))); + + // fetch signed doc + DataSource ds = LightweightSourceResolver.getDataSource(dssSignResponse); + if (ds == null) { + throw new ApiUtilsException("No datasource found in response"); + } + + InputStream incoming = ds.getInputStream(); + citizenSignature = IOUtils.toString(incoming); + incoming.close(); + + Logger.debug("citizenSignature:" + citizenSignature); + if (isDocumentServiceUsed(citizenSignature) == true) { + Logger.debug("Loading document from DocumentService."); + String url = getDtlUrlFromResponse(dssSignResponse); + // get Transferrequest + String transferRequest = getDocTransferRequest(dssSignResponse.getDocUI(), url); + // Load document from DocujmentService + byte[] data = getDocumentFromDtl(transferRequest, url); + citizenSignature = new String(data, "UTF-8"); + Logger.debug("Overridung citizenSignature with:" + citizenSignature); + } + + JAXBContext ctx = JAXBContext.newInstance(SignatureType.class.getPackage().getName()); + SignatureType root = ((JAXBElement) ctx.createUnmarshaller().unmarshal( + IOUtils.toInputStream(citizenSignature))).getValue(); + + // memorize signature into authblock + moaSession.setAuthBlock(citizenSignature); + + // extract certificate + for (Object current : root.getKeyInfo().getContent()) + if (((JAXBElement) current).getValue() instanceof X509DataType) { + for (Object currentX509Data : ((JAXBElement) current).getValue() + .getX509IssuerSerialOrX509SKIOrX509SubjectName()) { + JAXBElement casted = ((JAXBElement) currentX509Data); + if (casted.getName().getLocalPart().equals("X509Certificate")) { + moaSession.setSignerCertificate(new X509Certificate(((String) casted.getValue()) + .getBytes("UTF-8"))); + break; + } + } + } + + } catch (Throwable e) { + Logger.error("Could not extract citizen signature from C-PEPS", e); + throw new MOAIDException("stork.09", null); + } + Logger.debug("Foregin Citizen signature successfully extracted from STORK Assertion (signedDoc)"); + Logger.debug("Citizen signature will be verified by SZR Gateway!"); + + Logger.debug("fetching OAParameters from database"); + + // //read configuration paramters of OA + // AuthenticationSession moasession; + // try { + // moasession = AuthenticationSessionStoreage.getSession(moaSessionID); + // } catch (MOADatabaseException e2) { + // Logger.error("could not retrieve moa session"); + // throw new AuthenticationException("auth.01", null); + // } + OAAuthParameter oaParam = AuthConfigurationProvider.getInstance().getOnlineApplicationParameter( + moaSession.getPublicOAURLPrefix()); + if (oaParam == null) + throw new AuthenticationException("auth.00", new Object[] { moaSession.getPublicOAURLPrefix() }); + + // retrieve target + // TODO: check in case of SSO!!! + String targetType = null; + if (oaParam.getBusinessService()) { + String id = oaParam.getIdentityLinkDomainIdentifier(); + if (id.startsWith(AuthenticationSession.REGISTERANDORDNR_PREFIX_)) + targetType = id; + else + targetType = AuthenticationSession.REGISTERANDORDNR_PREFIX_ + moaSession.getDomainIdentifier(); + } else { + targetType = AuthenticationSession.TARGET_PREFIX_ + oaParam.getTarget(); + } + + Logger.debug("Starting connecting SZR Gateway"); + // contact SZR Gateway + IdentityLink identityLink = null; + executionContext.put("identityLinkAvailable", false); + try { + identityLink = STORKResponseProcessor.connectToSZRGateway(authnResponse.getPersonalAttributeList(), + oaParam.getFriendlyName(), targetType, null, oaParam.getMandateProfiles(), citizenSignature); + } catch (STORKException e) { + // this is really nasty but we work against the system here. We are supposed to get the gender attribute + // from + // stork. If we do not, we cannot register the person in the ERnP - we have to have the + // gender for the represented person. So here comes the dirty hack. + if (e.getCause() instanceof STORKException + && e.getCause().getMessage().equals("gender not found in response")) { + try { + Logger.trace("Initialize VelocityEngine..."); + + VelocityEngine velocityEngine = VelocityProvider.getClassPathVelocityEngine(); + Template template = velocityEngine.getTemplate("/resources/templates/fetchGender.html"); + VelocityContext context = new VelocityContext(); + context.put("SAMLResponse", request.getParameter("SAMLResponse")); + context.put("action", request.getRequestURL()); + + StringWriter writer = new StringWriter(); + template.merge(context, writer); + + response.getOutputStream().write(writer.toString().getBytes("UTF-8")); + } catch (Exception e1) { + Logger.error("Error sending gender retrival form.", e1); + // httpSession.invalidate(); + throw new MOAIDException("stork.10", null); + } + + return; + } + + Logger.error("Error connecting SZR Gateway", e); + throw new MOAIDException("stork.10", null); + } + Logger.debug("SZR communication was successfull"); + + if (identityLink == null) { + Logger.error("SZR Gateway did not return an identity link."); + throw new MOAIDException("stork.10", null); + } + moaSession.setForeigner(true); + + Logger.info("Received Identity Link from SZR Gateway"); + executionContext.put("identityLinkAvailable", true); + moaSession.setIdentityLink(identityLink); + + Logger.debug("Adding addtional STORK attributes to MOA session"); + moaSession.setStorkAttributes(authnResponse.getPersonalAttributeList()); + + Logger.debug("Add full STORK AuthnResponse to MOA session"); + moaSession.setStorkAuthnResponse(request.getParameter("SAMLResponse")); + + // We don't have BKUURL, setting from null to "Not applicable" + moaSession.setBkuURL("Not applicable (STORK Authentication)"); + + // free for single use + moaSession.setAuthenticatedUsed(false); + + // stork did the authentication step + moaSession.setAuthenticated(true); + + // TODO: found better solution, but QAA Level in response could be not supported yet + try { + + moaSession.setQAALevel(authnResponse.getAssertions().get(0).getAuthnStatements().get(0) + .getAuthnContext().getAuthnContextClassRef().getAuthnContextClassRef()); + + } catch (Throwable e) { + Logger.warn("STORK QAA-Level is not found in AuthnResponse. Set QAA Level to requested level"); + moaSession.setQAALevel(PVPConstants.STORK_QAA_PREFIX + oaParam.getQaaLevel()); + + } + + // session is implicit stored in changeSessionID!!!! + String newMOASessionID = AuthenticationSessionStoreage.changeSessionID(moaSession); + + Logger.info("Changed MOASession " + moaSessionID + " to Session " + newMOASessionID); + + // redirect + String redirectURL = null; + redirectURL = new DataURLBuilder().buildDataURL(moaSession.getAuthURL(), + ModulUtils.buildAuthURL(moaSession.getModul(), moaSession.getAction(), pendingRequestID), + newMOASessionID); + redirectURL = response.encodeRedirectURL(redirectURL); + + // response.setContentType("text/html"); + // response.setStatus(302); + // response.addHeader("Location", redirectURL); + response.sendRedirect(redirectURL); + Logger.info("REDIRECT TO: " + redirectURL); + + } catch (AuthenticationException e) { + handleError(null, e, request, response, pendingRequestID); + + } catch (MOAIDException e) { + handleError(null, e, request, response, pendingRequestID); + + } catch (Exception e) { + Logger.error("PEPSConnector has an interal Error.", e); + } + + finally { + ConfigurationDBUtils.closeSession(); + } + + } + + private boolean isDocumentServiceUsed(String citizenSignature) // TODo add better check + { + if (citizenSignature + .contains("
Service Name:{http://stork.eu}DocumentService
Port Name:{http://stork.eu}DocumentServicePort
")) + return true; + return false; + } + + /** + * Get DTL uril from the oasis sign response + * + * @param signRequest + * The signature response + * @return The URL of DTL service + * @throws SimpleException + */ + private String getDtlUrlFromResponse(SignResponse dssSignResponse) { + List documents = ApiUtils.findNamedElement(dssSignResponse.getOptionalOutputs(), + ApiUtils.OPTIONAL_OUTPUT_DOCUMENTWITHSIGNATURE, DocumentWithSignature.class); + DocumentType sourceDocument = documents.get(0).getDocument(); + + if (sourceDocument.getDocumentURL() != null) + return sourceDocument.getDocumentURL(); + else + return null;// throw new Exception("No document url found"); + } + + // From DTLPEPSUTIL + + /** + * Get document from DTL + * + * @param transferRequest + * The transfer request (attribute query) + * @param eDtlUrl + * The DTL url of external DTL + * @return the document data + * @throws SimpleException + */ + private byte[] getDocumentFromDtl(String transferRequest, String eDtlUrl) throws Exception { + URL url = null; + try { + url = new URL(dtlUrl); + QName qname = new QName("http://stork.eu", "DocumentService"); + + Service service = Service.create(url, qname); + DocumentService docservice = service.getPort(DocumentService.class); + + BindingProvider bp = (BindingProvider) docservice; + SOAPBinding binding = (SOAPBinding) bp.getBinding(); + binding.setMTOMEnabled(true); + + if (eDtlUrl.equalsIgnoreCase(dtlUrl)) + return docservice.getDocument(transferRequest, ""); + else + return docservice.getDocument(transferRequest, eDtlUrl); + } catch (Exception e) { + e.printStackTrace(); + throw new Exception("Error in getDocumentFromDtl", e); + } + } + + /** + * Get a document transfer request (attribute query) + * + * @param docId + * @return + * @throws SimpleException + */ + private String getDocTransferRequest(String docId, String destinationUrl) throws Exception { + String spCountry = docId.substring(0, docId.indexOf("/")); + final STORKSAMLEngine engine = STORKSAMLEngine.getInstance("VIDP"); + STORKAttrQueryRequest req = new STORKAttrQueryRequest(); + req.setAssertionConsumerServiceURL(dtlUrl); + req.setDestination(destinationUrl); + req.setSpCountry(spCountry); + req.setQaa(3);// TODO + PersonalAttributeList pal = new PersonalAttributeList(); + PersonalAttribute attr = new PersonalAttribute(); + attr.setName("docRequest"); + attr.setIsRequired(true); + attr.setValue(Arrays.asList(docId)); + pal.add(attr); + req.setPersonalAttributeList(pal); + + STORKAttrQueryRequest req1; + try { + req1 = engine.generateSTORKAttrQueryRequest(req); + return PEPSUtil.encodeSAMLTokenUrlSafe(req1.getTokenSaml()); + } catch (STORKSAMLEngineException e) { + e.printStackTrace(); + throw new Exception("Error in doc request attribute query generation", e); + } + } + +} diff --git a/id/server/modules/module-stork/src/main/resources/at/gv/egovernment/moa/id/auth/modules/stork/STORK.authmodule.beans.xml b/id/server/modules/module-stork/src/main/resources/at/gv/egovernment/moa/id/auth/modules/stork/STORK.authmodule.beans.xml new file mode 100644 index 000000000..2e924bdd0 --- /dev/null +++ b/id/server/modules/module-stork/src/main/resources/at/gv/egovernment/moa/id/auth/modules/stork/STORK.authmodule.beans.xml @@ -0,0 +1,14 @@ + + + + + + + + + + diff --git a/id/server/modules/module-stork/src/main/resources/at/gv/egovernment/moa/id/auth/modules/stork/STORKAuthentication.process.xml b/id/server/modules/module-stork/src/main/resources/at/gv/egovernment/moa/id/auth/modules/stork/STORKAuthentication.process.xml new file mode 100644 index 000000000..60989e638 --- /dev/null +++ b/id/server/modules/module-stork/src/main/resources/at/gv/egovernment/moa/id/auth/modules/stork/STORKAuthentication.process.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + -- cgit v1.2.3 From a9dc7e094a8732f9826ab77648758dd39adc7324 Mon Sep 17 00:00:00 2001 From: Thomas Knall Date: Wed, 4 Feb 2015 13:54:32 +0100 Subject: Add logging for automatic servlet registration. --- .../modules/stork/STORKWebApplicationInitializer.java | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) (limited to 'id/server/modules/module-stork/src/main') diff --git a/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/STORKWebApplicationInitializer.java b/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/STORKWebApplicationInitializer.java index 7478a57c3..c54c9a26d 100644 --- a/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/STORKWebApplicationInitializer.java +++ b/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/STORKWebApplicationInitializer.java @@ -4,6 +4,8 @@ import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.ServletRegistration; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.web.WebApplicationInitializer; import at.gv.egovernment.moa.id.auth.servlet.ProcessEngineSignalServlet; @@ -23,15 +25,24 @@ import at.gv.egovernment.moa.id.auth.servlet.ProcessEngineSignalServlet; * @see ProcessEngineSignalServlet */ public class STORKWebApplicationInitializer implements WebApplicationInitializer { + + private Logger log = LoggerFactory.getLogger(getClass()); + + private static final String SIGNAL_SERVLET_NAME = "ProcessEngineSignal"; + + private void addMapping(ServletRegistration servletRegistration, String mapping) { + log.debug("Adding mapping '{}' to servlet '{}' ({}).", mapping, SIGNAL_SERVLET_NAME, servletRegistration.getClassName()); + servletRegistration.addMapping(mapping); + } @Override public void onStartup(ServletContext servletContext) throws ServletException { - ServletRegistration servletRegistration = servletContext.getServletRegistration("ProcessEngineSignal"); + ServletRegistration servletRegistration = servletContext.getServletRegistration(SIGNAL_SERVLET_NAME); if (servletRegistration == null) { - throw new IllegalStateException("Servlet 'ProcessEngineSignal' expected to be registered."); + throw new IllegalStateException("Servlet '" + SIGNAL_SERVLET_NAME + "' expected to be registered (e.g. by web.xml)."); } - servletRegistration.addMapping("/PEPSConnectorWithLocalSigning"); - servletRegistration.addMapping("/PEPSConnector"); + addMapping(servletRegistration, "/PEPSConnectorWithLocalSigning"); + addMapping(servletRegistration, "/PEPSConnector"); } } -- cgit v1.2.3