Skip to content

Commit

Permalink
feat: implement TLS support (#76)
Browse files Browse the repository at this point in the history
  • Loading branch information
dan-r authored Nov 13, 2022
1 parent 18ee436 commit 40257b8
Show file tree
Hide file tree
Showing 8 changed files with 77 additions and 6 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ components/* | Contains reusable components
Path | Description
---|---
output/env.json | Used for setting environmental variables such as username and password
output/com/ibm/mq/samples/jms/PubSubBase.java | The base used for generated publishers and subscribers
output/com/asyncapi/PubSubBase.java | The base used for generated publishers and subscribers


## Container Information
Expand Down
14 changes: 12 additions & 2 deletions components/Common.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

import { createJavaArgsFromProperties } from '../utils/Types.utils';
import { collateModelNames } from '../utils/Models.utils';
import { MQCipherToJava } from './Connection/MQTLS';

export function Class({ childrenContent, name, implementsClass, extendsClass }) {
if (childrenContent === undefined) {
Expand Down Expand Up @@ -124,7 +125,15 @@ export function EnvJson({ asyncapi, params }) {
const mqChannel = getMqValues(url,'mqChannel');
const host = URLtoHost(url);
const domain = host.split(':', 1);

let cipher = protocol === 'ibmmq-secure' ? 'ANY' : '';

if (
protocol === 'ibmmq-secure' &&
asyncapi.server(params.server).bindings().ibmmq.cipherSpec
) {
cipher = MQCipherToJava(asyncapi.server(params.server).bindings().ibmmq.cipherSpec);
}

return `
{
"MQ_ENDPOINTS": [{
Expand All @@ -133,7 +142,8 @@ export function EnvJson({ asyncapi, params }) {
"CHANNEL": "${mqChannel}",
"QMGR": "${qmgr}",
"APP_USER": "${user}",
"APP_PASSWORD": "${password}"
"APP_PASSWORD": "${password}",
"CIPHER_SUITE": "${cipher}"
}]
}
`;
Expand Down
45 changes: 45 additions & 0 deletions components/Connection/MQTLS.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
export function MQCipherToJava(cipher) {
// List in line with Oracle JRE mappings from https://ibm.biz/mq-cipher-mappings
const ciphers = {
ECDHE_ECDSA_3DES_EDE_CBC_SHA256: "TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA",
ECDHE_ECDSA_AES_128_CBC_SHA256: "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256",
ECDHE_ECDSA_AES_128_GCM_SHA256: "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
ECDHE_ECDSA_AES_256_CBC_SHA384: "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384",
ECDHE_ECDSA_AES_256_GCM_SHA384: "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
ECDHE_ECDSA_NULL_SHA256: "TLS_ECDHE_ECDSA_WITH_NULL_SHA",
ECDHE_ECDSA_RC4_128_SHA256: "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA",
ECDHE_RSA_3DES_EDE_CBC_SHA256: "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA",
ECDHE_RSA_AES_128_CBC_SHA256: "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256",
ECDHE_RSA_AES_128_GCM_SHA256: "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
ECDHE_RSA_AES_256_CBC_SHA384: "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384",
ECDHE_RSA_AES_256_GCM_SHA384: "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
ECDHE_RSA_NULL_SHA256: "TLS_ECDHE_RSA_WITH_NULL_SHA",
ECDHE_RSA_RC4_128_SHA256: "TLS_ECDHE_RSA_WITH_RC4_128_SHA",
TLS_RSA_WITH_3DES_EDE_CBC_SHA: "TLS_RSA_WITH_3DES_EDE_CBC_SHA",
TLS_RSA_WITH_AES_128_CBC_SHA: "TLS_RSA_WITH_AES_128_CBC_SHA",
TLS_RSA_WITH_AES_128_CBC_SHA256: "TLS_RSA_WITH_AES_128_CBC_SHA256",
TLS_RSA_WITH_AES_128_GCM_SHA256: "TLS_RSA_WITH_AES_128_GCM_SHA256",
TLS_RSA_WITH_AES_256_CBC_SHA: "TLS_RSA_WITH_AES_256_CBC_SHA",
TLS_RSA_WITH_AES_256_CBC_SHA256: "TLS_RSA_WITH_AES_256_CBC_SHA256",
TLS_RSA_WITH_AES_256_GCM_SHA384: "TLS_RSA_WITH_AES_256_GCM_SHA384",
TLS_RSA_WITH_DES_CBC_SHA: "SSL_RSA_WITH_DES_CBC_SHA",
TLS_RSA_WITH_NULL_SHA256: "TLS_RSA_WITH_NULL_SHA256",
TLS_RSA_WITH_RC4_128_SHA256: "SSL_RSA_WITH_RC4_128_SHA",
ANY_TLS12: "*TLS12",
TLS_AES_128_GCM_SHA256: "TLS_AES_128_GCM_SHA256",
TLS_AES_256_GCM_SHA384: "TLS_AES_256_GCM_SHA384",
TLS_CHACHA20_POLY1305_SHA256: "TLS_CHACHA20_POLY1305_SHA256",
TLS_AES_128_CCM_SHA256: "TLS_AES_128_CCM_SHA256",
TLS_AES_128_CCM_8_SHA256: "TLS_AES_128_CCM_8_SHA256",
ANY: "*ANY",
ANY_TLS13: "*TLS13",
ANY_TLS12_OR_HIGHER: "*TLS12ORHIGHER",
ANY_TLS13_OR_HIGHER: "*TLS13ORHIGHER"
}

if (ciphers[cipher] === undefined) {
throw new Error('An invalid cipher spec was provided. Please see https://ibm.biz/mq-cipher-mappings');
}

return ciphers[cipher];
}
2 changes: 1 addition & 1 deletion components/PubSubBase/MQPubSubBase.js
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ function getPubSubContent(params) {
MQFirst.get("APP_PASSWORD").toString(),
null,
topicName,
null);
MQFirst.get("CIPHER_SUITE").toString());
// Build connection helper
ch = new ConnectionHelper(id, myConnection);
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@
},
"supportedProtocols": [
"ibmmq",
"ibmmq-secure",
"kafka",
"kafka-secure"
],
Expand Down
3 changes: 2 additions & 1 deletion test/Common.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,8 @@ test('EnvJson extracts correct values', async () => {
CHANNEL: 'DEV.APP.SVRCONN',
QMGR: 'QM1',
APP_USER: 'app',
APP_PASSWORD: 'passw0rd'
APP_PASSWORD: 'passw0rd',
CIPHER_SUITE: '*TLS12'
}]
});
expect(generatedJson).toBe(expectedJson);
Expand Down
5 changes: 4 additions & 1 deletion test/mocks/single-channel.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,11 @@ info:
servers:
production:
url: ibmmq://localhost:1414/QM1/DEV.APP.SVRCONN
protocol: ibmmq
protocol: ibmmq-secure
description: Production Instance 1
bindings:
ibmmq:
cipherSpec: ANY_TLS12
channels:
song/released:
publish:
Expand Down
11 changes: 11 additions & 0 deletions tutorials/IBMMQ.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,16 @@ You will then need to enter the directory you have just created, for example wit
cd ~/asyncapi-java-tutorial
```

## TLS

If you are connecting to servers using the ibmmq-secure binding and have a `cipherSpec` defined in your service specification, you will need to generate certificates and configure a keystore before your generated application will function. Please see [secure communication between IBM MQ endpoints with TLS](https://developer.ibm.com/tutorials/mq-secure-msgs-tls/) for more details.

With a keystore configured, the commands for steps 5 and 6 of the next section will need to include details of this, in the following format:

```
java -cp target/asyncapi-java-generator-0.1.0.jar -Djavax.net.ssl.trustStoreType=jks -Djavax.net.ssl.trustStore=clientkey.jks -Djavax.net.ssl.trustStorePassword=password -Dcom.ibm.mq.cfg.useIBMCipherMappings=false com.asyncapi.DemoSubscriber
```

## Running the Publisher/Subscriber Template
These commands will allow you to run the Java Template publisher/subscriber model using IBM MQ.
1. Run the AsyncAPI Generator. <br>**Note:** You may need to change the username and password values if you have not followed the IBM MQ tutorial.
Expand Down Expand Up @@ -60,6 +70,7 @@ These commands will allow you to run the Java Template publisher/subscriber mode
java -cp target/asyncapi-java-generator-0.1.0.jar com.asyncapi.DemoProducer
```
The messages will now be seen to be being sent from the running publisher to the running subscriber, using MQ topics. Your output from your subscriber should look something like
```
Oct 14, 2021 9:53:23 AM com.asyncapi.SingleReleasedSubscriber receive
Expand Down

0 comments on commit 40257b8

Please sign in to comment.