/* * Copyright 2003 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; import iaik.asn1.ObjectID; import iaik.pki.PKIException; import iaik.x509.X509Certificate; import iaik.x509.X509ExtensionInitException; import java.io.ByteArrayInputStream; 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.Iterator; import java.util.List; import java.util.Map; 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.auth.builder.AuthenticationBlockAssertionBuilder; import at.gv.egovernment.moa.id.auth.builder.BPKBuilder; import at.gv.egovernment.moa.id.auth.builder.CertInfoVerifyXMLSignatureRequestBuilder; import at.gv.egovernment.moa.id.auth.builder.CreateXMLSignatureRequestBuilder; import at.gv.egovernment.moa.id.auth.builder.DataURLBuilder; 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.builder.VerifyXMLSignatureRequestBuilder; 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.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.data.InfoboxValidationResult; 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.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.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.IdentityLinkAssertionParser; 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.servlet.PEPSConnectorServlet; import at.gv.egovernment.moa.id.auth.stork.STORKAuthnRequestProcessor; 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; 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.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.commons.db.dao.config.IdentificationNumber; import at.gv.egovernment.moa.id.commons.db.ex.MOADatabaseException; 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.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.data.AuthenticationData; import at.gv.egovernment.moa.id.storage.AssertionStorage; import at.gv.egovernment.moa.id.storage.AuthenticationSessionStoreage; import at.gv.egovernment.moa.id.storage.DBExceptionStoreImpl; import at.gv.egovernment.moa.id.util.HTTPUtils; import at.gv.egovernment.moa.id.util.MOAIDMessageProvider; import at.gv.egovernment.moa.id.util.Random; import at.gv.egovernment.moa.id.util.SSLUtils; import at.gv.egovernment.moa.id.util.client.mis.simple.MISMandate; import at.gv.egovernment.moa.logging.LogMsg; 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.FileUtils; import at.gv.egovernment.moa.util.MiscUtil; import at.gv.egovernment.moa.util.StringUtils; import at.gv.egovernment.moa.util.XPathUtils; 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.
{@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 * $ */ public class AuthenticationServer implements MOAIDAuthConstants { /** single instance */ private static AuthenticationServer instance; /** * time out in milliseconds used by {@link cleanup} for session store */ private long sessionTimeOutCreated = 15 * 60 * 1000; // default 10 minutes private long sessionTimeOutUpdated = 10 * 60 * 1000; // default 10 minutes /** * time out in milliseconds used by {@link cleanup} for authentication data * store */ private long authDataTimeOut = 2 * 60 * 1000; // default 2 minutes /** * Returns the single instance of AuthenticationServer. * * @return the single instance of AuthenticationServer */ public static AuthenticationServer getInstance() { if (instance == null) instance = new AuthenticationServer(); return instance; } /** * 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 scheme * determines the protocol used * @param sourceID * @return HTML form * @throws AuthenticationException * @see GetIdentityLinkFormBuilder * @see InfoboxReadRequestBuilder */ public String startAuthentication(AuthenticationSession session, String scheme) throws WrongParametersException, AuthenticationException, ConfigurationException, BuildException { if (session == null) { throw new AuthenticationException("auth.18", new Object[] { }); } //load OnlineApplication configuration OAAuthParameter oaParam = AuthConfigurationProvider.getInstance().getOnlineApplicationParameter(session.getPublicOAURLPrefix()); if (oaParam == null) throw new AuthenticationException("auth.00", new Object[] { session.getPublicOAURLPrefix() }); //load Template String template = null; if (session.getTemplateURL() != null) { try { template = new String(FileUtils.readURL(session.getTemplateURL())); } catch (IOException ex) { throw new AuthenticationException("auth.03", new Object[] { session.getTemplateURL(), ex.toString() }, ex); } } String infoboxReadRequest = ""; if (session.isSsoRequested()) { //load identityLink with SSO Target boolean isbuisness = false; String domainIdentifier = ""; IdentificationNumber ssobusiness = AuthConfigurationProvider.getInstance().getSSOBusinessService(); if (ssobusiness != null) { isbuisness = true; domainIdentifier = ssobusiness.getValue(); } //build ReadInfobox request infoboxReadRequest = new InfoboxReadRequestBuilder().build( isbuisness, domainIdentifier); } else { //build ReadInfobox request infoboxReadRequest = new InfoboxReadRequestBuilder().build( oaParam.getBusinessService(), oaParam .getIdentityLinkDomainIdentifier()); } String dataURL = new DataURLBuilder().buildDataURL( session.getAuthURL(), REQ_VERIFY_IDENTITY_LINK, session .getSessionID()); //removed in MOAID 2.0 String pushInfobox = ""; // VerifyInfoboxParameters verifyInfoboxParameters = oaParam // .getVerifyInfoboxParameters(); // if (verifyInfoboxParameters != null) { // pushInfobox = verifyInfoboxParameters.getPushInfobox(); // session.setPushInfobox(pushInfobox); // } //build CertInfo request String certInfoRequest = new CertInfoVerifyXMLSignatureRequestBuilder() .build(); String certInfoDataURL = new DataURLBuilder() .buildDataURL(session.getAuthURL(), REQ_START_AUTHENTICATION, session.getSessionID()); String htmlForm = new GetIdentityLinkFormBuilder().build(template, session.getBkuURL(), infoboxReadRequest, dataURL, certInfoRequest, certInfoDataURL, pushInfobox, oaParam); return htmlForm; } /** * 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 representation of the * <CreateXMLSignatureRequest> * @throws BKUException */ public String verifyIdentityLink(AuthenticationSession 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 }); AuthConfigurationProvider authConf = AuthConfigurationProvider .getInstance(); // 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 IdentityLink 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, authConf .getMoaSpIdentityLinkTrustProfileID()); // invokes the call Element domVerifyXMLSignatureResponse = new SignatureVerificationInvoker() .verifyXMLSignature(domVerifyXMLSignatureRequest); // parses the VerifyXMLSignatureResponse verifyXMLSignatureResponse = new VerifyXMLSignatureResponseParser( domVerifyXMLSignatureResponse).parseData(); OAAuthParameter oaParam = AuthConfigurationProvider.getInstance() .getOnlineApplicationParameter(session.getPublicOAURLPrefix()); // if OA is type is business service the manifest validation result has // to be ignored boolean ignoreManifestValidationResult = oaParam.getBusinessService() ? true : false; // validates the VerifyXMLSignatureResponseValidator.getInstance().validate( verifyXMLSignatureResponse, authConf.getIdentityLinkX509SubjectNames(), VerifyXMLSignatureResponseValidator.CHECK_IDENTITY_LINK, ignoreManifestValidationResult); session.setIdentityLink(identityLink); // now validate the extended infoboxes //Removed in MOA-ID 2.0 //verifyInfoboxes(session, infoboxReadResponseParameters, false); 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 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 String verifyCertificate(AuthenticationSession session, X509Certificate certificate) throws AuthenticationException, BuildException, ParseException, ConfigurationException, ValidateException, ServiceException, MOAIDException{ if (session == null) throw new AuthenticationException("auth.10", new Object[] { REQ_VERIFY_CERTIFICATE, PARAM_SESSIONID }); // 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); } AuthConfigurationProvider authConf = AuthConfigurationProvider .getInstance(); OAAuthParameter oaParam = AuthConfigurationProvider.getInstance() .getOnlineApplicationParameter(session.getPublicOAURLPrefix()); String returnvalue = getCreateXMLSignatureRequestAuthBlockOrRedirect(session, authConf, oaParam); return returnvalue; } /** * 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 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(AuthenticationSession session, MISMandate mandate) throws AuthenticationException, BuildException, ParseException, ConfigurationException, ValidateException, ServiceException { if (session == null) throw new AuthenticationException("auth.10", new Object[] { GET_MIS_SESSIONID, PARAM_SESSIONID }); OAAuthParameter oaParam = AuthConfigurationProvider.getInstance() .getOnlineApplicationParameter(session.getPublicOAURLPrefix()); try { // sets the extended SAML attributes for OID (Organwalter) setExtendedSAMLAttributeForMandatesOID(session, mandate, oaParam .getBusinessService()); validateExtendedSAMLAttributeForMandates(session, mandate, oaParam.getBusinessService()); } catch (SAXException e) { throw new AuthenticationException("auth.16", new Object[] { GET_MIS_SESSIONID }, e); } catch (IOException e) { throw new AuthenticationException("auth.16", new Object[] { GET_MIS_SESSIONID }, e); } catch (ParserConfigurationException e) { throw new AuthenticationException("auth.16", new Object[] { GET_MIS_SESSIONID }, e); } catch (TransformerException e) { throw new AuthenticationException("auth.16", new Object[] { GET_MIS_SESSIONID }, e); } } /** * * @param session * @param authConf * @param oaParam * @return * @throws ConfigurationException * @throws BuildException * @throws ValidateException */ public String getCreateXMLSignatureRequestAuthBlockOrRedirect( AuthenticationSession session, AuthConfigurationProvider authConf, OAAuthParameter oaParam) throws ConfigurationException, BuildException, ValidateException { // check for intermediate processing of the infoboxes if (session.isValidatorInputPending()) return "Redirect to Input Processor"; if (authConf == null) authConf = AuthConfigurationProvider.getInstance(); if (oaParam == null) oaParam = AuthConfigurationProvider.getInstance() .getOnlineApplicationParameter( session.getPublicOAURLPrefix()); // builds the AUTH-block String authBlock = buildAuthenticationBlock(session, oaParam); // builds the List transformsInfos = oaParam.getTransformsInfos(); if ((transformsInfos == null) || (transformsInfos.size() == 0)) { // no OA specific transforms specified, use default ones transformsInfos = authConf.getTransformsInfos(); } String createXMLSignatureRequest = new CreateXMLSignatureRequestBuilder() .build(authBlock, oaParam.getKeyBoxIdentifier(), transformsInfos); return createXMLSignatureRequest; } /** * Returns an CreateXMLSignatureRequest for signing the ERnP statement.
*
    *
  • Creates an CreateXMLSignatureRequest to be signed by the user
  • *
* * @param sessionID * ID of associated authentication session data * @param cert * The certificate from the user * @return String representation of the * <CreateXMLSignatureRequest> */ public String createXMLSignatureRequestForeignID(AuthenticationSession session, X509Certificate cert) throws AuthenticationException, BuildException, ParseException, ConfigurationException, ValidateException, ServiceException { if (session == null) throw new AuthenticationException("auth.10", new Object[] { REQ_VERIFY_CERTIFICATE, PARAM_SESSIONID }); AuthConfigurationProvider authConf = AuthConfigurationProvider .getInstance(); OAAuthParameter oaParam = AuthConfigurationProvider.getInstance() .getOnlineApplicationParameter(session.getPublicOAURLPrefix()); return getCreateXMLSignatureRequestForeigID(session, authConf, oaParam, cert); } public String getCreateXMLSignatureRequestForeigID( AuthenticationSession session, AuthConfigurationProvider authConf, OAAuthParameter oaParam, X509Certificate cert) throws ConfigurationException { // check for intermediate processing of the infoboxes if (session.isValidatorInputPending()) return "Redirect to Input Processor"; if (authConf == null) authConf = AuthConfigurationProvider.getInstance(); if (oaParam == null) oaParam = AuthConfigurationProvider.getInstance() .getOnlineApplicationParameter( session.getPublicOAURLPrefix()); Principal subject = cert.getSubjectDN(); String createXMLSignatureRequest = new CreateXMLSignatureRequestBuilder() .buildForeignID(subject.toString(), oaParam, session); 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 sessionID * ID of associated authentication session data * @param createXMLSignatureResponseParameters * The parameters from the response returned from the BKU * including the <CreateXMLSignatureResponse> * @throws BKUException */ public X509Certificate verifyXMLSignature(String sessionID, Map createXMLSignatureResponseParameters) throws AuthenticationException, BuildException, ParseException, ConfigurationException, ValidateException, ServiceException, BKUException { if (isEmpty(sessionID)) throw new AuthenticationException("auth.10", new Object[] { REQ_GET_FOREIGN_ID, PARAM_SESSIONID }); String xmlCreateXMLSignatureResponse = (String) createXMLSignatureResponseParameters .get(PARAM_XMLRESPONSE); if (isEmpty(xmlCreateXMLSignatureResponse)) throw new AuthenticationException("auth.10", new Object[] { REQ_GET_FOREIGN_ID, PARAM_XMLRESPONSE }); AuthConfigurationProvider authConf = AuthConfigurationProvider .getInstance(); // parses the CreateXMLSignatureResponseParser p = new CreateXMLSignatureResponseParser( xmlCreateXMLSignatureResponse); CreateXMLSignatureResponse createXMLSignatureResponse = p .parseResponseDsig(); // builds a for a call of MOA-SP Element domVerifyXMLSignatureRequest = new VerifyXMLSignatureRequestBuilder() .buildDsig(createXMLSignatureResponse, authConf .getMoaSpAuthBlockTrustProfileID()); // invokes the call Element domVerifyXMLSignatureResponse = new SignatureVerificationInvoker() .verifyXMLSignature(domVerifyXMLSignatureRequest); // parses the VerifyXMLSignatureResponse verifyXMLSignatureResponse = new VerifyXMLSignatureResponseParser( domVerifyXMLSignatureResponse).parseData(); return verifyXMLSignatureResponse.getX509certificate(); } /** * 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 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(String sessionID, Map readInfoboxResponseParameters) throws AuthenticationException, BuildException, ParseException, ConfigurationException, ValidateException, ServiceException, BKUException { if (isEmpty(sessionID)) throw new AuthenticationException("auth.10", new Object[] { REQ_VERIFY_CERTIFICATE, PARAM_SESSIONID }); 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(); return cert; } /** * Builds an authentication block <saml:Assertion> from * given session data. * * @param session * authentication session * * @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. */ private String buildAuthenticationBlock(AuthenticationSession session, OAAuthParameter oaParam) throws BuildException { IdentityLink identityLink = session.getIdentityLink(); String issuer = identityLink.getName(); String gebDat = identityLink.getDateOfBirth(); String identificationValue = null; String identificationType = null; //set empty AuthBlock BPK in case of OW or SSO or bpk is not requested if (session.isOW() || session.isSsoRequested() || oaParam.isRemovePBKFromAuthBlock()) { identificationType = ""; identificationValue = ""; } else if (identityLink.getIdentificationType().equals(Constants.URN_PREFIX_BASEID)) { if (oaParam.getBusinessService()) { String bpkBase64 = new BPKBuilder().buildWBPK(identityLink .getIdentificationValue(), oaParam.getIdentityLinkDomainIdentifier()); identificationValue = bpkBase64; if (oaParam.getIdentityLinkDomainIdentifier().startsWith(Constants.URN_PREFIX_WBPK + "+" )) identificationType = oaParam.getIdentityLinkDomainIdentifier(); else identificationType = Constants.URN_PREFIX_WBPK + "+" + oaParam.getIdentityLinkDomainIdentifier(); } else { String bpkBase64 = new BPKBuilder().buildBPK(identityLink .getIdentificationValue(), session.getTarget()); identificationValue = bpkBase64; identificationType = Constants.URN_PREFIX_CDID + "+" + session.getTarget(); } } else { identificationValue = identityLink.getIdentificationValue(); identificationType = identityLink.getIdentificationType(); } String issueInstant = DateTimeUtils.buildDateTimeUTC(Calendar .getInstance()); session.setIssueInstant(issueInstant); String authURL = session.getAuthURL(); String target = session.getTarget(); String targetFriendlyName = session.getTargetFriendlyName(); // Bug #485 // (https://egovlabs.gv.at/tracker/index.php?func=detail&aid=485&group_id=6&atid=105) // String oaURL = session.getPublicOAURLPrefix(); List extendedSAMLAttributes = session.getExtendedSAMLAttributesAUTH(); if (session.isSsoRequested()) { String oaURL =new String(); try { oaURL = AuthConfigurationProvider.getInstance().getSSOPublicUrl(); if (MiscUtil.isNotEmpty(oaURL)) oaURL = oaURL.replaceAll("&", "&"); } catch (ConfigurationException e) { } String authBlock = new AuthenticationBlockAssertionBuilder() .buildAuthBlockSSO(issuer, issueInstant, authURL, target, targetFriendlyName, identificationValue, identificationType, oaURL, gebDat, extendedSAMLAttributes, session, oaParam); return authBlock; } else { String oaURL = session.getPublicOAURLPrefix().replaceAll("&", "&"); String authBlock = new AuthenticationBlockAssertionBuilder() .buildAuthBlock(issuer, issueInstant, authURL, target, targetFriendlyName, identificationValue, identificationType, oaURL, gebDat, extendedSAMLAttributes, session, oaParam); 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( AuthenticationSession session, MISMandate 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( AuthenticationSession session, MISMandate 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( AuthenticationSession 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( MISMandate 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( MISMandate 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(MISMandate mandate) throws SAXException, IOException, ParserConfigurationException { ByteArrayInputStream bais = new ByteArrayInputStream(mandate .getMandate()); Document doc = DOMUtils.parseDocumentSimple(bais); 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
  • *
* * @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 * @throws BKUException */ public String verifyAuthenticationBlock(AuthenticationSession session, String xmlCreateXMLSignatureReadResponse) throws AuthenticationException, BuildException, ParseException, ConfigurationException, ServiceException, ValidateException, BKUException { 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 }); AuthConfigurationProvider authConf = AuthConfigurationProvider .getInstance(); // 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 }); } catch (IOException e) { throw new ParseException("parser.04", new Object[] { REQ_VERIFY_AUTH_BLOCK, PARAM_XMLRESPONSE }); } // validates if (session.isSsoRequested()) new CreateXMLSignatureResponseValidator().validateSSO(csresp, session); else new CreateXMLSignatureResponseValidator().validate(csresp, session); // builds a for a MOA-SPSS call List vtids = authConf.getMoaSpAuthBlockVerifyTransformsInfoIDs(); String tpid = authConf.getMoaSpAuthBlockTrustProfileID(); Element domVsreq = new VerifyXMLSignatureRequestBuilder().build(csresp, vtids, tpid); // debug output // invokes the call Element domVsresp = new SignatureVerificationInvoker() .verifyXMLSignature(domVsreq); // debug output // parses the VerifyXMLSignatureResponse vsresp = new VerifyXMLSignatureResponseParser( domVsresp).parseData(); if (Logger.isTraceEnabled()) { if (domVsresp != null) { try { String xmlVerifyXMLSignatureResponse = DOMUtils .serializeNode(domVsresp, true); Logger.trace(new LogMsg(xmlCreateXMLSignatureReadResponse)); Logger.trace(new LogMsg(xmlVerifyXMLSignatureResponse)); } catch (Throwable t) { t.printStackTrace(); Logger.info(new LogMsg(t.getStackTrace())); } } } // validates the VerifyXMLSignatureResponseValidator.getInstance().validate(vsresp, null, VerifyXMLSignatureResponseValidator.CHECK_AUTH_BLOCK, false); // Compare AuthBlock Data with information stored in session, especially // date and time CreateXMLSignatureResponseValidator.getInstance().validateSigningDateTime(csresp); // compares the public keys from the identityLink with the AuthBlock VerifyXMLSignatureResponseValidator.getInstance().validateCertificate( vsresp, session.getIdentityLink()); // post processing of the infoboxes Iterator iter = session.getInfoboxValidatorIterator(); boolean formpending = false; if (iter != null) { while (!formpending && iter.hasNext()) { Vector infoboxValidatorVector = (Vector) iter.next(); String identifier = (String) infoboxValidatorVector.get(0); String friendlyName = (String) infoboxValidatorVector.get(1); InfoboxValidator infoboxvalidator = (InfoboxValidator) infoboxValidatorVector .get(2); InfoboxValidationResult infoboxValidationResult = null; try { infoboxValidationResult = infoboxvalidator.validate(csresp .getSamlAssertion()); } catch (ValidateException e) { Logger.error("Error validating " + identifier + " infobox:" + e.getMessage()); throw new ValidateException("validator.44", new Object[] { friendlyName }); } if (!infoboxValidationResult.isValid()) { Logger.info("Validation of " + identifier + " infobox failed."); throw new ValidateException("validator.40", new Object[] { friendlyName, infoboxValidationResult.getErrorMessage() }); } String form = infoboxvalidator.getForm(); if (ParepUtils.isEmpty(form)) { AddAdditionalSAMLAttributes( session, infoboxValidationResult.getExtendedSamlAttributes(), identifier, friendlyName); } else { return "Redirect to Input Processor"; } } } session.setXMLVerifySignatureResponse(vsresp); session.setSignerCertificate(vsresp.getX509certificate()); vsresp.setX509certificate(null); session.setForeigner(false); if (session.getUseMandate()) { // mandate mode return null; } else { session.setAuthenticatedUsed(false); session.setAuthenticated(true); String oldsessionID = session.getSessionID(); //Session is implicte stored in changeSessionID!!! String newMOASessionID = AuthenticationSessionStoreage.changeSessionID(session); Logger.info("Changed MOASession " + oldsessionID + " to Session " + newMOASessionID); Logger.info("Daten angelegt zu MOASession " + newMOASessionID); return newMOASessionID; } } /** * 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 { Element identificationBpK = mandatePerson.getOwnerDocument() .createElementNS(Constants.PD_NS_URI, "Identification"); Element valueBpK = mandatePerson.getOwnerDocument().createElementNS( Constants.PD_NS_URI, "Value"); String bpkBase64 = new BPKBuilder().buildBPK(baseid, target); valueBpK.appendChild(mandatePerson.getOwnerDocument().createTextNode( bpkBase64)); 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 SAML artifact needed for retrieving authentication data, encoded * BASE64 */ public String getForeignAuthenticationData(AuthenticationSession session) throws AuthenticationException, BuildException, ParseException, ConfigurationException, ServiceException, ValidateException { if (session == null) throw new AuthenticationException("auth.10", new Object[] { REQ_VERIFY_AUTH_BLOCK, PARAM_SESSIONID }); // post processing of the infoboxes Iterator iter = session.getInfoboxValidatorIterator(); boolean formpending = false; if (iter != null) { while (!formpending && iter.hasNext()) { Vector infoboxValidatorVector = (Vector) iter.next(); String identifier = (String) infoboxValidatorVector.get(0); String friendlyName = (String) infoboxValidatorVector.get(1); InfoboxValidator infoboxvalidator = (InfoboxValidator) infoboxValidatorVector .get(2); InfoboxValidationResult infoboxValidationResult = null; try { infoboxValidationResult = infoboxvalidator.validate(session .getIdentityLink().getSamlAssertion()); } catch (ValidateException e) { Logger.error("Error validating " + identifier + " infobox:" + e.getMessage()); throw new ValidateException("validator.44", new Object[] { friendlyName }); } if (!infoboxValidationResult.isValid()) { Logger.info("Validation of " + identifier + " infobox failed."); throw new ValidateException("validator.40", new Object[] { friendlyName, infoboxValidationResult.getErrorMessage() }); } String form = infoboxvalidator.getForm(); if (ParepUtils.isEmpty(form)) { AddAdditionalSAMLAttributes( session, infoboxValidationResult.getExtendedSamlAttributes(), identifier, friendlyName); } else { return "Redirect to Input Processor"; } } } VerifyXMLSignatureResponse vsresp = new VerifyXMLSignatureResponse(); X509Certificate cert = session.getSignerCertificate(); vsresp.setX509certificate(cert); session.setAuthenticatedUsed(false); session.setAuthenticated(true); session.setXMLVerifySignatureResponse(vsresp); session.setSignerCertificate(vsresp.getX509certificate()); vsresp.setX509certificate(null); session.setForeigner(true); //TODO: regenerate MOASession ID! return "new Session"; } /** * Builds the AuthenticationData object together with the corresponding * <saml:Assertion> * * @param session * 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 * @throws BuildException * while building the <saml:Assertion> */ public static AuthenticationData buildAuthenticationData( AuthenticationSession session, OAAuthParameter oaParam, String target) throws ConfigurationException, BuildException { IdentityLink identityLink = session.getIdentityLink(); AuthenticationData authData = new AuthenticationData(); VerifyXMLSignatureResponse verifyXMLSigResp = session.getXMLVerifySignatureResponse(); boolean businessService = oaParam.getBusinessService(); authData.setMajorVersion(1); authData.setMinorVersion(0); authData.setAssertionID(Random.nextRandom()); authData.setIssuer(session.getAuthURL()); authData.setIssueInstant(DateTimeUtils.buildDateTimeUTC(Calendar .getInstance())); //baseID or wbpk in case of BusinessService without SSO or BusinessService SSO authData.setIdentificationValue(identityLink.getIdentificationValue()); authData.setIdentificationType(identityLink.getIdentificationType()); authData.setGivenName(identityLink.getGivenName()); authData.setFamilyName(identityLink.getFamilyName()); authData.setDateOfBirth(identityLink.getDateOfBirth()); authData.setQualifiedCertificate(verifyXMLSigResp .isQualifiedCertificate()); authData.setPublicAuthority(verifyXMLSigResp.isPublicAuthority()); authData.setPublicAuthorityCode(verifyXMLSigResp .getPublicAuthorityCode()); authData.setBkuURL(session.getBkuURL()); try { if (session.getUseMandate() && session.isOW()) { MISMandate mandate = session.getMISMandate(); authData.setBPK(mandate.getOWbPK()); authData.setBPKType(Constants.URN_PREFIX_CDID + "+" + "OW"); authData.setIdentityLink(identityLink); Logger.trace("Authenticated User is OW: " + mandate.getOWbPK()); } else { if (businessService) { //since we have foreigner, wbPK is not calculated in BKU if(identityLink.getIdentificationType().equals(Constants.URN_PREFIX_BASEID)) { String registerAndOrdNr = oaParam.getIdentityLinkDomainIdentifier(); if (registerAndOrdNr.startsWith(AuthenticationSession.REGISTERANDORDNR_PREFIX_)) { // If domainIdentifier starts with prefix // "urn:publicid:gv.at:wbpk+"; remove this prefix registerAndOrdNr = registerAndOrdNr .substring(AuthenticationSession.REGISTERANDORDNR_PREFIX_.length()); Logger.debug("Register and ordernumber prefix stripped off; resulting register string: " + registerAndOrdNr); } String wbpkBase64 = new BPKBuilder().buildWBPK(identityLink.getIdentificationValue(), registerAndOrdNr); authData.setBPK(wbpkBase64); authData.setBPKType( Constants.URN_PREFIX_WBPK + "+" + registerAndOrdNr); } else { authData.setBPK(identityLink.getIdentificationValue()); authData.setBPKType(identityLink.getIdentificationType()); } Logger.trace("Authenticate user with wbPK " + authData.getBPK()); Element idlassertion = session.getIdentityLink().getSamlAssertion(); //set bpk/wpbk; Node prIdentification = XPathUtils.selectSingleNode(idlassertion, IdentityLinkAssertionParser.PERSON_IDENT_VALUE_XPATH); prIdentification.getFirstChild().setNodeValue(authData.getBPK()); //set bkp/wpbk type Node prIdentificationType = XPathUtils.selectSingleNode(idlassertion, IdentityLinkAssertionParser.PERSON_IDENT_TYPE_XPATH); prIdentificationType.getFirstChild().setNodeValue(authData.getBPKType()); IdentityLinkAssertionParser idlparser = new IdentityLinkAssertionParser(idlassertion); IdentityLink idl = idlparser.parseIdentityLink(); authData.setIdentityLink(idl); } 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(), target); authData.setBPK(bpkBase64); authData.setBPKType(Constants.URN_PREFIX_CDID + "+" + oaParam.getTarget()); } Logger.trace("Authenticate user with bPK " + authData.getBPK()); authData.setIdentityLink(identityLink); } } return authData; } catch (Throwable ex) { throw new BuildException("builder.00", new Object[] { "AuthenticationData", ex.toString() }, ex); } } /** * Retrieves a session from the session store. * * @param id * session ID * @return AuthenticationSession stored with given session ID, * null if session ID unknown */ public static AuthenticationSession getSession(String id) throws AuthenticationException { AuthenticationSession session; try { session = AuthenticationSessionStoreage.getSession(id); if (session == null) throw new AuthenticationException("auth.02", new Object[] { id }); return session; } catch (MOADatabaseException e) { throw new AuthenticationException("parser.04", new Object[] { id }); } } /** * Cleans up expired session and authentication data stores. */ public void cleanup() { long now = new Date().getTime(); //clean AuthenticationSessionStore AuthenticationSessionStoreage.clean(now, sessionTimeOutCreated, sessionTimeOutUpdated); //clean AssertionStore AssertionStorage assertionstore = AssertionStorage.getInstance(); assertionstore.clean(now, authDataTimeOut); //clean ExeptionStore DBExceptionStoreImpl exstore = DBExceptionStoreImpl.getStore(); exstore.clean(now, authDataTimeOut); } /** * Sets the sessionTimeOut. * * @param seconds * Time out of the session in seconds */ public void setSecondsSessionTimeOutCreated(long seconds) { sessionTimeOutCreated = seconds * 1000; } public void setSecondsSessionTimeOutUpdated(long seconds) { sessionTimeOutUpdated = seconds * 1000; } /** * Sets the authDataTimeOut. * * @param seconds * Time out for signing AuthData in seconds */ public void setSecondsAuthDataTimeOut(long seconds) { authDataTimeOut = seconds * 1000; } /** * 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; } /** * 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, AuthenticationSession moasession) throws MOAIDException, AuthenticationException, WrongParametersException, ConfigurationException { if (moasession == null) { throw new AuthenticationException("auth.18", new Object[] { }); } //read configuration paramters of OA OAAuthParameter oaParam = AuthConfigurationProvider.getInstance().getOnlineApplicationParameter(moasession.getPublicOAURLPrefix()); if (oaParam == null) throw new AuthenticationException("auth.00", new Object[] { moasession.getPublicOAURLPrefix() }); //Start of STORK Processing STORKConfig storkConfig = AuthConfigurationProvider.getInstance().getStorkConfig(); CPEPS cpeps = storkConfig.getCPEPS(moasession.getCcc()); 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 = null; requestedAttributes = oaParam.getRequestedAttributes(); requestedAttributes.detach(); List reqAttributeList = new ArrayList(); List oaReqAttributeList = null; oaReqAttributeList = new ArrayList(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: " + moasession.getCcc()); Logger.debug("The following attributes are requested for this specific country:"); List countrySpecificReqAttributeList = new ArrayList(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) 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()); } } //TODO: check Target in case of SSO!! String spSector = StringUtils.isEmpty(moasession.getTarget()) ? "Business" : moasession.getTarget(); 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)); X509Certificate cert; try { cert = new X509Certificate(is); return cert; } catch (Throwable e) { throw new CertificateException(e); } } }