Fixes #5942.
return false;
}
-void WebServer::apiWrapper(WebServer::HandlerFunction handler, HttpRequest* req, HttpResponse* resp) {
+void WebServer::apiWrapper(WebServer::HandlerFunction handler, HttpRequest* req, HttpResponse* resp, bool allowPassword) {
if (optionsHandler(req, resp)) return;
resp->headers["access-control-allow-origin"] = "*";
}
bool auth_ok = req->compareHeader("x-api-key", d_apikey) || req->getvars["api-key"] == d_apikey;
-
+
+ if (!auth_ok && allowPassword) {
+ if (!d_webserverPassword.empty()) {
+ auth_ok = req->compareAuthorization(d_webserverPassword);
+ } else {
+ auth_ok = true;
+ }
+ }
+
if (!auth_ok) {
g_log<<Logger::Error<<req->logprefix<<"HTTP Request \"" << req->url.path << "\": Authentication by API Key failed" << endl;
throw HttpUnauthorizedException("X-API-Key");
}
}
-void WebServer::registerApiHandler(const string& url, HandlerFunction handler) {
- HandlerFunction f = boost::bind(&WebServer::apiWrapper, this, handler, _1, _2);
+void WebServer::registerApiHandler(const string& url, HandlerFunction handler, bool allowPassword) {
+ HandlerFunction f = boost::bind(&WebServer::apiWrapper, this, handler, _1, _2, allowPassword);
registerBareHandler(url, f);
}
void handleRequest(HttpRequest& request, HttpResponse& resp) const;
typedef boost::function<void(HttpRequest* req, HttpResponse* resp)> HandlerFunction;
- void registerApiHandler(const string& url, HandlerFunction handler);
+ void registerApiHandler(const string& url, HandlerFunction handler, bool allowPassword=false);
void registerWebHandler(const string& url, HandlerFunction handler);
enum class LogLevel : uint8_t {
std::shared_ptr<Server> d_server;
std::string d_apikey;
- void apiWrapper(WebServer::HandlerFunction handler, HttpRequest* req, HttpResponse* resp);
+ void apiWrapper(WebServer::HandlerFunction handler, HttpRequest* req, HttpResponse* resp, bool allowPassword);
std::string d_webserverPassword;
void webWrapper(WebServer::HandlerFunction handler, HttpRequest* req, HttpResponse* resp);
d_ws->bind();
// legacy dispatch
- d_ws->registerApiHandler("/jsonstat", boost::bind(&RecursorWebServer::jsonstat, this, _1, _2));
+ d_ws->registerApiHandler("/jsonstat", boost::bind(&RecursorWebServer::jsonstat, this, _1, _2), true);
d_ws->registerApiHandler("/api/v1/servers/localhost/cache/flush", &apiServerCacheFlush);
d_ws->registerApiHandler("/api/v1/servers/localhost/config/allow-from", &apiServerConfigAllowFrom);
d_ws->registerApiHandler("/api/v1/servers/localhost/config", &apiServerConfig);
d_ws->registerApiHandler("/api/v1/servers/localhost/rpzstatistics", &apiServerRPZStats);
d_ws->registerApiHandler("/api/v1/servers/localhost/search-data", &apiServerSearchData);
- d_ws->registerApiHandler("/api/v1/servers/localhost/statistics", &apiServerStatistics);
+ d_ws->registerApiHandler("/api/v1/servers/localhost/statistics", &apiServerStatistics, true);
d_ws->registerApiHandler("/api/v1/servers/localhost/zones/<id>", &apiServerZoneDetail);
d_ws->registerApiHandler("/api/v1/servers/localhost/zones", &apiServerZones);
- d_ws->registerApiHandler("/api/v1/servers/localhost", &apiServerDetail);
+ d_ws->registerApiHandler("/api/v1/servers/localhost", &apiServerDetail, true);
d_ws->registerApiHandler("/api/v1/servers", &apiServer);
d_ws->registerApiHandler("/api", &apiDiscovery);
WEBPORT = 5556
DNSPORT = 5300
APIKEY = '1234567890abcdefghijklmnopq-key'
+WEBPASSWORD = 'something'
PDNSUTIL_CMD = [os.environ.get("PDNSUTIL", "../pdns/pdnsutil"), "--config-dir=."]
NAMED_CONF_TPL = """
common_args = [
"--daemon=no", "--socket-dir=.", "--config-dir=.",
"--local-address=127.0.0.1", "--local-port="+str(DNSPORT),
- "--webserver=yes", "--webserver-port="+str(WEBPORT), "--webserver-address=127.0.0.1", "--webserver-password=something",
+ "--webserver=yes", "--webserver-port="+str(WEBPORT), "--webserver-address=127.0.0.1",
+ "--webserver-password="+WEBPASSWORD,
"--api-key="+APIKEY
]
test_env = {}
test_env.update(os.environ)
test_env.update({
+ 'WEBPASSWORD': WEBPASSWORD,
'WEBPORT': str(WEBPORT),
'APIKEY': APIKEY,
'DAEMON': daemon,
r = requests.get(self.url("/api/v1/servers/localhost"))
self.assertEquals(r.status_code, requests.codes.unauthorized)
+ def test_index_html(self):
+ r = requests.get(self.url("/"), auth=('admin', self.server_web_password))
+ self.assertEquals(r.status_code, requests.codes.ok)
+
def test_split_request(self):
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
+import requests
+import unittest
from test_helper import ApiTestCase, is_auth, is_recursor
r = self.session.get(self.url("/api/v1/servers/localhost/statistics?statistic=uptimeAAAA"))
self.assertEquals(r.status_code, 422)
self.assertIn("Unknown statistic name", r.json()['error'])
+
+ @unittest.skipIf(is_auth(), "Not applicable")
+ def test_read_statistics_using_password(self):
+ r = requests.get(self.url("/api/v1/servers/localhost/statistics"), auth=('admin', self.server_web_password))
+ self.assertEquals(r.status_code, requests.codes.ok)
+ self.assert_success_json(r)
self.server_address = '127.0.0.1'
self.server_port = int(os.environ.get('WEBPORT', '5580'))
self.server_url = 'http://%s:%s/' % (self.server_address, self.server_port)
+ self.server_web_password = os.environ.get('WEBPASSWORD', 'MISSING')
self.session = requests.Session()
self.session.headers = {'X-API-Key': os.environ.get('APIKEY', 'changeme-key'), 'Origin': 'http://%s:%s' % (self.server_address, self.server_port)}
url = 'http://127.0.0.1:' + str(self._webServerPort) + path
r = requests.get(url, headers=headers, timeout=self._webTimeout)
self.assertEquals(r.status_code, 401)
+
def testBasicAuthOnly(self):
"""
API: Basic Authentication Only