Author: coheigea
Date: Mon Feb 3 16:59:13 2014
New Revision: 1563980
URL: http://svn.apache.org/r1563980
Log:
Some fixes taken from WSS4J for the SamlAssertionValidator
Modified:
cxf/fediz/trunk/plugins/core/src/main/java/org/apache/cxf/fediz/core/saml/SamlAssertionValidator.java
Modified:
cxf/fediz/trunk/plugins/core/src/main/java/org/apache/cxf/fediz/core/saml/SamlAssertionValidator.java
URL:
http://svn.apache.org/viewvc/cxf/fediz/trunk/plugins/core/src/main/java/org/apache/cxf/fediz/core/saml/SamlAssertionValidator.java?rev=1563980&r1=1563979&r2=1563980&view=diff
==============================================================================
---
cxf/fediz/trunk/plugins/core/src/main/java/org/apache/cxf/fediz/core/saml/SamlAssertionValidator.java
(original)
+++
cxf/fediz/trunk/plugins/core/src/main/java/org/apache/cxf/fediz/core/saml/SamlAssertionValidator.java
Mon Feb 3 16:59:13 2014
@@ -26,11 +26,13 @@ import java.security.cert.CertificateNot
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.Date;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
+import org.apache.wss4j.common.cache.ReplayCache;
import org.apache.wss4j.common.crypto.Crypto;
import org.apache.wss4j.common.ext.WSSecurityException;
import org.apache.wss4j.common.saml.OpenSAMLUtil;
@@ -41,8 +43,6 @@ import org.apache.wss4j.dom.validate.Cre
import org.apache.wss4j.dom.validate.Validator;
import org.joda.time.DateTime;
import org.opensaml.common.SAMLVersion;
-import org.opensaml.xml.validation.ValidationException;
-import org.opensaml.xml.validation.ValidatorSuite;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -64,6 +64,12 @@ public class SamlAssertionValidator impl
* Assertion is valid. The default is 60 seconds.
*/
private int futureTTL = 60;
+
+ /**
+ * Whether to validate the signature of the Assertion (if it exists)
against the
+ * relevant profile. Default is true.
+ */
+ private boolean validateSignatureAgainstProfile = true;
/**
* Defines the kind of trust which is required thus assertion signature
validation is successful.
@@ -144,6 +150,9 @@ public class SamlAssertionValidator impl
// Check conditions
checkConditions(assertion);
+ // Check OneTimeUse Condition
+ checkOneTimeUse(assertion, data);
+
// Validate the assertion against schemas/profiles
validateAssertion(assertion);
@@ -180,7 +189,6 @@ public class SamlAssertionValidator impl
if (certs != null && certs.length > 0) {
validateCertificates(certs);
- validateCertificates(certs);
verifyTrustInCerts(certs, crypto, data,
data.isRevocationEnabled());
if (signatureTrustType.equals(TRUST_TYPE.CHAIN_TRUST_CONSTRAINTS))
{
if (matches(certs[0])) {
@@ -240,13 +248,13 @@ public class SamlAssertionValidator impl
RequestData data,
boolean enableRevocation
) throws WSSecurityException {
- String subjectString =
certificates[0].getSubjectX500Principal().getName();
//
// Use the validation method from the crypto to check whether the
subjects'
// certificate was really signed by the issuer stated in the
certificate
//
crypto.verifyTrust(certificates, enableRevocation);
if (LOG.isDebugEnabled()) {
+ String subjectString =
certificates[0].getSubjectX500Principal().getName();
LOG.debug(
"Certificate path has been verified for certificate with
subject " + subjectString
);
@@ -262,73 +270,73 @@ public class SamlAssertionValidator impl
crypto.verifyTrust(publicKey);
}
+
/**
* Check the Conditions of the Assertion.
*/
- protected void checkConditions(SamlAssertionWrapper assertion) throws
WSSecurityException {
- DateTime validFrom = null;
- DateTime validTill = null;
- if (assertion.getSamlVersion().equals(SAMLVersion.VERSION_20)
- && assertion.getSaml2().getConditions() != null) {
- validFrom = assertion.getSaml2().getConditions().getNotBefore();
- validTill = assertion.getSaml2().getConditions().getNotOnOrAfter();
- } else if (assertion.getSamlVersion().equals(SAMLVersion.VERSION_11)
- && assertion.getSaml1().getConditions() != null) {
- validFrom = assertion.getSaml1().getConditions().getNotBefore();
- validTill = assertion.getSaml1().getConditions().getNotOnOrAfter();
- }
-
- if (validFrom != null) {
- DateTime currentTime = new DateTime();
- currentTime = currentTime.plusSeconds(futureTTL);
- if (validFrom.isAfter(currentTime)) {
- LOG.debug("SAML Token condition (Not Before) not met");
- throw new
WSSecurityException(WSSecurityException.ErrorCode.FAILURE,
"invalidSAMLsecurity");
- }
- }
-
- if (validTill != null && validTill.isBeforeNow()) {
- LOG.debug("SAML Token condition (Not On Or After) not met");
- throw new
WSSecurityException(WSSecurityException.ErrorCode.FAILURE,
"invalidSAMLsecurity");
- }
+ protected void checkConditions(SamlAssertionWrapper samlAssertion) throws
WSSecurityException {
+ samlAssertion.checkConditions(futureTTL);
}
/**
- * Validate the assertion against schemas/profiles
- */
- protected void validateAssertion(SamlAssertionWrapper assertion) throws
WSSecurityException {
- if (assertion.getSaml1() != null) {
- ValidatorSuite schemaValidators =
-
org.opensaml.Configuration.getValidatorSuite("saml1-schema-validator");
- ValidatorSuite specValidators =
-
org.opensaml.Configuration.getValidatorSuite("saml1-spec-validator");
- try {
- schemaValidators.validate(assertion.getSaml1());
- specValidators.validate(assertion.getSaml1());
- } catch (ValidationException e) {
- LOG.debug("Saml Validation error: " + e.getMessage(), e);
- throw new WSSecurityException(
- WSSecurityException.ErrorCode.FAILURE,
"invalidSAMLsecurity", null, e
- );
- }
- } else if (assertion.getSaml2() != null) {
- ValidatorSuite schemaValidators =
-
org.opensaml.Configuration.getValidatorSuite("saml2-core-schema-validator");
- ValidatorSuite specValidators =
-
org.opensaml.Configuration.getValidatorSuite("saml2-core-spec-validator");
- try {
- schemaValidators.validate(assertion.getSaml2());
- specValidators.validate(assertion.getSaml2());
- } catch (ValidationException e) {
- LOG.debug("Saml Validation error: " + e.getMessage(), e);
+ * Check the "OneTimeUse" Condition of the Assertion. If this is set then
the Assertion
+ * is cached (if a cache is defined), and must not have been previously
cached
+ */
+ protected void checkOneTimeUse(
+ SamlAssertionWrapper samlAssertion, RequestData data
+ ) throws WSSecurityException {
+ if (samlAssertion.getSamlVersion().equals(SAMLVersion.VERSION_20)
+ && samlAssertion.getSaml2().getConditions() != null
+ && samlAssertion.getSaml2().getConditions().getOneTimeUse() != null
+ && data.getSamlOneTimeUseReplayCache() != null) {
+ String identifier = samlAssertion.getId();
+
+ ReplayCache replayCache = data.getSamlOneTimeUseReplayCache();
+ if (replayCache.contains(identifier)) {
throw new WSSecurityException(
- WSSecurityException.ErrorCode.FAILURE,
"invalidSAMLsecurity", null, e
- );
+ WSSecurityException.ErrorCode.INVALID_SECURITY,
+ "badSamlToken",
+ "A replay attack has been detected");
+ }
+
+ DateTime expires =
samlAssertion.getSaml2().getConditions().getNotOnOrAfter();
+ if (expires != null) {
+ Date rightNow = new Date();
+ long currentTime = rightNow.getTime();
+ long expiresTime = expires.getMillis();
+ replayCache.add(identifier, 1L + (expiresTime - currentTime) /
1000L);
+ } else {
+ replayCache.add(identifier);
}
+
+ replayCache.add(identifier);
}
}
/**
+ * Validate the samlAssertion against schemas/profiles
+ */
+ protected void validateAssertion(SamlAssertionWrapper samlAssertion)
throws WSSecurityException {
+ samlAssertion.validateAssertion(validateSignatureAgainstProfile);
+ }
+
+ /**
+ * Whether to validate the signature of the Assertion (if it exists)
against the
+ * relevant profile. Default is true.
+ */
+ public boolean isValidateSignatureAgainstProfile() {
+ return validateSignatureAgainstProfile;
+ }
+
+ /**
+ * Whether to validate the signature of the Assertion (if it exists)
against the
+ * relevant profile. Default is true.
+ */
+ public void setValidateSignatureAgainstProfile(boolean
validateSignatureAgainstProfile) {
+ this.validateSignatureAgainstProfile = validateSignatureAgainstProfile;
+ }
+
+ /**
* @return true if the certificate's SubjectDN matches the constraints
* defined in the subject DNConstraints; false, otherwise. The
* certificate subject DN only has to match ONE of the subject cert