Latest Activity

Describing JSON Services in WADL

Sergey Beryozkin - Sun, 10/02/2011 - 17:53
WADL can describe RESTful XML services really well, by having request and response representations linked to corresponding XML or Relax NG schema element declarations.
However, you've most likely seen the following fragments showing that both XML and JSON representations are supported:


<response>

<representation
mediaType="application/xml"
element="ns:Book""/>
<representation
mediaType="application/json"/>
</response>



The above fragment can describe a method like this one:


@GET
@Produces(
{"application/xml",
"application/json"})
public Book getBook() {...}



So given the WADL fragment above, the consumer can get an idea of how an XML response will look like, and thus how to consume and possibly validate it. The description of the JSON response representation gives no information at all.

That is not fair I can hear you, JSON fans, saying :-). Or perhaps I can hear people saying WADL is not good enough for describing JSON services. But CXF makes things possible :-), and hopefully the following two recent updates can help:

1. Setting a linkJsonToXmlSchema property on CXF WADLGenerator will result in a fragment like this one be created:



<response>

<representation
mediaType="application/xml"
element="ns:Book""/>
<representation
mediaType="application/json"/>
element="ns:Book""/>
</response>



Well, describing JSON representation with XML schema is not technically correct, but more often than not an XML schema element instance will give a pretty good idea how a JSON will look like, for example, a Book bean can be used to generate both XML and JSON sequences by the providers in charge.

2. Setting HTTP Accept header to application/json when requesting WADL will result in a WADL JSON representation returned. For example, given


?_wadl&_type=json


will return a JSON-format WADL instance. Is that really cool ? You bet it is. What about WADL grammar referencing XML schemas, does it really make sense to JSON-format XML schemas ? No it does not, but we have a JSON schema initiative so what you need to do is just configure WADLGenerator to reference a schema like the one describing Products in this section and here you go. For example:


WADLGenerator wg = new WADLGenerator();
wg.setSchemaLocations(
Collections.singletonList("json.schema"));
// do not create JAXB context
wg.setUseJaxbContextForQnames(false);
// let JSON provider handle it
wg.setIgnoreMessageWriters(false);


The provider can have the above properties set from Spring if needed.
The reference to the json.schema will be replaced with an absolute URI so the consumer handling a WADL JSON representation will be able to GET the referenced schema in the follow-up request.

For the above approach to become of some practical use, the tooling support is important. Consider opening a JIRA in the SoapUI project, vote for it and see what happens :-).

Enjoy !
Categories: Sergey Beryozkin

This Week's Links (2 October 2011)

Glen Mazza - Sun, 10/02/2011 - 13:00

Web service related links of interest this week:

Karaf Links:

Categories:

Apache Maven Wagon 2.0 released

Olivier Lamy - Thu, 09/29/2011 - 21:57
Apache Maven Wagon 2.0 has been released with some nice fixes/features.
See full changelog

The most important features are :
* using http(s) connection pooling: see my previous post.
* support of preemptive authentication: yes this will prevent your artifacts to be uploaded twice (as it was done until this release)

You can test that now. Download the shaded jar: wagon-http-2.0-shaded.jar and put it in your $M2_HOME/lib/ext (for maven 3+)

Note this version will part of Apache Maven official distribution in the next 3.0.4 release.

Have Fun !
--
Olivier

Apache Maven, Maven, Apache are trademarks of The Apache Software Foundation.


Categories: Olivier Lamy

Adding X.509 security headers to Apache CXF SOAP calls (WS-SecurityPolicy method)

Glen Mazza - Tue, 09/27/2011 - 13:00

This blog entry shows the modifications needed for the WSS4J interceptor-based CXF X509 token profile tutorial to use WS-SecurityPolicy instead. This method, as earlier shown for Metro and for CXF with the UsernameToken profile, is for when you wish to declare security requirements as WS-Policy elements within the WSDL instead of explicitly configuring interceptors.

The finished source code for this version (minus the keystores, which can be quickly created as shown in the original tutorial) is available here.

Just the following changes are needed from the original tutorial:

  • For Step #1, also add the cxf-rt-ws-policy dependency listed in Step #2 of the CXF/UsernameToken tutorial.

  • For Step #3, Substep #1, instead of having a client-context.xml file, use the following cxf.xml configuration file (important: note the filename change!), and place it in the same resources directory. Among other changes, this new file omits the explicit WSS4J interceptor declarations from the original version.

    <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jaxws="http://cxf.apache.org/jaxws" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd"> <jaxws:client name="{http://www.example.org/contract/DoubleIt}DoubleItPort" createdFromAPI="true"> <jaxws:properties> <entry key="ws-security.callback-handler" value="client.ClientKeystorePasswordCallback"/> <entry key="ws-security.encryption.properties" value="clientKeystore.properties"/> <entry key="ws-security.signature.properties" value="clientKeystore.properties"/> <entry key="ws-security.encryption.username" value="myservicekey"/> </jaxws:properties> </jaxws:client> </beans>

    Skip substep #3--the WSClient.java file from the original DoubleIt tutorial should be used. (However, you may wish to add the logging interceptors as given in this substep to see the SOAP requests and responses at the console window.)

  • For the service provider configuration in Step #4, replace the DoubleIt.wsdl in the service project with the WS-Policy-enhanced WSDL found in Step #2 of the Metro/X509 tutorial (give it the same name). After so doing, remove its <sc:keystore/> and <sc:truststore/> elements as those are Metro-specific.

    Next, in the war subproject's web.xml file's contextConfigLocation parameter, add the two additional modules shown in Step #5 of the CXF/UsernameToken tutorial.

    Finally, use the below cxf-servlet.xml file instead of the one given in the original tutorial. It removes the service-side WSS4J interceptor declarations while retaining keystore/truststore configuration information.

    <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jaxws="http://cxf.apache.org/jaxws" xmlns:soap="http://cxf.apache.org/bindings/soap" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd"> <bean id="myPasswordCallback" class="service.ServiceKeystorePasswordCallback" /> <jaxws:endpoint id="doubleit" implementor="service.DoubleItPortTypeImpl" address="/doubleit" wsdlLocation="WEB-INF/wsdl/DoubleIt.wsdl"> <jaxws:properties> <entry key="ws-security.callback-handler"> <ref bean="myPasswordCallback"/> </entry> <entry key="ws-security.encryption.properties" value="serviceKeystore.properties"/> <entry key="ws-security.signature.properties" value="serviceKeystore.properties"/> <entry key="ws-security.encryption.username" value="useReqSigCert"/> </jaxws:properties> </jaxws:endpoint> </beans>
Categories:

Enterprise level services coming to Apache CXF

Daniel Kulp - Mon, 09/26/2011 - 23:07
This past week, there was a discussion on the Apache CXF developer list about adding an enterprise grade Security Token Service (STS) into CXF. Talend has been developing an STS internally for some of our customers for a while now and we’re pretty excited to be able to contribute the results of that work back [...]
Categories: Daniel Kulp

Karaf Tutorial Part 3 - Improving configuration editing using the OSGI Metatype Service and the Felix Webconsole

Christian Schneider - Mon, 09/26/2011 - 18:47

Blog post added by Christian Schneider

In Karaf Tutorial Part 2 - Using the Configuration Admin Service we learned how to configure our bundles using simple configurations.

In this part we will learn how to use the Metatype Service and the Felix Webconsole to easily create and edit these configurations

Using the Webconsole to edit an untyped Configuration

So when we have the Karaf container from Part 2 running and the config present we can already use the Felix Webconsole to edit the configuration.

> features:install webconsole

Open your browser with http://localhost:8181/system/console/configMgr

You will see the list of configurations the config admin service knows about:

Untyped Configuration

So the first thing we want to see is the untyped configuration. To see this copy the ConfigApp.cfg file from the git sources to the etc dir of Karaf. It should now be listed in the above list. If you click edit you will see the following:


So you get a freeform text editor with the current config. You can edit and save the config.The config is changed in the config admin service and internally persisted but not written to the etc dir (in current Karaf version).

Now delete the file from etc again. The config will not be shown in the list anymore.

Typed configuration

Now we will take a look at typed configuration. The Felix Webconsole can create typed configurations and also show a nice Editor for them.

To enable this we need to create OSGi Metatype information in our bundle. To do this simply create a file in the directory OSGI-INF/metatype.

For our configapp example the following config will work:

<?xml version="1.0" encoding="UTF-8"?> <MetaData xmlns="http://www.osgi.org/xmlns/metadata/v1.0.0"      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"      xsi:schemaLocation="          http://www.osgi.org/xmlns/metadata/v1.0.0 http://www.osgi.org/xmlns/metatype/v1.1.0/metatype.xsd      ">      <OCD description="Configured Example Application" name="ConfigApp" id="ConfigApp">          <AD name="Title" id="title" required="true" type="String" default="Default Title" description="Title for the Application"/>      </OCD>      <Designate pid="ConfigApp">          <Object ocdref="ConfigApp"/>      </Designate> </MetaData>

So this is just an xml file with the MetaType Namespace. The object class definition (OCD) Element represents a configuration.

Attribute
Description
id
Id to reference in the designate element
name
User friendly name for editors
description
Longer description for editors

The  attribute definition (AD) represents an attribute.

Attribute
Description
id
ID for programmatic retrieval of this attribute
name
User friendly name to show in editors
description
Longer description for editors
required
(true|no) Determines if this attribute has to be filled
type
(String | Long | Double | Float | Integer | Byte |Char |Boolean | Short)
default
Default value if the attribute is not yet present

You can also define the values to choose from.

See http://dz.prosyst.com/pdoc/mbs_prof_6.1/um/framework/bundles/osgi/metatype/osgi.html for more information about the OSGi MetaType Service.

The last thing to define is the Designate element which maps the object class defintion to a config admin pid.

Test the Typed Config

Now build the configapp project using mvn install and copy the configapp.jar to the deploy directory of Karaf. The Webconsole should now show the ConfigApp Element in the configurations tab even if no such config exists.

You can then click edit and should see the following screen:


So we get a nice form to edit our configuration and also get default values if we create a new config. A click on Save will create or update this config in the config admin service and out bundle will reflect the change.

To see a larger example you can edit the configuration of the felix fileinstall bundle which will show the following screen:

Summary

So we have learned how to edit typed and untyped configuration with the Felix Webconsole and how to define configuration metadata.

View Online | Add Comment
Categories: Christian Schneider

Karaf Tutorial Part 2 - Using the Configuration Admin Service

Christian Schneider - Sat, 09/24/2011 - 09:09

Blog post edited by Christian Schneider

In the first part of the Karaf Tutorial we learned how to use maven and blueprint to offer and use pojo services and how to use the http service to publish a servlet.

In this second part we concentrate on configuration for our OSGi bundles. Unlike servlet containers OSGi contains a very good specification for configuration: The Config Admin Service from the OSGi enterprise spec. In this tutorial we will cover ussing the Config Admin Service with pure OSGi and blueprint and how to automatically deploy config files with your bundles.

The practical parts of this tutorial can be found on github in https://github.com/cschneider/Karaf-Tutorial/tree/master/configadmin

The Configuration Admin Service spec

We will first get a fast overview of the Configuration Admin Service spec. There two main interfaces for us to use:

  • ConfigurationAdmin - Allows to retrieve and change configurations. This service is offered by the Config Admin Service implementation
  • ManagedService - Allows to react on configuration changes. You have to implement this and register it as a service to get notified

So basically a configuration in the Config Admin Service is a Dictionary that contains attributes and their values. The Dictionary is identified by a persistent identifier (pid). This is simply a String that should uniquely identify the configuration.

How to work with configuration?

While you can retrieve a configuration using the ConfigurationAdmin.getConfiguration interface I would not recommend to do so. OSGi is very dynamic so it may happen that your bundle starts before the config admin service or that the config admin service did not yet read the configuration. So you may end up sometimes getting Null for the configuration.

So the recommended way is to use a ManagedService and react on updates. If your bundle can not start without config then it is a good idea to create the pojo class to be configured on the first update received.

Introducing our very simple class to be configured

As we want to implement a clean style of how to work with configuration the class to be configured should be a pure pojo. While it is of course possible to simply implement the ManagedService interface and work with the Dictionary directly this will make you depend on OSGi and the current Config Admin Service spec. So instead we use a simple bean class that has a title property. Additionally I added a refresh method that should be called after all configuration was changed.

public class MyApp { String title; public void setTitle(String title) { this.title = title; } public void refresh() { System.out.println("Configuration updated (title=" + title + ")"); } }

So our goal is to configure the title when the configuration changes and then call refresh. We will do this in pure OSGi and in blueprint.

Get some practice. Working with configs using pure OSGi interfaces

The first practical part in this tutorial shows how to use the config admin service using just OSGi interfaces. While this is probably not the way you will do it later it helps to understand what happens under the hood.

You can find the implementation in the subdirectory configapp (https://github.com/cschneider/Karaf-Tutorial/tree/master/configadmin/configapp)

So we first need a pom file for the maven build. You best start with the pom from the configapp example.
If you start fresh you will have to use the maven-bundle-plugin to make your project a OSGi bundle and you need to add two dependencies:

<dependency> <groupId>org.osgi</groupId> <artifactId>org.osgi.compendium</artifactId> <version>4.2.0</version> </dependency> <dependency> <groupId>org.osgi</groupId> <artifactId>org.osgi.core</artifactId> <version>4.2.0</version> </dependency>

The first is for the config admin service interfaces and the second is to be able to create the Activator and contains the basic OSGi interfaces.

Now we will care about updating the MyApp class. The following little class does the trick. We implement the ManagedService interface to talk to the Config Admin Service. So we get called whenever the config changes. The first thing is to check for null as this can happen when the config is removed. We could a this point stop our MyApp but to keep it simple we just ignore those. The next step is to create the MyApp class. Normally you would do this in the Activator but then you would have to be able to work with an empty configuration which is not always desired. The last part is to simply call the setter with the value from the config and call refresh after all settings were made.

private final class ConfigUpdater implements ManagedService { public void updated(Dictionary config) throws ConfigurationException { if (config == null) { return; } if (app == null) { app = new MyApp(); } app.setTitle((String)config.get("title")); app.refresh(); } }

Of course this does not yet do anything. The last step is to register the ConfigUpdater in the Activator.start. We simply use registerService like for every other service. The only special thing is that you have to set the property SERVICE_PID to your config pid so the Config Admin Service knows what config you want to watch.

Hashtable<String, Object> properties = new Hashtable<String, Object>(); properties.put(Constants.SERVICE_PID, CONFIG_PID); serviceReg = context.registerService(ManagedService.class.getName(), new ConfigUpdater() , properties); Making this simple example run
  • build the project with mvn install.
  • Start a fresh Karaf instance
  • Copy the configapp.jar bundle from the target dir to the Karaf deploy dir

Now we notice that nothing seems to happen. Calling list in the Karaf console you should be able to see that the bundle is indeed started but it will not do create any output as there is no config.
We still need to create the config file and set the title.

  • copy the existing file /configadmin-features/src/main/resources/ConfigApp.cfg to the /etc dir of the Karaf instance

The important part here is that the filename has to be <pid>.cfg. So the config admin service will find it.

Now the fileinstall bundle will detect the new file in etc. As the ending is .cfg it will consider it to be a config admin resource and create or update the Config Admin Service configuration with the pid determined from the file name.

So you should now see the following in the Karaf console. This shows that the configuration change was correctly detected and forwarded. If you now change the file using an editor and save the change will alsobe propagated.

Configuration updated (title=" + title + ") Digging into the config with the Karaf config commands

Type the following in the Karaf console:

> config:list Pid: ConfigApp BundleLocation: file:/C:/java/apache-karaf-2.2.3/deploy/configapp.jar Properties: service.pid = ConfigApp felix.fileinstall.filename = file:/C:/java/apache-karaf-2.2.3/etc/ConfigApp.cfg title = my Title

Among other configs you should find the above config "ConfigApp". The config shows where it has been loaded from, the pid and of course all properties we set in the file.

We can also change the config:

> config:edit ConfigApp > config:propset title "A better title" > config:proplist service.pid = ConfigApp felix.fileinstall.filename = file:/C:/java/apache-karaf-2.2.3/etc/ConfigApp.cfg title = A better title > config:update Configuration updated (title=A better title)

We see that the change is directly propagated to our bundle. If you look into the config file in etc you can see that the change is also persisted to the file. So the change will still be there if we restart Karaf.

Configuration with Blueprint

After we have worked with the Config Admin Service in pure OSGi we will now look how the same can be achieved in Blueprint. Fortunately this is quite easy as Blueprint does most of the work for us.

We simply define a cm:property-placeholder element. This works similar to property place holder with files but works with the Config Admin Service. We need to supply the config PID and the update strategy.
As strategy we select "reload". This means that after a change the blueprint context is reloaded to reflect the changes. We also set default properties that will be used when the config PID is not found or an attribute is not present.

The integration with our bean class is mostly a simple bean definition where we define the title property and assign the placeholder which will be resolved using the config admin service. The only special thing is the init-method. This is used to give us the chance to react after all changes were made like in the pure OSGi example.

For bluenprint we do not need any maven dependencies as our Java Code is a pure Java bean. The blueprint context is simply activated by putting it in the OSGI-INF/blueprint directory and by having the blueprint extender loaded. As blueprint is always loaded in Karaf we do not need anything else.

<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0" xmlns:cm="http://aries.apache.org/blueprint/xmlns/blueprint-cm/v1.1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" [http://www.osgi.org/xmlns/blueprint/v1.0.0] [http://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd] [http://aries.apache.org/blueprint/xmlns/blueprint-cm/v1.1.0] [http://svn.apache.org/repos/asf/aries/trunk/blueprint/blueprint-cm/src/main/resources/org/apache/aries/blueprint/compendium/cm/blueprint-cm-1.1.0.xsd] "> <cm:property-placeholder persistent-id="ConfigApp" update-strategy="reload" > <cm:default-properties> <cm:property name="title" value="Default Title"/> </cm:default-properties> </cm:property-placeholder> <bean id="myApp" init-method="refresh"> <property name="title" value="$\{title\}"></property> </bean> </blueprint>

In the above xml please remove the backslashes around title. This is just to avoid confluence interpreting it as a wiki macro.

Deploying config files

After we have successfully used the Config Admin Service the only thing that remains to go into production is to deploy our bundle together with a default configuration. This can be done using a Karaf feature file. We define our feature with the bundles it needs and simply add a configfile element. This makes Karaf deploy the given file into the etc directory of our Karaf installation. If the file is already present then it will not be overwritten.

<feature name="tutorial-configadmin" version="${pom.version}"> <bundle>mvn:net.lr.tutorial.configadmin/configapp/${pom.version}</bundle> <bundle>mvn:net.lr.tutorial.configadmin/configapp-blueprint/${pom.version}</bundle> <configfile finalname="/etc/ConfigApp.cfg">mvn:net.lr.tutorial.configadmin/configadmin-features/${pom.version}/cfg</configfile> </feature>

So one last question is how to deploy the config to maven for the configfile element to find it. This happens like for the feature with the build-helper-maven-plugin in Karaf See the pom file for details how to use it.

Summing it up and a look into the future

During this tutorial we have learned how the Config Admin Service works and how to use it with pure OSGi and blueprint. We have also seen how to build and deploy our projects together with documentation.

While this is already very usefull some small things are missing in my opinion. The first thing is that configfile does not really seem to be consistent with the config admin service. In fact Karaf does not use the config admin service to deploy the file. So what I would like to see is that the also existing config element not only writes the config to the config admin service but also persists it. Fortunately my colleague Jean Baptiste is already working on this. See https://issues.apache.org/jira/browse/KARAF-888

The other thing is that for enterprise environments a config admin service with some additional features is needed. One thing is that it should be possible to do configuration on a whole network of servers with a central source for configuration and a nice UI. The other thing is that you would like to not only deploy the default config but also the config the admin really wants for the system. So I  imagine that you should be able to define a deployment plan with bundles and features to install but also with the required configuration changes. If this is done right it will allow good audits of deployment and config changes and will also allow an admin to roll back a change in case something goes wrong. I hope we can provide some of this in one of the next Talend ESB EE releases.

View Online | Add Comment
Categories: Christian Schneider

Talend donates Security Token Service (STS) to Apache CXF

Colm O hEigeartaigh - Fri, 09/23/2011 - 16:31
I am pleased to announce that Talend has donated a Security Token Service (STS) implementation to Apache CXF, which will be part of the forthcoming 2.5 release. Since the 2.4.0 release, CXF ships with an STS framework (in the ws-security module), as well as a simple implementation of the framework in the examples. The STS that Talend has donated to the community is a sophisticated implementation of the STS framework that builds on top of CXF's existing mature security functionality.

In future blog posts I will document the features of the STS and how to configure it, as well as walk through some system tests. Here are some of the features and standards that the new STS supports:
  • WS-Trust 1.3/1.4
  • WS-SecurityPolicy1.3
  • Authentication Mechanisms for a RST:UsernameToken, SAML token (1.1/2.0), KerberosToken, X.509 Token.
  • Security Binding supported: Symmetric,Asymmetric, Transport 
  • Supports WS-Trust Issue/Validate and Cancel binding 
  • Can issue the following tokens:SAML 1.1/2.0Holder-Of-Key/Bearer, SecurityContextTokens, Custom Tokens.
  • Issued token can be encrypted 
  • Validate binding supports issuing a new token (token transformation).
  • Custom Validators can be implemented 
  • Creation of SAML tokens can be customized.
  • Advanced RST elements:KeyType (Public, Symmetric, Bearer), Entropy (Symmetric, Public) , OnBehalfOf, ActAs, Claims, SecondaryParameters
  • Pluggable claims handling and management
Categories: Colm O hEigeartaigh

The Case for Patch Releases

Hadrian Zbarcea - Wed, 09/21/2011 - 20:12
A new patch release of Apache Camel, version 2.8.1 was released last week. I didn't announce releases in a while. Why write about camel-2.8.1 then?

The reason is that the Apache Camel community didn't produce patch releases in the past (we only did it for the 1.6.x version before discontinuing support for the 1.x versions). We actually started producing patch releases back in April for camel-2.7.x. At the time, I wasn't sure if and how this will continue because you need enough support within the community and some had the view that at Apache we should only focus on innovation.

The untold truth about that though has to do with the business models of open source. ZDNet had an excellent article a while ago, which makes for interesting reading. The author left out another business model, let's name it FUD ware, that relies on bundling known, successful open source projects and claim that only your distribution is production ready and offers what the market needs. That works better if you have some influence over the community that produces the original open source project. It is not enough, that's for sure, but combined with other business models (such as 1. Support Ware or 4. Project Ware) it may make the needed difference.

A few of us however, want the original ASF distribution to be stable, secure and production ready. After a bit of a struggle I am happy we managed to get the Apache Camel community used to the idea of producing patch releases more frequently. Between Dan Kulp and myself we issued since mid April three patch releases on camel-2.7.x, camel-2.8.1 last week and camel-2.8.2 is only a few weeks away.

This way you, our users, won't have to wait at least a quarter to have your issues resolved. At the end of the day, you the users, are the Apache Camel community.
Categories: Hadrian Zbarcea

Adding X.509 security headers to Apache CXF SOAP calls

Glen Mazza - Tue, 09/20/2011 - 13:00

This tutorial shows how to modify the CXF version of the WSDL-first DoubleIt Example to include WS-Security (WSS) with X.509 public key certificates. As with UsernameToken headers, CXF provides two options for adding certificate-based security: standard WSS4J interceptors and WS-SecurityPolicy. The former will be covered below--see this entry for the modifications needed for the latter. Note, as a necessary disclaimer given the nature of this blog entry, the information below may have errors within it--make sure production work is carefully checked by experienced security engineers.

The source code for this tutorial (minus the keystores, which can be quickly created in Step #2 below) is available here.

Steps involved for enhancing Double-It with certificate-based security:

  1. Add CXF's WS-Security dependency to the project parent POM. This is the same as Step #2 of the CXF UsernameToken tutorial.

  2. Create key pairs for the client and the web service provider. We'll be creating three key pairs here using Java keytool--for the SOAP service provider and two independent clients to show how the web service handles security with multiple clients. From the DoubleIt project folder, run the following commands to create these keys: keytool -genkey -alias myservicekey -keyalg RSA -sigalg SHA1withRSA -keypass skpass -storepass sspass -keystore serviceKeystore.jks -dname "cn=localhost" keytool -genkey -alias myclientkey -keyalg RSA -sigalg SHA1withRSA -keypass ckpass -storepass cspass -keystore clientKeystore.jks -dname "cn=clientuser" keytool -genkey -alias myclient2key -keyalg RSA -sigalg SHA1withRSA -keypass ck2pass -storepass cs2pass -keystore client2Keystore.jks -dname "cn=client2user"

    Note these keys are self-signed so should not be used in actual production, and of course the passwords given here should be different in your production work. Also I've found the case sensitivity of key aliases to vary depending on the tool generating and/or processing them; for that reason I'm keeping the aliases all lowercase here.

    Next, we'll be setting up two-way trust between the SOAP client and web service provider, which involves each one's public key being loaded into the keystore of the other. The following commands will accomplish this: keytool -export -rfc -keystore clientKeystore.jks -storepass cspass -alias myclientkey -file MyClient.cer keytool -export -rfc -keystore client2Keystore.jks -storepass cs2pass -alias myclient2key -file MyClient2.cer keytool -import -trustcacerts -keystore serviceKeystore.jks -storepass sspass -alias myclientkey -file MyClient.cer -noprompt keytool -import -trustcacerts -keystore serviceKeystore.jks -storepass sspass -alias myclient2key -file MyClient2.cer -noprompt keytool -export -rfc -keystore serviceKeystore.jks -storepass sspass -alias myservicekey -file MyService.cer keytool -import -trustcacerts -keystore clientKeystore.jks -storepass cspass -alias myservicekey -file MyService.cer -noprompt keytool -import -trustcacerts -keystore client2Keystore.jks -storepass cs2pass -alias myservicekey -file MyService.cer -noprompt

    Once done, delete the temporary .cer files created and place the serviceKeystore.jks file in service/src/main/resources and clientKeystore.jks and client2Keystore.jks in client/src/main/resources, creating either directory first if necessary.

    Note: For simplicity with the various operating and file systems available, this tutorial will be placing the serviceKeystore.jks file inside the deployable WAR. For production use, however, you will probably want to place this file into some specific directory outside of your Maven project and provide the full path to this file in the serviceKeystore.properties file discussed below.

  3. Configure the SOAP client to encrypt and sign the SOAP request, and decrypt and verify the signature of the SOAP response. We'll need to configure a WSS4JInInterceptor and a WSS4JOutInterceptor to perform these tasks, which we will do through Spring configuration. We will also need to create a WSS4J properties file and a password callback handler for the client's private key. The client Java source file created in Step #9 of the WSDL-first tutorial will also need to be modified to accommodate the Spring configuration. Steps:

    1. Create the following client-context.xml file and place it in the client/src/main/resources folder.

      <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jaxws="http://cxf.apache.org/jaxws" xmlns:http="http://cxf.apache.org/transports/http/configuration" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd"> <bean id="client" class="org.example.contract.doubleit.DoubleItPortType" factory-bean="clientFactory" factory-method="create"/> <bean id="clientFactory" class="org.apache.cxf.jaxws.JaxWsProxyFactoryBean"> <property name="serviceClass" value="org.example.contract.doubleit.DoubleItPortType"/> <property name="address" value="http://localhost:8080/doubleit/services/doubleit"/> <property name="inInterceptors"> <list> <ref bean="TimestampSignEncrypt_Response"/> </list> </property> <property name="outInterceptors"> <list> <ref bean="TimestampSignEncrypt_Request"/> </list> </property> </bean> <!-- This bean is an Out interceptor which will add a timestamp, sign the timestamp and body, and then encrypt the timestamp and body. It uses 3DES as the symmetric key algorithm. --> <bean class="org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor" id="TimestampSignEncrypt_Request"> <constructor-arg> <map> <entry key="action" value="Timestamp Signature Encrypt"/> <entry key="user" value="myclientkey"/> <entry key="signaturePropFile" value="clientKeystore.properties"/> <entry key="encryptionPropFile" value="clientKeystore.properties"/> <entry key="encryptionUser" value="myservicekey"/> <entry key="passwordCallbackClass" value="client.ClientKeystorePasswordCallback"/> <entry key="signatureParts" value="{Element}{http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd}Timestamp;{Element}{http://schemas.xmlsoap.org/soap/envelope/}Body"/> <entry key="encryptionParts" value="{Element}{http://www.w3.org/2000/09/xmldsig#}Signature;{Content}{http://schemas.xmlsoap.org/soap/envelope/}Body"/> <entry key="encryptionSymAlgorithm" value="http://www.w3.org/2001/04/xmlenc#tripledes-cbc"/> </map> </constructor-arg> </bean> <!-- This bean is an In interceptor which will validate a signed, encrypted response, and timestamp it. --> <bean class="org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor" id="TimestampSignEncrypt_Response"> <constructor-arg> <map> <entry key="action" value="Timestamp Signature Encrypt"/> <entry key="signaturePropFile" value="clientKeystore.properties"/> <entry key="decryptionPropFile" value="clientKeystore.properties"/> <entry key="passwordCallbackClass" value="client.ClientKeystorePasswordCallback"/> </map> </constructor-arg> </bean> </beans>

      Many of the values chosen here and in the service config below mirror the test values given in a CXF test case. See the CXF documentation for more configuration information.

    2. Create the WSS4J properties file for the client's combination keystore/truststore and place it in the same folder:

      clientKeystore.properties:

      org.apache.ws.security.crypto.merlin.keystore.file=clientKeystore.jks org.apache.ws.security.crypto.merlin.keystore.password=cspass org.apache.ws.security.crypto.merlin.keystore.type=jks org.apache.ws.security.crypto.merlin.keystore.alias=myclientkey
    3. Replace the WSClient.java file to accommodate Spring configuration:

      package client; import org.example.contract.doubleit.DoubleItPortType; import org.springframework.beans.factory.xml.XmlBeanFactory; import org.springframework.core.io.ClassPathResource; import org.apache.cxf.endpoint.Client; import org.apache.cxf.frontend.ClientProxy; import org.apache.cxf.interceptor.LoggingInInterceptor; import org.apache.cxf.interceptor.LoggingOutInterceptor; public class WSClient { public static void main(String[] args) { XmlBeanFactory factory = new XmlBeanFactory( new ClassPathResource("client-context.xml")); DoubleItPortType port = (DoubleItPortType) factory.getBean("client"); // next three lines optional, they output the SOAP request/response XML Client client = ClientProxy.getClient(port); client.getInInterceptors().add(new LoggingInInterceptor()); client.getOutInterceptors().add(new LoggingOutInterceptor()); doubleIt(port, 10); } public static void doubleIt(DoubleItPortType port, int numToDouble) { int resp = port.doubleIt(numToDouble); System.out.println("The number " + numToDouble + " doubled is " + resp); } }
    4. Add the keystore callback handler in order to obtain the key password for the private key. Place the following ClientKeystorePasswordCallback.java file into the same package as the client's WSClient class:

      package client; import java.io.IOException; import java.util.HashMap; import java.util.Map; import javax.security.auth.callback.Callback; import javax.security.auth.callback.CallbackHandler; import javax.security.auth.callback.UnsupportedCallbackException; import org.apache.ws.security.WSPasswordCallback; public class ClientKeystorePasswordCallback implements CallbackHandler { private Map<String, String> passwords = new HashMap<String, String>(); public ClientKeystorePasswordCallback() { passwords.put("myclientkey", "ckpass"); } public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException { for (int i = 0; i < callbacks.length; i++) { WSPasswordCallback pc = (WSPasswordCallback)callbacks[i]; String pass = passwords.get(pc.getIdentifier()); if (pass != null) { pc.setPassword(pass); return; } } } }
  4. Configure the server to decrypt and verify the signature of the SOAP request, and encrypt and sign the SOAP response. For this process we'll need to modify the WEB-INF/cxf-servlet.xml from Step #6 of the WSDL-first tutorial to bring in the WSS4J interceptors. Replace that file with the following:

    <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:cxf="http://cxf.apache.org/core" xmlns:jaxws="http://cxf.apache.org/jaxws" xmlns:test="http://apache.org/hello_world_soap_http" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://cxf.apache.org/core http://cxf.apache.org/schemas/core.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd"> <!-- TimestampSignEncryptEndpoint endpoint definition This endpoint is configured to work with public key certificates on both client and service side. --> <jaxws:endpoint id="doubleit" implementor="service.DoubleItPortTypeImpl" address="/doubleit" wsdlLocation="WEB-INF/wsdl/DoubleIt.wsdl"> <jaxws:outInterceptors> <ref bean="TimestampSignEncrypt_Response"/> </jaxws:outInterceptors> <jaxws:inInterceptors> <ref bean="TimestampSignEncrypt_Request"/> </jaxws:inInterceptors> </jaxws:endpoint> <!-- WSS4JInInterceptor for decrypting and validating the signature of the SOAP request. --> <bean id="TimestampSignEncrypt_Request" class="org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor" > <constructor-arg> <map> <entry key="action" value="Timestamp Signature Encrypt"/> <entry key="signaturePropFile" value="serviceKeystore.properties"/> <entry key="decryptionPropFile" value="serviceKeystore.properties"/> <entry key="passwordCallbackClass" value="service.ServiceKeystorePasswordCallback"/> </map> </constructor-arg> </bean> <!-- WSS4JOutInterceptor for encoding and signing the SOAP response. --> <bean id="TimestampSignEncrypt_Response" class="org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor" > <constructor-arg> <map> <entry key="action" value="Timestamp Signature Encrypt"/> <entry key="user" value="myservicekey"/> <entry key="signaturePropFile" value="serviceKeystore.properties"/> <entry key="encryptionPropFile" value="serviceKeystore.properties"/> <entry key="encryptionUser" value="useReqSigCert"/> <entry key="passwordCallbackClass" value="service.ServiceKeystorePasswordCallback"/> <entry key="signatureParts" value="{Element}{http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd}Timestamp;{Element}{http://schemas.xmlsoap.org/soap/envelope/}Body"/> <entry key="encryptionParts" value="{Element}{http://www.w3.org/2000/09/xmldsig#}Signature;{Content}{http://schemas.xmlsoap.org/soap/envelope/}Body"/> <entry key="encryptionSymAlgorithm" value="http://www.w3.org/2001/04/xmlenc#tripledes-cbc"/> </map> </constructor-arg> </bean> </beans>

    Of special note is the useReqSigCert value for the encryptionUser parameter in the WSS4JOutInterceptor above. When this value is used instead of a specific client key alias, it tells the service to use the same key that was used to sign the SOAP request. This allows the service to handle any client whose public key is in the service's truststore. (See this WSO2 article for more information on handling multiple clients.)

    Next, create the following WSS4J properties file for the service's keystore/truststore and place it in the service/src/main/resources folder:

    serviceKeystore.properties:

    org.apache.ws.security.crypto.merlin.keystore.file=serviceKeystore.jks org.apache.ws.security.crypto.merlin.keystore.password=sspass org.apache.ws.security.crypto.merlin.keystore.type=jks org.apache.ws.security.crypto.merlin.keystore.alias=myservicekey

    Finally, we'll need to add the service's keystore callback handler in order to obtain the key password for the private key. Place the following ServiceKeystorePasswordCallback.java file into the same package as the service's DoubleItPortTypeImpl class:

    package service; import java.io.IOException; import java.util.HashMap; import java.util.Map; import javax.security.auth.callback.Callback; import javax.security.auth.callback.CallbackHandler; import javax.security.auth.callback.UnsupportedCallbackException; import org.apache.ws.security.WSPasswordCallback; public class ServiceKeystorePasswordCallback implements CallbackHandler { private Map<String, String> passwords = new HashMap<String, String>(); public ServiceKeystorePasswordCallback() { passwords.put("myservicekey", "skpass"); } public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException { for (int i = 0; i < callbacks.length; i++) { WSPasswordCallback pc = (WSPasswordCallback)callbacks[i]; String pass = passwords.get(pc.getIdentifier()); if (pass != null) { pc.setPassword(pass); return; } } } }
  5. Test the client. After deploying the servlet as described in Step #8 of the WSDL-first tutorial, run the client as shown in Step #10 and make sure you see the same output. Next, you may wish to reconfigure the client to use the second client key to confirm that the web service provider is accepting both clients.

    Prior to optionally activating transport-layer encryption (next step), it would be wise to check the SOAP messages to make sure they are being properly signed and encrypted at the message level. The logging activated in the SOAP client above should accomplish that (using Wireshark is another option.) Here is the request and response I received for this SOAP call:

    INFO: Outbound Message --------------------------- ID: 1 Address: http://localhost:8080/doubleit/services/doubleit Encoding: UTF-8 Content-Type: text/xml Headers: {Accept=[*/*], SOAPAction=[""]} Payload: <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> <soap:Header> <wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" soap:mustUnderstand="1"> <xenc:EncryptedKey xmlns:xenc="http://www.w3.org/2001/04/xmlenc#" Id="EK-12747936E7F83C159813176421345694"> <xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-1_5" /> <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#"> <wsse:SecurityTokenReference> <ds:X509Data> <ds:X509IssuerSerial> <ds:X509IssuerName>CN=localhost </ds:X509IssuerName> <ds:X509SerialNumber>1317633571 </ds:X509SerialNumber> </ds:X509IssuerSerial> </ds:X509Data> </wsse:SecurityTokenReference> </ds:KeyInfo> <xenc:CipherData> <xenc:CipherValue>ZmdQmouQD3MmR8gTHaMDncmNXZ8S4pkl+qdDK7nqy2iBHpy/HTWdCMgRnolmAwlzT6hy9e4+BRCTbwZLHSvad39MtOk+O/HQFTLqGBrLl7ne0aUQG98WXV3n2iSTnp7L1MsherqDHK5FSgx7VpM70U2C+25ny+IU23mp5NRWat4= </xenc:CipherValue> </xenc:CipherData> <xenc:ReferenceList> <xenc:DataReference URI="#ED-4" /> <xenc:DataReference URI="#ED-5" /> </xenc:ReferenceList> </xenc:EncryptedKey> <xenc:EncryptedData xmlns:xenc="http://www.w3.org/2001/04/xmlenc#" Id="ED-4" Type="http://www.w3.org/2001/04/xmlenc#Element"> <xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#tripledes-cbc" /> <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#"> <wsse:SecurityTokenReference xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsse11="http://docs.oasis-open.org/wss/oasis-wss-wssecurity-secext-1.1.xsd" wsse11:TokenType="http://docs.oasis-open.org/wss/oasis-wss-soap-message-security-1.1#EncryptedKey"> <wsse:Reference URI="#EK-12747936E7F83C159813176421345694" /> </wsse:SecurityTokenReference> </ds:KeyInfo> <xenc:CipherData> <xenc:CipherValue>yYYbMK88LqUrx0FtoelxODzyom2qX4n5HD8d+ZvNMQmUhSOoVOULpKoU2nb5kiLKBwDeyJZSl1XroHZ94KBqqxHMddGUc79l3lf9GCMRyNZWpY9atd3YxBrw6pKmGwHIcaKZIBWNMoq9R6iyDqK0JBo835KgSFmu2WvLmhrXTVtvsS64gw2tukYdf+KSJW7Mr3f+Ujp9usH6Jeh4O7njtsDNm101c0B+M39xbo+WNJfKDMkpn2y/am23656KPF/5ZAxBQ+VNc1NoC1VvPd2Hk2l+7fQWse+1a7fA3Sim6ODZMTVOwBbgxU5Z3FQPZc/BldqX9G/TC1b/UHI9rVfcUMBJPQ6ptARwrelLvb79hyu9xSJ/sfby9R7QlT2hDPxz1Qw/H7wAWfvdjO3ztcsI2SwThrRLmf+D1hpwY04hns9ltcIv4YgeoXQZKzFZB07Km8FeQwD0yPXx2fY4+2oCpnx8DlL9PjHiA81Pukj6TBjSb+pQXthF9bw///kcC/jMxSPUfzrQYu6xyLwr7gTZ8mtFDt3PSaWPxgQBz503+/lcSVCwk63tg2RiWxbDCxYbbJHTES7Gnet29McMN4VGPdfZxA7UFFuUk+q/AGpyZ9zMFw1e/kcnROrgjnvKshVLFJ1T7s+7QSmtm17AmwBvwJVvrHbnoAmIc5lgfMzs5tP+Z+FTnktjzBmeDjRNtDXCs7knckWkiXg5bw0sl3U6+VPr+m3XOglpuFSlIijZoXCvOGnWNqj6DvavhM4JJq5dP6X7mLlZExz06ldWXfa3zOK9FUW3a5v2FeY8y9CJhG038QBObwRNBFyTn9vEhkTp3gALEbAopNuw/n5igsXQgVgWiFJVZ7yNzXUVtOa1ujcy9Rrnr/MXVms9XIoswBKftTTBvpFeieA8ol5NRUYWECVE289SLocC/DWKf2yLsB6GeUen4SNt9qv052BfKOCYMGFiWtnYrfPcmZmDAxdkiDYqDzRWtt0eBbkbB2qWiUDrdq38IPv9z4CasaTmH90FpOojCshdaDOKjEYfNfQboeJ6Z7n7P/g7qzBL0PSiTX/XRc/p+5hXNZj9+K/GDjuS26VC2L2ZYfgVxbR8H3Pnkqfcjh/QOG1YHgvTUw16bFRjK2stHjWcovAdhMO7KMlJM9ZcQO3tQEn7TCJMCsEV8ij0XUv7B7NR1JUZxbhPWzNh4EeQcBKFzdB2nRr4N0DP3yCMf+02u+kMBVjCzkeaa100c+B7PjAmS2Lp3HRNaDQp/71FdQocr+wySaj8VpD4XIrdA1OhSvW0g1Xi0zzgOUNpO4S/UtorI3bxmE2221AeqOJ79t7k0zOEvpRvdHdJKeg5zHmQ5LgPsWVmcOnzd2RuYCXOumpB5GtOJ8lptwaaUD9OfdD9YSt3R1BmXimRvNfyVvjbkgbGhDNwwE4I2rhY2/YBJV76Hidrip5fNEhu/1yX/QvLpxVirWn7YWKjlYqlfBo2tCGeH3JUHec++fJJwVJr7nB+eaLbQ0+QCl+1PTkz/7Q1ETNosnXc63BLn5SoAwRAuCOEhjfIvB2Lye3xLMFO1E/mGMie33EvfGRRQZ+n4GWpRJAf4W+deG9SA1+YmRW5p4C48ETL1bliMZy6EApuuIYACRiYW/XItXKLdxgC83Nukvz4rrEz4EwrqX1Z1Vn+m/xpH3RMzWOtC7jeywM0Isa7skzjXuZrlAdv1dnfjBj8h3sRPoBwnZXJ7ref8/Kx7PPSQEUOT1buSTc9Qdlt9hMVjgm+INcvc6YkWQ7YAJgcwciCo1AN6M0NMKAzbp7eitd5p7uaZbui+B3VwtH1798q7pVVBh9JZVGEQMQOX3YZvFo1ls/vTIdS8hiOKtg661y98P/1YECOPElyzPIL1lTC19nRBW1yKMN6UffAxj8nWxzoCv2SOxMH8HfAzE8N8ZdGx+neRCl3hRS5ODfqkWWsep/RF5tJEjVgHnpDqZZYtbppkpydHqCS70UxPK5KgpEV59t12+QrwGvv0pyR7EUvLDdvLbaoA2lSpTIBM6WQENA26Vnq46A6sVQ56h0RpFul0X0ckPNEqDCkGKsMK9Co0lJ+t2/XTESA6B2wjXtiNdXfnDhM0lDHrLqkIYIIN/BboCo4KXWTdwqBhFNSGoOJAthsUccK/pyByIcfPhxkFQMr4jTY83GhFq0vjMkzvM0Hv98yKSYM4kncNdM5kK5zTRQfUu7gUUVYdpkOpUDVhn7xBB9PuQr2gPFC0atbG+0teanmarEd88NlysVNOWoEeiUYwzTqwYV7kVuvN6+SIb1nIqpUYVVKQm2oo14EwbIn/2IjnyuMinkbsaEl2D+C1LLw69LHvVGhtMPVNiBMCVcINgr+9dA2ARariJgpl7WrkfRS9KBBAXgbkk10CJnUT8enoeaUbiB17MoATxUc3O3hzLiYGFwG4PNcW5OKC7JRiUiLAK75GIW9lH/dNsLZpHs6X9525BXALK23d+9+gMb1sePvvNSixeByU7FXK4bGD+l5X1Mfz4/EgNZrXOE9lEx+h8diNGi4DLUignh2xza7SPTO5fOKsvw/AISuJJG+rAm5FyqCDBy/hCKXhHcU/ZgVQS9qbYeLHs28P3ycf15786VzT70cTc/Ve9pcgHzha0rM01ndLozgIkcV89JI7CqMGevxJaejPVfvtil1rBGKR6n4oTMlP4/lza+TM9u3q409yhtAj5yUlSahjZAttYks7m0zKkXVPXE0o28HSevL1gA7W1/c/PygGZNazIRyVxYHh+mnhnLzHLTiK+wG </xenc:CipherValue> </xenc:CipherData> </xenc:EncryptedData> <wsu:Timestamp wsu:Id="TS-1"> <wsu:Created>2011-10-03T11:42:14.242Z</wsu:Created> <wsu:Expires>2011-10-03T11:47:14.242Z</wsu:Expires> </wsu:Timestamp> </wsse:Security> </soap:Header> <soap:Body xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="id-2"> <xenc:EncryptedData xmlns:xenc="http://www.w3.org/2001/04/xmlenc#" Id="ED-5" Type="http://www.w3.org/2001/04/xmlenc#Content"> <xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#tripledes-cbc" /> <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#"> <wsse:SecurityTokenReference xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsse11="http://docs.oasis-open.org/wss/oasis-wss-wssecurity-secext-1.1.xsd" wsse11:TokenType="http://docs.oasis-open.org/wss/oasis-wss-soap-message-security-1.1#EncryptedKey"> <wsse:Reference URI="#EK-12747936E7F83C159813176421345694" /> </wsse:SecurityTokenReference> </ds:KeyInfo> <xenc:CipherData> <xenc:CipherValue>9MmmHrmHXaCSocFyODDmjWF/HCZ4BnxI3bjg9D9uLArYNrGtNHHIgReTZmXNeXjy1gbXxc+mNdU8iAAdGZwyyONfFDYlWSXluuLj5PEsL4YdYDjnMpQ+cLhdmns+Ca8GEM1DFOHlg47BbcOyFoFp3dieL+fR+gm2su4x3gDerIA= </xenc:CipherValue> </xenc:CipherData> </xenc:EncryptedData> </soap:Body> </soap:Envelope> -------------------------------------- Oct 3, 2011 7:42:15 AM org.apache.cxf.interceptor.AbstractLoggingInterceptor log INFO: Inbound Message ---------------------------- ID: 1 Response-Code: 200 Encoding: UTF-8 Content-Type: text/xml;charset=UTF-8 Headers: {Content-Length=[6007], content-type=[text/xml;charset=UTF-8], Date=[Mon, 03 Oct 2011 11:42:15 GMT], Server=[Apache-Coyote/1.1]} Payload: <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> <soap:Header> <wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" soap:mustUnderstand="1"> <xenc:EncryptedKey xmlns:xenc="http://www.w3.org/2001/04/xmlenc#" Id="EK-E12633052A10C87D0213176421350534"> <xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-1_5" /> <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#"> <wsse:SecurityTokenReference> <ds:X509Data> <ds:X509IssuerSerial> <ds:X509IssuerName>CN=clientuser </ds:X509IssuerName> <ds:X509SerialNumber>1317633571 </ds:X509SerialNumber> </ds:X509IssuerSerial> </ds:X509Data> </wsse:SecurityTokenReference> </ds:KeyInfo> <xenc:CipherData> <xenc:CipherValue>elpcRq5Pj4ibg4/O8VdEvwDC5AJI55Kpsuq9KbEBmZpMscaOaKpAYTrAeBPJMKUUViqT/ZJLNSCOKsp1n2TH/Cmscv1YXk1GXKjDhI74My8x7dPNglQ8+Hz0UlzEs2JGVRiAXNqY/2HC2p5Ew3ehizlECBTda8Lu57NMn4Tegx0= </xenc:CipherValue> </xenc:CipherData> <xenc:ReferenceList> <xenc:DataReference URI="#ED-4" /> <xenc:DataReference URI="#ED-5" /> </xenc:ReferenceList> </xenc:EncryptedKey> <xenc:EncryptedData xmlns:xenc="http://www.w3.org/2001/04/xmlenc#" Id="ED-4" Type="http://www.w3.org/2001/04/xmlenc#Element"> <xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#tripledes-cbc" /> <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#"> <wsse:SecurityTokenReference xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsse11="http://docs.oasis-open.org/wss/oasis-wss-wssecurity-secext-1.1.xsd" wsse11:TokenType="http://docs.oasis-open.org/wss/oasis-wss-soap-message-security-1.1#EncryptedKey"> <wsse:Reference URI="#EK-E12633052A10C87D0213176421350534" /> </wsse:SecurityTokenReference> </ds:KeyInfo> <xenc:CipherData> <xenc:CipherValue>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 </xenc:CipherValue> </xenc:CipherData> </xenc:EncryptedData> <wsu:Timestamp wsu:Id="TS-1"> <wsu:Created>2011-10-03T11:42:15.035Z</wsu:Created> <wsu:Expires>2011-10-03T11:47:15.035Z</wsu:Expires> </wsu:Timestamp> </wsse:Security> </soap:Header> <soap:Body xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="id-2"> <xenc:EncryptedData xmlns:xenc="http://www.w3.org/2001/04/xmlenc#" Id="ED-5" Type="http://www.w3.org/2001/04/xmlenc#Content"> <xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#tripledes-cbc" /> <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#"> <wsse:SecurityTokenReference xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsse11="http://docs.oasis-open.org/wss/oasis-wss-wssecurity-secext-1.1.xsd" wsse11:TokenType="http://docs.oasis-open.org/wss/oasis-wss-soap-message-security-1.1#EncryptedKey"> <wsse:Reference URI="#EK-E12633052A10C87D0213176421350534" /> </wsse:SecurityTokenReference> </ds:KeyInfo> <xenc:CipherData> <xenc:CipherValue>+Yq+dU+lvWtmZyt0cvsh64jY+vuDzgEI/e8HiCj+c+OVF9cWtgDjwVmmWkyiaOpDZTnLET6hbUPUst3DRyxdbDxDV/n7KkobLeNFOgGNbsckDVeadDQJ6/vyc705WlHAFlwvIddGMwic0ExHL+CaFToIfIgF+NWlztu2EMEFDW4Woso2YSFsAn/SyaOzeNCq </xenc:CipherValue> </xenc:CipherData> </xenc:EncryptedData> </soap:Body> </soap:Envelope> -------------------------------------- The number 10 doubled is 20
  6. (Optional) Activate transport-layer (HTTPS/SSL) security for the web service provider. While message-layer encryption in theory should be sufficient, transport-layer encryption provides an additional layer of security that some projects may wish to consider. A rapid way to modify the above project to also use SSL would be as follows:

    1. In the SOAP client's client-context.xml (address property of the clientFactory bean) and the web service provider's DoubleIt.wsdl file (soap:address under wsdl:port), update the SOAP endpoint URL to https://localhost:8443/doubleit/services/doubleit.
    2. Make the same modification to the service provider's web.xml file listed in Step #1 of the Metro/UsernameToken tutorial.
    3. If necessary, create and configure the application server key as described in Steps #1 and #2 of the SSL tutorial.
    4. Redeploy the web service provider and make a SOAP client call. While the log output activated by the SOAP client above will still be readable, using Wireshark will confirm that transport-layer encryption has been activated (the entire SOAP envelope, including element tags, will be indeciperable.)

Notes:

  • To gain access to stronger encryption algorithms (256-bit encryption), download and install the Java Cryptography Extension's unlimited strength files.
  • For certain encryption and signature algorithms (besides those provided by the JDK and JCE), you may need to import the BouncyCastle encryption library. For either service or client, you can download the BouncyCastle jar and place it in your JRE's lib/ext folder, or this can be activated using the following dependency in the DoubleIt/pom.xml: <dependency> <groupId>bouncycastle</groupId> <artifactId>bcprov-jdk16</artifactId> <version>140</version> </dependency>
  • For other errors, make sure you check your Tomcat or other servlet container logs in addition to anything output on the console, frequently more helpful debugging information is available there.
Categories:

Specifying custom AlgorithmSuite policies in Apache CXF 2.4.3

Colm O hEigeartaigh - Mon, 09/19/2011 - 12:01
When specifying a security binding via WS-SecurityPolicy, it is possible to define the algorithm suite via the "sp:AlgorithmSuite" policy. WS-SecurityPolicy defines a number of standard AlgorithmSuite policies, which control various security properties like the maximum and minimum Symmetric and Asymmetric key lengths, the encryption/signature/digest algorithms to use, etc. An example policy is given below. For this policy, the minimum symmetric key length is 256 bits, and the encryption algorithm is AES256:

<sp:AlgorithmSuite>
    <wsp:Policy>
        <sp:Basic256 />
    </wsp:Policy>
</sp:AlgorithmSuite>

There are certain scenarios where a user might want to use a non-standard AlgorithmSuite. For example, the minimum Asymmetric Key Length for all standard AlgorithmSuites is 1024 bits. This requires that the JDK has unrestricted security policies installed. If it is not possible to install unresticted security policies, a user might decide that using 512 bits RSA keys is sufficient (this is not recommended).

Apache CXF 2.4.3 provides support for specifying custom algorithm suites. A new interface is defined to create an AlgorithmSuite object given a policy, with a default implementation that supports the standard AlgorithmSuite policies. It is possible to create a new implementation of the AlgorithmSuiteLoader interface, and install it as a bus extension. For an example, there is a CXF system test that allows 512 bit asymmetric keys, with custom AlgorithmSuiteLoader and AlgorithmSuite implementations. The custom AlgorithmSuiteLoader implementation is spring-loaded, and registers itself as a bus extension.
Categories: Colm O hEigeartaigh

Maven Download time Improvement

Olivier Lamy - Sat, 09/17/2011 - 18:47
While working a bit on wagon (the api used in Apache Maven to download/upload artifacts), I wanted to reduce the http(s) connection creation number (see WAGON-348).
The current embedded http wagon in Maven Core is the lightweight one based on standard java libraries, this means http(s) connection are created for each download requests. As you know this socket creation can be time and resources consuming.
So as we are working on wagon 2.0 version, I have added a connection pooling mechanism in the wagon http (which is now based on Apache Http Client).
To prevent some classloading issues, the wagon jar to used is a shaded one.
You can test that now (with a maven 3.x version) with adding the jar in $M2_HOME/lib/ext/ :

wget -O wagon-http-2.0-SNAPSHOT-shaded.jar "https://repository.apache.org/content/groups/snapshots-group/org/apache/maven/wagon/wagon-http/2.0-SNAPSHOT/wagon-http-2.0-20110917.172345-31-shaded.jar"
&& cp wagon-http-2.0-SNAPSHOT-shaded.jar $M2_HOME/lib/ext/


Test build available here : http://people.apache.org/~olamy/maven/.

So a little improvement, don't be afraid you still will have time to drink one or two coffee when building a maven project :-).
Note download time will be improved if you use more than one repositories and especially https repositories.

Vote here if you want to have this in next maven core release : http://jira.codehaus.org/browse/MNG-5175.

And all feedbacks will be appreciate :-) (even if it's an issue :-) )

Have Fun !
--
Olivier

Apache Maven, Maven, Apache are trademarks of The Apache Software Foundation.


Categories: Olivier Lamy

Adding UsernameToken security headers in Apache CXF

Glen Mazza - Tue, 09/13/2011 - 13:00

This tutorial modifies the CXF version of the WSDL-first DoubleIt web service to include WS-Security with UsernameTokens. This profile should be used with transport-layer encryption (i.e., SSL) as a minimum to ensure the username and password are encrypted at least between the client and the first recipient node. Note the X.509 or SAML token profiles (along with its requisite client-side certificates) would be more appropriate instead if any of cases below apply:

  • Clients need to sign the request to guard against it being altered in transit
  • The SOAP response back to the client needs to be encrypted so that only the client can read it
  • There are intermediary nodes between client and service that would be unencrypting the message (and hence able to read its contents) before forwarding it on to the next node
  • The web service provider has incomplete nonce and timestamp support to guard against replay attacks, presently the case for CXF and possibly the same with GlassFish Metro.

CXF provides two main options for adding UsernameToken security headers, both of which will be covered below: standard WSS4J interceptors and WS-SecurityPolicy. The latter, which relies on a WS-Policy element defined within the WSDL, offers a more automated approach to using security and is the preferred approach if you have this element defined. Use WSS4J interceptors when security is not defined in the WSDL or you need more customized control of the security header construction.

The finished source code for this tutorial (using WS-SecurityPolicy method, with WSS4J interceptor method lines commented-out) is downloadable here.

  1. Implement SSL without basic authentication for the web service. This is the same as Step #1 of the Metro/UsernameToken guide.

  2. (Maven only) Include additional security dependencies. Add the following to the CXF dependencies section of the doubleit/pom.xml--note the lower should be added only if you're using WS-SecurityPolicy, as the inclusion of this dependency activates WS-SecurityPolicy by default within CXF.

    <dependency> <groupId>org.apache.cxf</groupId> <artifactId>cxf-rt-ws-security</artifactId> <version>${cxf.version}</version> </dependency>

    <!-- Omit if using standard WSS4J interceptors --> <dependency> <groupId>org.apache.cxf</groupId> <artifactId>cxf-rt-ws-policy</artifactId> <version>${cxf.version}</version> </dependency>

  3. Configure the client to provide the user and password. This will require modification of the client class as well as addition of a callback handler to supply the password for a given user. Replace the client created in Step #9 of the WSDL-first tutorial with the following--make sure you uncomment the implementation that you will be using:

    package client; import java.util.HashMap; import java.util.Map; import javax.xml.ws.BindingProvider; import org.apache.cxf.endpoint.Client; import org.apache.cxf.endpoint.Endpoint; import org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor; import org.apache.ws.security.WSConstants; import org.apache.ws.security.handler.WSHandlerConstants; import org.example.contract.doubleit.DoubleItPortType; import org.example.contract.doubleit.DoubleItService; public class WSClient { public static void main(String[] args) { DoubleItService service = new DoubleItService(); DoubleItPortType port = service.getDoubleItPort(); Map outProps = new HashMap(); Client client = org.apache.cxf.frontend.ClientProxy.getClient(port); Endpoint cxfEndpoint = client.getEndpoint(); // Manual WSS4JOutInterceptor interceptor process - start outProps.put(WSHandlerConstants.ACTION, WSHandlerConstants.USERNAME_TOKEN); outProps.put(WSHandlerConstants.USER, "joe"); outProps.put(WSHandlerConstants.PASSWORD_TYPE, WSConstants.PW_TEXT); outProps.put(WSHandlerConstants.PW_CALLBACK_CLASS, ClientPasswordCallback.class.getName()); WSS4JOutInterceptor wssOut = new WSS4JOutInterceptor(outProps); cxfEndpoint.getOutInterceptors().add(wssOut); // Manual WSS4JOutInterceptor interceptor process - end /* // Alternative WS-SecurityPolicy method Map ctx = ((BindingProvider)port).getRequestContext(); ctx.put("ws-security.username", "joe"); ctx.put("ws-security.callback-handler", ClientPasswordCallback.class.getName()); // ctx.put("ws-security.password", "joespassword"); // another option for passwords */ doubleIt(port, 10); doubleIt(port, 0); doubleIt(port, -10); } public static void doubleIt(DoubleItPortType port, int numToDouble) { int resp = port.doubleIt(numToDouble); System.out.println("The number " + numToDouble + " doubled is " + resp); } }

    Next supply the password CallbackHandler that was listed in the SOAP client above. Place this class in the same package as the SOAP client:

    package client; import java.io.IOException; import javax.security.auth.callback.Callback; import javax.security.auth.callback.CallbackHandler; import javax.security.auth.callback.UnsupportedCallbackException; import org.apache.ws.security.WSPasswordCallback; public class ClientPasswordCallback implements CallbackHandler { public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException { WSPasswordCallback pc = (WSPasswordCallback) callbacks[0]; if ("joe".equals(pc.getIdentifier())) { pc.setPassword("joespassword"); } // else {...} - can add more users, access DB, etc. } }
  4. (WS-SecurityPolicy method only) Add the <wsp:Policy/> security element to the service WSDL. You can use Netbeans to create this element, however note the sc:ValidatorConfiguration element Netbeans also creates is Metro-specific and should be removed before using with CXF. Not all features supported by Metro (i.e., that Netbeans will offer for you when creating a WSDL) will be available with CXF; you'll need to test your web service and client well before moving to production. For our tutorial here, change the DoubleIt.wsdl file to the following:

    <?xml version='1.0' encoding='UTF-8'?> <wsdl:definitions xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:di="http://www.example.org/schema/DoubleIt" xmlns:tns="http://www.example.org/contract/DoubleIt" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:fi="http://java.sun.com/xml/ns/wsit/2006/09/policy/fastinfoset/service" xmlns:tcp="http://java.sun.com/xml/ns/wsit/2006/09/policy/soaptcp/service" xmlns:sc="http://schemas.sun.com/2006/03/wss/server" xmlns:wspp="http://java.sun.com/xml/ns/wsit/policy" xmlns:t="http://schemas.xmlsoap.org/ws/2005/02/trust" xmlns:wsaw="http://www.w3.org/2005/08/addressing" xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy" xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy" xmlns:tc="http://schemas.sun.com/ws/2006/05/trust/server" name="DoubleIt" targetNamespace="http://www.example.org/contract/DoubleIt"> <wsdl:types> <xsd:schema targetNamespace="http://www.example.org/schema/DoubleIt"> <xsd:element name="DoubleIt"> <xsd:complexType> <xsd:sequence> <xsd:element name="numberToDouble" type="xsd:int" /> </xsd:sequence> </xsd:complexType> </xsd:element> <xsd:element name="DoubleItResponse"> <xsd:complexType> <xsd:sequence> <xsd:element name="doubledNumber" type="xsd:int" /> </xsd:sequence> </xsd:complexType> </xsd:element> </xsd:schema> </wsdl:types> <wsdl:message name="DoubleItRequest"> <wsdl:part element="di:DoubleIt" name="parameters" /> </wsdl:message> <wsdl:message name="DoubleItResponse"> <wsdl:part element="di:DoubleItResponse" name="parameters" /> </wsdl:message> <wsdl:portType name="DoubleItPortType"> <wsdl:operation name="DoubleIt"> <wsdl:input message="tns:DoubleItRequest" /> <wsdl:output message="tns:DoubleItResponse" /> </wsdl:operation> </wsdl:portType> <wsdl:binding name="DoubleItBinding" type="tns:DoubleItPortType"> <wsp:PolicyReference URI="#DoubleItBindingPolicy" /> <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http" /> <wsdl:operation name="DoubleIt"> <soap:operation soapAction="" /> <wsdl:input> <soap:body use="literal" /> </wsdl:input> <wsdl:output> <soap:body use="literal" /> </wsdl:output> </wsdl:operation> </wsdl:binding> <wsdl:service name="DoubleItService"> <wsdl:port name="DoubleItPort" binding="tns:DoubleItBinding"> <soap:address location="https://localhost:8443/doubleit/services/doubleit" /> </wsdl:port> </wsdl:service> <wsp:Policy wsu:Id="DoubleItBindingPolicy"> <wsp:ExactlyOne> <wsp:All> <wsaw:UsingAddressing xmlns:wsaw="http://www.w3.org/2006/05/addressing/wsdl" wsp:Optional="true" /> <sp:TransportBinding> <wsp:Policy> <sp:TransportToken> <wsp:Policy> <sp:HttpsToken RequireClientCertificate="false" /> </wsp:Policy> </sp:TransportToken> <sp:Layout> <wsp:Policy> <sp:Lax /> </wsp:Policy> </sp:Layout> <sp:IncludeTimestamp/> <sp:AlgorithmSuite> <wsp:Policy> <sp:Basic128 /> </wsp:Policy> </sp:AlgorithmSuite> </wsp:Policy> </sp:TransportBinding> <sp:SignedSupportingTokens> <wsp:Policy> <sp:UsernameToken sp:IncludeToken="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy/IncludeToken/AlwaysToRecipient"> <wsp:Policy> <sp:WssUsernameToken10 /> </wsp:Policy> </sp:UsernameToken> </wsp:Policy> </sp:SignedSupportingTokens> <sp:Wss11 /> </wsp:All> </wsp:ExactlyOne> </wsp:Policy> </wsdl:definitions>

    Metro uses the WSDL to store both client- and service-side security configuration, while CXF does so only for the latter.

  5. Configure the service provider to authenticate the username and password tokens. First, if you're using the WS-SecurityPolicy approach you'll need to declare two additional modules in the contextConfigLocation element of the service provider's web.xml file:

    <context-param> <param-name>contextConfigLocation</param-name> <param-value> ...other modules... classpath:META-INF/cxf/cxf-extension-policy.xml classpath:META-INF/cxf/cxf-extension-ws-security.xml </param-value> </context-param>

    Next, for either security method, we'll need to modify the cxf-servlet.xml configuration file from Step #6 of the WSDL-first tutorial to add either the WSS4J inbound interceptor or WS-SecurityPolicy information (not both!) Replace the previous cxf-servlet.xml file with the following, after modifying it based on your security implementation preference:

    <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jaxws="http://cxf.apache.org/jaxws" xmlns:soap="http://cxf.apache.org/bindings/soap" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd"> <bean id="myPasswordCallback" class="service.ServerPasswordCallback" /> <jaxws:endpoint id="doubleit" implementor="service.DoubleItPortTypeImpl" address="/doubleit" wsdlLocation="WEB-INF/wsdl/DoubleIt.wsdl"> <!-- Uncomment only if using WS-SecurityPolicy --> <!--jaxws:properties> <entry key="ws-security.callback-handler"> <ref bean="myPasswordCallback"/> </entry> </jaxws:properties--> <!-- Uncomment only if using standard WSS4J interceptors --> <jaxws:inInterceptors> <bean class="org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor"> <constructor-arg> <map> <entry key="action" value="UsernameToken"/> <entry key="passwordType" value="PasswordText"/> <entry key="passwordCallbackRef"> <ref bean="myPasswordCallback"/> </entry> </map> </constructor-arg> </bean> </jaxws:inInterceptors> </jaxws:endpoint> </beans>

    Once done we'll need to add the new server-side password callback class referenced above, which provides the correct password for a user, which the CXF framework uses to compare with what is supplied in the client request. Place the following ServerPasswordCallback class to the same package as the service's DoubleItPortTypeImpl SEI implementation class:

    package service; import java.io.IOException; import javax.security.auth.callback.Callback; import javax.security.auth.callback.CallbackHandler; import javax.security.auth.callback.UnsupportedCallbackException; import org.apache.ws.security.WSPasswordCallback; public class ServerPasswordCallback implements CallbackHandler { public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException { WSPasswordCallback pc = (WSPasswordCallback) callbacks[0]; if ("joe".equals(pc.getIdentifier())) { pc.setPassword("joespassword"); } } }

    You can now compile and redeploy the web service by running mvn clean install tomcat:undeploy tomcat:deploy from the DoubleIt base folder.

  6. Test the client. Run the client as shown in the DoubleIt tutorial. Best to test also with incorrect usernames and passwords to ensure the web service provider is catching these errors.

    If you're using the standard WSS4J approach, you can view the headers being added to the SOAP request if you temporarily switch your web service back to non-SSL usage (update the web.xml and URL within the WSDL), and activate logging within your WSClient class:

    import javax.xml.ws.Endpoint; import org.apache.cxf.interceptor.LoggingInInterceptor; import org.apache.cxf.interceptor.LoggingOutInterceptor; public class WSClient { public static void main(String[] args) { ... Endpoint cxfEndpoint = client.getEndpoint(); cxfEndpoint.getInInterceptors().add(new LoggingInInterceptor()); cxfEndpoint.getOutInterceptors().add(new LoggingOutInterceptor()); ...

    Make sure the Java logging file in the client/pom.xml points to a valid Java logging configuration file with a logging level of INFO or more verbose. Running the client from a terminal window will output results similar to the following:

    Oct 1, 2011 7:47:34 PM org.apache.cxf.interceptor.AbstractLoggingInterceptor log INFO: Outbound Message --------------------------- ID: 1 Address: http://localhost:8080/doubleit/services/doubleit Encoding: UTF-8 Content-Type: text/xml Headers: {Accept=[*/*], SOAPAction=[""]} Payload: <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> <soap:Header> <wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" soap:mustUnderstand="1"> <wsse:UsernameToken wsu:Id="UsernameToken-1"> <wsse:Username>joe</wsse:Username> <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">joespassword</wsse:Password> </wsse:UsernameToken> </wsse:Security> </soap:Header> <soap:Body> <ns2:DoubleIt xmlns:ns2="http://www.example.org/schema/DoubleIt"> <numberToDouble>10</numberToDouble> </ns2:DoubleIt> </soap:Body> </soap:Envelope> -------------------------------------- Oct 1, 2011 7:47:34 PM org.apache.cxf.interceptor.AbstractLoggingInterceptor log INFO: Inbound Message ---------------------------- ID: 1 Response-Code: 200 Encoding: UTF-8 Content-Type: text/xml;charset=UTF-8 Headers: {Content-Length=[238], content-type=[text/xml;charset=UTF-8], Date=[Sat, 01 Oct 2011 23:47:34 GMT], Server=[Apache-Coyote/1.1]} Payload: <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> <soap:Body> <ns2:DoubleItResponse xmlns:ns2="http://www.example.org/schema/DoubleIt"> <doubledNumber>20</doubledNumber> </ns2:DoubleItResponse> </soap:Body> </soap:Envelope> -------------------------------------- The number 10 doubled is 20

    If you do this, of course make sure to switch back to SSL for production usage.

Categories:

Congrats Master Melegrito!

Hadrian Zbarcea - Tue, 09/13/2011 - 04:34
Personal things don't usually belong here, but this is a bit special. I am also still sore after this weekend.

Once a year, me and Ama have the opportunity to go with our instructor, 4th Dan Tae Kwon Do Master Josh Geeson, to train in self defense against stick and knife with Master Julius Melegrito, event organized in Charlotte, NC by Master Evins.

The seminar was a real treat as expected. Master Melegrito's speed and technique are amazing. After drills with two sticks, we got to one stick, repeating the same techniques. After the shoulders started burning we dropped the stick altogether and went mano-mano, repeating again, the same techniques only to realize how similar they are to Hapkido and Tae Kwon Do. Too bad this year we ran out of time and didn't get to practice defense against knife attacks. I am not complaining much though because last year my partner was Master Robert Shin who's not very forgiving and the hardwood floor was, well, hard.


Yes, Ama, you are the best!

What makes this year's event special is that Guro Melegrito is now a Black Belt Magazine 2011 Hall of Famer, the Weapons Instructor of the Year. Congrats Master Melegrito, many thanks for visiting and see you again next year!
Categories: Hadrian Zbarcea

SAML SecurityPolicy enforcement in CXF 2.4.2

Colm O hEigeartaigh - Mon, 09/12/2011 - 14:44
Apache CXF 2.4.2 was released recently. In this blog post I want to delve into how CXF 2.4.2 enforces WS-SecurityPolicy expressions relating to SAML Assertions on the inbound side.

There are two policy expressions relating to SAML Assertions, the SamlToken and IssuedToken policy assertions. On the outbound side, the SamlToken expression will trigger a CallbackHandler to obtain a SAML Assertion to insert into the outbound security header, and the IssuedToken expression will use the STSClient to obtain a SAML Assertion from a Security Token Service (STS).

On the inbound side, any SAML Assertion received as part of the security header will be parsed initially by WSS4J. If the assertion is signed, then the signature is verified. If the confirmation method of the Subject of the Assertion is "holder-of-key", then WSS4J will parse the Subject KeyInfo and extract whatever credentials it can find, i.e. secret key or an X509Certificate. If no credential is found (or understood), then the default behaviour is to throw an exception. If the confirmation method is "holder-of-key", then the default behaviour (which is configurable) is to enforce that the Assertion is signed. Finally, WSS4J verifies trust in a certificate that was used to sign the assertion.

After WSS4J is done with validating a received SAML Assertion, CXF does some additional validation according to the configured security policy. For more information on any of the following terms (holder-of-key, sender-vouches, etc.), please consult the SAML Token Profile 1.1 specification.

1) SamlToken policy

If a SamlToken policy is used, the version of the received Assertion (1.1 or 2.0) is checked against the policy, e.g. if <sp:WssSamlV20Token11 /> is configured in the SAMLToken policy then the received Assertion must be a SAML 2.0 Assertion. Two checks are then done on the received Assertion, depending on what the subject confirmation method is.
  • Holder-of-key: If the subject confirmation method is "holder-of-key", there must be some proof-of-possession of the key associated with the subject of the assertion. CXF will enforce that either the key was used to sign some portion of the SOAP request, or alternatively the subject credential of the SAML Assertion must match a client certificate credential when 2-way TLS is used.
  • Sender-Vouches: If the subject confirmation method is "sender-vouches", then CXF will enforce that the SAML Assertion and SOAP Body are signed by the same signature. Alternatively, it will check that 2-way TLS is used.
2) IssuedToken Policy

If an IssuedToken policy is used, then the receiver is expecting to get a SAML Assertion that is issued by a third-party security service. If the subject confirmation method of the Assertion is "holder-of-key", then it does the same check as described above for a SamlToken policy. Additionally, if a "<sp:RequestSecurityTokenTemplate..../>" policy is configured, it will attempt to match the received Assertion against the RSTTemplate parameters:
  • TokenType: If a TokenType parameter is specified in the template, it will match this against the version of the received Assertion. For example, if the TokenType is "http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV1.1", then the Assertion must be a SAML 1.1 Assertion.
  • KeyType: If a KeyType parameter is specified in the template which ends with "SymmetricKey", then the subject of the Assertion must contain a secret key. If the KeyType parameter ends with "PublicKey", then the Subject must contain a Certificate or PublicKey.
Here is an example of a RequestSecurityTokenTemplate:

<sp:RequestSecurityTokenTemplate>
    <t:TokenType>
      http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile1.1#SAMLV1.1
   </t:TokenType>
   <t:KeyType>
     http://docs.oasis-open.org/ws-sx/ws-trust/200512/PublicKey
   </t:KeyType>
</sp:RequestSecurityTokenTemplate>

Issuer or IssuerName policies are not yet enforced, this will probably be done in a future version of CXF.
Categories: Colm O hEigeartaigh

Web Services Links (11 September 2011)

Glen Mazza - Sun, 09/11/2011 - 13:00

and also:

Categories:

Weekend Talendization: JMX monitoring samples for CXF, Camel and Karaf in Talend ESB

Glen Mazza - Fri, 09/09/2011 - 13:00

The examples folder for the upcoming Talend ESB 5.0 (presently at Milestone Release 4) contains three JMX examples showing how you can use monitor CXF web service providers, Camel Routes and Karaf bundles using Java Management Extensions (JMX). The Camel and CXF examples provide both Tomcat-based and OSGi bundle-based deployment options, and all three samples show how the JDK's JConsole JMX monitoring tool can be used to monitor and/or manage the deployed samples. Check the README file in each sample for more information.

Categories:

Updates to OSGi and Management coming in CXF

Daniel Kulp - Thu, 09/08/2011 - 18:27
In the last week or so, there’s been a bit of work going on in CXF to improve the OSGi experience with CXF as well as make it easier to manage. First off, Glen Mazza has done quite a bit of testing with JMX and wrote a very good blog entry about how to JMX [...]
Categories: Daniel Kulp

Tomcat Maven Plugin New Home at Apache Software Foundation

Olivier Lamy - Thu, 09/08/2011 - 15:50
The Tomcat Maven Plugin has now a new Home at Apache Software Foundation.
The home is located here .
You will find some details on :

  • Sources location

  • Bug Tracker location



Some more cleanups need to be done to finish the Apache Branding.
Next steps (new features) will be :

  • Support of Apache Tomcat7 trough a new mojo : tomcat7:*

  • New mojo to be able to build an executable war with an embedded tomcat inside to be able to do : java -jar mywar.war



All feedbacks will be appreciate.
Have Fun.

Apache Maven, Maven, Apache Tomcat, Tomcat, Apache are trademarks of The Apache Software Foundation.


Categories: Olivier Lamy

Annotation for the Claimcheck Pattern

Hadrian Zbarcea - Thu, 09/08/2011 - 04:00
The claimcheck pattern is described in the EIP book Camel is based on. The way it is described, the pattern uses a data store which means that it applies mostly to local processing. However, in most of the cases, at least in my experience, the processing is not local so one needs to retrieve the original message at a different location where access to the data store is not necessarily possible.

As a bit of background, the commonly used analogy for the claimcheck pattern is the process used to check-in baggage while traveling and claim it at the destination. The rationale is that cabin space is a scarce resource (as is cpu, memory and bandwidth) and different parts of the in-flight entity have different SLA requirements: humans need oxygen, leg room, pressurized cabin space, food, entertainment, etc. whereas baggages can be stacked in the cargo hold. In some cases they may take different routes to destination as well.

So how should this be implemented? Let's take a look at the elements that define the pattern. First we have a message that via some logic will be transformed into two messages (1).  Let's call the two Messages the "initial message" and the "claim message". That is the Content Filter part described in the pattern, not to be confused with the filter dsl in camel that is actually a Message Filter, very different thing.

Our two messages will travel separately between departure and arrival, to borrow the terminology from the travel analogy via two different Message Channels (2), which in Camel we know as routes. The first message channel is the initial route we setup, let's call it the "main channel". The second channel is a one way one, let's call it the "baggage channel". Between departure and arrival, the initial message will go on the bagage channel and the claim message will go on the main channel.

We also need to generate a Correlation Identifier (3) to preserve the association (the equivalent of the bar coded tag on the baggage and the boarding pass). The fact that one could have multiple baggages is outside the scope of this pattern, it can be handled by a splitter/aggregator. The correlation id is both attached to the initial message and supplied somewhere in the claim message.

The claim message will replace the initial message on the main channel and may undergo further processing. It may contain partial content from the initial message required for processing, it may need to be of a specific type, we cannot make many assumptions. Two things are clear though: it is produced from the initial message, so we need a Processor (4) for that, and it contains the correlation id, so we need an Expression (5) to extract it from there at destination. While we need to attach the correlation id to the initial message too, we have a bit more freedom on the baggage channel, so let's simplify things a bit and use a custom header/property instead of customizing too much and require another Expression.

Putting together the five elements above, it starts to look like in the general case we need a separate, configurable one-way (in-only) route with some processing in the departure and arrival endpoints. I already looks like our implementation will actually require a different kind of Endpoint which also means a Component. It should support multiple queues at departure and arrival (i.e. both for check-in and claim). Since processing takes place on the main channel and at arrival during baggage claim the initial message is restored, it must be retrieved from the arrival claim queue, which means that the arrival queue must support random access. This is a key aspect, sometimes overlooked, that gives a lot of grief when implementing this pattern.

As far as implementation goes, I started to play with a bit of code so you could see a solution in one of my next posts and probably in the Apache Camel trunk soon.
Categories: Hadrian Zbarcea

Pages

Subscribe to Talend Community Coders aggregator