Java tutorial
/******************************************************************************* * Copyright 2014 Federal Chancellery Austria * MOA-ID has been developed in a cooperation between BRZ, the Federal * Chancellery Austria - ICT staff unit, 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.servlet; import iaik.x509.X509Certificate; import java.io.IOException; import java.io.InputStream; import java.io.StringWriter; import java.io.UnsupportedEncodingException; import java.security.cert.CertificateException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import javax.activation.DataSource; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBElement; import javax.xml.bind.JAXBException; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.Source; import javax.xml.transform.TransformerConfigurationException; import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactoryConfigurationError; import javax.xml.transform.stream.StreamSource; import org.apache.commons.codec.binary.Base64; import org.apache.commons.io.IOUtils; import org.apache.commons.lang.StringEscapeUtils; import org.apache.velocity.Template; import org.apache.velocity.VelocityContext; import org.apache.velocity.app.VelocityEngine; import org.opensaml.saml2.core.StatusCode; import org.xml.sax.SAXException; import at.gv.egovernment.moa.id.auth.AuthenticationServer; import at.gv.egovernment.moa.id.auth.builder.DataURLBuilder; import at.gv.egovernment.moa.id.auth.data.AuthenticationSession; import at.gv.egovernment.moa.id.auth.data.IdentityLink; import at.gv.egovernment.moa.id.auth.exception.AuthenticationException; import at.gv.egovernment.moa.id.auth.exception.BKUException; import at.gv.egovernment.moa.id.auth.exception.BuildException; import at.gv.egovernment.moa.id.auth.exception.MOAIDException; import at.gv.egovernment.moa.id.auth.exception.ParseException; import at.gv.egovernment.moa.id.auth.exception.ServiceException; import at.gv.egovernment.moa.id.auth.stork.STORKException; import at.gv.egovernment.moa.id.auth.stork.STORKResponseProcessor; import at.gv.egovernment.moa.id.commons.db.ConfigurationDBUtils; import at.gv.egovernment.moa.id.commons.db.dao.config.AttributeProviderPlugin; import at.gv.egovernment.moa.id.config.ConfigurationException; import at.gv.egovernment.moa.id.config.auth.AuthConfigurationProvider; import at.gv.egovernment.moa.id.config.auth.OAAuthParameter; import at.gv.egovernment.moa.id.moduls.ModulUtils; import at.gv.egovernment.moa.id.protocols.pvp2x.PVPConstants; import at.gv.egovernment.moa.id.storage.AuthenticationSessionStoreage; import at.gv.egovernment.moa.id.util.HTTPUtils; import at.gv.egovernment.moa.id.util.VelocityProvider; import at.gv.egovernment.moa.logging.Logger; import at.gv.egovernment.moa.spss.MOAException; import at.gv.egovernment.moa.spss.api.SPSSFactory; import at.gv.egovernment.moa.spss.api.SignatureVerificationService; import at.gv.egovernment.moa.spss.api.common.Content; import at.gv.egovernment.moa.spss.api.xmlverify.VerifySignatureInfo; import at.gv.egovernment.moa.spss.api.xmlverify.VerifySignatureLocation; import at.gv.egovernment.moa.spss.api.xmlverify.VerifyXMLSignatureRequest; import at.gv.egovernment.moa.spss.api.xmlverify.VerifyXMLSignatureResponse; import at.gv.egovernment.moa.util.StringUtils; import at.gv.util.xsd.xmldsig.SignatureType; import at.gv.util.xsd.xmldsig.X509DataType; import eu.stork.oasisdss.api.ApiUtils; import eu.stork.oasisdss.api.LightweightSourceResolver; import eu.stork.oasisdss.api.exceptions.ApiUtilsException; import eu.stork.oasisdss.api.exceptions.UtilsException; import eu.stork.oasisdss.profile.SignRequest; import eu.stork.oasisdss.profile.SignResponse; import eu.stork.peps.auth.commons.IPersonalAttributeList; import eu.stork.peps.auth.commons.PEPSUtil; import eu.stork.peps.auth.commons.PersonalAttribute; import eu.stork.peps.auth.commons.STORKAuthnRequest; import eu.stork.peps.auth.commons.STORKAuthnResponse; import eu.stork.peps.auth.engine.STORKSAMLEngine; import eu.stork.peps.exceptions.STORKSAMLEngineException; //import at.gv.egovernment.moa.id.auth.data.VerifyXMLSignatureResponse; /** * Endpoint for receiving STORK response messages * @deprecated Use {@link at.gv.egovernment.moa.id.auth.modules.stork.tasks.PepsConnectorHandleResponseWithoutSignatureTask} instead. */ public class PEPSConnectorWithLocalSigningServlet extends AuthServlet { private static final long serialVersionUID = 1L; public static final String PEPSCONNECTOR_SERVLET_URL_PATTERN = "/PEPSConnectorWithLocalSigning"; private String oasisDssWebFormURL = "https://testvidp.buergerkarte.at/oasis-dss/DSSWebFormServlet";//load from config below /** * @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 { Logger.warn(getClass().getName() + " is deprecated and should not be used any more."); String moaSessionID1 = request.getParameter("moaSessionID"); String signResponse = request.getParameter("signresponse"); Logger.info("moaSessionID1:" + moaSessionID1); Logger.info("signResponse:" + signResponse); if (moaSessionID1 != null) { if (signResponse != null) { //redirect from oasis with signresponse handleSignResponse(request, response); } else { //should not occur throw new IOException("should not occur"); } } else { if (signResponse != null) { //should not occur throw new IOException("should not occur"); } else { //normal saml response handleSAMLResponse(request, response); } } return; } private void handleSignResponse(HttpServletRequest request, HttpServletResponse response) { Logger.info("handleSignResponse started"); String moaSessionID = request.getParameter("moaSessionID"); String signResponse = request.getParameter("signresponse"); Logger.info("moaSessionID:" + moaSessionID); Logger.info("signResponse:" + signResponse); String pendingRequestID = null; try { //load MOASession from database AuthenticationSession moaSession = AuthenticationServer.getSession(moaSessionID); //change MOASessionID moaSessionID = AuthenticationSessionStoreage.changeSessionID(moaSession); pendingRequestID = AuthenticationSessionStoreage.getPendingRequestID(moaSessionID); Logger.info("pendingRequestID:" + pendingRequestID); String signResponseString = new String(Base64.decodeBase64(signResponse), "UTF8"); Logger.info("RECEIVED signresponse:" + signResponseString); //create SignResponse object Source response1 = new StreamSource(new java.io.StringReader(signResponseString)); SignResponse dssSignResponse = ApiUtils.unmarshal(response1, SignResponse.class); // SignResponse dssSignResponse = (SignResponse) ApiUtils.unmarshal(new StreamSource(new java.io.StringReader(Base64.signResponse))); String citizenSignature = getCitizienSignatureFromSignResponse(dssSignResponse); // memorize signature into authblock moaSession.setAuthBlock(citizenSignature); X509Certificate cert = getSignerCertificate(citizenSignature); moaSession.setSignerCertificate(cert); VerifyXMLSignatureResponse xMLVerifySignatureResponse = verifyXMLSignature(citizenSignature); at.gv.egovernment.moa.id.auth.data.VerifyXMLSignatureResponse tmp = convert(xMLVerifySignatureResponse); moaSession.setXMLVerifySignatureResponse(tmp); try { IPersonalAttributeList personalAttributeList = moaSession .getAuthnResponseGetPersonalAttributeList(); //Add SignResponse TODO Add signature (extracted from signResponse)? List<String> values = new ArrayList<String>(); values.add(signResponseString); // values.add(citizenSignature); Logger.debug("Assembling signedDoc attribute"); PersonalAttribute signedDocAttribute = new PersonalAttribute("signedDoc", false, values, "Available"); personalAttributeList.add(signedDocAttribute); String authnContextClassRef = moaSession.getAuthnContextClassRef(); SZRGInsertion(moaSession, personalAttributeList, authnContextClassRef, citizenSignature); } catch (STORKException e) { // this is really nasty but we work against the system here. We are supposed to get the gender attribute from // stork. If we do not, we cannot register the person in the ERnP - we have to have the // gender for the represented person. So here comes the dirty hack. if (e.getCause() instanceof STORKException && e.getCause().getMessage().equals("gender not found in response")) { try { Logger.trace("Initialize VelocityEngine..."); VelocityEngine velocityEngine = VelocityProvider.getClassPathVelocityEngine(); Template template = velocityEngine.getTemplate("/resources/templates/fetchGender.html"); VelocityContext context = new VelocityContext(); context.put("SAMLResponse", request.getParameter("SAMLResponse")); context.put("action", request.getRequestURL()); StringWriter writer = new StringWriter(); template.merge(context, writer); response.getOutputStream().write(writer.toString().getBytes("UTF-8")); } catch (Exception e1) { Logger.error("Error sending gender retrival form.", e1); // httpSession.invalidate(); throw new MOAIDException("stork.10", null); } return; } Logger.error("Error connecting SZR Gateway", e); throw new MOAIDException("stork.10", null); } Logger.debug("Add full STORK AuthnResponse to MOA session"); moaSession.setStorkAuthnResponse(request.getParameter("SAMLResponse"));//TODO ask Florian/Thomas authnResponse? moaSession.setForeigner(true); //session is implicit stored in changeSessionID!!!! String newMOASessionID = AuthenticationSessionStoreage.changeSessionID(moaSession); Logger.info("Changed MOASession " + moaSessionID + " to Session " + newMOASessionID); //redirect String redirectURL = null; redirectURL = new DataURLBuilder().buildDataURL(moaSession.getAuthURL(), ModulUtils.buildAuthURL(moaSession.getModul(), moaSession.getAction(), pendingRequestID), newMOASessionID); redirectURL = response.encodeRedirectURL(redirectURL); response.sendRedirect(redirectURL); Logger.info("REDIRECT TO: " + redirectURL); } catch (AuthenticationException e) { handleError(null, e, request, response, pendingRequestID); } catch (MOAIDException e) { handleError(null, e, request, response, pendingRequestID); } catch (Exception e) { Logger.error("PEPSConnector has an interal Error.", e); } finally { ConfigurationDBUtils.closeSession(); } } private void handleSAMLResponse(HttpServletRequest request, HttpServletResponse response) { Logger.info("handleSAMLResponse started"); String pendingRequestID = null; 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("Beginning to extract SAMLResponse out of HTTP Request"); //extract STORK Response from HTTP Request //Decodes SAML Response byte[] decSamlToken; try { decSamlToken = PEPSUtil.decodeSAMLToken(request.getParameter("SAMLResponse")); Logger.debug("SAMLResponse: " + new String(decSamlToken)); } catch (NullPointerException e) { Logger.error("Unable to retrieve STORK Response", e); throw new MOAIDException("stork.04", null); } //Get SAMLEngine instance STORKSAMLEngine engine = STORKSAMLEngine.getInstance("outgoing"); STORKAuthnResponse authnResponse = null; try { //validate SAML Token Logger.debug("Starting validation of SAML response"); authnResponse = engine.validateSTORKAuthnResponse(decSamlToken, (String) request.getRemoteHost()); Logger.info("SAML response succesfully verified!"); } catch (STORKSAMLEngineException e) { Logger.error("Failed to verify STORK SAML Response", e); throw new MOAIDException("stork.05", null); } Logger.info("STORK SAML Response message succesfully extracted"); Logger.debug("STORK response: "); Logger.debug(authnResponse.toString()); Logger.debug("Trying to find MOA Session-ID ..."); //String moaSessionID = request.getParameter(PARAM_SESSIONID); //first use SAML2 relayState String moaSessionID = request.getParameter("RelayState"); // escape parameter strings moaSessionID = StringEscapeUtils.escapeHtml(moaSessionID); //check if SAML2 relaystate includes a MOA sessionID if (StringUtils.isEmpty(moaSessionID)) { //if relaystate is emtpty, use SAML response -> inResponseTo element as session identifier moaSessionID = authnResponse.getInResponseTo(); moaSessionID = StringEscapeUtils.escapeHtml(moaSessionID); if (StringUtils.isEmpty(moaSessionID)) { //No authentication session has been started before Logger.error("MOA-SessionID was not found, no previous AuthnRequest had been started"); Logger.debug("PEPSConnectorURL was: " + request.getRequestURL()); throw new AuthenticationException("auth.02", new Object[] { moaSessionID }); } else Logger.trace( "Use MOA SessionID " + moaSessionID + " from AuthnResponse->inResponseTo attribute."); } else //Logger.trace("MOA SessionID " + moaSessionID + " is found in http GET parameter."); Logger.trace("MOA SessionID " + moaSessionID + " is found in SAML2 relayState."); /*INFO!!!! * SAML message IDs has an different format then MOASessionIDs * This is only a workaround because many PEPS does not support SAML2 relayState or * MOASessionID as AttributConsumerServiceURL GET parameter */ // if (!ParamValidatorUtils.isValidSessionID(moaSessionID)) // throw new WrongParametersException("VerifyAuthenticationBlock", PARAM_SESSIONID, "auth.12"); pendingRequestID = AuthenticationSessionStoreage.getPendingRequestID(moaSessionID); //load MOASession from database AuthenticationSession moaSession = AuthenticationServer.getSession(moaSessionID); //change MOASessionID moaSessionID = AuthenticationSessionStoreage.changeSessionID(moaSession); Logger.info("Found MOA sessionID: " + moaSessionID); String statusCodeValue = authnResponse.getStatusCode(); if (!statusCodeValue.equals(StatusCode.SUCCESS_URI)) { Logger.error("Received ErrorResponse from PEPS: " + statusCodeValue); throw new MOAIDException("stork.06", new Object[] { statusCodeValue }); } Logger.info("Got SAML response with authentication success message."); Logger.debug("MOA session is still valid"); STORKAuthnRequest storkAuthnRequest = moaSession.getStorkAuthnRequest(); if (storkAuthnRequest == null) { Logger.error( "Could not find any preceeding STORK AuthnRequest to this MOA session: " + moaSessionID); throw new MOAIDException("stork.07", null); } Logger.debug("Found a preceeding STORK AuthnRequest to this MOA session: " + moaSessionID); ////////////// incorporate gender from parameters if not in stork response IPersonalAttributeList attributeList = authnResponse.getPersonalAttributeList(); // but first, check if we have a representation case if (STORKResponseProcessor.hasAttribute("mandateContent", attributeList) || STORKResponseProcessor.hasAttribute("representative", attributeList) || STORKResponseProcessor.hasAttribute("represented", attributeList)) { // in a representation case... moaSession.setUseMandate("true"); // and check if we have the gender value PersonalAttribute gender = attributeList.get("gender"); if (null == gender) { String gendervalue = (String) request.getParameter("gender"); if (null != gendervalue) { gender = new PersonalAttribute(); gender.setName("gender"); ArrayList<String> tmp = new ArrayList<String>(); tmp.add(gendervalue); gender.setValue(tmp); authnResponse.getPersonalAttributeList().add(gender); } } } ////////////////////////////////////////////////////////////////////////// Logger.debug("Starting extraction of signedDoc attribute"); //extract signed doc element and citizen signature String citizenSignature = null; try { PersonalAttribute signedDoc = authnResponse.getPersonalAttributeList().get("signedDoc"); String signatureInfo = null; if (signedDoc != null) { signatureInfo = signedDoc.getValue().get(0); //should not occur } else { //store SAMLResponse moaSession.setSAMLResponse(request.getParameter("SAMLResponse")); //store authnResponse //moaSession.setAuthnResponse(authnResponse);//not serializable moaSession.setAuthnResponseGetPersonalAttributeList(authnResponse.getPersonalAttributeList()); String authnContextClassRef = null; try { authnContextClassRef = authnResponse.getAssertions().get(0).getAuthnStatements().get(0) .getAuthnContext().getAuthnContextClassRef().getAuthnContextClassRef(); } catch (Throwable e) { Logger.warn( "STORK QAA-Level is not found in AuthnResponse. Set QAA Level to requested level"); } moaSession.setAuthnContextClassRef(authnContextClassRef); moaSession.setReturnURL(request.getRequestURL()); //load signedDoc String signRequest = moaSession.getSignedDoc(); //session is implicit stored in changeSessionID!!!! String newMOASessionID = AuthenticationSessionStoreage.changeSessionID(moaSession); //set return url to PEPSConnectorWithLocalSigningServlet and add newMOASessionID //signRequest String issuerValue = AuthConfigurationProvider.getInstance().getPublicURLPrefix(); String acsURL = issuerValue + PEPSConnectorWithLocalSigningServlet.PEPSCONNECTOR_SERVLET_URL_PATTERN; String url = acsURL + "?moaSessionID=" + newMOASessionID; //redirect to OASIS module and sign there boolean found = false; try { List<AttributeProviderPlugin> aps = AuthConfigurationProvider.getInstance() .getOnlineApplicationParameter(moaSession.getPublicOAURLPrefix()).getStorkAPs(); Logger.info("Found AttributeProviderPlugins:" + aps.size()); for (AttributeProviderPlugin ap : aps) { Logger.info("Found AttributeProviderPlugin attribute:" + ap.getAttributes()); if (ap.getAttributes().equalsIgnoreCase("signedDoc")) { // FIXME[tlenz]: A servlet's class field is not thread safe. oasisDssWebFormURL = ap.getUrl(); found = true; Logger.info("Loaded signedDoc attribute provider url from config:" + oasisDssWebFormURL); break; } } } catch (Exception e) { e.printStackTrace(); Logger.error("Loading the signedDoc attribute provider url from config failed"); } if (!found) { Logger.error("Failed to load the signedDoc attribute provider url from config"); } performRedirect(url, request, response, signRequest); return; } SignResponse dssSignResponse = (SignResponse) ApiUtils .unmarshal(new StreamSource(new java.io.StringReader(signatureInfo))); citizenSignature = getCitizienSignatureFromSignResponse(dssSignResponse); // memorize signature into authblock moaSession.setAuthBlock(citizenSignature); X509Certificate cert = getSignerCertificate(citizenSignature); moaSession.setSignerCertificate(cert); moaSession.setForeigner(true); } catch (Throwable e) { Logger.error("Could not extract citizen signature from C-PEPS", e); throw new MOAIDException("stork.09", null); } try { SZRGInsertion(moaSession, authnResponse.getPersonalAttributeList(), authnResponse.getAssertions().get(0).getAuthnStatements().get(0).getAuthnContext() .getAuthnContextClassRef().getAuthnContextClassRef(), citizenSignature); } catch (STORKException e) { // this is really nasty but we work against the system here. We are supposed to get the gender attribute from // stork. If we do not, we cannot register the person in the ERnP - we have to have the // gender for the represented person. So here comes the dirty hack. if (e.getCause() instanceof STORKException && e.getCause().getMessage().equals("gender not found in response")) { try { Logger.trace("Initialize VelocityEngine..."); VelocityEngine velocityEngine = VelocityProvider.getClassPathVelocityEngine(); Template template = velocityEngine.getTemplate("/resources/templates/fetchGender.html"); VelocityContext context = new VelocityContext(); context.put("SAMLResponse", request.getParameter("SAMLResponse")); context.put("action", request.getRequestURL()); StringWriter writer = new StringWriter(); template.merge(context, writer); response.getOutputStream().write(writer.toString().getBytes("UTF-8")); } catch (Exception e1) { Logger.error("Error sending gender retrival form.", e1); // httpSession.invalidate(); throw new MOAIDException("stork.10", null); } return; } Logger.error("Error connecting SZR Gateway", e); throw new MOAIDException("stork.10", null); } Logger.debug("Add full STORK AuthnResponse to MOA session"); moaSession.setStorkAuthnResponse(request.getParameter("SAMLResponse"));//TODO ask Florian/Thomas authnResponse? //session is implicit stored in changeSessionID!!!! String newMOASessionID = AuthenticationSessionStoreage.changeSessionID(moaSession); Logger.info("Changed MOASession " + moaSessionID + " to Session " + newMOASessionID); //redirect String redirectURL = null; redirectURL = new DataURLBuilder().buildDataURL(moaSession.getAuthURL(), ModulUtils.buildAuthURL(moaSession.getModul(), moaSession.getAction(), pendingRequestID), newMOASessionID); redirectURL = response.encodeRedirectURL(redirectURL); response.setContentType("text/html"); response.setStatus(302); response.addHeader("Location", redirectURL); Logger.info("REDIRECT TO: " + redirectURL); } catch (AuthenticationException e) { handleError(null, e, request, response, pendingRequestID); } catch (MOAIDException e) { handleError(null, e, request, response, pendingRequestID); } catch (Exception e) { Logger.error("PEPSConnector has an interal Error.", e); } finally { ConfigurationDBUtils.closeSession(); } } private void performRedirect(String url, HttpServletRequest req, HttpServletResponse resp, String signRequestString) throws MOAIDException { try { Logger.trace("Initialize VelocityEngine..."); VelocityEngine velocityEngine = VelocityProvider.getClassPathVelocityEngine(); Template template = velocityEngine.getTemplate("/resources/templates/oasis_dss_webform_binding.vm"); VelocityContext context = new VelocityContext(); Logger.debug("performRedirect, signrequest:" + signRequestString); Source signDoc = new StreamSource(new java.io.StringReader(signRequestString)); SignRequest signRequest = ApiUtils.unmarshal(signDoc, SignRequest.class); signRequest.setReturnURL("TODO"); signRequestString = IOUtils.toString(ApiUtils.marshalToInputStream(signRequest)); context.put("signrequest", Base64.encodeBase64String(signRequestString.getBytes("UTF8"))); context.put("clienturl", url); context.put("action", oasisDssWebFormURL); StringWriter writer = new StringWriter(); template.merge(context, writer); resp.getOutputStream().write(writer.toString().getBytes("UTF-8")); } catch (Exception e) { Logger.error("Error sending DSS signrequest.", e); throw new MOAIDException("stork.11", null); } } private String getCitizienSignatureFromSignResponseFromSAML(STORKAuthnResponse authnResponse) throws ApiUtilsException, IllegalArgumentException, TransformerConfigurationException, UtilsException, TransformerException, TransformerFactoryConfigurationError, IOException, MOAIDException { PersonalAttribute signedDoc = authnResponse.getPersonalAttributeList().get("signedDoc"); String signatureInfo = null; if (signedDoc == null) { Logger.error("SignedDoc = null, failed to extract Signresponse from authnResponse"); throw new MOAIDException("stork.09", null); } signatureInfo = signedDoc.getValue().get(0); SignResponse dssSignResponse = (SignResponse) ApiUtils .unmarshal(new StreamSource(new java.io.StringReader(signatureInfo))); String citizenSignature = getCitizienSignatureFromSignResponse(dssSignResponse); return citizenSignature; } private String getCitizienSignatureFromSignResponse(SignResponse dssSignResponse) throws IllegalArgumentException, TransformerConfigurationException, UtilsException, TransformerException, TransformerFactoryConfigurationError, IOException, ApiUtilsException { // fetch signed doc DataSource ds = LightweightSourceResolver.getDataSource(dssSignResponse); if (ds == null) { throw new ApiUtilsException("No datasource found in response"); } InputStream incoming = ds.getInputStream(); String citizenSignature = IOUtils.toString(incoming); incoming.close(); return citizenSignature; } private X509Certificate getSignerCertificate(String citizenSignature) throws CertificateException, JAXBException, UnsupportedEncodingException { JAXBContext ctx = JAXBContext.newInstance(SignatureType.class.getPackage().getName()); SignatureType root = ((JAXBElement<SignatureType>) ctx.createUnmarshaller() .unmarshal(IOUtils.toInputStream(citizenSignature))).getValue(); // extract certificate for (Object current : root.getKeyInfo().getContent()) if (((JAXBElement<?>) current).getValue() instanceof X509DataType) { for (Object currentX509Data : ((JAXBElement<X509DataType>) current).getValue() .getX509IssuerSerialOrX509SKIOrX509SubjectName()) { JAXBElement<?> casted = ((JAXBElement<?>) currentX509Data); if (casted.getName().getLocalPart().equals("X509Certificate")) { return new X509Certificate(((String) casted.getValue()).getBytes("UTF-8")); } } } return null; } private void SZRGInsertion(AuthenticationSession moaSession, IPersonalAttributeList personalAttributeList, String authnContextClassRef, String citizenSignature) throws STORKException, MOAIDException { Logger.debug("Foregin Citizen signature successfully extracted from STORK Assertion (signedDoc)"); Logger.debug("Citizen signature will be verified by SZR Gateway!"); Logger.debug("fetching OAParameters from database"); OAAuthParameter oaParam = AuthConfigurationProvider.getInstance() .getOnlineApplicationParameter(moaSession.getPublicOAURLPrefix()); if (oaParam == null) throw new AuthenticationException("auth.00", new Object[] { moaSession.getPublicOAURLPrefix() }); // retrieve target //TODO: check in case of SSO!!! String targetType = null; if (oaParam.getBusinessService()) { String id = oaParam.getIdentityLinkDomainIdentifier(); if (id.startsWith(AuthenticationSession.REGISTERANDORDNR_PREFIX_)) targetType = id; else targetType = AuthenticationSession.REGISTERANDORDNR_PREFIX_ + moaSession.getDomainIdentifier(); } else { targetType = AuthenticationSession.TARGET_PREFIX_ + oaParam.getTarget(); } Logger.debug("Starting connecting SZR Gateway"); //contact SZR Gateway IdentityLink identityLink = null; identityLink = STORKResponseProcessor.connectToSZRGateway(personalAttributeList, oaParam.getFriendlyName(), targetType, null, oaParam.getMandateProfiles(), citizenSignature); Logger.debug("SZR communication was successfull"); if (identityLink == null) { Logger.error("SZR Gateway did not return an identity link."); throw new MOAIDException("stork.10", null); } Logger.info("Received Identity Link from SZR Gateway"); moaSession.setIdentityLink(identityLink); Logger.debug("Adding addtional STORK attributes to MOA session"); moaSession.setStorkAttributes(personalAttributeList); //We don't have BKUURL, setting from null to "Not applicable" moaSession.setBkuURL("Not applicable (STORK Authentication)"); // free for single use moaSession.setAuthenticatedUsed(false); // stork did the authentication step moaSession.setAuthenticated(true); //TODO: found better solution, but QAA Level in response could be not supported yet try { if (authnContextClassRef == null) authnContextClassRef = PVPConstants.STORK_QAA_PREFIX + oaParam.getQaaLevel(); moaSession.setQAALevel(authnContextClassRef); } catch (Throwable e) { Logger.warn("STORK QAA-Level is not found in AuthnResponse. Set QAA Level to requested level"); moaSession.setQAALevel(PVPConstants.STORK_QAA_PREFIX + oaParam.getQaaLevel()); } } private VerifyXMLSignatureResponse verifyXMLSignature(String signature) throws AuthenticationException, ParseException, BKUException, BuildException, ConfigurationException, ServiceException, UnsupportedEncodingException, SAXException, IOException, ParserConfigurationException, MOAException { //Based on MOA demo client // Factory und Service instanzieren SPSSFactory spssFac = SPSSFactory.getInstance(); SignatureVerificationService sigVerifyService = SignatureVerificationService.getInstance(); Content sigDocContent1 = spssFac.createContent(IOUtils.toInputStream(signature, "UTF-8"), null); // Position der zu prfenden Signatur im Dokument angeben // (Nachdem im XPath-Ausdruck ein NS-Prfix verwendet wird, muss in einer Lookup-Tabelle // der damit bezeichnete Namenraum mitgegeben werden) HashMap nSMap = new HashMap(); nSMap.put("dsig", "http://www.w3.org/2000/09/xmldsig#"); VerifySignatureLocation sigLocation = spssFac.createVerifySignatureLocation("//dsig:Signature", nSMap); // Zu prfendes Dokument und Signaturposition zusammenfassen VerifySignatureInfo sigInfo = spssFac.createVerifySignatureInfo(sigDocContent1, sigLocation); // Prfrequest zusammenstellen VerifyXMLSignatureRequest verifyRequest = spssFac.createVerifyXMLSignatureRequest(null, // Wird Prfzeit nicht angegeben, wird aktuelle Zeit verwendet sigInfo, null, // Keine Ergnzungsobjekte notwendig null, // Signaturmanifest-Prfung soll nicht durchgefhrt werden false, // Hash-Inputdaten, d.h. tatschlich signierte Daten werden nicht zurckgeliefert "MOAIDBuergerkartePersonenbindungMitTestkarten");//TODO load from config //"Test-Signaturdienste"); // ID des verwendeten Vertrauensprofils VerifyXMLSignatureResponse verifyResponse = null; try { // Aufruf der Signaturprfung verifyResponse = sigVerifyService.verifyXMLSignature(verifyRequest); } catch (MOAException e) { // Service liefert Fehler System.err.println("Die Signaturprfung hat folgenden Fehler geliefert:"); System.err.println("Fehlercode: " + e.getMessageId()); System.err.println("Fehlernachricht: " + e.getMessage()); throw e; } // // Auswertung der Response // System.out.println(); // System.out.println("Ergebnisse der Signaturprfung:"); // System.out.println(); // // // Besondere Eigenschaften des Signatorzertifikats // SignerInfo signerInfo = verifyResponse.getSignerInfo(); // System.out.println("*** Ist Zertifikat des Signators qualifiziert? " + ((signerInfo.isQualifiedCertificate()) ? "ja" : "nein")); // System.out.println("*** Ist Zertifikat des Signators von einer Behrde? " + ((signerInfo.isPublicAuthority()) ? "ja" : "nein")); // // // Ergebnisse von Signatur- und Zertifikatsprfung // System.out.println(); // System.out.println("Ergebniscode der Signaturprfung: " + verifyResponse.getSignatureCheck().getCode()); // System.out.println("Ergebniscode der Zertifikatsprfung: " + verifyResponse.getCertificateCheck().getCode()); // // // Signatorzertifikat // System.out.println(); // System.out.println("*** Zertifikat des Signators:"); // System.out.println("Aussteller: " + signerInfo.getSignerCertificate().getIssuerDN()); // System.out.println("Subject: " + signerInfo.getSignerCertificate().getSubjectDN()); // System.out.println("Seriennummer: " + signerInfo.getSignerCertificate().getSerialNumber()); return verifyResponse; } private at.gv.egovernment.moa.id.auth.data.VerifyXMLSignatureResponse convert( VerifyXMLSignatureResponse xMLVerifySignatureResponse) { at.gv.egovernment.moa.id.auth.data.VerifyXMLSignatureResponse response = new at.gv.egovernment.moa.id.auth.data.VerifyXMLSignatureResponse(); response.setCertificateCheckCode(xMLVerifySignatureResponse.getCertificateCheck().getCode()); response.setPublicAuthority(xMLVerifySignatureResponse.getSignerInfo().isPublicAuthority()); // response.setPublicAuthorityCode(publicAuthorityCode) response.setQualifiedCertificate(xMLVerifySignatureResponse.getSignerInfo().isQualifiedCertificate()); response.setSignatureCheckCode(xMLVerifySignatureResponse.getSignatureCheck().getCode()); response.setSignatureManifestCheckCode(xMLVerifySignatureResponse.getSignatureManifestCheck().getCode()); // response.setSigningDateTime() // response.setX509certificate(x509certificate) response.setXmlDSIGManifestCheckCode(xMLVerifySignatureResponse.getSignatureManifestCheck().getCode()); // response.setXmlDSIGManigest(xMLVerifySignatureResponse.getSignatureManifestCheck()) // response.setXmlDsigSubjectName(xmlDsigSubjectName) return response; } }