管理领域、角色及用户
servlet container或web应用程序本身都可以控制Web应用程序资源的安全防护。在J2EE 规范中,前者称为容器管理(container-managed)的安全防护,而后者则称为应用程序 管理(application-managed)的安全防护,通过内嵌的机制,Tomcat提供了一些安全防 护的方法,而这是一种”容器管理”的安全防护。另一方面,如果有一系列具有自己的 登陆机制的servlet与JSP,则视此为一种应用程序管理的安全防护不管是哪种安全防护 类型,都使用称为领域(real)的组来管理用户与密码,本节会详细说明设定Tomcat的 领域,以及使用内嵌的功能来处理用户验证的方法。
在Tomcat的文件中的领域配置,以及Web应用程序的WEB-INF/web.xml文件中的<security-constraint>,分别定义了如何储存用户与角色信 息,及如何对webapp的用户进行授权。这两者都有许多设定的方式.也可以任意混和、随机搭使用。
领域
为了使用Tomcat的容器管理的安全阽护机制,必须设定领域,领域只是用户、密码及 角色的集合。Web应用程序可以在其web.xml中设定哪些用户组可以访问哪些资源,而 Tomcat的管理员则可以使用一个或多个领域实现来获取用户、密码及角色信息。
Tomcat含有可插入式的领域架构,并具备几种有用的领域实现:UserDatabaseRealm, JDBCRealm, JNDIRealm与JAASRealm。Java的开发者可以创建额外的领域实现,以便作为 与其用户和密码的接口。如欲指定应读使用何种领域,请在文件中插入Realm 元素,以className属性设定欲使用的领域,然后通过垓实现的自定义厲性以提供此领域 相关的配置信息:
cRealm className="sowe.realm.itnplementation,className11 customAttribute1=some custom value" customAttribute2=11 some other custom value "/>
后面的Realm配置是可以覆盖前面的。例如,在外部XML嵌套中,如果某个Realm被 配置为用于所有Host元素,而不是一个Host元素,且随后在文件的某个Host comainer元素中又声明了一个Realm,则第二个Realm的配置将用于包含该Realm的HOST元 素,但所有其他Host元素还是使用第一个Realm的配置
Tomcat的Realm API无法用来添加或移除用户,这不是Realm接口的一部分,您必须自己 想办法来添加或从领域中移除用户,除非您决定使用的领域刚好实现了这些功能。
UserDatabaseRealm
UserDatabaseRealm是从静态文件加载到内存中的,且直到Tomcat停止后才从内存中清 除。事实上,Tomcat所用的用户、密码及角色只存在于内存中;换句话说,权限文件 只会在启动时读入一次。在UseTDatabaseRealm中分配权限的默认文件为$CATALINA_HOME/conf目录中tomcat-users.xml。
tomcat-users.xml文件是使用此领域的关键。它包含一份可访问Web应用程序的用户淸 单。这是一个简单的XML文件,根元素是tomcat-users而且只能使用role及user元 素。毎个role元素只有一个属性:rolename。而每个user元素则有二个属性:username、 password及roles。示例2-1列出了Tomcat默认安装中所含的文件的内 容。
示例2-1 : tomcat-users.xml的发行版
<!-- 注意:在默认情况下,操作/manager" Web应用程序所需的“marager”角色中并不含有任何用 户。如果您要使用这个应用段序,必须定义用户名及密码均可任盘设定的用户。 --> <tomcat-users> <user name="tomcat" password="tomcat" roles="tomcat" /> <user name="role1" password="tomcat" roles="role1" /> <user name="both" passhord="tomcat" roles="tomcat, role1"/> </tomcat-users>
user与password的意义十分清楚了,不过在这里要解释一下有关roles的含义。角色 (role)是一组用户,而针对这组用户,Web应用程序可以定义一组特定的功能组合。 例如,Manager应用程序是Tomcat内含的一个示范性Web应用程序,它可以让您启用、停用以及移除其他的Web应用程序。要使用此应用程序,必须创建属干manager角色的用 户。当第一次访问Manager应用程序时,浏览器会要求输人此角色的用户名与密码,而 且除非使用该角色的用户登录,否则无法访问包含Manager应用程序的目录。
UserDatabaseRealms并非真正用于实际,因为它的唯一更新方式是编写能经由JNtM访问 Realm的自定义servlet。而该servlet需要能修改内存中的用户数据库,或磁盘上的tomcat-users.xml文件,最后,还需要重启动Tomcat,以便使这些修改生效。
JDBC Realm
相对UserDatabaseRealm而言,JDBCRealm具有更大的潜在的灵活性,并能动态地访问 数据。基本上这是使用关系型数据库的领域。用户、密码及角色保存在数据库中,而JDBCRealm会马上访问他们。例如,假设现成的管理软件在关系型数据库的数据表中新增 一个账号,JDBCRealm就会立刻访问它。在server.xml文件中,需要将JDBC的连接参数设成领域的属性。示例2-2列出的简单例子是为JabaDot新闻门户网站的JDBCRealm设定的。
示例2-2: JDBC Realm的示例
<!--替JabaDot用户数据库设定JDBC Real --> <Realm className="org.apache.catalina.realm.JDBCRealm" driverName="org. postgresql.Dliver" connectionURL="jdbc:postgresql:jabadot" connectionName="system" connectionPassword="something top secret" userTable="users" userCredCol="passwd" userRoleTable="controls" roleNameCol="roles" userNameCol="nick,/>
表2-2列出了使用JDBCRealm实现的Realm元素所允许的属性。
表 2-2: JDBCRealm 的厲性
属性 | 含义 |
---|---|
className | 此Realm实现的Java类名,对]DSCRealm而言,必须是org.apadie catalina.realm.JDBCRealm |
connectionName | 用来建立JDBC连接的数据库用户名称 |
connectionPassward | 用来建立JDBC连接的数据库密码 |
connectionURL | 用来建立JDBC连接的数据库URL |
digest | 摘要算法(SHA,MD2或只有MD5),默认值是"cleartext" |
driverName | JDBC驱动程序的Java类名 |
roleNameCol | 含有角色名(指定给用户)的角色表中的字段名 |
userNameCol | 在用户与角色数据表中,列出用户名的字段名 |
userCredCol | 用户数据表中,列出用户的密码的字段名 |
userRoleTable | 将角色映射至用户的数据表名 |
userTable | 列出用户与密码的数据表名 |
JNDIRealm
如果需要让Tomcat从LDAP目录取得用户名称,密码及角色,则可以使用JNDIRealma JNDIRealm是非常有弹性的Realm实现,可以依据用户名、密码及角色的LDAP目录来验 证用户的身份,同时还允许该数据用干许多不同的模式布局,JNDIRealm可以递归地搜寻 LDAP的层次目录,直到找到所需的信息为止,或者可以设定在目录服务器的特定位置 中寻找。您可以将密码存成明码的形式,并使用基本验证法,或者存储成摘要编码的形 式,而使用摘要验证法(下节会讨论这两种验证法)。
这是使用LDAP服务器的JNDIRealm示例:
<Realm className="org,apache.catalina.realm.JNDIRealm" connectionURL="ldap://ldap.groovywigs.com:389" userPattern="uid={0},ou=people,dc=groovywigs,dc=com" roleBase="out=groups,dc=groovywigs,dc=com" roleName="cn" roleSearch="(uniqueHember={o})"/>
JAASRealm
JMSRealm是经由JAAS (Java Authentication and Authorization Service, Java验证与授权服务)验证用户的一种领域实现。JAAS实现了标准的“可插入式验证模块” (PAM) 架构,此架构可让应用程序独立于验证实现之外。可以不经修改应用程序本身而只需 稍微修改应用程序的配置设定,在应用程序中插人垒新或更新的验证实现(此时为 Tomcat) 例如,依据Unix的用户/密码/组数据库,可以使用配置好的JAASRealm,验 证用户的身份,然后只需更改配置设定,而不需更改整个领域实现即可重新设定成依据 Kerberos来验证。除此之外,JAAS还支持堆栈式的验证模块,从而在一个验证堆桟中, 两个或三个验证模块可以彼此协同使用,对插入式验证模块进行堆栈处理,允许实现 Tomcat尚未实现自定义验证逻辑。
表2-4列出了 JAASRealm实现所支持的Realm属性。
表2-4: JAASRealm实现所支持的Realm属性
属性 | 含义 |
---|---|
className | 此领域实现的Java类名;对干]AASRealm必须是oig.apache. catalina.realm.JAASRealm |
appName | 传给JAAS LoginContext构造函数(并基于JAAS配置挑选适当的 登录方法)的应用程序名。默认值是“Tomcat”,不过,只要在JAAS.java.login.config文件中更改对应名,即可设成任何所要的值 |
userClassNames | 代表个别用户的javax.security.Principal类淸单,以逗号分隔。 对于UnixLoginModule设定值,应当包括UnixPrincipal类 |
roleClassNames | 代表安全角色的javax.security.Principal类治单,以逗号分隔。对于UnixLoginModule,设定值应该包栝UnixNumeric-GroupPrlncipal类 |
useContextClassLoader | 告知JAASRealm,或者从前后类加载器加载类,或者从Tomcat自身的类加载器加载类,默认值为true |
读者如杲想要在自己的计萬机上尝试使用专为UnixLoginModule设定的JAASRealm,请如示例2-3所示,在文件中安装Realm元素,在Web应用程序的文件中使 用示例2-4的配置,以及在主目录的根目录中加入java.login.conf件,其内容则可参阅 示例2-5。依据设置JVM的不同,在启动Tomcat前,可能需要先设定下列的环境变量, 让JAAS可以找到其登录的配置文件:
# export JAVA_OPTS=\ '-Djava .security.auth.login.config=/root/.java.login.config'
java.login.config文件可以存放于任何位置,只要以上面的环境变蚩指向它就可以了。
一旦启动Tomcat并首次请求受保护的资源时,JAASRealm应该会读取/etc/passwd及/etc/group文件,也会与OS交互比对密码,并且能使用该数据进行验证处理。
示例2-3:使用JAASRealm验证Unix用户与分组数据库的Realm配置
<Realm cla ssName='r org .apache, catalina. realm JAASRealm" userClassNames="com.sun.security.auth.UnixPrincipal" roleClassNames="com.sun.security.auth.UnixNumericGroupPrincipal"/>
示例2-4:显示给配置的JAASRealm的security-constraint、login-config 及 security-role 元 素的web.xml片段内容
<security-corstraint> <web-resource-collection> <web-resource-name>Entire Application</web-resource-name> <url- pattern>/*</url-pattern > </web-resource-collection> <auth-constraint> <role-name>0</role-name> </auth-constraint> </security-constraint> <login-config> <auth-method>FORM</auth-method> <realm-name>My Club Members-only Area</realm-name> <form-login-config> <forn-login-page>/login.html</form-login-page> <form-error-page>/error.html</form-error-page> </form-login-config> </login-config> <security-role> <role-name>0</role-name> </security-role>
示例2-5:存放于运行Tomcat的用户主目录中的JAAS.java.login.conf文件的完整内容
Tomcat { com.sun.security.auth.module.UnixLoginModule required debug=true; };
容器管理的安全防护
当访问受保护的资源时,容器管理的验证方法可以控制确认用户身份的方式。Tomcat支 持四种容器管理的安仝防护,而每种类型都以不同的方式取得身份:
基本验证 通过HTTP验证,需要提供base64编码文本的用户口令。
摘要验证
通过HTTP验证,需要提供摘要编码字符串的用户口令。
表单验证
在网页的表单上要求提供用户密码。
Client-cert 验证
以客户端数字证书来确认用户的身份。
单次签名(Single Sign-On)
设定好realm及验证方法后,需要处理用户登录的实际过程。对用户而言,登录应用程序 时常常令人庆烦,而您需要最小化必须验证身份的次数。每个Web应用裎序魷认要求用 户在第一次请求受保护的资源时登录。如果您执行多个Web应用程序.而每个程序都要 求用户验明身份,这对用户来说是有争议的&用户不能说清有多少独立的应用程序构成 了一个网站,所以他们不会知道正在请求跨越范围边界的资源,而会对为何要重复登录 感到疑惑不解。
Tomcat的“单次签名”功能可以让用户只需验明身份一次,就可访问虚拟主机上加载的 所有Web应用程序。如欲使用这个功能,您只需在主机 层加入SingleSignOn valve元素,在存储的Tomcat 6.0 server.xml文件中,该元素如下所示:
<!-- SingleSignOn valve,在Web应用程序中共享密码险证 文在/docs/cDnfig/valve,html中 --> <!-- <Valve className="org.apache.catalina.authenticator.SingleSignOn" /> -->
Tomcat发行版的默认server.xml文件含有被加上注释的单次签名的Valve配置示例,您可 以去掉注释并使用它。此后,在所设定虚拟主机内,任何在某context中被视为合法用 户,在同一主机的所有context内都会被视为合法。
使用单次签名的门阀(valve,门限)要注意如下一些重要约束:
必须设定vdve,且需将其嵌套在嵌套Web应用程序(以Context元素展现)的相同 Host元素中。
需要相同的Host层或外部嵌套层配置包含共享用户信息的Realm。
在Context层,Realm不能被覆盖。
使用单次签名的Web应用程序必须使用Tomcat内嵌的验证方法(在web.xml的auth- method元素中),而非自定义的验证方法。内嵌的方法包栝BASIC、DIGEST、FORM 及CLIENT-CERT验证几种形式。
如果使用单次签名,并希望在网站中整合另一个第三方的Web应用程序,且此新的 Web应用程序式使用自己的验证程序而不使用容器管理的安全防护机制,这基本上 是无法实现的对所有使用单一入口的Web应用程序,用户不得不登录一次,然后 当他们请求新的第三方的Web应用程序时,还要再登陆一次。如果您有源代码且又 是开发者,当然可以修改它,但可能不是这么简单。
单次签名的valve需要使用HTTP的cookie。
Servlet规范将用于储存用户会话(session) ID的cookie名的JSESSIONID名进行了标准化,在任何给定的HTTP客户端上,对每个Web应用程序而言,此会话ID值是唯一的, 即使使用了单次签名。SingleSignOnValue增加了自己的cookie井命名为JSESSI0NIDSS0, 它不是servlet规范的一部分,但为了使TomCat的单次签名功能能生效,您还必须要提供它。