上传brook.tar
tar zvf brook.tar 解压到/usr_projects/domains/mydomain/
有以下目录
brook-lib
brook-web-lib
bin
doc
conf
拷贝brook-web-lib中的jar到WEB-INF/lib下
可选:将setBrookEnv.sh 拷贝到 WLS_HOME/common/bin目录下,并修改其中BROOK_LIB环境变量
修改startWebLogic.sh,增加运行 setBrookEnv.sh(用于设置将brook2自身的jar包到app server的classpath中)
. /opt/bea/user_projects/domains/mydomain/brook/bin/setBrookEnv.sh
修改brook-lib/log4j.properties的日志级别和log4j.debug=false
可选(目前打包的时候已经拷贝):拷贝conf/brook-advice.properties到BROOK_LIB下
拷贝conf/brook.properties到WEB-INF下,修改其中showSession和excludePattern
修改web.xml,增加IdentityContextFilter
注意:被修改的weblogic和app的原文件需要备份(startWebLogic.sh 和web.xml),以便万一安装失败能恢复原来的文件
然后在console中
增加一个DataSource:
DriverName:com.mchz.brook.jdbc.proxy.DriverLoggingProxy
URL:jdbc:jdbcdslog:oracle:thin:@172.16.4.37:1521:xe;targetDriver=oracle.jdbc.OracleDriver
dump session信息,查看后修改sessionProperties
全部弄好后把log4j的日志级别调整为warning
<!--[if !supportLists]-->1. <!--[endif]-->对一个数据源的测试
<!--[if !supportLists]-->a) <!--[endif]-->测试环境搭建
<!--[if !supportLists]--> i. <!--[endif]-->Weblogic 8
<!--[if !supportLists]--> ii. <!--[endif]-->部署测试程序 brook-selenium2,直接点击界面上就可以测试
<!--[if !supportLists]-->2. <!--[endif]-->对多个数据源的测试(开发中已经测试过2个数据源的情况)
<!--[if !supportLists]-->a) <!--[endif]-->测试环境搭建
<!--[if !supportLists]--> i. <!--[endif]-->Weblogic 8,部署测试webapp和终端身份组件
<!--[if !supportLists]--> ii. <!--[endif]-->Oracle database 并且要在其中建一张test表,里面就一个id字段number类型
<!--[if !supportLists]--> iii. <!--[endif]-->安装setclientinfo存储过程
<!--[if !supportLists]--> iv. <!--[endif]-->
终端身份原理和文档
原理简述:自己实现了自定义的驱动程序,在目标应用上使用这个自定义的驱动建立DataSource,并配置目标应用使用新定义的DataSource
目标应用请求JDBC连接的时候,返回的是自定义的JDBC Connection,当发出SQL语句的时候,自定义驱动会先发出一条plsql存储过程的调用,把web端传过来的终端身份信息,传递到数据库中,然后在发出目标应用的sql语句,这样数据库就知道这条sql语句是从哪个终端发出的了。
Web前端就是一个Filter,拦截所有需要的URL请求,然后把终端信息,例如IP地址等获取出来,放到ThreadLocal的IdentityContext中,这样自定义驱动就能通过ThreadLocal获取到终端信息了。也可以通过配置,把需要的Session信息获取出来,不过这个需要一些尝试。在系统运行的时候,把session信息dump出来,然后挑选正确的key,配置到终端身份的配置信息中。如果无法获取key,是无法获取相应的值的。
对反向代理的支持。很多应用都采用了这样的架构:前段通过F5或者Radware这样的硬件,或者Haproxy这样的软件代理服务器,把http请求转发给后端的应用服务器集群,例如多个weblogic实例(各个weblogic并不相关,不是weblogic自身的集群)。在这样的情况下,如果不做其他的改动,Web端取到的终端IP是代理服务器的IP地址,而不是终端浏览器的IP地址。现在很多代理服务器(比如F5)都支持在转发HTTP请求的时候,在HTTP header中增加一个X-Forward-For头,把真正的HTTP请求的IP转发过来。通过在Web Filter中对这个字段进行检测,就能取到真正的HTTP请求的终端地址。但是,需要在F5或者其他代理服务器中打开对X-Forward-For的支持。
<!--[if !supportLineBreakNewLine]-->
<!--[endif]-->
对集群的支持。由于中间件部署方式有很多变化,需要在实施的时候也做相应的改变。
单个实例的情况是最简单的,只要部署好之后重启就可以了。
对于集群的情况,则需要滚动安装。也即:先停集群中一个中间件实例,安装部署,然后再加入回集群,依次进行直到所有的中间件实例上都安装完毕。
Oracle端:
Oracle中的v$session视图中,有所有当前连接到数据库的session信息。其中有两个字段client_identifier是用来表明终端信息的。在Oracle的JDBC驱动中(OracleConnection),提供了传递终端信息的API
SetEndToEndMetrics,但是此API只能针对Oracle 10及其以上版本才能生效。对于Oracle 9数据库,技术服务部提供了setclientinfo这个存储过程能够代替此API。
根据技术服务部门提供的信息,要让CAPAA能审计到终端的信息,无论是9i还是10g都必须调用setclientinfo这个存储过程,否则CAPAA无法审计到终端信息。
SVN http://svn.mchz.com.cn/svn/brook2
下面有三个工程
<!--[if !supportLists]-->1. <!--[endif]-->brook2-core:实现了自定义的jdbc驱动程序。目前此工程的编译并导出jar文件,是用了eclipse的export功能,今后需要写一个ant脚本来脱离ide的耦合。编译需要用jdk1.4的标准,因为客户大量使用的weblogic 816版本,是用jdk1.4的,否则会导致客户生产端报class文件版本不正确的错误而无法启动。代码中包含部分jmx的内容,目前尚未应用到实际生产环境中,如果编译时产生相关的编译错误,可以暂时先删除相应的代码。相应目录说明:
<!--[if !supportLists]-->a) <!--[endif]-->src目录:源代码
<!--[if !supportLists]-->b) <!--[endif]-->lib目录:依赖包
<!--[if !supportLists]-->c) <!--[endif]-->script目录:
<!--[if !supportLists]--> i. <!--[endif]-->setBrookEnv.sh Unix/Linux下,需要加入到weblogic启动脚本(startWeblogic.sh)中运行的配置脚本
<!--[if !supportLists]--> ii. <!--[endif]-->setBrookEvn.bat Windows平台下,需要加入到weblogic启动脚本(startWeblogic.sh)中运行的配置脚本
<!--[if !supportLists]--> iii. <!--[endif]-->setclientinfo.sql 需要在生产库端运行的plsql初始化脚本,会创建一个终端身份需要调用的plsql存储过程
<!--[if !supportLists]-->d) <!--[endif]-->doc目录:文档目录
<!--[if !supportLists]--> i. <!--[endif]-->deploy.txt 实施文档,包含简要的实施步骤
<!--[if !supportLists]--> ii. <!--[endif]-->history.txt 实施历史文档
<!--[if !supportLists]--> iii. <!--[endif]-->todo.txt 需要改进的todolist
<!--[if !supportLists]-->2. <!--[endif]-->brook2-web:实现了web端获取终端信息的filter,需要加载到第三方应用的web.xml文件中。目前此工程的编译并导出jar文件,是用了eclipse的export功能,今后需要写一个ant脚本来脱离ide的耦合。相应目录说明:
<!--[if !supportLists]-->a) <!--[endif]-->src目录:源代码
<!--[if !supportLists]-->b) <!--[endif]-->lib目录:依赖包
<!--[if !supportLists]-->3. <!--[endif]-->brook2-selenium:测试程序,部署好中间件和数据库之后,能够测试是否生效。项目在checkout 到eclipse之后,需要配置一些src目录到main/java,否则eclipse会报java源代码路径和package不匹配。build的时候,需要将brook2-core和brook2-web两个工程生成的jar包,放到此工程的lib目录下,然后运行ant脚本。相应目录说明
<!--[if !supportLists]-->a) <!--[endif]-->src/main/java目录:源代码
<!--[if !supportLists]-->b) <!--[endif]-->src/main/resource目录:资源目录
<!--[if !supportLists]--> i. <!--[endif]-->brook-advice.properties 终端身份的配置文件
<!--[if !supportLists]--> ii. <!--[endif]-->jdbc.properties jdbc连接配置
<!--[if !supportLists]--> iii. <!--[endif]-->log4j.properties 日志配置
<!--[if !supportLists]-->c) <!--[endif]-->src/main/webapp目录:brook2-selenium包含的webapp的文件和资源
brook2-selenium中需要应用brook2-core和brook2-core中生成的jar包
brook2-web需要引用brook2-core的jar包,或者在eclipse中指定项目的依赖关系
需要用JDK 1.4的编译器编译,或者在build.xml中指定。
代码解析:
实施详细文档:
上传brook.tar文件
在weblogic的domain目录下解压此压缩文件,生成一个brook目录。
目录结构:
bin:
设置brookclasspath的启动脚本,需要在启动weblogic domain的startWebLogic.sh中执行
setBrookEnv.sh (linux环境下)
setBrookEnv.bat (windows环境下)
brook-lib:
brook需要的jar包,在setBrookEnv脚本中加入到weblogic的classpath中
brook-web-lib:
需要拷贝到webapp的WEB-INF/lib目录下的jar包
conf:
配置文件
brook.properties 此文件需要拷贝到WEB-INF目录下
web.xml里面有设置filter的范例
doc:
deploy.txt 部署文档
修改setBrookEnv.sh,把其中的路径修改成当前正确的路径,主要是修改BROOK_LIB环境变量,把他指定到brook-lib的目录
修改startWebLogic.sh,在启动过程中执行setBrookEnv.sh,增加这一行
. /opt/bea/alfredxu/user_projects/domains/alfredxu/brook/bin/setBrookEnv.sh
把brook/brook-web-lib下的jar包拷贝到webapp下的WEB-INF/lib目录下
把conf/brook.properties拷贝到webapp下的WEB-INF目录下
修改webapp的web.xml文件,增加如下的filter配置
<filter>
<filter-name>brook</filter-name>
<filter-class>com.mchz.brook.web.filter.IdentityFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>brook</filter-name>
<url-pattern>*.do</url-pattern>
</filter-mapping>
其中filter-mapping中的url-pattern需要根据应用的情况来具体配置,有些应用的请求,不一定是.do结尾的
重启weblogic,让brook的jar生效。
配置brook用的连接池。在weblogic的console中,根据webapp使用的连接池,配置一个brook用的新连接池。
<!--[if gte vml 1]><v:shapetype id="_x0000_t75" coordsize="21600,21600" o:spt="75" o:preferrelative="t" path="m@4@5l@4@11@9@11@9@5xe" filled="f" stroked="f"> <v:stroke joinstyle="miter" /> <v:formulas> <v:f eqn="if lineDrawn pixelLineWidth 0" /> <v:f eqn="sum @0 1 0" /> <v:f eqn="sum 0 0 @1" /> <v:f eqn="prod @2 1 2" /> <v:f eqn="prod @3 21600 pixelWidth" /> <v:f eqn="prod @3 21600 pixelHeight" /> <v:f eqn="sum @0 0 1" /> <v:f eqn="prod @6 1 2" /> <v:f eqn="prod @7 21600 pixelWidth" /> <v:f eqn="sum @8 21600 0" /> <v:f eqn="prod @7 21600 pixelHeight" /> <v:f eqn="sum @10 21600 0" /> </v:formulas> <v:path o:extrusionok="f" gradientshapeok="t" o:connecttype="rect" /> <o:lock v:ext="edit" aspectratio="t" /> </v:shapetype><v:shape id="_x0000_i1027" type="#_x0000_t75" style='width:414.75pt; height:259.5pt'> <v:imagedata src="file:///C:\Users\hua\AppData\Local\Temp\msohtmlclip1\01\clip_image001.png" o:title="" /> </v:shape><![endif]--><!--[if !vml]--><!--[endif]-->
<!--[if gte vml 1]><v:shape id="_x0000_i1025" type="#_x0000_t75" style='width:414.75pt;height:259.5pt'> <v:imagedata src="file:///C:\Users\hua\AppData\Local\Temp\msohtmlclip1\01\clip_image003.png" o:title="" /> </v:shape><![endif]--><!--[if !vml]--><!--[endif]-->
然后把webapp使用的JNDI引用的连接池改为brook新配置的连接池
<!--[if gte vml 1]><v:shape id="_x0000_i1026" type="#_x0000_t75" style='width:414.75pt;height:259.5pt'> <v:imagedata src="file:///C:\Users\hua\AppData\Local\Temp\msohtmlclip1\01\clip_image005.png" o:title="" /> </v:shape><![endif]--><!--[if !vml]--><!--[endif]-->
重启weblogic,让webapp使用新的连接池。此时日志里面应该会显示新连接池初始化的日志信息。类似如下显示。
11:29:52,449 INFO ConnectionLogger:45 - connect to URL jdbc:jdbcdslog:oracle:thin:@172.16.4.37:1521:xe;targetDriver=oracle.jdbc.OracleDriver with properties: {user=asset, password=asset, v$session.program=brook}
11:29:52,449 DEBUG DriverLoggingProxy:54 - s = jdbc
11:29:52,449 DEBUG DriverLoggingProxy:54 - s = oracle
11:29:52,449 DEBUG DriverLoggingProxy:54 - s = thin
11:29:52,450 DEBUG DriverLoggingProxy:54 - s = @172.16.4.37
11:29:52,450 DEBUG DriverLoggingProxy:54 - s = 1521
11:29:52,450 DEBUG DriverLoggingProxy:54 - s = xe
11:29:52,450 DEBUG DriverLoggingProxy:54 - s = targetDriver
11:29:52,450 INFO DriverLoggingProxy:67 - connecting to database
11:29:52,451 INFO ConnectionLogger:45 - connect to URL jdbc:oracle:thin:@172.16.4.37:1521:xe with properties: {user=asset, v$session.terminal=spring, password=asset, v$session.program=veronica}
如何卸载
在console中将webapp使用的JNDI引用的连接池改为原来的连接池。
将web.xml中加入的filter去掉或者注释掉
将startWebLogic.sh中执行的setBrookEnv.sh那行去掉或者注释掉
重启weblogic
如何验证安装成功:
连接生产库,查询v$session表格中的client_identifier字段,看有没有相应的终端信息
查看CAPAA的访问审计,查看终端信息这个字段有没有终端IP
查看weblogic日志输出,在用户请求发出某条sql语句的时候,会有类似输出
16:44:29,719 INFO GenericLoggingProxy:54 - ==== need to set brook createStatement====
16:44:29,719 DEBUG ConnectionAdviceImpl:39 - in connection advice: connection advice ,target class:class oracle.jdbc.driver.T4CConnection
16:44:29,719 DEBUG AttachStrategy:42 - identity context is: com.mchz.brook.web.IdentityContext@11c8258[sessionId=GM9LPLbFQ2jtwFpJmRQh2Q3yP4hfnmGhJ3ZCMsRDV7WFnkCrQnhL!-1799731374!1334565869408,username=<null>,ip=172.16.4.100,host=172.16.4.100,etc={"etc":com.mchz.brook.web.IdentityContext@11c8258[sessionId=GM9LPLbFQ2jtwFpJmRQh2Q3yP4hfnmGhJ3ZCMsRDV7WFnkCrQnhL!-1799731374!1334565869408,username=<null>,ip=172.16.4.100,host=172.16.4.100,etc=<null>,action=<null>,module=<null>,sessionProperties={},ignored=false,accessTime=Mon Apr 16 16:44:29 CST 2012]},action=1334565869605,module=<null>,sessionProperties={},ignored=false,accessTime=Mon Apr 16 16:44:29 CST 2012]
16:44:29,720 DEBUG NormalAttachStrategy:25 - using normal attach strategy, need to attach: true
16:44:29,720 DEBUG IdentityContextStrategyStoreProcImpl:25 - call SetClientinfo(?,?,?,?) parameter: ip:172.16.4.100,{}, null, null, 1334565869605
16:44:29,733 DEBUG LogUtils:31 - createLogEntry()
16:44:29,733 INFO StatementLogger:53 - java.sql.Statement.executeQuery select * from v$session where action = '1334565869605' 12 ms.
注意:由于Oracle的关系,clientclientinfo这个存储过程中的
create or replace
procedure SetClientinfo(v_clientidentifier varchar2,v_clientinfo varchar2,v_module varchar2,v_action varchar2) is
l_sid Number;
l_ip varchar2(64);
l_session_info varchar2(4000);
begin
--dbms_session.set_identifier(v_clientidentifier);
dbms_application_info.set_client_info(v_clientinfo);
dbms_application_info.set_module(v_module,v_action);
select substr(v_clientidentifier,4,instr(substr(v_clientidentifier,3),',')-2),
substr(substr(v_clientidentifier,instr(substr(v_clientidentifier,3),',')+3),1,1000)
into l_ip,l_session_info from dual;
Tlgctxpkg.SetContext('end_ip',l_ip);
Tlgctxpkg.SetContext('end_session_info',l_session_info);
exception
when others then
null;
end SetClientinfo;
--dbms_session.set_identifier(v_clientidentifier);
这行代码,当需要在v$session中查看client_identifier的时候,需要注释掉,但是这个时候在client_identifier就无法被注入到访问审计中。终端信息在访问审计和v$session两者之间只能生效一个。
配置说明:
brook.properties
# session key properties format: sessionkey:beanpath:connkey,
excludePattern=.*.js|.*.css
sessionProperties=userinfo:username:username
showSessionEnabled=true
<!--[if !supportLineBreakNewLine]-->
<!--[endif]-->
excludePattern 指定哪些URL请求不需要注入终端身份,一般来说静态文件,js, css等不需要注入,可以优化性能
sessionProperties 指定那个session key对应的object的属性要被注入到终端身份中
showSessionEnabled 是否需要在终端输出中导出session信息,正式部署之后,推荐设置为false
brook-lib/brook-advice.properties
#brook global config
brook.attachStrategy=normal
#brook aspect config
#brook driver aspect config
brook.aspect.driver.enabled=true
brook.aspect.driver.v$session.program=veronica
brook.aspect.driver.v$session.terminal=spring
#brook connection aspect config
brook.aspect.connection.oracle.version=9
brook.aspect.connection.enabled=true
#sqllog aspect config
brook.aspect.sqllog.enabled=false
brook.aspect.sqllog.id=1
brook.rule.log.1=1;127.0..*;.*;.*;.*;log
brook.attachStrategy=normal 设置终端身份信息的策略,一般推荐为normal
brook.aspect.driver.enabled=true
是否设置driver级别的信息,如下:
brook.aspect.driver.v$session.program=veronica
brook.aspect.driver.v$session.terminal=spring
v$session中对应的program和terminal字段的值,可以用来帮助判断session是否是brook增强过的
brook.aspect.connection.oracle.version=9 重要,目前必须设置9才生效,即使是oracle 10的版本。因为目前就算是oracle 10版本通过setEndToEndMetrics调用设置终端信息,由于后台存储过程无法获取通过这种方式设置的终端信息,所以必须用oracle 9版本的通过调用setclientidentifier存储过程来设置
brook.aspect.connection.enabled=true是否设置connection级别的增强,即client_identifier
以下配置已经废弃,不推荐修改
brook.aspect.sqllog.enabled=false
brook.aspect.sqllog.id=1
brook.rule.log.1=1;127.0..*;.*;.*;.*;log
打包,各文件说明