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 2011/10/04 14:00:43 UTC

svn commit: r1178763 - in /cxf/trunk/rt/ws/security/src/main/java/org/apache/cxf/ws/security: SecurityConstants.java policy/interceptors/IssuedTokenInterceptorProvider.java trust/STSClient.java trust/delegation/WSSUsernameCallbackHandler.java

Author: coheigea
Date: Tue Oct  4 12:00:43 2011
New Revision: 1178763

URL: http://svn.apache.org/viewvc?rev=1178763&view=rev
Log:
Added the ability to use the STSClient in an intermediary.
 - There is a new configuration property to disable storing issued tokens per exchange
 - Caching is enabled for OnBehalfOf or ActAs tokens


Conflicts:

	rt/ws/security/src/main/java/org/apache/cxf/ws/security/policy/interceptors/IssuedTokenInterceptorProvider.java

Modified:
    cxf/trunk/rt/ws/security/src/main/java/org/apache/cxf/ws/security/SecurityConstants.java
    cxf/trunk/rt/ws/security/src/main/java/org/apache/cxf/ws/security/policy/interceptors/IssuedTokenInterceptorProvider.java
    cxf/trunk/rt/ws/security/src/main/java/org/apache/cxf/ws/security/trust/STSClient.java
    cxf/trunk/rt/ws/security/src/main/java/org/apache/cxf/ws/security/trust/delegation/WSSUsernameCallbackHandler.java

Modified: cxf/trunk/rt/ws/security/src/main/java/org/apache/cxf/ws/security/SecurityConstants.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/ws/security/src/main/java/org/apache/cxf/ws/security/SecurityConstants.java?rev=1178763&r1=1178762&r2=1178763&view=diff
==============================================================================
--- cxf/trunk/rt/ws/security/src/main/java/org/apache/cxf/ws/security/SecurityConstants.java (original)
+++ cxf/trunk/rt/ws/security/src/main/java/org/apache/cxf/ws/security/SecurityConstants.java Tue Oct  4 12:00:43 2011
@@ -112,6 +112,14 @@ public final class SecurityConstants {
     
     public static final String KERBEROS_CLIENT = "ws-security.kerberos.client";
     
+    /**
+     * Set this to "false" to not cache a SecurityToken per proxy object in the 
+     * IssuedTokenInterceptorProvider. This should be done if a token is being retrieved
+     * from an STS in an intermediary. The default value is "true".
+     */
+    public static final String CACHE_ISSUED_TOKEN_IN_ENDPOINT = 
+        "ws-security.cache.issued.token.in.endpoint";
+    
     public static final Set<String> ALL_PROPERTIES;
     
     static {
@@ -125,7 +133,7 @@ public final class SecurityConstants {
             SAML1_TOKEN_VALIDATOR, SAML2_TOKEN_VALIDATOR, TIMESTAMP_TOKEN_VALIDATOR,
             SIGNATURE_TOKEN_VALIDATOR, IS_BSP_COMPLIANT, TIMESTAMP_FUTURE_TTL,
             BST_TOKEN_VALIDATOR, SAML_CALLBACK_HANDLER, STS_TOKEN_ON_BEHALF_OF,
-            KERBEROS_CLIENT, SCT_TOKEN_VALIDATOR
+            KERBEROS_CLIENT, SCT_TOKEN_VALIDATOR, CACHE_ISSUED_TOKEN_IN_ENDPOINT
         }));
         ALL_PROPERTIES = Collections.unmodifiableSet(s);
     }

Modified: cxf/trunk/rt/ws/security/src/main/java/org/apache/cxf/ws/security/policy/interceptors/IssuedTokenInterceptorProvider.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/ws/security/src/main/java/org/apache/cxf/ws/security/policy/interceptors/IssuedTokenInterceptorProvider.java?rev=1178763&r1=1178762&r2=1178763&view=diff
==============================================================================
--- cxf/trunk/rt/ws/security/src/main/java/org/apache/cxf/ws/security/policy/interceptors/IssuedTokenInterceptorProvider.java (original)
+++ cxf/trunk/rt/ws/security/src/main/java/org/apache/cxf/ws/security/policy/interceptors/IssuedTokenInterceptorProvider.java Tue Oct  4 12:00:43 2011
@@ -25,11 +25,15 @@ import java.util.Arrays;
 import java.util.Collection;
 import java.util.List;
 import java.util.Map;
+import java.util.Properties;
+
+import org.w3c.dom.Element;
 
 import org.apache.cxf.endpoint.Endpoint;
 import org.apache.cxf.helpers.CastUtils;
 import org.apache.cxf.interceptor.Fault;
 import org.apache.cxf.message.Message;
+import org.apache.cxf.message.MessageUtils;
 import org.apache.cxf.phase.AbstractPhaseInterceptor;
 import org.apache.cxf.phase.Phase;
 import org.apache.cxf.service.model.EndpointInfo;
@@ -65,6 +69,9 @@ import org.apache.ws.security.util.WSSec
  * 
  */
 public class IssuedTokenInterceptorProvider extends AbstractPolicyInterceptorProvider {
+    
+    private static final String ASSOCIATED_TOKEN = 
+        IssuedTokenInterceptorProvider.class.getName() + "-" + "Associated_Token";
 
     public IssuedTokenInterceptorProvider() {
         super(Arrays.asList(SP11Constants.ISSUED_TOKEN, SP12Constants.ISSUED_TOKEN));
@@ -124,13 +131,7 @@ public class IssuedTokenInterceptorProvi
                 if (isRequestor(message)) {
                     IssuedToken itok = (IssuedToken)ais.iterator().next().getAssertion();
                     
-                    SecurityToken tok = (SecurityToken)message.getContextualProperty(SecurityConstants.TOKEN);
-                    if (tok == null) {
-                        String tokId = (String)message.getContextualProperty(SecurityConstants.TOKEN_ID);
-                        if (tokId != null) {
-                            tok = getTokenStore(message).getToken(tokId);
-                        }
-                    }
+                    SecurityToken tok = retrieveCachedToken(message);
                     if (tok == null) {
                         STSClient client = STSUtils.getClient(message, "sts", itok);
                         AddressingProperties maps =
@@ -156,22 +157,28 @@ public class IssuedTokenInterceptorProvi
                                 Map<String, Object> ctx = client.getRequestContext();
                                 mapSecurityProps(message, ctx);
                             
+                                Object o = message.getContextualProperty(SecurityConstants.STS_APPLIES_TO);
+                                String appliesTo = o == null ? null : o.toString();
+                                appliesTo = appliesTo == null 
+                                    ? message.getContextualProperty(Message.ENDPOINT_ADDRESS).toString()
+                                        : appliesTo;
+                                boolean enableAppliesTo = client.isEnableAppliesTo();
+                                
                                 client.setMessage(message);
-                                client.setTrust(getTrust10(aim));
-                                client.setTrust(getTrust13(aim));
-                                client.setTemplate(itok.getRstTemplate());
-                                if (maps == null) {
-                                    tok = client.requestSecurityToken();
-                                } else {
-                                    Object o = message
-                                        .getContextualProperty(SecurityConstants.STS_APPLIES_TO);
-                                    String s = o == null ? null : o.toString();
-                                    s = s == null 
-                                        ? message.getContextualProperty(Message.ENDPOINT_ADDRESS).toString()
-                                            : s;
-                                    client.setAddressingNamespace(maps.getNamespaceURI());
-                                    tok = client.requestSecurityToken(s);
+                                Element onBehalfOfToken = client.getOnBehalfOfToken();
+                                Element actAsToken = client.getActAsToken();
+                                
+                                SecurityToken secToken = 
+                                    handleDelegation(
+                                        message, onBehalfOfToken, actAsToken, appliesTo, enableAppliesTo
+                                    );
+                                if (secToken == null) {
+                                    secToken = getTokenFromSTS(message, client, aim, maps, itok, appliesTo);
                                 }
+                                tok = secToken;
+                                storeDelegationTokens(
+                                    message, tok, onBehalfOfToken, actAsToken, appliesTo, enableAppliesTo
+                                );
                             } catch (RuntimeException e) {
                                 throw e;
                             } catch (Exception e) {
@@ -190,10 +197,17 @@ public class IssuedTokenInterceptorProvi
                         for (AssertionInfo ai : ais) {
                             ai.setAsserted(true);
                         }
-                        message.getExchange().get(Endpoint.class).put(SecurityConstants.TOKEN_ID, 
-                                                                      tok.getId());
-                        message.getExchange().put(SecurityConstants.TOKEN_ID, 
-                                                  tok.getId());
+                        boolean cacheIssuedToken = 
+                            MessageUtils.getContextualBoolean(
+                                message, SecurityConstants.CACHE_ISSUED_TOKEN_IN_ENDPOINT, true
+                            );
+                        if (cacheIssuedToken) {
+                            message.getExchange().get(Endpoint.class).put(SecurityConstants.TOKEN_ID, 
+                                                                          tok.getId());
+                            message.getExchange().put(SecurityConstants.TOKEN_ID, tok.getId());
+                        } else {
+                            message.put(SecurityConstants.TOKEN_ID, tok.getId());
+                        }
                         getTokenStore(message).add(tok);
                     }
                 } else {
@@ -219,6 +233,156 @@ public class IssuedTokenInterceptorProvi
             return (Trust13)ais.iterator().next().getAssertion();
         }
         
+        private SecurityToken retrieveCachedToken(Message message) {
+            boolean cacheIssuedToken = 
+                MessageUtils.getContextualBoolean(
+                    message, SecurityConstants.CACHE_ISSUED_TOKEN_IN_ENDPOINT, 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 = getTokenStore(message).getToken(tokId);
+                    }
+                }
+            }
+            return tok;
+        }
+        
+        /**
+         * Parse ActAs/OnBehalfOf appropriately. See if the required token is stored in the cache.
+         */
+        private SecurityToken handleDelegation(
+            Message message, 
+            Element onBehalfOfToken,
+            Element actAsToken,
+            String appliesTo,
+            boolean enableAppliesTo
+        ) throws Exception {
+            TokenStore tokenStore = 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) {
+                    Properties properties = cachedToken.getProperties();
+                    if (properties != null && properties.containsKey(key)) {
+                        String associatedToken = properties.getProperty(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) {
+                    Properties properties = cachedToken.getProperties();
+                    if (properties != null && properties.containsKey(key)) {
+                        String associatedToken = properties.getProperty(key);
+                        SecurityToken issuedToken = tokenStore.getToken(associatedToken);
+                        if (issuedToken != null) {
+                            return issuedToken;
+                        }
+                    }
+                }
+            }
+            return null;
+        }
+        
+        private 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 void storeDelegationTokens(
+            Message message,
+            SecurityToken issuedToken,
+            Element onBehalfOfToken,
+            Element actAsToken,
+            String appliesTo,
+            boolean enableAppliesTo
+        ) throws Exception {
+            if (issuedToken == null) {
+                return;
+            }
+            TokenStore tokenStore = 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);
+                }
+                Properties properties = cachedToken.getProperties();
+                if (properties == null) {
+                    properties = new Properties();
+                    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);
+                }
+                Properties properties = cachedToken.getProperties();
+                if (properties == null) {
+                    properties = new Properties();
+                    cachedToken.setProperties(properties);
+                }
+                properties.put(key, issuedToken.getId());
+                tokenStore.add(cachedToken);
+            }
+        }
+        
+        private SecurityToken getTokenFromSTS(
+            Message message,
+            STSClient client,
+            AssertionInfoMap aim,
+            AddressingProperties maps,
+            IssuedToken itok,
+            String appliesTo
+        ) throws Exception {
+            client.setTrust(getTrust10(aim));
+            client.setTrust(getTrust13(aim));
+            client.setTemplate(itok.getRstTemplate());
+            if (maps == null) {
+                return client.requestSecurityToken();
+            } else {
+                client.setAddressingNamespace(maps.getNamespaceURI());
+                return client.requestSecurityToken(appliesTo);
+            }
+        }
+        
     }
     
     static class IssuedTokenInInterceptor extends AbstractPhaseInterceptor<Message> {

Modified: cxf/trunk/rt/ws/security/src/main/java/org/apache/cxf/ws/security/trust/STSClient.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/ws/security/src/main/java/org/apache/cxf/ws/security/trust/STSClient.java?rev=1178763&r1=1178762&r2=1178763&view=diff
==============================================================================
--- cxf/trunk/rt/ws/security/src/main/java/org/apache/cxf/ws/security/trust/STSClient.java (original)
+++ cxf/trunk/rt/ws/security/src/main/java/org/apache/cxf/ws/security/trust/STSClient.java Tue Oct  4 12:00:43 2011
@@ -616,7 +616,12 @@ public class STSClient implements Config
         if (enableAppliesTo) {
             addAppliesTo(writer, appliesTo);
         }
-        addOnBehalfOf(writer);
+        Element onBehalfOfToken = getOnBehalfOfToken();
+        if (onBehalfOfToken != null) {
+            writer.writeStartElement("wst", "OnBehalfOf", namespace);
+            StaxUtils.copy(onBehalfOfToken, writer);
+            writer.writeEndElement();
+        }
         if (sptt == null) {
             addTokenType(writer);
         }
@@ -651,8 +656,13 @@ public class STSClient implements Config
             StaxUtils.copy(el, writer);
             writer.writeEndElement();
         }
-        
-        addActAs(writer);
+
+        Element actAsSecurityToken = getActAsToken();
+        if (actAsSecurityToken != null) {
+            writer.writeStartElement(STSUtils.WST_NS_08_02, "ActAs");
+            StaxUtils.copy(actAsSecurityToken, writer);
+            writer.writeEndElement();
+        }
         
         writer.writeEndElement();
 
@@ -672,6 +682,42 @@ public class STSClient implements Config
         return token;
     }
     
+    /**
+     * Get the "OnBehalfOf" element to be sent to the STS.
+     */
+    public Element getOnBehalfOfToken() throws Exception {
+        return getDelegationSecurityToken(this.onBehalfOf);
+    }
+    
+    /**
+     * Get the "ActAs" element to be sent to the STS.
+     */
+    public Element getActAsToken() throws Exception {
+        return getDelegationSecurityToken(this.actAs);
+    }
+    
+    private Element getDelegationSecurityToken(Object delegationObject) throws Exception {
+        if (delegationObject != null) {
+            final boolean isString = delegationObject instanceof String;
+            final boolean isElement = delegationObject instanceof Element; 
+            final boolean isCallbackHandler = delegationObject instanceof CallbackHandler;
+            if (isString || isElement || isCallbackHandler) {
+                if (isString) {
+                    final Document doc =
+                        DOMUtils.readXml(new StringReader((String) delegationObject));
+                    return doc.getDocumentElement();
+                } else if (isElement) {
+                    return (Element) delegationObject;
+                } else {
+                    DelegationCallback callback = new DelegationCallback(message);
+                    ((CallbackHandler)delegationObject).handle(new Callback[]{callback});
+                    return callback.getToken();
+                }
+            }
+        }
+        return null;
+    }
+    
     private byte[] writeElementsForRSTSymmetricKey(W3CDOMStreamWriter writer,
             boolean wroteKeySize) throws Exception {
         byte[] requestorEntropy = null;
@@ -743,35 +789,6 @@ public class STSClient implements Config
         writer.writeEndElement();
     }
     
-    private void addOnBehalfOf(W3CDOMStreamWriter writer) throws Exception {
-        if (this.onBehalfOf != null) {
-            final boolean isString = this.onBehalfOf instanceof String;
-            final boolean isElement = this.onBehalfOf instanceof Element; 
-            final boolean isCallbackHandler = this.onBehalfOf instanceof CallbackHandler;
-            if (isString || isElement || isCallbackHandler) {
-                final Element tokenElement;
-                
-                if (isString) {
-                    final Document acAsDoc =
-                        DOMUtils.readXml(new StringReader((String) this.onBehalfOf));
-                    tokenElement = acAsDoc.getDocumentElement();
-                } else if (isElement) {
-                    tokenElement = (Element)this.onBehalfOf;
-                } else {
-                    DelegationCallback callback = new DelegationCallback(message);
-                    ((CallbackHandler)onBehalfOf).handle(new Callback[]{callback});
-                    tokenElement = callback.getToken();
-                }
-                
-                if (tokenElement != null) {
-                    writer.writeStartElement("wst", "OnBehalfOf", namespace);
-                    StaxUtils.copy(tokenElement, writer);
-                    writer.writeEndElement();
-                }
-            }
-        }
-    }
-    
     private Element getDocumentElement(DOMSource ds) {
         Node nd = ds.getNode();
         if (nd instanceof Document) {
@@ -1081,35 +1098,6 @@ public class STSClient implements Config
         }
     }
 
-    private void addActAs(W3CDOMStreamWriter writer) throws Exception {
-        if (this.actAs != null) {
-            final boolean isString = this.actAs instanceof String;
-            final boolean isElement = this.actAs instanceof Element; 
-            final boolean isCallbackHandler = this.actAs instanceof CallbackHandler;
-            if (isString || isElement || isCallbackHandler) {
-                final Element tokenElement;
-                
-                if (isString) {
-                    final Document acAsDoc =
-                        DOMUtils.readXml(new StringReader((String) this.actAs));
-                    tokenElement = acAsDoc.getDocumentElement();
-                } else if (isElement) {
-                    tokenElement = (Element) this.actAs;
-                } else {
-                    DelegationCallback callback = new DelegationCallback(message);
-                    ((CallbackHandler)actAs).handle(new Callback[]{callback});
-                    tokenElement = callback.getToken();
-                }
-                
-                if (tokenElement != null) {
-                    writer.writeStartElement(STSUtils.WST_NS_08_02, "ActAs");
-                    StaxUtils.copy(tokenElement, writer);
-                    writer.writeEndElement();
-                }
-            }
-        }
-    }
-
     private SecurityToken createSecurityToken(Element el, byte[] requestorEntropy)
         throws WSSecurityException {
 

Modified: cxf/trunk/rt/ws/security/src/main/java/org/apache/cxf/ws/security/trust/delegation/WSSUsernameCallbackHandler.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/ws/security/src/main/java/org/apache/cxf/ws/security/trust/delegation/WSSUsernameCallbackHandler.java?rev=1178763&r1=1178762&r2=1178763&view=diff
==============================================================================
--- cxf/trunk/rt/ws/security/src/main/java/org/apache/cxf/ws/security/trust/delegation/WSSUsernameCallbackHandler.java (original)
+++ cxf/trunk/rt/ws/security/src/main/java/org/apache/cxf/ws/security/trust/delegation/WSSUsernameCallbackHandler.java Tue Oct  4 12:00:43 2011
@@ -26,13 +26,12 @@ import javax.security.auth.callback.Call
 import javax.security.auth.callback.UnsupportedCallbackException;
 
 import org.w3c.dom.Document;
-import org.w3c.dom.Element;
 import org.w3c.dom.Node;
 
 import org.apache.cxf.helpers.DOMUtils;
 import org.apache.cxf.message.Message;
 import org.apache.cxf.ws.security.SecurityConstants;
-import org.apache.ws.security.message.WSSecUsernameToken;
+import org.apache.ws.security.message.token.UsernameToken;
 
 /**
  * This CallbackHandler implementation obtains a username via the jaxws property 
@@ -58,8 +57,8 @@ public class WSSUsernameCallbackHandler 
                     } else {
                         doc = DOMUtils.createDocument();
                     }
-                    Element token = createWSSEUsernameToken(username, doc);
-                    callback.setToken(token);
+                    UsernameToken usernameToken = createWSSEUsernameToken(username, doc);
+                    callback.setToken(usernameToken.getElement());
                 }
             } else {
                 throw new UnsupportedCallbackException(callbacks[i], "Unrecognized Callback");
@@ -67,12 +66,14 @@ public class WSSUsernameCallbackHandler 
         }
     }
     
-    private Element createWSSEUsernameToken(String username, Document doc) {
-        WSSecUsernameToken builder = new WSSecUsernameToken();
-        builder.setPasswordType(null);
-        builder.setUserInfo(username, null);
-        builder.prepare(doc);
-        return builder.getUsernameTokenElement();
+    private UsernameToken createWSSEUsernameToken(String username, Document doc) {
+        UsernameToken usernameToken = new UsernameToken(true, doc, null);
+        usernameToken.setName(username);
+        usernameToken.addWSUNamespace();
+        usernameToken.addWSSENamespace();
+        usernameToken.setID("id-" + username);
+        
+        return usernameToken;
     }
     
 }