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 <[email protected]>
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.

Reply via email to