Securing Caché Web Services
Adding Timestamps and Username Tokens
[Home] [Back] [Next]
InterSystems: The power behind what matters   
Class Reference   
Search:    

This chapter discusses timestamps and user tokens. It discusses the following topics:

Overview
A timestamp is the <Timestamp> security element in the WS-Security header. A timestamp is not strictly a security element. You can use it, however, to avoid replay attacks. Timestamps can also be useful for custom logging.
A username token is the <UsernameToken> security element in the WS-Security header; it carries a username. It can also carry the corresponding password (optionally in digest form). You typically use it for authentication, that is, to enable a Caché web client to use a web service that requires a password.
Caution:
The WS-Security header element is sent in clear text by default. To protect the password in a <UsernameToken>, you should use SSL/TLS, use the password digest, encrypt the <UsernameToken> (as described later in this book), or use some combination of these techniques.
Adding a Timestamp
To add a timestamp to the WS-Security header element, do the following in your web client or web service:
  1. Call the Create() class method of %SOAP.Security.Timestamp. This method takes one optional argument (the expiration interval in seconds). The default expiration interval is 300 seconds. For example:
     set ts=##class(%SOAP.Security.Timestamp).Create()
    This method creates an instance of %SOAP.Security.Timestamp, sets the values for its Created, Expires, and TimestampAtEnd properties, and returns the instance. This instance represents the <Timestamp> header element.
  2. Call the AddSecurityElement() method of the SecurityOut property of your web client or web service. For the method argument, use the %SOAP.Security.Timestamp instance you created. For example:
     do client.SecurityOut.AddSecurityElement(ts)
  3. Send the SOAP message. See the general comments in Adding Security Header Elements,” earlier in this book.
If you include a <Timestamp> element, Caché forces it to be first within <Security>.
Adding a Username Token
To add a username token, do the following in your web client:
  1. Optionally include the %soap.inc include file, which defines macros you might need to use.
  2. Call the Create() class method of %SOAP.Security.UsernameToken. For example:
     set user="SYSTEM"
     set pwd="_SYS" 
     set utoken=##class(%SOAP.Security.UsernameToken).Create(user,pwd)
    The method has an optional third argument (type), which specifies how to include the password in the username token. This must be one of the following:
    This method creates an instance of %SOAP.Security.UsernameToken, sets its Username and Password properties, and returns the instance. This object represents the <UsernameToken> header element.
    Note:
    If you are using this procedure to create a <UsernameToken> needed by a policy created by the Studio wizard, you must use the default type, $$$SOAPWSPasswordText, because the wizard does not generate policies that use other token types. You can, however, manually create a policy that uses the HashPassword assertion (which would use the type $$$SOAPWSPasswordDigest).
  3. Call the AddSecurityElement() method of the SecurityOut property of your web client or web service. For the method argument, use the %SOAP.Security.UsernameToken instance you created. For example:
     do client.SecurityOut.AddSecurityElement(utoken)
  4. Send the SOAP message. See the general comments in Adding Security Header Elements,” earlier in this book.
Timestamp and Username Token Example
This example shows a web service that requires password authentication, and a web client that sends a timestamp and username token in its request messages.
Caution:
This example sends the username and password in clear text.
To make this example work in your own environment, first do the following:
The web service is as follows:
Class Tokens.DivideWS Extends %SOAP.WebService
{

Parameter SECURITYIN = "REQUIRE";

///  Name of the Web service.
Parameter SERVICENAME = "TokensDemo";

///  SOAP namespace for the Web service
Parameter NAMESPACE = "http://www.myapp.org";

///  Divide arg1 by arg2 and return the result. In case of error, call ApplicationError.
Method Divide(arg1 As %Numeric = 2, arg2 As %Numeric = 8) As %Numeric [ WebMethod ]
{
  Try {
      Set ans=arg1 / arg2
      }Catch{
      Do ..ApplicationError("division error")
      }
  Quit ans
}

///  Create our own method to produce application specific SOAP faults.
Method ApplicationError(detail As %String)
{
    //details not shown here
}

}
The following client-side class invokes the proxy client (not shown here) and adds a username token:
Include %systemInclude

Class TokensClient.UseClient
{

ClassMethod Test() As %Numeric
{
  Set client=##class(TokensClient.TokensDemoSoap).%New()
  
  Do ..AddSecElements(.client)
  Set ans=client.Divide(1,2)
  
  Quit ans
}

ClassMethod AddSecElements(ByRef client As %SOAP.WebClient)
{
   Set utoken=##class(%SOAP.Security.UsernameToken).Create("_SYSTEM","SYS")
   Do client.SecurityOut.AddSecurityElement(utoken)

   Set ts=##class(%SOAP.Security.Timestamp).Create()
   Do client.SecurityOut.AddSecurityElement(ts) 
   Quit
}

}
A sample message from this client is as follows:
<?xml version="1.0" encoding="UTF-8" ?>
<SOAP-ENV:Envelope [parts omitted]>
  <SOAP-ENV:Header>
   <Security xmlns="[parts omitted]oasis-200401-wss-wssecurity-secext-1.0.xsd">
      <Timestamp xmlns="[parts omitted]oasis-200401-wss-wssecurity-utility-1.0.xsd">
         <Created>2010-03-12T20:18:03Z</Created>
         <Expires>2010-03-12T20:23:03Z</Expires>
      </Timestamp>
      <UsernameToken>
         <Username>_SYSTEM</Username>
         <Password 
          Type="[parts omitted]#PasswordText">
            SYS
         </Password>
      </UsernameToken>
      </Security>
   </SOAP-ENV:Header>
   <SOAP-ENV:Body>
      [omitted]
   </SOAP-ENV:Body>
</SOAP-ENV:Envelope>