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 2016/10/18 15:06:05 UTC

svn commit: r1765457 - in /webservices/wss4j/trunk: ws-security-common/src/main/java/org/apache/wss4j/common/ ws-security-common/src/main/java/org/apache/wss4j/common/crypto/ ws-security-dom/src/main/java/org/apache/wss4j/dom/handler/ ws-security-dom/s...

Author: coheigea
Date: Tue Oct 18 15:06:04 2016
New Revision: 1765457

URL: http://svn.apache.org/viewvc?rev=1765457&view=rev
Log:
added support for a constraint on issuer DN of client certificate

Added:
    webservices/wss4j/trunk/ws-security-dom/src/test/java/org/apache/wss4j/dom/message/SignatureIssuerCertConstraintsTest.java
    webservices/wss4j/trunk/ws-security-stax/src/test/java/org/apache/wss4j/stax/test/SignatureIssuerCertConstaintsTest.java
Modified:
    webservices/wss4j/trunk/ws-security-common/src/main/java/org/apache/wss4j/common/ConfigurationConstants.java
    webservices/wss4j/trunk/ws-security-common/src/main/java/org/apache/wss4j/common/crypto/CertificateStore.java
    webservices/wss4j/trunk/ws-security-common/src/main/java/org/apache/wss4j/common/crypto/Crypto.java
    webservices/wss4j/trunk/ws-security-common/src/main/java/org/apache/wss4j/common/crypto/CryptoBase.java
    webservices/wss4j/trunk/ws-security-common/src/main/java/org/apache/wss4j/common/crypto/Merlin.java
    webservices/wss4j/trunk/ws-security-common/src/main/java/org/apache/wss4j/common/crypto/MerlinAKI.java
    webservices/wss4j/trunk/ws-security-dom/src/main/java/org/apache/wss4j/dom/handler/RequestData.java
    webservices/wss4j/trunk/ws-security-dom/src/main/java/org/apache/wss4j/dom/handler/WSHandler.java
    webservices/wss4j/trunk/ws-security-dom/src/main/java/org/apache/wss4j/dom/validate/SignatureTrustValidator.java
    webservices/wss4j/trunk/ws-security-stax/src/main/java/org/apache/wss4j/stax/ext/WSSSecurityProperties.java
    webservices/wss4j/trunk/ws-security-stax/src/main/java/org/apache/wss4j/stax/impl/securityToken/SamlSecurityTokenImpl.java
    webservices/wss4j/trunk/ws-security-stax/src/main/java/org/apache/wss4j/stax/impl/securityToken/X509SecurityTokenImpl.java
    webservices/wss4j/trunk/ws-security-stax/src/main/java/org/apache/wss4j/stax/setup/ConfigurationConverter.java

Modified: webservices/wss4j/trunk/ws-security-common/src/main/java/org/apache/wss4j/common/ConfigurationConstants.java
URL: http://svn.apache.org/viewvc/webservices/wss4j/trunk/ws-security-common/src/main/java/org/apache/wss4j/common/ConfigurationConstants.java?rev=1765457&r1=1765456&r2=1765457&view=diff
==============================================================================
--- webservices/wss4j/trunk/ws-security-common/src/main/java/org/apache/wss4j/common/ConfigurationConstants.java (original)
+++ webservices/wss4j/trunk/ws-security-common/src/main/java/org/apache/wss4j/common/ConfigurationConstants.java Tue Oct 18 15:06:04 2016
@@ -817,6 +817,14 @@ public class ConfigurationConstants {
     public static final String SIG_SUBJECT_CERT_CONSTRAINTS = "sigSubjectCertConstraints";
 
     /**
+     * This configuration tag is a comma separated String of regular expressions which
+     * will be applied to the issuer DN of the certificate used for signature
+     * validation, after trust verification of the certificate chain associated with the
+     * certificate.
+     */
+    public static final String SIG_ISSUER_CERT_CONSTRAINTS = "sigIssuerCertConstraints";
+
+    /**
      * Time-To-Live is the time difference between creation and expiry time in
      * seconds in the WSS Timestamp. After this time the SOAP request is
      * invalid (at least the security data shall be treated this way).

Modified: webservices/wss4j/trunk/ws-security-common/src/main/java/org/apache/wss4j/common/crypto/CertificateStore.java
URL: http://svn.apache.org/viewvc/webservices/wss4j/trunk/ws-security-common/src/main/java/org/apache/wss4j/common/crypto/CertificateStore.java?rev=1765457&r1=1765456&r2=1765457&view=diff
==============================================================================
--- webservices/wss4j/trunk/ws-security-common/src/main/java/org/apache/wss4j/common/crypto/CertificateStore.java (original)
+++ webservices/wss4j/trunk/ws-security-common/src/main/java/org/apache/wss4j/common/crypto/CertificateStore.java Tue Oct 18 15:06:04 2016
@@ -268,7 +268,16 @@ public class CertificateStore extends Cr
         }
 
         // Finally check Cert Constraints
-        if (!matches(certs[0], subjectCertConstraints)) {
+        if (!matchesSubjectDnPattern(certs[0], subjectCertConstraints)) {
+            throw new WSSecurityException(WSSecurityException.ErrorCode.FAILED_AUTHENTICATION);
+        }
+    }
+
+    @Override
+    public void verifyTrust(X509Certificate[] certs, boolean enableRevocation, Collection<Pattern> subjectCertConstraints,
+                            Collection<Pattern> issuerCertConstraints) throws WSSecurityException {
+        verifyTrust(certs,enableRevocation,subjectCertConstraints);
+        if (!matchesIssuerDnPattern(certs[0], issuerCertConstraints)) {
             throw new WSSecurityException(WSSecurityException.ErrorCode.FAILED_AUTHENTICATION);
         }
     }

Modified: webservices/wss4j/trunk/ws-security-common/src/main/java/org/apache/wss4j/common/crypto/Crypto.java
URL: http://svn.apache.org/viewvc/webservices/wss4j/trunk/ws-security-common/src/main/java/org/apache/wss4j/common/crypto/Crypto.java?rev=1765457&r1=1765456&r2=1765457&view=diff
==============================================================================
--- webservices/wss4j/trunk/ws-security-common/src/main/java/org/apache/wss4j/common/crypto/Crypto.java (original)
+++ webservices/wss4j/trunk/ws-security-common/src/main/java/org/apache/wss4j/common/crypto/Crypto.java Tue Oct 18 15:06:04 2016
@@ -217,6 +217,21 @@ public interface Crypto {
     ) throws WSSecurityException;
 
     /**
+     * Evaluate whether a given certificate chain should be trusted.
+     *
+     * @param certs Certificate chain to validate
+     * @param enableRevocation whether to enable CRL verification or not
+     * @param subjectCertConstraints A set of constraints on the Subject DN of the certificates
+     * @param issuerCertConstraints A set of constraints on the Issuer DN of the certificates
+     * @throws WSSecurityException if the certificate chain is invalid
+     */
+    void verifyTrust(
+            X509Certificate[] certs, boolean enableRevocation,
+            Collection<Pattern> subjectCertConstraints,Collection<Pattern> issuerCertConstraints
+    ) throws WSSecurityException;
+
+
+    /**
      * Evaluate whether a given public key should be trusted directly (located
      *
      * @param certs Certificate chain to validate

Modified: webservices/wss4j/trunk/ws-security-common/src/main/java/org/apache/wss4j/common/crypto/CryptoBase.java
URL: http://svn.apache.org/viewvc/webservices/wss4j/trunk/ws-security-common/src/main/java/org/apache/wss4j/common/crypto/CryptoBase.java?rev=1765457&r1=1765456&r2=1765457&view=diff
==============================================================================
--- webservices/wss4j/trunk/ws-security-common/src/main/java/org/apache/wss4j/common/crypto/CryptoBase.java (original)
+++ webservices/wss4j/trunk/ws-security-common/src/main/java/org/apache/wss4j/common/crypto/CryptoBase.java Tue Oct 18 15:06:04 2016
@@ -318,25 +318,60 @@ public abstract class CryptoBase impleme
      *              has to match ONE of the subject cert constraints (not all).
      */
     protected boolean
-    matches(
+    matchesSubjectDnPattern(
         final X509Certificate cert, final Collection<Pattern> subjectDNPatterns
     ) {
-        if (subjectDNPatterns == null || subjectDNPatterns.isEmpty()) {
-            LOG.warn("No Subject DN Certificate Constraints were defined. This could be a security issue");
-            return true;
+
+        if (cert == null) {
+            LOG.debug("The certificate is null so no constraints matching was possible");
+            return false;
         }
-        if (!subjectDNPatterns.isEmpty()) {
+        String subjectName = cert.getSubjectX500Principal().getName();
+        return matchesName(subjectName,subjectDNPatterns);
+    }
+
+    /**
+     * @return      true if the certificate's Issuer DN 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
+    matchesIssuerDnPattern(
+            final X509Certificate cert, final Collection<Pattern> issuerDNPatterns
+    ) {
+
             if (cert == null) {
                 LOG.debug("The certificate is null so no constraints matching was possible");
                 return false;
             }
-            String subjectName = cert.getSubjectX500Principal().getName();
+        String issuerDn = cert.getIssuerDN().getName();
+        return matchesName(issuerDn,issuerDNPatterns);
+    }
+
+    /**
+     * @return      true if the provided name 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
+    matchesName(
+            final String name, final Collection<Pattern> patterns
+    ) {
+        if (patterns == null || patterns.isEmpty()) {
+            LOG.warn("No Subject DN Certificate Constraints were defined. This could be a security issue");
+            return true;
+        }
+        if (!patterns.isEmpty()) {
+            if (name == null || name.isEmpty()) {
+                LOG.debug("The name is null so no constraints matching was possible");
+                return false;
+            }
             boolean subjectMatch = false;
-            for (Pattern subjectDNPattern : subjectDNPatterns) {
-                final Matcher matcher = subjectDNPattern.matcher(subjectName);
+            for (Pattern subjectDNPattern : patterns) {
+                final Matcher matcher = subjectDNPattern.matcher(name);
                 if (matcher.matches()) {
                     if (LOG.isDebugEnabled()) {
-                        LOG.debug("Subject DN " + subjectName + " matches with pattern " + subjectDNPattern);
+                        LOG.debug("Name " + name + " matches with pattern " + subjectDNPattern);
                     }
                     subjectMatch = true;
                     break;

Modified: webservices/wss4j/trunk/ws-security-common/src/main/java/org/apache/wss4j/common/crypto/Merlin.java
URL: http://svn.apache.org/viewvc/webservices/wss4j/trunk/ws-security-common/src/main/java/org/apache/wss4j/common/crypto/Merlin.java?rev=1765457&r1=1765456&r2=1765457&view=diff
==============================================================================
--- webservices/wss4j/trunk/ws-security-common/src/main/java/org/apache/wss4j/common/crypto/Merlin.java (original)
+++ webservices/wss4j/trunk/ws-security-common/src/main/java/org/apache/wss4j/common/crypto/Merlin.java Tue Oct 18 15:06:04 2016
@@ -947,7 +947,16 @@ public class Merlin extends CryptoBase {
         }
 
         // Finally check Cert Constraints
-        if (!matches(certs[0], subjectCertConstraints)) {
+        if (!matchesSubjectDnPattern(certs[0], subjectCertConstraints)) {
+            throw new WSSecurityException(WSSecurityException.ErrorCode.FAILED_AUTHENTICATION);
+        }
+    }   
+
+    @Override
+    public void verifyTrust(X509Certificate[] certs, boolean enableRevocation, Collection<Pattern> subjectCertConstraints,
+                            Collection<Pattern> issuerCertConstraints) throws WSSecurityException {
+        verifyTrust(certs,enableRevocation,subjectCertConstraints);
+        if (!matchesIssuerDnPattern(certs[0], issuerCertConstraints)) {
             throw new WSSecurityException(WSSecurityException.ErrorCode.FAILED_AUTHENTICATION);
         }
     }

Modified: webservices/wss4j/trunk/ws-security-common/src/main/java/org/apache/wss4j/common/crypto/MerlinAKI.java
URL: http://svn.apache.org/viewvc/webservices/wss4j/trunk/ws-security-common/src/main/java/org/apache/wss4j/common/crypto/MerlinAKI.java?rev=1765457&r1=1765456&r2=1765457&view=diff
==============================================================================
--- webservices/wss4j/trunk/ws-security-common/src/main/java/org/apache/wss4j/common/crypto/MerlinAKI.java (original)
+++ webservices/wss4j/trunk/ws-security-common/src/main/java/org/apache/wss4j/common/crypto/MerlinAKI.java Tue Oct 18 15:06:04 2016
@@ -227,7 +227,7 @@ public class MerlinAKI extends Merlin {
         }
 
         // Finally check Cert Constraints
-        if (!matches(certs[0], subjectCertConstraints)) {
+        if (!matchesSubjectDnPattern(certs[0], subjectCertConstraints)) {
             throw new WSSecurityException(WSSecurityException.ErrorCode.FAILED_AUTHENTICATION);
         }
     }

Modified: webservices/wss4j/trunk/ws-security-dom/src/main/java/org/apache/wss4j/dom/handler/RequestData.java
URL: http://svn.apache.org/viewvc/webservices/wss4j/trunk/ws-security-dom/src/main/java/org/apache/wss4j/dom/handler/RequestData.java?rev=1765457&r1=1765456&r2=1765457&view=diff
==============================================================================
--- webservices/wss4j/trunk/ws-security-dom/src/main/java/org/apache/wss4j/dom/handler/RequestData.java (original)
+++ webservices/wss4j/trunk/ws-security-dom/src/main/java/org/apache/wss4j/dom/handler/RequestData.java Tue Oct 18 15:06:04 2016
@@ -73,6 +73,7 @@ public class RequestData {
     private ReplayCache nonceReplayCache;
     private ReplayCache samlOneTimeUseReplayCache;
     private Collection<Pattern> subjectDNPatterns = new ArrayList<>();
+    private Collection<Pattern> issuerDNPatterns = new ArrayList<>();
     private final List<BSPRule> ignoredBSPRules = new LinkedList<>();
     private boolean appendSignatureAfterTimestamp;
     private int originalSignatureActionPosition;
@@ -448,6 +449,21 @@ public class RequestData {
     }
 
     /**
+     * Get the Signature Issuer DN Cert Constraints
+     * @return
+     */
+    public Collection<Pattern> getIssuerDNPatterns() {
+        return issuerDNPatterns;
+    }
+    /**
+     * Set the Signature Issuer DN Cert Constraints
+     *
+     */
+    public void setIssuerDNPatterns(Collection<Pattern> issuerDNPatterns) {
+        this.issuerDNPatterns = issuerDNPatterns;
+    }
+
+    /**
      * Set the Audience Restrictions
      */
     public void setAudienceRestrictions(List<String> audienceRestrictions) {

Modified: webservices/wss4j/trunk/ws-security-dom/src/main/java/org/apache/wss4j/dom/handler/WSHandler.java
URL: http://svn.apache.org/viewvc/webservices/wss4j/trunk/ws-security-dom/src/main/java/org/apache/wss4j/dom/handler/WSHandler.java?rev=1765457&r1=1765456&r2=1765457&view=diff
==============================================================================
--- webservices/wss4j/trunk/ws-security-dom/src/main/java/org/apache/wss4j/dom/handler/WSHandler.java (original)
+++ webservices/wss4j/trunk/ws-security-dom/src/main/java/org/apache/wss4j/dom/handler/WSHandler.java Tue Oct 18 15:06:04 2016
@@ -1333,6 +1333,24 @@ public abstract class WSHandler {
                 reqData.setSubjectCertConstraints(subjectCertConstraints);
             }
         }
+        String issuerCertConstraintsStringValue =
+                    getString(WSHandlerConstants.SIG_ISSUER_CERT_CONSTRAINTS, reqData.getMsgContext());
+                if (issuerCertConstraintsStringValue != null) {
+                    String[] issuerCertConstraintsList = issuerCertConstraintsStringValue.split(",");
+                    if (issuerCertConstraintsList != null) {
+                        Collection<Pattern> issuerCertConstraints =
+                            new ArrayList<>(issuerCertConstraintsList.length);
+                        for (String certConstraint : issuerCertConstraintsList) {
+                            try {
+                                issuerCertConstraints.add(Pattern.compile(certConstraint.trim()));
+                            } catch (PatternSyntaxException ex) {
+                                LOG.debug(ex.getMessage(), ex);
+                                throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, ex);
+                            }
+                        }
+                        reqData.setIssuerDNPatterns(issuerCertConstraints);
+                    }
+                }
 
         boolean expandXOP =
             decodeBooleanConfigValue(

Modified: webservices/wss4j/trunk/ws-security-dom/src/main/java/org/apache/wss4j/dom/validate/SignatureTrustValidator.java
URL: http://svn.apache.org/viewvc/webservices/wss4j/trunk/ws-security-dom/src/main/java/org/apache/wss4j/dom/validate/SignatureTrustValidator.java?rev=1765457&r1=1765456&r2=1765457&view=diff
==============================================================================
--- webservices/wss4j/trunk/ws-security-dom/src/main/java/org/apache/wss4j/dom/validate/SignatureTrustValidator.java (original)
+++ webservices/wss4j/trunk/ws-security-dom/src/main/java/org/apache/wss4j/dom/validate/SignatureTrustValidator.java Tue Oct 18 15:06:04 2016
@@ -105,7 +105,8 @@ public class SignatureTrustValidator imp
         // certificate was really signed by the issuer stated in the certificate
         //
         Collection<Pattern> subjectCertConstraints = data.getSubjectCertConstraints();
-        crypto.verifyTrust(certificates, enableRevocation, subjectCertConstraints);
+        Collection<Pattern> issuerCertConstraints = data.getIssuerDNPatterns();
+        crypto.verifyTrust(certificates, enableRevocation, subjectCertConstraints,issuerCertConstraints);
         if (LOG.isDebugEnabled()) {
             String subjectString = certificates[0].getSubjectX500Principal().getName();
             LOG.debug(

Added: webservices/wss4j/trunk/ws-security-dom/src/test/java/org/apache/wss4j/dom/message/SignatureIssuerCertConstraintsTest.java
URL: http://svn.apache.org/viewvc/webservices/wss4j/trunk/ws-security-dom/src/test/java/org/apache/wss4j/dom/message/SignatureIssuerCertConstraintsTest.java?rev=1765457&view=auto
==============================================================================
--- webservices/wss4j/trunk/ws-security-dom/src/test/java/org/apache/wss4j/dom/message/SignatureIssuerCertConstraintsTest.java (added)
+++ webservices/wss4j/trunk/ws-security-dom/src/test/java/org/apache/wss4j/dom/message/SignatureIssuerCertConstraintsTest.java Tue Oct 18 15:06:04 2016
@@ -0,0 +1,147 @@
+/**
+ * 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.wss4j.dom.message;
+
+import java.util.Collections;
+import java.util.regex.Pattern;
+
+import org.apache.wss4j.common.crypto.Crypto;
+import org.apache.wss4j.common.crypto.CryptoFactory;
+import org.apache.wss4j.common.ext.WSSecurityException;
+import org.apache.wss4j.common.util.XMLUtils;
+import org.apache.wss4j.dom.WSConstants;
+import org.apache.wss4j.dom.common.SOAPUtil;
+import org.apache.wss4j.dom.common.SecurityTestUtil;
+import org.apache.wss4j.dom.engine.WSSConfig;
+import org.apache.wss4j.dom.engine.WSSecurityEngine;
+import org.apache.wss4j.dom.handler.RequestData;
+import org.apache.wss4j.dom.handler.WSHandlerResult;
+import org.apache.wss4j.dom.util.WSSecurityUtil;
+import org.junit.Test;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+
+/**
+ * A set of test-cases for signing and verifying SOAP requests, where the issuer of the certificate used to
+ * verify the signature is validated against a set of cert constraints.
+ */
+public class SignatureIssuerCertConstraintsTest extends org.junit.Assert {
+    private static final org.slf4j.Logger LOG =
+        org.slf4j.LoggerFactory.getLogger(SignatureIssuerCertConstraintsTest.class);
+    private Crypto crypto = null;
+    private Crypto cryptoCA = null;
+
+    @org.junit.AfterClass
+    public static void cleanup() throws Exception {
+        SecurityTestUtil.cleanup();
+    }
+
+    public SignatureIssuerCertConstraintsTest() throws Exception {
+        WSSConfig.init();
+        crypto = CryptoFactory.getInstance("wss40.properties");
+        cryptoCA = CryptoFactory.getInstance("wss40CA.properties");
+    }
+
+    /**
+     * The test uses the BinarySecurityToken key identifier type.
+     */
+    @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(doc);
+        secHeader.insertSecurityHeader();
+        Document signedDoc = builder.build(doc, crypto, secHeader);
+
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("Signed message with BST key identifier:");
+            String outputString =
+                XMLUtils.prettyDocumentToString(signedDoc);
+            LOG.debug(outputString);
+        }
+
+        Element securityHeader = WSSecurityUtil.getSecurityHeader(signedDoc, null);
+        String certConstraint = ".*CN=Werner.*OU=Apache.*";
+        verify(securityHeader, cryptoCA, certConstraint);
+
+        certConstraint = ".*CN=Werner2.*O=Apache.*";
+        try {
+            verify(securityHeader, cryptoCA, certConstraint);
+            fail("Failure expected on a bad cert constraint");
+        } catch (WSSecurityException ex) {
+            assertTrue(ex.getErrorCode() == WSSecurityException.ErrorCode.FAILED_AUTHENTICATION);
+        }
+    }
+
+    /**
+     * The test uses the BinarySecurityToken key identifier type.
+     */
+    @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(doc);
+        secHeader.insertSecurityHeader();
+        Document signedDoc = builder.build(doc, crypto, secHeader);
+
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("Signed message with BST key identifier:");
+            String outputString =
+                XMLUtils.prettyDocumentToString(signedDoc);
+            LOG.debug(outputString);
+        }
+
+        Element securityHeader = WSSecurityUtil.getSecurityHeader(signedDoc, null);
+        String certConstraint = ".*CN=Werner.*OU=Apache.*";
+        verify(securityHeader, cryptoCA, certConstraint);
+
+        certConstraint = ".*CN=Werner2.*O=Apache.*";
+        try {
+            verify(securityHeader, cryptoCA, certConstraint);
+            fail("Failure expected on a bad cert constraint");
+        } catch (WSSecurityException ex) {
+            assertTrue(ex.getErrorCode() == WSSecurityException.ErrorCode.FAILED_AUTHENTICATION);
+        }
+    }
+
+    private WSHandlerResult verify(
+        Element securityHeader, Crypto sigCrypto, String certConstraint
+    ) throws Exception {
+        WSSecurityEngine secEngine = new WSSecurityEngine();
+        RequestData data = new RequestData();
+        data.setSigVerCrypto(sigCrypto);
+
+        if (certConstraint != null) {
+            Pattern issuerDNPattern = Pattern.compile(certConstraint.trim());
+            data.setIssuerDNPatterns(Collections.singletonList(issuerDNPattern));
+        }
+
+        return secEngine.processSecurityHeader(securityHeader, data);
+    }
+
+}

Modified: webservices/wss4j/trunk/ws-security-stax/src/main/java/org/apache/wss4j/stax/ext/WSSSecurityProperties.java
URL: http://svn.apache.org/viewvc/webservices/wss4j/trunk/ws-security-stax/src/main/java/org/apache/wss4j/stax/ext/WSSSecurityProperties.java?rev=1765457&r1=1765456&r2=1765457&view=diff
==============================================================================
--- webservices/wss4j/trunk/ws-security-stax/src/main/java/org/apache/wss4j/stax/ext/WSSSecurityProperties.java (original)
+++ webservices/wss4j/trunk/ws-security-stax/src/main/java/org/apache/wss4j/stax/ext/WSSSecurityProperties.java Tue Oct 18 15:06:04 2016
@@ -110,6 +110,7 @@ public class WSSSecurityProperties exten
     private ReplayCache samlOneTimeUseReplayCache;
     private boolean validateSamlSubjectConfirmation = true;
     private Collection<Pattern> subjectDNPatterns = new ArrayList<>();
+    private Collection<Pattern> issuerDNPatterns = new ArrayList<>();
     private List<String> audienceRestrictions = new ArrayList<>();
     private boolean requireTimestampExpires;
 
@@ -169,6 +170,7 @@ public class WSSSecurityProperties exten
         this.validateSamlSubjectConfirmation = wssSecurityProperties.validateSamlSubjectConfirmation;
         this.encryptSymmetricEncrytionKey = wssSecurityProperties.encryptSymmetricEncrytionKey;
         this.subjectDNPatterns = wssSecurityProperties.subjectDNPatterns;
+        this.issuerDNPatterns = wssSecurityProperties.issuerDNPatterns;
         this.attachmentCallbackHandler = wssSecurityProperties.attachmentCallbackHandler;
         this.msgContext = wssSecurityProperties.msgContext;
         this.audienceRestrictions = wssSecurityProperties.audienceRestrictions;
@@ -869,6 +871,20 @@ public class WSSSecurityProperties exten
     public Collection<Pattern> getSubjectCertConstraints() {
         return subjectDNPatterns;
     }
+    /**
+     * Set the Signature Issuer Cert Constraints
+     */
+    public void setIssuerDNConstraints(Collection<Pattern> issuerDNPatterns) {
+        this.issuerDNPatterns = issuerDNPatterns;
+    }
+    /**
+     * Get the Signature Issuer Cert Constraints
+     */
+    public Collection<Pattern> getIssuerDNConstraints() {
+        return issuerDNPatterns;
+    }
+
+
 
     /**
      * Set the Audience Restrictions

Modified: webservices/wss4j/trunk/ws-security-stax/src/main/java/org/apache/wss4j/stax/impl/securityToken/SamlSecurityTokenImpl.java
URL: http://svn.apache.org/viewvc/webservices/wss4j/trunk/ws-security-stax/src/main/java/org/apache/wss4j/stax/impl/securityToken/SamlSecurityTokenImpl.java?rev=1765457&r1=1765456&r2=1765457&view=diff
==============================================================================
--- webservices/wss4j/trunk/ws-security-stax/src/main/java/org/apache/wss4j/stax/impl/securityToken/SamlSecurityTokenImpl.java (original)
+++ webservices/wss4j/trunk/ws-security-stax/src/main/java/org/apache/wss4j/stax/impl/securityToken/SamlSecurityTokenImpl.java Tue Oct 18 15:06:04 2016
@@ -206,11 +206,14 @@ public class SamlSecurityTokenImpl exten
             if (x509Certificates != null && x509Certificates.length > 0) {
                 boolean enableRevocation = false;
                 Collection<Pattern> subjectCertConstraints = null;
+                Collection<Pattern> issuerCertConstraints = null;
                 if (securityProperties != null) {
                     enableRevocation = securityProperties.isEnableRevocation();
                     subjectCertConstraints = securityProperties.getSubjectCertConstraints();
+                    issuerCertConstraints = securityProperties.getIssuerDNConstraints();
+
                 }
-                crypto.verifyTrust(x509Certificates, enableRevocation, subjectCertConstraints);
+                crypto.verifyTrust(x509Certificates, enableRevocation, subjectCertConstraints,issuerCertConstraints);
             }
             PublicKey publicKey = getPublicKey();
             if (publicKey != null) {

Modified: webservices/wss4j/trunk/ws-security-stax/src/main/java/org/apache/wss4j/stax/impl/securityToken/X509SecurityTokenImpl.java
URL: http://svn.apache.org/viewvc/webservices/wss4j/trunk/ws-security-stax/src/main/java/org/apache/wss4j/stax/impl/securityToken/X509SecurityTokenImpl.java?rev=1765457&r1=1765456&r2=1765457&view=diff
==============================================================================
--- webservices/wss4j/trunk/ws-security-stax/src/main/java/org/apache/wss4j/stax/impl/securityToken/X509SecurityTokenImpl.java (original)
+++ webservices/wss4j/trunk/ws-security-stax/src/main/java/org/apache/wss4j/stax/impl/securityToken/X509SecurityTokenImpl.java Tue Oct 18 15:06:04 2016
@@ -113,11 +113,13 @@ public abstract class X509SecurityTokenI
         if (x509Certificates != null && x509Certificates.length > 0) {
             boolean enableRevocation = false;
             Collection<Pattern> subjectCertConstraints = null;
+            Collection<Pattern> issuerCertConstraints = null;
             if (securityProperties != null) {
                 enableRevocation = securityProperties.isEnableRevocation();
                 subjectCertConstraints = securityProperties.getSubjectCertConstraints();
+                issuerCertConstraints = securityProperties.getIssuerDNConstraints();
             }
-            getCrypto().verifyTrust(x509Certificates, enableRevocation, subjectCertConstraints);
+            getCrypto().verifyTrust(x509Certificates, enableRevocation, subjectCertConstraints,issuerCertConstraints);
         }
     }
 

Modified: webservices/wss4j/trunk/ws-security-stax/src/main/java/org/apache/wss4j/stax/setup/ConfigurationConverter.java
URL: http://svn.apache.org/viewvc/webservices/wss4j/trunk/ws-security-stax/src/main/java/org/apache/wss4j/stax/setup/ConfigurationConverter.java?rev=1765457&r1=1765456&r2=1765457&view=diff
==============================================================================
--- webservices/wss4j/trunk/ws-security-stax/src/main/java/org/apache/wss4j/stax/setup/ConfigurationConverter.java (original)
+++ webservices/wss4j/trunk/ws-security-stax/src/main/java/org/apache/wss4j/stax/setup/ConfigurationConverter.java Tue Oct 18 15:06:04 2016
@@ -549,6 +549,24 @@ public final class ConfigurationConverte
                 properties.setSubjectCertConstraints(subjectCertConstraints);
             }
         }
+        // Subject Cert Constraints
+        String issuerCertConstraintsString =
+                getString(ConfigurationConstants.SIG_ISSUER_CERT_CONSTRAINTS, config);
+        if (issuerCertConstraintsString != null) {
+            String[] certConstraintsList = issuerCertConstraintsString.split(",");
+            if (certConstraintsList != null) {
+                Collection<Pattern> issuerCertConstraints =
+                        new ArrayList<>(certConstraintsList.length);
+                for (String certConstraint : certConstraintsList) {
+                    try {
+                        issuerCertConstraints.add(Pattern.compile(certConstraint.trim()));
+                    } catch (PatternSyntaxException ex) {
+                        LOG.error(ex.getMessage(), ex);
+                    }
+                }
+                properties.setSubjectCertConstraints(issuerCertConstraints);
+            }
+        }
 
         properties.setUtTTL(decodeTimeToLive(config, false));
         properties.setUtFutureTTL(decodeFutureTimeToLive(config, false));

Added: webservices/wss4j/trunk/ws-security-stax/src/test/java/org/apache/wss4j/stax/test/SignatureIssuerCertConstaintsTest.java
URL: http://svn.apache.org/viewvc/webservices/wss4j/trunk/ws-security-stax/src/test/java/org/apache/wss4j/stax/test/SignatureIssuerCertConstaintsTest.java?rev=1765457&view=auto
==============================================================================
--- webservices/wss4j/trunk/ws-security-stax/src/test/java/org/apache/wss4j/stax/test/SignatureIssuerCertConstaintsTest.java (added)
+++ webservices/wss4j/trunk/ws-security-stax/src/test/java/org/apache/wss4j/stax/test/SignatureIssuerCertConstaintsTest.java Tue Oct 18 15:06:04 2016
@@ -0,0 +1,202 @@
+/**
+ * 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.wss4j.stax.test;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.Map;
+import java.util.Properties;
+import java.util.regex.Pattern;
+
+import javax.xml.stream.XMLStreamReader;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+
+import org.apache.wss4j.common.ext.WSSecurityException;
+import org.apache.wss4j.dom.handler.RequestData;
+import org.apache.wss4j.dom.handler.WSHandlerConstants;
+import org.apache.wss4j.stax.ext.WSSConstants;
+import org.apache.wss4j.stax.ext.WSSSecurityProperties;
+import org.apache.wss4j.stax.setup.InboundWSSec;
+import org.apache.wss4j.stax.setup.WSSec;
+import org.apache.wss4j.stax.test.utils.StAX2DOM;
+import org.junit.Assert;
+import org.junit.Test;
+import org.w3c.dom.Document;
+import org.w3c.dom.NodeList;
+
+/**
+ * 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 SignatureIssuerCertConstaintsTest extends AbstractTestBase {
+
+    @Test
+    public void testBSTSignature() throws Exception {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        {
+            InputStream sourceDocument = this.getClass().getClassLoader().getResourceAsStream("testdata/plain-soap-1.1.xml");
+            String action = WSHandlerConstants.SIGNATURE;
+            Document securedDocument = doOutboundSecurityWithWSS4J(sourceDocument, action, new Properties());
+
+            //some test that we can really sure we get what we want from WSS4J
+            NodeList nodeList = securedDocument.getElementsByTagNameNS(WSSConstants.TAG_dsig_Signature.getNamespaceURI(), WSSConstants.TAG_dsig_Signature.getLocalPart());
+            Assert.assertEquals(nodeList.item(0).getParentNode().getLocalName(), WSSConstants.TAG_WSSE_SECURITY.getLocalPart());
+
+            javax.xml.transform.Transformer transformer = TRANSFORMER_FACTORY.newTransformer();
+            transformer.transform(new DOMSource(securedDocument), new StreamResult(baos));
+        }
+
+        //done signature; now test sig-verification: This should pass with a correct cert constraint check
+        {
+            WSSSecurityProperties securityProperties = new WSSSecurityProperties();
+            securityProperties.loadSignatureVerificationKeystore(this.getClass().getClassLoader().getResource("wss40CA.jks"), "security".toCharArray());
+            String certConstraint = ".*CN=Werner.*OU=Apache.*";
+            Pattern issuerDNPattern = Pattern.compile(certConstraint.trim());
+            securityProperties.setIssuerDNConstraints(Collections.singletonList(issuerDNPattern));
+
+            InboundWSSec wsSecIn = WSSec.getInboundWSSec(securityProperties);
+            XMLStreamReader xmlStreamReader = wsSecIn.processInMessage(xmlInputFactory.createXMLStreamReader(new ByteArrayInputStream(baos.toByteArray())));
+
+            Document document = StAX2DOM.readDoc(documentBuilderFactory.newDocumentBuilder(), xmlStreamReader);
+
+            //header element must still be there
+            NodeList nodeList = document.getElementsByTagNameNS(WSSConstants.TAG_dsig_Signature.getNamespaceURI(), WSSConstants.TAG_dsig_Signature.getLocalPart());
+            Assert.assertEquals(nodeList.getLength(), 1);
+            Assert.assertEquals(nodeList.item(0).getParentNode().getLocalName(), WSSConstants.TAG_WSSE_SECURITY.getLocalPart());
+        }
+
+        //done signature; now test sig-verification: This should fail with an incorrect cert constraint check
+        {
+            WSSSecurityProperties securityProperties = new WSSSecurityProperties();
+            securityProperties.loadSignatureVerificationKeystore(this.getClass().getClassLoader().getResource("wss40CA.jks"), "security".toCharArray());
+            String certConstraint = ".*CN=Werner2.*OU=Apache.*";
+            Pattern issuerDNPattern = Pattern.compile(certConstraint.trim());
+            securityProperties.setIssuerDNConstraints(Collections.singletonList(issuerDNPattern));
+
+            InboundWSSec wsSecIn = WSSec.getInboundWSSec(securityProperties, false, true);
+            XMLStreamReader xmlStreamReader = wsSecIn.processInMessage(xmlInputFactory.createXMLStreamReader(new ByteArrayInputStream(baos.toByteArray())));
+
+            try {
+                StAX2DOM.readDoc(documentBuilderFactory.newDocumentBuilder(), xmlStreamReader);
+                Assert.fail("Expected failure on a incorrect cert constraint check");
+            } catch (Exception ex) {
+                String errorMessage = "The security token could not be authenticated or authorized";
+                Assert.assertTrue(ex.getMessage().contains(errorMessage));
+            }
+        }
+    }
+
+    @Test
+    public void testBSTSignaturePKIPath() throws Exception {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        {
+            InputStream sourceDocument = this.getClass().getClassLoader().getResourceAsStream("testdata/plain-soap-1.1.xml");
+            String action = WSHandlerConstants.SIGNATURE;
+            Properties properties = new Properties();
+            properties.put(WSHandlerConstants.USE_SINGLE_CERTIFICATE, "false");
+            Document securedDocument = doOutboundSecurityWithWSS4J(sourceDocument, action, properties);
+
+            //some test that we can really sure we get what we want from WSS4J
+            NodeList nodeList = securedDocument.getElementsByTagNameNS(WSSConstants.TAG_dsig_Signature.getNamespaceURI(), WSSConstants.TAG_dsig_Signature.getLocalPart());
+            Assert.assertEquals(nodeList.item(0).getParentNode().getLocalName(), WSSConstants.TAG_WSSE_SECURITY.getLocalPart());
+
+            javax.xml.transform.Transformer transformer = TRANSFORMER_FACTORY.newTransformer();
+            transformer.transform(new DOMSource(securedDocument), new StreamResult(baos));
+        }
+
+        //done signature; now test sig-verification: This should pass with a correct cert constraint check
+        {
+            WSSSecurityProperties securityProperties = new WSSSecurityProperties();
+            securityProperties.loadSignatureVerificationKeystore(this.getClass().getClassLoader().getResource("wss40CA.jks"), "security".toCharArray());
+            String certConstraint = ".*CN=Werner.*OU=Apache.*";
+            Pattern issuerDNPattern = Pattern.compile(certConstraint.trim());
+            securityProperties.setIssuerDNConstraints(Collections.singletonList(issuerDNPattern));
+
+            InboundWSSec wsSecIn = WSSec.getInboundWSSec(securityProperties);
+            XMLStreamReader xmlStreamReader = wsSecIn.processInMessage(xmlInputFactory.createXMLStreamReader(new ByteArrayInputStream(baos.toByteArray())));
+
+            Document document = StAX2DOM.readDoc(documentBuilderFactory.newDocumentBuilder(), xmlStreamReader);
+
+            //header element must still be there
+            NodeList nodeList = document.getElementsByTagNameNS(WSSConstants.TAG_dsig_Signature.getNamespaceURI(), WSSConstants.TAG_dsig_Signature.getLocalPart());
+            Assert.assertEquals(nodeList.getLength(), 1);
+            Assert.assertEquals(nodeList.item(0).getParentNode().getLocalName(), WSSConstants.TAG_WSSE_SECURITY.getLocalPart());
+        }
+
+        //done signature; now test sig-verification: This should fail with an incorrect cert constraint check
+        {
+            WSSSecurityProperties securityProperties = new WSSSecurityProperties();
+            securityProperties.loadSignatureVerificationKeystore(this.getClass().getClassLoader().getResource("wss40CA.jks"), "security".toCharArray());
+            String certConstraint = ".*CN=Werner2.*OU=Apache.*";
+            Pattern issuerDNPattern = Pattern.compile(certConstraint.trim());
+            securityProperties.setIssuerDNConstraints(Collections.singletonList(issuerDNPattern));
+
+            InboundWSSec wsSecIn = WSSec.getInboundWSSec(securityProperties, false, true);
+            XMLStreamReader xmlStreamReader = wsSecIn.processInMessage(xmlInputFactory.createXMLStreamReader(new ByteArrayInputStream(baos.toByteArray())));
+
+            try {
+                StAX2DOM.readDoc(documentBuilderFactory.newDocumentBuilder(), xmlStreamReader);
+                Assert.fail("Expected failure on a incorrect cert constraint check");
+            } catch (Exception ex) {
+                String errorMessage = "The security token could not be authenticated or authorized";
+                Assert.assertTrue(ex.getMessage().contains(errorMessage));
+            }
+        }
+    }
+
+    @Override
+    protected Map<String, Object> doOutboundSecurityWithWSS4J_1(
+        InputStream sourceDocument, String action, final Properties properties
+    ) throws WSSecurityException, TransformerException, IOException {
+        CustomWSS4JHandler wss4JHandler = new CustomWSS4JHandler();
+        final Map<String, Object> messageContext = getMessageContext(sourceDocument);
+        messageContext.put(WSHandlerConstants.ACTION, action);
+        messageContext.put(WSHandlerConstants.USER, "wss40");
+        messageContext.put(WSHandlerConstants.SIG_KEY_ID, "DirectReference");
+
+        Properties sigProperties = new Properties();
+        sigProperties.setProperty("org.apache.wss4j.crypto.provider", "org.apache.wss4j.common.crypto.Merlin");
+        sigProperties.setProperty("org.apache.wss4j.crypto.merlin.keystore.file", "wss40.jks");
+        sigProperties.setProperty("org.apache.wss4j.crypto.merlin.keystore.password", "security");
+        sigProperties.setProperty("org.apache.wss4j.crypto.merlin.keystore.alias", "wss40");
+        wss4JHandler.setPassword(messageContext, "security");
+        messageContext.put(WSHandlerConstants.SIG_PROP_REF_ID, "" + sigProperties.hashCode());
+        messageContext.put("" + sigProperties.hashCode(), sigProperties);
+
+        Enumeration<?> enumeration = properties.propertyNames();
+        while (enumeration.hasMoreElements()) {
+            String s = (String) enumeration.nextElement();
+            messageContext.put(s, properties.get(s));
+        }
+
+        RequestData requestData = new RequestData();
+        requestData.setMsgContext(messageContext);
+
+        wss4JHandler.doSender(messageContext, requestData, true);
+
+        return messageContext;
+    }
+
+}