Showing posts with label stand-alone client. Show all posts
Showing posts with label stand-alone client. Show all posts

Monday, January 16, 2012

Have you ever tried to invoke secure WebLogic web services with javaws client? - part 2

OK... where were we?

Oh yes... everything seemed to be working fine (with few exceptions which constitute the norm in programming). So, we have a secure communication between server and client (tested by JUnit). Now, it's time to make the client really stand-alone, which means that it can run on a different machine without any WebLogic installation. Don't forget that the client classpath has a reference to the weblogic.jar found in directory <WL_HOME>/server/lib.

The first naive attempt was to simply move weblogic.jar along with all the other dependencies in a separate directory and set the runtime classpath. No luck... but I admit it... it was my fault since I haven't read carefully the manual on weblogic clients. This is a classic problem with us... we never EVER read the documentation!

Our dear Oracle offers an overview of the all types of weblogic clients here. According to this document, I should have used wseeclient.jar or perhaps wlfullclient.jar. The latter is supposed to cover all cases (at least the vast majority) but it turned out be insufficient as far as web services are concerned. No problem... wseeclient.jar seemed to be suitable for that.
Invoking web services.
Oracle has an extensive documentation on that, here. There is a section on invoking web services by truly-standalone clients, that is, clients that run on workstations with no WebLogic installation (see here). Have I told you that most developers (including me) do not actually read manuals? Or at least we never make a proper reading / studying, just a diagonal scan, keeping only those phrases that hit on us (there is a scientific explanation for this... I'm sure)! It is explicitly stated that:
the stand-alone client JAR file does not, however, support invoking Web Services that use the following advanced feature: Message-level security (WS-Security)
Disappointment... If I was more careful and have seen that, it would save me lots of time... But in my defense, I would expect that Oracle should provide a stand-alone client that does what it is meant to do! How is it ever possible that there is no actual client for this?!?!?!

In any case all candidates (weblogic.jar, wseeclient.jar and wlfullclient.jar) are not designed to be used as is. If you take a look at their manifest files (just jar-xvf them and look into the META-INF) there is an extensive classpath reference. Since only weblogic seemed to be the final winner then I had to concentrate on that.

Gathering all the weblogic dependencies and resetting the client classpath wouldn't work as well (dependency graph)! There were two choices:
  1. Continue the same procedure until I could finally include all resources in the client classpath.
  2. Be a bit smarter (no more than a chimp - see here and here) and monitor the classes which are loaded when the WL_HOME/server/lib/weblogic.jar is used in the client classpath.
The obvious choice was the second one. If you specify the -verbose flag in java command, then you get the list of classes and the corresponding jars. With the help of some regular expressions, I had finally gathered the list of necessary jars.
  • bcprov-jdk14-138.jar
  • com.bea.core.antlr.runtime_2.7.7.jar
  • com.bea.core.common.security.api_1.0.0.0_6-1-0-0.jar
  • com.bea.core.common.security.utils_1.0.0.0_6-1-0-0.jar
  • com.bea.core.datasource6_1.9.0.0.jar
  • com.bea.core.descriptor_1.9.0.0.jar
  • com.bea.core.diagnostics.core_2.5.0.0.jar
  • com.bea.core.i18n_1.8.0.0.jar
  • com.bea.core.logging_1.8.0.0.jar
  • com.bea.core.management.core_2.8.0.0.jar
  • com.bea.core.stax2_1.0.0.0_3-0-1.jar
  • com.bea.core.timers_1.7.0.0.jar
  • com.bea.core.utils_1.9.0.0.jar
  • com.bea.core.utils.classloaders_1.8.0.0.jar
  • com.bea.core.weblogic.rmi.client_1.8.0.0.jar
  • com.bea.core.weblogic.saaj_1.6.0.0.jar
  • com.bea.core.weblogic.security_1.0.0.0_6-1-0-0.jar
  • com.bea.core.weblogic.security.identity_1.1.2.1.jar
  • com.bea.core.weblogic.security.wls_1.0.0.0_6-1-0-0.jar
  • com.bea.core.weblogic.socket.api_1.2.0.0.jar
  • com.bea.core.weblogic.stax_1.8.0.0.jar
  • com.bea.core.weblogic.workmanager_1.9.0.0.jar
  • com.bea.core.woodstox_1.0.0.0_4-0-5.jar
  • com.bea.core.workarea_1.7.0.0.jar
  • com.bea.core.xml.beaxmlbeans_2.2.0.0_2-5-1.jar
  • com.bea.core.xml.weblogic.xpath_1.4.0.0.jar
  • cryptoj.jar
  • glassfish.jaxb_1.0.0.0_2-1-12.jar
  • glassfish.jaxws.fastinfoset_1.0.0.0_2-1-5.jar
  • glassfish.jaxws.rt_1.1.0.0_2-1-5.jar
  • glassfish.stax.ex_1.0.0.0_1-2.jar
  • glassfish.xmlstreambuffer_1.0.0.0_0-5-257.jar
  • javax.jms_1.1.1.jar
  • javax.servlet_1.0.0.0_2-5.jar
  • javax.xml.rpc_1.2.1.jar
  • swing-worker-1.1.jar
  • weblogic.jar
  • webservices.jar
  • ws.api_1.1.0.0.jar
These jars are found either in WL_HOME/server/lib or WL_HOME/../modules/.(WL_HOME is basically wlserver_10.3 in the WebLogic installation directory). So... I was almost there, right? WRONG!!!
"A solved problem creates two new problems, and the best prescription for happy living is not to solve any more problems than you have to" - Russell Baker
This is where java web start comes in to play... Remember that the client should run as a java web start program (the web service client is a part of PDF handling program). If you run the client from command line then everything worked just fine. If you do the exact same thing but using java web start instead (javaws <local_JNLP_file>) then you would get the following error:

java.lang.InternalError: error initializing kernel caused by: java.lang.AssertionError: Duplicate initialization of WorkManager
at weblogic.work.WorkManagerFactory.set(WorkManagerFactory.java:107)
at weblogic.work.ExecuteQueueFactory.initialize(ExecuteQueueFactory.java:23)
at weblogic.kernel.Kernel.initialize(Kernel.java:103)
at weblogic.kernel.Kernel.ensureInitialized(Kernel.java:64)
at weblogic.rjvm.wls.WLSRJVMEnvironment.ensureInitialized(WLSRJVMEnvironment.java:50)
at weblogic.protocol.ProtocolManager$DefaultAdminProtocolMaker.<clinit>(ProtocolManager.java:53)
at weblogic.protocol.ProtocolManager.getDefaultAdminProtocol(ProtocolManager.java:218)
at weblogic.protocol.ProtocolHandlerAdmin.<clinit>(ProtocolHandlerAdmin.java:23)
at weblogic.rjvm.wls.WLSRJVMEnvironment.registerRJVMProtocols(WLSRJVMEnvironment.java:120)
at weblogic.rjvm.RJVMManager.ensureInitialized(RJVMManager.java:87)
at weblogic.rjvm.RJVMManager.<clinit>(RJVMManager.java:46)
at weblogic.rjvm.LocalRJVM.<init>(LocalRJVM.java:97)
at weblogic.rjvm.LocalRJVM.<init>(LocalRJVM.java:28)
at weblogic.rjvm.LocalRJVM$LocalRJVMMaker.<clinit>(LocalRJVM.java:31)
at weblogic.rjvm.LocalRJVM.getLocalRJVM(LocalRJVM.java:72)
at weblogic.xml.crypto.utils.DOMUtils.generateId(DOMUtils.java:403)
at weblogic.xml.crypto.utils.DOMUtils.generateId(DOMUtils.java:395)
at weblogic.xml.crypto.utils.DOMUtils.assignId(DOMUtils.java:374)
at weblogic.xml.crypto.wss.SecurityBuilderImpl.assignUri(SecurityBuilderImpl.java:148)
at weblogic.wsee.security.policy.SigningReferencesFactory.getSigningReferences(SigningReferencesFactory.java:100)
at weblogic.wsee.security.wss.policy.wssp.SigningPolicyBlueprintImpl.addSignatureNodeListToReference(SigningPolicyBlueprintImpl.java:446)
at weblogic.wsee.security.wss.policy.wssp.SigningPolicyBlueprintImpl.addSignatureNodeListToReference(SigningPolicyBlueprintImpl.java:335)
at weblogic.wsee.security.wss.plan.SecurityMessageArchitect.resolveSignatureList(SecurityMessageArchitect.java:574)
at weblogic.wsee.security.wss.plan.SecurityMessageArchitect.resolveSignatureList(SecurityMessageArchitect.java:428)
at weblogic.wsee.security.wss.plan.SecurityMessageArchitect.constructMessage(SecurityMessageArchitect.java:304)
at weblogic.wsee.security.wss.plan.SecurityMessageArchitect.buildWssMessage(SecurityMessageArchitect.java:138)
at weblogic.wsee.security.wss.plan.SecurityMessageArchitect.buildWssMessage(SecurityMessageArchitect.java:121)
at weblogic.wsee.security.wss.SecurityPolicyArchitect.processOutbound(SecurityPolicyArchitect.java:225)
at weblogic.wsee.security.wss.SecurityPolicyArchitect.processMessagePolicy(SecurityPolicyArchitect.java:123)
at weblogic.wsee.security.wss.SecurityPolicyConductor.processRequestOutbound(SecurityPolicyConductor.java:119)
at weblogic.wsee.security.wss.SecurityPolicyConductor.processRequestOutbound(SecurityPolicyConductor.java:91)
at weblogic.wsee.security.wssp.handlers.WssClientHandler.processOutbound(WssClientHandler.java:117)
at weblogic.wsee.security.wssp.handlers.WssClientHandler.processRequest(WssClientHandler.java:69)
at weblogic.wsee.security.wssp.handlers.WssHandler.handleRequest(WssHandler.java:112)
at weblogic.wsee.jaxws.framework.jaxrpc.TubeFactory$JAXRPCTube.processRequest(TubeFactory.java:222)
at com.sun.xml.ws.api.pipe.Fiber.__doRun(Fiber.java:866)
at com.sun.xml.ws.api.pipe.Fiber._doRun(Fiber.java:815)
at com.sun.xml.ws.api.pipe.Fiber.doRun(Fiber.java:778)
at com.sun.xml.ws.api.pipe.Fiber.runSync(Fiber.java:680)
at com.sun.xml.ws.client.Stub.process(Stub.java:272)
at com.sun.xml.ws.client.sei.SEIStub.doProcess(SEIStub.java:153)
at com.sun.xml.ws.client.sei.SyncMethodHandler.invoke(SyncMethodHandler.java:115)
at com.sun.xml.ws.client.sei.SyncMethodHandler.invoke(SyncMethodHandler.java:95)
at com.sun.xml.ws.client.sei.SEIStub.invoke(SEIStub.java:136)
at $Proxy29.fetchCSD(Unknown Source)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at weblogic.wsee.jaxws.spi.ClientInstanceInvocationHandler.invoke(ClientInstanceInvocationHandler.java:84)
at $Proxy30.fetchCSD(Unknown Source)
at exchangecsdclient.CSDExchangeClientImpl.fetchCSD(CSDExchangeClientImpl.java:151)
at pdfutil.PDFUtilApp.initialize(PDFUtilApp.java:55)
at org.jdesktop.application.Application$1.run(Application.java:170)
at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:209)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:597)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:269)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:184)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:174)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:169)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:161)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:122)

at weblogic.kernel.Kernel.ensureInitialized(Kernel.java:66)
at weblogic.rjvm.wls.WLSRJVMEnvironment.ensureInitialized(WLSRJVMEnvironment.java:50)
at weblogic.protocol.ProtocolManager$DefaultAdminProtocolMaker.<clinit>(ProtocolManager.java:53)
at weblogic.protocol.ProtocolManager.getDefaultAdminProtocol(ProtocolManager.java:218)
at weblogic.protocol.ProtocolHandlerAdmin.<clinit>(ProtocolHandlerAdmin.java:23)
at weblogic.rjvm.wls.WLSRJVMEnvironment.registerRJVMProtocols(WLSRJVMEnvironment.java:120)
at weblogic.rjvm.RJVMManager.ensureInitialized(RJVMManager.java:87)
at weblogic.rjvm.RJVMManager.<clinit>(RJVMManager.java:46)
at weblogic.rjvm.LocalRJVM.<init>(LocalRJVM.java:97)
at weblogic.rjvm.LocalRJVM.<init>(LocalRJVM.java:28)
at weblogic.rjvm.LocalRJVM$LocalRJVMMaker.<clinit>(LocalRJVM.java:31)
at weblogic.rjvm.LocalRJVM.getLocalRJVM(LocalRJVM.java:72)
at weblogic.xml.crypto.utils.DOMUtils.generateId(DOMUtils.java:403)
at weblogic.xml.crypto.utils.DOMUtils.generateId(DOMUtils.java:395)
at weblogic.xml.crypto.utils.DOMUtils.assignId(DOMUtils.java:374)
at weblogic.xml.crypto.wss.SecurityBuilderImpl.assignUri(SecurityBuilderImpl.java:148)
at weblogic.wsee.security.policy.SigningReferencesFactory.getSigningReferences(SigningReferencesFactory.java:100)
at weblogic.wsee.security.wss.policy.wssp.SigningPolicyBlueprintImpl.addSignatureNodeListToReference(SigningPolicyBlueprintImpl.java:446)
at weblogic.wsee.security.wss.policy.wssp.SigningPolicyBlueprintImpl.addSignatureNodeListToReference(SigningPolicyBlueprintImpl.java:335)
at weblogic.wsee.security.wss.plan.SecurityMessageArchitect.resolveSignatureList(SecurityMessageArchitect.java:574)
at weblogic.wsee.security.wss.plan.SecurityMessageArchitect.resolveSignatureList(SecurityMessageArchitect.java:428)
at weblogic.wsee.security.wss.plan.SecurityMessageArchitect.constructMessage(SecurityMessageArchitect.java:304)
at weblogic.wsee.security.wss.plan.SecurityMessageArchitect.buildWssMessage(SecurityMessageArchitect.java:138)
at weblogic.wsee.security.wss.plan.SecurityMessageArchitect.buildWssMessage(SecurityMessageArchitect.java:121)
at weblogic.wsee.security.wss.SecurityPolicyArchitect.processOutbound(SecurityPolicyArchitect.java:225)
at weblogic.wsee.security.wss.SecurityPolicyArchitect.processMessagePolicy(SecurityPolicyArchitect.java:123)
at weblogic.wsee.security.wss.SecurityPolicyConductor.processRequestOutbound(SecurityPolicyConductor.java:119)
at weblogic.wsee.security.wss.SecurityPolicyConductor.processRequestOutbound(SecurityPolicyConductor.java:91)
at weblogic.wsee.security.wssp.handlers.WssClientHandler.processOutbound(WssClientHandler.java:117)
at weblogic.wsee.security.wssp.handlers.WssClientHandler.processRequest(WssClientHandler.java:69)
at weblogic.wsee.security.wssp.handlers.WssHandler.handleRequest(WssHandler.java:112)
at weblogic.wsee.jaxws.framework.jaxrpc.TubeFactory$JAXRPCTube.processRequest(TubeFactory.java:222)
at com.sun.xml.ws.api.pipe.Fiber.__doRun(Fiber.java:866)
at com.sun.xml.ws.api.pipe.Fiber._doRun(Fiber.java:815)
at com.sun.xml.ws.api.pipe.Fiber.doRun(Fiber.java:778)
at com.sun.xml.ws.api.pipe.Fiber.runSync(Fiber.java:680)
at com.sun.xml.ws.client.Stub.process(Stub.java:272)
at com.sun.xml.ws.client.sei.SEIStub.doProcess(SEIStub.java:153)
at com.sun.xml.ws.client.sei.SyncMethodHandler.invoke(SyncMethodHandler.java:115)
at com.sun.xml.ws.client.sei.SyncMethodHandler.invoke(SyncMethodHandler.java:95)
at com.sun.xml.ws.client.sei.SEIStub.invoke(SEIStub.java:136)
at $Proxy29.fetchCSD(Unknown Source)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at weblogic.wsee.jaxws.spi.ClientInstanceInvocationHandler.invoke(ClientInstanceInvocationHandler.java:84)
at $Proxy30.fetchCSD(Unknown Source)
at exchangecsdclient.CSDExchangeClientImpl.fetchCSD(CSDExchangeClientImpl.java:151)
at pdfutil.PDFUtilApp.initialize(PDFUtilApp.java:55)
at org.jdesktop.application.Application$1.run(Application.java:170)
at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:209)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:597)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:269)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:184)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:174)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:169)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:161)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:122)


Deadlock situation...

The good thing is that I discovered numerous veins in my face, the existence of which was a  total mystery for me. The bad thing is that I expressed my fury to my (alarmingly terrified) colleagues. Sorry guys...

The !@#$*@! WorkManager (see here) is initiated more than once! 

Classloading maze...

I posted the problem in the weblogic forums and I still wait for an answer. I could try to find a clean solution, but you know that, in the vast majority of situation, there is no time for that. So, I chose (with a relatively clean consciousness) another solution: bundle all jars in a single jar along with a small spawning class that simply sets the classpath (placing all jars in a temp directory) and initiates the original client in a new process.

It's not clean, I admit it! But it works! It works in both windows and linux environments (there is some additional testing to be done).

"A principle is the expression of perfection, and as imperfect beings like us cannot practice perfection, we devise every moment limits of its compromise in practice" - Mohandas Gandhi

Have you ever tried to invoke secure WebLogic web services with javaws client? - part 1

It was a beautiful sunny Monday morning in the capital - I live and work in Athens, Greece - despite the low temperature (at least for the Athenian criteria). Birds were chirping, people were whining about the known financial problems of Greece... the usual stuff... Nothing could foreshadow what would trouble me for the rest of the week.

I prepared a monstrous-in-dimensions cup of coffee and opened my - really huge and exponentially growing - task list. The task-in-focus seemed simple (ignorant me)!

Have you ever tried to invoke secure WebLogic web services with javaws client? 

The requirement was to build a java web start application that would manage PDF documents. That client should communicate with a server exchanging information like the PDF document itself and some other less significant stuff. The building blocks were there, referring to the server and client components. The actual task was to secure their communication. The server component is implemented as a web service running on WebLogic, so the secure communication would rely on WS-security.

Don't get me any wrong... I love WebLogic! Apart from the licensing policy, which requires thorough analysis and infinite amount of usually dead-end discussion, there are religious arguments against or in favor of WebLogic. I cannot say that I have been particularly involved with many application servers. I do have some professional experience with Tomcat (it's actually a Servlet container and not an full-blown application server, but anyway...), Glassfish and JBoss (not a full JavaEE6 app server, but implements the Web Profile - see the differences here). All these are perfectly OK (especially JBoss). They do their work. There are strong communities behind them that can help you with almost anything. But they are not WebLogic! It's a matter of taste... a purely subjective factor. I won't delve into much detail about the pros and cons of WebLogic or a JavaEE app server comparison (see here). I can only say one thing... WebLogic administration panel simply rocks! It's the best... extremely powerful and easy-to-use.

Leaving behind the discussion about app servers, there is a java web start application that manages PDF documents and a web service, running in WebLogic 10.3.3, that communicates with the aforementioned javaws app. What I had to do is secure the communication. Since the security requirements were very high, the best solution is to adopt message-level security (both encryption and signing).

Oracle has published a very good (but certainly not complete) documentation here. The selected ws-security policy is Wssp1.2-2007-Wss1.1-X509-Basic256.xml with both encryption and signing in all methods. I won't go into any details regarding the theory behind this... it's PKI stuff (not trivial but easy to learn).
Three things had to be implemented:
  • Configuring WebLogic web service security
  • Coding the web service
  • Coding the web service client

Configuring WebLogic web service security

The following steps need to be taken:
  • Obtain two private key and digital certificate pairs to be used by the Web services runtime. One of the pairs is used for digitally signing the SOAP message and the other for encrypting it. Although not required, Oracle recommends that you obtain two pairs that will be used only by WebLogic Web services. You must also ensure that both of the certificate's key usage matches what you are configuring them to do. For example, if you are specifying that a certificate be used for encryption, be sure that the certificate's key usage is specified as for encryption or is undefined. Otherwise, the Web services security runtime will reject the certificate. You can use the Cert Gen utility or Sun Microsystem's keytool utility (see here) to perform this step. For development purposes, the keytool utility is the easiest way to get started. The first step is to create the client & server credentials. The type of these credentials is non other than private key - X509 certificate pairs. 
  • Create, if one does not currently exist, a custom identity keystore for WebLogic Server and load the private key and digital certificate pairs you obtained in the preceding step into the identity keystore. If you have already configured WebLogic Server for SSL, then you have already created an identity keystore that you can also use in this step. You can use WebLogic's ImportPrivateKey utility and Sun Microsystem's keytool utility (see here) to perform this step. For development purposes, the keytool utility is the easiest way to get started.
  • Using the Administration Console, configure WebLogic Server to locate the keystore you created in the preceding step. If you are using a keystore that has already been configured for WebLogic Server, you do not need to perform this step.
  • Using the Administration Console, create the default Web service security configuration, which must be named default_wss. The default Web service security configuration is used by all Web services in the domain unless they have been explicitly programmed to use a different configuration. For further details, click here. Below, there is a sample of the local WebLogic configuration.
<webservice-security>
  <name>x509AuthSignEncrWSS</name>
  <webservice-token-handler>
    <name>th1</name>
    <class-name>weblogic.xml.crypto.wss.BinarySecurityTokenHandler</class-name>
    <token-type>x509</token-type>
    <configuration-property>
      <name>UseX509ForIdentity</name>
      <encrypt-value-required>false</encrypt-value-required>
      <value>true</value>
    </configuration-property>
    <handling-order>1</handling-order>
  </webservice-token-handler>
</webservice-security>
 
  • Update the default Web services security configuration you created in the preceding step to use one of the private key and digital certificate pairs for digitally signing SOAP messages. See Specify the key pair used to sign SOAP messages in Oracle WebLogic Server Administration Console Help. In the procedure, when you create the properties used to identify the keystore and key pair, enter the exact value for the Name of each property (such as IntegrityKeyStore, IntegrityKeyStorePassword, and so on), but enter the value that identifies your own previously-created keystore and key pair in the Value fields.
  • Similarly, update the default Web services security configuration you created in a preceding step to use the second private key and digital certificate pair for encrypting SOAP messages. See Specify the key pair used to encrypt SOAP messages in Oracle WebLogic Server Administration Console Help. In the procedure, when you create the properties used to identify the keystore and key pair, enter the exact value for the Name of each property (such as ConfidentialityKeyStore. ConfidentialityKeyStorePassword, and so on), but enter the value that identifies your own previously-created keystore and key pair in the Value fields.
Coding the web service

import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebService;
import weblogic.jws.Policies;
import weblogic.jws.Policy;

import weblogic.jws.WLHttpTransport;
import weblogic.jws.security.WssConfiguration;

@WebService()
@WssConfiguration(value="x509AuthSignEncrWSS")
@Policy(uri="Wssp1.2-2007-Wss1.1-X509-Basic256.xml")
public class MyFirstSecWS {

  @WebMethod(operationName = "sayHi")
  @Policies({
      @Policy(uri="policy:Wssp1.2-2007-SignBody.xml"),
      @Policy(uri="policy:Wssp1.2-2007-EncryptBody.xml")
  })
  public String sayHi(@WebParam(name = "name")
  String name) {
      return "Hi " + name;
  }
}
 
Nothing tricky here... very simple! We just denoted the security policy being used (Wssp1.2-2007-Wss1.1-X509-Basic256.xml) and the signing and encryption subpolicies (Wssp1.2-2007-SignBody.xml, Wssp1.2-2007-EncryptBody.xml) for the service method. Not that this is not the actual service, but just an example!!!


Coding the web service client
import java.io.FileInputStream;
import java.io.IOException;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.net.ssl.TrustManagerFactory;
import javax.xml.ws.BindingProvider;
import weblogic.security.SSL.TrustManager;

import weblogic.wsee.security.bst.ClientBSTCredentialProvider;
import weblogic.xml.crypto.wss.WSSecurityContext;
import weblogic.xml.crypto.wss.provider.CredentialProvider;

public class Main {

    public static void main(String[] args) {

// keystore that holds the client private key
String ksFile = <keystore filepath>
org.ciec.ws.client.MyFirstSecWSService service = new org.ciec.ws.client.MyFirstSecWSService();
org.ciec.ws.client.MyFirstSecWS port = service.getMyFirstSecWSPort();
//create credential provider and set it to the request context
List credProviders = new ArrayList();
//client side BinarySecurityToken credential provider -- x509
CredentialProvider cp = null;
    try {
 cp = new ClientBSTCredentialProvider(ksFile, <ksPassword>, <keyAlias>, <keyPassword>, <keystoreType - JKS or PKCS#12>,
  getPublicCertificate(<serverCertificatePath>));
    } catch (Exception ex) {
 Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
    }

credProviders.add(cp);
Map<String, Object> requestContext = ((BindingProvider) port).getRequestContext();
requestContext.put(WSSecurityContext.CREDENTIAL_PROVIDER_LIST, credProviders);
requestContext.put(WSSecurityContext.TRUST_MANAGER, new TrustManager() {
 public boolean certificateCallback(X509Certificate[] xcs, int i) {
     // validation code here that inspects the X.509 certificates being passed
     return true;
 }
    });
try {
    String response = port.sayHi("World");
    System.out.println("response = " + response);
} catch (Throwable e) {
    e.printStackTrace();
}
}

    public static X509Certificate getPublicCertificate(String path) throws IOException, CertificateException {
      FileInputStream is = new FileInputStream(path);
      CertificateFactory cf = CertificateFactory.getInstance("X.509");
      X509Certificate cert = (X509Certificate) cf.generateCertificate(is);
      return cert;
    }
}
 
It's not a proof of the PoincarĂ© conjecture... it's a simple piece of code defining some security attributes in respect to the web service port. Two things are established: the client's identity and trust resolution. Well... in the code shown above only the first one is trully established, defining all appropriate information for accessing the client's private key. This is done by creating a ClientBSTCredentialProvider object, which (according to javaDoc) creates client BST credential provider for the indicated keystore, certificate alias and server certificate. There are many signatures for the ClientBSTCredentialProvider constructor but only use the other that also specifies the server certificate as well, otherwise nothing will work! Unfortunately I could not find it in the oracle's documentation and took me some time to figure out...
Client handles server identification by defining  a TrustManager implementation with a proper callback function being responsible for returning true or false based on the  validity of theserver certificate it will be fed with. In the code shown above we simply trust everything (which of course we shouldn't).

Almost all the information mentioned up to this point is available through the oracle's online documentation. Everything worked just fine when the client was tested in NetBeans. I should also state here that I use NetBeans instead of Eclipse, without any concrete arguments - just a matter of choice. I have been using Eclipse for a number of years in the past. It's perfectly OK and to be honest with better look-n-feel than NetBeans!

As far as the client classpath is concerned, I used weblogic.jar which can be found in WL_HOME/server/lib. Oracle states that wlfullclient.jar should be used instead for WebLogic 10+. I'll go into that in a bit... Generally, there are numerous clients for WebLogic server components. The analysis of them can be found here.

The problems begun when I tried to make a truly stand-alone client in a workstation with no WebLogic installation... In my next post I will share my torture... Stay tuned for some purely technical headaches! 
“Never memorize something that you can look up” - Albert Einstein