You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cxf.apache.org by co...@apache.org on 2017/04/04 16:29:13 UTC

[2/3] cxf git commit: CXF-7315 - Abstract the STS client token caching behaviour to allow the user to plug in a custom implementation

CXF-7315 - Abstract the STS client token caching behaviour to allow the user to plug in a custom implementation

# Conflicts:
#	rt/security/src/main/java/org/apache/cxf/rt/security/SecurityConstants.java
#	rt/ws/security/src/main/java/org/apache/cxf/ws/security/policy/interceptors/IssuedTokenInterceptorProvider.java
#	rt/ws/security/src/main/java/org/apache/cxf/ws/security/policy/interceptors/STSTokenOutInterceptor.java
#	rt/ws/security/src/main/java/org/apache/cxf/ws/security/trust/STSTokenRetriever.java


Project: http://git-wip-us.apache.org/repos/asf/cxf/repo
Commit: http://git-wip-us.apache.org/repos/asf/cxf/commit/4b4bb843
Tree: http://git-wip-us.apache.org/repos/asf/cxf/tree/4b4bb843
Diff: http://git-wip-us.apache.org/repos/asf/cxf/diff/4b4bb843

Branch: refs/heads/3.1.x-fixes
Commit: 4b4bb8431520ac3571cce86a6557eb2480743815
Parents: d3f9087
Author: Colm O hEigeartaigh <co...@apache.org>
Authored: Tue Apr 4 15:59:33 2017 +0100
Committer: Colm O hEigeartaigh <co...@apache.org>
Committed: Tue Apr 4 16:50:16 2017 +0100

----------------------------------------------------------------------
 .../cxf/rt/security/SecurityConstants.java      |  11 +-
 .../IssuedTokenInterceptorProvider.java         |  15 +-
 .../interceptors/STSTokenOutInterceptor.java    |  22 +-
 .../security/trust/DefaultSTSTokenCacher.java   | 180 ++++++++++++++
 .../cxf/ws/security/trust/STSTokenCacher.java   |  59 +++++
 .../ws/security/trust/STSTokenRetriever.java    | 240 +++----------------
 6 files changed, 315 insertions(+), 212 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cxf/blob/4b4bb843/rt/security/src/main/java/org/apache/cxf/rt/security/SecurityConstants.java
----------------------------------------------------------------------
diff --git a/rt/security/src/main/java/org/apache/cxf/rt/security/SecurityConstants.java b/rt/security/src/main/java/org/apache/cxf/rt/security/SecurityConstants.java
index aa0106d..61d3966 100644
--- a/rt/security/src/main/java/org/apache/cxf/rt/security/SecurityConstants.java
+++ b/rt/security/src/main/java/org/apache/cxf/rt/security/SecurityConstants.java
@@ -343,7 +343,14 @@ public class SecurityConstants {
      */
     public static final String STS_TOKEN_IMMINENT_EXPIRY_VALUE =
         "security.sts.token.imminent-expiry-value";
-    
+
+    /**
+     * An implementation of the STSTokenCacher interface, if you want to plug in custom caching behaviour for
+     * STS clients. The default value is the DefaultSTSTokenCacher.
+     */
+    public static final String STS_TOKEN_CACHER_IMPL =
+        "security.sts.token.cacher.impl";
+
     public static final Set<String> COMMON_PROPERTIES;
     
     static {
@@ -359,7 +366,7 @@ public class SecurityConstants {
             DISABLE_STS_CLIENT_WSMEX_CALL_USING_EPR_ADDRESS, STS_TOKEN_CRYPTO,
             STS_TOKEN_PROPERTIES, STS_TOKEN_USERNAME, STS_TOKEN_ACT_AS, STS_TOKEN_ON_BEHALF_OF,
             STS_CLIENT, STS_APPLIES_TO, CACHE_ISSUED_TOKEN_IN_ENDPOINT, PREFER_WSMEX_OVER_STS_CLIENT_CONFIG,
-            STS_TOKEN_IMMINENT_EXPIRY_VALUE
+            STS_TOKEN_IMMINENT_EXPIRY_VALUE, STS_TOKEN_CACHER_IMPL
         }));
         COMMON_PROPERTIES = Collections.unmodifiableSet(s);
     }

http://git-wip-us.apache.org/repos/asf/cxf/blob/4b4bb843/rt/ws/security/src/main/java/org/apache/cxf/ws/security/policy/interceptors/IssuedTokenInterceptorProvider.java
----------------------------------------------------------------------
diff --git a/rt/ws/security/src/main/java/org/apache/cxf/ws/security/policy/interceptors/IssuedTokenInterceptorProvider.java b/rt/ws/security/src/main/java/org/apache/cxf/ws/security/policy/interceptors/IssuedTokenInterceptorProvider.java
index 141ec94..47615fc 100644
--- a/rt/ws/security/src/main/java/org/apache/cxf/ws/security/policy/interceptors/IssuedTokenInterceptorProvider.java
+++ b/rt/ws/security/src/main/java/org/apache/cxf/ws/security/policy/interceptors/IssuedTokenInterceptorProvider.java
@@ -32,12 +32,15 @@ import org.apache.cxf.interceptor.Fault;
 import org.apache.cxf.message.Message;
 import org.apache.cxf.phase.AbstractPhaseInterceptor;
 import org.apache.cxf.phase.Phase;
+import org.apache.cxf.rt.security.utils.SecurityUtils;
 import org.apache.cxf.ws.policy.AbstractPolicyInterceptorProvider;
 import org.apache.cxf.ws.policy.AssertionInfo;
 import org.apache.cxf.ws.policy.AssertionInfoMap;
 import org.apache.cxf.ws.security.SecurityConstants;
 import org.apache.cxf.ws.security.policy.PolicyUtils;
 import org.apache.cxf.ws.security.tokenstore.SecurityToken;
+import org.apache.cxf.ws.security.trust.DefaultSTSTokenCacher;
+import org.apache.cxf.ws.security.trust.STSTokenCacher;
 import org.apache.cxf.ws.security.trust.STSTokenRetriever;
 import org.apache.cxf.ws.security.trust.STSTokenRetriever.TokenRequestParams;
 import org.apache.cxf.ws.security.wss4j.PolicyBasedWSS4JInInterceptor;
@@ -130,8 +133,16 @@ public class IssuedTokenInterceptorProvider extends AbstractPolicyInterceptorPro
                     params.setTrust13(NegotiationUtils.getTrust13(aim));
                     params.setTokenTemplate(itok.getRequestSecurityTokenTemplate());
 
-                    SecurityToken tok = STSTokenRetriever.getToken(message, params);
-                    
+                    // Get a custom STSTokenCacher implementation if specified
+                    STSTokenCacher tokenCacher =
+                        (STSTokenCacher)SecurityUtils.getSecurityPropertyValue(
+                            SecurityConstants.STS_TOKEN_CACHER_IMPL, message
+                        );
+                    if (tokenCacher == null) {
+                        tokenCacher = new DefaultSTSTokenCacher();
+                    }
+                    SecurityToken tok = STSTokenRetriever.getToken(message, params, tokenCacher);
+
                     if (tok != null) {
                         assertIssuedToken(itok, aim);
                         for (AssertionInfo ai : ais) {

http://git-wip-us.apache.org/repos/asf/cxf/blob/4b4bb843/rt/ws/security/src/main/java/org/apache/cxf/ws/security/policy/interceptors/STSTokenOutInterceptor.java
----------------------------------------------------------------------
diff --git a/rt/ws/security/src/main/java/org/apache/cxf/ws/security/policy/interceptors/STSTokenOutInterceptor.java b/rt/ws/security/src/main/java/org/apache/cxf/ws/security/policy/interceptors/STSTokenOutInterceptor.java
index ac71eac..c49c364 100644
--- a/rt/ws/security/src/main/java/org/apache/cxf/ws/security/policy/interceptors/STSTokenOutInterceptor.java
+++ b/rt/ws/security/src/main/java/org/apache/cxf/ws/security/policy/interceptors/STSTokenOutInterceptor.java
@@ -33,7 +33,9 @@ import org.apache.cxf.phase.AbstractPhaseInterceptor;
 import org.apache.cxf.phase.Phase;
 import org.apache.cxf.ws.security.SecurityConstants;
 import org.apache.cxf.ws.security.tokenstore.SecurityToken;
+import org.apache.cxf.ws.security.trust.DefaultSTSTokenCacher;
 import org.apache.cxf.ws.security.trust.STSClient;
+import org.apache.cxf.ws.security.trust.STSTokenCacher;
 import org.apache.cxf.ws.security.trust.STSTokenRetriever;
 import org.apache.cxf.ws.security.trust.STSTokenRetriever.TokenRequestParams;
 
@@ -49,6 +51,7 @@ public class STSTokenOutInterceptor extends AbstractPhaseInterceptor<Message> {
     
     private STSClient stsClient;
     private TokenRequestParams tokenParams;
+    private STSTokenCacher tokenCacher = new DefaultSTSTokenCacher();
 
     public STSTokenOutInterceptor(AuthParams authParams, String stsWsdlLocation, Bus bus) {
         this(Phase.PREPARE_SEND, authParams, stsWsdlLocation, bus);
@@ -79,7 +82,7 @@ public class STSTokenOutInterceptor extends AbstractPhaseInterceptor<Message> {
         if (stsClient != null) {
             message.put(SecurityConstants.STS_CLIENT, stsClient);
         }
-        SecurityToken tok = STSTokenRetriever.getToken(message, tokenParams);
+        SecurityToken tok = STSTokenRetriever.getToken(message, tokenParams, tokenCacher);
         if (tok == null) {
             LOG.warning("Security token was not retrieved from STS");
         }
@@ -94,7 +97,24 @@ public class STSTokenOutInterceptor extends AbstractPhaseInterceptor<Message> {
     public STSClient getSTSClient() {
         return stsClient;
     }
+<<<<<<< HEAD
     
+=======
+
+    public STSTokenCacher getTokenCacher() {
+        return tokenCacher;
+    }
+
+    public void setTokenCacher(STSTokenCacher tokenCacher) {
+        this.tokenCacher = tokenCacher;
+    }
+
+    /**
+     * A enumeration to specify authentication mode in communication with STS.
+     * @deprecated use {@link org.apache.cxf.ws.security.trust.STSAuthParams.AuthMode}
+     */
+    @Deprecated
+>>>>>>> 048b46d... CXF-7315 - Abstract the STS client token caching behaviour to allow the user to plug in a custom implementation
     public enum AuthMode {
         X509(X509_ENDPOINT, KEY_TYPE_X509), 
         TRANSPORT(TRANSPORT_ENDPOINT, null);

http://git-wip-us.apache.org/repos/asf/cxf/blob/4b4bb843/rt/ws/security/src/main/java/org/apache/cxf/ws/security/trust/DefaultSTSTokenCacher.java
----------------------------------------------------------------------
diff --git a/rt/ws/security/src/main/java/org/apache/cxf/ws/security/trust/DefaultSTSTokenCacher.java b/rt/ws/security/src/main/java/org/apache/cxf/ws/security/trust/DefaultSTSTokenCacher.java
new file mode 100644
index 0000000..6fc26f0
--- /dev/null
+++ b/rt/ws/security/src/main/java/org/apache/cxf/ws/security/trust/DefaultSTSTokenCacher.java
@@ -0,0 +1,180 @@
+/**
+ * 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.cxf.ws.security.trust;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.w3c.dom.Element;
+
+import org.apache.cxf.interceptor.Fault;
+import org.apache.cxf.message.Message;
+import org.apache.cxf.rt.security.utils.SecurityUtils;
+import org.apache.cxf.ws.security.SecurityConstants;
+import org.apache.cxf.ws.security.tokenstore.SecurityToken;
+import org.apache.cxf.ws.security.tokenstore.TokenStore;
+import org.apache.cxf.ws.security.tokenstore.TokenStoreUtils;
+import org.apache.wss4j.common.ext.WSSecurityException;
+import org.apache.wss4j.common.saml.SamlAssertionWrapper;
+import org.apache.wss4j.dom.WSConstants;
+
+public class DefaultSTSTokenCacher implements STSTokenCacher {
+
+    public SecurityToken retrieveToken(Message message) {
+        boolean cacheIssuedToken =
+            SecurityUtils.getSecurityPropertyBoolean(SecurityConstants.CACHE_ISSUED_TOKEN_IN_ENDPOINT,
+                                              message,
+                                              true);
+        SecurityToken tok = null;
+        if (cacheIssuedToken) {
+            tok = (SecurityToken)message.getContextualProperty(SecurityConstants.TOKEN);
+            if (tok == null) {
+                String tokId = (String)message.getContextualProperty(SecurityConstants.TOKEN_ID);
+                if (tokId != null) {
+                    tok = TokenStoreUtils.getTokenStore(message).getToken(tokId);
+                }
+            }
+        } else {
+            tok = (SecurityToken)message.get(SecurityConstants.TOKEN);
+            if (tok == null) {
+                String tokId = (String)message.get(SecurityConstants.TOKEN_ID);
+                if (tokId != null) {
+                    tok = TokenStoreUtils.getTokenStore(message).getToken(tokId);
+                }
+            }
+        }
+        return tok;
+    }
+
+    public SecurityToken retrieveToken(Message message, Element delegationToken, String cacheKey) {
+        if (delegationToken == null) {
+            return null;
+        }
+        TokenStore tokenStore = TokenStoreUtils.getTokenStore(message);
+
+        // See if the token corresponding to the delegation Token is stored in the cache
+        // and if it points to an issued token
+        String id = getIdFromToken(delegationToken);
+        SecurityToken cachedToken = tokenStore.getToken(id);
+        if (cachedToken != null) {
+            Map<String, Object> properties = cachedToken.getProperties();
+            if (properties != null && properties.containsKey(cacheKey)) {
+                String associatedToken = (String)properties.get(cacheKey);
+                SecurityToken issuedToken = tokenStore.getToken(associatedToken);
+                if (issuedToken != null) {
+                    return issuedToken;
+                }
+            }
+        }
+
+        return null;
+    }
+
+    public void storeToken(Message message, SecurityToken securityToken) {
+        boolean cacheIssuedToken =
+            SecurityUtils.getSecurityPropertyBoolean(SecurityConstants.CACHE_ISSUED_TOKEN_IN_ENDPOINT,
+                                              message,
+                                              true)
+                && !isOneTimeUse(securityToken);
+        if (cacheIssuedToken) {
+            message.getExchange().getEndpoint().put(SecurityConstants.TOKEN, securityToken);
+            message.getExchange().put(SecurityConstants.TOKEN, securityToken);
+            message.put(SecurityConstants.TOKEN_ELEMENT, securityToken.getToken());
+            message.getExchange().put(SecurityConstants.TOKEN_ID, securityToken.getId());
+            message.getExchange().getEndpoint().put(SecurityConstants.TOKEN_ID,
+                                                    securityToken.getId());
+        } else {
+            message.put(SecurityConstants.TOKEN, securityToken);
+            message.put(SecurityConstants.TOKEN_ID, securityToken.getId());
+            message.put(SecurityConstants.TOKEN_ELEMENT, securityToken.getToken());
+        }
+        // ?
+        TokenStoreUtils.getTokenStore(message).add(securityToken);
+    }
+
+    public void storeToken(Message message, Element delegationToken, String secTokenId, String cacheKey) {
+        if (secTokenId == null || delegationToken == null) {
+            return;
+        }
+
+        TokenStore tokenStore = TokenStoreUtils.getTokenStore(message);
+
+        String id = getIdFromToken(delegationToken);
+        SecurityToken cachedToken = tokenStore.getToken(id);
+        if (cachedToken == null) {
+            cachedToken = new SecurityToken(id);
+            cachedToken.setToken(delegationToken);
+        }
+        Map<String, Object> properties = cachedToken.getProperties();
+        if (properties == null) {
+            properties = new HashMap<>();
+            cachedToken.setProperties(properties);
+        }
+        properties.put(cacheKey, secTokenId);
+        tokenStore.add(cachedToken);
+    }
+
+    public void removeToken(Message message, SecurityToken securityToken) {
+        // Remove token from cache
+        message.getExchange().getEndpoint().remove(SecurityConstants.TOKEN);
+        message.getExchange().getEndpoint().remove(SecurityConstants.TOKEN_ID);
+        message.getExchange().remove(SecurityConstants.TOKEN_ID);
+        message.getExchange().remove(SecurityConstants.TOKEN);
+        if (securityToken != null) {
+            TokenStoreUtils.getTokenStore(message).remove(securityToken.getId());
+        }
+    }
+
+    // Check to see if the received token is a SAML2 Token with "OneTimeUse" set. If so,
+    // it should not be cached on the endpoint, but only on the message.
+    private static boolean isOneTimeUse(SecurityToken issuedToken) {
+        Element token = issuedToken.getToken();
+        if (token != null && "Assertion".equals(token.getLocalName())
+            && WSConstants.SAML2_NS.equals(token.getNamespaceURI())) {
+            try {
+                SamlAssertionWrapper assertion = new SamlAssertionWrapper(token);
+
+                if (assertion.getSaml2().getConditions() != null
+                    && assertion.getSaml2().getConditions().getOneTimeUse() != null) {
+                    return true;
+                }
+            } catch (WSSecurityException ex) {
+                throw new Fault(ex);
+            }
+        }
+
+        return false;
+    }
+
+    private static String getIdFromToken(Element token) {
+        if (token != null) {
+            // Try to find the "Id" on the token.
+            if (token.hasAttributeNS(WSConstants.WSU_NS, "Id")) {
+                return token.getAttributeNS(WSConstants.WSU_NS, "Id");
+            } else if (token.hasAttributeNS(null, "ID")) {
+                return token.getAttributeNS(null, "ID");
+            } else if (token.hasAttributeNS(null, "AssertionID")) {
+                return token.getAttributeNS(null, "AssertionID");
+            }
+        }
+        return "";
+    }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cxf/blob/4b4bb843/rt/ws/security/src/main/java/org/apache/cxf/ws/security/trust/STSTokenCacher.java
----------------------------------------------------------------------
diff --git a/rt/ws/security/src/main/java/org/apache/cxf/ws/security/trust/STSTokenCacher.java b/rt/ws/security/src/main/java/org/apache/cxf/ws/security/trust/STSTokenCacher.java
new file mode 100644
index 0000000..9a5d128
--- /dev/null
+++ b/rt/ws/security/src/main/java/org/apache/cxf/ws/security/trust/STSTokenCacher.java
@@ -0,0 +1,59 @@
+/**
+ * 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.cxf.ws.security.trust;
+
+import org.w3c.dom.Element;
+
+import org.apache.cxf.message.Message;
+import org.apache.cxf.ws.security.tokenstore.SecurityToken;
+
+/**
+ * This interface allows you to plug in some custom logic when storing/retrieving STS tokens in/from the cache
+ */
+public interface STSTokenCacher {
+
+    /**
+     * Retrieve a cached STS token
+     */
+    SecurityToken retrieveToken(Message message);
+
+    /**
+     * Retrieve a cached STS token for a given delegation token Element
+     */
+    SecurityToken retrieveToken(Message message, Element delegationToken, String cacheKey);
+
+    /**
+     * Store a token in the cache
+     */
+    void storeToken(Message message, SecurityToken securityToken);
+
+    /**
+     * Store a given delegation token in the cache (or update it if it's already there), with a reference to the
+     * security token obtained from the STS.
+     */
+    void storeToken(Message message, Element delegationToken, String secTokenId, String cacheKey);
+
+    /**
+     * Remove a cached STS token
+     */
+    void removeToken(Message message, SecurityToken securityToken);
+
+}
+

http://git-wip-us.apache.org/repos/asf/cxf/blob/4b4bb843/rt/ws/security/src/main/java/org/apache/cxf/ws/security/trust/STSTokenRetriever.java
----------------------------------------------------------------------
diff --git a/rt/ws/security/src/main/java/org/apache/cxf/ws/security/trust/STSTokenRetriever.java b/rt/ws/security/src/main/java/org/apache/cxf/ws/security/trust/STSTokenRetriever.java
index 41556a7..cf25b27 100644
--- a/rt/ws/security/src/main/java/org/apache/cxf/ws/security/trust/STSTokenRetriever.java
+++ b/rt/ws/security/src/main/java/org/apache/cxf/ws/security/trust/STSTokenRetriever.java
@@ -19,7 +19,6 @@
 
 package org.apache.cxf.ws.security.trust;
 
-import java.util.HashMap;
 import java.util.Map;
 import java.util.logging.Level;
 import java.util.logging.Logger;
@@ -33,11 +32,6 @@ import org.apache.cxf.rt.security.utils.SecurityUtils;
 import org.apache.cxf.ws.addressing.AddressingProperties;
 import org.apache.cxf.ws.security.SecurityConstants;
 import org.apache.cxf.ws.security.tokenstore.SecurityToken;
-import org.apache.cxf.ws.security.tokenstore.TokenStore;
-import org.apache.cxf.ws.security.tokenstore.TokenStoreUtils;
-import org.apache.wss4j.common.ext.WSSecurityException;
-import org.apache.wss4j.common.saml.SamlAssertionWrapper;
-import org.apache.wss4j.dom.WSConstants;
 import org.apache.wss4j.policy.model.Trust10;
 import org.apache.wss4j.policy.model.Trust13;
 
@@ -53,63 +47,23 @@ public final class STSTokenRetriever {
     }
 
     public static SecurityToken getToken(Message message, TokenRequestParams params) {
-        SecurityToken tok = retrieveCachedToken(message);
-        if (tok == null) {
-            tok = issueToken(message, params);
-        } else {
-            tok = renewToken(message, tok, params);
-        }
+        return getToken(message, params, new DefaultSTSTokenCacher());
+    }
 
-        boolean cacheIssuedToken =
-            SecurityUtils.getSecurityPropertyBoolean(SecurityConstants.CACHE_ISSUED_TOKEN_IN_ENDPOINT,
-                                              message,
-                                              true)
-                && !isOneTimeUse(tok);
-        if (cacheIssuedToken) {
-            message.getExchange().getEndpoint().put(SecurityConstants.TOKEN, tok);
-            message.getExchange().put(SecurityConstants.TOKEN, tok);
-            message.put(SecurityConstants.TOKEN_ELEMENT, tok.getToken());
-            message.getExchange().put(SecurityConstants.TOKEN_ID, tok.getId());
-            message.getExchange().getEndpoint().put(SecurityConstants.TOKEN_ID,
-                                                          tok.getId());
+    public static SecurityToken getToken(Message message, TokenRequestParams params, STSTokenCacher tokenCacher) {
+        SecurityToken tok = tokenCacher.retrieveToken(message);
+        if (tok == null) {
+            tok = issueToken(message, params, tokenCacher);
         } else {
-            message.put(SecurityConstants.TOKEN, tok);
-            message.put(SecurityConstants.TOKEN_ID, tok.getId());
-            message.put(SecurityConstants.TOKEN_ELEMENT, tok.getToken());
+            tok = renewToken(message, tok, params, tokenCacher);
         }
-        // ?
-        TokenStoreUtils.getTokenStore(message).add(tok);
 
-        return tok;
-    }
+        tokenCacher.storeToken(message, tok);
 
-    private static SecurityToken retrieveCachedToken(Message message) {
-        boolean cacheIssuedToken =
-            SecurityUtils.getSecurityPropertyBoolean(SecurityConstants.CACHE_ISSUED_TOKEN_IN_ENDPOINT,
-                                              message,
-                                              true);
-        SecurityToken tok = null;
-        if (cacheIssuedToken) {
-            tok = (SecurityToken)message.getContextualProperty(SecurityConstants.TOKEN);
-            if (tok == null) {
-                String tokId = (String)message.getContextualProperty(SecurityConstants.TOKEN_ID);
-                if (tokId != null) {
-                    tok = TokenStoreUtils.getTokenStore(message).getToken(tokId);
-                }
-            }
-        } else {
-            tok = (SecurityToken)message.get(SecurityConstants.TOKEN);
-            if (tok == null) {
-                String tokId = (String)message.get(SecurityConstants.TOKEN_ID);
-                if (tokId != null) {
-                    tok = TokenStoreUtils.getTokenStore(message).getToken(tokId);
-                }
-            }
-        }
         return tok;
     }
 
-    private static SecurityToken issueToken(Message message, TokenRequestParams params) {
+    private static SecurityToken issueToken(Message message, TokenRequestParams params, STSTokenCacher tokenCacher) {
         AddressingProperties maps =
             (AddressingProperties)message
                 .get("javax.xml.ws.addressing.context.outbound");
@@ -152,20 +106,27 @@ public final class STSTokenRetriever {
                 Element onBehalfOfToken = client.getOnBehalfOfToken();
                 Element actAsToken = client.getActAsToken();
 
-                SecurityToken secToken =
-                    handleDelegation(
-                                     message, onBehalfOfToken, actAsToken, appliesTo,
-                                     enableAppliesTo
-                    );
+                String key = appliesTo;
+                if (!enableAppliesTo || key == null || "".equals(key)) {
+                    key = ASSOCIATED_TOKEN;
+                }
+                // See if the token corresponding to the OnBehalfOf/ActAs Token is stored in the cache
+                // and if it points to an issued token
+                SecurityToken secToken = tokenCacher.retrieveToken(message, onBehalfOfToken, key);
+                if (secToken == null) {
+                    secToken = tokenCacher.retrieveToken(message, actAsToken, key);
+                }
                 if (secToken != null) {
                     // Check to see whether the delegated token needs to be renewed
-                    secToken = renewToken(message, secToken, params);
+                    secToken = renewToken(message, secToken, params, tokenCacher);
                 } else {
                     secToken = getTokenFromSTS(message, client, maps, appliesTo, params);
                 }
-                storeDelegationTokens(
-                                      message, secToken, onBehalfOfToken, actAsToken, appliesTo,
-                                      enableAppliesTo);
+
+                if (secToken != null) {
+                    tokenCacher.storeToken(message, onBehalfOfToken, secToken.getId(), key);
+                    tokenCacher.storeToken(message, actAsToken, secToken.getId(), key);
+                }
                 return secToken;
             } catch (RuntimeException e) {
                 throw e;
@@ -183,7 +144,8 @@ public final class STSTokenRetriever {
     private static SecurityToken renewToken(
                                      Message message,
                                      SecurityToken tok,
-                                     TokenRequestParams params) {
+                                     TokenRequestParams params,
+                                     STSTokenCacher tokenCacher) {
         String imminentExpiryValue =
             (String)SecurityUtils.getSecurityPropertyValue(SecurityConstants.STS_TOKEN_IMMINENT_EXPIRY_VALUE, 
                                                            message);
@@ -198,17 +160,13 @@ public final class STSTokenRetriever {
         }
 
         // Remove token from cache
-        message.getExchange().getEndpoint().remove(SecurityConstants.TOKEN);
-        message.getExchange().getEndpoint().remove(SecurityConstants.TOKEN_ID);
-        message.getExchange().remove(SecurityConstants.TOKEN_ID);
-        message.getExchange().remove(SecurityConstants.TOKEN);
-        TokenStoreUtils.getTokenStore(message).remove(tok.getId());
+        tokenCacher.removeToken(message, tok);
 
         // If the user has explicitly disabled Renewing then we can't renew a token,
         // so just get a new one
         STSClient client = STSUtils.getClientWithIssuer(message, "sts", params.getIssuer());
         if (!client.isAllowRenewing()) {
-            return issueToken(message, params);
+            return issueToken(message, params, tokenCacher);
         }
 
         AddressingProperties maps =
@@ -241,7 +199,7 @@ public final class STSTokenRetriever {
                                               SecurityConstants.STS_ISSUE_AFTER_FAILED_RENEW, message, true);
                 if (issueAfterFailedRenew) {
                     // Perhaps the STS does not support renewing, so try to issue a new token
-                    return issueToken(message, params);
+                    return issueToken(message, params, tokenCacher);
                 } else {
                     throw ex;
                 }
@@ -252,7 +210,7 @@ public final class STSTokenRetriever {
                                               SecurityConstants.STS_ISSUE_AFTER_FAILED_RENEW, message, true);
                 if (issueAfterFailedRenew) {
                     // Perhaps the STS does not support renewing, so try to issue a new token
-                    return issueToken(message, params);
+                    return issueToken(message, params, tokenCacher);
                 } else {
                     throw new Fault(ex);
                 }
@@ -265,27 +223,6 @@ public final class STSTokenRetriever {
         }
     }
 
-    // Check to see if the received token is a SAML2 Token with "OneTimeUse" set. If so,
-    // it should not be cached on the endpoint, but only on the message.
-    private static boolean isOneTimeUse(SecurityToken issuedToken) {
-        Element token = issuedToken.getToken();
-        if (token != null && "Assertion".equals(token.getLocalName())
-            && WSConstants.SAML2_NS.equals(token.getNamespaceURI())) {
-            try {
-                SamlAssertionWrapper assertion = new SamlAssertionWrapper(token);
-
-                if (assertion.getSaml2().getConditions() != null
-                    && assertion.getSaml2().getConditions().getOneTimeUse() != null) {
-                    return true;
-                }
-            } catch (WSSecurityException ex) {
-                throw new Fault(ex);
-            }
-        }
-
-        return false;
-    }
-
     private static void mapSecurityProps(Message message, Map<String, Object> ctx) {
         for (String s : SecurityConstants.ALL_PROPERTIES) {
             Object v = message.getContextualProperty(s + ".it");
@@ -298,118 +235,7 @@ public final class STSTokenRetriever {
         }
     }
 
-    /**
-     * Parse ActAs/OnBehalfOf appropriately. See if the required token is stored in the cache.
-     */
-    private static SecurityToken handleDelegation(
-                                           Message message,
-                                           Element onBehalfOfToken,
-                                           Element actAsToken,
-                                           String appliesTo,
-                                           boolean enableAppliesTo) throws Exception {
-        TokenStore tokenStore = TokenStoreUtils.getTokenStore(message);
-        String key = appliesTo;
-        if (!enableAppliesTo || key == null || "".equals(key)) {
-            key = ASSOCIATED_TOKEN;
-        }
-        // See if the token corresponding to the OnBehalfOf Token is stored in the cache
-        // and if it points to an issued token
-        if (onBehalfOfToken != null) {
-            String id = getIdFromToken(onBehalfOfToken);
-            SecurityToken cachedToken = tokenStore.getToken(id);
-            if (cachedToken != null) {
-                Map<String, Object> properties = cachedToken.getProperties();
-                if (properties != null && properties.containsKey(key)) {
-                    String associatedToken = (String)properties.get(key);
-                    SecurityToken issuedToken = tokenStore.getToken(associatedToken);
-                    if (issuedToken != null) {
-                        return issuedToken;
-                    }
-                }
-            }
-        }
-
-        // See if the token corresponding to the ActAs Token is stored in the cache
-        // and if it points to an issued token
-        if (actAsToken != null) {
-            String id = getIdFromToken(actAsToken);
-            SecurityToken cachedToken = tokenStore.getToken(id);
-            if (cachedToken != null) {
-                Map<String, Object>  properties = cachedToken.getProperties();
-                if (properties != null && properties.containsKey(key)) {
-                    String associatedToken = (String)properties.get(key);
-                    SecurityToken issuedToken = tokenStore.getToken(associatedToken);
-                    if (issuedToken != null) {
-                        return issuedToken;
-                    }
-                }
-            }
-        }
-        return null;
-    }
-
-    private static String getIdFromToken(Element token) {
-        if (token != null) {
-            // Try to find the "Id" on the token.
-            if (token.hasAttributeNS(WSConstants.WSU_NS, "Id")) {
-                return token.getAttributeNS(WSConstants.WSU_NS, "Id");
-            } else if (token.hasAttributeNS(null, "ID")) {
-                return token.getAttributeNS(null, "ID");
-            } else if (token.hasAttributeNS(null, "AssertionID")) {
-                return token.getAttributeNS(null, "AssertionID");
-            }
-        }
-        return "";
-    }
-
-    private static void storeDelegationTokens(
-                                       Message message,
-                                       SecurityToken issuedToken,
-                                       Element onBehalfOfToken,
-                                       Element actAsToken,
-                                       String appliesTo,
-                                       boolean enableAppliesTo) throws Exception {
-        if (issuedToken == null) {
-            return;
-        }
-        TokenStore tokenStore = TokenStoreUtils.getTokenStore(message);
-        String key = appliesTo;
-        if (!enableAppliesTo || key == null || "".equals(key)) {
-            key = ASSOCIATED_TOKEN;
-        }
-        if (onBehalfOfToken != null) {
-            String id = getIdFromToken(onBehalfOfToken);
-            SecurityToken cachedToken = tokenStore.getToken(id);
-            if (cachedToken == null) {
-                cachedToken = new SecurityToken(id);
-                cachedToken.setToken(onBehalfOfToken);
-            }
-            Map<String, Object> properties = cachedToken.getProperties();
-            if (properties == null) {
-                properties = new HashMap<>();
-                cachedToken.setProperties(properties);
-            }
-            properties.put(key, issuedToken.getId());
-            tokenStore.add(cachedToken);
-        }
-        if (actAsToken != null) {
-            String id = getIdFromToken(actAsToken);
-            SecurityToken cachedToken = tokenStore.getToken(id);
-            if (cachedToken == null) {
-                cachedToken = new SecurityToken(id);
-                cachedToken.setToken(actAsToken);
-            }
-            Map<String, Object>  properties = cachedToken.getProperties();
-            if (properties == null) {
-                properties = new HashMap<>();
-                cachedToken.setProperties(properties);
-            }
-            properties.put(key, issuedToken.getId());
-            tokenStore.add(cachedToken);
-        }
-    }
-
-    private static SecurityToken getTokenFromSTS(Message message, STSClient client,
+    private static SecurityToken getTokenFromSTS(STSClient client,
                                           AddressingProperties maps, String appliesTo,
                                           TokenRequestParams params) throws Exception {
         client.setTrust(params.getTrust10());
@@ -483,4 +309,4 @@ public final class STSTokenRetriever {
             this.claims = claims;
         }
     }
-}
\ No newline at end of file
+}