Creating Secure Conversations
InterSystems IRIS supports secure conversations, following the WS-SecureConversation 1.3 specification. The easiest way to do this is to create a security policy and use the Establish Secure Session (Secure Conversation) option in the Web Service/Client Configuration Wizard. Another option is to manually create secure conversations, as described in this topic.
Overview
In a secure conversation, a web client makes an initial request to the web service and receives a message that contains a <SecurityContextToken>. This element contains information about a symmetric key that both parties can use. This information refers to a shared secret key known only to the two parties. Both parties can then use the symmetric key in subsequent exchanges, until the token expires or until the client cancels the token.
Rather than directly using the <SecurityContextToken> for these tasks (which is not recommended), both parties should generate a <DerivedKeyToken> from it, and then use that for encryption, signing, decryption, and signature validation.
The shared secret key can be specified in any of the following ways:
-
Jointly, by both parties, if they both provide a random entropy value. This is the typical scenario.
-
By the client, if the client provides a random client entropy value.
-
By the service, if the service provides a random service entropy value.
Starting a Secure Conversation
A web client starts a secure conversation. To do this in InterSystems IRIS, do the following within the web client:
-
Encrypt the SOAP body. The request sent by the client contains information that must be protected; this information is carried within the SOAP body.
Optionally secure the request message in other ways as needed.
-
Call the CreateBinarySecret() method of %SOAP.WST.EntropyOpens in a new tab. This method returns an instance of that class that represents the random client entropy. The method takes one argument, the size of the entropy in bytes.
For example:
set clientEntropy=##class(%SOAP.WST.Entropy).CreateBinarySecret(32)
This instance represents the <Entropy> element and the <BinarySecret> contained in it.
-
Call the CreateIssueRequest() class method of %SOAP.WST.RequestSecurityTokenOpens in a new tab. This method returns an instance of this class, which the client will use to request a secure conversation. The method has the following arguments:
-
Interval, the lifetime of the requested token. The default is 300 seconds; use an empty string to not specify a lifetime.
-
clientEntropy, the client entropy object you created in the previous step, if applicable.
-
requireServerEntropy, a boolean value that specifies whether the server must use server entropy when it creates the <SecurityContextToken>. The default is false.
set RST=##class(%SOAP.WST.RequestSecurityToken).CreateIssueRequest(300,clientEntropy,1)
-
-
Optionally specify the ComputedKeySize property of the %SOAP.WST.RequestSecurityTokenOpens in a new tab instance.
-
Call the StartSecureConversation() method of the web client. This method sends a message to the web service that requests a <SecurityContextToken> that both parties can use. This method takes one argument, the instance of %SOAP.WST.RequestSecurityTokenOpens in a new tab from the previous step.
This method returns a status code, which your code should check. If the response indicates success, the SecurityContextToken property of the client contains an instance of %SOAP.WSSC.SecurityContextTokenOpens in a new tab that represents the <SecurityContextToken> returned from the client. This element contains information about a symmetric key that both parties can use for encryption, signing, decryption, and signature validation.
-
Use the <SecurityContextToken> to respecify the security headers as needed. See Using the <SecurityContextToken>.
The following shows an example:
//encrypt the SOAP body because it contains part of the shared secret key
Set x509alias = "servernopassword"
Set cred = ##class(%SYS.X509Credentials).GetByAlias(x509alias)
set enckey=##class(%XML.Security.EncryptedKey).CreateX509(cred)
do client.SecurityOut.AddSecurityElement(enckey)
// if client entropy to be passed
set entropy=##class(%SOAP.WST.Entropy).CreateBinarySecret(32)
// request with 300 second lifetime and computed key using both client
//and server entropy.
set RST=##class(%SOAP.WST.RequestSecurityToken).CreateIssueRequest(300,entropy,1)
set sc=client.StartSecureConversation(RST) ; sends a SOAP message
Enabling an InterSystems IRIS Web Service to Support WS-SecureConversation
A secure conversation starts when a web client sends a message to the web service requesting a secure conversation. In response, the web service sends a <SecurityContextToken> that both parties can use.
To enable an InterSystems IRIS web service to respond with this token, override the OnStartSecureConversation() method of the web service. This method has the following signature:
Method OnStartSecureConversation(RST As %SOAP.WST.RequestSecurityToken) As
%SOAP.WST.RequestSecurityTokenResponseCollection
This method should do the following:
-
Encrypt the SOAP body. The message sent by OnStartSecureConversation() contains information that must be protected; this information is carried within the SOAP body.
Optionally secure the message in other ways as needed.
-
Optionally, call the CreateBinarySecret() method of %SOAP.WST.EntropyOpens in a new tab. This method returns an instance of that class that represents the random server entropy. The method takes one argument, the size of the entropy in bytes.
For example:
set serverEntropy=##class(%SOAP.WST.Entropy).CreateBinarySecret(32)
This instance represents the <Entropy> element and the <BinarySecret> contained in it.
-
Call the CreateIssueResponse() method of the %SOAP.WST.RequestSecurityTokenOpens in a new tab instance that is received by OnStartSecureConversation(). The CreateIssueResponse() method takes the following arguments:
-
$THIS, which represents the current web service instance.
-
keysize, the size of the desired key in bytes. This argument is used only if both server entropy and client entropy are provided. The default is the size of the smaller key, given the key in the client entropy and the key in the server entropy.
-
requireClientEntropy, which is either true or false, depending on whether the web service requires the request to include client entropy. If this is false, the request must not include client entropy.
-
serverEntropy, the server entropy object you created in step 2, if applicable.
-
error, a status code that is returned as an output parameter.
-
lifetime, an integer that specifies the lifetime of the secure conversation, in seconds.
For example:
set responseCollection=RST.CreateIssueResponse($this,,1,serverEntropy,.error)
-
-
Check the error output parameter from the previous step. If an error occurred, your code should set the SoapFault property of the web service and return an empty string.
-
In the case of success, return the instance of %SOAP.WST.RequestSecurityTokenResponseCollectionOpens in a new tab that was created by step 2.
This instance represents the <RequestSecurityTokenResponseCollection> element, which contains the <SecurityContextToken> that both parties can use.
The following shows an example:
Method OnStartSecureConversation(RST As %SOAP.WST.RequestSecurityToken)
As %SOAP.WST.RequestSecurityTokenResponseCollection
{
// encrypt the SOAP body sent by this messsage
//because it contains part of the shared secret key
Set x509alias = "clientnopassword"
Set cred = ##class(%SYS.X509Credentials).GetByAlias(x509alias)
set enckey=##class(%XML.Security.EncryptedKey).CreateX509(cred)
do ..SecurityOut.AddSecurityElement(enckey)
//Supply the server entropy
set serverEntropy=##class(%SOAP.WST.Entropy).CreateBinarySecret(32)
// Get the response collection for computed key
set responseCollection=RST.CreateIssueResponse($this,,1,serverEntropy,.error)
If error'="" {
set ..SoapFault=##class(%SOAP.WST.RequestSecurityTokenResponse).MakeFault("InvalidRequest")
Quit ""
}
Quit responseCollection
}
The OnStartSecureConversation() method is initially defined to return a <SecurityContextToken> only if that is specified by a policy. See Creating and Using Policies.
Using the <SecurityContextToken>
After a web service responds with a <SecurityContextToken>, the client instance and the service instance have access to the same symmetric key. Information about this key is contained in the SecurityContextToken property of both instances. The recommended procedure is as follows:
-
In the client, set the SecurityOut property to null, to remove the security headers that were used in the request message.
This is not needed in the web service, because the web service automatically clears the security headers after each call.
-
Optionally add the <SecurityContextToken> to the WS-Security header element. To do so, call the AddSecurityElement() method of the SecurityOut property of your web client or web service. For example:
set SCT=..SecurityContextToken do ..SecurityOut.AddSecurityElement(SCT)
This is necessary if you use the $$$SOAPWSReferenceSCT reference option when you create the derived key token in the next step. Otherwise, this step is not necessary.
-
Create a new <DerivedKeyToken> based on the <SecurityContextToken>. To do so, call the Create() method of %SOAP.WSSC.DerivedKeyTokenOpens in a new tab, as follows:
set dkenc=##class(%SOAP.WSSC.DerivedKeyToken).Create(SCT,refOpt)
In this scenario, you must specify the first argument to Create(), and refOpt must be one of the following reference values:
-
$$$SOAPWSReferenceSCT (a local reference) — The URI attribute of the reference starts with # and points to the wsu:Id value of the <SecurityContextToken> element, which must be included in the message.
-
$$$SOAPWSReferenceSCTIdentifier (a remote reference) — The URI attribute of the reference contains the <Identifier> value of the <SecurityContextToken> element, which does not have to be included in the message.
For example:
set dkenc=##class(%SOAP.WSSC.DerivedKeyToken).Create(SCT,$$$SOAPWSReferenceSCT)
-
-
Use the new <DerivedKeyToken> as wanted to specify security headers. See Using Derived Key Tokens for Encryption and Signing.
-
Send the SOAP message. See the general comments in Adding Security Header Elements.
The following shows an example:
//initiate conversation -- not shown here
//clear SecurityOut so that we can respecify the security header elements for
//the secure conversation
set client.SecurityOut=""
//get SecurityContextToken
set SCT=client.SecurityContextToken
do client.SecurityOut.AddSecurityElement(SCT)
// get derived keys
set dksig=##class(%SOAP.WSSC.DerivedKeyToken).Create(SCT,$$$SOAPWSReferenceSCT)
do client.SecurityOut.AddSecurityElement(dksig)
// create and add signature
set sig=##class(%XML.Security.Signature).Create(dksig,,$$$SOAPWSReferenceDerivedKey)
do client.SecurityOut.AddSecurityElement(sig)
//invoke web methods
Ending a Secure Conversation
A secure conversation ends as soon as the <SecurityContextToken> expires, but the web client can also end it by canceling an unexpired <SecurityContextToken>.
To end a secure conversation, call the CancelSecureConversation() method of the web client. For example:
set status=client.CancelSecureConversation()
The method returns a status value.
Note that this method sets the SecurityOut property of the client to an empty string.