0

I know my way around Java but I'm fairly inexperienced when it comes to the topic of SSL certificates. So my whole approach may be complete and utter nonsense.

What I'm trying to achieve is the following: I have a webservice build with Apache CXF in a Spring Boot application. That webservice is called a x509 client certificate and I want to use that certificate to get a JWT from a Keycloak instance which I have already configured. Getting the token from keycloak works when I do it like this:

var keystore = KeyStore.getInstance("PKCS12");
keystore.load(new ClassPathResource("keystore.pfx").getInputStream(), "myPassphrase".toCharArray());
HttpClient client = HttpClients.custom().setSSLContext(new SSLContextBuilder()
    .loadTrustMaterial(new ClassPathResource("truststore.jks").getFile(), "trustStorePW".toCharArray())
        .loadKeyMaterial(keystore, "myPassphrase".toCharArray())
        .build()
    ).setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE).build();

var postRequest = new HttpPost("https://localhost:8443/realms/master/protocol/openid-connect/token");
postRequest.addHeader("Content-Type", "application/x-www-form-urlencoded");
var entity = new StringEntity("grant_type=password&client_id=my-client&client_secret=my-secret");
postRequest.setEntity(entity);
var response = client.execute(postRequest);

That's fine and tells me that my keycloak setup is correct. What I'm trying to do now is to extract the certificate from the SOAP request and forward it to the keycloak call. I've done this with an interceptor and pull the certificate from the request like this:

if (httpRequest instanceof HttpServletRequest request
        && request.getAttribute("javax.servlet.request.ssl_session_mgr") instanceof SSLSupport sslSupport
        && sslSupport.getLocalCertificateChain() != null
) {
    for (var cert : sslSupport.getLocalCertificateChain()) {
        var keystore = KeyStore.getInstance("PKCS12");
        keystore.load(null, "passphrase".toCharArray());
        keystore.setCertificateEntry("1", cert);
        // then use the same code as before for calling keycloak
    }
}

But now I get {"error_description":"X509 client certificate is missing.","error":"invalid_request"}. Looking into it I realize that the main difference between the two keystores is that the one created from the HttpRequest does not contain the private key, so I suspect that's the reasons it doesn't work. The keystore.pfx I used in the first example contains only the client certificate btw.

Is there a way to make it work like this or is my whole approach completely wrong? Because that's what I'm starting to suspect. And if so, how could I solve this?

geanakuch
  • 778
  • 7
  • 13
  • 24
  • Maybe this answer helps you: https://stackoverflow.com/a/7202160/2846138 Just make sure that you actually use Apache httpclient for your requests. – cyberbrain Jun 20 '22 at 08:25
  • 1
    You can't use someone else's X.509 certificate as your own. Does that answer your question? If not, unclear what you're asking. – user207421 Jun 20 '22 at 08:39
  • @user207421, yes that was what I feared. But is there a way to just forward the certificate, or would I have to send the client to directly get their token from keycloak? – geanakuch Jun 20 '22 at 08:42
  • I don't know what you mean by 'forward', and you haven't enlightened us, but, again, if it means using it as your own, you can't. You have to be in possession of the private key. Otherwise the whole of PKI would be pointless. – user207421 Jun 20 '22 at 10:16
  • @cyberbrain There is nothing in that answer that accomplishes forwarding of client certificates, or that requires the Apache HTTP client. – user207421 Jun 20 '22 at 10:26

0 Answers0