diff options
Diffstat (limited to 'id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth')
21 files changed, 2175 insertions, 219 deletions
diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/AuthenticationServer.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/AuthenticationServer.java index a58f5fce2..a57ab5262 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/AuthenticationServer.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/AuthenticationServer.java @@ -29,8 +29,12 @@ import iaik.x509.X509Certificate; import java.io.ByteArrayInputStream; import java.io.File; import java.io.IOException; +import java.io.InputStream; import java.security.GeneralSecurityException; import java.security.Principal; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import java.util.HashMap; @@ -41,18 +45,24 @@ import java.util.Map; import java.util.Set; import java.util.Vector; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.TransformerException; import org.apache.xpath.XPathAPI; +import org.opensaml.saml2.metadata.RequestedAttribute; +import org.opensaml.xml.util.Base64; +import org.opensaml.xml.util.XMLHelper; import org.w3c.dom.Document; import org.w3c.dom.Element; -import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.SAXException; import at.gv.egovernment.moa.id.AuthenticationException; import at.gv.egovernment.moa.id.BuildException; +import at.gv.egovernment.moa.id.MOAIDException; import at.gv.egovernment.moa.id.ParseException; import at.gv.egovernment.moa.id.ServiceException; import at.gv.egovernment.moa.id.auth.builder.AuthenticationBlockAssertionBuilder; @@ -83,6 +93,9 @@ import at.gv.egovernment.moa.id.auth.parser.InfoboxReadResponseParser; import at.gv.egovernment.moa.id.auth.parser.SAMLArtifactParser; import at.gv.egovernment.moa.id.auth.parser.VerifyXMLSignatureResponseParser; import at.gv.egovernment.moa.id.auth.servlet.AuthServlet; +import at.gv.egovernment.moa.id.auth.servlet.PEPSConnectorServlet; +import at.gv.egovernment.moa.id.auth.stork.STORKAuthnRequestProcessor; +import at.gv.egovernment.moa.id.auth.stork.STORKException; import at.gv.egovernment.moa.id.auth.validator.CreateXMLSignatureResponseValidator; import at.gv.egovernment.moa.id.auth.validator.IdentityLinkValidator; import at.gv.egovernment.moa.id.auth.validator.InfoboxValidator; @@ -90,6 +103,9 @@ import at.gv.egovernment.moa.id.auth.validator.ValidateException; import at.gv.egovernment.moa.id.auth.validator.VerifyXMLSignatureResponseValidator; import at.gv.egovernment.moa.id.auth.validator.parep.ParepUtils; import at.gv.egovernment.moa.id.auth.validator.parep.ParepValidator; +import at.gv.egovernment.moa.id.auth.validator.parep.client.szrgw.CreateIdentityLinkResponse; +import at.gv.egovernment.moa.id.auth.validator.parep.client.szrgw.SZRGWClient; +import at.gv.egovernment.moa.id.auth.validator.parep.client.szrgw.SZRGWClientException; import at.gv.egovernment.moa.id.auth.validator.parep.client.szrgw.SZRGWConstants; import at.gv.egovernment.moa.id.config.ConfigurationException; import at.gv.egovernment.moa.id.config.ConfigurationProvider; @@ -98,6 +114,8 @@ import at.gv.egovernment.moa.id.config.auth.AuthConfigurationProvider; import at.gv.egovernment.moa.id.config.auth.OAAuthParameter; import at.gv.egovernment.moa.id.config.auth.VerifyInfoboxParameter; import at.gv.egovernment.moa.id.config.auth.VerifyInfoboxParameters; +import at.gv.egovernment.moa.id.config.stork.CPEPS; +import at.gv.egovernment.moa.id.config.stork.STORKConfig; import at.gv.egovernment.moa.id.data.AuthenticationData; import at.gv.egovernment.moa.id.util.HTTPUtils; import at.gv.egovernment.moa.id.util.MOAIDMessageProvider; @@ -113,6 +131,15 @@ import at.gv.egovernment.moa.util.DOMUtils; import at.gv.egovernment.moa.util.DateTimeUtils; import at.gv.egovernment.moa.util.FileUtils; import at.gv.egovernment.moa.util.StringUtils; +import eu.stork.mw.messages.saml.STORKAuthnRequest; +import eu.stork.vidp.messages.builder.STORKMessagesBuilder; +import eu.stork.vidp.messages.common.STORKConstants; +import eu.stork.vidp.messages.exception.SAMLException; +import eu.stork.vidp.messages.exception.SAMLValidationException; +import eu.stork.vidp.messages.stork.QualityAuthenticationAssuranceLevel; +import eu.stork.vidp.messages.stork.RequestedAttributes; +import eu.stork.vidp.messages.util.SAMLUtil; +import eu.stork.vidp.messages.util.XMLUtil; /** * API for MOA ID Authentication Service.<br> {@link AuthenticationSession} is @@ -543,16 +570,16 @@ public class AuthenticationServer implements MOAIDAuthConstants { int b = xmlInfoboxReadResponse.indexOf(se); if (b != -1) { // no identity link found Logger - .info("Es konnte keine Personenbindung auf der Karte gefunden werden. Versuche Anmeldung als ausländische eID."); + .info("Es konnte keine Personenbindung auf der Karte gefunden werden. Versuche Anmeldung als ausl�ndische eID."); return null; } - // spezifikationsgemäßer (SL1.2) Errorcode + // spezifikationsgem��er (SL1.2) Errorcode se = "ErrorCode>4002"; // b = xmlInfoboxReadResponse.contains(se); b = xmlInfoboxReadResponse.indexOf(se); if (b != -1) { // Unbekannter Infoboxbezeichner Logger - .info("Unbekannter Infoboxbezeichner. Versuche Anmeldung als ausländische eID."); + .info("Unbekannter Infoboxbezeichner. Versuche Anmeldung als ausl�ndische eID."); return null; } @@ -1732,7 +1759,7 @@ public class AuthenticationServer implements MOAIDAuthConstants { // builds authentication data and stores it together with a SAML // artifact AuthenticationData authData = buildAuthenticationData(session, vsresp, - useUTC); + useUTC, false); if (session.getUseMandate()) { // mandate mode @@ -2037,17 +2064,7 @@ public class AuthenticationServer implements MOAIDAuthConstants { AuthenticationSession session = getSession(sessionID); // AuthConfigurationProvider authConf = // AuthConfigurationProvider.getInstance(); - try { - String serializedAssertion = DOMUtils.serializeNode(session - .getIdentityLink().getSamlAssertion()); - session.setAuthBlock(serializedAssertion); - } catch (TransformerException e) { - throw new ParseException("parser.04", new Object[] { - REQ_VERIFY_AUTH_BLOCK, PARAM_XMLRESPONSE }); - } catch (IOException e) { - throw new ParseException("parser.04", new Object[] { - REQ_VERIFY_AUTH_BLOCK, PARAM_XMLRESPONSE }); - } + // post processing of the infoboxes Iterator iter = session.getInfoboxValidatorIterator(); boolean formpending = false; @@ -2097,7 +2114,7 @@ public class AuthenticationServer implements MOAIDAuthConstants { boolean useCondition = oaParam.getUseCondition(); int conditionLength = oaParam.getConditionLength(); AuthenticationData authData = buildAuthenticationData(session, vsresp, - useUTC); + useUTC, true); String samlAssertion = new AuthenticationDataAssertionBuilder().build( authData, session.getAssertionPrPerson(), session @@ -2141,6 +2158,9 @@ public class AuthenticationServer implements MOAIDAuthConstants { * authentication session * @param verifyXMLSigResp * VerifyXMLSignatureResponse from MOA-SP + * @param useUTC uses correct UTC time format + * @param useUTC indicates that authenticated citizen is a foreigner + * @param isForeigner indicates whether Austrian (false) or foreigner (true) authenticates * @return AuthenticationData object * @throws ConfigurationException * while accessing configuration data @@ -2149,7 +2169,7 @@ public class AuthenticationServer implements MOAIDAuthConstants { */ private AuthenticationData buildAuthenticationData( AuthenticationSession session, - VerifyXMLSignatureResponse verifyXMLSigResp, boolean useUTC) + VerifyXMLSignatureResponse verifyXMLSigResp, boolean useUTC, boolean isForeigner) throws ConfigurationException, BuildException { IdentityLink identityLink = session.getIdentityLink(); @@ -2196,21 +2216,44 @@ public class AuthenticationServer implements MOAIDAuthConstants { } } authData.setSignerCertificate(signerCertificateBase64); - if (businessService) { - authData.setWBPK(identityLink.getIdentificationValue()); + if(!isForeigner) { + //we have Austrian citizen + if (businessService) { + authData.setWBPK(identityLink.getIdentificationValue()); + } else { + authData.setBPK(identityLink.getIdentificationValue()); + + // BZ.., calculation of bPK already before sending AUTHBlock + /* + * if(identityLink.getIdentificationType().equals(Constants. + * URN_PREFIX_BASEID)) { // only compute bPK if online + * application is a public service and we have the Stammzahl + * String bpkBase64 = new BPKBuilder().buildBPK( + * identityLink.getIdentificationValue(), session.getTarget()); + * authData.setBPK(bpkBase64); } + */ + + } } else { - authData.setBPK(identityLink.getIdentificationValue()); - - // BZ.., calculation of bPK already before sending AUTHBlock - /* - * if(identityLink.getIdentificationType().equals(Constants. - * URN_PREFIX_BASEID)) { // only compute bPK if online - * application is a public service and we have the Stammzahl - * String bpkBase64 = new BPKBuilder().buildBPK( - * identityLink.getIdentificationValue(), session.getTarget()); - * authData.setBPK(bpkBase64); } - */ - + //we have foreigner, thus we have to calculate bPK and wbPK now (after receiving identity link from SZR-GW + if (businessService) { + //since we have foreigner, wbPK is not calculated in BKU + if(identityLink.getIdentificationType().equals(Constants.URN_PREFIX_BASEID)) { + String wbpkBase64 = new BPKBuilder().buildWBPK(identityLink.getIdentificationValue(), session.getDomainIdentifier()); + authData.setWBPK(wbpkBase64); + } + + } else { + + if(identityLink.getIdentificationType().equals(Constants.URN_PREFIX_BASEID)) { + // only compute bPK if online application is a public service and we have the Stammzahl + String bpkBase64 = new BPKBuilder().buildBPK(identityLink.getIdentificationValue(), session.getTarget()); + authData.setBPK(bpkBase64); + } + + + } + } String ilAssertion = oaParam.getProvideIdentityLink() ? identityLink .getSerializedSamlAssertion() @@ -2227,8 +2270,7 @@ public class AuthenticationServer implements MOAIDAuthConstants { session.setAssertionBusinessService(businessService); session.setAssertionIlAssertion(ilAssertion); session.setAssertionPrPerson(prPerson); - session - .setAssertionSignerCertificateBase64(signerCertificateBase64); + session.setAssertionSignerCertificateBase64(signerCertificateBase64); return authData; @@ -2482,4 +2524,288 @@ public class AuthenticationServer implements MOAIDAuthConstants { return value; } + + /** + * Does the request to the SZR-GW + * @param signature XMLDSIG signature + * @return Identity link assertion + * @throws SZRGWClientException + */ + public CreateIdentityLinkResponse getIdentityLink(String PEPSIdentifier, String PEPSFirstname, String PEPSFamilyname, String PEPSDateOfBirth, Element signature) throws SZRGWClientException { + + SZRGWClient client = new SZRGWClient(); + + try { + AuthConfigurationProvider authConf = AuthConfigurationProvider.getInstance(); + ConnectionParameter connectionParameters = authConf.getForeignIDConnectionParameter(); + + client.setAddress(connectionParameters.getUrl()); + if (connectionParameters.getUrl().toLowerCase().startsWith("https:")) { + Logger.debug("Initialisiere SSL Verbindung"); + try { + client.setSSLSocketFactory(SSLUtils.getSSLSocketFactory(AuthConfigurationProvider.getInstance(), connectionParameters)); + } catch (IOException e) { + Logger.error("Could not initialize SSL Factory", e); + throw new SZRGWClientException("Could not initialize SSL Factory"); + } catch (GeneralSecurityException e) { + Logger.error("Could not initialize SSL Factory", e); + throw new SZRGWClientException("Could not initialize SSL Factory"); + } catch (PKIException e) { + Logger.error("Could not initialize SSL Factory", e); + throw new SZRGWClientException("Could not initialize SSL Factory"); + } + } + Logger.info("Starte Kommunikation mit dem Stammzahlenregister Gateway(" + connectionParameters.getUrl() + ")..."); + } + catch (ConfigurationException e) { + Logger.warn(e); + Logger.warn(MOAIDMessageProvider.getInstance().getMessage("config.12", null )); + } + + // create request + CreateIdentityLinkResponse response = null; + Element request = null; + try { + Document doc = client.buildGetIdentityLinkRequest(PEPSIdentifier, PEPSFirstname, PEPSFamilyname, PEPSDateOfBirth, signature); + request = doc.getDocumentElement(); + + // send request + response = client.createIdentityLinkResponse(request); + } catch (SZRGWClientException e) { + // give him a second try - Nach dem Starten des Tomcat wird beim ersten Mal das Client-Zertifikat offenbar vom HTTPClient nicht mitgeschickt. + try { + response = client.createIdentityLinkResponse(request); + } + catch (SZRGWClientException e1) { + throw new SZRGWClientException(e1); + } + } + + + return response; + + } + + /** + * Starts a MOA-ID authentication process using STORK + * @param req HttpServletRequest + * @param resp HttpServletResponse + * @param ccc Citizen country code + * @param oaURL URL of the online application + * @param target Target parameter + * @param targetFriendlyName Friendly Name of Target + * @param authURL Authentication URL + * @param sourceID SourceID parameter + * @throws MOAIDException + * @throws AuthenticationException + * @throws WrongParametersException + * @throws ConfigurationException + */ + public static void startSTORKAuthentication( + HttpServletRequest req, + HttpServletResponse resp, + String ccc, + String oaURL, + String target, + String targetFriendlyName, + String authURL, + String sourceID) throws MOAIDException, AuthenticationException, WrongParametersException, ConfigurationException { + + //read configuration paramters of OA + OAAuthParameter oaParam = AuthConfigurationProvider.getInstance().getOnlineApplicationParameter(oaURL); + if (oaParam == null) + throw new AuthenticationException("auth.00", new Object[] { oaURL }); + + if (!oaParam.getBusinessService()) { + if (StringUtils.isEmpty(target)) + throw new WrongParametersException("StartAuthentication", PARAM_TARGET, "auth.05"); + } else { + target = null; + } + + //create MOA session + AuthenticationSession moaSession = newSession(); + Logger.info("MOASession " + moaSession.getSessionID() + " angelegt"); + moaSession.setTarget(target); + moaSession.setTargetFriendlyName(targetFriendlyName); + moaSession.setOAURLRequested(oaURL); + moaSession.setPublicOAURLPrefix(oaParam.getPublicURLPrefix()); + moaSession.setAuthURL(authURL); + moaSession.setBusinessService(oaParam.getBusinessService()); + moaSession.setDomainIdentifier(oaParam.getIdentityLinkDomainIdentifier()); + if (sourceID != null) + moaSession.setSourceID(sourceID); + + //Start of STORK Processing + STORKConfig storkConfig = AuthConfigurationProvider.getInstance().getStorkConfig(); + + CPEPS cpeps = storkConfig.getCPEPS(ccc); + + Logger.debug("Preparing to assemble STORK AuthnRequest witht the following values:"); + String destination = cpeps.getPepsURL().toExternalForm(); + Logger.debug("C-PEPS URL: " + destination); + + String acsURL = HTTPUtils.getBaseURL(req) + PEPSConnectorServlet.PEPSCONNECTOR_SERVLET_URL_PATTERN; + Logger.debug("MOA Assertion Consumer URL (PEPSConnctor): " + acsURL); + + String providerName= oaParam.getFriendlyName(); + String issuerValue = HTTPUtils.getBaseURL(req); + Logger.debug("Issuer value: " + issuerValue); + + QualityAuthenticationAssuranceLevel qaaLevel = STORKMessagesBuilder.buildQualityAuthenticationAssuranceLevel(oaParam.getQaaLevel().getValue()); + Logger.debug("QAALevel: " + qaaLevel.getValue()); + + RequestedAttributes requestedAttributes; + + requestedAttributes = oaParam.getRequestedAttributes(); + requestedAttributes.detach(); + List<RequestedAttribute> reqAttributeList = new ArrayList<RequestedAttribute>(); + List<RequestedAttribute> oaReqAttributeList = new ArrayList<RequestedAttribute>(oaParam.getRequestedAttributes().getRequestedAttributes()); + //check if country specific attributes must be additionally requested + if (!cpeps.getCountrySpecificRequestedAttributes().isEmpty()) { + //add country specific attributes to be requested (Hierarchy: default oa attributes > country specific attributes > oa specific attributes + Logger.debug("We have addtional country specific attributes to be requested from the C-PEPS of country: " + ccc); + Logger.debug("The following attributes are requested for this specific country:"); + List<RequestedAttribute> countrySpecificReqAttributeList = new ArrayList<RequestedAttribute>(cpeps.getCountrySpecificRequestedAttributes()); + for (RequestedAttribute csReqAttr : countrySpecificReqAttributeList) { + csReqAttr.detach(); + if (!STORKConstants.DEFAULT_STORK_REQUESTED_ATTRIBUTE_SET.contains(csReqAttr.getName())) { + //this country specific attribute does not override default attribute + if (SAMLUtil.containsAttribute(oaReqAttributeList, csReqAttr.getName())) { + //the same attribute is requested for OA, applying hierachy + //remove oa attribute + oaReqAttributeList.remove(SAMLUtil.getAttribute(oaReqAttributeList, csReqAttr.getName())); + //add country specific attribute instead + Logger.debug("Requested Attribute (" + csReqAttr.getName() + ") is also requested by OA but we use Country Specific value instead"); + } + oaReqAttributeList.add(csReqAttr); + Logger.debug("Country specific requested attribute: " + csReqAttr.getName() + ", isRequired: " + csReqAttr.isRequired()); + } else { + Logger.debug("Country specific requested attribute: " + csReqAttr.getName() + ", isRequired: " + csReqAttr.isRequired() + " tries to overwrite default requested and required attributes, hence we skip it."); + } + + } + reqAttributeList.addAll(oaReqAttributeList); + } else { + //no country specific requested attributes + reqAttributeList.addAll(oaReqAttributeList); + } + + reqAttributeList = (List<RequestedAttribute>) SAMLUtil.releaseDOM(reqAttributeList); + requestedAttributes = STORKMessagesBuilder.buildRequestedAttributes(reqAttributeList); + + if (Logger.isDebugEnabled()) { + Logger.debug("The following attributes are requested for this OA:"); + for (RequestedAttribute logReqAttr : reqAttributeList) { + Logger.debug("OA specific requested attribute: " + logReqAttr.getName() + ", isRequired: " + logReqAttr.isRequired()); + + } + } + + String spSector = StringUtils.isEmpty(target) ? "Business" : target; + String spInstitution = StringUtils.isEmpty(oaParam.getFriendlyName()) ? "UNKNOWN" : oaParam.getFriendlyName(); + String spApplication = spInstitution; + String spCountry = "AT"; + + String textToBeSigned = + CreateXMLSignatureRequestBuilder.buildForeignIDTextToBeSigned("wie im Signaturzertifikat (as in my signature certificate)", oaParam, moaSession); + + //generate AuthnRquest + STORKAuthnRequest storkAuthnRequest = STORKAuthnRequestProcessor.generateSTORKAuthnRequest( + destination, + acsURL, + providerName, + issuerValue, + qaaLevel, + requestedAttributes, + spSector, + spInstitution, + spApplication, + spCountry, + textToBeSigned, + "application/xhtml+xml"); + + Logger.debug("STORK AuthnRequest succesfully assembled."); + + //sign AuthnRequest + String keyStorePath = storkConfig.getSignatureCreationParameter().getKeyStorePath(); + String keyStorePassword = storkConfig.getSignatureCreationParameter().getKeyStorePassword(); + String keyName = storkConfig.getSignatureCreationParameter().getKeyName(); + String keyPassword = storkConfig.getSignatureCreationParameter().getKeyPassword(); + + Logger.debug("Starting signing process of STORK AuthnRequest."); + Logger.trace("Using the following Keystore and Key for that:"); + Logger.trace("KeyStore: " + keyStorePath); + Logger.trace("KeyName: " + keyName); + + try { + storkAuthnRequest = STORKAuthnRequestProcessor.signSTORKAuthnRequest(storkAuthnRequest, keyStorePath, keyStorePassword, keyName, keyPassword); + } catch (SAMLException e) { + Logger.error("Could not sign STORK SAML AuthnRequest.", e); + throw new MOAIDException("stork.00", null); + } + + Logger.info("STORK AuthnRequest successfully signed!"); + + //validate AuthnRequest + try { + STORKAuthnRequestProcessor.validateSTORKAuthnRequest(storkAuthnRequest); + } catch (SAMLValidationException e) { + Logger.error("STORK SAML AuthnRequest not valid.", e); + throw new MOAIDException("stork.01", null); + } + + Logger.debug("STORK AuthnRequest successfully internally validated."); + + //send + moaSession.setStorkAuthnRequest(storkAuthnRequest); + HttpSession httpSession = req.getSession(); + httpSession.setAttribute("MOA-Session-ID", moaSession.getSessionID()); + + Logger.debug("Preparing to send STORK AuthnRequest."); + + try { + STORKAuthnRequestProcessor.sendSTORKAuthnRequest(req, resp, storkAuthnRequest); + } catch (Exception e) { + Logger.error("Error sending STORK SAML AuthnRequest.", e); + httpSession.invalidate(); + throw new MOAIDException("stork.02", new Object[] { destination }); + } + + Logger.info("STORK AuthnRequest successfully sent to: " + storkAuthnRequest.getDestination()); + Logger.debug("STORKAuthnRequest sent (pretty print): "); + Logger.debug(XMLHelper.prettyPrintXML(storkAuthnRequest.getDOM())); + Logger.trace("STORKAuthnRequest sent (original): "); + Logger.trace(XMLUtil.printXML(storkAuthnRequest.getDOM())); + + } + + /** + * Extracts an X509 Certificate out of an XML signagture element + * @param signedXML XML signature element + * @return X509Certificate + * @throws CertificateException + */ + public static X509Certificate getCertificateFromXML(Element signedXML) throws CertificateException { + + NodeList nList = signedXML.getElementsByTagNameNS(Constants.DSIG_NS_URI, "X509Certificate"); + + String base64CertString = XMLUtil.getFirstTextValueFromNodeList(nList); + + if (StringUtils.isEmpty(base64CertString)) { + String msg = "XML does not contain a X509Certificate element."; + Logger.error(msg); + throw new CertificateException(msg); + } + + InputStream is = new ByteArrayInputStream(Base64.decode(base64CertString)); + + CertificateFactory cf; + X509Certificate cert = null; + cf = CertificateFactory.getInstance("X.509"); + cert = (X509Certificate)cf.generateCertificate(is); + + return cert; + } + } diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/MOAIDAuthConstants.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/MOAIDAuthConstants.java index f3be98ef0..7d5835f20 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/MOAIDAuthConstants.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/MOAIDAuthConstants.java @@ -47,6 +47,8 @@ public interface MOAIDAuthConstants { public static final String PARAM_SOURCEID = "sourceID"; /** servlet parameter "BKUSelectionTemplate" */ public static final String PARAM_BKUTEMPLATE = "BKUSelectionTemplate"; + /** servlet parameter "CCC (Citizen Country Code)" */ + public static final String PARAM_CCC = "CCC"; /** servlet parameter "BKUSelectionTemplate" */ public static final String PARAM_INPUT_PROCESSOR_SIGN_TEMPLATE = "InputProcessorSignTemplate"; /** default BKU URL */ diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/builder/BPKBuilder.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/builder/BPKBuilder.java index b6ba5871d..fa9789530 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/builder/BPKBuilder.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/builder/BPKBuilder.java @@ -56,7 +56,7 @@ public class BPKBuilder { target.length() == 0)) { throw new BuildException("builder.00", - new Object[] {"BPK", "Unvollständige Parameterangaben: identificationValue=" + + new Object[] {"BPK", "Unvollständige Parameterangaben: identificationValue=" + identificationValue + ",target=" + target}); } String basisbegriff = identificationValue + "+" + Constants.URN_PREFIX_CDID + "+" + target; @@ -86,7 +86,7 @@ public class BPKBuilder { registerAndOrdNr.length() == 0)) { throw new BuildException("builder.00", - new Object[] {"wbPK", "Unvollständige Parameterangaben: identificationValue=" + + new Object[] {"wbPK", "Unvollständige Parameterangaben: identificationValue=" + identificationValue + ",Register+Registernummer=" + registerAndOrdNr}); } String basisbegriff = identificationValue + "+" + Constants.URN_PREFIX_WBPK + "+" + registerAndOrdNr; diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/builder/CreateXMLSignatureRequestBuilder.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/builder/CreateXMLSignatureRequestBuilder.java index 9c696f245..2da7db2b2 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/builder/CreateXMLSignatureRequestBuilder.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/builder/CreateXMLSignatureRequestBuilder.java @@ -129,7 +129,31 @@ public class CreateXMLSignatureRequestBuilder implements Constants { * @return String representation of <code><CreateXMLSignatureRequest></code> */ public String buildForeignID(String subject, OAAuthParameter oaParam, AuthenticationSession session) { + + String request = ""; + request += "<sl:CreateXMLSignatureRequest xmlns:sl=\"http://www.buergerkarte.at/namespaces/securitylayer/1.2#\">"; + request += "<sl:KeyboxIdentifier>SecureSignatureKeypair</sl:KeyboxIdentifier>"; + request += "<sl:DataObjectInfo Structure=\"enveloping\">"; + request += "<sl:DataObject>"; + request += "<sl:XMLContent>"; + + request += buildForeignIDTextToBeSigned(subject, oaParam, session); + request += "</sl:XMLContent>"; + request += "</sl:DataObject>"; + request += "<sl:TransformsInfo>"; + request += "<sl:FinalDataMetaInfo>"; + request += "<sl:MimeType>application/xhtml+xml</sl:MimeType>"; + request += "</sl:FinalDataMetaInfo>"; + request += "</sl:TransformsInfo>"; + request += "</sl:DataObjectInfo>"; + request += "</sl:CreateXMLSignatureRequest>"; + + return request; + } + + public static String buildForeignIDTextToBeSigned(String subject, OAAuthParameter oaParam, AuthenticationSession session) { + String target = session.getTarget(); String sectorName = TargetToSectorNameMapper.getSectorNameViaTarget(target); @@ -137,14 +161,9 @@ public class CreateXMLSignatureRequestBuilder implements Constants { String date = DateTimeUtils.buildDate(cal); String time = DateTimeUtils.buildTime(cal); - String request = ""; - request += "<sl:CreateXMLSignatureRequest xmlns:sl=\"http://www.buergerkarte.at/namespaces/securitylayer/1.2#\">"; - request += "<sl:KeyboxIdentifier>SecureSignatureKeypair</sl:KeyboxIdentifier>"; - request += "<sl:DataObjectInfo Structure=\"enveloping\">"; - request += "<sl:DataObject>"; - request += "<sl:XMLContent>"; - - request += "<html xmlns=\"http://www.w3.org/1999/xhtml\">"; + String request = ""; + request += "<html xmlns=\"http://www.w3.org/1999/xhtml\">"; //application/xhtml+xml text/html + //request += "<meta http-equiv=\"content-type\" content=\"application/xhtml+xml; charset=UTF-8\">"; request += "<head>"; request += "<title>Signatur der Anmeldedaten</title>"; request += "<style type=\"text/css\" media=\"screen\">"; @@ -263,17 +282,9 @@ public class CreateXMLSignatureRequestBuilder implements Constants { request += "</body>"; request += "</html>"; - - request += "</sl:XMLContent>"; - request += "</sl:DataObject>"; - request += "<sl:TransformsInfo>"; - request += "<sl:FinalDataMetaInfo>"; - request += "<sl:MimeType>application/xhtml+xml</sl:MimeType>"; - request += "</sl:FinalDataMetaInfo>"; - request += "</sl:TransformsInfo>"; - request += "</sl:DataObjectInfo>"; - request += "</sl:CreateXMLSignatureRequest>"; - + return request; + } + } diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/data/AuthenticationSession.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/data/AuthenticationSession.java index 5a18b720b..e861c62fa 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/data/AuthenticationSession.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/data/AuthenticationSession.java @@ -24,6 +24,8 @@ package at.gv.egovernment.moa.id.auth.data; + + import iaik.x509.X509Certificate; import java.util.ArrayList; @@ -37,6 +39,7 @@ import at.gv.egovernment.moa.id.auth.validator.parep.ParepUtils; import at.gv.egovernment.moa.id.data.AuthenticationData; import at.gv.egovernment.moa.logging.Logger; import at.gv.egovernment.moa.util.Constants; +import eu.stork.mw.messages.saml.STORKAuthnRequest; /** * Session data to be stored between <code>AuthenticationServer</code> API calls. @@ -204,7 +207,10 @@ public class AuthenticationSession { */ private String pushInfobox; - + /** + * The STORK AuthRequest to be sent to the C-PEPS + */ + private STORKAuthnRequest storkAuthnRequest; /** * Constructor for AuthenticationSession. @@ -814,6 +820,23 @@ public class AuthenticationSession { public void setMandateReferenceValue(String mandateReferenceValue) { this.mandateReferenceValue = mandateReferenceValue; } + + /** + * Gets the STORK SAML AuthnRequest + * @return STORK SAML AuthnRequest + */ + public STORKAuthnRequest getStorkAuthnRequest() { + return storkAuthnRequest; + } + + /** + * Sets the STORK SAML AuthnRequest + * @param storkAuthnRequest STORK SAML AuthnRequest + */ + public void setStorkAuthnRequest(STORKAuthnRequest storkAuthnRequest) { + this.storkAuthnRequest = storkAuthnRequest; + } + } diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/servlet/AuthServlet.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/servlet/AuthServlet.java index a19618dc2..16041f8cb 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/servlet/AuthServlet.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/servlet/AuthServlet.java @@ -46,10 +46,18 @@ import org.apache.commons.fileupload.FileUploadException; import org.apache.commons.fileupload.disk.DiskFileItemFactory; import org.apache.commons.fileupload.servlet.ServletFileUpload; +import at.gv.egovernment.moa.id.AuthenticationException; +import at.gv.egovernment.moa.id.auth.AuthenticationServer; import at.gv.egovernment.moa.id.auth.MOAIDAuthConstants; import at.gv.egovernment.moa.id.auth.WrongParametersException; +import at.gv.egovernment.moa.id.auth.builder.DataURLBuilder; +import at.gv.egovernment.moa.id.auth.data.AuthenticationSession; +import at.gv.egovernment.moa.id.config.ConfigurationException; +import at.gv.egovernment.moa.id.config.auth.AuthConfigurationProvider; import at.gv.egovernment.moa.logging.Logger; +import at.gv.egovernment.moa.util.BoolUtils; import at.gv.egovernment.moa.util.URLDecoder; +import at.gv.egovernment.moa.util.URLEncoder; /** * Base class for MOA-ID Auth Servlets, providing standard error handling @@ -65,7 +73,16 @@ public class AuthServlet extends HttpServlet implements MOAIDAuthConstants { * */ private static final long serialVersionUID = -6929905344382283738L; + + + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) + throws ServletException, IOException { + Logger.debug("GET " + this.getServletName()); + + this.setNoCachingHeadersInHttpRespone(req, resp); +} /** * Handles an error. <br>> * <ul> @@ -260,4 +277,51 @@ public class AuthServlet extends HttpServlet implements MOAIDAuthConstants { public void init(ServletConfig servletConfig) throws ServletException { super.init(servletConfig); } + + /** + * Set response headers to avoid caching + * @param request HttpServletRequest + * @param response HttpServletResponse + */ + protected void setNoCachingHeadersInHttpRespone(HttpServletRequest request, HttpServletResponse response) { + response.setHeader(MOAIDAuthConstants.HEADER_EXPIRES,MOAIDAuthConstants.HEADER_VALUE_EXPIRES); + response.setHeader(MOAIDAuthConstants.HEADER_PRAGMA,MOAIDAuthConstants.HEADER_VALUE_PRAGMA); + response.setHeader(MOAIDAuthConstants.HEADER_CACHE_CONTROL,MOAIDAuthConstants.HEADER_VALUE_CACHE_CONTROL); + response.addHeader(MOAIDAuthConstants.HEADER_CACHE_CONTROL,MOAIDAuthConstants.HEADER_VALUE_CACHE_CONTROL_IE); + + } + + /** + * Adds a parameter to a URL. + * @param url the URL + * @param paramname parameter name + * @param paramvalue parameter value + * @return the URL with parameter added + */ + protected static String addURLParameter(String url, String paramname, String paramvalue) { + String param = paramname + "=" + paramvalue; + if (url.indexOf("?") < 0) + return url + "?" + param; + else + return url + "&" + param; + } + + /** + * Checks if HTTP requests are allowed + * @param authURL requestURL + * @throws AuthenticationException if HTTP requests are not allowed + * @throws ConfigurationException + */ + protected void checkIfHTTPisAllowed(String authURL) throws AuthenticationException, ConfigurationException { + // check if HTTP Connection may be allowed (through + // FRONTEND_SERVLETS_ENABLE_HTTP_CONNECTION_PROPERTY) + String boolStr = AuthConfigurationProvider.getInstance().getGenericConfigurationParameter( + AuthConfigurationProvider.FRONTEND_SERVLETS_ENABLE_HTTP_CONNECTION_PROPERTY); + if ((!authURL.startsWith("https:")) + && (false == BoolUtils.valueOf(boolStr))) + throw new AuthenticationException("auth.07", + new Object[] { authURL + "*" }); + + } + } diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/servlet/GetForeignIDServlet.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/servlet/GetForeignIDServlet.java index 246a47699..bf7a0f714 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/servlet/GetForeignIDServlet.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/servlet/GetForeignIDServlet.java @@ -24,19 +24,17 @@ package at.gv.egovernment.moa.id.auth.servlet;
-import iaik.pki.PKIException; - import java.io.IOException; -import java.security.GeneralSecurityException; +import java.security.cert.CertificateException; import java.util.Map; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import javax.xml.transform.TransformerException; import org.apache.commons.fileupload.FileUploadException; import org.apache.commons.lang.StringEscapeUtils; -import org.w3c.dom.Document; import org.w3c.dom.Element; import at.gv.egovernment.moa.id.MOAIDException; @@ -50,15 +48,10 @@ import at.gv.egovernment.moa.id.auth.data.IdentityLink; import at.gv.egovernment.moa.id.auth.parser.CreateXMLSignatureResponseParser; 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.SZRGWClient; import at.gv.egovernment.moa.id.auth.validator.parep.client.szrgw.SZRGWClientException; -import at.gv.egovernment.moa.id.config.ConfigurationException; -import at.gv.egovernment.moa.id.config.ConnectionParameter; -import at.gv.egovernment.moa.id.config.auth.AuthConfigurationProvider; -import at.gv.egovernment.moa.id.util.MOAIDMessageProvider; import at.gv.egovernment.moa.id.util.ParamValidatorUtils; -import at.gv.egovernment.moa.id.util.SSLUtils; import at.gv.egovernment.moa.logging.Logger; +import at.gv.egovernment.moa.util.DOMUtils; import at.gv.egovernment.moa.util.URLEncoder; /**
@@ -89,14 +82,7 @@ public class GetForeignIDServlet extends AuthServlet { protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
- Logger.debug("GET GetForeignIDServlet");
-
- resp.setHeader(MOAIDAuthConstants.HEADER_EXPIRES,MOAIDAuthConstants.HEADER_VALUE_EXPIRES);
- resp.setHeader(MOAIDAuthConstants.HEADER_PRAGMA,MOAIDAuthConstants.HEADER_VALUE_PRAGMA);
- resp.setHeader(MOAIDAuthConstants.HEADER_CACHE_CONTROL,MOAIDAuthConstants.HEADER_VALUE_CACHE_CONTROL);
- resp.addHeader(MOAIDAuthConstants.HEADER_CACHE_CONTROL,MOAIDAuthConstants.HEADER_VALUE_CACHE_CONTROL_IE);
-
-
+ super.doGet(req, resp);
}
/**
@@ -160,10 +146,17 @@ public class GetForeignIDServlet extends AuthServlet { CreateXMLSignatureResponse csresp =
new CreateXMLSignatureResponseParser(xmlCreateXMLSignatureResponse).parseResponseDsig();
- Element signature = csresp.getDsigSignature();
+ Element signature = csresp.getDsigSignature(); + + try { + session.setSignerCertificate(AuthenticationServer.getCertificateFromXML(signature)); + } catch (CertificateException e) { + Logger.error("Could not extract certificate from CreateXMLSignatureResponse"); + throw new MOAIDException("auth.14", null); + }
// make SZR request to the identity link
- CreateIdentityLinkResponse response = getIdentityLink(signature);
+ CreateIdentityLinkResponse response = AuthenticationServer.getInstance().getIdentityLink(null, null, null, null, signature);
if (response.isError()) {
@@ -173,28 +166,30 @@ public class GetForeignIDServlet extends AuthServlet { Element samlAssertion = response.getAssertion();
-// try {
-// System.out.println(DOMUtils.serializeNode(samlAssertion));
-// } catch (TransformerException e) {
-// e.printStackTrace();
-// }
+ try {
+ System.out.println("PB: " + DOMUtils.serializeNode(samlAssertion));
+ } catch (TransformerException e) {
+ e.printStackTrace();
+ }
IdentityLinkAssertionParser ilParser = new IdentityLinkAssertionParser(samlAssertion);
IdentityLink identitylink = ilParser.parseIdentityLink();
session.setIdentityLink(identitylink);
String samlArtifactBase64 =
- AuthenticationServer.getInstance().getForeignAuthenticationData(sessionID);
- if (!samlArtifactBase64.equals("Redirect to Input Processor")) {
- redirectURL = session.getOAURLRequested();
- if (!session.getBusinessService()) {
- redirectURL = addURLParameter(redirectURL, PARAM_TARGET, URLEncoder.encode(session.getTarget(), "UTF-8"));
- }
- redirectURL = addURLParameter(redirectURL, PARAM_SAMLARTIFACT, URLEncoder.encode(samlArtifactBase64, "UTF-8"));
- redirectURL = resp.encodeRedirectURL(redirectURL);
- } else {
- redirectURL = new DataURLBuilder().buildDataURL(session.getAuthURL(), AuthenticationServer.REQ_PROCESS_VALIDATOR_INPUT, session.getSessionID());
+ AuthenticationServer.getInstance().getForeignAuthenticationData(sessionID); + if (!samlArtifactBase64.equals("Redirect to Input Processor")) { + redirectURL = session.getOAURLRequested(); + if (!session.getBusinessService()) { + redirectURL = addURLParameter(redirectURL, PARAM_TARGET, URLEncoder.encode(session.getTarget(), "UTF-8")); + } + redirectURL = addURLParameter(redirectURL, PARAM_SAMLARTIFACT, URLEncoder.encode(samlArtifactBase64, "UTF-8")); + redirectURL = resp.encodeRedirectURL(redirectURL); + + } else { + redirectURL = new DataURLBuilder().buildDataURL(session.getAuthURL(), AuthenticationServer.REQ_PROCESS_VALIDATOR_INPUT, session.getSessionID()); }
+
resp.setContentType("text/html");
resp.setStatus(302);
resp.addHeader("Location", redirectURL);
@@ -210,84 +205,12 @@ public class GetForeignIDServlet extends AuthServlet { }
}
- /**
- * Adds a parameter to a URL.
- * @param url the URL
- * @param paramname parameter name
- * @param paramvalue parameter value
- * @return the URL with parameter added
- */
- private static String addURLParameter(String url, String paramname, String paramvalue) {
- String param = paramname + "=" + paramvalue;
- if (url.indexOf("?") < 0)
- return url + "?" + param;
- else
- return url + "&" + param;
- }
- /**
- * Does the request to the SZR-GW
- * @param signature XMLDSIG signature
- * @return Identity link assertion
- * @throws SZRGWClientException
- */
- private CreateIdentityLinkResponse getIdentityLink(Element signature) throws SZRGWClientException {
-
- SZRGWClient client = new SZRGWClient();
-
- try {
- AuthConfigurationProvider authConf = AuthConfigurationProvider.getInstance();
- ConnectionParameter connectionParameters = authConf.getForeignIDConnectionParameter();
-
- client.setAddress(connectionParameters.getUrl());
- if (connectionParameters.getUrl().toLowerCase().startsWith("https:")) {
- Logger.debug("Initialisiere SSL Verbindung");
- try {
- client.setSSLSocketFactory(SSLUtils.getSSLSocketFactory(AuthConfigurationProvider.getInstance(), connectionParameters));
- } catch (IOException e) {
- Logger.error("Could not initialize SSL Factory", e);
- throw new SZRGWClientException("Could not initialize SSL Factory");
- } catch (GeneralSecurityException e) {
- Logger.error("Could not initialize SSL Factory", e);
- throw new SZRGWClientException("Could not initialize SSL Factory");
- } catch (PKIException e) {
- Logger.error("Could not initialize SSL Factory", e);
- throw new SZRGWClientException("Could not initialize SSL Factory");
- }
- }
- Logger.info("Starte Kommunikation mit dem Stammzahlenregister Gateway(" + connectionParameters.getUrl() + ")...");
- }
- catch (ConfigurationException e) {
- Logger.warn(e);
- Logger.warn(MOAIDMessageProvider.getInstance().getMessage("config.12", null ));
- }
-
- // create request
- CreateIdentityLinkResponse response = null;
- Element request = null;
- try {
- Document doc = client.buildGetIdentityLinkRequest(null, null, null, null, signature);
- request = doc.getDocumentElement();
-
- // send request
- response = client.createIdentityLinkResponse(request);
- } catch (SZRGWClientException e) {
- // give him a second try - Nach dem Starten des Tomcat wird beim ersten Mal das Client-Zertifikat offenbar vom HTTPClient nicht mitgeschickt.
- try {
- response = client.createIdentityLinkResponse(request);
- }
- catch (SZRGWClientException e1) {
- throw new SZRGWClientException(e1);
- }
- }
-
-
- return response;
-
- }
+
+
/**
- * Builds the szrgw:GetIdentityLinkRequest für the SZR-GW
+ * Builds the szrgw:GetIdentityLinkRequest f�r the SZR-GW
* @param givenname
* @param familyname
* @param birthday
diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/servlet/GetMISSessionIDServlet.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/servlet/GetMISSessionIDServlet.java index 9d26ded8a..74b2f80b9 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/servlet/GetMISSessionIDServlet.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/servlet/GetMISSessionIDServlet.java @@ -206,20 +206,6 @@ public class GetMISSessionIDServlet extends AuthServlet { }
} - /** - * Adds a parameter to a URL. - * @param url the URL - * @param paramname parameter name - * @param paramvalue parameter value - * @return the URL with parameter added - */ - private static String addURLParameter(String url, String paramname, String paramvalue) { - String param = paramname + "=" + paramvalue; - if (url.indexOf("?") < 0) - return url + "?" + param; - else - return url + "&" + param; - }
-
+
}
diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/servlet/PEPSConnectorServlet.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/servlet/PEPSConnectorServlet.java new file mode 100644 index 000000000..4ec894d47 --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/servlet/PEPSConnectorServlet.java @@ -0,0 +1,227 @@ +package at.gv.egovernment.moa.id.auth.servlet;
+
+import java.io.IOException;
+import java.util.List;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+
+import org.opensaml.saml2.core.Assertion;
+import org.opensaml.saml2.core.StatusCode;
+import org.opensaml.xml.util.XMLHelper;
+import org.w3c.dom.Element;
+
+import at.gv.egovernment.moa.id.AuthenticationException;
+import at.gv.egovernment.moa.id.MOAIDException;
+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.ExtendedSAMLAttribute;
+import at.gv.egovernment.moa.id.auth.data.IdentityLink;
+import at.gv.egovernment.moa.id.auth.stork.STORKException;
+import at.gv.egovernment.moa.id.auth.stork.STORKResponseProcessor;
+import at.gv.egovernment.moa.id.util.HTTPUtils;
+import at.gv.egovernment.moa.logging.Logger;
+import at.gv.egovernment.moa.util.DOMUtils;
+import at.gv.egovernment.moa.util.StringUtils;
+import at.gv.egovernment.moa.util.URLEncoder;
+import eu.stork.mw.messages.saml.STORKAuthnRequest;
+import eu.stork.mw.messages.saml.STORKResponse;
+import eu.stork.vidp.messages.util.XMLUtil;
+
+/**
+ * Endpoint for receiving STORK response messages
+ */
+public class PEPSConnectorServlet extends AuthServlet {
+ private static final long serialVersionUID = 1L;
+
+ public static final String PEPSCONNECTOR_SERVLET_URL_PATTERN = "/PEPSConnector";
+
+
+ /**
+ * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
+ */
+ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+ super.doGet(request, response);
+ }
+
+ /**
+ * Handles the reception of a STORK response message
+ * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
+ */
+ protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+
+ try {
+
+ Logger.info("PEPSConnector Servlet invoked, expecting C-PEPS message.");
+ Logger.debug("This ACS endpoint is: " + HTTPUtils.getBaseURL(request));
+
+ super.setNoCachingHeadersInHttpRespone(request, response);
+ Logger.trace("No Caching headers set for HTTP response");
+
+ //check if https or only http
+ super.checkIfHTTPisAllowed(request.getRequestURL().toString());
+
+ Logger.debug("Trying to find MOA Session-ID");
+ HttpSession httpSession = request.getSession();
+ String moaSessionID = (String) httpSession.getAttribute("MOA-Session-ID");
+
+ if (StringUtils.isEmpty(moaSessionID)) {
+ //No authentication session has been started before
+ Logger.error("MOA-SessionID was not found, no previous AuthnRequest had been started");
+ throw new AuthenticationException("auth.02", new Object[] { moaSessionID });
+ } else {
+ //We know user and MOA takes over session handling, invalidate HttpSession
+ httpSession.invalidate();
+ }
+
+ Logger.info("Found MOA sessionID: " + moaSessionID);
+
+ Logger.debug("Beginning to extract SAMLResponse out of HTTP Request");
+
+ //extract STORK Response from HTTP Request
+ STORKResponse storkResponse = null;
+ try {
+ storkResponse = STORKResponseProcessor.receiveSTORKRepsonse(request, response);
+ } catch (STORKException e) {
+ Logger.error("Unable to retrieve STORK Response", e);
+ throw new MOAIDException("stork.04", null);
+ }
+
+ Logger.info("STORK SAML Response message succesfully extracted");
+ Logger.debug("STORK response (pretty print): ");
+ Logger.debug(XMLHelper.prettyPrintXML(storkResponse.getDOM()));
+ Logger.trace("STORK response (original): ");
+ Logger.trace(XMLUtil.printXML(storkResponse.getDOM()));
+
+ Logger.debug("Starting validation of SAML response");
+ //verify SAML response
+ try {
+ STORKResponseProcessor.verifySTORKResponse(storkResponse);
+ } catch (STORKException e) {
+ Logger.error("Failed to verify STORK SAML Response", e);
+ throw new MOAIDException("stork.05", null);
+ }
+
+ Logger.info("SAML response succesfully verified!");
+
+ String statusCodeValue = storkResponse.getStatus().getStatusCode().getValue();
+
+ 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.");
+
+ //check if authentication request was created before
+ AuthenticationSession moaSession = AuthenticationServer.getSession(moaSessionID);
+
+ 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);
+
+ Logger.debug("Starting validation of SAML assertion");
+ //verify SAML assertion
+ Assertion storkAssertion = storkResponse.getAssertions().get(0);
+ try {
+ STORKResponseProcessor.verifySTORKAssertion(
+ storkAssertion, //assertion
+ request.getRemoteAddr(), //IP address of user
+ storkAuthnRequest.getID(), //ID of STORK AuthnRequest
+ request.getRequestURL().toString(), //destination
+ HTTPUtils.getBaseURL(request), //audience
+ storkAuthnRequest.getRequestedAttributes()); //Requested Attributes
+ } catch (STORKException e) {
+ Logger.error("Failed to verify STORK SAML Assertion", e);
+ throw new MOAIDException("stork.08", null);
+ }
+
+ Logger.info("SAML assertion succesfully verified!");
+
+ Logger.debug("Starting extraction of signedDoc attribute");
+ //extract signed doc element and citizen signature
+ Element citizenSignature = null;
+ try {
+
+ citizenSignature = STORKResponseProcessor.extractCitizenSignature(storkAssertion);
+ moaSession.setAuthBlock(DOMUtils.serializeNode(citizenSignature));
+ moaSession.setSignerCertificate(AuthenticationServer.getCertificateFromXML(citizenSignature));
+
+ } catch (Exception 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("Starting connecting SZR Gateway");
+ //contact SZR Gateway
+ IdentityLink identityLink = null;
+ try {
+ identityLink = STORKResponseProcessor.connectToSZRGateway(citizenSignature, storkAssertion.getAttributeStatements().get(0).getAttributes());
+ } catch (STORKException e) {
+ 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);
+ }
+ Logger.info("Received Identity Link from SZR Gateway");
+ moaSession.setIdentityLink(identityLink);
+
+ Logger.debug("Adding addtional STORK attributes to MOA assertion");
+ //add other stork attributes to MOA assertion
+ List<ExtendedSAMLAttribute> moaExtendedSAMLAttibutes = STORKResponseProcessor.addAdditionalSTORKAttributes(storkAssertion.getAttributeStatements().get(0).getAttributes());
+ moaSession.setExtendedSAMLAttributesOA(moaExtendedSAMLAttibutes);
+
+ //We don't have BKUURL, setting from null to "Not applicable"
+ moaSession.setBkuURL("Not applicable (STORK Authentication)");
+
+ Logger.debug("Starting to assemble MOA assertion");
+ //produce MOA-Assertion and artifact
+ String samlArtifactBase64 =
+ AuthenticationServer.getInstance().getForeignAuthenticationData(moaSessionID);
+ Logger.info("MOA assertion assembled and SAML Artifact generated.");
+
+ //redirect
+ String redirectURL = null;
+ if (!samlArtifactBase64.equals("Redirect to Input Processor")) {
+ redirectURL = moaSession.getOAURLRequested();
+ if (!moaSession.getBusinessService()) {
+ redirectURL = addURLParameter(redirectURL, PARAM_TARGET, URLEncoder.encode(moaSession.getTarget(), "UTF-8"));
+ }
+ redirectURL = addURLParameter(redirectURL, PARAM_SAMLARTIFACT, URLEncoder.encode(samlArtifactBase64, "UTF-8"));
+ redirectURL = response.encodeRedirectURL(redirectURL);
+ } else {
+ redirectURL = new DataURLBuilder().buildDataURL(moaSession.getAuthURL(), AuthenticationServer.REQ_PROCESS_VALIDATOR_INPUT, moaSession.getSessionID());
+ }
+ response.setContentType("text/html");
+ response.setStatus(302);
+ response.addHeader("Location", redirectURL);
+ Logger.info("REDIRECT TO: " + redirectURL);
+
+
+
+ } catch (AuthenticationException e) {
+ handleError(null, e, request, response);
+ } catch (MOAIDException e) {
+ handleError(null, e, request, response);
+ }
+
+ }
+
+}
diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/servlet/StartAuthenticationServlet.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/servlet/StartAuthenticationServlet.java index 355e85ce5..012ed4c14 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/servlet/StartAuthenticationServlet.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/servlet/StartAuthenticationServlet.java @@ -26,6 +26,7 @@ package at.gv.egovernment.moa.id.auth.servlet; import java.io.IOException; import java.io.PrintWriter; +import java.util.List; import javax.servlet.ServletConfig; import javax.servlet.ServletException; @@ -33,18 +34,29 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.lang.StringEscapeUtils; +import org.opensaml.saml2.metadata.RequestedAttribute; import at.gv.egovernment.moa.id.AuthenticationException; import at.gv.egovernment.moa.id.MOAIDException; import at.gv.egovernment.moa.id.auth.AuthenticationServer; import at.gv.egovernment.moa.id.auth.MOAIDAuthInitializer; import at.gv.egovernment.moa.id.auth.WrongParametersException; +import at.gv.egovernment.moa.id.auth.stork.STORKAuthnRequestProcessor; import at.gv.egovernment.moa.id.config.auth.AuthConfigurationProvider; import at.gv.egovernment.moa.id.config.auth.OAAuthParameter; +import at.gv.egovernment.moa.id.config.stork.CPEPS; +import at.gv.egovernment.moa.id.config.stork.STORKConfig; +import at.gv.egovernment.moa.id.util.HTTPUtils; import at.gv.egovernment.moa.id.util.MOAIDMessageProvider; import at.gv.egovernment.moa.id.util.ParamValidatorUtils; import at.gv.egovernment.moa.logging.Logger; import at.gv.egovernment.moa.util.StringUtils; +import eu.stork.mw.messages.saml.STORKAuthnRequest; +import eu.stork.vidp.messages.builder.STORKMessagesBuilder; +import eu.stork.vidp.messages.exception.SAMLException; +import eu.stork.vidp.messages.exception.SAMLValidationException; +import eu.stork.vidp.messages.stork.QualityAuthenticationAssuranceLevel; +import eu.stork.vidp.messages.stork.RequestedAttributes; /** * Servlet requested for starting a MOA ID authentication session. @@ -77,7 +89,7 @@ public class StartAuthenticationServlet extends AuthServlet { protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { - Logger.debug("GET StartAuthentication"); + Logger.debug("GET StartAuthentication"); String authURL = req.getScheme() + "://" + req.getServerName(); if ((req.getScheme().equalsIgnoreCase("https") && req.getServerPort()!=443) || (req.getScheme().equalsIgnoreCase("http") && req.getServerPort()!=80)) { authURL = authURL.concat(":" + req.getServerPort()); @@ -91,6 +103,7 @@ public class StartAuthenticationServlet extends AuthServlet { String templateURL = req.getParameter(PARAM_TEMPLATE); String sessionID = req.getParameter(PARAM_SESSIONID); String useMandate = req.getParameter(PARAM_USEMANDATE); + String ccc = req.getParameter(PARAM_CCC); // escape parameter strings target = StringEscapeUtils.escapeHtml(target); @@ -100,11 +113,9 @@ public class StartAuthenticationServlet extends AuthServlet { templateURL = StringEscapeUtils.escapeHtml(templateURL); sessionID = StringEscapeUtils.escapeHtml(sessionID); useMandate = StringEscapeUtils.escapeHtml(useMandate); + ccc = StringEscapeUtils.escapeHtml(ccc); - resp.setHeader(HEADER_EXPIRES,HEADER_VALUE_EXPIRES); - resp.setHeader(HEADER_PRAGMA,HEADER_VALUE_PRAGMA); - resp.setHeader(HEADER_CACHE_CONTROL,HEADER_VALUE_CACHE_CONTROL); - resp.addHeader(HEADER_CACHE_CONTROL,HEADER_VALUE_CACHE_CONTROL_IE); + setNoCachingHeadersInHttpRespone(req, resp); try { @@ -121,35 +132,56 @@ public class StartAuthenticationServlet extends AuthServlet { throw new WrongParametersException("StartAuthentication", PARAM_USEMANDATE, "auth.12"); if (!ParamValidatorUtils.isValidSourceID(sourceID)) throw new WrongParametersException("StartAuthentication", PARAM_SOURCEID, "auth.12"); + if (!ParamValidatorUtils.isValidCCC(ccc)) + throw new WrongParametersException("StartAuthentication", PARAM_CCC, "auth.12"); + + OAAuthParameter oaParam = AuthConfigurationProvider.getInstance().getOnlineApplicationParameter(oaURL); if (oaParam == null) throw new AuthenticationException("auth.00", new Object[] { oaURL }); - + // get target and target friendly name from config String targetConfig = oaParam.getTarget(); - String targetFriendlyNameConfig = oaParam.getTargetFriendlyName(); + String targetFriendlyNameConfig = oaParam.getTargetFriendlyName(); + + String targetFriendlyName = null; + + if (StringUtils.isEmpty(targetConfig)) { + // no target attribut is given in OA config + // target is used from request + // check parameter + if (!ParamValidatorUtils.isValidTarget(target)) + throw new WrongParametersException("StartAuthentication", PARAM_TARGET, "auth.12"); + } else { + // use target from config + target = targetConfig; + targetFriendlyName = targetFriendlyNameConfig; + } + + STORKConfig storkConfig = AuthConfigurationProvider.getInstance().getStorkConfig(); - String getIdentityLinkForm = null; - if (StringUtils.isEmpty(targetConfig)) { - // no target attribut is given in OA config - // target is used from request - // check parameter - if (!ParamValidatorUtils.isValidTarget(target)) - throw new WrongParametersException("StartAuthentication", PARAM_TARGET, "auth.12"); + Logger.info("Starting authentication for a citizen of country: " + (StringUtils.isEmpty(ccc) ? "AT" : ccc)); + // STORK or normal authentication + if (storkConfig.isSTORKAuthentication(ccc)) { + //STORK authentication + Logger.trace("Found C-PEPS configuration for citizen of country: " + ccc); + Logger.debug("Starting STORK authentication"); - getIdentityLinkForm = AuthenticationServer.getInstance().startAuthentication(authURL, target, null, oaURL, templateURL, bkuURL, useMandate, sessionID, req.getScheme(), sourceID); - } - else { - // use target from config - getIdentityLinkForm = AuthenticationServer.getInstance().startAuthentication(authURL, targetConfig, targetFriendlyNameConfig, oaURL, templateURL, bkuURL, useMandate, sessionID, req.getScheme(), sourceID); + AuthenticationServer.startSTORKAuthentication(req, resp, ccc, oaURL, target, targetFriendlyName, authURL, sourceID); + + } else { + //normal MOA-ID authentication + Logger.debug("Starting normal MOA-ID authentication"); + + String getIdentityLinkForm = AuthenticationServer.getInstance().startAuthentication(authURL, target, targetFriendlyName, oaURL, templateURL, bkuURL, useMandate, sessionID, req.getScheme(), sourceID); + + resp.setContentType("text/html;charset=UTF-8"); + PrintWriter out = new PrintWriter(resp.getOutputStream()); + out.print(getIdentityLinkForm); + out.flush(); } - - resp.setContentType("text/html;charset=UTF-8"); - PrintWriter out = new PrintWriter(resp.getOutputStream()); - out.print(getIdentityLinkForm); - out.flush(); Logger.debug("Finished GET StartAuthentication"); } diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/servlet/VerifyAuthenticationBlockServlet.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/servlet/VerifyAuthenticationBlockServlet.java index f15f839d7..fbf700365 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/servlet/VerifyAuthenticationBlockServlet.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/servlet/VerifyAuthenticationBlockServlet.java @@ -326,19 +326,6 @@ public class VerifyAuthenticationBlockServlet extends AuthServlet { // handleError(null, e, req, resp); // } // } - /** - * Adds a parameter to a URL. - * @param url the URL - * @param paramname parameter name - * @param paramvalue parameter value - * @return the URL with parameter added - */ - private static String addURLParameter(String url, String paramname, String paramvalue) { - String param = paramname + "=" + paramvalue; - if (url.indexOf("?") < 0) - return url + "?" + param; - else - return url + "&" + param; - } + } diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/stork/AssertionVerifier.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/stork/AssertionVerifier.java new file mode 100644 index 000000000..7ffe59fd9 --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/stork/AssertionVerifier.java @@ -0,0 +1,56 @@ +/* + * Copyright 2011 by Graz University of Technology, Austria + * The Austrian STORK Modules have been developed by the E-Government + * Innovation Center EGIZ, a joint initiative of the Federal Chancellery + * Austria and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ + + +/**
+ *
+ */
+package at.gv.egovernment.moa.id.auth.stork;
+
+import java.util.List; + +import org.opensaml.saml2.core.Assertion; +import org.opensaml.saml2.metadata.RequestedAttribute; +
+/**
+ * Interface to be implemented for verifying SAML assertions + * + * @author bzwattendorfer
+ *
+ */
+public interface AssertionVerifier {
+ + /** + * Verifies a given assertion + * @param assertion SAML assertion + * @param reqIPAddress IP address of the client + * @param authnRequestID ID of the corresponding authentication request for verification + * @param recipient recipient for verification + * @param audience audience for verification + * @param reqAttrList RequestedAttribute list for verification + * @throws SecurityException + */
+ public void verify(Assertion assertion, String reqIPAddress, String authnRequestID, String recipient, String audience, List<RequestedAttribute> reqAttrList) throws SecurityException;
+
+}
diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/stork/CredentialProvider.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/stork/CredentialProvider.java new file mode 100644 index 000000000..b95ab6218 --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/stork/CredentialProvider.java @@ -0,0 +1,50 @@ +/* + * Copyright 2011 by Graz University of Technology, Austria + * The Austrian STORK Modules have been developed by the E-Government + * Innovation Center EGIZ, a joint initiative of the Federal Chancellery + * Austria and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ + + +/**
+ *
+ */
+package at.gv.egovernment.moa.id.auth.stork;
+
+import org.opensaml.xml.security.credential.Credential;
+
+import eu.stork.vidp.messages.exception.SAMLException;
+
+/**
+ * Interface supporting different kinds of Credentials + * + * @author bzwattendorfer
+ *
+ */
+public interface CredentialProvider {
+ + /** + * Gets appropriate credentials + * @return Credential object + * @throws SAMLException + */
+ public Credential getCredential() throws SAMLException;
+
+}
diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/stork/KeyStoreCredentialProvider.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/stork/KeyStoreCredentialProvider.java new file mode 100644 index 000000000..467210b4d --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/stork/KeyStoreCredentialProvider.java @@ -0,0 +1,126 @@ +/* + * Copyright 2011 by Graz University of Technology, Austria + * The Austrian STORK Modules have been developed by the E-Government + * Innovation Center EGIZ, a joint initiative of the Federal Chancellery + * Austria and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ + + +package at.gv.egovernment.moa.id.auth.stork;
+
+import java.security.KeyStore; +import java.security.PrivateKey; +import java.security.cert.X509Certificate; + +import org.opensaml.xml.security.credential.Credential; +import org.opensaml.xml.security.x509.BasicX509Credential; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import at.gv.egovernment.moa.util.KeyStoreUtils; +import at.gv.egovernment.moa.util.StringUtils; +import eu.stork.vidp.messages.exception.SAMLException; +
+/** + * Provides credentials from a KeyStore + * @author bzwattendorfer + * + */
+public class KeyStoreCredentialProvider implements CredentialProvider {
+
+ private final static Logger log = LoggerFactory.getLogger(KeyStoreCredentialProvider.class);
+ + /** KeyStore Path */
+ private String keyStorePath;
+ + /** KeyStore Password */
+ private String keyStorePassword;
+ + /** Specific Key Name as Credential */
+ private String keyName;
+ + /** Key password */
+ private String keyPassword;
+
+ /** + * Creates a KeyStoreCredentialProvider object + * @param keyStorePath KeyStore Path + * @param keyStorePassword KeyStore Password + * @param keyName KeyName of the key to be retrieved + * @param keyPassword Password for the Key + */
+ public KeyStoreCredentialProvider(String keyStorePath,
+ String keyStorePassword, String keyName, String keyPassword) {
+ super();
+ this.keyStorePath = keyStorePath;
+ this.keyStorePassword = keyStorePassword;
+ this.keyName = keyName;
+ this.keyPassword = keyPassword;
+ }
+
+ + /** + * Gets the credential object from the KeyStore + */
+ public Credential getCredential() throws SAMLException {
+ log.trace("Retrieving credentials for signing SAML Response.");
+
+ if (StringUtils.isEmpty(this.keyStorePath))
+ throw new SAMLException("No keyStorePath specified");
+ + //KeyStorePassword optional
+ //if (StringUtils.isEmpty(this.keyStorePassword))
+ // throw new SAMLException("No keyStorePassword specified");
+
+ if (StringUtils.isEmpty(this.keyName))
+ throw new SAMLException("No keyName specified");
+ + //KeyStorePassword optional
+ //if (StringUtils.isEmpty(this.keyPassword))
+ // throw new SAMLException("No keyPassword specified");
+
+ KeyStore ks;
+ try {
+ ks = KeyStoreUtils.loadKeyStore(this.keyStorePath, this.keyStorePassword);
+ } catch (Exception e) {
+ log.error("Failed to load keystore information", e);
+ throw new SAMLException(e);
+ }
+
+ //return new KeyStoreX509CredentialAdapter(ks, keyName, keyPwd.toCharArray());
+ BasicX509Credential credential = null;
+ try {
+ java.security.cert.X509Certificate certificate = (X509Certificate) ks.getCertificate(this.keyName);
+ PrivateKey privateKey = (PrivateKey) ks.getKey(this.keyName, this.keyPassword.toCharArray());
+ credential = new BasicX509Credential();
+ credential.setEntityCertificate(certificate);
+ credential.setPrivateKey(privateKey);
+
+ } catch (Exception e) {
+ log.error("Error retrieving signing credentials.", e);
+ throw new SAMLException(e);
+ }
+
+ return credential;
+
+ } + + +}
diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/stork/PEPSConnectorAssertionVerifier.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/stork/PEPSConnectorAssertionVerifier.java new file mode 100644 index 000000000..3048ccbee --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/stork/PEPSConnectorAssertionVerifier.java @@ -0,0 +1,241 @@ +/* + * Copyright 2011 by Graz University of Technology, Austria + * The Austrian STORK Modules have been developed by the E-Government + * Innovation Center EGIZ, a joint initiative of the Federal Chancellery + * Austria and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ + + +/**
+ *
+ */
+package at.gv.egovernment.moa.id.auth.stork;
+
+import java.util.List; + +import org.joda.time.DateTime; +import org.opensaml.saml2.core.Assertion; +import org.opensaml.saml2.core.Attribute; +import org.opensaml.saml2.core.Audience; +import org.opensaml.saml2.core.AudienceRestriction; +import org.opensaml.saml2.core.Conditions; +import org.opensaml.saml2.core.SubjectConfirmation; +import org.opensaml.saml2.core.SubjectConfirmationData; +import org.opensaml.saml2.metadata.RequestedAttribute; + +import at.gv.egovernment.moa.logging.Logger; +import eu.stork.vidp.messages.saml.STORKAttribute; +import eu.stork.vidp.messages.util.SAMLUtil; +
+/**
+ * Verifies the SAML assertion according to the STORK specification + * @author bzwattendorfer
+ *
+ */
+public class PEPSConnectorAssertionVerifier implements AssertionVerifier {
+
+ private static final int CLOCK_SKEW_MINUTES = 5; + + private static final boolean IS_USERS_CLIENT_IP_ADDRESS_TO_VERIFY = false;
+
+ /* (non-Javadoc)
+ * @see eu.stork.mw.peps.connector.validation.AssertionVerifier#verifyAssertion(org.opensaml.saml2.core.Assertion, java.lang.String, java.lang.String, java.lang.String)
+ */
+ public void verify(Assertion assertion, String reqIPAddress,
+ String authnRequestID, String recipient, String audience, List<RequestedAttribute> reqAttrList) throws SecurityException {
+
+ //SAML assertion need not to be signed, skipping signature validation
+
+ verifySubjectConfirmation(assertion, reqIPAddress, authnRequestID, recipient); + + Logger.debug("SubjectConfirmationData successfully verified"); +
+ verifyConditions(assertion, audience);
+ + Logger.debug("Conditions successfully verified"); + }
+
+
+ private void verifySubjectConfirmation(Assertion assertion, String reqAddress, String requestID, String recipient) throws SecurityException {
+ for (SubjectConfirmation sc : assertion.getSubject().getSubjectConfirmations()) {
+ verifySubjectConfirmationData(sc.getSubjectConfirmationData(), reqAddress, requestID, recipient);
+ }
+
+ }
+
+ private void verifySubjectConfirmationData(SubjectConfirmationData scData, String reqAddress, String requestID, String recipient) throws SecurityException {
+ //NotBefore not allowed in SSO profile
+ verifyNotOnOrAfter(scData.getNotOnOrAfter()); + + Logger.trace("NotOnOrAfter successfully verified");
+
+ if(IS_USERS_CLIENT_IP_ADDRESS_TO_VERIFY) {
+ verifyClientAddress(scData, reqAddress); + Logger.trace("User's client IP address successfully verified.");
+ } else {
+ Logger.warn("User's client IP address will not be verified.");
+ }
+
+ verifyRecipient(scData, recipient); + Logger.trace("Recipient successfully verified"); +
+ verifyInResponseTo(scData, requestID); + Logger.trace("InResponseTo successfully verified");
+
+ }
+
+ private void verifyNotBefore(DateTime notBefore) throws SecurityException {
+ if (notBefore.minusMinutes(CLOCK_SKEW_MINUTES).isAfterNow()) {
+ String msg = "Subject/Assertion not yet valid, Timestamp: ";
+ Logger.error(msg + notBefore);
+ throw new SecurityException(msg);
+ }
+
+ Logger.trace("Subject/Assertion already valid, notBefore: " + notBefore);
+
+ }
+
+ private void verifyNotOnOrAfter(DateTime notOnOrAfter) throws SecurityException {
+ if (notOnOrAfter.plusMinutes(CLOCK_SKEW_MINUTES).isBeforeNow()) {
+ String msg = "Subject/Assertion no longer valid.";
+ Logger.error(msg);
+ throw new SecurityException(msg);
+ }
+
+ Logger.trace("Subject/Assertion still valid, notOnOrAfter: " + notOnOrAfter);
+ }
+
+ private void verifyClientAddress(SubjectConfirmationData scData, String reqAddress) throws SecurityException {
+ if (!reqAddress.equals(scData.getAddress())) {
+ String msg = "Response coming from wrong Client-Address";
+ Logger.error("Response coming from wrong Client-Address " + reqAddress + ", expected " + scData.getAddress());
+ throw new SecurityException(msg);
+ }
+
+ }
+
+ private void verifyInResponseTo(SubjectConfirmationData scData, String requestID) throws SecurityException {
+ if (!scData.getInResponseTo().equals(requestID)) {
+ String msg = "Assertion issued for wrong request";
+ Logger.error(msg);
+ throw new SecurityException(msg);
+ }
+ }
+
+ private void verifyRecipient(SubjectConfirmationData scData, String reqRecipient) throws SecurityException {
+ if (!scData.getRecipient().equals(reqRecipient)) {
+ String msg = "Assertion intended for another recipient";
+ Logger.error("Assertion intended for recipient " + scData.getRecipient() + "but expected " + reqRecipient);
+ throw new SecurityException(msg);
+ }
+
+ }
+
+ private void verifyAudience(AudienceRestriction audienceRestriction, String reqAudience) throws SecurityException {
+ for (Audience audience : audienceRestriction.getAudiences()) {
+ if (audience.getAudienceURI().equals(reqAudience))
+ return;
+ }
+ String msg = "Assertion sent to wrong audience";
+ Logger.error("Assertion intended for wrong audience, expected " + reqAudience);
+ throw new SecurityException(msg);
+ }
+
+ private void verifyOneTimeUse(String assertionID) {
+ //not necessarily required to check since notBefore and notOnOrAfter are verified
+ //check response Store for already existing assertion
+
+ }
+
+ private void verifyConditions(Assertion assertion, String reqAudience) throws SecurityException {
+ Conditions conditions = assertion.getConditions();
+
+ verifyNotBefore(conditions.getNotBefore()); + Logger.trace("NotBefore successfully verified"); +
+ verifyNotOnOrAfter(conditions.getNotOnOrAfter()); + Logger.trace("NotOnOrAfter successfully verified");
+
+ verifyAudience(conditions.getAudienceRestrictions().get(0), reqAudience); + + Logger.trace("Audience successfully verified");
+
+ } + + public static void validateRequiredAttributes( + List<RequestedAttribute> reqAttrList, + List<Attribute> attrList) + throws STORKException { + + Logger.debug("Starting required attribute validation"); + + if (reqAttrList == null || reqAttrList.isEmpty()) { + Logger.error("Requested Attributes list is empty."); + throw new STORKException("No attributes have been requested"); + } + + if (attrList == null || attrList.isEmpty()) { + Logger.error("STORK AttributeStatement is empty."); + throw new STORKException("No attributes have been received"); + } + + Logger.trace("These attributes have been requested and received: "); + int count = 0; + for (RequestedAttribute reqAttr : reqAttrList) { + Logger.trace("Requested attribute: " + reqAttr.getName() + " isRequired: " + reqAttr.isRequired()); + for(Attribute attr : attrList) { + if (verifyRequestedAttribute(reqAttr, attr)) + count++; + } + } + + int numRequiredReqAttr = getNumberOfRequiredAttributes(reqAttrList); + Logger.trace("Number of requested required attributes: " + numRequiredReqAttr); + Logger.trace("Number of received required attributes: " + count); + + if (count != numRequiredReqAttr) { + Logger.error("Not all required attributes have been received"); + throw new STORKException("Not all required attributes have been received"); + } + Logger.debug("Received all required attributes!"); + + } + + private static boolean verifyRequestedAttribute(RequestedAttribute reqAttr, Attribute attr) { + + if ((reqAttr.getName()).equals(attr.getName())) { + if (reqAttr.isRequired() && SAMLUtil.getStatusFromAttribute(attr).equals(STORKAttribute.ALLOWED_ATTRIBUTE_STATUS_AVAIL)) { + Logger.trace("Received required attribute " + attr.getName() + " status: " + SAMLUtil.getStatusFromAttribute(attr)); + return true; + } + } + return false; + } + + private static int getNumberOfRequiredAttributes(List<RequestedAttribute> reqAttrList) { + int count = 0; + for (RequestedAttribute reqAttr : reqAttrList) + if (reqAttr.isRequired()) count++; + + return count; + } +
+
+}
diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/stork/PEPSConnectorResponseVerifier.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/stork/PEPSConnectorResponseVerifier.java new file mode 100644 index 000000000..2deeb2aae --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/stork/PEPSConnectorResponseVerifier.java @@ -0,0 +1,153 @@ +/* + * Copyright 2011 by Graz University of Technology, Austria + * The Austrian STORK Modules have been developed by the E-Government + * Innovation Center EGIZ, a joint initiative of the Federal Chancellery + * Austria and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ + + +/**
+ *
+ */
+package at.gv.egovernment.moa.id.auth.stork;
+
+ +import org.w3c.dom.Element; + +import at.gv.egovernment.moa.id.BuildException; +import at.gv.egovernment.moa.id.ParseException; +import at.gv.egovernment.moa.id.ServiceException; +import at.gv.egovernment.moa.id.auth.AuthenticationServer; +import at.gv.egovernment.moa.id.auth.builder.VerifyXMLSignatureRequestBuilder; +import at.gv.egovernment.moa.id.auth.data.VerifyXMLSignatureResponse; +import at.gv.egovernment.moa.id.auth.invoke.SignatureVerificationInvoker; +import at.gv.egovernment.moa.id.auth.parser.VerifyXMLSignatureResponseParser; +import at.gv.egovernment.moa.id.config.ConfigurationException; +import at.gv.egovernment.moa.id.config.auth.AuthConfigurationProvider; +import at.gv.egovernment.moa.logging.Logger; +import at.gv.egovernment.moa.util.Constants; +import eu.stork.mw.messages.saml.STORKResponse; +import eu.stork.vidp.messages.exception.SAMLValidationException; +import eu.stork.vidp.messages.util.SAMLUtil; +import eu.stork.vidp.messages.util.XMLUtil; +
+/**
+ * Verifies the SMAL response according to the STORK specification + * @author bzwattendorfer
+ *
+ */
+public class PEPSConnectorResponseVerifier implements ResponseVerifier {
+
+
+ /* (non-Javadoc)
+ * @see eu.stork.mw.peps.connector.validation.ResponseVerifier#verify(org.opensaml.saml2.core.Response)
+ */
+ public void verify(STORKResponse response) throws SecurityException {
+
+ verifySignature(response);
+ Logger.debug("Signature of SAML response valid.");
+
+ verifyStandardValidation(response);
+
+ Logger.debug("SAML response format valid.");
+
+ }
+
+
+ private void verifySignature(STORKResponse response) throws SecurityException {
+ //validate Signature
+ try {
+ if (response.isSigned()) { + + String trustProfileID = AuthConfigurationProvider.getInstance().getStorkConfig().getSignatureVerificationParameter().getTrustProfileID(); + + Logger.debug("Invoking MOA-SP with TrustProfileID: " + trustProfileID); +
+ // builds a <VerifyXMLSignatureRequest> for a call of MOA-SP + Element domVerifyXMLSignatureRequest = new VerifyXMLSignatureRequestBuilder() + .build(XMLUtil.printXML(response.getDOM()).getBytes(), trustProfileID); + + Logger.trace("VerifyXMLSignatureRequest for MOA-SP succesfully built"); + + Logger.trace("Calling MOA-SP"); + // invokes the call + Element domVerifyXMLSignatureResponse = new SignatureVerificationInvoker() + .verifyXMLSignature(domVerifyXMLSignatureRequest); + + // parses the <VerifyXMLSignatureResponse> + VerifyXMLSignatureResponse verifyXMLSignatureResponse = new VerifyXMLSignatureResponseParser( + domVerifyXMLSignatureResponse).parseData(); + + Logger.trace("Received VerifyXMLSignatureResponse from MOA-SP"); + + if (verifyXMLSignatureResponse.getSignatureCheckCode() != 0) { + String msg = "Signature of SAMLResponse not valid"; + Logger.error(msg); + throw new SecurityException(msg); + } + + Logger.debug("Signature of SAML response successfully verified"); + + if (verifyXMLSignatureResponse.getCertificateCheckCode() != 0) { + String msg = "Certificate of SAMLResponse not valid"; + Logger.error(msg); + throw new SecurityException(msg); + } + + Logger.debug("Signing certificate of SAML response succesfully verified"); +
+ } else {
+ String msg = "SAML Response is not signed.";
+ throw new SecurityException(msg);
+ }
+
+ } catch (ConfigurationException e) {
+ String msg = "Unable to load STORK configuration for STORK SAML Response signature verification.";
+ Logger.error(msg, e);
+ throw new SecurityException(msg, e);
+ } catch (ParseException e) { + String msg = "Unable to parse VerifyXMLSignature Request or Response."; + Logger.error(msg, e); + throw new SecurityException(msg, e); + } catch (BuildException e) { + String msg = "Unable to parse VerifyXMLSignature Request or Response."; + Logger.error(msg, e); + throw new SecurityException(msg, e); + } catch (ServiceException e) { + String msg = "Unable to invoke MOA-SP."; + Logger.error(msg, e); + throw new SecurityException(msg, e); + }
+
+ }
+
+ private void verifyStandardValidation(STORKResponse response) throws SecurityException {
+ try {
+ SAMLUtil.verifySAMLObjectStandardValidation(response, "saml2-core-schema-and-stork-validator");
+ } catch (SAMLValidationException e) {
+ String msg ="SAML Response received not valid.";
+ throw new SecurityException(msg, e);
+ }
+
+ }
+
+
+
+}
diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/stork/ResponseVerifier.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/stork/ResponseVerifier.java new file mode 100644 index 000000000..848937824 --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/stork/ResponseVerifier.java @@ -0,0 +1,44 @@ +/* + * Copyright 2011 by Graz University of Technology, Austria + * The Austrian STORK Modules have been developed by the E-Government + * Innovation Center EGIZ, a joint initiative of the Federal Chancellery + * Austria and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ + + +package at.gv.egovernment.moa.id.auth.stork;
+
+import eu.stork.mw.messages.saml.STORKResponse; + +/** + * Interface to be implemented for SAML response verification + * @author bzwattendorfer + * + */
+public interface ResponseVerifier {
+ + /** + * Verifies a STORK response + * @param response STORK response + * @throws SecurityException + */
+ public void verify(STORKResponse response) throws SecurityException;
+
+}
diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/stork/STORKAuthnRequestProcessor.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/stork/STORKAuthnRequestProcessor.java new file mode 100644 index 000000000..ff30919bc --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/stork/STORKAuthnRequestProcessor.java @@ -0,0 +1,170 @@ +/**
+ *
+ */
+package at.gv.egovernment.moa.id.auth.stork;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.lang.StringEscapeUtils;
+import org.apache.commons.lang.StringUtils;
+import org.apache.velocity.app.VelocityEngine;
+import org.opensaml.common.binding.BasicSAMLMessageContext;
+import org.opensaml.saml2.binding.encoding.HTTPPostEncoder;
+import org.opensaml.saml2.metadata.AssertionConsumerService;
+import org.opensaml.saml2.metadata.Endpoint;
+import org.opensaml.saml2.metadata.RequestedAttribute;
+import org.opensaml.ws.transport.http.HTTPOutTransport;
+import org.opensaml.ws.transport.http.HttpServletResponseAdapter;
+import org.opensaml.xml.security.credential.Credential;
+
+import at.gv.egovernment.moa.id.auth.servlet.PEPSConnectorServlet;
+import at.gv.egovernment.moa.id.util.HTTPUtils;
+import at.gv.egovernment.moa.logging.Logger;
+import eu.stork.mw.messages.saml.STORKAuthnRequest;
+import eu.stork.vidp.messages.builder.STORKMessagesBuilder;
+import eu.stork.vidp.messages.exception.SAMLException;
+import eu.stork.vidp.messages.exception.SAMLValidationException;
+import eu.stork.vidp.messages.stork.QualityAuthenticationAssuranceLevel;
+import eu.stork.vidp.messages.stork.RequestedAttributes;
+import eu.stork.vidp.messages.util.SAMLUtil;
+
+/**
+ * Class handling all necessary functionality for STORK AuthnRequest processing
+ *
+ * @author bzwattendorfer
+ *
+ */
+public class STORKAuthnRequestProcessor {
+
+ /**
+ * Creates a STORK AuthnRequest
+ * @param destination Destination URL
+ * @param acsURL Assertion Consumer Service URL
+ * @param providerName SP Provider Name
+ * @param issuerValue Issuer Name
+ * @param qaaLevel STORK QAALevel to be requested
+ * @param requestedAttributes Requested Attributes to be requested
+ * @param spSector Sp Sector
+ * @param spInstitution SP Institution
+ * @param spApplication SP Application
+ * @param spCountry SP Country
+ * @param textToBeSigned text to be included in signedDoc element
+ * @param mimeType mimeType for the text to be signed in signedDoc
+ * @return STORK AuthnRequest
+ */
+ public static STORKAuthnRequest generateSTORKAuthnRequest(
+ String destination,
+ String acsURL,
+ String providerName,
+ String issuerValue,
+ QualityAuthenticationAssuranceLevel qaaLevel,
+ RequestedAttributes requestedAttributes,
+ String spSector,
+ String spInstitution,
+ String spApplication,
+ String spCountry,
+ String textToBeSigned,
+ String mimeType) {
+
+
+ STORKAuthnRequest storkAuthnRequest =
+ STORKMessagesBuilder.buildSTORKAuthnRequest(
+ destination,
+ acsURL,
+ providerName,
+ issuerValue,
+ qaaLevel,
+ requestedAttributes,
+ spSector,
+ spInstitution,
+ spApplication,
+ spCountry);
+
+ STORKMessagesBuilder.buildAndAddSignatureRequestToAuthnRequest(storkAuthnRequest, textToBeSigned, mimeType, true);
+
+ Logger.debug("Added signedDoc attribute to STORK AuthnRequest");
+
+ return storkAuthnRequest;
+
+ }
+
+ /**
+ * Signs a STORK AuthnRequest
+ * @param storkAuthnRequest STORK AuthRequest to sign
+ * @param keyStorePath KeyStorePath to the signing key
+ * @param keyStorePassword KeyStore Password
+ * @param keyName Signing key name
+ * @param keyPassword Signing key password
+ * @return Signed STORK AuthnRequest
+ * @throws SAMLException
+ */
+ public static STORKAuthnRequest signSTORKAuthnRequest(
+ STORKAuthnRequest storkAuthnRequest,
+ String keyStorePath,
+ String keyStorePassword,
+ String keyName,
+ String keyPassword) throws SAMLException {
+
+ Logger.trace("Building Credential Provider for signing process");
+
+ CredentialProvider credentialProvider = new KeyStoreCredentialProvider(keyStorePath, keyStorePassword, keyName, keyPassword);
+
+ Credential credential = credentialProvider.getCredential();
+
+ Logger.trace("Credentials found");
+
+ SAMLUtil.signSAMLObject(storkAuthnRequest, credential);
+
+ return storkAuthnRequest;
+ }
+
+ /**
+ * Validates a STORK AuthnRequest
+ * @param storkAuthnRequest STORK AuthnRequest to validate
+ * @throws SAMLValidationException
+ */
+ public static void validateSTORKAuthnRequest(STORKAuthnRequest storkAuthnRequest) throws SAMLValidationException {
+
+ SAMLUtil.verifySAMLObjectStandardValidation(storkAuthnRequest, "saml2-core-schema-and-stork-validator");
+
+ }
+
+ /**
+ * Sends a STORK AuthnRequest (Endpoint taken out of AuthnRequest)
+ * @param request HttpServletRequest
+ * @param response HttpServletResponse
+ * @param storkAuthnRequest STORK AuthnRequest to send
+ * @throws Exception
+ */
+ public static void sendSTORKAuthnRequest(HttpServletRequest request, HttpServletResponse response, STORKAuthnRequest storkAuthnRequest) throws Exception {
+
+ Logger.trace("Create endpoint...");
+ Endpoint endpoint = STORKMessagesBuilder.buildSAMLObject(AssertionConsumerService.DEFAULT_ELEMENT_NAME);
+ endpoint.setBinding("urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST");
+ endpoint.setLocation(storkAuthnRequest.getDestination());
+
+
+ Logger.trace("Prepare SAMLMessageContext...");
+ HTTPOutTransport outTransport = new HttpServletResponseAdapter(response, request.isSecure());
+ BasicSAMLMessageContext<?, STORKAuthnRequest, ?> samlMessageContext = new BasicSAMLMessageContext();
+ samlMessageContext.setOutboundMessageTransport(outTransport);
+ samlMessageContext.setPeerEntityEndpoint(endpoint);
+
+ Logger.trace("Set STORK SAML AuthnRequest to SAMLMessageContext...");
+ samlMessageContext.setOutboundSAMLMessage(storkAuthnRequest);
+
+ Logger.trace("Initialize VelocityEngine...");
+
+ VelocityEngine velocityEngine = VelocityProvider.getClassPathVelocityEngine();
+
+// HTTPPostEncoder encoder = new HTTPPostEncoder(velocityEngine, "/templates/saml2-post-binding.vm");
+ HTTPPostEncoder encoder = new HTTPPostEncoder(velocityEngine, "/saml2-post-binding-moa.vm");
+
+ Logger.trace("HTTP-Post encode SAMLMessageContext...");
+ encoder.encode(samlMessageContext);
+ }
+
+
+
+}
diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/stork/STORKException.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/stork/STORKException.java new file mode 100644 index 000000000..5b737603b --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/stork/STORKException.java @@ -0,0 +1,42 @@ +/**
+ *
+ */
+package at.gv.egovernment.moa.id.auth.stork;
+
+
+/**
+ * Exception thrown if error occurs in STORK processing
+ * @author bzwattendorfer
+ *
+ */
+public class STORKException extends Exception{
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+
+ public STORKException() {
+ super();
+
+ }
+
+ public STORKException(String message, Throwable cause) {
+ super(message, cause);
+
+ }
+
+ public STORKException(String message) {
+ super(message);
+
+ }
+
+ public STORKException(Throwable cause) {
+ super(cause);
+
+ }
+
+
+
+
+}
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;
+ }
+
+}
diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/stork/VelocityProvider.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/stork/VelocityProvider.java new file mode 100644 index 000000000..29478718f --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/stork/VelocityProvider.java @@ -0,0 +1,88 @@ +/* + * Copyright 2011 by Graz University of Technology, Austria + * The Austrian STORK Modules have been developed by the E-Government + * Innovation Center EGIZ, a joint initiative of the Federal Chancellery + * Austria and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ + + +/**
+ *
+ */
+package at.gv.egovernment.moa.id.auth.stork;
+
+import org.apache.velocity.app.VelocityEngine; +import org.apache.velocity.runtime.RuntimeConstants; +
+/**
+ * Gets a Velocity Engine + * + * @author bzwattendorfer
+ *
+ */
+public class VelocityProvider {
+ + /** + * Gets velocityEngine from Classpath + * @return VelocityEngine + * @throws Exception + */
+ public static VelocityEngine getClassPathVelocityEngine() throws Exception {
+ VelocityEngine velocityEngine = getBaseVelocityEngine();
+ velocityEngine.setProperty(RuntimeConstants.RESOURCE_LOADER, "classpath");
+ velocityEngine.setProperty("classpath.resource.loader.class",
+ "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
+
+ velocityEngine.init();
+
+ return velocityEngine;
+ }
+ + /** + * Gets VelocityEngine from File + * @param rootPath File Path to template file + * @return VelocityEngine + * @throws Exception + */
+ public static VelocityEngine getFileVelocityEngine(String rootPath) throws Exception {
+ VelocityEngine velocityEngine = getBaseVelocityEngine();
+ velocityEngine.setProperty(RuntimeConstants.RESOURCE_LOADER, "file");
+ velocityEngine.setProperty("file.resource.loader.class",
+ "org.apache.velocity.runtime.resource.loader.FileResourceLoader");
+ velocityEngine.setProperty("file.resource.loader.path", rootPath);
+
+ velocityEngine.init();
+
+ return velocityEngine;
+ }
+ + /** + * Gets a basic VelocityEngine + * @return VelocityEngine + */
+ private static VelocityEngine getBaseVelocityEngine() {
+ VelocityEngine velocityEngine = new VelocityEngine();
+ velocityEngine.setProperty(RuntimeConstants.ENCODING_DEFAULT, "UTF-8");
+ velocityEngine.setProperty(RuntimeConstants.OUTPUT_ENCODING, "UTF-8");
+
+ return velocityEngine;
+ }
+
+}
|