You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hawq.apache.org by hu...@apache.org on 2019/03/16 03:36:16 UTC
[hawq] 01/06: HAWQ-1681. Support manage user in cloud
This is an automated email from the ASF dual-hosted git repository.
huor pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/hawq.git
commit 777072708525a6161e4f8114cc4894513e0c4bf9
Author: wcl14 <wa...@126.com>
AuthorDate: Tue May 29 16:26:22 2018 +0800
HAWQ-1681. Support manage user in cloud
---
src/backend/commands/user.c | 503 +++++++++++++++++++++++++++++++++++-
src/backend/commands/variable.c | 12 +-
src/backend/libpq/Makefile | 2 +-
src/backend/libpq/auth.c | 69 +++++
src/backend/libpq/cloudrest.c | 446 ++++++++++++++++++++++++++++++++
src/backend/libpq/hba.c | 15 ++
src/backend/tcop/postgres.c | 1 +
src/backend/utils/cache/lsyscache.c | 3 +-
src/backend/utils/init/miscinit.c | 7 +-
src/backend/utils/misc/guc.c | 24 ++
src/include/commands/user.h | 3 +
src/include/libpq/hba.h | 4 +-
src/include/utils/cloudrest.h | 88 +++++++
src/include/utils/guc.h | 6 +
14 files changed, 1167 insertions(+), 16 deletions(-)
diff --git a/src/backend/commands/user.c b/src/backend/commands/user.c
index f8fc301..d1da5a5 100644
--- a/src/backend/commands/user.c
+++ b/src/backend/commands/user.c
@@ -58,6 +58,7 @@
#include "utils/lsyscache.h"
#include "executor/execdesc.h"
+#include "utils/cloudrest.h"
#include "utils/resscheduler.h"
#include "utils/syscache.h"
@@ -112,6 +113,7 @@ static void AddRoleDenials(const char *rolename, Oid roleid,
static void DelRoleDenials(const char *rolename, Oid roleid,
List *dropintervals);
static bool resourceQueueIsBranch(Oid queueid);
+static Oid CreateNoPrivligeRole(char *rolename);
/* Check if current user has createrole privileges */
static bool
@@ -121,6 +123,11 @@ have_createrole_privilege(void)
cqContext *pcqCtx, cqc;
HeapTuple utup;
+ if (pg_cloud_auth)
+ {
+ return pg_cloud_createrole;
+ }
+
/* Superusers can always do everything */
if (superuser())
return true;
@@ -547,6 +554,52 @@ CreateRole(CreateRoleStmt *stmt)
else
new_record_nulls[Anum_pg_authid_rolpassword - 1] = true;
+ if (pg_cloud_auth)
+ {
+ char *errormsg;
+ int ret = check_authentication_from_cloud(stmt->role, password,
+ &createrole, USER_SYNC, "create", &errormsg);
+ elog(INFO, "in CreateRole, ret=%d", ret);
+ if (ret)
+ {
+ /*
+ * role exists in cloud, create it in database but without any authorities
+ */
+ if (ret == CLOUDSYNC_USEREXIST)
+ {
+ new_record[Anum_pg_authid_rolsuper - 1] = BoolGetDatum(
+ false);
+ new_record[Anum_pg_authid_rolcreaterole - 1] = BoolGetDatum(
+ false);
+ new_record[Anum_pg_authid_rolcreatedb - 1] = BoolGetDatum(
+ false);
+ new_record[Anum_pg_authid_rolcatupdate - 1] = BoolGetDatum(
+ false);
+ new_record[Anum_pg_authid_rolcanlogin - 1] = BoolGetDatum(
+ false);
+ new_record[Anum_pg_authid_rolcreaterextgpfd - 1] =
+ BoolGetDatum(false);
+ new_record[Anum_pg_authid_rolcreaterexthttp - 1] =
+ BoolGetDatum(false);
+ new_record[Anum_pg_authid_rolcreatewextgpfd - 1] =
+ BoolGetDatum(false);
+ new_record[Anum_pg_authid_rolcreaterexthdfs - 1] =
+ BoolGetDatum(false);
+ new_record[Anum_pg_authid_rolcreatewexthdfs - 1] =
+ BoolGetDatum(false);
+ }
+ else
+ {
+ elog(ERROR, "%s", errormsg);
+ if (errormsg)
+ {
+ pfree(errormsg);
+ errormsg = NULL;
+ }
+ }
+ }
+ }
+
if (validUntil)
new_record[Anum_pg_authid_rolvaliduntil - 1] =
DirectFunctionCall3(timestamptz_in,
@@ -1011,11 +1064,13 @@ AlterRole(AlterRoleStmt *stmt)
tuple = caql_getnext(pcqCtx);
- if (!HeapTupleIsValid(tuple)) {
+ if (!HeapTupleIsValid(tuple)
+ && !CheckUserExistOnCloud(pcqCtx, pg_authid_rel, stmt->role, &tuple,
+ true))
+ {
releaseResourceContextWithErrorReport(resourceid);
ereport(ERROR,
- (errcode(ERRCODE_UNDEFINED_OBJECT),
- errmsg("role \"%s\" does not exist", stmt->role)));
+ (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("role \"%s\" does not exist", stmt->role)));
}
roleid = HeapTupleGetOid(tuple);
@@ -1095,6 +1150,24 @@ AlterRole(AlterRoleStmt *stmt)
{
new_record[Anum_pg_authid_rolcreaterole - 1] = BoolGetDatum(createrole > 0);
new_record_repl[Anum_pg_authid_rolcreaterole - 1] = true;
+
+ if (pg_cloud_auth)
+ {
+ char *errormsg;
+ int ret;
+ ret = check_authentication_from_cloud(stmt->role, NULL,
+ &new_record[Anum_pg_authid_rolcreaterole - 1], USER_SYNC,
+ "alter", &errormsg);
+ elog(INFO, "in AlterRole, ret=%d", ret);
+ if (ret)
+ {
+ elog(ERROR, "%s", errormsg);
+ if (errormsg) {
+ pfree(errormsg);
+ errormsg = NULL;
+ }
+ }
+ }
}
if (createdb >= 0)
@@ -1132,6 +1205,23 @@ AlterRole(AlterRoleStmt *stmt)
CStringGetTextDatum(encrypted_password);
}
new_record_repl[Anum_pg_authid_rolpassword - 1] = true;
+
+ if (pg_cloud_auth)
+ {
+ char *errormsg;
+ int ret;
+ ret = check_authentication_from_cloud(stmt->role, password, NULL,
+ USER_SYNC, "alter", &errormsg);
+ elog(INFO, "in AlterRole, ret=%d", ret);
+ if (ret)
+ {
+ elog(ERROR, "%s", errormsg);
+ if (errormsg) {
+ pfree(errormsg);
+ errormsg = NULL;
+ }
+ }
+ }
}
/* unset password */
@@ -1549,6 +1639,25 @@ DropRole(DropRoleStmt *stmt)
cqContext cqc;
cqContext *pcqCtx;
+ if (pg_cloud_auth)
+ {
+ char *errormsg;
+ int ret = check_authentication_from_cloud(role, NULL, NULL,
+ USER_SYNC, "drop", &errormsg);
+ if (ret)
+ {
+ elog(ERROR, "%s", errormsg);
+ ereport(ERROR,
+ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+ errmsg("%s", errormsg),
+ errOmitLocation(true)));
+ if (errormsg) {
+ pfree(errormsg);
+ errormsg = NULL;
+ }
+ }
+ }
+
pcqCtx = caql_beginscan(
caql_addrel(cqclr(&cqc), pg_authid_rel),
cql("SELECT * FROM pg_authid "
@@ -1768,6 +1877,12 @@ RenameRole(const char *oldname, const char *newname)
cqContext cqc2;
cqContext *pcqCtx;
+ if (pg_cloud_auth)
+ {
+ ereport(ERROR,
+ (errcode(ERRCODE_CDB_FEATURE_NOT_YET), errmsg("Cannot support rename role name when using cloud auth yet") ));
+ }
+
rel = heap_open(AuthIdRelationId, RowExclusiveLock);
dsc = RelationGetDescr(rel);
@@ -2911,3 +3026,385 @@ DelRoleDenials(const char *rolename, Oid roleid, List *dropintervals)
*/
auth_time_file_update_needed();
}
+
+static Oid
+CreateNoPrivligeRole(char *rolename)
+{
+ Relation pg_authid_rel;
+ HeapTuple tuple;
+ Datum new_record[Natts_pg_authid];
+ bool new_record_nulls[Natts_pg_authid];
+ Oid roleid;
+ ListCell *item;
+ ListCell *option;
+ char *password = NULL; /* user password */
+ bool encrypt_password = Password_encryption; /* encrypt password? */
+ char encrypted_password[MAX_PASSWD_HASH_LEN + 1];
+ bool issuper = false; /* Make the user a superuser? */
+ bool inherit = true; /* Auto inherit privileges? */
+ bool createrole = false; /* Can this user create roles? */
+ bool createdb = false; /* Can the user create databases? */
+ bool canlogin = false; /* Can this user login? */
+ bool createrextgpfd = false; /* Can create readable gpfdist exttab? */
+ bool createrexthttp = false; /* Can create readable http exttab? */
+ bool createwextgpfd = false; /* Can create writable gpfdist exttab? */
+ bool createrexthdfs = false; /* Can create readable hdfs exttab? */
+ bool createwexthdfs = false; /* Can create writable hdfs exttab? */
+ int connlimit = -1; /* maximum connections allowed */
+ List *addroleto = NIL; /* roles to make this a member of */
+ List *rolemembers = NIL; /* roles to be members of this role */
+ List *adminmembers = NIL; /* roles to be admins of this role */
+ List *exttabcreate = NIL; /* external table create privileges being added */
+ List *exttabnocreate = NIL; /* external table create privileges being removed */
+ char *validUntil = NULL; /* time the login is valid until */
+ char *resqueue = NULL; /* resource queue for this role */
+ List *addintervals = NIL; /* list of time intervals for which login should be denied */
+ cqContext cqc;
+ cqContext cqc2;
+ cqContext *pcqCtx;
+ Oid queueid = InvalidOid;
+ int res = FUNC_RETURN_OK;
+ static char errorbuf[1024] = "";
+
+ /* Create a new resource context to manipulate role in resource manager. */
+ int resourceid = 0;
+ res = createNewResourceContext(&resourceid);
+ if (res != FUNC_RETURN_OK) {
+ Assert( res == COMM2RM_CLIENT_FULL_RESOURCECONTEXT );
+ ereport(ERROR,
+ (errcode(ERRCODE_INTERNAL_ERROR),
+ errmsg("Can not apply CREATE ROLE. "
+ "Because too many resource contexts were created.")));
+ }
+
+ /* Here, using user oid is more convenient. */
+ res = registerConnectionInRMByOID(resourceid,
+ BOOTSTRAP_SUPERUSERID,
+ errorbuf,
+ sizeof(errorbuf));
+ if (res != FUNC_RETURN_OK)
+ {
+ releaseResourceContextWithErrorReport(resourceid);
+ ereport(ERROR, (errcode(ERRCODE_INTERNAL_ERROR), errmsg("%s", errorbuf)));
+ }
+
+ /*
+ * Check the pg_authid relation to be certain the role doesn't already
+ * exist.
+ */
+ pg_authid_rel = heap_open(AuthIdRelationId, RowExclusiveLock);
+
+ pcqCtx =
+ caql_beginscan(
+ caql_addrel(cqclr(&cqc), pg_authid_rel),
+ cql("INSERT INTO pg_authid ",
+ NULL));
+
+ if (caql_getcount(
+ caql_addrel(cqclr(&cqc2), pg_authid_rel),
+ cql("SELECT COUNT(*) FROM pg_authid "
+ " WHERE rolname = :1 ",
+ PointerGetDatum(rolename)))) {
+ unregisterConnectionInRMWithErrorReport(resourceid);
+ releaseResourceContextWithErrorReport(resourceid);
+ ereport(ERROR,
+ (errcode(ERRCODE_DUPLICATE_OBJECT),
+ errmsg("role \"%s\" already exists",
+ rolename)));
+ }
+
+ /*
+ * Build a tuple to insert
+ */
+ MemSet(new_record, 0, sizeof(new_record));
+ MemSet(new_record_nulls, false, sizeof(new_record_nulls));
+
+ new_record[Anum_pg_authid_rolname - 1] =
+ DirectFunctionCall1(namein, CStringGetDatum(rolename));
+
+ new_record[Anum_pg_authid_rolsuper - 1] = BoolGetDatum(issuper);
+ new_record[Anum_pg_authid_rolinherit - 1] = BoolGetDatum(inherit);
+ new_record[Anum_pg_authid_rolcreaterole - 1] = BoolGetDatum(createrole);
+ new_record[Anum_pg_authid_rolcreatedb - 1] = BoolGetDatum(createdb);
+ /* superuser gets catupdate right by default */
+ new_record[Anum_pg_authid_rolcatupdate - 1] = BoolGetDatum(issuper);
+ new_record[Anum_pg_authid_rolcanlogin - 1] = BoolGetDatum(canlogin);
+ new_record[Anum_pg_authid_rolconnlimit - 1] = Int32GetDatum(connlimit);
+
+ /* Set the CREATE EXTERNAL TABLE permissions for this role */
+ if (exttabcreate || exttabnocreate)
+ SetCreateExtTableForRole(exttabcreate, exttabnocreate, &createrextgpfd,
+ &createrexthttp, &createwextgpfd,
+ &createrexthdfs, &createwexthdfs);
+
+ new_record[Anum_pg_authid_rolcreaterextgpfd - 1] = BoolGetDatum(createrextgpfd);
+ new_record[Anum_pg_authid_rolcreaterexthttp - 1] = BoolGetDatum(createrexthttp);
+ new_record[Anum_pg_authid_rolcreatewextgpfd - 1] = BoolGetDatum(createwextgpfd);
+ new_record[Anum_pg_authid_rolcreaterexthdfs - 1] = BoolGetDatum(createrexthdfs);
+ new_record[Anum_pg_authid_rolcreatewexthdfs - 1] = BoolGetDatum(createwexthdfs);
+
+ if (password)
+ {
+ if (!encrypt_password || isHashedPasswd(password))
+ new_record[Anum_pg_authid_rolpassword - 1] =
+ CStringGetTextDatum(password);
+ else
+ {
+ if (!hash_password(password, rolename, strlen(rolename),
+ encrypted_password))
+ {
+ elog(ERROR, "password encryption failed");
+ }
+
+ new_record[Anum_pg_authid_rolpassword - 1] =
+ CStringGetTextDatum(encrypted_password);
+ }
+ }
+ else
+ new_record_nulls[Anum_pg_authid_rolpassword - 1] = true;
+
+ if (validUntil)
+ new_record[Anum_pg_authid_rolvaliduntil - 1] =
+ DirectFunctionCall3(timestamptz_in,
+ CStringGetDatum(validUntil),
+ ObjectIdGetDatum(InvalidOid),
+ Int32GetDatum(-1));
+
+ else
+ new_record_nulls[Anum_pg_authid_rolvaliduntil - 1] = true;
+
+ resqueue = pstrdup(GP_DEFAULT_RESOURCE_QUEUE_NAME);
+ if (resqueue)
+ {
+ if (strcmp(resqueue, "none") == 0)
+ {
+ unregisterConnectionInRMWithErrorReport(resourceid);
+ releaseResourceContextWithErrorReport(resourceid);
+ ereport(ERROR,
+ (errcode(ERRCODE_RESERVED_NAME),
+ errmsg("resource queue name \"%s\" is reserved",
+ resqueue), errOmitLocation(true)));
+ }
+
+ queueid = GetResQueueIdForName(resqueue);
+ if (queueid == InvalidOid)
+ {
+ unregisterConnectionInRMWithErrorReport(resourceid);
+ releaseResourceContextWithErrorReport(resourceid);
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("resource queue \"%s\" does not exist",
+ resqueue), errOmitLocation(true)));
+ }
+
+ if(resourceQueueIsBranch(queueid))
+ {
+ unregisterConnectionInRMWithErrorReport(resourceid);
+ releaseResourceContextWithErrorReport(resourceid);
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("cannot assign non-leaf resource queue \"%s\" to role",
+ resqueue), errOmitLocation(true)));
+ }
+
+ new_record[Anum_pg_authid_rolresqueue - 1] =
+ ObjectIdGetDatum(queueid);
+ }
+ else
+ new_record_nulls[Anum_pg_authid_rolresqueue - 1] = true;
+
+ new_record_nulls[Anum_pg_authid_rolconfig - 1] = true;
+
+ tuple = caql_form_tuple(pcqCtx, new_record, new_record_nulls);
+
+
+ /*
+ * Insert new record in the pg_authid table
+ */
+ roleid = caql_insert(pcqCtx, tuple); /* implicit update of index as well */
+
+ /*
+ * send RPC: notify RM to update
+ */
+ if (resqueue && queueid != InvalidOid)
+ {
+ res = manipulateRoleForResourceQueue(resourceid,
+ roleid,
+ queueid,
+ MANIPULATE_ROLE_RESQUEUE_CREATE,
+ issuper,
+ rolename,
+ errorbuf,
+ sizeof(errorbuf));
+ }
+
+ /* We always unregister connection. */
+ unregisterConnectionInRMWithErrorReport(resourceid);
+
+ /* We always release resource context. */
+ releaseResourceContextWithErrorReport(resourceid);
+
+ if (resqueue && queueid != InvalidOid)
+ {
+ if ( res != FUNC_RETURN_OK )
+ {
+ ereport(ERROR,
+ (errcode(IS_TO_RM_RPC_ERROR(res) ?
+ ERRCODE_INTERNAL_ERROR :
+ ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("cannot apply CREATE ROLE because of %s", errorbuf)));
+ }
+ }
+
+ /*
+ * Advance command counter so we can see new record; else tests in
+ * AddRoleMems may fail.
+ */
+ if (addroleto || adminmembers || rolemembers)
+ CommandCounterIncrement();
+
+ /*
+ * Add the new role to the specified existing roles.
+ */
+ foreach(item, addroleto)
+ {
+ char *oldrolename = strVal(lfirst(item));
+ Oid oldroleid = get_roleid_checked(oldrolename);
+
+ AddRoleMems(oldrolename, oldroleid,
+ list_make1(makeString(rolename)),
+ list_make1_oid(roleid),
+ BOOTSTRAP_SUPERUSERID, false);
+ }
+
+ /*
+ * Add the specified members to this new role. adminmembers get the admin
+ * option, rolemembers don't.
+ */
+ AddRoleMems(rolename, roleid,
+ adminmembers, roleNamesToIds(adminmembers),
+ BOOTSTRAP_SUPERUSERID, true);
+ AddRoleMems(rolename, roleid,
+ rolemembers, roleNamesToIds(rolemembers),
+ BOOTSTRAP_SUPERUSERID, false);
+
+ /*
+ * Populate pg_auth_time_constraint with intervals for which this
+ * particular role should be denied access.
+ */
+ if (addintervals)
+ {
+ if (issuper)
+ ereport(ERROR,
+ (errmsg("cannot create superuser with DENY rules")));
+ AddRoleDenials(rolename, roleid, addintervals);
+ }
+
+ /*
+ * Close pg_authid, but keep lock till commit (this is important to
+ * prevent any risk of deadlock failure while updating flat file)
+ */
+ caql_endscan(pcqCtx);
+ heap_close(pg_authid_rel, NoLock);
+ CommitTransaction();
+ StartTransaction();
+ pg_authid_rel = heap_open(AuthIdRelationId, RowExclusiveLock);
+ pcqCtx =
+ caql_beginscan(
+ caql_addrel(cqclr(&cqc), pg_authid_rel),
+ cql("SELECT * FROM pg_authid "
+ " WHERE oid = :1 ",
+ PointerGetDatum(BOOTSTRAP_SUPERUSERID)));
+ tuple = caql_getnext(pcqCtx);
+ caql_endscan(pcqCtx);
+ heap_close(pg_authid_rel, NoLock);
+
+ /*
+ * Set flag to update flat auth file at commit.
+ */
+ auth_file_update_needed();
+
+ if (Gp_role == GP_ROLE_DISPATCH)
+ {
+ /* GPSQL: no dispatch to segments */
+ /* CdbDispatchUtilityStatement((Node *) stmt, "CreateRole"); */
+
+ /* MPP-6929: metadata tracking */
+ MetaTrackAddObject(AuthIdRelationId,
+ roleid,
+ BOOTSTRAP_SUPERUSERID,
+ "CREATE", "ROLE"
+ );
+ }
+
+ return roleid;
+}
+
+bool
+CheckUserExistOnCloudSimple(char *rolename, Oid *roleid)
+{
+ if (!pg_cloud_auth)
+ return false;
+
+ char *errormsg;
+ int ret = check_authentication_from_cloud(rolename, NULL, NULL, USER_EXIST,
+ "", &errormsg);
+ if (ret)
+ {
+ ereport(LOG,
+ (errmsg("%s", errormsg)));
+ if (errormsg) {
+ pfree(errormsg);
+ errormsg = NULL;
+ }
+ return false;
+ }
+ HeapTuple tuple;
+ *roleid = CreateNoPrivligeRole(rolename);
+ return true;
+}
+
+bool CheckUserExistOnCloud(cqContext *pcqCtx, Relation pg_authid_rel,
+ char *rolename, HeapTuple *tuple, bool forUpdate)
+{
+ if (!pg_cloud_auth)
+ return false;
+
+ char *errormsg;
+ int ret = check_authentication_from_cloud(rolename, NULL, NULL, USER_EXIST,
+ "", &errormsg);
+ if (ret)
+ {
+ ereport(LOG, (errmsg("%s", errormsg)));
+ if (errormsg)
+ {
+ pfree(errormsg);
+ errormsg = NULL;
+ }
+ return false;
+ }
+ caql_endscan(pcqCtx);
+ if (pg_authid_rel)
+ {
+ heap_close(pg_authid_rel, NoLock);
+ }
+ Oid roleid = CreateNoPrivligeRole(rolename);
+ cqContext cqc;
+ if (forUpdate)
+ {
+ pg_authid_rel = heap_open(AuthIdRelationId, RowExclusiveLock);
+ pcqCtx = caql_beginscan(caql_addrel(cqclr(&cqc), pg_authid_rel),
+ cql("SELECT * FROM pg_authid "
+ " WHERE oid = :1 "
+ " FOR UPDATE ", ObjectIdGetDatum(roleid)));
+ }
+ else
+ {
+ pcqCtx = caql_beginscan(
+ NULL, cql("SELECT * FROM pg_authid "
+ " WHERE oid = :1 ", ObjectIdGetDatum(roleid)));
+ }
+
+ *tuple = caql_getnext(pcqCtx);
+ return true;
+}
diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c
index b431228..6c801ee 100644
--- a/src/backend/commands/variable.c
+++ b/src/backend/commands/variable.c
@@ -776,12 +776,12 @@ assign_session_authorization(const char *value, bool doit, GucSource source)
PointerGetDatum((char *) value)));
roleTup = caql_getnext(pcqCtx);
- if (!HeapTupleIsValid(roleTup))
+ if (!HeapTupleIsValid(roleTup)
+ && !CheckUserExistOnCloud(pcqCtx, NULL, value, &roleTup, false))
{
if (source >= PGC_S_INTERACTIVE)
ereport(ERROR,
- (errcode(ERRCODE_UNDEFINED_OBJECT),
- errmsg("role \"%s\" does not exist", value)));
+ (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("role \"%s\" does not exist", value)));
return NULL;
}
@@ -922,12 +922,12 @@ assign_role(const char *value, bool doit, GucSource source)
PointerGetDatum((char *) value)));
roleTup = caql_getnext(pcqCtx);
- if (!HeapTupleIsValid(roleTup))
+ if (!HeapTupleIsValid(roleTup)
+ && !CheckUserExistOnCloud(pcqCtx, NULL, value, &roleTup, false))
{
if (source >= PGC_S_INTERACTIVE)
ereport(ERROR,
- (errcode(ERRCODE_UNDEFINED_OBJECT),
- errmsg("role \"%s\" does not exist", value)));
+ (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("role \"%s\" does not exist", value)));
return NULL;
}
diff --git a/src/backend/libpq/Makefile b/src/backend/libpq/Makefile
index 16124c7..a55f694 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 rangerrest.o
+ pqformat.o pqsignal.o sha2.o pg_sha2.o rangerrest.o cloudrest.o
include $(top_srcdir)/src/backend/common.mk
diff --git a/src/backend/libpq/auth.c b/src/backend/libpq/auth.c
index fbd2b32..1e0e888 100644
--- a/src/backend/libpq/auth.c
+++ b/src/backend/libpq/auth.c
@@ -40,6 +40,7 @@
#include "pgtime.h"
#include "postmaster/postmaster.h"
#include "utils/builtins.h"
+#include "utils/cloudrest.h"
#include "utils/datetime.h"
#include "utils/guc.h"
#include "utils/timestamp.h"
@@ -213,6 +214,12 @@ static int pg_SSPI_recvauth(Port *port);
#endif
static int CheckRADIUSAuth(Port *port);
+/*----------------------------------------------------------------
+ * Cloud Authentication
+ *----------------------------------------------------------------
+ */
+static int CheckCloudAuth(Port *port);
+
/*
* Maximum accepted size of GSS and SSPI authentication tokens.
*
@@ -313,6 +320,9 @@ auth_failed(Port *port, int status)
case uaRADIUS:
errstr = gettext_noop("RADIUS authentication failed for user \"%s\"");
break;
+ case uaCloud:
+ errstr = gettext_noop("Cloud authentication failed for user \"%s\"");
+ break;
default:
errstr = gettext_noop("authentication failed for user \"%s\": invalid authentication method");
break;
@@ -711,6 +721,9 @@ ClientAuthentication(Port *port)
case uaRADIUS:
status = CheckRADIUSAuth(port);
break;
+ case uaCloud:
+ status = CheckCloudAuth(port);
+ break;
case uaTrust:
status = STATUS_OK;
break;
@@ -2696,6 +2709,62 @@ CheckCertAuth(Port *port)
}
#endif
+/*
+ * Called when we have sent an authorization request for a password.
+ * Get the response and check it.
+ */
+static int
+CheckCloudAuth(Port *port)
+{
+ char *passwd;
+ int result;
+
+ pg_cloud_auth = true;
+
+ elog(LOG, "in CheckCloudAuth, port->hba->cloudserver=%s, pg_cloud_clustername=%s", port->hba->cloudserver, pg_cloud_clustername);
+ if (!port->hba->cloudserver || port->hba->cloudserver[0] == '\0')
+ {
+ ereport(LOG,
+ (errmsg("cloud server not specified")));
+ return STATUS_ERROR;
+ }
+
+ sendAuthRequest(port, AUTH_REQ_PASSWORD);
+
+ passwd = recv_password_packet(port);
+ if (passwd == NULL)
+ return STATUS_EOF; /* client wouldn't send password */
+
+ if (strlen(passwd) == 0)
+ {
+ ereport(LOG,
+ (errmsg("empty password returned by client")));
+ return STATUS_ERROR;
+ }
+
+ elog(LOG, "in CheckCloudAuth, before init_cloud_curl");
+ init_cloud_curl();
+
+ char *errormsg;
+ elog(LOG, "in CheckCloudAuth, before check_authentication_from_cloud");
+ result = check_authentication_from_cloud(port->user_name, passwd, NULL,
+ AUTHENTICATION_CHECK, "", &errormsg);
+ if (result)
+ {
+ ereport(LOG,
+ (errmsg("%s", errormsg)));
+ if (errormsg) {
+ pfree(errormsg);
+ errormsg = NULL;
+ }
+ }
+
+ pfree(passwd);
+
+ return result;
+
+}
+
/*----------------------------------------------------------------
* RADIUS authentication
diff --git a/src/backend/libpq/cloudrest.c b/src/backend/libpq/cloudrest.c
new file mode 100644
index 0000000..4ef0412
--- /dev/null
+++ b/src/backend/libpq/cloudrest.c
@@ -0,0 +1,446 @@
+///////////////////////////////////////////////////////////////////////////////
+// Copyright 2016, Oushu Inc.
+// All rights reserved.
+//
+// Author:
+///////////////////////////////////////////////////////////////////////////////
+
+#include "utils/cloudrest.h"
+
+#include <string.h>
+
+#include "utils/elog.h"
+
+char *pg_cloud_server = NULL;
+char *pg_cloud_token = NULL;
+bool pg_cloud_createrole;
+bool pg_cloud_auth = false;
+
+static void finalize_cloud_curl();
+
+static json_object *create_cloud_authentication_request_json(char *username, char *password)
+{
+ json_object *jrequest = json_object_new_object();
+
+ json_object *jusername = json_object_new_string(username);
+ json_object_object_add(jrequest, "username", jusername);
+ json_object *jpassword = json_object_new_string(password);
+ json_object_object_add(jrequest, "password", jpassword);
+ json_object *jclustername = json_object_new_string(pg_cloud_clustername);
+ json_object_object_add(jrequest, "clustername", jclustername);
+
+ return jrequest;
+}
+
+static json_object *create_cloud_usersync_request_json(char *username, char *password, bool *createuser, char *action)
+{
+ json_object *jrequest = json_object_new_object();
+
+ json_object *jaction = json_object_new_string(action);
+ json_object_object_add(jrequest, "action", jaction);
+ json_object *jtoken = json_object_new_string(pg_cloud_token);
+ json_object_object_add(jrequest, "token", jtoken);
+ json_object *jusername = json_object_new_string(username);
+ json_object_object_add(jrequest, "username", jusername);
+ if (password)
+ {
+ json_object *jpassword = json_object_new_string(password);
+ json_object_object_add(jrequest, "password", jpassword);
+ }
+ json_object *jclustername = json_object_new_string(pg_cloud_clustername);
+ json_object_object_add(jrequest, "clustername", jclustername);
+ if (createuser)
+ {
+ json_object *jcreateuser = json_object_new_boolean(*createuser);
+ json_object_object_add(jrequest, "cancreateuser", jcreateuser);
+ }
+
+ return jrequest;
+}
+
+static json_object *create_cloud_userexist_request_json(char *username)
+{
+ json_object *jrequest = json_object_new_object();
+
+ json_object *jusername = json_object_new_string(username);
+ json_object_object_add(jrequest, "username", jusername);
+ json_object *jclustername = json_object_new_string(pg_cloud_clustername);
+ json_object_object_add(jrequest, "clustername", jclustername);
+
+ 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 = (CURL_HANDLE) userp;
+ Assert(curl != NULL);
+
+ elog(DEBUG3, "cloud restful response size is %d. response buffer size is %d.", curl->response.response_size, curl->response.buffer_size);
+ int original_size = curl->response.buffer_size;
+ while(curl->response.response_size + realsize >= curl->response.buffer_size)
+ {
+ /* double the buffer size if the buffer is not enough.*/
+ curl->response.buffer_size = curl->response.buffer_size * 2;
+ }
+ if(original_size < curl->response.buffer_size)
+ {
+ /* repalloc is not same as realloc, repalloc's first parameter cannot be NULL */
+ curl->response.buffer = repalloc(curl->response.buffer, curl->response.buffer_size);
+ }
+ elog(DEBUG3, "cloud restful response size is %d. response buffer size is %d.", curl->response.response_size, curl->response.buffer_size);
+ if (curl->response.buffer == NULL)
+ {
+ /* allocate memory failed. probably out of memory */
+ elog(WARNING, "cannot allocate memory for cloud response");
+ return 0;
+ }
+ memcpy(curl->response.buffer + curl->response.response_size, contents, realsize);
+ curl->response.response_size += realsize;
+ curl->response.buffer[curl->response.response_size] = '\0';
+ elog(DEBUG3, "read from cloud restful response: %s", curl->response.buffer);
+ return realsize;
+}
+
+/**
+ * @return 0 curl success; -1 curl failed
+ */
+static int call_cloud_rest(CURL_HANDLE curl_handle, const char* request, char *action)
+{
+ int ret = -1;
+ CURLcode res;
+ Assert(request != NULL);
+
+ /*
+ * Re-initializes all options previously set on a specified CURL handle
+ * to the default values. This puts back the handle to the same state as
+ * it was in when it was just created with curl_easy_init.It does not
+ * change the following information kept in the handle: live connections,
+ * the Session ID cache, the DNS cache, the cookies and shares.
+ */
+ curl_easy_reset(curl_handle->curl_handle);
+ /* timeout: hard-coded temporarily and maybe should be a guc in future */
+ curl_easy_setopt(curl_handle->curl_handle, CURLOPT_TIMEOUT, 30L);
+
+ /* specify URL to get */
+ StringInfoData tname;
+ initStringInfo(&tname);
+ appendStringInfo(&tname, "%s", pg_cloud_server);
+ appendStringInfo(&tname, "/");
+ appendStringInfo(&tname, "%s", action);
+ curl_easy_setopt(curl_handle->curl_handle, CURLOPT_URL, tname.data);
+ elog(INFO, "in call_cloud_rest: %s", tname.data);
+ pfree(tname.data);
+
+ struct curl_slist *headers = NULL;
+ headers = curl_slist_append(headers, "Content-Type:application/json");
+ if (pg_cloud_token) {
+ char buf[512];
+ memset(buf, 0, sizeof(buf));
+ sprintf(buf, "token:%s", pg_cloud_token);
+ elog(INFO, "in call_cloud_rest: %s", buf);
+ headers = curl_slist_append(headers, buf);
+ }
+ curl_easy_setopt(curl_handle->curl_handle, CURLOPT_HTTPHEADER, headers);
+
+ curl_easy_setopt(curl_handle->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(ERROR, "cloud server from %s/%s is unavailable : %s.\n",
+ pg_cloud_server, action, curl_easy_strerror(res));
+ }
+ else
+ {
+ ret = 0;
+ elog(DEBUG3, "retrieved %d bytes data from cloud restful response.",
+ curl_handle->response.response_size);
+ }
+
+ return ret;
+}
+
+static int parse_cloud_auth_response(char* buffer, int *result, char **errormsg)
+{
+ if (buffer == NULL || strlen(buffer) == 0)
+ return -1;
+
+ elog(DEBUG3, "parse cloud restful response content : %s", buffer);
+
+ struct json_object *response = json_tokener_parse(buffer);
+ if (response == NULL)
+ {
+ elog(WARNING, "failed to parse json tokener.");
+ return -1;
+ }
+
+ struct json_object *jtoken = NULL;
+ if (!json_object_object_get_ex(response, "token", &jtoken))
+ {
+ elog(WARNING, "failed to get json \"token\" field.");
+ return -1;
+ }
+ char *token = json_object_get_string(jtoken);
+ size_t len = strlen(token);
+ MemoryContext old;
+ old = MemoryContextSwitchTo(TopMemoryContext);
+ pg_cloud_token = (char *)palloc0(len + 1);
+ memcpy(pg_cloud_token, token, len);
+ MemoryContextSwitchTo(old);
+ elog(INFO, "in parse_cloud_auth_response, token(%p): %s", pg_cloud_token, pg_cloud_token);
+
+ struct json_object *jcreaterole = NULL;
+ if (!json_object_object_get_ex(response, "cancreateuser", &jcreaterole))
+ {
+ elog(WARNING, "failed to get json \"cancreateuser\" field.");
+ return -1;
+ }
+ pg_cloud_createrole = json_object_get_boolean(jcreaterole);
+ elog(INFO, "pg_cloud_createrole=%d", pg_cloud_createrole);
+
+ struct json_object *jresult = NULL;
+ if (!json_object_object_get_ex(response, "result", &jresult))
+ {
+ elog(WARNING, "failed to get json \"result\" field.");
+ return -1;
+ }
+
+ json_bool ok = json_object_get_int(jresult);
+ if (ok == 1)
+ {
+ *result = CLOUDCHECK_OK;
+ }
+ else
+ {
+ struct json_object *jerror = NULL;
+ if (!json_object_object_get_ex(response, "error", &jerror))
+ {
+ elog(WARNING, "failed to get json \"token\" field.");
+ return -1;
+ }
+ char *err = json_object_get_string(jerror);
+ size_t len = strlen(err);
+ *errormsg = (char *)palloc0(len + 1);
+ memcpy(*errormsg, err, len);
+ (*errormsg)[len] = '\0';
+ *result = CLOUDCHECK_NO_PRIV;
+ elog(INFO, "errmsg=%s, size=%d", *errormsg, strlen(*errormsg));
+ }
+
+ return 0;
+}
+
+static int parse_cloud_sync_response(char* buffer, int *result, char **errormsg)
+{
+ if (buffer == NULL || strlen(buffer) == 0)
+ return -1;
+
+ elog(DEBUG3, "parse cloud restful response content : %s", buffer);
+
+ struct json_object *response = json_tokener_parse(buffer);
+ if (response == NULL)
+ {
+ elog(WARNING, "failed to parse json tokener.");
+ return -1;
+ }
+
+ struct json_object *jresult = NULL;
+ if (!json_object_object_get_ex(response, "result", &jresult))
+ {
+ elog(WARNING, "failed to get json \"result\" field.");
+ return -1;
+ }
+
+ int ok = json_object_get_boolean(jresult);
+ elog(INFO, "in parse_cloud_sync_response, ret=%d", ok);
+ if (ok == 0)
+ {
+ *result = CLOUDSYNC_OK;
+ }
+ else
+ {
+ struct json_object *jerror = NULL;
+ if (!json_object_object_get_ex(response, "error", &jerror))
+ {
+ elog(WARNING, "failed to get json \"token\" field.");
+ return -1;
+ }
+ char *err = json_object_get_string(jerror);
+ size_t len = strlen(err);
+ *errormsg = (char *)palloc0(len + 1);
+ memcpy(*errormsg, err, len);
+ (*errormsg)[len] = '\0';
+ if (ok == 1)
+ *result = CLOUDSYNC_USEREXIST;
+ else
+ *result = CLOUDSYNC_FAIL;
+ }
+
+ return 0;
+}
+
+static int parse_cloud_exist_response(char* buffer, int *result, char **errormsg)
+{
+ if (buffer == NULL || strlen(buffer) == 0)
+ return -1;
+
+ elog(DEBUG3, "parse cloud restful response content : %s", buffer);
+
+ struct json_object *response = json_tokener_parse(buffer);
+ if (response == NULL)
+ {
+ elog(WARNING, "failed to parse json tokener.");
+ return -1;
+ }
+
+ struct json_object *jresult = NULL;
+ if (!json_object_object_get_ex(response, "result", &jresult))
+ {
+ elog(WARNING, "failed to get json \"result\" field.");
+ return -1;
+ }
+
+ json_bool ok = json_object_get_boolean(jresult);
+ if (ok == 1)
+ {
+ *result = CLOUDUSER_EXIST;
+ }
+ else
+ {
+ *result = CLOUDUSER_NOTEXIST;
+ }
+
+ return 0;
+}
+
+void init_cloud_curl() {
+ memset(&curl_context_cloud, 0, sizeof(curl_context_t));
+ curl_global_init(CURL_GLOBAL_ALL);
+ /* init the curl session */
+ curl_context_cloud.curl_handle = curl_easy_init();
+ if (curl_context_cloud.curl_handle == NULL) {
+ /* cleanup curl stuff */
+ /* no need to cleanup curl_handle since it's null. just cleanup curl global.*/
+ curl_global_cleanup();
+ elog(ERROR, "initialize global curl context failed.");
+ }
+ curl_context_cloud.hasInited = true;
+ curl_context_cloud.response.buffer = palloc0(CURL_RES_BUFFER_SIZE);
+ curl_context_cloud.response.buffer_size = CURL_RES_BUFFER_SIZE;
+ elog(DEBUG3, "initialize global curl context for privileges check.");
+ on_proc_exit(finalize_cloud_curl, 0);
+}
+
+void finalize_cloud_curl() {
+ if (curl_context_cloud.response.buffer != NULL) {
+ pfree(curl_context_cloud.response.buffer);
+ }
+ /* cleanup curl stuff */
+ if (curl_context_cloud.curl_handle) {
+ curl_easy_cleanup(curl_context_cloud.curl_handle);
+ }
+ /* we're done with libcurl, so clean it up */
+ curl_global_cleanup();
+ curl_context_cloud.hasInited = false;
+ elog(DEBUG3, "finalize the global struct for curl handle context.");
+}
+
+int check_authentication_from_cloud(char *username, char *password,
+ bool *createuser, CouldAuthAction authAction, char * action,
+ char **errormsg)
+{
+ json_object* jrequest;
+ switch (authAction)
+ {
+ case AUTHENTICATION_CHECK:
+ jrequest = create_cloud_authentication_request_json(username, password);
+ break;
+ case USER_SYNC:
+ jrequest = create_cloud_usersync_request_json(username, password,
+ createuser, action);
+ break;
+ case USER_EXIST:
+ jrequest = create_cloud_userexist_request_json(username);
+ break;
+ default:
+ elog(ERROR, "Invalid cloud authentication action:%d", authAction);
+ }
+ Assert(jrequest != NULL);
+
+ const char *request = json_object_to_json_string(jrequest);
+ Assert(request != NULL);
+ elog(
+ DEBUG3, "send json request to cloud : %s", request);
+
+ /* call GET method to send request*/
+ Assert(curl_context_cloud.hasInited);
+ switch (authAction)
+ {
+ case AUTHENTICATION_CHECK:
+ if (call_cloud_rest(&curl_context_cloud, request, "cloudauthenticate") < 0)
+ {
+ return -1;
+ }
+ break;
+ case USER_SYNC:
+ if (call_cloud_rest(&curl_context_cloud, request, "syncuser") < 0)
+ {
+ return -1;
+ }
+ break;
+ case USER_EXIST:
+ if (call_cloud_rest(&curl_context_cloud, request, "userexist") < 0)
+ {
+ return -1;
+ }
+ break;
+ default:
+ elog(ERROR, "Invalid cloud authentication action:%d", authAction);
+ }
+
+ /* free the JSON object */
+ json_object_put(jrequest);
+
+ /* parse the JSON-format result */
+ int result,
+ ret;
+ switch (authAction)
+ {
+ case AUTHENTICATION_CHECK:
+ ret = parse_cloud_auth_response(curl_context_cloud.response.buffer,
+ &result, errormsg);
+ break;
+ case USER_SYNC:
+ ret = parse_cloud_sync_response(curl_context_cloud.response.buffer,
+ &result, errormsg);
+ break;
+ case USER_EXIST:
+ ret = parse_cloud_exist_response(curl_context_cloud.response.buffer,
+ &result, errormsg);
+ break;
+ default:
+ elog(ERROR, "Invalid cloud authentication action:%d", authAction);
+ }
+ if (ret < 0)
+ {
+ elog(
+ ERROR, "parse cloud response failed, cloud response content is %s",
+ curl_context_cloud.response.buffer == NULL? "empty.":curl_context_cloud.response.buffer);
+ }
+ if (curl_context_cloud.response.buffer != NULL)
+ {
+ /* reset response size to reuse the buffer. */
+ curl_context_cloud.response.response_size = 0;
+ }
+
+ elog(INFO, "in check_authentication_from_cloud: ret=%d", result);
+ return result;
+}
diff --git a/src/backend/libpq/hba.c b/src/backend/libpq/hba.c
index d430335..6f89133 100644
--- a/src/backend/libpq/hba.c
+++ b/src/backend/libpq/hba.c
@@ -25,12 +25,14 @@
#include <arpa/inet.h>
#include <unistd.h>
+#include "libpq/auth.h"
#include "libpq/ip.h"
#include "libpq/libpq.h"
#include "regex/regex.h"
#include "storage/fd.h"
#include "utils/flatfiles.h"
#include "utils/acl.h"
+#include "utils/cloudrest.h"
#include "utils/guc.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
@@ -1087,6 +1089,8 @@ parse_hba_line(List *line, int line_num, HbaLine *parsedline)
#endif
else if (strcmp(token, "radius") == 0)
parsedline->auth_method = uaRADIUS;
+ else if (strcmp(token, "cloud") == 0)
+ parsedline->auth_method = uaCloud;
else
{
ereport(LOG,
@@ -1373,6 +1377,17 @@ parse_hba_line(List *line, int line_num, HbaLine *parsedline)
REQUIRE_AUTH_OPTION(uaRADIUS, "radiusidentifier", "radius");
parsedline->radiusidentifier = pstrdup(c);
}
+ else if (strcmp(token, "cloudserver") == 0)
+ {
+ REQUIRE_AUTH_OPTION(uaCloud, "cloudserver", "cloud");
+ parsedline->cloudserver = pstrdup(c);
+ size_t len = strlen(parsedline->cloudserver);
+ MemoryContext old;
+ old = MemoryContextSwitchTo(TopMemoryContext);
+ pg_cloud_server = (char *)palloc0(len + 1);
+ memcpy(pg_cloud_server, parsedline->cloudserver, len);
+ MemoryContextSwitchTo(old);
+ }
else
{
ereport(LOG,
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index 4928ce2..cf0123e 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -137,6 +137,7 @@ extern char *savedSeqServerHost;
extern int savedSeqServerPort;
struct curl_context_t curl_context_ranger;
+struct curl_context_t curl_context_cloud;
/* ----------------
* global variables
* ----------------
diff --git a/src/backend/utils/cache/lsyscache.c b/src/backend/utils/cache/lsyscache.c
index 2bd929f..d2a09c3 100644
--- a/src/backend/utils/cache/lsyscache.c
+++ b/src/backend/utils/cache/lsyscache.c
@@ -54,6 +54,7 @@
#include "cdb/cdbpartition.h"
#include "commands/tablecmds.h"
#include "commands/trigger.h"
+#include "commands/user.h"
#include "miscadmin.h"
#include "nodes/makefuncs.h"
#include "parser/parse_clause.h" /* for sort_op_can_sort() */
@@ -3366,7 +3367,7 @@ get_roleid_checked(const char *rolname)
Oid roleid;
roleid = get_roleid(rolname);
- if (!OidIsValid(roleid))
+ if (!OidIsValid(roleid) && !(CheckUserExistOnCloudSimple(rolname, &roleid)))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("role \"%s\" does not exist", rolname),
diff --git a/src/backend/utils/init/miscinit.c b/src/backend/utils/init/miscinit.c
index 640cafa..c5384f9 100644
--- a/src/backend/utils/init/miscinit.c
+++ b/src/backend/utils/init/miscinit.c
@@ -444,11 +444,10 @@ InitializeSessionUserId(const char *rolename)
roleTup = caql_getnext(pcqCtx);
- if (!HeapTupleIsValid(roleTup))
+ if (!HeapTupleIsValid(roleTup)
+ && !CheckUserExistOnCloud(pcqCtx, NULL, rolename, &roleTup, false))
ereport(FATAL,
- (errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION),
- errmsg("role \"%s\" does not exist", rolename),
- errOmitLocation(true), errSendAlert(false)));
+ (errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION), errmsg("role \"%s\" does not exist", rolename), errOmitLocation(true), errSendAlert(false)));
rform = (Form_pg_authid) GETSTRUCT(roleTup);
roleid = HeapTupleGetOid(roleTup);
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 6577b4c..0cf51df 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -790,6 +790,21 @@ char *acl_type;
int rps_addr_port;
int rps_check_local_interval;
+char *rps_addr_host;
+char *rps_addr_suffix;
+int rps_addr_port;
+
+char *pg_cloud_clustername = NULL;
+
+/*auto-switch service*/
+bool enable_master_auto_ha = false;
+
+/*
+ * zookeeper_server hostlist
+ * "host1:port1,host2:port2,...,hostx:postx"
+ */
+char *ha_zookeeper_quorum = "localhost:2181";
+
/*
* Displayable names for context types (enum GucContext)
*
@@ -8228,6 +8243,15 @@ static struct config_string ConfigureNamesString[] =
},
{
+ {"clusterName", PGC_POSTMASTER, PRESET_OPTIONS,
+ gettext_noop("Corresponding identifier for this hawq cluster in oushu cloud system."),
+ NULL
+ },
+ &pg_cloud_clustername,
+ "", NULL, NULL
+ },
+
+ {
{"hawq_standby_address_host", PGC_POSTMASTER, PRESET_OPTIONS,
gettext_noop("standby server address hostname"),
NULL
diff --git a/src/include/commands/user.h b/src/include/commands/user.h
index 01fb92c..c71b6a7 100644
--- a/src/include/commands/user.h
+++ b/src/include/commands/user.h
@@ -11,6 +11,7 @@
#ifndef USER_H
#define USER_H
+#include "catalog/catquery.h"
#include "nodes/parsenodes.h"
@@ -22,5 +23,7 @@ extern void GrantRole(GrantRoleStmt *stmt);
extern void RenameRole(const char *oldname, const char *newname);
extern void DropOwnedObjects(DropOwnedStmt *stmt);
extern void ReassignOwnedObjects(ReassignOwnedStmt *stmt);
+extern bool CheckUserExistOnCloudSimple(char *rolename, Oid *roleid);
+extern bool CheckUserExistOnCloud(cqContext *pcqCtx, Relation pg_authid_rel, char *rolename, HeapTuple *tuple, bool forUpdate);
#endif /* USER_H */
diff --git a/src/include/libpq/hba.h b/src/include/libpq/hba.h
index bc81f9d..9779c62 100644
--- a/src/include/libpq/hba.h
+++ b/src/include/libpq/hba.h
@@ -29,7 +29,8 @@ typedef enum UserAuth
uaPAM,
uaLDAP,
uaCert,
- uaRADIUS
+ uaRADIUS,
+ uaCloud
} UserAuth;
typedef enum IPCompareMethod
@@ -77,6 +78,7 @@ typedef struct
char *radiussecret;
char *radiusidentifier;
int radiusport;
+ char *cloudserver;
} HbaLine;
/* kluge to avoid including libpq/libpq-be.h here */
diff --git a/src/include/utils/cloudrest.h b/src/include/utils/cloudrest.h
new file mode 100644
index 0000000..e4e3cc8
--- /dev/null
+++ b/src/include/utils/cloudrest.h
@@ -0,0 +1,88 @@
+///////////////////////////////////////////////////////////////////////////////
+// Copyright 2016, Oushu Inc.
+// All rights reserved.
+//
+// Author:
+///////////////////////////////////////////////////////////////////////////////
+#ifndef SRC_INCLUDE_UTILS_CLOUDREST_H_
+#define SRC_INCLUDE_UTILS_CLOUDREST_H_
+
+#include <json-c/json.h>
+#include <curl/curl.h>
+
+#include "postgres.h"
+#include "utils/guc.h"
+#include "miscadmin.h"
+#include "libpq/auth.h"
+#include "libpq/libpq-be.h"
+#include "tcop/tcopprot.h"
+
+#define HOST_BUFFER_SIZE 1025
+#define CURL_RES_BUFFER_SIZE 1024
+
+typedef enum
+{
+ AUTHENTICATION_CHECK = 0,
+ USER_SYNC,
+ USER_EXIST
+} CouldAuthAction;
+
+typedef enum
+{
+ CLOUDCHECK_OK = 0,
+ CLOUDCHECK_NO_PRIV,
+ CLOUDCHECK_UNKNOWN
+} CouldAuthResult;
+
+typedef enum
+{
+ CLOUDSYNC_OK = 0,
+ CLOUDSYNC_USEREXIST,
+ CLOUDSYNC_FAIL,
+ CLOUDSYNC_UNKNOWN
+} CouldSyncResult;
+
+typedef enum
+{
+ CLOUDUSER_EXIST = 0,
+ CLOUDUSER_NOTEXIST,
+} CouldExistResult;
+
+/*
+ * 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 response_size;
+ int buffer_size;
+ } response;
+
+ char* last_http_reponse;
+
+ bool hasInited;
+} curl_context_t;
+
+typedef curl_context_t* CURL_HANDLE;
+
+extern struct curl_context_t curl_context_cloud;
+
+extern void init_cloud_curl();
+extern int check_authentication_from_cloud(char *username, char *password,
+ bool *createuser, CouldAuthAction authAction, char * action,
+ char **errmsg);
+
+extern char *pg_cloud_server;
+extern char *pg_cloud_token;
+extern bool pg_cloud_createrole;
+extern bool pg_cloud_auth;
+
+#endif /* SRC_INCLUDE_UTILS_CLOUDREST_H_ */
diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h
index 38b217a..d1698a7 100644
--- a/src/include/utils/guc.h
+++ b/src/include/utils/guc.h
@@ -465,6 +465,12 @@ extern int rps_addr_port;
/* interval of checking local RPS */
extern int rps_check_local_interval;
+
+/*
+ * cloud authenticate
+ */
+extern char *pg_cloud_clustername;
+
/*
* During insertion in a table with parquet partitions,
* require tuples to be sorted by partition key.