幾個月前,我正在實施一個 OpenID Connect 服務器來管理我們數百個內部應用程序的訪問。 從我們自己的發展來看,在較小的規模上很方便,我們已經轉向了一個普遍接受的標準。 通過中央服務接入大大簡化了單調的操作,降低了實施授權的成本,讓您可以找到許多現成的解決方案,而無需在開發新解決方案時絞盡腦汁。 在本文中,我將討論這一轉變以及我們設法填補的障礙。
很久以前……這一切是如何開始的
幾年前,當內部應用太多需要人工控制時,我們寫了一個應用來控制公司內部的訪問。 這是一個簡單的 Rails 應用程序,連接到包含員工信息的數據庫,其中配置了對各種功能的訪問。 同時,我們提出了第一個單點登錄,它是基於客戶端和授權服務器端對令牌的驗證,令牌以帶有多個參數的加密形式傳輸,並在授權服務器上進行驗證。 這不是最方便的選擇,因為每個內部應用程序都必須描述相當多的邏輯層,並且員工數據庫與授權服務器完全同步。
一段時間後,我們決定簡化集中授權的任務。 SSO 被轉移到平衡器。 在 OpenResty 的幫助下,Lua 中添加了一個模板,用於檢查令牌,知道請求將發送到哪個應用程序,並可以檢查那裡是否有訪問權限。 這種方法大大簡化了控制對內部應用程序訪問的任務——在每個應用程序的代碼中,不再需要描述額外的邏輯。 結果,我們對外關閉了流量,應用程序本身對授權一無所知。
然而,還有一個問題沒有解決。 那些需要員工信息的應用程序呢? 可以為授權服務編寫一個 API,但是您必須為每個這樣的應用程序添加額外的邏輯。 此外,我們希望在我們的內部授權服務器上擺脫對我們自己編寫的應用程序之一的依賴,該應用程序面向未來轉換為 OpenSource。 我們改天再談。 這兩個問題的解決方案是 OAuth。
符合共同標準
OAuth 是一個可以理解、被普遍接受的授權標準,但由於只有它的功能是不夠的,他們立即開始考慮 OpenID Connect(OIDC)。 OIDC 本身是開放式身份驗證標準的第三個實現,它已流入 OAuth 2.0 協議(一種開放式授權協議)之上的附加組件。 該解決方案解決了缺少最終用戶數據的問題,並且還可以更改授權提供者。
但是,我們沒有選擇特定的提供商,而是決定為我們現有的授權服務器添加與 OIDC 的集成。 支持這一決定的是 OIDC 在最終用戶授權方面非常靈活的事實。 因此,可以在您當前的授權服務器上實施 OIDC 支持。
我們實現自己的 OIDC 服務器的方式
1)將數據轉換為所需的形式
要集成 OIDC,需要將當前的用戶數據轉換成標準可以理解的形式。 在 OIDC 中,這稱為索賠。 聲明本質上是用戶數據庫中的最終字段(姓名、電子郵件、電話等)。 存在
這組標誌組合成以下子集 - 範圍。 在授權期間,請求訪問的不是特定品牌,而是范圍,即使不需要範圍內的某些品牌。
2) 實施必要的撥款
OIDC 集成的下一部分是授權類型的選擇和實施,即所謂的授權。 所選應用程序與授權服務器之間的進一步交互場景將取決於所選授權。 下圖顯示了選擇正確授權的示例方案。
對於我們的第一個應用程序,我們使用了最常見的授權,即授權碼。 它與其他的不同之處在於它是一個三步,即正在進行額外的測試。 首先,用戶請求授權許可,收到一個token——Authorization Code,然後用這個token,就像用一張旅行票一樣,請求一個access token。 此授權腳本的所有主要交互都基於應用程序和授權服務器之間的重定向。 您可以閱讀有關此贈款的更多信息
OAuth 堅持授權後獲得的訪問令牌應該是臨時的並且應該更改的概念,最好平均每 10 分鐘更改一次。 Authorization Code grant是通過redirects進行的三步驗證,每10分鐘轉這麼一步,坦白說,這不是最賞心悅目的工作。 為了解決這個問題,還有一個grant——Refresh Token,我們國內也用過。 這裡的一切都更容易。 在另一個授權的驗證過程中,除了主要的訪問令牌之外,還會頒發另一個 - 刷新令牌,它只能使用一次,並且它的生命週期通常要長得多。 有了這個 Refresh Token,當主訪問令牌的 TTL(生存時間)結束時,對新訪問令牌的請求將來到另一個授權的端點。 使用過的刷新令牌立即重置為零。 此檢查分為兩步,可以在後台執行,用戶察覺不到。
3)設置自定義數據輸出格式
選定的授權實施後,授權工作,值得一提的是獲取有關最終用戶的數據。 OIDC 為此有一個單獨的端點,您可以在其中使用當前的訪問令牌請求用戶數據以及它是否是最新的。 而如果用戶的數據沒有那麼頻繁的變化,需要多次跟隨當前的,可以來JWT token這樣的解決方案。 該標準也支持這些令牌。 JWT token本身由三部分組成:header(關於token的信息)、payload(任何必要的數據)和signature(簽名,token是由服務器簽名的,你可以稍後查看其簽名的來源)。
在 OIDC 實現中,JWT 令牌稱為 id_token。 它可以與普通訪問令牌一起請求,剩下的就是驗證簽名。 授權服務器為此有一個單獨的端點,帶有一堆格式的公鑰
例如在谷歌上:
{
"issuer": "https://accounts.google.com",
"authorization_endpoint": "https://accounts.google.com/o/oauth2/v2/auth",
"device_authorization_endpoint": "https://oauth2.googleapis.com/device/code",
"token_endpoint": "https://oauth2.googleapis.com/token",
"userinfo_endpoint": "https://openidconnect.googleapis.com/v1/userinfo",
"revocation_endpoint": "https://oauth2.googleapis.com/revoke",
"jwks_uri": "https://www.googleapis.com/oauth2/v3/certs",
"response_types_supported": [
"code",
"token",
"id_token",
"code token",
"code id_token",
"token id_token",
"code token id_token",
"none"
],
"subject_types_supported": [
"public"
],
"id_token_signing_alg_values_supported": [
"RS256"
],
"scopes_supported": [
"openid",
"email",
"profile"
],
"token_endpoint_auth_methods_supported": [
"client_secret_post",
"client_secret_basic"
],
"claims_supported": [
"aud",
"email",
"email_verified",
"exp",
"family_name",
"given_name",
"iat",
"iss",
"locale",
"name",
"picture",
"sub"
],
"code_challenge_methods_supported": [
"plain",
"S256"
],
"grant_types_supported": [
"authorization_code",
"refresh_token",
"urn:ietf:params:oauth:grant-type:device_code",
"urn:ietf:params:oauth:grant-type:jwt-bearer"
]
}
因此,使用 id_token,您可以將所有必要的標誌轉移到令牌的有效負載中,而不必每次都聯繫授權服務器來請求用戶數據。 這種方法的缺點是來自服務器的用戶數據的變化不會立即到來,而是伴隨著一個新的訪問令牌。
執行結果
因此,在應用程序端實現了我們自己的 OIDC 服務器並配置了與它的連接之後,我們就解決了用戶信息傳輸的問題。
由於 OIDC 是一個開放標準,我們可以選擇現有的提供者或服務器實現。 我們嘗試了 Keycloak,事實證明它配置起來非常方便,在應用程序端設置和更改連接配置後,就可以使用了。 在應用程序方面,剩下的就是更改連接配置。
談論現有的解決方案
在我們的組織內,作為第一個 OIDC 服務器,我們組裝了自己的實現,並根據需要進行了補充。 在詳細審查了其他現成的解決方案之後,我們可以說這是一個有爭議的問題。 為了支持實施他們自己的服務器的決定,供應商方面擔心缺乏必要的功能,以及存在一個舊系統,其中對某些服務有不同的自定義授權,而且很多有關員工的數據已經存儲。 但是,在現成的實現中,有集成的便利。 例如,Keycloak有自己的用戶管理系統,數據直接存儲在裡面,在那裡你的用戶超車並不難。 為此,Keycloak 有一個 API,可讓您完全執行所有必要的傳輸操作。
在我看來,另一個經過認證的、有趣的實施示例是 Ory Hydra。 這很有趣,因為它由不同的組件組成。 要集成,您需要將您的用戶管理服務鏈接到他們的授權服務並根據需要進行擴展。
Keycloak 和 Ory Hydra 並不是唯一的現成解決方案。 最好選擇OpenID基金會認證的實現。 這些解決方案通常具有 OpenID 認證徽章。
如果您不想保留 OIDC 服務器,也不要忘記現有的付費提供商。 今天有很多不錯的選擇。
下一步是什麼
在不久的將來,我們將以不同的方式關閉內部服務的流量。 我們計劃將我們當前使用 OpenResty 的平衡器上的 SSO 轉移到基於 OAuth 的代理。 這裡已經有很多現成的解決方案,例如:
其他材料
來源: www.habr.com