Trott / solr-proxy

Reverse proxy to secure Solr, rejecting requests that might modify the Solr index.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Allow HTTPS

Trott opened this issue · comments

Probably best/easiest to do this by emulating http-proxy options target and maybe secure as well. For CLI, --backendPort and --backendHost could go away in favor of --target since the target option of http-proxy can be a string like https://localhost:8888. That conveys three pieces of information: host, port, and protocol.

commented

It would be useful to me in my applications to use the

ssl: {
    key: fs.readFileSync('valid-ssl-key.pem', 'utf8'),
    cert: fs.readFileSync('valid-ssl-cert.pem', 'utf8')
  }

options for http-proxy, since I run solr on localhost unencrypted, but I want traffic from outside to be encrypted.

@nmogk Wouldn't the encryption in that case be a feature to be implemented in http-proxy and not solr-proxy?

commented

It has been implemented as far as I could tell, so you could just pass the options which would enable ssl for solr-proxy.

Maybe I'm misunderstanding, and a pull request would be welcome, but I don't think that will work since the http-proxy isn't actually listening on a port. We don't called httpProxy.createServer() followed by .listen(), but rather call httpProxy.createProxyServer() and use the resulting object inside an http server. (This is straight out of the docs for using custom logic in the proxy. See https://github.com/nodejitsu/node-http-proxy#setup-a-stand-alone-proxy-server-with-custom-server-logic.)

Still, this should be totally do-able. Just the SSL option handling needs to be put in solr-proxy's index.js and not just passed along to http-proxy.

Just to get the use case clear here:

Currently you've got an HTTP solr-proxy talking to HTTP Solr? And you want an HTTPS solr-proxy to talk to HTTP Solr?

If replacing the modules index.js file with this works, then all I need to do is get the test working (certificates are making me sad and none of the usual "ignore invalid cert" options are working for me):

var httpProxy = require('http-proxy'),
    url = require('url'),
    extend = require('xtend'),
    debug = require('debug')('solr-proxy'),
    SolrProxy = {};

/*
 * Returns true if the request satisfies the following conditions:
 *  - HTTP method (e.g., GET) is in options.validHttpMethods
 *  - Path (eg. /solr/update) is in options.validPaths
 *  - All request query params (eg ?q=, ?stream.url=) not in options.invalidParams
 */
var validateRequest = function(request, options) {
  var parsedUrl = url.parse(request.url, true),
      path = parsedUrl.pathname,
      queryParams = Object.keys(parsedUrl.query);

  return options.validHttpMethods.indexOf(request.method) !== -1 &&
         options.validPaths.indexOf(path) !== -1 &&
         queryParams.every(function(p) {
           var paramPrefix = p.split('.')[0]; // invalidate not just "stream", but "stream.*"
           return options.invalidParams.indexOf(paramPrefix) === -1;
         });
};

var defaultOptions = {
  listenPort: 8008,
  validHttpMethods: ['GET'],
  validPaths: ['/solr/select'],
  invalidParams: ['qt', 'stream'],
  backend: {
    host: 'localhost',
    port: 8080
  }
};

var createServer = function(options) {
  var proxy = httpProxy.createProxyServer({target: options.backend});

  proxy.on('error', function(err, req, res) {
    res.writeHead(502, { 'Content-Type': 'text/plain' });
    res.end('Proxy error: ' + err);
  });

  var scheme;
  var myOptions;
  if (options.ssl) {
    scheme = require('https');
    myOptions = options.ssl;
  } else {
    scheme = require('http');
    myOptions = {};
  }

  // adapted from https://git.io/k5dCxQ
  var server = scheme.createServer(function(request, response) {
    if (validateRequest(request, options)) {
      debug('ALLOWED: ' + request.method + ' ' + request.url);
      proxy.web(request, response);
    } else {
      debug('DENIED: ' + request.method + ' ' + request.url);
      response.writeHead(403, 'Illegal request');
      response.write('solrProxy: access denied\n');
      response.end();
    }
  });
  return server;
};

SolrProxy.start = function(port, options) {
  options = options || {};
  options.backend = extend(defaultOptions.backend, options.backend);
  options = extend(defaultOptions, options);

  port = port || options.listenPort;

  var server = createServer(options);
  server.listen(port);
  return server;
};

module.exports = SolrProxy;

@nmogk Any chance you can try that index.js file above and tell me if it does what you want it to do or not?

commented

@Trott Thanks. I will give that a try sometime this weekend.

@nmogk I got the test working and published a new version of the module (2.1.0) with this feature. I'll close this, but feel free to comment here (and re-open if GitHub allows you to) if the feature isn't working for you.

I'm only testing on Node.js 8 and 10, so hopefully you're using one of those versions. If you're using 6, I'm willing to support that but I'll need to rework some test stuff.

(This wasn't implemented for command-line. I'll open a separate issue for that.)