Repository: incubator-hawq
Updated Branches:
  refs/heads/ranger afd1885bc -> f78b3e09c


HAWQ-1004. Call Ranger restful api to check privilege


Project: http://git-wip-us.apache.org/repos/asf/incubator-hawq/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-hawq/commit/f78b3e09
Tree: http://git-wip-us.apache.org/repos/asf/incubator-hawq/tree/f78b3e09
Diff: http://git-wip-us.apache.org/repos/asf/incubator-hawq/diff/f78b3e09

Branch: refs/heads/ranger
Commit: f78b3e09c9fbc847f65be0b2dda7fb62aa5f5627
Parents: afd1885
Author: Wen Lin <w...@pivotal.io>
Authored: Thu Nov 17 17:00:06 2016 +0800
Committer: Wen Lin <w...@pivotal.io>
Committed: Thu Nov 17 17:00:06 2016 +0800

----------------------------------------------------------------------
 src/backend/catalog/aclchk.c   |   4 +-
 src/backend/libpq/Makefile     |   2 +-
 src/backend/libpq/rangerrest.c | 343 ++++++++++++++++++++++++++++++++++++
 src/backend/libpq/rangerrest.h |  39 ++++
 4 files changed, 385 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/f78b3e09/src/backend/catalog/aclchk.c
----------------------------------------------------------------------
diff --git a/src/backend/catalog/aclchk.c b/src/backend/catalog/aclchk.c
index 038dd69..06f20f3 100644
--- a/src/backend/catalog/aclchk.c
+++ b/src/backend/catalog/aclchk.c
@@ -2672,8 +2672,8 @@ pg_rangercheck(AclObjectKind objkind, Oid object_oid, Oid 
roleid,
   char* rolename = getRoleName(roleid);
   List* actions = getActionName(mask);
   bool isAll = (how == ACLMASK_ALL) ? true: false;
-  //parameter objkind;
-  //return func(objectname, rolename, actions, isAll);
+
+  int ret = check_privilege_from_ranger(rolename, objkind, objectname, 
actions, isAll);
 
   if(objectname){
     pfree(objectname);

http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/f78b3e09/src/backend/libpq/Makefile
----------------------------------------------------------------------
diff --git a/src/backend/libpq/Makefile b/src/backend/libpq/Makefile
index 28a386f..16124c7 100644
--- a/src/backend/libpq/Makefile
+++ b/src/backend/libpq/Makefile
@@ -15,6 +15,6 @@ include $(top_builddir)/src/Makefile.global
 # be-fsstubs is here for historical reasons, probably belongs elsewhere
 
 OBJS = be-fsstubs.o be-secure.o auth.o crypt.o hba.o ip.o md5.o pqcomm.o \
-       pqformat.o pqsignal.o sha2.o pg_sha2.o
+       pqformat.o pqsignal.o sha2.o pg_sha2.o rangerrest.o
 
 include $(top_srcdir)/src/backend/common.mk

http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/f78b3e09/src/backend/libpq/rangerrest.c
----------------------------------------------------------------------
diff --git a/src/backend/libpq/rangerrest.c b/src/backend/libpq/rangerrest.c
new file mode 100644
index 0000000..aacc4e0
--- /dev/null
+++ b/src/backend/libpq/rangerrest.c
@@ -0,0 +1,343 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/*-------------------------------------------------------------------------
+ *
+ * rangerrest.c
+ *     routines to interact with Ranger REST API
+ *
+ *-------------------------------------------------------------------------
+ */
+#include <json-c/json.h>
+#include "rangerrest.h"
+#include "utils/elog.h"
+#include "utils/palloc.h"
+#include "postgres.h"
+#include "utils/acl.h"
+#include "nodes/pg_list.h"
+
+/*
+ * Internal buffer for libcurl context
+ */
+typedef struct curl_context_t
+{
+    CURL* curl_handle;
+
+    char curl_error_buffer[CURL_ERROR_SIZE];
+
+    int curl_still_running;
+
+    struct
+    {
+        char* buffer;
+        int size;
+    } response;
+
+    char* last_http_reponse;
+} curl_context_t;
+typedef curl_context_t* CURL_HANDLE;
+
+RangerACLResult parse_ranger_response(char* buffer)
+{
+    Assert(buffer != NULL);
+    if (strlen(buffer) == 0)
+        return RANGERCHECK_UNKNOWN;
+
+    struct json_object *response = json_tokener_parse(buffer);
+    struct json_object *result = json_object_object_get(response, "result");
+    char* szResult = json_object_get_string(result);
+    elog(LOG, "parse Ranger response, result:%s.", szResult);
+    if (strcmp(szResult, "true") == 0)
+    {
+        return RANGERCHECK_OK;
+    } else {
+        return RANGERCHECK_NO_PRIV;
+    }
+}
+
+/*
+ * A mapping from AclObjectKind to string
+ */
+char* AclObjectKindStr[] =
+{
+    "table",             /* pg_class */
+    "sequence",          /* pg_sequence */
+    "database",          /* pg_database */
+    "function",          /* pg_proc */
+    "operator",          /* pg_operator */
+    "type",              /* pg_type */
+    "language",          /* pg_language */
+    "namespace",         /* pg_namespace */
+    "oplass",            /* pg_opclass */
+    "conversion",        /* pg_conversion */
+    "tablespace",        /* pg_tablespace */
+    "filespace",         /* pg_filespace */
+    "filesystem",        /* pg_filesystem */
+    "fdw",               /* pg_foreign_data_wrapper */
+    "foreign_server",    /* pg_foreign_server */
+    "protocol",          /* pg_extprotocol */
+    "none"               /* MUST BE LAST */
+};
+
+/**
+ * Create a JSON object for Ranger request given some parameters.
+ *
+ *   {
+ *     "requestId": 1,
+ *     "user": "joe",
+ *     "groups": ["admin","us"],
+ *     "clientIp": "123.0.0.21",
+ *     "context": "SELECT * FROM sales",
+ *     "access":
+ *       [
+ *         {
+ *           "resource":
+ *           {
+ *             "database": "finance"
+ *           },
+ *           "privileges": ["connect"]
+ *         },
+ *         {
+ *           "resource":
+ *           {
+ *             "database": "finance",
+ *             "schema": "us",
+ *             "table": "sales"
+ *           },
+ *           "privileges": ["select, insert"]
+ *         }
+ *       ]
+ *   }
+ */
+json_object* create_ranger_request_json(char* user, AclObjectKind kind, char* 
object,
+        List* actions, char* how)
+{
+    Assert(user != NULL && object != NULL && privilege != NULL
+                    && how != NULL);
+    ListCell *cell = NULL;
+
+    elog(LOG, "build json for ranger request, user:%s, kind:%s, object:%s",
+              user, AclObjectKindStr[kind], object);
+    json_object *jrequest = json_object_new_object();
+    json_object *juser = json_object_new_string(user);
+
+    json_object *jaccess = json_object_new_array();
+    json_object *jelement = json_object_new_object();
+
+    json_object *jresource = json_object_new_object();
+    switch(kind)
+    {
+        case ACL_KIND_CLASS:
+        case ACL_KIND_SEQUENCE:
+        case ACL_KIND_PROC:
+        case ACL_KIND_NAMESPACE:
+        case ACL_KIND_LANGUAGE:
+        {
+            char *ptr = NULL; char *name = NULL;
+            char *first = NULL; // could be a database or protocol or 
tablespace
+            char *second = NULL; // could be a schema or language
+            char *third = NULL; // could be a table or sequence or function
+            for (int idx = 0, name = strtok_r(object, ".", &ptr);
+                 name;
+                 name = strtok_r(NULL, ".", &ptr), idx++)
+            {
+                if (idx == 0)
+                {
+                    first = pstrdup(name);
+                }
+                else if (idx == 1)
+                {
+                    second = pstrdup(name);
+                }
+                else
+                {
+                    third = pstrdup(name);
+                }
+            }
+
+            if (first != NULL)
+            {
+                json_object *jfirst = json_object_new_string(first);
+                json_object_object_add(jresource, "database", jfirst);
+            }
+            if (second != NULL)
+            {
+                json_object *jsecond = json_object_new_string(second);
+                json_object_object_add(jresource,
+                        (kind == ACL_KIND_LANGUAGE) ? "language" : "schema", 
jsecond);
+            }
+            if (third != NULL)
+            {
+                json_object *jthird = json_object_new_string(third);
+                json_object_object_add(jresource,
+                         (kind == ACL_KIND_CLASS) ? "table" :
+                         (kind == ACL_KIND_SEQUENCE) ? "sequence" : 
"function", jthird);
+            }
+
+            if (first != NULL)
+                pfree(first);
+            if (second != NULL)
+                pfree(second);
+            if (third != NULL)
+                pfree(third);
+            break;
+        }
+        case ACL_KIND_OPER:
+        case ACL_KIND_CONVERSION:
+        case ACL_KIND_DATABASE:
+        case ACL_KIND_TABLESPACE:
+        case ACL_KIND_TYPE:
+        case ACL_KIND_FILESYSTEM:
+        case ACL_KIND_FDW:
+        case ACL_KIND_FOREIGN_SERVER:
+        case ACL_KIND_EXTPROTOCOL:
+        {
+            json_object *jobject = json_object_new_string(object);
+            json_object_object_add(jresource, AclObjectKindStr[kind], jobject);
+            break;
+        }
+        default:
+            elog(ERROR, "unrecognized objkind: %d", (int) kind);
+    }
+
+    json_object *jactions = json_object_new_array();
+    foreach(cell, actions)
+    {
+        json_object* jaction = json_object_new_string((char 
*)cell->data.ptr_value);
+        json_object_array_add(jactions, jaction);
+    }
+    json_object_object_add(jelement, "resource", jresource);
+    json_object_object_add(jelement, "privileges", jactions);
+    json_object_array_add(jaccess, jelement);
+
+    json_object_object_add(jrequest, "user", juser);
+    json_object_object_add(jrequest, "access", jaccess);
+
+    return jrequest;
+}
+
+static size_t write_callback(char *contents, size_t size, size_t nitems,
+        void *userp)
+{
+    size_t realsize = size * nitems;
+    CURL_HANDLE curl = (struct curl_context *) userp;
+
+    curl->response.buffer = palloc0(realsize + 1);
+    memset(curl->response.buffer, 0, realsize + 1);
+    if (curl->response.buffer == NULL)
+    {
+        /* out of memory! */
+        elog(WARNING, "not enough memory for Ranger response");
+        return 0;
+    }
+
+    memcpy(curl->response.buffer, contents, realsize);
+    curl->response.size = realsize + 1;
+    elog(LOG, "read from Ranger Restful API: %s", curl->response.buffer);
+
+    return realsize;
+}
+
+void call_ranger_rest(CURL_HANDLE curl_handle, char* request)
+{
+    CURLcode res;
+    Assert(request != NULL);
+
+    curl_global_init(CURL_GLOBAL_ALL);
+
+    /* init the curl session */
+    curl_handle->curl_handle = curl_easy_init();
+    if (curl_handle->curl_handle == NULL)
+    {
+        goto _exit;
+    }
+    /* timeout */
+    curl_easy_setopt(curl_handle, CURLOPT_TIMEOUT, 1);
+
+    /* specify URL to get */
+    curl_easy_setopt(curl_handle->curl_handle, CURLOPT_URL, 
"http://localhost:8089/checkprivilege";);
+    /* specify format */
+    // struct curl_slist *plist = curl_slist_append(NULL, 
"Content-Type:application/json;charset=UTF-8");
+    // curl_easy_setopt(curl_handle, CURLOPT_HTTPHEADER, plist);
+    // curl_easy_setopt(curl_handle, CURLOPT_POSTFIELDS, request);
+
+    /* send all data to this function  */
+    curl_easy_setopt(curl_handle->curl_handle, CURLOPT_WRITEFUNCTION, 
write_callback);
+    curl_easy_setopt(curl_handle->curl_handle, CURLOPT_WRITEDATA, (void 
*)curl_handle);
+
+    res = curl_easy_perform(curl_handle->curl_handle);
+
+    /* check for errors */
+    if(res != CURLE_OK)
+    {
+        elog(WARNING, "curl_easy_perform() failed: %s\n",
+                curl_easy_strerror(res));
+    }
+    else
+    {
+        elog(LOG, "%lu bytes retrieved from Ranger Restful API.",
+                curl_handle->response.size);
+    }
+
+_exit:
+    /* cleanup curl stuff */
+    if (curl_handle->curl_handle)
+    {
+        curl_easy_cleanup(curl_handle->curl_handle);
+    }
+
+    /* we're done with libcurl, so clean it up */
+    curl_global_cleanup();
+}
+
+/*
+ * Check the privilege from Ranger for one role
+ */
+int check_privilege_from_ranger(char* user, AclObjectKind kind, char* object,
+        List* actions, char* how)
+{
+    json_object* jrequest = create_ranger_request_json(user, kind, object,
+            actions, how);
+
+    Assert(jrequest != NULL);
+    char* request = json_object_to_json_string(jrequest);
+    elog(LOG, "send JSON request to Ranger: %s", request);
+    Assert(request != NULL);
+
+    struct curl_context_t curl_context;
+    memset(&curl_context, 0, sizeof(struct curl_context_t));
+
+    /* call GET method to send request*/
+    call_ranger_rest(&curl_context, request);
+
+    /* free the JSON object */
+    json_object_put(jrequest);
+
+    /* parse the JSON-format result */
+    RangerACLResult ret = parse_ranger_response(curl_context.response.buffer);
+
+    /* free response buffer */
+    if (curl_context.response.buffer != NULL)
+    {
+        pfree(curl_context.response.buffer);
+    }
+
+    return ret;
+}
+

http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/f78b3e09/src/backend/libpq/rangerrest.h
----------------------------------------------------------------------
diff --git a/src/backend/libpq/rangerrest.h b/src/backend/libpq/rangerrest.h
new file mode 100644
index 0000000..4b73f46
--- /dev/null
+++ b/src/backend/libpq/rangerrest.h
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/*-------------------------------------------------------------------------
+ *
+ * rangerrest.h
+ *     routines to interact with Ranger REST API
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef RANGERREST_H
+#define RANGERREST_H
+
+#include <curl/curl.h>
+
+typedef enum
+{
+    RANGERCHECK_OK = 0,
+    RANGERCHECK_NO_PRIV,
+    RANGERCHECK_UNKNOWN
+} RangerACLResult;
+
+#endif

Reply via email to