summaryrefslogtreecommitdiff
path: root/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv
diff options
context:
space:
mode:
authorThomas Lenz <thomas.lenz@egiz.gv.at>2020-02-06 13:40:54 +0100
committerThomas Lenz <thomas.lenz@egiz.gv.at>2020-02-06 13:40:54 +0100
commit98a83cbb3f5eca50388f3d5f64fe1d760bc199d7 (patch)
tree7e953bbd8210335ac8665ed4bb6cbd673e6b446e /eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv
parentb1e267a57f896268239df835b45742c752310ed5 (diff)
downloadEAAF-Components-98a83cbb3f5eca50388f3d5f64fe1d760bc199d7.tar.gz
EAAF-Components-98a83cbb3f5eca50388f3d5f64fe1d760bc199d7.tar.bz2
EAAF-Components-98a83cbb3f5eca50388f3d5f64fe1d760bc199d7.zip
Refactor SamlVerificationEngine
add some more jUnit tests
Diffstat (limited to 'eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv')
-rw-r--r--eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/exception/SamlAssertionValidationExeption.java28
-rw-r--r--eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/exception/SamlMessageValidationException.java18
-rw-r--r--eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/utils/Saml2Utils.java5
-rw-r--r--eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/SamlVerificationEngine.java355
4 files changed, 368 insertions, 38 deletions
diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/exception/SamlAssertionValidationExeption.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/exception/SamlAssertionValidationExeption.java
new file mode 100644
index 00000000..9ba7ccb2
--- /dev/null
+++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/exception/SamlAssertionValidationExeption.java
@@ -0,0 +1,28 @@
+package at.gv.egiz.eaaf.modules.pvp2.exception;
+
+public class SamlAssertionValidationExeption extends SamlMessageValidationException {
+
+ private static final long serialVersionUID = 2054578783736917817L;
+
+ /**
+ * In case of a SAML2-Assertion validation error.
+ *
+ * @param messageId errorId
+ * @param parameters Message parameters
+ */
+ public SamlAssertionValidationExeption(String messageId, Object[] parameters) {
+ super(messageId, parameters);
+ }
+
+ /**
+ * In case of a SAML2-Assertion validation error.
+ *
+ * @param messageId errorId
+ * @param parameters Message parameters
+ * @param wrapped Exception that was thrown
+ */
+ public SamlAssertionValidationExeption(String messageId, Object[] parameters, Throwable wrapped) {
+ super(messageId, parameters, wrapped);
+ }
+
+}
diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/exception/SamlMessageValidationException.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/exception/SamlMessageValidationException.java
index 774d0927..56d8c4a5 100644
--- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/exception/SamlMessageValidationException.java
+++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/exception/SamlMessageValidationException.java
@@ -4,6 +4,24 @@ public class SamlMessageValidationException extends Pvp2Exception {
private static final long serialVersionUID = 2545822499416501014L;
+ /**
+ * In case of a SAML2-message validation error.
+ *
+ * @param messageId errorId
+ * @param parameters Message parameters
+ */
+ public SamlMessageValidationException(String messageId, Object[] parameters) {
+ super(messageId, parameters);
+
+ }
+
+ /**
+ * In case of a SAML2-message validation error.
+ *
+ * @param messageId errorId
+ * @param parameters Message parameters
+ * @param wrapped Exception that was thrown
+ */
public SamlMessageValidationException(String messageId, Object[] parameters, Throwable wrapped) {
super(messageId, parameters, wrapped);
diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/utils/Saml2Utils.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/utils/Saml2Utils.java
index a3154b0d..c476846b 100644
--- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/utils/Saml2Utils.java
+++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/utils/Saml2Utils.java
@@ -134,10 +134,7 @@ public class Saml2Utils {
@Nonnull EaafX509Credential signingCredential, boolean injectCertificate) throws SamlSigningException {
try {
- final String usedSigAlg = getKeyOperationAlgorithmFromCredential(signingCredential,
- PvpConstants.DEFAULT_SIGNING_METHODE_RSA,
- PvpConstants.DEFAULT_SIGNING_METHODE_EC);
-
+ final String usedSigAlg = signingCredential.getSignatureAlgorithmForSigning();
final Signature signature = createSignature(signingCredential, usedSigAlg, injectCertificate);
toSign.setSignature(signature);
diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/SamlVerificationEngine.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/SamlVerificationEngine.java
index 2e26de7f..e0a3ab8e 100644
--- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/SamlVerificationEngine.java
+++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/SamlVerificationEngine.java
@@ -19,6 +19,9 @@
package at.gv.egiz.eaaf.modules.pvp2.impl.verification;
+import java.util.ArrayList;
+import java.util.List;
+
import javax.xml.namespace.QName;
import javax.xml.transform.dom.DOMSource;
import javax.xml.validation.Schema;
@@ -26,27 +29,45 @@ import javax.xml.validation.Validator;
import at.gv.egiz.eaaf.core.exceptions.EaafProtocolException;
import at.gv.egiz.eaaf.core.exceptions.InvalidProtocolRequestException;
+import at.gv.egiz.eaaf.modules.pvp2.api.credential.EaafX509Credential;
import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IPvp2MetadataProvider;
import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IRefreshableMetadataProvider;
+import at.gv.egiz.eaaf.modules.pvp2.exception.SamlAssertionValidationExeption;
import at.gv.egiz.eaaf.modules.pvp2.exception.SchemaValidationException;
import at.gv.egiz.eaaf.modules.pvp2.impl.message.InboundMessage;
import at.gv.egiz.eaaf.modules.pvp2.impl.message.PvpSProfileRequest;
import at.gv.egiz.eaaf.modules.pvp2.impl.message.PvpSProfileResponse;
import org.apache.commons.lang3.StringUtils;
+import org.joda.time.DateTime;
import org.opensaml.core.criterion.EntityIdCriterion;
import org.opensaml.saml.common.xml.SAMLConstants;
import org.opensaml.saml.common.xml.SAMLSchemaBuilder;
import org.opensaml.saml.common.xml.SAMLSchemaBuilder.SAML1Version;
import org.opensaml.saml.criterion.EntityRoleCriterion;
import org.opensaml.saml.criterion.ProtocolCriterion;
+import org.opensaml.saml.saml2.core.Assertion;
+import org.opensaml.saml.saml2.core.Audience;
+import org.opensaml.saml.saml2.core.AudienceRestriction;
+import org.opensaml.saml.saml2.core.Conditions;
+import org.opensaml.saml.saml2.core.EncryptedAssertion;
import org.opensaml.saml.saml2.core.RequestAbstractType;
+import org.opensaml.saml.saml2.core.Response;
+import org.opensaml.saml.saml2.core.StatusCode;
import org.opensaml.saml.saml2.core.StatusResponseType;
+import org.opensaml.saml.saml2.encryption.Decrypter;
+import org.opensaml.saml.saml2.encryption.EncryptedElementTypeEncryptedKeyResolver;
import org.opensaml.saml.saml2.metadata.IDPSSODescriptor;
import org.opensaml.saml.saml2.metadata.SPSSODescriptor;
import org.opensaml.saml.security.impl.SAMLSignatureProfileValidator;
import org.opensaml.security.credential.UsageType;
import org.opensaml.security.criteria.UsageCriterion;
+import org.opensaml.xmlsec.encryption.support.ChainingEncryptedKeyResolver;
+import org.opensaml.xmlsec.encryption.support.DecryptionException;
+import org.opensaml.xmlsec.encryption.support.EncryptedKeyResolver;
+import org.opensaml.xmlsec.encryption.support.InlineEncryptedKeyResolver;
+import org.opensaml.xmlsec.encryption.support.SimpleRetrievalMethodEncryptedKeyResolver;
+import org.opensaml.xmlsec.keyinfo.impl.StaticKeyInfoCredentialResolver;
import org.opensaml.xmlsec.signature.support.SignatureException;
import org.opensaml.xmlsec.signature.support.SignatureTrustEngine;
import org.springframework.beans.factory.annotation.Autowired;
@@ -54,18 +75,40 @@ import org.w3c.dom.Element;
import org.xml.sax.SAXException;
import lombok.extern.slf4j.Slf4j;
+import net.shibboleth.utilities.java.support.net.BasicURLComparator;
+import net.shibboleth.utilities.java.support.net.URIException;
import net.shibboleth.utilities.java.support.resolver.CriteriaSet;
@Slf4j
public class SamlVerificationEngine {
private static SAMLSchemaBuilder schemaBuilder = new SAMLSchemaBuilder(SAML1Version.SAML_11);
+ private static final String ERROR_03 = "internal.pvp.03";
+ private static final String ERROR_10 = "internal.pvp.10";
+ private static final String ERROR_14 = "internal.pvp.14";
+ private static final String ERROR_15 = "internal.pvp.15";
+ private static final String ERROR_16 = "internal.pvp.16";
+ private static final String ERROR_17 = "internal.pvp.17";
+
+ private static final Object SIG_VAL_ERROR_MSG = "Signature verification return false";
+
+ /**
+ * 5 allow 3 minutes time jitter in before validation.
+ */
+ private static final int TIME_JITTER = 3;
+
+
+
+
+
@Autowired(required = true)
IPvp2MetadataProvider metadataProvider;
/**
* Verify signature of a signed SAML2 object.
*
+ *<p>This method only perform signature verification</p>
+ *
* @param msg SAML2 message
* @param sigTrustEngine TrustEngine
* @throws org.opensaml.xml.security.SecurityException In case of invalid
@@ -85,7 +128,7 @@ public class SamlVerificationEngine {
} else {
log.warn("SAML2 message type: {} not supported", msg.getClass().getName());
- throw new EaafProtocolException("9999", null);
+ throw new EaafProtocolException("internal.pvp.99", null);
}
@@ -94,13 +137,14 @@ public class SamlVerificationEngine {
throw e;
}
- log.debug(
- "PVP2X message validation FAILED. Relead metadata for entityID: " + msg.getEntityID());
+ log.debug("PVP2X message validation FAILED. Relead metadata for entityID: {}",
+ msg.getEntityID());
if (metadataProvider == null || !(metadataProvider instanceof IRefreshableMetadataProvider)
|| !((IRefreshableMetadataProvider) metadataProvider)
.refreshMetadataProvider(msg.getEntityID())) {
throw e;
+
} else {
log.trace("PVP2X metadata reload finished. Check validate message again.");
@@ -108,30 +152,261 @@ public class SamlVerificationEngine {
&& ((PvpSProfileRequest) msg).getSamlRequest() instanceof RequestAbstractType) {
verifyRequest((RequestAbstractType) ((PvpSProfileRequest) msg).getSamlRequest(),
sigTrustEngine);
+
} else {
verifyIdpResponse(((PvpSProfileResponse) msg).getResponse(), sigTrustEngine);
+
}
}
log.trace("Second PVP2X message validation finished");
+
}
}
+ /**
+ * Verify the signature of a signed SAML2 object from ServiceProvider.
+ *
+ * @param samlObj signed Response from ServiceProvider
+ * @param sigTrustEngine TrustEngie for verification
+ * @throws InvalidProtocolRequestException In case of a verification error
+ */
public void verifySloResponse(final StatusResponseType samlObj,
final SignatureTrustEngine sigTrustEngine) throws InvalidProtocolRequestException {
verifyResponse(samlObj, sigTrustEngine, SPSSODescriptor.DEFAULT_ELEMENT_NAME);
}
+ /**
+ * Verify the signature of a signed SAML2 object from IDP.
+ *
+ * <p>This method only perform signature verification</p>
+ *
+ * @param samlObj signed SAML2 message from IDP
+ * @param sigTrustEngine TrustEngie for verification
+ * @throws InvalidProtocolRequestException In case of a verification error
+ */
public void verifyIdpResponse(final StatusResponseType samlObj,
final SignatureTrustEngine sigTrustEngine) throws InvalidProtocolRequestException {
verifyResponse(samlObj, sigTrustEngine, IDPSSODescriptor.DEFAULT_ELEMENT_NAME);
}
+ /**
+ * Validate a PVP response and all included assertions.
+ *
+ *<p>
+ * If the SAML2 assertions are encrypted than they will be decrypted afterwards
+ * </p>
+ *
+ *<p>This method <b>DOES NOT</b> verify the <i>Destination</i> attribute in SAML2 Response</p>
+ *
+ * @param samlResp SAML2 Response object
+ * @param assertionDecryption Assertion decryption-credentials to decrypt SAML2
+ * assertions
+ * @param spEntityID EntityId of the SAML2 client
+ * @param loggerName Name for logging purposes
+ * @throws SamlAssertionValidationExeption In case of a validation error
+ */
+ public void validateAssertion(Response samlResp,
+ EaafX509Credential assertionDecryption, String spEntityID, String loggerName)
+ throws SamlAssertionValidationExeption {
+ validateAssertion(samlResp, assertionDecryption, spEntityID, loggerName, true);
+
+ }
+
+ /**
+ * Validate each SAML2 assertions in a SAML2 response. <br>
+ * <p>
+ * If the SAML2 assertions are encrypted than they will be decrypted afterwards
+ * </p>
+ *
+ *<p>This method <b>DOES NOT</b> verify the <i>Destination</i> attribute in SAML2 Response</p>
+ *
+ * @param samlResp SAML2 Response object
+ * @param assertionDecryption Assertion decryption-credentials to decrypt SAML2
+ * assertions
+ * @param spEntityID EntityId of the SAML2 client
+ * @param loggerName Name for logging purposes
+ * @param validateDateTime <code>true</code> if <i>getIssueInstant</i>
+ * attribute should be validated, otherwise false
+ * @throws SamlAssertionValidationExeption In case of a validation error
+ */
+ public void validateAssertion(Response samlResp, EaafX509Credential assertionDecryption,
+ String spEntityID, String loggerName, boolean validateDateTime)
+ throws SamlAssertionValidationExeption {
+ try {
+ // pre-validate the SAML2 response
+ assertionPreValidation(samlResp, loggerName, validateDateTime);
+
+ // get Assertion from response and decrypt them if the are encrypted
+ final List<Assertion> saml2assertions = getOrDecryptAndGetAssertions(samlResp, assertionDecryption);
+
+ // validate each assertion
+ final List<Assertion> validatedassertions = new ArrayList<>();
+ for (final Assertion saml2assertion : saml2assertions) {
+ if (internalAssertionValidation(saml2assertion, spEntityID, validateDateTime)) {
+ log.debug("Add valid Assertion:" + saml2assertion.getID());
+ validatedassertions.add(saml2assertion);
+
+ } else {
+ log.warn("Remove non-valid Assertion:" + saml2assertion.getID());
+ }
+
+ }
+
+ if (validatedassertions.isEmpty()) {
+ log.info("No valid PVP 2.1 assertion received.");
+ throw new SamlAssertionValidationExeption(ERROR_15, new Object[] { loggerName });
+
+ }
+
+ samlResp.getAssertions().clear();
+ samlResp.getEncryptedAssertions().clear();
+ samlResp.getAssertions().addAll(validatedassertions);
+
+ } catch (final DecryptionException e) {
+ log.warn("Assertion decrypt FAILED.", e);
+ throw new SamlAssertionValidationExeption(ERROR_16,
+ new Object[] { e.getMessage() }, e);
+
+// } catch (final ConfigurationException e) {
+// throw new AssertionValidationExeption("pvp.12",
+// new Object[]{loggerName, e.getMessage()}, e);
+ }
+ }
+
+ private boolean internalAssertionValidation(Assertion saml2assertion, String spEntityId,
+ boolean validateDateTime) {
+ boolean isAssertionValid = true;
+ try {
+ // schema validation
+ performSchemaValidation(saml2assertion.getDOM());
+
+ // validate DateTime conditions
+ final Conditions conditions = saml2assertion.getConditions();
+ if (conditions != null) {
+ final DateTime notbefore = conditions.getNotBefore().minusMinutes(5);
+ final DateTime notafter = conditions.getNotOnOrAfter();
+ if (validateDateTime
+ && (notbefore.isAfterNow() || notafter.isBeforeNow())) {
+ isAssertionValid = false;
+ log.info("Assertion with ID:{} is out of Date. [ Current:{} NotBefore:{} NotAfter:{} ]",
+ saml2assertion.getID(), new DateTime(), notbefore, notafter);
+
+ }
+
+ // validate audienceRestrictions are valid for this SP
+ final List<AudienceRestriction> audienceRest = conditions.getAudienceRestrictions();
+ if (audienceRest == null || audienceRest.size() == 0) {
+ log.info("Assertion with ID:{} has not 'AudienceRestriction' element",
+ saml2assertion.getID());
+ isAssertionValid = false;
+
+ } else {
+ for (final AudienceRestriction el : audienceRest) {
+ for (final Audience audience : el.getAudiences()) {
+ if (!urlCompare(spEntityId, audience.getAudienceURI())) {
+ log.info("Assertion with ID:{} 'AudienceRestriction' is not valid.",
+ saml2assertion.getID());
+ isAssertionValid = false;
+
+ }
+ }
+ }
+ }
+
+ } else {
+ log.info("Assertion with ID:{} contains not 'Conditions' element",
+ saml2assertion.getID());
+ isAssertionValid = false;
+
+ }
+
+ } catch (final SchemaValidationException e) {
+ isAssertionValid = false;
+ log.info("Assertion with ID:{} FAILED Schema validation. Msg: {}",
+ saml2assertion.getID(), e.getMessage());
+
+ } catch (final URIException e) {
+ isAssertionValid = false;
+ log.info("Assertion with ID:{} FAILED AudienceRestriction validation. Msg:",
+ saml2assertion.getID(), e.getMessage());
+
+ }
+
+ return isAssertionValid;
+
+ }
+
+ private List<Assertion> getOrDecryptAndGetAssertions(Response samlResp,
+ EaafX509Credential assertionDecryption) throws DecryptionException {
+ final List<Assertion> saml2assertions = new ArrayList<>();
+
+ // check encrypted Assertions
+ final List<EncryptedAssertion> encryAssertionList = samlResp.getEncryptedAssertions();
+ if (encryAssertionList != null && encryAssertionList.size() > 0) {
+ // decrypt assertions
+ log.debug("Found encryped assertion. Start decryption ...");
+ final List<EncryptedKeyResolver> listOfKeyResolvers = new ArrayList<>();
+ listOfKeyResolvers.add(new InlineEncryptedKeyResolver());
+ listOfKeyResolvers.add(new EncryptedElementTypeEncryptedKeyResolver());
+ listOfKeyResolvers.add(new SimpleRetrievalMethodEncryptedKeyResolver());
+
+ final Decrypter samlDecrypter = new Decrypter(null,
+ new StaticKeyInfoCredentialResolver(assertionDecryption),
+ new ChainingEncryptedKeyResolver(listOfKeyResolvers));
+
+ for (final EncryptedAssertion encAssertion : encryAssertionList) {
+ saml2assertions.add(samlDecrypter.decrypt(encAssertion));
+
+ }
+ log.debug("Assertion decryption finished. ");
+
+ }
+
+ saml2assertions.addAll(samlResp.getAssertions());
+
+ return saml2assertions;
+
+ }
+
+ private void performSchemaValidation(final Element source) throws SchemaValidationException {
+
+ String err = null;
+ try {
+ final Schema test = schemaBuilder.getSAMLSchema();
+ final Validator val = test.newValidator();
+ val.validate(new DOMSource(source));
+ log.debug("Schema validation check done OK");
+ return;
+
+ } catch (final SAXException e) {
+ err = e.getMessage();
+ if (log.isDebugEnabled() || log.isTraceEnabled()) {
+ log.warn("Schema validation FAILED with exception:", e);
+ } else {
+ log.warn("Schema validation FAILED with message: " + e.getMessage());
+ }
+
+ } catch (final Exception e) {
+ err = e.getMessage();
+ if (log.isDebugEnabled() || log.isTraceEnabled()) {
+ log.warn("Schema validation FAILED with exception:", e);
+ } else {
+ log.warn("Schema validation FAILED with message: " + e.getMessage());
+ }
+
+ }
+
+ throw new SchemaValidationException(ERROR_03, new Object[] { err });
+
+ }
+
private void verifyResponse(final StatusResponseType samlObj,
final SignatureTrustEngine sigTrustEngine, final QName defaultElementName)
throws InvalidProtocolRequestException {
+
final SAMLSignatureProfileValidator profileValidator = new SAMLSignatureProfileValidator();
try {
profileValidator.validate(samlObj.getSignature());
@@ -139,10 +414,10 @@ public class SamlVerificationEngine {
} catch (final SignatureException e) {
log.warn("Signature is not conform to SAML signature profile", e);
- throw new InvalidProtocolRequestException("pvp2.21", new Object[] {});
+ throw new InvalidProtocolRequestException(ERROR_10, new Object[] {e.getMessage() }, e);
} catch (final SchemaValidationException e) {
- throw new InvalidProtocolRequestException("pvp2.22", new Object[] { e.getMessage() });
+ throw new InvalidProtocolRequestException(ERROR_03, new Object[] { e.getMessage() }, e);
}
@@ -154,11 +429,14 @@ public class SamlVerificationEngine {
try {
if (!sigTrustEngine.validate(samlObj.getSignature(), criteriaSet)) {
- throw new InvalidProtocolRequestException("pvp2.21", new Object[] {});
+ throw new InvalidProtocolRequestException(ERROR_10, new Object[] {SIG_VAL_ERROR_MSG});
+
}
+
} catch (final org.opensaml.security.SecurityException e) {
log.warn("PVP2x message signature validation FAILED.", e);
- throw new InvalidProtocolRequestException("pvp2.21", new Object[] {});
+ throw new InvalidProtocolRequestException(ERROR_10, new Object[] {e.getMessage()}, e);
+
}
}
@@ -171,10 +449,10 @@ public class SamlVerificationEngine {
} catch (final SignatureException e) {
log.warn("Signature is not conform to SAML signature profile", e);
- throw new InvalidProtocolRequestException("pvp2.21", new Object[] {});
+ throw new InvalidProtocolRequestException(ERROR_10, new Object[] {e.getMessage()}, e);
} catch (final SchemaValidationException e) {
- throw new InvalidProtocolRequestException("pvp2.22", new Object[] { e.getMessage() });
+ throw new InvalidProtocolRequestException(ERROR_03, new Object[] { e.getMessage() }, e);
}
@@ -186,44 +464,53 @@ public class SamlVerificationEngine {
try {
if (!sigTrustEngine.validate(samlObj.getSignature(), criteriaSet)) {
- throw new InvalidProtocolRequestException("pvp2.21", new Object[] {});
+ throw new InvalidProtocolRequestException(ERROR_10, new Object[] {SIG_VAL_ERROR_MSG});
+
}
} catch (final org.opensaml.security.SecurityException e) {
log.warn("PVP2x message signature validation FAILED.", e);
- throw new InvalidProtocolRequestException("pvp2.21", new Object[] {});
+ throw new InvalidProtocolRequestException(ERROR_10, new Object[] {e.getMessage()}, e);
+
}
+
}
- protected void performSchemaValidation(final Element source) throws SchemaValidationException {
+ private void assertionPreValidation(Response samlResp, String loggerName, boolean validateDateTime)
+ throws SamlAssertionValidationExeption {
+ if (samlResp.getStatus().getStatusCode().getValue().equals(StatusCode.SUCCESS)) {
+ // validate response issueInstant
+ final DateTime issueInstant = samlResp.getIssueInstant();
+ if (issueInstant == null) {
+ log.warn("PVP response does not include a 'IssueInstant' attribute");
+ throw new SamlAssertionValidationExeption(ERROR_14,
+ new Object[] { loggerName, "'IssueInstant' attribute is not included" });
- String err = null;
- try {
- final Schema test = schemaBuilder.getSAMLSchema();
- final Validator val = test.newValidator();
- val.validate(new DOMSource(source));
- log.debug("Schema validation check done OK");
- return;
-
- } catch (final SAXException e) {
- err = e.getMessage();
- if (log.isDebugEnabled() || log.isTraceEnabled()) {
- log.warn("Schema validation FAILED with exception:", e);
- } else {
- log.warn("Schema validation FAILED with message: " + e.getMessage());
}
+ if (validateDateTime && issueInstant.minusMinutes(TIME_JITTER).isAfterNow()) {
+ log.warn("PVP response: IssueInstant DateTime is not valid anymore.");
+ throw new SamlAssertionValidationExeption(ERROR_14,
+ new Object[] { loggerName, "'IssueInstant' Time is not valid any more" });
- } catch (final Exception e) {
- err = e.getMessage();
- if (log.isDebugEnabled() || log.isTraceEnabled()) {
- log.warn("Schema validation FAILED with exception:", e);
- } else {
- log.warn("Schema validation FAILED with message: " + e.getMessage());
}
- }
+ } else {
+ log.info("PVP 2.x assertion includes an error. Receive errorcode "
+ + samlResp.getStatus().getStatusCode().getValue());
+ throw new SamlAssertionValidationExeption(ERROR_17,
+ new Object[] { loggerName,
+ samlResp.getIssuer().getValue(),
+ samlResp.getStatus().getStatusCode().getValue(),
+ samlResp.getStatus().getStatusMessage() != null
+ ? samlResp.getStatus().getStatusMessage().getMessage()
+ : " no status message" });
- throw new SchemaValidationException("pvp2.22", new Object[] { err });
+ }
+ }
+ private static boolean urlCompare(String url1, String url2) throws URIException {
+ final BasicURLComparator comparator = new BasicURLComparator();
+ comparator.setCaseInsensitive(false);
+ return comparator.compare(url1, url2);
}
}