You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hawq.apache.org by wl...@apache.org on 2016/11/17 09:01:55 UTC
incubator-hawq git commit: HAWQ-1004. Call Ranger restful api to
check privilege
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 <wl...@pivotal.io>
Authored: Thu Nov 17 17:00:06 2016 +0800
Committer: Wen Lin <wl...@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