一,CDB的公共性
在一个CDB里面,公共性的基本原则是,一个公共的事物在每一个现有的乃至未来的容器里都是一样的。
“公共”意味着“对所有容器通用”。相对的,一个本地的事物则被限制在一个现有的容器里。
公共性原则的一个方面是,只有公共用户可以操作一个公共事物。更确切的说,只有一个连接到root的公共用户可以create, destroy,或者修改一个公共用户或者角色的CDB属性。
1, CDB中的公共用户和本地用户
每一个持有那些能够定义数据库的对象的用户就是公共的。用户创建的用户则可能是公共的或者本地的。
具体可以看下图:
1.1,CDB中的公共用户
公共用户是在所有的PDB和root中有相同标识的数据库用户。
每一个公共用户都可以连接到root并且进行操作,以及在任何一个它有权限的PDB中进行操作。
每一个公共用户都是系统自带的或者用户创建的,如oracle自带的SYS和SYSTEM用户。
如下图所示,公共用户SYS,c##dba存在于CDB$ROOT,hrpd和salespdb中。hrpdb里面还有本地用户hr和rep,salespdb同样也有hr和rep,不过这两者是不同的。
公共用户有以下的特点:
- 一个公共用户可以登录任意一个容器,只要它在这个容器中拥有CREATE SESSION的权限,包括CDB$ROOT。公共用户不必在每个PDB中都拥有一样的权限,比如说,c##dba在hrpdb和root中有create session权限,但在salespdb中没有,这是因为只要公共用户拥有恰当的权限,它就可以在不同容器之间切换,root中的公共用户可以管理其他PDB容器。
- 每一个用户创建的公共用户必须以c##或者C##开头,系统自带的则不需要,本地用户不以c##或者C##开头。
- 公共用户的名字必须要包含ASCII或者EBCDIC字符
- 每一个公共用户的名字必须是跨容器唯一的,公共用户虽然位于root中,但一定可以用相同的身份连接到每一个PDB
- 公共用户的模式可以在每一个容器中都不一样,比如说,如果c##dba在多个容器中都拥有权限,那么在这些不同的容器中,c##dba可以拥有不同的objects。
1.2,CDB中的本地用户
本地用户跟公共用户的最大区别在于它只能够在单个PDB内进行操作。
它有以下几个特点:
- 本地用户是属于特定的PDB,并且在该PDB中可以拥有一个schema的。比如说本地用户hr,在hrpdb中拥有一个hr schema。
- 本地用户同样可以管理一个PDB,包括open和close。拥有SYSDBA权限的公共用户可以grant SYSDBA权限给一个本地用户,当然即便授权了SYSDBA,本地用户也依旧还是本地用户。
- 在一个PDB里面的本地用户不可以登录其他PDB或者CDB root,但是可以使用db link来获取数据。
- 本地用户的名字不可以以c##或者C##开头
- 本地用户的名字必须在它所属的PDB中唯一,用户名以及PDB公共决定了本地用户的唯一性。
2,公共和本地角色(role)
每一个系统自带的role都是公共的。在oracle提供的脚本里,对oracle自带的用户或者角色的授权操作是公共的,除了把系统权限授予PUBLIC角色。
用户创建的role可以是本地的,也可以是公共的。
2.1 CDB中的公共角色
公共角色存在于root里面和每一个现有的乃至未来新创建的PDB中。可以用于跨容器的操作,确保一个公共用户在每一个容器中都有角色的权限。
公共角色可以由用户创建,有些则是oracle提供的。
用户创建的话,名字必须以C##或者c##开头,并且只能包含ASCII或者EBCDIC字符。
比如说,如果你创建了一个公共用户c##dba,然后授予DBA公共角色,那么在每一个现有的以及将来创建的PDB中,都会有一个有DBA权限的c##dba。
用户只可以在公共用户上进行公共操作,比如说公共地授权:
用户是公共用户,并且当前容器是root
用户有set container的公共权限,也就是该权限被应用到了所有容器上
用户控制某个操作的权限,并且该权限是公共性的,比如说,为了创建一个公共角色,用户必须被授予了CREATE ROLE和SET CONTAINER的公共权限。
在CREATE ROLE的语句里,指定container=ALL表示该角色是公共的。
2.2,CDB中的本地角色
本地角色只存在于PDB中,就跟非CDB的数据库中的角色一样。本地角色只可以包含它所属的容器中的角色和权限。
在同一个CDB中的不同PDB可能有相同名字的本地角色,但是这些角色之间是完全独立的。
2.3,CDB中的权限和角色的授权操作
和非CDB中一样,CDB中一样可以grant role或者grant privileges,唯一的不同是,在CDB中,授权操作分为了本地和公共。
本地的只在它授予的容器中生效,公共的则是全局生效。
对于用户和角色来说,有分为公共和本地,但对于一个权限来说,则不会这么分。
如果用户在授予权限的时候,使用了CONTAINER=CURRENT,那么这就是本地授权操作。
如果使用的是CONTAINER=ALL,则是公共授权。
2.3.1,CDB中授权操作的原则
在一个CDB中,每一个授权操作,无论是公共的还是本地的,都是发生在某个容器中的。
授权操作的基本原则是:
- 公共或者本地的事物都可以本地化地授权或者被授权
- 只有公共事物可以公共性地授权或者被授权
本地用户,角色或者权限被定义为局限于某个容器内,所以,本地的用户不可以公共化的授予角色和权限,也不可以被公共化的授予权限。
2.3.2,CDB中的本地授权操作
角色和权限可以被本地化地授予用户和角色,无论授权操作的双方是本地的还是公共的。
下表解释了可能的授权情况:
注释:
1,公共角色里的权限对于被授权者来说,只在运行授权操作的容器内是有效的,不管这些权限被授予这个角色的时候是本地的还是公共的
2,本地角色里的权限对于被授权者来说,只在这个角色被创建的容器内是有效的
2.3.2.1,什么导致授权操作是本地的
当符合以下条件的时候,则授权是本地化的:
- 授权者拥有必要的权限来grant一个role或者权限。对于系统角色和权限来说,授权者必须对该角色或者权限拥有ADMIN OPTION。对于object权限,授权者则必须药有GRANT OPTION的权限。
- grant操作只应用到一个容器,默认的,GRANT语句会包含CONTAINER=CURRENT,表示该授权是本地化的
2.3.2.2,角色和权限被本地化授权
一个用户或者角色可以被本地化的授予某个权限,跟非CDB一样,就多了一句CONTAINER=CURRENT。
这里需要注意的是,公共用户也可以被本地授权。比如说,把READ ANY TABLE权限在hrpdb中本地授权给c##dba角色,那么拥有c##dba这个角色的公共用户只在hrpdb这个容器里面拥有read any table的权限。
2.3.3,CDB中的公共授权
用户账号或者角色只有在授权的双方都是公共的时候,该授权操作才是公共的,比如说grant A to B, A和B必须都是公共的。
以公共方式授予公共角色的权限(privileges),在所有的container里都是有效的。相反,如果权限是以本地的方式授予的,那么即便角色是公共的,该权限也只在本地有效。
2.3.3.1 什么导致授权操作是公共的
- 授权者是公共用户
- 被授权者是公共用户或者公共角色
- 授权者有足够的权限来进行授权,比如系统权限或者角色,授权者需要有ADMIN OPTION,对于某个对象,则必须是GRANT OPTION。
- 该授权面向所有容器,授权语句指明CONTAINER=ALL语句
- 如果授权操作是grant role to,则role必须是公共的,如果是grant xxx on object to,则该object必须是公共的
2.3.3.2,公共授权roles和privileges
关键之处,在于授权双方都必须是公共的,如果是授予权限,则必须有CONTAINER=ALL。
需要注意,如果把一个权限本地授权给一个公共角色,再把这个公共角色授权给一个公共用户,那么该公共用户所拥有的这个权限也只是本地的。
比如说,在hrpdb中,把SELECT ANY TABLE这个权限本地授予公共角色c##admin。然后再把c##admin授予公共用户c##dba,那么c##dba只在hrpdb中拥有SELECT ANY TABLE的权限。
2.3.4,CDB中授权给PUBLIC
在CDB里面,PUBLIC是一个公共角色,所有的用户默认都有这么一个角色,在一开始的时候,PUBLIC里面是没有权限的,但有大量授权给Java 对象。
这个角色是不能被删除的,即便你删除了也会被恢复,因为它的特殊性,所以你在DBA_ROLES或者SESSION_ROLES是查不到这个角色的。
在PDB中本地授权给PUBLIC,那么这些权限对该PDB中的所有本地用户和公共用户生效。
比如说,在hrpdb中,grant select on hr.employees to PUBLIC,则意味着所有hrpdb中的公共或者本地用户可以查询hr.employees表。
在其他PDB则没有这个权限。
如果授权给PUBLIC的操作是公共的话,那么这个权限将会对所有用户生效,本地用户在他们的PDB里面有效,公共用户则在所有它可以访问的容器里都有效。
所以oracle建议用户不要公共授权给PUBLIC。
2.3.5,授权场景
在这个场景里,SYSTEM创建了一个公共用户c##dba,并且给这个用户访问hrpdb中hr模式下的一个表的权限。
显示了CONTAINER子句是怎么影响所有角色和权限的授权的。第一列显示的是CDB$ROOT里的操作,第二列是hrpdb里的操作。