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.