Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: implement TLS support #76

Merged
merged 6 commits into from
Nov 13, 2022
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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');
Copy link
Collaborator

@dalelane dalelane Nov 13, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice touch 👍

}

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