CloudberryDB | 第4期 | 角色管理实现机制解读
角色是拥有数据库对象和权限的实体,在不同环境中角色可以是一个用户、一个组或者两者都有,本节介绍角色的创建、修改、删除和权限授予与回收。
1、角色创建
创建角色的语法:
角色创建通过函数CreateRole来完成,看下函数接口:
关键数据结构及函数步骤如下图所示:
CreateRoleStmt为语法树的一个节点,表示创建Role;RoleStmtType是一个枚举类型,用来表示创建ROLE、USER、GROUP;role为角色名;options为存储角色属性信息的DefElem链表,就是CREATE ROLE语法中的option,比如能否登录等属性。
DefElem中defnamespace为节点对应的命名空间;defname为角色属性名;arg为值或类型名;defaction表示SET\ADD\DROP等行为。
创建角色的流程如上图所示,就是解析出DefElem内容后,构建tuple填充系统表pg_authid、pg_auth_members和pg_auth_time_constraint;如果是QD,则最后需要分发执行计划给QE去执行。
下面看下详细流程:
1)若是创建用户则设置canlogin的属性为true,因为用户默认由登录权限;而创建角色和组时,若没有角色属性参数设置,则canlogin为false:
2)循环获取角色属性options中内容,并转化成对应角色属性值类型:
3)根据对应参数信息转换需要的角色属性类型,比如提取issuper值和createrole值:
4)将角色属性值及角色信息一起构建pg_authid的一个元组,写回系统表并更新索引:
5)IN ROLE role1,role2...会将新角色作为member加入到role1,role2...中,也就是更新pg_auth_members系统表:
6)ROLE role3,role4...:将角色role3、role4作为members加入到新角色:
以createdatabase权限看下pg_authid中存储用户的rolcreatedb权限用法:
从pg_authid的SysCache来查询,看下对应用户的rolcreatedb是否为true,若为false则无创建database权限,那么就报错。
2、修改角色属性
使用ALTER ROLE来修改角色的属性,语法:
通过AlterRole函数来实现,需要一个AlterRoleStmt的结构:
修改角色属性的流程入下图所示:
调用函数AlterRole修改用户角色时,先循环判断options,依次提取要修改的角色属性;然后查看系统表pg_authid,判断角色是否存在,若不存在则提示报错推出,否则进行相应的权限判断执行者是否有权限更改该角色的属性;最后构建一个新的元组将要更改的属性更新到新元组中,更新到pg_authid中。同时AlterRole也可以调整角色的成员关系,结构体中的action为1和-1分别表示增加和删除成员关系。
RENAME通过RenameRole来实现,AlterRoleSet来实现ALTER ROLE ... SET,更新pg_db_role_setting系统表。
3、删除角色
如果要删除一个角色,用DROP ROLE,调用函数DropRole来实现,该函数入参为DropRoleStmt结构体:
1)首先判断是否有权限执行,若无则报错
2)循环处理roles链表的角色,检查该角色是否存在,若不存在则根据missing_ok选择返回ERROR还是NOTICE:
3)通过扫描pg_authid和pg_auth_members删除所有涉及删除角色的元组,当然还会删除该角色在pg_password_history、pg_auth_time_constraint、pg_db_role_setting中的元组
4)最后若是QD,则将命令分发给QE执行
4、授权和回收角色
如果要授权或回收角色的成员关系,可以使用GRANT/REVOKE。如果声明了WITH ADMIN OPTION,那么被加入的成员角色还可以将其他角色加入父角色member中。角色的授予和回收通过GrantRole函数完成。他的入参结构:
其中behavior会标记是否级联回收角色。熟悉前面的系统表后,这个流程理解就比较简单:
1)授予角色时,grantee_roles中的角色添加到granted_roles中,通过调用AddRoleMems实现
2)回收角色的时候,将grantee_roles中的角色从granted_roles中删除,通过DelRoleMems实现
主要还是更新pg_auth_member系统表。