aboutsummaryrefslogtreecommitdiff
path: root/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/stork/STORKResponseProcessor.java
diff options
context:
space:
mode:
Diffstat (limited to 'id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/stork/STORKResponseProcessor.java')
-rw-r--r--id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/stork/STORKResponseProcessor.java405
1 files changed, 405 insertions, 0 deletions
diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/stork/STORKResponseProcessor.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/stork/STORKResponseProcessor.java
new file mode 100644
index 000000000..c98ca87b9
--- /dev/null
+++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/stork/STORKResponseProcessor.java
@@ -0,0 +1,405 @@
+/**
+ *
+ */
+package at.gv.egovernment.moa.id.auth.stork;
+
+import iaik.x509.X509Certificate;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.util.List;
+import java.util.Vector;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.xml.namespace.QName;
+import javax.xml.transform.TransformerException;
+
+import org.opensaml.common.binding.BasicSAMLMessageContext;
+import org.opensaml.saml2.binding.decoding.HTTPPostDecoder;
+import org.opensaml.saml2.core.Assertion;
+import org.opensaml.saml2.core.Attribute;
+import org.opensaml.saml2.metadata.RequestedAttribute;
+import org.opensaml.saml2.metadata.SurName;
+import org.opensaml.ws.transport.http.HTTPInTransport;
+import org.opensaml.ws.transport.http.HTTPOutTransport;
+import org.opensaml.ws.transport.http.HttpServletRequestAdapter;
+import org.opensaml.ws.transport.http.HttpServletResponseAdapter;
+import org.opensaml.xml.XMLObject;
+import org.opensaml.xml.schema.XSAny;
+import org.opensaml.xml.schema.XSString;
+import org.opensaml.xml.util.Base64;
+import org.opensaml.xml.util.XMLHelper;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+
+import at.gv.egovernment.moa.id.ParseException;
+import at.gv.egovernment.moa.id.auth.AuthenticationServer;
+import at.gv.egovernment.moa.id.auth.data.ExtendedSAMLAttribute;
+import at.gv.egovernment.moa.id.auth.data.ExtendedSAMLAttributeImpl;
+import at.gv.egovernment.moa.id.auth.data.IdentityLink;
+import at.gv.egovernment.moa.id.auth.parser.IdentityLinkAssertionParser;
+import at.gv.egovernment.moa.id.auth.validator.parep.client.szrgw.CreateIdentityLinkResponse;
+import at.gv.egovernment.moa.id.auth.validator.parep.client.szrgw.SZRGWClientException;
+import at.gv.egovernment.moa.logging.Logger;
+import at.gv.egovernment.moa.util.Constants;
+import at.gv.egovernment.moa.util.DOMUtils;
+import at.gv.egovernment.moa.util.DateTimeUtils;
+import at.gv.egovernment.moa.util.StringUtils;
+import eu.stork.mw.messages.saml.STORKResponse;
+import eu.stork.vidp.messages.common.STORKConstants;
+import eu.stork.vidp.messages.util.SAMLUtil;
+import eu.stork.vidp.messages.util.XMLUtil;
+
+/**
+ *
+ * Handles all functionality for the processing of a STORK response
+ * @author bzwattendorfer
+ *
+ */
+public class STORKResponseProcessor {
+
+ /** OASIS DSS Namespace */
+ public static final String OASIS_DSS_NS = "urn:oasis:names:tc:dss:1.0:core:schema";
+
+ /** OASIS DSS Success Message */
+ public static final String OASIS_DSS_SUCCESS_MSG = "urn:oasis:names:tc:dss:1.0:resultmajor:Success";
+
+ /**
+ * Extracts a STORK response from a HTTP message
+ * @param request HttpServletRequest
+ * @param response HttpServletResponse
+ * @return STORK Response
+ * @throws STORKException
+ */
+ public static STORKResponse receiveSTORKRepsonse(HttpServletRequest request, HttpServletResponse response) throws STORKException {
+
+ HTTPInTransport httpInTransport = new HttpServletRequestAdapter(request);
+ HTTPOutTransport httpOutTransport = new HttpServletResponseAdapter(response, request.isSecure());
+
+ httpInTransport.getPeerAddress();
+
+ String samlResponseString = request.getParameter("SAMLResponse");
+
+ if (StringUtils.isEmpty(samlResponseString)) {
+ Logger.error("SAMLResponse not found in request.");
+ throw new STORKException("SAMLResponse not found in request.");
+ }
+
+ BasicSAMLMessageContext samlMessageContext = new BasicSAMLMessageContext();
+
+ samlMessageContext.setInboundMessageTransport(httpInTransport);
+ samlMessageContext.setOutboundMessageTransport(httpOutTransport);
+
+ HTTPPostDecoder postDecoder = new HTTPPostDecoder();
+
+ try {
+ postDecoder.decode(samlMessageContext);
+ } catch (Exception e) {
+ Logger.error("Error decoding SAMLResponse message", e);
+ throw new STORKException("Error decoding SAMLResponse message", e);
+ }
+
+ if (!(samlMessageContext.getInboundSAMLMessage() instanceof STORKResponse)) {
+ Logger.error("Message received is not a SAMLResponse message");
+ throw new STORKException("Message received is not a SAMLResponse message");
+ }
+
+ STORKResponse samlResponse = (STORKResponse) samlMessageContext.getInboundSAMLMessage();
+
+ return samlResponse;
+ }
+
+ /**
+ * Verifies a STORK response according STORK specification
+ * @param storkResponse STORK Response to verify
+ * @throws STORKException if validation fails
+ */
+ public static void verifySTORKResponse(STORKResponse storkResponse) throws STORKException {
+
+ ResponseVerifier responseVerifier = new PEPSConnectorResponseVerifier();
+ try {
+ responseVerifier.verify(storkResponse);
+ } catch (SecurityException e) {
+ Logger.error("Error validating response message from PEPS.", e);
+ throw new STORKException("Error validating response message from PEPS.");
+ }
+
+ }
+
+ /**
+ * Verifies a STORK assertion
+ * @param assertion STORK assertion
+ * @param ipAddress Client IP address
+ * @param authnRequestID ID of the AuthnRequest
+ * @param recipient recipient for verification
+ * @param audience audience for verification
+ * @param reqAttributeList RequestedAttribute list for verification
+ * @throws STORKException
+ */
+ public static void verifySTORKAssertion(
+ Assertion assertion,
+ String ipAddress,
+ String authnRequestID,
+ String recipient,
+ String audience,
+ List<RequestedAttribute> reqAttributeList) throws STORKException {
+
+ //validate Assertion
+ AssertionVerifier assertionVerifier = new PEPSConnectorAssertionVerifier();
+ try {
+ assertionVerifier.verify(assertion, ipAddress, authnRequestID, recipient, audience, reqAttributeList);
+
+ //verify if all required attributes are present
+ PEPSConnectorAssertionVerifier.validateRequiredAttributes(reqAttributeList, assertion.getAttributeStatements().get(0).getAttributes());
+
+ } catch (SecurityException e) {
+ Logger.error("Error verifying assertion from PEPS", e);
+ throw new STORKException("Error validating assertion received from PEPS.");
+ }
+
+ }
+
+ /**
+ * Extracts the citizen signature from the signedDoc element present in the STORK assertion
+ * @param storkAssertion STORK assertion
+ * @return citizen signature as XML
+ * @throws STORKException
+ */
+ public static Element extractCitizenSignature(Assertion storkAssertion) throws STORKException {
+
+ Logger.debug("Processing DSS signature response from PEPS");
+
+ Element signatureResponse = getSignedDocAttributeValue(storkAssertion);
+
+ if (signatureResponse == null) {
+ String msg = "Could not find DSS signature response in SAML assertion";
+ Logger.error(msg);
+ throw new STORKException(msg);
+ }
+
+ Logger.debug("Found DSS signature in SAML assertion");
+
+ Logger.debug("DSS Signature creation response received from PEPS (pretty print):");
+ Logger.debug(XMLHelper.prettyPrintXML(signatureResponse));
+ Logger.trace("DSS Signature creation response received from PEPS (original):");
+ Logger.trace(XMLUtil.printXML(signatureResponse));
+
+ Element signature = getSignature(signatureResponse);
+
+ if (signature == null) {
+ String msg = "Could not find citizen signature in SAML assertion";
+ Logger.error(msg);
+ throw new STORKException(msg);
+ }
+
+ Logger.debug("Found foreign citizen signature in SAML assertion (pretty print):");
+ Logger.debug(XMLHelper.prettyPrintXML(signature));
+ Logger.trace("Found foreign citizen signature in SAML assertion (original):");
+ Logger.trace(XMLUtil.printXML(signature));
+
+ return signature;
+ }
+
+ /**
+ * Extracts the signedDoc attribute from a STORK assertion as XML
+ * @param storkAssertion STORK assertion
+ * @return Value of signedDoc attribute
+ * @throws STORKException
+ */
+ private static Element getSignedDocAttributeValue(Assertion storkAssertion) throws STORKException {
+
+ XMLObject xmlObj = SAMLUtil.getAttributeValue(storkAssertion.getAttributeStatements().get(0).getAttributes(), STORKConstants.STORK_ATTRIBUTE_SIGNEDDOC);
+
+
+ if (xmlObj instanceof XSAny)
+ return getSignedDocAttributeValueFromAny((XSAny) xmlObj);
+ else if (xmlObj instanceof XSString)
+ return getSignedDocAttributValueFromString((XSString) xmlObj);
+ else
+ return null;
+
+ }
+
+ /**
+ * Get signedDoc as XML if provided as anyType
+ * @param any AttributeValue as anyType
+ * @return signedDoc as XML
+ */
+ private static Element getSignedDocAttributeValueFromAny(XSAny any) {
+ if (!any.getUnknownXMLObjects(new QName(OASIS_DSS_NS, "SignResponse")).isEmpty()) {
+ XMLObject xmlObj = any.getUnknownXMLObjects(new QName(OASIS_DSS_NS, "SignResponse")).get(0);
+ return xmlObj.getDOM();
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Get signedDoc as XML if provided as String
+ * @param string AttributeValue as String
+ * @return signedDoc as XML
+ * @throws STORKException
+ */
+ private static Element getSignedDocAttributValueFromString(XSString string) throws STORKException {
+ try {
+ return XMLUtil.stringToDOM(string.getValue());
+ } catch (Exception e) {
+ Logger.error("Error building DOM", e);
+ throw new STORKException(e);
+
+ }
+ }
+
+ /**
+ * Extracts the signature value out of a DSS response
+ * @param signatureResponse DSS signature response
+ * @return signature
+ * @throws STORKException
+ */
+ private static Element getSignature(Element signatureResponse) throws STORKException {
+
+ NodeList nList = signatureResponse.getElementsByTagNameNS(OASIS_DSS_NS, "ResultMajor");
+
+ String resultMajor = XMLUtil.getFirstTextValueFromNodeList(nList);
+
+ if (StringUtils.isEmpty(resultMajor)) {
+ String msg = "DSS response not correct, ResultMajor element missing.";
+ Logger.error(msg);
+ throw new STORKException(msg);
+ }
+
+ Logger.trace("ResultMajor of DSS response: " + resultMajor);
+
+ if (!OASIS_DSS_SUCCESS_MSG.equals(resultMajor)) {
+ String msg = "DSS response not correct, ResultMajor is " + resultMajor;
+ Logger.error(msg);
+ throw new STORKException(msg);
+ }
+
+ NodeList nList2 = signatureResponse.getElementsByTagNameNS(OASIS_DSS_NS, "Base64Signature");;
+
+ String base64SigString = XMLUtil.getFirstTextValueFromNodeList(nList2);
+
+ if (StringUtils.isEmpty(base64SigString)) {
+ String msg = "DSS response not correct, Base64Signature element missing.";
+ Logger.error(msg);
+ throw new STORKException(msg);
+ }
+
+ Logger.trace("Base64Signature element of DSS response: " + base64SigString);
+
+ String sigString = new String(Base64.decode(base64SigString));
+
+ try {
+ return XMLUtil.stringToDOM(sigString);
+ } catch (Exception e) {
+ String msg = "Unable to extract signature from DSS response";
+ Logger.error(msg);
+ throw new STORKException(msg);
+ }
+
+
+ }
+
+ /**
+ * Handels connection to SZR-GW and returns Identity Link on success
+ * @param citizenSignature Citizen signature
+ * @param attributeList Received attribute List in assertion
+ * @return Identity Link
+ * @throws STORKException
+ */
+ public static IdentityLink connectToSZRGateway(Element citizenSignature, List<Attribute> attributeList) throws STORKException {
+ Logger.trace("Calling SZR Gateway with the following attributes:");
+
+ String fiscalNumber = SAMLUtil.getAttributeStringValue(attributeList, STORKConstants.STORK_ATTRIBUTE_FISCALNUMBER);
+ Logger.trace(STORKConstants.STORK_ATTRIBUTE_FISCALNUMBER + " : " + fiscalNumber);
+
+ String givenName = SAMLUtil.getAttributeStringValue(attributeList, STORKConstants.STORK_ATTRIBUTE_GIVENNAME);
+ Logger.trace(STORKConstants.STORK_ATTRIBUTE_GIVENNAME+ " : " + givenName);
+
+ String lastName = SAMLUtil.getAttributeStringValue(attributeList, STORKConstants.STORK_ATTRIBUTE_SURNAME);
+ Logger.trace(STORKConstants.STORK_ATTRIBUTE_SURNAME+ " : " + lastName);
+
+ String dateOfBirth = SAMLUtil.getAttributeStringValue(attributeList, STORKConstants.STORK_ATTRIBUTE_DATEOFBIRTH);
+ Logger.trace(STORKConstants.STORK_ATTRIBUTE_DATEOFBIRTH + " : " + dateOfBirth);
+
+ if (!StringUtils.isEmpty(dateOfBirth)) {
+ dateOfBirth = DateTimeUtils.formatPEPSDateToMOADate(dateOfBirth);
+ }
+
+ CreateIdentityLinkResponse response;
+ IdentityLink identityLink = null;
+ try {
+ Logger.trace("Starting call...");
+ response = AuthenticationServer.getInstance().getIdentityLink(fiscalNumber, givenName, lastName, dateOfBirth, citizenSignature);
+ if (response.isError()) {
+ Logger.error("Receveid ErrorResponse from SZR Gateway.");
+ throw new SZRGWClientException(response.getError());
+ }
+ else {
+ Logger.trace("Receveid Success Response from SZR Gateway.");
+ Element samlAssertion = response.getAssertion();
+
+ IdentityLinkAssertionParser ilParser = new IdentityLinkAssertionParser(samlAssertion);
+ identityLink = ilParser.parseIdentityLink();
+
+
+ Logger.debug("Received Identity Link from SZR Gateway");
+ //TODO: is this ok?
+// if (StringUtils.isEmpty(identityLink.getDateOfBirth())) {
+// identityLink.setDateOfBirth("9999-12-31");
+// }
+
+ }
+ } catch (SZRGWClientException e) {
+ Logger.error("Error connecting SZR-Gateway: ", e);
+ throw new STORKException("Error connecting SZR-Gateway: ", e);
+ } catch (ParseException e) {
+ Logger.error("Error parsing IdentityLink received from SZR-Gateway: ", e);
+ throw new STORKException("Error parsing IdentityLink received from SZR-Gateway: ", e);
+ }
+
+ return identityLink;
+
+ }
+
+
+ /**
+ * Transforms additional STORK attributes to MOA Extended attributes
+ * @param storkAttributeList STORK attribute list
+ * @return
+ */
+ public static List<ExtendedSAMLAttribute> addAdditionalSTORKAttributes(List<Attribute> storkAttributeList) {
+ List<ExtendedSAMLAttribute> moaExtendedSAMLAttributeList = new Vector<ExtendedSAMLAttribute>();
+
+ Logger.trace("Adding the following attributes to MOA assertion: ");
+ int count = 0;
+ //only add attributes different than eIdentifier, given name, surname, dateOfBirth, signedDoc
+ for (Attribute attribute : storkAttributeList) {
+ //attribute is not in default returned attribute set
+ if (!STORKConstants.DEFAULT_STORK_RETURNED_ATTRIBUTE_SET.contains(attribute.getName())) {
+
+ String attributeValue = null;
+ if (!attribute.getAttributeValues().isEmpty()) {
+ //we have attribute value
+ attributeValue = SAMLUtil.getStringValueFromXMLObject(attribute.getAttributeValues().get(0));
+ }
+ ExtendedSAMLAttribute extendedSAMLAttribute =
+ new ExtendedSAMLAttributeImpl(attribute.getName(), attributeValue, Constants.STORK_NS_URI, 0);
+ moaExtendedSAMLAttributeList.add(extendedSAMLAttribute);
+ count++;
+ Logger.trace("Additional attribute: " + attribute.getName());
+ }
+ }
+
+
+ Logger.debug("Added " + count + " STORK attribute(s) to the MOA assertion.");
+
+ return moaExtendedSAMLAttributeList;
+ }
+
+}