-
Notifications
You must be signed in to change notification settings - Fork 8
/
solr-security-proxy.js
114 lines (101 loc) · 4.13 KB
/
solr-security-proxy.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
#!/usr/bin/env node
var httpProxy = require('http-proxy'),
util = require('util'),
url = require('url'),
optimist = require('optimist'),
SolrSecurityProxy = exports;
/*
* Returns true if the request satisfies the following conditions:
* - HTTP method (eg. GET,POST,..) is not in options.invalidHttpMethods
* - 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.invalidHttpMethods.indexOf(request.method) === -1 &&
options.validPaths.indexOf(parsedUrl.pathname) !== -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,
invalidHttpMethods: ['POST'],
validPaths: ['/solr/select'],
invalidParams: ['qt', 'stream'],
backend: {
host: 'localhost',
port: 8080
},
validator: validateRequest
};
/*
* Merge user-supplied options with @defaultOptions*.
*/
var mergeDefaultOptions = function(defaultOptions, options) {
var mergedOptions = {};
options = options || {};
options.backend = options.backend || {};
mergedOptions.invalidHttpMethods = options.invalidHttpMethods || defaultOptions.invalidHttpMethods;
mergedOptions.validPaths = options.validPaths || defaultOptions.validPaths;
mergedOptions.invalidParams = options.invalidParams || defaultOptions.invalidParams;
mergedOptions.backend = options.backend || {};
mergedOptions.backend.host = options.backend.host || defaultOptions.backend.host;
mergedOptions.backend.port = options.backend.port || defaultOptions.backend.port;
mergedOptions.validator = options.validator || defaultOptions.validator;
return mergedOptions;
}
SolrSecurityProxy.createServer = function(options) {
var options = mergeDefaultOptions(defaultOptions, options);
// console.log(options);
// adapted from http://git.io/k5dCxQ
var server = httpProxy.createServer(function(request, response, proxy) {
if (options.validator(request, options)) {
proxy.proxyRequest(request, response, options.backend);
} else {
response.writeHead(403, 'Illegal request');
response.write("solrProxy: access denied\n");
response.end();
}
});
server.proxy.on('proxyError', function(err, req, res) {
res.writeHead(502, { 'Content-Type': 'text/plain' });
res.end('Proxy error: ' + err);
});
return server;
}
SolrSecurityProxy.start = function(port, options) {
var server = SolrSecurityProxy.createServer(options);
server.listen(port);
return server;
}
// if invoked directly, (eg "node solr-security-proxy.js"), start automatically
if (require.main === module) {
// TODO: refactor these; write tests
var options = {
'port': { description: "Listen on this port", default: 8008},
'backendPort': { description: "Solr backend port", default: 8080},
'backendHost': { description: "Solr backend host", default: 'localhost'},
'validPaths': { description: "Only allow these paths (comma separated)", default: '/solr/select'},
'invalidParams': { description: "Block these query params (comma separated)", default: 'qt,stream'},
'invalidMethods': { description: "Block these HTTP methods (comma separated)", default: 'POST'},
'help': { description: "Show usage", alias: 'h'},
};
var argv = optimist.usage('Usage: $0', options).argv
if (argv.help) {
optimist.showHelp();
} else {
var proxyOptions = {
backend: { port: argv.backendPort, host:argv.backendHost},
invalidHttpMethods: argv.invalidMethods.split(","),
invalidParams: argv.invalidParams.split(","),
validPaths: argv.validPaths.split(",")
};
SolrSecurityProxy.start(argv.port, proxyOptions);
util.puts("solr-security-proxy: localhost:" + argv.port + " --> " + argv.backendHost + ":" + argv.backendPort);
return;
}
}