Monday, July 22, 2013

WSO2 ESB - Multi HTTPS

WSO2 ESB - Multi HTTPS

(1) Assign more IP addresses to a physical device.

We will be using three addresses to associate distinct SSL context with.

192.168.1.2
192.168.1.3
192.168.1.4

Add those addressed to an existing network interface (wlan0 in my case).

---
root@ubuntu:~# ip addr add 192.168.1.2/24 dev wlan0 label wlan0:0
root@ubuntu:~# ip addr add 192.168.1.3/24 dev wlan0 label wlan0:1
root@ubuntu:~# ip addr add 192.168.1.4/24 dev wlan0 label wlan0:2
root@ubuntu:~# ip addr show
2: wlan0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP qlen 1000
    link/ether c4:85:08:1a:91:8b brd ff:ff:ff:ff:ff:ff
    inet 192.168.1.121/24 brd 192.168.1.255 scope global wlan0
    inet 192.168.1.2/24 scope global secondary wlan0:0
    inet 192.168.1.3/24 scope global secondary wlan0:0
    inet 192.168.1.4/24 scope global secondary wlan0:0
    inet6 fe80::c685:8ff:fe1a:918b/64 scope link
       valid_lft forever preferred_lft forever
---

(2) Add host entries to /etc/hosts

---
192.168.1.2 testhost1
192.168.1.3 testhost2
192.168.1.4 testhost3
---

Make sure all addresses respond to ping.

(2) Generate a SSL certificate for each IP address.

Certificate Details:
        Serial Number: 13642278243717938869 (0xbd531bc863d8feb5)
        Validity
            Not Before: Feb 12 14:05:20 2013 GMT
            Not After : Feb 12 14:05:20 2014 GMT
        Subject:
            countryName               = CH
            stateOrProvinceName       = ZH
            organizationName          = OK2C
            commonName                = testhost1
        X509v3 extensions:
            X509v3 Basic Constraints:
                CA:FALSE
            X509v3 Subject Key Identifier:
                90:CD:AE:2D:8A:EA:0E:9A:5E:B1:9F:02:DB:38:CE:00:D1:64:E8:89
            X509v3 Authority Key Identifier:
                keyid:80:74:26:CE:27:3D:66:A3:83:1F:68:BA:2E:59:02:7D:B8:4E:95:42

            X509v3 Subject Alternative Name:
                email:root@testhost1

Certificate Details:
        Serial Number: 13642278243717938870 (0xbd531bc863d8feb6)
        Validity
            Not Before: Feb 12 14:08:07 2013 GMT
            Not After : Feb 12 14:08:07 2014 GMT
        Subject:
            countryName               = CH
            stateOrProvinceName       = ZH
            organizationName          = OK2C
            commonName                = testhost2
        X509v3 extensions:
            X509v3 Basic Constraints:
                CA:FALSE
            X509v3 Subject Key Identifier:
                93:E5:04:83:86:6B:8E:D6:6F:61:A4:C1:F9:9D:EE:80:50:3A:89:43
            X509v3 Authority Key Identifier:
                keyid:80:74:26:CE:27:3D:66:A3:83:1F:68:BA:2E:59:02:7D:B8:4E:95:42

            X509v3 Subject Alternative Name:
                email:root@testhost2

Certificate Details:
        Serial Number: 13642278243717938871 (0xbd531bc863d8feb7)
        Validity
            Not Before: Feb 12 14:11:25 2013 GMT
            Not After : Feb 12 14:11:25 2014 GMT
        Subject:
            countryName               = CH
            stateOrProvinceName       = ZH
            organizationName          = OK2C
            commonName                = testhost3
        X509v3 extensions:
            X509v3 Basic Constraints:
                CA:FALSE
            X509v3 Subject Key Identifier:
                2B:F3:01:94:AC:9A:0C:81:37:2C:7B:62:EC:0C:10:F8:99:17:20:56
            X509v3 Authority Key Identifier:
                keyid:80:74:26:CE:27:3D:66:A3:83:1F:68:BA:2E:59:02:7D:B8:4E:95:42

            X509v3 Subject Alternative Name:
                email:root@testhost3

(5) Store testhost key material in PKCS12 format.

(6) Generate a test user certificate to be used for client authentication with one of the test hosts.

Certificate Details:
        Serial Number: 13642278243717938872 (0xbd531bc863d8feb8)
        Validity
            Not Before: Feb 13 19:14:15 2013 GMT
            Not After : Feb 13 19:14:15 2014 GMT
        Subject:
            countryName               = CH
            stateOrProvinceName       = ZH
            organizationName          = OK2C
            commonName                = Test User
        X509v3 extensions:
            X509v3 Basic Constraints:
                CA:FALSE
            X509v3 Subject Key Identifier:
                70:43:FD:C5:4B:AE:1A:C5:AC:41:3E:79:8B:71:3A:A3:BD:45:1B:D2
            X509v3 Authority Key Identifier:
                keyid:80:74:26:CE:27:3D:66:A3:83:1F:68:BA:2E:59:02:7D:B8:4E:95:42

            X509v3 Subject Alternative Name:
                email:testuser@testdomain

(7) Store test user key material in format recognizable by curl by concatenating private key and key certificate

---
cat testuser.key testuser.crt > testuser.curl
---

(9) Generate JKS trust store containing Test Root CA certificate.

(10) Configure Synapse to use multi-profile listener with three profiles.

Configure 192.168.1.2 and 192.168.1.3 to not require client authentication. Configure 192.168.1.4 to trust Test Root CA only and to require client authentication.

---
    <transportReceiver name="multi-https" class="org.apache.synapse.transport.nhttp.HttpCoreNIOMultiSSLListener">
        <parameter name="port">8343</parameter>
        <parameter name="non-blocking">true</parameter>
        <parameter name="SSLProfiles">
            <profile>
                <bindAddress>192.168.1.2</bindAddress>
                <KeyStore>
                    <Location>/home/oleg/src/wso2.com/multiple-ssl-profiles/CA/testhost1.p12</Location>
                    <Type>PKCS12</Type>
                    <Password>test</Password>
                    <KeyPassword>test</KeyPassword>
                </KeyStore>
            </profile>
            <profile>
                <bindAddress>192.168.1.3</bindAddress>
                <KeyStore>
                    <Location>/home/oleg/src/wso2.com/multiple-ssl-profiles/CA/testhost2.p12</Location>
                    <Type>PKCS12</Type>
                    <Password>test</Password>
                    <KeyPassword>test</KeyPassword>
                </KeyStore>
            </profile>
            <profile>
                <bindAddress>192.168.1.4</bindAddress>
                <KeyStore>
                    <Location>/home/oleg/src/wso2.com/multiple-ssl-profiles/CA/testhost3.p12</Location>
                    <Type>PKCS12</Type>
                    <Password>test</Password>
                    <KeyPassword>test</KeyPassword>
                </KeyStore>
                <TrustStore>
                    <Location>/home/oleg/src/wso2.com/multiple-ssl-profiles/CA/testtrust.jks</Location>
                    <Type>JKS</Type>
                    <Password>nopassword</Password>
                </TrustStore>
                <SSLVerifyClient>require</SSLVerifyClient>
            </profile>
        </parameter>
    </transportReceiver>
---

(11) Restart Synapse and make sure all SSL listener endpoints are properly configured and are active.

You should see the following INFO messages in the execution log

---
...
2013-02-14 11:24:08,794 [-] [main]  INFO ListenerContextBuilder MULTI-HTTPS Loading Identity Keystore from : /home/oleg/src/wso2.com/multiple-ssl-profiles/CA/testhost1.p12
2013-02-14 11:24:08,947 [-] [main]  INFO ListenerContextBuilder MULTI-HTTPS Subject DN: CN=testhost1, O=OK2C, ST=ZH, C=CH
2013-02-14 11:24:08,948 [-] [main]  INFO ListenerContextBuilder MULTI-HTTPS Issuer DN: CN=Test CA Root, O=OK2C, ST=ZH, C=CH
2013-02-14 11:24:09,046 [-] [main]  INFO ListenerContextBuilder MULTI-HTTPS Loading Identity Keystore from : /home/oleg/src/wso2.com/multiple-ssl-profiles/CA/testhost2.p12
2013-02-14 11:24:09,058 [-] [main]  INFO ListenerContextBuilder MULTI-HTTPS Subject DN: CN=testhost2, O=OK2C, ST=ZH, C=CH
2013-02-14 11:24:09,059 [-] [main]  INFO ListenerContextBuilder MULTI-HTTPS Issuer DN: CN=Test CA Root, O=OK2C, ST=ZH, C=CH
2013-02-14 11:24:09,063 [-] [main]  INFO ListenerContextBuilder MULTI-HTTPS Loading Identity Keystore from : /home/oleg/src/wso2.com/multiple-ssl-profiles/CA/testhost3.p12
2013-02-14 11:24:09,083 [-] [main]  INFO ListenerContextBuilder MULTI-HTTPS Subject DN: CN=testhost3, O=OK2C, ST=ZH, C=CH
2013-02-14 11:24:09,083 [-] [main]  INFO ListenerContextBuilder MULTI-HTTPS Issuer DN: CN=Test CA Root, O=OK2C, ST=ZH, C=CH
2013-02-14 11:24:09,084 [-] [main]  INFO ListenerContextBuilder MULTI-HTTPS Loading Trust Keystore from : /home/oleg/src/wso2.com/multiple-ssl-profiles/CA/testtrust.jks
...
2013-02-14 11:24:09,259 [-] [main]  INFO HttpCoreNIOListener MULTI-HTTPS Listener started on testhost1:8343
2013-02-14 11:24:09,260 [-] [main]  INFO HttpCoreNIOListener MULTI-HTTPS Listener started on testhost2:8343
2013-02-14 11:24:09,260 [-] [main]  INFO HttpCoreNIOListener MULTI-HTTPS Listener started on testhost3:8343
---

(12) Prepare request message and store it in tmp.xml file.

---
<?xml version='1.0' encoding='UTF-8'?>
  <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
    <soapenv:Header xmlns:wsa="http://www.w3.org/2005/08/addressing">
      <wsa:To>http://localhost:9000/services/SimpleStockQuoteService</wsa:To>
      <wsa:MessageID>urn:uuid:18796751-bd3a-4c96-966a-e463b2dfc179</wsa:MessageID>
      <wsa:Action>urn:getQuote</wsa:Action>
    </soapenv:Header>
    <soapenv:Body>
      <m0:getQuote xmlns:m0="http://services.samples"><m0:request><m0:symbol>IBM</m0:symbol></m0:request></m0:getQuote>
   </soapenv:Body>
 </soapenv:Envelope>
---

(12) Execute a request against non-SSL listener using curl to make all components work correctly. Ensure the response content is correct.

---
curl -X POST -H 'Content-Type: text/xml; charset=UTF-8' -H 'SOAPAction: "urn:getQuote"' -d @tmp.xml -v http://localhost:8280/
---

(13) Execute a request against testhost1 SSL listener using curl without appropriate trust material.

---
curl -X POST -H 'Content-Type: text/xml; charset=UTF-8' -H 'SOAPAction: "urn:getQuote"' -d @tmp.xml -v https://testhost1:8343/
---

Make sure connection is rejected by the client due to failure to verify server identity.

---
* About to connect() to testhost1 port 8343 (#0)
*   Trying 192.168.1.2...
* connected
* Connected to testhost1 (192.168.1.2) port 8343 (#0)
* successfully set certificate verify locations:
*   CAfile: none
  CApath: /etc/ssl/certs
* SSLv3, TLS handshake, Client hello (1):
* SSLv3, TLS handshake, Server hello (2):
* SSLv3, TLS handshake, CERT (11):
* SSLv3, TLS alert, Server hello (2):
* SSL certificate problem: unable to get local issuer certificate
* Closing connection #0
curl: (60) SSL certificate problem: unable to get local issuer certificate
---

(14) Execute a request against testhost1 SSL listener using curl with appropriate trust material.

---
curl -X POST -H 'Content-Type: text/xml; charset=UTF-8' -H 'SOAPAction: "urn:getQuote"' -d @tmp.xml --cacert CA/cacert.pem -v https://testhost1:8343/
---

Make sure the server's identity is correctly established and verified.

---
* About to connect() to testhost1 port 8343 (#0)
*   Trying 192.168.1.2...
* connected
* Connected to testhost1 (192.168.1.2) port 8343 (#0)
* successfully set certificate verify locations:
*   CAfile: CA/cacert.pem
  CApath: /etc/ssl/certs
* SSLv3, TLS handshake, Client hello (1):
* SSLv3, TLS handshake, Server hello (2):
* SSLv3, TLS handshake, CERT (11):
* SSLv3, TLS handshake, Server key exchange (12):
* SSLv3, TLS handshake, Server finished (14):
* SSLv3, TLS handshake, Client key exchange (16):
* SSLv3, TLS change cipher, Client hello (1):
* SSLv3, TLS handshake, Finished (20):
* SSLv3, TLS change cipher, Client hello (1):
* SSLv3, TLS handshake, Finished (20):
* SSL connection using ECDHE-RSA-DES-CBC3-SHA
* Server certificate:
*      subject: C=CH; ST=ZH; O=OK2C; CN=testhost1
*      start date: 2013-02
*      expire date: 2014-02
*      common name: testhost1 (matched)
*      issuer: C=CH; S
*      SSL certificate verify ok.
---

(15) Execute a request against testhost2 multi SSL listener using curl with appropriate trust material.

---
curl -X POST -H 'Content-Type: text/xml; charset=UTF-8' -H 'SOAPAction: "urn:getQuote"' -d @tmp.xml --cacert CA/cacert.pem -v https://testhost2:8343
---

Make sure the server's identity is correctly established and verified.

---
* About to connect() to testhost2 port 8343 (#0)
*   Trying 192.168.1.3...
* connected
* Connected to testhost2 (192.168.1.3) port 8343 (#0)
* successfully set certificate verify locations:
*   CAfile: CA/cacert.pem
  CApath: /etc/ssl/certs
* SSLv3, TLS handshake, Client hello (1):
* SSLv3, TLS handshake, Server hello (2):
* SSLv3, TLS handshake, CERT (11):
* SSLv3, TLS handshake, Server key exchange (12):
* SSLv3, TLS handshake, Server finished (14):
* SSLv3, TLS handshake, Client key exchange (16):
* SSLv3, TLS change cipher, Client hello (1):
* SSLv3, TLS handshake, Finished (20):
* SSLv3, TLS change cipher, Client hello (1):
* SSLv3, TLS handshake, Finished (20):
* SSL connection using ECDHE-RSA-DES-CBC3-SHA
* Server certificate:
*      subject: C=CH; ST=ZH; O=OK2C; CN=testhost2
*      start date: 2013-02
*      expire date: 2014-02
*      common name: testhost2 (matched)
*      issuer: C=CH; S
*      SSL certificate verify ok.
---

(16) Execute a request against testhost3 multi SSL listener using curl with appropriate trust material.

---
curl -X POST -H 'Content-Type: text/xml; charset=UTF-8' -H 'SOAPAction: "urn:getQuote"' -d @tmp.xml --cacert CA/cacert.pem -v https://testhost3:8343
---

Make sure the connection is rejected by the server due to the client failure to authenticate.

---
* About to connect() to testhost3 port 8343 (#0)
*   Trying 192.168.1.4...
* connected
* Connected to testhost3 (192.168.1.4) port 8343 (#0)
* successfully set certificate verify locations:
*   CAfile: CA/cacert.pem
  CApath: /etc/ssl/certs
* SSLv3, TLS handshake, Client hello (1):
* SSLv3, TLS handshake, Server hello (2):
* SSLv3, TLS handshake, CERT (11):
* SSLv3, TLS handshake, Server key exchange (12):
* SSLv3, TLS handshake, Request CERT (13):
* SSLv3, TLS handshake, Server finished (14):
* SSLv3, TLS handshake, CERT (11):
* SSLv3, TLS handshake, Client key exchange (16):
* SSLv3, TLS change cipher, Client hello (1):
* SSLv3, TLS handshake, Finished (20):
* Unknown SSL protocol error in connection to testhost3:8343
* Closing connection #0
---

(17) Execute a request against testhost3 multi SSL listener using curl with appropriate trust material and user private key.

---
curl -X POST -H 'Content-Type: text/xml; charset=UTF-8' -H 'SOAPAction: "urn:getQuote"' -d @tmp.xml --cacert CA/cacert.pem --cert CA/testuser.curl:test -v https://testhost3:8343
---

Make sure the server's identity is correctly established and verified.

---
* About to connect() to testhost3 port 8343 (#0)
*   Trying 192.168.1.4...
* connected
* Connected to testhost3 (192.168.1.4) port 8343 (#0)
* successfully set certificate verify locations:
*   CAfile: CA/cacert.pem
  CApath: /etc/ssl/certs
* SSLv3, TLS handshake, Client hello (1):
* SSLv3, TLS handshake, Server hello (2):
* SSLv3, TLS handshake, CERT (11):
* SSLv3, TLS handshake, Server key exchange (12):
* SSLv3, TLS handshake, Request CERT (13):
* SSLv3, TLS handshake, Server finished (14):
* SSLv3, TLS handshake, CERT (11):
* SSLv3, TLS handshake, Client key exchange (16):
* SSLv3, TLS handshake, CERT verify (15):
* SSLv3, TLS change cipher, Client hello (1):
* SSLv3, TLS handshake, Finished (20):
* SSLv3, TLS change cipher, Client hello (1):
* SSLv3, TLS handshake, Finished (20):
* SSL connection using ECDHE-RSA-DES-CBC3-SHA
* Server certificate:
*      subject: C=CH; ST=ZH; O=OK2C; CN=testhost3
*      start date: 2013-02
*      expire date: 2014-02
*      common name: testhost3 (matched)
*      issuer: C=CH; S
*      SSL certificate verify ok.
---
Required artifacts can be downloaded from HERE

Thanks to the developer for sharing this information with me.

WSO2 ESB 4.7 HTTP Endpoint

WSO2 ESB 4.7 HTTP Endpoint

SOAP client to REST back-end service using HTTP End point

Step 1: Build "SimpleStockQuoteService" service and start "axis2Server"

$ESB_HOME\samples\axis2Server\src\SimpleStockQuoteService>ant
$ESB_HOME\samples\axis2Server>axis2server.sh (or .bat)

Step 2: Create a HTTP endpoint ((say, HTTPEndPoint)

<endpoint xmlns="http://ws.apache.org/ns/synapse" name="HTTPEndPoint">
   <http uri-template="https://localhost:9100/{uri.var.path}/{uri.var.name}" method="post">
      <suspendOnFailure>
         <progressionFactor>1.0</progressionFactor>
      </suspendOnFailure>
      <markForSuspension>
         <retriesBeforeSuspension>0</retriesBeforeSuspension>
         <retryDelay>0</retryDelay>
      </markForSuspension>
   </http>
</endpoint>

Step 3: Create a pass through proxy with the endpoint defined above(Say TestProxy)

<proxy xmlns="http://ws.apache.org/ns/synapse" name="TestProxy" transports="https,http" statistics="disable" trace="disable" startOnLoad="true">
   <target>
      <inSequence>
         <property name="uri.var.path" value="services"/>
         <property name="uri.var.name" value="SimpleStockQuoteService"/>
         <send>
            <endpoint key="HTTPEndPoint"/>
         </send>
      </inSequence>
      <outSequence>
         <send/>
      </outSequence>
   </target>
   <description></description>
</proxy>

Step 4: Place a client request from the AXIS2CLIENT folder ($ESB_HOME/samples/axis2Client)
e.g. ant stockquote -Dsymbol=IBM -Dmode=quote -Daddurl=http://localhost:8280/services/TestProxy

Note: TCPMon can be placed between Client & WSO2 ESB and WSO2 ESB & Back End Service to monitor the request and responses.

This is for HTTP Method 'POST' only. If you want to configure for rest of the methods such as GET|DELETE|PUT, etc change the HTTP method as appropriate.

<http uri-template="https://localhost:9100/{uri.var.path}/{uri.var.name}" method="get">

Also this can be invoked and verified for https as well. However due to encription TCPMon cannot be use for monitoring. Tools such as Wireshark with Fidler might be helpful for HTTPS traffic analysing.

HTTP GET

<endpoint xmlns="http://ws.apache.org/ns/synapse" name="HttpEpGET">
   <http uri-template="http://localhost:9765/jaxrs_basic/services/customers/customerservice/customers/{uri.var.id}" method="get">
      <suspendOnFailure>
         <progressionFactor>1.0</progressionFactor>
      </suspendOnFailure>
      <markForSuspension>
         <retriesBeforeSuspension>0</retriesBeforeSuspension>
         <retryDelay>0</retryDelay>
      </markForSuspension>
   </http>
</endpoint>

<proxy xmlns="http://ws.apache.org/ns/synapse" name="JAXRS" transports="https,http" statistics="disable" trace="disable" startOnLoad="true">
   <target>
      <inSequence>
         <property name="messageType" value="application/xml" scope="axis2"/>
         <property name="ContentType" value="application/xml" scope="axis2"/>
         <property name="uri.var.id" expression="$body/Customer/id"/>
         <log level="full"/>
         <log level="custom">
            <property name="ID" expression="get-property('uri.var.id')"/>
            <property name="$body" expression="$body/Customer/id"/>
         </log>
         <send>
            <endpoint key="HttpEpGET"/>
         </send>
      </inSequence>
      <outSequence>
         <send/>
      </outSequence>
   </target>
   <description></description>
</proxy>


HTTP DELETE

The above endpoint method can be set to 'delete' to test the DELETE method.

HTTP PUT

<endpoint xmlns="http://ws.apache.org/ns/synapse" name="HttpEpPUT">
   <http uri-template="http://localhost:9765/jaxrs_basic/services/customers/customerservice/{uri.var.service}" method="put">
      <suspendOnFailure>
         <progressionFactor>1.0</progressionFactor>
      </suspendOnFailure>
      <markForSuspension>
         <retriesBeforeSuspension>0</retriesBeforeSuspension>
         <retryDelay>0</retryDelay>
      </markForSuspension>
   </http>
</endpoint>

<proxy xmlns="http://ws.apache.org/ns/synapse" name="JAXRSPUT" transports="https,http" statistics="disable" trace="disable" startOnLoad="true">
   <target>
      <inSequence>
         <property name="messageType" value="application/xml" scope="axis2"/>
         <property name="ContentType" value="application/xml" scope="axis2"/>
         <property name="uri.var.service" value="customers"/>
         <log level="full"/>
         <send>
            <endpoint key="HttpEpPUT"/>
         </send>
      </inSequence>
      <outSequence>
         <send/>
      </outSequence>
   </target>
   <description></description>
</proxy>

HTTP POST

 The above endpoint method can be set to 'post' to test the POST method.


References:
1. http://docs.wso2.org/wiki/display/ESB470/Using+REST+with+a+Proxy+Service
2. http://docs.wso2.org/wiki/display/AS501/JAX-RS+Basics