本文檔介紹了如何借助一個(gè)“數(shù)據(jù)庫(kù)”來(lái)配置 Tomcat ,從而實(shí)現(xiàn)容器管理安全性。所要連接的這種數(shù)據(jù)庫(kù)含有用戶名、密碼以及用戶角色。你只需知道的是,如果使用的 Web 應(yīng)用含有一個(gè)或多個(gè) 元素, 元素定義了用戶驗(yàn)證的必需細(xì)節(jié)信息。如果你不打算使用這些功能,則可以忽略這篇文檔。
關(guān)于容器管理安全性的基礎(chǔ)知識(shí),可參考 Servlet Specification (Version 2.4) 中的第 12 節(jié)內(nèi)容。
Realm(安全域)其實(shí)就是一個(gè)存儲(chǔ)用戶名和密碼的“數(shù)據(jù)庫(kù)”再加上一個(gè)枚舉列表。“數(shù)據(jù)庫(kù)”中的用戶名和密碼是用來(lái)驗(yàn)證 Web 應(yīng)用(或 Web 應(yīng)用集合)用戶合法性的,而每一合法用戶所對(duì)應(yīng)的角色存儲(chǔ)在枚舉列表中。可以把這些角色看成是類似 UNIX 系統(tǒng)中的 group(分組),因?yàn)橹挥心軌驌碛刑囟ń巧挠脩舨拍茉L問(wèn)特定的 Web 應(yīng)用資源(而不是通過(guò)對(duì)用戶名列表進(jìn)行枚舉適配)。特定用戶的用戶名下可以配置多個(gè)角色。
雖然 Servlet 規(guī)范描述了一個(gè)可移植機(jī)制,使應(yīng)用可以在 web.xml 部署描述符中聲明它們的安全需求,但卻沒(méi)有提供一種可移植 API 來(lái)定義出 Servlet 容器與相應(yīng)用戶及角色信息的接口。然而,在很多情況下,非常適于將 Servlet 容器與一些已有的驗(yàn)證數(shù)據(jù)庫(kù)或者生產(chǎn)環(huán)境中已存在的機(jī)制“連接”起來(lái)。因此,Tomcat 定義了一個(gè) Java 接口(org.apache.catalina.Realm),通過(guò)“插入”組件來(lái)建立連接。提供了 6 種標(biāo)準(zhǔn)插件,支持與各種驗(yàn)證信息源的連接:
另外,還可以編寫(xiě)自定義 Realm 實(shí)現(xiàn),將其整合到 Tomcat 中,只需這樣做:
在詳細(xì)介紹標(biāo)準(zhǔn) Realm 實(shí)現(xiàn)之前,簡(jiǎn)要了解 Realm 的配置方式是很關(guān)鍵的一步。大體來(lái)說(shuō),就是需要在conf/server.xml 配置文件中添加一個(gè) XML 元素,如下所示:
<Realm className="... class name for this implementation"
???????... other attributes for?this?implementation .../> ?
可以嵌入以下任何一種 Container 元素中。Realm 元素的位置至關(guān)重要,它會(huì)對(duì) Realm 的“范圍”(比如說(shuō)哪個(gè) Web 應(yīng)用能夠共享同一驗(yàn)證信息)有直接的影響。
對(duì)于每種標(biāo)準(zhǔn) Realm 實(shí)現(xiàn)來(lái)說(shuō),用戶的密碼默認(rèn)都是以明文方式保存的。在很多情況下,這種方式都非常糟糕,即使是一般的用戶也能收集到足夠的驗(yàn)證信息,從而以其他用戶的信息成功登錄。為了避免這種情況的發(fā)生,標(biāo)準(zhǔn) Realm 實(shí)現(xiàn)支持一種對(duì)用戶密碼進(jìn)行摘要式處理的機(jī)制,它能以無(wú)法輕易破解的形式對(duì)存儲(chǔ)的密碼進(jìn)行加密處理,同時(shí)保證Realm 實(shí)現(xiàn)仍能使用這種加密后的密碼進(jìn)行驗(yàn)證。
在標(biāo)準(zhǔn)的 Realm 驗(yàn)證時(shí),會(huì)將存儲(chǔ)的密碼與用戶所提供的密碼進(jìn)行比對(duì),這時(shí),我們可以通過(guò)指定 元素中的 digest 屬性來(lái)選擇摘要式密碼。該屬性值必須是一種java.security.MessageDigest 類所支持的摘要式算法(SHA、MD2、或 MD5)。當(dāng)你選擇該屬性值時(shí),存儲(chǔ)在 Realm 中的密碼內(nèi)容必須是明文格式,隨后它將被你所指定的算法進(jìn)行摘要式加密。
在調(diào)用 Realm 的 authenticate() 方法后,用戶所提供的明文密碼同樣也會(huì)利用上述你所指定的加密算法進(jìn)行加密,加密結(jié)果與 Realm 的返回值相比較。如果兩者相等,則表明原始密碼的明文形式更用戶所提供的密碼完全等同,因此該用戶身份驗(yàn)證成功。
可以采用以下兩種比較便利的方法來(lái)計(jì)算明文密碼的摘要值:
如果應(yīng)用需要?jiǎng)討B(tài)計(jì)算摘要式密碼,調(diào)用 org.apache.catalina.realm.RealmBase 類的靜態(tài) Digest() 方法,傳入明文密碼和摘要式算法名稱及字符編碼方案。該方法返回摘要式密碼。
如果使用 DIGEST 驗(yàn)證的摘要式密碼,用來(lái)生成摘要密碼的明文密碼則將有所不同,而且必須使用一次不加鹽的 MD5 算法。對(duì)應(yīng)到上面的范例,那就是必須把 {cleartext-password} 替換成 {username}:{realm}:{cleartext-password}。再比如說(shuō),在一個(gè)開(kāi)發(fā)環(huán)境中,可能采用這種形式:testUser:Authentication required:testPassword。{realm} 的值取自 Web 應(yīng)用 的 元素。如果沒(méi)有在 web.xml 中指定,則使用默認(rèn)的Authentication required。
若要使用非平臺(tái)默認(rèn)編碼的用戶名和(或)密碼,則命令如下:
CATALINA_HOME/bin/digest.[bat|sh] -a {algorithm} -e {encoding} {input}
但需要注意的是,一定要確保輸入正確地傳入摘要。摘要返回 {input}:{digest}。如果輸入在返回時(shí)出現(xiàn)損壞,摘要?jiǎng)t將無(wú)效。
摘要的輸出格式為 {salt}${iterations}${digest}。如果鹽的長(zhǎng)度為 0,迭代次數(shù)為 1,則輸出將簡(jiǎn)化為 {digest}。
CATALINA_HOME/bin/digest.[bat|sh] 的完整格式如下:
CATALINA_HOME/bin/digest.[bat|sh] [-a ] [-e ]
????????[-i ] [-s ] [-k ]
????????[-h ] ??
Tomcat 自帶的范例應(yīng)用中包含一個(gè)受到安全限制保護(hù)的區(qū)域,使用表單式登錄方式。為了訪問(wèn)它,在你的瀏覽器地址欄中輸入 http://localhost:8080/examples/jsp/security/protected/,并使用 UserDatabaseRealm 默認(rèn)的用戶名和密碼進(jìn)行登錄。
如果你希望使用 Manager 應(yīng)用在一個(gè)運(yùn)行的 Tomcat 安裝上來(lái)部署或取消部署 Web 應(yīng)用,那么必須在一個(gè)選定的 Realm 實(shí)現(xiàn)上,將 manager-gui 角色添加到至少一個(gè)用戶名上。這是因?yàn)?Manager 自身使用一個(gè)安全限制,要想在該應(yīng)用的 HTML 界面中訪問(wèn)請(qǐng)求 URI,就必須要有 manager-gui 角色。
出于安全性考慮,默認(rèn)情況下,Realm 中的用戶名(比如使用 conf/tomcat-users.xml)沒(méi)有被分配 manager-gui 角色。因此,用戶起初無(wú)法使用這個(gè)功能,除非 Tomcat 管理員特意將這一角色分配給他們。
Realm 的容器(Context、Host 及 Engine)所對(duì)應(yīng)的日志配置文件將記錄 Realm 所記錄下的調(diào)試和異常信息。