1. 過於詳細!終於搞懂SSO裡面的SAML和OIDC講的啥了
在了解SSO是什麼之前,我們需要搞清楚兩個概念: Authentication & Authorization。
Authentication(又被稱為AuthN,身份驗證),它指的是 the process of verifying that "you are who you say you are",也就是說這個過程是為了證明你是你。通常來說有這么幾個方式:
Authorization(又被稱為AuthZ,許可權驗證),他指的是 the process of verifying that "you are permitted to do what you are trying to do",也就是說這個過程是為了證明你是否擁有做這件事的許可權,比如修改某個表格等等,如果沒有許可權的話通常會返回 403 錯誤碼。
在 SSO 出現之前,用戶在不同的系統登錄就需要在不同的系統注冊多個賬號,然後需要自己記住多個用戶名和密碼,而如果這些系統是同一個平台的話,其實該平台還需要維護多套幾乎一模一樣的登錄系統,給用戶和平台都帶來了負擔。
而 SSO 就是一種authentication scheme(身份驗證方案),SSO 允許用戶使用同一個賬戶登錄不同的系統,很好地解決了上述的問題。它不但可以實現單一平台的登錄,假如某個平台之外的系統是信任該平台的,那麼外部系統也可以集成這個平台的 SSO, 比如現在的大多數網站都提供了 Google 賬號登錄的功能。
要實現 SSO,首先需要你正在開發的系統信任這個第三方登錄系統所提供的用戶信息,然後你需要按照一定的標准和協議去與其對接,接下來我們會介紹兩個比較常用的 SSO 協議 -- SAML 2.0 和 OIDC。
SAML 2.0是什麼
SAML 是 Security Assertion Markup Language 的簡稱,是一種基於XML的開放標准協議,用於在身份提供者(Identity Provider簡稱IDP)和服務提老伏供商(Service Provider簡稱SP)之間交換認證和授權數據。
SAML 2.0是該協議的最新版本,於2005年被結構化信息標准組織(OASIS)批准實行。
流程
SAML flow
SAML Assertion
那麼這個 SAML Assertion 又是個啥呢?
首先用戶為什麼可以訪問SP上的資源呢?肯定是因為沒含高其實SP也有一份用戶的資料,這個資料裡面可能有用戶的賬戶信息,許可權等等,但是現在用戶的信息是由IDP提供的,所以現在需要做的就是講兩份用戶信息映射起來,好讓SP知道IDP提供的用戶到底是哪一個。
而這個映射的約定,就是SP和IDP進行集成的時候的一個配置,這個配置叫做 metadata。這個配置有兩份,兩邊各一份,裡面約定了應該怎麼去映射用戶信息,簽名的證書等。IDP和SP會通過別的方式去交換這兩份 metadata。
所以其實 SAML Assertion 裡麵包含了用戶的唯一標識,能夠證明該用戶是誰。在SP拿到這份信息後就會按照一些規則去驗證裡面的信息是否是合法的用戶。
那麼問題來了,如果中間人知道了我們之間的規則隨便塞了一份信息進來咋辦?所以其實 SAML Assertion 裡面除了用戶信息其實還有IDP的簽名,只有SP先解析了裡面的簽名確認無誤之後才會信任這份信息。
知道了 SAML Assertion 是個啥以後,我們還需要弄清楚它是怎麼發送出去的。要弄清楚它們是怎麼發送出去的我們需要知道一個東西叫做 binding method。
SAML 2.0 有許多不同的 binding,它們其實就是 SAML Assertion 的交互方式:
其中現在用的比較多的是前三種,它們都是基於HTTP協議來實現的。
metadata
上面提到過 metadata 是為了讓IDP和SP明白彼此交流的信息,並且有一些枯尺安全考慮,裡面主要的信息有:
其中有一個欄位 md:KeyDescriptor 在SP中有一個 encryption,在SP和IDP進行通信建立信任的時候,IDP就會拿到SP加密的key,在用戶登錄成功後,IDP就會用這個key加密 SAML Assertion,SP拿到後通過自己的私鑰進行解密。另一個叫 signing 的欄位會被用來解析對方的簽名,用來辨別這個 Assertion 是不是我想要的人發過來的。
OIDC是什麼
OpenID Connect(OIDC) 是建立在 OAuth 2.0 協議之上的一個簡單的身份層,它允許計算客戶端根據授權伺服器執行的認證,以 JSON 作為數據格式,驗證終端用戶的身份。它是 OpenID 的第三代規范,前面分別有 OpenID 和 OpenID 2.0。它在OAuth 2.0 的基礎上增加了 ID Token 來解決第三方客戶端標識用戶身份認證的問題。
它的結構如圖所示:
image-20200601085202978
從它的結構圖中可以看出,除了核心實現外,OIDC 還提供了一系列可選的擴展功能。比如:
由於圖片距今已經有些年限了,其實現在OIDC還提供了許多可選的擴展,具體可到官網查看。
流程
由於 OIDC 是基於 OAuth 2.0 的,所以 OIDC 也擁有多種 flow。由於篇幅所限我這里會相對詳細地解釋 Authorization Code Flow,在開始前我們需要弄清楚幾個名稱:
Authorization Code flow
Implicit Flow 是在 OP redirect EU 到 RP 的時候會帶上 ID Token 和 Access Token(如果必要) 而不是 Authorization Code,同時在發送請求的時候也會有一些不同,需要帶上一些別的參數,這里就不細講了,總的流程是差不多的,詳情可以查看這里
Hybrid Flow 可以理解為上面兩個 flow 的結合,OP redirect EU 到 RP 的時候會帶上 Authorization Code,同時根據發送請求時候 Response Type 參數的不同還會帶上一些別的參數,具體流程可以參考這里
2. OAuth2.0和OIDC詳解
OAuth 是一個開放標準的授權框架,它為第三方應用獲取資源所有者在資源所在系統或應用上的部分資源提供了一種解決方案。
也就是說,假如你在騰訊雲存了一些圖片,現在你想在美圖秀秀上編輯這些圖片;此時的 "你" 就是資源所有者,第三方應用就是美圖秀秀,而資源伺服器就是騰訊雲;
這種情況下美圖秀秀直接訪問騰訊雲是獲取不到你的圖片的,所以美圖秀秀為了能獲取到這些照片就需要授權伺服器授權(當然,資源伺服器和授權伺服器有可能是同一個,也有可能是兩個不同的服務)
OAuth 就是為這種類似的場景定義的一套標准拆羨,目前已經發展到了 OAuth2.0 。 OAuth2.0 在 RFC 的文檔地址: https://datatracker.ietf.org/doc/html/rfc6749
下面可以通過一個場景來解釋一下, OAuth2.0 的原理:一個快遞員的問題
假設你住在一個大型的小區中,你經常點外賣,而小區有門禁系統,進入的時候需要輸密碼
為了能讓快遞員進入,你就需要為他提供一組密碼
如果你直接把你的密碼給了快遞員,那麼他就有了和你一樣的許可權,如果你想取消他的許可權,那隻能改密碼了,這樣你還要通知使用該密碼的其他人
所以你打算設計一套授權機制,既能讓快遞員進來,又能限制他的操作並且能隨時回收這個密碼
於是,你想出了一套辦法,完善門禁系統:
此處為什麼要給他生成一個令牌,而不是直接給他開門呢?
因為從小區大門到目的地可能會有多個門禁,所以就不用一直等著給快遞員開門了;同樣的,如果第二天快遞員再來時就不需要再獲取許可權了
密碼和令牌都讓獲取第三方獲取用戶數據,但是相較於密碼,令牌有如下的有點:
令牌能夠有效的控制第三方應用的訪問許可權和訪問時長;當然,令牌也是必須要保乎御迅密的,因為泄露令牌和泄露密碼一樣,也會造成安全問題,因此一般令牌的有效時間都會設置的比較短
OAuth2.0 提供了四種授權方式來應對不同的應用場景,
授權碼(authorization code)方式,指的是第三方應用先申請一個授權碼,然後再用該碼獲取令牌。
這種方式是最常用的流程,安全性也最高,它適用於那些有後端的 Web 應用。授權碼通過前端傳送,令牌則是儲存在後端,而且所有與資源伺服器的通信都在後端完成。這樣的前後端分離,可以避免令牌泄漏。
第一步,A 網站提供一個鏈接,用戶點擊後就會跳轉到 B 網站,授權用戶數據給 A 網站使用。下面就是 A 網站跳轉 B 網站的一個示意鏈接。
上面 URL 中, response_type 參數表示要求返回授權碼( code ), client_id 參數讓 B 知道是誰在請求, redirect_uri 參數是 B 接受或拒絕請求後的跳轉網址, scope 參數表示要求的授權范圍(這里是只讀)。
第二步,用戶跳轉後,B 網站會要求用戶登錄(如果是未登錄的情況下),然後詢問是否同意給予 A 網站授權;如果用戶同意授權,這時 B 網站就會跳回 redirect_uri 參數指定的網址。跳轉時,會傳回一個授權碼,就像下面這樣。
上面 URL 中, code 參數就是授權碼。註:這個授權碼與客戶端一一對應,通常只有10分鍾的有效期,並且只能使用一次
第三步,A 網站拿到授權碼以後,就可以在後端,向 B 網站請求令牌。
上面 URL 中, client_id 參數和 client_secret 參數用來讓 B 確認 A 的身份( client_secret 參數是保密的,因此只能在後端發請求), grant_type 參數的值是 AUTHORIZATION_CODE ,表示採用的授權方式是授權碼, code 參數是上一步拿到的授權碼, redirect_uri 參數是令牌頒發後的回調網址。
第四步,B 網站收到請求以後,就會頒發令牌。具體做法是向 redirect_uri 指定的網址,發送一段 JSON 數據。
上歲此面 JSON 數據中, access_token 欄位就是令牌,A 網站在後端拿到了。
有些 Web 應用是純前端應用,沒有後端。這時就不能用上面的方式了,必須將令牌儲存在前端。 RFC 6749 就規定了第二種方式,允許直接向前端頒發令牌。這種方式沒有授權碼這個中間步驟,所以稱為(授權碼)"隱藏式"(implicit)。
第一步,A 網站提供一個鏈接,要求用戶跳轉到 B 網站,授權用戶數據給 A 網站使用。
上面 URL 中, response_type 參數為 token ,表示要求直接返回令牌。
第二步,用戶跳轉到 B 網站,登錄後同意給予 A 網站授權。這時,B 網站就會跳回 redirect_uri 參數指定的跳轉網址,並且把令牌作為 URL 參數,傳給 A 網站。
上面 URL 中, token 參數就是令牌,A 網站因此直接在前端拿到令牌。
注意,令牌的位置是 URL 錨點(fragment),而不是查詢字元串(querystring),這是因為 OAuth 2.0 允許跳轉網址是 HTTP 協議,因此存在"中間人攻擊"的風險,而瀏覽器跳轉時,錨點不會發到伺服器,就減少了泄漏令牌的風險。
如果你高度信任某個應用,RFC 6749 也允許用戶把用戶名和密碼,直接告訴該應用。該應用就使用你的密碼,申請令牌,這種方式稱為"密碼式"(password)。**
第一步,A 網站要求用戶提供 B 網站的用戶名和密碼。拿到以後,A 就直接向 B 請求令牌。
上面 URL 中, grant_type 參數是授權方式,這里的 password 表示"密碼式", username 和 password 是 B 的用戶名和密碼。
第二步,B 網站驗證身份通過後,直接給出令牌。注意,這時不需要跳轉,而是把令牌放在 JSON 數據裡面,作為 HTTP 回應,A 因此拿到令牌。
這種方式需要用戶給出自己的用戶名/密碼,顯然風險很大,因此只適用於其他授權方式都無法採用的情況,而且必須是用戶高度信任的應用。
最後一種方式是憑證式(client credentials),適用於沒有前端的命令行應用,即在命令行下請求令牌。
第一步,A 應用在命令行向 B 發出請求。
上面 URL 中, grant_type 參數等於 client_credentials 表示採用憑證式, client_id 和 client_secret 用來讓 B 確認 A 的身份。
第二步,B 網站驗證通過以後,直接返回令牌。
這種方式給出的令牌,是針對第三方應用的,而不是針對用戶的,即有可能多個用戶共享同一個令牌。
A 網站拿到令牌以後,就可以向 B 網站的 API 請求數據了。
此時,每個發到 API 的請求,都必須帶有令牌。具體做法是在請求的頭信息,加上一個 Authorization 欄位,令牌就放在這個欄位裡面。
上面命令中, ACCESS_TOKEN 就是拿到的令牌。
令牌的有效期到了,如果讓用戶重新走一遍上面的流程,再申請一個新的令牌,很可能體驗不好,而且也沒有必要。OAuth 2.0 允許用戶自動更新令牌。
具體方法是,B 網站頒發令牌的時候,一次性頒發兩個令牌,一個用於獲取數據,另一個用於獲取新的令牌(refresh token 欄位)。令牌到期前,用戶使用 refresh token 發一個請求,去更新令牌。
上面 URL 中, grant_type 參數為 refresh_token 表示要求更新令牌, client_id 參數和 client_secret 參數用於確認身份, refresh_token 參數就是用於更新令牌的令牌
OAuth2.0 描述了授權 (Authorization) 的各種方式,但是這些方式中卻沒有定義如何進行認證 (Authentication)
認證 (Authentication) 和授權 (Autherization 這兩個表示的是不同的動作:
OpeID Connect (OIDC)對 OAuth2.0 進行了擴展,添加了用戶認證的功能,並且它和 OAuth2.0 的流程是相同的。有區別的地方就是它的認證請求的欄位中包含 scope=openid 如下所示:
在返回的響應中包含 ID Token ,用於獲取用戶身份,如下所示:
這裡面有幾個問題:
首先,
首先需要保證你的 OAuth2.0 請求是在 HTTPS 協議下發送的,這樣可以防止暴露用戶的信息。
其次就是一些釣魚網站;比如,有一個 A 網站需要獲取你在 B 網站上的資源或者數據,所以當你進入 A 網站的某個功能時,它會讓你跳轉到 B 網站,但是很有可能 B 網站是由 A 網站偽造跳轉過來的,此時需要你的授權,當你輸入賬密的時候,你的賬密就泄露了;這些釣魚網站就是用來收集用戶的賬密信息的,所以當跳到第二個網站的時候一定要證實該網站是不是你注冊過的合法的網站
參考連接:
https://datatracker.ietf.org/doc/html/rfc6749
https://auth0.com/intro-to-iam/what-is-oauth-2/
https://www.csoonline.com/article/3216404/what-is-oauth-how-the-open-authorization-framework-works.html
https://www.ruanyifeng.com/blog/2019/04/oauth_design.html
https://developer.okta.com/blog/2019/10/21/illustrated-guide-to-oauth-and-oidc
https://blog.runscope.com/posts/understanding-oauth-2-and-openid-connect
3. 談談單點登錄
寒假學習的小課題,把之前的筆記整理整理記錄一下(長文警告)因為當時看到的東西涉及很多,所以有一些地方沒有深入去探討。
網路:單點登錄(Single Sign On),簡稱為 SSO,是目前比較流行的企業業務整合的解決方案之一。SSO的定義是在多個應用系統中,用戶只需要登錄一次就可以訪問所有相互信任的應用系統。
簡而言之就是用戶在多個相互信任的應用系統中,只需要登錄一次,就可以訪問其他相互信任的應用系統。這里的關鍵是一次登錄,以及一次退出,都對所有的系統生效。
在普通的登錄中,比如典型的B/S情景,瀏覽器訪問伺服器,發送登錄請求,在發送完用戶名和密碼之後,伺服器會生成該用戶的session來標准該用戶的狀態,比如已登錄還是已注銷,並給一個cookie給瀏覽器,因此,用戶繼續訪問就會帶上這個cookies,服務端會根據這個Cookie找到對應的session,通過session來判斷這個用戶的登錄狀態。比如php中使用phpsessid。當然也可以自定義session的生命周期,session的生命周期過長的話一旦session被盜用就會出現用戶被竊取的情況。同時,生命周期過長的session配置會佔用較多的伺服器資源。
單點登錄主要針對同平台下多應用,多系統的情景下多次登錄的一種解決方案。單點登錄相當於將多個應用的認證體系聯通。
假設現在一個平台上有3個都帶有登錄功能的應用,由上面的普通登錄的情況可以想到,這3台伺服器都會自己的記錄session。那麼要想達到單點登錄,一個最簡單的方法就出現了:共享session。
共享session的方式來實現單點登錄是最方便也是最直接的。在三個子系統中,使用同一個額外的記錄session的伺服器,比如我們可以使用一個redis伺服器來存儲三個系統的session。
用戶登錄了應用1,獲取了應用1返回的cookies,再次訪問應用1的其他功能的候攜帶了cookie就是已登錄的狀態了,但是這樣又有新的問題,雖然實現了共享session,但是用戶登錄了應用1,獲取了應用1返回的cookie,但是因為cookie是無法跨域的,因此用戶無法使用應用1的cookie去訪問應用2。這里我們就需要將系統的全局cookie domain的屬性設置為頂級域名,比如應用1的域名是1.test.com,應用2的域名是2.test.com。在普通登錄的情況下,應用1的cookie domain的屬性是1.test.com,指這個cookie只能在該子域名上被使用。我們將系統的全局cookie domain設置為頂級域名,即.test.com,這樣就可以實現用戶登錄了應用1,之後可以以已登錄狀態訪問應用2和3。
上面的共享session的情況是三個應用都有登錄功能,還有一種類似的情況是應用1和應用2都有登錄模塊和其他模塊,還有一個單獨的SSO系統,是僅有登錄模塊的:
共享session的方法雖然簡單,但是存在局限性,因為使用了cookie頂域的特性,所以不能做到跨域。一個公司或者一個平台很可能不是所有的域名都在在一個一級域名之下的,所以同域名下的單點登錄並不是完整的單點登錄。
先說說openid,openid是一種認證標准,規定如何認證的標准!即其關注的是登錄時身份的認證。官方給出的一個場景,其中一方是一個openid身份伺服器,用來存放注冊好的openid賬號,另一方是受這個openid身份伺服器信賴的服務或應用。openid協議就是提供openid身份伺服器和被信賴的服務或應用之間的通信的。比如我們在很多網站上可以使用QQ登錄,這里的騰訊的QQ就是openid的身份伺服器,我們所要登錄的網站就是受信賴的服務或應用。
在使用openid實現單點登錄的方法有很多,可以使用上面共享session的方法,即把openid帶在cookie裡面,但是這樣也會出現一樣的cookie跨域的問題。
在實際場景中,我們在訪問提供服務的應用時檢測到未登錄就會直接跳轉到openid身份伺服器,或者沒有重定向而是在登錄表單附近點擊選擇使用第三方openid登錄,進行賬號密碼登錄(這可以保證我們所登錄的伺服器無法獲取我們的敏感身份認證信息),具體流程如下:
CAS全稱為Central Authentication Service即中央認證服務,是一個企業多語言單點登錄的解決方案,並努力去成為一個身份驗證和授權需求的綜合平台。CAS就是一個現成的單點登錄的demo,企業只需要簡單修改就可使用。
CAS支持各種協議,SAML,OAuth,OpenID,OIDC等等,支持LDAP,Radius,JWTX,509等等進行身份認證和授權,還有各種常用語言的客戶端,Java,PHP,C# 等等。反正就是一個十分完整的,兼容性特別好的SSO框架。
簡單了解CAS是如何實現單點登錄的。在官網上可以看到其給出的一個 流程圖 ,。這個圖說的特別詳細,一下就能看懂,直接原圖上進行標注查看:
學習了上面幾種單點登錄的知識,結合實際場景可知,跨域單點登錄才是真正的單點登錄,因為實際情況下很多平台或者域名不可能都在一個一級域名下。在解決跨域單點登錄的問題的時候,上面也給說了幾種方式,但是究其根本,就是利用一個SSO認證中心來實現認證與授權的。當然,也會有其他的解決跨域單點登錄的方案,但是大體流程都與cas類似。
比如在上圖的11步驟,也可使用POST包,或者JSONP和iframe方法來跨域發送請求進行重定向。
在利用認證中心來實現單點登錄是現在比較普遍的解決方案,那麼有沒有不需要使用認證中心來解決跨域單點登錄的方案呢?
利用JSONP同步登錄狀態,大概流程流程如下:
在學習單點登錄的過程中,在其中認證的過程中授權令牌的傳遞等相關信息沒有特別詳細的說明,而且在思考單點登錄的時候也會有想過一個比較矛盾的問題:單點登錄的目標是為了讓用戶可以在相互信任的系統中一次登錄即可,但是如果真的是做到所有用戶都可以訪問所有系統,豈不是會帶來越權的問題,是否需要對不同的用戶以不同的授權,甚至限制訪問的應用,但是這樣是不是就不是原本狹義的單點認證?
在說單點登錄的認證和授權之前,先談一談我一直想弄清楚的統一身份認證和單點登錄的區別。說起單點登錄可能很少聽過,但是統一身份認證肯定不陌生,不管是企業還是高校都會有這種統一身份認證的系統。
統一身份認證最重要的一方面就是身份認證,另一方面就是和身份認證相關的授權控制,許可權控制。而單點登錄是多應用一次登錄,也可以叫統一登錄,可以理解為主要在認證方面。對於統一身份認證來說會有賬號管理,如LDAP,認證管理OAuth,SMAL等,因此我覺得,統一身份認證一般是包括狹義的單點登錄,狹義的單點登錄,即只需要滿足多應用一次登錄即可。但是現在的單點登錄,SSO系統並不僅僅是要求這些,他的范圍正在慢慢擴大。
單點登錄的認證和授權,前面說到的CAS實現單點登錄里就會看到需要ticket來進行認證,授權。CAS支持多種認證方案,比如OAuth,OpenID,SAML等等,我們可以來比較比較用這些協議的區別,或者說是在哪些場景下使用哪些認證方案較為合適。本身單點登錄是沒有許可權控制的功能的,但是因為這些認證協議的需求,自然支持了許可權控制。
在使用SAML進行認證的過程中,可以看到下圖,其是基本流程都差不多,這里需要注意的就是在用戶在認證中心成功登陸之後,重定向的時候返回的是一個SAML token,一個XML節點,這里的token會包括用戶的身份信息,用戶名等。
在OAuth2.0的標准中流程是和上面的基本相同,但是OAuth2因為客戶端並沒有一點是瀏覽器,所以token中默認是沒有簽名的。這里可能沒有體現出來,OAuth2的目標是授權,所以token更關注的是許可權,token在向認證伺服器驗證的時候就會有不同的授權,但是既然是授權,就間接實現了認證。
在傳統的認證中都是基於session機制的,具體的session模式上面也說了,根據其特性可知session的一些確定:
https://www.mutuallyhuman.com/blog/choosing-an-sso-strategy-saml-vs-oauth2/
https://yq.aliyun.com/articles/636281
https://juejin.im/post/5d0dbb7e6fb9a07f0420512d
4. sso通信超時什麼意思
簡介
SSO是單點登錄的簡稱,常用的SSO的協議有兩種,分別是SAML和OAuth2。本文將會介紹兩種協議的不同之處,從而讓讀者對這兩種協議有更加深入的理解。
SAML
SAML的全稱是Security Assertion Markup Language, 是由OASIS制定的一套基於XML格式的開放標准,用在身份提供者(IdP)和服務提供者 (SP)之間交換身份驗證和授權數據。
SAML的一個非常重要的應用就是基於Web的單點登錄(SSO)。
在SAML協議中定義了三個角色,分別是principal:代表主體通常表示人類用戶。identity provider (IdP)身份提供者和service provider (SP)服務提供者。
IdP的作用就是進行身份認證,並且將用戶的認證信息和授權信息傳遞給服務提供者。
SP的作用就是進行用戶認證信息的驗證,並且授權用戶訪問指定的資源信息。
接下來,我們通過一個用SAML進行SSO認證的流程圖,來分析一下SAML是怎麼工作的。
上圖中User Agent就是web瀏覽器,我們看一下如果用戶想請求Service Provider的資源的時候,SAML協議是怎麼處理的。
用戶通過User Agent請求Service Provider,比如:
- http://sp.flydean.com/myresource
如果在第一步的時候,SP並沒有找到相應的有效安全上下文的話,則會生成對應的SAMLRequest,並將User Agent重定向到IdP:
- 302 Redirect
- Location: https://idp.flydean.com/SAML2/SSO/Redirect?SAMLRequest=request&RelayState=token
User agent將會發送一個get請求到IdP的SSO server :
- GET /SAML2/SSO/Redirect?SAMLRequest=request&RelayState=token HTTP/1.1
- Host: idp.flydean.com
用戶可以輸入用戶名密碼進行登錄。登錄成功之後,IdP將會返回一個XHTML form:
- ...
- form>
user agent 收到XHTML form之後將會提交該form給SP。
SP中的assertion consumer service將會處理這個請求,創建相關的安全上下文,並將user agent重定向到要訪問的資源頁面。
user agent再次請求SP資源。
因為安全上下文已經創建完畢,SP可以直接返回相應的資源,不用再次到IdP進行認證。
SP將會對該資源進行相應的安全檢查,如果發現已經有一個有效的安全上下文的話,SP將會跳過2-7步,直接進入第8步。
RelayState是SP維護的一個狀態信息,主要用來防止CSRF攻擊。
其中這個SAMLRequest是用Base64編碼的 ,下面是一個samlp:AuthnRequest的例子:
xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
ID="aaf23196-1773--474a-fe114412ab72"
Version="2.0"
IssueInstant="2020-09-05T09:21:59Z"
AssertionConsumerServiceIndex="0"
="0">
https://sp.flydean.com/SAML2saml:Issuer>
AllowCreate="true"
Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient"/>
samlp:AuthnRequest>
為了安全起見,SAMLRequest還可以使用SP提供的簽名key來進行簽名。
IdP收到這個AuthnRequest請求之後,將會進行安全驗證,如果是合法的AuthnRequest,那麼將會展示登錄界面。
這個form中包含了SAMLResponse信息,SAMLResponse中包含了用戶相關的信息。
同樣的SAMLResponse也是使用Base64進行編碼過的 。
xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
ID="identifier_2"
InResponseTo="identifier_1"
Version="2.0"
IssueInstant="2020-09-05T09:22:05Z"
Destination="https://sp.flydean.com/SAML2/SSO/POST">
https://idp.flydean.com/SAML2saml:Issuer>
Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
samlp:Status>
xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
ID="identifier_3"
Version="2.0"
IssueInstant="2020-09-05T09:22:05Z">
https://idp.flydean.com/SAML2saml:Issuer>
我們可以看到samlp:Response中包含有saml:Assertion信息。
我們可以看到上面的所有的信息交換都是由前端瀏覽器來完成的,在SP和IdP之間不存在直接的通信。
這種全部由前端來完成信息交換的方式好處就是協議流非常簡單,所有的消息都是簡單的GET或者POST請求。
如果為了提高安全性,也可以使用引用消息。也就是說IdP返回的不是直接的SAML assertion,而是一個SAML assertion的引用。SP收到這個引用之後,可以從後台再去查詢真實的SAML assertion,從而提高了安全性。
SAML的缺點
SAML協議是2005年制定的,在制定協議的時候基本上是針對於web應用程序來說的,但是那時候的web應用程序還是比較簡單的,更別提對App的支持。
SAML需要通過HTTP Redect和HTTP POST協議來傳遞用戶信息,並且通常是通過HTML FORM的格式來進行數據的提交的。如果應用程序並不是web應用,比如說是一個手機App應用。
這個手機APP應用的啟動鏈接是 my-photos://authenticate , 但是手機app可能並不能獲取到Http POST的body內容。他們只能夠通過URL來進行參數的傳遞。
這就意味著,在手機APP中不能夠使用SAML。
當然,要想工作也可以,不過需要進行一些改造。比如通過第三方應用對POST消息進行解析,然後將解析出來的SAMLRequest以URL參數的形式傳遞給APP。
另一種方法就是使用OAuth2.
OAuth2
因為Oauth2是在2012年才產生的。所以並沒有那麼多的使用限制。我們可以在不同的場合中使用OAuth2。
我們先來看一下OAuth2中授權的流程圖:
一般來說OAuth2中有4個角色。
resource owner:代表的是資源的所有者,可以通過提供用戶名密碼或者其他方式來進行授權。通常來是一個人。
resource server:代表的是最終需要訪問到資源的伺服器。比如github授權之後獲取到的用戶信息。
client:用來替代resource owner來進行交互的客戶端。
authorization server:用來進行授權的伺服器,可以生成相應的Access Token。
整個流程是這樣的:
Client向resource owner發起一個授權請求,resource owner輸入相應的認證信息,將authorization grant返回給client。
client再將獲取到的authorization grant請求授權伺服器,並返回access token。
client然後就可以拿著這個access token去請求resource server,最後獲取到受限資源。
OAuth2的缺點
OAuth2並沒有指定Resource Server怎麼和Authorization Server進行交互。也沒有規定返回用戶信息的內容和格式。這些都需要實現方自己去決定。
OAuth2默認是在HTTPS環境下工作的,所以並沒有約定信息的加密方式。我們需要自己去實現。
最後,OAuth2是一個授權協議,而不是認證協議。對於這個問題,其實我們可以考慮使用OpenID Connect協議。因為OpenID Connect就是基於OAuth2實現的,並且添加了認證協議。
OpenID Connect簡稱為OIDC,已成為Internet上單點登錄和身份管理的通用標准。它在OAuth2上構建了一個身份層,是一個基於OAuth2協議的身份認證標准協議。
OAuth2實際上只做了授權,而OpenID Connect在授權的基礎上又加上了認證。
OIDC的優點是:簡單的基於JSON的身份令牌(JWT),並且完全兼容OAuth2協議。
兩者的對比
在SAML協議中,SAML token中已經包含了用戶身份信息,但是在OAuth2,在拿到token之後,需要額外再做一次對該token的校驗。
但是另一方面,OAuth2因為需要再做一次認證,所以可以在 Authorization Server 端對token進行無效處理。
CAS簡介
做過SSO的應該都聽說過CAS。CAS的全稱是Central Authentication Service,是一個企業級的開源的SSO認證框架。
CAS內部集成了CAS1,2,3,SAML1,2,OAuth2,OpenID和OpenID Connect協議,非常的強大。我們會在後面的文章中介紹CAS的使用。
xmlns:ds="http://www.w3.org/2000/09/xmldsig#">...ds:Signature>
Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient">
3f7b3dcf-1674-4ecd-92c8-1544f346baf8
saml:NameID>
Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
InResponseTo="identifier_1"
Recipient="https://sp.flydean.com/SAML2/SSO/POST"
NotOnOrAfter="2020-09-05T09:27:05Z"/>
saml:SubjectConfirmation>
saml:Subject>
NotBefore="2020-09-05T09:17:05Z"
NotOnOrAfter="2020-09-05T09:27:05Z">
https://sp.flydean.com/SAML2saml:Audience>
saml:AudienceRestriction>
saml:Conditions>
AuthnInstant="2020-09-05T09:22:00Z"
SessionIndex="identifier_3">
urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport
saml:AuthnContextClassRef>
saml:AuthnContext>
saml:AuthnStatement>
saml:Assertion>
samlp:Response>