How to create a SSL SOAP Client in Nodejs - node.js

First of all, I'd like to make it clear this is my very first time dealing with certificates/keys/pfx/etc.. so please correct me if I'm wrong :)
I'm using node-soap to create a client to a web-server and consume its' WSDL. Doing so only on HTTP protocol and not HTTPS i had success and everything worked just fine, but now with the pfx I get the mac verify failure error.
the relevant code:
import * as soap from 'soap';
import * as fs from 'fs';
let client_options: {
forceSoap12Headers: true,
wsdl_options:{
pfx: fs.readFileSync('PATH\TO\MY\PFX')
}
};
soap.createClient('HTTPS\WEB-SERVER\URL?wsdl', client_options, (error, client)=>{
console.log(error.message) // <-- mac verify failure
console.log(client) // <-- undefined
});
Worth noting:
I could not find any documentation of the node-soap library for the -- wsdl_options property, the pfx one i accidently found while googling so i dont know any other options available.
Trying to deal with this error, i found that an option of passphrase: 'password' should be added to options BUT for options of createServer with the https library, not for creating a client with node-soap.. relevant links: stackoverflow question , git issue
I've been dealing with this for the past 3 days, got to debugging all node-soap, https, and request libraries.. got lost in there.
Any help or suggestions would be much appreciated, thanks in advance!

did you see this link in github? https://github.com/nodejs/node-v0.x-archive/issues/7407 it also says set passphrase: 'password' in this case

Related

Node httpAgent with proxy and certificates (https-proxy-agent with TLS)

So I'm trying to make a call inside my node test (AVA) that uses proxy and TLS authorization.
I'm using:
typescript: 3.9.3
ts-node: 8.10.2
axios: 0.21.1
https-proxy-agent: 5.0.0
What I've learnt so far:
AxiosProxyConfig is broken at the moment so I cannot use it:
Axios proxy is not working,
https-proxy-agent is indeed working as it was said by kraiz in bug thread, but... I cannot see anything about ca, cert and key I cannot provide those I was not able to find any docs except this one https-proxy-agent npm page.
So just to wrap up with some code, that's what I'm trying to do and I have no idea how to achieve that:
const httpsProxyAgent = new HttpsProxyAgent({
cert: this.cert,
key: this.key,
ca: this.ca,
host: PROXY_HOST,
port: PROXY_PORT,
});
// then later
const config: AxiosRequestConfig = {
httpsAgent: httpsProxyAgent,
headers: { ... }
proxy: false
};
Though HttpsProxyAgent seems to extend Agent those options (certs part) are not used and I get UNABLE_TO_VERIFY_LEAF_SIGNATURE error that indicates that ca is ignored.
Does anyone knows how to provide those certs to this agent?
I couldn't find any answers. I'm not a node expert so I might have missed something obvious.
Thanks in advance!
PS. I've also tried Objects.assign() like this
// this proxy agent is working for sure (tested)
const httpsProxyAgent = new HttpsProxyAgent('http://proxy:1234');
// trying to assign certs after creating httpsProxyAgent
Object.assign(httpsAgent.options, {
ca: this.ca,
key: this.key,
cert: this.cert
});
// then again passing it to AxiosRequestConfig.httpAgent and making a call
result was once again UNABLE_TO_VERIFY_LEAF_SIGNATURE.
PSS. I've seen this better-https-proxy-agent (git page) that seems to have solution, the only drawback is I cannot see any TS support.

Same Redis password that works with Redis client fails with Node.JS createClient() method?

I have a Redis server running with Node.JS version 10.4.2. I am using the NPM "redis" client with my app. I am using the following code to create the Redis client and to authenticate. (Note the code commented out below to see what else I tried):
var redis = require("redis");
// var redisClient = require('redis').createClient(process.env.REDIS_URL || redis);
var redisClient = redis.createClient(
{
port: process.env.REDIS_PORT,
host: process.env.REDIS_URL,
no_ready_check: true,
auth_pass: process.env.REDIS_AUTH
});
/*
// Authenticate with Redis.
redisClient.auth(process.env.REDIS_AUTH, function(err, reply) {
if (err) {
console.error(err);
}
else {
console.log(reply);
}
});
*/
However, I always get the error below:
ReplyError: ERR invalid password
When I used the code that is commented out, I did not use the "no_ready_check" property during createClient(). Some facts:
I triple-checked the value in process.env.REDIS_AUTH and it matches exactly what is in my Redis server conf file for the requirepass password value.
I can use the password to successfully authenticate when testing with the Redis command line client (redis-cli) so I know the Redis server is password protected and that the password works.
I know the password is getting through because when I use the code that is commented out, I can see the correct password in the arguments passed to the callback function.
Why isn't my password working with my Node.JS code and how can I fix this? Note, the password was generated using the SSL random password generator on Linux. I mention that in case it affects anything.
UPDATE: I got this working by using a much shorter password in the Redis server conf file. Apparently the Node.JS Redis package doesn't like the long random passwords generated by the Linux SSL utility, despite there being no strange characters in those passwords at all. I posted an issue on this subject on the package repo here:
https://github.com/NodeRedis/node_redis/issues/1411
I was using the following commands to create the password using OpenSSL on my Linux box:
openssl rand 60 | openssl base64 -A
Unfortunately openssl creates passwords with forward slashes in them "/". There may be other characters that are not healthy in this context, but I have not exhaustively tested them. Once I removed the forward slashes from the password, and after I restarted Redis server to register the changes, the client creation attempt worked from Node.JS.
Something is happening on the Node.JS side to those characters on the way to Redis. As I said, I had no problems when directly pasting the very same forward slash containing passwords into the Redis client when using the auth command. But using them from Node.JS causes the authentication attempt to fail.
My best advice to anyone reading this post is if you are using the openssl command to generate redis passwords for your Node.JS app, remove any characters are that are not strictly 'a-zA-Z' from the generated password. Perhaps someone will give a better solution later as a reply.

Firebase Server NodeJS failing to connect with Service Account

I have a pretty simple NodeJS server that I'm using to monitor our Firebase Database. My code is basically identical to the sample on the Firebase documentation:
var firebase = require("firebase");
firebase.initializeApp({
databaseURL: 'https://myurl.firebaseio.com/',
serviceAccount: 'path/to/json.json'
})
Now the issue I'm having is when I run this code from within our network, it doens't seem to be connection as a have a block of code right after to read some data and it never gets ran:
var nodeRef = this.db.ref("node");
nodeRef.on("child_added", function (snapshot, prevChildKey) {
// ...
}, function (error) {
console.log(error);
})
If I give everyone write access to the database, I can take out the serviceAccount setting on the initializeApp call, and everything works perfectly. I've tried running Fiddler to see what it might be making a request to that is failing, but I'm not seeing any requests pop up in Fiddler at all. Any ideas what this might be calling that our proxy would need to allow?
Our IT team found what the problem was, I had asked them to open accounts.google.com in our proxy server. It got set to "allow" instead of "tunnel".
According to them, the HSTS headers were causing the SSL decryption on the proxy unless it was set to tunnel, which was causing the "self signed certificate" error I mentioned above in the comments.
For me, disabling Kaspersky got it to work. You can try that.

NodeJS, Express server with ssl to use Dropbox API - 400 Bad Request

I'm currently at y-hack, hacking up an app. I've never deployed an app to a server before, but I've managed to create an AWS EC2 instance, I created ca certificates with startssl, and now I'm trying to retrieve information using the DropBox API.
My code works on my local machine just fine, but I keep getting a 400 Bad Request Error when I try to use the code on my server. Here's what my options look like:
var options = {
key: fs.readFileSync('./cred/ssl.key'),
cert: fs.readFileSync('./cred/ssl.crt'),
ca: [fs.readFileSync('./cred/sub.class1.server.ca.pem')]
}
And my server looks like:
https.createServer(options,app).listen(443, function(){
console.log('Express server listening on port ' + 443);
});
When I try authenticating I use the built-in dropbox javascript client and call:
var server = new Dropbox.AuthDriver.NodeServer(500);
All my ports are open and I'm able to access my website with HTTPS. I've verified that my SSL certificate is okay, but every time I make a request from my micro instance to DropBox, the page hangs. I tried:
curl https://www.dropbox.com/1/oauth2/authorize?client_id={client_id}&redirect_uri=https%3A%2F%2Fsimplestever.com%3A8912%2Foauth_callback/&response_type=code/&state={state}
And I get this as a response (forgive the formatting):
Error (400)
It seems the app you were using submitted a bad request. If you would like to report this error to the app's developer, include the information below.
More details for developers
Missing "response_type".
=====================
I'm very new to this all and only taught myself today. I never used curl before... If anyone has any idea why I'm having these issues with the request, it would be incredibly helpful! Cheers!
Edit: I curled with the escaped characters and it worked! ...which means the client may be broken? I'll replace it with a query and forget about the csrf variable for now to see if it works.
Edit2: I ended up writing the authentication request using the request module and it worked! Just in the nick of time. Cheers!
Edit3: I should give credit to the code I imitated. https://github.com/smarx/othw/blob/master/Node.js/app.js
I think the issue with your curl command is that it has unescaped ampersands. Try putting quotes around the whole URL.

Node.js HTTPS 400 Error - 'UNABLE_TO_VERIFY_LEAF_SIGNATURE'

I'm writing a Node.js app that has to request some data from one of our internal APIs. The tricky part is that the server I'm requesting data from has certain limitations:
The request must be made on HTTPS protocol (not HTTP)
The request must be made using a LAN IP address, because the domain name will not work internally
The request must appear to be requesting from the external domain name, because that is what the Virtual Host is setup for.
In order to do this, I'm running a bit of code that looks like this:
var headers = {
Host: externalHostname,
Hostname: externalHostname,
};
var options = {
host: InternalIP,
path: path,
method: 'GET',
headers: headers
};
var req = https.request(options, function(res) {
res.setEncoding('utf8');
var data = "";
res.on('data', function(chunk) {
data += chunk;
});
res.on('end', function() {
//Do something with that data
});
res.on('error', function(err) {
console.log("Error during HTTP request");
console.log(err);
});
});
req.end();
Unfortunately, I'm getting a 400 (Your browser sent a request that this server could not understand) error as a response. I've double and triple checked that the hostname, ip address, and path name are all correct (I can test them from within my browser, and all is good).
I did an output of my response variable (res), and am receiving an authorizationError value of UNABLE_TO_VERIFY_LEAF_SIGNATURE. I'm not sure what that is, or if it's my problem, but it's the only useful bit of information I could find.
I put a full output of my response variable here.
Any ideas on what might be causing this?
Update: I figured it out! I was trying to authenticate with the server by passing a ?PHPSESSID=asdad GET variable, but they have that disabled. I was able to make it work by setting PHPSESSID in the Cookie header.
set this process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = '0';
I hit here while debugging UNABLE_TO_VERIFY_LEAF_SIGNATURE error in an external api call from my nodejs server.
This error is hit when there is error during verification of the server certificate. While it is not recommended to disable the security by the following code (which is also available as another answer), it helps to verify if you are chasing the right bug. In other words, if putting this also does not fix it, there is something else wrong with the code.
process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = '0';
In my case, there was silly bug & request was going to localhost itself. Even after putting the above, request failed and that helped me uncover the bug.
Having said that, it is not recommended to use this as a solution. Rather figure out how you can provide additional certificates by setting agent:false & ca:[fs.readFileSync('root-cert.pem')] options. https.request documentation provides details. While chasing my bug, I also found few more useful resources:
ssl-tools.net site provides root & intermediate certificates. For example: Baltimore CyberTrust Root used by lives.api.net
ssl-root-cas module claims to provide additional CA certificates as used by popular browsers. I have not verified the claim.
openssl s_client -connect apis.live.net:443 -- prints the certificate chain. you need to replace the last parameter (url & port) with what you are connecting to.
check this out from the tls.js source in the latest node.js (there is much more this is what I think you need)
// AUTHENTICATION MODES
//
// There are several levels of authentication that TLS/SSL supports.
// Read more about this in "man SSL_set_verify".
//
// 1. The server sends a certificate to the client but does not request a
// cert from the client. This is common for most HTTPS servers. The browser
// can verify the identity of the server, but the server does not know who
// the client is. Authenticating the client is usually done over HTTP using
// login boxes and cookies and stuff.
//
// 2. The server sends a cert to the client and requests that the client
// also send it a cert. The client knows who the server is and the server is
// requesting the client also identify themselves. There are several
// outcomes:
//
// A) verifyError returns null meaning the client's certificate is signed
// by one of the server's CAs. The server know's the client idenity now
// and the client is authorized.
//
// B) For some reason the client's certificate is not acceptable -
// verifyError returns a string indicating the problem. The server can
// either (i) reject the client or (ii) allow the client to connect as an
// unauthorized connection.
//
// The mode is controlled by two boolean variables.
//
// requestCert
// If true the server requests a certificate from client connections. For
// the common HTTPS case, users will want this to be false, which is what
// it defaults to.
//
// rejectUnauthorized
// If true clients whose certificates are invalid for any reason will not
// be allowed to make connections. If false, they will simply be marked as
// unauthorized but secure communication will continue. By default this is
// false.
//
set rejectUnauthorized to false in your options and cross your fingers...let me know if the output changes.
Set this process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = '0';
Fixed the UNABLE_TO_VERIFY_LEAF_SIGNATURE problem for superagent.
Try this in command line:
npm config set strict-ssl false
It worked for me on mac.

Resources