In my last post I talked about using an out-of-the-box policy to sign your outgoing SOAP Message. Although it is not very well documented when you figure out how to configure the keystore and credential store it is quite simple to use. The problem is that the out-of-the-box policies need some tailoring before they can be used in the real world situations. Unfortunately I was only able to sign the entire body and not a specific element. What I needed was a more basic policy that only signs a specific element. So I needed to create a custom policy to do this. According to the documentation there is an API I can use, extend some classes and you can create your own policies. Simple, well in theory…
Â
Image is copyrighted. Used with permission from DuraLabel.com
You need to extend oracle.wsm.policyengine.impl.AssertionExecutor and create your own CustomAssertion class. The class should contain some standard methods with standard handling. I just followed oracle’s recommendations. You subclass this class again and create the actual Assertion/Policy Execution class. The main method that will do all the work is the execute method. It has one input parameter of type SOAPBindingMessageContext (implementation of IContext Interface). Well that is all you get. The SOAP Message with some convenience methods to access the Transport headers, SOAP body. So where do I start?
My first challenge was figuring out how to access the credential store and the keystore. I want my custom policy to have a property containing the csf key the policy will use to retrieve a private/public keypair from the (file/JKS) keystore. There is a custom policy sample in the documentation showing how to retrieve a credential store service instance you can use to retrieve csf key values.
So I assumed I could use the same trick to retrieve a keystore service instance and retrieve my keypair. Well wrong… There is a keyStore service available but this will not retrieve the (default JKS) Keystore but some other keystores. These keystores reside in a keystores.xml file in the config/fmwconfig directory. The keyStore service’s getKeyStore method was talking about stripeNames I never heard of before; setting the authorization permissions to access the keystores similar to what I did for access the credential store service did not work, so I could not get it working. The KeyStore Service’s getProperties method was actually returning the right keystore properties (from the jps-config.xml file). So I concluded I could at least use this method to retrieve the name, location and other properties of the (default) keystore. To retrieve the keystore itself I had to figure out another way to do that.
Later on I found an alternative approach to retrieve a credentialstore and the keystore properties. After some browsing through the wsm and jps packages I found the oracle.wsm.security.jps.JpsManager class. This class has the methods getCredentialStore, returning a credential store, and the getKeyStoreConfig method, returning the keystore property map I described earlier. So you can use this class also. But why wasn’t this in any sample?
Now for the second part of my challenge, how to actually get a keypair from the keystore. I figured out two, of course undocumented approaches:
1. oracle.wsm.security.jps.WsmKeyStoreFactory.getKeyStore
2. oracle.security.jps.internal.common.util.KeyStoreUtil.loadKeystore
Although the latter method has a clearer signature, to my opinion, I still would recommend using the first one. The fact that the package name of the second class contains “internal” suggests it is not meant to be used by us mere mortals.
So now for the actual creation of the policy headers and signatures itself. Does wsm offer me documented convenience classes that help me easily build up my WS security headers and do the signing and encrypting. I could not figure this out. It is unclear what to use. I would have expected some guidance here on how to construct a policy in a performant way. Some best practices/do’s and don’ts so you don’t end up with a policy blocking all message processing on high loads.
This can only lead to one conclusion. You can build your own custom policies but keep them simple. Add some headers or do some logging but do not try to implement sophisticated policies without knowing the implications on performance. If you really need to build a lot of custom policies it might even be wise to look at some SOA appliances to do the work like layer7 or Vordel (I cannot advise DataPower as it is a little too blue for my taste ;-) ). The amount of time and money you need to invest to create custom policies in OWSM could end up becoming more expensive than to buy a dedicated appliance optimized for this task only. If I would make a parallel building a custom policy now more resembles building your own car from scratch then building a custom car.
As a former employee of the Dutch distributor for Amberpoint in the Benelux I am somewhat surprised Oracle does not mention this product as an add-on or even alternative policy management and enforcement product. Amberpoint has extensive support for SOA management and security policies. Somehow Oracle decided to only market the business transaction monitoring functionalities of Amberpoint although it contains so much more. It could have extended their OWSM product so nicely. But perhaps it is too early for this, the merger is still ongoing. The fruits of this cooperation will reach us in due time.
So what can be done today? We can share our own experiences and best practices to make these custom policies usable for the masses. So write blogposts and share your code so we can all benefit. In an upcoming post I will talk about a custom policy that I have recently made.
.