Moved Spring-WS to separate dir.
This commit is contained in:
33
doc/src/docbkx/bibliography.xml
Normal file
33
doc/src/docbkx/bibliography.xml
Normal file
@@ -0,0 +1,33 @@
|
||||
<bibliography>
|
||||
<title>Bibliography</title>
|
||||
<biblioentry id="waldo-94">
|
||||
<authorgroup>
|
||||
<author>
|
||||
<firstname>Jim</firstname><surname>Waldo</surname>
|
||||
</author>
|
||||
<author>
|
||||
<firstname>Ann</firstname><surname>Wollrath</surname>
|
||||
</author>
|
||||
<author>
|
||||
<firstname>Sam</firstname><surname>Kendall</surname>
|
||||
</author>
|
||||
</authorgroup>
|
||||
<title>A Note on Distributed Computing</title>
|
||||
<publisher><publishername>Springer Verlag</publishername></publisher>
|
||||
<date>1994</date>
|
||||
</biblioentry>
|
||||
<biblioentry id="alpine">
|
||||
<authorgroup>
|
||||
<author>
|
||||
<firstname>Steve</firstname><surname>Loughran</surname>
|
||||
</author>
|
||||
<author>
|
||||
<firstname>Edmund</firstname><surname>Smith</surname>
|
||||
</author>
|
||||
</authorgroup>
|
||||
<title>Rethinking the Java SOAP Stack</title>
|
||||
<date>May 17, 2005</date>
|
||||
<copyright><year>2005</year>
|
||||
<holder>IEEE Telephone Laboratories, Inc.</holder></copyright>
|
||||
</biblioentry>
|
||||
</bibliography>
|
||||
365
doc/src/docbkx/contract-first.xml
Normal file
365
doc/src/docbkx/contract-first.xml
Normal file
@@ -0,0 +1,365 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<chapter id="contract">
|
||||
<title>Writing Contract-first Web Services</title>
|
||||
|
||||
<section id="contract-introduction">
|
||||
<title>Introduction</title>
|
||||
<para>
|
||||
In this chapter, we will give an overall tutorial on how to approach Web services development in
|
||||
contract-first style, i.e. starting with the XML Schema/WSDL contract instead of Java code. Spring-WS
|
||||
focusses on this development style, and this chapter might help you get started. Note that this chapter
|
||||
contains almost no Spring-WS specific information: it is mostly about XML, schema's, and WSDL.
|
||||
</para>
|
||||
<para>
|
||||
In this tutorial, we will define a Web service that can be used for Human Resources. Clients can send
|
||||
holiday request forms to this service to book a holiday. It is based on a metaphor for Service Oriented
|
||||
Architectures originally though of by <ulink
|
||||
url="http://blog.springframework.com/arjen/archives/2006/02/06/what-is-so-hard-about-soa/"><citetitle>Dan
|
||||
North</citetitle></ulink>.
|
||||
</para>
|
||||
<para>
|
||||
The most important thing when doing contract-first Web service development is to try and think in terms of
|
||||
XML. This means that Java-language concepts are of lesser importance. It is the XML that is sent across the
|
||||
wire, and you should focus on that.
|
||||
</para>
|
||||
</section>
|
||||
<section>
|
||||
<title>The Messages</title>
|
||||
<para>
|
||||
In this section, we will focus on the actual XML messages that are sent to and from the service. We will
|
||||
start out by determining what these messages look like.
|
||||
</para>
|
||||
<section>
|
||||
<title>Holiday</title>
|
||||
<para>
|
||||
In the scenario, we have to deal with holiday request, so it makes sense to determine what a holiday
|
||||
looks like:
|
||||
<programlisting>
|
||||
<![CDATA[<Holiday xmlns="http://mycompany.com/holidays/schemas">
|
||||
<StartDate>2006-07-03</StartDate>
|
||||
<EndDate>2006-07-07</EndDate>
|
||||
</Holiday>]]></programlisting>
|
||||
</para>
|
||||
<para>
|
||||
A holiday consists of a start date and an end date. We decided to use the standard
|
||||
<ulink url="http://www.cl.cam.ac.uk/~mgk25/iso-time.html"><citetitle>ISO 8601</citetitle></ulink> date
|
||||
format for the dates, because that will save a lot of parsing hassle. We also added a namespace to the
|
||||
element, to make sure our elements can used within other XML documents.
|
||||
</para>
|
||||
</section>
|
||||
<section>
|
||||
<title>Employee</title>
|
||||
<para>
|
||||
There is also the notion of an employee in the scenario. Here's what it looks like:
|
||||
<programlisting>
|
||||
<![CDATA[<Employee xmlns="http://mycompany.com/holidays/schemas">
|
||||
<Number>42</Number>
|
||||
<FirstName>Arjen</FirstName>
|
||||
<LastName>Poutsma</LastName>
|
||||
</Employee>]]></programlisting>
|
||||
</para>
|
||||
<para>
|
||||
We have used the same namespace as before. If this employee element could be used in other scenarios,
|
||||
it might make sense to use a different namespace, such as
|
||||
<literal>"http://mycompany.com/employees/schemas"</literal>.
|
||||
</para>
|
||||
</section>
|
||||
<section id="contract-holiday-request">
|
||||
<title>HolidayRequest</title>
|
||||
<para>
|
||||
Both the holiday and employee element can be put in a <literal>HolidayRequest</literal>:
|
||||
<programlisting>
|
||||
<![CDATA[<HolidayRequest xmlns="http://mycompany.com/holidays/schemas">
|
||||
<Holiday>
|
||||
<StartDate>2006-07-03</StartDate>
|
||||
<EndDate>2006-07-07</EndDate>
|
||||
</Holiday>
|
||||
<Employee>
|
||||
<Number>42</Number>
|
||||
<FirstName>Arjen</FirstName>
|
||||
<LastName>Poutsma</LastName>
|
||||
</Employee>
|
||||
</HolidayRequest>]]></programlisting>
|
||||
</para>
|
||||
<para>
|
||||
The order of the two element does not matter: <literal>Employee</literal> could have been the first
|
||||
element just as well. As long as all the data is there; that's what is important.
|
||||
In fact, the data is the only thing that is important: we are taking a <emphasis>data-driven</emphasis>
|
||||
approach.
|
||||
</para>
|
||||
</section>
|
||||
</section>
|
||||
<section id="contract-schema">
|
||||
<title>The Schema</title>
|
||||
<para>
|
||||
Now that we have seen some examples of the XML data that we will use, it makes sense to formalize this into
|
||||
a schema. Basically, there are four different ways of defining a grammar for XML:
|
||||
<itemizedlist>
|
||||
<listitem><para>DTDs</para></listitem>
|
||||
<listitem><para>
|
||||
<ulink url="http://www.w3.org/XML/Schema"><citetitle>XML Schema (XSD)</citetitle></ulink>
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
<ulink url="http://www.relaxng.org/"><citetitle>RELAX NG</citetitle></ulink>
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
<ulink url="http://www.schematron.com/"><citetitle>Schematron</citetitle></ulink>
|
||||
</para></listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
<para>
|
||||
DTDs have limited namespaces support, so they are not suitable for Web services. Relax NG and Schematron are
|
||||
certainly easier than XSDs. Unfortunately, they are not so widely supported across platforms. We will use
|
||||
XML Schema.
|
||||
</para>
|
||||
<para>
|
||||
By far the easiest way to create a XSD is to infer it from sample documents. Any good XML editor or Java IDE
|
||||
offers this functionality. Basically, these tools use some sample XML documents, and generate a schema from it
|
||||
that validates them all. The end result certainly needs to be polished up, but it's a great starting
|
||||
point.
|
||||
</para>
|
||||
<para>
|
||||
Using the sample described in <xref linkend="contract-holiday-request"/>, we end up with the following
|
||||
generated schema:
|
||||
<programlisting>
|
||||
<![CDATA[<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
||||
elementFormDefault="qualified"
|
||||
targetNamespace="http://mycompany.com/holidays/schemas"
|
||||
xmlns:holidays="http://mycompany.com/holidays/schemas">
|
||||
<xs:element name="HolidayRequest">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element ref="holidays:Holiday"/>
|
||||
<xs:element ref="holidays:Employee"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element name="Holiday">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element ref="holidays:StartDate"/>
|
||||
<xs:element ref="holidays:EndDate"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element name="StartDate" type="xs:NMTOKEN"/>
|
||||
<xs:element name="EndDate" type="xs:NMTOKEN"/>
|
||||
<xs:element name="Employee">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element ref="holidays:Number"/>
|
||||
<xs:element ref="holidays:FirstName"/>
|
||||
<xs:element ref="holidays:LastName"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element name="Number" type="xs:integer"/>
|
||||
<xs:element name="FirstName" type="xs:NCName"/>
|
||||
<xs:element name="LastName" type="xs:NCName"/>
|
||||
</xs:schema>]]></programlisting>
|
||||
</para>
|
||||
<para>
|
||||
The generated schema can obviously be improved. The first thing to notice is that everything is a root-level
|
||||
element. This means that the Web service should be able to accept all of these elements as data. This is not
|
||||
desirable: we only want to accept a <literal>HolidayRequest</literal>. By removing the wrapping element tags
|
||||
(thus keeping the types), and inlining the results, we can accomplish this.
|
||||
<programlisting>
|
||||
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
||||
xmlns:holidays="http://mycompany.com/holidays/schemas"
|
||||
elementFormDefault="qualified"
|
||||
targetNamespace="http://mycompany.com/holidays/schemas">
|
||||
<xs:element name="HolidayRequest">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element name="Holiday" <emphasis>type="holidays:HolidayType"</emphasis>/>
|
||||
<xs:element name="Employee" <emphasis>type="holidays:EmployeeType"</emphasis>/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:complexType name="HolidayType">
|
||||
<xs:sequence>
|
||||
<xs:element name="StartDate" type="xs:NMTOKEN"/>
|
||||
<xs:element name="EndDate" type="xs:NMTOKEN"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="EmployeeType">
|
||||
<xs:sequence>
|
||||
<xs:element name="Number" type="xs:integer"/>
|
||||
<xs:element name="FirstName" type="xs:NCName"/>
|
||||
<xs:element name="LastName" type="xs:NCName"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:schema></programlisting>
|
||||
</para>
|
||||
<para>
|
||||
The schema still has one problem: with a schema like this, you can expect the following messages to
|
||||
validate:
|
||||
<programlisting>
|
||||
<![CDATA[<HolidayRequest xmlns="http://mycompany.com/holidays/schemas">
|
||||
<Holiday>
|
||||
<StartDate>this is not a date</StartDate>
|
||||
<EndDate>neither is this</EndDate>
|
||||
</Holiday>
|
||||
...
|
||||
</HolidayRequest>]]></programlisting>
|
||||
</para>
|
||||
<para>
|
||||
Clearly, we must make sure that the start and end date are really dates. XML Schema has an excellent built-in
|
||||
<literal>date</literal> type which we can use. We also change the <literal>NCName</literal>s to
|
||||
<literal>string</literal>s. Finally, we change the <literal>sequence</literal> in
|
||||
<literal>HolidayRequest</literal> to <literal>all</literal>. This tells the XML parser that the order of
|
||||
<literal>Holiday</literal> and <literal>Employee</literal> is not significant. Our final XSD looks like this:
|
||||
<programlisting>
|
||||
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
||||
xmlns:holidays="http://mycompany.com/holidays/schemas"
|
||||
elementFormDefault="qualified"
|
||||
targetNamespace="http://mycompany.com/holidays/schemas">
|
||||
<xs:element name="HolidayRequest">
|
||||
<xs:complexType>
|
||||
<<emphasis>xs:all</emphasis>>
|
||||
<xs:element name="Holiday" type="holidays:HolidayType"/>
|
||||
<xs:element name="Employee" type="holidays:EmployeeType"/>
|
||||
</<emphasis>xs:all</emphasis>>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:complexType name="HolidayType">
|
||||
<xs:sequence>
|
||||
<xs:element name="StartDate" <emphasis>type="xs:date"</emphasis>/>
|
||||
<xs:element name="EndDate" <emphasis>type="xs:date"</emphasis>/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="EmployeeType">
|
||||
<xs:sequence>
|
||||
<xs:element name="Number" type="xs:integer"/>
|
||||
<xs:element name="FirstName" <emphasis>type="xs:string"</emphasis>/>
|
||||
<xs:element name="LastName" <emphasis>type="xs:string"</emphasis>/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:schema></programlisting>
|
||||
</para>
|
||||
<para>
|
||||
We can store this file with a convenient name such as <filename>holidays.xsd</filename>.
|
||||
</para>
|
||||
</section>
|
||||
<section id="contract-wsdl">
|
||||
<title>The WSDL</title>
|
||||
<para>
|
||||
Which leaves the WSDL. We start our WSDL with the standard preamble, and by importing our existing XSD. To
|
||||
separate the schema from the definition, we will use a separate namespace for the WSDL definitions:
|
||||
<literal>"http://mycompany.com/holidays/definitions"</literal>.
|
||||
<programlisting>
|
||||
<wsdl:definitions name="HumanResources"
|
||||
targetNamespace="http://mycompany.com/holidays/definitions"
|
||||
xmlns:tns="http://mycompany.com/holidays/definitions"
|
||||
<emphasis>xmlns:types="http://mycompany.com/holidays/schemas"</emphasis>
|
||||
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
|
||||
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
|
||||
<wsdl:types>
|
||||
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
|
||||
<emphasis><xsd:import namespace="http://mycompany.com/holidays/schemas"
|
||||
schemaLocation="holidays.xsd"/></emphasis>
|
||||
</xsd:schema>
|
||||
</wsdl:types>
|
||||
</wsdl:definitions></programlisting>
|
||||
</para>
|
||||
<para>
|
||||
Next, we define our messages based on the written schema. We only have one message: one with the
|
||||
<literal>HolidayRequest</literal> we put in the schema:
|
||||
<programlisting>
|
||||
<wsdl:definitions name="HumanResources"
|
||||
targetNamespace="http://mycompany.com/holidays/definitions"
|
||||
xmlns:tns="http://mycompany.com/holidays/definitions"
|
||||
xmlns:types="http://mycompany.com/holidays/schemas"
|
||||
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
|
||||
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
|
||||
<wsdl:types>
|
||||
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
|
||||
<xsd:import namespace="http://mycompany.com/holidays/schemas"
|
||||
schemaLocation="holidays.xsd"/>
|
||||
</xsd:schema>
|
||||
</wsdl:types>
|
||||
<emphasis><wsdl:message name="RequestHolidayInput"></emphasis>
|
||||
<emphasis><wsdl:part name="body" element="types:HolidayRequest" /></emphasis>
|
||||
<emphasis></wsdl:message></emphasis>
|
||||
</wsdl:definitions></programlisting>
|
||||
</para>
|
||||
<para>
|
||||
We add the messages to a port type as operations:
|
||||
<programlisting>
|
||||
<wsdl:definitions name="HumanResources"
|
||||
targetNamespace="http://mycompany.com/holidays/definitions"
|
||||
xmlns:tns="http://mycompany.com/holidays/definitions"
|
||||
xmlns:types="http://mycompany.com/holidays/schemas"
|
||||
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
|
||||
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
|
||||
<wsdl:types>
|
||||
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
|
||||
<xsd:import namespace="http://mycompany.com/holidays/schemas"
|
||||
schemaLocation="holidays.xsd"/>
|
||||
</xsd:schema>
|
||||
</wsdl:types>
|
||||
<wsdl:message name="RequestHolidayInput">
|
||||
<wsdl:part name="body" element="types:HolidayRequest" />
|
||||
</wsdl:message>
|
||||
<emphasis><wsdl:portType name="HumanResourcesPortType"></emphasis>
|
||||
<emphasis><wsdl:operation name="RequestHoliday"></emphasis>
|
||||
<emphasis><wsdl:input message="tns:RequestHolidayInput" /></emphasis>
|
||||
<emphasis></wsdl:operation></emphasis>
|
||||
<emphasis></wsdl:portType></emphasis>
|
||||
</wsdl:definitions></programlisting>
|
||||
</para>
|
||||
<para>
|
||||
That finished the abstract part of the WSDL (the interface, as it were), and leaves the concrete part. This
|
||||
part consists of a <literal>binding</literal>, which tells the client <emphasis>how</emphasis> to invoke the
|
||||
operations you've just defined; and a <literal>service</literal>, which tells it <emphasis>where</emphasis>
|
||||
to invoke it.
|
||||
</para>
|
||||
<para>
|
||||
Adding a concrete part is pretty standard: just refer to the abstract part you defined previously, make sure
|
||||
you use <emphasis>document/literal</emphasis> for the <literal><soap:binding></literal> elements
|
||||
(anything else is not interoperable), pick a <literal>soapAction</literal> (in this case
|
||||
<literal>http://example.com/RequestHoliday</literal>, but any URI will do), and determine the
|
||||
<literal>location</literal> URL where you want request to come in (in this case
|
||||
<literal>http://mycompany.com/humanresources</literal>):
|
||||
<programlisting>
|
||||
<wsdl:definitions name="HumanResources"
|
||||
targetNamespace="http://mycompany.com/holidays/definitions"
|
||||
xmlns:tns="http://mycompany.com/holidays/definitions"
|
||||
xmlns:types="http://mycompany.com/holidays/schemas"
|
||||
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
|
||||
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
|
||||
<wsdl:types>
|
||||
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
|
||||
<xsd:import namespace="http://mycompany.com/holidays/schemas"
|
||||
schemaLocation="holidays.xsd"/>
|
||||
</xsd:schema>
|
||||
</wsdl:types>
|
||||
<wsdl:message name="RequestHolidayInput">
|
||||
<wsdl:part name="body" element="types:HolidayRequest" />
|
||||
</wsdl:message>
|
||||
<wsdl:portType name="HumanResourcesPortType">
|
||||
<wsdl:operation name="RequestHoliday">
|
||||
<wsdl:input message="tns:RequestHolidayInput" />
|
||||
</wsdl:operation>
|
||||
</wsdl:portType>
|
||||
<wsdl:binding name="HumanResourcesBinding" type="tns:HumanResourcesPortType">
|
||||
<soap:binding <emphasis>style="document</emphasis>" transport="http://schemas.xmlsoap.org/soap/http" />
|
||||
<wsdl:operation name="RequestHoliday">
|
||||
<soap:operation <emphasis>soapAction="http://example.com/RequestHoliday"</emphasis> />
|
||||
<wsdl:input>
|
||||
<soap:body <emphasis>use="literal"</emphasis> />
|
||||
</wsdl:input>
|
||||
</wsdl:operation>
|
||||
</wsdl:binding>
|
||||
<wsdl:service name="HumanResourcesService">
|
||||
<wsdl:port name="HumanResourcesPort" binding="tns:HumanResourcesBinding">
|
||||
<soap:address <emphasis>location="http://mycompany.com/humanresources"</emphasis> />
|
||||
</wsdl:port>
|
||||
</wsdl:service>
|
||||
</wsdl:definitions></programlisting>
|
||||
</para>
|
||||
<para>
|
||||
This is the final WSDL. We will describe how to implement the resulting schema and WSDL in the next chapter.
|
||||
</para>
|
||||
</section>
|
||||
</chapter>
|
||||
BIN
doc/src/docbkx/images/oxm-exceptions.png
Normal file
BIN
doc/src/docbkx/images/oxm-exceptions.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 20 KiB |
48
doc/src/docbkx/images/oxm-exceptions.svg
Normal file
48
doc/src/docbkx/images/oxm-exceptions.svg
Normal file
@@ -0,0 +1,48 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN"
|
||||
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
|
||||
<!-- Generated by dot version 1.13 (v16) (Mon August 23, 2004)
|
||||
For user: (arjen) Arjen Poutsma Title: G Pages: 1 -->
|
||||
<svg width="525pt" height="192pt"
|
||||
viewBox = "-1 -1 524 191"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<g id="graph0" class="graph" style="font-family:Times-Roman;font-size:14.00;">
|
||||
<title>G</title>
|
||||
<g id="node1" class="node"><title>c1</title>
|
||||
<polygon style="fill:none;stroke:black;" points="259,40 374,40 374,4 259,4 259,40"/>
|
||||
<text text-anchor="middle" x="316" y="25" style="font-family:Arial Italic;font-size:10.00;">XmlMappingException</text>
|
||||
</g>
|
||||
<g id="node2" class="node"><title>c2</title>
|
||||
<polygon style="fill:none;stroke:black;" points="88,112 321,112 321,76 88,76 88,112"/>
|
||||
<text text-anchor="middle" x="204" y="97" style="font-family:Arial Regular;font-size:10.00;">GenericMarshallingFailureException</text>
|
||||
</g>
|
||||
<g id="edge2" class="edge"><title>c1->c2</title>
|
||||
<path style="fill:none;stroke:black;" d="M279,46C264,56 246,67 232,76"/>
|
||||
<polygon style="fill:none;stroke:black;" points="278,43 288,40 282,48 278,43"/>
|
||||
</g>
|
||||
<g id="node8" class="node"><title>c5</title>
|
||||
<polygon style="fill:none;stroke:black;" points="338,112 518,112 518,76 338,76 338,112"/>
|
||||
<text text-anchor="middle" x="428" y="97" style="font-family:Arial Regular;font-size:10.00;">ValidationFailureException</text>
|
||||
</g>
|
||||
<g id="edge8" class="edge"><title>c1->c5</title>
|
||||
<path style="fill:none;stroke:black;" d="M353,46C368,56 386,67 400,76"/>
|
||||
<polygon style="fill:none;stroke:black;" points="350,48 344,40 354,43 350,48"/>
|
||||
</g>
|
||||
<g id="node4" class="node"><title>c3</title>
|
||||
<polygon style="fill:none;stroke:black;" points="5,184 191,184 191,148 5,148 5,184"/>
|
||||
<text text-anchor="middle" x="98" y="169" style="font-family:Arial Regular;font-size:10.00;">MarshallingFailureException</text>
|
||||
</g>
|
||||
<g id="edge4" class="edge"><title>c2->c3</title>
|
||||
<path style="fill:none;stroke:black;" d="M168,118C154,128 138,139 124,148"/>
|
||||
<polygon style="fill:none;stroke:black;" points="167,115 177,112 171,120 167,115"/>
|
||||
</g>
|
||||
<g id="node6" class="node"><title>c4</title>
|
||||
<polygon style="fill:none;stroke:black;" points="209,184 413,184 413,148 209,148 209,184"/>
|
||||
<text text-anchor="middle" x="311" y="169" style="font-family:Arial Regular;font-size:10.00;">UnmarshallingFailureException</text>
|
||||
</g>
|
||||
<g id="edge6" class="edge"><title>c2->c4</title>
|
||||
<path style="fill:none;stroke:black;" d="M240,118C254,128 271,139 284,148"/>
|
||||
<polygon style="fill:none;stroke:black;" points="237,120 231,112 241,115 237,120"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.6 KiB |
49
doc/src/docbkx/index.xml
Normal file
49
doc/src/docbkx/index.xml
Normal file
@@ -0,0 +1,49 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN" "http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd" [
|
||||
<!ENTITY preface SYSTEM "preface.xml">
|
||||
<!ENTITY overview SYSTEM "overview.xml">
|
||||
<!ENTITY contract-first SYSTEM "contract-first.xml">
|
||||
<!ENTITY ws SYSTEM "ws.xml">
|
||||
<!ENTITY security SYSTEM "security.xml">
|
||||
<!ENTITY oxm SYSTEM "oxm.xml">
|
||||
<!ENTITY bibliography SYSTEM "bibliography.xml">
|
||||
]>
|
||||
<book>
|
||||
|
||||
<bookinfo>
|
||||
<title>Spring Web Services</title>
|
||||
<subtitle>
|
||||
Reference Documentation
|
||||
</subtitle>
|
||||
<releaseinfo>Version &version;</releaseinfo>
|
||||
<pubdate>(Work in progress)</pubdate>
|
||||
|
||||
<authorgroup>
|
||||
<author>
|
||||
<firstname>Arjen</firstname>
|
||||
<surname>Poutsma</surname>
|
||||
</author>
|
||||
</authorgroup>
|
||||
|
||||
<legalnotice>Copies of this document may be made for your own use and for distribution to others, provided that
|
||||
you do not charge any fee for such copies and further provided that each copy contains this Copyright
|
||||
Notice, whether distributed in print or electronically.</legalnotice>
|
||||
</bookinfo>
|
||||
|
||||
<toc/>
|
||||
|
||||
&preface;
|
||||
|
||||
&overview;
|
||||
|
||||
&contract-first;
|
||||
|
||||
&ws;
|
||||
|
||||
&security;
|
||||
|
||||
&oxm;
|
||||
|
||||
&bibliography;
|
||||
|
||||
</book>
|
||||
140
doc/src/docbkx/overview.xml
Normal file
140
doc/src/docbkx/overview.xml
Normal file
@@ -0,0 +1,140 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<chapter id="introduction">
|
||||
<title>Introduction</title>
|
||||
|
||||
<section>
|
||||
<title>Overview</title>
|
||||
<para>
|
||||
Spring-WS consists of three separate modules. This chapter discusses each of the modules in turn.
|
||||
</para>
|
||||
<para>
|
||||
The <link linkend="ws">Core</link> package is the central part of the Web services functionality. It
|
||||
provides the central <classname>WebServiceMessage</classname> and <classname>SoapMessage</classname>
|
||||
interfaces, the powerful message dispatching, and the various support classes for implementing Web service
|
||||
endpoints.
|
||||
</para>
|
||||
<para>
|
||||
The <link linkend="security">Security</link> package provides a WS-Security implementation that integrates
|
||||
with the core Web service package. It allows you to add principal tokens, sign, and decrypt and encrypt SOAP
|
||||
messages. Addtionally, it allows you to leverage your existing Acegi security implementation for
|
||||
authentication and authorization.
|
||||
</para>
|
||||
<para>
|
||||
The <link linkend="oxm">OXM</link> package provides integration for popular XML marshalling APIs, including
|
||||
JAXB 1 and 2. Using the OXM package means that you benefit from a unified exception hierarchy, and can wire
|
||||
up your favorite XML marshalling technology easily.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
|
||||
<section>
|
||||
<title>Why Spring Web Services?</title>
|
||||
<para>
|
||||
There are various other SOAP stacks available, why and where should you use Spring-WS? This section answers
|
||||
that question by showing what the focus of Spring-WS is.
|
||||
</para>
|
||||
<section>
|
||||
<title>Spring-WS is meant for Public Web Services</title>
|
||||
<para>
|
||||
One can distinguish between two different sorts of Web services. Private Web services are not used
|
||||
outside your application domain. They might form a part of your Enterprise Service Bus, or used as a
|
||||
means to communicate between a fat .NET client and a J2EE server. When the two sides of the spectrum
|
||||
(client and server) are under your control, you can easily expose (existing) methods, since you can
|
||||
(re)generate client code easily.
|
||||
</para>
|
||||
<para>
|
||||
Public Web services provide a separate interface to your application. They are often used by clients
|
||||
that are outside of your reach. When developing a public Web service, you should really think about the
|
||||
interface you are providing: it is probably going to be around for a while, and you cannot change it
|
||||
that often. As such, it is a good idea to place the Web service in a separate layer, thus hiding the
|
||||
inner workings of the application. As a result, you can change the Web service and the rest of the
|
||||
appliciation seperately.
|
||||
</para>
|
||||
</section>
|
||||
<section>
|
||||
<title>Spring-WS makes Web Services First Class Citizens of the Architecture</title>
|
||||
<para>
|
||||
Web Services deserve a proper place in an application architecture. Often, they exist as an afterthought
|
||||
in the application architecture, mostly because existing Java business interfaces are exposed as SOAP
|
||||
services. One could say that they are "SOAPified". Spring-WS provides a MVC-like framework for
|
||||
developing a Web service application layer, just like you would develop a layer especially for a Web
|
||||
user interface using Spring-MVC. Spring-WS also provides useful integration points with you existing
|
||||
Spring application architecture, such as the Acegi integration.
|
||||
</para>
|
||||
</section>
|
||||
<section>
|
||||
<title>Spring-WS is Data-Driven</title>
|
||||
<para>
|
||||
When Web Services started making their way into the Enterprise Computing world, developers considered
|
||||
Web Services just another, XML-based remoting protocol. Such remoting frameworks can be used with
|
||||
relative ease: on the server-side, one simply implements a specific interface such as
|
||||
<classname>java.rmi.Remote</classname>, and on the client side, a dynamic proxy is used.
|
||||
Unfortunately, because of this simplicity, remoting architectures have some issues:
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
They pretend there is no <emphasis>latency</emphasis> between the client and the server,
|
||||
while in fact there is both network and application latency,
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
They pretend that client and server have <emphasis>shared memory access</emphasis>, while in
|
||||
fact data must be both marshalled and unmarshalled,
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
They ignore the possibility of a <emphasis>request or response not reaching its
|
||||
destination</emphasis>,
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
They enforce a <emphasis>non-concurrent</emphasis> programming model, while in fact a
|
||||
concurrent approach seems more in place,
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
They enforce a <emphasis>tightly coupled architecture</emphasis>, where changes on the
|
||||
server-side result in changes on the client-side.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
It is not without reason that Gregor Hohpe calls a distributed architecture a <quote>fairy tale
|
||||
architecture</quote>: one is made to believe things that simply are not true. To quote <xref
|
||||
linkend="waldo-94"/>:
|
||||
<blockquote>
|
||||
<para>
|
||||
Objects that interact in a distributed system need to be dealt with in ways that are
|
||||
intrinsically different from objects that interact in a single address space.
|
||||
</para>
|
||||
</blockquote>
|
||||
</para>
|
||||
<para>
|
||||
Instead of being behavior-driven, Spring-WS is data-driven: it focusses on the data being sent, not on a
|
||||
particular method being invoked.
|
||||
</para>
|
||||
</section>
|
||||
<section>
|
||||
<title>Spring-WS Focusses on Contract-first Development</title>
|
||||
<para>
|
||||
SOAP services are defined in two contracts: the data contract (the XSD schema), and the service contract
|
||||
(the WSDL). Generating these contracts from Java-code is called <emphasis>contract-last
|
||||
development</emphasis> <xref linkend="alpine"/> identifies some problems with this approach, most
|
||||
importantly:
|
||||
<blockquote>
|
||||
<para>
|
||||
There is no way to ensure that a service’s published interface remains constant over time.
|
||||
Every redeployment of the service may change the classes, and hence the contract.
|
||||
</para>
|
||||
</blockquote>
|
||||
The alternative of contract-last development is <emphasis>contract-first development</emphasis>.
|
||||
Using this approach, the service and data contract are leading. Spring-WS focusses on contract-first Web
|
||||
service development, because is considered to be a best practice. After all, the actual XML that is sent
|
||||
across the wire is more important than the Java code that is used to implement it.
|
||||
</para>
|
||||
</section>
|
||||
</section>
|
||||
</chapter>
|
||||
617
doc/src/docbkx/oxm.xml
Normal file
617
doc/src/docbkx/oxm.xml
Normal file
@@ -0,0 +1,617 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<chapter id="oxm">
|
||||
<title>Marshalling XML using O/X Mappers</title>
|
||||
|
||||
<section id="oxm-introduction">
|
||||
<title>Introduction</title>
|
||||
<para>
|
||||
In this chapter, we will describe Spring's Object/XML Mapping support. Object/XML Mapping, or O/X mapping
|
||||
for short, is the act of converting an XML document to and from an object. This conversion process is also
|
||||
known as XML Marshalling, or XML Serialization. This chapter uses these terms interchangeably.
|
||||
</para>
|
||||
<para>
|
||||
Within the field of O/X mapping, a <emphasis>marshaller</emphasis> is responsible for serializing an object
|
||||
(graph) to XML. In similar fashion, an <emphasis>unmarshaller</emphasis> deserializes the XML to an object
|
||||
graph. This XML can take the form of a DOM document, an input or output stream, or a SAX handler.
|
||||
</para>
|
||||
<para>
|
||||
Some of the benefits of using Spring for your O/X mapping needs are:
|
||||
</para>
|
||||
<formalpara>
|
||||
<title>Ease of configuration</title>
|
||||
<para>
|
||||
Spring's bean factory makes it easy to configure marshallers, without needing to construct JAXB context,
|
||||
JiBX binding factories, etc. The marshallers can be configured as any other bean in your application
|
||||
context.
|
||||
</para>
|
||||
</formalpara>
|
||||
<formalpara>
|
||||
<title>Consistent Interfaces</title>
|
||||
<para>
|
||||
Spring's O/X mapping operates through two global interfaces: the
|
||||
<classname>Marshaller</classname>
|
||||
and
|
||||
<classname>Unmarshaller</classname>
|
||||
interface. These abstractions allow you to switch O/X mapping
|
||||
frameworks with relative ease, with little or no changes required on the classes that do the
|
||||
marshalling. This approach has the additional benefit of making it possible to do XML marshalling with a
|
||||
mix-and-match approach (e.g. some marshalling performed using JAXB, other using XMLBeans) in a
|
||||
non-intrusive fashion, leveraging the strength of each technology.
|
||||
</para>
|
||||
</formalpara>
|
||||
<formalpara>
|
||||
<title>Consistent Exception Hierarchy</title>
|
||||
<para>
|
||||
Spring provides a conversion from exceptions from the underlying O/X mapping tool to its own
|
||||
exception hierarchy with the
|
||||
<classname>XmlMappingException</classname>
|
||||
as the root exception. As can be
|
||||
expected, these runtime exceptions wrap the original exception so no information is lost.
|
||||
</para>
|
||||
</formalpara>
|
||||
</section>
|
||||
<section id="oxm-marshaller-unmarshaller">
|
||||
<title>Marshaller and Unmarshaller</title>
|
||||
<para>
|
||||
As stated in the introduction, a
|
||||
<emphasis>marshaller</emphasis>
|
||||
serializes an object to XML, and an
|
||||
<emphasis>unmarshaller</emphasis>
|
||||
deserializes XML stream to an object. In this section, we will describe
|
||||
the two Spring interfaces used for this purpose.
|
||||
</para>
|
||||
<section>
|
||||
<title>Marshaller</title>
|
||||
<para>
|
||||
Spring abstracts all marshalling operations behind the
|
||||
<classname>org.springframework.oxm.Marshaller</classname>
|
||||
interface, which is listed below.
|
||||
<programlisting><![CDATA[
|
||||
public interface Marshaller {
|
||||
|
||||
/**
|
||||
* Marshals the object graph with the given root into the provided Result.
|
||||
*/
|
||||
void marshal(Object graph, Result result)
|
||||
throws XmlMappingException, IOException;
|
||||
}]]></programlisting>
|
||||
The
|
||||
<classname>Marshaller</classname>
|
||||
interface has just one method, which marshals the given
|
||||
object to a given
|
||||
<classname>javax.xml.transform.Result</classname>
|
||||
. Result is a tagging interface that
|
||||
basically represents an XML output abstraction: concrete implementations wrap various XML
|
||||
representations, as indicated in the table below.
|
||||
<informaltable>
|
||||
<tgroup cols="2">
|
||||
<thead>
|
||||
<row>
|
||||
<entry>
|
||||
<classname>javax.xml.transform.Result</classname>
|
||||
implementation
|
||||
</entry>
|
||||
<entry>Wraps XML representation</entry>
|
||||
</row>
|
||||
</thead>
|
||||
<tbody>
|
||||
<row>
|
||||
<entry>
|
||||
<classname>javax.xml.transform.dom.DOMResult</classname>
|
||||
</entry>
|
||||
<entry>
|
||||
<classname>org.w3c.dom.Node</classname>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>
|
||||
<classname>javax.xml.transform.sax.SAXResult</classname>
|
||||
</entry>
|
||||
<entry>
|
||||
<classname>org.xml.sax.ContentHandler</classname>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>
|
||||
<classname>javax.xml.transform.stream.StreamResult</classname>
|
||||
</entry>
|
||||
<entry>
|
||||
<classname>java.io.File</classname>
|
||||
,
|
||||
<classname>java.io.OutputStream</classname>
|
||||
,
|
||||
or
|
||||
<classname>java.io.Writer</classname>
|
||||
</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</informaltable>
|
||||
</para>
|
||||
<note>
|
||||
<para>
|
||||
Although the
|
||||
<methodname>marshal</methodname>
|
||||
method accepts a plain object as its first parameter,
|
||||
most
|
||||
<classname>Marshaller</classname>
|
||||
implementations cannot handle arbitrary objects. Instead, an
|
||||
object class must be mapped in a mapping file, registered with the marshaller, or have a common base
|
||||
class. Refer to the further sections in this chapter to determine how your O/X technology of choice
|
||||
manages this.
|
||||
</para>
|
||||
</note>
|
||||
</section>
|
||||
<section>
|
||||
<title>Unmarshaller</title>
|
||||
<para>
|
||||
Similar to the
|
||||
<classname>Marshaller</classname>
|
||||
, there is the
|
||||
<classname>org.springframework.oxm.Unmarshaller</classname>
|
||||
interface.
|
||||
<programlisting><![CDATA[
|
||||
public interface Unmarshaller {
|
||||
|
||||
/**
|
||||
* Unmarshals the given provided Source into an object graph.
|
||||
*/
|
||||
Object unmarshal(Source source)
|
||||
throws XmlMappingException, IOException;
|
||||
}]]></programlisting>
|
||||
This interface also has one method, which reads from the given
|
||||
<classname>javax.xml.transform.Source</classname>
|
||||
(an XML input abstraction), and returns the
|
||||
object read. As with Result, Source is a tagging interface that has three concrete implementations. Each
|
||||
wraps a different XML representation, as indicated in the table below.
|
||||
<informaltable>
|
||||
<tgroup cols="2">
|
||||
<thead>
|
||||
<row>
|
||||
<entry>
|
||||
<classname>javax.xml.transform.Source</classname>
|
||||
implementation
|
||||
</entry>
|
||||
<entry>Wraps XML representation</entry>
|
||||
</row>
|
||||
</thead>
|
||||
<tbody>
|
||||
<row>
|
||||
<entry>
|
||||
<classname>javax.xml.transform.dom.DOMSource</classname>
|
||||
</entry>
|
||||
<entry>
|
||||
<classname>org.w3c.dom.Node</classname>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>
|
||||
<classname>javax.xml.transform.sax.SAXSource</classname>
|
||||
</entry>
|
||||
<entry>
|
||||
<classname>org.xml.sax.InputSource</classname>
|
||||
and
|
||||
<classname>org.xml.sax.XMLReader</classname>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>
|
||||
<classname>javax.xml.transform.stream.StreamSource</classname>
|
||||
</entry>
|
||||
<entry>
|
||||
<classname>java.io.File</classname>
|
||||
,
|
||||
<classname>java.io.InputStream</classname>
|
||||
,
|
||||
or
|
||||
<classname>java.io.Reader</classname>
|
||||
</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</informaltable>
|
||||
</para>
|
||||
</section>
|
||||
<para>
|
||||
Even though there are two separate marshalling interfaces (
|
||||
<classname>Marshaller</classname>
|
||||
and
|
||||
<classname>Unmarshaller</classname>
|
||||
), most implementations found in Spring-WS implement both in one class.
|
||||
This means that you can wire up one marshaller class and refer to it as marshaller and unmarshaller in your
|
||||
<filename>applicationContext.xml</filename>
|
||||
.
|
||||
</para>
|
||||
<section>
|
||||
<title>XmlMappingException</title>
|
||||
<para>
|
||||
Spring converts exceptions from the underlying O/X mapping tool to its own exception hierarchy with the
|
||||
<classname>XmlMappingException</classname>
|
||||
as the root exception. As can be expected, these runtime
|
||||
exceptions wrap the original exception so no information will be lost.
|
||||
</para>
|
||||
<para>
|
||||
Additionally, the
|
||||
<classname>MarshallingFailureException</classname>
|
||||
and
|
||||
<classname>UnmarshallingFailureException</classname>
|
||||
provide a distinction between marshalling and
|
||||
unmarshalling operations, even though the underlying O/X mapping tool does not do so.
|
||||
</para>
|
||||
<para>
|
||||
The O/X Mapping exception hierarchy is shown in the following figure:
|
||||
<mediaobject>
|
||||
<imageobject role="fo">
|
||||
<imagedata fileref="images/oxm-exceptions.svg"
|
||||
format="SVG" align="center"/>
|
||||
</imageobject>
|
||||
<imageobject role="html">
|
||||
<imagedata fileref="images/oxm-exceptions.png"
|
||||
format="PNG" align="center"/>
|
||||
</imageobject>
|
||||
<caption>
|
||||
<para>
|
||||
O/X Mapping exception hierarchy
|
||||
</para>
|
||||
</caption>
|
||||
</mediaobject>
|
||||
</para>
|
||||
</section>
|
||||
</section>
|
||||
<section id="oxm-usage">
|
||||
<title>Using Marshaller and Unmarshaller</title>
|
||||
<para>
|
||||
Spring's OXM can be used for a wide variety of situations. In the following example, we will use it to
|
||||
marshal the settings of a Spring-managed application as an XML file. We will use a simple JavaBean to
|
||||
represent the settings:
|
||||
<programlisting><![CDATA[
|
||||
public class Settings {
|
||||
private boolean fooEnabled;
|
||||
|
||||
public boolean isFooEnabled() {
|
||||
return fooEnabled;
|
||||
}
|
||||
|
||||
public void setFooEnabled(boolean fooEnabled) {
|
||||
this.fooEnabled = fooEnabled;
|
||||
}
|
||||
}]]></programlisting>
|
||||
</para>
|
||||
<para>
|
||||
The application class uses this bean to store its settings. Besides a main method, the class has two
|
||||
methods:
|
||||
<methodname>saveSettings</methodname>
|
||||
saves the settings bean to a file named
|
||||
<filename>settings.xml</filename>
|
||||
, and
|
||||
<methodname>loadSettings</methodname>
|
||||
loads these settings again. A
|
||||
<methodname>main</methodname>
|
||||
method constructs a Spring application context, and calls these two methods.
|
||||
<programlisting><![CDATA[
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import javax.xml.transform.stream.StreamResult;
|
||||
import javax.xml.transform.stream.StreamSource;
|
||||
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||
import org.springframework.oxm.Marshaller;
|
||||
import org.springframework.oxm.Unmarshaller;
|
||||
|
||||
public class Application {
|
||||
private static final String FILE_NAME = "settings.xml";
|
||||
private Settings settings = new Settings();
|
||||
private Marshaller marshaller;
|
||||
private Unmarshaller unmarshaller;
|
||||
|
||||
public void setMarshaller(Marshaller marshaller) {
|
||||
this.marshaller = marshaller;
|
||||
}
|
||||
|
||||
public void setUnmarshaller(Unmarshaller unmarshaller) {
|
||||
this.unmarshaller = unmarshaller;
|
||||
}
|
||||
|
||||
public void saveSettings() throws IOException {
|
||||
FileOutputStream os = null;
|
||||
try {
|
||||
os = new FileOutputStream(FILE_NAME);
|
||||
this.marshaller.marshal(settings, new StreamResult(os));
|
||||
} finally {
|
||||
if (os != null) {
|
||||
os.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void loadSettings() throws IOException {
|
||||
FileInputStream is = null;
|
||||
try {
|
||||
is = new FileInputStream(FILE_NAME);
|
||||
this.settings = (Settings) this.unmarshaller.unmarshal(new StreamSource(is));
|
||||
} finally {
|
||||
if (is != null) {
|
||||
is.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws IOException {
|
||||
ApplicationContext appContext = new ClassPathXmlApplicationContext("applicationContext.xml");
|
||||
Application application = (Application) appContext.getBean("application");
|
||||
application.saveSettings();
|
||||
application.loadSettings();
|
||||
}
|
||||
}]]></programlisting>
|
||||
The
|
||||
<classname>Application</classname>
|
||||
requires both a
|
||||
<methodname>marshaller</methodname>
|
||||
and
|
||||
<methodname>unmarshaller</methodname>
|
||||
property to be set. We can do so using the following
|
||||
<filename>applicationContext.xml</filename>
|
||||
:
|
||||
<programlisting><![CDATA[
|
||||
<beans>
|
||||
<bean id="application" class="Application">
|
||||
<property name="marshaller" ref="castorMarshaller" />
|
||||
<property name="unmarshaller" ref="castorMarshaller" />
|
||||
</bean>
|
||||
<bean id="castorMarshaller" class="org.springframework.oxm.castor.CastorMarshaller"/>
|
||||
</beans>
|
||||
|
||||
]]></programlisting>
|
||||
This application context uses Castor, but we could have used any of the other marshaller instances described
|
||||
later in this chapter. Note that Castor does not require any further configuration by default, so the bean
|
||||
definition is rather simple. Also note that the
|
||||
<classname>CastorMarshaller</classname>
|
||||
implements both
|
||||
<classname>Marshaller</classname>
|
||||
and
|
||||
<classname>Unmarshaller</classname>
|
||||
, so we can refer to the
|
||||
<varname>castorMarshaller</varname>
|
||||
bean in both the
|
||||
<varname>marshaller</varname>
|
||||
and
|
||||
<varname>unmarshaller</varname>
|
||||
property of the application.
|
||||
</para>
|
||||
<para>
|
||||
This sample application produces the following
|
||||
<filename>settings.xml</filename>
|
||||
file:
|
||||
<programlisting><![CDATA[
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<settings foo-enabled="false"/>
|
||||
]]></programlisting>
|
||||
</para>
|
||||
</section>
|
||||
<section id="oxm-jaxb">
|
||||
<title>JAXB</title>
|
||||
<para>
|
||||
The JAXB binding compiler translates a W3C XML Schema into one or more Java classes, a
|
||||
<filename>jaxb.properties</filename>
|
||||
file, and possibly other files, depending on the specific implementation of JAXB. Alternatively, JAXB2
|
||||
offers a way to generate a schema from annotated Java classes.
|
||||
</para>
|
||||
<para>
|
||||
Spring supports both the JAXB 1.0 as the JAXB 2.0 API as XML marshalling strategy, following the
|
||||
<classname>Marshaller</classname> and <classname>Unmarshaller</classname> interfaces described in
|
||||
<xref linkend="oxm-marshaller-unmarshaller"/>. The corresponding integration classes reside in the
|
||||
<classname>org.springframework.oxm.jaxb</classname>
|
||||
package.
|
||||
</para>
|
||||
<section>
|
||||
<title>Jaxb1Marshaller</title>
|
||||
<para>
|
||||
The <classname>Jaxb1Marshaller</classname> class implements both the Spring
|
||||
<classname>Marshaller</classname> and <classname>Unmarshaller</classname> interface. It requires a
|
||||
context path to operate, which you can set using the <varname>contextPath</varname> property. The
|
||||
context path is a list of colon (:) separated Java package names that contain schema derived classes.
|
||||
The marshaller has an additional <varname>validating</varname> property which defines whether to
|
||||
validate invoming XML.
|
||||
</para>
|
||||
<para>
|
||||
The next sample bean configuration shows how to configure a
|
||||
<classname>JaxbMarshaller</classname> using the classes generated to
|
||||
<varname>org.springframework.ws.samples.airline.schema</varname>.
|
||||
</para>
|
||||
<programlisting><![CDATA[<beans>
|
||||
|
||||
<bean id="jaxb1Marshaller" class="org.springframework.oxm.jaxb.Jaxb1Marshaller">
|
||||
<property name="contextPath" value="org.springframework.ws.samples.airline.schema"/>
|
||||
</bean>
|
||||
...
|
||||
|
||||
</beans>]]></programlisting>
|
||||
</section>
|
||||
<section>
|
||||
<title>Jaxb2Marshaller</title>
|
||||
<para>
|
||||
The <classname>Jaxb2Marshaller</classname> can be configured using the same <varname>contextPath</varname> property as the <classname>Jaxb1Marshaller</classname>. However, it also offers a <varname>classesToBeBound</varname> property, which allows you to set an array of classes to be supported by the marshaller. Schema validation is performed by specifying one or more schema resource to the bean, like so:
|
||||
</para>
|
||||
<programlisting><![CDATA[<beans>
|
||||
|
||||
<bean id="jaxb2Marshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
|
||||
<property name="classesToBeBound">
|
||||
<list>
|
||||
<value>org.springframework.oxm.jaxb.Flight</value>
|
||||
<value>org.springframework.oxm.jaxb.Flights</value>
|
||||
</list>
|
||||
</property>
|
||||
<property name="schema" value="classpath:org/springframework/oxm/schema.xsd"/>
|
||||
</bean>
|
||||
...
|
||||
|
||||
</beans>]]></programlisting>
|
||||
</section>
|
||||
</section>
|
||||
<section id="oxm-castor">
|
||||
<title>Castor</title>
|
||||
<para>
|
||||
Castor XML mapping is an open source XML binding framework. It allows you to transform the data contained in
|
||||
a java object model into/from an XML document. By default, it does not require any further configuration,
|
||||
though a mapping file can be used to have more control over the behavior of Castor.
|
||||
</para>
|
||||
<para>
|
||||
For more information on Castor, refer to the <ulink url="http://castor.org/xml-framework.html">
|
||||
<citetitle>Castor web site</citetitle></ulink>. The Spring integration classes reside in the
|
||||
<classname>org.springframework.oxm.castor</classname> package.
|
||||
</para>
|
||||
<section>
|
||||
<title>CastorMarshaller</title>
|
||||
<para>
|
||||
As with JAXB, the <classname>CastorMarshaller</classname> implements both the
|
||||
<classname>Marshaller</classname> and <classname>Unmarshaller</classname> interface. It can be wired up
|
||||
as follows:
|
||||
</para>
|
||||
<programlisting><![CDATA[
|
||||
<beans>
|
||||
|
||||
<bean id="castorMarshaller" class="org.springframework.oxm.castor.CastorMarshaller" />
|
||||
...
|
||||
|
||||
</beans>]]></programlisting>
|
||||
</section>
|
||||
<section>
|
||||
<title>Mapping</title>
|
||||
<para>
|
||||
Although it is possible to rely on Castor's default marshalling behavior, it might be necessary to have
|
||||
more control over it. This can be accomplished using a Castor mapping file. For more information, refer
|
||||
to <ulink url="http://castor.org/xml-mapping.html">Castor XML Mapping</ulink>.
|
||||
</para>
|
||||
<para>
|
||||
The mapping can be set using the <methodname>mappingLocation</methodname> resource property, indicated
|
||||
below with a classpath resource.
|
||||
</para>
|
||||
<programlisting><![CDATA[
|
||||
<beans>
|
||||
<bean id="castorMarshaller" class="org.springframework.oxm.castor.CastorMarshaller" >
|
||||
<property name="mappingLocation" value="classpath:mapping.xml" />
|
||||
</bean>
|
||||
</beans>
|
||||
]]></programlisting>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section id="oxm-xmlbeans">
|
||||
<title>XMLBeans</title>
|
||||
<para>
|
||||
XMLBeans is an XML binding tool that has full XML Schema support, and offers full XML Infoset fidelity. It
|
||||
takes a different approach that most other O/X mapping frameworks, in that all classes that are
|
||||
generated from an XML Schema are all derived from <classname>XmlObject</classname>, and contain XML binding
|
||||
information in them.
|
||||
</para>
|
||||
<para>
|
||||
For more information on XMLBeans, refer to the <ulink url="http://xmlbeans.apache.org/"> <citetitle>XMLBeans
|
||||
web site</citetitle></ulink> . The Spring-WS integration classes reside in the
|
||||
<classname>org.springframework.oxm.xmlbeans</classname> package.
|
||||
</para>
|
||||
<section>
|
||||
<title>XmlBeansMarshaller</title>
|
||||
<para>
|
||||
The <classname>XmlBeansMarshaller</classname> implements both the <classname>Marshaller</classname> and
|
||||
<classname>Unmarshaller</classname> interface. It can be wired up as follows:
|
||||
</para>
|
||||
<programlisting><![CDATA[
|
||||
<beans>
|
||||
|
||||
<bean id="xmlBeansMarshaller" class="org.springframework.oxm.xmlbeans.XmlBeansMarshaller" />
|
||||
...
|
||||
|
||||
</beans>]]></programlisting>
|
||||
<note>
|
||||
<para>
|
||||
Note that the <classname>XmlBeansMarshaller</classname> can only marshal objects of type
|
||||
<classname>XmlObject</classname>, and not every <classname>java.lang.Object</classname>.
|
||||
</para>
|
||||
</note>
|
||||
</section>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
<section id="oxm-jibx">
|
||||
<title>JiBX</title>
|
||||
<para>
|
||||
The JiBX framework offers a solution similar to JDO does for ORM: a binding definition defines the
|
||||
rules for how your Java objects are converted to or from XML. After preparing the binding and compiling the
|
||||
classes, a JiBX binding compiler enhances the class files, and adds code to handle converting instances of
|
||||
the classes from or to XML.
|
||||
</para>
|
||||
<para>
|
||||
For more information on JiBX, refer to the <ulink url="http://jibx.sourceforge.net/"><citetitle>JiBX web
|
||||
site</citetitle></ulink>. The Spring integration classes reside in the
|
||||
<varname>org.springframework.oxm.jibx</varname> package.
|
||||
</para>
|
||||
<section>
|
||||
<title>JibxMarshaller</title>
|
||||
<para>
|
||||
The <classname>JibxMarshaller</classname> class implements both the <classname>Marshaller</classname>
|
||||
and <classname>Unmarshaller</classname> interface. To operate, it requires the name of the class to
|
||||
marshall in, which you can set using the <varname>targetClass</varname> property. Optionally, you can
|
||||
set the binding name using the <varname>bindingName</varname> property. In the next sample, we refer to
|
||||
the <classname>flightsBindingFactory</classname> defined in the previous bean definition.
|
||||
</para>
|
||||
<programlisting><![CDATA[
|
||||
<beans>
|
||||
|
||||
<bean id="jibxFlightsMarshaller" class="org.springframework.oxm.jibx.JibxMarshaller">
|
||||
<property name="targetClass">org.springframework.oxm.jibx.Flights</property>
|
||||
</bean>
|
||||
|
||||
...
|
||||
]]></programlisting>
|
||||
<note>
|
||||
<para>
|
||||
A <classname>JibxMarshaller</classname> is configured for a single class. If you want to marshal
|
||||
multiple classes, you have to configure multiple <classname>JibxMarshaller</classname>s with
|
||||
different <varname>targetClass</varname>es.
|
||||
</para>
|
||||
</note>
|
||||
</section>
|
||||
</section>
|
||||
<section id="oxm-xstream">
|
||||
<title>XStream</title>
|
||||
<para>
|
||||
XStream is a simple library to serialize objects to XML and back again. It does not require any mapping, and
|
||||
generates clean XML.
|
||||
</para>
|
||||
<para>
|
||||
For more information on XStream, refer to the <ulink url="http://xstream.codehaus.org/"><citetitle>XStream
|
||||
web site</citetitle></ulink>. The Spring integration classes reside in the
|
||||
<varname>org.springframework.oxm.xstream</varname> package.
|
||||
</para>
|
||||
<section>
|
||||
<title>XStreamMarshaller</title>
|
||||
<para>
|
||||
The <classname>XStreamMarshaller</classname> does not require any configuration, and can be configured
|
||||
in an application context directly. To further customize the XML, you can set an
|
||||
<emphasis>alias map</emphasis>, which consists of string aliases mapped to classes:
|
||||
</para>
|
||||
<programlisting><![CDATA[
|
||||
<beans>
|
||||
|
||||
<bean id="xstreamMarshaller" class="org.springframework.oxm.xstream.XStreamMarshaller">
|
||||
<property name="aliases">
|
||||
<props>
|
||||
<prop key="Flight">org.springframework.oxm.xstream.Flight</prop>
|
||||
</props>
|
||||
</property>
|
||||
</bean>
|
||||
...
|
||||
|
||||
</beans>]]></programlisting>
|
||||
</section>
|
||||
<note>
|
||||
<para>
|
||||
Note that XStream is an XML serialization library, not a data binding library. Therefore, it has
|
||||
limited namespace support. As such, it is rather unsuitable for usage within Web services.
|
||||
</para>
|
||||
</note>
|
||||
</section>
|
||||
</chapter>
|
||||
20
doc/src/docbkx/preface.xml
Normal file
20
doc/src/docbkx/preface.xml
Normal file
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<preface id="preface">
|
||||
<title>Preface</title>
|
||||
<para>
|
||||
Web services development is a complicated affair. There is SOAP, there is REST. There is SOAP 1.1, and there is
|
||||
SOAP 1.2. There is rpc/encoded, and there is document/literal. There is WS-Addressing, WS-Security, WS-Policy,
|
||||
and various other Web service specifications. Implementing Web services using abstractions that magically turn
|
||||
Java into XML, but turn out to be leaky abstractions makes it even harder. Spring Web Services provides a
|
||||
solution for building interoperable Web services, while making it clear what XML is received and sent across the
|
||||
wire. Spring-WS provides a powerful <link linkend="ws">message dispatching framework</link>, various <link
|
||||
linkend="oxm">XML marshalling</link> techniques that can be used outside a Web service environment, and a <link
|
||||
linkend="security">WS-Security</link> solution that integrates with your existing application security
|
||||
solution.
|
||||
</para>
|
||||
<para>
|
||||
This document provides a reference guide to Spring-WS's features. Since this document is still a
|
||||
work-in-progress, if you have any requests or comments, please post them on the support forums at <ulink
|
||||
url="http://forum.springframework.org/forumdisplay.php?f=39"/>.
|
||||
</para>
|
||||
</preface>
|
||||
858
doc/src/docbkx/security.xml
Normal file
858
doc/src/docbkx/security.xml
Normal file
@@ -0,0 +1,858 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<chapter id="security">
|
||||
<title>Securing your Web services with Spring-WS</title>
|
||||
|
||||
<section id="security-introduction">
|
||||
<title>Introduction</title>
|
||||
<para>
|
||||
In this chapter, we will show you how to add WS-Security aspects to your Web services. We
|
||||
will focus on the three different areas of WS-Security, namely:
|
||||
</para>
|
||||
<formalpara>
|
||||
<title>Authentication</title>
|
||||
<para>
|
||||
This is the process of determining whether a <emphasis>principal</emphasis> is who they claim to be.
|
||||
In this context, a "principal" generally means a user, device or some other system which can perform an
|
||||
action in your application.
|
||||
</para>
|
||||
</formalpara>
|
||||
<formalpara>
|
||||
<title>Digital signatures</title>
|
||||
<para>
|
||||
The digital signature of a message is a piece of information based on both the document and the signer's
|
||||
private key. It is created through the use of a hash function and a private signing function
|
||||
(encrypting with the signer's private key).
|
||||
</para>
|
||||
</formalpara>
|
||||
<formalpara>
|
||||
<title>Encryption and Decryption</title>
|
||||
<para>
|
||||
<emphasis>Encryption</emphasis> is the process of transforming data into a form that is impossible to
|
||||
read without the appropriate key. It is mainly used to keep information hidden from anyone for whom it
|
||||
is not intended. <emphasis>Decryption</emphasis> is the reverse of encryption; it is the process of
|
||||
transforming of encrypted data back into an readable form.
|
||||
</para>
|
||||
</formalpara>
|
||||
<para>
|
||||
All of these three areas are implemented using the <classname>XwsSecurityInterceptor</classname>, which we
|
||||
will describe in <xref linkend="security-xws-security-interceptor"/>
|
||||
</para>
|
||||
<note>
|
||||
<para>
|
||||
Note that WS-Security (especially encryption and signing) requires substantial amounts of memory,
|
||||
and will also decrease performance. If performance is important to you, you might want to consider using
|
||||
not using WS-Security.
|
||||
</para>
|
||||
</note>
|
||||
</section>
|
||||
<section id="security-xws-security-interceptor">
|
||||
<title>XwsSecurityInterceptor</title>
|
||||
<para>
|
||||
The <classname>XwsSecurityInterceptor</classname> is an <classname>EndpointInterceptor</classname> (see
|
||||
<xref linkend="ws-endpoint-interceptor"/>) that is based on SUN's XML and Web Services Security package
|
||||
(XWSS). This WS-Security implementation is part of the Java Web Services Developer Pack (<ulink
|
||||
url="http://java.sun.com/webservices/"><citetitle>Java WSDP</citetitle></ulink>).
|
||||
</para>
|
||||
<para>
|
||||
Like any other endpoint interceptor, it is defined in the endpoint mapping (see <xref
|
||||
linkend="ws-endpoint-mapping"/>). This means that you can be selective about adding WS-Security support:
|
||||
some endpoint mappings require it, while others do not.
|
||||
</para>
|
||||
<para>
|
||||
The <classname>XwsSecurityInterceptor</classname> requires a <emphasis>security policy file</emphasis> to
|
||||
operate. This XML file tells the interceptor what security aspects to require from incoming SOAP messages,
|
||||
and what aspects to add to outgoing messages. The basic format of the policy file will be explained in the
|
||||
following sections, but you can find a more in-depth tutorial <ulink
|
||||
url="http://java.sun.com/webservices/docs/1.6/tutorial/doc/XWS-SecurityIntro4.html#wp564887">
|
||||
<citetitle>here</citetitle></ulink>. You can set the policy with the
|
||||
<methodname>policyConfiguration</methodname> property, which requires a Spring resource.
|
||||
The policy file can contain multiple elements, e.g. require a username
|
||||
token on incoming messages, and sign all outgoing messages. It contains a
|
||||
<literal>SecurityConfiguration</literal> element as root (not a <literal>JAXRPCSecurity</literal>
|
||||
element).
|
||||
</para>
|
||||
<para>
|
||||
Additionally, the security interceptor requires one or more <classname>CallbackHandler</classname>s to
|
||||
operate. These handlers are used to retrieve certificates, private keys, validate user credentials, etc.
|
||||
Spring-WS offers handlers for most common security concerns, e.g. authenticating against a Acegi
|
||||
authentication manager, signing outgoing messages based on a X509 certificate. The following sections
|
||||
will indicate what callback handler to use for which security concern. You can set the callback handlers
|
||||
using the <methodname>callbackHandler</methodname> or <methodname>callbackHandlers</methodname> property.
|
||||
</para>
|
||||
<para>
|
||||
Here is an example that shows how to wire the <classname>XwsSecurityInterceptor</classname> up:
|
||||
<programlisting><![CDATA[
|
||||
<beans>
|
||||
<bean id="wsSecurityInterceptor"
|
||||
class="org.springframework.ws.soap.security.xwss.XwsSecurityInterceptor">
|
||||
<property name="policyConfiguration" value="classpath:securityPolicy.xml"/>
|
||||
<property name="callbackHandlers">
|
||||
<list>
|
||||
<ref bean="certificateHandler"/>
|
||||
<ref bean="authenticationHandler"/>
|
||||
</list>
|
||||
</property>
|
||||
</bean>
|
||||
...
|
||||
</beans>
|
||||
]]></programlisting>
|
||||
This interceptor is configured using the <filename>securityPolicy.xml</filename> file on the classpath. It
|
||||
uses two callback handlers which are defined further on in the file.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="keystore">
|
||||
<title>Key stores</title>
|
||||
<para>
|
||||
For most cryptographic operations, you will use standard <classname>java.security.KeyStore</classname>
|
||||
objects. This includes certificate verification, message signing, signature verification, encryption, but
|
||||
excludes username and time-stamp verification. This section aims to give you some background knowledge on
|
||||
key stores, and the Java tools that you can use to store keys and certificates in a key store file. This
|
||||
information is mostly not related to Spring-WS, but to the general cryptographic features of Java.
|
||||
</para>
|
||||
<para>
|
||||
The <classname>java.security.KeyStore</classname> class represents a storage facility for cryptographic keys
|
||||
and certificates. It can contain three different sort of elements:
|
||||
</para>
|
||||
<formalpara>
|
||||
<title>Private Keys</title>
|
||||
<para>
|
||||
These keys are used for self-authentication. The private key is accompanied by certificate chain for
|
||||
the corresponding public key. Within the field of WS-Security, this accounts to message signing and
|
||||
message decryption.
|
||||
</para>
|
||||
</formalpara>
|
||||
<formalpara>
|
||||
<title>Symmetric Keys</title>
|
||||
<para>
|
||||
Symmetric (or secret) keys are used for message encryption and decryption as well. The difference
|
||||
being that both sides (sender and recipient) share the same, secret key.
|
||||
</para>
|
||||
</formalpara>
|
||||
<formalpara>
|
||||
<title>Trusted certificates</title>
|
||||
<para>
|
||||
These X509 certificates are called a <emphasis>trusted certificate</emphasis> because the keystore owner
|
||||
trusts that the public key in the certificates indeed belong to the owner of the certificate. Within
|
||||
WS-Security, these certificates are used for certificate validation, signature verification, and
|
||||
encryption.
|
||||
</para>
|
||||
</formalpara>
|
||||
<section>
|
||||
<title>KeyTool</title>
|
||||
Supplied with your Java Virtual Machine is the <command>keytool</command>, a key and certificate management
|
||||
utility. You can use this tool to create new key stores, add new private keys and certificates to them, etc.
|
||||
It is beyond the scope of this document to provide a full reference of the <command>keytool</command>
|
||||
command, but you can find a reference <ulink
|
||||
url="http://java.sun.com/j2se/1.4.2/docs/tooldocs/windows/keytool.html">
|
||||
<citetitle>here</citetitle></ulink>, or by giving the command <prompt>keytool -help</prompt> on the command
|
||||
line.
|
||||
</section>
|
||||
<section>
|
||||
<title>KeyStoreFactoryBean</title>
|
||||
<para>
|
||||
To easily load a key store using Spring configuration, you can use the
|
||||
<classname>KeyStoreFactoryBean</classname>. It has a resource location property, which you can set to
|
||||
point to the path of the key store to load. A password may be given to check the integrity of the
|
||||
key store data. If a password is not given, integrity checking is not performed.
|
||||
</para>
|
||||
<programlisting><![CDATA[
|
||||
<bean id="keyStore" class="org.springframework.ws.soap.security.support.KeyStoreFactoryBean">
|
||||
<property name="password" value="password"/>
|
||||
<property name="location" value="classpath:org/springframework/ws/soap/security/xwss/test-keystore.jks"/>
|
||||
</bean>]]></programlisting>
|
||||
<caution>
|
||||
<para>
|
||||
If you don't specify the location property, a new, empty key store will be created, which is most
|
||||
likely not what you want.
|
||||
</para>
|
||||
</caution>
|
||||
</section>
|
||||
<section id="security-key-store-callback-handler">
|
||||
<title>KeyStoreCallbackHandler</title>
|
||||
<para>
|
||||
To use the key stores within a <classname>XwsSecurityInterceptor</classname>, you will need to define a
|
||||
<classname>KeyStoreCallbackHandler</classname>. This callback has three properties with type key store:
|
||||
(<methodname>keyStore</methodname>, <methodname>trustStore</methodname>, and
|
||||
<methodname>symmetricStore</methodname>). The exact stores used by the handler depend on the
|
||||
cryptographic operations that are to be performed by this handler. For private key operation, the
|
||||
<methodname>keyStore</methodname> is used, for symmetric key operations the
|
||||
<methodname>symmetricStore</methodname>, and for determining trust relationships, the
|
||||
<methodname>trustStore</methodname>. The following table indicates this:
|
||||
<informaltable>
|
||||
<tgroup cols="2">
|
||||
<thead>
|
||||
<row>
|
||||
<entry>Cryptographic operation</entry>
|
||||
<entry>Key store used</entry>
|
||||
</row>
|
||||
</thead>
|
||||
<tbody>
|
||||
<row>
|
||||
<entry>Certificate validation</entry>
|
||||
<entry>
|
||||
first the <methodname>keyStore</methodname>, then the
|
||||
<methodname>trustStore</methodname>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>Decryption based on private key</entry>
|
||||
<entry><methodname>keyStore</methodname></entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>Decryption based on symmetric key</entry>
|
||||
<entry><methodname>symmetricStore</methodname></entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>Encryption based on public key certificate</entry>
|
||||
<entry><methodname>trustStore</methodname></entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>Encryption based on symmetric key</entry>
|
||||
<entry><methodname>symmetricStore</methodname></entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>Signing</entry>
|
||||
<entry><methodname>keyStore</methodname></entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>Signature verification</entry>
|
||||
<entry><methodname>trustStore</methodname></entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</informaltable>
|
||||
Additionally, the <classname>KeyStoreCallbackHandler</classname> has a
|
||||
<methodname>privateKeyPassword</methodname> property, which should be set to unlock the private key(s)
|
||||
contained in the <methodname>keyStore</methodname>.
|
||||
</para>
|
||||
<para>
|
||||
If the <methodname>symmetricStore</methodname> is not set, it will default to the
|
||||
<methodname>keyStore</methodname>. If the key or trust store is not set, the callback handler will use
|
||||
the standard Java mechanism to load or create it. Refer to the JavaDoc of the
|
||||
<classname>KeyStoreCallbackHandler</classname> to know how this mechanism works.
|
||||
</para>
|
||||
<para>
|
||||
For instance, if you want to use the <classname>KeyStoreCallbackHandler</classname> to validate incoming
|
||||
certificates or signatures, you would use a trust store, like so:
|
||||
<programlisting><![CDATA[
|
||||
<beans>
|
||||
<bean id="keyStoreHandler" class="org.springframework.ws.soap.security.xwss.callback.KeyStoreCallbackHandler">
|
||||
<property name="trustStore" ref="trustStore"/>
|
||||
</bean>
|
||||
|
||||
<bean id="trustStore" class="org.springframework.ws.soap.security.support.KeyStoreFactoryBean">
|
||||
<property name="location" value="classpath:truststore.jks"/>
|
||||
<property name="password" value="changeit"/>
|
||||
</bean>
|
||||
</beans>]]></programlisting>
|
||||
If you want to use it to decrypt incoming certificates or sign outgoing messages, you would use a key
|
||||
store, like so:
|
||||
<programlisting><![CDATA[
|
||||
<beans>
|
||||
<bean id="keyStoreHandler" class="org.springframework.ws.soap.security.xwss.callback.KeyStoreCallbackHandler">
|
||||
<property name="keyStore" ref="keyStore"/>
|
||||
<property name="privateKeyPassword" value="changeit"/>
|
||||
</bean>
|
||||
|
||||
<bean id="keyStore" class="org.springframework.ws.soap.security.support.KeyStoreFactoryBean">
|
||||
<property name="location" value="classpath:keystore.jks"/>
|
||||
<property name="password" value="changeit"/>
|
||||
</bean>
|
||||
</beans>]]></programlisting>
|
||||
</para>
|
||||
<para>
|
||||
The following sections will indicate where the <classname>KeyStoreCallbackHandler</classname> can be
|
||||
used, and which properties to set for particular cryptographic operations.
|
||||
</para>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Authentication</title>
|
||||
<para>
|
||||
As stated in the introduction, <emphasis>authentication</emphasis> is the task of determining whether a
|
||||
principal is who they claim to be. Within WS-Security, authentication can take two forms: using a username
|
||||
and password token (using either a plain text password or a password digest), or using a X509 certificate.
|
||||
</para>
|
||||
<section>
|
||||
<title>Plain Text Username Authentication</title>
|
||||
<para>
|
||||
The simplest form of username authentication uses <emphasis>plain text passwords</emphasis>. In this
|
||||
scenario, the SOAP message will contain a <literal>UsernameToken</literal> element, which itself
|
||||
contains a <literal>Username</literal> element and a <literal>Password</literal> element which contains
|
||||
the plain text password. Plain text authentication can be compared to the Basic Authentication provided
|
||||
by HTTP servers.
|
||||
</para>
|
||||
<warning>
|
||||
<para>
|
||||
Note that plain text passwords are not very secure. Therefore, you should always add additional
|
||||
security measures to your transport layer if you are using them (using HTTPS instead of plain HTTP,
|
||||
for instance).
|
||||
</para>
|
||||
</warning>
|
||||
<para>
|
||||
To require that every incoming message contains a <literal>UsernameToken</literal> with a plain
|
||||
text password, the security policy file should contain a <literal>RequireUsernameToken</literal>
|
||||
element, with the <literal>passwordDigestRequired</literal> attribute set to <literal>false</literal>.
|
||||
You can find a reference of possible child elements <ulink
|
||||
url="http://java.sun.com/webservices/docs/1.6/tutorial/doc/XWS-SecurityIntro4.html#wp567459">
|
||||
<citetitle>here</citetitle></ulink>.
|
||||
</para>
|
||||
<programlisting><![CDATA[
|
||||
<xwss:SecurityConfiguration xmlns:xwss="http://java.sun.com/xml/ns/xwss/config">
|
||||
...
|
||||
<xwss:RequireUsernameToken passwordDigestRequired="false" nonceRequired="false"/>
|
||||
...
|
||||
</xwss:SecurityConfiguration>]]></programlisting>
|
||||
<para>
|
||||
If the username token is not present, the <classname>XwsSecurityInterceptor</classname> will return a
|
||||
SOAP Fault to the sender. If it is present, it will fire a
|
||||
<classname>PasswordValidationCallback</classname> with a <classname>PlainTextPasswordRequest</classname>
|
||||
to the registered handlers. Within Spring-WS, there are three classes which handle this particular
|
||||
callback.
|
||||
</para>
|
||||
<section id="security-simple-password-validation-callback-handler">
|
||||
<title>SimplePasswordValidationCallbackHandler</title>
|
||||
<para>
|
||||
The simplest password validation handler is the
|
||||
<classname>SimplePasswordValidationCallbackHandler</classname>. This handler validates passwords
|
||||
against a in-memory <classname>Properties</classname> object, which you can specify using the
|
||||
<methodname>users</methodname> property, like so:
|
||||
</para>
|
||||
<programlisting><![CDATA[
|
||||
<bean id="passwordValidationHandler"
|
||||
class="org.springframework.ws.soap.security.xwss.callback.SimplePasswordValidationCallbackHandler">
|
||||
<property name="users">
|
||||
<props>
|
||||
<prop key="Bert">Ernie</prop>
|
||||
</props>
|
||||
</property>
|
||||
</bean>]]></programlisting>
|
||||
<para>
|
||||
In this case, we are only allowing the user "Bert" to log in using the password "Ernie".
|
||||
</para>
|
||||
</section>
|
||||
<section>
|
||||
<title>AcegiPlainTextPasswordValidationCallbackHandler</title>
|
||||
<para>
|
||||
The <classname>AcegiPlainTextPasswordValidationCallbackHandler</classname> uses the excellent <ulink
|
||||
url="http://acegisecurity.org/"><citetitle>Acegi Security Framework</citetitle></ulink> to
|
||||
authenticate users. It is beyond the scope of this document to describe Acegi, but suffice it to say
|
||||
that Acegi is a full-fledged security framework. You can read more about Acegi in the <ulink
|
||||
url="http://acegisecurity.org/docbook/acegi.html"><citetitle>Acegi reference
|
||||
documentation</citetitle></ulink>.
|
||||
</para>
|
||||
<para>
|
||||
The <classname>AcegiPlainTextPasswordValidationCallbackHandler</classname> requires an Acegi
|
||||
<classname>AuthenticationManager</classname> to operate. It uses this manager to authenticate against a
|
||||
<classname>UsernamePasswordAuthenticationToken</classname> that it creates. If authentication is
|
||||
successful, the token is stored in the <classname>SecurityContextHolder</classname>. You can set the
|
||||
authentication manager using the <methodname>authenticationManager</methodname> property:
|
||||
</para>
|
||||
<programlisting><![CDATA[
|
||||
<beans>
|
||||
<bean id="acegiHandler"
|
||||
class="org.springframework.ws.soap.security.xwss.callback.acegi.AcegiPlainTextPasswordValidationCallbackHandler">
|
||||
<property name="authenticationManager" ref="authenticationManager"/>
|
||||
</bean>
|
||||
|
||||
<bean id="authenticationManager" class="org.acegisecurity.providers.ProviderManager">
|
||||
<property name="providers">
|
||||
<bean class="org.acegisecurity.providers.dao.DaoAuthenticationProvider">
|
||||
<property name="userDetailsService" ref="userDetailsService"/>
|
||||
</bean>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean id="userDetailsService" class="com.mycompany.app.dao.UserDetailService" />
|
||||
...
|
||||
</beans>]]></programlisting>
|
||||
</section>
|
||||
<section>
|
||||
<title>JaasPlainTextPasswordValidationCallbackHandler</title>
|
||||
<para>
|
||||
The <classname>JaasPlainTextPasswordValidationCallbackHandler</classname> is based on the standard
|
||||
<ulink url="http://java.sun.com/products/jaas/"><citetitle>Java Authentication and Authorization
|
||||
Service</citetitle></ulink>. It is beyond the scope of this document to provide a full
|
||||
introduction into JAAS, but there is a <ulink
|
||||
url="http://www.javaworld.com/javaworld/jw-09-2002/jw-0913-jaas.html">
|
||||
<citetitle>good tutorial</citetitle></ulink> available.
|
||||
</para>
|
||||
<para>
|
||||
The <classname>JaasPlainTextPasswordValidationCallbackHandler</classname> only requires a
|
||||
<methodname>loginContextName</methodname> to operate. It creates a new JAAS
|
||||
<classname>LoginContext</classname> using this name, and handles the standard JAAS
|
||||
<classname>NameCallback</classname> and <classname>PasswordCallback</classname> using the username
|
||||
and password provided in the SOAP message. This means that this callback handler
|
||||
integrates with any JAAS
|
||||
<classname>LoginModule</classname> that fires these callbacks during the
|
||||
<methodname>login()</methodname> phase, which is standard behavior.
|
||||
</para>
|
||||
<para>
|
||||
You can wire up a <classname>JaasPlainTextPasswordValidationCallbackHandler</classname> as follows:
|
||||
</para>
|
||||
<programlisting><![CDATA[
|
||||
<bean id="jaasValidationHandler"
|
||||
class="org.springframework.ws.soap.security.xwss.callback.jaas.JaasPlainTextPasswordValidationCallbackHandler">
|
||||
<property name="loginContextName" value="MyLoginModule" />
|
||||
</bean>]]></programlisting>
|
||||
<para>
|
||||
In this case, the callback handler uses the <classname>LoginContext</classname> named
|
||||
"MyLoginModule". This module should be defined in your <filename>jaas.config</filename> file, as
|
||||
explained in the abovementioned tutorial.
|
||||
</para>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Digest Username Authentication</title>
|
||||
<para>
|
||||
When using password digests, the SOAP message also contain a <literal>UsernameToken</literal> element,
|
||||
which itself contains a <literal>Username</literal> element and a <literal>Password</literal> element.
|
||||
The difference is that the password is not sent as plain text, but as a <emphasis>digest</emphasis>.The
|
||||
recipient compares this digest to the digest he calculated from the known password of the user, and if
|
||||
they are the same, the user is authenticated. It can be compared to the Digest
|
||||
Authentication provided by HTTP servers.
|
||||
</para>
|
||||
<para>
|
||||
To require that every incoming message contains a <literal>UsernameToken</literal> element with a
|
||||
password digest, the security policy file should contain a <literal>RequireUsernameToken</literal>
|
||||
element, with the <literal>passwordDigestRequired</literal> attribute set to <literal>true</literal>.
|
||||
Additionally, the <literal>nonceRequired</literal> should be set to <literal>true</literal>:
|
||||
You can find a reference of possible child elements <ulink
|
||||
url="http://java.sun.com/webservices/docs/1.6/tutorial/doc/XWS-SecurityIntro4.html#wp567459">
|
||||
<citetitle>here</citetitle></ulink>.
|
||||
</para>
|
||||
<programlisting><![CDATA[
|
||||
<xwss:SecurityConfiguration xmlns:xwss="http://java.sun.com/xml/ns/xwss/config">
|
||||
...
|
||||
<xwss:RequireUsernameToken passwordDigestRequired="true" nonceRequired="true"/>
|
||||
...
|
||||
</xwss:SecurityConfiguration>]]></programlisting>
|
||||
<para>
|
||||
If the username token is not present, the <classname>XwsSecurityInterceptor</classname> will return a
|
||||
SOAP Fault to the sender. If it is present, it will fire a
|
||||
<classname>PasswordValidationCallback</classname> with a <classname>DigestPasswordRequest</classname>
|
||||
to the registered handlers. Within Spring-WS, there are two classes which handle this particular
|
||||
callback.
|
||||
</para>
|
||||
<section>
|
||||
<title>SimplePasswordValidationCallbackHandler</title>
|
||||
<para>
|
||||
The <classname>SimplePasswordValidationCallbackHandler</classname> can handle both plain text
|
||||
passwords as well as password digests. It is described in <xref
|
||||
linkend="security-simple-password-validation-callback-handler"/>.
|
||||
</para>
|
||||
</section>
|
||||
<section>
|
||||
<title>AcegiDigestPasswordValidationCallbackHandler</title>
|
||||
<para>
|
||||
The <classname>AcegiPlainTextPasswordValidationCallbackHandler</classname> requires an Acegi
|
||||
<classname>UserDetailService</classname> to operate. It uses this service to retrieve the password
|
||||
of the user specified in the token. The digest of the password contained in this details object is
|
||||
then compared with the digest in the message. If they are equal, the user has succesfully
|
||||
authenticated, and a <classname>UsernamePasswordAuthenticationToken</classname> is stored in the
|
||||
<classname>SecurityContextHolder</classname>. You can set the service using the
|
||||
<methodname>userDetailsService</methodname>. Additionally, you can set a
|
||||
<methodname>userCache</methodname> property, to cache loaded user details.
|
||||
</para>
|
||||
<programlisting><![CDATA[
|
||||
<beans>
|
||||
<bean class="org.springframework.ws.soap.security.xwss.callback.acegi.AcegiDigestPasswordValidationCallbackHandler">
|
||||
<property name="userDetailsService" ref="userDetailsService"/>
|
||||
</bean>
|
||||
|
||||
<bean id="userDetailsService" class="com.mycompany.app.dao.UserDetailService" />
|
||||
...
|
||||
</beans>]]></programlisting>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section id="security-certificate-authentication">
|
||||
<title>Certificate Authentication</title>
|
||||
<para>
|
||||
A more secure way of authentication uses X509 certificates. In this scenerario, the SOAP message
|
||||
contains a <literal>BinarySecurityToken</literal>, which contains a Base 64-encoded version of a X509
|
||||
certificate. The recipient is used by the recipient to authenticate. The certificate stored in the
|
||||
message is also used to sign the message (see <xref linkend="security-verifying-signatures"/>).
|
||||
</para>
|
||||
<para>
|
||||
To make sure that all incoming SOAP messages carry a <literal>BinarySecurityToken</literal>, the
|
||||
security policy file should contain a <literal>RequireSignature</literal> element. This element can
|
||||
carry further other elements, which will be covered in <xref linkend="security-verifying-signatures"/>.
|
||||
You can find a reference of possible child elements <ulink
|
||||
url="http://java.sun.com/webservices/docs/1.6/tutorial/doc/XWS-SecurityIntro4.html#wp565769">
|
||||
<citetitle>here</citetitle></ulink>.
|
||||
</para>
|
||||
<programlisting><![CDATA[
|
||||
<xwss:SecurityConfiguration xmlns:xwss="http://java.sun.com/xml/ns/xwss/config">
|
||||
...
|
||||
<xwss:RequireSignature requireTimestamp="false">
|
||||
...
|
||||
</xwss:SecurityConfiguration>]]></programlisting>
|
||||
<para>
|
||||
When a message arrives that carries no certificate, the <classname>XwsSecurityInterceptor</classname>
|
||||
will return a SOAP Fault to the sender. If it is present, it will fire a
|
||||
<classname>CertificateValidationCallback</classname>. There are three handlers within Spring-WS
|
||||
which handle this callback for authentication purposes.
|
||||
</para>
|
||||
<note>
|
||||
<para>
|
||||
In most cases, certificate <emphasis>authentication</emphasis> should be preceded by certificate
|
||||
<emphasis>validation</emphasis>, since you only want authenticate against valid certificates.
|
||||
Invalid certificates such as certificates for which the expiration date has passed, or which are not
|
||||
in your store of trusted certificates, should be ignored.
|
||||
</para>
|
||||
<para>
|
||||
In Spring-WS terms, this means that the
|
||||
<classname>AcegiCertificateValidationCallbackHandler</classname> or
|
||||
<classname>JaasCertificateValidationCallbackHandler</classname> should be preceded by
|
||||
<classname>KeyStoreCallbackHandler</classname>. This can be accomplished by setting the order of the
|
||||
<methodname>callbackHandlers</methodname> property in the configuration of the
|
||||
<classname>XwsSecurityInterceptor</classname>:
|
||||
<programlisting><![CDATA[
|
||||
<bean id="wsSecurityInterceptor"
|
||||
class="org.springframework.ws.soap.security.xwss.XwsSecurityInterceptor">
|
||||
<property name="policyConfiguration" value="classpath:securityPolicy.xml"/>
|
||||
<property name="callbackHandlers">
|
||||
<list>
|
||||
<ref bean="keyStoreHandler"/>
|
||||
<ref bean="acegiHandler"/>
|
||||
</list>
|
||||
</property>
|
||||
</bean>
|
||||
]]></programlisting>
|
||||
Using this setup, the interceptor will first determine if the certificate in the message is valid
|
||||
using the keystore, and then authenticate against it.
|
||||
</para>
|
||||
</note>
|
||||
<section>
|
||||
<title>KeyStoreCallbackHandler</title>
|
||||
<para>
|
||||
The <classname>KeyStoreCallbackHandler</classname> uses a standard Java key store to validate
|
||||
certificates. This certificate validation process consists of the following steps:
|
||||
<orderedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
First, the handler will check whether the certificate is in the private
|
||||
<methodname>keyStore</methodname>. If it is, it is valid.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
If the certificate is not in the private key store, the handler will check whether the
|
||||
the current date and time are within the validity period given in the certificate.
|
||||
If they are not, the certificate is invalid; if it is, it will continue with the final
|
||||
step.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Finally, a <emphasis>certification path</emphasis> for the certificate is created. This
|
||||
basically means that the handler will determine whether the certificate has been issued
|
||||
by any of the certificate authorities in the <methodname>trustStore</methodname>. If it
|
||||
a certification path can be built succesfully, the certificate is valid. Otherwise, it
|
||||
is not.
|
||||
</para>
|
||||
</listitem>
|
||||
</orderedlist>
|
||||
</para>
|
||||
<para>
|
||||
To use the <classname>KeyStoreCallbackHandler</classname> for certificate validation purposes, you
|
||||
will most likely only set the <methodname>trustStore</methodname> property:
|
||||
<programlisting><![CDATA[
|
||||
<beans>
|
||||
<bean id="keyStoreHandler" class="org.springframework.ws.soap.security.xwss.callback.KeyStoreCallbackHandler">
|
||||
<property name="trustStore" ref="trustStore"/>
|
||||
</bean>
|
||||
|
||||
<bean id="trustStore" class="org.springframework.ws.soap.security.support.KeyStoreFactoryBean">
|
||||
<property name="location" value="classpath:truststore.jks"/>
|
||||
<property name="password" value="changeit"/>
|
||||
</bean>
|
||||
</beans>]]></programlisting>
|
||||
Using this setup, the certificate that is to be validated must either be in the trust store itself,
|
||||
or the trust store must contain a certificate authority that issued the certificate.
|
||||
</para>
|
||||
</section>
|
||||
<section>
|
||||
<title>AcegiCertificateValidationCallbackHandler</title>
|
||||
<para>
|
||||
The <classname>AcegiCertificateValidationCallbackHandler</classname> requires an Acegi
|
||||
<classname>AuthenticationManager</classname> to operate. It uses this manager authenticate against a
|
||||
<classname>X509AuthenticationToken</classname> that it creates. The configured authentication
|
||||
manager is expected to supply a provider which can handle this token (usually an instance of
|
||||
<classname>X509AuthenticationProvider</classname>). If authentication is succesfull, the token is
|
||||
stored in the <classname>SecurityContextHolder</classname>. You can set the authentication manager
|
||||
using the <methodname>authenticationManager</methodname> property:
|
||||
</para>
|
||||
<programlisting><![CDATA[
|
||||
<beans>
|
||||
<bean id="acegiCertificateHandler"
|
||||
class="org.springframework.ws.soap.security.xwss.callback.acegi.AcegiCertificateValidationCallbackHandler">
|
||||
<property name="authenticationManager" ref="authenticationManager"/>
|
||||
</bean>
|
||||
|
||||
<bean id="authenticationManager"
|
||||
class="org.acegisecurity.providers.ProviderManager">
|
||||
<property name="providers">
|
||||
<bean class="org.acegisecurity.providers.x509.X509AuthenticationProvider">
|
||||
<property name="x509AuthoritiesPopulator">
|
||||
<bean class="org.acegisecurity.providers.x509.populator.DaoX509AuthoritiesPopulator">
|
||||
<property name="userDetailsService" ref="userDetailsService"/>
|
||||
</bean>
|
||||
</property>
|
||||
</bean>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean id="userDetailsService" class="com.mycompany.app.dao.UserDetailService" />
|
||||
...
|
||||
</beans>]]></programlisting>
|
||||
<para>
|
||||
In this case, we are using a custom user details service to obtain authentication details based on
|
||||
the certificate. Refer to the <ulink
|
||||
url="http://acegisecurity.org/docbook/acegi.html"><citetitle>Acegi reference
|
||||
documentation</citetitle></ulink> for more information about authentication against X509
|
||||
certificates.
|
||||
</para>
|
||||
</section>
|
||||
<section>
|
||||
<title>JaasCertificateValidationCallbackHandler</title>
|
||||
<para>
|
||||
The <classname>JaasCertificateValidationCallbackHandler</classname> requires a
|
||||
<methodname>loginContextName</methodname> to operate. It creates a new JAAS
|
||||
<classname>LoginContext</classname> using this name and with the
|
||||
<classname>X500Principal</classname> of the certificate. This means that this callback handler
|
||||
integrates with any JAAS <classname>LoginModule</classname> that handles X500 principals.
|
||||
</para>
|
||||
<para>
|
||||
You can wire up a <classname>JaasCertificateValidationCallbackHandler</classname> as follows:
|
||||
</para>
|
||||
<programlisting><![CDATA[
|
||||
<bean id="jaasValidationHandler"
|
||||
class="org.springframework.ws.soap.security.xwss.callback.jaas.JaasCertificateValidationCallbackHandler">
|
||||
<property name="loginContextName">MyLoginModule</property>
|
||||
</bean>]]></programlisting>
|
||||
<para>
|
||||
In this case, the callback handler uses the <classname>LoginContext</classname> named
|
||||
"MyLoginModule". This module should be defined in your <filename>jaas.config</filename> file, and
|
||||
should be able to authenticate against X500 principals.
|
||||
</para>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Digital Signatures</title>
|
||||
<para>
|
||||
The <emphasis>digital signature</emphasis> of a message is a piece of information based on both the document
|
||||
and the signer's private key. There are two main tasks related to signatures in WS-Security: verifying
|
||||
signatures and signing messages.
|
||||
</para>
|
||||
<section id="security-verifying-signatures">
|
||||
<title>Verifying Signatures</title>
|
||||
<para>
|
||||
Just like <link linkend="security-certificate-authentication">certificate-based authentication</link>,
|
||||
a signed message contains a <literal>BinarySecurityToken</literal>, which contains the certificate used
|
||||
to sign the message. Additionally, it contains a <literal>SignedInfo</literal> block, which indicates
|
||||
what part of the message was signed.
|
||||
</para>
|
||||
<para>
|
||||
To make sure that all incoming SOAP messages carry a <literal>BinarySecurityToken</literal>, the
|
||||
security policy file should contain a <literal>RequireSignature</literal> element.
|
||||
It can also contain a <literal>SignatureTarget</literal> element, which specifies the target message
|
||||
part which was expected to be signed, and various other subelements. You can also define the private key
|
||||
alias to use, whether to use a symmetric instead of a private key, and many other properties. You can
|
||||
find a reference of possible child elements <ulink
|
||||
url="http://java.sun.com/webservices/docs/1.6/tutorial/doc/XWS-SecurityIntro4.html#wp565769">
|
||||
<citetitle>here</citetitle></ulink>.
|
||||
</para>
|
||||
<programlisting><![CDATA[
|
||||
<xwss:SecurityConfiguration xmlns:xwss="http://java.sun.com/xml/ns/xwss/config">
|
||||
<xwss:RequireSignature requireTimestamp="false"/>
|
||||
</xwss:SecurityConfiguration>]]></programlisting>
|
||||
<para>
|
||||
If the signature is not present, the <classname>XwsSecurityInterceptor</classname> will return a
|
||||
SOAP Fault to the sender. If it is present, it will fire a
|
||||
<classname>SignatureVerificationKeyCallback</classname> to the registered handlers. Within Spring-WS,
|
||||
there are is one class which handles this particular callback: the
|
||||
<classname>KeyStoreCallbackHandler</classname>.
|
||||
</para>
|
||||
|
||||
<section>
|
||||
<title>KeyStoreCallbackHandler</title>
|
||||
<para>
|
||||
As described in <xref linkend="security-key-store-callback-handler"/>, the
|
||||
<classname>KeyStoreCallbackHandler</classname> uses a <classname>java.security.KeyStore</classname>
|
||||
for handling various cryptographic callbacks, including signature verification. For signature
|
||||
verification, the handler uses the <methodname>trustStore</methodname> property:
|
||||
</para>
|
||||
<programlisting><![CDATA[
|
||||
<beans>
|
||||
<bean id="keyStoreHandler" class="org.springframework.ws.soap.security.xwss.callback.KeyStoreCallbackHandler">
|
||||
<property name="trustStore" ref="trustStore"/>
|
||||
</bean>
|
||||
|
||||
<bean id="trustStore" class="org.springframework.ws.soap.security.support.KeyStoreFactoryBean">
|
||||
<property name="location" value="classpath:org/springframework/ws/soap/security/xwss/test-truststore.jks"/>
|
||||
<property name="password" value="changeit"/>
|
||||
</bean>
|
||||
</beans>]]></programlisting>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Signing Messages</title>
|
||||
<para>
|
||||
When signing a message, the <classname>XwsSecurityInterceptor</classname> adds the
|
||||
<literal>BinarySecurityToken</literal> to the message, and a <literal>SignedInfo</literal> block, which
|
||||
indicates what part of the message was signed.
|
||||
</para>
|
||||
<para>
|
||||
To sign all outgoing SOAP messages, the
|
||||
security policy file should contain a <literal>Sign</literal> element.
|
||||
It can also contain a <literal>SignatureTarget</literal> element, which specifies the target message
|
||||
part which was expected to be signed, and various other subelements. You can also define the private key
|
||||
alias to use, whether to use a symmetric instead of a private key, and many other properties. You can
|
||||
find a reference of possible child elements <ulink
|
||||
url="http://java.sun.com/webservices/docs/1.6/tutorial/doc/XWS-SecurityIntro4.html#wp565497">
|
||||
<citetitle>here</citetitle></ulink>.
|
||||
</para>
|
||||
<programlisting><![CDATA[
|
||||
<xwss:SecurityConfiguration xmlns:xwss="http://java.sun.com/xml/ns/xwss/config">
|
||||
<xwss:Sign includeTimestamp="false" />
|
||||
</xwss:SecurityConfiguration>]]></programlisting>
|
||||
<para>
|
||||
The <classname>XwsSecurityInterceptor</classname> will fire a
|
||||
<classname>SignatureKeyCallback</classname> to the registered handlers. Within Spring-WS,
|
||||
there are is one class which handles this particular callback: the
|
||||
<classname>KeyStoreCallbackHandler</classname>.
|
||||
</para>
|
||||
<section>
|
||||
<title>KeyStoreCallbackHandler</title>
|
||||
<para>
|
||||
As described in <xref linkend="security-key-store-callback-handler"/>, the
|
||||
<classname>KeyStoreCallbackHandler</classname> uses a <classname>java.security.KeyStore</classname>
|
||||
for handling various cryptographic callbacks, including signing messages. For adding signatures,
|
||||
the handler uses the <methodname>keyStore</methodname> property. Additionally, you must set
|
||||
the <methodname>privateKeyPassword</methodname> property to unlock the private key used for signing.
|
||||
</para>
|
||||
<programlisting><![CDATA[
|
||||
<beans>
|
||||
<bean id="keyStoreHandler" class="org.springframework.ws.soap.security.xwss.callback.KeyStoreCallbackHandler">
|
||||
<property name="keyStore" ref="keyStore"/>
|
||||
<property name="privateKeyPassword" value="changeit"/>
|
||||
</bean>
|
||||
|
||||
<bean id="keyStore" class="org.springframework.ws.soap.security.support.KeyStoreFactoryBean">
|
||||
<property name="location" value="classpath:keystore.jks"/>
|
||||
<property name="password" value="changeit"/>
|
||||
</bean>
|
||||
</beans>]]></programlisting>
|
||||
</section>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Encryption and Decryption</title>
|
||||
<para>
|
||||
When <emphasis>encrypting</emphasis>, the message is transformed into a form that can only be read with the
|
||||
appropriate key. The message can be <emphasis>decrypted</emphasis> to reveal the original, readable message.
|
||||
</para>
|
||||
<section>
|
||||
<title>Decryption</title>
|
||||
<para>
|
||||
To decrypt incoming SOAP messages, the security policy file should contain a
|
||||
<literal>RequireEncryption</literal> element. This element can further carry a
|
||||
<literal>EncryptionTarget</literal> element which indicates which part of the message should be
|
||||
encrypted, a <literal>SymmetricKey</literal> to indicate that a shared secret instead of the regular
|
||||
private key should be used to decrypt the message. You can read a description of the other elements
|
||||
<ulink url="http://java.sun.com/webservices/docs/1.6/tutorial/doc/XWS-SecurityIntro4.html#wp565951">
|
||||
<citetitle>here</citetitle></ulink>.
|
||||
</para>
|
||||
<programlisting><![CDATA[
|
||||
<xwss:SecurityConfiguration xmlns:xwss="http://java.sun.com/xml/ns/xwss/config">
|
||||
<xwss:RequireEncryption />
|
||||
</xwss:SecurityConfiguration>]]></programlisting>
|
||||
<para>
|
||||
If an incoming message is not encrypted, the <classname>XwsSecurityInterceptor</classname> will return a
|
||||
SOAP Fault to the sender. If it is present, it will fire a <classname>DecryptionKeyCallback</classname>
|
||||
to the registered handlers. Within Spring-WS, there is one class which handled this particular callback:
|
||||
the <classname>KeyStoreCallbackHandler</classname>.
|
||||
</para>
|
||||
<section>
|
||||
<title>KeyStoreCallbackHandler</title>
|
||||
<para>
|
||||
As described in <xref linkend="security-key-store-callback-handler"/>, the
|
||||
<classname>KeyStoreCallbackHandler</classname> uses a <classname>java.security.KeyStore</classname>
|
||||
for handling various cryptographic callbacks, including decryption. For decryption,
|
||||
the handler uses the <methodname>keyStore</methodname> property. Additionally, you must set
|
||||
the <methodname>privateKeyPassword</methodname> property to unlock the private key used for
|
||||
decryption. For decryption based on symmetric keys, it will use the
|
||||
<methodname>symmetricStore</methodname>.
|
||||
</para>
|
||||
<programlisting><![CDATA[
|
||||
<beans>
|
||||
<bean id="keyStoreHandler" class="org.springframework.ws.soap.security.xwss.callback.KeyStoreCallbackHandler">
|
||||
<property name="keyStore" ref="keyStore"/>
|
||||
<property name="privateKeyPassword" value="changeit"/>
|
||||
</bean>
|
||||
|
||||
<bean id="keyStore" class="org.springframework.ws.soap.security.support.KeyStoreFactoryBean">
|
||||
<property name="location" value="classpath:keystore.jks"/>
|
||||
<property name="password" value="changeit"/>
|
||||
</bean>
|
||||
</beans>]]></programlisting>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Encryption</title>
|
||||
<para>
|
||||
To encrypt outgoing SOAP messages, the security policy file should contain a <literal>Encrypt</literal>
|
||||
element. This element can further carry a <literal>EncryptionTarget</literal> element which indicates
|
||||
which part of the message should be encrypted, a <literal>SymmetricKey</literal> to indicate that a
|
||||
shared secret instead of the regular private key should be used to decrypt the message. You can read a
|
||||
description of the other elements <ulink
|
||||
url="http://java.sun.com/webservices/docs/1.6/tutorial/doc/XWS-SecurityIntro4.html#wp565951">
|
||||
<citetitle>here</citetitle></ulink>.
|
||||
</para>
|
||||
<programlisting><![CDATA[
|
||||
<xwss:SecurityConfiguration xmlns:xwss="http://java.sun.com/xml/ns/xwss/config">
|
||||
<xwss:Encrypt />
|
||||
</xwss:SecurityConfiguration>]]></programlisting>
|
||||
<para>
|
||||
The <classname>XwsSecurityInterceptor</classname> will fire a
|
||||
<classname>EncryptionKeyCallback</classname> to the registered handlers in order to retrieve the
|
||||
encryption information. Within Spring-WS, there is one class which handled this particular callback: the
|
||||
<classname>KeyStoreCallbackHandler</classname>.
|
||||
</para>
|
||||
<section>
|
||||
<title>KeyStoreCallbackHandler</title>
|
||||
<para>
|
||||
As described in <xref linkend="security-key-store-callback-handler"/>, the
|
||||
<classname>KeyStoreCallbackHandler</classname> uses a <classname>java.security.KeyStore</classname>
|
||||
for handling various cryptographic callbacks, including encryption. For encryption based on public
|
||||
keys, the handler uses the <methodname>trustStore</methodname> property. For encryption based on
|
||||
symmetric keys, it will use the <methodname>symmetricStore</methodname>.
|
||||
</para>
|
||||
<programlisting><![CDATA[
|
||||
<beans>
|
||||
<bean id="keyStoreHandler" class="org.springframework.ws.soap.security.xwss.callback.KeyStoreCallbackHandler">
|
||||
<property name="trustStore" ref="trustStore"/>
|
||||
</bean>
|
||||
|
||||
<bean id="trustStore" class="org.springframework.ws.soap.security.support.KeyStoreFactoryBean">
|
||||
<property name="location" value="classpath:truststore.jks"/>
|
||||
<property name="password" value="changeit"/>
|
||||
</bean>
|
||||
</beans>]]></programlisting>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
</section>
|
||||
</chapter>
|
||||
|
||||
193
doc/src/docbkx/ws.xml
Normal file
193
doc/src/docbkx/ws.xml
Normal file
@@ -0,0 +1,193 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<chapter id="ws">
|
||||
<title>Document-driven Web services with Spring-WS</title>
|
||||
|
||||
<section id="ws-introduction">
|
||||
<title>Introduction</title>
|
||||
<para>
|
||||
Spring's Web service framework is designed around
|
||||
</para>
|
||||
</section>
|
||||
<section>
|
||||
<title>MessageDispatcher</title>
|
||||
<para>
|
||||
Spring-WS is designed around a central dispatching mechanism, which forwards
|
||||
</para>
|
||||
</section>
|
||||
<section>
|
||||
<title>Endpoints</title>
|
||||
</section>
|
||||
<section id="ws-endpoint-mapping">
|
||||
<title>Endpoint mappings</title>
|
||||
<para>
|
||||
The endpoint mapping is responsible for mapping incoming messages to appropriate endpoints. It does this by
|
||||
delivering a <classname>EndpointInterceptorChain</classname>, which consists of the endpoint that matches
|
||||
the incoming request, and an optional list of endpoint interceptors. When a message is received by the
|
||||
<classname>MessageDispatcher</classname>, it will ask the registered endpoint mappings to come up with a
|
||||
appropriate <classname>HandlerExecutionChain</classname>. After that, the
|
||||
<classname>MessageDispatcher</classname> will invoke the endpoint and interceptors in the chain.
|
||||
</para>
|
||||
<para>
|
||||
Most endpoint mappings inherit from the <classname>AbstractEndpointMapping</classname>, which offers the
|
||||
following properties:
|
||||
<informaltable>
|
||||
<tgroup cols="2">
|
||||
<tbody>
|
||||
<row>
|
||||
<entry>
|
||||
<methodname>interceptors</methodname>
|
||||
</entry>
|
||||
<entry>
|
||||
the list of interceptors use. <interfacename>EndpointInterceptor</interfacename>s are
|
||||
discussed in <xref linkend="ws-endpoint-interceptor"/>.
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>
|
||||
<methodname>defaultHandler</methodname>
|
||||
</entry>
|
||||
<entry>
|
||||
the default handler to use. This endpoint will be returned if no specific mapping was
|
||||
found.
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>
|
||||
|
||||
</entry>
|
||||
</row>
|
||||
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</informaltable>
|
||||
</para>
|
||||
<section>
|
||||
<title>SoapActionEndpointMapping</title>
|
||||
</section>
|
||||
<section>
|
||||
<title>PayloadRootQNameEndpointMapping</title>
|
||||
</section>
|
||||
<section id="ws-endpoint-interceptor">
|
||||
<title>Adding <interfacename>EndpointInterceptors</interfacename></title>
|
||||
</section>
|
||||
<section>
|
||||
<title>Handling Exceptions</title>
|
||||
<para>
|
||||
Spring-WS provides
|
||||
<classname>EndpointExceptionResolvers</classname>
|
||||
to ease the pain of unexpected
|
||||
exceptions occurring while your message is being processed by an endpoint which matched the request.
|
||||
<classname>EndpointExceptionResolver</classname>
|
||||
s somewhat resemble the exception mappings that can be
|
||||
defined in the web application descriptor
|
||||
<filename>web.xml</filename>
|
||||
.
|
||||
Rather than expose the innards of your application by giving a client a full stack trace, you can handle
|
||||
the exception any way you want, e.g. return a SOAP fault with a specific fault code and string.
|
||||
Furthermore, a programmatic way of handling exceptions gives you many more options for how to respond
|
||||
appropriately.
|
||||
</para>
|
||||
<para>
|
||||
Besides implementing the
|
||||
<classname>HandlerExceptionResolver</classname>
|
||||
interface, which is only a
|
||||
matter of implementing the
|
||||
<methodname>resolveException(MessageContext, endpoint, Exception)</methodname>
|
||||
method and returning a
|
||||
boolean, you may also use the
|
||||
<classname>SoapFaultMappingExceptionResolver</classname>
|
||||
.
|
||||
This resolver enables you to take the class name of any exception that might be thrown and map it to a
|
||||
SOAP Fault, like so:
|
||||
<programlisting><![CDATA[
|
||||
<bean id="exceptionResolver"
|
||||
class="org.springframework.ws.soap.endpoint.SoapFaultMappingExceptionResolver">
|
||||
<property name="defaultFault" value="RECEIVER,Server error">
|
||||
</property>
|
||||
<property name="exceptionMappings">
|
||||
<props>
|
||||
<prop key="org.springframework.oxm.ValidationFailureException">
|
||||
SENDER,Invalid request
|
||||
</prop>
|
||||
</props>
|
||||
</property>
|
||||
</bean>
|
||||
]]></programlisting>
|
||||
This configuration will map exceptions of type
|
||||
<classname>ValidationFailureException</classname>
|
||||
to a
|
||||
sender side SOAP Fault with a fault string "Invalid request".
|
||||
If any other exception occurs, it will return the default fault: a server side fault with fault string
|
||||
"Server error".
|
||||
Refer to the Javadoc of
|
||||
<classname>SoapFaultDefinitionEditor</classname>
|
||||
to read more about the exact
|
||||
notation of the faults.
|
||||
</para>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Similarities between Spring-MVC and Spring-WS</title>
|
||||
<para>
|
||||
Spring-WS has the same basic architecture as Spring's Web MVC framework.
|
||||
The table below shows some of the core concepts of Spring Web MVC, and the corresponding class in Spring-WS.
|
||||
<informaltable>
|
||||
<tgroup cols="2">
|
||||
<thead>
|
||||
<row>
|
||||
<entry>Spring Web MVC</entry>
|
||||
<entry>Spring Web Services</entry>
|
||||
</row>
|
||||
</thead>
|
||||
<tbody>
|
||||
<row>
|
||||
<entry>
|
||||
<classname>DispatcherServlet</classname>
|
||||
</entry>
|
||||
<entry>
|
||||
<classname>MessageDispatcher</classname>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>handler</entry>
|
||||
<entry>endpoint</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>
|
||||
<classname>HandlerAdapter</classname>
|
||||
</entry>
|
||||
<entry>
|
||||
<classname>EndpointAdapter</classname>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>
|
||||
<classname>HandlerMapping</classname>
|
||||
</entry>
|
||||
<entry>
|
||||
<classname>EndpointMapping</classname>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>
|
||||
<classname>HandlerInterceptor</classname>
|
||||
</entry>
|
||||
<entry>
|
||||
<classname>EndpointInterceptor</classname>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>
|
||||
<classname>HandlerExceptionResolver</classname>
|
||||
</entry>
|
||||
<entry>
|
||||
<classname>EndpointExceptionResolver</classname>
|
||||
</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</informaltable>
|
||||
</para>
|
||||
</section>
|
||||
</chapter>
|
||||
Reference in New Issue
Block a user