级别: 初级 Tyler Anderson (tyleranderson5@yahoo.com), 自由撰稿人
2005 年 12 月 15 日 在当前环境下,开发安全应用程序和保护数据尤为重要。学习如何通过使用 Java? 2 Platform, Enterprise Edition (J2EE) 声明性安全在 Apache Geronimo 应用服务器中限制目录访问而为您的系统增加另一层安全。使用一个简单的 Web 应用程序作为例子,本文演示如何通过在 web.xml 文件中添加安全约束并且即使允许访问也要指明角色和用户来控制目录访问。
简介
应用服务器技术正在稳步向前发展。因此,越来越多的企业应用开发人员开始利用它的优点 —— 包括它最近正式的 J2EE 1.4 认证版。
对于任何 Web 服务器来说,通过限制对目录的访问来保护您的目录不被任意的 Web 浏览器访问是安全必不可少的组成部分。本文向您展示如何使用 Apache Geronimo 创建一个简单的 Web 应用程序,它允许用户访问、登录并且获准访问站点上的其他区域。本文适用于小到中型的应用程序,因为它通过利用属性文件登录模块实现了简单的安全。通过部署 GBeans 而控制目录访问,GBeans 指定 Geronimo 上的安全部署计划。应用程序在 geronimo-web.xml 文件中展开这个部署计划并且在 web.xml 文件中创建安全约束。本文使用 Apache Geronimo M5 版并且假设您没有任何关于 Geronimo 的预备知识。
从 Apache Geronimo 开始
要使用 Geronimo,您需要 Java 2 Platform, Standard Edition (J2SE) 1.4.2_08(或者更新的,但是要在 1.5 之前的版本)。安装完 Java 代码后,再从 Apache (参阅 参考资料 链接到 Web 站点)下载 Geronimo M5。选择 .zip 文件(针对 Microsoft? Windows 或者 Linux? 操作系统)或者 .tar.gz 文件(针对 Linux 操作系统)。
下载完成后,解压缩 .zip 或 .tar.gz 文件。现在,您已经为启动服务器做好准备了。
启动 Geronimo 服务器
在控制台窗口转向 Geronimo 发行版的根目录,通过键入如下命令执行 server.jar 文件:
服务器开始装载所有的模块以及所有的应用程序模块(参见 图 1)。
图 1. 启动 Geronimo
现在,您已经为创建应用程序做好准备了。
介绍应用程序
本文包含一个名为 XYZ Enterprise example application 的示例应用程序,您可以下载它。这个应用程序要求用户在访问内容之前必须先登录。这个站点由三个易用的 Web 页面组成。把站点根目录下的索引页作为 Web 站点、下载区域以及管理员区域的主页面。首先,您需要了解应用程序的目录结构。
了解应用程序的目录结构
应用程序具有一个包含应用程序所有元素的目录结构。创建一个名为 secApp 的目录。这是应用程序的根目录。在 secApp 中创建如下子目录:
- downloads(下载区域)
- restricted(管理员区域)
- verify(包含登录表单和无效用户/密码页面)
- WEB-INF(包含 Geronimo 对于您的应用程序所需的 .xml 文件)
本文其余部分将介绍上面每个目录的内容。
开始页面
开始页面 —— 当访问者访问 Web 站点时第一个显示的页面 —— 指向对用户可用的其他部分和活动。在您的应用程序根目录下 (./secApp/index.html) 创建名为 index.html 的文件。在文件中添加 HTML 代码,如 清单 1 所示。
清单 1. 开始页面
<html><head><title>TylerCo.</title></head>
<body>
<h1>Welcome to TylerCo.</h1>
There's a lot to do on this Web site.<br>
The user's downloads area is <a href="downloads/">here</a>.<br>
Administrators can log in <a href="restricted/">here</a>.
</body>
</html>
|
这个页面显示了将用户带到下载区域的两个链接,而且,它也提供了管理员用户登录的链接。示例浏览器输出参见 图 2 。
图 2. 显示开始页面
现在我们来看下载区域。
下载区域
下载区域允许用户浏览页面或者下载可用的内容。创建文件名为 index.html 的文件并把它放在 downloads 目录下。在文件中添加 HTML 代码,如 清单 2 所示。
清单 2. 下载区域
<html><head><title>Welcome to TylerCo.</title></head>
<body>
<h1>DOWNLOADS AREA</h1>
Welcome to the downloads area for registered users only!<br>
Go back to the <a href="../">main page</a>.
</body>
</html>
|
这个页面可以被扩展为包含文件下载或者用户浏览其他页面的链接。也显示了一个返回主页面的链接。下载区域的示例浏览器输出参见 图 3。
图 3. 显示下载区域
现在我们来看管理员区域。
管理员区域
管理员区域的存在是为了代表这样一个区域,这个区域只允许具有管理员访问权限的用户进入并且执行与管理相关的活动,如为用户添加和改进新内容。创建另外一个名为 index.html 的文件并把它放到 restricted 目录下(参阅 清单 3)。
清单 3. 管理员页面
<html><head><title>ADMIN</title></head>
<body>
<h1>HELLO ADMIN</h1>
What would you like to do?<br>
Go back to the <a href="../">main page</a>.
</body>
</html>
|
这个页面可以被扩展为包含允许管理员从下载区域添加、编辑、修改或者删除内容的链接。下载区域的示例浏览器输出参见 图 4。
图 4. 显示管理员页面
接下来,了解如何设置安全。
设置安全
Geronimo 通过一系列文件保证敏感数据的目录访问安全。首先,通过 my-realm.xml 定义部署计划,指定您的应用程序在安全访问时遵守的部署计划。web.xml 文件列出应用程序中存在的约束和安全角色以及允许访问某个目录的角色。geronimo-web.xml 文件定义哪个用户或者用户组包含 web.xml 中定义的安全角色。
GBeans
GBean 是 Geronimo 的一种封装对象、管理它们的生命周期以及表示依赖关系的独特方式。实际上,Geronimo 内核完全不依赖服务器上所装载的特定模块。这种模块化方法使 Geronimo 成为高度可伸缩的服务器。GBean 是连接您的部署计划和 Geronimo 内核的接口。GBeans 具有状态,而且它可以与其他的 GBeans 和内核进行通信及交互,您的应用程序就是通过这种方式进行身份验证的。用户提交用户名和密码后,Geronimo 与您的 GBeans 交互,对来访的用户进行身份验证。
接下来使用 GBeans 配置您的部署计划
配置部署计划
使用 GBeans 部署您的部署计划并且将它与 Geronimo 内核相连接。文件 my-realm.xml 定义了三个 GBeans 用来协调身份验证类型、登录用法以及用户登录到的安全领域。创建文件 my-realm.xml,并把它放在 WEB-INF 目录下,开始对它进行定义,如 清单 4 所示。
清单 4. 登录属性 GBean
<?xml version="1.0" encoding="UTF-8"?>
<configuration
xmlns="http://geronimo.apache.org/xml/ns/deployment-1.0"
configId="com/ibm/geronimo/security/myRealm"
parentId="org/apache/geronimo/Security"
>
<gbean name="my-login"
class="org.apache.geronimo.security.jaas.LoginModuleGBean">
<attribute name="loginModuleClass">
org.apache.geronimo.security.realm.providers.PropertiesFileLoginModule
</attribute>
<attribute name="serverSide">true</attribute>
<attribute name="options">
usersURI=var/security/my_users.properties
groupsURI=var/security/my_groups.properties
</attribute>
<attribute name="loginDomainName">my-realm</attribute>
</gbean>
...
|
首先,在配置标记中指定部署计划的 configId,它将扩展 parentId 指定的 org.apache.geronimo.Security 类。应用程序通过 geronimo-web.xml 文件链接到这个部署计划。
第一个 GBean (my-login) 指定已注册的用户和组,如它们相应的属性文件中定义的那样,这些用户和组被允许进行目录访问。当用户登录并输入用户名和密码时,会检查这些文件。通过 清单 4 中指定的 loginDomainName 属性,这个 GBean 被链接到第二个 GBean(my-realm,如 清单 5 所示)。
清单 5. 登录域名 GBean(领域)
...
</gbean>
<gbean name="my-realm"
class="org.apache.geronimo.security.realm.GenericSecurityRealm">
<attribute name="realmName">my-realm</attribute>
<reference name="LoginModuleConfiguration">
<name>my-login</name>
</reference>
<reference name="ServerInfo">
<module>org/apache/geronimo/System</module>
<name>ServerInfo</name>
</reference>
<reference name="LoginService">
<module>org/apache/geronimo/Security</module>
<name>JaasLoginService</name>
</reference>
</gbean>
...
|
这个 my-realm GBean 指定用户登录到的域并且定义 System 和 Security 模块。通过 清单 6 中指定的 LoginModuleConfiguration,它把自己链接到下一个 GBean(也是 my-login)。
清单 6. 登录配置 GBean
...
</gbean>
<gbean name="my-login"
class="org.apache.geronimo.security.jaas.JaasLoginModuleUse">
<attribute name="controlFlag">REQUIRED</attribute>
<reference name="LoginModule">
<name>my-login</name>
</reference>
</gbean>
</configuration>
|
最后一个 GBean (my-login) 指定登录配置属性。controlFlag 指定为了验证成功,必须返回一个有效结果。这个 GBean 通过 LoginModule 指针链接到 清单 4 中的第一个 GBean(名称相同)。
接下来,在 web.xml 文件中配置安全。
声明性 J2EE 安全:web.xml
现在已经设置了 GBeans,您还需要把它们与您的应用程序绑定。创建名为 web.xml 的文件,并把它放在 WEB-INF 目录下,开始定义该文件,如 清单 7 所示。
清单 7. 指定安全角色
<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
version="2.4">
<security-role>
<role-name>registered-users</role-name>
</security-role>
<security-role>
<role-name>administrators</role-name>
</security-role>
...
|
这将通过指定 XML 名称空间来设置 web.xml 文件。然而,以粗体显示的安全角色是这里讨论的重点。您的应用程序中有两个角色:registered-users 和 administrators。随后在 geronimo-web.xml 文件中指定了每个角色中的用户。接下来,定义目录安全约束,如 清单 8 所示。
清单 8. 指定安全约束
...
<role-name>administrators</role-name>
</security-role>
<security-constraint>
<web-resource-collection>
<web-resource-name>Registered Users</web-resource-name>
<url-pattern>/downloads/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>registered-users</role-name>
<role-name>administrators</role-name>
</auth-constraint>
</security-constraint>
<security-constraint>
<web-resource-collection>
<web-resource-name>Administrators Only!</web-resource-name>
<url-pattern>/restricted/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>administrators</role-name>
</auth-constraint>
</security-constraint>
...
|
这里有两个约束:一个用于 download 目录,另一个用于 restricted 目录。downloads 目录允许 registered-users 和 administrators 访问,正如 auth-constraint 标记中所定义的那样。接下来定义用来登录的表单,如 清单 9 所示。
清单 9. 指定登录表单
...
</auth-constraint>
</security-constraint>
<login-config>
<auth-method>FORM</auth-method>
<realm-name>Jetty Realm</realm-name>
<form-login-config>
<form-login-page>/verify/login.html</form-login-page>
<form-error-page>/verify/loginError.html</form-error-page>
</form-login-config>
</login-config>
</web-app>
|
form-login-page 标记指定登录页面,而 form-error-login 标记指定当用户名/密码组合不能通过验证时将用户重定向到的页面。
声明性 J2EE 安全:geronimo-web.xml
现在您已经设置了三个 GBeans 和领域,并且定义了您的安全角色和约束。您还需要定义角色到用户/组的映射。创建名为 geronimo-web.xml 的文件,把它放在 WEB-INF 目录下并且定义该文件,如 清单 10 所示。
清单 10. 指定角色到用户/组的映射
<?xml version="1.0" encoding="UTF-8"?>
<web-app
xmlns="http://geronimo.apache.org/xml/ns/j2ee/web-1.0"
xmlns:sec="http://geronimo.apache.org/xml/ns/security-1.0"
configId="com/ibm/geronimo/security/myApp"
parentId="com/ibm/geronimo/security/myRealm">
<context-root>/security</context-root>
<context-priority-classloader>false</context-priority-classloader>
<security-realm-name>my-realm</security-realm-name>
<security>
<default-principal realm-name="my-realm">
<principal class=
"org.apache.geronimo.security.realm.providers.GeronimoUserPrincipal"
name="nobody"/>
</default-principal>
<role-mappings>
<role role-name="registered-users">
<realm realm-name="my-realm">
<principal class=
"org.apache.geronimo.security.realm.providers.GeronimoGroupPrincipal"
name="registeredUsers" designated-run-as="true"/>
</realm>
</role>
<role role-name="administrators">
<realm realm-name="my-realm">
<principal class=
"org.apache.geronimo.security.realm.providers.GeronimoUserPrincipal"
name="admin"/>
<principal class=
"org.apache.geronimo.security.realm.providers.GeronimoUserPrincipal"
name="root"/>
</realm>
</role>
</role-mappings>
</security>
</web-app>
|
首先,查看一下 configId 和 parentId 的值。configId 指定您的应用程序的名称,即 com/ibm/geronimo/security/myApp,并且扩展您前面所配置的领域:com/ibm/geronimo/security/myRealm。接下来设置环境,环境是指您的应用程序在 Geronimo 上部署时所在的目录。
然后,在 <security-realm-name> 标记中确定您将使用的领域的名称(这个领域名是您在 my-realm.xml 文件中已经定义的),并在 <security> 标记中定义映射。
默认用户映射 —— nobody —— 首先被定义。然后定义角色映射。回忆一下您刚才在 web.xml 文件中定义了两个安全角色。第一个映射将 registeredUsers 组中的所有用户映射到 registered-users 角色。第二个也是最后一个映射将管理员和根用户映射到 administrators 角色。接下来定义与 registeredUsers 组相关的用户以及每个用户和密码。
属性文件
您还记得在 清单 4 中所引用的用户和组的属性文件吗?当有用户登录时,您的应用程序引用的用户名和密码将被保存在 users.properties 和 groups.properties 文件中。users.properties 文件保存用户名和密码,而 groups.properties 文件保存组名以及与每个组相关的用户。
现在,您需要定义属性。首先,创建名为 my_users.properties 的文件,并把它放在如下位置,即您的 Geronimo 发行版的根目录下:./var/security/my_users.properties。如 清单 11 所示对它进行定义。
清单 11. 定义用户和他们的密码
admin=imtheboss
root=icandeleteanything
bob=by
joe=schmoe
kris=sy
john=doe
nobody=nobody
|
现在您已经指定了用户和密码,稍后用户尝试登录时将根据用户和密码对其进行身份验证。也可以定义用户组。创建文件 my_groups.properties,并把它放在与刚刚创建的 my_users.properties 文件相同的目录下:
bosses=admin,root
registeredUsers=bob,joe,kris,john
nobody=nobody
|
registeredUsers 组是重要的组,因为它与应用程序中的 registered-users 角色相关。因此,bob、joe、kris 和 john 都是可获得对您的应用程序的 download 目录的访问权的注册用户。
接下来定义登录页面。
定义登录页面
在 清单 9 中,您指定了用户请求访问任何 restircted 目录时使用的表单。现在开始对它们进行定义。
登录页面
当用户点击开始页面上的下载区域链接后,用户被重定向到登录页面。创建文件 login.html,把它放在 verify 目录下并对它进行定义,如 清单 12所示。
清单 12. 登录页面
<html>
<h1>LOGIN</h1>
<form method="POST" action="j_security_check">
Username:<br>
<input size="20" name="j_username">
<br><br>
Password:<br>
<input size="20" name="j_password" type="password">
amp;nbsp;amp;nbsp;<input name="submit" type="submit" value="Login">
</form>
</html>
|
该表单使用 J2EE 安全填写。具有 j_security_check 行为的表单向 Geronimo 表明身份验证是基于表单的。j_username 指定请求安全检查的用户的用户名,j_password 指定密码。提交表单将数据发送给 Geronimo,它连接到您的 GBeans 并且对用户进行身份验证。示例浏览器输出参见 图 5。
图 5. 显示登录页面
接下来,定义登录出错页面。
登录出错页面
当用户名/密码组合身份验证失败时,用户被重定向到这个页面。创建页面 loginError.html,把它放在与 login.html 文件相同的目录下。对它进行验证和定义,如 清单 13 所示。
清单 13. 登录出错页面
<html>
<h1>ERROR</h1>
UNABLE TO VERIFY:<br>
INVALID username or password.
</html>
|
向用户显示一个简单的页面,表明他们输入了一个无效的用户名/密码组合(参见 图 6)。
图 6. 显示出错页面
祝贺您,您的应用程序完成了!接下来,通过在 Geronimo 上部署它对它进行测试。
测试应用程序
要对您的应用程序进行测试,首先在服务器上部署安全计划,然后部署您的应用程序。
部署部署计划
将安全部署计划部署并链接到 Geronimo,允许您的应用程序随后进行扩展并且使用其中的安全配置。在一个新的控制台窗口中转向您的 Geronimo 安装目录的根目录。键入如下命令部署部署计划:
java -jar bin/deployer.jar --user system --password manager
deploy ../secApp/WEB-INF/my-realm.xml
|
通过接受默认用户名和密码组合、执行部署命令并且把 my-realm.xml 作为要部署的文件,这个命令将执行 deployer.jar 文件。Geronimo 输出如下内容,表示部署成功:
Deployed com/ibm/geronimo/security/myRealm
|
它已经取得了部署计划的 configId 并且把它部署在 Geronimo 上了。现在可以在您的应用程序中使用它了。
部署应用程序
接下来开始在 Geronimo 上部署并且测试您的应用程序。然而,首先,您需要把它存档为一个 .war 文件。打开另外一个控制台窗口,并且转向您的应用程序的根目录,即 secApp 目录。通过键入下面这个命令,创建您的应用程序的 .war 文件。
jar cvf security.war downloads verify WEB-INF restricted index.html
|
这将您的应用程序的所有文件都放入一个 .war 文件,即 security.war,Geronimo 可以读取该文件。通过键入下面这个命令在 Geronimo 上部署您的应用程序:
java -jar bin/deployer.jar --user system --password manager
deploy ../secApp/security.war
|
现在在 Geronimo 上部署了您的应用程序。Geronimo 输出类似于以下的信息,表示部署成功。
Deployed com/ibm/geronimo/security/myApp @
http://your-a9279112e3:8080/security
|
应用程序部署完成,准备进行测试。
测试应用程序
通过访问刚刚创建的 Web 站点测试您的应用程序。打开 Web 浏览器,把它转向 URL http://localhost:8080/security/。开始页面将被载入,如 图 2所示。
现在点击将用户带到下载区域的链接。应该载入登录页面,如 图 5 所示。输入您前面创建的 my_user.properties 文件中定义的用户名和密码(参见 图 7)。
图 7. 登录
点击 Login 后,将载入下载页面。点击链接返回主页面。现在,点击带您到管理员登录区域的链接。示例浏览器输出如 图 8 所示。
图 8. 禁止
允许 Bob 访问下载区域,但是由于他不是管理员用户或者根用户,所以禁止他访问安全目录。registered-users 角色有效!
要测试 administrators 角色,您需要通过关闭并重新打开您的浏览器进行注销。这样做可以重置所有的登录信息。现在,您可以测试 administrators 角色了。点击将您带到管理员登录区域的链接(您可能必须通过按下 Shift 键并且点击 Reload 才能重新载入登录页面)。这将把您带到同一个登录页面,只是这次您输入不同的用户名/密码组合(参见 图 9)。
图 9. 作为根用户登录
管理员页面像预期的那样被载入。现在返回主页面,并转到下载区域。下载区区域面也像预期的那样被载入。administrators 角色有效!
结束语
祝贺您!您已经学习了如何在 Apache Geronimo 应用服务器上创建并且部署应用程序,保护目录内容不受非授权的访问。通过只允许某些用户访问,为您的操作增加了另外一层安全。
下载 | 描述 | 名字 | 大小 | 下载方法 |
|---|
| XYZ Enterprise example application | source.zip | 4 KB | HTTP |
|---|
参考资料 学习
获得产品和技术
讨论
关于作者  | |  | Tyler Anderson 2004 年毕业于 Brigham Young University 并且获得计算机科学学士学位,现在正处于攻读计算机工程科学硕士学位的最后一个学期。过去,他曾经是 DPMG.COM 的数据库编程人员,而现在他是 Stexar Corp. 的工程师,Stexar Corp. 的总部位于 Oregon 的 Beaverton。 |
对本文的评价
|