You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ws.apache.org by gi...@apache.org on 2013/07/10 11:32:38 UTC

svn commit: r1501691 - in /webservices/wss4j/trunk: ws-security-policy-stax/src/main/java/org/apache/wss4j/policy/stax/assertionStates/ ws-security-policy-stax/src/test/java/org/apache/wss4j/policy/stax/test/ ws-security-stax/src/main/java/org/apache/w...

Author: giger
Date: Wed Jul 10 09:32:37 2013
New Revision: 1501691

URL: http://svn.apache.org/r1501691
Log:
WSS-457 - Incorrect validation of ProtectTokens assertion 

Modified:
    webservices/wss4j/trunk/ws-security-policy-stax/src/main/java/org/apache/wss4j/policy/stax/assertionStates/TokenProtectionAssertionState.java
    webservices/wss4j/trunk/ws-security-policy-stax/src/test/java/org/apache/wss4j/policy/stax/test/TokenProtectionTest.java
    webservices/wss4j/trunk/ws-security-stax/src/main/java/org/apache/wss4j/stax/ext/WSSUtils.java

Modified: webservices/wss4j/trunk/ws-security-policy-stax/src/main/java/org/apache/wss4j/policy/stax/assertionStates/TokenProtectionAssertionState.java
URL: http://svn.apache.org/viewvc/webservices/wss4j/trunk/ws-security-policy-stax/src/main/java/org/apache/wss4j/policy/stax/assertionStates/TokenProtectionAssertionState.java?rev=1501691&r1=1501690&r2=1501691&view=diff
==============================================================================
--- webservices/wss4j/trunk/ws-security-policy-stax/src/main/java/org/apache/wss4j/policy/stax/assertionStates/TokenProtectionAssertionState.java (original)
+++ webservices/wss4j/trunk/ws-security-policy-stax/src/main/java/org/apache/wss4j/policy/stax/assertionStates/TokenProtectionAssertionState.java Wed Jul 10 09:32:37 2013
@@ -91,10 +91,7 @@ public class TokenProtectionAssertionSta
             for (int i = 0; i < tokenSecurityEvents.size(); i++) {
                 TokenSecurityEvent<? extends SecurityToken> tokenSecurityEvent = tokenSecurityEvents.get(i);
 
-                SecurityToken securityToken = tokenSecurityEvent.getSecurityToken();
-                while (securityToken.getKeyWrappingToken() != null) {
-                    securityToken = securityToken.getKeyWrappingToken();
-                }
+                SecurityToken securityToken = getEffectiveSignatureToken(tokenSecurityEvent.getSecurityToken());
 
                 //a token can only be signed if it is included in the message:
                 if (securityToken.isIncludedInMessage() && isSignatureToken(securityToken)) {
@@ -142,8 +139,9 @@ public class TokenProtectionAssertionSta
         return false;
     }
 
-    private boolean isEndorsingToken(SecurityToken securityToken) {
-        List<WSSecurityTokenConstants.TokenUsage> tokenUsages = securityToken.getTokenUsages();
+    private boolean isEndorsingToken(SecurityToken securityToken) throws XMLSecurityException {
+        SecurityToken rootToken = WSSUtils.getRootToken(securityToken);
+        List<WSSecurityTokenConstants.TokenUsage> tokenUsages = rootToken.getTokenUsages();
         for (int i = 0; i < tokenUsages.size(); i++) {
             WSSecurityTokenConstants.TokenUsage tokenUsage = tokenUsages.get(i);
             if (tokenUsage.getName().contains("Endorsing")) {
@@ -153,8 +151,9 @@ public class TokenProtectionAssertionSta
         return false;
     }
 
-    private boolean isSignedSupportingToken(SecurityToken securityToken) {
-        List<WSSecurityTokenConstants.TokenUsage> tokenUsages = securityToken.getTokenUsages();
+    private boolean isSignedSupportingToken(SecurityToken securityToken) throws XMLSecurityException {
+        SecurityToken rootToken = WSSUtils.getRootToken(securityToken);
+        List<WSSecurityTokenConstants.TokenUsage> tokenUsages = rootToken.getTokenUsages();
         for (int i = 0; i < tokenUsages.size(); i++) {
             WSSecurityTokenConstants.TokenUsage tokenUsage = tokenUsages.get(i);
             if (tokenUsage.getName().contains("Signed")) {
@@ -164,8 +163,9 @@ public class TokenProtectionAssertionSta
         return false;
     }
 
-    private boolean isMainSignatureToken(SecurityToken securityToken) {
-        List<WSSecurityTokenConstants.TokenUsage> tokenUsages = securityToken.getTokenUsages();
+    private boolean isMainSignatureToken(SecurityToken securityToken) throws XMLSecurityException {
+        SecurityToken rootToken = WSSUtils.getRootToken(securityToken);
+        List<WSSecurityTokenConstants.TokenUsage> tokenUsages = rootToken.getTokenUsages();
         return tokenUsages.contains(WSSecurityTokenConstants.TokenUsage_MainSignature);
     }
 
@@ -178,10 +178,7 @@ public class TokenProtectionAssertionSta
         for (int i = 0; i < signedElementEvents.size(); i++) {
             SignedElementSecurityEvent signedElementSecurityEvent = signedElementEvents.get(i);
             if (WSSUtils.pathMatches(signedElementSecurityEvent.getElementPath(), signaturePath, true, false)) {
-                SecurityToken signingSecurityToken = signedElementSecurityEvent.getSecurityToken();
-                while (signingSecurityToken != null && signingSecurityToken.getKeyWrappingToken() != null) {
-                    signingSecurityToken = signingSecurityToken.getKeyWrappingToken();
-                }
+                SecurityToken signingSecurityToken = getEffectiveSignatureToken(signedElementSecurityEvent.getSecurityToken());
                 //todo ATM me just check if the token signs a signature but we don't know if it's the main signature
                 if (signingSecurityToken != null && signingSecurityToken.getId().equals(securityToken.getId())) {
                     return true;
@@ -197,19 +194,15 @@ public class TokenProtectionAssertionSta
             if (WSSUtils.pathMatches(signedElementSecurityEvent.getElementPath(), securityToken.getElementPath(), false, false)) {
 
                 SecurityToken signingSecurityToken = signedElementSecurityEvent.getSecurityToken();
-                while (signingSecurityToken != null && signingSecurityToken.getKeyWrappingToken() != null) {
-                    signingSecurityToken = signingSecurityToken.getKeyWrappingToken();
-                }
+                signingSecurityToken = getEffectiveSignatureToken(signingSecurityToken);
 
-                if (signingSecurityToken != null && signingSecurityToken.getId().equals(securityToken.getId())) {
+                if (signingSecurityToken.getId().equals(securityToken.getId())) {
                     //ok we've found the correlating signedElementSecurityEvent. Now we have to find the Token that
                     //is covered by this signedElementSecurityEvent:
                     for (int j = 0; j < tokenSecurityEvents.size(); j++) {
                         TokenSecurityEvent<? extends SecurityToken> tokenSecurityEvent = tokenSecurityEvents.get(j);
-                        SecurityToken st = tokenSecurityEvent.getSecurityToken();
-                        while (st.getKeyWrappingToken() != null) {
-                            st = st.getKeyWrappingToken();
-                        }
+                        SecurityToken st = getEffectiveSignatureToken(tokenSecurityEvent.getSecurityToken());
+
                         if (signedElementSecurityEvent.getXmlSecEvent() == st.getXMLSecEvent()) {
                             //...and we got the covered token
                             //next we have to see if the token is the same:
@@ -243,10 +236,8 @@ public class TokenProtectionAssertionSta
                 for (int j = 0; j < signedElementEvents.size(); j++) {
                     SignedElementSecurityEvent signedElementSecurityEvent = signedElementEvents.get(j);
                     if (WSSUtils.pathMatches(signedElementSecurityEvent.getElementPath(), elementPath, false, false)) {
-                        SecurityToken elementSignatureToken = signedElementSecurityEvent.getSecurityToken();
-                        while (elementSignatureToken != null && elementSignatureToken.getKeyWrappingToken() != null) {
-                            elementSignatureToken = elementSignatureToken.getKeyWrappingToken();
-                        }
+                        SecurityToken elementSignatureToken = getEffectiveSignatureToken(signedElementSecurityEvent.getSecurityToken());
+
                         if (elementSignatureToken != null && elementSignatureToken.getId().equals(securityToken.getId())) {
                             if (!signedElements.contains(signedElementSecurityEvent)) {
                                 signedElements.add(signedElementSecurityEvent);
@@ -266,4 +257,21 @@ public class TokenProtectionAssertionSta
 
         return true;
     }
+
+    private SecurityToken getEffectiveSignatureToken(SecurityToken securityToken) throws XMLSecurityException {
+        SecurityToken tmp = WSSUtils.getRootToken(securityToken);
+        List<? extends SecurityToken> wrappedTokens = tmp.getWrappedTokens();
+        for (int i = 0; i < wrappedTokens.size(); i++) {
+            SecurityToken token = wrappedTokens.get(i);
+            if (isSignatureToken(token)) {
+                //WSP 1.3, 6.5 [Token Protection] Property: Note that in cases where derived keys are used
+                //the 'main' token, and NOT the derived key token, is covered by the signature.
+                if (WSSecurityTokenConstants.DerivedKeyToken.equals(token.getTokenType())) {
+                    return tmp;
+                }
+                tmp = token;
+            }
+        }
+        return tmp;
+    }
 }

Modified: webservices/wss4j/trunk/ws-security-policy-stax/src/test/java/org/apache/wss4j/policy/stax/test/TokenProtectionTest.java
URL: http://svn.apache.org/viewvc/webservices/wss4j/trunk/ws-security-policy-stax/src/test/java/org/apache/wss4j/policy/stax/test/TokenProtectionTest.java?rev=1501691&r1=1501690&r2=1501691&view=diff
==============================================================================
--- webservices/wss4j/trunk/ws-security-policy-stax/src/test/java/org/apache/wss4j/policy/stax/test/TokenProtectionTest.java (original)
+++ webservices/wss4j/trunk/ws-security-policy-stax/src/test/java/org/apache/wss4j/policy/stax/test/TokenProtectionTest.java Wed Jul 10 09:32:37 2013
@@ -26,10 +26,14 @@ import org.apache.wss4j.stax.securityTok
 import org.apache.wss4j.stax.impl.securityToken.X509SecurityTokenImpl;
 import org.apache.wss4j.stax.securityEvent.OperationSecurityEvent;
 import org.apache.xml.security.stax.ext.XMLSecurityConstants;
+import org.apache.xml.security.stax.impl.securityToken.AbstractInboundSecurityToken;
+import org.apache.xml.security.stax.impl.util.IDGenerator;
+import org.apache.xml.security.stax.securityEvent.EncryptedKeyTokenSecurityEvent;
 import org.apache.xml.security.stax.securityEvent.SignedElementSecurityEvent;
 import org.apache.xml.security.stax.securityEvent.X509TokenSecurityEvent;
 import org.apache.xml.security.stax.securityToken.InboundSecurityToken;
 import org.apache.xml.security.stax.securityToken.SecurityToken;
+import org.apache.xml.security.stax.securityToken.SecurityTokenConstants;
 import org.testng.Assert;
 import org.testng.annotations.Test;
 
@@ -489,4 +493,215 @@ public class TokenProtectionTest extends
             Assert.assertEquals(e.getFaultCode(), WSSecurityException.INVALID_SECURITY);
         }
     }
+
+    @Test
+    public void testPolicySymmetricBindingProtectSignatureToken() throws Exception {
+        String policyString =
+                "<sp:SymmetricBinding xmlns:sp=\"http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702\" xmlns:sp3=\"http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200802\">\n" +
+                        "<wsp:Policy xmlns:wsp=\"http://schemas.xmlsoap.org/ws/2004/09/policy\">\n" +
+                        "   <sp:AlgorithmSuite>\n" +
+                        "       <wsp:Policy>\n" +
+                        "           <sp:Basic256/>\n" +
+                        "       </wsp:Policy>\n" +
+                        "   </sp:AlgorithmSuite>\n" +
+                        "<sp:ProtectTokens/>\n" +
+                        "</wsp:Policy>\n" +
+                        "</sp:SymmetricBinding>";
+        PolicyEnforcer policyEnforcer = buildAndStartPolicyEngine(policyString);
+
+        List<XMLSecurityConstants.ContentType> protectionOrder = new LinkedList<XMLSecurityConstants.ContentType>();
+        protectionOrder.add(XMLSecurityConstants.ContentType.SIGNATURE);
+
+        List<QName> bstPath = new ArrayList<QName>();
+        bstPath.addAll(WSSConstants.WSSE_SECURITY_HEADER_PATH);
+        bstPath.add(WSSConstants.TAG_wsse_BinarySecurityToken);
+
+        List<QName> ekPath = new ArrayList<QName>();
+        ekPath.addAll(WSSConstants.WSSE_SECURITY_HEADER_PATH);
+        ekPath.add(WSSConstants.TAG_xenc_EncryptedKey);
+
+        List<QName> sigPath = new ArrayList<QName>();
+        sigPath.addAll(WSSConstants.WSSE_SECURITY_HEADER_PATH);
+        sigPath.add(WSSConstants.TAG_dsig_Signature);
+
+        X509SecurityTokenImpl x509SecurityToken = getX509Token(WSSecurityTokenConstants.X509V3Token);
+        x509SecurityToken.addTokenUsage(WSSecurityTokenConstants.TokenUsage_MainSignature);
+        x509SecurityToken.setElementPath(bstPath);
+
+        AbstractInboundSecurityToken ekSecurityToken = new AbstractInboundSecurityToken(
+                null, IDGenerator.generateID(null),
+                SecurityTokenConstants.KeyIdentifier_EncryptedKey, true) {
+            @Override
+            public SecurityTokenConstants.TokenType getTokenType() {
+                return SecurityTokenConstants.EncryptedKeyToken;
+            }
+        };
+        ekSecurityToken.addTokenUsage(WSSecurityTokenConstants.TokenUsage_Signature);
+        ekSecurityToken.setKeyWrappingToken(x509SecurityToken);
+        ekSecurityToken.setElementPath(ekPath);
+
+        x509SecurityToken.addWrappedToken(ekSecurityToken);
+
+        X509TokenSecurityEvent x509TokenSecurityEvent = new X509TokenSecurityEvent();
+        x509TokenSecurityEvent.setSecurityToken(x509SecurityToken);
+        policyEnforcer.registerSecurityEvent(x509TokenSecurityEvent);
+
+        EncryptedKeyTokenSecurityEvent encryptedKeyTokenSecurityEvent = new EncryptedKeyTokenSecurityEvent();
+        encryptedKeyTokenSecurityEvent.setSecurityToken(ekSecurityToken);
+        policyEnforcer.registerSecurityEvent(encryptedKeyTokenSecurityEvent);
+
+        SignedElementSecurityEvent signedElementSecurityEvent = new SignedElementSecurityEvent(ekSecurityToken, true, protectionOrder);
+        signedElementSecurityEvent.setElementPath(ekPath);
+        policyEnforcer.registerSecurityEvent(signedElementSecurityEvent);
+
+        OperationSecurityEvent operationSecurityEvent = new OperationSecurityEvent();
+        operationSecurityEvent.setOperation(new QName("definitions"));
+
+        policyEnforcer.registerSecurityEvent(operationSecurityEvent);
+        policyEnforcer.doFinal();
+    }
+
+    @Test
+    public void testPolicySymmetricBindingProtectRootToken() throws Exception {
+        String policyString =
+                "<sp:SymmetricBinding xmlns:sp=\"http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702\" xmlns:sp3=\"http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200802\">\n" +
+                        "<wsp:Policy xmlns:wsp=\"http://schemas.xmlsoap.org/ws/2004/09/policy\">\n" +
+                        "   <sp:AlgorithmSuite>\n" +
+                        "       <wsp:Policy>\n" +
+                        "           <sp:Basic256/>\n" +
+                        "       </wsp:Policy>\n" +
+                        "   </sp:AlgorithmSuite>\n" +
+                        "<sp:ProtectTokens/>\n" +
+                        "</wsp:Policy>\n" +
+                        "</sp:SymmetricBinding>";
+        PolicyEnforcer policyEnforcer = buildAndStartPolicyEngine(policyString);
+
+        List<XMLSecurityConstants.ContentType> protectionOrder = new LinkedList<XMLSecurityConstants.ContentType>();
+        protectionOrder.add(XMLSecurityConstants.ContentType.SIGNATURE);
+
+        List<QName> bstPath = new ArrayList<QName>();
+        bstPath.addAll(WSSConstants.WSSE_SECURITY_HEADER_PATH);
+        bstPath.add(WSSConstants.TAG_wsse_BinarySecurityToken);
+
+        List<QName> ekPath = new ArrayList<QName>();
+        ekPath.addAll(WSSConstants.WSSE_SECURITY_HEADER_PATH);
+        ekPath.add(WSSConstants.TAG_xenc_EncryptedKey);
+
+        List<QName> sigPath = new ArrayList<QName>();
+        sigPath.addAll(WSSConstants.WSSE_SECURITY_HEADER_PATH);
+        sigPath.add(WSSConstants.TAG_dsig_Signature);
+
+        X509SecurityTokenImpl x509SecurityToken = getX509Token(WSSecurityTokenConstants.X509V3Token);
+        x509SecurityToken.addTokenUsage(WSSecurityTokenConstants.TokenUsage_MainSignature);
+        x509SecurityToken.setElementPath(bstPath);
+
+        AbstractInboundSecurityToken ekSecurityToken = new AbstractInboundSecurityToken(
+                null, IDGenerator.generateID(null),
+                SecurityTokenConstants.KeyIdentifier_EncryptedKey, true) {
+            @Override
+            public SecurityTokenConstants.TokenType getTokenType() {
+                return SecurityTokenConstants.EncryptedKeyToken;
+            }
+        };
+        ekSecurityToken.addTokenUsage(WSSecurityTokenConstants.TokenUsage_Signature);
+        ekSecurityToken.setKeyWrappingToken(x509SecurityToken);
+        ekSecurityToken.setElementPath(ekPath);
+
+        x509SecurityToken.addWrappedToken(ekSecurityToken);
+
+        X509TokenSecurityEvent x509TokenSecurityEvent = new X509TokenSecurityEvent();
+        x509TokenSecurityEvent.setSecurityToken(x509SecurityToken);
+        policyEnforcer.registerSecurityEvent(x509TokenSecurityEvent);
+
+        EncryptedKeyTokenSecurityEvent encryptedKeyTokenSecurityEvent = new EncryptedKeyTokenSecurityEvent();
+        encryptedKeyTokenSecurityEvent.setSecurityToken(ekSecurityToken);
+        policyEnforcer.registerSecurityEvent(encryptedKeyTokenSecurityEvent);
+
+        SignedElementSecurityEvent signedElementSecurityEvent = new SignedElementSecurityEvent(x509SecurityToken, true, protectionOrder);
+        signedElementSecurityEvent.setElementPath(bstPath);
+        policyEnforcer.registerSecurityEvent(signedElementSecurityEvent);
+
+        OperationSecurityEvent operationSecurityEvent = new OperationSecurityEvent();
+        operationSecurityEvent.setOperation(new QName("definitions"));
+
+        try {
+            policyEnforcer.registerSecurityEvent(operationSecurityEvent);
+        } catch (WSSecurityException e) {
+            Assert.assertTrue(e.getCause() instanceof PolicyViolationException);
+            Assert.assertEquals(e.getCause().getMessage(),
+                    "Token /{http://schemas.xmlsoap.org/soap/envelope/}Envelope/{http://schemas.xmlsoap.org/soap/envelope/}Header/{http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd}Security/{http://www.w3.org/2001/04/xmlenc#}EncryptedKey must be signed by its signature.");
+            Assert.assertEquals(e.getFaultCode(), WSSecurityException.INVALID_SECURITY);
+        }
+    }
+
+    @Test
+    public void testPolicySymmetricBindingProtectAllToken() throws Exception {
+        String policyString =
+                "<sp:SymmetricBinding xmlns:sp=\"http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702\" xmlns:sp3=\"http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200802\">\n" +
+                        "<wsp:Policy xmlns:wsp=\"http://schemas.xmlsoap.org/ws/2004/09/policy\">\n" +
+                        "   <sp:AlgorithmSuite>\n" +
+                        "       <wsp:Policy>\n" +
+                        "           <sp:Basic256/>\n" +
+                        "       </wsp:Policy>\n" +
+                        "   </sp:AlgorithmSuite>\n" +
+                        "<sp:ProtectTokens/>\n" +
+                        "</wsp:Policy>\n" +
+                        "</sp:SymmetricBinding>";
+        PolicyEnforcer policyEnforcer = buildAndStartPolicyEngine(policyString);
+
+        List<XMLSecurityConstants.ContentType> protectionOrder = new LinkedList<XMLSecurityConstants.ContentType>();
+        protectionOrder.add(XMLSecurityConstants.ContentType.SIGNATURE);
+
+        List<QName> bstPath = new ArrayList<QName>();
+        bstPath.addAll(WSSConstants.WSSE_SECURITY_HEADER_PATH);
+        bstPath.add(WSSConstants.TAG_wsse_BinarySecurityToken);
+
+        List<QName> ekPath = new ArrayList<QName>();
+        ekPath.addAll(WSSConstants.WSSE_SECURITY_HEADER_PATH);
+        ekPath.add(WSSConstants.TAG_xenc_EncryptedKey);
+
+        List<QName> sigPath = new ArrayList<QName>();
+        sigPath.addAll(WSSConstants.WSSE_SECURITY_HEADER_PATH);
+        sigPath.add(WSSConstants.TAG_dsig_Signature);
+
+        X509SecurityTokenImpl x509SecurityToken = getX509Token(WSSecurityTokenConstants.X509V3Token);
+        x509SecurityToken.addTokenUsage(WSSecurityTokenConstants.TokenUsage_MainSignature);
+        x509SecurityToken.setElementPath(bstPath);
+
+        AbstractInboundSecurityToken ekSecurityToken = new AbstractInboundSecurityToken(
+                null, IDGenerator.generateID(null),
+                SecurityTokenConstants.KeyIdentifier_EncryptedKey, true) {
+            @Override
+            public SecurityTokenConstants.TokenType getTokenType() {
+                return SecurityTokenConstants.EncryptedKeyToken;
+            }
+        };
+        ekSecurityToken.addTokenUsage(WSSecurityTokenConstants.TokenUsage_Signature);
+        ekSecurityToken.setKeyWrappingToken(x509SecurityToken);
+        ekSecurityToken.setElementPath(ekPath);
+
+        x509SecurityToken.addWrappedToken(ekSecurityToken);
+
+        X509TokenSecurityEvent x509TokenSecurityEvent = new X509TokenSecurityEvent();
+        x509TokenSecurityEvent.setSecurityToken(x509SecurityToken);
+        policyEnforcer.registerSecurityEvent(x509TokenSecurityEvent);
+
+        EncryptedKeyTokenSecurityEvent encryptedKeyTokenSecurityEvent = new EncryptedKeyTokenSecurityEvent();
+        encryptedKeyTokenSecurityEvent.setSecurityToken(ekSecurityToken);
+        policyEnforcer.registerSecurityEvent(encryptedKeyTokenSecurityEvent);
+
+        SignedElementSecurityEvent signedElementSecurityEvent = new SignedElementSecurityEvent(x509SecurityToken, true, protectionOrder);
+        signedElementSecurityEvent.setElementPath(bstPath);
+        policyEnforcer.registerSecurityEvent(signedElementSecurityEvent);
+
+        signedElementSecurityEvent = new SignedElementSecurityEvent(ekSecurityToken, true, protectionOrder);
+        signedElementSecurityEvent.setElementPath(ekPath);
+        policyEnforcer.registerSecurityEvent(signedElementSecurityEvent);
+
+        OperationSecurityEvent operationSecurityEvent = new OperationSecurityEvent();
+        operationSecurityEvent.setOperation(new QName("definitions"));
+
+        policyEnforcer.registerSecurityEvent(operationSecurityEvent);
+        policyEnforcer.doFinal();
+    }
 }

Modified: webservices/wss4j/trunk/ws-security-stax/src/main/java/org/apache/wss4j/stax/ext/WSSUtils.java
URL: http://svn.apache.org/viewvc/webservices/wss4j/trunk/ws-security-stax/src/main/java/org/apache/wss4j/stax/ext/WSSUtils.java?rev=1501691&r1=1501690&r2=1501691&view=diff
==============================================================================
--- webservices/wss4j/trunk/ws-security-stax/src/main/java/org/apache/wss4j/stax/ext/WSSUtils.java (original)
+++ webservices/wss4j/trunk/ws-security-stax/src/main/java/org/apache/wss4j/stax/ext/WSSUtils.java Wed Jul 10 09:32:37 2013
@@ -532,5 +532,13 @@ public class WSSUtils extends XMLSecurit
             stringBuilder.append(qName.toString());
         }
         return stringBuilder.toString();
-    }    
+    }
+
+    public static SecurityToken getRootToken(SecurityToken securityToken) throws XMLSecurityException {
+        SecurityToken tmp = securityToken;
+        while (tmp.getKeyWrappingToken() != null) {
+            tmp = tmp.getKeyWrappingToken();
+        }
+        return tmp;
+    }
 }