簡體   English   中英

有條件地使用ADFS進行登錄

[英]Conditionally use ADFS for login

我需要為我們的一位客戶集成ADFS。

我們正在使用OWIN和OAuth Bearer令牌以及JWT Bearer Auth。 所有這些都很好。 輸入用戶名(電子郵件)和密碼,針對我們的數據庫用戶存儲進行身份驗證,獲得承載令牌。

僅當輸入的用戶名位於特定域(即客戶端的域)中時,才需要請求客戶端的ADFS服務器進行身份驗證。 (我們不需要詢問密碼;登錄名已被修改為首先詢問電子郵件,檢查它是否是客戶端域,然后查看是否是客戶端域,然后詢問密碼-看看Box.com是如何做到的,這非常相似。 )

我們目前完全不使用AD,也沒有工廠這樣做,這意味着所有點綴在網絡上的“聯合”示例都無法以任何方式為我們提供幫助,因為它們假定您已經在使用ADFS或Azure AD,而我們不是。

我們的移動應用程序正在使用ADAL 1.0庫,並且在某種程度上運行良好(它還需要#2才能工作)

1)我不知道如何將用戶的瀏覽器重定向到客戶的ADFS登錄頁面。 一切都使用一個庫,並且所有這些庫都是在編譯時配置的-但我不知道該用戶將ADFS發送給哪個客戶端,直到該用戶在運行時實際啟動登錄過程為止。 另外,這不是使用Azure AD,這是本地服務器-所以我不能使用Microsoft網關。

2)回調需要解析用戶的令牌,確保它對我們有意義,並通過所有簽名檢查,然后我們發布自己的承載令牌-我們不能使用客戶端的令牌。 這應該相對容易一些,但是我不知道如何告訴ADFS端點什么是回調URL。

是的,我知道編寫這些庫的原因是為了使其更難解決。 我沒有太多選擇-這些庫想接管整個過程,但是我想有條件地調用它們。

更多信息:

客戶端ADFS為3.0

我有能力使用OWIN的身份驗證,並且如果按下,可能可以在編譯時設置客戶端。

好。 我敢肯定我會為此得到一些廢話,但是這是可行的。

我們最終有條件地使用了OAuth2-檢查用戶的電子郵件地址,查看域,並加載其單點登錄體驗的配置信息。

我找不到可以有條件調用的OWIN的任何OAuth2中間件(即使我為它們配置了字幕並處於“被動”模式,ADAL庫也不起作用),所以最終我使用適當的參數手動重定向到IDP。 我們的移動開發人員將ADAL 1.0與Xamarin一起使用,因此我能夠從該工作流程中獲取OAuth2 URL( https://adfs.example.net/oauth2/authorize )並在那里重定向。

解決步驟1:我創建了一個OAuth2回調終結點(必須在ADFS上注冊!我有一個querystring參數,該參數暗示要加載的SSO配置,但是一點都不能改變-它必須始終相同那一個IdP),並設置一種方法來交換令牌的“代碼”查詢字符串參數。 這是一個非常簡單的HTTPS調用,但是您將必須自己驗證令牌(這是我的要求步驟2所必需的),並且必須有一堆代碼來挖掘電子郵件地址/用戶名聲明。 您必須設置授權類型以進行傳輸,並准備處理不同的聲明名稱空間。 請記住要傳遞您的回調URL-OAuth2標准要求您再次傳遞它,保持不變-否則您的代碼無效。

使用出色的System.IdentityModel.Tokens.Jwt庫驗證令牌為有效令牌后(您希望參考Stack Overflow上的其他問題,了解如何以PEM格式加載X509證書,因為我們希望將IDP的pubkey存儲在數據庫中的ascii裝甲的PEM格式-目前被認為很不錯的代碼),並且適用於預期的受眾,並且發行人是您所期望的(以防有人嘗試破壞域)提示),並且簽名匹配(捕獲了大多數這些較早的情況),並且簽名與用戶鍵入的電子郵件地址匹配(這是OWIN“外部Cookie”中間件的工作,當您可以使用時):

然后只有這樣,您才能發行令牌。

我必須在啟動代碼中存儲對JWT保護庫的引用(我們正在使用Autofac):

builder.RegisterInstance(customFormat).As<ISecureDataFormat<AuthenticationTicket>>();

ISecureDataFormat是用於保護/取消保護JWT密鑰的注冊內容。 我無法找到一種方法來利用OWIN身份驗證對象,從而無法找到將該實例作為某個位置的屬性,因此我不得不將對其的引用存儲在我們的Io​​C模塊中。

我們的登錄代碼(自定義身份驗證提供程序)如下所示:

        var cookiesIdentity = await _userManager.CreateIdentityAsync(user, CookieAuthenticationDefaults.AuthenticationType);
        Request.GetOwinContext().Authentication.SignIn(new AuthenticationProperties { IsPersistent = true }, cookiesIdentity);

        // login
        var properties = new AuthenticationProperties(new Dictionary<string, string>
        {
            { "userName", globalUser.UserName },
            { "userId", globalUser.Id.ToString() }
        })
        {
            IsPersistent = true,
            IssuedUtc = DateTime.UtcNow,
            ExpiresUtc = DateTime.UtcNow.AddDays(28),
        };

        // jwt
        var oAuthIdentity = await _userManager.CreateIdentityAsync(user, "JWT");
        oAuthIdentity.AddClaim(new Claim(JwtRegisteredClaimNames.Sub, user.Id.ToString()));
        oAuthIdentity.AddClaim(new Claim(JwtRegisteredClaimNames.Email, user.Email));
        oAuthIdentity.AddClaim(new Claim(JwtRegisteredClaimNames.GivenName, user.Contact.ContactFirstName + " " + user.Contact.ContactLastName));

        Microsoft.Owin.Security.AuthenticationTicket at = new Microsoft.Owin.Security.AuthenticationTicket(oAuthIdentity, properties);
        string jwt = Startup.Resolve<ISecureDataFormat<AuthenticationTicket>>().Protect(at);

字符串“ jwt”是實際的原始身份驗證票證,我們將其存儲在本地存儲中以對API進行身份驗證。 (是的,我們的應用程序很奇怪。您登錄了MVC頁面,但是這些頁面使用JWT令牌調用了API,與移動應用程序一樣。它不是SPA,但有點像一個。)

解決方案2:Microsoft ADAL庫不是從OAuth2進程返回授權代碼,而是從ADFS返回實際的令牌。 我建立了另一個端點,該端點在步驟1解決方案的中間啟動該過程,並調用相同的方法來驗證令牌,提取用戶名/電子郵件並返回承載令牌。 ADAL庫已經驗證了登錄表單上輸入的用戶名與令牌中的聲明匹配,但是服務器需要先驗證令牌是否合法,然后再將其交換為我們的JWT承載令牌。

我敢肯定,這本來可以容易得多,但是老實說,OAuth2並不是很難手工完成的-但只有在您被迫時才這樣做。 OWIN中間件經過了充分的測試,涵蓋了我下個月要尋找的特殊情況-它只是不真正支持跳過很多步驟。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM