具体实施方式
1实施背景:假设现有一交换机监控系统,管理电信网络中的各程控交换机(SWITCH)。系统维护人员可以完成如下操作:
1.交换机状态查询(SWITCH.READ)
2.交换机启动及停止(SWITCH.OPER)
规定管理员(ADMIN)才能够进行查询及启停操作,而普通维护人员(ATTENDANT)仅能够查询交换机状态。在项目的建设中共有4台交换机需要被监控管理:SWITCH1,SWITCH2,SWITCH3,SWITCH4。依据地域的划分,系统将被江苏省公司(JIANGSU)、南京分公司(NANJING)、苏州分公司(SUZHOU)同时维护。其中SWITCH1、SWITCH2归南京分公司维护,SWITCH3、SWITCH4归苏州分公司维护,而省公司可以同时维护这四台交换机。依据部门的划分,规定网发部(DEP.NET)可以维护SWITCH1、SWITCH4,运维部(DEP.RUN)维护SWITCH2、SWITCH3。也就是说,省公司网发部可以对SWITCH1、SWITCH4进行操作,省公司运维部可以对SWITCH2、SWITCH3进行操作;南京分公司网发部可以对SWITCH1进行操作,南京分公司运维部可以对SWITCH2进行操作;苏州分公司网发部可以对SWITCH3进行操作,苏州分公司运维部可以对SWITCH4进行操作。
现使用本发明所使用模型实现上述访问控制各需求。
为实现上述访问控制需求,模型应实现如下几个功能域:
1.管理功能域(Administrative Functions):创建,管理模型中各元素集合及关系,以建立访问控制的多种组件;
2.支撑功能域(Supporting System Functions):实现访问控制模型功能,用于当用户与系统进行交互的时候插入访问控制逻辑;
3.检查功能域(Reviews Functions):检查管理功能的行为结果,包括查询、日志、统计等
在该示例中,我们就管理功能域和支撑功能域进行描述。
4.Administrative Functions:创建,管理元素集合及关系,以建立访问控制的多种组件;
5.Supporting System Functions:实现访问控制模型功能,用于当用户与系统进行交互的时候插入访问控制逻辑;
6.Reviews Functions:检查管理功能的行为结果,包括查询、日志、统计等Administrative Functions
首先应完成各概念的管理,包括各用户、角色等等记录的增删改查等功能,考虑使用数据库实现数据的存储,建表语句如下:
1.用户
CREATE TABLE TC_USER(
ID VARCHAR2(32)PRIMARY KEY,
NAME VARCHAR2(64),
PASSWORD VARCHAR2(32),
2.角色
CREATE TABLE TC_ROLE(
ID VARCHAR2(32)PRIMARY KEY,
TITLE VARCHAR2(64),
DESCRIPTION VARCHAR2(256),
VIRTUALROLEID VARCHAR2(32)
3.用户角色关联表
CREATE TABLE TC_USER_ROLE(
USERID VARCHAR2(32),
ROLEID VARCHAR2(32),
PRIMARY KEY(USERID,ROLEID)
4.虚拟角色
CREATE TABLE TC_VIRTUALROLE(
ID VARCHAR2(32)PRIMARY KEY,
TITLE VARCHAR2(64),
DESCRIPTION VARCHAR2(256)
5.权限
CREATE TABLE TC_PERMISSION(
ID VARCHAR2(32)PRIMARY KEY,
TITLE VARCHAR2(64)
6.虚拟角色权限关联表
CREATE TABLE TC_VROLE_PERMISSION(
VIRTUALROLEID VARCHAR2(32),
PERMISSIONID VARCHAR2(32),
PRIMARY KEY(VIRTUALROLEID,PERMISSIONID)
7.维度
CREATE TABLE TC_DIMENSION(
ID VARCHAR2(32)PRIMARY KEY,
NAME VARCHAR2(64),
TITLE VARCHAR2(64)
8.维度取值
CREATE TABLE TC_DIMENSIONVALUE(
ID VARCHAR2(32)PRIMARY KEY,
PARENTID VARCHAR2(32),
DIMENSIONID VARCHAR2(32),
TITLE VARCHAR2(64),
NAME VARCHAR2(32)
9.角色维度取值关联表
CREATE TABLE TC_ROLE_DIMENSIONVALUE(
ROLEID VARCHAR2(32),
DIMENSIONVALUEID VARCHAR2(32),
PRIMARY KEY(ROLEID,DIMENSIONVALUEID)
10.维度取值被管对象关联表
CREATE TABLE TC_DV_SO(
DVID VARCHAR2(32),
SOID VARCHAR2(32)
考虑到模型中SevuredObject概念来源于软件系统的各个数据实体,假设各数据实体在数据库中存在记录,可以使用数据库视图来完成SecuredObject的收集,比如系统中需要将交换机(Switch)和端口(PortCode)纳入访问控制,可建立如下视图:
CREATE OR REPLACE VIEW VC_SECUREDOBJECT(ENTITYID,TYPE,TITLE)AS(
SELECT ID,′SWITCH′,NAME FROM TC_SWITCH
UNION
SELECT ID,′PORTCODE′,PORTCODE FROM TC_PORTCODE
UNION
SELECT ID,TYPE,TITLE FROM TC_GENERALSO)
TC_GENELRALSO表为SecuredObject的存储提供了通用的解决方式,如果系统中数据实体没有相应数据表,可以将手动配置记录在该表中以纳入管理。CREATE TABLE TC_GENERALSO(
ID VARCHAR2(32)PRIMARY KEY,
TITLE VARCHAR2(64),
TYPE VARCHAR2(32))
Supporting System Functions
用户的授权信息得到记录之后,系统在运行时应完成对用户权限的判断,以实现访问控制模型的功能。可将发出业务操作请求的用户信息与系统中记录的授权信息进行匹配,如果发现请求在记录信息允许的范围之内,则通过;否则失败。
控制过程可分为操作控制和数据控制两步。
1.操作控制
用户请求的业务方法,其方法本身应该知道该方法使用什么Permission来控制用户的请求,因此应该业务方法应该承担起选取合适Permission记录的职责。并委托模型中提供的通用Authorizator完成对权限的判断。
2管理功能域实现
首先应完成模型中各元素的管理,包括各用户、角色、虚拟角色、权限、维度、维度取值等要素记录的增删改查等功能。
2.1类设计
下面给出管理功能域的类设计。类共分为三种,实体类、管理类和数据访问类。实体类为模型中的各个要素;管理类实现了对这些实体类的查询、修改等管理操作,依据其分管范围的不同,管理类罗列如下:
1.UserManager:管理用户的增删改查,管理用户和角色之间的关系分配
2.RoleManager:管理角色的增删改查,管理角色和虚拟角色、角色和维度取值之间的关系分配
3.PermissionManager:管理权限的读取、虚拟角色的增删改查,管理虚拟角色和权限之间的关系分配
4.DimensionManager:管理SecuredObject的查询、管理维度、维度取值的增删改查,管理SecuredObject和维度取值之间的关系分配。
各管理类将数据库原子操作委托给数据访问类实现,这里我们将其称为DAO(数据访问对象)。管理类关注于面向模型的业务操作,并统一协调数据库事务处理。而各DAO关心某一种数据实体的数据库操作,在该示例中以接口形式描述,具体实现可以采用JDBC、ORMapping等方式,由于和本发明没有直接关系,这里不再赘述。
下面以UML类图的方式给出管理功能域相关类的静态设计:
1.图2是用户及用户管理类UML类图
2.图3是角色、虚拟角色及角色管理类UML类图
3.图4是权限及权限管理类图
4.图5是维度、维度取值、SecuredObject及维度管理类
以上各类实现了模型中管理功能域的核心功能,客户端代码可以通过调用各Manager类实现对模型中各要素的查询及修改。同时管理功能域也是支撑功能域的基础,为运行时访问控制提供基本的数据支持。
2.2数据库设计
使用数据库实现模型中各元素的存储,另下面描述的各表中的记录均可以通过客户端代码调用管理功能域提供的API生成。建表语句如下:
1.用户表:记录系统中所有用户
CREATE TABLE TC_USER(
ID VARCHAR2(32)PRIMARY KEY,
NAME VARCHAR2(64),
PASSWORD VARCHAR2(32),
2.角色表:记录系统中所有角色
CREATE TABLE TC_ROLE(
ID VARCHAR2(32)PRIMARY KEY,
TITLE VARCHAR2(64),
DESCRIPTION VARCHAR2(256),
VIRTUALROLEID VARCHAR2(32))
在该示例中角色表应该存在如下各记录:
ID |
TITLE |
DESCRIPTION |
VIRTUALROLEID |
JIANGSU_NET_ADMIN |
江苏网发部管理员 | |
ADMIN |
JIANGSU_NET_ATTENDANT |
江苏网发部维护人员 | |
ATTENDANT |
JIANGSU_RUN_ADMIN |
江苏运维部管理员 | |
ADMIN |
JIANGSU_RUN_ATTENDANT |
江苏运维部维护人员 | |
ATTENDANT |
NANJING_NET_ADMIN |
南京网发部管理员 | |
ADMIN |
NANJING_NET_ATTENDANT |
南京网发部维护人员 | |
ATTENDANT |
NANJING_RUN_ADMIN |
南京运维部管理员 | |
ADMIN |
NANJING_RUN_ATTENDANT |
南京运维部维护人员 | |
ATTENDANT |
SUZHOU_NET_ADMIN |
苏州网发部管理员 | |
ADMIN |
SUZHOU_NET_ATTENDANT |
苏州网发部维护人员 | |
ATTENDANT |
SUZHOU_RUN_ADMIN |
苏州运维部管理员 | |
ADMIN |
SUZHOU_RUN_ATTENDANT |
苏州运维部维护人员 | |
ATTENDANT |
3.用户角色关联表:记录用户和角色之间多对多的关联关系
CREATE TABLE TC_USER_ROLE(
USERID VARCHAR2(32),
ROLEID VARCHAR2(32),
PRIMARY KEY(USERID,ROLEID)
4.虚拟角色表:记录系统中所有虚拟角色
CREATE TABLE TC_VIRTUALROLE(
ID VARCHAR2(32)PRIMARY KEY,
TITLE VARCHAR2(64),
DESCRIPTION VARCHAR2(256)
在该示例中虚拟角色应该存在如下各记录:
ID |
TITLE |
DESCRIPTION |
ADMIN |
管理员 |
具有所有操作权限 |
ATTENDANT |
维护人员 |
具有查看权限 |
5.权限表:记录系统中所有权限点
CREATE TABLE TC_PERMISSION(
ID VARCHAR2(32)PRIMARY KEY,
TITLE VARCHAR2(64))
在该示例中权限表应该存在如下各记录:
SWITCH.READ |
查询交换机状态 | |
SWITCH.OPER |
对交换机启停 | |
6.虚拟角色权限关联表:记录系统中虚拟角色和权限点之间多对多的联系
CREATE TABLE TC_VROLE_PERMISSION(
VIRTUALROLEID VARCHAR2(32),
PERMISSIONID VARCHAR2(32),
PRIMARY KEY(VIRTUALROLEID,PERMISSIONID)
在该示例中虚拟角色权限关联表应该存在如下各记录:
VIRTUALROLEID |
PERMISSIONID | |
ADMIN |
SWITCH.READ | |
ADMIN |
SWITCH.OPER | |
ATTENDANT |
SWITCH.READ | |
7.维度表:记录系统中所有维度
CREATE TABLE TC_DIMENSION(
ID VARCHAR2(32)PRIMARY KEY,
NAME VARCHAR2(64),
TITLE VARCHAR2(64)
在该示例中维度表应该存在如下各记录:
ID |
TITLE | |
DOMAIN |
地域 | |
DEPART |
部门 | |
8.维度取值表:记录系统中所有维度取值
CREATE TABLE TC_DIMENSIONVALUE(
ID VARCHAR2(32)PRIMARY KEY,
PARENTID VARCHAR2(32),
DIMENSIONID VARCHAR2(32),
TITLE VARCHAR2(64),
NAME VARCHAR2(32)
在该示例中维度取值表应该存在如下各记录:
ID |
PARENTID |
DIMENSIONID |
TITIE |
NAME |
JIANGSU | |
DOMAIN |
江苏 |
JIANGSU |
NANJING |
JIANGSU |
DOMAIN |
南京 |
NANJING |
SUZHOU |
JIANGSU |
DOMAIN |
苏州 |
SUZHOU |
NET | |
DEPART |
网发部 |
NET |
9.角色维度取值关联表:记录系统中角色与维度取值之间的多对多的关联关系
CREATE TABLE TC_ROLE_DIMENSIONVALUE(
ROLEID VARCHAR2(32),
DIMENSIONVALUEID VARCHAR2(32),
PRIMARY KEY(ROLEID,DIMENSIONVALUEID)
在该示例中角色维度取值关联表应该存在如下各记录:
ROLEID |
DIMENSIONVALUEID | |
JIANGSU_NET_ADMIN |
JIANGSU | |
JIANGSU_NET_ADMIN |
NET | |
JIANGSU_NET_ATTENDANT |
JIANGSU | |
JIANGSU_NET_ATTENDANT |
NET | |
JIANGSU_RUN_ADMIN |
JIANGSU | |
JIANGSU_RUN_ADMIN |
RUN | |
JIANGSU_RUN_ATTENDANT |
JIANGSU | |
JIANGSU_RUN_ATTENDANT |
RUN | |
NANJING_NET_ADMIN |
NANJING | |
NANJING_NET_ADMIN |
NET | |
NANJING_NET_ATTENDANT |
NANJING | |
NANJING_NET_ATTENDANT |
NET | |
NANJING_RUN_ADMIN |
NANJING | |
NANJING_RUN_ADMIN |
RUN | |
NANJING_RUN_ATTENDANT |
NANJING | |
NANJING_RUN_ATTENDANT |
RUN | |
SUZHOU_NET_ADMIN |
SUZHOU | |
SUZHOU_NET_ADMIN |
NET | |
SUZHOU_NET_ATTENDANT |
SUZHOU | |
SUZHOU_NET_ATTENDANT |
NET | |
SUZHOU_RUN_ADMIN |
SUZHOU | |
SUZHOU_RUN_ADMIN |
RUN | |
SUZHOU_RUN_ATTENDANT |
SUZHOU | |
SUZHOU_RUN_ATTENDANT |
RUN | |
10.安全管理对象视图:记录系统中所有受访问控制模块管理的被管理对象
考虑到模型中SecuredObject概念来源于软件系统的各个被管理对象,假设各对象在数据库中存在记录,可以使用数据库视图来完成SecuredObject的收集,比如系统中需要将交换机(SWITCH)纳入访问控制,可建立如下视图:
CREATE OR REPLACE VIEW VC_SECUREDOBJECT(ENTITYID,TYPE,TITLE)AS(
SELECT ID,′SWITCH′,TITLE FROM TC_SWITCH
UNION
SELECT ID,TYPE,TITLE FROM TC_GENERALSO
)
CREATE TABLE TC_SWITCH(
ID VARCHAR2(32)PRIMARY KEY,
TITLE VARCHAR2(64),
)
CREATE TABLE TC_GENERALSO(
ID VARCHAR2(32)PRIMARY KEY,
TITLE VARCHAR2(64),
TYPE VARCHAR2(32))
ENTITYID代表系统中该被管理对象的唯一标识;TYPE代表该对象的类型,在这里我们把所有交换机类型对象的类型定义为“SWITCH”;TITLE为其可识别的名字。
TC_GENELRALSO表为SecuredObject的存储提供了通用的解决方式,如果系统中被管理对象没有象交换机那样拥有自己独立的数据表,可以将其记录配置在该表中以纳入管理。注意需要为对象定义合适的类型。
这里我们将交换机信息配置在TC_SWITCH表中,记录如下:
ID |
TITLE | |
SWITCH1 |
交换机1 | |
SWITCH2 |
交换机2 | |
SWITCH3 |
交换机3 | |
SWITCH4 |
交换机4 | |
则视图VC_SECUREDOBJECT中记录为:
ENTITYID |
TYPE |
TITLE |
SWITCH1 |
SWITCH |
交换机1 |
SWITCH2 |
SWITCH |
交换机2 |
SWITCH3 |
SWITCH |
交换机3 |
SWITCH4 |
SWITCH |
交换机4 |
在该示例中TC_GENERALSO表中不需要配置任何数据。
11.维度取值被管对象关联表:记录系统中维度取值与被管理对象之间多对多的关联关系
CREATE TABLE TC_DV_SO(
DVID VARCHAR2(32),
SOID VARCHAR2(32)
在该示例中维度取值被管对象关联表应该存在如下各记录:
DVID |
SOID | |
JIANGSU |
SWITCH1 | |
JIANGSU |
SWITCH2 | |
JIANGSU |
SWITCH3 | |
JIANGSU |
SWITCH4 | |
NANJING |
SWITCH1 | |
NANJING |
SWITCH2 | |
SUZHOU |
SWITCH3 | |
SUZHOU |
SWITCH4 | |
NET |
SWITCH1 | |
NET |
SWITCH4 | |
RUN |
SWITCH2 | |
RUN |
SWITCH3 | |
3支撑功能域实现
用户的授权信息得到记录之后,系统在运行时应完成对用户权限的判断,以实现访问控制模型的功能。我们将这样的功能称为支撑功能域。
在本示例的实现中,我们期望将访问控制介入的逻辑剥离于核心业务逻辑之外,即核心业务逻辑不必关心权限这么一件事。可以通过代理模式实现该目的。类图如图6所示:说明:
1.接口ISwitchService描述了系统提供的业务功能:交换机状态查询(read方法)、交换机启动(start方法)和交换机停止(stop方法)
2.类SwitchManager实现这三个业务方法的逻辑
3.SwitchService织入访问控制逻辑
控制过程可分为操作权限控制和数据权限控制两步。
3.1操作权限控制
SwitchService实现操作权限控制逻辑织入的原理是:对每个需要控制的业务方法进行包装,在执行真正的业务方法之前,根据上下文环境获取调用该用户的身份信息,并根据该业务方法所绑定的权限点进行查找匹配,如果该用户与该权限点具有关联关系,则认为通过操作权限的控制,否则应该抛出权限异常。
这里需要注意的是,用户请求的业务方法,其方法本身应该知道该方法使用什么Permission来控制用户的请求。因此,业务方法应该承担起选取合适Permission记录的职责。
操作权限查找匹配的详细过程由Authorizator组件封装,SwitchService只需收集用户和权限信息,将控制逻辑委托给Authorizator即可。流程如图7所示:
以start()方法为例,典型的SwitchService伪代码如下:
public void start()throws Exception{
User user=getUserFromContext();
String permissionId="SWITCH.OPER";
try{
authrizator.hasOperationPermission(user,permissionId);
}catch(PermissionDeniedException e){
throw e;
switchManager.start();
Authorizator实现权限控制的具体方法为获取该用户所有角色,并根据角色获取对应的虚拟角色,虚拟角色记录了权限信息,如果在虚拟角色集中最终找到了对应Permission,认为该用户具有该操作权限。伪代码如下:
public void hasOperationPermission(User user,String permissionId)<br/>
throws PermissionDeniedException{
Set roles=user.getRoles();
for(Iterator iter=roles.iterator();iter.hasNext();){
Role role=(Role)iter.next();
Set permissionSet=role.getVirtualRole().getPermissions();
if(permissionSet==null)
continue;
for(Iterator iterl=permissionSet.iterator();iterl.hasNext();)<br/>
{
Permission element=(Permission)iterl.next();
if(element.getId().equals(permissionId))
return;
throw new PermissionDeniedException(user,permissionId);
3.2数据权限控制
数据控制同样可以通过包装业务方法来实现。比如当用户请求查询某些被管理对象的时候,可以考虑使用过滤器来将用户不具有数据权限的对象过滤掉:
过滤器应该由各业务模块自行实现,具体流程可以是获取该用户所有角色,判断角色下的DimensionValue的集合,就可以得到SecuredObject的集合,使用该集合作为过滤的依据,在过滤过程中应该注意在同一Dimension下各DimensionValue之间,应该对SecuredObject取并集,在不同Dimension下应该取交集。
对于那些非查询类的业务操作,可以通过类似的匹配方法,判断该用户是否具有对相关对象的权限。匹配的详细过程可以委托给DataAuthorizator实现。
以read方法为例,典型的SwitchService的伪代码如下:
public SwitchStatus read(Switch switch)throws Exception{
User user=getUserFromContext();
String securedObjectType="SWITCH";
try{
dataAuthorizator.hasDataPermission(user,switchId,securedObjectType);
}catch(PermissionDeniedException e){
throw e;return switchManager.read(switch);
dataAuthorizator伪代码如下:
public void hasDataPermission(User user,String soId,String soType)throws
PemissionDeniedException{
Set securedObjectsUnderUser=
dimensionManager.getSecuredObjectsUnderUser(user,soType);
可以看出,DimensionManager封装了获取用户名下所有安全管理对象的逻辑,由于用户可以同时具有一个或多个角色,因此,用户名下所有安全管理对象应该是各角色下安全管理对象的并集。
为了求出某一个角色下所有该类型的被管理对象的集合,必须先将该角色下所有维度取值按照其维度类型进行分组。求出每个维度取值下关联的被管理对象,同组间先取并集,然后各组间取交集。最终得到被管对象集合。