Communicate Between Stylesheets Using WebSphere DataPower Context Variables
Communicate Between Stylesheets Using WebSphere DataPower Context Variables
Table of contents
Every variable has a name, which is really a URL beginning with var:. There are four variable
syntaxes:
Note that the dp: XML namespace prefix is declared, and referenced as both an extension
element prefix -- explicit dp: elements should be processed as extensions, not copied to the
output -- and that the prefix should be excluded from the stylesheet's result. We set a variable
namedheader on whatever our output context is containing an XSLT node-set with the header
we're interested in, and then also copy the entire contents of our input into that context. If a
transform action is configured with an input context of INPUT and an output context of saved,
then the savedcontext will contain the input tree, plus an additional header variable with the
SOAP header we're interested in. This policy is shown in Figure 1.
Figure 1. Processing policy configuration invoking "get SOAP header" stylesheet
You can use the dp:variable() extension function to retrieve the contents of the variable in the
response rule. This is called like any other XPath function. Because we expect its value to be a
node-set, we'll call it from an <xsl:copy-of/> statement to insert its value into the result, as
shown in Listing 2.
Listing 2. Inserting a saved SOAP header
<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:tns="http://www.example.org/tns"
xmlns:dp="http://www.datapower.com/extensions"
extension-element-prefixes="dp"
exclude-result-prefixes="dp">
<xsl:output method="xml"/>
<xsl:template match="/">
<soap:Envelope>
<soap:Header>
<xsl:copy-of select="/soap:Envelope/soap:Header/*"/>
<xsl:copy-of select="dp:variable('var://context/saved/header')"/>
</soap:Header>
<xsl:copy-of select="/soap:Envelope/soap:Body"/>
</soap:Envelope>
</xsl:template>
</xsl:stylesheet>
This stylesheet refers to the "saved" context from the request rule explicitly, so it might be
configured to take INPUT as its input and OUTPUT as its output. Since this is running as the
response rule, it reads its input from the back-side service and writes its output as the response
to the initial front-side connection.
As a debugging aid, the DataPower probe can be used to look at the saved variables. Figure 2
shows how the probe presents the list of variables after sending a sample XML file through the
device with this policy. Because the context variables can be accessed from any other
stylesheet, the probe considers these "global".
Figure 2. DataPower XI50 probe with context variables
Listing 3 shows how this technique can be applied to select a different stylesheet depending on
the SOAP version of the input message. The stylesheet looks at the input message, and
chooses either a stylesheet suited to handling SOAP 1.1 or 1.2 messages based on the name
of its root element. A processing policy is then configured to run first this stylesheet, and then
the stylesheet named byvar://context/stylesheet/name.
Listing 3. Picking a stylesheet based on SOAP version
<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:soap11="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:soap12="http://www.w3.org/2003/05/soap-envelope"
xmlns:tns="http://www.example.org/tns"
xmlns:dp="http://www.datapower.com/extensions"
extension-element-prefixes="dp"
exclude-result-prefixes="dp">
<xsl:output method="xml"/>
<xsl:template match="/">
<xsl:apply-templates mode="pick-stylesheet"/>
<xsl:copy-of select="/"/>
</xsl:template>
<xsl:template match="/soap11:Envelope" mode="pick-stylesheet">
<dp:set-variable name="'var://context/stylesheet/name'"
value="'local:///soap-1.1.xsl'"/>
</xsl:template>
<xsl:template match="/soap12:Envelope" mode="pick-stylesheet">
<dp:set-variable name="'var://context/stylesheet/name'"
value="'local:///soap-1.2.xsl'"/>
</xsl:template>
<xsl:template match="*" mode="pick-stylesheet">
<xsl:message terminate="yes">Unrecognized SOAP envelope</xsl:message>
</xsl:template>
</xsl:stylesheet>
You could also use context variables to name a schema for a validate action if a particular
schema variant is only known through something like aversion attribute on the
document root element. Using a context variable as the target rule name for a call action lets
you call a rule dynamically based on something in the input.
One other interesting set-up is providing a context name, rather than a URL, as the stylesheet
name in a transform action. In this case, the contents of that context are used as a stylesheet,
rather than fetching a fixed stylesheet. You might use this to fill in XPath expressions in the
stylesheet for<xsl:key/> based on an unknown input, or otherwise set a fixed element name in
an actual stylesheet from the input. Note that you need to use the <xsl:namespacealias/> directive to generate XSLT from XSLT. For more information, see section 7.1.1 of
Summary
DataPower extensions provide powerful features for communicating between stylesheets. A
value or XML tree can be computed in one stylesheet, saved, and used in another stylesheet,
possibly on the return path in the same transaction. You can also use context variables to
dynamically select a stylesheet, or use the output of one step as the stylesheet of the next.
Introduction
In the world of Web services, Web Services Description Language (WSDL) documents
describe the interfaces provided by Web services -- and indicate where instances of
those Web services can be found on the network. In general, WSDL documents are
composed and consumed with the aid of various development tools. As with virtually all
Web service related information, WSDL documents are expressed as standard XML
documents.
One of the strengths of XML is the availability of increasingly powerful tools to process
the data. One such tool, XSLT, can be used to effect complex transformations on XML
data. Since WSDL documents are expressed as XML, it is possible to automate a wide
variety of WSDL conversion tasks using XSLT. This article describes some of the
approaches that have proven useful in processing WSDL documents with XSLT (and
some that haven't) and lists some general techniques that can be applied to simplify
automated processing of WSDL documents.
This document assumes a working knowledge of both WSDL and XSLT. The following
links on IBM developerWorks offer useful background information:
For more information on WSDL, refer to the article, New to SOA and
Web services.
There are two basic approaches to modifying a WSDL document. The first uses a
language such a Java or C and an XML-parsing API such as SAX or DOM. The original
WSDL document is read, its contents parsed and modified by the algorithm and the
modified WSDL document constructed -- either by manually assembling the document
out of strings or by using a language-specific XML library. The second approach utilizes
an XSL transform that specifies how the input WSDL document should be manipulated
to produce the output WSDL document. While many of the techniques described here
apply to the first approach, the XML approach has several advantages:
1.
Extracting structure from a WSDL document using XSL results in some interesting
challenges. To allow use of the widest possible set of XSL transform engines, restrict
stylesheets to features defined in XSL version 1.1. Some of the features added in XSL
version 2.0 will simplify some of the XSL shown here, but will not be prevalent in many
environments for some time.
The largest obstacle in processing WSDL documents with XSL is the extensive use of
namespace prefixes within attribute values in WSDL documents. These namespace
prefixes are used to correlate messages, portTypes, bindings and ports. While XSL is
adept at handling namespaces on both elements and attributes in the input document,
its constructs for dealing with them inside attribute values and character data are
somewhat weak.
Back to top
Relationships within a WSDL document
While it is not possible to fully describe the structure of a WSDL document here, it is
worth describing a few of the salient relationships among elements of the WSDL
document. Correct manipulation of the WSDL document depends on understanding and
preserving these relationships.
Figure 1. Relationship of WSDL document elements
wsdl:binding/wsdl:operation/wsdl:input/@name =
wsdl:portType/wsdl:operation/wsdl:input/@name
wsdl:binding/wsdl:operation/wsdl:output/@name =
wsdl:portType/wsdl:operation/wsdl:output/@name
wsdl:binding/wsdl:operation/wsdl:fault/@name =
wsdl:portType/wsdl:operation/wsdl:fault/@name
Back to top
Techniques
What follows are several techniques and XSL snippets that have proven useful in
processing WSDL documents. Many of these approaches could be generalized to work
with non-WSDL XML documents as well.
In addition to an XSL snippet, each technique described below includes a simple
example stylesheet showing how the technique can be used to process a WSDL
document. For each example stylesheet, the output of applying the stylesheet to the
following contrived WSDL document is also shown:
Listing 1. test.wsdl used in examples
<wsdl:message name="faultmsg"/>
<wsdl:portType name="porttype">
<!-- one-way operation -->
<wsdl:operation name="porttype-op1">
<wsdl:input message="test:inputmsg1" name="porttype-op1-input"/>
</wsdl:operation>
<!-- request-response operation -->
<wsdl:operation name="porttype-op2">
<wsdl:input message="test:inputmsg2" name="porttype-op2-input"/>
<wsdl:output message="test:outputmsg" name="porttype-op2-output"/>
<wsdl:fault message="test:faultmsg" name="porttype-op2-fault"/>
</wsdl:operation>
<!-- solicit-response operation -->
<wsdl:operation name="porttype-op3">
<wsdl:output message="test:outputmsg" name="porttype-op3-output"/>
<wsdl:input message="test:inputmsg3" name="porttype-op3-input"/>
<wsdl:fault message="test:faultmsg" name="porttype-op3-fault"/>
</wsdl:operation>
<!-- notification operation -->
<wsdl:operation name="porttype-op4">
<wsdl:output message="test:outputmsg" name="porttype-op4-output"/>
</wsdl:operation>
</wsdl:portType>
<wsdl:fault name="porttype-op3-fault">
<soap:fault name="porttype-op3-fault" use="literal"/>
</wsdl:fault>
</wsdl:operation>
<wsdl:operation name="porttype-op4">
<soap:operation soapAction="http://tempuri.org/test/soapAction"/>
<wsdl:output name="porttype-op4-output">
<soap:body use="literal" parts="outputmsg-part"/>
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="service">
<wsdl:port name="service-port" binding="test:binding">
<soap:address location="http://localhost:9080/not/used"/>
</wsdl:port>
</wsdl:service>
</wsdl:definitions>
Many WSDL elements define attributes of type qname. Since the mapping of
namespace prefixes to URIs is not required to be unique or consistent even within a
single document, any robust WSDL parsing logic must be able to translate the
namespace prefixes in qnames to namespace URIs. The XSL namespace-uri() function
maps a namespace prefix to a namespace URI, but only understands nodes in the input
document. Since the namespace prefix is part of an attribute value in the WSDL case,
some additional work is required.
The following XSL code translates the namespace prefix in a string to the corresponding
namespace URI. If the supplied string does not contain a prefix, the namespace URI is
an empty string. Placing this logic in its own template allows it to be easily invoked from
anywhere, in the context of arbitrary elements.
Listing 2. Technique 1 XSL
<!-- emits the namespace uri associated with the prefix of the
specified qname based on current()'s namespace nodes -->
<xsl:template name="namespace-uri-of-qname">
<xsl:param name="qname"/>
<xsl:if test="contains($qname,':')">
<xsl:value-of select="namespace::*[name()=substring-before($qname,':')]"/>
</xsl:if>
</xsl:template>
<xsl:text>prefix of </xsl:text>
<xsl:value-of select="name()"/>
<xsl:text> maps to namespace uri </xsl:text>
<xsl:call-template name="namespace-uri-of-qname">
<xsl:with-param name="qname" select="name()"/>
</xsl:call-template>
<xsl:text>
</xsl:text>
<xsl:text>prefix of </xsl:text>
<xsl:value-of select="@message"/>
<xsl:text> maps to namespace uri </xsl:text>
<xsl:call-template name="namespace-uri-of-qname">
<xsl:with-param name="qname" select="@message"/>
</xsl:call-template>
<xsl:text>
</xsl:text>
</xsl:template>
</xsl:stylesheet>
Running the above example against the test WSDL document produces:
Listing 4. Technique 1 example output
prefix
prefix
prefix
prefix
prefix
prefix
of
of
of
of
of
of
The reverse problem exists when an XSL stylesheet needs to generate qnames in
WSDL document attributes. That is, the XSL stylesheet knows the namespace URI, but
needs to emit a namespace prefix that is mapped to that URI for the current element.
The XSL transform engine would handle this automatically if the namespace were
associated with an output element, but since WSDL requires it to be in an attribute
value, manual processing is required. Error handling makes the XSL for this technique a
bit more complex than for the first technique. Also shown in the following XSL is a
special case template that emits a prefix for the WSDL
document's targetNamespace URI.
Listing 5. Technique 2 XSL
<!-- emits a prefix that maps to the specified namespace uri for current() -->
<xsl:template name="prefix-for-namespace">
<xsl:param name="namespace-uri"/>
<xsl:if test="$namespace-uri">
<!-- terminate if current() does not have a prefix for $namespace-uri -->
<xsl:if test="not(namespace::*[string() = $namespace-uri])">
<xsl:message terminate="yes">
<xsl:text>Unable to find namespace prefix for namespace </xsl:text>
<xsl:value-of select="$namespace-uri"/>
<xsl:text> while processing </xsl:text>
<xsl:value-of select="name()"/>
<xsl:text> element.</xsl:text>
</xsl:message>
</xsl:if>
<xsl:value-of select="name(namespace::*[string() = $namespace-uri])"/>
<xsl:text>:</xsl:text>
</xsl:if>
</xsl:template>
Running the above example against the test WSDL document produces:
Listing 7. Technique 2 example output
namespace uri http://www.w3.org/2001/XMLSchema mapped by prefix xsd:
targetNamepace uri mapped by prefix test:
The last of the qname techniques provides an analog to theXSL local-name() function.
As with the previous techniques XSL provides this function for nodes in the source
document, but the fact that WSDL uses an attribute value to store the qname
complicates matters.
Listing 8. Technique 3 XSL
<!-- emits the local name of the specified qname -->
<xsl:template name="local-name-of-qname">
<xsl:param name="qname"/>
<xsl:choose>
<xsl:when test="contains($qname,':')">
<xsl:value-of select="substring-after($qname,':')"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$qname"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
Running the above example against the test WSDL document produces:
Listing 10. Technique 3 example output
local name of foo:bar is bar
local name of baz is baz
The approach shown below uses XSL named keys in conjunction with the templates
introduced in the previous techniques to build a robust solution to this problem.
Running the above example against the test WSDL document produces:
has
has
has
has
1
1
1
0
input
input
input
input
parts,
parts,
parts,
parts,
0
1
1
1
output
output
output
output
parts,
parts,
parts,
parts,
0
0
0
0
fault
fault
fault
fault
parts
parts
parts
parts
<xsl:text> </xsl:text>
<xsl:call-template name="local-name-of-qname">
<xsl:with-param name="qname" select="@type"/>
</xsl:call-template>
</xsl:template>
<!-- dump out the messages associated with each binding operation -->
<xsl:template match="wsdl:binding/wsdl:operation">
<xsl:text> operation: </xsl:text>
<xsl:value-of select="@name"/>
<xsl:text>
</xsl:text>
<xsl:variable name="porttype-key">
<xsl:apply-templates select=".." mode="porttype-key"/>
</xsl:variable>
<xsl:variable name="opname">
<xsl:value-of select="@name"/>
</xsl:variable>
<xsl:for-each select="wsdl:input">
<xsl:text> input: </xsl:text>
<xsl:value-of select="@name"/>
<xsl:text> -> message: </xsl:text>
<xsl:for-each select="key('porttype',$porttype-key)/
wsdl:operation[@name=$opname]/
wsdl:input[@name=current()/@name]">
<xsl:value-of select="@message"/>
</xsl:for-each>
<xsl:text>
</xsl:text>
</xsl:for-each>
<xsl:if test="not(wsdl:input)">
<xsl:text> (no inputs)
</xsl:text>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
Running the above example against the test WSDL document produces:
Listing 16. Technique 5 example output
binding: binding
operation: porttype-op1
input: porttype-op1-input -> message: test:inputmsg1
operation: porttype-op2
input: porttype-op2-input -> message: test:inputmsg2
operation: porttype-op3
input: porttype-op3-input -> message: test:inputmsg3
operation: porttype-op4
(no inputs)
The final qname mapping is from the wsdl:service/wsdl:port back to the wsdl:binding.
Again, named keys provide the solution.
Listing 17. Technique 6 XSL
<!-- index of wsdl:binding by namespace uri and wsdl:binding/@name -->
<xsl:key name="binding" match="wsdl:binding"
use="concat(/wsdl:definitions/@targetNamespace,' ',@name)"/>
<xsl:text> </xsl:text>
<xsl:call-template name="local-name-of-qname">
<xsl:with-param name="qname" select="@binding"/>
</xsl:call-template>
</xsl:template>
This example puts together many of the techniques described here to generate a
summary of the operations provided by each wsdl:servicein a WSDL document.
Listing 18. Technique 6 example
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:import href="wsdl-util.xsl"/>
<xsl:strip-space elements="*"/>
<xsl:output method="text"/>
Running the above example against the test WSDL document produces:
Listing 19. Technique 6 example output
service: service
void porttype-op1(xsd:string inputmsg1-part);
xsd:base64Binary porttype-op2(xsd:decimal inputmsg2-part) throws faultmsg;
xsd:base64Binary porttype-op3(xsd:integer inputmsg3-part) throws faultmsg;
xsd:base64Binary porttype-op4();
This is more of a best practice than a technique per se, but it has proven extremely
useful. When transforming WSDL documents into new WSDL documents, it is often
tempting to insert additional data types and messages directly into the new WSDL
document. If this new information is static (that is, does not depend on the input WSDL)
consider using the WSDL import mechanism instead. Importing these definitions gives
you the ability to change them later without re-transforming all the WSDL documents.
Due to the nature of this technique, it is not included in the downloadable wsdl-util.xsl.
Listing 20. Technique 7 XSL
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:output method="xml" indent="yes"/>
<xsl:preserve-space elements="*"/>
Here are the relevant portions of test.wsdl after being updated by the XSL shown above:
Listing 21. Technique 7 example output
<?xml version="1.0"?>
<wsdl:definitions name="test"
targetNamespace="http://tempuri.org/test/"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:test="http://tempuri.org/test/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
<wsdl:import namespace="http://tempuri.org/mystuff" location="mystuff.wsdl"/>
<wsdl:message name="inputmsg1">
<wsdl:part name="inputmsg1-part" type="xsd:string"/>
</wsdl:message>
...
Here are the relevant portions of test.wsdl after being updated by the XSL shown above:
Listing 23. Technique 8 example output
...
<wsdl:message name="faultmsg"/>
<wsdl:portType name="porttype-mysuffix">
<!-- one-way operation -->
<wsdl:operation name="porttype-op1">
<wsdl:input message="test:inputmsg1" name="porttype-op1-input"/>
</wsdl:operation>
...
Back to top
Themes
In conclusion, here are some higher-level themes from the techniques shown above for
processing WSDL documents with XSL. Hopefully they will save you some time and
mental anguish the next time you need to hack a WSDL document with XSL:
1.
2.
3.
4.
5.
6.
The local context does not persist beyond the scope of the transaction. A
transaction can include both a request component and a response component.
The local context cannot be accessed by any object outside the scope of the
transaction. In other words, a service cannot read and use the variable.
A local context variable can be user-defined or based on an extension variable.
var://context/context/variable
Addresses a variable that is called variable in a context
called context. The following example transforms the document
in the tmp1context with a style sheet. The style sheet is
referenced by the stylesheet-1 variable (in
the apple context) and stores the transformed document in
the tmp2 context:
xform tmp1 var://context/apple/stylesheet-1 tmp2
A named context does not persist beyond the scope of the transaction. A
transaction can include both a request component and a response component.
The local context cannot be accessed by any object outside of the scope of the
transaction. In other words, the service cannot read and use the variable.
Note: Creating variables in a named context is the preferred
approach. This form decouples the variable from the input and
output contexts and allows the variable to be accessed from
any step in a scope.
A named context variable can be user-defined or can be based on an extension
variable.
var://service/variable
Addresses a variable that is made available to a DataPower
service that is attached to a session.
Many service variables are supported in XSLT and GatewayScript . For
example, the variable skip-backside has the XSLT
formvar://service/mpgw/skip-backside and
the GatewayScript form mpgw.skipBackside. The term "slash notation"
refers to the XSLT name form and the term "dot notation" refers to
the GatewayScript name form. GatewayScript variables that are not supported
do not appear in the syntax section of the description of the variable.
Calls to GatewayScript variables support both forms of names.
A program that uses the dot notation form establishes access
to the service variables in two steps: requiring the module that
holds the service variables (service-metadata) and setting a
variable to access the variables. For example:
var serviceVars = require ( 'service-metadata' ); // import the
service variables functions
serviceVars.mpgw.skipBackside = true;
// write to the
skipbackside service variable
Both these name forms are listed in the function information where both are
supported. When the GatewayScript name form is not in the list,
the GatewayScript form is not supported. GatewayScript checks the data type
when a new value is assigned to a service variable. The gettermethod returns
a value with the correct data type.
var://system/variable
Addresses a global variable that is available in all contexts.
System variables persist beyond the scope of request-response
processing and can be read by other objects on the appliance.
If the content of a variable needs to be read or set outside the
scope of request-response processing, use a system variable.
Service variables
Service variables enable the setting and retrieval of pieces of
state that usually reflect the state of the current transaction.
Parent topic: DataPower Gateway
Configuration
WS-Security
Once the header has been configured as described in the next section, the firewall
policy is added.
Headers
In the firmware version, the DataPower appliance generated two connection header
tags. By adding suppression for this tag, only one connection header is sent by the
DataPower appliance. Figure 5 shows the Headers page with the connection header tag
suppressed in the "back" direction:
Figure 5. Configuring the headers
Processing policy
The processing policy includes just two rules: the Request rule decrypts the incoming
message body, and the Response rule encrypts the message body of the reply.
Following the traditions of security literature, the keys used in this article are named
AliceKey and BobKey. The requesting application sends messages encrypted with the
AliceKey, and the DataPower appliance encrypts the reply with the BobKey.
Request (decryption) rule
The Request rule includes a match rule property and a decrypt action as in the following
figure. The matching rule property matches on all URLs.
Figure 6. The decryption rule
The decrypt action is configured to decrypt the incoming message as determined from
the WS-Security headers and information contained within the SOAP message. As the
requesting application has encrypted the message with the AliceKey, it is used for
decryption within the DataPower appliance.
Figure 7. The decryption action
The response rule performs the opposite, encrypting the messages flowing in this
direction:
Figure 8. The encryption rule
The encryption action is configured to encrypt the SOAP message body using WSSecurity, and it uses the predefined key BobKey:
Figure 9. The encryption action
The private half of the BobKey is owned by the requesting application, so that it can
decrypt the message sent by the DataPower appliance.
Configuring Message Broker
The processing being performed is that of the Web services sample WSHOST, which is
supplied with WebSphere Message Broker V6. For more information about this sample,
go to the Message Broker toolkit and select Help => Samples Gallery on the Toolkit
menu:
Figure 11. The two WebSphere Message Broker message flows
The first message flow processes the incoming SOAP/HTTP message after t has been
decrypted by the DataPower appliance. After converting the message format and
protocol, it writes an output message to a WebSphere MQ queue, which is read and
processed by the WebSphere MQ application.
The second message flow receives the WebSphere MQ reply message from the
WebSphere MQ application and converts the format and protocol of the input message
into a SOAP/HTTP reply message. The reply message generated by the second
message flow is passed to the DataPower appliance, so that it can be encrypted prior to
being returned to the requesting application.
HTTP Input node properties
The input node properties show the URL on which this flow is configured to receive
requests. The HTTPS box remains unchecked -- a later section enables it to complete
the security.
WebSphere MQ application
The following sections show the messages that flow within the system to and from the
DataPower appliance. Figure 12 below shows the placement of these messages within
the overall flow. Messages between Message Broker and the backend WebSphere MQ
application are not shown.
Figure 12. Highlighting the messages described in this section
Shown below is the HTTP body of the message sent to the DataPower appliance by the
requesting application. The real content of the message in its encrypted form is
highlighted (in bold) and has been truncated for readability. For the full contents of this
and subsequent messages, see Downloads below.
Message 1. The message sent from the application to the DataPower appliance
Here is the HTTP body of the message sent by the DataPower appliance to Message
Broker. The body (in bold) has been decrypted to reveal the SOAP request:
Message 2. Message sent from the DataPower appliance to Message Broker
<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:c="http://www.brokersamplewshost.ibm.com"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soapenv:Header>
<wsse:Security soapenv:mustUnderstand="1"
xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wsswssecurity-secext-1.0.xsd">
</wsse:Security>
</soapenv:Header>
<soapenv:Body>
<c:IA81CONFIN>
<MessageId>IA81CONF</MessageId>
<OrderNumber>ON4002</OrderNumber>
<ItemReference>IY4003</ItemReference>
<ItemQuantity>4</ItemQuantity>
<CustomerNumber>CY4004</CustomerNumber>
</c:IA81CONFIN>
</soapenv:Body>
</soapenv:Envelope>
Here is the HTTP body of the message returned by Message Broker to the DataPower
appliance. For this return trip, two additional fields, DeliveryRef and Confirm (in bold),
are included at the end of the message:
Message 3. Message sent from Message Broker to the DataPower appliance
<?xml version="1.0"?>
<tns:Envelope xmlns:tns="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:NS1="http://www.brokersamplewshost.ibm.com"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<tns:Body>
<NS1:IA81CONFOUT>
<MessageId>IA81CONF</MessageId>
<OrderNumber>ON4002</OrderNumber>
<ItemReference>IY4003</ItemReference>
<ItemQuantity>4</ItemQuantity>
<CustomerNumber>CY4004</CustomerNumber>
<DeliveryRef>JOHNCORP</DeliveryRef>
<Confirm>Y</Confirm>
</NS1:IA81CONFOUT>
</tns:Body>
</tns:Envelope>
The HTTP body of the message returned by the DataPower appliance to the requesting
application follows a similar pattern to the first message sent to the DataPower
appliance. The difference is that the contents of this message is encrypted using the
return key. Decrypting this message would reveal the message sent by Message
Broker.
Message 4. Message sent from the DataPower appliance to the application
Securing the connection between the DataPower appliance and Message Broker
Adding SSL support between the DataPower appliance and Message Broker completes
the security of the connections between them:
Figure 13. Securing the link between the DataPower appliance and Message Broker
To enable SSL for Message Broker, it must first be configured and assigned a
certificate. For this article, a self-signed certificate within a key store is used by the
Message Broker HTTP listener process. You could also use a certificate signed by a
certificate authority. The broker is then configured to use this key store.
The Java ikeyman application is used to create the key store. To create a self-signed
certificate stored within this key store, select New Self-Signed Certificate. For this
article the following configuration is used:
Figure 14. The self-signed certificate in ikeyman
To provide the public half of this certificate to the the DataPower appliance,
select Extract certificate. The following commands enable SSL, configure the key
store, provide the password for this key store, and set the HTTPS port:
Listing 4. The commands to enable HTTPS in Message Broker
>mqsichangeproperties WBRK6_DEFAULT_BROKER -b httplistener -o HTTPListener
-n enableSSLConnector -v true
>mqsichangeproperties WBRK6_DEFAULT_BROKER -b httplistener -o HTTPSConnector
-n keystoreFile -v "c:\Program Files\IBM\WMBv6.0\MyKeystore.jks"
>mqsichangeproperties WBRK6_DEFAULT_BROKER -b httplistener -o HTTPSConnector
-n keystorePass -v ********
>mqsichangeproperties WBRK6_DEFAULT_BROKER -b httplistener -o HTTPSConnector
-n port -v 7083
The broker must be restarted for these changes to take effect within the HTTP listener
process. You can then use the following two commands to verify the previous settings:
Listing 5. The commands report the HTTPS settings in Message Broker
>mqsireportproperties WBRK6_DEFAULT_BROKER -b httplistener -o HTTPListener -a
HTTPListener=''
uuid='HTTPListener'
enableSSLConnector='true'
traceLevel='none'
traceSize='4194304'
BIP8071I: Successful command completion.
>mqsireportproperties WBRK6_DEFAULT_BROKER -b httplistener -o HTTPSConnector -a
HTTPSConnector=''
uuid='HTTPSConnector'
keystoreFile='c:\Program Files\IBM\WMBv6.0\MyKeystore.jks'
keystorePass='********'
port='7083'
BIP8071I: Successful command completion.
With the broker restarted, you can configure the HTTP input node for HTTPS and
redeploy the message flow to the broker. Figure 15 shows the properties of the HTTP
Input node within the message flow, with Use HTTPS checked:
Figure 15. Properties of the HTTP node with the Use HTTPS item checked
You can use the netstat -a (or equivalent) command after Message Broker is restarted
and an HTTPS flow is deployed, to confirm that the HTTP listener is listening on the
configured port.
Configuring client-side SSL in the DataPower appliance
You must upload a certificate of the key generated for Message Broker into the
DataPower appliance, which is added as a trusted server within an SSL profile that is
then used for the SSL client crypto profile. To create and associate an SSL client crypto
profile, select Create on the main XML Firewall configuration page. To configure the
profile upload, then add the certificate exported from ikeyman to the Trusted Servers
section of the crypto profile. Select the option to authenticate and validate the certificate.
With this check the DataPower appliance can be trusted to connect only to trusted
servers.
Figure 16. The Trusted Server configuration
You must also reconfigure the XML firewall to point to the SSL port of the HTTP listener
(in this case the default value of 7083).
SSL encryption
To observe this change, an HTTP tunnel is placed between the DataPower appliance
and Message Broker and used to observe messages that pass in both directions
between the two components. Whilst some of the initial exchange that forms the SSL
protocol passes as clear text, after the private keys are established for the session, all
data is encrypted.
Message Broker Explorer
Message Broker Explorer (IS02 support pack) now includes a wizard that can configure
an XML firewall within the DataPower appliance for connection with HTTP flows
provisioned by Message Broker. For more information, see the first article below under
"Resources."
Conclusion
This article has demonstrated how you can use a WebSphere DataPower SOA
appliance to extend the function provided by WebSphere Message Broker and provide
WS-Security of SOAP messages to HTTP message flows. The article also showed how
to provide security between WebSphere Message Broker and the DataPow