領域設定操作方法
目次
クイックスタート
此文件說明如何設定 Tomcat 以支援容器管理的安全性,方法是連線到現有的使用者名稱、密碼和使用者角色「資料庫」。只有在您使用包含一個或多個 <security-constraint>
元素和定義使用者如何驗證自己的身分的 <login-config>
元素的 Web 應用程式時,才需要留心這一點。如果您沒有使用這些功能,您可以安全地略過此文件。
有關容器管理的安全性基本背景資訊,請參閱 Servlet 規範(第 2.4 版) 的第 12 節。
有關使用 Tomcat 的單一登入功能(允許使用者在與虛擬主機相關聯的所有 Web 應用程式中驗證自己一次)的資訊,請參閱 此處。
概要
領域とは
領域是識別 Web 應用程式(或一組 Web 應用程式)的有效使用者的使用者名稱和密碼「資料庫」,以及與每個有效使用者相關聯的角色清單。您可以將角色視為類似於類 Unix 作業系統中的群組,因為特定 Web 應用程式資源的存取權限會授與給擁有特定角色的所有使用者(而不是列舉相關聯的使用者名稱清單)。特定使用者可以有任意數量的角色與其使用者名稱相關聯。
雖然 Servlet 規範描述了應用程式宣告其安全性需求的可攜式機制(在 web.xml
部署描述子中),但沒有可攜式 API 定義 Servlet 容器與相關使用者和角色資訊之間的介面。然而,在許多情況下,將 Servlet 容器「連線」到生產環境中已存在的某些現有驗證資料庫或機制是可取的。因此,Tomcat 定義了一個 Java 介面 (org.apache.catalina.Realm
),可由「外掛」元件實作以建立此連線。提供了六個標準外掛程式,支援連線到各種驗證資訊來源
- DataSourceRealm - 存取儲存在關聯式資料庫中的驗證資訊,透過命名的 JNDI JDBC 資料來源存取。
- JNDIRealm - 存取儲存在基於 LDAP 的目錄伺服器中的驗證資訊,透過 JNDI 提供者存取。
- UserDatabaseRealm - 存取儲存在 UserDatabase JNDI 資源中的驗證資訊,通常由 XML 文件 (
conf/tomcat-users.xml
) 支援。 - MemoryRealm - 存取儲存在記憶體中物件集合中的驗證資訊,該集合由 XML 文件 (
conf/tomcat-users.xml
) 初始化。 - JAASRealm - 透過 Java 驗證和授權服務 (JAAS) 架構存取驗證資訊。
您也可以撰寫自己的 Realm
實作,並將其與 Tomcat 整合。為此,您需要
- 實作
org.apache.catalina.Realm
, - 將編譯好的 Realm 放置於 $CATALINA_HOME/lib 中,
- 在下方「設定 Realm」區段中,宣告您的 Realm,
- 向 MBeans 描述符 宣告您的 Realm。
領域の設定
在深入探討標準 Realm 實作的細節之前,了解 Realm 的設定方式非常重要。一般而言,您會在 conf/server.xml
設定檔中加入一個 XML 元素,如下所示
<Realm className="... class name for this implementation"
... other attributes for this implementation .../>
<Realm>
元素可以嵌套在下列任一 Container
元素中。Realm 元素的位置會直接影響該 Realm 的「範圍」(例如,哪些 Web 應用程式會共用相同的驗證資訊)
- 在 <Engine> 元素中 - 這個 Realm 會在所有虛擬主機上的所有 Web 應用程式中共用,除非它被嵌套在從屬的
<Host>
或<Context>
元素中的 Realm 元素覆寫。 - 在 <Host> 元素中 - 這個 Realm 會在這個虛擬主機的所有 Web 應用程式中共用,除非它被嵌套在從屬的
<Context>
元素中的 Realm 元素覆寫。 - 在 <Context> 元素中 - 這個 Realm 僅會用於這個 Web 應用程式。
共通機能
ダイジェストパスワード
對於每個標準的 Realm
實作,使用者的密碼(預設)會以明文儲存。在許多環境中,這是不被允許的,因為驗證資料的隨意觀察者可以收集足夠的資訊來成功登入,並冒充其他使用者。為避免這個問題,標準實作支援摘要使用者密碼的概念。這允許以編碼方式儲存密碼(以不易還原的形式),但 Realm
實作仍可將其用於驗證。
當標準 Realm 透過擷取儲存的密碼並將其與使用者提供的密碼進行比較來進行驗證時,您可以透過在 <Realm>
元素中放置 CredentialHandler
元素來選擇摘要密碼。支援 SSHA、SHA 或 MD5 等演算法的簡單選擇是使用 MessageDigestCredentialHandler
。此元素必須設定為 java.security.MessageDigest
類別支援的摘要演算法之一(SSHA、SHA 或 MD5)。當您選擇這個選項時,儲存在 Realm
中的密碼內容必須是經過指定演算法摘要處理的密碼明文版本。
當呼叫 Realm 的 authenticate()
方法時,使用者指定的(明文)密碼本身會由相同的演算法摘要處理,而結果會與 Realm
傳回的值進行比較。相等的比對結果表示原始密碼的明文版本與使用者提供的密碼相同,因此這個使用者應該被授權。
為了計算明文密碼的摘要值,支援兩種便利的技術
- 如果您正在撰寫需要動態計算摘要密碼的應用程式,請呼叫
org.apache.catalina.realm.RealmBase
類別的靜態Digest()
方法,傳遞明文密碼、摘要演算法名稱和編碼作為引數。此方法將會傳回摘要密碼。 - 如果您想要執行命令列公用程式來計算摘要密碼,請直接執行
此明文密碼的摘要版本將會傳回標準輸出。
CATALINA_HOME/bin/digest.[bat|sh] -a {algorithm} {cleartext-password}
如果使用摘要密碼搭配 DIGEST 驗證,用於產生摘要的明文會有所不同,而摘要必須使用 MD5 演算法的單一反覆運算,且不含鹽值。在上述範例中,{cleartext-password}
必須替換為 {username}:{realm}:{cleartext-password}
。例如,在開發環境中,這可能會採用 testUser:Authentication required:testPassword
的形式。{realm}
的值取自於 Web 應用程式的 <login-config>
的 <realm-name>
元素。如果未在 web.xml 中指定,則會使用 Authentication required
的預設值。
使用
CATALINA_HOME/bin/digest.[bat|sh] -a {algorithm} -e {encoding} {input}
支援使用與平台預設值不同的編碼的使用者名稱和/或密碼,但必須小心確保輸入正確傳遞給摘要器。摘要器會傳回 {input}:{digest}
。如果輸入在傳回中顯示已損毀,則摘要將會無效。
摘要的輸出格式為 {salt}${iterations}${digest}
。如果鹽值長度為零,且反覆運算次數為一,則輸出會簡化為 {digest}
。
CATALINA_HOME/bin/digest.[bat|sh]
的完整語法為
CATALINA_HOME/bin/digest.[bat|sh] [-a <algorithm>] [-e <encoding>]
[-i <iterations>] [-s <salt-length>] [-k <key-length>]
[-h <handler-class-name>] [-f <password-file> | <credentials>]
- -a - 用於產生儲存憑證的演算法。如果未指定,則會使用處理常式的預設值。如果未指定處理常式或演算法,則會使用
SHA-512
的預設值 - -e - 用於任何必要的位元組轉換為字元或字元轉換為位元組的編碼。如果未指定,則會使用系統編碼 (
Charset#defaultCharset()
)。 - -i - 產生儲存憑證時使用的反覆運算次數。如果未指定,則會使用 CredentialHandler 的預設值。
- -s - 作為憑證一部分產生並儲存的鹽值長度 (以位元組為單位)。如果未指定,則會使用 CredentialHandler 的預設值。
- -k - 產生憑證時建立的任何金鑰的長度 (以位元為單位)。如果未指定,則會使用 CredentialHandler 的預設值。
- -h - 要使用的 CredentialHandler 的完全限定類別名稱。如果未指定,則會依序測試內建處理常式 (MessageDigestCredentialHandler,然後是 SecretKeyCredentialHandler),並使用第一個接受指定演算法的處理常式。
- -f - 包含要編碼密碼的檔案名稱。檔案中的每一行都應該只包含一個密碼。使用此選項會忽略其他密碼輸入。
アプリケーションの例
隨 Tomcat 附帶的範例應用程式包含一個受安全約束保護,並使用表單式登入的區域。若要存取它,請將瀏覽器指向 https://127.0.0.1:8080/examples/jsp/security/protected/,並使用預設 UserDatabaseRealm 所描述的其中一個使用者名稱和密碼登入。
マネージャーアプリケーション
如果您想要使用 管理員應用程式 在正在執行的 Tomcat 安裝中部署和解除部署應用程式,您必須將「manager-gui」角色新增至所選領域實作中的至少一個使用者名稱。這是因為管理員網路應用程式本身使用安全約束,需要角色「manager-gui」才能存取該應用程式 HTML 介面中的任何要求 URI。
基於安全考量,預設領域中沒有任何使用者名稱(亦即使用 conf/tomcat-users.xml
)被指派「manager-gui」角色。因此,在 Tomcat 管理員特別將此角色指派給一個或多個使用者之前,沒有人能夠使用此應用程式的功能。
標準領域実装
DataSourceRealm
簡介
DataSourceRealm 是 Tomcat Realm
介面的實作,它會在透過 JNDI 命名 JDBC 資料來源存取的關聯式資料庫中查詢使用者。它具有大量的設定彈性,讓您能夠調整至現有的表格和欄位名稱,只要您的資料庫結構符合下列需求即可
- 必須有一個表格,以下稱為使用者表格,其中包含此
Realm
應辨識的每一個有效使用者的單一列。 - 使用者表格必須包含至少兩欄(如果現有的應用程式需要,它可以包含更多欄)
- 使用者登入時,Tomcat 會辨識的使用者名稱。
- 使用者登入時,Tomcat 會辨識的密碼。此值可以是明文或摘要 - 請參閱下方以取得更多資訊。
- 必須有一個表格,以下稱為使用者角色表格,其中包含指派給特定使用者的每一個有效角色的單一列。使用者可以有零個、一個或多個有效角色。
- 使用者角色表格必須包含至少兩欄(如果現有的應用程式需要,它可以包含更多欄)
- Tomcat 會辨識的使用者名稱(與在使用者表格中指定的相同值)。
- 與此使用者相關聯的有效角色名稱。
クイックスタート
若要設定 Tomcat 以使用 DataSourceRealm,您需要執行下列步驟
- 如果您尚未執行此步驟,請在資料庫中建立符合上述需求的表格和欄位。
- 設定 Tomcat 可使用的資料庫使用者名稱和密碼,至少擁有上述表格的唯讀存取權限。(Tomcat 永遠不會嘗試寫入這些表格。)
- 設定資料庫的 JNDI 名稱 JDBC 資料來源。請參閱 JNDI 資料來源範例操作指南,以取得如何設定 JNDI 名稱 JDBC 資料來源的資訊。務必根據 JNDI 資料來源定義的位置,適當地設定
Realm
的localDataSource
屬性。 - 在
$CATALINA_BASE/conf/server.xml
檔案中,設定<Realm>
元素,如下所述。 - 如果 Tomcat 已在執行中,請重新啟動 Tomcat。
Realm 元素屬性
若要設定 DataSourceRealm,您將建立一個 <Realm>
元素,並將其嵌套在 $CATALINA_BASE/conf/server.xml
檔案中,如 上方 所述。DataSourceRealm 的屬性定義在 Realm 設定文件當中。
範例
建立所需表格的 SQL 範例腳本可能如下所示(根據您的特定資料庫調整語法)
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 資料庫的範例,設定上述表格,並使用 JNDI JDBC 資料來源,名稱為「java:/comp/env/jdbc/authority」。
<Realm className="org.apache.catalina.realm.DataSourceRealm"
dataSourceName="jdbc/authority"
userTable="users" userNameCol="user_name" userCredCol="user_pass"
userRoleTable="user_roles" roleNameCol="role_name"/>
其他注意事項
DataSourceRealm 根據下列規則運作
- 當使用者嘗試第一次存取受保護的資源時,Tomcat 將呼叫此
Realm
的authenticate()
方法。因此,您直接對資料庫所做的任何變更(新增使用者、變更密碼或角色等)將立即反映出來。 - 使用者經過驗證後,使用者(及其關聯的角色)會快取在 Tomcat 中,直到使用者登入為止。(對於基於 FORM 的驗證,表示直到工作階段逾時或失效為止;對於 BASIC 驗證,表示直到使用者關閉瀏覽器為止)。快取的使用者不會儲存和還原跨工作階段序列化。已經驗證使用者的資料庫資訊有任何變更,不會反映在使用者下次再次登入之前。
- 管理使用者和使用者角色表格中的資訊是您自己的應用程式的責任。Tomcat 沒有提供任何內建功能來維護使用者和角色。
JNDIRealm
簡介
JNDIRealm 是 Tomcat Realm
介面的實作,會在 JNDI 提供者(通常是與 JNDI API 類別一起提供的標準 LDAP 提供者)存取的 LDAP 目錄伺服器中尋找使用者。此領域支援使用目錄進行驗證的各種方法。
連線到目錄
領域與目錄的連線由connectionURL 組態屬性定義。這是一個由 JNDI 提供者定義格式的 URL。它通常是 LDAP URL,用來指定要連線的目錄伺服器的網域名稱,以及(選擇性)埠號和所需根命名內容的識別名稱 (DN)。
如果您有多個提供者,您可以組態alternateURL。如果無法在connectionURL 對提供者建立 socket 連線,系統會嘗試使用alternateURL。
為了搜尋目錄並擷取使用者和角色資訊,領域會使用connectionName 和connectionPassword 屬性指定的使用者名稱和密碼,向目錄驗證自身。如果未指定這些屬性,連線會是匿名的。在許多情況下,這就已足夠。
選取使用者的目錄項目
每個可以驗證的使用者都必須在目錄中由一個個別項目表示,此項目對應到connectionURL 屬性定義的初始 DirContext
中的一個元素。此使用者項目必須有一個包含用於驗證的使用者名稱的屬性。
通常使用者的項目識別名稱包含用於驗證的使用者名稱,但對所有使用者而言都是相同的。在這種情況下,userPattern 屬性可以用來指定 DN,其中「{0}」標記出應替換使用者名稱的位置。
否則,領域必須搜尋目錄才能找到包含使用者名稱的唯一項目。下列屬性會組態此搜尋
- userBase - 為包含使用者的子樹的基礎條目。如果未指定,搜尋基礎為頂層內容。
- userSubtree - 搜尋範圍。如果希望搜尋以 userBase 條目為根的整個子樹,請設定為
true
。預設值false
會要求單層級搜尋,僅包含頂層。 - userSearch - 指定在替換使用者名稱後要使用的 LDAP 搜尋篩選器的模式。
驗證使用者
-
繫結模式
預設情況下,領域會透過繫結至目錄(使用該使用者的條目 DN 和使用者提供的密碼)來驗證使用者。如果此簡單繫結成功,使用者即被視為已驗證。
基於安全性考量,目錄可能會儲存使用者的密碼摘要,而非明文版本(更多資訊,請參閱 已摘要密碼)。在這種情況下,目錄會在簡單繫結作業的一部分中,自動計算使用者提供的純文字密碼的正確摘要,然後再與儲存的值進行驗證。因此,在繫結模式中,領域不會參與摘要處理。摘要屬性不會使用,如果設定,將會被忽略。
-
比較模式
或者,領域可以從目錄中擷取儲存的密碼,並與使用者提供的密碼明確比較。此模式透過將 userPassword 屬性設定為使用者條目中包含密碼的目錄屬性名稱來設定。
比較模式有一些缺點。首先,必須設定 connectionName 和 connectionPassword 屬性,才能讓領域在目錄中讀取使用者的密碼。基於安全性考量,這通常是不希望的;事實上,許多目錄實作甚至不允許目錄管理員讀取這些密碼。此外,領域必須自行處理密碼摘要,包括所使用的演算法變異,以及在目錄中表示密碼雜湊的方式。但是,領域有時可能需要存取儲存的密碼,例如支援 HTTP Digest 存取驗證 (RFC 2069)。(請注意,HTTP 摘要驗證不同於上文所討論的使用者資訊儲存庫中的密碼摘要)。
將角色指派給使用者
目錄領域支援兩種方法來表示目錄中的角色
-
角色作為明確的目錄項目
角色可以用明確的目錄項目表示。角色項目通常是 LDAP 群組項目,其中一個屬性包含角色名稱,另一個屬性包含該角色中使用者的識別名稱或使用者名稱。下列屬性會設定目錄搜尋,以尋找與經過驗證的使用者相關聯的角色名稱
- roleBase - 角色搜尋的基本項目。如果未指定,搜尋基礎就是頂層目錄內容。
- roleSubtree - 搜尋範圍。如果希望搜尋以
roleBase
項目為根的整個子樹,請設定為true
。預設值false
會要求單層級搜尋,僅包含頂層。 - roleSearch - 用於選取角色項目的 LDAP 搜尋篩選條件。它可以包含經過驗證使用者的識別名稱和/或使用者名稱和/或使用者目錄項目中屬性的模式替換 "{0}" 和/或 "{1}" 和/或 "{2}"。使用 userRoleAttribute 指定提供 "{2}" 值的屬性名稱。
- roleName - 角色項目中包含該角色名稱的屬性。
- roleNested - 啟用巢狀角色。如果希望在角色中巢狀角色,請設定為
true
。如果設定,則會遞迴嘗試每個新找到的 roleName 和識別名稱,以進行新的角色搜尋。預設值為false
。
-
角色作為使用者項目屬性
角色名稱也可以作為使用者目錄項目中屬性的值。使用 userRoleName 指定此屬性名稱。
可以同時使用這兩種角色表示方法。
クイックスタート
若要設定 Tomcat 使用 JNDIRealm,您需要執行下列步驟
- 請確定您的目錄伺服器已設定符合上述需求的架構。
- 如果需要,請為 Tomcat 設定使用者名稱和密碼,以取得對上述資訊的唯讀權限。(Tomcat 永遠不會嘗試修改此資訊。)
- 在
$CATALINA_BASE/conf/server.xml
檔案中,設定<Realm>
元素,如下所述。 - 如果 Tomcat 已在執行中,請重新啟動 Tomcat。
Realm 元素屬性
若要設定 JNDIRealm,您需要建立一個 <Realm>
元素,並將它巢狀在您的 $CATALINA_BASE/conf/server.xml
檔案中,如 上方所述。JNDIRealm 的屬性定義在 Realm 設定文件檔中。
範例
在您的目錄伺服器中建立適當的架構不在本文件討論範圍內,因為它會因每個目錄伺服器實作而異。在下列範例中,我們會假設您使用的是 OpenLDAP 目錄伺服器 (版本 2.0.11 或更新版本),它可以從 https://www.openldap.org 下載。假設您的 slapd.conf
檔案包含下列設定 (以及其他設定)
database ldbm
suffix dc="mycompany",dc="com"
rootdn "cn=Manager,dc=mycompany,dc=com"
rootpw secret
對於 connectionURL
,我們將假設目錄伺服器與 Tomcat 執行於同一台機器上。請參閱 http://docs.oracle.com/javase/7/docs/technotes/guides/jndi/index.html,以取得有關設定和使用 JNDI LDAP 提供者的更多資訊。
接下來,假設此目錄伺服器已填充如下所示的元素(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(例如 jjones)登入應用程式,且匿名連線足以搜尋目錄並擷取角色資訊,則針對上述設定的 OpenLDAP 目錄伺服器,範例 Realm
元素可能如下所示
<Realm className="org.apache.catalina.realm.JNDIRealm"
connectionURL="ldap://127.0.0.1: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 和使用者提供的密碼繫結至目錄進行驗證,然後搜尋目錄以找出使用者的角色。
現在假設在登入時,使用者預期輸入電子郵件地址,而非使用者 ID。在此情況下,realm 必須搜尋目錄以找出使用者的項目。(當使用者項目保存在對應於不同組織單位或公司位置的多個子樹中時,也需要進行搜尋)。
此外,假設除了群組項目外,您還想要使用使用者項目的屬性來儲存角色。現在,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"
connectionURL="ldap://127.0.0.1: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 會搜尋目錄以找出具有該值作為其郵件屬性的唯一項目,並嘗試以 uid=jjones,ou=people,dc=mycompany,dc=com
和提供的密碼繫結至目錄。如果驗證成功,則會指派三個角色給他們:「role2」和「role3」(其目錄項目中「memberOf」屬性的值),以及「tomcat」(他們所屬的唯一群組項目中「cn」屬性的值)。
最後,若要透過從目錄中擷取密碼並在 realm 中進行本地比對來驗證使用者,您可以使用類似這樣的 realm 設定
<Realm className="org.apache.catalina.realm.JNDIRealm"
connectionName="cn=Manager,dc=mycompany,dc=com"
connectionPassword="secret"
connectionURL="ldap://127.0.0.1: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 會呼叫此
Realm
的authenticate()
方法。因此,您對目錄所做的任何變更(新增使用者、變更密碼或角色等)都會立即反映出來。 - 使用者驗證後,使用者(及其關聯的角色)會在 Tomcat 中快取,持續時間為使用者的登入期間。(對於基於 FORM 的驗證,表示在工作階段逾時或失效之前;對於 BASIC 驗證,表示在使用者關閉瀏覽器之前)。快取的使用者不會在工作階段序列化中儲存和還原。對於已驗證使用者的目錄資訊的任何變更,不會反映在使用者下次再次登入之前。
- 管理目錄伺服器中的資訊是您自己的應用程式的責任。Tomcat 沒有提供任何內建功能來維護使用者和角色。
UserDatabaseRealm
簡介
UserDatabaseRealm 是 Tomcat Realm
介面的實作,使用 JNDI 資源儲存使用者資訊。預設情況下,JNDI 資源由 XML 檔案支援。它並非設計用於大規模生產用途。在啟動時,UserDatabaseRealm 會從 XML 文件載入所有使用者的資訊及其對應的角色(預設情況下,此文件會從 $CATALINA_BASE/conf/tomcat-users.xml
載入)。使用者、其密碼及其角色都可能動態編輯,通常透過 JMX。變更可以儲存,並會反映在 XML 檔案中。
Realm 元素屬性
若要設定 UserDatabaseRealm,您將建立一個 <Realm>
元素,並將其嵌套在 $CATALINA_BASE/conf/server.xml
檔案中,如 上方 所述。UserDatabaseRealm 的屬性定義在 Realm 設定文件檔中。
使用者檔案格式
對於基於 XML 檔案的 UserDatabase
,使用者檔案使用與 MemoryRealm 相同的格式。
範例
Tomcat 的預設安裝設定嵌套在 <Engine>
元素內的 UserDatabaseRealm,以便套用至所有虛擬主機和網路應用程式。conf/tomcat-users.xml
檔案的預設內容為
<tomcat-users>
<user username="tomcat" password="tomcat" roles="tomcat" />
<user username="role1" password="tomcat" roles="role1" />
<user username="both" password="tomcat" roles="tomcat,role1" />
</tomcat-users>
其他注意事項
UserDatabaseRealm 根據下列規則操作
- 當 Tomcat 首次啟動時,它會從使用者檔案載入所有已定義的使用者及其關聯資訊。對此檔案中的資料所做的變更將不會在 Tomcat 重新啟動之前被辨識。變更可以透過 UserDatabase 資源進行。Tomcat 提供可透過 JMX 存取的 MBeans 以供此目的使用。
- 當使用者嘗試首次存取受保護資源時,Tomcat 會呼叫此
Realm
的authenticate()
方法。 - 使用者經過驗證後,將在使用者登入期間與 Tomcat 關聯。(對於基於 FORM 的驗證,表示在工作階段逾時或失效之前;對於 BASIC 驗證,表示在使用者關閉其瀏覽器之前)。然而,使用者角色仍會反映
UserDatabase
內容,這與其他 realm 不同。如果使用者從資料庫中移除,將會被視為沒有任何角色。UserDatabaseRealm
的useStaticPrincipal
屬性可用於快取使用者及其所有角色。快取的使用者不會在工作階段序列化中儲存和還原。當使用者的主體物件因任何原因而序列化時,它也會被具有角色的靜態等效物件取代,而這些角色將不再反映資料庫內容。
MemoryRealm
簡介
MemoryRealm 是 Tomcat Realm
介面的簡單示範實作。它並非設計用於生產用途。在啟動時,MemoryRealm 會從 XML 文件載入所有使用者的資訊及其對應的角色(預設情況下,此文件會從 $CATALINA_BASE/conf/tomcat-users.xml
載入)。對此檔案中的資料所做的變更將不會在 Tomcat 重新啟動之前被辨識。
Realm 元素屬性
若要設定 MemoryRealm,您將建立一個 <Realm>
元素,並將其嵌套在 $CATALINA_BASE/conf/server.xml
檔案中,如 上方 所述。MemoryRealm 的屬性定義在 Realm 設定文件檔中。
使用者檔案格式
使用者檔案(預設為 conf/tomcat-users.xml
)必須是 XML 文件,其根元素為 <tomcat-users>
。根元素內將嵌套一個 <user>
元素,代表每個有效使用者,包含下列屬性
- 名稱 - 此使用者必須用來登入的使用者名稱。
- 密碼 - 此使用者必須用來登入的密碼(如果
<Realm>
元素未設定digest
屬性,則為明文;否則,會按照 此處 所述適當地摘要處理)。 - 角色 - 與此使用者相關聯的角色名稱的逗號分隔清單。
其他注意事項
MemoryRealm 根據下列規則運作
- 當 Tomcat 第一次啟動時,它會從使用者檔案載入所有已定義的使用者及其相關資訊。此檔案中的資料變更將不會在 Tomcat 重新啟動之前被辨識出來。
- 當使用者嘗試首次存取受保護資源時,Tomcat 會呼叫此
Realm
的authenticate()
方法。 - 使用者經過驗證後,使用者(及其相關角色)會在 Tomcat 中快取,持續到使用者登入期間。(對於基於 FORM 的驗證,這表示在工作階段逾時或失效之前;對於 BASIC 驗證,這表示在使用者關閉瀏覽器之前)。快取的使用者不會在工作階段序列化中儲存和還原。
- 管理使用者檔案中的資訊是應用程式的責任。Tomcat 沒有提供任何內建功能來維護使用者和角色。
JAASRealm
簡介
JAASRealm 是 Tomcat Realm
介面的實作,它透過 Java 驗證與授權服務 (JAAS) 架構來驗證使用者,該架構現在提供為標準 Java SE API 的一部分。
使用 JAASRealm 讓開發人員能夠將幾乎任何可以想像的安全領域與 Tomcat 的 CMA 結合起來。
JAASRealm 是 Tomcat 的 J2EE v1.4 JAAS-based J2EE 驗證架構的原型,基於 JCP 規格要求 196,以增強容器管理的安全性和推廣「可插入」驗證機制,其實作會與容器無關。
根據 JAAS 登入模組和主體(請參閱 javax.security.auth.spi.LoginModule
和 javax.security.Principal
),您可以開發自己的安全機制,或包裝其他第三方機制,以與 Tomcat 實作的 CMA 整合。
クイックスタート
若要設定 Tomcat 使用 JAASRealm 和您自己的 JAAS 登入模組,您需要遵循下列步驟
- 根據 JAAS 編寫您自己的 LoginModule、使用者和角色類別(請參閱 JAAS 驗證教學 和 JAAS 登入模組開發人員指南),由 JAAS 登入內容(
javax.security.auth.login.LoginContext
)管理。在開發 LoginModule 時,請注意 JAASRealm 的內建CallbackHandler
目前僅辨識NameCallback
和PasswordCallback
。 - 儘管 JAAS 未指定,您應該建立不同的類別來區分使用者和角色,延伸
javax.security.Principal
,以便 Tomcat 可以判斷從登入模組傳回的主體是使用者還是角色(請參閱org.apache.catalina.realm.JAASRealm
)。無論如何,傳回的第一個主體永遠會被視為使用者主體。 - 將已編譯的類別放置在 Tomcat 的類別路徑中
- 為 Java 設定 login.config 檔案(請參閱 JAAS LoginConfig 檔案),並透過指定其位置給 JVM 來告訴 Tomcat 在何處找到它,例如設定環境變數:
JAVA_OPTS=$JAVA_OPTS -Djava.security.auth.login.config==$CATALINA_BASE/conf/jaas.config
- 在 web.xml 中設定安全限制,以保護您要保護的資源
- 在 server.xml 中設定 JAASRealm 模組
- 如果 Tomcat 已在執行中,請重新啟動 Tomcat。
Realm 元素屬性
若要設定 JAASRealm,如上述步驟 6 所述,您必須建立一個 <Realm>
元素,並將它嵌在 <Engine>
節點內的 $CATALINA_BASE/conf/server.xml
檔案中。JAASRealm 的屬性定義在 Realm 設定文件。
範例
以下是 server.xml 片段範例。
<Realm className="org.apache.catalina.realm.JAASRealm"
appName="MyFooRealm"
userClassNames="org.foobar.realm.FooUser"
roleClassNames="org.foobar.realm.FooRole"/>
您的登入模組負責建立和儲存代表使用者的主體 (javax.security.auth.Subject
) 的使用者和角色物件。如果您的登入模組未建立使用者物件,但也不會擲回登入例外,則 Tomcat CMA 會中斷,而您會停留在 https://127.0.0.1:8080/myapp/j_security_check URI 或其他未指定的位置。
JAAS 方法的彈性有兩個面向
- 您可以在自己的登入模組中執行幕後所需的任何處理作業。
- 您可以透過變更設定並重新啟動伺服器,插入完全不同的 LoginModule,而無需變更應用程式的任何程式碼。
其他注意事項
- 當使用者第一次嘗試存取受保護的資源時,Tomcat 會呼叫此
Realm
的authenticate()
方法。因此,您直接在安全機制中所做的任何變更(新增使用者、變更密碼或角色等)都會立即反映出來。 - 使用者驗證後,使用者(及其關聯的角色)會快取在 Tomcat 中,持續到使用者登入期間。對於基於 FORM 的驗證,這表示在工作階段逾時或失效之前;對於 BASIC 驗證,這表示在使用者關閉瀏覽器之前。已驗證使用者的安全資訊的任何變更,在使用者下次再次登入之前,不會反映出來。
- 與其他
Realm
實作一樣,如果server.xml
中的<Realm>
元素包含digest
屬性,則支援摘要密碼;JAASRealm 的CallbackHandler
會在將密碼傳回LoginModule
之前摘要密碼
CombinedRealm
簡介
CombinedRealm 是 Tomcat Realm
介面的實作,它透過一個或多個子 Realm 來驗證使用者。
使用 CombinedRealm 可讓開發人員結合多個相同或不同類型的 Realm。這可用於針對不同的來源進行驗證,在一個 Realm 失敗時提供備援,或用於需要多個 Realm 的任何其他目的。
子 Realm 是透過在定義 CombinedRealm 的 Realm
元素內嵌套 Realm
元素來定義的。驗證將針對每個 Realm
按照它們列出的順序嘗試。針對任何 Realm 的驗證都足以驗證使用者。
Realm 元素屬性
若要設定 CombinedRealm,請建立一個 <Realm>
元素,並將它嵌在 <Engine>
或 <Host>
內的 $CATALINA_BASE/conf/server.xml
檔案中。您也可以將它嵌在 context.xml
檔案中的 <Context>
節點內。
範例
以下是 server.xml 片段使用 UserDatabase Realm 和 DataSource Realm 的範例。
<Realm className="org.apache.catalina.realm.CombinedRealm" >
<Realm className="org.apache.catalina.realm.UserDatabaseRealm"
resourceName="UserDatabase"/>
<Realm className="org.apache.catalina.realm.DataSourceRealm"
dataSourceName="jdbc/authority"
userTable="users" userNameCol="user_name" userCredCol="user_pass"
userRoleTable="user_roles" roleNameCol="role_name"/>
</Realm>
LockOutRealm
簡介
LockOutRealm 是 Tomcat Realm
介面的實作,它延伸 CombinedRealm 以提供鎖定功能,在特定時間內有太多次驗證失敗時,提供使用者鎖定機制。
為了確保正確運作,此 Realm 有合理的同步程度。
此 Realm 不需要修改基礎 Realm 或相關使用者儲存機制。它會記錄所有失敗的登入,包括不存在使用者的登入。為了防止透過故意使用無效使用者進行要求而導致阻斷服務攻擊(並因此導致此快取變大),已驗證失敗使用者的清單大小受到限制。
子 Realm 是透過在定義 LockOutRealm 的 Realm
元素內嵌套 Realm
元素來定義的。驗證會針對每個 Realm
依照列出的順序嘗試。針對任何 Realm 的驗證都足以驗證使用者。
Realm 元素屬性
若要設定 LockOutRealm,請建立一個 <Realm>
元素,並將它嵌在 <Engine>
或 <Host>
內的 $CATALINA_BASE/conf/server.xml
檔案中。您也可以將它嵌在 context.xml
檔案中的 <Context>
節點內。LockOutRealm 的屬性定義在 Realm 設定文件。
範例
以下是 server.xml 片段將鎖定功能新增至 UserDatabase Realm 的範例。
<Realm className="org.apache.catalina.realm.LockOutRealm" >
<Realm className="org.apache.catalina.realm.UserDatabaseRealm"
resourceName="UserDatabase"/>
</Realm>