如何验证来自一个C#应用程序到WIF的请求允许使用SAML断言ASP.NET的WebAPI应用 [英] How to authenticate a request from a c# application to a WIF enabled ASP.NET WebApi application using a SAML assertion

查看:689
本文介绍了如何验证来自一个C#应用程序到WIF的请求允许使用SAML断言ASP.NET的WebAPI应用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经安装ThinkTecture身份服务器作为STS,已经建立了网络API项目,并在Visual Studio中使用的身份和访问工具,并指出我的联邦元数据,以便使用WIF联合身份验证。这是web.config中的相关部分看起来是这样的:

 < system.identityModel>
    < identityConfiguration saveBootstrapContext =真正的>
      < audienceUris>
        <增加价值=HTTP://本地主机:41740 //>
      < / audienceUris>    < securityTokenHandlers>
        <加上TYPE =System.IdentityModel.Tokens.SamlSecurityTokenHandler,System.IdentityModel,版本= 4.0.0.0,文化=中性公钥= B77A5C561934E089/>
        <加上TYPE =System.IdentityModel.Tokens.Saml2SecurityTokenHandler,System.IdentityModel,版本= 4.0.0.0,文化=中性公钥= B77A5C561934E089/>
    < / securityTokenHandlers>      < issuerNameRegistry TYPE =System.IdentityModel.Tokens.ValidatingIssuerNameRegistry,System.IdentityModel.Tokens.ValidatingIssuerNameRegistry>
        <机构名称=htt​​p://auth.myserver.com/samples>
          <&按键GT;
            <加入指纹=F89C10B505E015774D02E323DEDA32878F794028/>
          < /键>
          < validIssuers>
            <添加名称=htt​​p://auth.myserver.com/samples/>
          < / validIssuers>
        < /权威>
      < / issuerNameRegistry>
      <! - certificationValidationMode设置为无的身份和访问工具为Visual Studio。为发展宗旨.-->
      < certificateValidation certificateValidationMode =无/>
    < / identityConfiguration>
  < /system.identityModel>
  < system.identityModel.services>
    < federationConfiguration>
      <的CookieHandler requireSsl =FALSE/>
      < wsFederation passiveRedirectEnabled =真发行人=htt​​ps://10.40.40.68/issue/wsfed的境界=HTTP://本地主机:41740 /requireHttps =FALSE/>
    < / federationConfiguration>
  < /system.identityModel.services>

这用于验证谁使用API​​从浏览器用户的伟大工程。

我现在需要调用从客户端应用程序code(C#)相同的API - 允许调用APIClient - 使用了HTTPClient

在为了做到这一点,我已将此添加到web.config中:

 < securityTokenHandlers>
        <! - <加上TYPE =System.IdentityModel.Tokens.JwtSecurityTokenHandler,System.IdentityModel.Tokens.Jwt/> - >
        <加上TYPE =System.IdentityModel.Tokens.SamlSecurityTokenHandler,System.IdentityModel,版本= 4.0.0.0,文化=中性公钥= B77A5C561934E089/>
        <加上TYPE =System.IdentityModel.Tokens.Saml2SecurityTokenHandler,System.IdentityModel,版本= 4.0.0.0,文化=中性公钥= B77A5C561934E089/>
< / securityTokenHandlers>

我的假设是,如果我添加SAML令牌处理程序,并添加一个SAML断言到HTTP头授权,WIF会挑选和验证请求。

我可以调用STS获得SAML令牌作为GetSamlToken方法描述如下:<一href=\"https://github.com/thinktecture/Thinktecture.IdentityModel.45/blob/master/Samples/Web%20API%20Security/Clients/SamlAuthentication/Program.cs\"相对=nofollow>在这里输入链接的描述

这给了我一个SAML断言,我重视HttpClient的标题:

  client.SetToken(SAML,AuthenticationHeader);

其中的 AuthenticationHeader 的是SAML断言我从服务器接收。
问题是网页API并不做任何事情与samle断言 - 仿佛它甚至没有看到它,我只在响应重定向到STS获得。

我是什么做错了吗?我如何可以验证,并呼吁其他code我保护的Web API方法,而无需切换到智威汤逊等。

在此先感谢您的帮助!

- 更新

我添加以下到我的WebApiConfig.cs为@Brock建议:

 公共静态无效的注册(HttpConfiguration配置)
{
    //跨源资源共享
    //CorsConfig.RegisterCors(GlobalConfiguration.Configuration);
    CorsConfig.RegisterCors(配置);
    // CorsConfiguration corsConfig =新CorsConfiguration();
    //corsConfig.AllowAll();
    // VAR corsHandler =新CorsMessageHandler(corsConfig,配置);
    //config.MessageHandlers.Add(corsHandler);
    //身份认证控制器配置
    变种认证= CreateAuthenticationConfiguration();
    config.MessageHandlers.Add(新的AuthenticationHandler(认证));    // ASP.Net的Web API使用NewtonSoft Json.net本身,
    //以下行强制网页API使用XML序列化,而不是数据串行合同
    config.Formatters.XmlFormatter.UseXmlSerializer =真;    log.Debug(注册的Web API路线);
    //注册API路线}
私有静态AuthenticationConfiguration CreateAuthenticationConfiguration()
{
    VAR认证=新AuthenticationConfiguration
    {
        ClaimsAuthenticationManager =新ClaimsTransformer()
        RequireSsl =假,
        EnableSessionToken =真
    };    #区域IdentityServer SAML
    authentication.AddSaml2(
        issuerThumbprint:F89C10B505E015774D02E323DEDA32878F794028
        证书中issuerName:https://10.40.40.68/issue/wsfed
        audienceUri:HTTP://本地主机:41740 /,// Constants.Realm,
        certificateValidator:System.IdentityModel.Selectors.X509CertificateValidator.None,
        选项​​:AuthenticationOptions.ForAuthorizationHeader(SAML),
        方案:AuthenticationScheme.SchemeOnly(SAML));
    #endregion    #区域客户端证书
    authentication.AddClientCertificate(ClientCertificateMode.ChainValidation);
    #endregion    返回认证;
}

不过,我仍然得到302响应。这是我提出请求:

  ServicePointManager.ServerCertificateValidationCallback + =(发件人,证书链,sslPolicyErrors)=&GT;真正;
VAR厂=新WSTrustChannelFactory(
    新UserNameWSTrustBinding(SecurityMode.TransportWithMessageCredential)
    https://10.40.40.68/issue/wstrust/mixed/username);
factory.TrustVersion = TrustVersion.WSTrust13;factory.Credentials.UserName.UserName =名为myusername;
factory.Credentials.UserName.Password =密码;VAR RST =新RequestSecurityToken
{
    请求类型= RequestTypes.Issue,
    关键字类型= KeyTypes.Bearer,
    TokenType = Thinktecture.IdentityModel.Constants.TokenTypes.Saml2TokenProfile11,
    AppliesTo =新EndpointReference的(HTTP://本地主机:41740 /)
};VAR令牌= factory.CreateChannel()问题(RST)为System.IdentityModel.Tokens.GenericXmlSecurityToken。串即为MyToken = token.TokenXml.OuterXml;HttpClient的客户端=新的HttpClient(新HttpClientHandler
{
    ClientCertificateOptions = ClientCertificateOption.Automatic,
    AllowAutoRedirect = FALSE
});client.SetToken(SAML,即为MyToken);
//client.SetBearerToken(myToken);VAR RESP = client.GetAsync(HTTP://本地主机:41740 / API /客户端,HttpCompletionOption.ResponseContentRead)。结果;
Assert.IsTrue(resp.IsSuccessStatus code);


解决方案

网页API V1不具有管道自动查找在请求令牌。这个功能缺失是由Thinktecture IdentityModel在它的Web API认证消息处理程序提供。检查样本文件夹为例(专门为AuthenticationConfiguration类和AddSaml2 API):

<一个href=\"https://github.com/thinktecture/Thinktecture.IdentityModel.45/tree/master/Samples/Web%20API%20Security\" rel=\"nofollow\">https://github.com/thinktecture/Thinktecture.IdentityModel.45/tree/master/Samples/Web%20API%20Security

I have setup ThinkTecture identity server as a STS, Have setup a web api project, and used the "identity and access" tool in visual studio and pointed it to my federation metadata to enable federated authentication using WIF. This is what the related portion of web.config looks like:

<system.identityModel>
    <identityConfiguration saveBootstrapContext="true">
      <audienceUris>
        <add value="http://localhost:41740/" />
      </audienceUris>

    <securityTokenHandlers>
        <add type="System.IdentityModel.Tokens.SamlSecurityTokenHandler, System.IdentityModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089" />
        <add type="System.IdentityModel.Tokens.Saml2SecurityTokenHandler, System.IdentityModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089" />
    </securityTokenHandlers>            

      <issuerNameRegistry type="System.IdentityModel.Tokens.ValidatingIssuerNameRegistry, System.IdentityModel.Tokens.ValidatingIssuerNameRegistry">
        <authority name="http://auth.myserver.com/samples">
          <keys>
            <add thumbprint="F89C10B505E015774D02E323DEDA32878F794028" />
          </keys>
          <validIssuers>
            <add name="http://auth.myserver.com/samples" />
          </validIssuers>
        </authority>
      </issuerNameRegistry>
      <!--certificationValidationMode set to "None" by the the Identity and Access Tool for Visual Studio. For development purposes.-->
      <certificateValidation certificateValidationMode="None" />
    </identityConfiguration>
  </system.identityModel>
  <system.identityModel.services>
    <federationConfiguration>
      <cookieHandler requireSsl="false" />
      <wsFederation passiveRedirectEnabled="true" issuer="https://10.40.40.68/issue/wsfed" realm="http://localhost:41740/" requireHttps="false" />
    </federationConfiguration>
  </system.identityModel.services>

This works great for authenticating users who use the API from the browser.

I now need to call the same API from code (C#) in a client application - lets call that APIClient - using HTTPClient.

In order to do so, I added this to the web.config:

<securityTokenHandlers>
        <!--<add type="System.IdentityModel.Tokens.JwtSecurityTokenHandler, System.IdentityModel.Tokens.Jwt" />-->
        <add type="System.IdentityModel.Tokens.SamlSecurityTokenHandler, System.IdentityModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089" />
        <add type="System.IdentityModel.Tokens.Saml2SecurityTokenHandler, System.IdentityModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089" />
</securityTokenHandlers>

My assumption was that If I add the SAML token handler and add a SAML assertion to the HTTP Authorize header, WIF will pick that up and authenticate the request.

I can call the STS to get a SAML token as described in the GetSamlToken method here: enter link description here

That gives me a SAML assertion that I attach to the HTTPClient header:

client.SetToken("SAML", AuthenticationHeader);

Where AuthenticationHeader is the SAML assertion I received from the server. The problem is web api doesn't do anything with the samle assertion - as if it doesn't even see it, All I get in response a a redirect to the STS.

What am I doing wrong? How can I authenticate and call my protected web api method from other code without having to switch to JWT, etc.?

Thanks in advance for your help!

-- updated

I have added the following to my WebApiConfig.cs as @Brock suggested:

public static void Register(HttpConfiguration config)
{
    // Cross Origin Resource Sharing
    //CorsConfig.RegisterCors(GlobalConfiguration.Configuration);
    CorsConfig.RegisterCors(config);


    //CorsConfiguration corsConfig = new CorsConfiguration();
    //corsConfig.AllowAll();
    //var corsHandler = new CorsMessageHandler(corsConfig, config);
    //config.MessageHandlers.Add(corsHandler);


    // authentication configuration for identity controller
    var authentication = CreateAuthenticationConfiguration();
    config.MessageHandlers.Add(new AuthenticationHandler(authentication));



    // ASP.Net web api uses NewtonSoft Json.net natively, 
    // the following line forces the web api to use the xml serializer instead of data contract serializer
    config.Formatters.XmlFormatter.UseXmlSerializer = true;

    log.Debug("Registering Web API Routes");


    // register api routes

}




private static AuthenticationConfiguration CreateAuthenticationConfiguration()
{
    var authentication = new AuthenticationConfiguration
    {
        ClaimsAuthenticationManager = new ClaimsTransformer(),
        RequireSsl = false,
        EnableSessionToken = true
    };

    #region IdentityServer SAML
    authentication.AddSaml2(
        issuerThumbprint: "F89C10B505E015774D02E323DEDA32878F794028",
        issuerName: "https://10.40.40.68/issue/wsfed",
        audienceUri: "http://localhost:41740/",//Constants.Realm,
        certificateValidator: System.IdentityModel.Selectors.X509CertificateValidator.None,
        options: AuthenticationOptions.ForAuthorizationHeader("SAML"),
        scheme: AuthenticationScheme.SchemeOnly("SAML"));
    #endregion

    #region Client Certificates
    authentication.AddClientCertificate(ClientCertificateMode.ChainValidation);
    #endregion

    return authentication;
}

However I still get a 302 response. This is how I make the request:

ServicePointManager.ServerCertificateValidationCallback += (sender, certificate, chain, sslPolicyErrors) => true;


var factory = new WSTrustChannelFactory(
    new UserNameWSTrustBinding(SecurityMode.TransportWithMessageCredential),
    "https://10.40.40.68/issue/wstrust/mixed/username");
factory.TrustVersion = TrustVersion.WSTrust13;

factory.Credentials.UserName.UserName = "myusername";
factory.Credentials.UserName.Password = "password";

var rst = new RequestSecurityToken
{
    RequestType = RequestTypes.Issue,
    KeyType = KeyTypes.Bearer,
    TokenType = Thinktecture.IdentityModel.Constants.TokenTypes.Saml2TokenProfile11,
    AppliesTo = new EndpointReference("http://localhost:41740/")
};

var token = factory.CreateChannel().Issue(rst) as System.IdentityModel.Tokens.GenericXmlSecurityToken;

string myToken = token.TokenXml.OuterXml;

HttpClient client = new HttpClient(new HttpClientHandler
{
    ClientCertificateOptions = ClientCertificateOption.Automatic,
    AllowAutoRedirect = false
});

client.SetToken("SAML", myToken);
//client.SetBearerToken(myToken);

var resp = client.GetAsync("http://localhost:41740/api/clients", HttpCompletionOption.ResponseContentRead).Result;
Assert.IsTrue(resp.IsSuccessStatusCode);

解决方案

Web API v1 doesn't have plumbing to automatically look for tokens in the request. This missing feature was provided by Thinktecture IdentityModel in its Web API authentication message handler. Check the sample folder for an example (specifically for the AuthenticationConfiguration class and the AddSaml2 API):

https://github.com/thinktecture/Thinktecture.IdentityModel.45/tree/master/Samples/Web%20API%20Security

这篇关于如何验证来自一个C#应用程序到WIF的请求允许使用SAML断言ASP.NET的WebAPI应用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆