Hi all,
just a bit of a wrap up in case someone could use it in the future ...
The usecase:
Connect to an Identitiy provider through HTTPS based on TLSv1.2 with
client authentication required (a password protected PKCS12 file
"clientCERTKEY.p12" with client certificate and key was provided
together with a CA certificate for trusting the server certificate
"serverCA.crt"). Extract a chunk of XML from the response which
represents a SAML assertion and and use it to call another service again
over TLSv1.2 with the same client certificate/key pair.
TLSv1.2 with mutual authentication requires a longer SSL handshake
during which both Server and Client are authenticated and trusted.
Objective:
Do as much as possible in XQuery without descending into the Java dungeon.
Solution:
1) import the serverCA.crt int a dedicated Java keystore
(localtruststore.jks) that will act as truststore. This works probably
also if the cert is imported in the global truststore but we did not
want to pollute the global store while testing. Note that you have to
set a password to protect the truststore during importing.
/keytool -v -importcert -keystore localtruststore.jks -file serverCA.crt
/2) instruct basex to use the newly created truststore plus the
clientCERTKEY.p12 file as keystore for the client. This has been
resolved by modifying the BaseX startup line to look like:
/
//java -Djavax.net.ssl.keyStore=path/to/clientCERTKEY.p12
-Djavax.net.ssl.keyStorePassword=THEGIVENPASSFORP12
-Djavax.net.ssl.keyStoreType=PKCS12
-Djavax.net.ssl.trustStore=path/to/localtruststore.jks
-Djavax.net.ssl.trustStorePassword=THEPASSWORDFORTRUSTSTORE -jar BaseX.jar
/
3) Up to this point it worked fine. I just used http:send-request to
send my request from a basexgui for instance and I was easily able to
migrate the SAML assertion from the response to the request for the
second service.
4) The second call failed because of an annoying (but rather common)
issue with the server certificate whose DN entries did not match
correctly the requiremnts for the second service url. So I had to write
a Custom HostnameVerifier in Java (plenty of examples on the web). And
unfortunately I had to pollute my xquery workflow (put the jar in
library folder and link it up in the code like below).
/Java code for the verifier://
//package com.nw.tls;//
//
//import javax.net.ssl.HostnameVerifier;//
//import javax.net.ssl.HttpsURLConnection;//
//import javax.net.ssl.SSLSession;//
//
//public class LaxHostNameVerifier implements HostnameVerifier{//
//
// public LaxHostNameVerifier() {//
//HttpsURLConnection.setDefaultHostnameVerifier(this);//
// }//
////
// @Override//
// public boolean verify(String hostname, SSLSession session) {//
// return true//;
// }//
//}/
Code for including it into XQuery
/declare namespace Verifier = "java:com.nw.tls.LaxHostNameVerifier";//
//let $init := Verifier:new()/
5) In a last effort we've found out a way to link extra jars by
declaring them as java agents on the startup line. So I was finally able
to use my pure XQuery flow by just enriching the startup line like below:
/java -Djavax.net.ssl.keyStore=path/to/clientCERTKEY.p12
-Djavax.net.ssl.keyStorePassword=THGIVENPASSFORP12
-Djavax.net.ssl.keyStoreType=PKCS12
-Djavax.net.ssl.trustStore=path/to/localtruststore.jks
-Djavax.net.ssl.trustStorePassword=THEPASSWORDFORTRUSTSTORE
-javaagent:LaxHostnameVerifierAgent.jar -jar BaseX.jar/
Thats'all folks.
Final question to Christian ... instead of ignoring certificates
altogether could you plan for a less risky option
IGNORE_HOSTNAME_VERIFICATION which just ignores the verification of the
host name of a certificate? I think this is such a common case that it
might deserve a dedicated flag. Isn't it?
Thanks for the support.
Kind regards and Seaon Greetings to wveryone!
Marco.
On 11/12/2017 21:41, Christian Grün wrote:
That’s good news, Marco!
All I remember was that I updated the Java keystore with certificates
in the part in order to be able to use the https protocol. The
IGNORECERT option can be disabled to ignore certificates.
Looking forward to your »success story«,
Christian
On Mon, Dec 11, 2017 at 9:37 PM, Marco Lettere <m.lett...@gmail.com> wrote:
Hi again,
your words put me on the right way. My doubt was how to pass the information
to the http module send-request functon.
After some investigation I've found out that it may be done by setting some
env variables through -D in the startup scripts pointing to server and
client certificates put in proper keystore and truststore.
At this point http:send-request will transparently use the mutual
certificate exchange without any fiddling with Java code!
That's absolutely great!
Now I'm very close to the final solution and just need to relax the default
hostname verifier. Anyone already did this with basex?
Thanks again for everything.
Marco.
[1] java -cp "$CP" -Djavax.net.ssl.keyStore=/path/to/keystore.p12
-Djavax.net.ssl.keyStorePassword=thepass -Djavax.net.ssl.keyStoreType=PKCS12
-Djavax.net.ssl.trustStore=/path/to/trustsotre.jks
-Djavax.net.ssl.trustStorePassword=thepass $BASEX_JVM org.basex.BaseXGUI
"$@"
On 07/12/2017 22:02, Christian Grün wrote:
Ciao Marco.
Just wanted to be sure that there isn't a way to do everything in XQuery.
Is
it?
I think the HTTP Module could be used for that. What have you tried so
far?
Saluti
Christian