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.lettere@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