openGauss源码解析(195)

openGauss源码解析:安全管理源码解析(6)

9.3 角色管理

角色是拥有数据库对象和权限的实体,在不同的环境中角色可以认为是一个用户、一个组或者兼顾两者。角色管理包含了角色的创建、修改、删除、权限授予和回收操作。

9.3.1 角色创建

如果在openGauss上需要创建一个角色,可以使用SQL命令CREATE ROLE,其语法为:

CREATE ROLE role_name [ [ WITH ] option [ ... ] ] [ ENCRYPTED | UNENCRYPTED ] { PASSWORD | IDENTIFIED BY } { 'password' | DISABLE };

创建角色是通过函数CreateRole实现的,其函数接口为:

void CreateRole(CreateRoleStmt* stmt)

其中,CreateRoleStmt为创建角色时所需的数据结构,具体数据结构代码如下:

typedef struct CreateRoleStmt {

NodeTag type;

RoleStmtType stmt_type; /* 将要创建的角色类型 ROLE/USER/GROUP */

char* role; /* 角色名 */

List* options; /* 角色属性列表 */

} CreateRoleStmt;

字段stmt_type是枚举类型,相关代码如下:

typedef enum RoleStmtType {

ROLESTMT_ROLE, /* 代表创建角色 */

ROLESTMT_USER, /* 代表创建用户 */

ROLESTMT_GROUP, /* 代表创建组用户 */

} RoleStmtType;

字段option用来存储角色的属性信息,具体的数据结构为:

typedef struct DefElem {

NodeTag type;

char* defnamespace; /* 节点对应的命名空间 */

char* defname; /* 节点对应的角色属性名 */

Node* arg; /* 表示值或类型名 */

DefElemAction defaction; /* SET/ADD/DROP 等其他未指定的行为 */

} DefElem;

在上述的关键数据结构基础之上,完整的创建角色流程如图9-14所示。

图9-14 openGauss角色创建流程

创建角色时先判断所要创建的角色类型。如果是创建用户,则设置其canlogin属性为true,因为用户默认具有登录权限。而创建角色和创建组时,若角色属性参数没有声明的话,则canlogin属性默认为false。相关代码如下:

/* 默认值可能因原始语句类型而异 */

switch (stmt->stmt_type) {

case ROLESTMT_ROLE:

break;

case ROLESTMT_USER:

canlogin = true;

break;

case ROLESTMT_GROUP:

break;

default:

break;

}

检查完所要创建的角色类型以后,开始循环获取角色属性options中的内容,并将其转换成对应的角色属性值类型。相关代码如下:

/* 从node tree中获取option */

foreach (option, stmt->options) {

DefElem* defel = (DefElem*)lfirst(option);

if (strcmp(defel->defname, "password") == 0 || strcmp(defel->defname, "encryptedPassword") == 0 ||

strcmp(defel->defname, "unencryptedPassword") == 0) {

if (dpassword != NULL) {

clean_role_password(dpassword);

ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("conflicting or redundant options")));

}

dpassword = defel;

if (strcmp(defel->defname, "encryptedPassword") == 0)

encrypt_password = true;

else if (strcmp(defel->defname, "unencryptedPassword") == 0) {

clean_role_password(dpassword);

ereport(ERROR,

(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),

errmsg("Permission denied to create role with option UNENCRYPTED.")));

}

} else if (strcmp(defel->defname, "sysid") == 0) {

ereport(NOTICE, (errmsg("SYSID can no longer be specified")));

} else if (strcmp(defel->defname, "inherit") == 0) {

if (dinherit != NULL) {

clean_role_password(dpassword);

ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("conflicting or redundant options")));

}

dinherit = defel;

} else if (strcmp(defel->defname, "createrole") == 0) {

if (dcreaterole != NULL) {

clean_role_password(dpassword);

ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("conflicting or redundant options")));

}

dcreaterole = defel;

} else if (strcmp(defel->defname, "createdb") == 0) {

if (dcreatedb != NULL) {

clean_role_password(dpassword);

ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("conflicting or redundant options")));

}

dcreatedb = defel;

} else if (strcmp(defel->defname, "useft") == 0) {

if (duseft != NULL) {

clean_role_password(dpassword);

ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("conflicting or redundant options")));

}

duseft = defel;

……

根据对应的参数信息转换需要的角色属性值类型,如提取issuper值和createrole值等。相关代码如下:

if (dissuper != NULL)

issuper = intVal(dissuper->arg) != 0;

if (dinherit != NULL)

inherit = intVal(dinherit->arg) != 0;

if (dcreaterole != NULL)

createrole = intVal(dcreaterole->arg) != 0;

if (dcreatedb != NULL)

createdb = intVal(dcreatedb->arg) != 0;

……

在完成了转换以后,将角色属性值以及角色的信息一起构建一个pg_authid的元组,再写回系统表并更新索引。作相关代码如下:

/* 检查pg_authid relation,确认该角色没有存在*/

Relation pg_authid_rel = heap_open(AuthIdRelationId, RowExclusiveLock);

TupleDesc pg_authid_dsc = RelationGetDescr(pg_authid_rel);

if (OidIsValid(get_role_oid(stmt->role, true))) {

str_reset(password);

ereport(ERROR, (errcode(ERRCODE_DUPLICATE_OBJECT), errmsg("role \"%s\" already exists", stmt->role)));

}

……

/* 创建一个插入的tuple */

errno_t errorno = memset_s(new_record, sizeof(new_record), 0, sizeof(new_record));

securec_check(errorno, "\0", "\0");

errorno = memset_s(new_record_nulls, sizeof(new_record_nulls), false, sizeof(new_record_nulls));

securec_check(errorno, "\0", "\0");

new_record[Anum_pg_authid_rolname - 1] = DirectFunctionCall1(namein, CStringGetDatum(stmt->role));

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);

new_record[Anum_pg_authid_rolcatupdate - 1] = BoolGetDatum(issuper);

new_record[Anum_pg_authid_rolcanlogin - 1] = BoolGetDatum(canlogin);

new_record[Anum_pg_authid_rolreplication - 1] = BoolGetDatum(isreplication);

new_record[Anum_pg_authid_rolauditadmin - 1] = BoolGetDatum(isauditadmin);

new_record[Anum_pg_authid_rolsystemadmin - 1] = BoolGetDatum(issystemadmin);

new_record[Anum_pg_authid_rolconnlimit - 1] = Int32GetDatum(connlimit);

……

HeapTuple tuple = heap_form_tuple(pg_authid_dsc, new_record, new_record_nulls);

if (u_sess->proc_cxt.IsBinaryUpgrade && OidIsValid(u_sess->upg_cxt.binary_upgrade_next_pg_authid_oid)) {

HeapTupleSetOid(tuple, u_sess->upg_cxt.binary_upgrade_next_pg_authid_oid);

u_sess->upg_cxt.binary_upgrade_next_pg_authid_oid = InvalidOid;

}

roleid = simple_heap_insert(pg_authid_rel, tuple);

if (IsUnderPostmaster) {

if (OidIsValid(rpoid) && (rpoid != DEFAULT_POOL_OID))

recordDependencyOnRespool(AuthIdRelationId, roleid, rpoid);

u_sess->wlm_cxt->wlmcatalog_update_user = true;

}

……

完成更新以后,将新创建的角色加入指定存在的父角色中。相关代码如下:

/* 将新角色添加到指定的现有角色中 */

foreach (item, addroleto) {

char* oldrolename = strVal(lfirst(item));

Oid oldroleid = get_role_oid(oldrolename, false);

AddRoleMems(

oldrolename, oldroleid, list_make1(makeString(stmt->role)), list_make1_oid(roleid), GetUserId(), false);

}

AddRoleMems(stmt->role, roleid, adminmembers, roleNamesToIds(adminmembers), GetUserId(), true);

AddRoleMems(stmt->role, roleid, rolemembers, roleNamesToIds(rolemembers), GetUserId(), false);

至此就完成了整个角色创建的过程。

posted @ 2024-05-06 10:45  openGauss-bot  阅读(1)  评论(0编辑  收藏  举报