package at.gv.egovernment.moa.id.auth; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.security.Principal; import java.security.cert.CertificateException; import java.util.Calendar; import java.util.List; import java.util.Map; import java.util.Vector; import javax.servlet.http.HttpServletRequest; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.TransformerException; import org.apache.commons.lang.StringEscapeUtils; import org.apache.xpath.XPathAPI; import org.opensaml.xml.util.Base64; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.util.Base64Utils; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NodeList; import org.xml.sax.SAXException; import at.gv.egiz.eaaf.core.api.IRequest; import at.gv.egiz.eaaf.core.api.idp.auth.data.IIdentityLink; import at.gv.egiz.eaaf.core.exceptions.EAAFBuilderException; import at.gv.egiz.eaaf.core.impl.data.Pair; import at.gv.egiz.eaaf.core.impl.idp.auth.builder.BPKBuilder; import at.gv.egiz.eaaf.core.impl.utils.DOMUtils; import at.gv.egiz.eaaf.core.impl.utils.DataURLBuilder; import at.gv.egiz.eaaf.core.impl.utils.FileUtils; import at.gv.egovernment.moa.id.advancedlogging.MOAIDEventConstants; import at.gv.egovernment.moa.id.advancedlogging.MOAReversionLogger; import at.gv.egovernment.moa.id.auth.builder.AuthenticationBlockAssertionBuilder; import at.gv.egovernment.moa.id.auth.builder.CreateXMLSignatureRequestBuilder; import at.gv.egovernment.moa.id.auth.builder.GetIdentityLinkFormBuilder; import at.gv.egovernment.moa.id.auth.builder.InfoboxReadRequestBuilder; import at.gv.egovernment.moa.id.auth.data.AuthenticationSession; import at.gv.egovernment.moa.id.auth.data.CreateXMLSignatureResponse; import at.gv.egovernment.moa.id.auth.data.ExtendedSAMLAttributeImpl; import at.gv.egovernment.moa.id.auth.data.VerifyXMLSignatureResponse; import at.gv.egovernment.moa.id.auth.exception.AuthenticationException; import at.gv.egovernment.moa.id.auth.exception.BuildException; 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.exception.ValidateException; import at.gv.egovernment.moa.id.auth.exception.WrongParametersException; import at.gv.egovernment.moa.id.auth.invoke.SignatureVerificationInvoker; import at.gv.egovernment.moa.id.auth.parser.CreateXMLSignatureResponseParser; import at.gv.egovernment.moa.id.auth.parser.InfoboxReadResponseParser; import at.gv.egovernment.moa.id.auth.parser.VerifyXMLSignatureResponseParser; 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.VerifyXMLSignatureRequestBuilder; 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.client.szrgw.SZRGWConstants; import at.gv.egovernment.moa.id.commons.MOAIDAuthConstants; import at.gv.egovernment.moa.id.commons.api.AuthConfiguration; import at.gv.egovernment.moa.id.commons.api.IOAAuthParameters; import at.gv.egovernment.moa.id.commons.api.data.ExtendedSAMLAttribute; import at.gv.egovernment.moa.id.commons.api.data.IAuthenticationSession; import at.gv.egovernment.moa.id.commons.api.data.IMISMandate; import at.gv.egovernment.moa.id.commons.api.data.IVerifiyXMLSignatureResponse; import at.gv.egovernment.moa.id.commons.api.exceptions.BKUException; import at.gv.egovernment.moa.id.commons.api.exceptions.ConfigurationException; import at.gv.egovernment.moa.id.commons.api.exceptions.MOAIDException; import at.gv.egovernment.moa.id.config.ConfigurationProviderImpl; import at.gv.egovernment.moa.id.logging.SpecificTraceLogger; import at.gv.egovernment.moa.id.protocols.pvp2x.PVPConstants; import at.gv.egovernment.moa.logging.Logger; import at.gv.egovernment.moa.util.Constants; import at.gv.egovernment.moa.util.DateTimeUtils; import at.gv.egovernment.moa.util.MiscUtil; import at.gv.egovernment.moa.util.StringUtils; import at.gv.egovernment.moaspss.logging.LogMsg; import iaik.asn1.ObjectID; import iaik.x509.X509Certificate; import iaik.x509.X509ExtensionInitException; /** * API for MOA ID Authentication Service.
{@link AuthenticationSession} is * stored in a session store and retrieved by giving the session ID. * * @author Paul Ivancsics * @version $Id: AuthenticationServer.java 1273 2012-02-27 14:50:18Z kstranacher * $ */ @Service("CitizenCardAuthenticationServer") public class AuthenticationServer extends BaseAuthenticationServer { @Autowired private MOAReversionLogger revisionsLogger; @Autowired private AuthConfiguration authConfig; /** * Constructor for AuthenticationServer. */ public AuthenticationServer() { super(); } /** * Processes the beginning of an authentication session. * * * @param authURL URL of the servlet to be used as data URL * @param target "Geschäftsbereich" of the online application requested * @param targetFriendlyName Friendly name of the target if the target is configured via * configuration * @param oaURL online application URL requested * @param bkuURL URL of the "Bürgerkartenumgebung" to be used; may be * null; in this case, the default location will be * used * @param useMandate Indicates if mandate is used or not * @param templateURL URL providing an HTML template for the HTML form generated * @param templateMandteURL URL providing an HTML template for the HTML form generated * (for signing in mandates mode) * @param req determines the protocol used * @param pendingReq * @param sourceID * @return HTML form * @throws AuthenticationException * @see GetIdentityLinkFormBuilder * @see InfoboxReadRequestBuilder */ public String startAuthentication(IAuthenticationSession session, HttpServletRequest req, IRequest pendingReq) throws WrongParametersException, AuthenticationException, ConfigurationException, BuildException { if (session == null) { throw new AuthenticationException("auth.18", new Object[]{}); } //load OnlineApplication configuration IOAAuthParameters oaParam = pendingReq.getServiceProviderConfiguration(IOAAuthParameters.class); if (oaParam == null) throw new AuthenticationException("auth.00", new Object[]{pendingReq.getSPEntityId()}); //load Template String templateURL = pendingReq.getRawData( MOAIDAuthConstants.AUTHPROCESS_DATA_SECURITYLAYERTEMPLATE, String.class); String template = null; if (MiscUtil.isNotEmpty(templateURL)) { try { template = new String(FileUtils.readURL(templateURL)); } catch (IOException ex) { throw new AuthenticationException("auth.03", new Object[]{ templateURL, ex.toString()}, ex); } } else { throw new AuthenticationException("auth.04", new Object[]{ "SecurityLayerTemplate", "No template definde"}); } String infoboxReadRequest = ""; String ssoDomainIdentifier = authConfig.getSSOTagetIdentifier(); if (MiscUtil.isNotEmpty(ssoDomainIdentifier) && pendingReq.needSingleSignOnFunctionality()) { Logger.debug("SSO Login requested"); //load identityLink with SSO Target boolean isbuisness = false; if (ssoDomainIdentifier.startsWith(PREFIX_WPBK)) { isbuisness = true; } else { isbuisness = false; } //build ReadInfobox request infoboxReadRequest = new InfoboxReadRequestBuilder().build( isbuisness, ssoDomainIdentifier); } else { Logger.debug("Non-SSO Login requested or SSO not allowed/possible"); //build ReadInfobox request infoboxReadRequest = new InfoboxReadRequestBuilder().build( oaParam.hasBaseIdInternalProcessingRestriction(), oaParam .getAreaSpecificTargetIdentifier()); } //build DataURL for BKU request String dataURL = new DataURLBuilder().buildDataURL( pendingReq.getAuthURL(), REQ_VERIFY_IDENTITY_LINK, pendingReq.getPendingRequestId()); //removed in MOAID 2.0 String pushInfobox = ""; //get Applet Parameters String appletwidth = req.getParameter(PARAM_APPLET_WIDTH); String appletheigth = req.getParameter(PARAM_APPLET_HEIGTH); appletheigth = StringEscapeUtils.escapeHtml(appletheigth); appletwidth = StringEscapeUtils.escapeHtml(appletwidth); try { String htmlForm = new GetIdentityLinkFormBuilder().build(template, session.getBkuURL(), infoboxReadRequest, dataURL, null, null, pushInfobox, oaParam, appletheigth, appletwidth, pendingReq.getAuthURL()); return htmlForm; } catch (BuildException e) { throw new BuildException("builder.07", null, e); } } /** * Processes an <InfoboxReadResponse> sent by the security layer implementation.
* * * @param sessionID * ID of associated authentication session data * @param infoboxReadResponseParameters * The parameters from the response returned from the BKU including the * <InfoboxReadResponse> * @return String "found!" in case the identity link could be retrieved and successfully validated, {@code null} in * case the identity link could not be retrieved (indicates that the card did not contain an identity link * which might indicate a foreign identity). Note that failing to parse or failing to validate the identity * link results in an Exception being thrown. * @throws BKUException */ public String verifyIdentityLink(IRequest pendingReq, IAuthenticationSession session, Map infoboxReadResponseParameters) throws AuthenticationException, BuildException, ParseException, ConfigurationException, ValidateException, ServiceException, BKUException { if (session == null) throw new AuthenticationException("auth.10", new Object[]{ REQ_VERIFY_IDENTITY_LINK, PARAM_SESSIONID}); String xmlInfoboxReadResponse = (String) infoboxReadResponseParameters .get(PARAM_XMLRESPONSE); if (isEmpty(xmlInfoboxReadResponse)) throw new AuthenticationException("auth.10", new Object[]{ REQ_VERIFY_IDENTITY_LINK, PARAM_XMLRESPONSE}); // check if an identity link was found // Errorcode 2911 von Trustdesk BKU (nicht spezifikationskonform // (SL1.2)) // CharSequence se = "ErrorCode>2911".substring(0); // boolean b = xmlInfoboxReadResponse.contains(se); String se = "ErrorCode>2911"; 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 auslaendische eID."); return null; } // spezifikationsgemaess (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 auslaendische eID."); return null; } // parses the IIdentityLink identityLink = new InfoboxReadResponseParser( xmlInfoboxReadResponse).parseIdentityLink(); // validates the identity link IdentityLinkValidator.getInstance().validate(identityLink); // builds a for a call of MOA-SP Element domVerifyXMLSignatureRequest = new VerifyXMLSignatureRequestBuilder() .build(identityLink, authConfig .getMoaSpIdentityLinkTrustProfileID(pendingReq.getServiceProviderConfiguration(IOAAuthParameters.class).isUseIDLTestTrustStore())); // invokes the call Element domVerifyXMLSignatureResponse = SignatureVerificationInvoker.getInstance() .verifyXMLSignature(domVerifyXMLSignatureRequest); // parses the IVerifiyXMLSignatureResponse verifyXMLSignatureResponse = new VerifyXMLSignatureResponseParser( domVerifyXMLSignatureResponse).parseData(); IOAAuthParameters oaParam = pendingReq.getServiceProviderConfiguration(IOAAuthParameters.class); // validates the VerifyXMLSignatureResponseValidator.getInstance().validate( verifyXMLSignatureResponse, authConfig.getIdentityLinkX509SubjectNames(), VerifyXMLSignatureResponseValidator.CHECK_IDENTITY_LINK, oaParam, authConfig); session.setIdentityLink(identityLink); // now validate the extended infoboxes //Removed in MOA-ID 2.0 //verifyInfoboxes(session, infoboxReadResponseParameters, false); revisionsLogger.logEvent(pendingReq, MOAIDEventConstants.AUTHPROCESS_IDL_VALIDATED); return "found!"; } /** * Processes an <InfoboxReadResponse> sent by the * security layer implementation.
*
    *
  • Validates given <InfoboxReadResponse>
  • *
  • Parses identity link enclosed in * <InfoboxReadResponse>
  • *
  • Verifies identity link by calling the MOA SP component
  • *
  • Checks certificate authority of identity link
  • *
  • Stores identity link in the session
  • *
  • Verifies all additional infoboxes returned from the BKU
  • *
  • Creates an authentication block to be signed by the user
  • *
  • Creates and returns a <CreateXMLSignatureRequest> * containg the authentication block, meant to be returned to the security * layer implementation
  • *
* @param pendingReq * * @param sessionID ID of associated authentication session data * @param infoboxReadResponseParameters The parameters from the response returned from the BKU * including the <InfoboxReadResponse> * @return String representation of the * <CreateXMLSignatureRequest> */ public void verifyCertificate(IAuthenticationSession session, X509Certificate certificate, IRequest pendingReq) throws AuthenticationException, BuildException, ParseException, ConfigurationException, ValidateException, ServiceException, MOAIDException { // check if person is a Organwalter // if true - don't show bPK in AUTH Block try { for (ObjectID OWid : MOAIDAuthConstants.OW_LIST) { if (certificate.getExtension(OWid) != null) { session.setOW(true); } } } catch (X509ExtensionInitException e) { Logger.warn("Certificate extension is not readable."); session.setOW(false); } } /** * Processes an Mandate sent by the MIS.
*
    *
  • Validates given Mandate
  • *
  • Verifies Mandate by calling the MOA SP component
  • *
  • Creates an authentication block to be signed by the user
  • *
  • Creates and returns a <CreateXMLSignatureRequest> * containg the authentication block, meant to be returned to the security * layer implementation
  • *
* @param pendingReq * @param pendingReq * * @param sessionID ID of associated authentication session data * @param infoboxReadResponseParameters The parameters from the response returned from the BKU * including the <InfoboxReadResponse> * @return String representation of the * <CreateXMLSignatureRequest> */ public void verifyMandate(IRequest pendingReq, IAuthenticationSession session, IMISMandate mandate) throws AuthenticationException, BuildException, ParseException, ConfigurationException, ValidateException, ServiceException { if (session == null) throw new AuthenticationException("auth.10", new Object[]{ GET_MIS_SESSIONID, PARAM_SESSIONID}); IOAAuthParameters oaParam = pendingReq.getServiceProviderConfiguration(IOAAuthParameters.class); try { // sets the extended SAML attributes for OID (Organwalter) setExtendedSAMLAttributeForMandatesOID(session, mandate, oaParam .hasBaseIdTransferRestriction()); validateExtendedSAMLAttributeForMandates(session, mandate, oaParam.hasBaseIdTransferRestriction()); } catch (SAXException e) { throw new AuthenticationException("auth.15", new Object[]{GET_MIS_SESSIONID}, e); } catch (IOException e) { throw new AuthenticationException("auth.15", new Object[]{GET_MIS_SESSIONID}, e); } catch (ParserConfigurationException e) { throw new AuthenticationException("auth.15", new Object[]{GET_MIS_SESSIONID}, e); } catch (TransformerException e) { throw new AuthenticationException("auth.15", new Object[]{GET_MIS_SESSIONID}, e); } } /** * @param session * @param pendingReq * @return * @throws ConfigurationException * @throws BuildException * @throws ValidateException */ public String getCreateXMLSignatureRequestAuthBlockOrRedirect( IAuthenticationSession session, IRequest pendingReq) throws ConfigurationException, BuildException, ValidateException, EAAFBuilderException { IOAAuthParameters oaParam = pendingReq.getServiceProviderConfiguration(IOAAuthParameters.class); // builds the AUTH-block String authBlock = buildAuthenticationBlock(session, oaParam, pendingReq); // builds the List transformsInfos = authConfig.getTransformsInfos(); String createXMLSignatureRequest = new CreateXMLSignatureRequestBuilder() .build(authBlock, oaParam.getKeyBoxIdentifier(), transformsInfos); SpecificTraceLogger.trace("Req. Authblock: " + Base64Utils.encodeToString(createXMLSignatureRequest.getBytes())); SpecificTraceLogger.trace("OA config: " + pendingReq.getServiceProviderConfiguration(IOAAuthParameters.class).toString()); SpecificTraceLogger.trace("saml1RequestedTarget: " + pendingReq.getRawData(MOAIDAuthConstants.AUTHPROCESS_DATA_TARGET, String.class)); SpecificTraceLogger.trace("saml1RequestedFriendlyName: " + pendingReq.getRawData(MOAIDAuthConstants.AUTHPROCESS_DATA_TARGETFRIENDLYNAME, String.class)); return createXMLSignatureRequest; } /** * Returns an CreateXMLSignatureRequest for signing the ERnP statement.
*
    *
  • Creates an CreateXMLSignatureRequest to be signed by the user
  • *
* @param pendingReq * * @param sessionID ID of associated authentication session data * @param cert The certificate from the user * @return String representation of the * <CreateXMLSignatureRequest> */ public String createXMLSignatureRequestForeignID(IRequest pendingReq, X509Certificate cert) throws AuthenticationException, BuildException, ParseException, ConfigurationException, ValidateException, ServiceException { Principal subject = cert.getSubjectDN(); String createXMLSignatureRequest = new CreateXMLSignatureRequestBuilder() .buildForeignID(subject.toString(), pendingReq); return createXMLSignatureRequest; } /** * Processes an <CreateXMLSignatureResponse> sent by the * security layer implementation.
*
    *
  • Validates given <CreateXMLSignatureResponse>
  • *
  • Parses response enclosed in * <CreateXMLSignatureResponse>
  • *
  • Verifies signature by calling the MOA SP component
  • *
  • Returns the signer certificate
  • *
* @param pendingReq * * @param sessionID ID of associated authentication session data * @param readInfoboxResponseParameters The parameters from the response returned from the BKU * including the <ReadInfoboxResponse> * @throws BKUException */ public X509Certificate getCertificate(IRequest pendingReq, Map readInfoboxResponseParameters) throws AuthenticationException, BuildException, ParseException, ConfigurationException, ValidateException, ServiceException, BKUException { String xmlReadInfoboxResponse = (String) readInfoboxResponseParameters .get(PARAM_XMLRESPONSE); if (isEmpty(xmlReadInfoboxResponse)) throw new AuthenticationException("auth.10", new Object[]{ REQ_VERIFY_CERTIFICATE, PARAM_XMLRESPONSE}); // parses the InfoboxReadResponseParser p = new InfoboxReadResponseParser( xmlReadInfoboxResponse); X509Certificate cert = p.parseCertificate(); revisionsLogger.logEvent(pendingReq, MOAIDEventConstants.AUTHPROCESS_CERTIFICATE_VALIDATED); return cert; } /** * Builds an authentication block <saml:Assertion> from * given session data. * * @param session authentication session * @param pendingReq * @return <saml:Assertion> as a String * @throws BuildException If an error occurs on serializing an extended SAML attribute * to be appended to the AUTH-Block. * @throws ConfigurationException */ private String buildAuthenticationBlock(IAuthenticationSession session, IOAAuthParameters oaParam, IRequest pendingReq) throws BuildException, ConfigurationException, EAAFBuilderException { IIdentityLink identityLink = session.getIdentityLink(); String issuer = identityLink.getName(); // replace ' in name with ' issuer = issuer.replaceAll("'", "'"); String gebDat = identityLink.getDateOfBirth(); String identificationValue = null; String identificationType = null; String identificationTypeFriendlyName = null; //get processing data from pending-request String authURL = pendingReq.getAuthURL(); @Deprecated String saml1RequestedTarget = pendingReq.getRawData( MOAIDAuthConstants.AUTHPROCESS_DATA_TARGET, String.class); @Deprecated String saml1RequestedFriendlyName = pendingReq.getRawData( MOAIDAuthConstants.AUTHPROCESS_DATA_TARGETFRIENDLYNAME, String.class); //set empty AuthBlock BPK in case of OW or SSO or bpk is not requested if (session.isOW() || pendingReq.needSingleSignOnFunctionality() || oaParam.isRemovePBKFromAuthBlock()) { identificationType = ""; identificationValue = ""; } else if (identityLink.getIdentificationType().equals(Constants.URN_PREFIX_BASEID)) { if (MiscUtil.isNotEmpty(saml1RequestedTarget)) { Logger.debug("Build AuthBlock bPK from SAML1 requested target"); Pair calcId = new BPKBuilder().generateAreaSpecificPersonIdentifier( identityLink.getIdentificationValue(), identityLink.getIdentificationType(), saml1RequestedTarget); identificationValue = calcId.getFirst(); identificationType = calcId.getSecond(); identificationTypeFriendlyName = saml1RequestedFriendlyName; } else { Pair calcId = new BPKBuilder().generateAreaSpecificPersonIdentifier( identityLink.getIdentificationValue(), identityLink.getIdentificationType(), oaParam.getAreaSpecificTargetIdentifier()); identificationValue = calcId.getFirst(); identificationType = calcId.getSecond(); identificationTypeFriendlyName = oaParam.getAreaSpecificTargetIdentifierFriendlyName(); } } else { identificationValue = identityLink.getIdentificationValue(); identificationType = identityLink.getIdentificationType(); identificationTypeFriendlyName = oaParam.getAreaSpecificTargetIdentifierFriendlyName(); } //set AuthBlock generation time to session String issueInstant = DateTimeUtils.buildDateTimeUTC(Calendar.getInstance()); session.setIssueInstant(issueInstant); //load extend attributes List extendedSAMLAttributes = session.getExtendedSAMLAttributesAUTH(); //load special authblock text patterns for replacement Map authBlockTextPatterns = AuthenticationBlockAssertionBuilder. generateSpezialAuthBlockPatternMap(pendingReq, issuer, gebDat, issueInstant); String authBlock = null; if (pendingReq.needSingleSignOnFunctionality()) { String oaURL = pendingReq.getAuthURL(); if (MiscUtil.isNotEmpty(oaURL)) oaURL = oaURL.replaceAll("&", "&"); authBlock = new AuthenticationBlockAssertionBuilder() .buildAuthBlockSSO(issuer, issueInstant, authURL, oaURL, gebDat, extendedSAMLAttributes, session, oaParam, authBlockTextPatterns); } else { String oaURL = oaParam.getPublicURLPrefix().replaceAll("&", "&"); authBlock = new AuthenticationBlockAssertionBuilder() .buildAuthBlock(issuer, issueInstant, authURL, identificationValue, identificationType, gebDat, oaURL, identificationTypeFriendlyName, extendedSAMLAttributes, session, oaParam, authBlockTextPatterns); } session.setExtendedSAMLAttributesAUTH(extendedSAMLAttributes); return authBlock; } /** * Verifies the infoboxes (except of the identity link infobox) returned by * the BKU by calling appropriate validator classes. * * @param session The actual authentication session. * @param mandate The Mandate from the MIS * @throws AuthenticationException * @throws ConfigurationException * @throws TransformerException * @throws ParserConfigurationException * @throws IOException * @throws SAXException */ private void validateExtendedSAMLAttributeForMandates( IAuthenticationSession session, IMISMandate mandate, boolean business) throws ValidateException, ConfigurationException, SAXException, IOException, ParserConfigurationException, TransformerException { ExtendedSAMLAttribute[] extendedSAMLAttributes = addExtendedSamlAttributes( mandate, business, false); int length = extendedSAMLAttributes.length; for (int i = 0; i < length; i++) { ExtendedSAMLAttribute samlAttribute = extendedSAMLAttributes[i]; verifySAMLAttribute(samlAttribute, i, "MISService", "MISService"); } } /** * Verifies the infoboxes (except of the identity link infobox) returned by * the BKU by calling appropriate validator classes. * * @param session The actual authentication session. * @param mandate The Mandate from the MIS * @throws AuthenticationException * @throws ConfigurationException * @throws TransformerException * @throws ParserConfigurationException * @throws IOException * @throws SAXException */ private void setExtendedSAMLAttributeForMandatesOID( IAuthenticationSession session, IMISMandate mandate, boolean business) throws ValidateException, ConfigurationException, SAXException, IOException, ParserConfigurationException, TransformerException { ExtendedSAMLAttribute[] extendedSamlAttributes = addExtendedSamlAttributesOID( mandate, business); AddAdditionalSAMLAttributes(session, extendedSamlAttributes, "MISService", "MISService"); } /** * Adds given SAML Attributes to the current session. They will be appended * to the final SAML Assertion or the AUTH block. If the attributes are * already in the list, they will be replaced. * * @param session The current session * @param extendedSAMLAttributes The SAML attributes to add * @param identifier The infobox identifier for debug purposes * @param friendlyNam The friendly name of the infobox for debug purposes */ private static void AddAdditionalSAMLAttributes( IAuthenticationSession session, ExtendedSAMLAttribute[] extendedSAMLAttributes, String identifier, String friendlyName) throws ValidateException { if (extendedSAMLAttributes == null) return; List oaAttributes = session.getExtendedSAMLAttributesOA(); if (oaAttributes == null) oaAttributes = new Vector(); List authAttributes = session.getExtendedSAMLAttributesAUTH(); if (authAttributes == null) authAttributes = new Vector(); int length = extendedSAMLAttributes.length; for (int i = 0; i < length; i++) { ExtendedSAMLAttribute samlAttribute = extendedSAMLAttributes[i]; Object value = verifySAMLAttribute(samlAttribute, i, identifier, friendlyName); if ((value instanceof String) || (value instanceof Element)) { switch (samlAttribute.getAddToAUTHBlock()) { case ExtendedSAMLAttribute.ADD_TO_AUTHBLOCK_ONLY: replaceExtendedSAMLAttribute(authAttributes, samlAttribute); break; case ExtendedSAMLAttribute.ADD_TO_AUTHBLOCK: replaceExtendedSAMLAttribute(authAttributes, samlAttribute); replaceExtendedSAMLAttribute(oaAttributes, samlAttribute); break; case ExtendedSAMLAttribute.NOT_ADD_TO_AUTHBLOCK: replaceExtendedSAMLAttribute(oaAttributes, samlAttribute); break; default: Logger .info("Invalid return value from method \"getAddToAUTHBlock()\" (" + samlAttribute.getAddToAUTHBlock() + ") in SAML attribute number " + (i + 1) + " for infobox " + identifier); throw new ValidateException("validator.47", new Object[]{ friendlyName, String.valueOf((i + 1))}); } } else { Logger .info("The type of SAML-Attribute number " + (i + 1) + " returned from " + identifier + "-infobox validator is not valid. Must be either \"java.Lang.String\"" + " or \"org.w3c.dom.Element\""); throw new ValidateException("validator.46", new Object[]{ identifier, String.valueOf((i + 1))}); } } session.setExtendedSAMLAttributesAUTH(authAttributes); session.setExtendedSAMLAttributesOA(oaAttributes); } /** * Adds the AUTH block related SAML attributes to the validation result. * This is needed always before the AUTH block is to be signed, because the * name of the mandator has to be set * * @throws ParserConfigurationException * @throws IOException * @throws SAXException * @throws TransformerException */ protected static ExtendedSAMLAttribute[] addExtendedSamlAttributes( IMISMandate mandate, boolean business, boolean provideStammzahl) throws SAXException, IOException, ParserConfigurationException, TransformerException { Vector extendedSamlAttributes = new Vector(); extendedSamlAttributes.clear(); // Name Element domMandate = mandateToElement(mandate); Element nameSpaceNode = domMandate.getOwnerDocument().createElement( "NameSpaceNode"); nameSpaceNode.setAttribute("xmlns" + SZRGWConstants.PD_POSTFIX, Constants.PD_NS_URI); nameSpaceNode.setAttribute("xmlns" + SZRGWConstants.MANDATE_POSTFIX, SZRGWConstants.MANDATE_NS); Element mandator = (Element) XPathAPI.selectSingleNode(domMandate, "//md:Mandate/md:Mandator", nameSpaceNode); // Mandate extendedSamlAttributes.add(new ExtendedSAMLAttributeImpl( EXT_SAML_MANDATE_RAW, domMandate, SZRGWConstants.MANDATE_NS, ExtendedSAMLAttribute.NOT_ADD_TO_AUTHBLOCK)); // (w)bpk String wbpk = ParepUtils.extractMandatorWbpk(mandator); if (!ParepUtils.isEmpty(wbpk)) { if (!ParepUtils.isPhysicalPerson(mandator)) { String idType = ParepUtils .extractMandatorIdentificationType(mandator); if (!ParepUtils.isEmpty(idType) && idType.startsWith(Constants.URN_PREFIX_BASEID)) { extendedSamlAttributes.add(new ExtendedSAMLAttributeImpl( EXT_SAML_MANDATE_CB_BASE_ID, ParepUtils.getRegisterString(idType) + ": " + wbpk, SZRGWConstants.MANDATE_NS, ExtendedSAMLAttribute.ADD_TO_AUTHBLOCK_ONLY)); } } else if (business) { extendedSamlAttributes.add(new ExtendedSAMLAttributeImpl( EXT_SAML_MANDATE_WBPK, wbpk, SZRGWConstants.MANDATE_NS, ExtendedSAMLAttribute.ADD_TO_AUTHBLOCK_ONLY)); } } ExtendedSAMLAttribute[] ret = new ExtendedSAMLAttribute[extendedSamlAttributes .size()]; extendedSamlAttributes.copyInto(ret); Logger.debug("ExtendedSAML Attributes: " + ret.length); return ret; } /** * Adds the AUTH block related SAML attributes to the validation result. * This is needed always before the AUTH block is to be signed, because the * name of the mandator has to be set * * @throws ParserConfigurationException * @throws IOException * @throws SAXException * @throws TransformerException */ private static ExtendedSAMLAttribute[] addExtendedSamlAttributesOID( IMISMandate mandate, boolean business) throws SAXException, IOException, ParserConfigurationException, TransformerException { Vector extendedSamlAttributes = new Vector(); extendedSamlAttributes.clear(); // RepresentationType extendedSamlAttributes.add(new ExtendedSAMLAttributeImpl( EXT_SAML_MANDATE_REPRESENTATIONTYPE, EXT_SAML_MANDATE_REPRESENTATIONTEXT, SZRGWConstants.MANDATE_NS, ExtendedSAMLAttribute.NOT_ADD_TO_AUTHBLOCK)); String oid = mandate.getProfRep(); if (oid != null) { extendedSamlAttributes.add(new ExtendedSAMLAttributeImpl( EXT_SAML_MANDATE_OID, oid, SZRGWConstants.MANDATE_NS, ExtendedSAMLAttribute.NOT_ADD_TO_AUTHBLOCK)); String oidDescription = mandate.getTextualDescriptionOfOID(); extendedSamlAttributes.add(new ExtendedSAMLAttributeImpl( EXT_SAML_MANDATE_OIDTEXTUALDESCRIPTION, oidDescription, SZRGWConstants.MANDATE_NS, ExtendedSAMLAttribute.NOT_ADD_TO_AUTHBLOCK)); } ExtendedSAMLAttribute[] ret = new ExtendedSAMLAttribute[extendedSamlAttributes .size()]; extendedSamlAttributes.copyInto(ret); Logger.debug("ExtendedSAML Attributes: " + ret.length); return ret; } /** * @param mandate * @return * @throws ParserConfigurationException * @throws IOException * @throws SAXException */ private static Element mandateToElement(IMISMandate mandate) throws SAXException, IOException, ParserConfigurationException { ByteArrayInputStream bais = new ByteArrayInputStream(mandate .getMandate()); Document doc = DOMUtils.parseDocumentSimple(bais); bais.close(); return doc.getDocumentElement(); } protected static void replaceExtendedSAMLAttribute(List attributes, ExtendedSAMLAttribute samlAttribute) { if (null == attributes) { attributes = new Vector(); } else { String id = samlAttribute.getName(); int length = attributes.size(); for (int i = 0; i < length; i++) { ExtendedSAMLAttribute att = (ExtendedSAMLAttribute) attributes .get(i); if (id.equals(att.getName())) { // replace attribute attributes.set(i, samlAttribute); return; } } attributes.add(samlAttribute); } } /** * Processes a <CreateXMLSignatureResponse> sent by the * security layer implementation.
*
    *
  • Validates given <CreateXMLSignatureResponse>
  • *
  • Parses <CreateXMLSignatureResponse> for error * codes
  • *
  • Parses authentication block enclosed in * <CreateXMLSignatureResponse>
  • *
  • Verifies authentication block by calling the MOA SP component
  • *
  • Creates authentication data
  • *
  • Creates a corresponding SAML artifact
  • *
  • Stores authentication data in the authentication data store indexed * by the SAML artifact
  • *
  • Deletes authentication session
  • *
  • Returns the SAML artifact, encoded BASE64
    New id of the authenticated MOA session or {@code null} in case of mandate mode (???)
  • *
* @param pendingReq * * @param sessionID session ID of the running authentication session * @param xmlCreateXMLSignatureReadResponse String representation of the * <CreateXMLSignatureResponse> * @return SAML artifact needed for retrieving authentication data, encoded * BASE64
New id of the authenticated MOA session or {@code null} in case of mandate mode (???) * @throws BKUException */ public void verifyAuthenticationBlock(IRequest pendingReq, IAuthenticationSession session, String xmlCreateXMLSignatureReadResponse) throws AuthenticationException, BuildException, ParseException, ConfigurationException, ServiceException, ValidateException, BKUException, EAAFBuilderException { if (session == null) throw new AuthenticationException("auth.10", new Object[]{ REQ_VERIFY_AUTH_BLOCK, PARAM_SESSIONID}); if (isEmpty(xmlCreateXMLSignatureReadResponse)) throw new AuthenticationException("auth.10", new Object[]{ REQ_VERIFY_AUTH_BLOCK, PARAM_XMLRESPONSE}); // parses CreateXMLSignatureResponse csresp = new CreateXMLSignatureResponseParser( xmlCreateXMLSignatureReadResponse).parseResponse(); try { String serializedAssertion = DOMUtils.serializeNode(csresp .getSamlAssertion()); session.setAuthBlock(serializedAssertion); } catch (TransformerException e) { throw new ParseException("parser.04", new Object[]{ REQ_VERIFY_AUTH_BLOCK, PARAM_XMLRESPONSE}, e); } catch (IOException e) { throw new ParseException("parser.04", new Object[]{ REQ_VERIFY_AUTH_BLOCK, PARAM_XMLRESPONSE}, e); } // validates if (pendingReq.needSingleSignOnFunctionality()) new CreateXMLSignatureResponseValidator().validateSSO(csresp, session, pendingReq); else new CreateXMLSignatureResponseValidator().validate(csresp, session, pendingReq, authConfig.getBasicConfigurationBoolean( ConfigurationProviderImpl.VALIDATION_AUTHBLOCK_TARGETFRIENDLYNAME, true)); // builds a for a MOA-SPSS call List vtids = authConfig.getMoaSpAuthBlockVerifyTransformsInfoIDs(); String tpid = authConfig.getMoaSpAuthBlockTrustProfileID(pendingReq.getServiceProviderConfiguration(IOAAuthParameters.class).isUseAuthBlockTestTestStore()); Element domVsreq = new VerifyXMLSignatureRequestBuilder().build(csresp, vtids, tpid); // debug output Element domVsresp = null; // try { // invokes the call domVsresp = SignatureVerificationInvoker.getInstance().verifyXMLSignature(domVsreq); // parses the IVerifiyXMLSignatureResponse vsresp = new VerifyXMLSignatureResponseParser( domVsresp).parseData(); if (Logger.isTraceEnabled()) { if (domVsresp != null) { try { String xmlVerifyXMLSignatureResponse = DOMUtils .serializeNode(domVsresp, true); Logger.trace("Signature from BKU: " + new LogMsg(xmlCreateXMLSignatureReadResponse)); Logger.trace("Signature verification request: " + new LogMsg(DOMUtils.serializeNode(domVsreq, true))); Logger.trace("Signature verification result: " + new LogMsg(xmlVerifyXMLSignatureResponse)); } catch (Throwable t) { t.printStackTrace(); Logger.info(new LogMsg(t.getStackTrace())); } } } IOAAuthParameters oaParam = pendingReq.getServiceProviderConfiguration(IOAAuthParameters.class); // validates the VerifyXMLSignatureResponseValidator.getInstance().validate(vsresp, null, VerifyXMLSignatureResponseValidator.CHECK_AUTH_BLOCK, oaParam, authConfig); // Compare AuthBlock Data with information stored in session, especially // date and time CreateXMLSignatureResponseValidator.getInstance().validateSigningDateTime(csresp); try { // compares the public keys from the identityLink with the AuthBlock VerifyXMLSignatureResponseValidator.getInstance().validateCertificate( vsresp, session.getIdentityLink()); } catch ( ValidateException e) { Logger.error("Signature verification error. ", e); Logger.error("Signed Data: " + session.getAuthBlock()); try { Logger.error("VerifyRequest: " + DOMUtils.serializeNode(domVsreq)); Logger.error("VerifyResponse: " + DOMUtils.serializeNode(domVsresp)); } catch (TransformerException e1) { e1.printStackTrace(); } catch (IOException e1) { e1.printStackTrace(); } throw e; } session.setXMLVerifySignatureResponse(vsresp); session.setSignerCertificate(vsresp.getX509certificate()); vsresp.setX509certificate(null); session.setForeigner(false); //set QAA Level four in case of card authentifcation session.setQAALevel(PVPConstants.EIDAS_QAA_HIGH); revisionsLogger.logEvent(pendingReq, MOAIDEventConstants.AUTHPROCESS_AUTHBLOCK_VALIDATED); revisionsLogger.logPersonalInformationEvent(pendingReq, session.getIdentityLink() ); } /** * Processes a <CreateXMLSignatureResponse> sent by the * security layer implementation.
*
    *
  • Validates given <CreateXMLSignatureResponse>
  • *
  • Parses <CreateXMLSignatureResponse> for error * codes
  • *
  • Parses authentication block enclosed in * <CreateXMLSignatureResponse>
  • *
  • Verifies authentication block by calling the MOA SP component
  • *
  • Creates authentication data
  • *
  • Creates a corresponding SAML artifact
  • *
  • Stores authentication data in the authentication data store indexed * by the SAML artifact
  • *
  • Deletes authentication session
  • *
  • Returns the SAML artifact, encoded BASE64
  • *
* * @param sessionID session ID of the running authentication session * @param xmlCreateXMLSignatureReadResponse String representation of the * <CreateXMLSignatureResponse> * @return SAML artifact needed for retrieving authentication data, encoded * BASE64 */ protected Element createIdentificationBPK(Element mandatePerson, String baseid, String target) throws BuildException, EAAFBuilderException { Element identificationBpK = mandatePerson.getOwnerDocument() .createElementNS(Constants.PD_NS_URI, "Identification"); Element valueBpK = mandatePerson.getOwnerDocument().createElementNS( Constants.PD_NS_URI, "Value"); Pair targedId = new BPKBuilder().generateAreaSpecificPersonIdentifier(baseid, target); valueBpK.appendChild(mandatePerson.getOwnerDocument().createTextNode( targedId.getFirst())); Element typeBpK = mandatePerson.getOwnerDocument().createElementNS( Constants.PD_NS_URI, "Type"); typeBpK.appendChild(mandatePerson.getOwnerDocument().createTextNode( "urn:publicid:gv.at:cdid+bpk")); identificationBpK.appendChild(valueBpK); identificationBpK.appendChild(typeBpK); return identificationBpK; } protected String getBaseId(Element mandatePerson) throws TransformerException, IOException { NodeList list = mandatePerson.getElementsByTagNameNS( Constants.PD_NS_URI, "Identification"); for (int i = 0; i < list.getLength(); i++) { Element identification = (Element) list.item(i); Element type = (Element) identification.getElementsByTagNameNS( Constants.PD_NS_URI, "Type").item(0); if (type.getTextContent().compareToIgnoreCase( "urn:publicid:gv.at:baseid") == 0) { Element value = (Element) identification .getElementsByTagNameNS(Constants.PD_NS_URI, "Value") .item(0); return value.getTextContent(); } } return null; } /** * Gets the foreign authentication data.
*
    *
  • Creates authentication data
  • *
  • Creates a corresponding SAML artifact
  • *
  • Stores authentication data in the authentication data store indexed * by the SAML artifact
  • *
  • Deletes authentication session
  • *
  • Returns the SAML artifact, encoded BASE64
  • *
* * @param sessionID session ID of the running authentication session * @return String "new Session" */ public void getForeignAuthenticationData(IAuthenticationSession session) throws AuthenticationException, BuildException, ParseException, ConfigurationException, ServiceException, ValidateException { if (session == null) throw new AuthenticationException("auth.10", new Object[]{ REQ_VERIFY_AUTH_BLOCK, PARAM_SESSIONID}); IVerifiyXMLSignatureResponse vsresp = new VerifyXMLSignatureResponse(); X509Certificate cert = session.getSignerCertificate(); vsresp.setX509certificate(cert); session.setXMLVerifySignatureResponse(vsresp); session.setSignerCertificate(vsresp.getX509certificate()); vsresp.setX509certificate(null); session.setForeigner(true); } /** * Checks a parameter. * * @param param parameter * @return true if the parameter is null or empty */ private boolean isEmpty(String param) { return param == null || param.length() == 0; } /** * Checks the correctness of SAML attributes and returns its value. * * @param param samlAttribute * @param i the number of the verified attribute for messages * @param identifier the infobox identifier for messages * @param friendlyname the friendly name of the infobox for messages * @return the SAML attribute value (Element or String) */ protected static Object verifySAMLAttribute( ExtendedSAMLAttribute samlAttribute, int i, String identifier, String friendlyName) throws ValidateException { String name = samlAttribute.getName(); if (name == null) { Logger.info("The name of SAML-Attribute number " + (i + 1) + " returned from " + identifier + "-infobox validator is null."); throw new ValidateException("validator.45", new Object[]{ friendlyName, "Name", String.valueOf((i + 1)), "null"}); } if (name == "") { Logger.info("The name of SAML-Attribute number " + (i + 1) + " returned from " + identifier + "-infobox validator is empty."); throw new ValidateException("validator.45", new Object[]{ friendlyName, "Name", String.valueOf((i + 1)), "leer"}); } if (samlAttribute.getNameSpace() == null) { Logger.info("The namespace of SAML-Attribute number " + (i + 1) + " returned from " + identifier + "-infobox validator is null."); throw new ValidateException("validator.45", new Object[]{friendlyName, "Namespace", String.valueOf((i + 1)), "null"}); } Object value = samlAttribute.getValue(); if (value == null) { Logger.info("The value of SAML-Attribute number " + (i + 1) + " returned from " + identifier + "-infobox validator is null."); throw new ValidateException("validator.45", new Object[]{ friendlyName, "Wert", String.valueOf((i + 1)), "null"}); } return value; } /** * 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 = null; if (nList != null && nList.getLength() != 0) { base64CertString = nList.item(0).getTextContent(); } 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)); X509Certificate cert; try { cert = new X509Certificate(is); return cert; } catch (Throwable e) { throw new CertificateException(e); } finally { try { is.close(); } catch (IOException e) { Logger.warn("Close InputStream failed." , e); } } } }