1438 lines
79 KiB
XML
1438 lines
79 KiB
XML
<?xml version="1.0" encoding="UTF-8"?>
|
|
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
|
|
"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd">
|
|
<chapter id="security">
|
|
<title>Securing your Web services with Spring-WS</title>
|
|
|
|
<section id="security-introduction">
|
|
<title>Introduction</title>
|
|
<para>
|
|
This chapter explains 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 not using
|
|
WS-Security, or simply use HTTP-based security.
|
|
</para>
|
|
</note>
|
|
</section>
|
|
<section id="security-xws-security-interceptor">
|
|
<title><classname>XwsSecurityInterceptor</classname></title>
|
|
<para>
|
|
The <classname>XwsSecurityInterceptor</classname> is an <classname>EndpointInterceptor</classname>
|
|
(see <xref linkend="server-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="server-endpoint-mapping"/>). This means that you can be selective about adding WS-Security
|
|
support: some endpoint mappings require it, while others do not.
|
|
</para>
|
|
<note>
|
|
<para>
|
|
Note that the XWSS requires both a SUN 1.5 JDK and the SUN SAAJ reference implementation.
|
|
The WSS4J interceptor does not have these requirements (see
|
|
<xref linkend="security-wss4j-security-interceptor"/>).
|
|
</para>
|
|
</note>
|
|
<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 id="keystore">
|
|
<title>Keystores</title>
|
|
<para>
|
|
For most cryptographic operations, you will use the standard <classname>java.security.KeyStore</classname>
|
|
objects. This includes certificate verification, message signing, signature verification, and encryption, but
|
|
excludes username and time-stamp verification. This section aims to give you some background knowledge on
|
|
keystores, and the Java tools that you can use to store keys and certificates in a keystore 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>
|
|
<para>
|
|
Supplied with your Java Virtual Machine is the <command>keytool</command> program, a key and certificate
|
|
management utility. You can use this tool to create new keystores, 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.5.0/docs/tooldocs/windows/keytool.html"><citetitle>here</citetitle></ulink>,
|
|
or by giving the command <prompt>keytool -help</prompt> on the command line.
|
|
</para>
|
|
</section>
|
|
<section>
|
|
<title>KeyStoreFactoryBean</title>
|
|
<para>
|
|
To easily load a keystore 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 keystore to load. A password may be given to check the integrity of the
|
|
keystore 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 keystore 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 keystores within a <classname>XwsSecurityInterceptor</classname>, you will need to define a
|
|
<classname>KeyStoreCallbackHandler</classname>. This callback has three properties with type keystore:
|
|
(<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>Keystore 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 an 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> requires only 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 contains 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 successfully
|
|
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
|
|
further carry 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 to 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 keystore 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 keystore, 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
|
|
a certification path can be built successfully, the certificate is valid. Otherwise,
|
|
the certificate is not.
|
|
</para>
|
|
</listitem>
|
|
</orderedlist>
|
|
</para>
|
|
<para>
|
|
To use the <classname>KeyStoreCallbackHandler</classname> for certificate validation purposes, you
|
|
will most likely set only 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 to 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 succesful, 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, and 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, and 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>
|
|
</section>
|
|
<section id="security-wss4j-security-interceptor">
|
|
<title><classname>Wss4jSecurityInterceptor</classname></title>
|
|
<para>
|
|
The <classname>Wss4jSecurityInterceptor</classname> is an <classname>EndpointInterceptor</classname>
|
|
(see <xref linkend="server-endpoint-interceptor"/>) that is based on
|
|
<ulink url="http://ws.apache.org/wss4j/">Apache's WSS4J</ulink>.
|
|
</para>
|
|
<para>
|
|
WSS4J implements the following standards:
|
|
<itemizedlist>
|
|
<listitem><para>OASIS Web Serives Security: SOAP Message Security 1.0 Standard 200401, March 2004</para></listitem>
|
|
<listitem><para>Username Token profile V1.0</para></listitem>
|
|
<listitem><para>X.509 Token Profile V1.0</para></listitem>
|
|
</itemizedlist>
|
|
</para>
|
|
<para>
|
|
This inteceptor supports messages created by the <classname>AxiomSoapMessageFactory</classname> and the
|
|
<classname>SaajSoapMessageFactory</classname>.
|
|
</para>
|
|
|
|
<section>
|
|
<title>Configuring <classname>Wss4jSecurityInterceptor</classname></title>
|
|
<para>
|
|
WSS4J uses no external configuration file; the interceptor is entirely configured by properties.
|
|
The validation and securement actions executed by this interceptor are specified via
|
|
<property>validationActions</property> and <property>securementActions</property> properties, respectively.
|
|
Actions are passed as a space-separated strings. Here is an example configuration:
|
|
</para>
|
|
<programlisting><![CDATA[<bean class="org.springframework.ws.soap.security.wss4j.Wss4jSecurityInterceptor">
|
|
<property name="validationActions" value="UsernameToken Decrypt"/>
|
|
...
|
|
<property name="securementActions" value="Decrypt"/>
|
|
...
|
|
</bean>]]></programlisting>
|
|
<para>Validation actions are:</para>
|
|
<informaltable>
|
|
<tgroup cols="2">
|
|
<thead>
|
|
<row>
|
|
<entry>Validation action</entry>
|
|
<entry>Description</entry>
|
|
</row>
|
|
</thead>
|
|
<tbody>
|
|
<row>
|
|
<entry><methodname>UsernameToken</methodname></entry>
|
|
<entry>Validates username token</entry>
|
|
</row>
|
|
<row>
|
|
<entry><methodname>Timestamp</methodname></entry>
|
|
<entry>Validates the timestamp</entry>
|
|
</row>
|
|
<row>
|
|
<entry><methodname>Encrypt</methodname></entry>
|
|
<entry>Decrypts the message</entry>
|
|
</row>
|
|
<row>
|
|
<entry><methodname>Signature</methodname></entry>
|
|
<entry>Validates the signature</entry>
|
|
</row>
|
|
<row>
|
|
<entry><methodname>NoSecurity</methodname></entry>
|
|
<entry>No action performed</entry>
|
|
</row>
|
|
</tbody>
|
|
</tgroup>
|
|
</informaltable>
|
|
<para>Securement actions are:</para>
|
|
<informaltable>
|
|
<tgroup cols="2">
|
|
<thead>
|
|
<row>
|
|
<entry>Securement action</entry>
|
|
<entry>Description</entry>
|
|
</row>
|
|
</thead>
|
|
<tbody>
|
|
<row>
|
|
<entry><methodname>UsernameToken</methodname></entry>
|
|
<entry>Adds a username token</entry>
|
|
</row>
|
|
<row>
|
|
<entry><methodname>UsernameTokenSignature</methodname></entry>
|
|
<entry>Adds a username token and a signature username token secret key</entry>
|
|
</row>
|
|
<row>
|
|
<entry><methodname>Timestamp</methodname></entry>
|
|
<entry>Adds a timestamp</entry>
|
|
</row>
|
|
<row>
|
|
<entry><methodname>Encrypt</methodname></entry>
|
|
<entry>Encrypts the response</entry>
|
|
</row>
|
|
<row>
|
|
<entry><methodname>Signature</methodname></entry>
|
|
<entry>Signs the response</entry>
|
|
</row>
|
|
<row>
|
|
<entry><methodname>NoSecurity</methodname></entry>
|
|
<entry>No action performed</entry>
|
|
</row>
|
|
</tbody>
|
|
</tgroup>
|
|
</informaltable>
|
|
<para>
|
|
The order of the actions is significant and is enforced by the interceptor. The interceptor
|
|
will reject an incoming SOAP message if its security actions were performed in a different order than
|
|
the one specified by <methodname>validationActions</methodname>.
|
|
</para>
|
|
</section>
|
|
<section>
|
|
<title>Handling Digital Certificates</title>
|
|
<para>
|
|
For cryptographic operations requiring interaction with a keystore or certificate handling
|
|
(signature, encryption and decryption operations), WSS4J
|
|
requires an instance of <interfacename>org.apache.ws.security.components.crypto.Crypto</interfacename>.
|
|
</para>
|
|
<para>
|
|
<interfacename>Crypto</interfacename> instances can be obtained from WSS4J's
|
|
<classname>CryptoFactory</classname> or more conveniently
|
|
with the Spring-WS <classname>CryptoFactoryBean</classname>.
|
|
</para>
|
|
<section>
|
|
<title>CryptoFactoryBean</title>
|
|
<para>
|
|
Spring-WS provides a convenient factory bean, <classname>CryptoFactoryBean</classname>
|
|
that constructs and configures <classname>Crypto</classname> instances via strong-typed properties
|
|
(prefered) or through a <classname>Properties</classname> object.
|
|
</para>
|
|
<para>
|
|
By default, <classname>CryptoFactoryBean</classname> returns instances of
|
|
<classname>org.apache.ws.security.components.crypto.Merlin</classname>.
|
|
This can be changed by setting the <property>cryptoProvider</property> property
|
|
(or its equivalent <literal>org.apache.ws.security.crypto.provider</literal> string property).
|
|
</para>
|
|
<para>
|
|
Here is a simple example configuration:
|
|
</para>
|
|
<programlisting><![CDATA[
|
|
<bean class="org.springframework.ws.soap.security.wss4j.support.CryptoFactoryBean">
|
|
<property name="keyStorePassword" value="mypassword"/>
|
|
<property name="keyStoreLocation" value="file:/path_to_keystore/keystore.jks"/>
|
|
</bean>
|
|
]]></programlisting>
|
|
</section>
|
|
</section>
|
|
<section>
|
|
<title>Authentication</title>
|
|
<section>
|
|
<title>Validating Username Token</title>
|
|
<para>
|
|
Spring-WS provides a set of callback handlers to integrate with Acegi Security (and Spring Security).
|
|
Additionally, a simple callback handler <classname>SimplePasswordValidationCallbackHandler</classname>
|
|
is provided to configure users and passwords with an in-memory <classname>Properties</classname> object.
|
|
</para>
|
|
<para>
|
|
Callback handlers are configured via <classname>Wss4jSecurityInterceptor</classname>'s
|
|
<property>validationCallbackHandler</property> property.
|
|
</para>
|
|
<section>
|
|
<title>SimplePasswordValidationCallbackHandler</title>
|
|
<para>
|
|
<classname>SimplePasswordValidationCallbackHandler</classname> validates plain text and digest
|
|
username tokens against an in-memory <classname>Properties</classname> object. It is configured
|
|
as follows:
|
|
</para>
|
|
<programlisting><![CDATA[<bean id="callbackHandler"
|
|
class="org.springframework.ws.soap.security.wss4j.callback.SimplePasswordValidationCallbackHandler">
|
|
<property name="users">
|
|
<props>
|
|
<prop key="Bert">Ernie</prop>
|
|
</props>
|
|
</property>
|
|
</bean>]]></programlisting>
|
|
</section>
|
|
<section>
|
|
<title>AcegiPlainTextPasswordValidationCallbackHandler</title>
|
|
<para>
|
|
The <classname>AcegiPlainTextPasswordValidationCallbackHandler</classname> requires an Acegi
|
|
<interfacename>AuthenticationManager</interfacename> 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 <property>authenticationManager</property> property:
|
|
</para>
|
|
<programlisting><![CDATA[<beans>
|
|
<bean id="acegiHandler"
|
|
class="org.springframework.ws.soap.security.wss4j.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>AcegiDigestPasswordValidationCallbackHandler</title>
|
|
<para>
|
|
The <classname>AcegiDigestPasswordValidationCallbackHandler</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
|
|
successfully authenticated, and a <classname>UsernamePasswordAuthenticationToken</classname> is
|
|
stored in the <classname>SecurityContextHolder</classname>. You can set the service using the
|
|
<property>userDetailsService</property>. Additionally, you can set a
|
|
<property>userCache</property> property, to cache loaded user details.
|
|
</para>
|
|
<programlisting><![CDATA[<beans>
|
|
<bean class="org.springframework.ws.soap.security.wss4j.callback.acegi.AcegiDigestPasswordValidationCallbackHandler">
|
|
<property name="userDetailsService" ref="userDetailsService"/>
|
|
</bean>
|
|
|
|
<bean id="userDetailsService" class="com.mycompany.app.dao.UserDetailService" />
|
|
...
|
|
</beans>
|
|
]]></programlisting>
|
|
</section>
|
|
</section>
|
|
<section>
|
|
<title>Adding Username Token</title>
|
|
<para>
|
|
Adding a username token to an outgoing message is as simple as adding
|
|
<literal>UsernameToken</literal> to the <property>securementActions</property> property of the
|
|
<classname>Wss4jSecurityInterceptor</classname> and specifying
|
|
<property>securementUsername</property> and <property>securementPassword</property>.
|
|
</para>
|
|
<para>
|
|
The password type can be set via the <property>securementPasswordType</property> property. Possible
|
|
values are <literal>PasswordText</literal> for plain text passwords or
|
|
<literal>PasswordDigest</literal> for digest passwords, which is the default.
|
|
</para>
|
|
<para>
|
|
The following example generates a username token with a digest password:
|
|
</para>
|
|
<programlisting><![CDATA[<bean class="org.springframework.ws.soap.security.wss4j.Wss4jSecurityInterceptor">
|
|
<property name="securementActions" value="UsernameToken"/>
|
|
<property name="securementUsername" value="Ernie"/>
|
|
<property name="securementPassword" value="Bert"/>
|
|
</bean>]]></programlisting>
|
|
<para>
|
|
If plain text password type is chosen, it is possible to instruct the interceptor to add
|
|
<literal>Nonce</literal> and/or <literal>Created</literal> elements using the
|
|
<property>securementUsernameTokenElements</property> property. The value must be a list containing
|
|
the desired elements' names separated by spaces (case sensitive).
|
|
</para>
|
|
<para>
|
|
The next example generates a username token with a plain text password,
|
|
a <literal>Nonce</literal> and a <literal>Created</literal> element:
|
|
</para>
|
|
<programlisting><![CDATA[<bean class="org.springframework.ws.soap.security.wss4j.Wss4jSecurityInterceptor">
|
|
<property name="securementActions" value="UsernameToken"/>
|
|
<property name="securementUsername" value="Ernie"/>
|
|
<property name="securementPassword" value="Bert"/>
|
|
<property name="securementPasswordType" value="PasswordText"/>
|
|
<property name="securementUsernameTokenElements" value="Nonce Created"/>
|
|
</bean>]]></programlisting>
|
|
</section>
|
|
</section>
|
|
<section>
|
|
<title>Security Timestamps</title>
|
|
<para>
|
|
This section describes the various timestamp options available in the
|
|
<classname>Wss4jSecurityInterceptor</classname>.
|
|
</para>
|
|
<section>
|
|
<title>Validating Timestamps</title>
|
|
<para>
|
|
To validate timestamps add <literal>Timestamp</literal> to the
|
|
<property>validationActions</property> property.
|
|
It is possible to override timestamp semantics specified by the initiator of the SOAP message
|
|
by setting <property>timestampStrict</property> to <literal>true</literal> and
|
|
specifying a server-side time to live in seconds (defaults to 300) via the
|
|
<property>timeToLive</property> property
|
|
<footnote>
|
|
<para>
|
|
The interceptor will always reject already expired timestamps whatever the value of
|
|
<property>timeToLive</property> is.
|
|
</para>
|
|
</footnote>.
|
|
</para>
|
|
<para>
|
|
In the following example, the interceptor will limit the timestamp validity window to 10
|
|
seconds, rejecting any valid timestamp token outside that window:
|
|
</para>
|
|
<programlisting><![CDATA[<bean class="org.springframework.ws.soap.security.wss4j.Wss4jSecurityInterceptor">
|
|
<property name="validationActions" value="Timestamp"/>
|
|
<property name="timestampStrict" value="true"/>
|
|
<property name="timeToLive" value="10"/>
|
|
</bean>
|
|
]]></programlisting>
|
|
</section>
|
|
<section>
|
|
<title>Adding Timestamps</title>
|
|
<para>
|
|
Adding <literal>Timestamp</literal> to the <property>securementActions</property> property
|
|
generates a timestamp header in outgoing messages. The
|
|
<property>timestampPrecisionInMilliseconds</property> property specifies whether the precision
|
|
of the generated timestamp is in milliseconds. The default value is <literal>true</literal>.
|
|
</para>
|
|
<programlisting><![CDATA[<bean class="org.springframework.ws.soap.security.wss4j.Wss4jSecurityInterceptor">
|
|
<property name="securementActions" value="Timestamp"/>
|
|
<property name="timestampPrecisionInMilliseconds" value="true"/>
|
|
</bean>
|
|
]]></programlisting>
|
|
</section>
|
|
</section>
|
|
<section>
|
|
<title>Digital Signatures</title>
|
|
<para>
|
|
This section describes the various signature options available in the
|
|
<classname>Wss4jSecurityInterceptor</classname>.
|
|
</para>
|
|
<section>
|
|
<title>Verifying Signatures</title>
|
|
<para>
|
|
To instruct the <classname>Wss4jSecurityInterceptor</classname>,
|
|
<property>validationActions</property> must contain the <literal>Signature</literal> action.
|
|
Additionally, the <property>validationSignatureCrypto</property> property
|
|
must point to the keystore containing the public certificates of the initiator:
|
|
</para>
|
|
<programlisting><![CDATA[<bean id="wsSecurityInterceptor" class="org.springframework.ws.soap.security.wss4j.Wss4jSecurityInterceptor">
|
|
<property name="validationActions" value="Signature"/>
|
|
<property name="validationSignatureCrypto">
|
|
<bean class="org.springframework.ws.soap.security.wss4j.support.CryptoFactoryBean">
|
|
<property name="keyStorePassword" value="123456"/>
|
|
<property name="keyStoreLocation" value="classpath:/keystore.jks"/>
|
|
</bean>
|
|
</property>
|
|
</bean>]]></programlisting>
|
|
</section>
|
|
<section>
|
|
<title>Signing Messages</title>
|
|
<para>
|
|
Signing outgoing messages is enabled by adding <literal>Signature</literal> action
|
|
to the <property>securementActions</property>. The alias and the password of the private key to use
|
|
are specified by the <property>securementUsername</property> and
|
|
<property>securementPassword</property> properties respectively.
|
|
<property>securementSignatureCrypto</property> must point to the keystore containing the private key:
|
|
</para>
|
|
<programlisting><![CDATA[<bean class="org.springframework.ws.soap.security.wss4j.Wss4jSecurityInterceptor">
|
|
<property name="securementActions" value="Signature"/>
|
|
<property name="securementUsername" value="mykey"/>
|
|
<property name="securementPassword" value="123456"/>
|
|
<property name="securementSignatureCrypto">
|
|
<bean class="org.springframework.ws.soap.security.wss4j.support.CryptoFactoryBean">
|
|
<property name="keyStorePassword" value="123456"/>
|
|
<property name="keyStoreLocation" value="classpath:/keystore.jks"/>
|
|
</bean>
|
|
</property>
|
|
</bean>
|
|
]]></programlisting>
|
|
<para>
|
|
Furthermore, the signature algorithm can be defined
|
|
via the <property>securementSignatureAlgorithm</property>
|
|
(Currently this parameter is ignored - SHA1RSA is the only supported algorithm).
|
|
</para>
|
|
<para>
|
|
The key identifier type to use can be customized via the
|
|
<property>securementSignatureKeyIdentifier</property> property.
|
|
Only <literal>IssuerSerial</literal> and <literal>DirectReference</literal>
|
|
are valid for signature.
|
|
</para>
|
|
<para>
|
|
<property>securementSignatureParts</property> property controls which part of the message shall be
|
|
signed.
|
|
The value of this property is a list of semi-colon separated element names that identify the
|
|
elements to sign.
|
|
The general form of a signature part is <literal>{}{namespace}Element</literal>
|
|
<footnote>
|
|
<para>
|
|
The first empty brackets are used for encryption parts only.
|
|
</para>
|
|
</footnote>.
|
|
The default behavior is to sign the SOAP body.
|
|
</para>
|
|
<para>
|
|
As an example, here is how to sign the <literal>echoResponse</literal> element
|
|
in the Spring Web Services echo sample:
|
|
</para>
|
|
<programlisting><![CDATA[<property name="securementSignatureParts"
|
|
value="{}{http://www.springframework.org/spring-ws/samples/echo}echoResponse"/>
|
|
]]></programlisting>
|
|
<para>
|
|
The WS Security specifications define several formats to transfer the signature tokens
|
|
(certificates) or references to these tokens. Thus, the plain element name
|
|
<literal>Token</literal>
|
|
signs the token and takes care of the different formats.
|
|
To sign the SOAP body and the signature token the value
|
|
of <property>securementSignatureParts</property> must contain:
|
|
</para>
|
|
<programlisting><![CDATA[<property name="securementSignatureParts">
|
|
<value>
|
|
{}{http://schemas.xmlsoap.org/soap/envelope/}Body;
|
|
Token
|
|
</value>
|
|
</property>]]></programlisting>
|
|
<para>
|
|
To specify an element without a namespace use the string <literal>Null</literal>
|
|
as the namespace name (case sensitive).
|
|
</para>
|
|
<para>
|
|
If there is no other element in the request with a local name of <methodname>Body</methodname> then
|
|
the SOAP namespace identifier can be empty (<methodname>{}</methodname>).
|
|
</para>
|
|
</section>
|
|
<section>
|
|
<title>Signature Confirmation</title>
|
|
<para>
|
|
Signature confirmation is enabled by setting <property>enableSignatureConfirmation</property> to
|
|
<literal>true</literal>.
|
|
Note that signature confirmation action spans over the request and the response.
|
|
This implies that <methodname>secureResponse</methodname> and <methodname>validateRequest</methodname>
|
|
must be set to true (which is the default value) even if there are no corresponding security actions.
|
|
</para>
|
|
<programlisting><![CDATA[<bean class="org.springframework.ws.soap.security.wss4j.Wss4jSecurityInterceptor">
|
|
<property name="validationActions" value="Signature"/>
|
|
<property name="enableSignatureConfirmation" value="true"/>
|
|
<property name="validationSignatureCrypto">
|
|
<bean class="org.springframework.ws.soap.security.wss4j.support.CryptoFactoryBean">
|
|
<property name="keyStorePassword" value="123456"/>
|
|
<property name="keyStoreLocation" value="file:/keystore.jks"/>
|
|
</bean>
|
|
</property>
|
|
</bean>]]></programlisting>
|
|
</section>
|
|
</section>
|
|
<section>
|
|
<title>Encryption and Decryption</title>
|
|
<para>
|
|
This section describes the various encryption and descryption options available in the
|
|
<classname>Wss4jSecurityInterceptor</classname>.
|
|
</para>
|
|
<section>
|
|
<title>Decryption</title>
|
|
<para>
|
|
Decryption of incoming SOAP messages requires <literal>Encrypt</literal> action be added
|
|
to the <property>securementActions</property> property. The rest of the configuration
|
|
depends on the key information that appears in the message
|
|
<footnote>
|
|
<para>
|
|
This is because WSS4J needs only a Crypto for encypted keys, whereas embedded key name
|
|
validation is delegated to a callback handler.
|
|
</para>
|
|
</footnote>.
|
|
</para>
|
|
<para>
|
|
To decrypt messages with an embedded encypted symmetric key
|
|
(<literal>xenc:EncryptedKey</literal> element),
|
|
<property>validationDecryptionCrypto</property> needs to point to a keystore containing the
|
|
decryption private key. Additionally,
|
|
<property>validationCallbackHandler</property> has to be injected
|
|
with a <classname>org.springframework.ws.soap.security.wss4j.callback.KeyStoreCallbackHandler</classname>
|
|
specifying the key's password:
|
|
</para>
|
|
<programlisting><![CDATA[<bean class="org.springframework.ws.soap.security.wss4j.Wss4jSecurityInterceptor">
|
|
<property name="validationActions" value="Encrypt"/>
|
|
<property name="validationDecryptionCrypto">
|
|
<bean class="org.springframework.ws.soap.security.wss4j.support.CryptoFactoryBean">
|
|
<property name="keyStorePassword" value="123456"/>
|
|
<property name="keyStoreLocation" value="classpath:/keystore.jks"/>
|
|
</bean>
|
|
</property>
|
|
<property name="validationCallbackHandler">
|
|
<bean class="org.springframework.ws.soap.security.wss4j.callback.KeyStoreCallbackHandler">
|
|
<property name="privateKeyPassword" value="mykeypass"/>
|
|
</bean>
|
|
</property>
|
|
</bean>]]></programlisting>
|
|
<para>
|
|
To support decryption of messages with an embedded <emphasis>key name</emphasis>
|
|
(<literal>ds:KeyName</literal> element),
|
|
configure a <classname>KeyStoreCallbackHandler</classname> that
|
|
points to the keystore with the symmetric secret key. The property
|
|
<property>symmetricKeyPassword</property> indicates the key's password, the key name being the
|
|
one specified by <literal>ds:KeyName</literal> element:
|
|
</para>
|
|
<programlisting><![CDATA[<bean class="org.springframework.ws.soap.security.wss4j.Wss4jSecurityInterceptor">
|
|
<property name="validationActions" value="Encrypt"/>
|
|
<property name="validationCallbackHandler">
|
|
<bean class="org.springframework.ws.soap.security.wss4j.callback.KeyStoreCallbackHandler">
|
|
<property name="keyStore">
|
|
<bean class="org.springframework.ws.soap.security.support.KeyStoreFactoryBean">
|
|
<property name="location" value="classpath:keystore.jks"/>
|
|
<property name="type" value="JCEKS"/>
|
|
<property name="password" value="123456"/>
|
|
</bean>
|
|
</property>
|
|
<property name="symmetricKeyPassword" value="mykeypass"/>
|
|
</bean>
|
|
</property>
|
|
</bean>]]></programlisting>
|
|
</section>
|
|
<section>
|
|
<title>Encryption</title>
|
|
<para>
|
|
Adding <literal>Encrypt</literal> to the <property>securementActions</property> enables encryption
|
|
of outgoing messages.
|
|
The certifacte's alias to use for the encryption is set via the
|
|
<property>securementEncryptionUser</property> property.
|
|
The keystore where the certificate reside is accessed using the
|
|
<property>securementEncryptionCrypto</property> property.
|
|
As encryption relies on public certificates, no password needs to be passed.
|
|
</para>
|
|
<programlisting><![CDATA[<bean class="org.springframework.ws.soap.security.wss4j.Wss4jSecurityInterceptor">
|
|
<property name="securementActions" value="Encrypt"/>
|
|
<property name="securementEncryptionUser" value="mycert"/>
|
|
<property name="securementEncryptionCrypto">
|
|
<bean class="org.springframework.ws.soap.security.wss4j.support.CryptoFactoryBean">
|
|
<property name="keyStorePassword" value="123456"/>
|
|
<property name="keyStoreLocation" value="file:/keystore.jks"/>
|
|
</bean>
|
|
</property>
|
|
</bean>]]></programlisting>
|
|
<para>
|
|
Encryption can be customized in several ways:
|
|
The key identifier type to use is defined by <property>securementEncryptionKeyIdentifier</property>.
|
|
Possible values are <literal>IssuerSerial</literal>, <literal>X509KeyIdentifier</literal>,
|
|
<literal>DirectReference</literal>, <literal>Thumbprint</literal>,
|
|
<literal>SKIKeyIdentifier</literal> or <literal>EmbeddedKeyName</literal>.
|
|
</para>
|
|
<para>
|
|
The <property>securementEncryptionKeyTransportAlgorithm</property> property
|
|
defines which algorithm to use to encrypt the generated symmetric key. Supported values are
|
|
<literal>http://www.w3.org/2001/04/xmlenc#rsa-1_5</literal>, which is the default, and
|
|
<literal>http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p</literal>.
|
|
</para>
|
|
<para>
|
|
The symmetric encryption algorithm to use can be set via the
|
|
<property>securementEncryptionSymAlgorithm</property> property.
|
|
Supported values are <literal>http://www.w3.org/2001/04/xmlenc#aes128-cbc</literal> (default value),
|
|
<literal>http://www.w3.org/2001/04/xmlenc#tripledes-cbc</literal>,
|
|
<literal>http://www.w3.org/2001/04/xmlenc#aes256-cbc</literal>,
|
|
<literal>http://www.w3.org/2001/04/xmlenc#aes192-cbc</literal>.
|
|
</para>
|
|
<para>
|
|
Finally, the <property>securementEncryptionParts</property> property defines which parts of the
|
|
message will be encrypted. The value of this property is a list of semi-colon separated element
|
|
names that identify the elements to encrypt. An encryption mode specifier and a namespace
|
|
identification, each inside a pair of curly brackets, may precede each element name.
|
|
The encryption mode specifier is either <literal>{Content}</literal> or
|
|
<literal>{Element}</literal>
|
|
<footnote>
|
|
<para>
|
|
Please refer to the W3C XML Encryption specification about the differences between
|
|
Element and Content encryption.
|
|
</para>
|
|
</footnote>.
|
|
The following example identifies the <literal>echoResponse</literal> from the echo sample:
|
|
</para>
|
|
<programlisting><![CDATA[<property name="securementEncryptionParts"
|
|
value="{Content}{http://www.springframework.org/spring-ws/samples/echo}echoResponse"/>]]></programlisting>
|
|
<para>
|
|
Be aware that the element name, the namespace identifier, and the encryption modifier are case
|
|
sensitive.
|
|
The encryption modifier and the namespace identifier can be omitted. In this case the encryption
|
|
mode defaults to <literal>Content</literal> and the namespace is set to the SOAP namespace.
|
|
</para>
|
|
<para>
|
|
To specify an element without a namespace use the value <literal>Null</literal> as the namespace
|
|
name (case sensitive).
|
|
If no list is specified, the handler encrypts the SOAP Body in <literal>Content</literal> mode by
|
|
default.
|
|
</para>
|
|
</section>
|
|
</section>
|
|
</section>
|
|
</chapter> |