2009年9月20日星期日

ADF_035:ADF高级开发 之二:为ADF Web应用增加安全

运行环境:JDeveloper 11.1.2.1.0 + Oracle Database 10g Express Edition 10.2.0.1。
完成《Enable Security in a Fusion Web Application》。

本实验需要使用FOD Schema,请参考《发布与运行 Oracle Fusion Order Demo》。

关于ADF Security的原理介绍,请参考《ADF Security 介绍》。

重要步骤说明:

1. 创建ADF Web应用
这里使用了两个以前没有使用过的组件:Output Text(Formatted)和Navigation List。
Output Text(Formatted)与普通Output Text组件的区别是文本内容支持HTML Tag。
Navigation List组件的用法如下:
(1)在一对多的主从关系中,拖放主对象ProductsBaseView1生成ADF Navigation List:

(2)在一对多的主从关系中,拖放从对象WarehouseStockLevelsView2生成Bar Graph:

(3)最终的界面设计效果如下:

如果有合适的场景以后可以考虑使用。

2. Enable ADF Security
(1)选择Enable ADF Security后,ADF 整个应用(包括Model和ViewController Project)将被保护起来,所有Web页面在没有授权的情况下将无法访问。

(2)本界面中的三个选项的含义如下:
ADF Authentication and Authorization:增加认证和授权表明用户必须认证通过才能访问他们可以访问的资源
ADF Authentication:只增加认证功能。
Remove ADF Security Configuration:移除ADF Security,之前的安全设置并不会丢失,只是不再使用。这个是考虑到开发人员有时可能想临时去掉安全性。

(3)本界面中的四个选项的含义如下:
HTTP Basic Authentication:由浏览器弹出一个登录窗口,不提供Logout功能,且账号和口令只是简单地使用base64编码,不安全,只适用于测试。
HTTP Digest Authentication:使用摘要算法加密口令,其余特性与HTTP Basic Authentication相同。
HTTPS Client Authentication (Public Key Certificate):用户需要提供数字证书(其中的公钥表明用户身份)来进行认证。
Form-Based Authentication:基于表单的认证,表单将把用户账号和口令通过j_SecurityCheck提交到Container安全认证模块。

(4)本界面中的三个选项的含义如下:
如果选择选项2或3,ADF Security会自动创建一个Application Role:test-all,该角色拥有全部权限,主要是为了方便测试使用。
No Automatic Grant:不创建Application Role:test-all,也就不给test-all自动授予任何权限。
Grant to Existing Objects Only:给test-all授予现有的对象(ADF task flows和web pages)View权限。
Grant to All Objects or Grant to New Objects:给test-all授予所有的对象(现在的和将来添加的ADF task flows和web pages)View权限。

(5)设置认证通过后的welcome页面

(6)总结界面


3. 完成Wizard后,将会创建和修改以下配置文件
(1)web.xml
<servlet>
<servlet-name>adfAuthentication</servlet-name>
<servlet-class>oracle.adf.share.security.authentication.AuthenticationServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
...
<servlet-mapping>
<servlet-name>adfAuthentication</servlet-name>
<url-pattern>/adfAuthentication</url-pattern>
</servlet-mapping>
...
<security-constraint>
<web-resource-collection>
<web-resource-name>adfAuthentication</web-resource-name>
<url-pattern>/adfAuthentication</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>valid-users</role-name>
</auth-constraint>
</security-constraint>
<login-config>
<auth-method>FORM</auth-method>
<form-login-config>
<form-login-page>/login.html</form-login-page>
<form-error-page>/error.html</form-error-page>
</form-login-config>
</login-config>
<security-role>
<role-name>valid-users</role-name>
</security-role>
注意,这里定义了一个用于认证的Servlet:AuthenticationServlet,以及一个Application Role:valid-users。
(2)welogic.xml
<security-role-assignment>
<role-name>valid-users</role-name>
<principal-name>users</principal-name>
</security-role-assignment>
注意,这里把角色valid-users映射到了WebLogic中的组:users上。
组user是Weblogic中的一个隐含组,所有的用户都属于user组,这样所有的用户也就具有了valid-users角色。
(3)jps-config.xml
JPS的含义是“Java Platform Security”,该文件位于Application Resources下的Descriptors\META-INF。
该文件负责定义policy store service provider并且创建一个policy store的实例,比如credential store的位置。
(4)adf-config.xml
由JPS接管ADF Security,该文件位于Application Resources下的Descriptors\ADF META-INF。
<sec:JaasSecurityContext initialContextFactoryClass="oracle.adf.share.security.JAASInitialContextFactory" jaasProviderClass="oracle.adf.share.security.providers.jps.JpsSecurityContext" authorizationEnforce="true" authenticationRequire="true"/>
(5)jazn-data.xml
负责具体定义<policy-store> element。

4. 在jazn-data.xml中定义授权信息
(1)创建Application Roles。

可以看出,这里ADF Security已经创建了两个Application Roles:authenticated-role和anonymous-role。
如果资源只要通过认证就可以访问,那么需要把这些资源的访问权限授予authenticated-role。
如果资源是完全公开的,即使用户没有登录也可以访问,那么需要把这些资源的访问权限授予anonymous-role,这一点与一般的Web应用不同,需要注意。
(2)创建Enterprise Roles。

(3)创建Users。

(4)为Application Roles授予权限(Resource Grants)。

可以授予的权限有:
View:默认选中。允许访问该页面或该Task Flow。注意,View并不是表明该页面是“read-only”的,页面上呈现出来的所有操作都可以执行。
Customize:允许运行时定制化该页面,一旦修改,所有人都可以看到修改后的页面。用于Portal应用中,类似于Portal管理员的角色。
Edit:允许使用Oracle Composer修改页面,该权限覆盖权限 Customize和Personalize。
Grant:允许运行时为其它角色授权是否可以访问该页面。
Personalize:允许运行时个性化页面,只为该用户自己。用于Portal应用。
(5)建立Application Roles 、Enterprise Roles以及Users之间的映射关系。

5. 使用Security EL设置组件的属性
一般来说,如果某个用户没有查看某个页面的权限,就不要显示可以导航到该页面的链接。
否则,用户点击了,然后再告诉用户“对不起,你没有查看此页面的权限。“,用户的感受不好,而且容易造成安全漏洞。
(1)用户登录成功后,显示“欢迎 某某”。
<af:outputFormatted value="Welcome #{securityContext.userName}" id="pt_of1" rendered="#{securityContext.authenticated}" inlineStyle="color:White; font-size:small; font-weight:bold;"/>
(2)用户没登录时,显示一个“钥匙”图标;用户登录成功后,显示一个“锁”的图标。
<af:image id="pt_i1" source="#{securityContext.authenticated ? resource['images:listLockIcon.png'] : resource['images:key.png']}"/>
(3)用户没登录时,提示用户“点击这里登录”;用户登录成功后,直接导向登录成功后的第一个页面。
<af:goLink text="#{securityContext.authenticated ? "Logout" : "Login"} " id="pt_gl1" destination='#{securityContext.authenticated ? "/adfAuthentication?logout=true&end_url=/faces/welcome.jsf" : "/adfAuthentication?success_url=/faces/products.jsf"}' inlineStyle="color:White; font-size:small; font-weight:bold;"/>
(4)如果用户没有登录,就不要显示那些登录成功后才能点击的链接。
<af:commandLink text="products" id="pt_cl2" action="products" rendered="#{securityContext.authenticated}"/>
(5)如果用户没有某个权限(比如View某个页面),就不要显示导向那个页面的链接。
<af:commandLink text="stock" id="pt_cl3" action="stock" rendered="#{securityContext.regionViewable['view.pageDefs.stockPageDef']}"/>
(6)如果用户不具备某个角色,就不要显示某个组件。
<af:panelLabelAndMessage label="#{bindings.CostPrice.hints.label}" id="plam3" rendered="#{securityContext.userInRole['staff']}">
<af:outputText value="#{bindings.CostPrice.inputValue}" id="ot3"/>
</af:panelLabelAndMessage>

Project 下载:SecureApplication.7z

参考文献:
1. http://blog.whitehorses.nl/2010/01/29/weblogic-web-application-container-security-part-1/
2. http://blog.whitehorses.nl/2010/02/01/weblogic-web-application-container-security-part-2-adf-security/
3. http://andrejusb.blogspot.com/2010/05/migrating-security-policies-from.html
4. http://www.oracle.com/technology/products/jdev/tips/muench/credmig111100/index.html
5. http://andrejusb.blogspot.com/2009/01/practical-adf-security-deployment-on.html
6. http://docs.oracle.com/cd/E14571_01/web.1111/b31974/adding_security.htm

没有评论: