You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ws.apache.org by co...@apache.org on 2012/06/22 17:14:00 UTC
svn commit: r1352919 - in /webservices/wss4j/trunk/src:
main/java/org/apache/ws/security/handler/
main/java/org/apache/ws/security/validate/
test/java/org/apache/ws/security/message/
Author: coheigea
Date: Fri Jun 22 15:13:59 2012
New Revision: 1352919
URL: http://svn.apache.org/viewvc?rev=1352919&view=rev
Log:
[WSS-395] - Support Certificate Constraints on the Subject DN of the certificate used for signature validation
Added:
webservices/wss4j/trunk/src/test/java/org/apache/ws/security/message/SignatureCertConstraintsTest.java
Modified:
webservices/wss4j/trunk/src/main/java/org/apache/ws/security/handler/RequestData.java
webservices/wss4j/trunk/src/main/java/org/apache/ws/security/handler/WSHandler.java
webservices/wss4j/trunk/src/main/java/org/apache/ws/security/handler/WSHandlerConstants.java
webservices/wss4j/trunk/src/main/java/org/apache/ws/security/validate/SignatureTrustValidator.java
Modified: webservices/wss4j/trunk/src/main/java/org/apache/ws/security/handler/RequestData.java
URL: http://svn.apache.org/viewvc/webservices/wss4j/trunk/src/main/java/org/apache/ws/security/handler/RequestData.java?rev=1352919&r1=1352918&r2=1352919&view=diff
==============================================================================
--- webservices/wss4j/trunk/src/main/java/org/apache/ws/security/handler/RequestData.java (original)
+++ webservices/wss4j/trunk/src/main/java/org/apache/ws/security/handler/RequestData.java Fri Jun 22 15:13:59 2012
@@ -19,6 +19,15 @@
package org.apache.ws.security.handler;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.regex.Pattern;
+
+import javax.security.auth.callback.CallbackHandler;
+import javax.xml.namespace.QName;
+
import org.apache.ws.security.SOAPConstants;
import org.apache.ws.security.WSConstants;
import org.apache.ws.security.WSEncryptionPart;
@@ -30,19 +39,13 @@ import org.apache.ws.security.message.WS
import org.apache.ws.security.message.token.UsernameToken;
import org.apache.ws.security.validate.Validator;
-import java.util.ArrayList;
-import java.util.List;
-import java.security.cert.X509Certificate;
-
-import javax.security.auth.callback.CallbackHandler;
-import javax.xml.namespace.QName;
-
/**
* This class holds per request data.
*
* @author Werner Dittmann (Werner.Dittmann@t-online.de)
*/
public class RequestData {
+
private Object msgContext = null;
private boolean noSerialization = false;
private SOAPConstants soapConstants = null;
@@ -79,6 +82,7 @@ public class RequestData {
protected boolean requireSignedEncryptedDataElements = false;
private ReplayCache timestampReplayCache;
private ReplayCache nonceReplayCache;
+ private Collection<Pattern> subjectDNPatterns = new ArrayList<Pattern>();
public void clear() {
soapConstants = null;
@@ -102,6 +106,7 @@ public class RequestData {
enableRevocation = false;
timestampReplayCache = null;
nonceReplayCache = null;
+ subjectDNPatterns.clear();
}
public Object getMsgContext() {
@@ -480,5 +485,21 @@ public class RequestData {
public ReplayCache getNonceReplayCache() {
return nonceReplayCache;
}
+
+ /**
+ * Set the Signature Subject Cert Constraints
+ */
+ public void setSubjectCertConstraints(Collection<Pattern> subjectCertConstraints) {
+ if (subjectCertConstraints != null) {
+ subjectDNPatterns.addAll(subjectCertConstraints);
+ }
+ }
+
+ /**
+ * Get the Signature Subject Cert Constraints
+ */
+ public Collection<Pattern> getSubjectCertConstraints() {
+ return subjectDNPatterns;
+ }
}
Modified: webservices/wss4j/trunk/src/main/java/org/apache/ws/security/handler/WSHandler.java
URL: http://svn.apache.org/viewvc/webservices/wss4j/trunk/src/main/java/org/apache/ws/security/handler/WSHandler.java?rev=1352919&r1=1352918&r2=1352919&view=diff
==============================================================================
--- webservices/wss4j/trunk/src/main/java/org/apache/ws/security/handler/WSHandler.java (original)
+++ webservices/wss4j/trunk/src/main/java/org/apache/ws/security/handler/WSHandler.java Fri Jun 22 15:13:59 2012
@@ -42,10 +42,13 @@ import javax.security.auth.callback.Call
import java.security.cert.X509Certificate;
import java.util.Arrays;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
+import java.util.regex.Pattern;
+import java.util.regex.PatternSyntaxException;
/**
@@ -1105,6 +1108,25 @@ public abstract class WSHandler {
reqData, WSHandlerConstants.ENABLE_REVOCATION, false
);
reqData.setEnableRevocation(enableRevocation);
+
+ String certConstraints =
+ getString(WSHandlerConstants.SIG_SUBJECT_CERT_CONSTRAINTS, reqData.getMsgContext());
+ if (certConstraints != null) {
+ String[] certConstraintsList = certConstraints.split(",");
+ if (certConstraintsList != null) {
+ Collection<Pattern> subjectCertConstraints =
+ new ArrayList<Pattern>(certConstraintsList.length);
+ for (String certConstraint : certConstraintsList) {
+ try {
+ subjectCertConstraints.add(Pattern.compile(certConstraint.trim()));
+ } catch (PatternSyntaxException ex) {
+ log.debug(ex.getMessage(), ex);
+ throw new WSSecurityException(ex.getMessage(), ex);
+ }
+ }
+ reqData.setSubjectCertConstraints(subjectCertConstraints);
+ }
+ }
}
/*
Modified: webservices/wss4j/trunk/src/main/java/org/apache/ws/security/handler/WSHandlerConstants.java
URL: http://svn.apache.org/viewvc/webservices/wss4j/trunk/src/main/java/org/apache/ws/security/handler/WSHandlerConstants.java?rev=1352919&r1=1352918&r2=1352919&view=diff
==============================================================================
--- webservices/wss4j/trunk/src/main/java/org/apache/ws/security/handler/WSHandlerConstants.java (original)
+++ webservices/wss4j/trunk/src/main/java/org/apache/ws/security/handler/WSHandlerConstants.java Fri Jun 22 15:13:59 2012
@@ -675,6 +675,15 @@ public final class WSHandlerConstants {
*/
public static final String TTL_FUTURE_TIMESTAMP = "futureTimeToLive";
+ /**
+ * This configuration tag is a comma separated String of regular expressions which
+ * will be applied to the subject DN of the certificate used for signature
+ * validation, after trust verification of the certificate chain associated with the
+ * certificate. These constraints are not used when the certificate is contained in
+ * the keystore (direct trust).
+ */
+ public static final String SIG_SUBJECT_CERT_CONSTRAINTS = "sigSubjectCertConstraints";
+
//
// Internal storage constants
Modified: webservices/wss4j/trunk/src/main/java/org/apache/ws/security/validate/SignatureTrustValidator.java
URL: http://svn.apache.org/viewvc/webservices/wss4j/trunk/src/main/java/org/apache/ws/security/validate/SignatureTrustValidator.java?rev=1352919&r1=1352918&r2=1352919&view=diff
==============================================================================
--- webservices/wss4j/trunk/src/main/java/org/apache/ws/security/validate/SignatureTrustValidator.java (original)
+++ webservices/wss4j/trunk/src/main/java/org/apache/ws/security/validate/SignatureTrustValidator.java Fri Jun 22 15:13:59 2012
@@ -24,6 +24,9 @@ import java.security.PublicKey;
import java.security.cert.CertificateExpiredException;
import java.security.cert.CertificateNotYetValidException;
import java.security.cert.X509Certificate;
+import java.util.Collection;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
import org.apache.ws.security.WSSecurityException;
import org.apache.ws.security.components.crypto.Crypto;
@@ -66,9 +69,9 @@ public class SignatureTrustValidator imp
boolean trust = false;
boolean enableRevocation = data.isRevocationEnabled();
if (certs.length == 1) {
- trust = verifyTrustInCert(certs[0], crypto, enableRevocation);
+ trust = verifyTrustInCert(certs[0], crypto, data, enableRevocation);
} else {
- trust = verifyTrustInCerts(certs, crypto, enableRevocation);
+ trust = verifyTrustInCerts(certs, crypto, data, enableRevocation);
}
if (trust) {
return credential;
@@ -110,25 +113,16 @@ public class SignatureTrustValidator imp
}
}
- /**
- * Evaluate whether a given certificate should be trusted.
- *
- * Policy used in this implementation:
- * 1. Search the keystore for the transmitted certificate
- * 2. Search the keystore for a connection to the transmitted certificate
- * (that is, search for certificate(s) of the issuer of the transmitted certificate
- * 3. Verify the trust path for those certificates found because the search for the issuer
- * might be fooled by a phony DN (String!)
- *
- * @param cert the certificate that should be validated against the keystore
- * @param crypto A crypto instance to use for trust validation
- * @return true if the certificate is trusted, false if not
- * @throws WSSecurityException
- */
@Deprecated
protected boolean verifyTrustInCert(X509Certificate cert, Crypto crypto)
throws WSSecurityException {
- return verifyTrustInCert(cert, crypto, false);
+ return verifyTrustInCert(cert, crypto, new RequestData(), false);
+ }
+
+ @Deprecated
+ protected boolean verifyTrustInCert(X509Certificate cert, Crypto crypto, boolean enableRevocation)
+ throws WSSecurityException {
+ return verifyTrustInCert(cert, crypto, new RequestData(), enableRevocation);
}
/**
@@ -143,6 +137,7 @@ public class SignatureTrustValidator imp
*
* @param cert the certificate that should be validated against the keystore
* @param crypto A crypto instance to use for trust validation
+ * @param data A RequestData instance
* @param enableRevocation Whether revocation is enabled or not
* @return true if the certificate is trusted, false if not
* @throws WSSecurityException
@@ -150,6 +145,7 @@ public class SignatureTrustValidator imp
protected boolean verifyTrustInCert(
X509Certificate cert,
Crypto crypto,
+ RequestData data,
boolean enableRevocation
) throws WSSecurityException {
String subjectString = cert.getSubjectX500Principal().getName();
@@ -221,7 +217,10 @@ public class SignatureTrustValidator imp
+ subjectString
);
}
- return true;
+ Collection<Pattern> subjectCertConstraints = data.getSubjectCertConstraints();
+ if (matches(cert, subjectCertConstraints)) {
+ return true;
+ }
}
if (LOG.isDebugEnabled()) {
@@ -272,20 +271,21 @@ public class SignatureTrustValidator imp
return false;
}
- /**
- * Evaluate whether the given certificate chain should be trusted.
- *
- * @param certificates the certificate chain that should be validated against the keystore
- * @param crypto A Crypto instance to use for trust validation
- * @return true if the certificate chain is trusted, false if not
- * @throws WSSecurityException
- */
@Deprecated
protected boolean verifyTrustInCerts(
X509Certificate[] certificates,
Crypto crypto
) throws WSSecurityException {
- return verifyTrustInCerts(certificates, crypto, false);
+ return verifyTrustInCerts(certificates, crypto, new RequestData(), false);
+ }
+
+ @Deprecated
+ protected boolean verifyTrustInCerts(
+ X509Certificate[] certificates,
+ Crypto crypto,
+ boolean enableRevocation
+ ) throws WSSecurityException {
+ return verifyTrustInCerts(certificates, crypto, new RequestData(), enableRevocation);
}
/**
@@ -293,6 +293,7 @@ public class SignatureTrustValidator imp
*
* @param certificates the certificate chain that should be validated against the keystore
* @param crypto A Crypto instance
+ * @param data A RequestData instance
* @param enableRevocation Whether revocation is enabled or not
* @return true if the certificate chain is trusted, false if not
* @throws WSSecurityException
@@ -300,6 +301,7 @@ public class SignatureTrustValidator imp
protected boolean verifyTrustInCerts(
X509Certificate[] certificates,
Crypto crypto,
+ RequestData data,
boolean enableRevocation
) throws WSSecurityException {
if (certificates == null || certificates.length < 2) {
@@ -318,7 +320,10 @@ public class SignatureTrustValidator imp
+ subjectString
);
}
- return true;
+ Collection<Pattern> subjectCertConstraints = data.getSubjectCertConstraints();
+ if (matches(certificates[0], subjectCertConstraints)) {
+ return true;
+ }
}
if (LOG.isDebugEnabled()) {
@@ -340,4 +345,40 @@ public class SignatureTrustValidator imp
return crypto.verifyTrust(publicKey);
}
+ /**
+ * @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 constraints (not all).
+ */
+ protected boolean
+ matches(
+ final java.security.cert.X509Certificate cert,
+ final Collection<Pattern> subjectDNPatterns
+ ) {
+ if (subjectDNPatterns.isEmpty()) {
+ LOG.warn("No Subject DN Certificate Constraints were defined. This could be a security issue");
+ }
+ if (!subjectDNPatterns.isEmpty()) {
+ if (cert == null) {
+ LOG.debug("The certificate is null so no constraints matching was possible");
+ return false;
+ }
+ String subjectName = cert.getSubjectX500Principal().getName();
+ boolean subjectMatch = false;
+ for (Pattern subjectDNPattern : subjectDNPatterns) {
+ final Matcher matcher = subjectDNPattern.matcher(subjectName);
+ if (matcher.matches()) {
+ LOG.debug("Subject DN " + subjectName + " matches with pattern " + subjectDNPattern);
+ subjectMatch = true;
+ break;
+ }
+ }
+ if (!subjectMatch) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
}
Added: webservices/wss4j/trunk/src/test/java/org/apache/ws/security/message/SignatureCertConstraintsTest.java
URL: http://svn.apache.org/viewvc/webservices/wss4j/trunk/src/test/java/org/apache/ws/security/message/SignatureCertConstraintsTest.java?rev=1352919&view=auto
==============================================================================
--- webservices/wss4j/trunk/src/test/java/org/apache/ws/security/message/SignatureCertConstraintsTest.java (added)
+++ webservices/wss4j/trunk/src/test/java/org/apache/ws/security/message/SignatureCertConstraintsTest.java Fri Jun 22 15:13:59 2012
@@ -0,0 +1,140 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.ws.security.message;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.regex.Pattern;
+
+import org.apache.ws.security.WSConstants;
+import org.apache.ws.security.WSSConfig;
+import org.apache.ws.security.WSSecurityEngine;
+import org.apache.ws.security.WSSecurityEngineResult;
+import org.apache.ws.security.WSSecurityException;
+import org.apache.ws.security.common.SOAPUtil;
+import org.apache.ws.security.components.crypto.Crypto;
+import org.apache.ws.security.components.crypto.CryptoFactory;
+import org.apache.ws.security.handler.RequestData;
+import org.apache.ws.security.util.WSSecurityUtil;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+
+/**
+ * A set of test-cases for signing and verifying SOAP requests, where the certificate used to
+ * verify the signature is validated against a set of cert constraints.
+ */
+public class SignatureCertConstraintsTest extends org.junit.Assert {
+ private static final org.apache.commons.logging.Log LOG =
+ org.apache.commons.logging.LogFactory.getLog(SignatureCertConstraintsTest.class);
+ private Crypto crypto = null;
+ private Crypto cryptoCA = null;
+
+ public SignatureCertConstraintsTest() throws Exception {
+ WSSConfig.init();
+ crypto = CryptoFactory.getInstance("wss40.properties");
+ cryptoCA = CryptoFactory.getInstance("wss40CA.properties");
+ }
+
+ /**
+ * The test uses the BinarySecurityToken key identifier type.
+ */
+ @org.junit.Test
+ public void testBSTSignature() throws Exception {
+ WSSecSignature builder = new WSSecSignature();
+ builder.setUserInfo("wss40", "security");
+ builder.setKeyIdentifierType(WSConstants.BST_DIRECT_REFERENCE);
+
+ Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
+ WSSecHeader secHeader = new WSSecHeader();
+ secHeader.insertSecurityHeader(doc);
+ Document signedDoc = builder.build(doc, crypto, secHeader);
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Signed message with BST key identifier:");
+ String outputString =
+ org.apache.ws.security.util.XMLUtils.PrettyDocumentToString(signedDoc);
+ LOG.debug(outputString);
+ }
+
+ Element securityHeader = WSSecurityUtil.getSecurityHeader(signedDoc, null);
+ String certConstraint = ".*CN=Colm.*O=Apache.*";
+ verify(securityHeader, cryptoCA, certConstraint);
+
+ certConstraint = ".*CN=Colm2.*O=Apache.*";
+ try {
+ verify(securityHeader, cryptoCA, certConstraint);
+ fail("Failure expected on a bad cert constraint");
+ } catch (WSSecurityException ex) {
+ // expected
+ }
+ }
+
+ /**
+ * The test uses the BinarySecurityToken key identifier type.
+ */
+ @org.junit.Test
+ public void testBSTSignaturePKIPath() throws Exception {
+ WSSecSignature builder = new WSSecSignature();
+ builder.setUserInfo("wss40", "security");
+ builder.setKeyIdentifierType(WSConstants.BST_DIRECT_REFERENCE);
+ builder.setUseSingleCertificate(false);
+
+ Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
+ WSSecHeader secHeader = new WSSecHeader();
+ secHeader.insertSecurityHeader(doc);
+ Document signedDoc = builder.build(doc, crypto, secHeader);
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Signed message with BST key identifier:");
+ String outputString =
+ org.apache.ws.security.util.XMLUtils.PrettyDocumentToString(signedDoc);
+ LOG.debug(outputString);
+ }
+
+ Element securityHeader = WSSecurityUtil.getSecurityHeader(signedDoc, null);
+ String certConstraint = ".*CN=Colm.*O=Apache.*";
+ verify(securityHeader, cryptoCA, certConstraint);
+
+ certConstraint = ".*CN=Colm2.*O=Apache.*";
+ try {
+ verify(securityHeader, cryptoCA, certConstraint);
+ fail("Failure expected on a bad cert constraint");
+ } catch (WSSecurityException ex) {
+ // expected
+ }
+ }
+
+ private List<WSSecurityEngineResult> verify(
+ Element securityHeader, Crypto sigCrypto, String certConstraint
+ ) throws Exception {
+ WSSecurityEngine secEngine = new WSSecurityEngine();
+ RequestData data = new RequestData();
+ data.setSigCrypto(sigCrypto);
+
+ if (certConstraint != null) {
+ Pattern subjectDNPattern = Pattern.compile(certConstraint.trim());
+ data.setSubjectCertConstraints(Collections.singletonList(subjectDNPattern));
+ }
+
+ return secEngine.processSecurityHeader(securityHeader, data);
+ }
+
+}