Making certificate reference configurable in WSS4J based java callout

Not applicable

Hi,


I have implemented WSS4J based encryption and decryption as java program and used java callout to access them in Apigee. This approach is working as expected.

I would like to make the certificate reference in the java program configurable in vault (or somewhere external to the jar). This is required to make sure the certificate change doesn't trigger a redeployment from operations management perspective.

Any help on this will be of a great help.

Here is the snapshot of the callout policy and java code snippet that is referencing the certificate key store.

JCall.WSSDecrypt.xml

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<JavaCallout name="JCall.WSSDecrypt">
    <ClassName>com.apigee.wss.WSSDecryptorCallout</ClassName>
    <ResourceURL>java://InternalWSS.jar</ResourceURL>
</JavaCallout>

Java program to decrypt:

Properties props = new Properties();
props.setProperty("org.apache.wss4j.crypto.provider", "org.apache.wss4j.common.crypto.Merlin");
props.setProperty("org.apache.wss4j.crypto.merlin.keystore.type", "jks");
props.setProperty("org.apache.wss4j.crypto.merlin.keystore.password", keyStorePassword);
props.setProperty("org.apache.wss4j.crypto.merlin.keystore.alias", keyStoreAlias);

// reference to the keystore in jks format
props.setProperty("org.apache.wss4j.crypto.merlin.keystore.file", "resources/APIX_KeyStore.jks");


crypto = CryptoFactory.getInstance(props);
secEngine.setWssConfig(WSSConfig.getNewInstance());

......then the code to do decryption using the RequestData API

I am looking at pointers to pass the keystore file (.jks) as input to the java program from Apigee callout proxy so that i can make it configurable.

Open to any other suggestion to make it configurable to make sure the jar doesn't change with the certificate change.

0 1 1,731
1 REPLY 1

Hi Ravi,

I know this is a VERY OLD question, and my reply at this point will probably not help you. But it may help someone else, some other future reader.

In general the way to provide "dynamic" values to a Java callout is via properties in the policy configuration. For example:

<JavaCallout name="JCall.WSSDecrypt">
    <Properties>
        <Property name="foo">value-goes-here</Property>
        <Property name="bar">another-value-goes-here</Property>
    </Properties>
    <ClassName>com.apigee.wss.WSSDecryptorCallout</ClassName>
    <ResourceURL>java://InternalWSS.jar</ResourceURL>
</JavaCallout>

The constructor of the callout receives these properties as a Map.

The key here is you can specify specific strings as the values of these properties, or variable names. As an example of the former:

<JavaCallout name="JCall.WSSDecrypt">
    <Properties>
        <Property name="verification-certificate">
      -----BEGIN CERTIFICATE-----
      MIIC4jCCAcqgAwIBAgIQ.....aKLWSqMhozdhXsIIKvJQ==
      -----END CERTIFICATE-----
        </Property>
        <Property name="bar">another-value-goes-here</Property>
    </Properties>
    <ClassName>com.apigee.wss.WSSDecryptorCallout</ClassName>
    <ResourceURL>java://InternalWSS.jar</ResourceURL>
</JavaCallout>

...and then your Java code can de-serialize the cert once, and use it in all subsequent calls.

An extension of that idea, which is more suitable to cases in which you are dealing with private keys, is to reference a variable name, which holds the key material.

<JavaCallout name="JCall.WSSDecrypt">
    <Properties>
        <Property name="var-for-private-key">variable_name_with_privkey</Property>
    </Properties>
    <ClassName>com.apigee.wss.WSSDecryptorCallout</ClassName>
    <ResourceURL>java://InternalWSS.jar</ResourceURL>
</JavaCallout>

And here, you would use MessageContext.getVariable() to retrieve the private key. As above, you'd de-serialize the private key and then employ it for signing. You will want to cache these keys and not instantiate one for every request, for performance.

The private key itself should be stored in the Encrypted KVM and retrieved with a KeyValueMapOperations/GET policy that runs just before the Java callout.

For working example of code that deserializes and caches certs, public keys, and private keys, you can refer to this repo.