【问题标题】:Pingfederate opentoken module CORS request returns 302 instead of 200Pingfederate opentoken 模块 CORS 请求返回 302 而不是 200
【发布时间】:2016-08-08 01:58:18
【问题描述】:

我们正在使用 Ping Federate 保护两个 Web 服务器(IIS 和都使用 IIS 集成工具包或 Ping 的 opentoken 模块进行保护)。一台服务器托管 WEB API 应用程序,另一台服务器托管网页。 Web API 应用程序已启用 CORS。

网页向 API 服务器发出带有 json 数据的 Ajax 发布请求。这会导致浏览器启动预检选项请求。在 API 服务器上,Ping 模块拦截这个不包含凭据的请求(规范说预检选项请求不应该包含凭据)并在 Web API 代码可以处理它之前返回 302 重定向,而它应该返回 200 .

我目前唯一的猜测是制作一个处理选项请求的自定义模块并将其安装在 opentoken 模块之前。还有其他可能/更好的解决方案吗?

【问题讨论】:

    标签: javascript cors iis-7.5 pingfederate preflight


    【解决方案1】:

    我没有等待 PING,而是在他们的 .NET 集成工具包/代理上放置了一个 IAuthorizationFilter。像这样的自定义过滤器的好处是您可以更好地控制 API 端点的安全要求。

    在编写过滤器时,我使用了以下参考:

    • http://www.asp.net/web-api/overview/security/authentication-filters
    • https://msdn.microsoft.com/en-us/magazine/dn781361.aspx

      使用开放令牌; 使用 PF.SAML.Result; 使用系统; 使用 System.Collections.Generic; 使用 System.Configuration; 使用 System.Linq; 使用 System.Net.Http; 使用 System.Net.Http.Headers; 使用 System.Security.Claims; 使用 System.Text; 使用 System.Threading; 使用 System.Threading.Tasks; 使用 System.Web.Http.Filters;

      命名空间 PF.SAML.Filters { 公共类 PingAuthenticationAttribute : IAuthenticationFilter { 公共布尔 AllowMultiple { 获取 { 返回 false; } }

          // http://www.asp.net/web-api/overview/security/authentication-filters
          // https://msdn.microsoft.com/en-us/magazine/dn781361.aspx
          public async Task AuthenticateAsync( HttpAuthenticationContext context, CancellationToken cancellationToken )
          {
              await Task.Run( () => {
                  /*
                   * Look for credentials in the request.
                   * If there are no credentials, do nothing and return (no-op).
                   * If there are credentials but the filter does not recognize the authentication scheme, do nothing and return (no-op). Another filter in the pipeline might understand the scheme.
                   * If there are credentials that the filter understands, try to authenticate them.
                   * If the credentials are bad, return 401 by setting context.ErrorResult.
                   * If the credentials are valid, create an IPrincipal and set context.Principal.
                   */
                  var opentoken = context.Request.Headers.GetCookies()
                      .SelectMany( c => c.Cookies )
                      .Where( c => c.Name == "opentoken" )
                      .FirstOrDefault();
      
                  if( opentoken == null ) return;
      
                  var userInfo = getOpenToken( opentoken.Value );
      
                  if( userInfo == null ) {
                      context.ErrorResult = new AuthenticationFailureResult( "Invalid Token", context.Request );
                      return;
                  }
      
                  var claims = new List<Claim>();
                  foreach( var item in userInfo ) {
                      foreach( var value in userInfo[item.Key] ) {
                          claims.Add( new Claim( item.Key, value ) );
                      }
                  }
      
                  var id = new ClaimsIdentity( claims, "opentoken" );
                  var principle = new ClaimsPrincipal( new[] { id } );
      
                  context.Principal = principle;
      
              } );
          }
      
          public async Task ChallengeAsync( HttpAuthenticationChallengeContext context, CancellationToken cancellationToken )
          {
              await Task.Run( () => {
                  var challenge = new AuthenticationHeaderValue( "SAML" );
                  context.Result = new AddChallengeOnUnauthorizedResult( challenge, context.Result );
              } );
          }
      
      
          private MultiStringDictionary getOpenToken( string token )
          {
              MultiStringDictionary attributes = null;
      
              Configuration.Agent agentConfig = (Configuration.Agent) ConfigurationManager.GetSection( "pfConfigurationGroup/agentConfiguration" ); 
              AgentConfiguration config = new AgentConfiguration
              {
                  CookieDomain = agentConfig.CookieDomain,
                  CookiePath = agentConfig.CookiePath,
                  NotBeforeTolerance = agentConfig.NotBeforeTolerance,
                  ObfuscatePassword = agentConfig.ObfuscatePassword,
                  RenewUntilLifetime = agentConfig.RenewUntilLifetime,
                  SecureCookie = agentConfig.SecureCookie,
                  SessionCookie = agentConfig.SessionCookie,
                  TokenLifetime = agentConfig.TokenLifetime,
                  TokenName = agentConfig.TokenName,
                  UseCookie = agentConfig.UseCookie,
                  UseSunJCE = agentConfig.UseSunJCE,
                  UseVerboseErrorMessages = agentConfig.UseVerboseErrorMessages
              };
      
              var str = ( config.ObfuscatePassword
                  ? Encoding.UTF8.GetString( Obfuscator.Deobfuscate( agentConfig.Password ) )
                  : Encoding.ASCII.GetString( Convert.FromBase64String( agentConfig.Password ) ) );
              config.SetPassword( str, Token.CipherSuite.AES_128_CBC );
      
              // TODO: Check for token expiration
      
              Agent agent = new Agent( config );
              attributes = agent.ReadTokenMultiStringDictionary( token );
      
              return attributes;
          }
      }
      

      }

    【讨论】:

    • 我最终合并了我的服务器来解决这个问题。如果 PING 没有提供解决方案,这似乎是最好的方法,所以我会将其标记为答案,但如果 PING 提供有用的信息,可能会更改它。
    • 我建议您放置一个您创建的过滤器示例(如果可能)或更通用的过滤器示例。 StackOverflow 对链接答案不屑一顾(链接可能会消失,更难找到信息等)。 - 一个例子得到了赞成!
    【解决方案2】:

    这是 PING Federate IIS 代理/集成工具包实现的错误吗?

    我同意 OP。当前的 W3C 建议 (https://www.w3.org/TR/cors/#preflight-request) 明确表示在预检/OPTIONS 请求中排除用户凭据。因此,一个 OPTIONS 请求应该允许匿名请求。让 302 指向身份提供者 (IdP) 告诉我它没有遵循建议。


    (这只对 PING 服务器本身有帮助,集成工具包仍然需要允许匿名 OPTIONS 请求。) Ping Federate 在码头配置文件中返回了更多配置设置:

    <security-constraint>
        <web-resource-collection>
          <web-resource-name>Disable TRACE OPTIONS HEAD</web-resource-name>
          <url-pattern>/*</url-pattern>
          <http-method>TRACE</http-method>
          <http-method>OPTIONS</http-method> 
        </web-resource-collection>
        <auth-constraint/>
    </security-constraint> 
    

    【讨论】:

    • 我认为这可能是错误。我正在等待 PING 的回复,看看他们是否有关于此问题的更多信息。
    猜你喜欢
    • 1970-01-01
    • 2011-03-25
    • 1970-01-01
    • 2020-07-30
    • 2018-05-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-09
    相关资源
    最近更新 更多