简体   繁体   English

OWIN身份验证管道以及如何正确使用Katana中间件?

[英]The OWIN authentication pipeline, and how to use Katana middleware correctly?

I've recently started looking at the new ASP.Net Identity framework and the Katana middleware, there's a surprising amount of code and documentation out there, but I'm seeing what appears to be a lot of conflicting information, which I guess is a result of the increasing frequency of code updates. 我最近开始研究新的ASP.Net Identity框架和Katana中间件,那里有大量的代码和文档,但是我看到的似乎是很多相互矛盾的信息,我想这是一个代码更新频率增加的结果。

I'm looking to use WsFederation Authentication against an internal ADFS 2 service, but the way the OWIN authentication pipeline works has me a little confused and I'm hoping someone can offer some definitive information. 我希望对内部ADFS 2服务使用WsFederation身份验证,但是OWIN身份验证管道的工作方式让我有些困惑,我希望有人可以提供一些确定的信息。

Specifically, I'm interested in the order in which middleware should be hooked up and which modules are required in various scenarios, I'd like to get rid of anything that doesn't need to be there and at the same time ensure that the process is as secure as possible. 具体来说,我对连接中间件的顺序以及在各种情况下需要哪些模块的顺序很感兴趣,我想摆脱不需要的任何东西,同时确保过程是尽可能安全的。

For example, it would appear that UseWsFederationAuthentication should be used in conjunction with UseCookieAuthentication , but I'm not sure what the correct AuthenticationType would be ( this post suggests that it's just an identifier string, but is it's value significant?) or even if we still need to use SetDefaultSignInAsAuthenticationType . 例如,看起来UseWsFederationAuthentication应该与UseCookieAuthentication结合使用,但是我不确定正确的AuthenticationType是什么( 这篇文章建议它只是一个标识符字符串,但是它的值有意义吗?),即使我们仍然需要使用SetDefaultSignInAsAuthenticationType

I also noticed this thread on the Katana Project discussions board, where Tratcher mentions a common mistake, but isn't very specific as to which part of the code is in error. 我还在Katana Project讨论板上注意到了线程,Tratcher在其中提到了一个常见错误,但是对于代码的哪一部分有错误,并不是很具体。

Personally, I'm now using the following (with a custom SAML Token handler to read the token string into a valid XML document), it works for me, but is it optimal? 就我个人而言,我现在使用以下代码(带有自定义的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
                }
            }
        }
    }
);

Many thanks for anything you can offer to help clear up this confusion for me. 非常感谢您为我消除这种困惑提供的任何帮助。

As @Tratcher said, the AuthenticationType parameter is used by Microsoft.Owin.Security as a key to do lookups of authentication middleware instances. 正如@Tratcher所说, Microsoft.Owin.Security使用AuthenticationType参数作为查找身份验证中间件实例的键。

The code below will use the following simple helper method to require that all requests are authenticated. 下面的代码将使用以下简单的辅助方法来要求所有请求都经过身份验证。 In practice you're more likely to use an [Authorize] attribute on sensitive controllers, but I wanted an example that doesn't rely on any frameworks: 在实践中,您更有可能在敏感控制器上使用[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);
        }
    });
}

The context.Authentication.Challenge(authenticationTypes) call will issue an authentication challenge from each of the provided authentication types. context.Authentication.Challenge(authenticationTypes)调用将从每个提供的身份验证类型发出身份验证质询。 We're just going to provide the one, our WS-Federation authentication type. 我们将只提供一种,即WS-Federation身份验证类型。

Correct Code 正确的代码

So first, here's an example of the "optimal" Owin Startup configuration for a site that's simply using WS-Federation, as you are: 因此,首先,这是一个仅使用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();
}

Note the use of the "WS-Fed Auth (Primary)" AuthenticationType to uniquely identify the WS-Federation middleware instance we've configured. 请注意,使用"WS-Fed Auth (Primary)" AuthenticationType来唯一标识我们已配置的WS-Federation中间件实例。 This means that you could, for example, use a "WS-Fed Auth (Secondary)" with a separate WS-Federation server as a fallback, if you had that requirement. 这意味着,例如,如果有此要求,则可以将"WS-Fed Auth (Secondary)"与单独的WS-Federation服务器一起用作备用。

This configuration will do the following: 此配置将执行以下操作:

  1. First, tell the Owin security pipeline that by default we want to authenticate requests with the default CookeAuthentication AthenticationType value . 首先,告诉Owin安全管道,默认情况下,我们要使用默认的CookeAuthentication AthenticationType值对请求进行身份验证。 (That's just a constant string on that CookieAuthenticationDefaults class, and it's the default value used by the CookieAuthenticationOptions.AuthenticationType property.) (这只是该CookieAuthenticationDefaults类上的常量字符串,它是CookieAuthenticationOptions.AuthenticationType属性使用的默认值。)
  2. Next, register a cookie authentication middleware instance with all default options, so it corresponds to the AuthenticationType key that we set as the default in step 1. 接下来,使用所有默认选项注册一个cookie身份验证中间件实例,使其对应于我们在步骤1中设置为默认值的AuthenticationType密钥。
  3. Next, register a WS-Federation authentication middleware instance with options that we define in the Web.config file, and with a custom AuthenticationType value so we can refer to it later . 接下来,使用我们在Web.config文件中定义的选项以及自定义AuthenticationType值注册WS-Federation身份验证中间件实例, 以便我们稍后可以参考它
  4. After all the authentication middleware registrations are done, we tell the pipeline to authenticate all requests (via our custom helper method that calls the Microsoft.Owin.Security methods for issuing challenges to any unauthenticated request) 完成所有身份验证中间件的注册后,我们告诉管道对所有请求进行身份验证(通过我们的自定义帮助方法,该方法调用Microsoft.Owin.Security方法,以向任何未身份验证的请求发出挑战)
  5. Finally, if the user has been authenticated, show the welcome page! 最后,如果用户已通过身份验证,请显示欢迎页面!

Wrong Code 错误代码

So there are a couple ways you can go wrong here. 因此,您可以通过以下几种方式在这里出错。

Not providing a default authentication type 不提供默认的身份验证类型

To experiment, I tried doing this, and you'll see right away what the problem is: 为了进行试验,我尝试这样做,您会立即看到问题所在:

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

    app.SetDefaultSignInAsAuthenticationType(x);
}

That first call will give you the exception you mentioned in your first comment: 第一次致电会给您在第一条评论中提到的例外情况:

"A default value for SignInAsAuthenticationType was not found in IAppBuilder Properties. This can happen if your authentication middleware are added in the wrong order, or if one is missing." “在IAppBuilder属性中找不到SignInAsAuthenticationType的默认值。如果以错误的顺序添加身份验证中间件,或者缺少身份验证中间件,则可能会发生这种情况。”

Right - because by default the Microsoft.Owin.Security pipeline doesn't assume anything about the middleware you're going to use (ie, Microsoft.Owin.Security.Cookies isn't even known to be present), so it doesn't know what should be the default. 是的-因为默认情况下, Microsoft.Owin.Security管道不会假设您要使用的中间件(即,甚至不存在Microsoft.Owin.Security.Cookies ),所以它不会不知道默认值是什么。

Using the wrong default authentication type 使用错误的默认身份验证类型

This cost me a lot of time today because I didn't really know what I was doing: 今天,这花费了我很多时间,因为我真的不知道自己在做什么:

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

    // ... remainder of configuration
}

So, that's going to keep trying to authenticate the caller with WS-Federation on every call. 因此,这将继续尝试在每次调用时使用WS-Federation 对调用方进行身份验证 It's not that that's super-expensive, it's that the WS-Federation middleware will actually issue a challenge on every request. 并不是说这很昂贵,而是WS-Federation中间件实际上会在每个请求上发出挑战。 So you can't ever get in, and you see a whole lot of login URLs fly past you. 因此,您永远无法进入,并且看到大量登录URL飞过您。 :P :P

Possibilities 可能性

So what's great about having all this flexibility in the pipeline is that you can do some really cool things. 因此,在管道中拥有所有这些灵活性的最大好处就是您可以做一些非常酷的事情。 For instance, I have a domain with two different web apps inside of it, running under different subpaths like: example.com/foo and example.com/bar . 例如,我有一个域,其中包含两个不同的Web应用程序,并在不同的子路径下运行,例如: example.com/fooexample.com/bar You can use Owin's mapping functionality (as in app.Map(...) ) to set up a totally different authentication pipeline for each of those apps. 您可以使用Owin的映射功能(如app.Map(...) )为每个应用程序设置完全不同的身份验证管道。 In my case, one is using WS-Federation, while the other is using client certificates. 就我而言,一个正在使用WS联合身份验证,而另一个正在使用客户端证书。 Trying to do that in the monolithic System.Web framework would be horrible. 试图在单一的System.Web框架中做到这一System.Web是可怕的。 :P :P

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM