Adding Timestamps and Username Tokens
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.
The WS-Security header element is sent in clear text by default. To protect the password in a <UsernameToken>, you should use SSL/TLS, 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:
-
Call the Create() class method of %SOAP.Security.TimestampOpens in a new tab. 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.TimestampOpens in a new tab, sets the values for its Created, Expires, and TimestampAtEnd properties, and returns the instance. This instance represents the <Timestamp> header element.
-
Call the AddSecurityElement() method of the SecurityOut property of your web client or web service. For the method argument, use the %SOAP.Security.TimestampOpens in a new tab instance you created. For example:
do client.SecurityOut.AddSecurityElement(ts)
-
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:
-
Optionally include the %soap.inc include file, which defines macros you might need to use.
-
Call the Create() class method of %SOAP.Security.UsernameTokenOpens in a new tab. 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:
-
$$$SOAPWSPasswordText — Include the password in plain text. This is the default.
-
$$$SOAPWSPasswordDigest — Do not include the password but instead include its digest. The digest, Nonce, and Created timestamp are derived as specified by WS-Security 1.1.
Important:This option is available only for SOAP clients interacting with third-party servers that support it. PasswordDigest authentication requires the server to store the plain-text password, which is not acceptable in a modern security environment. The PasswordDigest algorithm should be considered a legacy feature. To protect the password in a <UsernameToken>, you should use SSL/TLS, encrypt the <UsernameToken>, or use some combination of these techniques.
-
$$$SOAPWSPasswordNone — Do not include the password.
This method creates an instance of %SOAP.Security.UsernameTokenOpens in a new tab, 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).
-
-
Call the AddSecurityElement() method of the SecurityOut property of your web client or web service. For the method argument, use the %SOAP.Security.UsernameTokenOpens in a new tab instance you created. For example:
do client.SecurityOut.AddSecurityElement(utoken)
-
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.
This example sends the username and password in clear text.
To make this example work in your own environment, first do the following:
-
For the web application to which the web service belongs, configure that application to support only password authentication:
-
From the Management Portal home page, select System Administration > Security > Applications > Web Applications.
-
Select the web application.
-
Select only the Password option and then select Save.
-
-
Edit the client to use an appropriate Caché username and password, if you are not using the defaults.
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>