diff options
Diffstat (limited to 'id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/AuthenticationServer.java')
-rw-r--r-- | id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/AuthenticationServer.java | 2133 |
1 files changed, 2133 insertions, 0 deletions
diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/AuthenticationServer.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/AuthenticationServer.java new file mode 100644 index 000000000..e86db4a5c --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/AuthenticationServer.java @@ -0,0 +1,2133 @@ +/* + * 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.pki.PKIException; +import iaik.x509.X509Certificate; + +import java.io.ByteArrayInputStream; +import java.io.File; +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.apache.xpath.XPathAPI; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.xml.sax.SAXException; + +import at.gv.egovernment.moa.id.AuthenticationException; +import at.gv.egovernment.moa.id.BuildException; +import at.gv.egovernment.moa.id.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.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.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.client.szrgw.SZRGWConstants; +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.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.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.<br> + * {@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 <code>AuthenticationServer</code>. + * + * @return the single instance of <code>AuthenticationServer</code> + */ + public static AuthenticationServer getInstance() { + if (instance == null) + instance = new AuthenticationServer(); + return instance; + } + /** + * Constructor for AuthenticationServer. + */ + public AuthenticationServer() { + super(); + } + /** + * Processes request to select a BKU. + * <br/>Processing depends on value of {@link AuthConfigurationProvider#getBKUSelectionType}. + * <br/>For <code>bkuSelectionType==HTMLComplete</code>, a <code>returnURI</code> for the + * "BKU Auswahl" service is returned. + * <br/>For <code>bkuSelectionType==HTMLSelect</code>, 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 <code>HTMLSelect</code>; may be null + * @param templateURL URL providing an HTML template for the HTML form to be used + * for call <code>startAuthentication</code> + * @return for <code>bkuSelectionType==HTMLComplete</code>, the <code>returnURI</code> for the + * "BKU Auswahl" service; + * for <code>bkuSelectionType==HTMLSelect</code>, 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.05"); + if (isEmpty(oaURL)) + throw new WrongParametersException("StartAuthentication", PARAM_OA, "auth.05"); + + 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.05"); + } 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. + * <ul> + * <li>Starts an authentication session</li> + * <li>Creates an <code><InfoboxReadRequest></code></li> + * <li>Creates an HTML form for querying the identity link from the + * security layer implementation. + * <br>Form parameters include + * <ul> + * <li>the <code><InfoboxReadRequest></code></li> + * <li>the data URL where the security layer implementation sends it response to</li> + * </ul> + * </ul> + * @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 <code>null</code>; 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( + String authURL, + String target, + String targetFriendlyName, + String oaURL, + String templateURL, + String bkuURL, + String useMandate, + String sessionID, + String scheme, + String sourceID) + throws WrongParametersException, AuthenticationException, ConfigurationException, BuildException { + + String useMandateString = null; + boolean useMandateBoolean = false; + if ((useMandate != null) && (useMandate.compareTo("") != 0)) { + useMandateString = useMandate; + } + else { + useMandateString = "false"; + } + + if (useMandateString.compareToIgnoreCase("true") == 0) + useMandateBoolean = true; + else + useMandateBoolean = false; + + if (isEmpty(sessionID)) { + if (isEmpty(authURL)) + throw new WrongParametersException("StartAuthentication", "AuthURL", "auth.05"); + + //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.05"); + } + 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.05"); + } else { + if (useMandateBoolean) { + Logger.error("Online-Mandate Mode for bussines application not supported."); + throw new AuthenticationException("auth.17", null); + } + target = null; + targetFriendlyName = null; + } + session = newSession(); + Logger.info("MOASession " + session.getSessionID() + " angelegt"); + session.setTarget(target); + session.setTargetFriendlyName(targetFriendlyName); + session.setOAURLRequested(oaURL); + session.setPublicOAURLPrefix(oaParam.getPublicURLPrefix()); + session.setAuthURL(authURL); + session.setTemplateURL(templateURL); + session.setBusinessService(oaParam.getBusinessService()); + if (sourceID != null) + session.setSourceID(sourceID); + } + // 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()); + session.setUseMandate(useMandateString); + 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 <code><InfoboxReadResponse></code> sent by the + * security layer implementation.<br> + * <ul> + * <li>Validates given <code><InfoboxReadResponse></code></li> + * <li>Parses identity link enclosed in <code><InfoboxReadResponse></code></li> + * <li>Verifies identity link by calling the MOA SP component</li> + * <li>Checks certificate authority of identity link</li> + * <li>Stores identity link in the session</li> + * <li>Verifies all additional infoboxes returned from the BKU</li> + * <li>Creates an authentication block to be signed by the user</li> + * <li>Creates and returns a <code><CreateXMLSignatureRequest></code> + * containg the authentication block, meant to be returned to the + * security layer implementation</li> + * </ul> + * + * @param sessionID ID of associated authentication session data + * @param infoboxReadResponseParameters The parameters from the response returned from + * the BKU including the <code><InfoboxReadResponse></code> + * @return String representation of the <code><CreateXMLSignatureRequest></code> + */ + 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); + + //System.out.println("PB: " + xmlInfoboxReadResponse); + + 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); + 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 ausländische eID."); + return null; + } + // spezifikationsgemäßer (SL1.2) Errorcode + se = "ErrorCode>4002"; + //b = xmlInfoboxReadResponse.contains(se); + b = xmlInfoboxReadResponse.indexOf(se); + if (b!=-1) { // Unbekannter Infoboxbezeichner + Logger.info("Unbekannter Infoboxbezeichner. Versuche Anmeldung als ausländische eID."); + return null; + } + + // for testing new identity link certificate +// xmlInfoboxReadResponse = null; +// try { +// File file = new File("c:/temp/XXXMuster.xml"); +// FileInputStream fis; +// +// fis = new FileInputStream(file); +// byte[] array = Utils.readFromInputStream(fis); +// +// xmlInfoboxReadResponse = new String(array); +// System.out.println(xmlInfoboxReadResponse); +// +// } catch (FileNotFoundException e) { +// e.printStackTrace(); +// } catch (UtilsException e) { +// e.printStackTrace(); +// } + + + + // parses the <InfoboxReadResponse> + IdentityLink identityLink = + new InfoboxReadResponseParser(xmlInfoboxReadResponse).parseIdentityLink(); + // validates the identity link + IdentityLinkValidator.getInstance().validate(identityLink); + // builds a <VerifyXMLSignatureRequest> 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 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 <VerifyXMLSignatureResponse> + 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); + } + + + /** + * Processes an <code>Mandate</code> sent by the + * MIS.<br> + * <ul> + * <li>Validates given <code>Mandate</code></li> + * <li>Verifies Mandate by calling the MOA SP component</li> + * <li>Creates an authentication block to be signed by the user</li> + * <li>Creates and returns a <code><CreateXMLSignatureRequest></code> + * containg the authentication block, meant to be returned to the + * security layer implementation</li> + * </ul> + * + * @param sessionID ID of associated authentication session data + * @param infoboxReadResponseParameters The parameters from the response returned from + * the BKU including the <code><InfoboxReadResponse></code> + * @return String representation of the <code><CreateXMLSignatureRequest></code> + */ + public void verifyMandate(String sessionID, MISMandate mandate) + throws + AuthenticationException, + BuildException, + ParseException, + ConfigurationException, + ValidateException, + ServiceException { + + if (isEmpty(sessionID)) + throw new AuthenticationException("auth.10", new Object[] { GET_MIS_SESSIONID, PARAM_SESSIONID}); + + String sMandate = new String(mandate.getMandate()); + if (sMandate == null | sMandate.compareToIgnoreCase("") == 0) { + Logger.error("Mandate is empty."); + throw new AuthenticationException("auth.16", new Object[] { GET_MIS_SESSIONID}); + } + + + AuthenticationSession session = getSession(sessionID); + OAAuthParameter oaParam = + AuthConfigurationProvider.getInstance().getOnlineApplicationParameter( + session.getPublicOAURLPrefix()); + + + + try { + // sets the extended SAML attributes for OID (Organwalter) + setExtendedSAMLAttributeForMandatesOID(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); + } + + + if (oaParam.getProvideFullMandatorData()) { + try { + // set extended SAML attributes if provideMandatorData is true + setExtendedSAMLAttributeForMandates(session, mandate, oaParam.getBusinessService(), oaParam.getProvideStammzahl()); + } 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()); + +// if (!fromMandate) { + //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, oaParam); + +// session.setAuthBlock(authBlock); + // builds the <CreateXMLSignatureRequest> + 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.<br> + * <ul> + * <li>Creates an CreateXMLSignatureRequest to be signed by the user</li> + * </ul> + * + * @param sessionID ID of associated authentication session data + * @param cert The certificate from the user + * @return String representation of the <code><CreateXMLSignatureRequest></code> + */ + 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 <code><CreateXMLSignatureResponse></code> sent by the + * security layer implementation.<br> + * <ul> + * <li>Validates given <code><CreateXMLSignatureResponse></code></li> + * <li>Parses response enclosed in <code><CreateXMLSignatureResponse></code></li> + * <li>Verifies signature by calling the MOA SP component</li> + * <li>Returns the signer certificate</li> + * </ul> + * + * @param sessionID ID of associated authentication session data + * @param createXMLSignatureResponseParameters The parameters from the response returned from + * the BKU including the <code><CreateXMLSignatureResponse></code> + */ + 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 <CreateXMLSignatureResponse> + CreateXMLSignatureResponseParser p = new CreateXMLSignatureResponseParser(xmlCreateXMLSignatureResponse); + CreateXMLSignatureResponse createXMLSignatureResponse = p.parseResponseDsig(); + + // builds a <VerifyXMLSignatureRequest> 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 verifyXMLSignatureResponse = + new VerifyXMLSignatureResponseParser(domVerifyXMLSignatureResponse).parseData(); + + + //int code = verifyXMLSignatureResponse.getSignatureCheckCode(); + + return verifyXMLSignatureResponse.getX509certificate(); + + } + + /** + * Processes an <code><CreateXMLSignatureResponse></code> sent by the + * security layer implementation.<br> + * <ul> + * <li>Validates given <code><CreateXMLSignatureResponse></code></li> + * <li>Parses response enclosed in <code><CreateXMLSignatureResponse></code></li> + * <li>Verifies signature by calling the MOA SP component</li> + * <li>Returns the signer certificate</li> + * </ul> + * + * @param sessionID ID of associated authentication session data + * @param readInfoboxResponseParameters The parameters from the response returned from + * the BKU including the <code><ReadInfoboxResponse></code> + */ + 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 <CreateXMLSignatureResponse> + InfoboxReadResponseParser p = new InfoboxReadResponseParser(xmlReadInfoboxResponse); + X509Certificate cert = p.parseCertificate(); + + return cert; + + } + + /** + * Builds an authentication block <code><saml:Assertion></code> from given session data. + * @param session authentication session + * + * @return <code><saml:Assertion></code> 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 = identityLink.getIdentificationValue(); + String identificationType = identityLink.getIdentificationType(); + + String issueInstant = DateTimeUtils.buildDateTime(Calendar.getInstance(), oaParam.getUseUTC()); + 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(); + String oaURL = session.getPublicOAURLPrefix().replaceAll("&", "&"); + List extendedSAMLAttributes = session.getExtendedSAMLAttributesAUTH(); + String authBlock = new AuthenticationBlockAssertionBuilder().buildAuthBlock( + issuer, + issueInstant, + authURL, + target, + targetFriendlyName, + 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 (<code>Stammzahl</code>en) + * 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(); + session.setExtendedSAMLAttributesAUTH(new Vector()); // Initialize SAML Attributes + session.setExtendedSAMLAttributesOA(new Vector()); + + //System.out.println("SAML set: " + session.getExtendedSAMLAttributesAUTH().size()); + + if (verifyInfoboxParameters != null) { + + 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."); + } + } + } + } + } + + /** + * 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 setExtendedSAMLAttributeForMandates( + AuthenticationSession session, MISMandate mandate, boolean business, boolean provideStammzahl) + throws ValidateException, ConfigurationException, SAXException, IOException, ParserConfigurationException, TransformerException + { + + ExtendedSAMLAttribute[] extendedSamlAttributes = addExtendedSamlAttributes(mandate, business, provideStammzahl); + + + AddAdditionalSAMLAttributes(session, extendedSamlAttributes, "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"); + + } + + /** + * 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<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 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, MISMandate mandate) throws ValidateException +// { +// +// List oaAttributes = session.getExtendedSAMLAttributesOA(); +// if (oaAttributes==null) oaAttributes = new Vector(); +// List authAttributes = session.getExtendedSAMLAttributesAUTH(); +// if (authAttributes==null) authAttributes = new Vector(); +// +// +// addExtendedSamlAttributes(authAttributes, mandate); +// +// 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 + */ + + private static ExtendedSAMLAttribute[] addExtendedSamlAttributes(MISMandate mandate, boolean business, boolean provideStammzahl) throws SAXException, IOException, ParserConfigurationException, TransformerException { + Vector extendedSamlAttributes = new Vector(); + + + extendedSamlAttributes.clear(); + + //extendedSamlAttributes.add(new ExtendedSAMLAttributeImpl(ParepValidator.EXT_SAML_MANDATE_RAW, mandate, SZRGWConstants.MANDATE_NS, ExtendedSAMLAttribute.NOT_ADD_TO_AUTHBLOCK)); + + // 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); + + // first check if physical person + //Element name = (Element) XPathAPI.selectSingleNode(mandator, "descendant-or-self::pr:Name/pr:GivenName", nameSpaceNode); + //String mandatorname = ParepUtils.extractMandatorName(mandator); + + //extendedSamlAttributes.add(new ExtendedSAMLAttributeImpl(ParepValidator.EXT_SAML_MANDATE_NAME, mandatorname, SZRGWConstants.MANDATE_NS, ExtendedSAMLAttribute.ADD_TO_AUTHBLOCK_ONLY)); + // Geburtsdatum + //String dob = ParepUtils.extractMandatorDateOfBirth(mandator); + //if (dob != null && !"".equals(dob)) { + // extendedSamlAttributes.add(new ExtendedSAMLAttributeImpl(ParepValidator.EXT_SAML_MANDATE_DOB, dob, SZRGWConstants.MANDATE_NS, ExtendedSAMLAttribute.ADD_TO_AUTHBLOCK_ONLY)); + //} + + // Mandate + extendedSamlAttributes.add(new ExtendedSAMLAttributeImpl(ParepValidator.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(ParepValidator.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(ParepValidator.EXT_SAML_MANDATE_WBPK, wbpk, SZRGWConstants.MANDATE_NS, ExtendedSAMLAttribute.ADD_TO_AUTHBLOCK_ONLY)); + } + } + +// String oid = mandate.getProfRep(); +// if (oid != null) { +// String oidDescription = mandate.getTextualDescriptionOfOID(); +// extendedSamlAttributes.add(new ExtendedSAMLAttributeImpl(ParepValidator.EXT_SAML_MANDATE_OIDTEXTUALDESCRIPTION, oidDescription, 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(ParepValidator.EXT_SAML_MANDATE_REPRESENTATIONTYPE, ParepValidator.EXT_SAML_MANDATE_REPRESENTATIONTEXT, SZRGWConstants.MANDATE_NS, ExtendedSAMLAttribute.NOT_ADD_TO_AUTHBLOCK)); + + + String oid = mandate.getProfRep(); + + if (oid != null) { + extendedSamlAttributes.add(new ExtendedSAMLAttributeImpl(ParepValidator.EXT_SAML_MANDATE_OID, oid, SZRGWConstants.MANDATE_NS, ExtendedSAMLAttribute.NOT_ADD_TO_AUTHBLOCK)); + String oidDescription = mandate.getTextualDescriptionOfOID(); + extendedSamlAttributes.add(new ExtendedSAMLAttributeImpl(ParepValidator.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(); + } + private 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 <code><CreateXMLSignatureResponse></code> sent by the + * security layer implementation.<br> + * <ul> + * <li>Validates given <code><CreateXMLSignatureResponse></code></li> + * <li>Parses <code><CreateXMLSignatureResponse></code> for error codes</li> + * <li>Parses authentication block enclosed in + * <code><CreateXMLSignatureResponse></code></li> + * <li>Verifies authentication block by calling the MOA SP component</li> + * <li>Creates authentication data</li> + * <li>Creates a corresponding SAML artifact</li> + * <li>Stores authentication data in the authentication data store + * indexed by the SAML artifact</li> + * <li>Deletes authentication session</li> + * <li>Returns the SAML artifact, encoded BASE64</li> + * </ul> + * + * @param sessionID session ID of the running authentication session + * @param xmlCreateXMLSignatureReadResponse String representation of the + * <code><CreateXMLSignatureResponse></code> + * @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> + 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 <CreateXMLSignatureResponse> + new CreateXMLSignatureResponseValidator().validate(csresp, session); + // builds a <VerifyXMLSignatureRequest> 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> + 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 <VerifyXMLSignatureResponse> + 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"; + } + } + } + + OAAuthParameter oaParam = + AuthConfigurationProvider.getInstance().getOnlineApplicationParameter( + session.getPublicOAURLPrefix()); + boolean useUTC = oaParam.getUseUTC(); + + // builds authentication data and stores it together with a SAML artifact + AuthenticationData authData = buildAuthenticationData(session, vsresp, useUTC); + + if (session.getUseMandate()) { + // mandate mode + //session.setAssertionAuthBlock(assertionAuthBlock) + + // set signer certificate + session.setSignerCertificate(vsresp.getX509certificate()); + + return null; + } + else { + + String samlAssertion = + new AuthenticationDataAssertionBuilder().build( + authData, + session.getAssertionPrPerson(), + session.getAssertionAuthBlock(), + session.getAssertionIlAssertion(), + session.getBkuURL(), + session.getAssertionSignerCertificateBase64(), + session.getAssertionBusinessService(), + session.getExtendedSAMLAttributesOA()); + authData.setSamlAssertion(samlAssertion); + + String assertionFile = AuthConfigurationProvider.getInstance().getGenericConfigurationParameter("AuthenticationServer.WriteAssertionToFile"); + if (!ParepUtils.isEmpty(assertionFile)) + try { + ParepUtils.saveStringToFile(samlAssertion, new File(assertionFile)); + } catch (IOException e) { + throw new BuildException( + "builder.00", + new Object[] { "AuthenticationData", e.toString()}, + e); + } + + String samlArtifact = + new SAMLArtifactBuilder().build(session.getAuthURL(), session.getSessionID(), session.getSourceID()); + storeAuthenticationData(samlArtifact, authData); + + // invalidates the authentication session + sessionStore.remove(sessionID); + Logger.info( + "Anmeldedaten zu MOASession " + sessionID + " angelegt, SAML Artifakt " + samlArtifact); + return samlArtifact; + + } + + + + + } + + /** + * Processes a <code><CreateXMLSignatureResponse></code> sent by the + * security layer implementation.<br> + * <ul> + * <li>Validates given <code><CreateXMLSignatureResponse></code></li> + * <li>Parses <code><CreateXMLSignatureResponse></code> for error codes</li> + * <li>Parses authentication block enclosed in + * <code><CreateXMLSignatureResponse></code></li> + * <li>Verifies authentication block by calling the MOA SP component</li> + * <li>Creates authentication data</li> + * <li>Creates a corresponding SAML artifact</li> + * <li>Stores authentication data in the authentication data store + * indexed by the SAML artifact</li> + * <li>Deletes authentication session</li> + * <li>Returns the SAML artifact, encoded BASE64</li> + * </ul> + * + * @param sessionID session ID of the running authentication session + * @param xmlCreateXMLSignatureReadResponse String representation of the + * <code><CreateXMLSignatureResponse></code> + * @return SAML artifact needed for retrieving authentication data, encoded BASE64 + */ + public String verifyAuthenticationBlockMandate( + String sessionID, + Element mandate) + 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(); + + + IdentityLink tempIdentityLink = null; + + if (session.getUseMandate()) { + tempIdentityLink = 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); + } + + + tempIdentityLink.setDateOfBirth(dateOfBirth); + tempIdentityLink.setFamilyName(familyName); + tempIdentityLink.setGivenName(givenName); + tempIdentityLink.setIdentificationType(identificationType); + tempIdentityLink.setIdentificationValue(identificationValue); + tempIdentityLink.setPrPerson(prPerson); + try { + tempIdentityLink.setSamlAssertion(session.getIdentityLink().getSamlAssertion()); + } catch (Exception e) { + throw new ValidateException("validator.64", null); + } + + } + + } + + // builds authentication data and stores it together with a SAML artifact + AuthenticationData authData = session.getAssertionAuthData(); //buildAuthenticationData(session, vsresp, replacementIdentityLink); + + + Element mandatePerson = tempIdentityLink.getPrPerson(); +// try { +// System.out.println("MANDATE: " + DOMUtils.serializeNode(mandatePerson)); +// } +// catch(Exception e) { +// e.printStackTrace(); +// } + String mandateData = null; + try { + OAAuthParameter oaParam = + AuthConfigurationProvider.getInstance().getOnlineApplicationParameter( + session.getPublicOAURLPrefix()); + boolean provideStammzahl = oaParam.getProvideStammzahl(); + if (!provideStammzahl) { + String isPrPerson = mandatePerson.getAttribute("xsi:type"); + + if (!StringUtils.isEmpty(isPrPerson)) { + if (isPrPerson.equalsIgnoreCase("pr:PhysicalPerson")) { + Node prIdentification = mandatePerson.getFirstChild(); + prIdentification.getFirstChild().setTextContent(""); +// Element.appendChild(Document.createTextNode(String)); +// prIdentification.getFirstChild(). + } + } + + } + mandateData = DOMUtils.serializeNode(mandatePerson); + } catch (TransformerException e1) { + throw new AuthenticationException("auth.16", new Object[] { GET_MIS_SESSIONID}); + } catch (IOException e1) { + throw new AuthenticationException("auth.16", new Object[] { GET_MIS_SESSIONID}); + } + + String samlAssertion = + new AuthenticationDataAssertionBuilder().buildMandate( + authData, + session.getAssertionPrPerson(), + mandateData, + session.getAssertionAuthBlock(), + session.getAssertionIlAssertion(), + session.getBkuURL(), + session.getAssertionSignerCertificateBase64(), + session.getAssertionBusinessService(), + session.getSourceID(), + session.getExtendedSAMLAttributesOA()); + authData.setSamlAssertion(samlAssertion); + + String assertionFile = AuthConfigurationProvider.getInstance().getGenericConfigurationParameter("AuthenticationServer.WriteAssertionToFile"); + if (!ParepUtils.isEmpty(assertionFile)) + try { + ParepUtils.saveStringToFile(samlAssertion, new File(assertionFile)); + } catch (IOException e) { + throw new BuildException( + "builder.00", + new Object[] { "AuthenticationData", e.toString()}, + e); + } + + String samlArtifact = + new SAMLArtifactBuilder().build(session.getAuthURL(), session.getSessionID(), session.getSourceID()); + 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.<br> + * <ul> + * <li>Creates authentication data</li> + * <li>Creates a corresponding SAML artifact</li> + * <li>Stores authentication data in the authentication data store + * indexed by the SAML artifact</li> + * <li>Deletes authentication session</li> + * <li>Returns the SAML artifact, encoded BASE64</li> + * </ul> + * + * @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"; + } + } + } + + VerifyXMLSignatureResponse vsresp = new VerifyXMLSignatureResponse(); + X509Certificate cert = session.getSignerCertificate(); + vsresp.setX509certificate(cert); + + OAAuthParameter oaParam = + AuthConfigurationProvider.getInstance().getOnlineApplicationParameter( + session.getPublicOAURLPrefix()); + boolean useUTC = oaParam.getUseUTC(); + AuthenticationData authData = buildAuthenticationData(session, vsresp, useUTC); + + + String samlAssertion = + new AuthenticationDataAssertionBuilder().build( + authData, + session.getAssertionPrPerson(), + session.getAssertionAuthBlock(), + session.getAssertionIlAssertion(), + session.getBkuURL(), + session.getAssertionSignerCertificateBase64(), + session.getAssertionBusinessService(), + session.getExtendedSAMLAttributesOA()); + authData.setSamlAssertion(samlAssertion); + + String assertionFile = AuthConfigurationProvider.getInstance().getGenericConfigurationParameter("AuthenticationServer.WriteAssertionToFile"); + if (!ParepUtils.isEmpty(assertionFile)) + try { + ParepUtils.saveStringToFile(samlAssertion, new File(assertionFile)); + } catch (IOException e) { + throw new BuildException( + "builder.00", + new Object[] { "AuthenticationData", e.toString()}, + e); + } + + String samlArtifact = + new SAMLArtifactBuilder().build(session.getAuthURL(), session.getSessionID(), session.getSourceID()); + 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 <code><saml:Assertion></code> + * @param session authentication session + * @param verifyXMLSigResp VerifyXMLSignatureResponse from MOA-SP + * @return AuthenticationData object + * @throws ConfigurationException while accessing configuration data + * @throws BuildException while building the <code><saml:Assertion></code> + */ + private AuthenticationData buildAuthenticationData( + AuthenticationSession session, + VerifyXMLSignatureResponse verifyXMLSigResp, + boolean useUTC) + throws ConfigurationException, BuildException { + + IdentityLink identityLink = session.getIdentityLink(); + 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(), useUTC)); + 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()); + authData.setUseUTC(oaParam.getUseUTC()); + 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() : ""; + + session.setAssertionAuthBlock(authBlock); + session.setAssertionAuthData(authData); + session.setAssertionBusinessService(businessService); + session.setAssertionIlAssertion(ilAssertion); + session.setAssertionPrPerson(prPerson); + session.setAssertionSignerCertificateBase64(signerCertificateBase64); + + return authData; + + + } catch (Throwable ex) { + throw new BuildException( + "builder.00", + new Object[] { "AuthenticationData", ex.toString()}, + ex); + } + } + /** + * Retrieves <code>AuthenticationData</code> indexed by the SAML artifact. + * The <code>AuthenticationData</code> is deleted from the store upon end of this call. + * + * @return <code>AuthenticationData</code> + */ + 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) { + //System.out.println("assertionHandle: " + assertionHandle); + 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 <code>AuthenticationSession</code> 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 <code>AuthenticationSession</code> stored with given session ID, + * <code>null</code> 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; + } +} |