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

Reply via email to