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