Thursday, May 3, 2012

It took some time and check various resources for me to setup an ws-endpoint with signing and encryption in Spring integration to setup. I spent most of my time with misspelled passwords, incosistent libraries, configuing soap ui, learning policy files etc.

Key Stores and Certificates

Keystores are files which hold public-private keys or only public keys.

Private key's are only known by the owner and public keys are distrubuted clients.

Your clients (not the client applications you wrote; people/software demanding from your server) can use your public key to verify that it is really signed by you. If a document is signed with a private key, it can only be verified with matching public key. Since the matching private key is only known by the sender; you can be sure that that document is signed by him/her. In this case you need to obtain public key of him/her in a secure way. This is an another story; let's assume you know him and he send it via e-mail.

Your clients can also use your public key to encrypt a document and send to you. If a document is encrypted with a public key, it can only be decrypted with matching private key. Since you are only one who knows that the private key (you hope so :) ), you can decrypt the document sent.

In keystore files; you store your private-public key pairs and public keys (certificates of other trusted clients).

I believe this short introduction was enough for you to understand purpose of following commands, however you can check here to go deeper into these terms.

Let me describe each command above. Although they are on windows; you can run them on linux/mac as well, it is distrubuted with jdk.

In first command; we create a keystore. Password of keystore is test1234. This keystore is for client. Client owns this file and does not share with anyone :) In practice client must generate this. Since information is very secret; we also encrypt private-public key pair with another password "client1pass". A keystore may have many enteries with different password. This entry is named (alias) "client1". (Note keystore file is generated automatically since it does not exist before).

In the second command we extract public key from client private-public key pair as a certificate. Please note that we DO NOT extract private key. Although there are some ways to achieve it, keytool does not allow you to extratc it.

Now server must trust the public key we had extracted on step 2. In order to achieve that we add the certificate we extracted at step 2 to server's keystore. (again this file is created since it does not exists before.). Server will use this public key to check signature validity in future.

Let's create a public-private key for server. So that client can encrypt a document using server's public key and server can decrypt it with it's private key.

This time we extract public key of server as a certificate

And we add server's certificate to client's key store.

Meanwhile let me tell you what truststore is. Truststore is a keystore too; where it is expected to put the public key's (certificates) of other parties (whom you trust) in it. Although I use certificate and public-key as it refers to same thing; it is not. Certificate contains public-key and muck more data which is not our topic now.

Great; we have keys. Lets's continue.

Policy Files

Following files are at server side. The first one mandates that client should send username&password while the second one asks user to encrypt soap body (with server's public key) and sign it (with client's private key).

You need to add response policies if you need to sign and encrypt ws responses. In that case; for responses; you could use private key of server to sign the document and public key of client to encrypt it.

Username and Password Only Policy:

Signing and Encrption Policy:

Let's skip details and continue with endpoints:

Endpoints

There are three endpoints with different intercaptors. I am not going to add all the source code here. Please clone the project to examine /META-INF/spring/integration/ws-endpoints-config.xml file. Let me summarize that configuration file:

URL

Interceptors

Service Bean

echo

logger

ws-echo-inbound

secureEcho

logger,authenticatorWithDigestUsernameInterceptor

ws-echo-inbound

certifiedUserEcho

logger,authenticatorWithTrustedCertificateInterceptor

ws-echo-inbound

Difference between interceptors:(note: security interceptors and dependant beans are defined in /META-INF/spring/integration/ws-security-config.xml)

First handler will check whether the certificate is in the private keyStore. If it is, it is valid. If the certificate is not in the "private keystore", the handler will check whether the current date and time are within the validity period given in the certificate. If they are not, the certificate is invalid; if it is, it will continue with the final step: Checking it with trust store. In our case; we use same keystore file as a keystore and truststore. However we still need to define both.

With the help of second bean; we authenticate the user: Yes user has a valid certificate, but does he allowed to continue? Which roles will she/he have?

I added comments all around in the project. I hope you understand what I described until here. Now it is time to to setup soapUI.

With maven or your prefred ide; deploy this application to tomcat or jetty on your local under context "/hi". URL mappings are bound to hostnames. (localhost:8080/hi/service/echo and 127.0.0.1:8080/hi/service/echo is not same).

SoapUI Settings:

With SoapUI we will test first and third endpoints; I leave second one as an exercise :).

As you create a new project you are asked to select a wsdl file / url. Show the wsdl file in /wsdls/com/yamanyar/esb/services/XmlEcho.wsdl. It will create a soapUI project.

Open the Request1 of XmlExhoSoap11Binding node and modify the endpoint such:

"http://localhost:8080/hi/service/echo". Then just play run button; message you sent will be replied back:

Now let's test third endpoint. Add another endpoint like:
"http://localhost:8080/hi/service/certifiedUserEcho"

If you run again, due to "request signature and encryption" policies you will recieve an error. You need to configure soapUI to sign and encrypt body of the soap message.

Double click on the project, click on "WS-Security Configurations" and then "Keystores". As seen on the image below we add a keystore (/policies/store/local/client1ks.jks (which contains private-public key of client and public key of server as described above, password was: test1234)):

Again, as seen in the image below, (1) click "Outgoing WS-Security Configuration",click (2) "add" and give a name to your configuration then and add sub-component encryption (3). (namespace is not seen on image, it is: http://schemas.xmlsoap.org/soap/envelope/)

Repeat the same for signature. Order of encryption and signature is important. Change with order keys if it is not seen as below on your screen.

Now assign the configuration to "http://localhost:8080/hi/service/certifiedUserEcho" endpoint.

To achieve that double click on XmlEchoSoap11Binding, select "Service Endpoints" and select the configuration from outgoing messages tab as seen below: