HAWQ-1257. Prompt all tables which user doesn't have right once
Project: http://git-wip-us.apache.org/repos/asf/incubator-hawq/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-hawq/commit/bf4742cb Tree: http://git-wip-us.apache.org/repos/asf/incubator-hawq/tree/bf4742cb Diff: http://git-wip-us.apache.org/repos/asf/incubator-hawq/diff/bf4742cb Branch: refs/heads/2.1.0.0-incubating Commit: bf4742cb6c4cd71c9174f030c54e28b8c2595942 Parents: 3b15739 Author: interma <inte...@outlook.com> Authored: Wed Jan 11 14:51:21 2017 +0800 Committer: Wen Lin <w...@pivotal.io> Committed: Thu Jan 12 17:45:20 2017 +0800 ---------------------------------------------------------------------- src/backend/catalog/aclchk.c | 60 +++++++++--- src/backend/libpq/rangerrest.c | 139 ++++++++++++++++++++------ src/backend/parser/parse_relation.c | 163 ++++++++++++++++++------------- src/include/utils/rangerrest.h | 13 ++- 4 files changed, 255 insertions(+), 120 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/bf4742cb/src/backend/catalog/aclchk.c ---------------------------------------------------------------------- diff --git a/src/backend/catalog/aclchk.c b/src/backend/catalog/aclchk.c index 01a4f94..73de11b 100644 --- a/src/backend/catalog/aclchk.c +++ b/src/backend/catalog/aclchk.c @@ -2710,17 +2710,23 @@ List *pg_rangercheck_batch(List *arg_list) List *aclresults = NIL; List *requestargs = NIL; ListCell *arg; + elog(LOG, "rangeracl batch check, acl list length:%d\n", arg_list->length); foreach(arg, arg_list) { RangerPrivilegeArgs *arg_ptr = (RangerPrivilegeArgs *) lfirst(arg); + AclObjectKind objkind = arg_ptr->objkind; Oid object_oid = arg_ptr->object_oid; char *objectname = getNameFromOid(objkind, object_oid); char *rolename = getRoleName(arg_ptr->roleid); List* actions = getActionName(arg_ptr->mask); bool isAll = (arg_ptr->how == ACLMASK_ALL) ? true: false; + RangerPrivilegeResults *aclresult = (RangerPrivilegeResults *) palloc(sizeof(RangerPrivilegeResults)); - aclresult->result = -1; + aclresult->result = RANGERCHECK_NO_PRIV; aclresult->relOid = object_oid; + // this two sign fields will be set in create_ranger_request_json() + aclresult->resource_sign = 0; + aclresult->privilege_sign = 0; aclresults = lappend(aclresults, aclresult); RangerRequestJsonArgs *requestarg = (RangerRequestJsonArgs *) palloc(sizeof(RangerRequestJsonArgs)); @@ -2733,14 +2739,15 @@ List *pg_rangercheck_batch(List *arg_list) } // foreach - RangerACLResult ret = check_privilege_from_ranger(requestargs); - - ListCell *result; - int k = 0; - foreach(result, aclresults) { - RangerPrivilegeResults *result_ptr = (RangerPrivilegeResults *) lfirst(result); - result_ptr->result = ret; - ++k; + int ret = check_privilege_from_ranger(requestargs, aclresults); + if (ret < 0) + { + elog(WARNING, "ranger service unavailable or unexpected error\n"); + ListCell *result; + foreach(result, aclresults) { + RangerPrivilegeResults *result_ptr = (RangerPrivilegeResults *) lfirst(result); + result_ptr->result = RANGERCHECK_NO_PRIV; + } } if(requestargs) { @@ -2760,10 +2767,6 @@ List *pg_rangercheck_batch(List *arg_list) requestargs = NULL; } - if(ret != RANGERCHECK_OK){ - elog(ERROR, "ACL check failed\n"); - } - elog(LOG, "oids%d\n", arg_list->length); return aclresults; } @@ -2777,6 +2780,16 @@ pg_rangercheck(AclObjectKind objkind, Oid object_oid, Oid roleid, bool isAll = (how == ACLMASK_ALL) ? true: false; elog(LOG, "rangeraclcheck kind:%d,objectname:%s,role:%s,mask:%u\n",objkind,objectname,rolename,mask); + + List *resultargs = NIL; + RangerPrivilegeResults *aclresult = (RangerPrivilegeResults *) palloc(sizeof(RangerPrivilegeResults)); + aclresult->result = RANGERCHECK_NO_PRIV; + aclresult->relOid = object_oid; + // this two sign fields will be set in create_ranger_request_json() + aclresult->resource_sign = 0; + aclresult->privilege_sign = 0; + resultargs = lappend(resultargs, aclresult); + List *requestargs = NIL; RangerRequestJsonArgs *requestarg = (RangerRequestJsonArgs *) palloc(sizeof(RangerRequestJsonArgs)); requestarg->user = rolename; @@ -2785,8 +2798,25 @@ pg_rangercheck(AclObjectKind objkind, Oid object_oid, Oid roleid, requestarg->actions = actions; requestarg->isAll = isAll; requestargs = lappend(requestargs, requestarg); - int ret = check_privilege_from_ranger(requestargs); + AclResult result = ACLCHECK_NO_PRIV; + int ret = check_privilege_from_ranger(requestargs, resultargs); + if (ret == 0) + { + ListCell *arg; + foreach(arg, resultargs) { + // only one element + RangerPrivilegeResults *arg_ptr = (RangerPrivilegeResults *) lfirst(arg); + if (arg_ptr->result == RANGERCHECK_OK) + result = ACLCHECK_OK; + break; + } + } + + if (resultargs) + { + list_free_deep(resultargs); + } if (requestargs) { ListCell *cell = list_head(requestargs); @@ -2802,7 +2832,7 @@ pg_rangercheck(AclObjectKind objkind, Oid object_oid, Oid roleid, list_free_deep(requestargs); requestargs = NULL; } - return ret; + return result; } /* http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/bf4742cb/src/backend/libpq/rangerrest.c ---------------------------------------------------------------------- diff --git a/src/backend/libpq/rangerrest.c b/src/backend/libpq/rangerrest.c index 5406251..74777dc 100644 --- a/src/backend/libpq/rangerrest.c +++ b/src/backend/libpq/rangerrest.c @@ -25,6 +25,7 @@ *------------------------------------------------------------------------- */ #include "utils/rangerrest.h" +#include "utils/hsearch.h" /* * A mapping from AclObjectKind to string */ @@ -68,12 +69,16 @@ static void getClientIP(char *remote_host) } } -RangerACLResult parse_ranger_response(char* buffer) +/* + * parse ranger response + * @param buffer ranger response + * @param result_list List of RangerPrivilegeResults + * @return 0 parse success; -1 other error + */ +static int parse_ranger_response(char* buffer, List *result_list) { if (buffer == NULL || strlen(buffer) == 0) - { - return RANGERCHECK_UNKNOWN; - } + return -1; elog(DEBUG3, "parse ranger restful response content : %s", buffer); @@ -81,40 +86,84 @@ RangerACLResult parse_ranger_response(char* buffer) if (response == NULL) { elog(WARNING, "json_tokener_parse failed"); - return RANGERCHECK_NO_PRIV; + return -1; } struct json_object *accessObj = NULL; if (!json_object_object_get_ex(response, "access", &accessObj)) { elog(WARNING, "get json access field failed"); - return RANGERCHECK_NO_PRIV; + return -1; } int arraylen = json_object_array_length(accessObj); elog(DEBUG3, "parse ranger response result array length: %d",arraylen); - - // here should return which table's acl check failed in future. for (int i=0; i< arraylen; i++){ struct json_object *jvalue = NULL; struct json_object *jallow = NULL; + struct json_object *jresource = NULL; + struct json_object *jprivilege = NULL; jvalue = json_object_array_get_idx(accessObj, i); + if (jvalue == NULL) + return -1; if (!json_object_object_get_ex(jvalue, "allowed", &jallow)) - { - return RANGERCHECK_NO_PRIV; - } - json_bool result = json_object_get_boolean(jallow); - if(result != 1){ - return RANGERCHECK_NO_PRIV; + return -1; + if (!json_object_object_get_ex(jvalue, "resource", &jresource)) + return -1; + if (!json_object_object_get_ex(jvalue, "privileges", &jprivilege)) + return -1; + + json_bool ok = json_object_get_boolean(jallow); + + const char *resource_str = json_object_get_string(jresource); + const char *privilege_str = json_object_get_string(jprivilege); + uint32 resource_sign = string_hash(resource_str, strlen(resource_str)); + uint32 privilege_sign = string_hash(privilege_str, strlen(privilege_str)); + elog(DEBUG3, "ranger response access sign, resource_str:%s, privilege_str:%s", + resource_str, privilege_str); + + ListCell *result; + /* get each resource result by use sign */ + foreach(result, result_list) { + /* loop find is enough for performence*/ + RangerPrivilegeResults *result_ptr = (RangerPrivilegeResults *) lfirst(result); + /* if only one access in response, no need to check sign*/ + if (arraylen > 1 && + (result_ptr->resource_sign != resource_sign || result_ptr->privilege_sign != privilege_sign) ) + continue; + + if (ok == 1) + result_ptr->result = RANGERCHECK_OK; + else + result_ptr->result = RANGERCHECK_NO_PRIV; } } - return RANGERCHECK_OK; + return 0; +} + +/** + * convert a string to lower + */ +static void str_tolower(char *dest, const char *src) +{ + Assert(src != NULL); + Assert(dest != NULL); + int len = strlen(src); + for (int i = 0; i < len; i++) + { + unsigned char ch = (unsigned char) src[i]; + if (ch >= 'A' && ch <= 'Z') + ch += 'a' - 'A'; + *(dest+i) = ch; + } + dest[len] = '\0'; } + /** * Create a JSON object for Ranger request given some parameters. - * + * example: * { * "requestId": 1, * "user": "joe", @@ -141,10 +190,12 @@ RangerACLResult parse_ranger_response(char* buffer) * } * ] * } - * - * args: List of RangerRequestJsonArgs + * + * @param request_list List of RangerRequestJsonArgs + * @param result_list List of RangerPrivilegeResults + * @return the parsed json object */ -json_object *create_ranger_request_json(List *args) +static json_object *create_ranger_request_json(List *request_list, List *result_list) { json_object *jrequest = json_object_new_object(); json_object *juser = NULL; @@ -152,7 +203,8 @@ json_object *create_ranger_request_json(List *args) char *user = NULL; ListCell *arg; - foreach(arg, args) + int j = 0; + foreach(arg, request_list) { RangerRequestJsonArgs *arg_ptr = (RangerRequestJsonArgs *) lfirst(arg); if (user == NULL) @@ -162,7 +214,7 @@ json_object *create_ranger_request_json(List *args) } AclObjectKind kind = arg_ptr->kind; char* object = arg_ptr->object; - Assert(user != NULL && object != NULL && privilege != NULL && arg_ptr->isAll); + Assert(user != NULL && object != NULL); elog(DEBUG3, "build json for ranger restful request, user:%s, kind:%s, object:%s", user, AclObjectKindStr[kind], object); @@ -249,12 +301,27 @@ json_object *create_ranger_request_json(List *args) ListCell *cell; foreach(cell, arg_ptr->actions) { - json_object* jaction = json_object_new_string((char *)cell->data.ptr_value); + /* need more normalization in future */ + char lower_action[32]; + str_tolower(lower_action, (char *)cell->data.ptr_value); + lower_action[sizeof(lower_action)-1] = '\0'; + + json_object* jaction = json_object_new_string(lower_action); json_object_array_add(jactions, jaction); } json_object_object_add(jelement, "privileges", jactions); json_object_array_add(jaccess, jelement); - + + /* set access sign */ + RangerPrivilegeResults *result_ptr = (RangerPrivilegeResults *)list_nth(result_list, j); + const char *resource_str = json_object_to_json_string(jresource); + const char *privilege_str = json_object_to_json_string(jactions); + result_ptr->resource_sign = string_hash(resource_str, strlen(resource_str)); + result_ptr->privilege_sign = string_hash(privilege_str, strlen(privilege_str)); + elog(DEBUG3, "request access sign, resource_str:%s, privilege_str:%s", + resource_str, privilege_str); + + j++; } // foreach char str[32]; sprintf(str,"%d",request_id); @@ -310,9 +377,9 @@ static size_t write_callback(char *contents, size_t size, size_t nitems, } /** - * @returns: 0 curl success; -1 curl failed + * @return 0 curl success; -1 curl failed */ -int call_ranger_rest(CURL_HANDLE curl_handle, const char* request) +static int call_ranger_rest(CURL_HANDLE curl_handle, const char* request) { int ret = -1; CURLcode res; @@ -339,6 +406,7 @@ int call_ranger_rest(CURL_HANDLE curl_handle, const char* request) appendStringInfo(&tname, "/"); appendStringInfo(&tname, "%s", rps_addr_suffix); curl_easy_setopt(curl_handle->curl_handle, CURLOPT_URL, tname.data); + pfree(tname.data); struct curl_slist *headers = NULL; headers = curl_slist_append(headers, "Content-Type:application/json"); @@ -373,28 +441,37 @@ int call_ranger_rest(CURL_HANDLE curl_handle, const char* request) } /* - * arg_list: List of RangerRequestJsonArgs + * check privilege(s) from ranger + * @param request_list List of RangerRequestJsonArgs + * @param result_list List of RangerPrivilegeResults + * @return 0 get response from ranger and parse success; -1 other error */ -int check_privilege_from_ranger(List *arg_list) +int check_privilege_from_ranger(List *request_list, List *result_list) { - json_object* jrequest = create_ranger_request_json(arg_list); + json_object* jrequest = create_ranger_request_json(request_list, result_list); Assert(jrequest != NULL); + const char *request = json_object_to_json_string(jrequest); - elog(DEBUG3, "send json request to ranger : %s", request); Assert(request != NULL); + elog(DEBUG3, "send json request to ranger : %s", request); /* call GET method to send request*/ Assert(curl_context_ranger.hasInited); if (call_ranger_rest(&curl_context_ranger, request) < 0) { - return RANGERCHECK_NO_PRIV; + return -1; } /* free the JSON object */ json_object_put(jrequest); /* parse the JSON-format result */ - RangerACLResult ret = parse_ranger_response(curl_context_ranger.response.buffer); + int ret = parse_ranger_response(curl_context_ranger.response.buffer, result_list); + if (ret < 0) + { + elog(WARNING, "parse ranger response failed, response[%s]", + curl_context_ranger.response.buffer == NULL? "":curl_context_ranger.response.buffer); + } if (curl_context_ranger.response.buffer != NULL) { /* reset response size to reuse the buffer. */ http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/bf4742cb/src/backend/parser/parse_relation.c ---------------------------------------------------------------------- diff --git a/src/backend/parser/parse_relation.c b/src/backend/parser/parse_relation.c index f9444ef..1dc6b86 100644 --- a/src/backend/parser/parse_relation.c +++ b/src/backend/parser/parse_relation.c @@ -2714,12 +2714,12 @@ warnAutoRange(ParseState *pstate, RangeVar *relation, int location) void ExecCheckRTPerms(List *rangeTable) { - if (enable_ranger && !fallBackToNativeChecks(ACL_KIND_CLASS,rangeTable,GetUserId())) - { - if(rangeTable!=NULL) - ExecCheckRTPermsWithRanger(rangeTable); - return; - } + if (enable_ranger && !fallBackToNativeChecks(ACL_KIND_CLASS,rangeTable,GetUserId())) + { + if(rangeTable!=NULL) + ExecCheckRTPermsWithRanger(rangeTable); + return; + } ListCell *l; foreach(l, rangeTable) { @@ -2734,70 +2734,93 @@ ExecCheckRTPerms(List *rangeTable) void ExecCheckRTPermsWithRanger(List *rangeTable) { - List *ranger_check_args = NIL; - ListCell *l; - foreach(l, rangeTable) - { - - AclMode requiredPerms; - Oid relOid; - Oid userid; - RangeTblEntry *rte = (RangeTblEntry *) lfirst(l); - - if (rte->rtekind != RTE_RELATION) - continue; - requiredPerms = rte->requiredPerms; - if (requiredPerms == 0) - continue; - - relOid = rte->relid; - userid = rte->checkAsUser ? rte->checkAsUser : GetUserId(); - - RangerPrivilegeArgs *ranger_check_arg = (RangerPrivilegeArgs *) palloc(sizeof(RangerPrivilegeArgs)); - ranger_check_arg->objkind = ACL_KIND_CLASS; - ranger_check_arg->object_oid = relOid; - ranger_check_arg->roleid = userid; - ranger_check_arg->mask = requiredPerms; - ranger_check_arg->how = ACLMASK_ALL; - ranger_check_args = lappend(ranger_check_args, ranger_check_arg); - - } // foreach - - if (ranger_check_args == NIL) - return; - - // ranger ACL check with package Oids - List *aclresults = NIL; - aclresults = pg_rangercheck_batch(ranger_check_args); - if (aclresults == NIL) - { - elog(ERROR, "ACL check failed\n"); - return; - } - - // check result - ListCell *result; - foreach(result, aclresults) - { - RangerPrivilegeResults *result_ptr = (RangerPrivilegeResults *) lfirst(result); - if(result_ptr->result != RANGERCHECK_OK) - { - Oid relOid = result_ptr->relOid; - const char *rel_name = get_rel_name_partition(relOid); - aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_CLASS, rel_name); - } - } - - if (ranger_check_args) - { - list_free_deep(ranger_check_args); - ranger_check_args = NIL; - } - if (aclresults) - { - list_free_deep(aclresults); - aclresults = NIL; - } + List *ranger_check_args = NIL; + ListCell *l; + foreach(l, rangeTable) + { + + AclMode requiredPerms; + Oid relOid; + Oid userid; + RangeTblEntry *rte = (RangeTblEntry *) lfirst(l); + + if (rte->rtekind != RTE_RELATION) + continue; + requiredPerms = rte->requiredPerms; + if (requiredPerms == 0) + continue; + + relOid = rte->relid; + userid = rte->checkAsUser ? rte->checkAsUser : GetUserId(); + + RangerPrivilegeArgs *ranger_check_arg = (RangerPrivilegeArgs *) palloc(sizeof(RangerPrivilegeArgs)); + ranger_check_arg->objkind = ACL_KIND_CLASS; + ranger_check_arg->object_oid = relOid; + ranger_check_arg->roleid = userid; + ranger_check_arg->mask = requiredPerms; + ranger_check_arg->how = ACLMASK_ALL; + ranger_check_args = lappend(ranger_check_args, ranger_check_arg); + + } + + if (ranger_check_args == NIL) + return; + + /* ranger ACL check with package Oids */ + List *aclresults = NIL; + aclresults = pg_rangercheck_batch(ranger_check_args); + if (aclresults == NIL) + { + elog(ERROR, "ACL check failed\n"); + return; + } + + /* check result */ + StringInfoData acl_fail_msg; + bool acl_allok = true; + + ListCell *result; + foreach(result, aclresults) + { + RangerPrivilegeResults *result_ptr = (RangerPrivilegeResults *) lfirst(result); + if(result_ptr->result != RANGERCHECK_OK) + { + if (acl_allok) + { + initStringInfo(&acl_fail_msg); + appendStringInfo(&acl_fail_msg, "permission denied for relation(s): "); + } + else + { + appendStringInfo(&acl_fail_msg, ", "); + } + acl_allok = false; + + /* collect all acl fail relations */ + Oid relOid = result_ptr->relOid; + const char *rel_name = get_rel_name_partition(relOid); + appendStringInfo(&acl_fail_msg, "%s", rel_name); + } + } + + if (ranger_check_args) + { + list_free_deep(ranger_check_args); + ranger_check_args = NIL; + } + if (aclresults) + { + list_free_deep(aclresults); + aclresults = NIL; + } + + if (!acl_allok) + { + errstart(ERROR, __FILE__, __LINE__, PG_FUNCNAME_MACRO, TEXTDOMAIN); + errmsg("%s", acl_fail_msg.data), + pfree(acl_fail_msg.data); + errfinish(errOmitLocation(true)); + } } /* http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/bf4742cb/src/include/utils/rangerrest.h ---------------------------------------------------------------------- diff --git a/src/include/utils/rangerrest.h b/src/include/utils/rangerrest.h index f67d8e5..136804f 100644 --- a/src/include/utils/rangerrest.h +++ b/src/include/utils/rangerrest.h @@ -84,6 +84,13 @@ typedef struct RangerPrivilegeResults { RangerACLResult result; Oid relOid; + + /* + * string_hash of access[i] field of ranger request + * use the sign to identify each resource result + */ + uint32 resource_sign; + uint32 privilege_sign; } RangerPrivilegeResults; typedef struct RangerRequestJsonArgs { @@ -94,10 +101,8 @@ typedef struct RangerRequestJsonArgs { bool isAll; } RangerRequestJsonArgs; -RangerACLResult parse_ranger_response(char *); -json_object *create_ranger_request_json(List *); -int call_ranger_rest(CURL_HANDLE curl_handle, const char *request); -extern int check_privilege_from_ranger(List *); extern struct curl_context_t curl_context_ranger; +int check_privilege_from_ranger(List *request_list, List *result_list); + #endif