Supporting Tokens and Issued Token Delegation in WSIT

By Shyam Rao

The March, 2007 Tech Tip Securing Web Services Using WSIT introduced Web Services Interoperability Technology (WSIT), an implementation of open web services technologies that enables interoperability between Java EE and .Net. Built on Java API for XML Web Services (JAX-WS), WSIT addresses key aspects of web services interoperability such as reliable messaging, transaction handling, and security. After introducing WSIT, the tip showed how to use the WS-Security support in WSIT so that a client can access a service in the same security domain. It also showed how to use the WS-Trust support in WSIT to access a service in a different security domain.

This tip expands on the earlier tip. It focuses on:

  • Supporting tokens with sender-vouches SAML assertions
  • Security Token Service (STS)-issued tokens

Used in combination, supporting tokens with sender-vouches SAML assertions and STS-issued tokens can be used to issue a token from an STS and delegate it to a user who is different than the web service client.

Note that an issued token may not be for the web service client directly, but for an another entity with which the web service client has a direct trust relationship. In this kind of scenario, the web service client acts as a proxy. The actual user logs into this proxy using his or her trusted credentials. The web service client then acts on behalf of the actual user to ask for a token from the STS, that is, the web service client trust STS. The STS issues a token, which is intended for use only by the actual user and not by the web services client.

In this tip, you'll learn about:

  • Supporting tokens
  • Sender-vouches SAML assertions
  • WS-Trust extensions in WSIT

You'll also learn how to:

  • Populate detail for an actual user in an SAML token to be issued from the requestor's SAML token.
  • Develop a WS-Trust application with extensions.

A sample application package accompanies the tip. The code examples in the tip are taken from the source code of the sample (which is included in the package).

Supporting Tokens

In WS-Security, security bindings use tokens to secure a message exchange. The tokens, which represent security credentials such as an X509 certificates, are used to sign all or part of a message. This signature is called a message signature. A supporting token augments the claims provided by the token associated with a message signature.

There are four properties related to supporting tokens that can be referenced by a security binding: supporting tokens, signed supporting tokens, endorsing supporting tokens, and signed endorsing supporting tokens. Each of the these properties is specified by an assertion: SupportingTokens, SignedSupportingTokens, EndorsingSupportingTokens, and SignedEndorsingSupportingTokens, respectively.

For more information about supporting tokens, see the document Web Services Security Policy.

Sender-Vouches SAML Assertions

Security Assertion Markup Language (SAML) is an XML standard for exchanging authentication and authorization data between security domains. The authentication and authorization information is specified in SAML assertions which are communicated between an identity provider (a producer of assertions) and a service provider (a consumer of assertions). SAML assertions are attached to SOAP messages inside the security header of the message.

One of the supporting tokens you can specify in a security binding is an SAML token. A SAML token uses SAML assertions as security tokens. One type of SAML token is the sender-vouches SAML token. This token uses a method called a sender-vouches method to establish the correspondence between a SOAP message and the SAML assertions added to the SOAP message. The attesting entity provides the confirmation evidence that is used to establish the correspondence between the subject of the SAML subject statements in SAML assertions and SOAP message content.

For more information about the sender-vouches method, see the document Web Services Security: SAML Token Profile.

WS-Trust Extensions in WSIT

The technique used in this tip takes advantage of extensions that the WS-Trust implementation in WSIT exposes. These extensions make the WSIT STS implementation more transparent to users. You can implement these extension points if you want to implement an STS according to your business requirements.

Recall from the March, 2007 Tech Tip that an STS is a trust authority that you can use to issue a security token for a client to access a service if the client and the service are in different security domains and have no direct trust relationship.

The WS-Trust implementation in WSIT exposes the following extensions:

  • STSAuthorizationProvider. This extension enables runtime authorization of a requestor for a token to be issued by the STS. For example, you can create two users and in the provider implementation, include authorization logic that allows only one of the users to access the target service. You get the user name from the user's Subject principal.

  • STSAttributeProvider. This extension enables details about the requestor to be included in the token to be issued by the STS. If this extensions is implemented, the provider implementation returns an attribute that is included in a SAML assertion created by the STS. Users may have different identities for different services. You may have an identity mapping for different services. On the service side, you can supply a SAML token validator to check if the actual user id and attributes returned by the provider implementation are included or not. For example, suppose a user named alice maps to abcd if the target service is http:// ... and has attributes such as role and email address. In that case, the issued SAML token will include a user attribute such as the role of the user, which can be used for authorization to the service.

  • STSConfigurationProvider. This extension allows you to add or replace STS configuration properties beyond what is specified in the <STSConfiguration> element of an STS's WSDL. The STS WSDL specifies attributes for configuring an STS, such as the issuer for the STS, issued tokens from this STS must be encrypted or not, and issued keys from the STS must be encrypted or not. If you write a STSConfiguration element and you want to change values of few properties at run time, then you need to implement this provider.

Note that providers can plug in an extension implementation to an STS using the standard ServiceFinder with a file name such as com.sun.xml.ws.api.security.trust.STSAttributeProvider. This file contains the actual implementation class.

Populate Detail for an Actual User in an SAML Token To Be Issued By an STS

Suppose a client does not possess any certificates of its own, but only knows about the STS/Service certificate. In this case, the STS/Service requires the client to authenticate using a encrypted Username token. The Username token is a means of identifying the requestor by user name to the STS/Service.

Suppose too that the STS issues an SAML token to the client to talk to a service. A SAML token uses SAML assertions as security tokens. There are three way in which STS could populate the user's claims in the issued SAML Token:

  • Access the user's claims in development code. This isn't of much use in real-time applications.

  • Implement the STSAttributeProvider extension in WSIT's WS-Trust implementation to return the user's ID and attribute values specified at runtime.

  • Implement the STSAttributeProvider extension in WSIT's WS-Trust implementation and use the user's claims specified in the requestor's SAML token. This adds the requestor's SAML token to the PublicCredential Set, that is, the set of public credentials held by the client's subject. If you use WSIT with StreamingSecurity, which is the default, the requestor's SAML is added as an XMLStreamReader. If you use WSIT with the DisableStreamingSecurity policy assertion, the SAML assertion is added as a DOM Element in the PublicCredential set. For more information about DisableStreamingSecurity, see the blog Improved XWSS implementation in WSIT Milestone 3.

You can implement the third approach by (1) adding a signed supporting SAML token in the STS WSDL -- this passes information about the user to the STS for the token to be issued, and (2) implementing the STSAttributeProvider extension.

For example, here is part of an assertion in an STS's WSDL to include a SAML token as a signed supporting token (some of the lines in this example have been broken to fit the width of the page):

   <sp:SignedSupportingTokens  
    xmlns:sp=
     "http://schemas.xmlsoap.org/ws/2005/07/securitypolicy">
     <wsp:Policy xmlns:
      wsp="http://schemas.xmlsoap.org/ws/2004/09/policy">
       <sp:SamlToken sp:IncludeToken=
    "http://schemas.xmlsoap.org/ws/2005/07/
      securitypolicy/IncludeToken/AlwaysToRecipient">
         <wsp:Policy>
           <sp:WssSamlV11Token10></sp:WssSamlV11Token10>
         </wsp:Policy>
       </sp:SamlToken>
     </wsp:Policy>
   </sp:SignedSupportingTokens>

In the similar way, you can pass a SAML token, as a signed supporting token, and a Username/X509 token for authorization to a regular web service.

Here is part of a sample provider implementation of the STSAttributeProvider extension that populates the issued SAML token with the actual user's claims:

public class SampleSTSAttributeProvider implements 
    STSAttributeProvider{    
  public Map<QName, List<String>> getClaimedAttributes(
      final Subject subject, final String appliesTo, 
      final String tokenType, final Claims claims){
    final Set<Principal> principals = subject.getPrincipals();
    final Set publicCredential = subject.getPublicCredentials();
    final Map<QName, List<String>>
         attrs = new HashMap<QName, List<String>>()
    // You can iterate over the client's 
    // subject.getPublicCredentials() for the SAML token and 
    // retrieve the values(NameIdentifier, Attributes) from 
    // it and set it in the SAML Token to be issued. You can 
    // find a description of the actual implementation of 
    // this part later in this TechTip. You can also find 
    // this code in the sample package
      return attrs;
   }   
}

You may also implement the STSAuthorizationProvider extension and the STSAttributeProvider extension to check a web service client's authorization claims for the token to be issued.

Developing a WS-Trust Application With Extensions

Let's create an application that uses the technique highlighted in the "Populate Detail for an Actual User in an SAML Token" section, that is, the technique that implements the STSAttributeProvider extension and uses the user's claims specified in the requestor's SAML Token. Let's develop the application using the NetBeans IDE. You can download the NetBeans IDE from the NetBeans site.

To build this application, you:

  • Include a signed supporting SAML token in an existing NetBeans security profile called "Username Authentication with Symmetric Keys".
  • Implement the STSAttributeProvider extension to populate the actual user's name identifier and attributes in an SAML token to be issued from the requestor's SAML token.
  • Plug in the STSAttributeProvider extension implementation to an STS.
  • Implement an SAML handler for the client.
  • Get the actual user's username and password.

To include a signed Supporting SAML token in the existing NetBeans profile "Username Authentication with Symmetric Keys":

  1. Create an STS Project using NetBeans.

  2. Right click on the project. Select Edit Web Services Attribute. Then select the Username Authentication with Symmetric key security mechanism. In response, the following WSDL is generated (some of the lines in this example have been broken to fit the width of the page):

          <sp:SignedSupportingTokens    
           xmlns:
            sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy">
               <wsp:Policy 
             xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy">
                 <sp:UsernameToken 
            sp:IncludeToken=
          "http://schemas.xmlsoap.org/ws/2005/07/securitypolicy/
            IncludeToken/AlwaysToRecipient">
                   <wsp:Policy>
                     <sp:WssUsernameToken10/>
                   </wsp:Policy>
                 </sp:UsernameToken>        
               </wsp:Policy>
          </sp:SignedSupportingTokens>

  3. Edit the generated STS WSDL by adding a SignedSupportingTokens assertion for a SAML token just below the existing SignedSupportingTokens assertions (some of the lines in this example have been broken to fit the width of the page):

          <sp:SignedSupportingTokens    
           xmlns:
            sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy">
               <wsp:Policy 
             xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy">
                 <sp:UsernameToken 
           sp:IncludeToken=
           "http://schemas.xmlsoap.org/ws/2005/07/securitypolicy/
             IncludeToken/AlwaysToRecipient">
                  <wsp:Policy>
                    <sp:WssUsernameToken10/>
                  </wsp:Policy>
                </sp:UsernameToken>        
                  </wsp:Policy>
          </sp:SignedSupportingTokens>
          <sp:SignedSupportingTokens  
        xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy">
            <wsp:Policy 
           xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy">
              <sp:SamlToken 
           sp:IncludeToken=
           "http://schemas.xmlsoap.org/ws/2005/07/securitypolicy/
             IncludeToken/AlwaysToRecipient">
                <wsp:Policy>
                  <sp:WssSamlV11Token10></sp:WssSamlV11Token10>
                </wsp:Policy>
              </sp:SamlToken>
            </wsp:Policy>
          </sp:SignedSupportingTokens>

To implement the STSAttributeProvider extension to populate the actual user's name identifier and attributes in an SAML token to be issued from the requestor's SAML Token:

  1. Write a class that populates the issued Token's name identifier with the one present in requestor's SAML Token. Here is a code snippet for a class that does that using streaming security in WSIT (some of the lines in this example have been broken to fit the width of the page):

          String name_identifier = null;
          Iterator iterator = publicCredential.iterator();
          while (iterator.hasNext()){
            Object obj = iterator.next();
            if (obj instanceof XMLStreamReader){
              XMLStreamReader samlAssertion = (XMLStreamReader)obj;
              try {
                if(samlAssertion.getEventType() 
                 != XMLStreamReader.START_DOCUMENT)
                  StreamUtil.moveToNextElement(samlAssertion);
                while(samlAssertion.getEventType() 
                 != XMLStreamReader.END_DOCUMENT){
                  if (samlAssertion.getLocalName()
                   .equals("NameIdentifier") ||
                    samlAssertion.getLocalName().equals("NameID")){
                    name_identifier = samlAssertion.getElementText();
                  }
                  samlAssertion.next();
                }
              } catch (XMLStreamException ex) {
                System.out.println(
           "Exception while reading SamlAssertion as XMLStreamReader : "
            +ex);
              }    
            }
          }
          if (name_identifier != null){
            List<String> nameIds = new ArrayList<String>();
            nameIds.add(name_identifier);
            attrs.put(new QName("http://sun.com", 
             NAME_IDENTIFIER), nameIds);
          }

  2. Write a class that populates the issued Token's attributes with the attributes present in requestor's SAML Token. Here is a code snippet for a class that does that using streaming security in WSIT (some of the lines in this example have been broken to fit the width of the page):

          String name_identifier = null;
          Iterator iterator = publicCredential.iterator();
          while (iterator.hasNext()){
            Object obj = iterator.next();
            if (obj instanceof XMLStreamReader){
              XMLStreamReader samlAssertion = (XMLStreamReader)obj;
              try {
                if(samlAssertion.getEventType() == 
                       XMLStreamReader.START_DOCUMENT)
                  StreamUtil.moveToNextElement(samlAssertion);
                while(samlAssertion.getEventType() 
                       != XMLStreamReader.END_DOCUMENT){
                  if (samlAssertion.getEventType() == 
                         XMLStreamReader.START_ELEMENT
                         && samlAssertion.getLocalName().equals(
                          "Attribute")){
                    int attributeCount = 
                      samlAssertion.getAttributeCount();
                    for (int i=0; i<attributeCount; i++){
                      if(samlAssertion.getAttributeLocalName(i).equals(
                       "AttributeName")
                       ||samlAssertion.getAttributeLocalName(i).equals(
                        "Name")){
                        // Set up a dummy attribute value
                        final QName key = new QName("http://sun.com",
                                    samlAssertion.getAttributeValue(i));
                        List<String> tokenRequestor = 
                         new ArrayList<String>();
                        if(samlAssertion.hasNext()){
                          samlAssertion.next();
                          if (samlAssertion.getLocalName().equals(
                           "AttributeValue")){
                            tokenRequestor.add(
                             samlAssertion.getElementText());
                            attrs.put(key, tokenRequestor);
                            break;
                          }
                        }
                     }
                    }
                  }
                  samlAssertion.next();
                }
              } catch (XMLStreamException ex) {
                System.out.println(
           "Exception while reading SamlAssertion as XMLStreamReader : "
            +ex);
              }
            }
          }   

To plug in the STSAttributeProvider extension implementation to an STS:

  1. Open the already-created STS project in NetBeans.

  2. Create a two-level directory with name META-INF/services under Source Packages.

  3. Create a file with the name com.sun.xml.ws.api.security.trust.STSAttributeProvider under the META-INF/services directory. The file contains the implementation class, fs.simple.sts.SampleSTSAttributeProvider, for the sample package.

  4. Plug in the STSAttributeProvider extension implementation to the STS using the standard Service finder mechanism.

To implement an SAML handler for the client:

  1. Create a project for the client.

  2. Download the SAML Callback Handler implementation from the XWSS project utilities page. To create a SAML Sender Vouches with Certificates, you can use the downloaded SAML Callback Handler, as is, with the package name xwss.saml. But for a SAML Holder-of-Key, you need to edit two statements in the callback handler implementation:

          // home must be the GlassFish install directory
          String home = System.getProperty("WSIT_HOME");
          // specify the client private key alias from your client 
          // keystore
          String client_priv_key_alias="xws-security-client; 

    Note: For setting the Sender-Vouches (SV) SAML Token's subject with the actual user's username, you need to edit the methods createSVSAMLAssertion(), createSVSAMLAssertion20() and add a new constructor SamlCallbackHandler(String username) in the callback handler. You can see these changes in the client's project of the sample package.

  3. Right click on client's Web Service References for the STS. Select the Edit Web Service Attributes option. Then select the WSIT Configuration tab. Expand Username Authentication and click on the Browse... button to get the SAML callback handler class.

To get the actual user's username and password:

  1. Open the already-created client project in NetBeans.

  2. Open the index.jsp page and add the following lines of code:

    <form action="FinancialServiceClientServlet" method="POST">
        username : <input type="text" name="userName">
        password : <input type="password" name="passWord">
        <input type="submit" value="Log In">
    </form>

    Adding these lines enables the actual user to login to a web services client with a valid username and password. Here, the client acts as a proxy. After successful validation of the actual user to the web services client, the client asks for an issued token from the STS on behalf of the actual user. The web services client creates a SAML Token in which the subject's name identifier in the SAML assertion is populated with the actual user's login name. The STS then extracts the actual user's login name from the SAML Token in the request message and populates the issued SAML token's subject with that login name.

Running the Sample

The instructions for running the sample package are based on GlassFish Version 2 Release Candidate 1 and the NetBeans 5.5.1 IDE. The instructions assume that you have installed the WSIT plugin into NetBeans. For information on installing the WSIT plugin into NetBeans, see Web Services Interoperability Technology: How to Download and Install.

A sample package accompanies this tip. To install and run the sample:

  1. If you haven't already done so, download GlassFish Version 2 Release Candidate 1, and install it.

  2. Download the copyv3.zip file from the XWSS project utilities page and unzip the file. Then:

    • Set the AS_HOME system property to where you installed GlassFish Version 2 Release Candidate 1

    • Change to the directory where you unzipped the copyv3 files. Make sure that the value for the AS_KEYSTORE_PASSWORD property in the build.xml file is the correct keystore password for the GlassFish application server keystore.

    • Enter the following command:

            ant

      This copies the sample certificates to the GlassFish application server keystores for use with the sample.

  3. Download the sample package and extract its contents. You should now see the newly extracted directory as <sample_install_dir>/ws-trust-ext, where <sample_install_dir> is the directory where you installed the sample package. For example, if you extracted the contents to C:\\ on a Windows machine, then your newly created directory should be at C:\\ws-trust-ext.

  4. There are three NetBeans projects in the extracted sample package:

    • FinancialService: A service project
    • FinancialServiceSTS: An STS project
    • FinancialServiceClient: A client project

    Open the three projects in the NetBeans editor.

  5. Attach the registered application server to the three projects. To do this, right click on the project and select Properties. Then click on Run. Select server from the drop-down list.

  6. Change the location of the keystore and truststore to <GF_HOME>/domains/domain1/config/keystore.jks and <GF_HOME>/domains/domain1/config/cacerts.jks, respectively, where <GF_HOME> is where you installed GlassFish Version 2 Release Candidate 1. Do this for the service, STS, and client. To do this, select the WSIT Configuration tab in the web services attribute editor for each project's web services node. Then change the location of the Keystore and Truststore to the absolute path of the application server's keystore and truststore.

  7. Add the following JVM option in the domain.xml file in the <GF_HOME>/domains/domain1/config/ directory:

          <jvm-options>-DWSIT_HOME=${com.sun.aas.installRoot}
          </jvm-options>
          <jvm-options>
          -Dcom.sun.xml.ws.transport.http.HttpAdapter.dump=true
          </jvm-options>       
          <jvm-options>
          -Dcom.sun.xml.ws.transport.http.client.HttpTransportPipe.dump=true
          </jvm-options> 

  8. Start the application server by entering the following command:

          <GF_HOME>/bin/asadmin start-domain domain1

  9. Add an application server user. The user will be used as the username token for the request message to the STS. See Adding Users to GlassFish. for further information. Create a user with the following username and password:
    username : test
    password : test

    You can also create other usernames and password. But to do that, you need to edit the username and password in the client configuration file of the STS in the client's project.

  10. Run the three projects:

    • Right click on the FinancialService project and select Run Project.
    • Right click on the FinancialServiceSTS project and select Run Project.
    • Right click on the FinancialServiceClient project and select Run Project.

    You must run the FinancialServiceClient project last.

    A browser window will open with a JSP page asking you to login with a username and password. You can enter any username and password -- the sample code does not have an implementation for validating the actual user. The objective of this page is to get the actual user's login id from the login page and put it in the subject of a created SAML token on the client side.

    You should see the following response:

    Balance = 1,000,000 Acknowledgement = successfully
    deposited

    You can view the message flows by examining the log file for the application server.

About the Author

Shyam Rao is a member of the Web Services Security Group. He has been involved with WS-Security, WS-Trust and WS-SecureConversation in the Tango project.

Comments:

A way to complicated! "Write a class that populates the issued ...", and after that? How should the reader integrate this class into the project? I tried to realize the whole wsit secure conversation and STS framework. But there are no simple documents. Only complicated (too focused) and outdated documents out there! Horrible!

Posted by WS on November 26, 2007 at 06:46 AM PST #

To know more about WSIT secure conversation and STS framework, you can have a look at WSIT tutorial (chapter 4,5,6 : https://wsit-docs.dev.java.net/releases/1-0-FCS/index.html) & http://blogs.sun.com/trustjdg/

Here "Write a class that populates the issued ..." means implementation of STSAttributeProvider extension to populate the actual user's name identifier and attributes in an SAML token to be issued from the requestor's SAML Token.

This tech tip also defines how to plugin/integrate STSAttributeProvider extension implementation to an STS:

1. Open the already-created STS project in NetBeans.

2. Create a two-level directory with name META-INF/services under Source Packages.

3. Create a file with the name com.sun.xml.ws.api.security.trust.STSAttributeProvider under the META-INF/services directory. The file contains the implementation class, fs.simple.sts.SampleSTSAttributeProvider, for the sample package.

4. Plug in the STSAttributeProvider extension implementation to the STS using the standard Service finder mechanism.

If you download the sample of this TechTip, then you can see the implementation of STSAttributeProvider in ws-trust-ext\\FinancialServiceSTS\\src\\java\\fs\\simple\\sts\\SampleSTSAttributeProvider.java

You may post all of your web services (security,trust,secureconversation,securitypolicy) related queries here in Metro Forum for immediate answer : http://forums.java.net/jive/forum.jspa?forumID=46&start=0

Thanks
-- Shyam

Posted by shyam rao on November 26, 2007 at 04:49 PM PST #

Where can I get the copy of STS source code for my customization???

Posted by guest on February 24, 2008 at 12:40 PM PST #

Here is the blog entry on "how to create a custom STS" :
http://blogs.sun.com/trustjdg/entry/create_customer_sts_with_wsit

There is a sample attached with this techtip(http://java.sun.com/mailers/techtips/enterprise/2007/download/ttaug2007TTWstrust-ext.zip), which has the code for custom STS.

Is it answered your question ?

Posted by Shyam Rao on February 25, 2008 at 01:33 PM PST #

Post a Comment:
Comments are closed for this entry.
About

edort

Search

Archives
« April 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today