certificatecxfjax-wswss4j

JAX-WS CXF WSS4J Adding certificates at runtime for message signing


I need a JAX-WS client (generated with wsdl2java) to sign its messages and validate signature of response messages. It should not be on transport level but messsage level. The certificate is not known at compile time (every user has their own certificate and are uploaded).

If it was at transport level I would create a keystore with the needed certificate and from that create a KeyManagerFactory. - Trustfactory would be created the same way but reused.

    val certFactory = CertificateFactory.getInstance("X.509")

    val certStream = getResource("file").openStream().buffered()
    val cert = certFactory.generateCertificate(certStream)

    val clientKeystore = KeyStore.getInstance(KeyStore.getDefaultType())
    clientKeystore.load(null, null)
    clientKeystore.setCertificateEntry("certificate", cert)

    val kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm())
    kmf.init(clientKeystore, "".toCharArray())

    val caCertStream = getResource("file").openStream().buffered()
    val caCert = certFactory.generateCertificate(caCertStream)

    val caKeyStore = KeyStore.getInstance(KeyStore.getDefaultType())
    caKeyStore.load(null, null)
    caKeyStore.setCertificateEntry("ca-certificate", caCert)

    val context = SSLContext.getInstance("TLSv1.2")
    context.init(keyManagerFactory.keyManagers, trustManagerFactory.trustManagers, null)
    requestContext.put(JAXWSProperties.SSL_SOCKET_FACTORY, context.socketFactory)

However, since it needs to be at message level it seems I need to use WSS4J, and as far as I can tell this only works with a property file that reference a keystore file.

How can I add certificates for signing and verification at message level with WSS4J?


Solution

  • I forgot to post my answer; better late than never.

    The trick is to override the method loadCryptoFromPropertiesFile in WSS4JOutInterceptor and WSS4JInInterceptor. Instead of loading it from a file you just load it from whatever you have created in real-time.

            val cryptoProvider = Merlin()
            cryptoProvider.setTrustStore(trustKeyStore)
            cryptoProvider.setKeyStore(keystore)
    
            val fetchClient = ClientProxy.getClient(fetchPort)
            val fetchEndpoint = fetchClient.endpoint
    
            val wssOut: WSS4JOutInterceptor = object : WSS4JOutInterceptor(outProps) {
                override fun loadCryptoFromPropertiesFile(propFilename: String, reqData: RequestData): Crypto {
                    return cryptoProvider
                }
            }
            fetchEndpoint.outInterceptors.add(wssOut)
    
            val wssIn: WSS4JInInterceptor = object : WSS4JInInterceptor(inProps) {
                override fun loadCryptoFromPropertiesFile(propFilename: String, reqData: RequestData): Crypto {
                    return cryptoProvider
                }
            }
            fetchEndpoint.inInterceptors.add(wssIn)