Nodejs SOAP client throwing error [ERR_TLS_CERT_ALTNAME_INVALID]: Hostname/IP does not match certificate's altnames:
I am trying to call a SOAP service using soap in nodejs. However I am getting error [ERR_TLS_CERT_ALTNAME_INVALID]: Hostname/IP does not match certificate's altnames: IP: XXX.XXX.XXX.XXX is not in the cert's list:. I am new to nodejs and not sure how to call a SOAP service which requires certificate from nodejs. Other ways to call SOAP services requiring certificates in Nodejs are also welcome.
var url = "https://soapserviceurl?wsdl";
soap.createClient(url, function (err, client) {
if (err) {
console.log("Error Occurred!!");
console.log(err);
}
else {
console.log(client.describe());
}
});
please try
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0" //this is insecure
Or:
var soap = require('soap'),
request = require('request'),
fs = require('fs');
var url = "https://soapserviceurl?wsdl";
var req = request.defaults({
strictSSL: false
);
soap.createClient(url, {
request : req
}, function(err, client) {
//your code
});
Or:
soap.createClient(url, {
request : req,
wsdl_options: {
cert: fs.readFileSync('cert/cert.pem'), //path to pem
key: fs.readFileSync('cert/cert.key'), //path to private key
rejectUnauthorized: false
}
}, function(err, client) {
//your code
});
The answer above doesn't work anymore because as of SOAP as of v0.40.0, it uses Axios for web requests, and not the request package. I couldn't find a recent answer for this and I spent a while figuring it out.
See in the documentation:
request (Object): Override the default request module (Axios as of v0.40.0).
wsdl_options (Object): Set options for the request module on WSDL requests. If using the default request module, see Request Config | Axios Docs.
Based on the link above and instructions like these https://smallstep.com/hello-mtls/doc/client/axios, this is the new way to do it:
First, so the WSDL endpoint is fetched with authentication, get the client like this:
import soap from 'soap';
import fs from 'fs';
import https from 'https';
const client = await soap.createClientAsync(api_url, {
wsdl_options: {
httpsAgent: new https.Agent({
key: fs.readFileSync('personal.key'),
cert: fs.readFileSync('personal.cert'),
}),
}
});
The key difference is that instead of passing cert and key in wsdl_options, you have to pass a new https.Agent with the cert and key.
Next, before making any call, ensure they are also called with certificate authentication:
client.setSecurity(new soap.ClientSSLSecurity('personal.key', 'personal.cert'));
Related
I am using a next js node server as my app. And a ngnix as my https server with self-signed certificate in which my API node server is at behind.
But I am getting a self-signed certificate error.
So, in my next js , I will contact the https server either by fetch and axios. for example.
Is there a easy way on how to get ride of it without buying SSL from real CA?
What I have tried:
This problem couldn't be by pass thru chrome insecure content enabling since it is a server error.
I am guessing this could be achieved from either setting node server / fetch or axios. But I am so new on this kind of problem.
second update
process.env["NODE_TLS_REJECT_UNAUTHORIZED"] = 0;
works to get rid of the fetch error:
But now it shown this error with put method:
net::ERR_CERT_AUTHORITY_INVALID
What I have done is to put process.env["NODE_TLS_REJECT_UNAUTHORIZED"] = 0; on every api call.
For example
try {
process.env["NODE_TLS_REJECT_UNAUTHORIZED"] = 0;
const res = await axios.put(url);
} catch (error) {
console.log(error);
}
I am still looking for a solution.
Try adding httpsAgent in your fetch call
const https = require('https');
const httpsAgent = new https.Agent({
rejectUnauthorized: false,
});
const response = await fetch("https://localhost/api", {
// Adding method type
method: "POST",
// Adding body or contents to send
body: JSON.stringify(
{data:"data"}),
// Adding headers to the request
headers: {
"Content-type": "application/json; charset=UTF-8"
},
agent: httpsAgent,
})
It worked for me
I am having a very weird issue by using the Nodejs https module.
What I was trying to do is, calling the 3rd party API for some service, the following is my code:
const https = require("https");
function request(accessId, secretKey, host, api, body, timeout=3000) {
let bodyString = JSON.stringify(body);
let time = Math.round(new Date().getTime()/1000).toString();
// I have implemented the signBody function
let sign = signBody(accessId, secretKey, time, bodyString);
let header = {
"Content-Type": "application/json",
"AccessId": accessId,
"TimeStamp": time,
"Sign": sign,
};
let options = {
method: 'POST',
timeout: timeout,
headers: header,
}
let url = new URL(api,host);
https.request(url, options, (res) => {...});
}
They weird part is, if I'm running the function by node xxx.js to trigger the request("MY_ACCESS_ID", "MY_SECRET_KEY", "https://api.xxxx.com", "/service/api/v3", MY_BODY) function, it works as expected. However, this request(...) function is part of my webserver, and it is used by a API (I'm using express.js), such as:
// the myService implemented the request() function
let myService = require("./myService.js")
router.get("/myAPI", (req, res, next) => {
request("MY_ACCESS_ID", "MY_SECRET_KEY", "https://api.xxxx.com", "/service/api/v3", MY_BODY)
})
it always shows the error: Error: connect ECONNREFUSED 127.0.0.1:443
I have no idea why the same code is behaving different. I thought it probably https.request issue. they I tried to use axios for the post request. The other weird things showed up. By using the exactly same header, https.request() returns success from the service provider and axios.post returns error message: Sign check error, please check the way to generate Sign.
This is so crazy....no idea of this issue. Any idea ??
BTW, I have solved the issue by implementing as:
const https = require("https");
function request(accessId, secretKey, host, api, body, timeout=3000) {
let bodyString = JSON.stringify(body);
let time = Math.round(new Date().getTime()/1000).toString();
// I have implemented the signBody function
let sign = signBody(accessId, secretKey, time, bodyString);
let header = {
"Content-Type": "application/json",
"AccessId": accessId,
"TimeStamp": time,
"Sign": sign,
};
let options = {
hostname: host,
path: api,
method: 'POST',
timeout: timeout,
headers: header,
}
https.request(options, (res) => {...});
}
But still no idea what is the difference.
I would check the final url constructed inside the https.request method. The non-working version makes a request to 127.0.0.1:443, which wouldn't work since your localhost doesn't support https(only http) and 443 is usually for https.
See https://nodejs.org/api/https.html#https_https_request_url_options_callback for default port number.
Axios has different implementation inside the post() method and it may manipulate your sign string by url encoding it before sending to the 3rd-party API.
Created a nodejs library which makes an https request with client certificates(.crt,.key files) to a different server to get the response. For making a request I used the "request" npm module.
While benchmarking the library,
I was making 2000 requests to my library to make a request but the library couldn't handle more than 150-200
simultaneously. Suppose, I used Http server then library throughput has been increased with 1800-1850 simultaneously.
what I observed is while making https request, I think the event loop is blocked. so that it couldn't able to handle or accept the requests.
I have also tried using the https core module, node-fetch, axios npm modules. There is no difference in the throughput of my library.
Also, we have tried using the cluster concept of nodejs. but it's not suitable for my library.
Please help me with what should I do, to increase the throughput of my library.
My Code:
const request = require('request');
const fs = require('fs');
const path = require('path');
function makeRequest() {
let headers = {'Content-Type':'application/json'};
let body = '{name:'library'}';
let options = {
url: 'https://IP:PORT/CONTEXT',
method: 'POST',
headers: headers,
body: body,
agentOptions:
{
cert: fs.readFileSync(path.resolve(__dirname, 'ssl/my.crt')),
key: fs.readFileSync(path.resolve(__dirname, 'ssl/my.key')),
passphrase: '123456'
}
}
request(options, (err, response, body) => {
if (err) {
console.log('err :>> ', err);
} else {
console.log('response :>> ', response.statusCode);
}
})
}
This question already has answers here:
How to do HTTPS GET with client certificate in node
(1 answer)
Nodejs request to a web service with .p12 certificate
(2 answers)
Node.js Rest call to a server that requires a certificate
(1 answer)
Closed 3 years ago.
I'm trying to make a POST request from a Node/Express server to a ecommerce provider while authenticating with a .PEM certificate, which I converted from a .p12 file using openssl as per their instructions. The provider is supposed to return a unique transaction ID.
I've tried using the Request module as below but I'm getting a "bad certificate" error every time. I've tried with agentOptions, without agentOptions, checked the .pem file is being read correctly, etc.
Error: write EPROTO 140059546118016:error:14094412:SSL routines:ssl3_read_bytes:sslv3 alert bad certificate:../deps/openssl/openssl/ssl/record/rec_layer_s3.c:1407:SSL alert number 42
const options = {
url: "https://ecommerce.com:12345/some/route",
agentOptions: {
passphrase: process.env.MY_PASSPHRASE,
ca: fs.readFileSync("./ssl/certificate.pem")
},
rejectUnauthorized: false,
form: {
amount: 100,
currency: 981
}
};
await request.post(options, (err, res, body) => {
console.log({ err, res, body });
});
I'm new to Node.js, and even newer with SSL :( apologies if I'm not explaining or understanding this correctly. Any help/direction will be much appreciated.
SOLVED
Sample working code. Using the same exact key in cert and key fields worked for some reason.
const fs = require("fs");
const request = require("request-promise");
const options = {
url: "https://provider.com:18443/some/path",
headers: {
"User-Agent": "node.js"
},
strictSSL: false,
form: {
// currency, language, provider-specific options here
},
cert: fs.readFileSync("./ssl/my_key.pem"),
key: fs.readFileSync("./ssl/my_key.pem"),
passphrase: process.env.PASSPHRASE
};
const req = await request.post(options, (err, httpResponse, body) => {
// do stuff with body here
})
Working on a webapp using Ogone Direct Paiment, a code working for an old account is working but giving me same error for the new one.
I've added the call made and the answer, maybe someone is used to Ogone API.
The error seems to tell me I have to make a SSL 128bit call but I have no idea how to do that. I've tried lot of things, including userAgent, generate certificate myself with openssl command but without result.
If you're familiar with Ogone, let me know how to fix it or how to change the configuration to allow simple queries.
Otherwise, could you explain me how to make a SSL 128 bit call with nodeJS module request?
Request call
const request= require('request');
const datas = {
url : 'https://secure.ogone.com/ncol/prod/orderdirect_utf8.asp',
method:"POST",
form: 'queryUrlEncoded',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
};
request(datas, (err, response, body) => {
err && console.error(err);
body && console.log(body);
});
Response received
<?xml version="1.0"?>
<ncresponse [...] NCSTATUS="5" NCERROR="50001115" NCERRORPLUS="SSL 128 required">
</ncresponse>
The module you are using has feature to apply SSL but for that you would need a certificate with key, long story short, yes it is possible.
const fs = require('fs')
, path = require('path')
, certFile = path.resolve(__dirname, 'ssl/client.crt')
, keyFile = path.resolve(__dirname, 'ssl/client.key')
, caFile = path.resolve(__dirname, 'ssl/ca.cert.pem')
, request = require('request');
const options = {
url: 'https://api.some-server.com/',
cert: fs.readFileSync(certFile),
key: fs.readFileSync(keyFile),
passphrase: 'password',
ca: fs.readFileSync(caFile)
};
request.get(options);
Copied from documentation.
Click Here for Documentation