I'm using request in my app to send a POST request over HTTPS with Client Authentication. Request always throws an error Error: Invalid URI "/" and I couldn't do anything to solve it. I've tried used url.parse instead of passing a string but it's still the same.
request.post({
uri: 'https://localhost:5000',
key: credentials.key,
ca: credentials.ca,
cert: credentials.cert,
passphrase: credentials.passphrase,
rejectUnauthorized: false
}, { form: { data: payload }});
Turns out it was caused by passing the second object to request.post, it should be inside the first object.
request.post('https://localhost:5000/', {
key: credentials.key,
ca: credentials.ca,
cert: credentials.cert,
passphrase: credentials.passphrase,
rejectUnauthorized: false,
form: { data: payload }
});
Related
I want to pass a .crt and .key files in order to authenticate and send Post Request using axios . I tired this :
const fs = require('fs')
axios({
rejectUnauthorized: false,
headers: {
'Content-Type': 'application/json'
},
method: 'post',
url: myURL,
cert: fs.readFileSync("../src/certif/mycrt.crt"),
key: fs.readFileSync("../src/certif/mykey.key"),
data: json_object
})
it failed to authenticate i get AuthenticationFailed error.
file are binary data and for that you have to use form data. You can not use json to send files
I am trying to make a request from my Firebase function to a custom server that requires a certficate (.pfx). Based on this answer:
Upload TLS client certificate to Firebase cloud functions
My code is as follows:
const functions = require('firebase-functions');
const request = require('request');
var fs = require('fs');
// The Firebase Admin SDK to access the Firebase Realtime Database.
const admin = require('firebase-admin');
admin.initializeApp();
exports.postBankId = functions.https.onRequest(async (req, res) => {
console.log('PostBankId');
const ipAddress = req.query.ipAddress;
const requestBody = '{ "endUserIp": "' + ipAddress +'" }';
console.log('requestBody:', requestBody);
const options = {
url: 'https://appapi2.test.bankid.com/rp/v5/auth',
json: true,
pfx: fs.readFileSync('bankidtest.pfx'),
passphrase: 'myPassPhraseHere',
body: requestBody
}
request.post(options, (err, response) => {
if (err) {
console.log('bankid creation error: ' + JSON.stringify(err))
res.status(500).send('Failed with error: ' + JSON.stringify(err));
}
if (response) {
res.status(200).send('Success');
console.log('Succes body: ' + response.body)
}
});
});
The answer I get:
{"code":"UNABLE_TO_VERIFY_LEAF_SIGNATURE"}
I place the bankidtest.pfx in the same folder as index.js. And it seems to be uploaded, because if removing it produces another error:
Error: could not handle the request
Edit1:
placing the path to the cert in agentOptions does not work either. Gives same UNABLE_TO_VERIFY_LEAF_SIGNATURE error.
var options = {
url: 'https://appapi2.test.bankid.com/rp/v5/auth',
headers: {
"content-type": "application/json",
},
agentOptions: {
pfx: fs.readFileSync('bankidtest.pfx'),
passphrase: '********'
}
};
Edit2:
Got it semi-working. Setting the request-parameter "rejectUnauthorized" to "false", makes the request work. But according to BankId, this is not a safe or recommended way. The semi-working code is:
request({
url: "https://appapi2.test.bankid.com/rp/v5/auth",
host: "appapi2.test.bankid.com",
rejectUnauthorized: false, // This like makes it work
requestCert: true,
method: "POST",
headers: {
"content-type": "application/json",
'Connection': "Keep-Alive"
},
body: requestBody,
agentOptions: {
pfx: fs.readFileSync('bankidtest.pfx'),
passphrase: '*****'
},
Edit3:
Tried npm install ssl-root-cas and then added this to the top of my index.js:
var sslRootCAs = require('ssl-root-cas/latest')
sslRootCAs.inject()
But then I got this error:
Error: EROFS: read-only file system, open '/srv/node_modules/ssl-root-cas/pems/mozilla-certdata.txt'
at Object.fs.openSync (fs.js:646:18)
at Object.fs.writeFileSync (fs.js:1299:33)
at /srv/node_modules/ssl-root-cas/ca-store-generator.js:219:10
at IncomingMessage.<anonymous>
(/srv/node_modules/#coolaj86/urequest/index.js:154:9)
Edit4:
Tried these instead for depricated inject() but without success. No read-only-error this time, but still UNABLE_TO_VERIFY_LEAF_SIGNATURE:
var rootCas = require('ssl-root-cas/latest').create();
//rootCas.addFile(__dirname + '/mycerts.crt');
rootCas.addFile('mycerts.cer');
rootCas.addFile('mycerts.crt');
rootCas.addFile('bankidtest.pfx'); // Also tried with __dirname
require('https').globalAgent.options.ca = rootCas;
// Also tried this:
//require('https').globalAgent.options.ca = require('ssl-root-cas').rootCas
Edit5 Solved it
Seemed as a CA was needed that was not derived from the pfx file.
Bank-ID provided a CA as a text in their documentation. Starting with "-----BEGIN CERTIFICATE"... I copied the text into a pem file and referenced it from my index.js-file like this:
agentOptions: {
pfx: fs.readFileSync('bankidtest.pfx'),
passphrase: '*****',
ca: fs.readFileSync('certificate.pem')
},
I have a problem when I run get a response for service. There are two services. For the first service, it's working perfectly but in the second I have issue "Error [ERR_TLS_CERT_ALTNAME_INVALID]: Hostname/IP does not match certificate's altnames: Cert is empty". When I used Postman with certificates its works perfectly. What should I set or implement to make it works?
I tried using: checkServerIdentity, rejectUnauthorized: true.
let options = {
hostname: 'ws.aaa.bbb.nn',
path: '/api',
method: 'GET',
key: fs.readFileSync('/private.crt'),
cert: fs.readFileSync('/public.crt'),
passphrase: '***'
};
const req = https.request(options, (res) => {
let body = '';
res.on('data', (chunk)=> {
body += chunk;
console.log(body)
});
});
Should be status code 200.
Seems you got a bad certificate.
Get a correct one or just turn the SSL certificate verification off.
I had the same problem, Just try to set Authorization Type to "Inherit auth from parent".
i get a certificate from an azure key vault :
const certificate = await keyVaultClient.getCertificate(this.keyVaultUri, certificateName, '');
i get the certificate ... first good thing :)
But after i don't find how i can set the certificate in the header of an https request.
i've tried different ways without any success.
Someone knows how i can achieve that. Below test done.
var options = {
hostname: 'url.domain.com',
port: 443,
path: '/method1',
method: 'GET',
agent: false,
rejectUnauthorized: false,
strictSSL: false,
//pfx: certificate.cer.toString('utf8'),
//pfx: certificate.cer.toString('base64'),
pfx: certificate,
passphrase: 'passphrase'
};
const req = https.request(options, (res: any) => { });
Note that if i use the certificate on the drive, it works :
pfx: fs.readFileSync(__dirname + '/my.pfx'),
Thanks in advance
i've found a solution.
First to get the certificate, i've used the method 'getSercret' in place of 'getCertificate' :
let keyVaultClient = new KeyVault.KeyVaultClient(azureCredential);
const secret = await keyVaultClient.getSecret(this.keyVaultUri, secretName, '');
In the header option, i've passed the secret in a buffer with base 64 format :
var options = {
hostname: 'myurl.ti',
port: 443,
path: '/mySuperMethod',
method: 'GET',
agent: false,
rejectUnauthorized: false,
strictSSL: false,
pfx: new Buffer(secret.value, 'base64'),
passphrase: ''
};
You see that the passphrase (password to secure password) is empty. Why ? in fact when you upload a certificate in azure keyvault, you have to mention the password. But after keyvault doesn't keep the password and it's set to blank.
That's known by microsoft and for me it's an issue.
Here an article that explain that : https://thuansoldier.net/7462/
Regards Mathieu
I am trying to make a request with a p12 file or a pfx, but I can't get it to work. If I use PEM and KEY the code works fine. But Azure Keyvault does not support PEM and KEY. Is there an alternative that works with KEY/PEM certificates?
This is how I generated a p12/pfx file if that is the problem.
openssl pkcs12 -export -out certificate.pfx -inkey 1231181189.key -in
1231181189.pem -certfile CA.pem
Here is an example code, if I comment out cert and key the system does not work,
Error: read ECONNRESET
But if I comment out pfx and passphrase and use pem and key the connection work.
var request = require('request');
var fs = require('fs');
var path = require('path');
var certFile = __dirname + '/certs/1231181189.pem';
var keyFile = __dirname + '/certs/1231181189.key';
var options = {
method: 'POST',
url: 'https://mss.cpc.getswish.net/swish-cpcapi/api/v1/paymentrequests',
headers: { 'Content-Type': 'application/json' },
agentOptions: {
cert: fs.readFileSync(certFile),
key: fs.readFileSync(keyFile),
pfx: fs.readFileSync(__dirname + '/certs/certificate.pfx'),
passphrase: 'swish'
},
body: {
payeePaymentReference: '0123456789',
callbackUrl: 'https://example.com/api/swishcb/paymentrequests',
payerAlias: '4671234768',
payeeAlias: '1231181189',
amount: '100',
currency: 'SEK',
message: 'Kingston USB Flash Drive 8 GB'
},
json: true
};
request(options, function (error, response, body) {
if (error) throw new Error(error);
console.log(response.headers);
console.log(body);
});
ECONNRESET means the far end -- in your case the endpoint on swish.net -- unceremoniously disconnected from the https client in your nodejs program. It's hard to know precisely why it did so. It's likely due to some sort of security failure. Robust servers don't explain security failures; after all why help cybercreeps? It's possible looking at a log on that server will tell you more.
In the meantime, it's possible the npm request package you use to wrap node's https agent function doesn't know anything about .pfx files or passwords, and therefore attempts to connect without any client certificates.
The pemutils package may allow you to extract the information you need from your .pfx file and use it. Something like this may work (not debugged).
var request = require('request');
var pemutils = require('pemutils');
var fs = require('fs');
var path = require('path');
const pfxFile = __dirname + '/certs/certificate.pfx';
pemutils.fromPfx({
path: pfxFile,
password: 'myPass'
}, function(err, pfxresults) {
if(err) throw err;
var options = {
method: 'POST',
url: 'https://mss.cpc.getswish.net/swish-cpcapi/api/v1/paymentrequests',
headers: { 'Content-Type': 'application/json' },
agentOptions: {
cert: pfxresults.certificate,
key: pfxresults.key,
},
body: {
...
},
json: true
};
...
Notice the .fromPfx method is asynchronous.
I have the same issue with Azure APIM and I also need basic auth for the request.
I send request with axios like below:
const fs = require("fs");
const axios = require("axios");
const https = require("https");
(async function () {
try {
const response = await axios.request({
url: "url",
method: "get",
headers: {
accept: "application/json",
},
auth: {
username: "name",
password: "pw",
},
httpsAgent: new https.Agent({
pfx: fs.readFileSync(
__dirname + "/mycert.pfx"
),
}),
});
console.log(JSON.stringify(response.data));
} catch (error) {
console.log(error);
}
})();