1

我创建了一个 ASP.NET WebAPI 项目,该项目使用基于声明的 WIF 身份验证。我还使用托管在本地 IIS 上的 Thinktecture Identity Server 作为 STS。浏览器一切正常;我被重定向到登录页面,并且可以在Thread.CurrentPrincipal.Identity我的一个 REST API 控制器中看到正确的身份。

我的问题是我无法弄清楚如何让活动客户端进行身份验证。我花了几个小时搜索和阅读,但无法让它发挥作用。这就像我的 WebAPI 甚至从不查看 HTTP 标头。我尝试创建自己的 IHttpModule 来拦截请求,并且可以在标头中看到我的 SAML 令牌。我在客户端中得到的响应是用户在使用浏览器时通常会被重定向到的登录页面。我也尝试了这个问题中提到的所有内容。

我的活跃客户如下所示:

static void Main(string[] args)
{
    string token = GetSamlToken();
    CallService(token);
}

static Uri _baseAddress = new Uri("http://localhost:50565/");
static string _realm = "http://localhost:50565/";

private static string GetSamlToken()
{
    var factory = new WSTrustChannelFactory(
        new UserNameWSTrustBinding(SecurityMode.TransportWithMessageCredential), "https://localhost/idsrv/issue/wstrust/mixed/username");
    factory.TrustVersion = TrustVersion.WSTrust13;

    factory.Credentials.UserName.UserName = "bob";
    factory.Credentials.UserName.Password = "p@assword";

    var rst = new RequestSecurityToken
    {
        RequestType = RequestTypes.Issue,
        KeyType = KeyTypes.Bearer,
        TokenType = TokenTypes.Saml2TokenProfile11,
        AppliesTo = new EndpointReference(_realm) 
    };

    System.Net.ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };

    var token = factory.CreateChannel().Issue(rst) as GenericXmlSecurityToken;
    return token.TokenXml.OuterXml;
}

private static void CallService(string token)
{
    var client = new HttpClient
    {
        BaseAddress = _baseAddress
    };

    client.SetToken("SAML", token); //Constants.IdSrv.SamlScheme

    while (true)
    {
        "Calling service.".ConsoleYellow();

        var response = client.GetAsync("api/values").Result;

        response.EnsureSuccessStatusCode();

        var content = response.Content.ReadAsStringAsync();
        content.Wait();

        Console.WriteLine(content.Result);

        Console.ReadLine();
    }
}

我的 web.config 的相关部分如下所示:

<configuration>
  <configSections>
    <section name="system.identityModel" type="System.IdentityModel.Configuration.SystemIdentityModelSection, System.IdentityModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089" />
    <section name="system.identityModel.services" type="System.IdentityModel.Services.Configuration.SystemIdentityModelServicesSection, System.IdentityModel.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089" />
  </configSections>
  <location path="FederationMetadata">
    <system.web>
      <authorization>
        <allow users="*" />
      </authorization>
    </system.web>
  </location>
  <appSettings>
    <add key="ida:FederationMetadataLocation" value="https://localhost/idsrv/FederationMetadata/2007-06/FederationMetadata.xml" />
    <add key="ida:Issuer" value="https://localhost/idsrv/issue/wsfed" />
    <add key="ida:ProviderSelection" value="productionSTS" />
  </appSettings>
  <system.web>
    <authorization>
      <deny users="?" />
    </authorization>
    <authentication mode="None" />
  </system.web>
  <system.webServer>
    <validation validateIntegratedModeConfiguration="false" />
    <modules runAllManagedModulesForAllRequests="true">
      <remove name="FormsAuthentication" />

      <add name="WSFederationAuthenticationModule" type="System.IdentityModel.Services.WSFederationAuthenticationModule, System.IdentityModel.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" preCondition="managedHandler" />
      <add name="SessionAuthenticationModule" type="System.IdentityModel.Services.SessionAuthenticationModule, System.IdentityModel.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" preCondition="managedHandler" />
    </modules>
    <handlers>
      <remove name="ExtensionlessUrlHandler-ISAPI-4.0_32bit" />
      <remove name="ExtensionlessUrlHandler-ISAPI-4.0_64bit" />
      <remove name="ExtensionlessUrlHandler-Integrated-4.0" />
      <remove name="WebDav" />
      <add name="ExtensionlessUrlHandler-ISAPI-4.0_32bit" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
      <add name="ExtensionlessUrlHandler-ISAPI-4.0_64bit" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
      <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
    </handlers>
  </system.webServer>

  <system.identityModel>
    <identityConfiguration>
      <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>
      <audienceUris>
        <add value="http://localhost:50565/" />
      </audienceUris>
      <certificateValidation certificateValidationMode="None" />
      <claimsAuthorizationManager type="MvcApplication1.Claims.CustomAuthorizationManager, MvcApplication1" />
      <issuerNameRegistry type="System.IdentityModel.Tokens.ValidatingIssuerNameRegistry, System.IdentityModel.Tokens.ValidatingIssuerNameRegistry">
        <authority name="http://identityserver.v2.thinktecture.com/samples">
          <keys>
            <add thumbprint="E590FF943557129F13F0DF618EC8B23B88983110" />
          </keys>
          <validIssuers>
            <add name="http://identityserver.v2.thinktecture.com/samples" />
          </validIssuers>
        </authority>
      </issuerNameRegistry>
    </identityConfiguration>
  </system.identityModel>
  <system.identityModel.services>
    <federationConfiguration>
      <cookieHandler requireSsl="false" />
      <wsFederation passiveRedirectEnabled="true" issuer="https://localhost/idsrv/issue/wsfed" realm="http://localhost:50565/" requireHttps="false" />
    </federationConfiguration>
  </system.identityModel.services>
</configuration>

我还在AuthenticationHandler我的 WebApiConfig.cs 中添加了这样的(基于以及我提到的其他 SO 问题):

var authentication = CreateAuthenticationConfiguration();
config.MessageHandlers.Add(new AuthenticationHandler(authentication));

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

    #region IdentityServer SAML
    authentication.AddSaml2(
        issuerThumbprint: "E590FF943557129F13F0DF618EC8B23B88983110",
        issuerName: "https://localhost/idsrv/issue/wsfed",
        audienceUri: "http://localhost:50565/",
        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;
}

在我看来,WSFederationAuthenticationModule 首先拦截请求,然后在 AuthenticationHandler 有机会查找标头中存在的 SAML 令牌之前重定向到 STS 登录。任何人都可以看到我的配置有什么问题或缺失吗?

4

1 回答 1

1

尝试删除

  <authorization>
      <deny users="?" />
    </authorization>

从您的网络配置的 system.web 部分。我不确定 SAML,但我使用 JWT 相对容易实现这一点,而且我认为对于基于 REST 的客户端来说,这是比 SAML 更好的选择。

于 2014-07-02T18:39:17.630 回答