Apache Tomcat Servlet/JSP 容器

Apache Tomcat 5.5 Servlet/JSP 容器

Jaxmao Logo

Apache Tomcat 5.5 Servlet/JSP 容器

权限管理 - 域(Realm)的设置

目录

快 速 上 手

什么是域(Realm)?
配置一个域(Realm)
域的共有属性
把密码加密(Digested)
应用程序示例
Tomcat管理员程序
在域(Realm)里面纪录日志
Tomcat现有的标准域(Realm)
JDBCRealm
DataSourceRealm
JNDIRealm
MemoryRealm
JAASRealm
UserDatabaseRealm

快 速 上 手

这个文档描述了怎样通过用一个现有"数据库"里的用户名,密码以及角色来配置 Tomcat,从而来支持容器管理的安全性(container managed security)。 如果你使用一个网络程序,而这个程序里包括了一个或多个<security-constraint> 元素,以及一个定义用户怎样认证他们自己的<login-config>元素,那你就需要设置 这些域(Realm)。如果你不使用这些功能,你就可以跳过这个文档。

关于容器管理安全性的基础背景知识,参看 Servlet 规范 (Version 2.4),第12章。

关于使用Tomcat 5的一次性登录特性(允许用户只需认证他自己一次就可以使用和虚拟 主机相关的所有网络程序)的信息。请看这里。

概述
什么是域(Realm)?

域(Realm)是一个存储用户名,密码以及和用户名相联系的角色的”数据库”, 用户名,密码用来验证 用户对一个或多个web应用程序的有效性。访问应用程序中特定资源的权限是被授予了拥有特殊角色的用户, 而不是相关的用户名。通过用户名相关联,一个用户可以有任意数量的角色。

尽管Servlet规范描述了一个可以让应用程序声明它们安全性要求(在web.xml 部署描述符里)的机制,但是并没有的API(应用编程接口)来定义一个基于servlet容器和其 相关用户角色之间的界面(interface)。然而在许多情况下,最好能把一个servlet容器和那些已经存在 的认证数据库或机制“连接”起来。因此,Tomcat 5定义了一个 Java界面(org.apache.catalina.Realm),它可以通过"插件"来实现 这种连接。这里提供了五个标准的插件,用来支持与各个认证信息来源的连接:

  • JDBCRealm - 通过JDBC驱动来访问贮存在关系数据库里的认证信息。
  • DataSourceRealm - 通过一个叫做JNDI JDBC 的 数据源(DataSource)来访问贮存在关系数据库里的认证信息。
  • JNDIRealm - 通过JNDI provider来访问贮存在基于 LDAP(轻量目录访问协议)的目录服务器里的认证信息。
  • MemoryRealm - 访问贮存在电脑内存里的认证信息,它是通过一个 XML文件(conf/tomcat-users.xml)来进行初始化的。
  • JAASRealm - 使用 Java Authentication & Authorization Service (JAAS).

也可以编写你自己的Realm implementation,然后与Tomcat整合在一起。你需要:

  • 实现org.apache.catalina.Realm
  • 把编译过的文件放置到&#036;CATALINA_HOME/server/lib里边
  • 象下面的"配置一个域(Realm)" 章节里描述的那样声明你的realm。
  • 用MBeans 描述符声明你的realm。

配置一个域(Realm)

在进入详细的标准Realm实现之前,弄懂怎样配置一个域(Realm)是很重要的。通常,你需要把 一个XML元素加入到你的conf/server.xml配置文件中,它看起来象这样:

&lt;Realm className="... class name for this implementation" 
... other attributes for this implementation .../&gt;

<Realm>元素可以被套嵌在下列任何一个Container 元素里面。这个Realm元素所处的位置直接影响到这个域(Realm)的作用范围(比如,哪些web应用程序 会共享相同的认证信息):

  • 在<Engine>元素里边 - 这个域(Realm)将会被所有虚拟主机上的所有 网络程序共享,除非它被嵌套在下级<Host> 或 <Context>元素里的Realm元素覆盖。
  • 在<Host>元素里边 - 这个域(Realm)将会被该虚拟主机上所有的 网络程序所共享,除非它被嵌套在下级<Context>元素里的Realm元素覆盖。
  • 在<Context>元素里边 - 这个域(Realm)只被该网络程序使用。
共有特性
把密码加密

对于每个现有的Realm实现里,用户的密码(默认情况下)以明文形式 被贮存。在许多环境中,这是不理想的,因为任何人看见了认证数据都可以收集足够信息成功登录,冒充 其他用户。为了避免这个问题,标准的实现支持digesting用户密码的概念。这被贮存的 密码是被加密后的(以一种不易被转换回去的形式),但是Realm实现还是可以用它来认证。

当一个标准的realm通过取得贮存的密码并把它与用户提供的密码值作比较来认证时,你可通过在你 的元素<Realm>上指定digest属性选择digested密码。 这个属性的值必须是java.security.MessageDigest class (SHA, MD2, or MD5) 支持的digest 算法之一。当你选择这一选项,贮存在域(Realm)里的密码内容必须是这个密码的明文 形式,然后被指定的运算法则来加密。

当这个Realm的authenticate()方法被调用,用户指定的(明文) 密码被相同的运算法来加密,它的结果与Realm返回的值作比较。如果两个值对等的话,就意味着 原始密码的明文版与用户提供的一样,所以这个用户就被认证了。

要计算一个明文密码经过加密的值,Tomcat 支持下面两个便利的技术:

  • 如果你在编写一个需要自动加密密码的程序, 调用org.apache.catalina.realm.RealmBase类里的Digest()方法, 把明文密码和加密的算法名字作为参数传递过去。这种方法会返回的是经过加密的密码。
  • 如果你想要使用命令行设施来加密密码,简单地执行以下命令:
    java org.apache.catalina.realm.RealmBase \ 
    -a {algorithm} {cleartext-password}
    这个明文密码的加密版本会以标准输出 形式返回。

如果使用加密的密码进行DIGEST认证,用于产生digest的明文是不一样的。在上面的例子中, {cleartext-password}必须被{username}:{realm}:{cleartext-password} 取代。比如说,在一个开发环境中它是这样的形式testUser:localhost:8080:testPassword。

要使用上面所说的任何一个技术,需要把$CATALINA_HOME/server/lib/catalina.jar 文件放在你的class path上,让RealmBase类可以被使用。另外,你还需要JMX.jar和 commons-logging.jar文件 (要么是 commons-logging-api.jar 要么是 commons-logging.jar)。 Tomcat包括有这俩个文件。

非ASCII的用户名和/或密码也被支持,但你需要使用下面的命令

java org.apache.catalina.realm.RealmBase \ -a {algorithm} -e {encoding} {input}
不过必须要保证这个非ASCII输入正确地传递给digester。这个digester会返回 {input}:{digest}值。如果返回的input有误,加密也就是无效的。

应用程序示例

和Tomcat一起的应用程序示例包括被安全限制保护的一个区域,需要使用基于-表格(form-based)的登录。 想要访问它,把浏览器指向http://localhost:8080/jsp-examples/security/protected/, 并使用默认的MemoryRealm里所描述的用户名和密码来登录。

Tomcat管理员程序

如果你想要使用管理员程序(Manager Application) 在运行的Tomcat安装里部署和删除应用程序,你必须在你选择的Realm实现中至少给一个用户名添加 "manager"角色。这是因为管理员网络应用程序本身使用一个安全限制, 需要"manager"的角色在这个程序里面访问任何请求URI。

因为安全的原因,在默认的Realm里(i.e. 使用 conf/tomcat-users.xml文件)没有用户名被指派"manager"角色。 因此,在Tomcat administrator特别地给一个或几个用户指派这个角色之前,没有人能够利用这个程序。

在域(Realm)里面纪录日志

每个Realm排错和异常信息将由与这个realm的容器相关的日志配置记录下来: 它的Context, Host, 或 Engine。

Tomcat现有的标准域(Realm)
JDBCRealm

简介

JDBCRealm是一个Tomcat Realm界面实现,它通过JDBC驱动来查看关系数据库 里的用户信息。这里配置的可塑性很大,它让你能够使用现存的表名和列名(column names),只要你的 数据库结构与下面的要求一致:

  • 必须要有一个表格(table)存在,它必须是每一行包含一个这个Realm所能识别的 合法用户。下面引用叫做users的表格。
  • 这个用户表格必须包括至少两列(如果你的程序需要还可以有更多列)。
    • 可被Tomcat识别的用户登录名称(username)。
    • 可被Tomcat识别的用户登录密码。这个值可以是明文式(cleartext)或是被编码过(digested) 的形式 - 下面可查看更多信息。
  • 必须要有一个表格存在,它必须是每一行包含一个指派给某个特定用户的某个合法角色。 下面引用叫做user_roles的表格。
  • 这个user_roles表格必须包括至少两列(如果你的程序需要还可以有更多列):
    • 可被Tomcat识别的用户登录名称(和users table里指定的值相同)。
    • 和这个user_name相关联的有效role_name。

快 速 上 手

要设置好Tomcat来使用JDBCRealm,你必须遵守下面这些步骤:

  1. 根据上面所描述的规定,在你的数据库里产生表格(tables)和列(columns)。
  2. 配置一个可供Tomcat使用的用户名称和密码,它至少应该有只读(read only)权限来访问上述表格。 (Tomcat从不会试图去改写这些表格)。
  3. 把你将要使用的JDBC驱动复制件放置到$CATALINA_HOME/server/lib目录 (如果你不想让网络程序使用它的话)或者放在$CATALINA_HOME/common/lib(如果 Tomcat 和你的程序都要使用它的话)。注意,唯一只有JAR文件才能 被识别。
  4. 象下面所描述的那样,在你的$CATALINA_HOME/conf/server.xml文件设置一个 <Realm>元素。
  5. 如果Tomcat 5已经在运行,重新启动它。

Realm元素属性

为了配置一个 JDBCRealm, 你必须如上面描述的那样在 $CATALINA_HOME/conf/server.xml文件里产生一个<Realm>元素 该元素支持的属性可在Realm 配置里面找到。

例子

一个用于产生所需表格的SQL script示例也许看起来象这样(根据你特定的数据库需要做些语法上的改编):

create table users ( 
user_name varchar(15) not null primary key, 
user_pass varchar(15) not null 
); 

create table user_roles ( 
user_name varchar(15) not null, 
role_name varchar(15) not null, 
primary key (user_name, role_name) 
);

关于Realm元素的例子被包括在默认的$CATALINA_HOME/conf/server.xml 文件里(但被 commented out)。在下面的例子中,使用了一个叫做"authority"的 MySQL数据库,根据上面所描述的表格进行了配置,可以通过用户名"dbuser" 和 密码"dbpass"进行访问:

<Realm className="org.apache.catalina.realm.JDBCRealm" debug="99" 
driverName="org.gjt.mm.mysql.Driver" 
connectionURL="jdbc:mysql://localhost/authority?user=dbuser&amp;amp;password=dbpass" 
userTable="users" userNameCol="user_name" userCredCol="user_pass" 
userRoleTable="user_roles" roleNameCol="role_name"/>

另外的注意事项

JDBCRealm根据下面的规则进行运作:

  • 当一个用户第一次试图访问被保护的资源时,Tomcat 5会传叫(call)这个Realm 的authenticate()方法。因此,你对于这个数据库所做的认何直接更改(新用户,更改 过的密码和角色等等)都会被立即反映出来。
  • 一但用户被认证,用户(以及其相关角色)在这个用户登录期间会被高速缓存(cache)在Tomcat里。 (对于是基于表单(FORM-based)认证的用户,在会话结束或者注销后认证失效;对于BASIC认证的用户, 要等到用户关闭窗口后认证才失效)。被高速缓存的用户不会 在会话系列之间被贮存或再生(restored)。对于已经被认证的用户,任何有关数据库信息的更改,一直 要等到下次用户再次登录后才会被显示出来。
  • 管理users和user_roles表格里的信息应该是你的应用程序的职责。Tomcat没有 提供任何built-in 能力来维护用户及其角色信息。
DataSourceRealm

简介

DataSourceRealm是一个Tomcat 5 Realm界面实现,它通过 一个叫做JDBC DataSource的JNDI来访问查询关系数据库里的用户信息。这里配置的可塑性很大,让你 能够使用现有的表名和列名,只要你的数据库结构与下面的要求一致:

  • 必须要有一个表格(table)存在,它必须是每一行包含一个这个Realm所能识别的 合法用户。下面引用叫做users的表格。
  • 这个用户表格必须包括至少两列(如果你的程序需要还可以有更多列)。
    • 可被Tomcat识别的用户登录名称(username)。
    • 可被Tomcat识别的用户登录密码。这个值可以是明文式(cleartext)或是被编码过(digested) 的形式 - 下面可查看更多信息。
  • 必须要有一个表格存在,它必须是每一行包含一个指派给某个特定用户的某个合法角色。下面引用叫 做用户角色的表格。
  • 这个用户角色表格必须包括至少两列(如果你的程序需要还可以有更多列):
    • 可被Tomcat识别的用户登录名称(和users table里指定的值相同)。
    • 和这个用户相关联的有效角色名称。

快 速 上 手

要设置好Tomcat来使用DataSourceRealm,你必须遵守下面这些步骤:

  1. 根据上面所描述的规定,在你的数据库里产生表格(tables)和列(columns)。
  2. 配置一个可供Tomcat使用的用户名称和密码,它至少应该有只读(read only)权限来访问上述表格。 (Tomcat从不会试图去改写这些表格)。
  3. 为你的数据库配置一个叫做JDBC DataSource的JNDI。关于怎样配置一个叫做JDBC DataSource的 JNDI的信息请参看JNDI DataSource Example HOW-TO 。
  4. 象下面所描述的那样,在你的$CATALINA_HOME/conf/server.xml文件设置一个 <Realm>元素。
  5. 如果Tomcat 5已经在运行,重新启动它。

Realm元素属性

为了配置一个 DataSourceRealm, 你必须如上面描述的那样在 $CATALINA_HOME/conf/server.xml文件里产生一个<Realm>元素 该元素支持的属性可在Realm 配置里面找到。

例子

一个用于产生所需表格的SQL script示例也许看起来象这样(根据你特定的数据库需要做些语法上的改编):

create table users ( 
user_name varchar(15) not null primary key, 
user_pass varchar(15) not null 
); 

create table user_roles ( 
user_name varchar(15) not null, 
role_name varchar(15) not null, 
primary key (user_name, role_name) 
);

在下面的例子中,使用了一个叫做"authority"的MySQL数据库,根据上面所描述的表格 进行了配置,可以通过"java:/comp/env/jdbc/authority"访问JNDI JDBC DataSource:

<Realm className="org.apache.catalina.realm.DataSourceRealm" debug="99" 
dataSourceName="jdbc/authority" 
userTable="users" userNameCol="user_name" userCredCol="user_pass" 
userRoleTable="user_roles" roleNameCol="role_name"/>

另外的注意事项

DataSourceRealm根据下面的规则进行运作:

  • 当一个用户第一次试图访问被保护的资源时,Tomcat 5会传叫(call)这个Realm的 authenticate()方法。因此,你对于这个数据库所做的认何直接更改(新用户,更改过的 密码和角色等等)都会被立即反映出来。
  • 一但用户被认证,用户(以及其相关角色)在这个用户登录期间会被高速缓存(cache)在Tomcat里。 (对于是基于表单(FORM-based)认证的用户,在会话结束或者注销后认证失效;对于BASIC认证的用户, 要等到用户关闭窗口后认证才失效)。被高速缓存的用户不会 在会话系列之间被贮存或再生(restored)。对于已经被认证的用户,任何有关数据库信息的更改,一直 要等到下次用户再次登录后才会被显示出来。
  • 管理users和user_roles角色表格里的信息应该是你的应用程序的职责。Tomcat没有 提供任何built-in 能力来维护用户及其角色信息。
JNDIRealm

简介

DataSourceRealm是一个Tomcat 5 Realm界面实现,它通过一个JNDI provider 来访问查询LDAP目录里的用户信息(通常是与JNDI API类一起的标准LDAP provider)。这个realm支持一系列使用目录来进行认证的方法。

与目录相连接

这个realm与目录的连接是由connectionURL配置属性定义的。这个URL的 格式又是由JNDI provider来定义的。它通常是一个LDAP URL,用来指定相连接的目录服务器的领域 名称,或者端口数码以及所需的root naming context的特殊名称。

如果你有不止一个供应者(provider),你可以配置一个alternateURL。如果 不能在connectionURL与供应者连接上,机器就会试图使用alternateURL来连接。

在为了查询目录和搜索用户及其角色进行连接的时候,这个realm就通过connectionName 和 connectionPassword 属性指定的用户名称和密码来向这个目录认证它自己。 如果属性没有被指定,连接就是无名的。在许多情形下,这也足够了。

选择用户的目录进入

每一个能被认证的用户必须在目录里由一个单个登录(individual entry)来代表,这个单个登录与 初始DirContext里边被connectionURL属性定义的一个元素相 对应。这个用户登录必须有一个包含认证用的用户名称的属性(attribute).

通常这个用户登录的特殊名称包含提供给认证用的用户名,否则所有用户都一样。在这种情况下, userPattern这个属性也许可用来指定DN(特殊名称),用"{0}" 来标记用户名在什么地方可被替代。

否则这个realm必须搜寻(search)目录才能找到包含用户名称的独特的登录。这样的搜寻由下面的这些 属性配置:

  • userBase - 这个输入是作为包含用户信息subtree的基础。如果没有 指定,search base是最上层context。
  • userSubtree - 搜寻范围。如果你想搜寻根基于 userBase entry的整个subtree,把它设置为true。 默认的值false要求仅仅包括上层的单层搜寻。
  • userSearch - 指定要使用的LDAP搜寻过滤器的模式

认证用户

  • 绑定模式

    在默认的情况下,realm通过与带有用户和用户密码的目录绑定在一起来认证一个用户。如果这个简单 的绑定成功的话,用户就被认为被认证过了。

    因为安全的原因,目录会储存digest形式的用户密码,而不是明码版本(更多信息请看 Digested 密码)。在这种情况下,作为简单绑定操作的一部分, 目录在与储存的值核对之前自动把用户提供的正文密码换算成正确的digest。因此在绑定模式里,域(realm) 没有参与digest过程。这个digest属性没有被使用,即使被设置了,也被忽略掉。

  • 比较模式

    另外,域(realm)可以从目录中取出储存的密码并与用户提供的值做直接比较。通过把 userPassword属性设定为带有密码的用户输入里的一个 directory attribute的名字来配置这个模式。

    比较模式有一些不利的地方。第一,connectionName 和 connectionPassword 属性必须配置能让realm去阅读在目录里的用户密码。 因为安全的原因,这通常是不可取的,事实上,许多目录implementations不允许,即使是目录管理员 也不允许阅读这些密码。另外,realm必须自己处理password digests,包括使用运算法则的变化, 和在目录里表示密码hashes的方法。不过,realm有时也需要访问储存的密码,例如,要支持 HTTP Digest Access Authentication (RFC 2069)。(注意,HTTP digest认证不同于上面所 讨论的在用户信息储藏室里的password digests储存)。

给用户指派角色

目录域(realm)支持下列两种方法来在目录里代表角色:

  • 作为显式目录输入的角色

    角色可以通过显式的目录输入来代表。一个role entry通常是一个LDAP group entry,它具有一个 包含这个角色的名字以及另一个值为这个角色的特殊名字或用户名的属性。下面的这些属性配置一个目录 搜寻来发现与这个认证过的用户相关联的角色名称。

    • roleBase - 角色搜寻的基础输入。如果没有指定,search base是顶层目录context。
    • roleSubtree - 搜寻范围。如果你想搜寻根基于roleBase entry的整个subtree,把它设置为true。默认的值false要求仅仅 包含顶层的单层搜寻。
    • roleSearch - 选择角色输入的LDAP搜寻过滤器。它可选择性地包含两个 模式替代:"{0}" 代替被认证过的用户的特殊名字,以及/或者 "{1}" 代替 被认证过的用户的用户名。
    • roleName - 包含那个角色名字的role entry里的属性。
  • 作为用户输入的一个属性的角色

    角色名字也可以作为在用户目录输入里一个属性的值。使用userRoleName来 指定这个属性的名称。

这两种代表角色方法的组合也可以被使用。

快 速 上 手

要设置好Tomcat来使用JNDIRealm,你必须遵守下面这些步骤:

  1. 确保你的目录服务器是依据上面的要求配置的。
  2. 如果需要,配置一个可供Tomcat使用的用户名称和密码,它应该有只读(read only)权限来访问 上述表格。(Tomcat从不会试图去改写这些表格)。
  3. 把你将要使用的JNDI驱动(通常ldap.jar available with JNDI)复制件放置 到$CATALINA_HOME/server/lib目录(如果你不想让网络程序使用它的话)或者放在 $CATALINA_HOME/common/lib(如果Tomcat 5和你的程序都要使用它的话)。
  4. 象下面所描述的那样,在你的$CATALINA_HOME/conf/server.xml文件设置一个 <Realm>元素。
  5. 如果Tomcat 5已经在运行,重新启动它。

Realm元素属性

为了配置一个 JNDIRealm, 你必须如上面描述的那样在 $CATALINA_HOME/conf/server.xml文件里产生一个<Realm>元素 该元素支持的属性可在Realm 配置里面找到。

例子

因为每个目录服务器的实现都不同,在你的目录服务器里产生相适宜的schema超出了本文的范围。在 下面的例子里,我们假设你使用的是OpenLDAP目录服务器(2.0.11或其后版本),你可以从 http://www.openldap.org下载它。 假设你的slapd.conf文件包含下面的设置:

database ldbm 
suffix dc="mycompany",dc="com" 
rootdn "cn=Manager,dc=mycompany,dc=com" 
rootpw secret

至于connectionURL,我们假设目录服务器和Tomcat一样在同一个机器上运行。 更多关于配置和使用JNDI LDAP provider的信息,请参看http://java.sun.com/products/jndi/docs.html 。

下一步,假设这个目录服务器具有下面这些元素(以LDIF格式):

# Define top-level entry 
dn: dc=mycompany,dc=com 
objectClass: dcObject 
dc:mycompany 

# Define an entry to contain people 
# searches for users are based on this entry 
dn: ou=people,dc=mycompany,dc=com 
objectClass: organizationalUnit 
ou: people 

# Define a user entry for Janet Jones 
dn: uid=jjones,ou=people,dc=mycompany,dc=com 
objectClass: inetOrgPerson 
uid: jjones 
sn: jones 
cn: janet jones 
mail: j.jones@mycompany.com 
userPassword: janet 

# Define a user entry for Fred Bloggs 
dn: uid=fbloggs,ou=people,dc=mycompany,dc=com 
objectClass: inetOrgPerson 
uid: fbloggs 
sn: bloggs 
cn: fred bloggs 
mail: f.bloggs@mycompany.com 
userPassword: fred 

# Define an entry to contain LDAP groups 
# searches for roles are based on this entry 
dn: ou=groups,dc=mycompany,dc=com 
objectClass: organizationalUnit 
ou: groups 

# Define an entry for the "tomcat" role 
dn: cn=tomcat,ou=groups,dc=mycompany,dc=com 
objectClass: groupOfUniqueNames 
cn: tomcat 
uniqueMember: uid=jjones,ou=people,dc=mycompany,dc=com 
uniqueMember: uid=fbloggs,ou=people,dc=mycompany,dc=com 

# Define an entry for the "role1" role 
dn: cn=role1,ou=groups,dc=mycompany,dc=com 
objectClass: groupOfUniqueNames 
cn: role1 
uniqueMember: uid=fbloggs,ou=people,dc=mycompany,dc=com

假设用户使用他们的uid (e.g. jjones)来登入应用程序,并且无名的连接足够用来搜索目录和取得 角色信息,如上面所描述配置的OpenLDAP目录服务器的Realm元素示例看起来象这样:

<Realm className="org.apache.catalina.realm.JNDIRealm" debug="99" 
connectionURL="ldap://localhost:389" 
userPattern="uid={0},ou=people,dc=mycompany,dc=com" 
roleBase="ou=groups,dc=mycompany,dc=com" 
roleName="cn" 
roleSearch="(uniqueMember={0})" 
/>

在这样的配置下,realm通过把用户名替代到userPattern里去来决定用户的特殊的 唯一名字,通过把这个特殊的唯一名字(DN)和用户提供的密码与目录绑定来认证,并搜索目录来发现用户的角色。

现在假设用户在登入时使用他们的email地址,而不是他们的userid。在这种情况下,realm必须搜索 目录来寻找用户的输入。(当用户输入被放在与不同的组织单位或公司位置相对应的多个subtrees里时, 搜索也是必要的)。

进一步,假设除了群体输入外,你想要使用关于用户输入的一个属性来保存角色信息。这里,关于Janet Jones的输入读起来象这样:

dn: uid=jjones,ou=people,dc=mycompany,dc=com 
objectClass: inetOrgPerson 
uid: jjones 
sn: jones 
cn: janet jones 
mail: j.jones@mycompany.com 
memberOf: role2 
memberOf: role3 
userPassword: janet

这个realm的配置应该满足这些新的要求:

<Realm className="org.apache.catalina.realm.JNDIRealm" debug="99" 
connectionURL="ldap://localhost:389" 
userBase="ou=people,dc=mycompany,dc=com" 
userSearch="(mail={0})" 
userRoleName="memberOf" 
roleBase="ou=groups,dc=mycompany,dc=com" 
roleName="cn" 
roleSearch="(uniqueMember={0})" 
/>

现在,当Janet Jones以"j.jones@mycompany.com"登录时,realm在目录里搜索具 有那个值作为它的mail属性的独特输入,并以所给的密码,及以下uid=jjones,ou=people,dc=mycompany,dc=com 与目录绑定。如果认证成功,她就被指派给三个角色:"role2" and "role3"分别作为 她的目录输入里"memberOf"属性的值,"tomcat"作为唯一一个群体(她是其中 一个成员)输入"cn"属性的值。

最后,要想通过从目录中取得密码,并在realm里做局部比较来认证,你也许需要使用象这样的一个realm配置:

<Realm className="org.apache.catalina.realm.JNDIRealm" debug="99" 
connectionName="cn=Manager,dc=mycompany,dc=com" 
connectionPassword="secret" 
connectionURL="ldap://localhost:389" 
userPassword="userPassword" 
userPattern="uid={0},ou=people,dc=mycompany,dc=com" 
roleBase="ou=groups,dc=mycompany,dc=com" 
roleName="cn" 
roleSearch="(uniqueMember={0})" 
/>

当然,正如上面所描述的,通常比较偏向使用默认的绑定模式来认证。

另外的注意事项

JNDIRealm根据下面的规则进行运作:

  • 当一个用户第一次试图访问被保护的资源时,Tomcat 5会调用这个Realm 的authenticate()方法。因此,你在目录里的任何更改(新用户,更改过的密码或角色, 等等)会立即被反映出来。
  • 一旦用户被认证过,这个用户(及其相关的角色)在这个用户登录期间被高速缓存(cached)在Tomcat 里。(对于基于-表格(FORM-based)的认证,这意味着直致会话时间结束或无效;对于BASIC认证,这 意味着用户关闭他们的浏览器)。被缓存的用户在会话系列之间不 被保存和再贮存。一个已经被认证过的用户的任何目录信息的更改,直到下次用户再登录时才会被反映出来。
  • 管理目录服务器里的信息是你的程序自身的责任。Tomcat不提供任何内在的功能来维持用户及角色信息。
MemoryRealm

简介

MemoryRealm是一个简单的Tomcat 5 Realm界面实现。它 不是为大量用户名称认证而设计的。在启动时,MemoryRealm从一个XML文件装载关于所有用户,以及他们相应的 角色的信息(在默认情况下,这个文件从$CATALINA_HOME/conf/tomcat-users.xml 被装载)。这个文件里的数据更改直到Tomcat被重新被启动后才会被识别。

Realm元素属性

为了配置一个 MemoryRealm, 你必须如上面描述的那样在 $CATALINA_HOME/conf/server.xml文件里产生一个<Realm>元素 该元素支持的属性可在Realm 配置里面找到。

用户文件格式

用户文件(默认文件conf/tomcat-users.xml必须是一个带有 根元素<tomcat-users>的XML文件。每个合法用户 的<user>元素嵌套在根元素里,包含有下列属性:

  • name(名称) - 这个用户必须用来登录的用户名。
  • password(密码)- 这个用户登录必须使用的密码(如果 在<Realm>元素上digest属性没有被设置,或者没有象 这里描述的那样正确地被digested)。
  • roles(角色) - 与这个用户相关的以逗号分隔开的角色名称列单。

例子

The default contents of the conf/tomcat-users.xml file is:

<tomcat-users> 
<user name="tomcat" password="tomcat" roles="tomcat" /> 
<user name="role1" password="tomcat" roles="role1" /> 
<user name="both" password="tomcat" roles="tomcat,role1" /> 
</tomcat-users>

另外的注意事项

MemoryRealm根据下面的规则进行运作:

  • 当Tomcat第一次启动,它从用户文件装载了所有定义的用户以及他们的相关信息。直到Tomcat被 重新启动之前,这个文件里的数据的更改不会被识别出来。
  • 当一个用户第一次试图访问被保护的资源时,Tomcat 5会调用这个Realm 的authenticate()方法。
  • 一旦用户被认证过,这个用户(及其相关的角色)在这个用户登录期间被高速缓存(cached)在Tomcat 里。(对于基于-表格(FORM-based)的认证,这意味着直致会话时间结束或无效;对于BASIC认证,这意味 着用户关闭他们的浏览器)。被缓存的用户在会话系列之间不被保存和再贮存。
  • 管理目录服务器里的信息是你的程序自身的责任。Tomcat不提供任何内在的功能来维持用户及角色信息。
UserDatabaseRealm

简介

UserDatabaseRealm 是一个简单的Tomcat 5 Realm界面实现。所有用户和 他们的角色信息都来自于 JNDI 资源。这个 JNDI资源实现的是UserDatabase界面。

Realm元素属性

为了配置一个 UserDatabaseRealm, 你必须如上面描述的那样在 $CATALINA_HOME/conf/server.xml文件里产生一个<Realm>元素 该元素支持的属性可在Realm 配置里面找到。

例子

缺省安装的Tomcat 5 配置的 UserDatabaseRealm 嵌套在<Engine>元素内, 所以它适用于所有虚拟主机和web应用。这个域(realm)使用与MemoryRealm相同的 tomcat-users.xml。

JAASRealm

简介

JAASRealm 是一个通过Java Authentication & Authorization Service (JAAS)框架认证用户的Tomcat 4 Realm 接口 的实现,而这个JAAS是一个Java软件包,它在Java 2 SDK 1.3里是作为选择性软件包被使用,在 SDK 1.4里它则完全整合在其中了。

使用JAASRealm给予开发人员这种能力,那就是把任何可想象的安全realm与 Tomcat 的CMA组合在一起。

JAASRealm是基于JAAS的J2EE 1.4版本的J2EE认证框架的原型(prototype),它是在 JCP Specification Request 196 基础上来加强容器-管理的安全性,并促进不依赖于容器 的实现的'pluggable'认证机制。 JCP Specification Request 196

在JAAS登录模块和原则(参看javax.security.auth.spi.LoginModule 和javax.security.Principal)的基础上,你可以开发你自己的安全机制或者把第三方 的机制与Tomcat执行的CMA整合包裹在一起。

快 速 上 手

要设置好Tomcat来与你自己JAAS login模块一起使用JAASRealm,你必须遵守下面这些步骤:

  1. 在JAAS (参看the JAAS Authentication Tutorial 和 the JAAS Login Module Developer's Guide)基础上编写你自己的由JAAS Login Context (javax.security.auth.login.LoginContext) 管理的 LoginModule, User 和Role 类。在开发你的LoginModule时,注意JAASRealm自身具有的 CallbackHandler目前仅仅能识别NameCallback 和PasswordCallback。 the JAAS Authentication Tutorial the JAAS Login Module Developer's Guide
  2. 尽管JAAS里没有指明,但你还是应该通过扩展javax.security.Principal产生 不同的类来区分用户和角色,这样Tomcat可以从你的login module返回的Principals中区别 哪个是用户,哪个是角色(参看org.apache.catalina.realm.JAASRealm)。 不然的话,返回的第一个Principal总是被当作用户Principal。
  3. 把编译过的类放置在Tomcat的classpath上。
  4. 设置一个Java的login.config文件(参看JAAS LoginConfig file),并对JVM指明 这个文件的位置告诉Tomcat到哪里去找到它。例如,可以把环境变量设置如下: JAVA_OPTS=-DJAVA_OPTS=-Djava.security.auth.login.config==$CATALINA_HOME/conf/jaas.config 。 JAAS LoginConfig file JAVA_OPTS=-DJAVA_OPTS=-Djava.security.auth.login.config==$CATALINA_HOME/conf/jaas.config
  5. 在你的web.xml文件里为你想要保护的资源配置安全-限制(security-constraints) 。
  6. 在你的server.xml文件里配置JAASRealm模块(module)。
  7. 如果Tomcat 5已经在运行,重新启动它。

Realm元素属性

为了配置一个 JAASRealm, 你必须如上面描述的那样在 $CATALINA_HOME/conf/server.xml文件里产生一个<Realm>元素 该元素支持的属性可在Realm 配置里面找到。

例子

你的server.xml文件看起来应该象这个例子这样。

<Realm className="org.apache.catalina.realm.JAASRealm" 
appName="MyFooRealm" 
userClassNames="org.foobar.realm.FooUser" 
roleClassNames="org.foobar.realm.FooRole" 
debug="99"/>

是你的login模块的责任来产生并保存代表用户的Principals的( javax.security.auth.Subject ) User和Role对象(objects)。如果你的login模块没有产生一个user object ,也没有抛出一个login异常, 那么Tomcat CMA 会终断,你会被停留在http://localhost:8080/myapp/j_security_check URI 或其他未指定的位置。

JAAS方法的可塑性有两层:

  • 你可以在你自己的login模块里实现任何你需要的程序处理。
  • 不用对你的应用程序编码有任何更改,你可以通过更改配置并重新启动服务器来插入(plug in)一个完全 不同的LoginModule。

另外的注意事项

  • 当一个用户第一次试图访问一个被保护的资源,Tomcat 5会调用这个Realm的 authenticate()方法。这样一来,你在这个安全机制里做的任何更改(新用户,更改密码 和角色,等等)会立即被反映出来。
  • 一旦用户被认证过,这个用户(及其相关的角色)在这个用户登录期间被零时缓存(cached)在Tomcat里。 对于基于-表格(FORM-based)的认证,这意味着直致会话时间结束或无效;对于BASIC认证,这意味着直到 用户关闭他们的浏览器。对于被认证过的用户,任何安全信息更改在这个用户再次登录之前都不 会被反映出来。
  • 和其他Realm实现一样,如果server.xml 里面的 <Realm>元素包含有一个digest属性,digested密码就被支持; JAASRealm 的 CallbackHandler在把密码传递回LoginModule 之前会先digest密码。

Copyright © 1999-2006, Apache Software Foundation