Dot-Net

OWIN 身份驗證管道正確使用 Katana 中間件?

  • September 4, 2014

我正在尋找針對內部 ADFS 2 服務使用 WsFederation Authentication 並使用 OWIN authentication pipeline 。

什麼被認為是連接中間件的順序,以及在各種場景中需要哪些模組,程式碼最少?


例如,看起來UseWsFederationAuthentication應該與 結合使用UseCookieAuthentication,但我不確定正確的AuthenticationType是什麼(這篇文章表明它只是一個標識符字元串,但它的價值是否重要?)或者即使我們仍然需要使用SetDefaultSignInAsAuthenticationType.

我還注意到Katana 項目討論板上的這個執行緒,其中 Tratcher 提到了一個常見錯誤,但並沒有具體說明程式碼的哪一部分出錯。

以下(使用自定義 SAML 令牌處理程序將令牌字元串讀入有效的 XML 文件)有效,但它是最優的嗎?

var appURI = ConfigurationManager.AppSettings["app:URI"];
var fedPassiveTokenEndpoint = ConfigurationManager.AppSettings["wsFederation:PassiveTokenEndpoint"];
var fedIssuerURI = ConfigurationManager.AppSettings["wsFederation:IssuerURI"];
var fedCertificateThumbprint = ConfigurationManager.AppSettings["wsFederation:CertificateThumbprint"];

var audienceRestriction = new AudienceRestriction(AudienceUriMode.Always);

audienceRestriction.AllowedAudienceUris.Add(new Uri(appURI));

var issuerRegistry = new ConfigurationBasedIssuerNameRegistry();

issuerRegistry.AddTrustedIssuer(fedCertificateThumbprint, fedIssuerURI);

app.UseCookieAuthentication(
   new CookieAuthenticationOptions
   {
       AuthenticationType = WsFederationAuthenticationDefaults.AuthenticationType // "Federation"
   }
);

app.UseWsFederationAuthentication(
   new WsFederationAuthenticationOptions
   {
       Wtrealm = appURI,
       SignOutWreply = appURI,
       Configuration = new WsFederationConfiguration
       {
           TokenEndpoint = fedPassiveTokenEndpoint
       },
       TokenValidationParameters = new TokenValidationParameters
       {
           AuthenticationType = WsFederationAuthenticationDefaults.AuthenticationType
       },
       SecurityTokenHandlers = new SecurityTokenHandlerCollection
       {                        
           new SamlSecurityTokenHandlerEx
           {
               CertificateValidator = X509CertificateValidator.None,
               Configuration = new SecurityTokenHandlerConfiguration
               {
                   AudienceRestriction = audienceRestriction,
                   IssuerNameRegistry = issuerRegistry
               }
           }
       }
   }
);

正如@Tratcher 所說,該AuthenticationType參數用作Microsoft.Owin.Security查找身份驗證中間件實例的密鑰。

下面的程式碼將使用以下簡單的幫助方法來要求所有請求都經過身份驗證。在實踐中,您更有可能[Authorize]在敏感控制器上使用屬性,但我想要一個不依賴任何框架的範例:

private static void AuthenticateAllRequests(IAppBuilder app, params string[] authenticationTypes)
{
   app.Use((context, continuation) =>
   {
       if (context.Authentication.User != null &&
           context.Authentication.User.Identity != null &&
           context.Authentication.User.Identity.IsAuthenticated)
       {
           return continuation();
       }
       else
       {
           context.Authentication.Challenge(authenticationTypes);
           return Task.Delay(0);
       }
   });
}

context.Authentication.Challenge(authenticationTypes)呼叫將從每個提供的身份驗證類型發出身份驗證質詢。我們只提供一種,我們的 WS-Federation 身份驗證類型。

正確的程式碼

因此,首先,這是一個簡單地使用 WS-Federation 的站點的“最佳”Owin 啟動配置範例,就像您一樣:

public void Configuration(IAppBuilder app)
{
   app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);

   app.UseCookieAuthentication(new CookieAuthenticationOptions());

   app.UseWsFederationAuthentication(new WsFederationAuthenticationOptions
   {
       AuthenticationType = "WS-Fed Auth (Primary)",
       Wtrealm = ConfigurationManager.AppSettings["app:URI"],
       MetadataAddress = ConfigurationManager.AppSettings["wsFederation:MetadataEndpoint"]
   });

   AuthenticateAllRequests(app, "WS-Fed Auth (Primary)");

   app.UseWelcomePage();
}

請注意使用"WS-Fed Auth (Primary)" AuthenticationType來唯一標識我們配置的 WS-Federation 中間件實例。這意味著,例如"WS-Fed Auth (Secondary)",如果您有此要求,您可以將 a 與單獨的 WS-Federation 伺服器一起用作備份。

此配置將執行以下操作:

  1. 首先,告訴 Owin 安全管道,預設情況下我們要使用預設的 CookeAuthentication AthenticationType 值對請求進行身份驗證。(這只是CookieAuthenticationDefaults該類上的一個常量字元串,它是該屬性使用的預設值CookieAuthenticationOptions.AuthenticationType。)
  2. 接下來,使用所有預設選項註冊一個 cookie 身份驗證中間件實例,因此它對應於AuthenticationType我們在步驟 1 中設置為預設值的密鑰。
  3. 接下來,使用我們在 Web.config 文件中定義的選項和自定義的 AuthenticationType 值註冊一個 WS-Federation 身份驗證中間件實例,以便我們以後可以引用它
  4. 在完成所有身份驗證中間件註冊後,我們告訴管道對所有請求進行身份驗證(通過我們的自定義幫助方法,該Microsoft.Owin.Security方法呼叫向任何未經身份驗證的請求發出挑戰的方法)
  5. 最後,如果使用者已通過身份驗證,則顯示歡迎頁面!

錯誤的程式碼

所以這裡有幾種方法可能會出錯。

未提供預設身份驗證類型

為了進行實驗,我嘗試這樣做,您會立即看到問題所在:

public void Configuration(IAppBuilder app)
{
   var x = app.GetDefaultSignInAsAuthenticationType();

   app.SetDefaultSignInAsAuthenticationType(x);
}

第一次通話會給您在第一條評論中提到的例外情況:

“在 IAppBuilder 屬性中找不到 SignInAsAuthenticationType 的預設值。如果您的身份驗證中間件以錯誤的順序添加或缺少一個,則可能會發生這種情況。”

對 - 因為預設情況下,Microsoft.Owin.Security管道不假設您將使用的中間件(即,Microsoft.Owin.Security.Cookies甚至不知道是否存在),所以它不知道應該是什麼預設值。

使用錯誤的預設身份驗證類型

今天這花了我很多時間,因為我真的不知道自己在做什麼:

public void Configuration(IAppBuilder app)
{
   app.SetDefaultSignInAsAuthenticationType("WS-Fed AAD Auth");

   // ... remainder of configuration
}

因此,這將繼續嘗試*在每次呼叫時使用 WS-Federation 對呼叫者進行身份驗證。並不是說這非常昂貴,而是 WS-Federation 中間件實際上會對每個請求發出挑戰。*所以你永遠無法進入,你會看到一大堆登錄 URL 從你身邊飛過。:P

可能性

因此,在管道中擁有所有這些靈活性的好處在於,您可以做一些非常酷的事情。例如,我有一個域,其中包含兩個不同的 Web 應用程序,在不同的子路徑下執行,例如:example.com/fooexample.com/bar. 您可以使用 Owin 的映射功能(如 參考資料app.Map(...))為每個應用程序設置完全不同的身份驗證管道。在我的例子中,一個使用 WS-Federation,而另一個使用客戶端證書。試圖在單體System.Web框架中做到這一點將是可怕的。:P

引用自:https://stackoverflow.com/questions/25663773