/*******************************************************************************
* Copyright 2014 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.
******************************************************************************/
/*
* 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.validator;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.Iterator;
import java.util.List;
import javax.xml.bind.DatatypeConverter;
import org.jaxen.SimpleNamespaceContext;
import org.w3c.dom.Element;
import at.gv.egiz.eaaf.core.api.IRequest;
import at.gv.egiz.eaaf.core.api.idp.auth.data.IIdentityLink;
import at.gv.egiz.eaaf.core.exceptions.EAAFBuilderException;
import at.gv.egiz.eaaf.core.impl.data.Pair;
import at.gv.egiz.eaaf.core.impl.idp.auth.builder.BPKBuilder;
import at.gv.egiz.eaaf.core.impl.utils.XPathUtils;
import at.gv.egovernment.moa.id.auth.builder.AuthenticationBlockAssertionBuilder;
import at.gv.egovernment.moa.id.auth.data.CreateXMLSignatureResponse;
import at.gv.egovernment.moa.id.auth.data.SAMLAttribute;
import at.gv.egovernment.moa.id.auth.exception.BuildException;
import at.gv.egovernment.moa.id.auth.exception.ValidateException;
import at.gv.egovernment.moa.id.commons.MOAIDAuthConstants;
import at.gv.egovernment.moa.id.commons.api.IOAAuthParameters;
import at.gv.egovernment.moa.id.commons.api.data.ExtendedSAMLAttribute;
import at.gv.egovernment.moa.id.commons.api.data.IAuthenticationSession;
import at.gv.egovernment.moa.id.commons.api.exceptions.ConfigurationException;
import at.gv.egovernment.moa.id.config.TargetToSectorNameMapper;
import at.gv.egovernment.moa.id.config.auth.AuthConfigurationProviderFactory;
import at.gv.egovernment.moa.id.logging.SpecificTraceLogger;
import at.gv.egovernment.moa.logging.Logger;
import at.gv.egovernment.moa.util.Constants;
import at.gv.egovernment.moa.util.MiscUtil;
import at.gv.egovernment.moa.util.StringUtils;
/**
*
* This class is used to validate an {@link CreateXMLSignatureResponse}
* returned by the security layer.
* This class implements the Singleton pattern.
* @author Stefan Knirsch
* @version $Id$
*/
public class CreateXMLSignatureResponseValidator {
/** Xpath expression to the dsig:Signature element */
private static final String SIGNATURE_XPATH = Constants.DSIG_PREFIX + ":Signature";
private static final String XADES_1_1_1_SIGNINGTIME_PATH = "//" + Constants.XADES_1_1_1_NS_PREFIX + ":SigningTime";
private static final String XADES_1_3_2_SIGNINGTIME_PATH = "//" + Constants.XADES_1_3_2_NS_PREFIX + ":SigningTime";
private static final long MAX_DIFFERENCE_IN_MILLISECONDS = 600000; // 10min
/** Singleton instance. null
, if none has been created. */
private static CreateXMLSignatureResponseValidator instance;
private static SimpleNamespaceContext NS_CONTEXT;
static {
NS_CONTEXT = new SimpleNamespaceContext();
NS_CONTEXT.addNamespace(Constants.XADES_1_1_1_NS_PREFIX, Constants.XADES_1_1_1_NS_URI);
NS_CONTEXT.addNamespace(Constants.XADES_1_2_2_NS_PREFIX, Constants.XADES_1_2_2_NS_URI);
NS_CONTEXT.addNamespace(Constants.XADES_1_3_2_NS_PREFIX, Constants.XADES_1_3_2_NS_URI);
NS_CONTEXT.addNamespace(Constants.XADES_1_4_1_NS_PREFIX, Constants.XADES_1_4_1_NS_URI);
}
/**
* Constructor for a singleton CreateXMLSignatureResponseValidator.
* @return an instance of CreateXMLSignatureResponseValidator
* @throws ValidateException if no instance can be created
*/
public static synchronized CreateXMLSignatureResponseValidator getInstance()
throws ValidateException {
if (instance == null) {
instance = new CreateXMLSignatureResponseValidator();
}
return instance;
}
/**
* The Method validate is used for validating an explicit {@link CreateXMLSignatureResponse}
* @param createXMLSignatureResponse
* @param session
* @param pendingReq
* @throws ValidateException
* @throws BuildException
* @throws ConfigurationException
*/
public void validate(CreateXMLSignatureResponse createXMLSignatureResponse, IAuthenticationSession session, IRequest pendingReq)
throws ValidateException, BuildException, ConfigurationException, EAAFBuilderException {
// A3.056: more then one /saml:Assertion/saml:AttributeStatement/saml:Subject/saml:NameIdentifier
IOAAuthParameters oaParam = pendingReq.getServiceProviderConfiguration(IOAAuthParameters.class);
String oaURL = oaParam.getPublicURLPrefix();
IIdentityLink identityLink = session.getIdentityLink();
@Deprecated
String saml1RequestedTarget = pendingReq.getRawData(
MOAIDAuthConstants.AUTHPROCESS_DATA_TARGET, String.class);
@Deprecated
String saml1RequestedFriendlyName = pendingReq.getRawData(
MOAIDAuthConstants.AUTHPROCESS_DATA_TARGETFRIENDLYNAME, String.class);
try {
Element samlAssertion = createXMLSignatureResponse.getSamlAssertion();
//validate issuer
String issuer = samlAssertion.getAttribute("Issuer");
if (issuer == null) {
// should not happen, because parser would dedect this
throw new ValidateException("validator.32", null);
}
// replace ' in name with '
issuer = issuer.replaceAll("'", "'");
if (!issuer.equals(identityLink.getName()))
throw new ValidateException("validator.33", new Object[] {issuer, identityLink.getName()});
//validate issuerInstant
String issueInstant = samlAssertion.getAttribute("IssueInstant");
if (!issueInstant.equals(session.getIssueInstant()))
throw new ValidateException("validator.39", new Object[] {issueInstant, session.getIssueInstant()});
//validate extended attributes
SAMLAttribute[] samlAttributes = createXMLSignatureResponse.getSamlAttributes();
boolean foundOA = false;
boolean foundGB = false;
boolean foundWBPK = false;
int offset = 0;
// check number of SAML attributes
List extendedSAMLAttributes = session.getExtendedSAMLAttributesAUTH();
int extendedSAMLAttributesNum = 0;
if (extendedSAMLAttributes != null) {
extendedSAMLAttributesNum = extendedSAMLAttributes.size();
}
int expectedSAMLAttributeNumber = AuthenticationBlockAssertionBuilder.NUM_OF_SAML_ATTRIBUTES + extendedSAMLAttributesNum;
//remove one attribute from expected attributes if public SP target or wbPK is not part of AuthBlock
if (!session.getSAMLAttributeGebeORwbpk()) expectedSAMLAttributeNumber--;
//check number of attributes in AuthBlock response against expected number of attributes
int actualSAMLAttributeNumber = samlAttributes.length;
if (actualSAMLAttributeNumber != expectedSAMLAttributeNumber) {
Logger.error("Wrong number of SAML attributes in CreateXMLSignatureResponse: expected " +
expectedSAMLAttributeNumber + ", but was " + actualSAMLAttributeNumber);
throw new ValidateException("validator.36",
new Object[] {String.valueOf(actualSAMLAttributeNumber), String.valueOf(expectedSAMLAttributeNumber)});
}
//now check every single attribute
SAMLAttribute samlAttribute = null;
Pair userSectorId = null;
if (session.getSAMLAttributeGebeORwbpk()) {
//check the first attribute ("Geschaeftsbereich" or "wbPK")
samlAttribute = samlAttributes[0];
//calculate bPK or wbPK as reference value for validation
if (MiscUtil.isNotEmpty(saml1RequestedTarget))
userSectorId = new BPKBuilder().generateAreaSpecificPersonIdentifier(
identityLink.getIdentificationValue(), identityLink.getIdentificationType(),
saml1RequestedTarget);
else
userSectorId = new BPKBuilder().generateAreaSpecificPersonIdentifier(
identityLink.getIdentificationValue(), identityLink.getIdentificationType(),
oaParam.getAreaSpecificTargetIdentifier());
//every sector specific identifier that has not 'urn:publicid:gv.at:cdid+' as prefix
// is internally handled as an AuthBlock with wbPK
if (!userSectorId.getSecond().startsWith(MOAIDAuthConstants.PREFIX_CDID)) {
if (!samlAttribute.getName().equals("wbPK")) {
if (samlAttribute.getName().equals("Geschaeftsbereich")) {
throw new ValidateException("validator.26", null);
} else {
throw new ValidateException("validator.37",
new Object[] {samlAttribute.getName(), "wbPK", String.valueOf(1)});
}
}
if (samlAttribute.getNamespace().equals("http://reference.e-government.gv.at/namespace/moa/20020822#")) {
foundWBPK = true;
try {
Element attrValue = (Element)samlAttribute.getValue();
String value = ((Element)attrValue.getElementsByTagNameNS(Constants.PD_NS_URI, "Value").item(0)).getFirstChild().getNodeValue();
String type = ((Element)attrValue.getElementsByTagNameNS(Constants.PD_NS_URI, "Type").item(0)).getFirstChild().getNodeValue();
if (!value.equals(userSectorId.getFirst()))
throw new ValidateException("validator.28",
new Object[] {value, userSectorId.getFirst()});
if (!type.equals(userSectorId.getSecond()))
throw new ValidateException("validator.28",
new Object[] {type, userSectorId.getSecond()});
} catch (Exception ex) {
throw new ValidateException("validator.29", null);
}
} else
throw new ValidateException("validator.30", null);
} else {
if (!samlAttribute.getName().equals("Geschaeftsbereich")) {
if (samlAttribute.getName().equals("wbPK"))
throw new ValidateException("validator.26", null);
else
throw new ValidateException("validator.37",
new Object[] {samlAttribute.getName(), "Geschaeftsbereich", String.valueOf(1)});
}
if (samlAttribute.getNamespace().equals("http://reference.e-government.gv.at/namespace/moa/20020822#")) {
foundGB = true;
String sectorName = TargetToSectorNameMapper.getSectorNameViaTarget(userSectorId.getSecond());
if (StringUtils.isEmpty(sectorName)) {
if (saml1RequestedFriendlyName != null)
sectorName = saml1RequestedFriendlyName;
else
sectorName = oaParam.getAreaSpecificTargetIdentifierFriendlyName();
}
String refValueSector = userSectorId.getSecond().substring(MOAIDAuthConstants.PREFIX_CDID.length()) + " (" + sectorName + ")";
if (!refValueSector.equals((String)samlAttribute.getValue()))
throw new ValidateException("validator.13", new Object[] {(String)samlAttribute.getValue(), refValueSector});
} else
throw new ValidateException("validator.12", null);
}
} else
//check nothing if wbPK or public SP target is not part of AuthBlock
offset--;
// check the second attribute (must be "OA")
samlAttribute = samlAttributes[1 + offset];
if (!samlAttribute.getName().equals("OA"))
throw new ValidateException("validator.37",
new Object[] {samlAttribute.getName(), "OA", String.valueOf(2)});
if (samlAttribute.getNamespace().equals("http://reference.e-government.gv.at/namespace/moa/20020822#")) {
foundOA = true;
if (!oaURL.equals((String)samlAttribute.getValue()))
throw new ValidateException("validator.16", new Object[] {":gefunden wurde '" + oaURL + "', erwartet wurde '" + samlAttribute.getValue()});
} else
throw new ValidateException("validator.15", null);
// check the third attribute (must be "Geburtsdatum")
samlAttribute = samlAttributes[2 + offset];
if (!samlAttribute.getName().equals("Geburtsdatum"))
throw new ValidateException("validator.37",
new Object[] {samlAttribute.getName(), "Geburtsdatum", String.valueOf(3)});
if (samlAttribute.getNamespace().equals("http://reference.e-government.gv.at/namespace/moa/20020822#")) {
String samlDateOfBirth = (String)samlAttribute.getValue();
String dateOfBirth = identityLink.getDateOfBirth();
if (!samlDateOfBirth.equals(dateOfBirth))
throw new ValidateException("validator.34", new Object[] {samlDateOfBirth, dateOfBirth});
} else
throw new ValidateException("validator.35", null);
// check four attribute could be a special text
samlAttribute = samlAttributes[3 + offset];
if (!samlAttribute.getName().equals("SpecialText"))
throw new ValidateException("validator.37",
new Object[] {samlAttribute.getName(), "SpecialText", String.valueOf(4)});
if (samlAttribute.getNamespace().equals("http://reference.e-government.gv.at/namespace/moa/20020822#")) {
String samlSpecialText = (String)samlAttribute.getValue();
samlSpecialText = samlSpecialText.replaceAll("'", "'");
String text = "";
if (MiscUtil.isNotEmpty(oaParam.getAditionalAuthBlockText())) {
Logger.debug("Use addional AuthBlock Text from OA=" + oaParam.getPublicURLPrefix());
text = oaParam.getAditionalAuthBlockText();
}
String specialText = AuthenticationBlockAssertionBuilder.generateSpecialText(text,
AuthenticationBlockAssertionBuilder.generateSpezialAuthBlockPatternMap(
pendingReq, issuer, identityLink.getDateOfBirth(), issueInstant));
if (!samlSpecialText.equals(specialText))
throw new ValidateException("validator.67", new Object[] {samlSpecialText, specialText});
} else
throw new ValidateException("validator.35", null);
//check unique AuthBlock tokken
samlAttribute = samlAttributes[4 + offset];
if (!samlAttribute.getName().equals("UniqueTokken"))
throw new ValidateException("validator.37",
new Object[] {samlAttribute.getName(), "UniqueTokken", String.valueOf(5)});
if (samlAttribute.getNamespace().equals("http://reference.e-government.gv.at/namespace/moa/20020822#")) {
String uniquetokken = (String)samlAttribute.getValue();
if (!uniquetokken.equals(session.getAuthBlockTokken()))
throw new ValidateException("validator.70", new Object[] {uniquetokken, session.getAuthBlockTokken()});
} else
throw new ValidateException("validator.35", null);
// now check the extended SAML attributes
int i = AuthenticationBlockAssertionBuilder.NUM_OF_SAML_ATTRIBUTES + offset;
if (extendedSAMLAttributes != null) {
Iterator it = extendedSAMLAttributes.iterator();
while (it.hasNext()) {
ExtendedSAMLAttribute extendedSAMLAttribute = (ExtendedSAMLAttribute)it.next();
samlAttribute = samlAttributes[i];
String actualName = samlAttribute.getName();
String expectedName = extendedSAMLAttribute.getName();
if (!actualName.equals(expectedName))
throw new ValidateException("validator.38",
new Object[] {"Name", String.valueOf((i+1)), actualName, actualName, expectedName });
String actualNamespace = samlAttribute.getNamespace();
String expectedNamespace = extendedSAMLAttribute.getNameSpace();
if (!actualNamespace.equals(expectedNamespace))
throw new ValidateException("validator.38",
new Object[] {"Namespace", String.valueOf((i+1)), actualName, actualNamespace, expectedNamespace, });
Object expectedValue = extendedSAMLAttribute.getValue();
Object actualValue = samlAttribute.getValue();
try {
if (expectedValue instanceof String) {
// replace \r\n because text might be base64-encoded
String expValue = StringUtils.replaceAll((String)expectedValue,"\r","");
expValue = StringUtils.replaceAll(expValue,"\n","");
String actValue = StringUtils.replaceAll((String)actualValue,"\r","");
actValue = StringUtils.replaceAll(actValue,"\n","");
if (!expValue.equals(actValue))
throw new ValidateException("validator.38",
new Object[] {"Wert", String.valueOf((i+1)), actualName, actualValue, expectedValue });
} else if (expectedValue instanceof Element) {
// only check the name of the element
String actualElementName = ((Element)actualValue).getNodeName();
String expectedElementName = ((Element)expectedValue).getNodeName();
if (!(expectedElementName.equals(actualElementName)))
throw new ValidateException("validator.38",
new Object[] {"Wert", String.valueOf((i+1)), actualName, actualElementName, expectedElementName});
} else
// should not happen
throw new ValidateException("validator.38",
new Object[] {"Typ", String.valueOf((i+1)), expectedName, "java.lang.String oder org.wrc.dom.Element", expectedValue.getClass().getName()});
} catch (ClassCastException e) {
throw new ValidateException("validator.38",
new Object[] {"Typ", String.valueOf((i+1)), expectedName, expectedValue.getClass().getName(), actualValue.getClass().getName()});
}
i++;
}
}
if (!foundOA)
throw new ValidateException("validator.14", null);
if (userSectorId != null && !userSectorId.getSecond().startsWith(MOAIDAuthConstants.PREFIX_CDID)) {
if (session.getSAMLAttributeGebeORwbpk() && !foundWBPK)
throw new ValidateException("validator.31", null);
} else {
if (!foundGB && session.getSAMLAttributeGebeORwbpk())
throw new ValidateException("validator.11", null);
}
//Check if dsig:Signature exists
Element dsigSignature = (Element) XPathUtils.selectSingleNode(samlAssertion, SIGNATURE_XPATH);
if (dsigSignature == null)
throw new ValidateException("validator.05", new Object[] {"im AUTHBlock"}) ;
} catch (Exception e) {
SpecificTraceLogger.trace("Validate AuthBlock without SSO");
SpecificTraceLogger.trace("Signed AuthBlock: " + session.getAuthBlock());
SpecificTraceLogger.trace("OA config: " + oaParam.toString());
SpecificTraceLogger.trace("saml1RequestedTarget: " + saml1RequestedTarget);
SpecificTraceLogger.trace("saml1RequestedFriendlyName: " + saml1RequestedFriendlyName);
throw e;
}
}
/**
* The Method validate is used for validating an explicit {@link CreateXMLSignatureResponse}
* @param createXMLSignatureResponse
* @param session
* @param pendingReq
* @throws ValidateException
*/
public void validateSSO(CreateXMLSignatureResponse createXMLSignatureResponse, IAuthenticationSession session, IRequest pendingReq)
throws ValidateException {
try {
// A3.056: more then one /saml:Assertion/saml:AttributeStatement/saml:Subject/saml:NameIdentifier
String oaURL = pendingReq.getAuthURL();
IIdentityLink identityLink = session.getIdentityLink();
Element samlAssertion = createXMLSignatureResponse.getSamlAssertion();
String issuer = samlAssertion.getAttribute("Issuer");
if (issuer == null) {
// should not happen, because parser would dedect this
throw new ValidateException("validator.32", null);
}
// replace ' in name with '
issuer = issuer.replaceAll("'", "'");
String issueInstant = samlAssertion.getAttribute("IssueInstant");
if (!issueInstant.equals(session.getIssueInstant())) {
throw new ValidateException("validator.39", new Object[] {issueInstant, session.getIssueInstant()});
}
String name = identityLink.getName();
if (!issuer.equals(name)) {
throw new ValidateException("validator.33", new Object[] {issuer, name});
}
SAMLAttribute[] samlAttributes = createXMLSignatureResponse.getSamlAttributes();
boolean foundOA = false;
// boolean foundGB = false;
// boolean foundWBPK = false;
int offset = 0;
// check number of SAML aatributes
List extendedSAMLAttributes = session.getExtendedSAMLAttributesAUTH();
int extendedSAMLAttributesNum = 0;
if (extendedSAMLAttributes != null) {
extendedSAMLAttributesNum = extendedSAMLAttributes.size();
}
int expectedSAMLAttributeNumber =
AuthenticationBlockAssertionBuilder.NUM_OF_SAML_ATTRIBUTES_SSO + extendedSAMLAttributesNum;
if (!session.getSAMLAttributeGebeORwbpk()) expectedSAMLAttributeNumber--;
int actualSAMLAttributeNumber = samlAttributes.length;
if (actualSAMLAttributeNumber != expectedSAMLAttributeNumber) {
Logger.error("Wrong number of SAML attributes in CreateXMLSignatureResponse: expected " +
expectedSAMLAttributeNumber + ", but was " + actualSAMLAttributeNumber);
throw new ValidateException(
"validator.36",
new Object[] {String.valueOf(actualSAMLAttributeNumber), String.valueOf(expectedSAMLAttributeNumber)});
}
SAMLAttribute samlAttribute;
if (!session.getSAMLAttributeGebeORwbpk()) {
offset--;
}
// check the first attribute (must be "OA")
samlAttribute = samlAttributes[0 + offset];
if (!samlAttribute.getName().equals("OA")) {
throw new ValidateException(
"validator.37",
new Object[] {samlAttribute.getName(), "OA", String.valueOf(2)});
}
if (samlAttribute.getNamespace().equals("http://reference.e-government.gv.at/namespace/moa/20020822#")) {
foundOA = true;
if (!oaURL.equals((String)samlAttribute.getValue())) { // CHECKS für die AttributeVALUES fehlen noch
throw new ValidateException("validator.16", new Object[] {":gefunden wurde '" + oaURL + "', erwartet wurde '" + samlAttribute.getValue()});
}
} else {
throw new ValidateException("validator.15", null);
}
// check the third attribute (must be "Geburtsdatum")
samlAttribute = samlAttributes[1 + offset];
if (!samlAttribute.getName().equals("Geburtsdatum")) {
throw new ValidateException(
"validator.37",
new Object[] {samlAttribute.getName(), "Geburtsdatum", String.valueOf(3)});
}
if (samlAttribute.getNamespace().equals("http://reference.e-government.gv.at/namespace/moa/20020822#")) {
String samlDateOfBirth = (String)samlAttribute.getValue();
String dateOfBirth = identityLink.getDateOfBirth();
if (!samlDateOfBirth.equals(dateOfBirth)) {
throw new ValidateException("validator.34", new Object[] {samlDateOfBirth, dateOfBirth});
}
} else {
throw new ValidateException("validator.35", null);
}
// check four attribute could be a special text
samlAttribute = samlAttributes[2 + offset];
if (!samlAttribute.getName().equals("SpecialText")) {
throw new ValidateException(
"validator.37",
new Object[] {samlAttribute.getName(), "SpecialText", String.valueOf(4)});
}
if (samlAttribute.getNamespace().equals("http://reference.e-government.gv.at/namespace/moa/20020822#")) {
String samlSpecialText = (String)samlAttribute.getValue();
samlSpecialText = samlSpecialText.replaceAll("'", "'");
String text = "";
try {
if (MiscUtil.isNotEmpty(AuthConfigurationProviderFactory.getInstance().getSSOSpecialText())) {
text = AuthConfigurationProviderFactory.getInstance().getSSOSpecialText();
Logger.debug("Use addional AuthBlock Text from SSO=" +text);
}
else
text = new String();
} catch (ConfigurationException e) {
Logger.warn("Addional AuthBlock Text can not loaded from SSO!", e);
}
String specialText = AuthenticationBlockAssertionBuilder.generateSpecialText(text,
AuthenticationBlockAssertionBuilder.generateSpezialAuthBlockPatternMap(
pendingReq, issuer, identityLink.getDateOfBirth(), issueInstant));
if (!samlSpecialText.equals(specialText)) {
throw new ValidateException("validator.67", new Object[] {samlSpecialText, specialText});
}
} else {
throw new ValidateException("validator.35", null);
}
//check unique AuthBlock tokken
samlAttribute = samlAttributes[3 + offset];
if (!samlAttribute.getName().equals("UniqueTokken")) {
throw new ValidateException(
"validator.37",
new Object[] {samlAttribute.getName(), "UniqueTokken", String.valueOf(5)});
}
if (samlAttribute.getNamespace().equals("http://reference.e-government.gv.at/namespace/moa/20020822#")) {
String uniquetokken = (String)samlAttribute.getValue();
if (!uniquetokken.equals(session.getAuthBlockTokken())) {
throw new ValidateException("validator.70", new Object[] {uniquetokken, session.getAuthBlockTokken()});
}
} else {
throw new ValidateException("validator.35", null);
}
// now check the extended SAML attributes
int i = AuthenticationBlockAssertionBuilder.NUM_OF_SAML_ATTRIBUTES_SSO + offset;
if (extendedSAMLAttributes != null) {
Iterator it = extendedSAMLAttributes.iterator();
while (it.hasNext()) {
ExtendedSAMLAttribute extendedSAMLAttribute = (ExtendedSAMLAttribute)it.next();
samlAttribute = samlAttributes[i];
String actualName = samlAttribute.getName();
String expectedName = extendedSAMLAttribute.getName();
if (!actualName.equals(expectedName)) {
throw new ValidateException(
"validator.38",
new Object[] {"Name", String.valueOf((i+1)), actualName, actualName, expectedName });
}
String actualNamespace = samlAttribute.getNamespace();
String expectedNamespace = extendedSAMLAttribute.getNameSpace();
if (!actualNamespace.equals(expectedNamespace)) {
throw new ValidateException(
"validator.38",
new Object[] {"Namespace", String.valueOf((i+1)), actualName, actualNamespace, expectedNamespace, });
}
Object expectedValue = extendedSAMLAttribute.getValue();
Object actualValue = samlAttribute.getValue();
try {
if (expectedValue instanceof String) {
// replace \r\n because text might be base64-encoded
String expValue = StringUtils.replaceAll((String)expectedValue,"\r","");
expValue = StringUtils.replaceAll(expValue,"\n","");
String actValue = StringUtils.replaceAll((String)actualValue,"\r","");
actValue = StringUtils.replaceAll(actValue,"\n","");
if (!expValue.equals(actValue)) {
throw new ValidateException(
"validator.38",
new Object[] {"Wert", String.valueOf((i+1)), actualName, actualValue, expectedValue });
}
} else if (expectedValue instanceof Element) {
// only check the name of the element
String actualElementName = ((Element)actualValue).getNodeName();
String expectedElementName = ((Element)expectedValue).getNodeName();
if (!(expectedElementName.equals(actualElementName))){
throw new ValidateException(
"validator.38",
new Object[] {"Wert", String.valueOf((i+1)), actualName, actualElementName, expectedElementName});
}
} else {
// should not happen
throw new ValidateException(
"validator.38",
new Object[] {"Typ", String.valueOf((i+1)), expectedName, "java.lang.String oder org.wrc.dom.Element", expectedValue.getClass().getName()});
}
} catch (ClassCastException e) {
throw new ValidateException(
"validator.38",
new Object[] {"Typ", String.valueOf((i+1)), expectedName, expectedValue.getClass().getName(), actualValue.getClass().getName()});
}
i++;
}
}
if (!foundOA) throw new ValidateException("validator.14", null);
//Check if dsig:Signature exists
// NodeList nl = createXMLSignatureResponse.getSamlAssertion().getElementsByTagNameNS(Constants.DSIG_NS_URI, "Signature");
// if (nl.getLength() != 1) {
// throw new ValidateException("validator.05", null);
// }
Element dsigSignature = (Element) XPathUtils.selectSingleNode(samlAssertion, SIGNATURE_XPATH);
if (dsigSignature == null) {
throw new ValidateException("validator.05", new Object[] {"im AUTHBlock"}) ;
}
} catch (Exception e) {
SpecificTraceLogger.trace("Validate AuthBlock with SSO");
SpecificTraceLogger.trace("Signed AuthBlock: " + session.getAuthBlock());
SpecificTraceLogger.trace("OA config: " + pendingReq.getServiceProviderConfiguration().toString());
throw e;
}
}
public void validateSigningDateTime( CreateXMLSignatureResponse csresp) throws ValidateException {
Element dsigSignatureElement = csresp.getDsigSignature();
if (dsigSignatureElement == null) {
throw new ValidateException("validator.05", new Object[] {"im AUTHBlock"}) ;
}
else {
Element signingTimeElem = (Element) XPathUtils.selectSingleNode(dsigSignatureElement, NS_CONTEXT, XADES_1_1_1_SIGNINGTIME_PATH);
if (signingTimeElem == null) {
signingTimeElem = (Element) XPathUtils.selectSingleNode(dsigSignatureElement, NS_CONTEXT, XADES_1_3_2_SIGNINGTIME_PATH);
if (signingTimeElem == null)
throw new ValidateException("validator.68", null) ;
}
String signingTimeStr = signingTimeElem.getTextContent();
if (signingTimeStr == null)
throw new ValidateException("validator.68", null) ;
Calendar signingTimeCal = DatatypeConverter.parseDate(signingTimeStr);
Calendar serverTimeCal = new GregorianCalendar();
long diff = Math.abs(signingTimeCal.getTimeInMillis() - serverTimeCal.getTimeInMillis());
if (diff > MAX_DIFFERENCE_IN_MILLISECONDS)
throw new ValidateException("validator.69", new Object[] {"mehr als " + MAX_DIFFERENCE_IN_MILLISECONDS + " Millisekunden"}) ;
Logger.debug("Compare \"" + signingTimeCal.getTime() + "\" (SigningTime) with \"" + serverTimeCal.getTime() + "\" (server time)");
}
}
}