You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cxf.apache.org by dv...@apache.org on 2010/08/02 15:55:40 UTC

svn commit: r981509 - in /cxf/branches/2.2.x-fixes: ./ rt/ws/security/src/main/java/org/apache/cxf/ws/security/wss4j/ rt/ws/security/src/main/java/org/apache/cxf/ws/security/wss4j/policyhandlers/ rt/ws/security/src/test/java/org/apache/cxf/ws/security/...

Author: dvaleri
Date: Mon Aug  2 13:55:39 2010
New Revision: 981509

URL: http://svn.apache.org/viewvc?rev=981509&view=rev
Log:
Merged revisions 980898,980941 via svnmerge from 
https://svn.apache.org/repos/asf/cxf/trunk

........
  r980898 | dvaleri | 2010-07-30 13:53:49 -0400 (Fri, 30 Jul 2010) | 1 line
  
  [CXF-2921] Changed interceptor behavior for case where there is no WS-S header.  Now allows for policy interceptor to process results even when there is no header.
........
  r980941 | dvaleri | 2010-07-30 16:25:26 -0400 (Fri, 30 Jul 2010) | 1 line
  
  [CXF-2915] Applied patches for SignedSupportingToken with mod to fix regression against SignatureConfirmation tests.
........

Added:
    cxf/branches/2.2.x-fixes/rt/ws/security/src/test/java/org/apache/cxf/ws/security/wss4j/example-sts-issued-saml-assertion.xml
      - copied unchanged from r980941, cxf/trunk/rt/ws/security/src/test/java/org/apache/cxf/ws/security/wss4j/example-sts-issued-saml-assertion.xml
    cxf/branches/2.2.x-fixes/rt/ws/security/src/test/java/org/apache/cxf/ws/security/wss4j/signed_elements_with_sst_issued_token_policy.xml
      - copied unchanged from r980941, cxf/trunk/rt/ws/security/src/test/java/org/apache/cxf/ws/security/wss4j/signed_elements_with_sst_issued_token_policy.xml
    cxf/branches/2.2.x-fixes/rt/ws/security/src/test/java/org/apache/cxf/ws/security/wss4j/transport_binding_policy.xml
      - copied unchanged from r980941, cxf/trunk/rt/ws/security/src/test/java/org/apache/cxf/ws/security/wss4j/transport_binding_policy.xml
Modified:
    cxf/branches/2.2.x-fixes/   (props changed)
    cxf/branches/2.2.x-fixes/rt/ws/security/src/main/java/org/apache/cxf/ws/security/wss4j/WSS4JInInterceptor.java
    cxf/branches/2.2.x-fixes/rt/ws/security/src/main/java/org/apache/cxf/ws/security/wss4j/policyhandlers/AbstractBindingBuilder.java
    cxf/branches/2.2.x-fixes/rt/ws/security/src/main/java/org/apache/cxf/ws/security/wss4j/policyhandlers/AsymmetricBindingHandler.java
    cxf/branches/2.2.x-fixes/rt/ws/security/src/test/java/org/apache/cxf/ws/security/wss4j/PolicyBasedWss4JInOutTest.java

Propchange: cxf/branches/2.2.x-fixes/
------------------------------------------------------------------------------
    svn:mergeinfo = /cxf/trunk:980898-980941

Propchange: cxf/branches/2.2.x-fixes/
------------------------------------------------------------------------------
Binary property 'svnmerge-integrated' - no diff available.

Modified: cxf/branches/2.2.x-fixes/rt/ws/security/src/main/java/org/apache/cxf/ws/security/wss4j/WSS4JInInterceptor.java
URL: http://svn.apache.org/viewvc/cxf/branches/2.2.x-fixes/rt/ws/security/src/main/java/org/apache/cxf/ws/security/wss4j/WSS4JInInterceptor.java?rev=981509&r1=981508&r2=981509&view=diff
==============================================================================
--- cxf/branches/2.2.x-fixes/rt/ws/security/src/main/java/org/apache/cxf/ws/security/wss4j/WSS4JInInterceptor.java (original)
+++ cxf/branches/2.2.x-fixes/rt/ws/security/src/main/java/org/apache/cxf/ws/security/wss4j/WSS4JInInterceptor.java Mon Aug  2 13:55:39 2010
@@ -217,27 +217,39 @@ public class WSS4JInInterceptor extends 
                 t2 = System.currentTimeMillis();
             }
 
-            if (wsResult == null) { // no security header found
-                if (doAction == WSConstants.NO_SECURITY) {
-                    return;
-                } else if (doc.getSOAPPart().getEnvelope().getBody().hasFault()) {
-                    LOG.warning("Request does not contain required Security header, " 
+            if (wsResult != null) { // security header found
+                if (reqData.getWssConfig().isEnableSignatureConfirmation()) {
+                    checkSignatureConfirmation(reqData, wsResult);
+                }
+
+                checkSignatures(msg, reqData, wsResult);
+                checkTimestamps(msg, reqData, wsResult);
+                checkActions(msg, reqData, wsResult, actions);
+                doResults(msg, actor, doc, wsResult);
+            } else { // no security header found
+                // Create an empty result vector to pass into the required validation
+                // methods.
+                wsResult = new Vector<Object>();
+                
+                if (doc.getSOAPPart().getEnvelope().getBody().hasFault()) {
+                    LOG.warning("Request does not contain Security header, " 
                                 + "but it's a fault.");
-                    return;
+                    // We allow lax action matching here for backwards compatibility
+                    // with manually configured WSS4JInInterceptors that previously
+                    // allowed faults to pass through even if their actions aren't
+                    // a strict match against those configured.  In the WS-SP case,
+                    // we will want to still call doResults as it handles asserting
+                    // certain assertions that do not require a WS-S header such as
+                    // a sp:TransportBinding assertion.  In the case of WS-SP,
+                    // the unasserted assertions will provide confirmation that
+                    // security was not sufficient.
+                    // checkActions(msg, reqData, wsResult, actions);
+                    doResults(msg, actor, doc, wsResult);
                 } else {
-                    LOG.warning("Request does not contain required Security header");
-                    throw new WSSecurityException(WSSecurityException.INVALID_SECURITY);
+                    checkActions(msg, reqData, wsResult, actions);
+                    doResults(msg, actor, doc, wsResult);
                 }
             }
-            if (reqData.getWssConfig().isEnableSignatureConfirmation()) {
-                checkSignatureConfirmation(reqData, wsResult);
-            }
-
-            checkSignatures(msg, reqData, wsResult);
-            checkTimestamps(msg, reqData, wsResult);
-            checkActions(msg, reqData, wsResult, actions);
-            
-            doResults(msg, actor, doc, wsResult);
 
             if (doTimeLog) {
                 t3 = System.currentTimeMillis();

Modified: cxf/branches/2.2.x-fixes/rt/ws/security/src/main/java/org/apache/cxf/ws/security/wss4j/policyhandlers/AbstractBindingBuilder.java
URL: http://svn.apache.org/viewvc/cxf/branches/2.2.x-fixes/rt/ws/security/src/main/java/org/apache/cxf/ws/security/wss4j/policyhandlers/AbstractBindingBuilder.java?rev=981509&r1=981508&r2=981509&view=diff
==============================================================================
--- cxf/branches/2.2.x-fixes/rt/ws/security/src/main/java/org/apache/cxf/ws/security/wss4j/policyhandlers/AbstractBindingBuilder.java (original)
+++ cxf/branches/2.2.x-fixes/rt/ws/security/src/main/java/org/apache/cxf/ws/security/wss4j/policyhandlers/AbstractBindingBuilder.java Mon Aug  2 13:55:39 2010
@@ -119,7 +119,11 @@ import org.apache.ws.security.message.WS
 import org.apache.ws.security.message.WSSecTimestamp;
 import org.apache.ws.security.message.WSSecUsernameToken;
 import org.apache.ws.security.message.token.SecurityTokenReference;
+import org.apache.ws.security.transform.STRTransform;
 import org.apache.ws.security.util.WSSecurityUtil;
+import org.apache.xml.security.signature.XMLSignatureException;
+import org.apache.xml.security.transforms.TransformationException;
+import org.apache.xml.security.transforms.Transforms;
 
 /**
  * 
@@ -462,11 +466,11 @@ public abstract class AbstractBindingBui
                     this.encryptedTokensIdList.add(secToken.getId());
                 }
         
-                if (secToken.getX509Certificate() == null) {
+                if (secToken.getX509Certificate() == null) {   
                     //Add the extracted token
                     ret.put(token, new WSSecurityTokenHolder(secToken));
                 } else {
-                    WSSecSignature sig = new WSSecSignature();                    
+                    WSSecSignatureHelper sig = new WSSecSignatureHelper();                    
                     sig.setX509Certificate(secToken.getX509Certificate());
                     sig.setCustomTokenId(secToken.getId());
                     sig.setKeyIdentifierType(WSConstants.CUSTOM_KEY_IDENTIFIER);
@@ -500,8 +504,10 @@ public abstract class AbstractBindingBui
                         throw new Fault(e);
                     }
                     
+                    addSupportingElement(cloneElement(sig.getSecRef().getElement()));
+                    
                     if (suppTokens.isEncryptedToken()) {
-                        encryptedTokensIdList.add(sig.getBSTTokenId());
+                        encryptedTokensIdList.add(secToken.getId());
                     }
                     ret.put(token, sig);                
                 }
@@ -554,10 +560,22 @@ public abstract class AbstractBindingBui
             Object tempTok =  entry.getValue();
             WSEncryptionPart part = null;
             
-            if (tempTok instanceof WSSecSignature) {
-                WSSecSignature tempSig = (WSSecSignature) tempTok;
-                if (tempSig.getBSTTokenId() != null) {
-                    part = new WSEncryptionPart(tempSig.getBSTTokenId());
+            if (tempTok instanceof WSSecSignatureHelper) {
+                WSSecSignatureHelper tempSig = (WSSecSignatureHelper) tempTok;
+                if ((WSConstants.WSS_SAML_NS + WSConstants.SAML_ASSERTION_ID).
+                    equals(tempSig.getSecRef().getKeyIdentifierValueType())) {
+                               
+                    // NOTE: This usage of WSEncryptionPart is a workaroud that is
+                    // coupled with WSSecSignatureHelper. This approach is used so that
+                    // we can force WSS4J to sign the assertion through a STR that
+                    // WSS4J did not create during message signature creation.
+                    part = new WSEncryptionPart(tempSig.getStrUri(), "ExternalSTRTransform", "Element",
+                          WSConstants.PART_TYPE_ELEMENT);
+            
+                } else {
+                    if (tempSig.getBSTTokenId() != null) {
+                        part = new WSEncryptionPart(tempSig.getBSTTokenId());
+                    }
                 }
             } else if (tempTok instanceof WSSecUsernameToken) {
                 WSSecUsernameToken unt = (WSSecUsernameToken)tempTok;
@@ -1282,8 +1300,8 @@ public abstract class AbstractBindingBui
             }
         }
     }
-    protected WSSecSignature getSignatureBuider(TokenWrapper wrapper, Token token, boolean endorse) {
-        WSSecSignature sig = new WSSecSignature();
+    protected WSSecSignatureHelper getSignatureBuider(TokenWrapper wrapper, Token token, boolean endorse) {
+        WSSecSignatureHelper sig = new WSSecSignatureHelper();
         checkForX509PkiPath(sig, token);        
         setKeyIdentifierType(sig, wrapper, token);
         
@@ -1717,4 +1735,48 @@ public abstract class AbstractBindingBui
         
         signedParts.addAll(signedEncryptedParts);
     }
+    
+    private static final class WSSecSignatureHelper extends WSSecSignature {
+        public SecurityTokenReference getSecRef() {
+            return this.secRef;
+        }
+
+        public String getStrUri() {
+            return this.strUri;
+        }
+
+        @Override
+        public void addReferencesToSign(Vector references,
+                WSSecHeader secHeader) throws WSSecurityException {
+            final Vector<Object> unalteredReferences = new Vector<Object>();
+
+            try {
+                for (int part = 0; part < references.size(); part++) {
+                    final WSEncryptionPart encPart = (WSEncryptionPart) references.get(part);
+
+                    final String elemName = encPart.getName();
+                    final Transforms transforms = new Transforms(document);
+
+                    if (elemName != null && "ExternalSTRTransform".equals(encPart.getNamespace())) {
+                        final Element ctx = this.createSTRParameter(document);
+                        transforms.addTransform(STRTransform.implementedTransformURI, ctx);
+                        this.sig.addDocument("#" + elemName, transforms, this.getDigestAlgo());
+                    } else {
+                        unalteredReferences.add(encPart);
+                    }
+                }
+            } catch (TransformationException e1) {
+                throw new WSSecurityException(
+                    WSSecurityException.FAILED_SIGNATURE, "noXMLSig", null, e1
+                );
+            } catch (XMLSignatureException e1) {
+                throw new WSSecurityException(
+                    WSSecurityException.FAILED_SIGNATURE, "noXMLSig", null, e1
+                );
+            }
+
+            super.addReferencesToSign(unalteredReferences, secHeader);
+        }
+    }
+    
 }

Modified: cxf/branches/2.2.x-fixes/rt/ws/security/src/main/java/org/apache/cxf/ws/security/wss4j/policyhandlers/AsymmetricBindingHandler.java
URL: http://svn.apache.org/viewvc/cxf/branches/2.2.x-fixes/rt/ws/security/src/main/java/org/apache/cxf/ws/security/wss4j/policyhandlers/AsymmetricBindingHandler.java?rev=981509&r1=981508&r2=981509&view=diff
==============================================================================
--- cxf/branches/2.2.x-fixes/rt/ws/security/src/main/java/org/apache/cxf/ws/security/wss4j/policyhandlers/AsymmetricBindingHandler.java (original)
+++ cxf/branches/2.2.x-fixes/rt/ws/security/src/main/java/org/apache/cxf/ws/security/wss4j/policyhandlers/AsymmetricBindingHandler.java Mon Aug  2 13:55:39 2010
@@ -95,7 +95,7 @@ public class AsymmetricBindingHandler ex
 
     private void doSignBeforeEncrypt() {
         try {
-            Vector<WSEncryptionPart> sigs = getSignedParts();
+            Vector<WSEncryptionPart> sigs = new Vector<WSEncryptionPart>();
             if (isRequestor()) {
                 //Add timestamp
                 if (timestampEl != null) {
@@ -197,6 +197,9 @@ public class AsymmetricBindingHandler ex
                 } catch (WSSecurityException e) {
                     //REVISIT - exception
                     e.printStackTrace();
+                } catch (SOAPException e) {
+                    //REVISIT - exception
+                    e.printStackTrace();
                 }
             }
 
@@ -334,7 +337,8 @@ public class AsymmetricBindingHandler ex
             }
         }
     }
-    private void doSignature(Vector<WSEncryptionPart> sigParts) throws WSSecurityException {
+    
+    private void doSignature(Vector<WSEncryptionPart> sigParts) throws WSSecurityException, SOAPException {
         Token sigToken = null;
         TokenWrapper wrapper = null;
         if (isRequestor()) {
@@ -385,18 +389,16 @@ public class AsymmetricBindingHandler ex
             }
         } else {
             WSSecSignature sig = getSignatureBuider(wrapper, sigToken, false);
-            sig.prependBSTElementToHeader(secHeader);
-            insertBeforeBottomUp(sig.getSignatureElement());
-            
-            if (abinding.isTokenProtection()) {                
-                // Special flag telling WSS4J to sign the initiator token.
-                // Use this instead of the BST ID so that we don't
-                // have to deal with maintaining such logic here.
-                sigParts.add(new WSEncryptionPart("Token", null, 
-                        "Element", WSConstants.PART_TYPE_ELEMENT));
+                      
+            // This action must occur before sig.prependBSTElementToHeader
+            if (abinding.isTokenProtection()
+                    && sig.getBSTTokenId() != null) {
+                sigParts.add(new WSEncryptionPart(sig.getBSTTokenId()));
             }
-                    
+
             sig.prependBSTElementToHeader(secHeader);
+            insertBeforeBottomUp(sig.getSignatureElement());
+            sigParts.addAll(this.getSignedParts());
             
             AlgorithmSuite algorithmSuite = abinding.getAlgorithmSuite();
             sig.setSignatureAlgorithm(algorithmSuite.getAsymmetricSignature());
@@ -406,7 +408,6 @@ public class AsymmetricBindingHandler ex
             sig.addReferencesToSign(sigParts, secHeader);
             sig.computeSignature();
             signatures.add(sig.getSignatureValue());
-
                         
             mainSigId = addWsuIdToElement(sig.getSignatureElement());
         }

Modified: cxf/branches/2.2.x-fixes/rt/ws/security/src/test/java/org/apache/cxf/ws/security/wss4j/PolicyBasedWss4JInOutTest.java
URL: http://svn.apache.org/viewvc/cxf/branches/2.2.x-fixes/rt/ws/security/src/test/java/org/apache/cxf/ws/security/wss4j/PolicyBasedWss4JInOutTest.java?rev=981509&r1=981508&r2=981509&view=diff
==============================================================================
--- cxf/branches/2.2.x-fixes/rt/ws/security/src/test/java/org/apache/cxf/ws/security/wss4j/PolicyBasedWss4JInOutTest.java (original)
+++ cxf/branches/2.2.x-fixes/rt/ws/security/src/test/java/org/apache/cxf/ws/security/wss4j/PolicyBasedWss4JInOutTest.java Mon Aug  2 13:55:39 2010
@@ -18,11 +18,13 @@
  */
 package org.apache.cxf.ws.security.wss4j;
 
-
+import java.net.URL;
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.List;
 import java.util.Map;
+import java.util.Properties;
 import java.util.Vector;
 import java.util.concurrent.Executor;
 
@@ -58,12 +60,17 @@ import org.apache.cxf.ws.policy.PolicyEx
 import org.apache.cxf.ws.security.SecurityConstants;
 import org.apache.cxf.ws.security.policy.SP12Constants;
 import org.apache.cxf.ws.security.policy.model.AsymmetricBinding;
+import org.apache.cxf.ws.security.tokenstore.MemoryTokenStore;
+import org.apache.cxf.ws.security.tokenstore.SecurityToken;
+import org.apache.cxf.ws.security.tokenstore.TokenStore;
 import org.apache.cxf.ws.security.wss4j.CryptoCoverageUtil.CoverageType;
 import org.apache.cxf.ws.security.wss4j.PolicyBasedWSS4JOutInterceptor.PolicyBasedWSS4JOutInterceptorInternal;
 import org.apache.neethi.Policy;
 import org.apache.ws.security.WSConstants;
 import org.apache.ws.security.WSDataRef;
 import org.apache.ws.security.WSSecurityEngineResult;
+import org.apache.ws.security.components.crypto.Crypto;
+import org.apache.ws.security.components.crypto.CryptoFactory;
 import org.apache.ws.security.handler.WSHandlerConstants;
 import org.apache.ws.security.handler.WSHandlerResult;
 import org.apache.ws.security.util.WSSecurityUtil;
@@ -101,6 +108,29 @@ public class PolicyBasedWss4JInOutTest e
                 null,
                 Arrays.asList(CoverageType.SIGNED));
     }
+    
+    @Test
+    public void testTransportBinding() throws Exception {
+        this.runInInterceptorAndValidate(
+                "wsse-request-clean.xml",
+                "transport_binding_policy.xml",
+                Arrays.asList(SP12Constants.TRANSPORT_BINDING,
+                              SP12Constants.TRANSPORT_TOKEN),
+                null,
+                new ArrayList<CoverageType>());
+        
+        // Note that outbound does not asset TRANSPORT_TOKEN as another handler
+        // would assert that.
+        this.runAndValidate(
+                "wsse-request-clean.xml",
+                "transport_binding_policy.xml",
+                Arrays.asList(SP12Constants.TRANSPORT_BINDING),
+                null,
+                Arrays.asList(SP12Constants.TRANSPORT_BINDING,
+                              SP12Constants.TRANSPORT_TOKEN),
+                null,
+                new ArrayList<CoverageType>());
+    }
 
     // TODO this test does not follow the traditional pattern as no server-side enforcement
     // of algorithm suites yet exists.  This support is blocked on WSS4J patches.  In the interim
@@ -110,6 +140,15 @@ public class PolicyBasedWss4JInOutTest e
         runOutInterceptorAndValidateAsymmetricBinding("signed_elements_policy.xml");
         runOutInterceptorAndValidateAsymmetricBinding("signed_elements_Basic256Sha256_policy.xml");
     }
+    
+    // TODO this test does not follow the traditional pattern as no server-side enforcement
+    // of algorithm suites yet exists.  This support is blocked on WSS4J patches.  In the interim
+    // the outbound side is tested ONLY.
+    @Test
+    public void testSignedElementsWithIssuedSAMLToken() throws Exception {
+        this.runOutInterceptorAndValidateSamlTokenAttached(
+                "signed_elements_with_sst_issued_token_policy.xml");
+    }
 
     @Test
     public void testSignedPartsPolicyWithIncompleteCoverage() throws Exception {
@@ -621,6 +660,7 @@ public class PolicyBasedWss4JInOutTest e
         t.transform(new DOMSource(inDoc), new StreamResult(System.out));
         */
         
+        
         this.runInInterceptorAndValidate(inDoc,
                 inPolicy, inAssertions.getAssertedAssertions(),
                 inAssertions.getNotAssertedAssertions(), types);
@@ -726,7 +766,17 @@ public class PolicyBasedWss4JInOutTest e
         AssertionInfoMap aim = new AssertionInfoMap(policy);
         
         final SoapMessage msg = 
-            this.getOutSoapMessageForDom(document, aim); 
+            this.getOutSoapMessageForDom(document, aim);
+        
+        return this.runOutInterceptorAndValidate(msg, policy, aim,
+                assertedOutAssertions, notAssertedOutAssertions);       
+    }    
+        
+    
+    private Document runOutInterceptorAndValidate(SoapMessage msg, Policy policy,
+            AssertionInfoMap aim,
+            List<QName> assertedOutAssertions, 
+            List<QName> notAssertedOutAssertions) throws Exception {
         
         this.getOutInterceptor().handleMessage(msg);
         
@@ -761,7 +811,7 @@ public class PolicyBasedWss4JInOutTest e
         return msg.getContent(SOAPMessage.class).getSOAPPart();
     }
     
-    // TODO: This method can be removed when testAsymmetricBindingPolicyWithSignedElements
+    // TODO: This method can be removed when testAsymmetricBindingAlgorithmSuitePolicy
     // is cleaned up by adding server side enforcement of signature related algorithms.
     private void runOutInterceptorAndValidateAsymmetricBinding(String policyDoc) throws Exception {
         final Document originalDoc = this.readDocument("wsse-request-clean.xml");
@@ -777,6 +827,50 @@ public class PolicyBasedWss4JInOutTest e
         
         this.verifySignatureAlgorithms(signedDoc, aim);
     }
+      
+    // TODO: This method can be removed or reduced when testSignedElementsWithIssuedSAMLToken is
+    // cleaned up.
+    private void runOutInterceptorAndValidateSamlTokenAttached(String policyDoc) throws Exception {
+        // create the request message
+        final Document document = this.readDocument("wsse-request-clean.xml");
+        final Element outPolicyElement = 
+            this.readDocument(policyDoc).getDocumentElement();
+        final Policy policy = this.policyBuilder.getPolicy(outPolicyElement);
+        
+        AssertionInfoMap aim = new AssertionInfoMap(policy);        
+        SoapMessage msg = this.getOutSoapMessageForDom(document, aim);
+        
+        // add an "issued" assertion into the message exchange
+        Element issuedAssertion = 
+            this.readDocument("example-sts-issued-saml-assertion.xml").getDocumentElement();
+        
+        String assertionId = issuedAssertion.getAttributeNode("AssertionID").getNodeValue();
+        
+        SecurityToken issuedToken = 
+            new SecurityToken(assertionId, issuedAssertion, null);
+        
+        Properties cryptoProps = new Properties();
+        URL url = ClassLoader.getSystemResource("META-INF/cxf/outsecurity.properties");
+        cryptoProps.load(url.openStream());
+        Crypto crypto = CryptoFactory.getInstance(cryptoProps);
+        String alias = cryptoProps.getProperty("org.apache.ws.security.crypto.merlin.keystore.alias");
+        issuedToken.setX509Certificate(crypto.getCertificates(alias)[0], crypto);
+        
+        msg.getExchange().get(Endpoint.class).put(SecurityConstants.TOKEN_ID, 
+                issuedToken.getId());
+        msg.getExchange().put(SecurityConstants.TOKEN_ID, issuedToken.getId());
+        
+        TokenStore tokenStore = new MemoryTokenStore();
+        msg.getExchange().get(Endpoint.class).getEndpointInfo()
+            .setProperty(TokenStore.class.getName(), tokenStore);
+        tokenStore.add(issuedToken);
+        
+        // fire the interceptor and verify results
+        final Document signedDoc = this.runOutInterceptorAndValidate(
+                msg, policy, aim, null, null);
+        
+        verifySignatureCoversAssertion(signedDoc, assertionId);
+    }
     
     private PolicyBasedWSS4JOutInterceptorInternal getOutInterceptor() {
         return (new PolicyBasedWSS4JOutInterceptor()).createEndingInterceptor();
@@ -876,6 +970,7 @@ public class PolicyBasedWss4JInOutTest e
     
     // TODO: This method can be removed when runOutInterceptorAndValidateAsymmetricBinding
     // is cleaned up by adding server side enforcement of signature related algorithms.
+    // See https://issues.apache.org/jira/browse/WSS-222
     private void verifySignatureAlgorithms(Document signedDoc, AssertionInfoMap aim) throws Exception { 
         final AssertionInfo assertInfo = aim.get(SP12Constants.ASYMMETRIC_BINDING).iterator().next();
         assertNotNull(assertInfo);
@@ -918,7 +1013,55 @@ public class PolicyBasedWss4JInOutTest e
         final String canonMethod =  (String) canonAlgoExpr.evaluate(signedDoc, XPathConstants.STRING);
         assertEquals(expectedCanonAlgorithm, canonMethod);
     }
-
+    
+    // TODO: This method can be removed when runOutInterceptorAndValidateSamlTokenAttached
+    // is cleaned up.
+    private void verifySignatureCoversAssertion(Document signedDoc, String assertionId) throws Exception {
+        XPathFactory factory = XPathFactory.newInstance();
+        XPath xpath = factory.newXPath();
+        final NamespaceContext nsContext = this.getNamespaceContext();
+        xpath.setNamespaceContext(nsContext);
+        
+        // Find the SecurityTokenReference for the assertion
+        final XPathExpression strExpr = xpath.compile(
+            "/s:Envelope/s:Header/wsse:Security/wsse:SecurityTokenReference/wsse:KeyIdentifier");
+        
+        final NodeList strKeyIdNodes = 
+            (NodeList) strExpr.evaluate(signedDoc, XPathConstants.NODESET);
+        
+        String strId = null;
+        for (int i = 0; i < strKeyIdNodes.getLength(); i++) {
+            Node keyIdNode = (Node) strKeyIdNodes.item(i);
+            String strKey = keyIdNode.getTextContent();
+            if (strKey.equals(assertionId)) {
+                Node strNode = (Node) keyIdNode.getParentNode();
+                strId = strNode.getAttributes().
+                    getNamedItemNS(nsContext.getNamespaceURI("wsu"), "Id").getNodeValue();
+                break;
+            }
+        }
+        assertNotNull("SecurityTokenReference for " + assertionId + " not found in security header.", strId);
+        
+        // Verify STR is included in the signature references
+        final XPathExpression sigRefExpr = xpath.compile(
+            "/s:Envelope/s:Header/wsse:Security/ds:Signature/ds:SignedInfo/ds:Reference");
+        
+        final NodeList sigReferenceNodes = 
+            (NodeList) sigRefExpr.evaluate(signedDoc, XPathConstants.NODESET);
+        
+        boolean foundStrReference = false;
+        for (int i = 0; i < sigReferenceNodes.getLength(); i++) {
+            Node sigRefNode = (Node) sigReferenceNodes.item(i);
+            String sigRefURI = sigRefNode.getAttributes().getNamedItem("URI").getNodeValue();
+            if (sigRefURI.equals("#" + strId)) {
+                foundStrReference = true;
+                break;
+            }
+        }
+        
+        assertTrue("SecurityTokenReference for " + assertionId + " is not signed.", foundStrReference);
+    }
+    
     private static final class MockEndpoint extends 
         AbstractAttributedInterceptorProvider implements Endpoint {