Watson Assistant - UNABLE_TO_GET_ISSUER_CERT_LOCALLY - node.js

I am trying to connect my NodeJS client application running locally from within a corporate proxy to Watson Assistant Service.
To set-up connection, I am using the following code.
var HttpsProxyAgent = require('https-proxy-agent');
var httpsAgent = new HttpsProxyAgent("<proxyserver:port>");
var assistant = new AssistantV2({
version: '2019-02-28',
authenticator: new IamAuthenticator
({apikey: *<apikey here>*, httpsAgent}),
url: 'https://gateway-wdc.watsonplatform.net/assistant/api',
disableSslVerification: true,
httpsAgent,
});
But, I get the following error in console
Server running on port: 3100
{ Error: unable to get local issuer certificate
at RequestWrapper.formatError (*<actual path hidden>*\node_modules\ibm-watson\node_modules\ibm-cloud-sdk-core\lib\request-wrapper.js:208:21)
at *<actual path hidden>*\node_modules\ibm-watson\node_modules\ibm-cloud-sdk-core\lib\request-wrapper.js:196:25
at processTicksAndRejections (internal/process/next_tick.js:81:5)
message: 'unable to get local issuer certificate',
statusText: 'UNABLE_TO_GET_ISSUER_CERT_LOCALLY',
body:
'Response not received - no connection was made to the service.' }
Kindly advise.

This problem is caused by your proxy performing TLS intercept.
You have several options:
set strict-ssl=false.
set NODE_EXTRA_CA_CERTS=fullpath_to_certificates_file
For the first method, you are disabling certificate validation. This might be OK in a controlled environment (your source code) but make sure you know what you are doing.
For the second method, ask your admin for the SSL root and intermediate certificates. Basically, you are telling your system to trust those certificates.

Related

Openssl issue when sending email through AWS SES

Update:
If I follow the instructions from Using the Command Line to Send Email Using the Amazon SES SMTP Interface, I can get the email to send perfectly from my local and my ec2 instance.
We're using nodemailer to send email through SMTP. When we configure everything using Gmail's SMTP user/pass, everything works fine.
We're trying to move to AWS SES. Everything is seemingly set up fine (domains are verified, we're out of SANDBOX mode, and we're using the SMTP user/pass credentials).
We're using the exact same code, and just swapping out the smtp user/pass/host in our credentials file. When sending the mail with the SES credentials, we're getting this error:
Email was not send due to the following error: [Error: 62024:error:1408F10B:SSL routines:ssl3_get_record:wrong version number:c:\ws\deps\openssl\openssl\ssl\record\ssl3_record.c:332:
] {
library: 'SSL routines',
function: 'ssl3_get_record',
reason: 'wrong version number',
code: 'ESOCKET',
command: 'CONN'
}
According to this GitHub issue, the problem seems to be:
You are either trying to use TLS on a non-TLS port or the openssl
version you use is not compatible with the server.
I'm not quite sure what to do with that information. Our SSL cert is on ELB.
Here's the code that's responsible for sending the actual email:
"use strict";
const nodemailer = require("nodemailer");
const transporter = nodemailer.createTransport({
host: process.env.SMTP_HOST,
port: process.env.SMTP_PORT,
secure: process.env.SMTP_SECURE,
auth: {
user: process.env.SMTP_AUTH_USER,
pass: process.env.SMTP_AUTH_PASS
}
});
module.exports = {
sendMail: (to, subject, html, callback) => {
const mailOptions = {
from: "no-reply#xyz.com",
to,
subject,
html
};
transporter.sendMail(mailOptions, (err, info) => {
if (err) {
return callback(err);
}
return callback(null, info);
});
}
};
TLDR;
Use port 465 when the secure option is true.
What I Did
I went by the comment of #moulder on the question and it worked.
To be clear, you should use 465, true to use SSL to connect, or 587, false to connect without SSL and upgrade via STARTTLS. Any other combination won't work. The code was buggy, fixing it here:
Source: Fabien Potencier at symfony/symfony#34846
See also symfony/symfony/34067
What Amazon Says
Just like there are HTTP and HTTPS ("s" for secure), there is SMTP and SMTPS (kinda)... As for the secure version of the communication, there are to ways to establish that security.
STARTTLS - The client connects with no security. The server says it supports security. Then, the client negotiates security contracts with the SMTP server and migrate from insecure to secure communication.
TLS Wrapper - The client goes secure from the beginning.
Source: Amazon SES Docs - Connecting to an SMTP endpoint

Simple http2 NodeJS Server from official docs & postman not working

I am learning how to build an http2 server with NodeJS 10 LTS official documentation. I copy pasted the server side code into server.js and run node on it, but when I try to connect with postman (REST testing tool) I receive an error.
const http2 = require('http2');
const fs = require('fs');
const server = http2.createSecureServer({
key: fs.readFileSync('localhost-privkey.pem'),
cert: fs.readFileSync('localhost-cert.pem')
});
server.on('error', (err) => console.error(err));
server.on('stream', (stream, headers) => {
// stream is a Duplex
stream.respond({
'content-type': 'text/html',
':status': 200
});
stream.end('<h1>Hello World</h1>');
});
server.listen(8443);
The error I receive from postman is as follows:
Unknown ALPN Protocol, expected `h2` to be available.
If this is a HTTP request: The server was not configured with the `allowHTTP1` option or a listener for the `unknownProtocol` event.
Things I have tried to solve the problem:
As required in the official documentation I have created private and public certificate (.pem).
I have included the public certificate inside postman software. So now the only error I receive is the one mentioned above (Unknown ALPN protocol).
What else is needed to make the example in the official docs work? I could not find online resources for that, and all the previous questions on stackoverflow relates to old versions of NodeJS when http2 was not still native.
Try to add allowHTTP1: true in Server options at it says server not configure with the allowHTTP1
const server = http2.createSecureServer({
key: fs.readFileSync('localhost-privkey.pem'),
cert: fs.readFileSync('localhost-cert.pem')
});
To
const server = http2.createSecureServer({
key: fs.readFileSync('localhost-privkey.pem'),
cert: fs.readFileSync('localhost-cert.pem'),
allowHTTP1: true
});
From github http2 documentation :
allowHTTP1 {boolean} Incoming client connections that do not support HTTP/2 will be downgraded to HTTP/1.x when set to true. See the 'unknownProtocol' event. See ALPN negotiation. Default: false.
Here i found better answer already on Stackoverflow Configure HTTP2 NodeJS Server
Ok, after thorough investigation I found a satisfactory answer to a great extent.
The https request should be https://localhost:8443/stream to get a response from the server with Hello World. Without the stream path there is no response.
postman gives 403 response after installing the public certificate, but insomnia doesn't give any response.
Using google chrome developer tools in the Network tab I can finally get response 200 OK from the server as shown below.

Accessing SMTP server with AUTH NTLM from Node.js

I'm trying to access a SMTP server with AUTH type of NTLM.
I'm using nodemailer and nodemailer-smtp-transport as such:
var config = require('./config.json');
var nodemailer = require('nodemailer');
var smtpTransport = require('nodemailer-smtp-transport');
var transporter = nodemailer.createTransport(smtpTransport({
host : config.mailer.host,
port: config.mailer.port,
auth: {
user: config.mailer.username,
pass: config.mailer.password
},
authMethod: 'PLAIN'
}));
But it doesn't work. The error I get is:
{ [Error: Invalid login: 504 5.7.4 Unrecognized authentication type]
code: 'EAUTH',
response: '504 5.7.4 Unrecognized authentication type',
responseCode: 504 }
Which makes sense, because if I telnet into the SMTP server
ehlo server.domain.net
250-server.domin.net Hello [10.100.10.100]
250-SIZE
250-PIPELINING
250-DSN
250-ENHANCEDSTATUSCODES
250-X-ANONYMOUSTLS
250-AUTH NTLM
250-X-EXPS GSSAPI NTLM
250-8BITMIME
250-BINARYMIME
250-CHUNKING
250-XEXCH50
250 XRDST
And enter
AUTH PLAIN
I get
504 5.7.4 Unrecognized authentication type
But inside Node, if I change the authMethod to 'NTLM', I get an error that says
{ [Error: Unknown authentication method "NTLM"] code: 'EAUTH' }
I'm suspecting that nodemailer just doesn't support NTLM. If that's the case, how do I connect to a SMTP server that requires NTLM authentication type?
Thanks
My company ran into the same problem a few days ago. The options we considered were:
Ask the exchange server admins to enable PLAIN auth under STARTTLS (it is secure and appears to only involve ticking a couple of checkboxes)
Set up a local relay (e.g. postfix) that relays to Exchange, and use the postfix relay from nodemailer
Fork nodemailer and add NTLM support
Unfortunately we hit political issues on the easy options (1) and (2), so had to fork nodemailer.
I didn't send a pull request yet, but the fork is here. For the time being the easiest way to use it is via npm by referring directly to the github project in your package json, e.g.:
"dependences": {
"nodemailer": "steveliles/nodemailer"
}
If you're interested, most of the change was actually in a sub-sub-project (smtp-connection), and the forks of nodemailer, nodemailer-smtp-pool, and nodemailer-smtp-transport are only necessary to get my smtp-connection fork to be picked up.
We didn't need to implement the NTLM protocol, as SamDecrock's httpntlm already did the hard work.
It has only been tested against Exchange 2007 over TLS (with STARTTLS) and no domain or workstation.
If you do need domain + workstation in the credentials, just add them to nodemailer's options.auth and they will be passed through, e.g.
var smtpConfig = {
host: 'ntlm.boo.hoo',
port: 25,
auth: {
domain: 'windows-domain',
workstation: 'windows-workstation',
user: 'user#somedomain.com',
pass: 'pass'
}
};
We were even more unlucky in that the exchange server we're connecting to doesn't have a valid SSL certificate, but luckily nodemailer can handle that by setting tls: {rejectUnauthorized: false} in the options.
From version 6.x.x, you can use custom auth:
https://github.com/nodemailer/nodemailer-ntlm-auth
Refs: https://nodemailer.com/smtp/#authentication
If this is an internal/service type application and your server admin doesn't mind, you can ask them to create a host without authorization and just get rid of
auth: {
user: '-----------',
pass: '-----------'
}
Since I'm just creating a service type app just to send emails on a schedule, my server admin allowed this for me.
Worked for me but I'm sure this solution is not for everyone!

Using Node.js with TLS getting HTTP hostname wrong error

I'm trying to write a simple Node.js server applicationthat will accept client requests, and allowing me to change the TLS/SSL protocol to use. It works fine with a browser (Firefox).
However, when I call the Node.js server from WebSphere Liberty Profile, no matter which TLS/SSL protocol I try to use, I am getting the very confusing error message:
[ERROR ] IOException invoking https://dlwester:32080/W3CookieServiceEmulator/workplace/services/w3cookie/callback/auth_data: HTTPS hostname wrong: should be <dlwester>
As you can see, it's telling me I'm using the wrong hostname, but the hostname it's telling me I should be using is what I'm already using. I've even tried using port 443, so that I don't need to specify a port, but it still gives me the same error message.
I'm not sure if the error is with Node.js or my WLP code (using JAX-RS client). I've not found a way in Node.js to bypass verifying the hostname.
var options = {
key: 'my.key',
cert: 'my.cert',
ciphers: 'TLSv1.2,TLSv1.1,TLSv1.0,SSLv3',
honorCipherOrder: true,
rejectUnauthorized: false
}
server = https.createServer(options, requestListener);
So I guess that's my first question - can I bypass hostname verification?
Has anyone else run into this error, and know a way to get around it?
This is the client verifying the hostname, not the server. You never mentioned the hostname used in your certificate -- if it doesn't match the hostname you use to address it from the client: fix the certificate.

NodeJS check validity of SSL certification other host

I want to check from my server, if the SSL certificate is valid on another server/domain. Is there any way how I can check this?
I think I need to use the https API from NodeJS, but I'm not sure.
When you make an SSL request from NodeJS using its https library, it will take care of the job of verifying the validity of the server it's contacting.
From NodeJS doc:
rejectUnauthorized: If true, the server certificate is verified
against the list of supplied CAs. An 'error' event is emitted if
verification fails. Verification happens at the connection level,
before the HTTP request is sent. Default true
Further more, you can assert the res.socket.authorized attribute in the response:
var https = require('https');
var options = {
host: 'google.com',
method: 'get',
path: '/'
};
var req = https.request(options,
function (res) {
console.log('certificate authorized:' + res.socket.authorized);
});
req.end();
You can also use res.socket.getPeerCertificate() to get detailed information on the server certificate.

Resources