I am using JBoss AS 6.1 with CXF 2.3.1 bundled and I believe the version
of WSS4J included in that is 1.5.8.   My version of the JDK is 1.6.

I have been struggling for several days now to get a simple test going
using SOAPUi 4.5.1 as the client.  I have reviewed the WS-Security spec,
looked at numerous tutorials, including the documentation on the CXF
website and Mr. Mazza's blog describing the process.  I cannot be sure
whether the problem is SOAPUi or my service.  In any case, I am sort of
constrained to use this old version of JBoss AS along with it's old
versions of CXF and WSS4j, so many of the features described on the CXF
tutorial are not applicable, I believe, for example the
DefaultCryptoCoverageChecker.  I think I would prefer to use the
interceptors rather than the WS-Policy as I am not using the WSDL first
method.  I have not tried the WS-Policy annotations.

I have a server.keystore which contains the public/private key pair for
the server.  Into this I have also imported the client certs for two
test clients, client1 and client2.
So, I have the inverse, a client1.keystore with client1 public/private
keys and the server public key certificate is imported into this file.
Likewise for client2.  The aliases for these are server, client1, and
client2, respectively.  The passwords for all the keystores and aliases
is currently just "password".


First, here is an excerpt of my service implementation:

@WebService(serviceName = "My_Web_Service", name = "MyWebService",
targetNamespace = "http://mycompany.com";)
@SOAPBinding(style = SOAPBinding.Style.DOCUMENT, use =
SOAPBinding.Use.LITERAL, parameterStyle =
SOAPBinding.ParameterStyle.WRAPPED)
//@EndpointConfig(configFile = "WEB-INF/jaxws-endpoint-config.xml",
configName  = "Standard WSSecurity Endpoint")
public class MyWebService {

        private static Log log = LogFactory.getLog(MyWebService.class);

        /**
         * Returns the list of Area of Operation codes.
         *
         * @return List<AreaOfOperationsBean>
         */
        @WebMethod()
        @WebResult(name = "payLoad")
        public PayLoad getAreaOfOperationsData()

        {
                log.debug("Req method: getCipAreaOfOperationsData!");

                [... setup the payload object deleted]
                return p;

        } // getAreaOfOperationsData()

[...]
}

Configuration of the WSS4J interceptors is done using the
jbossws-cxf.xml file which is in the WEB-INF directory of my service
WAR:


<beans
  xmlns='http://www.springframework.org/schema/beans'
  xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
  xmlns:beans='http://www.springframework.org/schema/beans'
  xmlns:jaxws='http://cxf.apache.org/jaxws'
  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'>


  <bean id="Sign_Request"
class="org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor">
    <constructor-arg>
      <map>
        <entry key="action" value="Timestamp Signature"/>
        <entry key="signaturePropFile"  value="security.properties"/>
        <entry key="decryptionPropFile" value="security.properties"/>
        <entry key="passwordCallbackClass"
value="com.mycompany.ws.common.KeystorePasswordCallback"/>
      </map>
    </constructor-arg>
  </bean>


  <bean id="Sign_Response"
class="org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor">
    <constructor-arg>
      <map>
        <entry key="action" value="Timestamp Signature Encrypt"/>
        <entry key="user" value="server "/>
        <entry key="signaturePropFile"  value="security.properties"/>
        <entry key="encryptionPropFile" value="security.properties"/>
       <!-- <entry key="encryptionUser" value="useReqSigCert"/>  -->
        <entry key="encryptionUser" value="client1 " />
        <entry key="signatureKeyIdentifier" value="DirectReference"/>
        <entry key="encryptionKeyIdentifier" value="DirectReference" /> 
        <entry key="passwordCallbackClass"
value="com.mycompany.ws.common.KeystorePasswordCallback"/>
        <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.o
rg/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="encryptionKeyTransportAlgorithm"
value="http://www.w3.org/2001/04/xmlenc#rsa-1_5"/>
        <entry key="encryptionSymAlgorithm"
value="http://www.w3.org/2001/04/xmlenc#tripledes-cbc"/>
      </map>
    </constructor-arg>
  </bean>

  <jaxws:endpoint
    id='CipService'
    address='http://@jboss.bind.address@:8080/ws-cip'
    implementor='com.mycompany.ws.MyService'>
    <jaxws:invoker>
      <bean class='org.jboss.wsf.stack.cxf.InvokerJSE'/>
    </jaxws:invoker>
    <jaxws:outInterceptors>
        <bean
class="org.apache.cxf.binding.soap.saaj.SAAJOutInterceptor"/>
        <ref bean="Sign_Response"/>
    </jaxws:outInterceptors>

    <jaxws:inInterceptors>
        <ref bean="Sign_Request"/>
        <bean
class="org.apache.cxf.binding.soap.saaj.SAAJInInterceptor"/>
    </jaxws:inInterceptors>

  </jaxws:endpoint>
</beans>

You'll note that I have encryptionUser = useReqSigCert commented out at
the moment because I haven't been able to get it working, so I'm trying
to just hardcode the client alias, but alas, that isn't working either
as you will see.

My password callback handler is simple:

 package com.mycompany.ws.common;

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.log4j.Logger;
import org.apache.ws.security.WSPasswordCallback;

public class KeystorePasswordCallback implements CallbackHandler {

        private static Logger log = Logger
                        .getLogger(KeystorePasswordCallback.class);
        private Map<String, String> passwords = new HashMap<String,
String>();

        public KeystorePasswordCallback() {
                log.info("Creating ws security callback handler...");
                passwords.put("server ", "password");
                passwords.put("client1 ", "password");
                passwords.put("client2 ", "password");
        }

        public void handle(Callback[] callbacks) throws IOException,
                        UnsupportedCallbackException {
                log.info("KeystorePasswordCallback invoked handle");
                for (int i = 0; i < callbacks.length; i++) {
                        WSPasswordCallback pc = (WSPasswordCallback)
callbacks[i];
                        String id = pc.getIdentifier();
                        log.info("Looking up password for identifier: "
+ id);
                        String pass = passwords.get(pc.getIdentifier());
                        if (pass != null) {
                                pc.setPassword(pass);
                                return;
                        }
                }
        }

        public void setAliasPassword(String alias, String password) {
                passwords.put(alias, password);
        }
}


My security.properties file is located in the WEB-INF directory (since
my service is a POJO):

org.apache.ws.security.crypto.provider=org.apache.ws.security.components
.crypto.Merlin
org.apache.ws.security.crypto.merlin.keystore.type=jks
org.apache.ws.security.crypto.merlin.keystore.password=password
org.apache.ws.security.crypto.merlin.keystore.alias=server
org.apache.ws.security.crypto.merlin.file=server.keystore


Since I have the client certs with their public keys in there, I don't
think I need a separate truststore.

OK, so that's all of the server side.  My goal is to test this using
soapUi version 4.5.1.  This version of soapUi is using an embedded Java
JRE 1.7 if that makes a difference.
I hope someone is familiar with it, but basically, under my project
configuration I have defined the two client keystores, client1.keystore
and client2.keystore and entered their password.
My "incoming" WS-Security configuration is simple;  there isn't much to
configure there:  I have specified the decrypt and signature keystores
as client1.keystore and included the password.

For the "outgoing" WS-Security configuration, I currently have a default
Username/alias of "client1", the default password of "password", no
actor specified, and "Must Understand" is not checked.  For  the
actions:

"Timestamp" with a TTL of 1800000 and millisecond precision.

"Signature" with
        Keystore = client1.keystore
        Alias = client1
        Password = password
        Key Identifier Type:    [options are "Issurer Name and Serial
Number", "Binary Security Token",  "X509 Certificate", and "Subject Key
Identifier"].  I have tried all of them and my current setting is
"Binary Security Token".  (In the WS-Security spec it said an X.509 cert
was an example of such)
        Signature Algorithm is:
http://www.w3.org/2000/09/xmldsig#rsa-sha1
        Signature Canonicalization is:
http://www.w3.org/2001/10/xml-exc-c14n#
        Digest Algorithm is: http://www.w3.org/2000/09/xmldsig#sha1
        Use Single Certificate: true
        I currently do not have any Parts specified.  I think this may
be incorrect, or at least not recommended.


OK, so when I create a request in SoapUi and attach the "outgoing"
ws-security stuff and send it to the server, I see this in the console:

17:44:10,348 INFO  [com.mycompany.ws.common.KeystorePasswordCallback]
Creating ws security callback handler...
17:44:10,348 INFO  [com. mycompany.ws.common.KeystorePasswordCallback]
KeystorePasswordCallback invoked handle
17:44:10,348 INFO  [com. mycompany.ws.common.KeystorePasswordCallback]
Looking up password for identifier: server

And, then, in the soapUi error log, I see this stack trace:

Wed Apr 17 17:44:10 CDT
2013:ERROR:org.apache.ws.security.WSSecurityException: The signature or
decryption was invalid
   org.apache.ws.security.WSSecurityException: The signature or
decryption was invalid
        at
org.apache.ws.security.processor.EncryptedKeyProcessor.handleToken(Encry
ptedKeyProcessor.java:106)
        at
org.apache.ws.security.WSSecurityEngine.processSecurityHeader(WSSecurity
Engine.java:396)
        at
org.apache.ws.security.WSSecurityEngine.processSecurityHeader(WSSecurity
Engine.java:304)
        at
org.apache.ws.security.WSSecurityEngine.processSecurityHeader(WSSecurity
Engine.java:249)
        at
com.eviware.soapui.impl.wsdl.support.wss.IncomingWss.processIncoming(Inc
omingWss.java:121)
        at
com.eviware.soapui.impl.wsdl.submit.transports.http.support.attachments.
WsdlSinglePartHttpResponse.processIncomingWss(WsdlSinglePartHttpResponse
.java:49)
        at
com.eviware.soapui.impl.wsdl.submit.transports.http.support.attachments.
WsdlSinglePartHttpResponse.<init>(WsdlSinglePartHttpResponse.java:38)
        at
com.eviware.soapui.impl.wsdl.submit.filters.HttpPackagingResponseFilter.
wsdlRequest(HttpPackagingResponseFilter.java:71)
        at
com.eviware.soapui.impl.wsdl.submit.filters.HttpPackagingResponseFilter.
afterAbstractHttpResponse(HttpPackagingResponseFilter.java:48)
        at
com.eviware.soapui.impl.wsdl.submit.filters.AbstractRequestFilter.afterR
equest(AbstractRequestFilter.java:64)
        at
com.eviware.soapui.impl.wsdl.submit.transports.http.HttpClientRequestTra
nsport.sendRequest(HttpClientRequestTransport.java:297)
        at
com.eviware.soapui.impl.wsdl.WsdlSubmit.run(WsdlSubmit.java:123)
        at java.util.concurrent.Executors$RunnableAdapter.call(Unknown
Source)
        at java.util.concurrent.FutureTask$Sync.innerRun(Unknown Source)
        at java.util.concurrent.FutureTask.run(Unknown Source)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown
Source)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown
Source)
        at java.lang.Thread.run(Unknown Source)
   Caused by: org.apache.ws.security.WSSecurityException: General
security error (The private key for the supplied alias does not exist in
the keystore)
        at
org.apache.ws.security.components.crypto.Merlin.getPrivateKey(Merlin.jav
a:661)
        at
org.apache.ws.security.processor.EncryptedKeyProcessor.handleToken(Encry
ptedKeyProcessor.java:103)
        ... 17 more
   Caused by: java.security.UnrecoverableKeyException: Cannot recover
key
        at sun.security.provider.KeyProtector.recover(Unknown Source)
        at sun.security.provider.JavaKeyStore.engineGetKey(Unknown
Source)
        at sun.security.provider.JavaKeyStore$JKS.engineGetKey(Unknown
Source)
        at java.security.KeyStore.getKey(Unknown Source)
        at
org.apache.ws.security.components.crypto.Merlin.getPrivateKey(Merlin.jav
a:647)
        ... 18 more


But, I know that the alias DOES exist in the keystore.   I was confused
by the fact that the PasswordCallbackhandler is looking up the password
for "server", so I tried putting "client1" in there instead of "
useReqSigCert" for that reason, but the result is the same.  I read
somewhere on a JBoss forum something about useReqSigCert not working
correctly unless the request was also encrypted, so I have tried also
encrypting the request from SoapUi.

When encrypting from the client, I add a third action "Encryption" using
the following settings:
Keystore = client1.keystore
Alias = server
Password = "password"
Key Identifier Type  = "Binary Security Token"  [ in addition to the
options for signing, it also adds "Embedded KeyInfo", "Embed Security
Token Reference", and "Thumbprint SHA1 Identifier".  Again, I've tried
them all with the exception of Embedded Key Info because I am unclear
what to enter for "Embedded KeyName" and "Embedded Key Password"

Embedded Keyname = blank
Embedded Key Password = blank
Symmetric Encoding Algorithm =
http://www.w3.org/2001/04/xmlenc#tripledes-cbc
Key Encryption Algorithm = http://www.w2.org/2001/04/xmlenc#rsa-1_5
Create Encrypted Key = checked.  (I've tried it both ways)
Parts = blank.  (My understanding is that when parts are blank, the
entire SOAP message is signed or encrypted.  Again, perhaps not
recommended?)

When I do that, I get an error on the server:
org.apache.cxf.interceptor.Fault: Message part
{http://www.w3.org/2001/04/xmlenc#}EncryptedData was not recognized.
(Does it exist in service WSDL?)

Ok, so I uncheck the "Create Encrypted Key" and try again and I get:
19:06:57,547 INFO  [com.mycompany.ws.common.KeystorePasswordCallback]
Creating Akimeka ws security callback handler...
19:06:57,547 INFO  [com.mycompany.ws.common.KeystorePasswordCallback]
KeystorePasswordCallback invoked handle
19:06:57,547 INFO  [com.mycompany.ws.common.KeystorePasswordCallback]
Looking up password for identifier: null
19:06:57,547 WARN  [org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor]
: org.apache.ws.security.WSSecurityException: The signature or
decryption was invalid (Unsupported key identification)

I switch to Key Identifier = "X509 Certificate"  I get the same error.
I switch to "Issuer Name and Serial", same error.  "Embedded KeyInfo"
gets me an "actions mismatch" error on the server.

And, so you get the drift:  I'm basically a chimp with a keyboard here,
trying to stumble upon a Shakespearean sonnet.  I have no idea what the
correct settings should be.  (Although I swear I have some dim
recollection of getting client to server decrypting working at some
point over the past several days.)

So...  I feel like what I want to do should be very simple, but I'm not
sure how to proceed at this point.  I may be dealing with problems with
SoapUi, with this old version of CXF/WSS4j/Jboss, or just plain
ignorance, but I sure could use some help.

Sorry for the long mail, thanks in advance.









NOTICE: This transmission (including all attachments) is company confidential, 
is intended only for the individual or entity named above, and is likely to 
contain privileged, proprietary and confidential information that is exempt 
from disclosure requests under applicable law. If you are not the intended 
recipient, you are hereby notified that any disclosure, copying, distribution, 
use of or reliance upon any of the information contained in this transmission 
is strictly prohibited. Any inadvertent or unauthorized disclosure shall not 
compromise or waive the confidentiality of this transmission. If you have 
received this transmission in error, please forward this message immediately to 
[email protected] <mailto:[email protected]>  and delete or otherwise 
remove this email from your system.  Thank you

Reply via email to