You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@cxf.apache.org by Sagi Mann <sa...@gmail.com> on 2008/10/07 19:58:13 UTC

[JSSESupport] SSL Error getting client Certs

Hello all,
I'm new to CXF and am currently evaluating it. I'm experiencing issues when
trying to set it up over HTTPS, as a web application that requires
CLIENT-CERT authentication.

My env is this:
JBoss 4.0.5 GA which runs my CXF-based web service, plus another separate
simple servlet web app.
My standalone webservice client is a CXF java application. I also have a
standalone java app that simply connects to the servlet (not the webservice)
using apache's httpclient. Both client apps set the same the javax.net.ssl.*
properties for key and trust stores.
All apps run on the same host.

When I invoke the servlet standalone client, it is able to connect to the
servlet and authenticate using its certificate - no problems.

When I invoke the webservice client, I get a 1 min timeout and after that a
long exception (I cut it short for clarity):

INFO: Interceptor has thrown exception, unwinding now
org.apache.cxf.interceptor.Fault: Could not send Message.
        at
org.apache.cxf.interceptor.MessageSenderInterceptor$MessageSenderEndingInterceptor.handleMessage(MessageSenderInterceptor.java:64)
        at
org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:220)
        ...
Caused by: java.net.SocketTimeoutException: Read timed out
        ... 7 more
Exception in thread "main" javax.xml.ws.soap.SOAPFaultException: Could not
send Message.
        ...
Caused by: org.apache.cxf.interceptor.Fault: Could not send Message.
        ... 2 more
Caused by: java.net.SocketTimeoutException: Read timed out
        ... 7 more
Java Result: 1


I also get on the server side (JBoss) log file:

2008-10-07 19:15:04,026 INFO  [org.apache.tomcat.util.net.jsse.JSSESupport]
SSL Error getting client Certs
javax.net.ssl.SSLHandshakeException: null cert chain
	at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Alerts.java:150)
        ...
2008-10-07 19:15:04,027 WARN  [org.apache.coyote.http11.Http11Processor]
Exception getting SSL attributes
javax.net.ssl.SSLHandshakeException: null cert chain
	at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Alerts.java:150)
        ...
2008-10-07 19:15:04,028 TRACE [org.jboss.security.SecurityAssociation]
clear, server=true


Both webservice app and servlet app use the SAME pre-configured jaas entry:

<jboss-web>
  
<security-domain>java:/jaas/servlet-clientcert-secdomain</security-domain>
</jboss-web>


What other info can I provide to diagnose this?

Here is what I could think of:

The jaas entry looks like this:

<server> 
    <mbean code="org.jboss.security.plugins.JaasSecurityDomain"
           name="jboss.security:service=SecurityDomain">
        <constructor>
            <arg type="java.lang.String"
value="servlet-clientcert-secdomain"/>
        </constructor>
        <attribute name="KeyStoreURL">v:\tmp\servertrust.jks</attribute>
        <attribute name="KeyStorePass">changeit</attribute>
        <depends>jboss.security:service=JaasSecurityManager</depends>
    </mbean>
</server>


And the login module looks like this (in login-config.xml):

  <application-policy name = "servlet-clientcert-secdomain">
    <authentication>

       <login-module code="org.jboss.security.auth.spi.BaseCertLoginModule"
          flag = "required">
          <module-option
name="password-stacking">useFirstPass</module-option>
          <module-option
name="securityDomain">java:/jaas/servlet-clientcert-secdomain</module-option>
       </login-module>

       <login-module
code="org.jboss.security.auth.spi.UsersRolesLoginModule"
          flag = "required">
          <module-option
name="password-stacking">useFirstPass</module-option>
          <module-option
name="usersProperties">clientcert-users.properties</module-option>
          <module-option
name="rolesProperties">clientcert-roles.properties</module-option>
       </login-module>
    </authentication>
 </application-policy>


The clientcert-users.properties is empty, and the
clientcert-roles.properties contains a mapping between the cert DN and the
'tester' role which is used by both web apps:

CN\=testhost7,\ OU\=orgunit,\ O\=org,\ L\=city,\ ST\=state,\ C\=st=tester


In both web apps, web.xml contains:

    <security-constraint>
        <display-name>Constraint1</display-name>
        <web-resource-collection>
            <web-resource-name>all</web-resource-name>
            <description/>
            <url-pattern>/*</url-pattern>
            <http-method>GET</http-method>
            <http-method>POST</http-method>
            <http-method>HEAD</http-method>
            <http-method>PUT</http-method>
            <http-method>OPTIONS</http-method>
            <http-method>TRACE</http-method>
            <http-method>DELETE</http-method>
        </web-resource-collection>
        <auth-constraint>
            <description/>
            <role-name>tester</role-name>
            </auth-constraint>
        </security-constraint>
    <login-config>
        <auth-method>CLIENT-CERT</auth-method>
        </login-config>
    <security-role>
        <description/>
        <role-name>tester</role-name>
    </security-role>


The webservice client code is the one generated by the cxf client code
generator:


public final class Hello_HelloImplPort_Client {
    
    private static final QName SERVICE_NAME = new QName("http://cxf/",
"HelloService");
    
    private Hello_HelloImplPort_Client() {
    }
    
    public static void main(String args[]) throws Exception {
        System.setProperty("javax.net.ssl.keyStore",
"v:/tmp/clientkey.jks");
        System.setProperty("javax.net.ssl.keyStorePassword", "changeit");
        System.setProperty("javax.net.ssl.trustStore",
"v:/tmp/clienttrust.jks");
        System.setProperty("javax.net.ssl.trustStorePassword", "changeit");
        
        URL wsdlURL = HelloService.WSDL_LOCATION;
        if (args.length > 0) {
            File wsdlFile = new File(args[0]);
            try {
                if (wsdlFile.exists()) {
                    wsdlURL = wsdlFile.toURI().toURL();
                } else {
                    wsdlURL = new URL(args[0]);
                }
            } catch (MalformedURLException e) {
                e.printStackTrace();
            }
        }
        
        HelloService ss = new HelloService(wsdlURL, SERVICE_NAME);
        Hello port = ss.getHelloImplPort();
        // start invoking the port's methods...
    }
}


The servlet client code is this:

            System.setProperty("javax.net.ssl.keyStore",
"v:/tmp/clientkey.jks");
            System.setProperty("javax.net.ssl.keyStorePassword",
"changeit");
            System.setProperty("javax.net.ssl.trustStore",
"v:/tmp/clienttrust.jks");
            System.setProperty("javax.net.ssl.trustStorePassword",
"changeit");
            URL url;
            url = new URL(args[0]);
            conmgr.getParams().setDefaultMaxConnectionsPerHost(10);
            HttpClient hc = new HttpClient();
            GetMethod method = new GetMethod(url.toURI().toString());
            hc.executeMethod(method);
            System.out.println(method.getResponseBodyAsString());
            method.releaseConnection();


both clients get the following parameter at runtime:

https://testhost7:8443/servlet-clientcert/TestServlet

-- 
View this message in context: http://www.nabble.com/-JSSESupport--SSL-Error-getting-client-Certs-tp19863789p19863789.html
Sent from the cxf-user mailing list archive at Nabble.com.


Re: [JSSESupport] SSL Error getting client Certs

Posted by Sagi Mann <sa...@gmail.com>.
I have an update, possibly with a solution that I found and works for me.
After googling for a few more hours and trying various things, I found out
that I can eliminate the error and get the method invocation working by:
1. properly (but oddly) setting the id of the HTTP conduit (see below)
2. adding the secureSocketProtocol="SSL" attribute to the
tlsClientParameters element in the xml

About #1, here are my findings, which are a bit odd. If anyone would care to
explain this, maybe I'm misusing the xml... or maybe it's sth for JIRA?

When using a <jaxws:client> element along with the appropriate code to use
it, both of the following conduit IDs work for me:
    <http:conduit name="*.http-conduit">
    <http:conduit name="{http://cxf/}HelloPort.http-conduit">

BUT: when I don't use a jaxws:client element, and create my service without
Spring, only the first id works, i.e. "*.http-conduit". The other does not
work.

Here is all my code and config:

Let's start with the jaxws client that is created with Spring:

config:

<?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:sec="http://cxf.apache.org/configuration/security"
       xmlns:http="http://cxf.apache.org/transports/http/configuration"
       xmlns:jaxws="http://cxf.apache.org/jaxws"
       xmlns:soap="http://cxf.apache.org/bindings/soap" 
       xsi:schemaLocation="
       http://cxf.apache.org/configuration/security
http://cxf.apache.org/schemas/configuration/security.xsd
       http://cxf.apache.org/transports/http/configuration
http://cxf.apache.org/schemas/configuration/http-conf.xsd
       http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
       http://cxf.apache.org/bindings/soap
http://cxf.apache.org/schemas/configuration/soap.xsd
       http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd"
>
    <http:conduit name="{http://cxf/}HelloPort.http-conduit">
    <!-- also works:
    <http:conduit name="*.http-conduit">
    -->
        
        <http:tlsClientParameters disableCNCheck="false"
secureSocketProtocol="SSL">
            <sec:trustManagers>
                <sec:keyStore type="JKS" password="changeit"
                              file="v:/tmp/clienttrust.jks"/>
            </sec:trustManagers>
            <sec:keyManagers keyPassword="changeit">
                <sec:keyStore type="JKS" password="changeit" 
                              file="v:/tmp/clientkey.jks"/>
            </sec:keyManagers>
            <sec:cipherSuitesFilter>
                <sec:include>.*_EXPORT_.*</sec:include>
                <sec:include>.*_EXPORT1024_.*</sec:include>
                <sec:include>.*_WITH_DES_.*</sec:include>
                <sec:include>.*_WITH_NULL_.*</sec:include>
                <sec:exclude>.*_DH_anon_.*</sec:exclude>
            </sec:cipherSuitesFilter>
        </http:tlsClientParameters>
    </http:conduit>
    <jaxws:client id="client1" 
                  serviceClass="cxf.client.Hello" 
                  address="https://mann2:8443/cxf-web-ws/services/hello"
    /> 
    
</beans> 

code:

        ClassPathXmlApplicationContext context = new
ClassPathXmlApplicationContext(
                new String[]{"JaxwsSecureClient.xml"});
        
        Hello port = (Hello)context.getBean("client1");
        // invoke methods here...


 Now the other client:

config:

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:sec="http://cxf.apache.org/configuration/security"
       xmlns:http="http://cxf.apache.org/transports/http/configuration"
       xmlns:jaxws="http://java.sun.com/xml/ns/jaxws"
       xsi:schemaLocation="
       http://cxf.apache.org/configuration/security
       http://cxf.apache.org/schemas/configuration/security.xsd
       http://cxf.apache.org/transports/http/configuration
       http://cxf.apache.org/schemas/configuration/http-conf.xsd
       http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
    
    <http:conduit name="*.http-conduit">
    <!-- DOES NOT WORK:
    <http:conduit name="{http://cxf/}HelloPort.http-conduit">
    -->
      
        <http:tlsClientParameters disableCNCheck="false"
secureSocketProtocol="SSL">
            <sec:trustManagers>
                <sec:keyStore type="JKS" password="changeit"
                              file="v:/tmp/clienttrust.jks"/>
            </sec:trustManagers>
            <sec:keyManagers keyPassword="changeit">
                <sec:keyStore type="JKS" password="changeit" 
                              file="v:/tmp/clientkey.jks"/>
            </sec:keyManagers>
            <sec:cipherSuitesFilter>
                <sec:include>.*_EXPORT_.*</sec:include>
                <sec:include>.*_EXPORT1024_.*</sec:include>
                <sec:include>.*_WITH_DES_.*</sec:include>
                <sec:include>.*_WITH_NULL_.*</sec:include>
                <sec:exclude>.*_DH_anon_.*</sec:exclude>
            </sec:cipherSuitesFilter>
        </http:tlsClientParameters>
    </http:conduit>
</beans> 

code:

        SpringBusFactory bf = new SpringBusFactory();
        URL busFile = null;
        busFile =
Hello_HelloImplPort_Client.class.getResource("/WibbleClient.xml");
        Bus bus = bf.createBus(busFile.toString());
        bf.setDefaultBus(bus);
        cxf.client.HelloService ss = new HelloService(wsdlURL,
SERVICE_NAME);
        cxf.client.Hello port = ss.getHelloImplPort();
        // invoke methods here...

-- 
View this message in context: http://www.nabble.com/-JSSESupport--SSL-Error-getting-client-Certs-tp19863789p19889913.html
Sent from the cxf-user mailing list archive at Nabble.com.


Re: [JSSESupport] SSL Error getting client Certs

Posted by Sagi Mann <sa...@gmail.com>.
I activated the SSL debug on both JBoss (server) and java (client) sides.

On the server side, I see a lot of:

2008-10-08 23:39:59,828 INFO  [STDOUT] .
2008-10-08 23:39:59,828 INFO  [STDOUT] .
2008-10-08 23:39:59,828 INFO  [STDOUT] .
2008-10-08 23:39:59,828 INFO  [STDOUT] : 

But somewhere right before the exception I see:

2008-10-08 23:39:59,832 INFO  [STDOUT] .
2008-10-08 23:39:59,833 INFO  [STDOUT] *** Certificate chain
2008-10-08 23:39:59,833 INFO  [STDOUT] ***
2008-10-08 23:39:59,833 INFO  [STDOUT] %% Invalidated:  [Session-2,
TLS_DHE_DSS_WITH_AES_128_CBC_SHA]
2008-10-08 23:39:59,833 INFO  [STDOUT] http-Mann2%2F192.168.1.4-8443-2
2008-10-08 23:39:59,833 INFO  [STDOUT] , SEND TLSv1 ALERT:  
2008-10-08 23:39:59,833 INFO  [STDOUT] fatal, 
2008-10-08 23:39:59,834 INFO  [STDOUT] description = bad_certificate
2008-10-08 23:39:59,834 INFO  [STDOUT] Padded plaintext before ENCRYPTION: 
len = 32


On the client side, I get a lot of output, but I don't really know how to
read it... maybe someone can help? see attached.
http://www.nabble.com/file/p19888309/client.log client.log 
-- 
View this message in context: http://www.nabble.com/-JSSESupport--SSL-Error-getting-client-Certs-tp19863789p19888309.html
Sent from the cxf-user mailing list archive at Nabble.com.


Re: [JSSESupport] SSL Error getting client Certs

Posted by Daniel Kulp <dk...@apache.org>.
The only thing I can think of is to run your client with:
-Djavax.net.debug=all 

and see what it's trying to do with the handshakes and stuff.   That MAY help 
diagnose things.   In theory, what you are doing is correct.


Dan


On Wednesday 08 October 2008 3:08:24 pm Sagi Mann wrote:
> I have an update:
>
> I also tried setting up a "conduit" as described in the CXF
> http://cwiki.apache.org/CXF20DOC/client-http-transport-including-ssl-suppor
>t.html website
>
> and I got the same results:
>
> <beans xmlns="http://www.springframework.org/schema/beans"
>   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
>   xmlns:sec="http://cxf.apache.org/configuration/security"
>   xmlns:http="http://cxf.apache.org/transports/http/configuration"
>   xmlns:jaxws="http://java.sun.com/xml/ns/jaxws"
>   xsi:schemaLocation="
>            http://cxf.apache.org/configuration/security
>            http://cxf.apache.org/schemas/configuration/security.xsd
>            http://cxf.apache.org/transports/http/configuration
>            http://cxf.apache.org/schemas/configuration/http-conf.xsd
>            http://www.springframework.org/schema/beans
>            http://www.springframework.org/schema/beans/spring-beans.xsd">
>
>   <http:conduit name="{https://cxf}HelloImplPort.http-conduit">
>     <http:tlsClientParameters disableCNCheck="true"
> secureSocketProtocol="SSL">
>       <sec:trustManagers>
>           <sec:keyStore type="JKS" password="changeit"
>                file="v:/tmp/clienttrust.jks"/>
>       </sec:trustManagers>
>       <sec:keyManagers keyPassword="changeit">
>            <sec:keyStore type="JKS" password="changeit"
>                 file="v:/tmp/clientkey.jks"/>
>       </sec:keyManagers>
>       <sec:cipherSuitesFilter>
>         <sec:include>.*_EXPORT_.*</sec:include>
>         <sec:include>.*_EXPORT1024_.*</sec:include>
>         <sec:include>.*_WITH_DES_.*</sec:include>
>         <sec:include>.*_WITH_NULL_.*</sec:include>
>         <sec:exclude>.*_DH_anon_.*</sec:exclude>
>       </sec:cipherSuitesFilter>
>     </http:tlsClientParameters>
>    </http:conduit>
> </beans>
>
>
> This is a copy of the WibbleClient.xml file from the wsdl_first_https with
> the obvious needed changes to the namespace and port. Note that the
> wsdl_first_https sample in the CXF distribution package works fine. But in
> that project, the webservice is not running in side an app server, but as a
> standalone app. And for those cases, CXF provides the option to configure
> the server key/truststore within the cxf configuration. This is not
> possible AFAIK for JAXWS endpoints which run as a servlet in an app server.
>
> In my webservice, this is the cxf.xml (you can see there is no mentioning
> of key or trust stores):
>
> <?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"
>        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">
>
>     <import resource="classpath:META-INF/cxf/cxf.xml" />
>     <import resource="classpath:META-INF/cxf/cxf-extension-soap.xml"/>
>     <import resource="classpath:META-INF/cxf/cxf-servlet.xml" />
>     <jaxws:endpoint id="hello"
>                     implementor="cxf.HelloImpl"
>                     address="/hello"/>
> </beans>
>
> any ideas on how to get client-cert authentication working for a web
> service running in an app server??
> thanks.



-- 
Daniel Kulp
dkulp@apache.org
http://dankulp.com/blog

Re: [JSSESupport] SSL Error getting client Certs

Posted by Sagi Mann <sa...@gmail.com>.
I have an update:

I also tried setting up a "conduit" as described in the CXF 
http://cwiki.apache.org/CXF20DOC/client-http-transport-including-ssl-support.html
website 

and I got the same results:

<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:sec="http://cxf.apache.org/configuration/security"
  xmlns:http="http://cxf.apache.org/transports/http/configuration"
  xmlns:jaxws="http://java.sun.com/xml/ns/jaxws"
  xsi:schemaLocation="
           http://cxf.apache.org/configuration/security
           http://cxf.apache.org/schemas/configuration/security.xsd
           http://cxf.apache.org/transports/http/configuration
           http://cxf.apache.org/schemas/configuration/http-conf.xsd
           http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans.xsd">

  <http:conduit name="{https://cxf}HelloImplPort.http-conduit">
    <http:tlsClientParameters disableCNCheck="true"
secureSocketProtocol="SSL">
      <sec:trustManagers>
          <sec:keyStore type="JKS" password="changeit"
               file="v:/tmp/clienttrust.jks"/>
      </sec:trustManagers>
      <sec:keyManagers keyPassword="changeit">
           <sec:keyStore type="JKS" password="changeit" 
                file="v:/tmp/clientkey.jks"/>
      </sec:keyManagers>
      <sec:cipherSuitesFilter>
        <sec:include>.*_EXPORT_.*</sec:include>
        <sec:include>.*_EXPORT1024_.*</sec:include>
        <sec:include>.*_WITH_DES_.*</sec:include>
        <sec:include>.*_WITH_NULL_.*</sec:include>
        <sec:exclude>.*_DH_anon_.*</sec:exclude>
      </sec:cipherSuitesFilter>
    </http:tlsClientParameters>
   </http:conduit>
</beans> 


This is a copy of the WibbleClient.xml file from the wsdl_first_https with
the obvious needed changes to the namespace and port. Note that the
wsdl_first_https sample in the CXF distribution package works fine. But in
that project, the webservice is not running in side an app server, but as a
standalone app. And for those cases, CXF provides the option to configure
the server key/truststore within the cxf configuration. This is not possible
AFAIK for JAXWS endpoints which run as a servlet in an app server.

In my webservice, this is the cxf.xml (you can see there is no mentioning of
key or trust stores):

<?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"
       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">
    
    <import resource="classpath:META-INF/cxf/cxf.xml" />
    <import resource="classpath:META-INF/cxf/cxf-extension-soap.xml"/>
    <import resource="classpath:META-INF/cxf/cxf-servlet.xml" />
    <jaxws:endpoint id="hello"
                    implementor="cxf.HelloImpl"
                    address="/hello"/>
</beans>

any ideas on how to get client-cert authentication working for a web service
running in an app server??
thanks.
-- 
View this message in context: http://www.nabble.com/-JSSESupport--SSL-Error-getting-client-Certs-tp19863789p19885396.html
Sent from the cxf-user mailing list archive at Nabble.com.