From b1f03e0d4b33c7d25b047d7d2e1d7ff9972192d4 Mon Sep 17 00:00:00 2001 From: Costa Tsaousis Date: Fri, 13 May 2016 02:52:28 +0300 Subject: [PATCH] registry completed, including impersonate --- src/registry.c | 83 ++++++++++++++++++++++++++++---- src/registry.h | 1 + src/web_client.c | 24 +++++++--- web/dashboard.js | 120 ++++++++++++++++++++++++++++++++++------------ web/index.html | 122 ++++++++++++++++++++++++++++++++++++----------- 5 files changed, 275 insertions(+), 75 deletions(-) diff --git a/src/registry.c b/src/registry.c index 8cc19d62..932ee5af 100644 --- a/src/registry.c +++ b/src/registry.c @@ -540,9 +540,7 @@ static inline PERSON *registry_person_allocate(const char *person_guid, time_t w if(!person_guid) { for (; ;) { uuid_t uuid; - if (uuid_generate_time_safe(uuid) == -1) - info("Registry: uuid_generate_time_safe() reports UUID generation is not safe for uniqueness."); - + uuid_generate(uuid); uuid_unparse_lower(uuid, p->guid); debug(D_REGISTRY, "Registry: Checking if the generated person guid '%s' is unique", p->guid); @@ -923,7 +921,7 @@ PERSON *registry_request_delete(char *person_guid, char *machine_guid, char *url // make sure the user is not deleting the url it uses if(!strcmp(delete_url, pu->url->url)) { - info("Registry Delete Request: delete URL is the one currently accessing, person: '%s', machine '%s', url '%s', delete url '%s'", p->guid, m->guid, pu->url->url, delete_url); + info("Registry Delete Request: delete URL is the one currently accessed, person: '%s', machine '%s', url '%s', delete url '%s'", p->guid, m->guid, pu->url->url, delete_url); return NULL; } @@ -931,7 +929,7 @@ PERSON *registry_request_delete(char *person_guid, char *machine_guid, char *url PERSON_URL *dpu = dictionary_get(p->urls, delete_url); if(!dpu) { - info("Registry Delete Request: URL not found for person, person: '%s', machine '%s', url '%s', delete url '%s'", p->guid, m->guid, pu->url->url, delete_url); + info("Registry Delete Request: URL not found for person: '%s', machine '%s', url '%s', delete url '%s'", p->guid, m->guid, pu->url->url, delete_url); registry_person_urls_unlock(p); return NULL; } @@ -1110,7 +1108,7 @@ int registry_request_access_json(struct web_client *w, char *person_guid, char * if(!p) { registry_json_header(w, "access", REGISTRY_STATUS_FAILED); registry_json_footer(w); - return 400; + return 412; } // set the cookie @@ -1119,7 +1117,7 @@ int registry_request_access_json(struct web_client *w, char *person_guid, char * // generate the response registry_json_header(w, "access", REGISTRY_STATUS_OK); - buffer_strcat(w->response.data, ",\n\t\"urls\": ["); + buffer_sprintf(w->response.data, ",\n\t\"person_guid\": \"%s\",\n\t\"urls\": [", p->guid); struct registry_json_walk_person_urls_callback c = { p, NULL, w, 0 }; dictionary_get_all(p->urls, registry_json_person_url_callback, &c); buffer_strcat(w->response.data, "\n\t]\n"); @@ -1137,7 +1135,7 @@ int registry_request_delete_json(struct web_client *w, char *person_guid, char * if(!p) { registry_json_header(w, "delete", REGISTRY_STATUS_FAILED); registry_json_footer(w); - return 400; + return 412; } // generate the response @@ -1155,7 +1153,7 @@ int registry_request_search_json(struct web_client *w, char *person_guid, char * if(!m) { registry_json_header(w, "search", REGISTRY_STATUS_FAILED); registry_json_footer(w); - return 400; + return 404; } registry_json_header(w, "search", REGISTRY_STATUS_OK); @@ -1170,6 +1168,73 @@ int registry_request_search_json(struct web_client *w, char *person_guid, char * } +int registry_person_url_callback_verify_machine_exists(void *entry, void *machine) { + PERSON_URL *pu = (PERSON_URL *)entry; + MACHINE *m = (MACHINE *)machine; + + if(pu->machine == m) + return 1; + else + return 0; +} + +// the main method for switching user identity +int registry_request_switch_json(struct web_client *w, char *person_guid, char *machine_guid, char *url, char *new_person_guid, time_t when) { + (void)url; + (void)when; + + if(!registry.enabled) + return registry_json_disabled(w, "switch"); + + PERSON *op = registry_person_find(person_guid); + if(!op) { + registry_json_header(w, "switch", REGISTRY_STATUS_FAILED); + registry_json_footer(w); + return 430; + } + + PERSON *np = registry_person_find(new_person_guid); + if(!np) { + registry_json_header(w, "switch", REGISTRY_STATUS_FAILED); + registry_json_footer(w); + return 431; + } + + MACHINE *m = registry_machine_find(machine_guid); + if(!m) { + registry_json_header(w, "switch", REGISTRY_STATUS_FAILED); + registry_json_footer(w); + return 432; + } + + // verify the old person has access to this machine + int count = dictionary_get_all(op->urls, registry_person_url_callback_verify_machine_exists, m); + if(!count) { + registry_json_header(w, "switch", REGISTRY_STATUS_FAILED); + registry_json_footer(w); + return 433; + } + + // verify the new person has access to this machine + count = dictionary_get_all(np->urls, registry_person_url_callback_verify_machine_exists, m); + if(!count) { + registry_json_header(w, "switch", REGISTRY_STATUS_FAILED); + registry_json_footer(w); + return 434; + } + + // set the cookie of the new person + // the user just switched identity + registry_set_person_cookie(w, np); + + // generate the response + registry_json_header(w, "switch", REGISTRY_STATUS_OK); + buffer_sprintf(w->response.data, ",\n\t\"person_guid\": \"%s\"", np->guid); + registry_json_footer(w); + return 200; +} + + // ---------------------------------------------------------------------------- // REGISTRY THIS MACHINE UNIQUE ID diff --git a/src/registry.h b/src/registry.h index 03ffbb31..d95383b5 100644 --- a/src/registry.h +++ b/src/registry.h @@ -8,6 +8,7 @@ extern int registry_request_access_json(struct web_client *w, char *person_guid, char *machine_guid, char *url, char *name, time_t when); extern int registry_request_delete_json(struct web_client *w, char *person_guid, char *machine_guid, char *url, char *delete_url, time_t when); extern int registry_request_search_json(struct web_client *w, char *person_guid, char *machine_guid, char *url, char *request_machine, time_t when); +extern int registry_request_switch_json(struct web_client *w, char *person_guid, char *machine_guid, char *url, char *new_person_guid, time_t when); extern int registry_request_hello_json(struct web_client *w); extern int registry_init(void); diff --git a/src/web_client.c b/src/web_client.c index 463d0862..5cba375d 100644 --- a/src/web_client.c +++ b/src/web_client.c @@ -812,7 +812,8 @@ int web_client_api_request_v1_registry(struct web_client *w, char *url) *machine_url = NULL, *url_name = NULL, *search_machine_guid = NULL, - *delete_url = NULL; + *delete_url = NULL, + *to_person_guid = NULL; while(url) { char *value = mystrsep(&url, "?&[]"); @@ -829,6 +830,7 @@ int web_client_api_request_v1_registry(struct web_client *w, char *url) else if(!strcmp(value, "hello")) action = 'H'; else if(!strcmp(value, "delete")) action = 'D'; else if(!strcmp(value, "search")) action = 'S'; + else if(!strcmp(value, "switch")) action = 'W'; } else if(!strcmp(name, "machine")) machine_guid = value; @@ -848,6 +850,10 @@ int web_client_api_request_v1_registry(struct web_client *w, char *url) if(!strcmp(name, "for")) search_machine_guid = value; } + else if(action == 'W') { + if(!strcmp(name, "to")) + to_person_guid = value; + } } if(action == 'A' && (!machine_guid || !machine_url || !url_name)) { @@ -868,15 +874,12 @@ int web_client_api_request_v1_registry(struct web_client *w, char *url) machine_guid?machine_guid:"UNSET", machine_url?machine_url:"UNSET", search_machine_guid?search_machine_guid:"UNSET"); return 400; } - - /* - * No, this is not right - if(action != 'H' && !person_guid[0]) { + else if(action == 'W' && (!machine_guid || !machine_url || !to_person_guid)) { buffer_flush(w->response.data); - buffer_sprintf(w->response.data, "Invalid registry request - you need to send your cookie for this action."); + buffer_sprintf(w->response.data, "Invalid registry request - switching identity requires these parameters: machine ('%s'), url ('%s'), to ('%s')", + machine_guid?machine_guid:"UNSET", machine_url?machine_url:"UNSET", to_person_guid?to_person_guid:"UNSET"); return 400; } - */ switch(action) { case 'A': @@ -888,6 +891,9 @@ int web_client_api_request_v1_registry(struct web_client *w, char *url) case 'S': return registry_request_search_json(w, person_guid, machine_guid, machine_url, search_machine_guid, time(NULL)); + case 'W': + return registry_request_switch_json(w, person_guid, machine_guid, machine_url, to_person_guid, time(NULL)); + case 'H': return registry_request_hello_json(w); @@ -1632,6 +1638,10 @@ void web_client_process(struct web_client *w) { code_msg = "Not Found"; break; + case 412: + code_msg = "Preconditions Failed"; + break; + default: code_msg = "Internal Server Error"; break; diff --git a/web/dashboard.js b/web/dashboard.js index d201f0f6..85620a7b 100644 --- a/web/dashboard.js +++ b/web/dashboard.js @@ -496,7 +496,11 @@ 407: { message: "Cannot HELLO netdata server", alert: false }, 408: { message: "Netdata servers sent invalid response to HELLO", alert: false }, 409: { message: "Cannot ACCESS netdata registry", alert: false }, - 410: { message: "Netdata registry ACCESS failed", alert: false } + 410: { message: "Netdata registry ACCESS failed", alert: false }, + 411: { message: "Netdata registry server send invalid response to DELETE ", alert: false }, + 412: { message: "Netdata registry DELETE failed", alert: false }, + 413: { message: "Netdata registry server send invalid response to SWITCH ", alert: false }, + 414: { message: "Netdata registry SWITCH failed", alert: false } }; NETDATA.errorLast = { code: 0, @@ -5487,28 +5491,11 @@ // Registry of netdata hosts NETDATA.registry = { - server: null, - machine_guid: null, - hostname: null, - urls: null, - - init: function() { - if(typeof netdataNoRegistry !== 'undefined' && netdataNoRegistry) - return; - - NETDATA.registry.hello(NETDATA.serverDefault, function(data) { - if(data) { - NETDATA.registry.server = data.registry; - NETDATA.registry.machine_guid = data.machine_guid; - NETDATA.registry.hostname = data.hostname; - - NETDATA.registry.access(10, function (person_urls) { - NETDATA.registry.parsePersonUrls(person_urls); - - }); - } - }); - }, + server: null, // the netdata registry server + person_guid: null, // the unique ID of this browser / user + machine_guid: null, // the unique ID the netdata server that served dashboard.js + hostname: null, // the hostname of the netdata server that served dashboard.js + urls: null, // the user's other URLs parsePersonUrls: function(person_urls) { if(person_urls) { @@ -5543,6 +5530,24 @@ netdataRegistryCallback(NETDATA.registry.urls); }, + init: function() { + if(typeof netdataNoRegistry !== 'undefined' && netdataNoRegistry) + return; + + NETDATA.registry.hello(NETDATA.serverDefault, function(data) { + if(data) { + NETDATA.registry.server = data.registry; + NETDATA.registry.machine_guid = data.machine_guid; + NETDATA.registry.hostname = data.hostname; + + NETDATA.registry.access(10, function (person_urls) { + NETDATA.registry.parsePersonUrls(person_urls); + + }); + } + }); + }, + hello: function(host, callback) { // send HELLO to a netdata server: // 1. verifies the server is reachable @@ -5572,11 +5577,12 @@ access: function(max_redirects, callback) { // send ACCESS to a netdata registry: - // 1. it let it know we are accessing a netdata server (in the URL) + // 1. it lets it know we are accessing a netdata server (its machine GUID and its URL) // 2. it responds with a list of netdata servers we know // the registry identifies us using a cookie it sets the first time we access it + // the registry may respond with a redirect URL to send us to another registry $.ajax({ - url: NETDATA.registry.server + '/api/v1/registry?action=access&machine=' + NETDATA.registry.machine_guid + '&name=' + encodeURIComponent(NETDATA.registry.hostname) + '&url=' + encodeURIComponent(NETDATA.serverDefault) + '&visible_url=' + encodeURIComponent(document.location), + url: NETDATA.registry.server + '/api/v1/registry?action=access&machine=' + NETDATA.registry.machine_guid + '&name=' + encodeURIComponent(NETDATA.registry.hostname) + '&url=' + encodeURIComponent(NETDATA.serverDefault), // + '&visible_url=' + encodeURIComponent(document.location), async: true, cache: false, xhrFields: { withCredentials: true } // required for the cookie @@ -5586,24 +5592,76 @@ if(typeof data.registry === 'string') redirect = data.registry; - if(typeof data.status !== 'string' || data.status !== 'ok') + if(typeof data.status !== 'string' || data.status !== 'ok') { + NETDATA.error(409, NETDATA.registry.server + ' responded with: ' + JSON.stringify(data)); data = null; + } if(data === null && redirect !== null && max_redirects > 0) { + NETDATA.registry.server = redirect; NETDATA.registry.access(max_redirects - 1, callback); } - else if(data === null) { - NETDATA.error(409, NETDATA.registry.server + ' response: ' + JSON.stringify(data)); - if(typeof callback === 'function') - callback(null); - } else { + if(typeof data.person_guid === 'string') + NETDATA.registry.person_guid = data.person_guid; + if(typeof callback === 'function') callback(data.urls); } }) .fail(function() { NETDATA.error(410, NETDATA.registry.server); + + if(typeof callback === 'function') + callback(null); + }); + }, + + delete: function(delete_url, callback) { + // send DELETE to a netdata registry: + $.ajax({ + url: NETDATA.registry.server + '/api/v1/registry?action=delete&machine=' + NETDATA.registry.machine_guid + '&name=' + encodeURIComponent(NETDATA.registry.hostname) + '&url=' + encodeURIComponent(NETDATA.serverDefault) + '&delete_url=' + encodeURIComponent(delete_url), + async: true, + cache: false, + xhrFields: { withCredentials: true } // required for the cookie + }) + .done(function(data) { + if(typeof data.status !== 'string' || data.status !== 'ok') { + NETDATA.error(411, NETDATA.registry.server + ' responded with: ' + JSON.stringify(data)); + data = null; + } + + if(typeof callback === 'function') + callback(data); + }) + .fail(function() { + NETDATA.error(412, NETDATA.registry.server); + + if(typeof callback === 'function') + callback(null); + }); + }, + + switch: function(new_person_guid, callback) { + // impersonate + $.ajax({ + url: NETDATA.registry.server + '/api/v1/registry?action=switch&machine=' + NETDATA.registry.machine_guid + '&name=' + encodeURIComponent(NETDATA.registry.hostname) + '&url=' + encodeURIComponent(NETDATA.serverDefault) + '&to=' + new_person_guid, + async: true, + cache: false, + xhrFields: { withCredentials: true } // required for the cookie + }) + .done(function(data) { + if(typeof data.status !== 'string' || data.status !== 'ok') { + NETDATA.error(413, NETDATA.registry.server + ' responded with: ' + JSON.stringify(data)); + data = null; + } + + if(typeof callback === 'function') + callback(data); + }) + .fail(function() { + NETDATA.error(414, NETDATA.registry.server); + if(typeof callback === 'function') callback(null); }); diff --git a/web/index.html b/web/index.html index 126f31a4..225e201e 100644 --- a/web/index.html +++ b/web/index.html @@ -362,23 +362,37 @@ var netdataRegistryCallback = function(urls) { if(urls) { + var found = 0; var el = ''; var a1 = ''; $.each(urls, function(i, u) { - if(u.guid === NETDATA.registry.machine_guid) - el += '
  • ' + u.name + '
  • '; - else + if(u.guid !== NETDATA.registry.machine_guid) { + found++; el += '
  • ' + u.name + '
  • '; - - a1 += '
  • '; + a1 += '
  • '; + } }); + + if(!found) { + el += '
  • your netdata server list is empty...
  • '; + a1 += '
  •  
  • '; + + el += '' + + '
  • EU - London (DigitalOcean.com)
  • ' + + '
  • US - Atlanta (CDN77.com)
  • ' + + '
  • EU - Athens
  • '; + a1 += '' + + '
  •  
  • ' + + '
  •  
  • '+ + '
  •  
  • '; + } el += ''; a1 += ''; el += '
  • What is this?
  • '; - a1 += '
  • ' + a1 += '
  • ' document.getElementById('mynetdata_servers').innerHTML = el; document.getElementById('mynetdata_actions1').innerHTML = a1; @@ -404,12 +418,6 @@
    + +