Sunday 17 May 2015

HTTPS security for Webservices with cxf using embedded Jetty

HTTPS is a communications protocol for secure all communication over a computer network, with especially wide deployment on the Internet. The main purpose of HTTPS is to provide authentication of web application. It uses following two secure protocol layer

    - SSL (Secure Sockets Layer)
    - TLS (Transport Layer Security)

Both of these use asymmetric public key Infrastructure (PKI) system.

An asymmetric system uses two 'keys' to encrypt communications, a 'public' key and a 'private' key. Anything encrypted with the public key can only be decrypted by the private key and vice-versa. more details can be found at HTTPS .

In this blog instruction we will discuss how to enable transport layer security for web application using cxf embedded jetty.
We already implemented sample web application using cxf embedded jetty Webservice with cxf using embedded Jetty . This time we will just secure this application by changing configuration.

  • Keystore, Truststore, Certificates.
  • We will use keytool command to prepare keystore , truststore and importing exporting certificates.
    For example purpose we used following command to prepare required Keystore , Truststore and Certificates. It is not required to use example files user always have option to use their own keystore , truststore and certificates.
     
     keytool -v -genkey -alias KServer -keyalg RSA -keystore kblogger.jks -dname "cn=localhost, ou=KBLOG, o=blogger, c=IN" -storepass blogger -keypass blogger -validity 360
     keytool -list -v -keystore kblogger.jks  -storepass blogger -keypass blogger
     keytool -export -v -alias KServer -file client.cer -keystore kblogger.jks -storepass blogger -keypass blogger -validity 360
     keytool -import -v -trustcacerts -alias KServer -file client.cer -keystore truststore.jks -storepass blogger -keypass blogger -validity 360
     keytool -import -v -alias kclient -file client.cer -keystore kClient.jks -storepass blogger -keypass blogger -validity 360
     
  • CXF embedded Jetty configuration
  • Entire cxf embabded jetty configuration devided in following two part.

    • Transport layer secuirty configuration(httpj:identifiedTLSServerParameters)
    • Jetty engine configuration (httpj:engine)

         1. Transport layer secuirty (httpj:identifiedTLSServerParameters)


    Specifies a reusable set of properties for securing an HTTP server. It has a single attribute, id, that specifies a unique identifier by which the property set can be referred.
    We will use this element to configure HTTP transport layer security.
    httpj:tlsServerParameters Specifies a set of properties for configuring the security used for the specific Jetty instance.
    See the TLS Configuration page for more information.

    Edit a xml file name cxf-jetty-beans.xml under WEB-INF/conf and add following configuration snippets

     
      <httpj:tlsServerParameters> 
        <sec:keyManagers keyPassword="blogger"> 
          <sec:keyStore type="JKS" password="blogger" file="D:\kblogger.jks" /> 
        </sec:keyManagers> 
        <sec:trustManagers> 
          <sec:keyStore type="JKS" password="blogger" file="D:\truststore.jks" /> 
        </sec:trustManagers> 
        <sec:cipherSuitesFilter> 
          <!-- these filters ensure that a ciphersuite with export-suitable or null encryption is used, 
             but exclude anonymous Diffie-Hellman 
             key change as this is vulnerable to man-in-the-middle attacks --> 
          <sec:include>.*_EXPORT_.*</sec:include> 
          <sec:include>.*_EXPORT1024_.*</sec:include> 
          <sec:include>.*_WITH_DES_.*</sec:include> 
          <sec:include>.*_WITH_AES_.*</sec:include> 
          <sec:include>.*_WITH_NULL_.*</sec:include> 
          <sec:exclude>.*_DH_anon_.*</sec:exclude> 
        </sec:cipherSuitesFilter> 
        <sec:clientAuthentication want="true" required="true" /> 
      </httpj:tlsServerParameters> 
     
    Following table explain the elements and attributes of complexType TLSServerParametersIdentifiedType that we used in above xml snippet for configuring transport layer security.

    ComplexType :- TLSServerParametersIdentifiedType
    name space :- http://cxf.apache.org/configuration/security
    xsd path :- http://cxf.apache.org/schemas/configuration/security.xsd
    Element/(a)Attribute Type Description
    (a)id String Unique idetifier of TLS server parameters
    tlsServerParameters TLSServerParametersType Specifies an instance of the security parameters for the Jetty instance.
    keyManagers KeyManagersType This element contains the KeyManagers specification.
    (a)keyPassword String This attribute specified the password that unlock keys within the keystore.
    keyStore KeyStoreType A KeyStoreType represents the information needed to load a collection of key and certificate material from a desired location. The "url", "file", and "resource" attributes are intended to be mutually exclusive, though this assumption is not encoded in schema. The precedence order observed by the runtime is 1) "file", 2) "resource", and 3) "url".
    (a)type String This attribute specifies the type of the keystore. It is highly correlated to the provider. Most common examples are "jks" "pkcs12".
    (a)password String This attribute specifes the integrity password for the keystore. This is not the password that unlock keys within the keystore.
    (a)file String This attribute specifies the File location of the keystore. This element should be a properly accessible file from the working directory. Only one attribute of "url", "file", or "resource" is allowed.
    trustManagers TrustManagersType This structure contains the specification of JSSE TrustManagers for a single Keystore used for trusted certificates.
    keyStore KeyStoreType
    cipherSuitesFilter FiltersType This element contains the filters of the supported CipherSuites that will be supported and used if available.
    include String Include all the possible specified ciphersuite.
    exclude String Exclude all the possible specified ciphersuite.
    clientAuthentication ClientAuthentication This element contains Client Authentication specification.
    (a)want String This Boolean attribute specifies if client authentication should be requested. Example value true or false.
    (a)required String This Boolean attribute specifies if client authentication should be required. Example value true or false.

         2. Jetty engine configuration (httpj:engine)


    Referring tlsServerParameters in jetty engine configuration
     
     <httpj:engine port="666"> 
       <!-- Use "secureJetty" in jetty engine to activate https security --> 
       <httpj:tlsServerParametersRef id="secureJetty" /> 
       <!-- jetty thread pooling --> 
       <httpj:threadingParameters minThreads="5" maxThreads="15" /> 
       <httpj:handlers> 
         <ref bean="defaultHandler" /> 
       </httpj:handlers> 
       <httpj:sessionSupport>true</httpj:sessionSupport> 
     </httpj:engine> 
     
    Finally cxf-jetty-beans.xml will looks like following
     
     <?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:cxf="http://cxf.apache.org/core"
      xmlns:sec="http://cxf.apache.org/configuration/security"
      xmlns:http-conf="http://cxf.apache.org/transports/http/configuration"
      xmlns:jaxws="http://cxf.apache.org/jaxws"
      xmlns:http="http://cxf.apache.org/transports/http/configuration"
      xmlns:httpj="http://cxf.apache.org/transports/http-jetty/configuration"
      xmlns:wsa="http://cxf.apache.org/ws/addressing"
      xmlns:wsrm-policy="http://schemas.xmlsoap.org/ws/2005/02/rm/policy"
      xmlns:wsrm-mgr="http://cxf.apache.org/ws/rm/manager"
      xsi:schemaLocation="
           http://cxf.apache.org/core
           http://cxf.apache.org/schemas/core.xsd
           http://cxf.apache.org/configuration/security
           http://cxf.apache.org/schemas/configuration/security.xsd
           http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans.xsd
           http://cxf.apache.org/transports/http/configuration
           http://cxf.apache.org/schemas/configuration/http-conf.xsd
           http://cxf.apache.org/transports/http-jetty/configuration
           http://cxf.apache.org/schemas/configuration/http-jetty.xsd
           http://schemas.xmlsoap.org/ws/2005/02/rm/policy
           http://schemas.xmlsoap.org/ws/2005/02/rm/wsrm-policy.xsd
           http://cxf.apache.org/ws/rm/manager
           http://cxf.apache.org/schemas/configuration/wsrm-manager.xsd
           http://cxf.apache.org/transports/http/configuration
           http://cxf.apache.org/schemas/configuration/http-conf.xsd
           http://cxf.apache.org/jaxws
           http://cxf.apache.org/schemas/jaxws.xsd">
      <!-- import resource -->
      <import resource="classpath:META-INF/cxf/cxf*.xml" />
      <bean id="biosocket" class="org.eclipse.jetty.server.bio.SocketConnector">
       <property name="host" value="localhost" />
       <property name="port" value="9003" />
      </bean>
      <bean id="defaultHandler" class="org.eclipse.jetty.server.handler.DefaultHandler" />
      <!-- Cxf Bus implementation -->
      <cxf:bus>
       <!-- Cxf features implementation global -->
       <cxf:features>
        <!-- cxf logging implementation -->
        <cxf:logging />
       </cxf:features>
      </cxf:bus>
      <!-- Jetty server configuration and implementation -->
      <httpj:engine-factory bus="cxf">
       <!-- Transport layer secuirty -->
       <httpj:identifiedTLSServerParameters id="secureJetty">
        <httpj:tlsServerParameters>
         <sec:keyManagers keyPassword="blogger">
          <sec:keyStore type="JKS" password="blogger" file="D:/kblogger.jks" />
         </sec:keyManagers>
         <sec:trustManagers>
          <sec:keyStore type="JKS" password="blogger" file="D:/truststore.jks" />
         </sec:trustManagers>
          <sec:cipherSuitesFilter>
         <!-- these filters ensure that a ciphersuite with export-suitable or null encryption is used, but exclude anonymous Diffie-Hellman
          key change as this is vulnerable to man-in-the-middle attacks -->
          <sec:include>.*_EXPORT_.*</sec:include>
          <sec:include>.*_EXPORT1024_.*</sec:include>
          <sec:include>.*_WITH_DES_.*</sec:include>
          <sec:include>.*_WITH_AES_.*</sec:include>
          <sec:include>.*_WITH_NULL_.*</sec:include>
          <sec:exclude>.*_DH_anon_.*</sec:exclude>
          </sec:cipherSuitesFilter>
          <!-- want="true"  -->
         <sec:clientAuthentication want="true" required="true" />
        </httpj:tlsServerParameters>
       </httpj:identifiedTLSServerParameters>
       <!-- jetty engine configuration-->
       <httpj:engine port="666">
        <!-- Use "secureJetty" in jetty engine to activate https security -->
        <httpj:tlsServerParametersRef id="secureJetty" />
        <!-- jetty thread pooling -->
        <httpj:threadingParameters minThreads="5" maxThreads="15" />
        <httpj:handlers>
         <ref bean="defaultHandler" />
         <httpj:sessionSupport>true</httpj:sessionSupport> 
        </httpj:handlers>
       </httpj:engine>
      </httpj:engine-factory>
     </beans>
     

    Modify exsiting cxf-beans.xml WEB-INF/conf/cxf-beans.xml add following xml snippet.

     
      <?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">
       <jaxws:endpoint xmlns:tns="http://poc.kaustuv.com/ws/service/greetings"
        id="greetings"
        implementor="com.kaustuv.poc.ws.service.greetings.GreetingsImpl"
        wsdlLocation="WEB-INF/wsdl/Sample.wsdl"
        endpointName="tns:GreetingsPort"
        serviceName="tns:GreetingsService"
        address="https://localhost:666/Greetings">
        <!-- to use the catalina default 8443 port user address="/Greetings" -->
       </jaxws:endpoint>
      </beans>
     
  • Export and package this as war.Destination path %JBOSS_HOME%\server\default
  • Open command prompt and go to directory %JBOSS_HOME\bin
  • Execute run.bat -c default -b 0.0.0.0
  • Deployement will be sucessfull according to above instructions. following log message will apear in jboss console log.
     
     main:21:34:55,310:INFO:[STDERR]:May 14, 2015 9:34:55 PM org.apache.cxf.service.factory.ReflectionServiceFactoryBean buildServiceFromWSDL
     INFO: Creating Service {http://poc.kaustuv.com/ws/service/greetings}GreetingsService from WSDL: WEB-INF/wsdl/Sample.wsdl
     main:21:34:56,283:INFO:[STDERR]:May 14, 2015 9:34:56 PM org.apache.cxf.endpoint.ServerImpl initDestination
     INFO: Setting the server's publish address to be https://localhost:666/Greetings
     main:21:34:56,456:INFO:[STDERR]:May 14, 2015 9:34:56 PM org.eclipse.jetty.server.Server doStart
     INFO: jetty-7.5.4.v20111024
     main:21:34:56,963:INFO:[STDERR]:May 14, 2015 9:34:56 PM org.eclipse.jetty.server.AbstractConnector doStart
     INFO: Started CXFJettySslSocketConnector@0.0.0.0:666 STARTING
     main:21:34:57,179:INFO:[STDERR]:May 14, 2015 9:34:57 PM org.eclipse.jetty.server.handler.ContextHandler startContext
     INFO: started o.e.j.s.h.ContextHandler{,null}
     main:21:34:57,189:INFO :[ContextLoader]:Root WebApplicationContext: initialization completed in 6443 ms
     
    WSDL url : https://localhost:666/Greetings?wsdl Before accessing wsdl url user must install certificate that server side will provide. Then after we will be able to see wsdl otherwise we will get following connection close error in browser and in server console we will get following error.
     
     WARNING: 0:0:0:0:0:0:0:1:57089 
     javax.net.ssl.SSLHandshakeException: null cert chain
      at sun.security.ssl.Handshaker.checkThrown(Handshaker.java:1421)
      at sun.security.ssl.SSLEngineImpl.checkTaskThrown(SSLEngineImpl.java:535)
      at sun.security.ssl.SSLEngineImpl.writeAppRecord(SSLEngineImpl.java:1214)
      at sun.security.ssl.SSLEngineImpl.wrap(SSLEngineImpl.java:1186)
      at javax.net.ssl.SSLEngine.wrap(SSLEngine.java:469)
      at org.eclipse.jetty.io.nio.SslSelectChannelEndPoint.wrap(SslSelectChannelEndPoint.java:642)
      at org.eclipse.jetty.io.nio.SslSelectChannelEndPoint.process(SslSelectChannelEndPoint.java:309)
      at org.eclipse.jetty.io.nio.SslSelectChannelEndPoint.fill(SslSelectChannelEndPoint.java:398)
      at org.eclipse.jetty.http.HttpParser.fill(HttpParser.java:949)
      at org.eclipse.jetty.http.HttpParser.parseNext(HttpParser.java:274)
      at org.eclipse.jetty.http.HttpParser.parseAvailable(HttpParser.java:218)
      at org.eclipse.jetty.server.AsyncHttpConnection.handle(AsyncHttpConnection.java:51)
      at org.eclipse.jetty.io.nio.SelectChannelEndPoint.handle(SelectChannelEndPoint.java:586)
      at org.eclipse.jetty.io.nio.SelectChannelEndPoint$1.run(SelectChannelEndPoint.java:44)
      at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:598)
      at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:533)
      at java.lang.Thread.run(Thread.java:745)
     Caused by: javax.net.ssl.SSLHandshakeException: null cert chain
      at sun.security.ssl.Alerts.getSSLException(Alerts.java:192)
      at sun.security.ssl.SSLEngineImpl.fatal(SSLEngineImpl.java:1666)
      at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:304)
      at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:292)
      at sun.security.ssl.ServerHandshaker.clientCertificate(ServerHandshaker.java:1804)
      at sun.security.ssl.ServerHandshaker.processMessage(ServerHandshaker.java:222)
      at sun.security.ssl.Handshaker.processLoop(Handshaker.java:969)
      at sun.security.ssl.Handshaker$1.run(Handshaker.java:909)
      at sun.security.ssl.Handshaker$1.run(Handshaker.java:906)
      at java.security.AccessController.doPrivileged(Native Method)
      at sun.security.ssl.Handshaker$DelegatedTask.run(Handshaker.java:1359)
      at org.eclipse.jetty.io.nio.SslSelectChannelEndPoint.process(SslSelectChannelEndPoint.java:283)
     
      Post Development testing
    Following image will lead us to import client keystore in soapui, Which will be mentioned by client before calling client web service. Step 1. Loading client keystore which contain certificate provided by server. Step 2. Using keystore in webservice request.
    • References:
    Jetty wiki
    Embedded Jetty
    CXF documents

    European Union laws require you to give European Union visitors information about cookies used on your blog. In many cases, these laws also require you to obtain consent.

    As a courtesy, we have added a notice on your blog to explain Google's use of certain Blogger and Google cookies, including use of Google Analytics and AdSense cookies.

    No comments:

    Post a Comment