/* * Copyright 2003 Federal Chancellery Austria * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package at.gv.egovernment.moa.id.auth; import iaik.ixsil.exceptions.UtilsException; import iaik.ixsil.util.Utils; import iaik.pki.PKIException; import iaik.x509.X509Certificate; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.security.GeneralSecurityException; import java.security.Principal; import java.util.Calendar; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.Vector; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.TransformerException; import org.w3c.dom.Element; import org.xml.sax.SAXException; import HTTPClient.Util; import at.gv.egovernment.moa.id.AuthenticationException; import at.gv.egovernment.moa.id.BuildException; import at.gv.egovernment.moa.id.ParseException; import at.gv.egovernment.moa.id.ServiceException; import at.gv.egovernment.moa.id.auth.builder.AuthenticationBlockAssertionBuilder; import at.gv.egovernment.moa.id.auth.builder.AuthenticationDataAssertionBuilder; 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.InfoboxValidatorParamsBuilder; import at.gv.egovernment.moa.id.auth.builder.PersonDataBuilder; import at.gv.egovernment.moa.id.auth.builder.SAMLArtifactBuilder; import at.gv.egovernment.moa.id.auth.builder.SelectBKUFormBuilder; 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.IdentityLink; import at.gv.egovernment.moa.id.auth.data.InfoboxValidationResult; import at.gv.egovernment.moa.id.auth.data.InfoboxValidatorParams; import at.gv.egovernment.moa.id.auth.data.VerifyXMLSignatureResponse; import at.gv.egovernment.moa.id.auth.invoke.SignatureVerificationInvoker; import at.gv.egovernment.moa.id.auth.parser.CreateXMLSignatureResponseParser; import at.gv.egovernment.moa.id.auth.parser.ExtendedInfoboxReadResponseParser; import at.gv.egovernment.moa.id.auth.parser.InfoboxReadResponseParser; import at.gv.egovernment.moa.id.auth.parser.SAMLArtifactParser; import at.gv.egovernment.moa.id.auth.parser.VerifyXMLSignatureResponseParser; import at.gv.egovernment.moa.id.auth.servlet.AuthServlet; import at.gv.egovernment.moa.id.auth.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.ValidateException; import at.gv.egovernment.moa.id.auth.validator.VerifyXMLSignatureResponseValidator; import at.gv.egovernment.moa.id.auth.validator.parep.ParepUtils; import at.gv.egovernment.moa.id.auth.validator.parep.ParepValidator; import at.gv.egovernment.moa.id.auth.validator.parep.config.ParepConfiguration; import at.gv.egovernment.moa.id.config.ConfigurationException; import at.gv.egovernment.moa.id.config.ConfigurationProvider; 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.auth.VerifyInfoboxParameter; import at.gv.egovernment.moa.id.config.auth.VerifyInfoboxParameters; import at.gv.egovernment.moa.id.data.AuthenticationData; 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.logging.LogMsg; import at.gv.egovernment.moa.logging.Logger; import at.gv.egovernment.moa.util.Base64Utils; import at.gv.egovernment.moa.util.BoolUtils; 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.StringUtils; /** * 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$ */ public class AuthenticationServer implements MOAIDAuthConstants { /** single instance */ private static AuthenticationServer instance; /** session data store (session ID -> AuthenticationSession) */ private static Map sessionStore = new HashMap(); /** authentication data store (assertion handle -> AuthenticationData) */ private static Map authenticationDataStore = new HashMap(); /** * time out in milliseconds used by {@link cleanup} for session store */ private long sessionTimeOut = 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 request to select a BKU. *
Processing depends on value of {@link AuthConfigurationProvider#getBKUSelectionType}. *
For bkuSelectionType==HTMLComplete, a returnURI for the * "BKU Auswahl" service is returned. *
For bkuSelectionType==HTMLSelect, an HTML form for BKU selection is returned. * @param authURL base URL of MOA-ID Auth component * @param target "Geschäftsbereich" * @param oaURL online application URL requested * @param bkuSelectionTemplateURL template for BKU selection form to be used * in case of HTMLSelect; may be null * @param templateURL URL providing an HTML template for the HTML form to be used * for call startAuthentication * @return for bkuSelectionType==HTMLComplete, the returnURI for the * "BKU Auswahl" service; * for bkuSelectionType==HTMLSelect, an HTML form for BKU selection * @throws WrongParametersException upon missing parameters * @throws AuthenticationException when the configured BKU selection service cannot be reached, * and when the given bkuSelectionTemplateURL cannot be reached * @throws ConfigurationException on missing configuration data * @throws BuildException while building the HTML form */ public String selectBKU( String authURL, String target, String oaURL, String bkuSelectionTemplateURL, String templateURL) throws WrongParametersException, AuthenticationException, ConfigurationException, BuildException { //check if HTTP Connection may be allowed (through FRONTEND_SERVLETS_ENABLE_HTTP_CONNECTION_PROPERTY) String boolStr = AuthConfigurationProvider.getInstance().getGenericConfigurationParameter( AuthConfigurationProvider.FRONTEND_SERVLETS_ENABLE_HTTP_CONNECTION_PROPERTY); if ((!authURL.startsWith("https:")) && (false == BoolUtils.valueOf(boolStr))) throw new AuthenticationException("auth.07", new Object[] { authURL + "*" }); if (isEmpty(authURL)) throw new WrongParametersException("StartAuthentication", "AuthURL", "auth.5"); if (isEmpty(oaURL)) throw new WrongParametersException("StartAuthentication", PARAM_OA, "auth.5"); ConnectionParameter bkuConnParam = AuthConfigurationProvider.getInstance().getBKUConnectionParameter(); if (bkuConnParam == null) throw new ConfigurationException( "config.08", new Object[] { "BKUSelection/ConnectionParameter" }); OAAuthParameter oaParam = AuthConfigurationProvider.getInstance().getOnlineApplicationParameter(oaURL); if (oaParam == null) throw new AuthenticationException("auth.00", new Object[] { oaURL }); if (!oaParam.getBusinessService()) { if (isEmpty(target)) throw new WrongParametersException("StartAuthentication", PARAM_TARGET, "auth.5"); } else { if (!isEmpty(target)) { Logger.info("Ignoring target parameter thus application type is \"businessService\""); } target = null; } AuthenticationSession session = newSession(); Logger.info("MOASession " + session.getSessionID() + " angelegt"); session.setTarget(target); session.setOAURLRequested(oaURL); session.setPublicOAURLPrefix(oaParam.getPublicURLPrefix()); session.setAuthURL(authURL); session.setTemplateURL(templateURL); session.setBusinessService(oaParam.getBusinessService()); String returnURL = new DataURLBuilder().buildDataURL(authURL, REQ_START_AUTHENTICATION, session.getSessionID()); String bkuSelectionType = AuthConfigurationProvider.getInstance().getBKUSelectionType(); if (bkuSelectionType.equals(AuthConfigurationProvider.BKU_SELECTION_TYPE_HTMLCOMPLETE)) { // bkuSelectionType==HTMLComplete String redirectURL = bkuConnParam.getUrl() + "?" + AuthServlet.PARAM_RETURN + "=" + returnURL; return redirectURL; } else { // bkuSelectionType==HTMLSelect String bkuSelectTag; try { bkuSelectTag = readBKUSelectTag(AuthConfigurationProvider.getInstance(), bkuConnParam); } catch (Throwable ex) { throw new AuthenticationException( "auth.11", new Object[] { bkuConnParam.getUrl(), ex.toString()}, ex); } String bkuSelectionTemplate = null; // override template url by url from configuration file if (oaParam.getBkuSelectionTemplateURL() != null) { bkuSelectionTemplateURL = oaParam.getBkuSelectionTemplateURL(); } if (bkuSelectionTemplateURL != null) { try { bkuSelectionTemplate = new String(FileUtils.readURL(bkuSelectionTemplateURL)); } catch (IOException ex) { throw new AuthenticationException( "auth.03", new Object[] { bkuSelectionTemplateURL, ex.toString()}, ex); } } String htmlForm = new SelectBKUFormBuilder().build(bkuSelectionTemplate, returnURL, bkuSelectTag); return htmlForm; } } /** * Method readBKUSelectTag. * @param conf the ConfigurationProvider * @param connParam the ConnectionParameter for that connection * @return String * @throws ConfigurationException on config-errors * @throws PKIException on PKI errors * @throws IOException on any data error * @throws GeneralSecurityException on security errors */ private String readBKUSelectTag(ConfigurationProvider conf, ConnectionParameter connParam) throws ConfigurationException, PKIException, IOException, GeneralSecurityException { if (connParam.isHTTPSURL()) return SSLUtils.readHttpsURL(conf, connParam); else return HTTPUtils.readHttpURL(connParam.getUrl()); } /** * 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 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 templateURL URL providing an HTML template for the HTML form generated * @param scheme determines the protocol used * @return HTML form * @throws AuthenticationException * @see GetIdentityLinkFormBuilder * @see InfoboxReadRequestBuilder */ public String startAuthentication( String authURL, String target, String oaURL, String templateURL, String bkuURL, String sessionID, String scheme) throws WrongParametersException, AuthenticationException, ConfigurationException, BuildException { if (isEmpty(sessionID)) { if (isEmpty(authURL)) throw new WrongParametersException("StartAuthentication", "AuthURL", "auth.5"); //check if HTTP Connection may be allowed (through FRONTEND_SERVLETS_ENABLE_HTTP_CONNECTION_PROPERTY) String boolStr = AuthConfigurationProvider.getInstance().getGenericConfigurationParameter( AuthConfigurationProvider.FRONTEND_SERVLETS_ENABLE_HTTP_CONNECTION_PROPERTY); if ((!authURL.startsWith("https:")) && (false == BoolUtils.valueOf(boolStr))) throw new AuthenticationException("auth.07", new Object[] { authURL + "*" }); if (isEmpty(oaURL)) throw new WrongParametersException("StartAuthentication", PARAM_OA, "auth.5"); } AuthenticationSession session; OAAuthParameter oaParam; if (sessionID != null) { session = getSession(sessionID); oaParam = AuthConfigurationProvider.getInstance().getOnlineApplicationParameter( session.getPublicOAURLPrefix()); } else { oaParam = AuthConfigurationProvider.getInstance().getOnlineApplicationParameter(oaURL); if (oaParam == null) throw new AuthenticationException("auth.00", new Object[] { oaURL }); if (!oaParam.getBusinessService()) { if (isEmpty(target)) throw new WrongParametersException("StartAuthentication", PARAM_TARGET, "auth.5"); } else { target = null; } session = newSession(); Logger.info("MOASession " + session.getSessionID() + " angelegt"); session.setTarget(target); session.setOAURLRequested(oaURL); session.setPublicOAURLPrefix(oaParam.getPublicURLPrefix()); session.setAuthURL(authURL); session.setTemplateURL(templateURL); session.setBusinessService(oaParam.getBusinessService()); } // BKU URL has not been set yet, even if session already exists if (bkuURL == null) { if (scheme!=null && scheme.equalsIgnoreCase("https")) { bkuURL = DEFAULT_BKU_HTTPS; } else { bkuURL = DEFAULT_BKU; } } session.setBkuURL(bkuURL); session.setDomainIdentifier(oaParam.getIdentityLinkDomainIdentifier()); String infoboxReadRequest = new InfoboxReadRequestBuilder().build(oaParam.getSlVersion12(), oaParam.getBusinessService(), oaParam.getIdentityLinkDomainIdentifier()); String dataURL = new DataURLBuilder().buildDataURL( session.getAuthURL(), REQ_VERIFY_IDENTITY_LINK, session.getSessionID()); String template = null; // override template url by url from configuration file if (oaParam.getTemplateURL() != null) { templateURL = oaParam.getTemplateURL(); } else { templateURL = session.getTemplateURL(); } if (templateURL != null) { try { template = new String(FileUtils.readURL(templateURL)); } catch (IOException ex) { throw new AuthenticationException( "auth.03", new Object[] { templateURL, ex.toString()}, ex); } } String pushInfobox = ""; VerifyInfoboxParameters verifyInfoboxParameters = oaParam.getVerifyInfoboxParameters(); if (verifyInfoboxParameters != null) { pushInfobox = verifyInfoboxParameters.getPushInfobox(); session.setPushInfobox(pushInfobox); } String certInfoRequest = new CertInfoVerifyXMLSignatureRequestBuilder().build(oaParam.getSlVersion12()); String certInfoDataURL = new DataURLBuilder().buildDataURL( session.getAuthURL(), REQ_START_AUTHENTICATION, session.getSessionID()); String htmlForm = new GetIdentityLinkFormBuilder().build( template, bkuURL, infoboxReadRequest, dataURL, certInfoRequest, certInfoDataURL, pushInfobox); 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> */ public String verifyIdentityLink(String sessionID, Map infoboxReadResponseParameters) throws AuthenticationException, BuildException, ParseException, ConfigurationException, ValidateException, ServiceException { if (isEmpty(sessionID)) 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}); AuthenticationSession session = getSession(sessionID); if (session.getTimestampIdentityLink() != null) throw new AuthenticationException("auth.01", new Object[] { sessionID }); session.setTimestampIdentityLink(); 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); if (b) { // no identity link found Logger.info("Es konnte keine Personenbindung auf der Karte gefunden werden. Versuche Anmeldung als ausländische eID."); return null; } // spezifikationsgemäßer (SL1.2) Errorcode se = "ErrorCode>4002"; b = xmlInfoboxReadResponse.contains(se); if (b) { // Unbekannter Infoboxbezeichner Logger.info("Unbekannter Infoboxbezeichner. Versuche Anmeldung als ausländische eID."); return null; } // for testing new identity link certificate // https://localhost:8443/moa-id-auth/StartAuthentication?Target=AR&OA=https://localhost:8443/TestMOAID_OA/LoginServletExample // xmlInfoboxReadResponse = null; // try { // File file = new File("c:/temp/xxxMuster-new-cert_infobox.xml"); // FileInputStream fis; // // fis = new FileInputStream(file); // byte[] array = Utils.readFromInputStream(fis); // // xmlInfoboxReadResponse = new String(array); // //System.out.println(xmlInfoboxReadResponse); // // } catch (FileNotFoundException e) { // // TODO Auto-generated catch block // e.printStackTrace(); // } catch (UtilsException e) { // // TODO Auto-generated catch block // e.printStackTrace(); // } // // 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(); if (identityLink.getIdentificationType().equalsIgnoreCase(Constants.URN_PREFIX_BASEID)) { } 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 verifyInfoboxes(session, infoboxReadResponseParameters, !oaParam.getProvideStammzahl()); return getCreateXMLSignatureRequestAuthBlockOrRedirect(session, authConf, oaParam); } 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()); //BZ.., calculate bPK for signing to be already present in AuthBlock IdentityLink identityLink = session.getIdentityLink(); if (identityLink.getIdentificationType().equals(Constants.URN_PREFIX_BASEID)) { // only compute bPK if online application is a public service and we have the Stammzahl String bpkBase64 = new BPKBuilder().buildBPK( identityLink.getIdentificationValue(), session.getTarget()); identityLink.setIdentificationValue(bpkBase64); } //..BZ // builds the AUTH-block String authBlock = buildAuthenticationBlock(session); // session.setAuthBlock(authBlock); // builds the String[] transformsInfos = oaParam.getTransformsInfos(); if ((transformsInfos == null) || (transformsInfos.length == 0)) { // no OA specific transforms specified, use default ones transformsInfos = authConf.getTransformsInfos(); } String createXMLSignatureRequest = new CreateXMLSignatureRequestBuilder().build(authBlock, oaParam.getKeyBoxIdentifier(), transformsInfos, oaParam.getSlVersion12()); 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(String sessionID, X509Certificate cert) throws AuthenticationException, BuildException, ParseException, ConfigurationException, ValidateException, ServiceException { if (isEmpty(sessionID)) throw new AuthenticationException("auth.10", new Object[] { REQ_VERIFY_CERTIFICATE, PARAM_SESSIONID}); AuthenticationSession session = getSession(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> */ public X509Certificate verifyXMLSignature(String sessionID, Map createXMLSignatureResponseParameters) throws AuthenticationException, BuildException, ParseException, ConfigurationException, ValidateException, ServiceException { 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}); AuthenticationSession session = getSession(sessionID); /*if (session.getTimestampIdentityLink() != null) throw new AuthenticationException("auth.01", new Object[] { sessionID });*/ //session.setTimestampIdentityLink(); 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(); //int code = verifyXMLSignatureResponse.getSignatureCheckCode(); 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> */ public X509Certificate getCertificate(String sessionID, Map readInfoboxResponseParameters) throws AuthenticationException, BuildException, ParseException, ConfigurationException, ValidateException, ServiceException { 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) throws BuildException { IdentityLink identityLink = session.getIdentityLink(); String issuer = identityLink.getName(); String gebDat = identityLink.getDateOfBirth(); String identificationValue = identityLink.getIdentificationValue(); String identificationType = identityLink.getIdentificationType(); String issueInstant = DateTimeUtils.buildDateTime(Calendar.getInstance()); session.setIssueInstant(issueInstant); String authURL = session.getAuthURL(); String target = session.getTarget(); //Bug #485 (https://egovlabs.gv.at/tracker/index.php?func=detail&aid=485&group_id=6&atid=105) //String oaURL = session.getPublicOAURLPrefix(); String oaURL = session.getPublicOAURLPrefix().replaceAll("&", "&"); List extendedSAMLAttributes = session.getExtendedSAMLAttributesAUTH(); String authBlock = new AuthenticationBlockAssertionBuilder().buildAuthBlock( issuer, issueInstant, authURL, target, identificationValue, identificationType, oaURL, gebDat, extendedSAMLAttributes, session); 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 infoboxReadResponseParams The parameters returned from the BKU as response * to an infobox read request (including the infobox * tokens to be verified). * @param hideStammzahl Indicates whether source pins (Stammzahlen) * should be hidden in any SAML attribute that may be * returned by a validator. * * @throws AuthenticationException If the verification of at least one infobox fails. * @throws ConfigurationException If the OAuthParameter cannot be extracted. */ private void verifyInfoboxes( AuthenticationSession session, Map infoboxReadResponseParams, boolean hideStammzahl) throws ValidateException, ConfigurationException { AuthConfigurationProvider authConfigurationProvider = AuthConfigurationProvider.getInstance(); // get the default VerifyInfobox parameters Map defaultInfoboxParameters = null; VerifyInfoboxParameters defaultVerifyInfoboxParameters = authConfigurationProvider.getDefaultVerifyInfoboxParameters(); if (defaultVerifyInfoboxParameters != null) { defaultInfoboxParameters = defaultVerifyInfoboxParameters.getInfoboxParameters(); } // get the OA specific VerifyInfobox parameters Map infoboxParameters = null; OAAuthParameter oaParam = authConfigurationProvider.getOnlineApplicationParameter(session.getPublicOAURLPrefix()); VerifyInfoboxParameters verifyInfoboxParameters = oaParam.getVerifyInfoboxParameters(); if (verifyInfoboxParameters != null) { session.setExtendedSAMLAttributesAUTH(new Vector()); // Initialize SAML Attributes session.setExtendedSAMLAttributesOA(new Vector()); infoboxParameters = verifyInfoboxParameters.getInfoboxParameters(); // get the list of infobox identifiers List identifiers = verifyInfoboxParameters.getIdentifiers(); if (identifiers != null) { // step through the identifiers and verify the infoboxes Iterator it = identifiers.iterator(); while (it.hasNext()) { String identifier = (String)it.next(); // get the infobox read response from the map of parameters String infoboxReadResponse = (String)infoboxReadResponseParams.get(identifier); // get the configuration parameters VerifyInfoboxParameter verifyInfoboxParameter = null; Object object = infoboxParameters.get(identifier); // if not present, use default if ((object == null) && (defaultInfoboxParameters != null)) { object = defaultInfoboxParameters.get(identifier); } if (object != null) { verifyInfoboxParameter = (VerifyInfoboxParameter)object; } if (infoboxReadResponse != null) { if (verifyInfoboxParameter == null) { // should not happen because of the pushinfobox mechanism; check it anyway Logger.error("No validator for verifying \"" + identifier + "\"-infobox configured."); throw new ValidateException("validator.41", new Object[] {identifier}); } else { String friendlyName = verifyInfoboxParameter.getFriendlyName(); boolean isParepRequest = false; // parse the infobox read reponse List infoboxTokenList = null; try { infoboxTokenList = ExtendedInfoboxReadResponseParser.parseInfoboxReadResponse(infoboxReadResponse, friendlyName); } catch (ParseException e) { Logger.error("InfoboxReadResponse for \"" + identifier + "\"-infobox could not be parsed successfully: " + e.getMessage()); throw new ValidateException("validator.43", new Object[] {friendlyName}); } // set compatibility mode for mandates infobox and all infoboxes (it is possible to be a parep infobox) session.setMandateCompatibilityMode(ParepConfiguration.isMandateCompatibilityMode(verifyInfoboxParameter.getApplicationSpecificParams())); // check for party representation in mandates infobox if (Constants.INFOBOXIDENTIFIER_MANDATES.equalsIgnoreCase(identifier) && !((infoboxTokenList == null || infoboxTokenList.size() == 0))){ //We need app specific parameters if (null==verifyInfoboxParameter.getApplicationSpecificParams()) { throw new ValidateException("validator.66", new Object[] {friendlyName}); } Element mandate = ParepValidator.extractPrimaryToken(infoboxTokenList); //ParepUtils.serializeElement(mandate, System.out); String mandateID = ParepUtils.extractRepresentativeID(mandate); if (!isEmpty(mandateID) && ("*".equals(mandateID) || mandateID.startsWith(MOAIDAuthConstants.PARTY_REPRESENTATION_OID_NUMBER))) { isParepRequest = true; } if (!isParepRequest) { //if mandates validator is disabled we must throw an error in this case if (!ParepUtils.isValidatorEnabled(verifyInfoboxParameter.getApplicationSpecificParams())) { throw new ValidateException("validator.60", new Object[] {friendlyName}); } } } // get the class for validating the infobox InfoboxValidator infoboxValidator = null; try { Class validatorClass = null; if (isParepRequest) { // Mandates infobox in party representation mode validatorClass = Class.forName("at.gv.egovernment.moa.id.auth.validator.parep.ParepValidator"); } else { validatorClass = Class.forName(verifyInfoboxParameter.getValidatorClassName()); } infoboxValidator = (InfoboxValidator) validatorClass.newInstance(); } catch (Exception e) { Logger.error("Could not load validator class \"" + verifyInfoboxParameter.getValidatorClassName() + "\" for \"" + identifier + "\"-infobox: " + e.getMessage()); throw new ValidateException("validator.42", new Object[] {friendlyName}); } Logger.debug("Successfully loaded validator class \"" + verifyInfoboxParameter.getValidatorClassName() + "\" for \"" + identifier + "\"-infobox."); // build the parameters for validating the infobox InfoboxValidatorParams infoboxValidatorParams = InfoboxValidatorParamsBuilder.buildInfoboxValidatorParams( session, verifyInfoboxParameter, infoboxTokenList, oaParam); // now validate the infobox InfoboxValidationResult infoboxValidationResult = null; try { infoboxValidationResult = infoboxValidator.validate(infoboxValidatorParams); } 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()}); } Logger.info(identifier + " infobox successfully validated."); // store the validator for post processing session.addInfoboxValidator(identifier, friendlyName, infoboxValidator); // get the SAML attributes to be appended to the AUTHBlock or to the final // SAML Assertion AddAdditionalSAMLAttributes(session, infoboxValidationResult.getExtendedSamlAttributes(), identifier, friendlyName); } } else { if ((verifyInfoboxParameter !=null) && (verifyInfoboxParameter.isRequired())) { Logger.info("Infobox \"" + identifier + "\" is required, but not returned from the BKU"); throw new ValidateException( "validator.48", new Object[] {verifyInfoboxParameter.getFriendlyName()}); } Logger.debug("Infobox \"" + identifier + "\" not returned from BKU."); } } } } } /** * Intermediate processing of the infoboxes. The first pending infobox * validator may validate the provided input * * @param session The current authentication session * @param parameters The parameters got returned by the user input fields */ public static void processInput(AuthenticationSession session, Map parameters) throws ValidateException { // post processing of the infoboxes Iterator iter = session.getInfoboxValidatorIterator(); if (iter != null) { while (iter.hasNext()) { Vector infoboxValidatorVector = (Vector) iter.next(); InfoboxValidator infoboxvalidator = (InfoboxValidator) infoboxValidatorVector.get(2); if (!ParepUtils.isEmpty(infoboxvalidator.getForm())) { String identifier = (String) infoboxValidatorVector.get(0); String friendlyName = (String) infoboxValidatorVector.get(1); InfoboxValidationResult infoboxValidationResult = null; try { infoboxValidationResult = infoboxvalidator.validate(parameters); } 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()}); } AddAdditionalSAMLAttributes(session, infoboxValidationResult.getExtendedSamlAttributes(), identifier, friendlyName); } } } } /** * 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<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 */ public String verifyAuthenticationBlock( String sessionID, String xmlCreateXMLSignatureReadResponse) throws AuthenticationException, BuildException, ParseException, ConfigurationException, ServiceException, ValidateException { if (isEmpty(sessionID)) 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}); AuthenticationSession session = getSession(sessionID); 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 new CreateXMLSignatureResponseValidator().validate(csresp, session); // builds a for a MOA-SPSS call String[] 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); // TODO See Bug #144 // Compare AuthBlock Data with information stored in session, especially date and time // 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"; } } } // Exchange person data information by a mandate if needed List oaAttributes = session.getExtendedSAMLAttributesOA(); IdentityLink replacementIdentityLink = null; if (session.isMandateCompatibilityMode() && oaAttributes != null && oaAttributes.size()>0) { // look if we have a mandate boolean foundMandate = false; Iterator it = oaAttributes.iterator(); while (!foundMandate && it.hasNext()) { ExtendedSAMLAttribute samlAttribute = (ExtendedSAMLAttribute)it.next(); if (ParepValidator.EXT_SAML_MANDATE_RAW.equals(samlAttribute.getName())) { Object value = samlAttribute.getValue(); if (value instanceof Element) { Element mandate = (Element) value; replacementIdentityLink = new IdentityLink(); Element mandator = ParepUtils.extractMandator(mandate); String dateOfBirth = ""; Element prPerson = null; String familyName = ""; String givenName = ""; String identificationType = ""; String identificationValue = ""; if (mandator != null) { boolean physical = ParepUtils.isPhysicalPerson(mandator); if (physical) { familyName = ParepUtils.extractText(mandator, "descendant-or-self::pr:Name/pr:FamilyName/text()"); givenName = ParepUtils.extractText(mandator, "descendant-or-self::pr:Name/pr:GivenName/text()"); dateOfBirth = ParepUtils.extractMandatorDateOfBirth(mandator); } else { familyName = ParepUtils.extractMandatorFullName(mandator); } identificationType = ParepUtils.getIdentification(mandator, "Type"); identificationValue = ParepUtils.extractMandatorWbpk(mandator); prPerson = ParepUtils.extractPrPersonOfMandate(mandate); if (physical && session.getBusinessService() && identificationType!=null && Constants.URN_PREFIX_BASEID.equals(identificationType)) { // now we calculate the wbPK and do so if we got it from the BKU identificationType = Constants.URN_PREFIX_WBPK + "+" + session.getDomainIdentifier(); identificationValue = new BPKBuilder().buildWBPK(identificationValue, session.getDomainIdentifier()); ParepUtils.HideStammZahlen(prPerson, true, null, null, true); } } replacementIdentityLink.setDateOfBirth(dateOfBirth); replacementIdentityLink.setFamilyName(familyName); replacementIdentityLink.setGivenName(givenName); replacementIdentityLink.setIdentificationType(identificationType); replacementIdentityLink.setIdentificationValue(identificationValue); replacementIdentityLink.setPrPerson(prPerson); try { replacementIdentityLink.setSamlAssertion(session.getIdentityLink().getSamlAssertion()); } catch (Exception e) { throw new ValidateException("validator.64", null); } } else { Logger.info("The type of Mandate SAML-Attribute is not \"org.w3c.dom.Element\""); throw new ValidateException("validator.64", null); } } } } // builds authentication data and stores it together with a SAML artifact AuthenticationData authData = buildAuthenticationData(session, vsresp, replacementIdentityLink); String samlArtifact = new SAMLArtifactBuilder().build(session.getAuthURL(), session.getSessionID()); storeAuthenticationData(samlArtifact, authData); // invalidates the authentication session sessionStore.remove(sessionID); Logger.info( "Anmeldedaten zu MOASession " + sessionID + " angelegt, SAML Artifakt " + samlArtifact); return samlArtifact; } /** * 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( String sessionID) throws AuthenticationException, BuildException, ParseException, ConfigurationException, ServiceException, ValidateException { if (isEmpty(sessionID)) throw new AuthenticationException("auth.10", new Object[] { REQ_VERIFY_AUTH_BLOCK, PARAM_SESSIONID}); AuthenticationSession session = getSession(sessionID); //AuthConfigurationProvider authConf = AuthConfigurationProvider.getInstance(); try { String serializedAssertion = DOMUtils.serializeNode(session.getIdentityLink().getSamlAssertion()); session.setAuthBlock(serializedAssertion); } catch (TransformerException e) { throw new ParseException("parser.04", new Object[] { REQ_VERIFY_AUTH_BLOCK, PARAM_XMLRESPONSE}); } catch (IOException e) { throw new ParseException("parser.04", new Object[] { REQ_VERIFY_AUTH_BLOCK, PARAM_XMLRESPONSE}); } // post processing of the infoboxes Iterator iter = session.getInfoboxValidatorIterator(); boolean formpending = false; 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"; } } } // Exchange person data information by a mandate if needed List oaAttributes = session.getExtendedSAMLAttributesOA(); IdentityLink replacementIdentityLink = null; if (session.isMandateCompatibilityMode() && oaAttributes != null && oaAttributes.size()>0) { // look if we have a mandate boolean foundMandate = false; Iterator it = oaAttributes.iterator(); while (!foundMandate && it.hasNext()) { ExtendedSAMLAttribute samlAttribute = (ExtendedSAMLAttribute)it.next(); if (ParepValidator.EXT_SAML_MANDATE_RAW.equals(samlAttribute.getName())) { Object value = samlAttribute.getValue(); if (value instanceof Element) { Element mandate = (Element) value; replacementIdentityLink = new IdentityLink(); Element mandator = ParepUtils.extractMandator(mandate); String dateOfBirth = ""; Element prPerson = null; String familyName = ""; String givenName = ""; String identificationType = ""; String identificationValue = ""; if (mandator != null) { boolean physical = ParepUtils.isPhysicalPerson(mandator); if (physical) { familyName = ParepUtils.extractText(mandator, "descendant-or-self::pr:Name/pr:FamilyName/text()"); givenName = ParepUtils.extractText(mandator, "descendant-or-self::pr:Name/pr:GivenName/text()"); dateOfBirth = ParepUtils.extractMandatorDateOfBirth(mandator); } else { familyName = ParepUtils.extractMandatorFullName(mandator); } identificationType = ParepUtils.getIdentification(mandator, "Type"); identificationValue = ParepUtils.extractMandatorWbpk(mandator); prPerson = ParepUtils.extractPrPersonOfMandate(mandate); if (physical && session.getBusinessService() && identificationType!=null && Constants.URN_PREFIX_BASEID.equals(identificationType)) { // now we calculate the wbPK and do so if we got it from the BKU identificationType = Constants.URN_PREFIX_WBPK + "+" + session.getDomainIdentifier(); identificationValue = new BPKBuilder().buildWBPK(identificationValue, session.getDomainIdentifier()); ParepUtils.HideStammZahlen(prPerson, true, null, null, true); } } replacementIdentityLink.setDateOfBirth(dateOfBirth); replacementIdentityLink.setFamilyName(familyName); replacementIdentityLink.setGivenName(givenName); replacementIdentityLink.setIdentificationType(identificationType); replacementIdentityLink.setIdentificationValue(identificationValue); replacementIdentityLink.setPrPerson(prPerson); try { replacementIdentityLink.setSamlAssertion(session.getIdentityLink().getSamlAssertion()); } catch (Exception e) { throw new ValidateException("validator.64", null); } } else { Logger.info("The type of Mandate SAML-Attribute is not \"org.w3c.dom.Element\""); throw new ValidateException("validator.64", null); } } } } VerifyXMLSignatureResponse vsresp = new VerifyXMLSignatureResponse(); X509Certificate cert = session.getForeignSignerCertificate(); vsresp.setX509certificate(cert); AuthenticationData authData = buildAuthenticationData(session, vsresp, replacementIdentityLink); String samlArtifact = new SAMLArtifactBuilder().build(session.getAuthURL(), session.getSessionID()); storeAuthenticationData(samlArtifact, authData); // invalidates the authentication session sessionStore.remove(sessionID); Logger.info( "Anmeldedaten zu MOASession " + sessionID + " angelegt, SAML Artifakt " + samlArtifact); return samlArtifact; } /** * Builds the AuthenticationData object together with the * corresponding <saml:Assertion> * @param session authentication session * @param verifyXMLSigResp VerifyXMLSignatureResponse from MOA-SP * @return AuthenticationData object * @throws ConfigurationException while accessing configuration data * @throws BuildException while building the <saml:Assertion> */ private AuthenticationData buildAuthenticationData( AuthenticationSession session, VerifyXMLSignatureResponse verifyXMLSigResp, IdentityLink replacementIdentityLink) throws ConfigurationException, BuildException { IdentityLink identityLink; if (replacementIdentityLink == null) { identityLink = session.getIdentityLink(); } else { // We have got data form a mandate we need now to use to stay compatible with applications identityLink = replacementIdentityLink; } AuthenticationData authData = new AuthenticationData(); OAAuthParameter oaParam = AuthConfigurationProvider.getInstance().getOnlineApplicationParameter( session.getPublicOAURLPrefix()); boolean businessService = oaParam.getBusinessService(); authData.setMajorVersion(1); authData.setMinorVersion(0); authData.setAssertionID(Random.nextRandom()); authData.setIssuer(session.getAuthURL()); authData.setIssueInstant(DateTimeUtils.buildDateTime(Calendar.getInstance())); 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()); boolean provideStammzahl = oaParam.getProvideStammzahl(); if (provideStammzahl) { authData.setIdentificationValue(identityLink.getIdentificationValue()); } String prPerson = new PersonDataBuilder().build(identityLink, provideStammzahl); try { String signerCertificateBase64 = ""; if (oaParam.getProvideCertifcate()) { X509Certificate signerCertificate = verifyXMLSigResp.getX509certificate(); if (signerCertificate != null) { signerCertificateBase64 = Base64Utils.encode(signerCertificate.getEncoded()); } else { Logger.info("\"provideCertificate\" is \"true\", but no signer certificate available"); } } authData.setSignerCertificate(signerCertificateBase64); if (businessService) { authData.setWBPK(identityLink.getIdentificationValue()); } else { authData.setBPK(identityLink.getIdentificationValue()); //BZ.., calculation of bPK already before sending AUTHBlock /* if (identityLink.getIdentificationType().equals(Constants.URN_PREFIX_BASEID)) { // only compute bPK if online application is a public service and we have the Stammzahl String bpkBase64 = new BPKBuilder().buildBPK( identityLink.getIdentificationValue(), session.getTarget()); authData.setBPK(bpkBase64); }*/ } String ilAssertion = oaParam.getProvideIdentityLink() ? identityLink.getSerializedSamlAssertion() : ""; if (!oaParam.getProvideStammzahl()) { ilAssertion = StringUtils.replaceAll(ilAssertion, identityLink.getIdentificationValue(), ""); } String authBlock = oaParam.getProvideAuthBlock() ? session.getAuthBlock() : ""; String samlAssertion = new AuthenticationDataAssertionBuilder().build( authData, prPerson, authBlock, ilAssertion, session.getBkuURL(), signerCertificateBase64, businessService, session.getExtendedSAMLAttributesOA()); authData.setSamlAssertion(samlAssertion); String assertionFile = AuthConfigurationProvider.getInstance().getGenericConfigurationParameter("AuthenticationServer.WriteAssertionToFile"); if (!ParepUtils.isEmpty(assertionFile)) ParepUtils.saveStringToFile(samlAssertion, new File(assertionFile)); //Ex: "c:/saml_assertion.xml" return authData; } catch (Throwable ex) { throw new BuildException( "builder.00", new Object[] { "AuthenticationData", ex.toString()}, ex); } } /** * Retrieves AuthenticationData indexed by the SAML artifact. * The AuthenticationData is deleted from the store upon end of this call. * * @return AuthenticationData */ public AuthenticationData getAuthenticationData(String samlArtifact) throws AuthenticationException { String assertionHandle; try { assertionHandle = new SAMLArtifactParser(samlArtifact).parseAssertionHandle(); } catch (ParseException ex) { throw new AuthenticationException("1205", new Object[] { samlArtifact, ex.toString()}); } AuthenticationData authData = null; synchronized (authenticationDataStore) { authData = (AuthenticationData) authenticationDataStore.get(assertionHandle); if (authData == null) { Logger.error("Assertion not found for SAML Artifact: " + samlArtifact); throw new AuthenticationException("1206", new Object[] { samlArtifact }); } boolean keepAssertion = false; try { String boolStr = AuthConfigurationProvider.getInstance().getGenericConfigurationParameter("AuthenticationServer.KeepAssertion"); if (null!=boolStr && boolStr.equalsIgnoreCase("true")) keepAssertion = true;//Only allowed for debug purposes!!! } catch (ConfigurationException ex) { throw new AuthenticationException("1205", new Object[] { samlArtifact, ex.toString()}); } if (!keepAssertion) { authenticationDataStore.remove(assertionHandle); } } long now = new Date().getTime(); if (now - authData.getTimestamp().getTime() > authDataTimeOut) throw new AuthenticationException("1207", new Object[] { samlArtifact }); Logger.debug("Assertion delivered for SAML Artifact: " + samlArtifact); return authData; } /** * Stores authentication data indexed by the assertion handle contained in the * given saml artifact. * @param samlArtifact SAML artifact * @param authData authentication data * @throws AuthenticationException when SAML artifact is invalid */ private void storeAuthenticationData(String samlArtifact, AuthenticationData authData) throws AuthenticationException { try { SAMLArtifactParser parser = new SAMLArtifactParser(samlArtifact); // check type code 0x0001 byte[] typeCode = parser.parseTypeCode(); if (typeCode[0] != 0 || typeCode[1] != 1) throw new AuthenticationException("auth.06", new Object[] { samlArtifact }); String assertionHandle = parser.parseAssertionHandle(); synchronized (authenticationDataStore) { Logger.debug("Assertion stored for SAML Artifact: " + samlArtifact); authenticationDataStore.put(assertionHandle, authData); } } catch (AuthenticationException ex) { throw ex; } catch (Throwable ex) { throw new AuthenticationException("auth.06", new Object[] { samlArtifact }); } } /** * Creates a new session and puts it into the session store. * * @param id Session ID * @return AuthenticationSession created * @exception AuthenticationException * thrown when an AuthenticationSession is running * already for the given session ID */ private static AuthenticationSession newSession() throws AuthenticationException { String sessionID = Random.nextRandom(); AuthenticationSession newSession = new AuthenticationSession(sessionID); synchronized (sessionStore) { AuthenticationSession session = (AuthenticationSession) sessionStore.get(sessionID); if (session != null) throw new AuthenticationException("auth.01", new Object[] { sessionID }); sessionStore.put(sessionID, newSession); } return newSession; } /** * 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 = (AuthenticationSession) sessionStore.get(id); if (session == null) throw new AuthenticationException("auth.02", new Object[] { id }); return session; } /** * Cleans up expired session and authentication data stores. */ public void cleanup() { long now = new Date().getTime(); synchronized (sessionStore) { Set keys = new HashSet(sessionStore.keySet()); for (Iterator iter = keys.iterator(); iter.hasNext();) { String sessionID = (String) iter.next(); AuthenticationSession session = (AuthenticationSession) sessionStore.get(sessionID); if (now - session.getTimestampStart().getTime() > sessionTimeOut) { Logger.info( MOAIDMessageProvider.getInstance().getMessage( "cleaner.02", new Object[] { sessionID })); sessionStore.remove(sessionID); } } } synchronized (authenticationDataStore) { Set keys = new HashSet(authenticationDataStore.keySet()); for (Iterator iter = keys.iterator(); iter.hasNext();) { String samlAssertionHandle = (String) iter.next(); AuthenticationData authData = (AuthenticationData) authenticationDataStore.get(samlAssertionHandle); if (now - authData.getTimestamp().getTime() > authDataTimeOut) { Logger.info( MOAIDMessageProvider.getInstance().getMessage( "cleaner.03", new Object[] { authData.getAssertionID() })); authenticationDataStore.remove(samlAssertionHandle); } } } } /** * Sets the sessionTimeOut. * @param seconds Time out of the session in seconds */ public void setSecondsSessionTimeOut(long seconds) { sessionTimeOut = 1000 * seconds; } /** * Sets the authDataTimeOut. * @param seconds Time out for signing AuthData in seconds */ public void setSecondsAuthDataTimeOut(long seconds) { authDataTimeOut = 1000 * seconds; } /** * 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) */ private 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; } }