[[ActAs_WS-Trust_Scenario]]
= ActAs WS-Trust Scenario

The ActAs feature is used in scenarios that require composite
delegation. It is commonly used in multi-tiered systems where an
application calls a service on behalf of a logged in user or a service
calls another service on behalf of the original caller.

ActAs is nothing more than a new sub-element in the RequestSecurityToken
(RST). It provides additional information about the original caller when
a token is negotiated with the STS. The ActAs element usually takes the
form of a token with identity claims such as name, role, and
authorization code, for the client to access the service.

The ActAs scenario is an extension of
<<ActAs_WS-Trust_Scenario,the basic
WS-Trust scenario>>. In this example the ActAs service calls the
ws-service on behalf of a user. There are only a couple of additions to
the basic scenario's code. An ActAs web service provider and callback
handler have been added. The ActAs web services' WSDL imposes the same
security policies as the ws-provider. UsernameTokenCallbackHandler is
new. It is a utility that generates the content for the ActAs element.
And lastly there are a couple of code additions in the STS to support
the ActAs request.

== Web service provider

This section examines the web service elements from the basic WS-Trust
scenario that have been changed to address the needs of the ActAs
example. The components are

* ActAs web service provider's WSDL
* ActAs web service provider's Interface and Implementation classes.
* ActAsCallbackHandler class
* UsernameTokenCallbackHandler
* Crypto properties and keystore files
* MANIFEST.MF

=== Web service provider WSDL

The ActAs web service provider's WSDL is a clone of the ws-provider's
WSDL. The wsp:Policy section is the same. There are changes to the
service endpoint, targetNamespace, portType, binding name, and service.

[source,xml]
----
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<definitions targetNamespace="http://www.jboss.org/jbossws/ws-extensions/actaswssecuritypolicy" name="ActAsService"
             xmlns:tns="http://www.jboss.org/jbossws/ws-extensions/actaswssecuritypolicy"
             xmlns:xsd="http://www.w3.org/2001/XMLSchema"
             xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
             xmlns="http://schemas.xmlsoap.org/wsdl/"
             xmlns:wsp="http://www.w3.org/ns/ws-policy"
             xmlns:wsam="http://www.w3.org/2007/05/addressing/metadata"
             xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
             xmlns:wsaws="http://www.w3.org/2005/08/addressing"
             xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702"
             xmlns:t="http://docs.oasis-open.org/ws-sx/ws-trust/200512">
    <types>
        <xsd:schema>
            <xsd:import namespace="http://www.jboss.org/jbossws/ws-extensions/actaswssecuritypolicy"
                    schemaLocation="ActAsService_schema1.xsd"/>
        </xsd:schema>
    </types>
    <message name="sayHello">
        <part name="parameters" element="tns:sayHello"/>
    </message>
    <message name="sayHelloResponse">
        <part name="parameters" element="tns:sayHelloResponse"/>
    </message>
    <portType name="ActAsServiceIface">
        <operation name="sayHello">
            <input message="tns:sayHello"/>
            <output message="tns:sayHelloResponse"/>
        </operation>
    </portType>
    <binding name="ActAsServicePortBinding" type="tns:ActAsServiceIface">
        <wsp:PolicyReference URI="#AsymmetricSAML2Policy" />
        <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document"/>
        <operation name="sayHello">
            <soap:operation soapAction=""/>
            <input>
                <soap:body use="literal"/>
                <wsp:PolicyReference URI="#Input_Policy" />
            </input>
            <output>
                <soap:body use="literal"/>
                <wsp:PolicyReference URI="#Output_Policy" />
            </output>
        </operation>
    </binding>
    <service name="ActAsService">
        <port name="ActAsServicePort" binding="tns:ActAsServicePortBinding">
            <soap:address location="http://@jboss.bind.address@:8080/jaxws-samples-wsse-policy-trust-actas/ActAsService"/>
        </port>
    </service>
 
</definitions>
----

[[web-service-interface]]
=== Web Service Interface

The web service provider interface class, ActAsServiceIface, is a simple
web service definition.

[source, java]
----
package org.jboss.test.ws.jaxws.samples.wsse.policy.trust.actas;
 
import javax.jws.WebMethod;
import javax.jws.WebService;
 
@WebService
(
   targetNamespace = "http://www.jboss.org/jbossws/ws-extensions/actaswssecuritypolicy"
)
public interface ActAsServiceIface
{
   @WebMethod
   String sayHello();
}
----

[[web-service-implementation]]
=== Web Service Implementation

The web service provider implementation class, ActAsServiceImpl, is a
simple POJO. It uses the standard WebService annotation to define the
service endpoint and two Apache WSS4J annotations, EndpointProperties
and EndpointProperty used for configuring the endpoint for the CXF
runtime. The WSS4J configuration information provided is for WSS4J's
Crypto Merlin implementation.

ActAsServiceImpl is calling ServiceImpl acting on behalf of the user.
Method setupService performs the requisite configuration setup.

[source, java]
----
package org.jboss.test.ws.jaxws.samples.wsse.policy.trust.actas;
 
import org.apache.cxf.Bus;
import org.apache.cxf.BusFactory;
import org.apache.cxf.annotations.EndpointProperties;
import org.apache.cxf.annotations.EndpointProperty;
import org.apache.cxf.ws.security.SecurityConstants;
import org.apache.cxf.ws.security.trust.STSClient;
import org.jboss.test.ws.jaxws.samples.wsse.policy.trust.service.ServiceIface;
import org.jboss.test.ws.jaxws.samples.wsse.policy.trust.shared.WSTrustAppUtils;
 
import javax.jws.WebService;
import javax.xml.namespace.QName;
import javax.xml.ws.BindingProvider;
import javax.xml.ws.Service;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Map;
 
@WebService
(
   portName = "ActAsServicePort",
   serviceName = "ActAsService",
   wsdlLocation = "WEB-INF/wsdl/ActAsService.wsdl",
   targetNamespace = "http://www.jboss.org/jbossws/ws-extensions/actaswssecuritypolicy",
   endpointInterface = "org.jboss.test.ws.jaxws.samples.wsse.policy.trust.actas.ActAsServiceIface"
)
 
@EndpointProperties(value = {
      @EndpointProperty(key = "ws-security.signature.username", value = "myactaskey"),
      @EndpointProperty(key = "ws-security.signature.properties", value =  "actasKeystore.properties"),
      @EndpointProperty(key = "ws-security.encryption.properties", value = "actasKeystore.properties"),
      @EndpointProperty(key = "ws-security.callback-handler", value = "org.jboss.test.ws.jaxws.samples.wsse.policy.trust.actas.ActAsCallbackHandler")
})
 
public class ActAsServiceImpl implements ActAsServiceIface
{
   public String sayHello() {
      try {
         ServiceIface proxy = setupService();
         return "ActAs " + proxy.sayHello();
      } catch (MalformedURLException e) {
         e.printStackTrace();
      }
      return null;
   }
 
   private  ServiceIface setupService()throws MalformedURLException {
      ServiceIface proxy = null;
      Bus bus = BusFactory.newInstance().createBus();
 
      try {
         BusFactory.setThreadDefaultBus(bus);
 
         final String serviceURL = "http://" + WSTrustAppUtils.getServerHost() + ":8080/jaxws-samples-wsse-policy-trust/SecurityService";
         final QName serviceName = new QName("http://www.jboss.org/jbossws/ws-extensions/wssecuritypolicy", "SecurityService");
         final URL wsdlURL = new URL(serviceURL + "?wsdl");
         Service service = Service.create(wsdlURL, serviceName);
         proxy = (ServiceIface) service.getPort(ServiceIface.class);
 
         Map<String, Object> ctx = ((BindingProvider) proxy).getRequestContext();
         ctx.put(SecurityConstants.CALLBACK_HANDLER, new ActAsCallbackHandler());
 
         ctx.put(SecurityConstants.SIGNATURE_PROPERTIES,
            Thread.currentThread().getContextClassLoader().getResource("actasKeystore.properties" ));
         ctx.put(SecurityConstants.SIGNATURE_USERNAME, "myactaskey" );
         ctx.put(SecurityConstants.ENCRYPT_PROPERTIES,
            Thread.currentThread().getContextClassLoader().getResource("../../META-INF/clientKeystore.properties" ));
         ctx.put(SecurityConstants.ENCRYPT_USERNAME, "myservicekey");
 
         STSClient stsClient = new STSClient(bus);
         Map<String, Object> props = stsClient.getProperties();
         props.put(SecurityConstants.USERNAME, "alice");
         props.put(SecurityConstants.ENCRYPT_USERNAME, "mystskey");
         props.put(SecurityConstants.STS_TOKEN_USERNAME, "myactaskey" );
         props.put(SecurityConstants.STS_TOKEN_PROPERTIES,
            Thread.currentThread().getContextClassLoader().getResource("actasKeystore.properties" ));
         props.put(SecurityConstants.STS_TOKEN_USE_CERT_FOR_KEYINFO, "true");
 
         ctx.put(SecurityConstants.STS_CLIENT, stsClient);
 
      } finally {
         bus.shutdown(true);
      }
 
      return proxy;
   }
 
}
----

[[actascallbackhandler]]
=== ActAsCallbackHandler

ActAsCallbackHandler is a callback handler for the WSS4J Crypto API. It
is used to obtain the password for the private key in the keystore. This
class enables CXF to retrieve the password of the user name to use for
the message signature. This class has been revised to return the
passwords for this service, myactaskey and the "actas" user, alice.

[source, java]
----
package org.jboss.test.ws.jaxws.samples.wsse.policy.trust.actas;
 
import org.jboss.wsf.stack.cxf.extensions.security.PasswordCallbackHandler;
import java.util.HashMap;
import java.util.Map;
 
public class ActAsCallbackHandler extends PasswordCallbackHandler {
 
   public ActAsCallbackHandler()
   {
      super(getInitMap());
   }
 
   private static Map<String, String> getInitMap()
   {
      Map<String, String> passwords = new HashMap<String, String>();
      passwords.put("myactaskey", "aspass");
      passwords.put("alice", "clarinet");
      return passwords;
   }
}
----

[[usernametokencallbackhandler]]
=== UsernameTokenCallbackHandler

The ActAs and OnBeholdOf sub-elements of the RequestSecurityToken are
required to be defined as WSSE Username Tokens. This utility generates
the properly formated element.

[source, java]
----
package org.jboss.test.ws.jaxws.samples.wsse.policy.trust.shared;
 
import org.apache.cxf.helpers.DOMUtils;
import org.apache.cxf.message.Message;
import org.apache.cxf.ws.security.SecurityConstants;
import org.apache.cxf.ws.security.trust.delegation.DelegationCallback;
import org.apache.ws.security.WSConstants;
import org.apache.ws.security.message.token.UsernameToken;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.Element;
import org.w3c.dom.ls.DOMImplementationLS;
import org.w3c.dom.ls.LSSerializer;
 
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.UnsupportedCallbackException;
import java.io.IOException;
import java.util.Map;
 
/**
* A utility to provide the 3 different input parameter types for jaxws property
* "ws-security.sts.token.act-as" and "ws-security.sts.token.on-behalf-of".
* This implementation obtains a username and password via the jaxws property
* "ws-security.username" and "ws-security.password" respectively, as defined
* in SecurityConstants.  It creates a wss UsernameToken to be used as the
* delegation token.
*/
 
public class UsernameTokenCallbackHandler implements CallbackHandler {
 
   public void handle(Callback[] callbacks)
      throws IOException, UnsupportedCallbackException {
      for (int i = 0; i < callbacks.length; i++) {
         if (callbacks[i] instanceof DelegationCallback) {
            DelegationCallback callback = (DelegationCallback) callbacks[i];
            Message message = callback.getCurrentMessage();
 
            String username =
               (String)message.getContextualProperty(SecurityConstants.USERNAME);
            String password =
               (String)message.getContextualProperty(SecurityConstants.PASSWORD);
            if (username != null) {
               Node contentNode = message.getContent(Node.class);
               Document doc = null;
               if (contentNode != null) {
                  doc = contentNode.getOwnerDocument();
               } else {
                  doc = DOMUtils.createDocument();
               }
               UsernameToken usernameToken = createWSSEUsernameToken(username,password, doc);
               callback.setToken(usernameToken.getElement());
            }
         } else {
            throw new UnsupportedCallbackException(callbacks[i], "Unrecognized Callback");
         }
      }
   }
 
   /**
    * Provide UsernameToken as a string.
    * @param ctx
    * @return
    */
   public String getUsernameTokenString(Map<String, Object> ctx){
      Document doc = DOMUtils.createDocument();
      String result = null;
      String username = (String)ctx.get(SecurityConstants.USERNAME);
      String password = (String)ctx.get(SecurityConstants.PASSWORD);
      if (username != null) {
         UsernameToken usernameToken = createWSSEUsernameToken(username,password, doc);
         result = toString(usernameToken.getElement().getFirstChild().getParentNode());
      }
      return result;
   }
 
   /**
    *
    * @param username
    * @param password
    * @return
    */
   public String getUsernameTokenString(String username, String password){
      Document doc = DOMUtils.createDocument();
      String result = null;
      if (username != null) {
         UsernameToken usernameToken = createWSSEUsernameToken(username,password, doc);
         result = toString(usernameToken.getElement().getFirstChild().getParentNode());
      }
      return result;
   }
 
   /**
    * Provide UsernameToken as a DOM Element.
    * @param ctx
    * @return
    */
   public Element getUsernameTokenElement(Map<String, Object> ctx){
      Document doc = DOMUtils.createDocument();
      Element result = null;
      UsernameToken usernameToken = null;
         String username = (String)ctx.get(SecurityConstants.USERNAME);
      String password = (String)ctx.get(SecurityConstants.PASSWORD);
      if (username != null) {
         usernameToken = createWSSEUsernameToken(username,password, doc);
         result = usernameToken.getElement();
      }
      return result;
   }
 
   /**
    *
    * @param username
    * @param password
    * @return
    */
   public Element getUsernameTokenElement(String username, String password){
      Document doc = DOMUtils.createDocument();
      Element result = null;
      UsernameToken usernameToken = null;
      if (username != null) {
         usernameToken = createWSSEUsernameToken(username,password, doc);
         result = usernameToken.getElement();
      }
      return result;
   }
 
   private UsernameToken createWSSEUsernameToken(String username, String password, Document doc) {
 
      UsernameToken usernameToken = new UsernameToken(true, doc,
         (password == null)? null: WSConstants.PASSWORD_TEXT);
      usernameToken.setName(username);
      usernameToken.addWSUNamespace();
      usernameToken.addWSSENamespace();
      usernameToken.setID("id-" + username);
 
      if (password != null){
         usernameToken.setPassword(password);
      }
 
      return usernameToken;
   }
 
 
   private String toString(Node node) {
      String str = null;
 
      if (node != null) {
         DOMImplementationLS lsImpl = (DOMImplementationLS)
            node.getOwnerDocument().getImplementation().getFeature("LS", "3.0");
         LSSerializer serializer = lsImpl.createLSSerializer();
         serializer.getDomConfig().setParameter("xml-declaration", false); //by default its true, so set it to false to get String without xml-declaration
         str = serializer.writeToString(node);
      }
      return str;
   }
 
}
----

[[crypto-properties-and-keystore-files]]
=== Crypto properties and keystore files

The ActAs service must provide its own credentials. The requisite
properties file, actasKeystore.properties, and keystore, actasstore.jks,
were created.

....
org.apache.ws.security.crypto.provider=org.apache.ws.security.components.crypto.Merlin
org.apache.ws.security.crypto.merlin.keystore.type=jks
org.apache.ws.security.crypto.merlin.keystore.password=aapass
org.apache.ws.security.crypto.merlin.keystore.alias=myactaskey
org.apache.ws.security.crypto.merlin.keystore.file=actasstore.jks
....

[[manifest.mf]]
=== MANIFEST.MF

When deployed on WildFly this application requires access to the JBossWs
and CXF APIs provided in modules org.jboss.ws.cxf.jbossws-cxf-client and
org.apache.cxf. The Apache CXF internals, org.apache.cxf.impl, are
needed in handling the ActAs and OnBehalfOf extensions. The dependency
statement directs the server to provide them at deployment.

....
Manifest-Version: 1.0
Ant-Version: Apache Ant 1.8.2
Created-By: 1.7.0_25-b15 (Oracle Corporation)
Dependencies: org.jboss.ws.cxf.jbossws-cxf-client, org.apache.cxf.impl
....

[[security-token-service]]
== Security Token Service

This section examines the STS elements from the basic WS-Trust scenario
that have been changed to address the needs of the ActAs example. The
components are.

* STS's implementation class.
* STSCallbackHandler class

[[sts-implementation-class]]
=== STS Implementation class

The initial description of SampleSTS can be found
<<sts-implementation-class,here>>.

The declaration of the set of allowed token recipients by address has
been extended to accept ActAs addresses and OnBehalfOf addresses. The
addresses are specified as reg-ex patterns.

The TokenIssueOperation requires class, UsernameTokenValidator be
provided in order to validate the contents of the OnBehalfOf claims and
class, UsernameTokenDelegationHandler to be provided in order to process
the token delegation request of the ActAs on OnBehalfOf user.

[source, java]
----
 package org.jboss.test.ws.jaxws.samples.wsse.policy.trust.sts;
 
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
 
import javax.xml.ws.WebServiceProvider;
 
import org.apache.cxf.annotations.EndpointProperties;
import org.apache.cxf.annotations.EndpointProperty;
import org.apache.cxf.interceptor.InInterceptors;
import org.apache.cxf.sts.StaticSTSProperties;
import org.apache.cxf.sts.operation.TokenIssueOperation;
import org.apache.cxf.sts.operation.TokenValidateOperation;
import org.apache.cxf.sts.service.ServiceMBean;
import org.apache.cxf.sts.service.StaticService;
import org.apache.cxf.sts.token.delegation.UsernameTokenDelegationHandler;
import org.apache.cxf.sts.token.provider.SAMLTokenProvider;
import org.apache.cxf.sts.token.validator.SAMLTokenValidator;
import org.apache.cxf.sts.token.validator.UsernameTokenValidator;
import org.apache.cxf.ws.security.sts.provider.SecurityTokenServiceProvider;
 
@WebServiceProvider(serviceName = "SecurityTokenService",
      portName = "UT_Port",
      targetNamespace = "http://docs.oasis-open.org/ws-sx/ws-trust/200512/",
      wsdlLocation = "WEB-INF/wsdl/ws-trust-1.4-service.wsdl")
//be sure to have dependency on org.apache.cxf module when on AS7, otherwise Apache CXF annotations are ignored
@EndpointProperties(value = {
      @EndpointProperty(key = "ws-security.signature.username", value = "mystskey"),
      @EndpointProperty(key = "ws-security.signature.properties", value = "stsKeystore.properties"),
      @EndpointProperty(key = "ws-security.callback-handler", value = "org.jboss.test.ws.jaxws.samples.wsse.policy.trust.sts.STSCallbackHandler"),
      @EndpointProperty(key = "ws-security.validate.token", value = "false") //to let the JAAS integration deal with validation through the interceptor below
})
@InInterceptors(interceptors = {"org.jboss.wsf.stack.cxf.security.authentication.SubjectCreatingPolicyInterceptor"})
public class SampleSTS extends SecurityTokenServiceProvider
{
   public SampleSTS() throws Exception
   {
      super();
 
      StaticSTSProperties props = new StaticSTSProperties();
      props.setSignatureCryptoProperties("stsKeystore.properties");
      props.setSignatureUsername("mystskey");
      props.setCallbackHandlerClass(STSCallbackHandler.class.getName());
      props.setIssuer("DoubleItSTSIssuer");
 
      List<ServiceMBean> services = new LinkedList<ServiceMBean>();
      StaticService service = new StaticService();
      service.setEndpoints(Arrays.asList(
         "http://localhost:(\\d)*/jaxws-samples-wsse-policy-trust/SecurityService",
         "http://\\[::1\\]:(\\d)*/jaxws-samples-wsse-policy-trust/SecurityService",
         "http://\\[0:0:0:0:0:0:0:1\\]:(\\d)*/jaxws-samples-wsse-policy-trust/SecurityService",
 
         "http://localhost:(\\d)*/jaxws-samples-wsse-policy-trust-actas/ActAsService",
         "http://\\[::1\\]:(\\d)*/jaxws-samples-wsse-policy-trust-actas/ActAsService",
         "http://\\[0:0:0:0:0:0:0:1\\]:(\\d)*/jaxws-samples-wsse-policy-trust-actas/ActAsService",
 
         "http://localhost:(\\d)*/jaxws-samples-wsse-policy-trust-onbehalfof/OnBehalfOfService",
         "http://\\[::1\\]:(\\d)*/jaxws-samples-wsse-policy-trust-onbehalfof/OnBehalfOfService",
         "http://\\[0:0:0:0:0:0:0:1\\]:(\\d)*/jaxws-samples-wsse-policy-trust-onbehalfof/OnBehalfOfService"
      ));
      services.add(service);
 
      TokenIssueOperation issueOperation = new TokenIssueOperation();
      issueOperation.setServices(services);
      issueOperation.getTokenProviders().add(new SAMLTokenProvider());
      // required for OnBehalfOf
      issueOperation.getTokenValidators().add(new UsernameTokenValidator());
      // added for OnBehalfOf and ActAs
      issueOperation.getDelegationHandlers().add(new UsernameTokenDelegationHandler());
      issueOperation.setStsProperties(props);
 
      TokenValidateOperation validateOperation = new TokenValidateOperation();
      validateOperation.getTokenValidators().add(new SAMLTokenValidator());
      validateOperation.setStsProperties(props);
 
      this.setIssueOperation(issueOperation);
      this.setValidateOperation(validateOperation);
   }
}
----

[[stscallbackhandler]]
=== STSCallbackHandler

The user, alice, and corresponding password was required to be added for
the ActAs example.

[source, java]
----
package org.jboss.test.ws.jaxws.samples.wsse.policy.trust.sts;
 
import java.util.HashMap;
import java.util.Map;
 
import org.jboss.wsf.stack.cxf.extensions.security.PasswordCallbackHandler;
 
public class STSCallbackHandler extends PasswordCallbackHandler
{
   public STSCallbackHandler()
   {
      super(getInitMap());
   }
 
   private static Map<String, String> getInitMap()
   {
      Map<String, String> passwords = new HashMap<String, String>();
      passwords.put("mystskey", "stskpass");
      passwords.put("alice", "clarinet");
      return passwords;
   }
}
----

[[web-service-requester]]
== Web service requester

This section examines the ws-requester elements from the basic WS-Trust
scenario that have been changed to address the needs of the ActAs
example. The component is

* ActAs web service requester implementation class

[[web-service-requester-implementation]]
=== Web service requester Implementation

The ActAs ws-requester, the client, uses standard procedures for
creating a reference to the web service in the first four lines. To
address the endpoint security requirements, the web service's "Request
Context" is configured via the BindingProvider. Information needed in
the message generation is provided through it. The ActAs user,
myactaskey, is declared in this section and UsernameTokenCallbackHandler
is used to provide the contents of the ActAs element to the STSClient.
In this example a STSClient object is created and provided to the
proxy's request context. The alternative is to provide keys tagged with
the ".it" suffix as was done in
https://docs.jboss.org/author/display/JBWS/WS-Trust+and+STS#WS-TrustandSTS-WebservicerequesterImplementation[the
Basic Scenario client]. The use of ActAs is configured through the props
map using the SecurityConstants.STS_TOKEN_ACT_AS key. The alternative is
to use the STSClient.setActAs method.

[source, java]
----
 final QName serviceName = new QName("http://www.jboss.org/jbossws/ws-extensions/actaswssecuritypolicy", "ActAsService");
final URL wsdlURL = new URL(serviceURL + "?wsdl");
Service service = Service.create(wsdlURL, serviceName);
ActAsServiceIface proxy = (ActAsServiceIface) service.getPort(ActAsServiceIface.class);
 
Bus bus = BusFactory.newInstance().createBus();
try {
    BusFactory.setThreadDefaultBus(bus);
 
    Map<String, Object> ctx = proxy.getRequestContext();
 
    ctx.put(SecurityConstants.CALLBACK_HANDLER, new ClientCallbackHandler());
    ctx.put(SecurityConstants.ENCRYPT_PROPERTIES,
        Thread.currentThread().getContextClassLoader().getResource(
        "META-INF/clientKeystore.properties"));
    ctx.put(SecurityConstants.ENCRYPT_USERNAME, "myactaskey");
    ctx.put(SecurityConstants.SIGNATURE_PROPERTIES,
        Thread.currentThread().getContextClassLoader().getResource(
        "META-INF/clientKeystore.properties"));
    ctx.put(SecurityConstants.SIGNATURE_USERNAME, "myclientkey");
 
    // Generate the ActAs element contents and pass to the STSClient as a string
    UsernameTokenCallbackHandler ch = new UsernameTokenCallbackHandler();
    String str = ch.getUsernameTokenString("alice","clarinet");
    ctx.put(SecurityConstants.STS_TOKEN_ACT_AS, str);
 
    STSClient stsClient = new STSClient(bus);
    Map<String, Object> props = stsClient.getProperties();
    props.put(SecurityConstants.USERNAME, "bob");
    props.put(SecurityConstants.CALLBACK_HANDLER, new ClientCallbackHandler());
    props.put(SecurityConstants.ENCRYPT_PROPERTIES,
        Thread.currentThread().getContextClassLoader().getResource(
        "META-INF/clientKeystore.properties"));
    props.put(SecurityConstants.ENCRYPT_USERNAME, "mystskey");
    props.put(SecurityConstants.STS_TOKEN_USERNAME, "myclientkey");
    props.put(SecurityConstants.STS_TOKEN_PROPERTIES,
        Thread.currentThread().getContextClassLoader().getResource(
        "META-INF/clientKeystore.properties"));
    props.put(SecurityConstants.STS_TOKEN_USE_CERT_FOR_KEYINFO, "true");
 
    ctx.put(SecurityConstants.STS_CLIENT, stsClient);
} finally {
    bus.shutdown(true);
}
proxy.sayHello();
----
