cxf-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From conflue...@apache.org
Subject [CONF] Apache CXF Documentation > WS-Security
Date Wed, 08 Aug 2012 19:08:00 GMT
<html>
<head>
    <base href="https://cwiki.apache.org/confluence">
            <link rel="stylesheet" href="/confluence/s/2042/9/1/_/styles/combined.css?spaceKey=CXF20DOC&amp;forWysiwyg=true"
type="text/css">
    </head>
<body style="background: white;" bgcolor="white" class="email-body">
<div id="pageContent">
<div id="notificationFormat">
<div class="wiki-content">
<div class="email">
    <h2><a href="https://cwiki.apache.org/confluence/display/CXF20DOC/WS-Security">WS-Security</a></h2>
    <h4>Page <b>edited</b> by             <a href="https://cwiki.apache.org/confluence/display/~mazzag">Glen
Mazza</a>
    </h4>
        <div id="versionComment">
        <b>Comment:</b>
        Changed the text to highlight WS-SecPol as the preferred first option.<br />
    </div>
        <br/>
                         <h4>Changes (2)</h4>
                                 
    
<div id="page-diffs">
                    <table class="diff" cellpadding="0" cellspacing="0">
    
            <tr><td class="diff-snipped" >...<br></td></tr>
            <tr><td class="diff-unchanged" >* Timestamp messages <br> <br></td></tr>
            <tr><td class="diff-deleted-lines" style="color:#999;background-color:#fdd;text-decoration:line-through;">Currently,
CXF implements WS-Security by integrating [WSS4J|http://ws.apache.org/wss4j]. To use the integration,
you&#39;ll need to configure these interceptors and add them to your service and/or client
as detailed in this article. Alternatively, WS-Security can be implemented by using [WS-SecurityPolicy|http://cxf.apache.org/docs/ws-securitypolicy.html],
which provides a more comprehensive and sophisticated validation of the security properties
of a received message. <br></td></tr>
            <tr><td class="diff-added-lines" style="background-color: #dfd;">CXF
relies on [WSS4J|http://ws.apache.org/wss4j] in large part to implement WS-Security.  Within
your own services, WS-Security can be activated by using [WS-SecurityPolicy|http://cxf.apache.org/docs/ws-securitypolicy.html],
which provides a comprehensive and sophisticated validation of the security properties of
a received message.  A non-WS-SecurityPolicy approach is usually also possible by way of CXF
interceptors added to your service and/or client as detailed in this article. <br></td></tr>
            <tr><td class="diff-unchanged" > <br>h1. Overview of encryption
and signing <br></td></tr>
            <tr><td class="diff-snipped" >...<br></td></tr>
    
            </table>
    </div>                            <h4>Full Content</h4>
                    <div class="notificationGreySide">
        <h1><a name="WS-Security-WSSecurity"></a>WS-Security</h1>

<p>WS-Security provides means to secure your services above and beyond transport level
protocols such as HTTPS. Through a number of standards such as XML-Encryption, and headers
defined in the WS-Security standard, it allows you to:</p>
<ul>
	<li>Pass authentication tokens between services</li>
	<li>Encrypt messages or parts of messages</li>
	<li>Sign messages</li>
	<li>Timestamp messages</li>
</ul>


<p>CXF relies on <a href="http://ws.apache.org/wss4j" class="external-link" rel="nofollow">WSS4J</a>
in large part to implement WS-Security.  Within your own services, WS-Security can be activated
by using <a href="http://cxf.apache.org/docs/ws-securitypolicy.html" class="external-link"
rel="nofollow">WS-SecurityPolicy</a>, which provides a comprehensive and sophisticated
validation of the security properties of a received message.  A non-WS-SecurityPolicy approach
is usually also possible by way of CXF interceptors added to your service and/or client as
detailed in this article.</p>

<h1><a name="WS-Security-Overviewofencryptionandsigning"></a>Overview of
encryption and signing</h1>

<p>WS-Security makes heavy use of public/private key cryptography. To really understand
how to configure WS-Security, it is helpful - if not necessary - to understand these basics.
The Wikipedia has an <a href="http://en.wikipedia.org/wiki/Public-key_cryptography" class="external-link"
rel="nofollow">excellent entry</a> on this, but we'll try to summarize the relevant
basics here (This content is a modified version of the wikipedia content..)</p>

<p>With public key cryptography, a user has a pair of public and private keys.  These
are generated using a large prime number and a key function.<br/>
<span class="image-wrap" style=""><img src="http://upload.wikimedia.org/wikipedia/commons/thumb/3/3f/Public_key_making.svg/250px-Public_key_making.svg.png"
style="border: 0px solid black" /></span></p>

<p>The keys are related mathematically, but cannot be derived from one another. With
these keys we can encrypt messages. For example, if Bob wants to send a message to Alice,
he can encrypt a message using her public key. Alice can then decrypt this message using her
private key. Only Alice can decrypt this message as she is the only one with the private key.<br/>
<span class="image-wrap" style=""><img src="http://upload.wikimedia.org/wikipedia/commons/thumb/f/f9/Public_key_encryption.svg/280px-Public_key_encryption.svg.png"
style="border: 0px solid black" /></span></p>

<p>Messages can also be signed. This allows you to ensure the authenticity of the message.
If Alice wants to send a message to Bob, and Bob wants to be sure that it is from Alice, Alice
can sign the message using her private key. Bob can then verify that the message is from Alice
by using her public key.<br/>
<span class="image-wrap" style=""><img src="http://upload.wikimedia.org/wikipedia/commons/thumb/1/1e/Public_key_signing.svg/280px-Public_key_signing.svg.png"
style="border: 0px solid black" /></span></p>

<h1><a name="WS-Security-ConfiguringtheWSS4JInterceptors"></a>Configuring
the WSS4J Interceptors</h1>

<p>To enable WS-Security within CXF for a server or a client, you'll need to set up
the WSS4J interceptors. You can either do this via the API for standalone web services or
via Spring XML configuration for servlet-hosted ones. This section will provide an overview
of how to do this, and the following sections will go into more detail about configuring the
interceptors for specific security actions.</p>

<p>It is important to note that:</p>
<ol>
	<li>If you are using CXF 2.0.x, you must add the SAAJ(In/Out)Interceptors if you're
using WS-Security (This is done automatically for you from CXF 2.1 onwards). These enable
creation of a DOM tree for each request/response. The support libraries for WS-Security require
DOM trees.</li>
	<li>The web service provider may not need both in and out WS-Security interceptors.
For instance, if you are just requiring signatures on incoming messages, the web service provider
will just need an incoming WSS4J interceptor and only the SOAP client will need an outgoing
one.</li>
</ol>


<h2><a name="WS-Security-AddingtheinterceptorsviatheAPI"></a>Adding the
interceptors via the API</h2>

<p>On the Server side, you'll want to add the interceptors to your CXF Endpoint. If
you're publishing your service using the JAX-WS APIs, you can get your CXF endpoint like this:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
<span class="code-keyword">import</span> org.apache.cxf.endpoint.Endpoint;
<span class="code-keyword">import</span> org.apache.cxf.jaxws.EndpointImpl;

EndpointImpl jaxWsEndpoint = (EndpointImpl) Endpoint.publish(<span class="code-quote">"http:<span
class="code-comment">//host/service"</span>, 
</span>    myServiceImpl);
Endpoint cxfEndpoint = jaxWsEndpoint.getServer().getEndpoint();
</pre>
</div></div>
<p>If you've used the (JaxWs)ServerFactoryBean, you can simply access it via the Server
object:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
<span class="code-keyword">import</span> org.apache.cxf.endpoint.Endpoint;
<span class="code-keyword">import</span> org.apache.cxf.endpoint.Server;
<span class="code-keyword">import</span> org.apache.cxf.frontend.ServerFactoryBean;

ServerFactoryBean factory = ...;
...
Server server = factory.create();
Endpoint cxfEndpoint = server.getEndpoint();
</pre>
</div></div>
<p>On the client side, you can obtain a reference to the CXF endpoint using the ClientProxy
helper:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
<span class="code-keyword">import</span> org.apache.cxf.frontend.ClientProxy;
...

GreeterService gs = <span class="code-keyword">new</span> GreeterService();
Greeter greeter = gs.getGreeterPort();
...
org.apache.cxf.endpoint.Client client = ClientProxy.getClient(greeter);
org.apache.cxf.endpoint.Endpoint cxfEndpoint = client.getEndpoint();
</pre>
</div></div>
<p><a name="WS-Security-addinterceptors"></a>Now you're ready to add the
interceptors:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
<span class="code-keyword">import</span> org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor;
<span class="code-keyword">import</span> org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor;
...

Map&lt;<span class="code-object">String</span>,<span class="code-object">Object</span>&gt;
inProps= <span class="code-keyword">new</span> HashMap&lt;<span class="code-object">String</span>,<span
class="code-object">Object</span>&gt;();
... <span class="code-comment">// how to configure the properties is outlined below;
</span>
WSS4JInInterceptor wssIn = <span class="code-keyword">new</span> WSS4JInInterceptor(inProps);
cxfEndpoint.getInInterceptors().add(wssIn);

Map&lt;<span class="code-object">String</span>,<span class="code-object">Object</span>&gt;
outProps = <span class="code-keyword">new</span> HashMap&lt;<span class="code-object">String</span>,<span
class="code-object">Object</span>&gt;();
... <span class="code-comment">// how to configure the properties is outlined below;
</span>
WSS4JOutInterceptor wssOut = <span class="code-keyword">new</span> WSS4JOutInterceptor(outProps);
cxfEndpoint.getOutInterceptors().add(wssOut);
</pre>
</div></div>

<h1><a name="WS-Security-SpringXMLConfiguration"></a>Spring XML Configuration</h1>

<p>If you're using Spring to build endpoints (e.g., web services running on a servlet
container such as Tomcat), you can easily accomplish the above using your bean definitions
instead.</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-xml">
<span class="code-tag">&lt;import resource=<span class="code-quote">"classpath:META-INF/cxf/cxf.xml"</span>
/&gt;</span>
<span class="code-tag">&lt;import resource=<span class="code-quote">"classpath*:META-INF/cxf/cxf-extension-*.xml"</span>
/&gt;</span>

&lt;jaxws:endpoint id=<span class="code-quote">"myService"</span>
   implementor=<span class="code-quote">"com.acme.MyServiceImpl"</span>
   address=<span class="code-quote">"http://localhost:9001/MyService"</span>&gt;

   &lt;bean id=<span class="code-quote">"myPasswordCallback"</span>
      class=<span class="code-quote">"com.mycompany.webservice.ServerPasswordCallback"</span>/&gt;

   <span class="code-tag">&lt;jaxws:inInterceptors&gt;</span>
      <span class="code-tag">&lt;bean class=<span class="code-quote">"org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor"</span>&gt;</span>
         <span class="code-tag">&lt;constructor-arg&gt;</span>
            <span class="code-tag">&lt;map&gt;</span>
               <span class="code-tag">&lt;entry key=<span class="code-quote">"action"</span>
value=<span class="code-quote">"UsernameToken"</span>/&gt;</span>
               <span class="code-tag">&lt;entry key=<span class="code-quote">"passwordType"</span>
value=<span class="code-quote">"PasswordDigest"</span>/&gt;</span>
               <span class="code-tag">&lt;entry key=<span class="code-quote">"signaturePropFile"</span>
value=<span class="code-quote">"..."</span>/&gt;</span>
               <span class="code-tag">&lt;entry key=<span class="code-quote">"passwordCallbackRef"</span>&gt;</span>
                  <span class="code-tag">&lt;ref bean=<span class="code-quote">"myPasswordCallback"</span>/&gt;</span>
               <span class="code-tag">&lt;/entry&gt;</span>
               ...
            <span class="code-tag">&lt;/map&gt;</span>
         <span class="code-tag">&lt;/constructor-arg&gt;</span>
      <span class="code-tag">&lt;/bean&gt;</span>
   <span class="code-tag">&lt;/jaxws:inInterceptors&gt;</span>
<span class="code-tag">&lt;/jaxws:endpoint&gt;</span>
</pre>
</div></div>

<p>The entry keys and values given in the constructor-arg element above (action, signaturePropFile,
etc.) map to the text strings in WSS4J's <a href="http://ws.apache.org/wss4j/apidocs/org/apache/ws/security/handler/WSHandlerConstants.html"
class="external-link" rel="nofollow">WSHandlerConstants</a> and <a href="http://ws.apache.org/wss4j/apidocs/org/apache/ws/security/WSConstants.html"
class="external-link" rel="nofollow">WSConstants</a> classes for the corresponding
WSHandlerConstants.XXXXX and WSConstants.XXXX constants you see in the section below (also
see the WSS4J configuration <a href="http://ws.apache.org/wss4j/config.html" class="external-link"
rel="nofollow">page</a>).  So by viewing WSHandlerConstants, for example, you can
see that the WSHandlerConstants.USERNAME_TOKEN value given below would need to be "UsernameToken"
instead when doing Spring configuration.</p>

<p>If you want to avoid looking up the text keys for the WSHandlerConstants.XXXXX and
WSConstants.XXXX constants, you can also use the Spring util namespace to reference static
constants in your Spring context as shown below.</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-xml">
&lt;beans
  ...
  <span class="code-keyword">xmlns:util</span>=<span class="code-quote">"http://www.springframework.org/schema/util"</span>
  ...
  xsi:schemaLocation="
        ...
        http://www.springframework.org/schema/util 
        http://www.springframework.org/schema/util/spring-util.xsd"&gt;

  ...

  <span class="code-tag">&lt;bean class=<span class="code-quote">"org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor"</span>&gt;</span>
    <span class="code-tag">&lt;constructor-arg&gt;</span>
      <span class="code-tag">&lt;map&gt;</span>
        <span class="code-tag">&lt;entry value=<span class="code-quote">"UsernameToken"</span>&gt;</span>
          <span class="code-tag">&lt;key&gt;</span>
            &lt;util:constant 
                static-field=<span class="code-quote">"org.apache.ws.security.handler.WSHandlerConstants.ACTION"</span>/&gt;
          <span class="code-tag">&lt;/key&gt;</span>
        <span class="code-tag">&lt;/entry&gt;</span>
        ...
      <span class="code-tag">&lt;/map&gt;</span>
    <span class="code-tag">&lt;/constructor-arg&gt;</span>
  <span class="code-tag">&lt;/bean&gt;</span>

  ...  
</pre>
</div></div>

<h2><a name="WS-Security-AdditionalConfigurationOptions"></a>Additional
Configuration Options</h2>

<p>While the CXF WSS4J interceptors support the standard configuration properties available
in WSHandlerConstants.XXXXX and WSConstants.XXXX, CXF also provides access to some additional
low level configuration capabilities in WSS4J and some other security related interceptors.</p>

<h3><a name="WS-Security-ValidatingSignatureand%2ForEncryptionofMessageContents"></a>Validating
Signature and/or Encryption of Message Contents</h3>

<p>As of CXF 2.2.8, the CryptoCoverageChecker interceptor allows one to validate signature
and encryption coverage of message contents without migrating to a WS-SecurityPolicy based
configuration.  The interceptor can support enforcement of signature and encryption coverage
at both the element and content level (be aware that the combination of signature and content
do not represent a valid combination of coverage type and coverage scope).  To configure this
interceptor using the API, follow the example below.</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
<span class="code-keyword">import</span> org.apache.cxf.ws.security.wss4j.CryptoCoverageChecker;
<span class="code-keyword">import</span> org.apache.cxf.ws.security.wss4j.CryptoCoverageChecker.XPathExpression;
<span class="code-keyword">import</span> org.apache.cxf.ws.security.wss4j.CryptoCoverageUtil.CoverageScope;
<span class="code-keyword">import</span> org.apache.cxf.ws.security.wss4j.CryptoCoverageUtil.CoverageType;

Map&lt;<span class="code-object">String</span>, <span class="code-object">String</span>&gt;
prefixes = <span class="code-keyword">new</span> HashMap&lt;<span class="code-object">String</span>,
<span class="code-object">String</span>&gt;();
        prefixes.put(<span class="code-quote">"ser"</span>, <span class="code-quote">"http:<span
class="code-comment">//www.sdj.pl"</span>);
</span>        prefixes.put(<span class="code-quote">"soap"</span>, <span
class="code-quote">"http:<span class="code-comment">//schemas.xmlsoap.org/soap/envelope/"</span>);
</span>
List&lt;XPathExpression&gt; xpaths = Arrays.asList(
    <span class="code-keyword">new</span> XPathExpression(<span class="code-quote">"<span
class="code-comment">//ser:Header"</span>, CoverageType.SIGNED, 
</span>        CoverageScope.ELEMENT),
    <span class="code-keyword">new</span> XPathExpression(<span class="code-quote">"<span
class="code-comment">//soap:Body"</span>, CoverageType.ENCRYPTED, 
</span>        CoverageScope.CONTENT));

CryptoCoverageChecker checker = <span class="code-keyword">new</span> CryptoCoverageChecker(prefixes,
xpaths);
</pre>
</div></div>

<p>The interceptor can also be configured in Spring using the conventional bean definition
format.</p>

<p>After configuring the interceptor as above, simply add the interceptor to your client
or server interceptor chain as shown previsouly with the WSS4J interceptors.  Ensure that
you include the WSS4JInInterceptor in the chain or all requests will be denied if you enforce
any coverage XPaths.</p>

<h3><a name="WS-Security-CustomProcessors"></a>Custom Processors</h3>

<p>As of CXF 2.0.10 and 2.1.4, you can specify custom WSS4J Processor configurations
on the WSS4JInInterceptor.  To activate this configuration option, one provides a non-WSS4J
defined property, wss4j.processor.map, to the WSS4JInInterceptor as shown in the following
Spring example.  The same configuratoin can be acheieved through the API as well.  The key
value is an XML qualified name of the WS-S header element to process with the given processor
implementation.  The entry values can be a String representing a class name of the processor
to instantiate, an Object implementing Processor, or null to disable processing of the given
WS-S header element.</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-xml">
<span class="code-tag">&lt;bean class=<span class="code-quote">"org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor"</span>&gt;</span>
  <span class="code-tag">&lt;constructor-arg&gt;</span>
    <span class="code-tag">&lt;map&gt;</span>
      ...
      &lt;!-- This reconfigures the processor implementation that WSS4j uses to 
               process a WS-S Signature element. --&gt;
      <span class="code-tag">&lt;entry key=<span class="code-quote">"wss4j.processor.map"</span>&gt;</span>
        <span class="code-tag">&lt;map key-type=<span class="code-quote">"javax.xml.namespace.QName"</span>&gt;</span>
          <span class="code-tag">&lt;entry value=<span class="code-quote">"my.class"</span>&gt;</span>
            <span class="code-tag">&lt;key&gt;</span>
              <span class="code-tag">&lt;bean class=<span class="code-quote">"javax.xml.namespace.QName"</span>&gt;</span>
                <span class="code-tag">&lt;constructor-arg value=<span class="code-quote">"http://www.w3.org/2000/09/xmldsig#"</span>/&gt;</span>
                <span class="code-tag">&lt;constructor-arg value=<span class="code-quote">"Signature"</span>/&gt;</span>
              <span class="code-tag">&lt;/bean&gt;</span>
            <span class="code-tag">&lt;/key&gt;</span>
          <span class="code-tag">&lt;/entry&gt;</span>
        <span class="code-tag">&lt;/map&gt;</span>
      <span class="code-tag">&lt;/entry&gt;</span>
      ...
    <span class="code-tag">&lt;/map&gt;</span>
  <span class="code-tag">&lt;/constructor-arg&gt;</span>
<span class="code-tag">&lt;/bean&gt;</span>
</pre>
</div></div>

<h3><a name="WS-Security-CustomActions"></a>Custom Actions</h3>

<p>As of CXF 2.2.6, you can specify custom WSS4J Action configurations on the WSS4JOutInterceptor.
 To activate this configuration option, one provides a non-WSS4J defined property, wss4j.action.map,
to the WSS4JOutInterceptor as shown in the following Spring example.  The same configuratoin
can be acheieved through the API as well.  The key value is an integer representing the WSS4J
action identifier.  The entry values can be a String representing a class name of the action
to instantiate or an Object implementing Action.  This configuration option allows you to
override built-in action implementations or add your own.</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-xml">
<span class="code-tag">&lt;bean class=<span class="code-quote">"org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor"</span>&gt;</span>
  <span class="code-tag">&lt;constructor-arg&gt;</span>
    <span class="code-tag">&lt;map&gt;</span>
      ...
      &lt;!-- Redefines the action for SAMLTokenSigned 
               to use a custom implementation.  --&gt;
      <span class="code-tag">&lt;entry key=<span class="code-quote">"wss4j.action.map"</span>&gt;</span>
        <span class="code-tag">&lt;map key-type=<span class="code-quote">"java.lang.Integer"</span>
value-type=<span class="code-quote">"java.lang.Object"</span>&gt;</span>
          <span class="code-tag">&lt;entry key=<span class="code-quote">"0x10"</span>
value-ref=<span class="code-quote">"mySamlTokenSignedAction"</span>/&gt;</span>
        <span class="code-tag">&lt;/map&gt;</span>
      <span class="code-tag">&lt;/entry&gt;</span>      ...
    <span class="code-tag">&lt;/map&gt;</span>
  <span class="code-tag">&lt;/constructor-arg&gt;</span>
<span class="code-tag">&lt;/bean&gt;</span>
</pre>
</div></div>

<p>For the case that adding new custom action, if the new key int number is 12345, you
must also specify new action name as string "12345".</p>

<h1><a name="WS-Security-ConfiguringWSSecurityActions"></a>Configuring WS-Security
Actions</h1>

<h2><a name="WS-Security-UsernameTokenAuthentication"></a>Username Token
Authentication</h2>

<p>WS-Security supports many ways of specifying tokens. One of these is the UsernameToken
header. It is a standard way to communicate a username and password or password digest to
another endpoint.  Be sure to review the OASIS <a href="http://tinyurl.com/65n78j" class="external-link"
rel="nofollow">UsernameToken Profile Specification</a> for important security considerations
when using UsernameTokens. </p>

<p>If a nonce is present in a UsernameToken then it should be cached by the message
recipient to guard against replay attacks. This behaviour is enabled by default starting with
CXF 2.6.0. This functionality is also available from Apache CXF 2.4.7 and 2.5.3 onwards, but
is not enabled by default at all for backwards-compatibility reasons. The following properties
control nonce caching:</p>

<ul>
	<li>"ws-security.enable.nonce.cache" - Whether to cache UsernameToken nonces. The default
value (for CXF 2.6.0) is "true" for message recipients, and "false" for message initiators.
Set it to true to cache for both cases. The default value for CXF 2.4.x and 2.5.x is false.
See <a href="http://cxf.apache.org/javadoc/latest/org/apache/cxf/ws/security/SecurityConstants.html#ENABLE_NONCE_CACHE"
class="external-link" rel="nofollow">here</a> for more information.</li>
	<li>"ws-security.nonce.cache.instance" - This holds a reference to a <a href="http://ws.apache.org/wss4j/apidocs/org/apache/ws/security/cache/ReplayCache.html"
class="external-link" rel="nofollow">ReplayCache</a> instance used to cache UsernameToken
nonces. The default instance that is used is the <a href="http://svn.apache.org/viewvc/cxf/trunk/rt/ws/security/src/main/java/org/apache/cxf/ws/security/cache/EHCacheReplayCache.java?view=markup"
class="external-link" rel="nofollow">EHCacheReplayCache</a>.</li>
	<li>"ws-security.cache.config.file" - Set this property to point to a configuration
file for the underlying caching implementation. The default configuration file that is used
is <a href="http://svn.apache.org/viewvc/cxf/trunk/rt/ws/security/src/main/resources/cxf-ehcache.xml?view=markup"
class="external-link" rel="nofollow">cxf-ehcache.xml</a> in the cxf-rt-ws-security
module.</li>
</ul>


<p>For the server side, you'll want to set up the following properties on your WSS4JInInterceptor
(see <a href="#WS-Security-addinterceptors">above</a> for code sample):</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
inProps.put(WSHandlerConstants.ACTION, WSHandlerConstants.USERNAME_TOKEN);
<span class="code-comment">// Password type : plain text
</span>inProps.put(WSHandlerConstants.PASSWORD_TYPE, WSConstants.PW_TEXT);
<span class="code-comment">// <span class="code-keyword">for</span> hashed
password use:
</span><span class="code-comment">//properties.put(WSHandlerConstants.PASSWORD_TYPE,
WSConstants.PW_DIGEST);
</span><span class="code-comment">// Callback used to retrieve password <span
class="code-keyword">for</span> given user.
</span>inProps.put(WSHandlerConstants.PW_CALLBACK_CLASS, 
    ServerPasswordHandler.class.getName());
</pre>
</div></div>

<p>The password callback class allows you to retrieve the password for a given user
so that WS-Security can determine if they're authorized. Here is a small example:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
<span class="code-keyword">import</span> java.io.IOException;
<span class="code-keyword">import</span> javax.security.auth.callback.Callback;
<span class="code-keyword">import</span> javax.security.auth.callback.CallbackHandler;
<span class="code-keyword">import</span> javax.security.auth.callback.UnsupportedCallbackException;
<span class="code-keyword">import</span> org.apache.ws.security.WSPasswordCallback;

<span class="code-keyword">public</span> class ServerPasswordCallback <span
class="code-keyword">implements</span> CallbackHandler {

    <span class="code-keyword">public</span> void handle(Callback[] callbacks)
<span class="code-keyword">throws</span> IOException, 
        UnsupportedCallbackException {

        WSPasswordCallback pc = (WSPasswordCallback) callbacks[0];

        <span class="code-keyword">if</span> (pc.getIdentifier().equals(<span
class="code-quote">"joe"</span>)) {
            <span class="code-comment">// set the password on the callback. This will
be compared to the
</span>            <span class="code-comment">// password which was sent from
the client.
</span>            pc.setPassword(<span class="code-quote">"password"</span>);
        }
    }

}
</pre>
</div></div>
<p>Note that for up to and including CXF 2.3.x, the password validation of the special
case of a plain-text password (or any other yet unknown  password type) is delegated to the
callback  class, see <a href="http://ws.apache.org/wss4j/apidocs/org/apache/ws/security/processor/UsernameTokenProcessor.html#handleUsernameToken(org.w3c.dom.Element,%20javax.security.auth.callback.CallbackHandler)"
class="external-link" rel="nofollow">org.apache.ws.security.processor.UsernameTokenProcessor#handleUsernameToken()
method javadoc</a> of the <a href="http://ws.apache.org/wss4j/" class="external-link"
rel="nofollow">WSS4J</a> project. In that case, the ServerPasswordCallback should
be something like the following one:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
<span class="code-keyword">public</span> class ServerPasswordCallback <span
class="code-keyword">implements</span> CallbackHandler {

    <span class="code-keyword">public</span> void handle(Callback[] callbacks)
<span class="code-keyword">throws</span> IOException, 
        UnsupportedCallbackException {

        WSPasswordCallback pc = (WSPasswordCallback) callbacks[0];

        <span class="code-keyword">if</span> (pc.getIdentifer().equals(<span
class="code-quote">"joe"</span>) {
           <span class="code-keyword">if</span> (!pc.getPassword().equals(<span
class="code-quote">"password"</span>)) {
                <span class="code-keyword">throw</span> <span class="code-keyword">new</span>
IOException(<span class="code-quote">"wrong password"</span>);
           }
        }
    }

}
</pre>
</div></div>
<p>For CXF 2.4 onwards, the callback handler supplies the password for all cases, and
the validation is done internally (but can be configured). See <a href="http://coheigea.blogspot.com/2011/02/usernametoken-processing-changes-in.html"
class="external-link" rel="nofollow">here</a> for more information.<br/>
On the Client side you'll want to configure the WSS4J outgoing properties:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
outProps.put(WSHandlerConstants.ACTION, WSHandlerConstants.USERNAME_TOKEN);
<span class="code-comment">// Specify our username
</span>outProps.put(WSHandlerConstants.USER, <span class="code-quote">"joe"</span>);
<span class="code-comment">// Password type : plain text
</span>outProps.put(WSHandlerConstants.PASSWORD_TYPE, WSConstants.PW_TEXT);
<span class="code-comment">// <span class="code-keyword">for</span> hashed
password use:
</span><span class="code-comment">//properties.put(WSHandlerConstants.PASSWORD_TYPE,
WSConstants.PW_DIGEST);
</span><span class="code-comment">// Callback used to retrieve password <span
class="code-keyword">for</span> given user.
</span>outProps.put(WSHandlerConstants.PW_CALLBACK_CLASS, 
    ClientPasswordHandler.class.getName());
</pre>
</div></div>
<p>Once again we're using a password callback, except this time instead of specifying
our password on the server side, we're specifying the password we want sent with the message.
This is so we don't have to store our password in our configuration file.</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
<span class="code-keyword">import</span> java.io.IOException;
<span class="code-keyword">import</span> javax.security.auth.callback.Callback;
<span class="code-keyword">import</span> javax.security.auth.callback.CallbackHandler;
<span class="code-keyword">import</span> javax.security.auth.callback.UnsupportedCallbackException;
<span class="code-keyword">import</span> org.apache.ws.security.WSPasswordCallback;

<span class="code-keyword">public</span> class ClientPasswordCallback <span
class="code-keyword">implements</span> CallbackHandler {

    <span class="code-keyword">public</span> void handle(Callback[] callbacks)
<span class="code-keyword">throws</span> IOException, 
        UnsupportedCallbackException {

        WSPasswordCallback pc = (WSPasswordCallback) callbacks[0];

        <span class="code-comment">// set the password <span class="code-keyword">for</span>
our message.
</span>        pc.setPassword(<span class="code-quote">"password"</span>);
    }

}
</pre>
</div></div>

<p>In the case of multiple users with different passwords, use the  <a href="http://ws.apache.org/wss4j/apidocs/org/apache/ws/security/WSPasswordCallback.html"
class="external-link" rel="nofollow">WSPasswordCallback</a>'s getIdentifier() method
to obtain the username of the current SOAP request.</p>

<p><a href="http://depressedprogrammer.wordpress.com/2007/07/31/cxf-ws-security-using-jsr-181-interceptor-annotations-xfire-migration/"
class="external-link" rel="nofollow">Here is an example</a> of WS-Security implemented
using annotations for interceptors (uses UsernameToken).</p>

<h3><a name="WS-Security-WSSecurityUsernameTokenandCustomAuthentication"></a>WS-Security
UsernameToken and Custom Authentication</h3>

<p>If needed, one may want to configure a jaxws:endpoint with a "ws-security.validate.token"
property set to false and register a custom org.apache.cxf.interceptor.security.AbstractUsernameTokenInInterceptor
implementation for using a WSS4J UsernameToken wrapped in a CXF specific UsernameToken for
the custom authentication and Subject creation. The JAASLoginInterceptor will also recognize
a CXF UsernameToken and thus can be used instead of the custom org.apache.cxf.interceptor.security.AbstractUsernameTokenInterceptor.
 (Prior to CXF 2.4.0, use "ws-security.ut.no-callbacks" instead of "ws-security.validate.token"
with the value of true instead of false to  postpone the validation of the token.)</p>

<h2><a name="WS-Security-UsingX.509Certificates"></a>Using X.509 Certificates</h2>

<p>The X.509 Certificate Token Profile (<a href="http://www.oasis-open.org/committees/download.php/16785/wss-v1.1-spec-os-x509TokenProfile.pdf"
class="external-link" rel="nofollow">pdf</a>) provides another option for implementing
WS-Security.  For the Signature and Encryption actions, you'll need to create a public &amp;
private key for the entities involved.  You can generate a self-signed key pair for your development
environment via the following steps.  Keep in mind these will not be signed by an external
authority like Verisign, so are inappropriate for production use.</p>

<p>1. Creating private key with given alias and password like "myAlias"/"myAliasPassword"
in keystore (protected by password for<br/>
security reasons)</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
keytool -genkey -alias myAlias -keypass myAliasPassword -keystore \ 
  privatestore.jks -storepass keyStorePassword -dname <span class="code-quote">"cn=myAlias"</span>
-keyalg RSA
</pre>
</div></div>
<p>The alias is simply a way to identify the key pair. In this instance we are using
the RSA algorithm.</p>

<p>2. Self-sign our certificate (in production environment this will be done by a company
like Verisign).</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
keytool -selfcert -alias myAlias -keystore privatestore.jks \ 
    -storepass keyStorePassword -keypass myAliasPassword
</pre>
</div></div>
<p>3. Export the public key from our private keystore to file named key.rsa</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
keytool -export -alias myAlias -file key.rsa -keystore privatestore.jks \ 
    -storepass keyStorePassword
</pre>
</div></div>
<p>4. Import the public key to new keystore:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
keytool -<span class="code-keyword">import</span> -alias myAlias  -file key.rsa
-keystore publicstore.jks \ 
    -storepass keyStorePassword
</pre>
</div></div>
<p>So now we have two keystores containing our keys - a public one (publicstore.jks)
and a private one (privatestore.jks). Both of them have keystore password set to keyStorePass
(this not recommended for production but ok for development) and alias set to myAlias. The
file key.rsa can removed from filesystem, since it used only temporarily.  Storing keys in
keystores is strongly advised because a keystore is protected by a password.</p>

<p>A more detailed description of key generation can be found here:<br/>
<a href="http://java.sun.com/javase/6/docs/technotes/tools/solaris/keytool.html" class="external-link"
rel="nofollow">http://java.sun.com/javase/6/docs/technotes/tools/solaris/keytool.html</a></p>

<p>How to create a production certificate can be found here:<br/>
<a href="http://support.globalsign.net/en/objectsign/java.cfm" class="external-link" rel="nofollow">http://support.globalsign.net/en/objectsign/java.cfm</a></p>

<h3><a name="WS-Security-Signing"></a>Signing</h3>

<p>Signing a message is used to validate to the recipient that the message could only
have come from a certain sender, and that the message was not altered in transit.  It involves
the sender encrypting a digest (hash) of the message with its private key, and the recipient
unencrypting the hash with the sender's public key, and recalculating the digest of the message
to make sure the message was not altered in transit (i.e., that the digest values calculated
by both the sender and recipient are the same).  For this process to occur you must ensure
that the Client's public key has been imported into the server's keystore using keytool.</p>

<p>On the client side, our outgoing WS-Security properties will look like so (see <a
href="#WS-Security-addinterceptors">above</a> for code sample):</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
outProps.put(WSHandlerConstants.ACTION, <span class="code-quote">"Signature"</span>);
outProps.put(WSHandlerConstants.USER, <span class="code-quote">"myAlias"</span>);
outProps.put(WSHandlerConstants.PW_CALLBACK_CLASS, 
    ClientCallbackHandler.class.getName());
outProps.put(WSHandlerConstants.SIG_PROP_FILE, <span class="code-quote">"client_sign.properties"</span>);
</pre>
</div></div>

<p>The USER that is specified is the key alias for the client.  The password callback
class is responsible for providing that key's password.  </p>

<div class='panelMacro'><table class='tipMacro'><colgroup><col width='24'><col></colgroup><tr><td
valign='top'><img src="/confluence/images/icons/emoticons/check.gif" width="16" height="16"
align="absmiddle" alt="" border="0"></td><td><b>Tip</b><br />For
X.509 support you will normally have multiple actions, e.g. Encryption with Signature.  For
these cases, just space-separate the actions in the ACTION property as follows:
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
outProps.put(WSHandlerConstants.ACTION, 
    WSHandlerConstants.TIMESTAMP + <span class="code-quote">" "</span> + 
    WSHandlerConstants.SIGNATURE + <span class="code-quote">" "</span> + 
    WSHandlerConstants.ENCRYPT);
</pre>
</div></div>
<p>Alternatively, you may space-separate the string literals you see above in the Spring
configuration (e.g., "Signature Encrypt")</p></td></tr></table></div>

<p>Our client_sign.properties file contains several settings to configure WSS4J:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
org.apache.ws.security.crypto.provider=org.apache.ws.security.components.crypto.Merlin
org.apache.ws.security.crypto.merlin.keystore.type=jks
org.apache.ws.security.crypto.merlin.keystore.password=keyStorePassword
org.apache.ws.security.crypto.merlin.keystore.alias=myAlias
org.apache.ws.security.crypto.merlin.file=client_keystore.jks
</pre>
</div></div>
<p>On the server side, we need to configure our incoming WSS4J interceptor to verify
the signature using the Client's public key.</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
inProps.put(WSHandlerConstants.ACTION, <span class="code-quote">"Signature"</span>);
inProps.put(WSHandlerConstants.SIG_PROP_FILE, <span class="code-quote">"server.properties"</span>);
</pre>
</div></div>
<p>Our server_sign.properties file contains several settings to configure WSS4J:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
org.apache.ws.security.crypto.provider=org.apache.ws.security.components.crypto.Merlin
org.apache.ws.security.crypto.merlin.keystore.type=jks
org.apache.ws.security.crypto.merlin.keystore.password=amex123
org.apache.ws.security.crypto.merlin.file=server_keystore.jks
</pre>
</div></div>

<h3><a name="WS-Security-Encryption"></a>Encryption</h3>

<p>Encryption involves the sender encrypting the message with the recipient's public
key to ensure that only the recipient can read the message (only the recipient has its own
private key, necessary for decrypting the message.)  This requires the sender to have the
recipient's public key in its keystore.</p>

<p>The process for encrypting is very similar to and indeed usually combined with the
signature process above.  Our <a href="http://svn.apache.org/viewvc/cxf/trunk/systests/src/test/java/org/apache/cxf/systest/ws/security/"
class="external-link" rel="nofollow">WS-Security test sample</a> provides an example
of encrypting requests and responses, also check <a href="http://www.jroller.com/gmazza/entry/cxf_x509_profile"
class="external-link" rel="nofollow">this blog entry</a> for a more end-to-end example
showing signature and encryption of both SOAP requests and responses.</p>
    </div>
        <div id="commentsSection" class="wiki-content pageSection">
        <div style="float: right;">
            <a href="https://cwiki.apache.org/confluence/users/viewnotifications.action"
class="grey">Change Notification Preferences</a>
        </div>
        <a href="https://cwiki.apache.org/confluence/display/CXF20DOC/WS-Security">View
Online</a>
        |
        <a href="https://cwiki.apache.org/confluence/pages/diffpagesbyversion.action?pageId=49572&revisedVersion=52&originalVersion=51">View
Changes</a>
                |
        <a href="https://cwiki.apache.org/confluence/display/CXF20DOC/WS-Security?showComments=true&amp;showCommentArea=true#addcomment">Add
Comment</a>
            </div>
</div>
</div>
</div>
</div>
</body>
</html>

Mime
View raw message