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 2013/09/05 12:38:30 UTC

svn commit: r1520272 - in /cxf/trunk/services/sts: sts-core/src/main/java/org/apache/cxf/sts/operation/ sts-core/src/main/java/org/apache/cxf/sts/request/ sts-core/src/test/java/org/apache/cxf/sts/operation/ systests/advanced/src/test/resources/org/apa...

Author: coheigea
Date: Thu Sep  5 10:38:30 2013
New Revision: 1520272

URL: http://svn.apache.org/r1520272
Log:
[CXF-5251] - Implement more stringent requirements on allowing OnBehalfOf/ActAs in the STS

Added:
    cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/request/DefaultDelegationHandler.java
    cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/request/DelegationHandler.java
    cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/request/HOKDelegationHandler.java
    cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/request/UsernameTokenDelegationHandler.java
    cxf/trunk/services/sts/systests/basic/src/test/java/org/apache/cxf/systest/sts/common/HOKDelegationHandler.java
Modified:
    cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/operation/AbstractOperation.java
    cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/operation/TokenIssueOperation.java
    cxf/trunk/services/sts/sts-core/src/test/java/org/apache/cxf/sts/operation/IssueOnbehalfofUnitTest.java
    cxf/trunk/services/sts/systests/advanced/src/test/resources/org/apache/cxf/systest/sts/deployment/cxf-sts.xml
    cxf/trunk/services/sts/systests/basic/src/test/java/org/apache/cxf/systest/sts/issueunit/IssueUnitTest.java
    cxf/trunk/services/sts/systests/basic/src/test/resources/org/apache/cxf/systest/sts/deployment/cxf-transport.xml
    cxf/trunk/services/sts/systests/basic/src/test/resources/org/apache/cxf/systest/sts/deployment/cxf-x509.xml

Modified: cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/operation/AbstractOperation.java
URL: http://svn.apache.org/viewvc/cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/operation/AbstractOperation.java?rev=1520272&r1=1520271&r2=1520272&view=diff
==============================================================================
--- cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/operation/AbstractOperation.java (original)
+++ cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/operation/AbstractOperation.java Thu Sep  5 10:38:30 2013
@@ -36,7 +36,6 @@ import javax.xml.ws.handler.MessageConte
 
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
-
 import org.apache.cxf.common.logging.LogUtils;
 import org.apache.cxf.helpers.DOMUtils;
 import org.apache.cxf.sts.IdentityMapper;
@@ -49,6 +48,8 @@ import org.apache.cxf.sts.claims.Request
 import org.apache.cxf.sts.claims.RequestClaimCollection;
 import org.apache.cxf.sts.event.AbstractSTSEvent;
 import org.apache.cxf.sts.event.STSEventListener;
+import org.apache.cxf.sts.request.DefaultDelegationHandler;
+import org.apache.cxf.sts.request.DelegationHandler;
 import org.apache.cxf.sts.request.KeyRequirements;
 import org.apache.cxf.sts.request.ReceivedToken;
 import org.apache.cxf.sts.request.ReceivedToken.STATE;
@@ -102,7 +103,16 @@ public abstract class AbstractOperation 
     protected TokenStore tokenStore;
     protected ClaimsManager claimsManager = new ClaimsManager();
     protected STSEventListener eventPublisher;
+    protected DelegationHandler delegationHandler = new DefaultDelegationHandler();
     
+    public DelegationHandler getDelegationHandler() {
+        return delegationHandler;
+    }
+
+    public void setDelegationHandler(DelegationHandler delegationHandler) {
+        this.delegationHandler = delegationHandler;
+    }
+
     public boolean isReturnReferences() {
         return returnReferences;
     }
@@ -609,7 +619,6 @@ public abstract class AbstractOperation 
                                 Relationship.class.getName(), relationship);
                     }
                 }
-    
                 if (relationship == null || relationship.getType().equals(Relationship.FED_TYPE_IDENTITY)) {
                     // federate identity
                     IdentityMapper identityMapper = null;

Modified: cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/operation/TokenIssueOperation.java
URL: http://svn.apache.org/viewvc/cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/operation/TokenIssueOperation.java?rev=1520272&r1=1520271&r2=1520272&view=diff
==============================================================================
--- cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/operation/TokenIssueOperation.java (original)
+++ cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/operation/TokenIssueOperation.java Thu Sep  5 10:38:30 2013
@@ -143,6 +143,15 @@ public class TokenIssueOperation extends
                     providerParameters.setPrincipal(wssecToken.getPrincipal());
                 }
             }
+            
+            if (delegationHandler != null) {
+                String appliesToAddress = extractAddressFromAppliesTo(tokenRequirements.getAppliesTo());
+                if (!delegationHandler.isDelegationAllowed(context, tokenRequirements, appliesToAddress)) {
+                    LOG.fine("Token Delegation (OnBehalfOf/ActAs) is not allowed for this particular token");
+                    throw new STSException("Token Delegation (OnBehalfOf/ActAs) is not allowed", 
+                                           STSException.REQUEST_FAILED);
+                }
+            }
 
             // Validate OnBehalfOf token if present
             if (providerParameters.getTokenRequirements().getOnBehalfOf() != null) {

Added: cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/request/DefaultDelegationHandler.java
URL: http://svn.apache.org/viewvc/cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/request/DefaultDelegationHandler.java?rev=1520272&view=auto
==============================================================================
--- cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/request/DefaultDelegationHandler.java (added)
+++ cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/request/DefaultDelegationHandler.java Thu Sep  5 10:38:30 2013
@@ -0,0 +1,151 @@
+/**
+ * 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.sts.request;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.xml.ws.WebServiceContext;
+
+import org.w3c.dom.Element;
+import org.apache.cxf.common.logging.LogUtils;
+import org.apache.wss4j.common.ext.WSSecurityException;
+import org.apache.wss4j.common.saml.SamlAssertionWrapper;
+import org.apache.wss4j.common.saml.builder.SAML1Constants;
+import org.apache.wss4j.common.saml.builder.SAML2Constants;
+import org.apache.wss4j.dom.WSConstants;
+import org.opensaml.saml1.core.AudienceRestrictionCondition;
+
+
+/**
+ * The Default DelegationHandler implementation. It disallows ActAs or OnBehalfOf for
+ * all cases apart from the case of a Bearer SAML Token. In addition, the AppliesTo
+ * address (if supplied) must match an AudienceRestriction address (if in token)
+ */
+public class DefaultDelegationHandler implements DelegationHandler {
+    
+    private static final Logger LOG = 
+        LogUtils.getL7dLogger(DefaultDelegationHandler.class);
+    
+    /**
+     * Returns true if delegation is allowed.
+     * @param context WebServiceContext
+     * @param tokenRequirements The parameters extracted from the request
+     * @param appliesToAddress The AppliesTo address (if any)
+     * @param onBehalfOf whether the token was received OnBehalfOf or ActAs
+     * @return true if delegation is allowed.
+     */
+    public boolean isDelegationAllowed(
+        WebServiceContext context,
+        TokenRequirements tokenRequirements, 
+        String appliesToAddress
+    ) {
+        if (tokenRequirements.getOnBehalfOf() != null 
+            && !isDelegationAllowed(context, tokenRequirements.getOnBehalfOf(), appliesToAddress)) {
+            return false;
+        }
+        
+        if (tokenRequirements.getActAs() != null 
+            && !isDelegationAllowed(context, tokenRequirements.getActAs(), appliesToAddress)) {
+            return false;
+        }
+        
+        return true;
+    }
+    
+    /**
+     * Is Delegation allowed for a particular token
+     */
+    protected boolean isDelegationAllowed(
+        WebServiceContext context,
+        ReceivedToken receivedToken, 
+        String appliesToAddress
+    ) {
+        // It must be a SAML Token
+        if (!isSAMLToken(receivedToken)) {
+            LOG.fine("Received token is not a SAML Token");
+            return false;
+        }
+
+        Element validateTargetElement = (Element)receivedToken.getToken();
+        try {
+            SamlAssertionWrapper assertion = new SamlAssertionWrapper(validateTargetElement);
+
+            for (String confirmationMethod : assertion.getConfirmationMethods()) {
+                if (!(SAML1Constants.CONF_BEARER.equals(confirmationMethod)
+                    || SAML2Constants.CONF_BEARER.equals(confirmationMethod))) {
+                    LOG.fine("An unsupported Confirmation Method was used: " + confirmationMethod);
+                    return false;
+                }
+            }
+
+            if (appliesToAddress != null) {
+                List<String> addresses = getAudienceRestrictions(assertion);
+                if (!(addresses.isEmpty() || addresses.contains(appliesToAddress))) {
+                    LOG.fine("The AppliesTo address " + appliesToAddress + " is not contained"
+                             + " in the Audience Restriction addresses in the assertion");
+                    return false;
+                }
+            }
+        } catch (WSSecurityException ex) {
+            LOG.log(Level.WARNING, "Error in ascertaining whether delegation is allowed", ex);
+            return false;
+        }
+
+        return true;
+    }
+    
+    protected boolean isSAMLToken(ReceivedToken target) {
+        Object token = target.getToken();
+        if (token instanceof Element) {
+            Element tokenElement = (Element)token;
+            String namespace = tokenElement.getNamespaceURI();
+            String localname = tokenElement.getLocalName();
+            if ((WSConstants.SAML_NS.equals(namespace) || WSConstants.SAML2_NS.equals(namespace))
+                && "Assertion".equals(localname)) {
+                return true;
+            }
+        }
+        return false;
+    }
+    
+    protected List<String> getAudienceRestrictions(SamlAssertionWrapper assertion) {
+        List<String> addresses = new ArrayList<String>();
+        if (assertion.getSaml1() != null) {
+            for (AudienceRestrictionCondition restriction 
+                : assertion.getSaml1().getConditions().getAudienceRestrictionConditions()) {
+                for (org.opensaml.saml1.core.Audience audience : restriction.getAudiences()) {
+                    addresses.add(audience.getUri());
+                }
+            }
+        } else if (assertion.getSaml2() != null) {
+            for (org.opensaml.saml2.core.AudienceRestriction restriction 
+                : assertion.getSaml2().getConditions().getAudienceRestrictions()) {
+                for (org.opensaml.saml2.core.Audience audience : restriction.getAudiences()) {
+                    addresses.add(audience.getAudienceURI());
+                }
+            }
+        }
+        
+        return addresses;
+    }
+    
+}
\ No newline at end of file

Added: cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/request/DelegationHandler.java
URL: http://svn.apache.org/viewvc/cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/request/DelegationHandler.java?rev=1520272&view=auto
==============================================================================
--- cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/request/DelegationHandler.java (added)
+++ cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/request/DelegationHandler.java Thu Sep  5 10:38:30 2013
@@ -0,0 +1,44 @@
+/**
+ * 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.sts.request;
+
+import javax.xml.ws.WebServiceContext;
+
+
+/**
+ * This interface controls whether the STS allows an authenticated user to get a token
+ * OnBehalfOf or ActAs another token. The tokens should be taken from the TokenRequirements
+ * object passed as a parameter.
+ */
+public interface DelegationHandler {
+    
+    /**
+     * Returns true if delegation is allowed.
+     * @param context WebServiceContext
+     * @param tokenRequirements The parameters extracted from the request
+     * @param appliesToAddress The AppliesTo address (if any)
+     * @return true if delegation is allowed.
+     */
+    boolean isDelegationAllowed(
+        WebServiceContext context,
+        TokenRequirements tokenRequirements, 
+        String appliesToAddress
+    );
+    
+}
\ No newline at end of file

Added: cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/request/HOKDelegationHandler.java
URL: http://svn.apache.org/viewvc/cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/request/HOKDelegationHandler.java?rev=1520272&view=auto
==============================================================================
--- cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/request/HOKDelegationHandler.java (added)
+++ cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/request/HOKDelegationHandler.java Thu Sep  5 10:38:30 2013
@@ -0,0 +1,85 @@
+/**
+ * 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.sts.request;
+
+import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.xml.ws.WebServiceContext;
+
+import org.w3c.dom.Element;
+
+import org.apache.cxf.common.logging.LogUtils;
+import org.apache.wss4j.common.ext.WSSecurityException;
+import org.apache.wss4j.common.saml.SamlAssertionWrapper;
+import org.apache.wss4j.common.saml.builder.SAML1Constants;
+import org.apache.wss4j.common.saml.builder.SAML2Constants;
+
+/**
+ * This DelegationHandler implementation extends the Default implementation to allow SAML
+ * Tokens with HolderOfKey Subject Confirmation.
+ */
+public class HOKDelegationHandler extends DefaultDelegationHandler {
+    
+    private static final Logger LOG = 
+        LogUtils.getL7dLogger(HOKDelegationHandler.class);
+    
+    /**
+     * Is Delegation allowed for a particular token
+     */
+    @Override
+    protected boolean isDelegationAllowed(
+        WebServiceContext context,
+        ReceivedToken receivedToken, 
+        String appliesToAddress
+    ) {
+        // It must be a SAML Token
+        if (!isSAMLToken(receivedToken)) {
+            return false;
+        }
+
+        Element validateTargetElement = (Element)receivedToken.getToken();
+        try {
+            SamlAssertionWrapper assertion = new SamlAssertionWrapper(validateTargetElement);
+
+            for (String confirmationMethod : assertion.getConfirmationMethods()) {
+                if (!(SAML1Constants.CONF_BEARER.equals(confirmationMethod)
+                    || SAML1Constants.CONF_HOLDER_KEY.equals(confirmationMethod)
+                    || SAML2Constants.CONF_BEARER.equals(confirmationMethod)
+                    || SAML2Constants.CONF_HOLDER_KEY.equals(confirmationMethod))) {
+                    return false;
+                }
+            }
+
+            if (appliesToAddress != null) {
+                List<String> addresses = getAudienceRestrictions(assertion);
+                if (!(addresses.isEmpty() || addresses.contains(appliesToAddress))) {
+                    return false;
+                }
+            }
+        } catch (WSSecurityException ex) {
+            LOG.log(Level.WARNING, "Error in ascertaining whether delegation is allowed", ex);
+            return false;
+        }
+
+        return true;
+    }
+    
+}
\ No newline at end of file

Added: cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/request/UsernameTokenDelegationHandler.java
URL: http://svn.apache.org/viewvc/cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/request/UsernameTokenDelegationHandler.java?rev=1520272&view=auto
==============================================================================
--- cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/request/UsernameTokenDelegationHandler.java (added)
+++ cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/request/UsernameTokenDelegationHandler.java Thu Sep  5 10:38:30 2013
@@ -0,0 +1,79 @@
+/**
+ * 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.sts.request;
+
+import java.util.List;
+
+import javax.xml.ws.WebServiceContext;
+
+import org.w3c.dom.Element;
+
+import org.apache.wss4j.common.ext.WSSecurityException;
+import org.apache.wss4j.common.saml.SamlAssertionWrapper;
+import org.apache.wss4j.common.saml.builder.SAML1Constants;
+import org.apache.wss4j.common.saml.builder.SAML2Constants;
+
+/**
+ * This DelegationHandler implementation extends the Default implementation to allow UsernameTokens
+ * for OnBehalfOf/ActAs
+ */
+public class UsernameTokenDelegationHandler extends DefaultDelegationHandler {
+    
+    /**
+     * Is Delegation allowed for a particular token
+     */
+    protected boolean isDelegationAllowed(
+        WebServiceContext context,
+        ReceivedToken receivedToken, 
+        String appliesToAddress
+    ) {
+        if (receivedToken.isUsernameToken()) {
+            return true;
+        }
+        
+        // It must be a SAML Token
+        if (!isSAMLToken(receivedToken)) {
+            return false;
+        }
+
+        Element validateTargetElement = (Element)receivedToken.getToken();
+        try {
+            SamlAssertionWrapper assertion = new SamlAssertionWrapper(validateTargetElement);
+
+            for (String confirmationMethod : assertion.getConfirmationMethods()) {
+                if (!(SAML1Constants.CONF_BEARER.equals(confirmationMethod)
+                    || SAML2Constants.CONF_BEARER.equals(confirmationMethod))) {
+                    return false;
+                }
+            }
+
+            if (appliesToAddress != null) {
+                List<String> addresses = getAudienceRestrictions(assertion);
+                if (!(addresses.isEmpty() || addresses.contains(appliesToAddress))) {
+                    return false;
+                }
+            }
+        } catch (WSSecurityException ex) {
+            return false;
+        }
+
+        return true;
+    }
+    
+}
\ No newline at end of file

Modified: cxf/trunk/services/sts/sts-core/src/test/java/org/apache/cxf/sts/operation/IssueOnbehalfofUnitTest.java
URL: http://svn.apache.org/viewvc/cxf/trunk/services/sts/sts-core/src/test/java/org/apache/cxf/sts/operation/IssueOnbehalfofUnitTest.java?rev=1520272&r1=1520271&r2=1520272&view=diff
==============================================================================
--- cxf/trunk/services/sts/sts-core/src/test/java/org/apache/cxf/sts/operation/IssueOnbehalfofUnitTest.java (original)
+++ cxf/trunk/services/sts/sts-core/src/test/java/org/apache/cxf/sts/operation/IssueOnbehalfofUnitTest.java Thu Sep  5 10:38:30 2013
@@ -19,6 +19,7 @@
 package org.apache.cxf.sts.operation;
 
 import java.security.Principal;
+import java.security.cert.X509Certificate;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
@@ -32,7 +33,6 @@ import javax.xml.namespace.QName;
 
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
-
 import org.apache.cxf.helpers.DOMUtils;
 import org.apache.cxf.jaxws.context.WebServiceContextImpl;
 import org.apache.cxf.jaxws.context.WrappedMessageContext;
@@ -48,8 +48,11 @@ import org.apache.cxf.sts.claims.ClaimsH
 import org.apache.cxf.sts.claims.ClaimsManager;
 import org.apache.cxf.sts.common.CustomUserClaimsHandler;
 import org.apache.cxf.sts.common.PasswordCallbackHandler;
+import org.apache.cxf.sts.request.HOKDelegationHandler;
 import org.apache.cxf.sts.request.KeyRequirements;
+import org.apache.cxf.sts.request.ReceivedKey;
 import org.apache.cxf.sts.request.TokenRequirements;
+import org.apache.cxf.sts.request.UsernameTokenDelegationHandler;
 import org.apache.cxf.sts.service.EncryptionProperties;
 import org.apache.cxf.sts.service.ServiceMBean;
 import org.apache.cxf.sts.service.StaticService;
@@ -75,6 +78,7 @@ import org.apache.cxf.ws.security.sts.pr
 import org.apache.cxf.ws.security.sts.provider.model.secext.UsernameTokenType;
 import org.apache.wss4j.common.crypto.Crypto;
 import org.apache.wss4j.common.crypto.CryptoFactory;
+import org.apache.wss4j.common.crypto.CryptoType;
 import org.apache.wss4j.common.ext.WSSecurityException;
 import org.apache.wss4j.common.principal.CustomTokenPrincipal;
 import org.apache.wss4j.common.saml.SamlAssertionWrapper;
@@ -160,6 +164,550 @@ public class IssueOnbehalfofUnitTest ext
         assertTrue(!securityTokenResponse.isEmpty());
     }
     
+    /**
+     * Test to successfully issue a SAML 2 token on-behalf-of a SAML 1 token
+     */
+    @org.junit.Test
+    public void testIssueSaml2TokenOnBehalfOfSaml1() throws Exception {
+        TokenIssueOperation issueOperation = new TokenIssueOperation();
+
+        // Add Token Provider
+        List<TokenProvider> providerList = new ArrayList<TokenProvider>();
+        providerList.add(new SAMLTokenProvider());
+        issueOperation.setTokenProviders(providerList);
+        
+        // Add Token Validator
+        List<TokenValidator> validatorList = new ArrayList<TokenValidator>();
+        validatorList.add(new SAMLTokenValidator());
+        issueOperation.setTokenValidators(validatorList);
+
+        // Add Service
+        ServiceMBean service = new StaticService();
+        service.setEndpoints(Collections.singletonList("http://dummy-service.com/dummy"));
+        issueOperation.setServices(Collections.singletonList(service));
+
+        // Add STSProperties object
+        STSPropertiesMBean stsProperties = new StaticSTSProperties();
+        Crypto crypto = CryptoFactory.getInstance(getEncryptionProperties());
+        stsProperties.setEncryptionCrypto(crypto);
+        stsProperties.setSignatureCrypto(crypto);
+        stsProperties.setEncryptionUsername("myservicekey");
+        stsProperties.setSignatureUsername("mystskey");
+        stsProperties.setCallbackHandler(new PasswordCallbackHandler());
+        stsProperties.setIssuer("STS");
+        issueOperation.setStsProperties(stsProperties);
+
+        // Mock up a request
+        RequestSecurityTokenType request = new RequestSecurityTokenType();
+        JAXBElement<String> tokenType = 
+            new JAXBElement<String>(
+                    QNameConstants.TOKEN_TYPE, String.class, WSConstants.WSS_SAML2_TOKEN_TYPE
+            );
+        request.getAny().add(tokenType);
+
+        // Get a SAML Token via the SAMLTokenProvider
+        CallbackHandler callbackHandler = new PasswordCallbackHandler();
+        Element samlToken = 
+            createSAMLAssertion(WSConstants.WSS_SAML_TOKEN_TYPE, crypto, "mystskey", callbackHandler);
+        Document doc = samlToken.getOwnerDocument();
+        samlToken = (Element)doc.appendChild(samlToken);
+        OnBehalfOfType onbehalfof = new OnBehalfOfType();
+        onbehalfof.setAny(samlToken);
+
+        JAXBElement<OnBehalfOfType> onbehalfofType = 
+            new JAXBElement<OnBehalfOfType>(
+                    QNameConstants.ON_BEHALF_OF, OnBehalfOfType.class, onbehalfof
+            );
+        request.getAny().add(onbehalfofType);
+
+        // Mock up message context
+        MessageImpl msg = new MessageImpl();
+        WrappedMessageContext msgCtx = new WrappedMessageContext(msg);
+        WebServiceContextImpl webServiceContext = new WebServiceContextImpl(msgCtx);
+
+        // Issue a token
+        RequestSecurityTokenResponseCollectionType response = 
+            issueOperation.issue(request, webServiceContext);
+        List<RequestSecurityTokenResponseType> securityTokenResponse = 
+            response.getRequestSecurityTokenResponse();
+        assertTrue(!securityTokenResponse.isEmpty());
+    }
+    
+    /**
+     * Test to successfully issue a SAML 2 token on-behalf-of a SAML 2 Symmetric HOK token
+     */
+    @org.junit.Test
+    public void testIssueSaml2TokenOnBehalfOfSaml2SymmetricHOK() throws Exception {
+        TokenIssueOperation issueOperation = new TokenIssueOperation();
+
+        // Add Token Provider
+        List<TokenProvider> providerList = new ArrayList<TokenProvider>();
+        providerList.add(new SAMLTokenProvider());
+        issueOperation.setTokenProviders(providerList);
+        
+        // Add Token Validator
+        List<TokenValidator> validatorList = new ArrayList<TokenValidator>();
+        validatorList.add(new SAMLTokenValidator());
+        issueOperation.setTokenValidators(validatorList);
+
+        // Add Service
+        ServiceMBean service = new StaticService();
+        service.setEndpoints(Collections.singletonList("http://dummy-service.com/dummy"));
+        issueOperation.setServices(Collections.singletonList(service));
+
+        // Add STSProperties object
+        STSPropertiesMBean stsProperties = new StaticSTSProperties();
+        Crypto crypto = CryptoFactory.getInstance(getEncryptionProperties());
+        stsProperties.setEncryptionCrypto(crypto);
+        stsProperties.setSignatureCrypto(crypto);
+        stsProperties.setEncryptionUsername("myservicekey");
+        stsProperties.setSignatureUsername("mystskey");
+        stsProperties.setCallbackHandler(new PasswordCallbackHandler());
+        stsProperties.setIssuer("STS");
+        issueOperation.setStsProperties(stsProperties);
+
+        // Mock up a request
+        RequestSecurityTokenType request = new RequestSecurityTokenType();
+        JAXBElement<String> tokenType = 
+            new JAXBElement<String>(
+                    QNameConstants.TOKEN_TYPE, String.class, WSConstants.WSS_SAML2_TOKEN_TYPE
+            );
+        request.getAny().add(tokenType);
+
+        // Get a SAML Token via the SAMLTokenProvider
+        CallbackHandler callbackHandler = new PasswordCallbackHandler();
+        Element samlToken = 
+            createSAMLAssertion(WSConstants.WSS_SAML2_TOKEN_TYPE, crypto, "mystskey", 
+                            callbackHandler, null, STSConstants.SYMMETRIC_KEY_TYPE);
+        Document doc = samlToken.getOwnerDocument();
+        samlToken = (Element)doc.appendChild(samlToken);
+        OnBehalfOfType onbehalfof = new OnBehalfOfType();
+        onbehalfof.setAny(samlToken);
+
+        JAXBElement<OnBehalfOfType> onbehalfofType = 
+            new JAXBElement<OnBehalfOfType>(
+                    QNameConstants.ON_BEHALF_OF, OnBehalfOfType.class, onbehalfof
+            );
+        request.getAny().add(onbehalfofType);
+
+        // Mock up message context
+        MessageImpl msg = new MessageImpl();
+        WrappedMessageContext msgCtx = new WrappedMessageContext(msg);
+        WebServiceContextImpl webServiceContext = new WebServiceContextImpl(msgCtx);
+
+        // Issue a token
+        
+        // This should fail as the default DelegationHandler does not allow HolderOfKey
+        try {
+            issueOperation.issue(request, webServiceContext);
+            fail("Failure expected as HolderOfKey is not allowed by default");
+        } catch (STSException ex) {
+            // expected
+        }
+        
+        issueOperation.setDelegationHandler(new HOKDelegationHandler());
+        
+        RequestSecurityTokenResponseCollectionType response = 
+            issueOperation.issue(request, webServiceContext);
+        List<RequestSecurityTokenResponseType> securityTokenResponse = 
+            response.getRequestSecurityTokenResponse();
+        assertTrue(!securityTokenResponse.isEmpty());
+    }
+    
+    /**
+     * Test to successfully issue a SAML 2 token on-behalf-of a SAML 1 Symmetric HOK token
+     */
+    @org.junit.Test
+    public void testIssueSaml2TokenOnBehalfOfSaml1SymmetricHOK() throws Exception {
+        TokenIssueOperation issueOperation = new TokenIssueOperation();
+
+        // Add Token Provider
+        List<TokenProvider> providerList = new ArrayList<TokenProvider>();
+        providerList.add(new SAMLTokenProvider());
+        issueOperation.setTokenProviders(providerList);
+        
+        // Add Token Validator
+        List<TokenValidator> validatorList = new ArrayList<TokenValidator>();
+        validatorList.add(new SAMLTokenValidator());
+        issueOperation.setTokenValidators(validatorList);
+
+        // Add Service
+        ServiceMBean service = new StaticService();
+        service.setEndpoints(Collections.singletonList("http://dummy-service.com/dummy"));
+        issueOperation.setServices(Collections.singletonList(service));
+
+        // Add STSProperties object
+        STSPropertiesMBean stsProperties = new StaticSTSProperties();
+        Crypto crypto = CryptoFactory.getInstance(getEncryptionProperties());
+        stsProperties.setEncryptionCrypto(crypto);
+        stsProperties.setSignatureCrypto(crypto);
+        stsProperties.setEncryptionUsername("myservicekey");
+        stsProperties.setSignatureUsername("mystskey");
+        stsProperties.setCallbackHandler(new PasswordCallbackHandler());
+        stsProperties.setIssuer("STS");
+        issueOperation.setStsProperties(stsProperties);
+
+        // Mock up a request
+        RequestSecurityTokenType request = new RequestSecurityTokenType();
+        JAXBElement<String> tokenType = 
+            new JAXBElement<String>(
+                    QNameConstants.TOKEN_TYPE, String.class, WSConstants.WSS_SAML2_TOKEN_TYPE
+            );
+        request.getAny().add(tokenType);
+
+        // Get a SAML Token via the SAMLTokenProvider
+        CallbackHandler callbackHandler = new PasswordCallbackHandler();
+        Element samlToken = 
+            createSAMLAssertion(WSConstants.WSS_SAML_TOKEN_TYPE, crypto, "mystskey", 
+                            callbackHandler, null, STSConstants.SYMMETRIC_KEY_TYPE);
+        Document doc = samlToken.getOwnerDocument();
+        samlToken = (Element)doc.appendChild(samlToken);
+        OnBehalfOfType onbehalfof = new OnBehalfOfType();
+        onbehalfof.setAny(samlToken);
+
+        JAXBElement<OnBehalfOfType> onbehalfofType = 
+            new JAXBElement<OnBehalfOfType>(
+                    QNameConstants.ON_BEHALF_OF, OnBehalfOfType.class, onbehalfof
+            );
+        request.getAny().add(onbehalfofType);
+
+        // Mock up message context
+        MessageImpl msg = new MessageImpl();
+        WrappedMessageContext msgCtx = new WrappedMessageContext(msg);
+        WebServiceContextImpl webServiceContext = new WebServiceContextImpl(msgCtx);
+
+        // Issue a token
+        
+        // This should fail as the default DelegationHandler does not allow HolderOfKey
+        try {
+            issueOperation.issue(request, webServiceContext);
+            fail("Failure expected as HolderOfKey is not allowed by default");
+        } catch (STSException ex) {
+            // expected
+        }
+        
+        issueOperation.setDelegationHandler(new HOKDelegationHandler());
+        
+        RequestSecurityTokenResponseCollectionType response = 
+            issueOperation.issue(request, webServiceContext);
+        List<RequestSecurityTokenResponseType> securityTokenResponse = 
+            response.getRequestSecurityTokenResponse();
+        assertTrue(!securityTokenResponse.isEmpty());
+    }
+    
+    /**
+     * Test to successfully issue a SAML 2 token on-behalf-of a SAML 2 PublicKey HOK token
+     */
+    @org.junit.Test
+    public void testIssueSaml2TokenOnBehalfOfSaml2PublicKeyHOK() throws Exception {
+        TokenIssueOperation issueOperation = new TokenIssueOperation();
+
+        // Add Token Provider
+        List<TokenProvider> providerList = new ArrayList<TokenProvider>();
+        providerList.add(new SAMLTokenProvider());
+        issueOperation.setTokenProviders(providerList);
+        
+        // Add Token Validator
+        List<TokenValidator> validatorList = new ArrayList<TokenValidator>();
+        validatorList.add(new SAMLTokenValidator());
+        issueOperation.setTokenValidators(validatorList);
+
+        // Add Service
+        ServiceMBean service = new StaticService();
+        service.setEndpoints(Collections.singletonList("http://dummy-service.com/dummy"));
+        issueOperation.setServices(Collections.singletonList(service));
+
+        // Add STSProperties object
+        STSPropertiesMBean stsProperties = new StaticSTSProperties();
+        Crypto crypto = CryptoFactory.getInstance(getEncryptionProperties());
+        stsProperties.setEncryptionCrypto(crypto);
+        stsProperties.setSignatureCrypto(crypto);
+        stsProperties.setEncryptionUsername("myservicekey");
+        stsProperties.setSignatureUsername("mystskey");
+        stsProperties.setCallbackHandler(new PasswordCallbackHandler());
+        stsProperties.setIssuer("STS");
+        issueOperation.setStsProperties(stsProperties);
+
+        // Mock up a request
+        RequestSecurityTokenType request = new RequestSecurityTokenType();
+        JAXBElement<String> tokenType = 
+            new JAXBElement<String>(
+                    QNameConstants.TOKEN_TYPE, String.class, WSConstants.WSS_SAML2_TOKEN_TYPE
+            );
+        request.getAny().add(tokenType);
+        
+        // Get a SAML Token via the SAMLTokenProvider
+        CallbackHandler callbackHandler = new PasswordCallbackHandler();
+        Element samlToken = 
+            createSAMLAssertion(WSConstants.WSS_SAML2_TOKEN_TYPE, crypto, "mystskey", 
+                            callbackHandler, null, STSConstants.PUBLIC_KEY_KEYTYPE);
+        Document doc = samlToken.getOwnerDocument();
+        samlToken = (Element)doc.appendChild(samlToken);
+        OnBehalfOfType onbehalfof = new OnBehalfOfType();
+        onbehalfof.setAny(samlToken);
+
+        JAXBElement<OnBehalfOfType> onbehalfofType = 
+            new JAXBElement<OnBehalfOfType>(
+                    QNameConstants.ON_BEHALF_OF, OnBehalfOfType.class, onbehalfof
+            );
+        request.getAny().add(onbehalfofType);
+
+        // Mock up message context
+        MessageImpl msg = new MessageImpl();
+        WrappedMessageContext msgCtx = new WrappedMessageContext(msg);
+        WebServiceContextImpl webServiceContext = new WebServiceContextImpl(msgCtx);
+
+        // Issue a token
+        
+        // This should fail as the default DelegationHandler does not allow HolderOfKey
+        try {
+            issueOperation.issue(request, webServiceContext);
+            fail("Failure expected as HolderOfKey is not allowed by default");
+        } catch (STSException ex) {
+            // expected
+        }
+        
+        issueOperation.setDelegationHandler(new HOKDelegationHandler());
+        
+        RequestSecurityTokenResponseCollectionType response = 
+            issueOperation.issue(request, webServiceContext);
+        List<RequestSecurityTokenResponseType> securityTokenResponse = 
+            response.getRequestSecurityTokenResponse();
+        assertTrue(!securityTokenResponse.isEmpty());
+    }
+    
+    /**
+     * Test to successfully issue a SAML 2 token on-behalf-of a SAML 1 PublicKey HOK token
+     */
+    @org.junit.Test
+    public void testIssueSaml2TokenOnBehalfOfSaml1PublicKeyHOK() throws Exception {
+        TokenIssueOperation issueOperation = new TokenIssueOperation();
+
+        // Add Token Provider
+        List<TokenProvider> providerList = new ArrayList<TokenProvider>();
+        providerList.add(new SAMLTokenProvider());
+        issueOperation.setTokenProviders(providerList);
+        
+        // Add Token Validator
+        List<TokenValidator> validatorList = new ArrayList<TokenValidator>();
+        validatorList.add(new SAMLTokenValidator());
+        issueOperation.setTokenValidators(validatorList);
+
+        // Add Service
+        ServiceMBean service = new StaticService();
+        service.setEndpoints(Collections.singletonList("http://dummy-service.com/dummy"));
+        issueOperation.setServices(Collections.singletonList(service));
+
+        // Add STSProperties object
+        STSPropertiesMBean stsProperties = new StaticSTSProperties();
+        Crypto crypto = CryptoFactory.getInstance(getEncryptionProperties());
+        stsProperties.setEncryptionCrypto(crypto);
+        stsProperties.setSignatureCrypto(crypto);
+        stsProperties.setEncryptionUsername("myservicekey");
+        stsProperties.setSignatureUsername("mystskey");
+        stsProperties.setCallbackHandler(new PasswordCallbackHandler());
+        stsProperties.setIssuer("STS");
+        issueOperation.setStsProperties(stsProperties);
+
+        // Mock up a request
+        RequestSecurityTokenType request = new RequestSecurityTokenType();
+        JAXBElement<String> tokenType = 
+            new JAXBElement<String>(
+                    QNameConstants.TOKEN_TYPE, String.class, WSConstants.WSS_SAML2_TOKEN_TYPE
+            );
+        request.getAny().add(tokenType);
+        
+        // Get a SAML Token via the SAMLTokenProvider
+        CallbackHandler callbackHandler = new PasswordCallbackHandler();
+        Element samlToken = 
+            createSAMLAssertion(WSConstants.WSS_SAML_TOKEN_TYPE, crypto, "mystskey", 
+                            callbackHandler, null, STSConstants.PUBLIC_KEY_KEYTYPE);
+        Document doc = samlToken.getOwnerDocument();
+        samlToken = (Element)doc.appendChild(samlToken);
+        OnBehalfOfType onbehalfof = new OnBehalfOfType();
+        onbehalfof.setAny(samlToken);
+
+        JAXBElement<OnBehalfOfType> onbehalfofType = 
+            new JAXBElement<OnBehalfOfType>(
+                    QNameConstants.ON_BEHALF_OF, OnBehalfOfType.class, onbehalfof
+            );
+        request.getAny().add(onbehalfofType);
+
+        // Mock up message context
+        MessageImpl msg = new MessageImpl();
+        WrappedMessageContext msgCtx = new WrappedMessageContext(msg);
+        WebServiceContextImpl webServiceContext = new WebServiceContextImpl(msgCtx);
+
+        // Issue a token
+        
+        // This should fail as the default DelegationHandler does not allow HolderOfKey
+        try {
+            issueOperation.issue(request, webServiceContext);
+            fail("Failure expected as HolderOfKey is not allowed by default");
+        } catch (STSException ex) {
+            // expected
+        }
+        
+        issueOperation.setDelegationHandler(new HOKDelegationHandler());
+        
+        RequestSecurityTokenResponseCollectionType response = 
+            issueOperation.issue(request, webServiceContext);
+        List<RequestSecurityTokenResponseType> securityTokenResponse = 
+            response.getRequestSecurityTokenResponse();
+        assertTrue(!securityTokenResponse.isEmpty());
+    }
+    
+    /**
+     * Test to unsuccessfully issue a SAML 2 token on-behalf-of a SAML 2 token. The
+     * problem is that the Audience Restriction URLs in the original token do not
+     * match the AppliesTo address.
+     */
+    @org.junit.Test
+    public void testSaml2AudienceRestriction() throws Exception {
+        TokenIssueOperation issueOperation = new TokenIssueOperation();
+
+        // Add Token Provider
+        List<TokenProvider> providerList = new ArrayList<TokenProvider>();
+        providerList.add(new SAMLTokenProvider());
+        issueOperation.setTokenProviders(providerList);
+        
+        // Add Token Validator
+        List<TokenValidator> validatorList = new ArrayList<TokenValidator>();
+        validatorList.add(new SAMLTokenValidator());
+        issueOperation.setTokenValidators(validatorList);
+
+        // Add Service
+        ServiceMBean service = new StaticService();
+        service.setEndpoints(Collections.singletonList("http://dummy-service.com/dummy"));
+        issueOperation.setServices(Collections.singletonList(service));
+
+        // Add STSProperties object
+        STSPropertiesMBean stsProperties = new StaticSTSProperties();
+        Crypto crypto = CryptoFactory.getInstance(getEncryptionProperties());
+        stsProperties.setEncryptionCrypto(crypto);
+        stsProperties.setSignatureCrypto(crypto);
+        stsProperties.setEncryptionUsername("myservicekey");
+        stsProperties.setSignatureUsername("mystskey");
+        stsProperties.setCallbackHandler(new PasswordCallbackHandler());
+        stsProperties.setIssuer("STS");
+        issueOperation.setStsProperties(stsProperties);
+
+        // Mock up a request
+        RequestSecurityTokenType request = new RequestSecurityTokenType();
+        JAXBElement<String> tokenType = 
+            new JAXBElement<String>(
+                    QNameConstants.TOKEN_TYPE, String.class, WSConstants.WSS_SAML2_TOKEN_TYPE
+            );
+        request.getAny().add(tokenType);
+
+        // Get a SAML Token via the SAMLTokenProvider
+        CallbackHandler callbackHandler = new PasswordCallbackHandler();
+        Element samlToken = 
+            createSAMLAssertion(WSConstants.WSS_SAML2_TOKEN_TYPE, crypto, "mystskey", callbackHandler);
+        Document doc = samlToken.getOwnerDocument();
+        samlToken = (Element)doc.appendChild(samlToken);
+        OnBehalfOfType onbehalfof = new OnBehalfOfType();
+        onbehalfof.setAny(samlToken);
+
+        JAXBElement<OnBehalfOfType> onbehalfofType = 
+            new JAXBElement<OnBehalfOfType>(
+                    QNameConstants.ON_BEHALF_OF, OnBehalfOfType.class, onbehalfof
+            );
+        request.getAny().add(onbehalfofType);
+
+        // Mock up message context
+        MessageImpl msg = new MessageImpl();
+        WrappedMessageContext msgCtx = new WrappedMessageContext(msg);
+        WebServiceContextImpl webServiceContext = new WebServiceContextImpl(msgCtx);
+
+        // Issue a token - this should work
+        issueOperation.issue(request, webServiceContext);
+        
+        request.getAny().add(createAppliesToElement("http://dummy-service.com/dummy2"));
+        // This should fail
+        try {
+            issueOperation.issue(request, webServiceContext);
+            fail("Failure expected due to AudienceRestriction");
+        } catch (STSException ex) {
+            // expected
+        }
+    }
+    
+    /**
+     * Test to unsuccessfully issue a SAML 2 token on-behalf-of a SAML 1 token. The
+     * problem is that the Audience Restriction URLs in the original token do not
+     * match the AppliesTo address.
+     */
+    @org.junit.Test
+    public void testSaml1AudienceRestriction() throws Exception {
+        TokenIssueOperation issueOperation = new TokenIssueOperation();
+
+        // Add Token Provider
+        List<TokenProvider> providerList = new ArrayList<TokenProvider>();
+        providerList.add(new SAMLTokenProvider());
+        issueOperation.setTokenProviders(providerList);
+        
+        // Add Token Validator
+        List<TokenValidator> validatorList = new ArrayList<TokenValidator>();
+        validatorList.add(new SAMLTokenValidator());
+        issueOperation.setTokenValidators(validatorList);
+
+        // Add Service
+        ServiceMBean service = new StaticService();
+        service.setEndpoints(Collections.singletonList("http://dummy-service.com/dummy"));
+        issueOperation.setServices(Collections.singletonList(service));
+
+        // Add STSProperties object
+        STSPropertiesMBean stsProperties = new StaticSTSProperties();
+        Crypto crypto = CryptoFactory.getInstance(getEncryptionProperties());
+        stsProperties.setEncryptionCrypto(crypto);
+        stsProperties.setSignatureCrypto(crypto);
+        stsProperties.setEncryptionUsername("myservicekey");
+        stsProperties.setSignatureUsername("mystskey");
+        stsProperties.setCallbackHandler(new PasswordCallbackHandler());
+        stsProperties.setIssuer("STS");
+        issueOperation.setStsProperties(stsProperties);
+
+        // Mock up a request
+        RequestSecurityTokenType request = new RequestSecurityTokenType();
+        JAXBElement<String> tokenType = 
+            new JAXBElement<String>(
+                    QNameConstants.TOKEN_TYPE, String.class, WSConstants.WSS_SAML2_TOKEN_TYPE
+            );
+        request.getAny().add(tokenType);
+
+        // Get a SAML Token via the SAMLTokenProvider
+        CallbackHandler callbackHandler = new PasswordCallbackHandler();
+        Element samlToken = 
+            createSAMLAssertion(WSConstants.WSS_SAML_TOKEN_TYPE, crypto, "mystskey", callbackHandler);
+        Document doc = samlToken.getOwnerDocument();
+        samlToken = (Element)doc.appendChild(samlToken);
+        OnBehalfOfType onbehalfof = new OnBehalfOfType();
+        onbehalfof.setAny(samlToken);
+
+        JAXBElement<OnBehalfOfType> onbehalfofType = 
+            new JAXBElement<OnBehalfOfType>(
+                    QNameConstants.ON_BEHALF_OF, OnBehalfOfType.class, onbehalfof
+            );
+        request.getAny().add(onbehalfofType);
+
+        // Mock up message context
+        MessageImpl msg = new MessageImpl();
+        WrappedMessageContext msgCtx = new WrappedMessageContext(msg);
+        WebServiceContextImpl webServiceContext = new WebServiceContextImpl(msgCtx);
+
+        // Issue a token - this should work
+        issueOperation.issue(request, webServiceContext);
+        
+        request.getAny().add(createAppliesToElement("http://dummy-service.com/dummy2"));
+        // This should fail
+        try {
+            issueOperation.issue(request, webServiceContext);
+            fail("Failure expected due to AudienceRestriction");
+        } catch (STSException ex) {
+            // expected
+        }
+    }
     
     /**
      * Test to successfully issue a SAML 2 token on-behalf-of a UsernameToken
@@ -221,6 +769,17 @@ public class IssueOnbehalfofUnitTest ext
         WebServiceContextImpl webServiceContext = new WebServiceContextImpl(msgCtx);
 
         // Issue a token
+        
+        // This should fail as the default DelegationHandler does not allow UsernameTokens
+        try {
+            issueOperation.issue(request, webServiceContext);
+            fail("Failure expected as UsernameTokens are not accepted for OnBehalfOf by default");
+        } catch (STSException ex) {
+            // expected
+        }
+        
+        issueOperation.setDelegationHandler(new UsernameTokenDelegationHandler());
+        
         RequestSecurityTokenResponseCollectionType response = 
             issueOperation.issue(request, webServiceContext);
         List<RequestSecurityTokenResponseType> securityTokenResponse = 
@@ -286,6 +845,8 @@ public class IssueOnbehalfofUnitTest ext
         MessageImpl msg = new MessageImpl();
         WrappedMessageContext msgCtx = new WrappedMessageContext(msg);
         WebServiceContextImpl webServiceContext = new WebServiceContextImpl(msgCtx);
+        
+        issueOperation.setDelegationHandler(new UsernameTokenDelegationHandler());
 
         // Issue a token - this will fail as the UsernameToken validation fails
         try {
@@ -350,7 +911,7 @@ public class IssueOnbehalfofUnitTest ext
         CallbackHandler callbackHandler = new PasswordCallbackHandler();
         Element samlToken = 
             createSAMLAssertion(WSConstants.WSS_SAML2_TOKEN_TYPE, crypto, "mystskey",
-                    callbackHandler, realms);
+                    callbackHandler, realms, STSConstants.BEARER_KEY_KEYTYPE);
         Document doc = samlToken.getOwnerDocument();
         samlToken = (Element)doc.appendChild(samlToken);
         OnBehalfOfType onbehalfof = new OnBehalfOfType();
@@ -625,7 +1186,8 @@ public class IssueOnbehalfofUnitTest ext
     private Element createSAMLAssertion(
             String tokenType, Crypto crypto, String signatureUsername, CallbackHandler callbackHandler
     ) throws WSSecurityException {
-        return createSAMLAssertion(tokenType, crypto, signatureUsername, callbackHandler, null);
+        return createSAMLAssertion(tokenType, crypto, signatureUsername, 
+                                   callbackHandler, null, STSConstants.BEARER_KEY_KEYTYPE);
     }
 
     /*
@@ -633,14 +1195,14 @@ public class IssueOnbehalfofUnitTest ext
      */
     private Element createSAMLAssertion(
             String tokenType, Crypto crypto, String signatureUsername, CallbackHandler callbackHandler,
-            Map<String, SAMLRealm> realms
+            Map<String, SAMLRealm> realms, String keyType
     ) throws WSSecurityException {
         SAMLTokenProvider samlTokenProvider = new SAMLTokenProvider();
         samlTokenProvider.setRealmMap(realms);
 
         TokenProviderParameters providerParameters = 
             createProviderParameters(
-                    tokenType, STSConstants.BEARER_KEY_KEYTYPE, crypto, signatureUsername, callbackHandler
+                    tokenType, keyType, crypto, signatureUsername, callbackHandler
             );
         if (realms != null) {
             providerParameters.setRealm("A");
@@ -664,6 +1226,14 @@ public class IssueOnbehalfofUnitTest ext
 
         KeyRequirements keyRequirements = new KeyRequirements();
         keyRequirements.setKeyType(keyType);
+        
+        CryptoType cryptoType = new CryptoType(CryptoType.TYPE.ALIAS);
+        cryptoType.setAlias("myclientkey");
+        X509Certificate[] certs = crypto.getX509Certificates(cryptoType);
+        ReceivedKey receivedKey = new ReceivedKey();
+        receivedKey.setX509Cert(certs[0]);
+        keyRequirements.setReceivedKey(receivedKey);
+        
         parameters.setKeyRequirements(keyRequirements);
 
         parameters.setPrincipal(new CustomTokenPrincipal("alice"));
@@ -681,6 +1251,8 @@ public class IssueOnbehalfofUnitTest ext
         stsProperties.setSignatureUsername(signatureUsername);
         stsProperties.setCallbackHandler(callbackHandler);
         stsProperties.setIssuer("STS");
+        stsProperties.setEncryptionUsername("myservicekey");
+        stsProperties.setEncryptionCrypto(crypto);
         parameters.setStsProperties(stsProperties);
 
         parameters.setEncryptionProperties(new EncryptionProperties());
@@ -761,5 +1333,20 @@ public class IssueOnbehalfofUnitTest ext
         return claimType;
     }
 
-
+    /*
+     * Mock up an AppliesTo element using the supplied address
+     */
+    private Element createAppliesToElement(String addressUrl) {
+        Document doc = DOMUtils.createDocument();
+        Element appliesTo = doc.createElementNS(STSConstants.WSP_NS, "wsp:AppliesTo");
+        appliesTo.setAttributeNS(WSConstants.XMLNS_NS, "xmlns:wsp", STSConstants.WSP_NS);
+        Element endpointRef = doc.createElementNS(STSConstants.WSA_NS_05, "wsa:EndpointReference");
+        endpointRef.setAttributeNS(WSConstants.XMLNS_NS, "xmlns:wsa", STSConstants.WSA_NS_05);
+        Element address = doc.createElementNS(STSConstants.WSA_NS_05, "wsa:Address");
+        address.setAttributeNS(WSConstants.XMLNS_NS, "xmlns:wsa", STSConstants.WSA_NS_05);
+        address.setTextContent(addressUrl);
+        endpointRef.appendChild(address);
+        appliesTo.appendChild(endpointRef);
+        return appliesTo;
+    }
 }

Modified: cxf/trunk/services/sts/systests/advanced/src/test/resources/org/apache/cxf/systest/sts/deployment/cxf-sts.xml
URL: http://svn.apache.org/viewvc/cxf/trunk/services/sts/systests/advanced/src/test/resources/org/apache/cxf/systest/sts/deployment/cxf-sts.xml?rev=1520272&r1=1520271&r2=1520272&view=diff
==============================================================================
--- cxf/trunk/services/sts/systests/advanced/src/test/resources/org/apache/cxf/systest/sts/deployment/cxf-sts.xml (original)
+++ cxf/trunk/services/sts/systests/advanced/src/test/resources/org/apache/cxf/systest/sts/deployment/cxf-sts.xml Thu Sep  5 10:38:30 2013
@@ -54,12 +54,16 @@
 		<property name="validateOperation" ref="transportValidateDelegate" />
 	</bean>
 
+    <bean id="utDelegationHandler"
+          class="org.apache.cxf.sts.request.UsernameTokenDelegationHandler" />
+          
 	<bean id="transportIssueDelegate" class="org.apache.cxf.sts.operation.TokenIssueOperation">
 		<property name="tokenProviders" ref="transportTokenProviders" />
 		<property name="services" ref="transportService" />
 		<property name="stsProperties" ref="transportSTSProperties" />
 		<property name="claimsManager" ref="claimsManager" />
 		<property name="tokenStore" ref="defaultTokenStore" />
+		<property name="delegationHandler" ref="utDelegationHandler" />
 	</bean>
 
 	<bean id="transportValidateDelegate" class="org.apache.cxf.sts.operation.TokenValidateOperation">

Added: cxf/trunk/services/sts/systests/basic/src/test/java/org/apache/cxf/systest/sts/common/HOKDelegationHandler.java
URL: http://svn.apache.org/viewvc/cxf/trunk/services/sts/systests/basic/src/test/java/org/apache/cxf/systest/sts/common/HOKDelegationHandler.java?rev=1520272&view=auto
==============================================================================
--- cxf/trunk/services/sts/systests/basic/src/test/java/org/apache/cxf/systest/sts/common/HOKDelegationHandler.java (added)
+++ cxf/trunk/services/sts/systests/basic/src/test/java/org/apache/cxf/systest/sts/common/HOKDelegationHandler.java Thu Sep  5 10:38:30 2013
@@ -0,0 +1,71 @@
+/**
+ * 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.systest.sts.common;
+
+import javax.xml.ws.WebServiceContext;
+
+import org.w3c.dom.Element;
+import org.apache.cxf.sts.request.DefaultDelegationHandler;
+import org.apache.cxf.sts.request.ReceivedToken;
+import org.apache.wss4j.common.ext.WSSecurityException;
+import org.apache.wss4j.common.saml.SamlAssertionWrapper;
+import org.apache.wss4j.common.saml.builder.SAML1Constants;
+import org.apache.wss4j.common.saml.builder.SAML2Constants;
+
+/**
+ * This DelegationHandler implementation extends the Default implementation to allow SAML
+ * Tokens with HolderOfKey Subject Confirmation. It also doesn't require that the AppliesTo
+ * address matches an AudienceRestriction condition in the SAML Token.
+ */
+public class HOKDelegationHandler extends DefaultDelegationHandler {
+    
+    /**
+     * Is Delegation allowed for a particular token
+     */
+    @Override
+    protected boolean isDelegationAllowed(
+        WebServiceContext context,
+        ReceivedToken receivedToken, 
+        String appliesToAddress
+    ) {
+        // It must be a SAML Token
+        if (!isSAMLToken(receivedToken)) {
+            return false;
+        }
+
+        Element validateTargetElement = (Element)receivedToken.getToken();
+        try {
+            SamlAssertionWrapper assertion = new SamlAssertionWrapper(validateTargetElement);
+
+            for (String confirmationMethod : assertion.getConfirmationMethods()) {
+                if (!(SAML1Constants.CONF_BEARER.equals(confirmationMethod)
+                    || SAML1Constants.CONF_HOLDER_KEY.equals(confirmationMethod)
+                    || SAML2Constants.CONF_BEARER.equals(confirmationMethod)
+                    || SAML2Constants.CONF_HOLDER_KEY.equals(confirmationMethod))) {
+                    return false;
+                }
+            }
+        } catch (WSSecurityException ex) {
+            return false;
+        }
+
+        return true;
+    }
+    
+}
\ No newline at end of file

Modified: cxf/trunk/services/sts/systests/basic/src/test/java/org/apache/cxf/systest/sts/issueunit/IssueUnitTest.java
URL: http://svn.apache.org/viewvc/cxf/trunk/services/sts/systests/basic/src/test/java/org/apache/cxf/systest/sts/issueunit/IssueUnitTest.java?rev=1520272&r1=1520271&r2=1520272&view=diff
==============================================================================
--- cxf/trunk/services/sts/systests/basic/src/test/java/org/apache/cxf/systest/sts/issueunit/IssueUnitTest.java (original)
+++ cxf/trunk/services/sts/systests/basic/src/test/java/org/apache/cxf/systest/sts/issueunit/IssueUnitTest.java Thu Sep  5 10:38:30 2013
@@ -19,7 +19,6 @@
 package org.apache.cxf.systest.sts.issueunit;
 
 import java.net.URL;
-import java.security.cert.X509Certificate;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -27,10 +26,7 @@ import java.util.Properties;
 
 import javax.security.auth.callback.CallbackHandler;
 import javax.xml.namespace.QName;
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
 
-import org.w3c.dom.Document;
 import org.w3c.dom.Element;
 
 import org.apache.cxf.Bus;
@@ -57,7 +53,6 @@ import org.apache.cxf.ws.security.tokens
 import org.apache.cxf.ws.security.trust.STSClient;
 import org.apache.wss4j.common.crypto.Crypto;
 import org.apache.wss4j.common.crypto.CryptoFactory;
-import org.apache.wss4j.common.crypto.CryptoType;
 import org.apache.wss4j.common.ext.WSSecurityException;
 import org.apache.wss4j.common.principal.CustomTokenPrincipal;
 import org.apache.wss4j.common.saml.OpenSAMLUtil;
@@ -67,7 +62,6 @@ import org.apache.wss4j.dom.WSConstants;
 import org.apache.wss4j.dom.WSDocInfo;
 import org.apache.wss4j.dom.WSSecurityEngineResult;
 import org.apache.wss4j.dom.handler.RequestData;
-import org.apache.wss4j.dom.message.token.X509Security;
 import org.apache.wss4j.dom.processor.Processor;
 import org.apache.wss4j.dom.processor.SAMLTokenProcessor;
 import org.junit.BeforeClass;
@@ -245,21 +239,10 @@ public class IssueUnitTest extends Abstr
         SpringBusFactory.setDefaultBus(bus);
         SpringBusFactory.setThreadDefaultBus(bus);
         
-        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
-        DocumentBuilder builder = factory.newDocumentBuilder();
-        Document doc = builder.newDocument();
-        
-        X509Security bst = new X509Security(doc);
-        Crypto crypto = CryptoFactory.getInstance("clientKeystore.properties");
-        CryptoType cryptoType = new CryptoType(CryptoType.TYPE.ALIAS);
-        cryptoType.setAlias("myclientkey");
-        X509Certificate[] certs = crypto.getX509Certificates(cryptoType);
-        bst.setX509Certificate(certs[0]);
-        
         // Get a token
         SecurityToken token = 
             requestSecurityToken(
-                SAML2_TOKEN_TYPE, BEARER_KEYTYPE, bst.getElement(), bus, DEFAULT_ADDRESS, null, null, null, null
+                SAML2_TOKEN_TYPE, BEARER_KEYTYPE, null, bus, DEFAULT_ADDRESS, null, null, null, null
             );
         assertTrue(SAML2_TOKEN_TYPE.equals(token.getTokenType()));
         assertTrue(token.getToken() != null);

Modified: cxf/trunk/services/sts/systests/basic/src/test/resources/org/apache/cxf/systest/sts/deployment/cxf-transport.xml
URL: http://svn.apache.org/viewvc/cxf/trunk/services/sts/systests/basic/src/test/resources/org/apache/cxf/systest/sts/deployment/cxf-transport.xml?rev=1520272&r1=1520271&r2=1520272&view=diff
==============================================================================
--- cxf/trunk/services/sts/systests/basic/src/test/resources/org/apache/cxf/systest/sts/deployment/cxf-transport.xml (original)
+++ cxf/trunk/services/sts/systests/basic/src/test/resources/org/apache/cxf/systest/sts/deployment/cxf-transport.xml Thu Sep  5 10:38:30 2013
@@ -46,11 +46,43 @@
             <cxf:logging/>
         </cxf:features>
     </cxf:bus>
+    
+    <bean id="hokDelegationHandler"
+          class="org.apache.cxf.systest.sts.common.HOKDelegationHandler" />
 
     <bean id="transportSTSProviderBean2"
         class="org.apache.cxf.ws.security.sts.provider.SecurityTokenServiceProvider">
-        <property name="issueOperation" ref="transportIssueDelegate" />
-        <property name="validateOperation" ref="transportValidateDelegate" />
+        <property name="issueOperation" ref="transportIssueDelegate2" />
+        <property name="validateOperation" ref="transportValidateDelegate2" />
+    </bean>
+
+    <bean id="transportIssueDelegate2" class="org.apache.cxf.sts.operation.TokenIssueOperation">
+        <property name="tokenProviders" ref="transportTokenProviders2" />
+        <property name="tokenValidators" ref="transportTokenValidators" />
+        <property name="services" ref="transportService" />
+        <property name="stsProperties" ref="transportSTSProperties" />
+        <property name="delegationHandler" ref="hokDelegationHandler" />
+    </bean>
+
+    <bean id="transportValidateDelegate2" class="org.apache.cxf.sts.operation.TokenValidateOperation">
+        <property name="tokenValidators" ref="transportTokenValidators2" />
+        <property name="stsProperties" ref="transportSTSProperties" />
+    </bean>
+
+    <util:list id="transportTokenValidators2">
+        <ref bean="transportSamlTokenValidator2" />
+    </util:list>
+
+    <util:list id="transportTokenProviders2">
+        <ref bean="transportSamlTokenProvider2" />
+    </util:list>
+    
+     <bean id="transportSamlTokenValidator2" class="org.apache.cxf.sts.token.validator.SAMLTokenValidator">
+        <property name="samlRealmCodec" ref="samlRealmCodec" />
+    </bean>
+    
+    <bean id="transportSamlTokenProvider2" class="org.apache.cxf.sts.token.provider.SAMLTokenProvider">
+        <property name="realmMap" ref="realms"/>
     </bean>
 
     <bean id="transportIssueDelegate" class="org.apache.cxf.sts.operation.TokenIssueOperation">
@@ -58,13 +90,14 @@
         <property name="tokenValidators" ref="transportTokenValidators" />
         <property name="services" ref="transportService" />
         <property name="stsProperties" ref="transportSTSProperties" />
+        <property name="delegationHandler" ref="hokDelegationHandler" />
     </bean>
 
     <bean id="transportValidateDelegate" class="org.apache.cxf.sts.operation.TokenValidateOperation">
         <property name="tokenValidators" ref="transportTokenValidators" />
         <property name="stsProperties" ref="transportSTSProperties" />
     </bean>
-
+    
     <util:list id="transportTokenValidators">
         <ref bean="transportSamlTokenValidator" />
     </util:list>
@@ -72,14 +105,18 @@
     <util:list id="transportTokenProviders">
         <ref bean="transportSamlTokenProvider" />
     </util:list>
-
+    
+    <bean id="transportSamlTokenValidator" class="org.apache.cxf.sts.token.validator.SAMLTokenValidator">
+    </bean>
+    
+    <bean id="transportSamlTokenProvider" class="org.apache.cxf.sts.token.provider.SAMLTokenProvider">
+    </bean>
 
     <bean id="transportSTSProviderBean"
-        class="org.apache.cxf.sts.provider.DefaultSecurityTokenServiceProvider">
-        <property name="services" ref="transportService" />
-        <property name="stsProperties" ref="transportSTSProperties" />
+        class="org.apache.cxf.ws.security.sts.provider.SecurityTokenServiceProvider">
+        <property name="issueOperation" ref="transportIssueDelegate" />
+        <property name="validateOperation" ref="transportValidateDelegate" />
     </bean>
-
  
     <bean id="transportService" class="org.apache.cxf.sts.service.StaticService">
         <property name="endpoints" ref="transportEndpoints" />
@@ -90,14 +127,6 @@
         </value>
     </util:list>
     
-    <bean id="transportSamlTokenValidator" class="org.apache.cxf.sts.token.validator.SAMLTokenValidator">
-        <property name="samlRealmCodec" ref="samlRealmCodec" />
-    </bean>
-    
-    <bean id="transportSamlTokenProvider" class="org.apache.cxf.sts.token.provider.SAMLTokenProvider">
-        <property name="realmMap" ref="realms"/>
-    </bean>
-    
     <bean id="realmA"
         class="org.apache.cxf.sts.token.realm.SAMLRealm">
         <property name="issuer" value="a-issuer"/>

Modified: cxf/trunk/services/sts/systests/basic/src/test/resources/org/apache/cxf/systest/sts/deployment/cxf-x509.xml
URL: http://svn.apache.org/viewvc/cxf/trunk/services/sts/systests/basic/src/test/resources/org/apache/cxf/systest/sts/deployment/cxf-x509.xml?rev=1520272&r1=1520271&r2=1520272&view=diff
==============================================================================
--- cxf/trunk/services/sts/systests/basic/src/test/resources/org/apache/cxf/systest/sts/deployment/cxf-x509.xml (original)
+++ cxf/trunk/services/sts/systests/basic/src/test/resources/org/apache/cxf/systest/sts/deployment/cxf-x509.xml Thu Sep  5 10:38:30 2013
@@ -46,12 +46,16 @@
 	    <property name="issueOperation" ref="x509IssueDelegate" />
 	    <property name="validateOperation" ref="x509ValidateDelegate" />
     </bean>
+    
+    <bean id="utDelegationHandler"
+          class="org.apache.cxf.sts.request.UsernameTokenDelegationHandler" />
 
 	<bean id="x509IssueDelegate" class="org.apache.cxf.sts.operation.TokenIssueOperation">
 		<property name="tokenProviders" ref="x509SamlTokenProvider" />
 		<property name="tokenValidators" ref="x509TokenValidatorsOBO" />
 		<property name="services" ref="x509Service" />
 		<property name="stsProperties" ref="x509STSProperties" />
+		<property name="delegationHandler" ref="utDelegationHandler" />
 	</bean>
 
 	<bean id="x509ValidateDelegate" class="org.apache.cxf.sts.operation.TokenValidateOperation">