Quinton Pike
Quinton Pike

Reputation: 3861

NodeJS https client errors - 400

I am creating a NodeJS service that connects to Proxmox 2.1's REST api.

My Script:

// module dependencies
var http    = require('http'),
    url     = require('url'),
    https   = require('https'),
    querystring = require('querystring'),
    fs     = require('fs');

exports.urlReq = function(reqUrl, options, cb){
    if(typeof options === "function"){ cb = options; options = {}; }// incase no options passed in

    // parse url to chunks
    reqUrl = url.parse(reqUrl);

    // http.request settings
    var settings = { 
        host: reqUrl.hostname,
        port: reqUrl.port || 80,
        path: reqUrl.pathname,
        headers: options.headers || {},
        method: options.method || 'GET',
        requestCert: false
    };

    // if there are params:
    if(options.params){
        options.params = querystring.stringify(options.params); 
        settings.headers['Content-Length'] = options.params.length; 
    }; 


    // MAKE THE REQUEST
    var req = https.request(settings); 

    req.on('error', function(err) {
        console.log(err);
    });

    // when the response comes back
    req.on('response', function(res){
        res.body = '';

        console.log("statusCode: ", res.statusCode);
        console.log("headers: ", res.headers);

        res.setEncoding('utf-8');

        // concat chunks
        res.on('data', function(chunk){ res.body += chunk });

        res.on('error', function(err){
            throw err;
        })

        // when the response has finished
        res.on('end', function(){

            // fire callback
            cb(res.body, res);
        });
    }); 

    // if there are params: write them to the request
    if(options.params){ req.write(options.params) };

    // end the request
    req.end();
}

The script works for GET requests, although when doing POST requests, it dies. It does not throw any errors, it just silently fails.

When console logging the response, here is the res.connection object:

connection: 
      { pair: [Object],
        writable: true,
        readable: true,
        _paused: false,
        _needDrain: false,
        _pending: [],
        _pendingCallbacks: [],
        _pendingBytes: 0,
        socket: [Object],
        encrypted: [Object],
        authorized: false,
        _controlReleased: true,
        _events: [Object],
        _pool: <Buffer 48 54 54 50 2f 31 2e 31 20 34 30 30 20 50 61 72 61 6d 65 74 65 72 20 76 65 72 69 66 69 63 61 74 69 6f 6e 20 66 61 69 6c 65 64 20 2d 20 64 75 70 6c 69 63 ...>,
        _poolStart: 332,
        _poolEnd: 65536,
        parser: [Object],
        _httpMessage: [Circular],
        ondata: [Function: socketOnData],
        onend: [Function: socketOnEnd],
        npnProtocol: undefined,
        authorizationError: 'UNABLE_TO_VERIFY_LEAF_SIGNATURE' },

The server uses a self signed SSL Cert.

Any help would be extremely appreciated,

Thanks!

Upvotes: 1

Views: 5126

Answers (2)

suitablyawesome
suitablyawesome

Reputation: 131

This is rather old, but I ran into a similar problem recently with Proxmox and wanted to contribute in case anyone else is seeing this issue.

To work around the "authorizationError: 'UNABLE_TO_VERIFY_LEAF_SIGNATURE'" error, you can instruct node.js to accept self-signed certificates(which it rejects by default), put this at the top of your script:

process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = '0';

Also, I can't tell in your code if you set the Content-Type header, but it must be set to application/x-www-form-urlencoded for POSTs to the Proxmox API. Perhaps you set it already in options.headers, but as you specify Content-Length, I wasn't sure. The CSRFPreventionToken is also required for POSTs, so that should be passed as part of the header, as well.

Upvotes: 3

Sim&#243;n
Sim&#243;n

Reputation: 455

authorized: false and authorizationError: 'UNABLE_TO_VERIFY_LEAF_SIGNATURE' clearly state it's a certificate issue, generally due to a certificate not being properly signed by a Root Certification Authority.

I don't know if you can set up a properly signed certificate on the Proxmox server, but whoever manages it should. If it's some piece of software that you maintain or administrate, then you have two options (note that the following applies to every situation where an HTTPS client needs to trust an HTTPS server):

  1. Install a properly signed certificate on the server (buy it, or tell whoever manages it to do so); or
  2. Have your client to trust the unverifiable certificate.

If you're going to do the first thing, then there's nothing else to do from the client side.

So, what follows are brief instructions on how to get your nodejs HTTPS Client to trust a self-signed certificate from a particular server (note that it will only add that particular certificate to the trust chain, not all self-signed certificates):

  1. Visit the target URL with a web browser, and save the certificate locally. Mozilla Firefox supports exporting certificates in PEM format.
  2. If your browser can't export certificates in PEM format, then use OpenSSL to convert it.
  3. Finally, instruct the HTTPS Agent to trust the certificate via the TLS Server options object. See nodejs tls.connect() documentation for details.

Upvotes: 2

Related Questions