Wednesday, May 23, 2007

在ORACLE数据库上创建VPD(Virtual Private Databases)安全策略的实战记录

在ORACLE数据库上创建VPD(Virtual Private Databases)安全策略的实战记录


作者:陈海青(joson chen)
网站:www.chq.name

日期:2007.05.24


版权声明:转载或引用本网版权所有之内容须注明“转自(或引自)chq.name (Junit fans)”字样,并标明本网站网址 http://www.chq.name


一、关于VPD
VPD,即:Virtual Private Database,提供了对数据库的精密访问控制(graind access
control (FGAC)).
使用VPD,可以在数据记录集定义用户的访问权限.


二、使用VPD的示例:


1)未进行权限控制时,执行的查询语句,可以看到所有商品在2002年的销售额:
SELECT year, prod_category,
sum(sales)
FROM sales_mv
WHERE year = '2002';


2)如果加上了VPD策略,限制访问指定范围内的产品(例如仅能访问'VIDEOS','RADIOS'),
再执行上述的查询语句,会自动加上限制条件--AND
prod_category in ('VIDEOS','RADIOS'),最后实际执行的语句为:


SELECT year, prod_category, sum(sales)
FROM sales_fact
WHERE year =
'2002'
AND prod_category in ('VIDEOS','RADIOS'); --自动加上的限制条件


三、操作的过程


以下为作者总结在ORACLE数据库上创建vpd(Virtual Private Databases),完成安全策略管理,并应用于www.chq.name上的实战记录,于070524更新完毕。


1:确定数据库对象及互相之间的关系
1)相关表和视图

数据库中有两类表,代码表和数据表,数据表均有一个“机构代码”字段(DM_JG),
其“前七位”等于用户代码表的“机构代码”

建立脚本:
CREATE TABLE dm_users
(
user_dm VARCHAR2(11) NOT
NULL,

jg_dm
VARCHAR2(11) NOT NULL
);

CREATE TABLE
DIM_JBXX
(pk VARCHAR2(50) NOT
NULL,
data VARCHAR2(11)
jg_dm
VARCHAR2(11) NOT NULL); --www.chq.name

CREATE VIEW
VIEW_JBXX as select * from DIM_JBXX
;


2)相关用户,并为其授权

相关用户有三个:

VPD:数据表和VPD对象的属主,允许访问全部数据;
1234502
:数据访问用户,其用户名为其单位代码的前7位,访问受限用户
建立脚本:

CONNECT sys/password@www.chq.name
AS SYSDBA;
CREATE USER VPD IDENTIFIED BY VPD

DEFAULT TABLESPACE VPD TEMPORARY TABLESPACE temp;
GRANT connect,
resource TO VPD;

CREATE USER 1234502 IDENTIFIED
BY 1234502
DEFAULT TABLESPACE users TEMPORARY TABLESPACE
temp;
GRANT connect, resource TO 1234502;



GRANT EXECUTE ON DBMS_RLS TO PUBLIC;


CONN VPD/VPD@www.chq.name


GRANT SELECT, INSERT ON V_JBXX TO 1234502, 1234512;


2:定义安全策略(Security Policies)的目标


在数据库里,每个用户分配一个机构代码,在这里直接使用该代码的前7位作为用户名,相关的数据表均有一个“机构代码”字段
安全策略目标:每个用户仅能浏览和操作“机构代码”与自己的机构代码相同的数据记录。
例外情况:vpd用户可以不受限制访问数据


3:创建应用环境(Application Context)

应用环境是一个包含系列环境变量名称和值的值对的集合,是存储用户的环境变量的空间;
系统提供了默认的环境USERENV,含有当前会话相关的默认的变量,如用户名、主机和应用程序名等


1)为创建VPD的context和context package的用户授权,
CONNECT sys/password@www.chq.name AS
SYSDBA;
GRANT create any context, create public synonym TO
VPD;
CONNECT VPD/VPD@www.chq.name;


2)创建应用环境 CTX_VPD_SEC
CREATE CONTEXT CTX_VPD_SEC USING
VPD.PKG_VPD_SEC;


4:创建VPD应用程序包,在包里增加设置环境变量的函数、存储过程

这个包的作用是提供设置环境变量的工具(函数或存储过程),供on login触发器或应用程序等调用。


1) 创建VPD应用程序包PKG_VPD_SEC的包头
CONNECT VPD/VPD@www.chq.name;

CREATE OR REPLACE PACKAGE VPD.PKG_VPD_SEC AS

PROCEDURE Set_Context;
END PKG_VPD_SEC;


2)创建VPD应用程序包的包体
CREATE OR REPLACE PACKAGE BODY
VPD.PKG_VPD_SEC IS
PROCEDURE Set_Context IS

lv_user VARCHAR2(11);
lv_jg_dm
VARCHAR2(11);
BEGIN

DBMS_Session.Set_Context('CTX_VPD_SEC','SETUP','TRUE');

v_ouser := SYS_CONTEXT('USERENV','SESSION_USER');

DBMS_Session.Set_Context('CTX_VPD_SEC','DM_USER',
lv_user);
BEGIN
SELECT
substr(JG_DM,1,7)
INTO
lv_jg_dm
FROM
dm_users
WHERE user_dm =
lv_user;

DBMS_Session.Set_Context('CTX_VPD_SEC','JG_DM', lv_jg_dm);

EXCEPTION
WHEN NO_DATA_FOUND
THEN

DBMS_Session.Set_Context('CTX_VPD_SEC','JG_DM',
substr(lv_user,1,7));
END;

DBMS_Session.Set_Context('CTX_VPD_SEC','SETUP','FALSE');
END
Set_Context;
END PKG_VPD_SEC;
/
SHOW ERRORS


3)授权其他用户可以访问并运行 PKG_VPD_SEC 包:
GRANT EXECUTE ON VPD.PKG_VPD_SEC TO
PUBLIC;
CREATE PUBLIC SYNONYM PKG_VPD_SEC FOR VPD.PKG_VPD_SEC;


4)建立用户登陆触发器,每次登录后首先设置自己的应用环境变量
CONNECT sys/password@www.chq.name AS
SYSDBA;
CREATE OR REPLACE TRIGGER VPD.Set_Security_Context
AFTER LOGON ON
DATABASE
BEGIN
VPD.PKG_VPD_SEC.Set_Context;
END;
/
SHOW
ERRORS


5:创建VPD应用程序-安全策略包,创建策略函数,为简便起见仍使用PKG_VPD_SEC

这是实现策略的函数,该函数从应用环境取得变量值,形成查询语句的一部分


1)建立安全策略( Security Policies)包的包头,简便起见修改PKG_VPD_SEC
--In order for the
context package to have any effect on the users interaction with the database,

--we need to define a Security_Package for use with the security policy.

--This package will tell the database how to treat any interactions with the
specified table:


CONNECT vpd/vpd @ www.chq.name;


CREATE OR REPLACE PACKAGE VPD.PKG_VPD_SEC AS
PROCEDURE
Set_Context;


FUNCTION User_Data_Insert_Security(Owner VARCHAR2, Objname
VARCHAR2)
RETURN VARCHAR2;

FUNCTION
User_Data_Select_Security(Owner VARCHAR2, Objname
VARCHAR2)
RETURN VARCHAR2;
END
Security_Package;
/
2)修改包体,增加安全策略函数:


CREATE OR REPLACE PACKAGE BODY Security_Package IS


PROCEDURE Set_Context IS
......
END
Set_Context;


FUNCTION User_Data_Select_Security(Owner VARCHAR2, Objname
VARCHAR2)RETURN VARCHAR2 IS
Predicate
VARCHAR2(2000);
BEGIN
Predicate :=
'1=2';
IF (SYS_CONTEXT('USERENV','SESSION_USER') = 'VPD')
THEN
Predicate := NULL;

ELSE
Predicate := 'JG_DM =
SYS_CONTEXT(''CTX_VPD_SEC'',''JG_DM'')';
END
IF;
RETURN Predicate;
END
User_Data_Select_Security;


FUNCTION User_Data_Insert_Security(Owner VARCHAR2, Objname VARCHAR2)
RETURN VARCHAR2 IS
Predicate VARCHAR2(2000);

BEGIN
Predicate := '1=2';
IF
(SYS_CONTEXT('USERENV','SESSION_USER') = 'VPD')
THEN
Predicate := NULL;

ELSE
Predicate := 'JG_DM =
SYS_CONTEXT(''CTX_VPD_SEC'',''JG_DM'')';
END
IF;
RETURN Predicate;
END
User_Data_Insert_Security;
END Security_Package;
/
SHOW
ERRORS
3)授权所有用户可以访问并运行安全策略包 PKG_VPD_SEC:


GRANT EXECUTE ON VPD.PKG_VPD_SEC TO PUBLIC;
--CREATE PUBLIC
SYNONYM PKG_VPD_SEC FOR VPD.PKG_VPD_SEC;


6:将策略函数应用到一个表或视图上
使用oracle
提供的DBMS_RLS包来实现安全策略的应用管理。
例如:
CONNECT VPD/VPD@www.chq.name;


BEGIN
DBMS_Rls.Add_Policy('VPD', 'VIEW_JBXX',
'USER_DATA_INSERT_POLICY',


'VPD',
'PKG_VPD_SEC.USER_DATA_INSERT_SECURITY',

'INSERT', TRUE);
DBMS_Rls.Add_Policy('VPD', 'VIEW_JBXX',
'USER_DATA_INSERT_POLICY',


'VPD',
'PKG_VPD_SEC.USER_DATA_INSERT_SECURITY',

'SELECT');

END;
或者:
execute
DBMS_RLS.ADD_POLICY(object_schema=>'VPD',object_name=>'V_FACT_data',policy_name=>'USER_DATA_INSERT_POLICY',

function_schema=>'VPD',policy_function=>'PKG_VPD_SEC.USER_DATA_INSERT_SECURITY',

statement_type=>'select',update_check=>FALSE,enable=>true)

)


注意事项:
1)DBMS_RLS包最初的运行权限须由sys用户授予VPD用户。
2)插入失败的报错信息:
ORA-28115:
policy with check option violation



参考资料:
1 : Oracle9i DBA Handbook ,Kevin Loney and Marlene Theriault ,etc, The McGraw-Hill co.Inc. 中文版:蒋蕊等译 机械工业出版社
2: http://www.oracle-base.com/articles/8i/VirtualPrivateDatabases.php
3:http://www.adp-gmbh.ch/ora/security/VPD/index.html
4:http://www.chq.name
5: http://xsb.itpub.net/post/419/59520
6: http://junit.vicp.net
7:http://zhouwf0726.itpub.net/post/9689/158056



Saturday, May 19, 2007

kettle2.3.1升级到2.5.0后 相关API的变化

kettle2.3.1升级到2.5.0后 相关API的变化
use kettle API under version 2.5.0
作者:陈海青(joson chen)
网站:http://www.chq.name/
日期:2007.05.13

版权声明:转载或引用本网版权所有之内容须注明“转自(或引自)chq.name (Junit fans)”字样,并标明本网站网址http://www.chq.name

1:需引入新的jar包:commons-vfs-1.0.jar
should import the new jar:commons-vfs-1.0.jar
2:使用oracle数据库时,构造TransMeta时,可以使用SchemaName参数,而不必在表名加SchemaName,已由www.chq.name使用oracle9i进行了测试.
when fill in TransMeta ,should use the parameter SchemaName,in 2.3.1,use tablename =SchemaName . tablename ,tested by http://www.chq.name/ on oracle9i.
3:使用新的构造方法StepMeta(fromstepid, fromstepname,(StepMetaInterface) tii) 代替原来的StepMeta(log,fromstepid, fromstepname,(StepMetaInterface) tii)。因为参数logging已经是单实例的,不必再作为参数传送了。
use new constructor method StepMeta(fromstepid, fromstepname,(StepMetaInterface) tii),delete the parameter log,for deprecated The logging is now a singlton, use the constructor without it.
4:将TableInputMeta原来的方法 setDatabase(targetDBInfo) 替换为 setDatabaseMeta(targetDBInfo),这个替换很生硬,使用原来的方法直接显示"未定义的方法".
in class TableInputMeta,use method "setDatabaseMeta(targetDBInfo)" replace the old one ,setDatabase(targetDBInfo),otherwise, compiler will report : The method setDatabase(DatabaseMeta) is undefined for the type TableInputMeta.