單點登錄實現中,系統之間的協議對接是非常重要的一環,一般涉及的標準協議類型有 CAS、OAuth、OpenID Connect、SAML,本文將對四種主流 SSO協議進行概述性的介紹,并比較其異同,讀者亦可按圖索驥、厘清關鍵概念。
一、認證與授權的區別
在介紹具體協議之前,有必要先說明“認證(Authentication)”和“授權(Authorization)”的區別。
- 認證(Authentication)即確認該用戶的身份是他所聲明的那個人;
- 授權(Authorization)即根據用戶身份授予他訪問特定資源的權限。
也就是說,當用戶登錄應用系統時,系統需要先認證用戶身份,然后依據用戶身份再進行授權。認證與授權需要聯合使用,才能讓用戶真正登入并使用應用系統。
二、CAS
Central Authentication Service簡稱CAS,是一種常見的B/S架構的SSO協議。和其他任何SSO協議一樣,用戶僅需登陸一次,訪問其他應用則無需再次登陸。
顧名思義,CAS是一種僅用于Authentication的服務,它和OAuth/OIDC協議不一樣,并不能作為一種Authorization的協議。
當前CAS協議包括CAS 1.0、CAS2.0、CAS3.0版本,這三個版本的認證流程基本類似。
CAS的認證流程通過包括幾部分參與者:
- Client: 通常為使用瀏覽器的用戶
- CAS Client: 實現CAS協議的Web應用
- CAS Server: 作為統一認證的CAS服務器
認證流程大致為:
- Client(終端用戶)在瀏覽器里請求訪問Web應用example;
- 瀏覽器發起一個GET請求訪問example應用的主頁https://www.example.com;
- 應用example發現當前用戶處于未登陸狀態,Redirect用戶至CAS服務器進行認證;
- 用戶請求CAS服務器;
- CAS發現當前用戶在CAS服務器中處于未登陸狀態, 要求用戶必須得先登陸;
- CAS服務器返回登陸頁面至瀏覽器;
- 用戶在登陸界面中輸入用戶名和密碼(或者其他認證方式);
- 用戶把用戶名和密碼通過POST,提交至CAS服務器;
- CAS對用戶身份進行認證,若用戶名和密碼正確,則生成SSO會話, 且把會話ID通過Cookie的方式返回至用戶的瀏覽器端(此時,用戶在CAS服務端處于登陸狀態);
- CAS服務器同時也會把用戶重定向至CAS Client, 且同時發送一個Service Ticket;
- CAS Client的服務端收到這個Service Ticket以后,請求CAS Server對該ticket進行校驗;
- CAS Server把校驗結果返回給CAS Client, 校驗結果包括該ticket是否合法,以及該ticket中包含對用戶信息;
- 至此,CAS Client根據Service Ticket得知當前登陸用戶的身份,CAS Client處于登陸態。
經過上述流程以后,CAS Server和CAS Client都處于登陸態,當用戶如果訪問另外一個CAS Client 2的時候,用戶不需要再次認證,即會跳過5、6、7、8、9這幾步,從而達到SSO的效果。
注: CAS 1.0是個非常簡單粗陋的協議,在2.0、3.0版本中,Service Ticket的校驗結果均為XML格式, 且引入了一種proxy模式(不在本文做深入討論)。
CAS協議的詳細標準定義,請參考:
https://apereo.github.io/cas/6.2.x/protocol/CAS-Protocol-Specification.html
筆者意見:
1. CAS協議是一個比較簡陋單點登陸協議,協議本身比較輕量級也比較容易實現,但是能夠解決的場景比較單一;
2. 雜亂:CAS 3.0又引入了基于SAML對Service Ticket進行校驗;
3. CAS Client和CAS Server之間的互信是通過接口調用的方式來建立, 沒有任何加密/簽名機制來保證進一步的安全;
4. 缺乏校驗CAS Client自身身份的機制;
5. 市面上實現了CAS協議的應用并不多,筆者也不推薦這種協議。
三、OAuth 2.0
談到OAuth, 通常是指OAuth 2.0協議,它是一種Authorization協議并不是一種Authentication協議,雖然OAuth 2的流程中只描述了Authorization。但是在實際使用中,Authorization脫離Authentication并沒有任何意義。
OAuth 2.0解決的主要場景是: 第三方應用如何被授權訪問資源服務器。整個流程參與者包括幾個組成部分:
- Resource Owner: 資源擁有者,通常為終端用戶
- Resource Server: 資源提供者
- Authorization Server: 授權服務器
- Client: 請求訪問服務訪問的應用
抽象的授權流程大致為:
OAuth-flow
假定一個在線音樂服務,用戶zhangsan想通過某音視頻播放軟件來播放在線音樂, 但是在播放音樂之前,該音視頻軟件必須得通過YuFu(即玉符IDaaS)認證授權,得到zhangsan的同意之后才能訪問在線音樂。
在這個場景中,zhangsan為Resource Owner, 在線音樂服務為Resource Server, Client為某音視頻播放軟件,YuFu作為Authorization Server。
- 音視頻軟件向zhangsan發起授權請求,請求zhangsan同意訪問在線音樂服務;
- 根據不同的授權模式,zhangsan同意該授權,且返回一個"授權"給音視頻服務;
- 音視頻服務攜帶zhangsan的授權,請求YuFu頒發一個access_token, 用于訪問在線音樂;
- YuFu校驗音視頻服務自身的合法性之后,頒發access_token;
- 音視頻服務攜帶access_token, 代表zhangsan請求訪問在線音樂;
- 在線音樂服務校驗完access_token以后,提供音樂服務. 播放器開始播放音樂。
上述是一個抽象的授權流程,而在具體實現中,在前三步中會有幾個變種,即不同的授權模式,常見的授權模式包括:
- Authorization Code Grant: 授權碼模式,最為常用,最安全,強烈推薦;
- Implicit Grant: 適用于SPA應用,已經不再推薦使用,被PKCE模式所替代;
- Resource Owner Password Credentials Grant: 需要把用戶的用戶名和密碼暴露給Client;
- Client Credential Grant: 整個流程沒有用戶的概念,適用于服務端->服務端調用的場景。
可以發現在整個流程中,音視頻播放器并不需要知道zhangsan的密碼,只是需要得到zhangsan的授權就可以訪問在線音樂,而整個授權是由Authorization Server來負責。
本文并不會展開討論Authorization Code模式,詳細協議文檔定義請參考:
https://tools.ietf.org/html/rfc6749
筆者意見:相比CAS協議,OAuth2.0不同的授權模式能夠解決更多的場景,更安全、更流行,且通過PKCE模式能夠實現移動端的單點登錄,這個是其他SSO協議都不具備的(PKCE模式參考資料:https://tools.ietf.org/html/rfc7636)。
四、OpenID Connect
OpenID Connect簡稱OIDC,是基于OAuth2.0擴展出來的一個協議。除了能夠OAuth2.0中的Authorization場景,還額外定義了Authentication的場景,可以說OIDC協議是當今最流行的協議。
相比OAuth2,OIDC引入了id_token等和userinfo相關的概念:
- 整個OAuth2協議,只是定義了access_token/refresh_token,但是這倆token只是為了保護Resource Server的,并沒有Resource Owner的身份信息;
- OIDC引入了id_token的概念,用這個特殊的token來表示這是Resource Owner的身份證:
- 標準化id_token的格式:即大家熟知的JWT;
- 標準化id_token的內容:Standard Claims
- 參考:https://openid.net/specs/openid-connect-core-1_0.html#StandardClaims
- OIDC引入了關于如何獲取詳細userinfo的Endpoint;
- OIDC定義了類似于SAML Metadata的Discovery接口,俗稱well-known接口:
- 參考:https://openid.net/specs/openid-connect-discovery-1_0.html
OIDC協議的登陸授權流程和OAuth2.0基本類似, 整個流程的參與者也類似,只不過換了個術語:
- OpenID Provider:簡稱OP,負責認證和授權
- Relying Party:簡稱RP,OAuth 2.0中的Client
OIDC-flow
可以說OIDC協議是目前最主流的SSO標準協議,且對開發者友好,實現起來比較簡單。
詳細協議標準定義參考:
https://openid.net/specs/openid-connect-core-1_0.html
五、SAML 2.0
SAML協議全稱為Security Assertion Markup Language,它是一個基于XML的標準協議。SAML標準定義了身份提供者(Identity Provider)和服務提供者(Service Provider)之間,如何通過SAML規范,采用加密和簽名的方式來建立互信,從而交換用戶身份信息。
SAML是一個非常古老的Authentication的協議,在早期B/S架構的企業級應用中非常流行。
SAML協議非常龐大,定義了很多optional的細節(即不是必須實現)。但這個也是雙刃劍,這一點恰恰也是SAML協議的缺點,作為實現者,必須得同時兼顧這些optional的細節,給開發者帶來較大的挑戰。
技術上,SAML協議基于XML,以Assertion的方式,通過簽名和加密交換用戶身份信息. 這一點和OIDC協議中的ID_Token類似(采用簽名/加密的id_token來交換用戶身份)。
SAML流程的參與者包括Service Provider(SP)和Identity Provider(IDP)兩個重要角色,且整個流程包括如下兩個使用場景:
- SP Initiated: 服務提供者主動發起
- IDP Initiated: 身份認證服務器主動發起
下面是大致的認證流程:
saml-flow
- End User從瀏覽器中請求訪問某SP:https://www.example.com ;
- https://www.example.com發現用戶未登陸,則發起SAML的AuthnRequest請求至IDP, 用戶瀏覽器跳轉至IDP頁面;
- IDP發現用戶處于未登陸狀態,重定向用戶至IDP的登陸界面,請求用戶進行身份驗證
- 用戶在登陸頁面中進行身份認證, 通常情況下需要校驗用戶名和密碼;
- IDP校驗用戶身份,若成功,則把包含著用戶身份信息的校驗結果,以SAML Reponse的形式,簽名/加密發送給SP;
- SP拿到用戶身份信息以后,進行簽名驗證/解密,拿到明文的用戶身份信息,此時SP處于登陸狀態,可以對用戶提供服務。
可以看到,在整個流程中,IDP是負責頒發用戶身份,SP負責信任IDP頒發的用戶身份, SP和IDP之間的信任關系是需要提前建立的,即SP和IDP需要提前把雙方的信息預先配置到對方,通過證書信任的方式來建立互信。
SAML協議的標準定義可參考:
http://docs.oasis-open.org/security/saml/Post2.0/sstc-saml-tech-overview-2.0.html
六、各協議簡單對比
上面簡單介紹了主流的幾種SSO協議,本質上它們大同小異,都是基于中心信任的機制,服務提供者和身份提供者之間通過互信來交換用戶信息,只是每個協議信息交換的細節不同,或者概念上有些不同。
最后,通過一個簡單對比表格來總結本文重點內容: