利用 OAuth 和 SAML 同盟 Windows Live 與 SharePoint 2010 的錦囊妙計
英文原文已於 2012 年 3 月 1 日星期四發佈
曾有許多網友和我聊到讓 SharePoint 與 Windows Live 同盟這件事。從表面上看來,這似乎是個不錯的主意。首先,Windows Live 擁有數百萬名使用者,每個人都用他們的電子郵件地址登入,而電子郵件地址就是我們經常用來表示身分的東西;再者,它是一項大型可擴充的服務,而我們也有無數現成的做法說明,可以直接或是透過 ACS (存取控制服務) 使用。所以為何我會對它和 SharePoint 的合作有這麼多的抱怨呢?曾經親身嘗試過的人一定知道,和 Windows Live 同盟時,您沒有辦法以宣告的形式取得使用者的電子郵件地址。您只會得到一個特殊的 Windows Live 識別碼,又稱為 PUID。就我所知,「PUID」實際上就是「GUID」,因為它的樣子和用途差不多就是如此。
舉例來說,假設您真的和 Windows Live 同盟好了,該如何將某人加入網站?您必須取得他們的 PUID,再把這個 PUID 加到 SharePoint 群組或權限等級。但您認識的人中,有誰知道自己的 PUID 是什麼用的呢?(如果您知道,那您也真是太宅了)。就算您真的那麼神,知道您的 PUID 好了,想想看,當您打算授予使用者不同網站集合的存取權限時,它又能有多大用處?真有誰能夠從一大串列出的 PUID (視情況之不同,也有可能是從人員選擇器) 中正確挑出您嗎?拜託,怎麼可能!因此,我對這事可說是十分灰心。
事實上我覺得用 ACS,還比較有機會能生出個比較理想的解決方案。在提供現成樣本給 Windows Live、Google、Yahoo 和 Facebook 等身分識別提供者這方面,ACS 的確表現不俗。對於 Facebook 他們甚至還施展了一點魔法,真正運用了 OAuth 進行驗證,並傳回一組 SAML 宣告。酷吧!所以他們為什麼對於 Windows Live 不也比照辦理呢?Windows Live 現在已可支援 OAuth,看來這項眾望所歸的功能應是指日可待。但僅管我們殷切期盼,ACS 仍舊不動聲色。這就來到了本文的重點啦,我終於決定親自下馬,自己動手來寫一個!
為什麼我們比較喜歡 OAuth?這是因為它不像直接與 Windows Live 同盟時只會給您 PUID,Windows Live 中的 OAuth 支援,讓您可以得到更多的使用者資訊,甚至包括使用者的電子郵件地址。因此,我的妙計大致如下:
- 利用 Windows Identity Foundation (WIF) 寫一個自訂的身分識別提供者。
- 當有人被重新導向至我們的 STS 時,假如他們尚未經過驗證,我們就會再次將他們重新導向到 Windows Live。要做到這一點,您必須建立一個 Windows Live 的「應用程式」,關於這點我稍後會詳細解釋。
- 使用者經過驗證之後,就會再度導向回自訂的 STS。當他們返回時,查詢字串會包含一個登入 Token;交換此登入 Token 即可存取 Token。
- STS 接著會利用登入碼對 Windows Live 發出另一項要求,要求存取 Token。
- 取回存取 Token 時,它會再利用存取 Token 對 Windows Live 發出最後一項要求,也就是要求有關使用者的一些基本資訊 (我晚點會再解釋我們取回的內容)。
- 從 Windows Live 取回使用者資訊之後,我們會運用自己的自訂 STS 為使用者建立一組 SAML 宣告,並填入使用者資訊。接著會再重新導回要求我們驗證的應用程式,讓它利用這些 SAML Token 去做它要做的事。在這個例子中,我用了標準的 ASP.NET 應用程式和 SharePoint 2010 Web App 兩者來測試我的 STS。
現在呢,所有的原始碼都有附在這篇貼文內,但還有一些設定要做。而且您也必須利用應用程式 ID 和您從 Windows Live 取回的密碼,重新編譯應用程式。不過除了複製貼上以外,其實不必再另外寫什麼別的程式碼了。現在就讓我們走過一遍所有必要的步驟吧。
建立 Token 簽署憑證
您必須建立用以簽署 SAML Token 的憑證。用以簽署憑證的憑證沒什麼特殊之處,只不過您必須確定您擁有它的私密金鑰。在我的情況中,我把「憑證服務」安裝在我的網域中,所以我只要開啟 IIS 管理員並選取建立「網域憑證」的選項就行了。照著精靈的指示,不消兩三下,我用私密金鑰建立的新憑證就已經完成了。我為這個專案建立了一個叫做 livevbtoys 的憑證。
和我在下一段說明的一樣,當要求最開始傳入 STS 時,使用者都是匿名使用者。為了能使用該憑證簽署 SAML Token,我們必須允許 IIS 程序存取該憑證的私密金鑰。當有匿名要求傳入時,IIS 程序的身分會是「網路服務」。若要授予存取金鑰的權限,您必須:
- 開啟 MMC。
- 新增憑證嵌入式管理單元。選取本機電腦的電腦存放區。
- 開啟個人憑證存放區,找到您為簽署 SAML Token 所建立的憑證。如果您有照我上面說的方法建立的話,預設憑證就會在其中。如果您是用其他的方式建立憑證,可能必須手動將它加入存放區。
- 在憑證上按一下滑鼠右鍵,選擇 [管理私密金鑰] 的選項。
- 在具有金鑰存取權限的使用者清單中,新增「網路服務」並授予「讀取」權限。
請注意,如果您沒有正確進行此一步驟,當您想要執行應用程式時,可能會看到「金鑰組不存在」之類的錯誤。意思就是說 IIS 程序沒有足夠的權限可以存取私密金鑰,因此無法用它來簽署 SAML Token。
安裝應用程式及必要組件
安裝應用程式在這裡其實只是說要在 IIS 中建立 ASP.NET,複製所需部分,然後確定已安裝最新版的 WIF。在您設定好並在一台伺服器上運行之後,您當然還會想要增加一個或多個額外的伺服器,以確保能有容錯應急的備案。但在這裡我只打算帶您大致看過一遍在單一伺服器上的必要設定。
有關如何在 IIS 中建立 ASP.NET 應用程式,就不加詳述了。要建立 ASP.NET 應用程式的話,您可以使用 Visual Studio、IIS 管理員等進行。
注意: 如果您用我於此處所提供的程式碼,然後直接在 Visual Studio 中開啟專案,會看到主機或網站不存在之類的問題。這是因為它使用的是我的伺服器名稱。要修正這問題最簡單的做法就是手動編輯 WindowsLiveOauthSts.sln 檔,將其中的 https 值改成您環境中實際存在的值。
實際建立之後,還有幾件事情一定要做。
- 在 IIS 管理員中新增 PassiveSTS.aspx 做為 STS 網站的預設文件。
- 在 IIS 中變更應用程式的驗證設定,停用所有「匿名驗證」以外的驗證類型。
- STS 必須在 SSL 上運行,所以您必須取得適當的憑證,並確定您有更新要使用自訂 STS 應用程式之 IIS 虛擬伺服器上的繫結。
- 記得要將您的 Token 簽署憑證指紋,放進信賴憑證者一方 (如果您「不是」使用 SharePoint 進行測試) 的 web.config 之 trustedIssuers 區段內新增元素的指紋屬性中。如果您使用 Visual Studio 中的 [新增 STS 參照精靈],它會代替您完成。
以上就是 IIS 中所需的一切設定。
更新與建立自訂的 STS 專案
隨附的 zip 檔中包含了稱為 WindowsLiveOauthSts 的 Visual Studio 2010 專案。待 IIS 設定完成,而且也照著上述說明更新 WindowsLiveOauthSts.sln 檔之後,您應該就可以順利地在 Visual Studio 中開啟專案了。首先您要做的其中一件事是更新 PassiveSTS.aspx.cs 類別中的 CLIENT_ID 和 CLIENT_SECRET 常數。當您建立新的 Windows Live 應用程式時,會取到它們。我不打算逐步說明 (因為 Windows Live 有很多人可以教您這個),但我可以報給您一個建立 Windows Live 應用程式的好去處:https://manage.dev.live.com/Applications/Index?wa=wsignin1.0 (可能為英文網頁)。還有,當您建立應用程式時,一定要記得將 [重新導向網域] 設成您的自訂 STS 所在位置,例如 https://myserver.foo.com。
現在您已有了 ID 和密碼,以下就是應用程式必須要更新的地方:
- 更新 PassiveSTS.aspx.cs 類別中的 CLIENT_ID 和 CLIENT_SECRET 常數。
- 更新 web.config 檔中 appSettings 區段內的 SigningCertificateName。請注意,您可以不必變更 IssuerName 設定,但如果想改的話也是可以的。
- 更新 STS 專案中 FederationMetadata.xml 文件的 Token 簽署憑證。選好您要使用的憑證之後,即可使用本文隨附的 test.exe 應用程式,取得該憑證的字串值。您必須複製它以取代 federationmetadata.xml 中的兩個 X509Certificate 元素值。
還有一件值得提出來的事,在 CustomSecurityTokenService.cs 檔中,您可以選擇將名為 enableAppliesToValidation 的變數設為 True,然後提供可使用此自訂 STS 的 URL 清單。在這裏我選擇不作任何限制,所以該變數為 False。若打算鎖定您的自訂 STS,請在現在變更它。待這些變更都完成之後,就可以重新編譯應用程式,並開始使用了。
還有一點,我也附帶了一個 ASP.NET 應用程式範例,是我在建立這些東西時用來進行測試的。它位於一個叫做 LiveRP 的專案中,我不打算在這裡說太多。假設您有需要測試什麼的話,可以參考看看。只是要記得照上面說的,要變更 STS Token 簽署憑證的指紋。
SharePoint 設定
到這個階段我們的自訂 STS 一切都已設定完成,而且也應該可以正常運作了。最後要做的一件事,就只剩下要在 SharePoint 中建立一個新的 SPTrustedIdentityToken 發行者,並設定新的或現有的 Web 應用程式來使用它。設定 SPTrustedIdentityTokenIssuer 有幾個要點需留意,我會提供給您我在建立自己的發行者時所使用的 PowerShell,並會加以說明:
$cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2("c:\livevbtoys.cer")
New-SPTrustedRootAuthority -Name "SPS Live Token Signing Certificate" -Certificate $cert
$map = New-SPClaimTypeMapping -IncomingClaimType "https://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress" -IncomingClaimTypeDisplayName "EmailAddress" -SameAsIncoming
$map2 = New-SPClaimTypeMapping -IncomingClaimType "https://blogs.technet.com/b/speschka/claims/id" -IncomingClaimTypeDisplayName "WindowsLiveID" -SameAsIncoming
$map3 = New-SPClaimTypeMapping -IncomingClaimType "https://blogs.technet.com/b/speschka/claims/full_name" -IncomingClaimTypeDisplayName "FullName" -SameAsIncoming
$map4 = New-SPClaimTypeMapping -IncomingClaimType "https://blogs.technet.com/b/speschka/claims/first_name" -IncomingClaimTypeDisplayName "FirstName" -SameAsIncoming
$map5 = New-SPClaimTypeMapping -IncomingClaimType "https://blogs.technet.com/b/speschka/claims/last_name" -IncomingClaimTypeDisplayName "LastName" -SameAsIncoming
$map6 = New-SPClaimTypeMapping -IncomingClaimType "https://blogs.technet.com/b/speschka/claims/link" -IncomingClaimTypeDisplayName "Link" -SameAsIncoming
$map7 = New-SPClaimTypeMapping -IncomingClaimType "https://blogs.technet.com/b/speschka/claims/gender" -IncomingClaimTypeDisplayName "Gender" -SameAsIncoming
$map8 = New-SPClaimTypeMapping -IncomingClaimType "https://blogs.technet.com/b/speschka/claims/locale" -IncomingClaimTypeDisplayName "Locale" -SameAsIncoming
$map9 = New-SPClaimTypeMapping -IncomingClaimType "https://blogs.technet.com/b/speschka/claims/updated_time" -IncomingClaimTypeDisplayName "WindowsLiveLastUpdatedTime" -SameAsIncoming
$map10 = New-SPClaimTypeMapping -IncomingClaimType "https://blogs.technet.com/b/speschka/claims/account" -IncomingClaimTypeDisplayName "AccountName" -SameAsIncoming
$map11 = New-SPClaimTypeMapping -IncomingClaimType "https://blogs.technet.com/b/speschka/claims/accesstoken" -IncomingClaimTypeDisplayName "WindowsLiveAccessToken" -SameAsIncoming
$realm = "https://spslive.vbtoys.com/_trust/"
$ap = New-SPTrustedIdentityTokenIssuer -Name "SpsLive" -Description "Window Live oAuth Identity Provider for SAML" -realm $realm -ImportTrustCertificate $cert -ClaimsMappings $map,$map2,$map3,$map4,$map5,$map6,$map7,$map8,$map9,$map10,$map11 -SignInUrl "https://spr200.vbtoys.com/WindowsLiveOauthSts/PassiveSTS.aspx" -IdentifierClaim "https://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress"
這裡有幾件事情要注意:
- 如上所述,我建立了一個用以簽署 Token 的憑證,叫做 livevbtoys.cer。我把它加入到我的 SPTrustedRootAuthority 清單中,然後建立它與我 Token 發行者之間的關聯。
- 我已為所有我自訂的 STS 正傳回的宣告建立了宣告對應。如您所見,它比起直接和 Windows Live 同盟來得明顯地好更多。此外還有一件事要注意,我從 Windows Live 取得的存取 Token,在這裡以宣告的形式呈現。雖然它對於 Facebook 是管用的,但我沒測試過,所以我不確定 Windows Live 能不能讓您重複使用它。也許改天我會以這為主題,再寫一篇文章。
- $realm 值超級重要。它一定要指向您的 Web 應用程式之根網站,並且包含 /_trust/ 目錄。如果這一步做錯,當您在驗證後重新導回時,SharePoint 只會丟給您 500 項錯誤。
- 建立 Token 發行者時的 –SignInUrl 參數,就是連到我自訂 STS 的 PassiveSTS.aspx 頁面之絕對 URL。
差不多就是如此了!設定完成之後,您仍會使用現成的人員選擇器和宣告提供者,所以也不會有任何查閱功能,就和預期的一樣。要授予人員權限時,就用他們登入 Windows Live 所使用的電子郵件地址。您還可以延伸這個範例,併用 Azure 宣告提供者 (請參考我的這篇部落格文章:https://blogs.msdn.com/b/sharepoint_cht/archive/2012/03/07/the-azure-custom-claim-provider-for-sharepoint-project-part-1.aspx)。這表示您會使用這個 STS 讓您可以處理 Windows Live 的驗證,並取回一些真正的 SAML 宣告,再使用 Azure 自訂宣告提供者專案,將通過驗證的使用者新增到您的 Azure 目錄存放區,以及用以選擇使用者的人員選擇器。
這張圖說明了一切,這就是當您首次來到 SharePoint 網站並以 Windows Live 進行驗證的樣子:
您首次登入時,它會詢問您自訂的 STS 應用程式是否可以共用您的資訊。這裡沒什麼特別需要在意的,只不過是標準 OAuth 權限的作用罷了。看起來就像下面這樣;請注意到它顯示出的是我在 STS 中要求的資料。如果您想要的話,也可以要求一組完全不同的資料。您只需查看 Window Live OAuth SDK,思考一下您要改變什麼,並想出做法就行了:
接受以後,您就會重新導回 SharePoint 網站。在這個範例中我使用的是「SharePoint 宣告」網頁組件,我曾經在這裡發表過它的貼文:https://blogs.technet.com/b/speschka/archive/2010/02/13/figuring-out-what-claims-you-have-in-sharepoint-2010.aspx (可能為英文網頁)。透過 OAuth 您可以看到我從 Windows Live 取得的所有宣告,現在都是 SAML 宣告了,這都要歸功於我的自訂 STS。而且事實上,我也可以用我為本專案所建立的 Windows Live 電子郵件地址來登入 (從右上角的登入控制項):
這是翻譯後的部落格文章。英文原文請參閱 Finally A USEFUL Way to Federate With Windows Live and SharePoint 2010 Using OAuth and SAML