簡介
Security Assertion Markup Language (SAML) 是用於表示和交換用戶 身份、身份驗證和屬性信息的 OASIS 開放標准。SAML 正在成為創建單點登錄 (SSO) 解 決方案的常用技術。對於希望向其業務伙伴的已授權用戶提供業務服務的公司,可以應 用這種技術創建 SSO 解決方案,從而跨企業聯合 Web 服務資源。
請考慮一個業 務場景:您希望自己的用戶能夠訪問伙伴公司的業務服務。最好的 SSO 效果是,用戶只 需向您的企業驗證身份,而不需要向其他公司驗證身份。當用戶訪問 Web 服務資源時, 可以使用 SAML 令牌傳遞用戶身份和屬性數據。由於業務和私密性問題,這些公司很可 能不會把它們的多個用戶目錄整合為單一公用用戶目錄。這意味著 SAML 令牌將包含來 自外部安全域的用戶身份,它們不是在業務服務提供者的用戶目錄中定義的。本文討論 如何使用 IBM® WebSphere® Application Server V7.0 Fix Pack 7 中的 SAML 支持跨多個安全域邊界斷言 SAML 令牌,以及使用外部安全域用戶身份和定制的 SAML 組屬性直接做出訪問控制決策。您會看到,與身份和組映射技術相比,根據信任關系斷 言外部身份和定制的組屬性更容易管理。
SAML 令牌
SAML 令牌由令牌頒 發者進行數字簽名以確保令牌的完整性。業務服務提供者可以檢驗令牌頒發者的數字簽 名,從而確認 SAML 令牌中用戶身份的真實性。檢驗令牌頒發者的數字簽名是檢驗業務 伙伴之間的信任關系的基礎。本文描述用於斷言 SAML 令牌以在應用服務器運行時環境 中創建用戶安全上下文的信任模型。本文還包含一個 EJB™ 3.0 Java™ API for XML Web Services (JAX-WS) 示例應用程序,通過它說明如何根據 SAML 令牌頒發 者和 Web 服務提供者之間的信任關系配置跨安全域 SAML 斷言。您將通過這個應用程序 學習如何配置業務服務,從而使用 SAML 令牌做出資源訪問控制決策。
使用應用服務器 SAML 令牌斷言信任模型構建 SSO 解決方案有許多優點:
對於用戶來說,優點是他們只需向自己的安全域驗證身份,然後就能夠通過信任關系 訪問業務伙伴的 Web 服務資源。用戶不需要管理其他安全域的賬號和身份驗證數據。
對於 IT 管理員來說,明顯的優點是通過使用基於標准的 SAML 技術實現廣泛的第三 方互操作性。
對於 IT 管理員的另一個主要優點是,降低聯合業務資源時的身份管理成本。不需要 整合公司的用戶目錄,即使這在業務場景中是可行的,這個任務也很麻煩。
對於 IT 管理員的另一個優點是,保留外部安全域中的用戶身份,可以在安全和業務 審計記錄中包含它們。
除非另外說明,本文中的 WebSphere Application Server 是指應用了 Fix Pack 7 (V7.0.0.7) 或更高版本的 WebSphere Application Server V7.0。
多安全域業務場景
圖 1 是一個 Web 服務聯合業務場景示例。圖中顯示三個 WebSphere Application Server 安全域,每個安全域包含自己的用戶存儲庫配置。這些安全域可以代表不同的業 務單位或不同的公司。左邊兩個安全域中的用戶發送 Web 服務消息以訪問右邊安全域的 資源。用戶在 SAML 令牌中發送他們的身份,向目標安全域指出自己的身份。Web 服務 提供者使用 SAML 用戶身份創建安全上下文;例如 JAAS 主體。做出資源訪問控制決策 需要代表客戶機的 JAAS 主體。
圖 1. 跨 WebSphere Application Server 安全域斷言 SAML 令牌
如果這三個安全域共享一個公用用戶目錄,那麼 Web 服務提供者只需把接收的 SAML 令牌的主體身份映射到本地用戶目錄中的用戶條目,就可以創建代表請求者的 JAAS 主 體。如果這三個安全域並不共享公用用戶目錄,Web 服務提供者仍然可以把接收的 SAML 主體身份映射到本地用戶目錄中的用戶條目,但是需要配置本地用戶目錄。如果安全域 代表單獨的公司或業務單位,每個安全域很可能有自己的用戶目錄。對於外部安全域和 外部用戶目錄中的每個用戶身份,管理員可以在本地用戶目錄中創建一個具有相同身份 的條目,這基本上是一對一映射配置。管理員也可以把外部安全域中的所有用戶身份映 射到本地用戶目錄中的單一用戶條目,這是多對一映射。在更一般的情況下,管理員可 以設置多對多映射,把外部用戶身份和組映射到本地用戶目錄中的某些用戶身份和組。
設置用於身份映射的身份和組很繁瑣,還會產生一種有意思的副作用。如果某人使用 原本只用於身份映射的用戶 ID 向本地安全域驗證身份,那麼會發生什麼呢?另外,隨 著安全域數量增加,映射配置很可能會變得更復雜。對於業務審計來說,也希望知道訪 問資源的原用戶。稍後介紹的一種方法可以完全避免身份映射,可以自然地保留原來的 用戶身份。
本文利用 WebSphere Application Server 的 多安全域 特性。一個安全域包含一套 單獨的安全策略和配置數據,其中包括用戶存儲庫配置。WebSphere Application Server 允許在一個計算單元中配置多個安全域。如果啟用全局安全性,可以配置至少一 個安全域作為管理安全域,再在同一計算單元中配置零個或多個應用安全域。管理安全 域由管理子系統使用,包括部署管理器、節點代理和管理控制台應用程序。如果沒有定 義應用安全域,管理安全域還作為應用服務器的默認安全域。應用服務器可以連接應用 安全域,服務器上部署的所有應用程序都使用這個安全域。
多個安全域提供更好的應用程序和用戶隔離。可信身份驗證領域 (TAR) 機制提供一 種安全、簡便的方法,可以管理來自外部安全域的用戶和應用程序以及對本地安全域中 資源的訪問,其前提條件是外部安全域是本地安全域所信任的。外部安全域用戶會保留 其身份,不需要針對本地用戶目錄檢驗他們。WebSphere Application Server V7.0 實 現通過 RMI/IIOP CSIv2 協議支持 LTPA 安全令牌和 EJB 資源訪問。WebSphere Application Server SAML 特性擴展了 TAR 機制,支持通過 Web 服務安全協議和 SAML 安全令牌訪問資源。
實際上,只要 SAML 令牌是由 Web 服務提供者所信任的令牌頒發者頒發的,Web 服 務提供者就可以接受來自外部安全域的 Web 服務請求。使用 SAML 令牌中的身份和組屬 性來創建 JAAS 主體。不需要通過訪問本地目錄查找任何本地用戶身份和屬性。可以把 可信外部安全域用戶身份和組直接分配給本地安全角色。這種機制不涉及配置本地用戶 目錄,因此顯著簡化了訪問控制配置。但是,Web 服務提供者如何檢查信任關系呢?
可以通過配置 WebSphere Application Server 中的 SAML 特性在三個點上執行信任 關系檢查。應用服務器可以檢查:
SAML 令牌頒發者的數字簽名是否有效,從而檢查令牌的真實性。
特定的頒發者是否確實可信,從而對用戶身份進行 SAML 斷言。
特定的頒發者是否代表可信的安全域,即是否允許這個安全域中的用戶進入目標安全 域。
檢查信任關系之後,Web 服務提供者可以對接收的 SAML 令牌執行斷言,從而使用 SAML 令牌頒發者名稱、用戶身份和可選的組成員關系屬性在安全上下文中創建客戶機調 用者主體。安全上下文的創建基於信任關系,所以應用服務器不需要針對本地安全域的 用戶存儲庫檢查 SAML 用戶身份。這種基於信任關系的方法不需要在本地用戶存儲庫中 定義或映射外部安全域的用戶。
如果涉及的所有安全域都是 WebSphere Application Server,那麼可以完整地使用 策略配置來設置跨安全域的 SAML 斷言和訪問控制,不需要其他代碼。但是,WebSphere Application Server 也支持發起請求的安全域或 SAML 令牌頒發者不是 WebSphere Application Server(或任何 IBM 產品)的場景。SAML 規范沒有指定組屬性名,所以 WebSphere Application Server 可以配置為使用任何 SAML 屬性代表用戶身份和組。如 果目標安全域不是 WebSphere Application Server,根據具體產品不同,可能可以通過 配置或定制代碼設置三個信任關系檢查,但是這種配置超出了本文的范圍。
可以按兩種方法之一使用策略集和綁定配置把包含外部安全域身份和組的客戶機調用 者主體傳播給下游的 Web 服務:
可以把 Web 服務請求中 原來的 SAML 令牌傳播 到 WebSphere Application Server ,在這種情況下將應用相同的信任關系檢查。
也可以在 Web 服務消息 中傳播整個客戶機 RunAs 主體,RunAs 主體中已經包含接 收到的 SAML 令牌。
作為最佳實踐,對於 Web 服務客戶機和 Web 服務提供者之間的消息交換應該采用傳 輸級保護(例如 SSL),或者采用消息級加密和簽名,或者同時采取這兩種保護機制。 圖 1 中使用藍色的鎖圖標表示消息保護。SAML 令牌中的所有信息(包括用戶身份和屬 性)必須由 SAML 令牌頒發者執行數字簽名。圖 1 中使用紅色的鎖圖標表示 SAML 令牌 由頒發者簽名。盡管本文假設所有安全域都由基於 WebSphere Application Server 的 系統組成,但是也可以對其他應用服務器應用這種技術。下一節介紹 WebSphere Application Server SAML 斷言信任模型。強烈建議配置其他廠商的應用服務器或編寫 代碼,從而相應地實施信任關系檢查。
信任模型
WebSphere Application Server 可以配置為根據與 SAML 令牌頒發者的信任關系斷 言 SAML 令牌。在創建安全上下文以斷言 SAML 令牌時,應用服務器不需要針對本地用 戶存儲庫檢驗 SAML 身份。WebSphere Application Server 信任模型在前面提到的三個 信任關系檢查點上執行信任關系檢查。信任關系檢查的基礎是 SAML 令牌由頒發者執行 數字簽名。
圖 2 所示的示例 SAML 2.0 發送者令牌包含整個 SAML 令牌的數字簽名。在對 SAML 令牌執行簽名時,必須使用封裝的簽名,這意味著嵌入的簽名覆蓋整個 SAML 令牌。數 字簽名 ds:Reference URI 屬性引用 SAML 令牌 ID _93B335BAA1D8B8811A1257438450816。SAML 令牌的頒發者使用自己的私鑰簽名 SAML 令 牌,在令牌中包含相應的 X.509 證書。圖中的 SAML 令牌圖標包含一個證書圖標,這表 示 SAML 令牌中嵌入的頒發者證書。Web 服務提供者可以使用嵌入的證書中的公鑰檢查 頒發者數字簽名的完整性,使用嵌入的證書檢查頒發者是否值得信任。
圖 2. 由頒發者執行數字簽名的示例 SAML 2.0 發送者令牌
第一個信任關系檢查點
第一個檢查點檢查頒發者簽名證書是否確實是應用服務器所信任的 SAML 令牌頒發者 。應用服務器根據配置的信任存儲中的證書檢查接收到的證書。然後,應用服務器使用 檢查過的頒發者簽名證書中的公鑰檢查 SAML 令牌數字簽名,從而檢查接收到的令牌的 完整性。數字簽名檢查確認接收到的 SAML 令牌中的信息沒有被篡改過。
在這個檢查點上,應用服務器確保它只接受來自可信頒發者的 SAML 令牌。
第二個信任關系檢查點
可以把應用服務器配置為針對策略集綁定配置檢查 SAML 令牌頒發者名稱屬性和包含 的簽名證書。為了實現最優結果,應該在策略集綁定配置中指定證書所有者名稱和 SAML 令牌頒發者名稱,讓應用服務器可以在簽名證書和頒發者名稱之間建立聯系。這樣,應 用服務器可以檢查由某個令牌頒發者(由指定的簽名證書表示)簽名的 SAML 令牌的頒 發者名稱是否與策略集綁定配置中定義的頒發者名稱一致。在默認情況下,應用服務器 使用 SAML 令牌頒發者名稱代表外部安全域。具體地說,應用服務器檢查頒發者是否確 實可信,從而只接受來自特定安全域的用戶。
這個檢查點對於維護應用服務器運行時完整性很重要;當某個 SAML 令牌頒發者被破 解時,它確保損害只限於來自這個安全域的用戶,不會擴散到屬於其他安全域的用戶。
第三個信任關系檢查點
應用服務器檢查外部安全域是否可信。具體地說,SAML 令牌頒發者名稱確實在入站 可信身份驗證領域列表中定義了。應用服務器有一個信任任何外部安全域的配置選項。 為了實現最優結果,應該在可信身份驗證領域列表中顯式地指定可信外部安全域。
在這個檢查點上,應用服務器確保只對可信外部安全域中的用戶允許 SAML 令牌斷言 。
主體確認方法考慮因素
WebSphere Application Server 支持 OASIS Web Services Security SAML Token Profile 1.1 Specification,支持發送者主體確認方法和密鑰持有者主體確認方法:
密鑰持有者主體確認方法要求整個 SAML 令牌由頒發者執行數字簽名,還有其他安全 需求。
發送者主體確認方法不要求應用服務器執行 SAML 令牌數字簽名。
在默認情況下,應用服務器檢查 SAML 令牌是否按照兩種確認方法的要求簽名。檢查 SAML 令牌數字簽名和簽名證書是 SAML 令牌斷言信任模型的基礎,信任模型應用於發送 者 SAML 令牌和密鑰持有者 SAML 令牌。對於密鑰持有者主體確認,SAML 令牌在密碼學 意義上與包含它的 SOAP 消息相關聯。因此,Web 服務客戶機使用 SAML 令牌中定義的 密鑰對 SOAP 請求消息執行數字簽名。因此,Web 服務接收者可以檢查 Web 服務客戶機 是否確實知道密鑰,以此確認它擁有 SAML 令牌。使用密鑰持有者 SAML 令牌可以提高 消息和 SAML 令牌保護的強度,但是並不影響 SAML 令牌斷言信任模型。
斷言 SAML 令牌
當通過 SAML 令牌斷言創建安全上下文時,應用服務器運行時代碼需要 SAML 令牌中 的外部安全域名、用戶身份和(可選的)用戶組成員關系數據。
應用服務器運行時從經過檢驗的 SAML 令牌中提取出 SAML 令牌頒發者名稱,使用它 作為外部安全域身份驗證領域名(圖 3)。
圖 3. SAML 2.0 頒發者斷言示例
在默認情況下,對於 SAML 1.1 令牌,用戶安全名稱是 NameIdentifier 斷言(圖 4 );對於 SAML 2.0 令牌,是 NameID 斷言(圖 5)。也可以把其他 SAML 屬性配置為 用戶安全名稱。
圖 4. SAML 1.1 NameIdentifier 示例
圖 5. SAML 2.0 NameID 示例
SAML 規范沒有指定標准的組成員關系屬性。應用服務器提供的 策略集綁定配置 可 以指定應該使用哪個 SAML 屬性定義組成員關系(如果有的話)。SAML 1.1 和 SAML 2.0 AttributeStatement 斷言中定義的組成員關系示例見圖 6 和圖 7。
圖 6. SAML 1.1 組成員關系屬性示例
圖 7. SAML 2.0 組成員關系屬性示例
SAML 1.1 示例在 AttributeAssertion 元素中包含一個 Subject 斷言。只有 SAML 1.1 規范要求這麼做。
對於前面的示例,安全上下文中的客戶機調用者主體包含以下用戶信息:
Realm name: acme.com
Security name: Alice
Unique ID: acme.com/Alice
Unique group ID 1: acme.com/Acme employee
Unique group ID 2: acme.com/Gold membership
跨 WebSphere Application Server 安全域斷言
下載 部分包含一個示例 Web 服務客戶機應用程序和 Web 服務提供者應用程序,它 們演示如何設置策略集、綁定和可信身份驗證領域配置以實現跨安全域 SAML 令牌斷言 。圖 8 顯示示例應用程序涉及的解決方案部分(藍色圈中的部分)。
圖 8. 跨安全域 SAML 令牌斷言
示例應用程序是自包含的,可以很簡便地運行它。通常,在聯合 Web 服務資源(後 面討論)時,使用 Security Token Service (STS) 驗證用戶的身份並把 SAML 令牌頒 發給經過授權的用戶。示例應用程序並不依賴於外部 STS,而是利用 WebSphere Application Server SAML Token Factory API 創建 SAML 令牌(在本文中稱為自頒發 的 SAML 令牌)。為了演示跨安全域 SAML 令牌斷言,示例應用程序需要區分至少兩個 安全域。為了演示跨安全域斷言,常常必須配置兩個應用服務器,每個服務器在一個單 獨的安全域中。為了簡化這個示例的配置,示例應用程序在單一應用服務器上演示跨安 全域行為。在創建自頒發的 SAML 令牌時,示例應用程序通過設置 SAML 令牌頒發者屬 性表示外部安全域。因此,SAML 令牌中的用戶和組信息代表外部安全域中的用戶,而不 是本地用戶存儲庫中定義的用戶。圖 9 說明示例應用程序的元素。
圖 9. 示例應用程序使用自頒發的 SAML 令牌演示跨安全域 SAML 斷言
除了編寫定制的代碼之外,另一種方法是通過配置策略集綁定從安全上下文中的 RunAs 主體生成 SAML 令牌。當從 RunAs 主體創建自頒發的 SAML 令牌時(而且 RunAs 主體尚未包含 SAML 令牌),WebSphere Application Server V7 Fix Pack 7 實現從 RunAs 主體中的 WSCredential 對象中提取出用戶身份,但是並不在 SAML 令牌中插入 組成員關系信息。因此,本文采用定制代碼方式,通過程序從 WSCredential 對象中提 取出組信息並插入 SAML 令牌。
如圖 9 所示,浏覽器用戶使用基於表單的登錄向示例應用程序驗證身份。Web 浏覽 器用戶需要輸入用戶名和密碼,向本地用戶存儲庫驗證身份。Web 服務客戶機應用程序 使用用戶身份生成自頒發的 SAML 令牌,但是使用一個預先配置的安全域領域名作為令 牌頒發者和組成員關系數據。Web 服務客戶機通過發送包含自頒發 SAML 令牌的 SOAP 消息來調用 EJBWSProviderApp Web 服務。用一個密鑰對 SAML 令牌執行簽名,這個密 鑰是 EJBWSProviderApp Web 服務提供者所信任的。EJBWSProviderApp Web 服務提供者 在三個信任關系檢查點上檢查信任關系。EJBWSProviderApp 是一個 EJB 3.0 bean,使 用 JAX-WS 編程模型把它公開為 Web 服務。選用 EJB Web 服務實現是為了演示如何設 置授權策略,以及如何檢查訪問控制決策中使用的 SAML 斷言。
清單 1 中的代碼片段說明示例 Web 服務客戶機如何生成自頒發的 SAML 2.0 令牌。
清單 1
1. package com.ibm.wss.sample.ejbws;
2. import java.util.ArrayList;
3. import javax.security.auth.Subject;
4. import javax.servlet.ServletException;
5. import com.ibm.websphere.security.auth.WSSubject;
6. import com.ibm.websphere.security.cred.WSCredential;
7. import com.ibm.websphere.wssecurity.wssapi.token.SAMLTokenFactory;
8. import com.ibm.websphere.wssecurity.wssapi.token.SecurityToken;
9. import com.ibm.wsspi.wssecurity.saml.config.CredentialConfig;
10. import com.ibm.wsspi.wssecurity.saml.config.ProviderConfig;
11. import com.ibm.wsspi.wssecurity.saml.config.RequesterConfig;
12. import com.ibm.wsspi.wssecurity.saml.data.SAMLAttribute;
13. import com.ibm.wsspi.wssecurity.saml.data.SAMLNameID;
14. public class SamlTokenGenerator {
15. public static SecurityToken getSamlToken() throws
16. ServletException
17. {
18. SecurityToken samlToken = null;
19. String name = getPrincipal();
20. String[] groups = getGroups();
21. String localRealm = getRealm();
22. System.out.println("SAML principal name: " + name);
23. try {
24. SAMLTokenFactory samlFactory =
25. SAMLTokenFactory.getInstance("http://docs.oasis
26. -open.org/wss/oasis-wss-saml-token-profile- 1.1#SAMLV2.0");
27. RequesterConfig reqData =
28. samlFactory.newBearerTokenGenerateConfig ();
29. CredentialConfig cred =
30. samlFactory.newCredentialConfig();
31. reqData.setAuthenticationMethod("Password");
32. //Password is the authentication method
33. //create SAML NameID or NameIdentifer using principal
34. // in Caller Subject
35. SAMLNameID nameID = null;
36. nameID = new
37. SAMLNameID (name,null,localRealm,null,null);
38. cred.setSAMLNameID(nameID);
39. //Create SAML Attributes using group memberships
40. // in Caller Subject
41. if (groups!= null && groups.length >0){
42. ArrayList<SAMLAttribute> al = new
43. ArrayList<SAMLAttribute>();
44. SAMLAttribute sattribute = new
45. SAMLAttribute("Membership", groups,
46. null,null /* format*/, null, null );
47. al.add(sattribute);
48. cred.setSAMLAttributes(al);
49. }
50. ProviderConfig samlIssuerCfg =
51. samlFactory.newDefaultProviderConfig ("acme.com");
52. //acme.com is issuer name
53. samlToken = samlFactory.newSAMLToken(cred, reqData,
54. samlIssuerCfg);
55. } catch(Throwable e) {
56. System.out.println("testNewSecurityTokenV1Bearer:
57. caught exception: "+e.getMessage() + "\n");
58. e.printStackTrace(System.out);
59. }
59. return samlToken;
60. }
61.
62. private static String getPrincipal(){
63. String name = null;
64. String realm = null;
65. try {
66. Subject subject = WSSubject.getRunAsSubject();
67. WSCredential credential = null;
68.
69. if (subject != null ) {
70. java.util.Set<Object> publicCreds =
71. subject.getPublicCredentials();
72. if (publicCreds != null && publicCreds.size() > 0)
73. {
74. java.util.Iterator<Object> publicCredIterator =
75. publicCreds.iterator();
76. while (publicCredIterator.hasNext())
77. {
78. Object cred = publicCredIterator.next ();
79. if (cred != null && cred instanceof
80. WSCredential)
81. {
82. credential = (WSCredential) cred;
83. name = credential.getSecurityName();
84. realm = credential.getRealmName();
85. break;
86. }
87. }
88. }
89. }
90.
91. if (name != null && (name.contains(realm))) {
92. name =
93. name.substring(name.indexOf(realm)+realm.length() +1);
94. }
95. } catch (Exception e){
96. name="UNAUTHENTICATED";
97. }
98. return name;
99. }
100. private static String [] getGroups() throws ServletException {
101. String []grps = null;
102. try {
103. WSCredential credential = null;
104. Subject subject = null;
105. ArrayList groups = new ArrayList();
106. try {
107. subject = WSSubject.getRunAsSubject();
108. } catch (Exception ex) {
109. System.out.println("Exception caught upon invoking
110. WSSubject.getCallerSubject():" + ex.getMessage ());
111. ex.printStackTrace(System.out);
112. throw new ServletException(ex.getCause());
113. }
114. if (subject != null ) {
115. java.util.Set<Object> publicCreds =
116. subject.getPublicCredentials();
117. if (publicCreds != null && publicCreds.size() > 0)
118. {
119. java.util.Iterator<Object> publicCredIterator =
120. publicCreds.iterator();
121. while (publicCredIterator.hasNext())
122. {
123. Object cred = publicCredIterator.next ();
124. if (cred != null && cred instanceof
125. WSCredential)
126. {
127. credential = (WSCredential) cred;
128. break;
129. }
130. }
131. }
132. }
133. if (credential != null){
134. groups = credential.getGroupIds();
135. }
136. if (groups != null && groups.size() >0) {
137. String realm = credential.getRealmName();
138. grps = new String[groups.size()] ;
139. groups.toArray(grps);
140. for (int i=0; i<groups.size();){
141. String name = grps[i];
142. if (name != null && name.contains (realm)){
143. name =
144. name.substring(name.indexOf(realm)+realm.length() +1);
145. grps[i] = name;
146. }
147. i++;
148. }
149. }
150. } catch (Exception e){
151. System.out.println("Exception caught populating groups:"
152. + e.getMessage());
153. e.printStackTrace(System.out);
154. throw new ServletException(e.getCause());
155. }
156. return grps;
157. }
158. private static String getRealm() throws ServletException {
159. String realm = null;
160. try {
161. Subject subject = WSSubject.getRunAsSubject();
162. WSCredential credential = null;
163.
164. if (subject != null ) {
165. java.util.Set<Object> publicCreds =
166. subject.getPublicCredentials();
167. if (publicCreds != null && publicCreds.size() > 0)
168. {
169. java.util.Iterator<Object> publicCredIterator =
170. publicCreds.iterator();
171. while (publicCredIterator.hasNext())
172. {
173. Object cred = publicCredIterator.next ();
174. if (cred != null && cred instanceof
175. WSCredential)
176. {
177. credential = (WSCredential) cred;
178. realm = credential.getRealmName();
179. break;
180. }
181. }
182. }
183. }
184. } catch (Exception e){
185. System.out.println("Exception caught retrieving realm:"
186. + e.getMessage());
187. e.printStackTrace(System.out);
188. throw new ServletException(e.getCause());
189. }
190. return realm;
191. }
192. }
在清單 1 中:
在第 24-26 行上創建 SAMLTokenFactory 實例以生成 SAML 2.0 令牌。
RequestConfig 對象指定新令牌的需求。
第 27-28 行上的 newBearerTokenGenerateConfig() 調用指定令牌應該需要發送者 主體確認方法。
第 50-51 行把 SAML 令牌頒發者名稱設置為 acme.com。
使用頒發者名稱表示安全域的名稱。
第 35-38 行中的代碼設置用戶身份。
第 41-49 行添加組成員關系 SAML 屬性。
第 53-54 行生成一個用於測試的 SAML 2.0 令牌,其中包含發送者信息以及用戶身 份和屬性。
在第 62 行上,getPrincipal() 方法從 RunAs 主體中提取出用戶安全名稱。如果 UserRegistry getSecurityName() 方法返回的名稱包含 realm/ 前綴,getPrincipal() 方法就刪除它。
在第 100 行上,getGroups() 方法從 RunAs 主體中提取出用戶組。在 WebSphere Application Server 中,組信息的格式是 "group:<realm>/group_name"。當提 取組名時,getGroups() 方法刪除前綴 "group:<realm>/"。
在第 158 行上,getRealm() 方法從 RunAs 主體中提取出領域屬性。
將對新令牌執行簽名。代碼並沒有顯式地指定應該對新令牌執行簽名,因為這裡的代 碼使用默認的令牌頒發者屬性生成新令牌。第 36 行上創建的 ProviderConfig 對象包 含 SAMLIssuerConfig.properties 文件中指定的默認屬性。圖 12 給出應用程序的示例 SAMLIssuerConfig.properties 文件。屬性文件定義默認的密鑰存儲、用於打開密鑰存 儲的密碼和用於 SAML 令牌簽名的私鑰。這些是最初在 ProviderConfig 對象中設置的 默認值。可以使用 ProviderConfig 接口修改任何屬性。
在 $install_root/profiles/$PROFILE/config/cells$/CELLNAME/sts 目錄中可以找 到計算單元級屬性文件的拷貝。可以在服務器級定義屬性文件。
通常,設置了策略集之後,Web 服務安全運行時環境會從安全上下文中的 RunAs 主 體中提取出用戶身份信息,從而創建並發送 SAML 令牌。不需要編寫定制的代碼。但是 ,對於本示例,希望模擬在外部安全域中創建的 SAML 令牌。因此,必須通過程序生成 一個自頒發的 SAML 令牌並把它注入 Web 服務安全運行時環境中,從而禁用使用 RunAs 主體生成 SAML 令牌的默認行為。清單 2 中的代碼實現這個目標。代碼把自頒發的 SAML 令牌保存在 AxisService RequestContext 中。當找到 SAML 令牌時,Web 服務安 全運行時環境在下游消息中傳播 RequestContext 中的令牌。
清單 2
43. SAMLToken samlToken = <self-issued SAML tokens previously generated>;
44.
45. Map<String, Object> requestContext = ((BindingProvider)
46. servicePort).getRequestContext ();
47.
48. requestContext.put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, serviceURL);
49. //Put the samlToken into RequestContext
50. requestContext.put(
51. com.ibm.wsspi.wssecurity.saml.config.SamlConstants.SAMLTOKEN_IN_MESSAGECONTEX T,
samlToken);
示例應用程序的 Web 服務提供者端很簡單。Web 服務提供者端演示如何使用 SAML 斷言做出訪問控制決策,但是不需要定制的代碼。
配置應用服務器
本節提供設置示例應用程序、策略集和綁定配置的步驟。這些說明假設您已經熟悉通 過配置策略集和綁定使用 SAML 令牌的過程。更多信息參見 WebSphere Application Server Information Center 和 參考資料 中列出的 JAX-WS 文章。
要想運行本文的示例應用程序和學習以下幾節,需要對應用服務器執行一些配置:
安裝 WebSphere Application Server Version 7.0 Fix Pack 7 或更高版本。
下載並安裝 下載 部分中的示例 Web 服務客戶機應用程序和 Web 服務提供者應用程 序。
按 這些說明 從默認策略存儲庫導入 SAML 2.0 Bearer WSHTTPS default 策略集( 圖 10)。這個策略集要求 Web 服務客戶機用發送者主體確認方法發送 SAML 2.0 令牌 ,並用 SSL 保護消息。
圖 10. 從默認存儲庫導入 SAML 2.0 Bearer WSHTTPS default 策略集
假設啟用了 WebSphere Application Server 全局安全性,配置可信的外部安全域。 最簡單的方法是使用 Security Configuration 向導啟用管理安全性。還需要啟用應用 程序安全性,讓示例應用程序可以使用安全上下文中經過身份驗證的用戶主體創建 SAML 令牌。這個步驟涉及在 Web 服務提供者端上配置第三個信任關系檢查點。使用應用服務 器模擬目標安全域 Web 服務提供者需要這個步驟。WebSphere Application Server V7.0 身份驗證子系統支持斷言包含外部領域名的用戶身份,它根據入站可信身份驗證領 域列表檢查外部領域名。完成這個配置步驟之後,WebSphere Application Server 可以 用外部安全域中的用戶身份創建客戶機調用者主體。
完成配置全局安全性的步驟之後,按以下步驟配置可信安全域:
在 Global Security 面板上,單擊 Configure beside Available realm definitions。
單擊 Trusted authentication realms - inbound。
選擇 Trust realms as indicated below(圖 11)。
單擊 Add External Realm。
在 External realm name 中添加 SAML 令牌頒發者名稱。SAML 令牌頒發者名稱提供 SAML 令牌的頒發者的相關信息,這一信息在 SAML 2.0 令牌的 <Issuer> 元素或 SAML 1.1 令牌的 Issuer 屬性中。對於這個示例,添加 acme.com 作為可信外部領域, 見圖 11。
圖 11. 把 SAML 令牌頒發者 acme.com 定義為可信身份驗證領域
在您的用戶存儲庫中創建用戶名 Alice 和密碼。在這個測試中,內置的聯合存儲庫 作為用戶存儲庫。使用應用服務器模擬發起請求的安全域 Web 服務客戶機需要這個步驟 。在用戶存儲庫中添加用戶 Alice 是必需的,這樣才能使用浏覽器向受保護的示例應用 程序驗證身份並訪問它。在這個示例中,聯合的用戶存儲庫作為本地用戶存儲庫,默認 的領域名是 defaultWIMFileBasedRealm。示例應用程序接受一個經過身份驗證的用戶身 份,用它創建 SAML 令牌並把令牌頒發者設置為 "acme.com",以此模擬跨安全域斷言。 必須啟用應用程序安全性,讓安全運行時對應用程序實施安全約束,並把經過身份驗證 的用戶身份放在安全上下文中。
把示例密鑰存儲文件和示例信任存儲文件解壓到安裝示例應用程序的概要文件下面的 etc\ws-security\samples 目錄中。密鑰存儲密碼是 storepass,密鑰密碼是 keypass 。示例密鑰存儲文件 saml-provider.jceks 包含 RSA 私鑰以及相應的 X.509 證書和 RSA 公鑰。密鑰存儲文件用於對自頒發的 SAML 令牌執行數字簽名。信任存儲文件 recipient.jceks 包含相同的 X.509 證書,Web 服務接受者使用它檢查 SAML 令牌的真 實性。可以使用 WebSphere Application Server 附帶的 keytool 命令生成密鑰存儲( 清單 3)。
清單 3
keytool -genkey -alias samlissuer -keystore saml-provider.jceks -dname
"CN=SAMLIssuer, O=ACME" -storepass storepass -keypass keypass - storetype
jceks -validity 5000 -keyalg RSA
使用以下命令把頒發者證書導出到 issuerpub.cert 文件中,然後創建信任存儲文件 recipient.jceks:
清單 4
keytool -export -alias samlissuer -file issuerpub.cer - keystore
saml-provider.jceks -storepass storepass -storetype jceks
keytool -import -alias samlissuer -file issuerpub.cer -keystore
recipient.jceks -storepass storepass -storetype jceks
-keypass keypass –oprompt
實際上,可以使用 saml-provider.jceks 文件同時作為密鑰存儲文件和信任存儲文 件,因為 saml-provider.jceks 包含頒發者 X.509 證書,還因為這個示例使用單一應 用服務器。在一般情況下,如果在兩個安全域中的兩個應用服務器上運行示例 Web 服務 客戶機和 Web 服務提供者,就應該創建包含頒發者 X.509 證書但不包含私鑰的信任存 儲文件。
編輯位於 $install_root/profiles/$PROFILE/config/cells$/CELLNAME/sts 的配置 文件 SAMLIssuerConfig.properties,設置密鑰存儲和信任存儲。當創建自頒發的 SAML 令牌時,SAML 令牌工廠使用這個屬性文件中的密鑰存儲和其他配置數據對 SAML 令牌執 行簽名。當通過程序檢查 SAML 令牌時,信任存儲文件配置作為 SAML 令牌工廠使用的 默認值。修改後的屬性文件應該與圖 12 相似。
圖 12. 示例 SAMLIssuerConfig.properties 文件
為了演示,示例應用程序包含 SAML samlbearerAssertProvider 和 samlbearerAssertionClient 綁定示例。這兩個一般綁定示例是通過復制並修改 WebSphere Application Server 附帶的一般綁定示例 Saml Bearer Provider Sample 和 Saml Bearer Client Sample 創建的。稍後會看到如何創建這兩個綁定文件。基本上 ,需要把 Saml Bearer Client Sample 改為生成自頒發的 SAML 令牌,而不是向外部 STS 請求 SAML 令牌。還需要把 Saml Bearer Provider Sample 一般綁定改為選用 SAML 令牌代表調用者身份並啟用跨安全域斷言。您不必自己創建這些綁定,可以按照下 一步中的說明導入示例綁定。
導入示例客戶機一般綁定的步驟是,把示例應用程序包含的綁定文件解壓到一個臨時 目錄中,然後使用 importBinding 命令腳本或管理控制台中的 Import 按鈕把它們導入 應用服務器中。用臨時目錄中的 .../bindings/samlbearerAssertionClient 目錄結構 創建一個路徑。
配置 Web 服務客戶機
為了創建所需的一般客戶機綁定(只在選擇不導入 samlbearerAssertionClient 綁 定示例的情況下),執行以下步驟並修改 Saml Bearer Client Sample:
登錄管理控制台。
在左邊的導航欄中選擇 Services。
展開 Policy sets 並選擇 General client policy set bindings。
在 General client policy set bindings 對話框中,選擇 Saml Bearer Client sample,然後單擊集合表格中的 Copy。輸入您選擇的名稱;例如 samlbearerAssertionClient。
關於配置 SAML 2.0 發送者令牌的客戶機和提供者綁定的信息,參見 WebSphere Application Server Information Center。刪除四個定制的 SAML 令牌生成器回調處理 器屬性:stsURI、wstrustClientPolicy、wstrustClientBinding 和 wstrustClientSoapVersion。示例應用程序使用自頒發的 SAML 令牌,不需要這些屬性 ;但是,當向外部 STS 請求 SAML 令牌時,需要這些屬性。圖 13 給出完成後的客戶機 一般綁定。
圖 13. 示例 Web 服務客戶機綁定
配置 Web 服務提供者
為了創建所需的一般服務器綁定(同樣,只在選擇不導入 samlbearerAssertionProvider 綁定示例的情況下),執行以下步驟,復制並修改 Saml Bearer Provider Sample:
登錄管理控制台。
在左邊的導航欄中選擇 Services。
展開 Policy sets 並選擇 General provider policy set bindings。
在 General provider policy set bindings 對話框中,選擇 Saml Bearer Provider sample,然後單擊集合表格中的 Copy。輸入您選擇的名稱;例如 samlbearerAssertProvider。
關於配置 SAML 發送者令牌的客戶機和提供者綁定的信息,參見 WebSphere Application Server Information Center。把令牌消費者定制回調 trustStorePath 和 trustStorePassword 屬性的屬性值替換為 cecipiens.jceks 的值。圖 14 給出完成後 的提供者一般綁定。
圖 14. 示例 Web 服務提供者綁定
圖 14 所示的信任存儲配置對應於第一個信任關系檢查點。SAML 令牌消費者針對 recipient.jceks 中的證書檢驗 SAML 令牌頒發者數字簽名和簽名證書。
執行下一個步驟配置第二個信任關系檢查點。一定要通過配置 Web 服務綁定顯式地 列出可信的 SAML 頒發者和相應的證書,從而確保包含指定證書的 SAML 令牌只能斷言 指定頒發者安全域中的用戶憑證。換句話說,SAML 令牌消費者檢查接收到的 SAML 令牌 中的頒發者名稱是否與配置的 trustedIssuer 匹配,以及頒發者 X.509 證書所有者名 稱是否與配置的 trustedSubjectDN 匹配。
添加定制屬性 trustedIssuer_n 和 trustedSubjectDN_n,前者定義可信的 SAML 頒 發者名稱,後者定義可信的 X.509 證書(其中的 _n 是從 1 開始的整數,對於每個頒 發者遞增 1)。配置 trustedIssuer_ 和 trustedSubjectDN_ 屬性(盡管它們是可選的 )。如果沒有指定 trustedIssuer 屬性,令牌消費者就不會檢驗 SAML 令牌中的頒發者 名稱。如果沒有指定 trustedSubjectDN 屬性,令牌消費者就不會檢驗接收到的頒發者 X.509 證書的所有者字段。圖 15 給出可信頒發者配置的綁定示例。
圖 15. 包含 SAML 令牌頒發者檢查的示例 Web 服務提供者綁定
添加更多可信伙伴。
可以通過遞增整數 n 添加更多可信的頒發者。例如,圖 16 顯示兩個可信頒發者。 後綴數字 _n 必須是連續的。如果刪除一對屬性,比如 trustedIssuer_m 和 trustedSubjectDN_m,那麼必須把從 _m+1 到 _n 的條目下移一位。在序列中留下間隙 會導致令牌消費者處理錯誤。
圖 16. 配置另一個可信外部安全域
為跨域 SAML ID 斷言配置 Web 服務調用者綁定。
進入 Caller 面板,單擊 New,在 Caller identity local part 中添加作為調用者 令牌的 SAML 令牌。在這個示例中,添加 http://docs.oasis-open.org/wss/oasis- wss-saml-token-profile-1.1#SAMLV2.0 作為調用者身份本地部分。
添加回調處理器: com.ibm.websphere.wssecurity.callbackhandler.SAMLIdAssertionCallbackHandler。
添加回調處理器定制屬性 crossDomainIdAssertion 並把它的值設置為 true。如果 不定義這個屬性,Web 服務安全運行時的默認行為是執行本地身份斷言,把 SAML 令牌 用戶身份映射到當前安全域的用戶存儲庫中的用戶條目。如果定義了 crossDomainIdAssertion 屬性並設置為 true,Web 服務安全運行時會斷言 SAML 令牌 用戶身份和組屬性,創建一個代表此用戶的調用者 JAAS 主體。在這種情況下,Web 服 務安全運行時並不訪問當前安全域的用戶存儲庫。
還可以添加回調處理器定制屬性 groupName_n(其中的 n 是遞增 1 的正整數)以指 定 SAML 組名稱。這個屬性很有用,因為 SAML 規范沒有定義代表組信息的標准屬性。
例如,如果需要由 AttributeName=SecretAuthorizationGroup 定義的組成員關系, 那麼添加定制屬性 groupName_1=SecretAuthorizationGroup。Web 服務安全運行時使用 接收到的 SAML 令牌中指定的屬性值填充調用者 WSCredential 對象組成員信息。如果 沒有定義 groupMName_n 屬性,那麼 WebSphere Application Server Web 服務安全實 現會自動地掃描 SAML 屬性斷言名稱 "groups"、"group"、"memberof"、"membership" 、"groupmembership"、"members"、"groupid"、"role" 和 "roles",使用它們的屬性 值作為憑證的組成員信息。
還可以添加回調處理器定制屬性 principalName_n(其中的 n 是遞增 1 的正整數) 以指定用作調用者身份的 SAML 令牌屬性。例如,如果希望使用屬性 email 作為調用者 的主體,那麼添加定制屬性 principalName_1=email。如果沒有定義 principalName_n 屬性,那麼 WebSphere Application Server Web 服務安全實現在默認情況下使用 SAML NameIdentifier 斷言(SAML 1.1)或 NameId(SAML 2.0)作為調用者的主體名稱。注 意,Web 服務安全運行時把 principalName_n 和 groupName_n 與 trustedIssuer_n 和 trustedSubjectDN_n 組織在一起。換句話說,groupName_n 和 principalName_n(如果 定義了)指定由特定頒發者(trustedIssuer_n)頒發的 SAML 令牌中的身份和組屬性。
圖 17 給出用於斷言 SAML 令牌的調用者綁定。
圖 17. 包含跨安全域設置的示例 Web 服務提供者調用者綁定
如果添加更多可信伙伴,可以定義更多的主體和組屬性映射規則。如圖 18 所示,在 創建調用者主體時,使用由 bigCorp.com 頒發的 SAML 令牌中的 email 屬性作為用戶 主體名稱。
圖 18. 定義另一個主體映射規則
設置應用程序
在 WebSphere Application Server 上安裝示例應用程序。
把示例密鑰存儲文件解壓到安裝示例應用程序的概要文件下面的 etc\ws- security\samples 目錄中。密鑰存儲密碼是 storepass,密鑰密碼是 keypass。
連接 SAML 2.0 Bearer WSHTTPS default 策略集,然後連接客戶機綁定 samlbearerAssertionClient 和服務綁定 samlbearerAssertProvider。
配置授權表,向來自可信域的外部用戶授予訪問權:
在管理控制台上,單擊 Enterprise applications,然後單擊適當的 EJB Web 服務 應用程序。這個示例使用 testEJBWSProviderApp 應用程序。確保用 Java Platform, Enterprise Edition (Java EE) 安全性保護服務 EJB。testEJBWSProviderApp 應用程 序是一個 EJB 3.0 應用程序,所有 EJB 方法都由安全注解定義的角色保護。
單擊 Security role to user/group mapping。給可信外部領域中的用戶和組分配角 色。在這個示例中,給 acme.com 領域中的用戶 Alice 定義安全角色 SayHelloUsers, 見圖 19。
圖 19. 向外部安全域的用戶和組授予對 Java EE 資源的訪問權
運行示例聯合 Web 服務
啟動一個浏覽器會話,訪問這個 URL: http://localhost:9080/testEJBWSClientWeb/testEJBWSBrowserClient.jsp。
當表單登錄頁面出現時,輸入 Alice 作為用戶 ID,輸入 security 作為密碼,然後 單擊 Logon(圖 20)。
圖 20. 示例應用程序的表單登錄頁面
根據自己的系統修改 EJB 服務 URL(最初顯示 https://localhost:9443/testEJB_HTTPRouter/HelloBeanService),見圖 21。需要指 定 HTTPS 端口,因為 Saml Bearer WSHTTPS Default 策略集要求 SSL 傳輸級的消息保 護。
圖 21. 示例應用程序的主服務頁面
如果跨域 ID 斷言成功,會收到圖 22 所示的消息。
圖 22. 示例應用程序的結果頁面
Web 服務提供者由 EJB 安全角色保護。授權配置要求發出請求的用戶是外部安全域 acme.com 中的 Alice。產生前面的結果就表明 SAML 令牌斷言已經成功了。
假設在本地用戶存儲庫中定義了另一個用戶 Tom,½†是沒有在授權表 中為 [email protected] 授權。當作為 Tom 再次登錄時,應該會看到圖 23 所示的授權錯誤 。
圖 23. 外部用戶沒有得到授權
聯合 Web 服務資源
通過這個示例 Web 服務應用程序,您看到了如何跨安全 域斷言 SAML 令牌,以及如何使用斷言的外部用戶身份和組成員數據做出訪問控制決策 。可以應用這種技術跨公司和業務伙伴之間的企業邊界聯合 Web 服務。典型的企業環境 使用 STS 向經過授權的用戶頒發安全令牌。圖 24 給出一個典型的業務場景。
圖 24. Web 服務聯合使用場景
在這個業務場景中,Web 客戶機(浏覽器)用戶通過駐留在 WebSphere Application Server 上的公司門戶應用程序訪問業務服務。當訪問業務伙伴的 Web 服 務時,門戶應用程序在 Web 服務消息的安全頭中放上代表 Web 客戶機的 SAML 令牌。 可以把門戶應用程序配置為從 Web 客戶機獲得身份驗證數據,用這些數據向 STS 驗證 身份,請求 Web 客戶機的 SAML 令牌。WebSphere Application Server 提供 WS-Trust 1.3 和 WS-Trust 1.2(DRAFT 版本)的信任客戶機實現,可以與外部 STS 集成。為了 向 STS 驗證身份,門戶應用程序可以提示 Web 客戶機用戶輸入身份驗證數據。在執行 最初的身份驗證之後,門戶應用程序可以維持與 Web 客戶機的身份驗證會話,使用客戶 機憑證向 STS 驗證身份,代表客戶機請求 SAML 令牌。
可用的身份驗證方法包括使用身份斷言、使用自頒發的 SAML 令牌和使用客戶機 Kerberos 憑證。已經向 Kerberos 服務器驗證身份的 Web 客戶機可以使用它們的 Kerberos 憑證向門戶應用程序驗證身份,委托門戶服務器使用它們的 Kerberos 憑證向 STS 驗證身份。STS 實現必須支持 Kerberos 身份驗證。WebSphere Application Server 可以根據安全上下文中的用戶身份生成自頒發的 SAML 令牌。應用服務器可以使 用自頒發的 SAML 令牌代表客戶機向 STS 驗證身份以請求 SAML 令牌,只要 STS 支持 這種使用模式。對於 IBM Tivoli® Federated Identity Manager STS,門戶應用程 序還可以使用來自用戶的 LTPA 令牌向 Tivoli STS 驗證身份。
圖 25 顯示一個 相似的場景,在這裡 Web 服務客戶機(Java 客戶機)用戶直接訪問業務伙伴的 Web 服 務。Web 服務客戶機向 STS 驗證身份以請求 SAML 令牌。他們可以使用用戶 ID 和密碼 、Kerberos 令牌或 X.509 客戶機證書,只要 STS 支持此種身份驗證數據。
圖 25. 訪問聯合 Web 服務提供者的 Web 服務客戶機
要想修改示例 Web 服務客戶機綁定,讓它使用外部 STS 頒發 SAML 令牌,應 該指定與 STS 交互所需的 STS 端點 URL、策略集和綁定。綁定配置面板的示例見圖 26 。
圖 26. 把 Web 服務客戶機配置為使用外部 STS 頒發 SAML 令牌
結束語
通過使用 IBM WebSphere Application Server V7.0 Fix Pack 7 和 更高版本中的 SAML 特性,可以使用 SSO 解決方案跨安全域斷言 SAML 令牌。通過結合 使用 SAML 斷言和可信身份驗證領域特性,可以使用用戶身份和組成員 SAML 斷言實現 基於聲明的資源訪問控制。信任模型和三個信任關系檢查點確保系統的安全性和完整性 。本文提供了一個示例 EJB 3.0 JAX-WS 應用程序,演示跨安全域 SAML 斷言和基於聲 明的訪問控制。也可以應用這種技術跨企業安全域聯合 Web 服務資源。本文描述的 SSO 解決方案為 Web 應用程序和 Web 服務用戶提供 SSO 的便捷性,同時降低 IT 管理員的 身份管理負擔。
來源:
http://www.ibm.com/developerworks/cn/websphere/techjournal/1004_chao/1 004_chao.html