C# OWIN认证管道,以及如何正确使用Katana中间件?

C# OWIN认证管道,以及如何正确使用Katana中间件?,c#,owin,adfs,katana,ws-federation,C#,Owin,Adfs,Katana,Ws Federation,我最近开始研究新的ASP.Net Identity framework和Katana中间件,那里有大量令人惊讶的代码和文档,但我看到了很多相互冲突的信息,我想这是代码更新频率不断增加的结果 我希望对内部ADFS 2服务使用WsFederation身份验证,但OWIN身份验证管道的工作方式让我有点困惑,我希望有人能提供一些明确的信息 具体来说,我感兴趣的是中间件连接的顺序,以及在各种场景中需要哪些模块,我想去掉不需要的任何东西,同时确保流程尽可能安全 例如,UseWsFederationAuthe

我最近开始研究新的ASP.Net Identity framework和Katana中间件,那里有大量令人惊讶的代码和文档,但我看到了很多相互冲突的信息,我想这是代码更新频率不断增加的结果

我希望对内部ADFS 2服务使用WsFederation身份验证,但OWIN身份验证管道的工作方式让我有点困惑,我希望有人能提供一些明确的信息

具体来说,我感兴趣的是中间件连接的顺序,以及在各种场景中需要哪些模块,我想去掉不需要的任何东西,同时确保流程尽可能安全

例如,
UseWsFederationAuthentication
似乎应该与
UseCookieAuthentication
结合使用,但我不确定正确的
AuthenticationType
是什么(post表明它只是一个标识符字符串,但它的值是否重要?)或者即使我们仍然需要使用
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
用作查找身份验证中间件实例的密钥

下面的代码将使用以下简单的helper方法来要求对所有请求进行身份验证。实际上,您更可能在敏感控制器上使用
[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-Federation服务器的
“WS-Feded Auth(Secondary)”
用作后备方案

此配置将执行以下操作:

  • 首先,告诉Owin安全管道,默认情况下,我们希望使用默认的CookeeAuthentication AthenticationType值对请求进行身份验证。(这只是
    CookieAuthenticationDefaults
    类上的一个常量字符串,它是
    CookieAuthenticationOptions.AuthenticationType
    属性使用的默认值。)
  • 接下来,使用所有默认选项注册cookie身份验证中间件实例,使其对应于我们在步骤1中设置为默认值的
    AuthenticationType
    密钥
  • 接下来,使用我们在Web.config文件中定义的选项和自定义AuthenticationType值注册WS-Federation身份验证中间件实例,以便我们以后可以引用它
  • 完成所有身份验证中间件注册后,我们通知管道对所有请求进行身份验证(通过我们的自定义帮助器方法,该方法调用
    Microsoft.Owin.Security
    方法,用于对任何未经身份验证的请求发出质询)
  • 最后,如果用户已通过身份验证,则显示欢迎页面 错误代码 所以这里有两种方法可以让你出错

    不提供默认身份验证类型 为了进行实验,我尝试了这样做,您将立即看到问题所在:

    public void Configuration(IAppBuilder app)
    {
        var x = app.GetDefaultSignInAsAuthenticationType();
    
        app.SetDefaultSignInAsAuthenticationType(x);
    }
    
    第一个电话将为您提供您在第一条评论中提到的例外情况:

    在IAppBuilder属性中找不到SignanAuthenticationType的默认值。如果身份验证中间件的添加顺序错误,或者缺少一个,则可能会发生这种情况

    右-因为默认情况下,
    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/foo
    example.com/bar
    。您可以使用Owin的映射功能(如
    app.Map(…)
    )为每个应用程序设置完全不同的身份验证管道。在我的例子中,一个使用WS-Federation,而另一个使用客户端证书。在单片
    系统.Web
    框架中尝试这样做将是可怕的:P

    另外,如果我替换WsFederationAuthentica