Friday May 28, 2010

Security Token Service and Identity Delegation with Metro

by Jiandong Guo

Metro is a high performance, extensible, easy-to-use web services stack. It combines the JAX-WS reference implementation with Web Services Interoperability Technology (WSIT), an implementation of numerous WS-\* standards to enable interoperability with other implementations and to provide Quality of Service (QOS) features such as security, reliability, and transaction support. Metro is available in the open source, enterprise-ready, modular GlassFish v3 application server as well as in the open source, enterprise-ready, GlassFish v2 application server. Metro also runs in the Tomcat web container. In addition, it has been successfully used in other application servers.

WSIT implements the following web services security specifications published by the Organization for the Advancement of Structured Information Standards (OASIS) consortium: WS-Security, WS-SecurityPolicy, WS-SecureConversation, and WS-Trust. An earlier tech tip, Using WS-Trust Support in Metro to Secure Web Services, focused on the support in Metro for WS-Trust. It described the basics of WS-Trust and its Security Token Service (STS) framework and showed how to take advantage of Metro's support of WS-Trust and STS to secure a web service.

The latest release of Metro, Metro 2.0, provides many enhancements and new features, which are described in Metro 2.0 One Pagers. Among those enhancements is support for WS-Trust 1.4 and WS-SecureConversation 1.4. The following tip describes how you can use the enhanced support for WS-Trust and WS-SecureConversation in Metro 2.0 to access a back-end resource through a chain of services. You'll also learn how identity delegation in STS is used to access the back-end resource in a secure way.

A sample application package accompanies the tip. The package includes a sample application that demonstrates the concepts and techniques described in this tip. The code examples shown in the tip are taken from source code in the sample application.

Identity Delegation

To understand identity delegation, let's briefly review some basic concepts related to WS-Trust and STS. WS-Trust is a WS-\* specification that provides extensions to the WS-Security specification. WS-Security provides the basic framework for message level security in web services. WS-Trust builds on that base to specify a framework for broker trust across different security domains. It specifically deals with the issuing, renewing, and validating of security tokens, as well as with ways to establish, assess the presence of, and broker trust relationships between participants in a secure message exchange.

For a web service and its client to communicate securely there needs to be a trust relationship established between the service and the client. If the service and client are in the same security domain they can have a direct trust relationship. In this type of relationship the service and client can authenticate each other directly.

However, if the client and the service are in different security domains they have no direct trust relationship. In that case, you can use an STS to authenticate the client. The STS is an authority trusted by the client and the service. You can also use an STS to issue a security token, that is, a collection of claims such as name, role, and authorization code, for the client to access the service. A request for a security token is made by sending a Request Security Token (RST) message to the STS using an <wst:RequestSecurityToken> element.

The STS approach works well if a client needs to securely access a service in another domain. But what if the called service needs to securely access another service on behalf of the original client? For example, what if the client needs to securely access a back-end resource through the second service? In previous versions of WS-Trust, there was no way to pass along the authenticated identity of the client through this chain of services. That obstacle was resolved in the current version of the WS-Trust specification, WS-Trust 1.4.

In particular, WS-Trust 1.4 defines extensions to the <wst:RequestSecurityToken> element for indicating delegation and forwarding requirements on the requested security token. One of those extensions is the <wst:ActAs> element. The specification defines the <wst:ActAs> element as follows:

This OPTIONAL element indicates that the requested token is expected to contain information about the identity represented by the content of this element and the token requestor intends to use the returned token to act as this identity. The identity that the requestor wants to act-as is specified by placing a security token or <wsse:SecurityTokenReference> element within the <wst:ActAs> element.

In other words, by specifying a token in the <wst:ActAs> element of an RST — let's call the <wst:ActAs> element the "ActAs" element — you can request an STS to issue a security token that contains information about the identity specified in the ActAs element. The identity in the ActAs element can be that of the original caller. By specifying a token in the ActAs element — let's call the token the "ActAs token" — that identifies a client, you can enable one service to call another service in a secure way on behalf of a client.

Figure 1 illustrates the control flow in a typical identity delegation scenario. Here a client, Client, wants to access a back-end resource (not shown) across security domains. To do that, the client calls a service, Service, which in turn calls a second service, Service 1, to access the resource.

Control Flow in an Identity Delegation Scenario

Figure 1. Control Flow in an Identity Delegation Scenario

  1. Client calls the STS using an RST to authenticate itself. Client obtains a token from the STS.
  2. Client forwards the STS-issued token to Service.
  3. Service calls the STS to authenticate itself using its credential. It also specifies an ActAs token in the RST that identifies Client. In response, the STS issues a security token whose subject is Client, but that also contains an "actas" attribute identifying Service. Let's call that token the Service token.
  4. Service calls Service1, passing it the Service token. By examining the Service token, Service1 recognizes that Service is acting on behalf of the initial requester, Client.
  5. Service1 accesses the back-end resource and sends a response to Service.
  6. Service forwards the response to Client.

Implementing Identity Delegation

In order to implement identity delegation, you need to add an ActAs token to the RST submitted by the pertinent service. For example, in the identity delegation scenario illustrated in Figure 1, you need to add an ActAs token in the RST issued by Service, and that ActAs token needs to identify Client.

To do this, you can take advantage of a new feature in Metro 2.0 that allows you to programmatically inject STS information and token requirements into a web service client at run time. The following code snippet shows the code you can add to the web service client. You can find the code in the FSImpl class in the sample application. This class implements a web service named IFinancialService. In the sample application, the IFinancialService web service calls another web service, IPingService, to access a resource.


      STSIssuedTokenConfiguration config = new DefaultSTSIssuedTokenConfiguration();

         Token actAsToken = getActAsToken();
         config.getOtherOptions().put(STSIssuedTokenConfiguration.ACT_AS, actAsToken);
         STSIssuedTokenFeature feature = new STSIssuedTokenFeature(config);

         IPingService stub = service.getCustomBindingIPingService(new WebServiceFeature[]{feature});

The DefaultSTSIssuedTokenConfiguration, STSIssuedTokenConfiguration, Token, and STSIssuedTokenFeature classes are part of Metro's WS-Trust implementation. The WebServiceFeature class is a JAX-WS class implemented in Metro.

In this approach you:

  • Create an STSIssuedTokenConfiguration object to hold the run-time configuration information.
  • Get the ActAs token as a Token object and add it to the configuration object.
  • Inject the configuration as a WebServiceFeature object.

Note that in the STS, both the subject for the requestor and the subject for the act-as user are available in the STSAttributeProvider. The STSAttributeProvider class is a part of Metro's WS-Trust implementation. The class exposes an extension to WS-Trust that enables details about the requestor to be included in the token to be issued by the STS. If this extension is implemented, the provider implementation returns an attribute that is included in a SAML assertion created by the STS.

The following code snippet is from an STSAttributeProvider implementation, SampleSTSAttributeProvider, that is in the sample application.


   public Map<QName, List<String>> getClaimedAttributes(Subject subject, String appliesTo, String tokenType, Claims claims){

       // find the id of the requestor
       String name = null;

       Set<Principal> principals = subject.getPrincipals();
       if (principals != null){
           final Iterator iterator = principals.iterator();
           while (iterator.hasNext()){
               String cnName = principals.iterator().next().getName();
               int pos = cnName.indexOf("=");
               name = cnName.substring(pos+1);

       // Check if it is the ActAs case
       if ("true".equals(claims.getOtherAttributes().get(new QName("ActAs")))){
           // Get the ActAs token
           Element token = null;
           for (Object obj : claims.getSupportingProperties()){
                if (obj instanceof Subject){
                    token = (Element)((Subject)obj).getPublicCredentials().iterator().next();

       // get the attributes to be included in the SAML assertion accordingly

Securing the Back-End Service

You can secure the back-end service in a chain of services, such as Service1 in the scenario illustrated in Figure 1, with the token issued by the STS. You can also secure the back-end service with its own credential, such as an X509 certificate, or with both a token issued by the STS and a certificate. The back-end service must trust the STS, but not necessarily have a direct trust relationship with the intermediate service. Unlike the Sender-Vouches case, the back-end service should not ask for the intermediate service to provide any of its credentials to sign the issued token and the message. Instead, it trusts the STS for the validity of the service token.

The NetBeans IDE offers an easy way to enable secure conversations in Metro for a web service. For details on using the NetBeans IDE to enable secure conversations in Metro for a web service, see the tip Using WS-Trust Support in Metro to Secure Web Services.

The NetBeans IDE provides a set of security profiles that specify the mechanism to be used in securing conversations. Four of these profiles secure web services with STS-issued tokens. Here are the four profiles and the STS-issued token-based mechanisms they implement:

  • STS Issued Token. Symmetric binding with a symmetric keyed-issued token as a protection token.
  • STS Issued Token with Service Certificate. Asymmetric binding.
  • STS Issued Endorsing Token. Asymmetric binding with keyed-issued token as endorsing supporting token.
  • STS Issued Supporting Token. Symmetric binding with bearer-issued token as encrypted signed supporting token.

You can choose any of the four STS-issued token based mechanisms to secure the back-end service.

Securing the STS

In an identity delegation scenario involving a chain of services, as illustrated in Figure 1, messages exchanged between the intermediate service and the STS are secured with service credentials and STS credentials. However, the only thing changed in each request is the addition of an ActAs token to the message payload. In this situation, it makes sense to enable a secure conversation for the STS through WS-SecureConversation. The WS-SecureConversation standard introduces secure sessions on top of WS-Security. It enhances overall security through key derivations and improves performance by avoiding repeated key exchanges in multi-message exchange scenarios. So by enabling a secure conversation for the STS, you not only enhance overall security, but you can also improve performance.

You can enable a secure conversation for the STS in the same way as for a regular web service. To take advantage of the secure conversation session with the STS, you must share a common STSIssuedTokenConfiguration object with different calls from the intermediate service to the back-end service.

See the Tech Tip Secure Conversations for Web Services With Metro to learn the basics of WS-SecureConversation and see examples of using the WS-SecureConversation support in Metro.

Token Propagation

Although this tip focuses on identity delegation as a technique for securely accessing the back-end resource through a chain of services, there is an alternative approach. The intermediate service, such as Service in Figure 1, can propagate the end user's identity by calling the back-end service with the token it receives from the client. This approach is called token propagation. Figure 2 illustrates the control flow in a typical token propagation scenario.

Figure 2: Control Flow in a Token Propagation

  1. Client sends a request to the STS. The request message carries the username/password of the user and is secured with the STS certificate. The STS issues a SAML assertion containing the username as the subject ID, and the role attribute. The STS then sends a response message with the issued token to Client.
  2. Client sends a request to Service. The message carries the SAML assertion from the previous step for authentication, and is secured, that is, signed and encrypted, with the service certificate.
  3. Service sends a request to Service 1. The message carries the SAML assertion from the previous step and is secured, that is, signed and encrypted, with the Service 1 certificate. Service 1 checks the SAML assertion.
  4. Service 1 sends a response to Service.
  5. Service forwards the response to Client.

Token propagation is more efficient than identity delegation with an ActAs token. However, it is less secure than identity delegation for the following reasons:

  • The back-end service won't be able to apply the AudiencesRestrictionCondition check on the SAML assertion. The AudiencesRestrictionCondition is used to restrict the validity of a SAML assertion to a specific audience.
  • The assertion has to be used as a unkeyed assertion from the intermediate requestor to the back-end service.

For these reasons, token propagation is a better choice for service chains in the same security domain. In any case, you can configure the back-end service for token propagation using either of the following security mechanisms:

  • SAML Authorization with SSL. Transport binding using a SAML token as a SignedSupportingToken.
  • Symmetric binding using a SAML token as a SignedEncryptedSupportingToken.

The following code shows how to obtain the user SAML assertion in the intermediate service:

   Element samlAssertion = null;
   Subject subj = SubjectAccessor.getRequesterSubject(context);
   Set<Object> set = subj.getPublicCredentials();
   for (Object obj : set) {
        if (obj instanceof XMLStreamReader) {
            XMLStreamReader reader = (XMLStreamReader) obj;
            //To create a DOM Element representing the Assertion :
            samlAssertion = SAMLUtil.createSAMLAssertion(reader);
        } else if (obj instanceof Element) {
            samlAssertion = (Element) obj;

Here is how to inject to the context for the proxy to the back-end service:

   ((BindingProvider)stub).getRequestContext().put("userSAMLAssertion", getSAMLAssertion());

You can find a complete code sample for token propagation here.

The Sample Application

A sample application package that accompanies the tip. The package includes a sample application that demonstrates identity delegation using ActAs. The STS in the sample application contains two endpoints. One endpoint is for end users who require username/password for authentication. The other endpoint is for the intermediate requestor that has secure conversation enabled and requires an X509 certificate for authentication.

The intermediate service is configured to use the STS Issued Token mechanism, where an issued token with a symmetric proof is used as the protection token.

The back-end service is configured to use an STS-issued endorsing token, where the X509 certificate of the back-end service is used as the protection token and an issued token with a public proof key is as an endorsing supporting token.

To build, deploy, and run the sample, do the following:

  1. If you haven't already done so, download and install GlassFish v3 or GlassFish v2 .
  2. (GlassFish v2 only.) If you haven't already done so, download and install Metro 2.0 into GlassFish.
  3. If you use JDK 1.6, copy the webservices-api.jar file from the METRO_HOME/lib directory to the JAVA_HOME/jre/lib/endorsed directory, where METRO_HOME is the directory where you installed Metro 2.0, and JAVA_HOME is the directory where you installed JDK 6.
  4. Download the sample application package and extract its contents. You should now see a newly extracted directory named delegate.
  5. Copy the delegate/certs/xws-security directory to one of the following locations:
    • (GlassFish v3): GF_LOC/glassfish
    • (GlassFish v2): GF_LOC/glassfish

    where GF_LOC is the directory where you installed GlassFish.

    The delegate/certs/xws-security directory contains key stores for the sample.

  6. Edit the /delegate/src/fs/ file to properly set glassfish.home to the location of GlassFish in your environment.
  7. In the following files, replace $WSIT_HOME with the GlassFish location:
    • /delegate/src/fs/etc/service/PingService.wsdl
    • /delegate/src/fs/etc/service1/PingService.wsdl
    • /delegate/src/fs/etc/client/wsit-client.xml
    • /delegate/src/fs/etc/service/client/wsit-client.xml
    • /delegate/src/fs/etc/sts/sts.wsdl
  8. Start GlassFish.
  9. Change the directory to /delegate/src/fs and enter the following commend from the command line:
       ant run-sample

    You will be prompted to enter a username and password. Enter the username alice and the password alice, or the username bob and the password bob. These two username-password pairs are preconfigured for use with the sample application.

    If the sample application runs successfully, you should see balance=100000.

About the Author

Jiandong Guo has lead the development of implementations and solutions based on WS-SecureConversation and WS-Trust in the Metro project in Sun . He is currently a security architect in Oracle security and Identity management platform security group.




« February 2017