Okta和Sustainsys.SAML2的AuthenticateResult.Succeeded为假

问题描述

我有一个利用Sustainsys.Saml2.AspNetCor2(2.7.0)的.Net Core 2应用程序。前端是Angular应用程序。我采用的SAML方法基于并非常类似于此参考实现中采用的方法https://github.com/hmacat/Saml2WebAPIAndAngularSpaExample

*测试IDP(https://stubidp.sustainsys.com)一切正常。

但是,当我们尝试与Okta集成时,即使发布到ASC端点的SAML似乎表明身份验证成功,回调方法(请参见下文)中的AuthenticateResult.Succeeded属性始终为false。我们根本没有看到任何错误。只是没有成功。

(请注意,我的公司无权访问Okta-由合作伙伴公司维护。)

这是控制器中的服务器代码

[AllowAnonymous]
    [HttpPost,HttpGet]
    [Route("api/Security/InitiateSamlSingleSignOn")]
    public IActionResult InitiateSamlSingleSignOn(string returnUrl)
    {
      return new ChallengeResult(
          Saml2Defaults.Scheme,new AuthenticationProperties
          {
            RedirectUri = Url.Action(nameof(SamlLoginCallback),new { returnUrl })
          });
    }

    [AllowAnonymous]
    [HttpPost,HttpGet]
    [Route("api/Security/SamlLoginCallback")]
    public async Task<IActionResult> SamlLoginCallback(string returnUrl)
    {
      var authenticateResult = await HttpContext.AuthenticateAsync(ApplicationSamlConstants.External);

      if (!authenticateResult.Succeeded)
      {
        return Unauthorized();
      }
  
     // more code below,never reached
  
   }

以下是Okta发送的一些SAML的屏幕截图,是使用Chrome扩展程序SAML-tracer捕获的:

enter image description here

我不知道如何进一步调查。 任何帮助将不胜感激!

在ConfigureServices方法中,如果有用,我(在相关部分)有以下内容

public void ConfigureServices(IServiceCollection services)
{
  // [snip]
  if (usingSAML)
  {
    services.Configure<CookiePolicyOptions>(options =>
    {
      // SameSiteMode.None is required to support SAML SSO.
      options.MinimumSameSitePolicy = SameSiteMode.None;

      options.CheckConsentNeeded = context => false;

      // Some older browsers don't support SameSiteMode.None.
      options.OnAppendCookie = cookieContext => SameSite.CheckSameSite(cookieContext.Context,cookieContext.CookieOptions);
      options.OnDeleteCookie = cookieContext => SameSite.CheckSameSite(cookieContext.Context,cookieContext.CookieOptions);
    });
    
    authBuilder = services.AddAuthentication(o =>
    {
      o.DefaultScheme = ApplicationSamlConstants.Application;
      o.DefaultSignInScheme = ApplicationSamlConstants.External;
      o.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
      o.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    });

    authBuilder.AddCookie(CookieAuthenticationDefaults.AuthenticationScheme,options =>
    {
      // see https://stackoverflow.com/questions/46243697/asp-net-core-persistent-authentication-custom-cookie-authentication
      options.ExpireTimeSpan = new System.TimeSpan(365,0);
      options.AccessDeniedpath = new PathString("/login");
      options.LoginPath = new PathString("/login");
    })
    .AddCookie(ApplicationSamlConstants.Application)
    .AddCookie(ApplicationSamlConstants.External)
    .AddSaml2(options =>
    {
      options.SPOptions.EntityId = new EntityId(this.Configuration["Saml:SPEntityId"]);
      options.IdentityProviders.Add(
          new IdentityProvider(
              new EntityId(this.Configuration["Saml:IDPEntityId"]),options.SPOptions)
          {
            MetadataLocation = this.Configuration["Saml:IDPMetaDataBaseUrl"],LoadMetadata = true,});
      options.SPOptions.ServiceCertificates.Add(new X509Certificate2(this.Configuration["Saml:CertificateFileName"]));
    });
  }
 // [snip]
}

更新:我修改代码以捕获更多的日志记录信息,并且发现在Saml2 / Acs端点上,正在对用户进行身份验证。 在日志文件中,我看到以下内容

2020-09-14 09:28:09.307 -05:00 [DBG] Signature validation passed for Saml Response Microsoft.IdentityModel.Tokens.Saml2.Saml2Id
2020-09-14 09:28:09.369 -05:00 [DBG] Extracted SAML assertion id1622894416505593469999142
2020-09-14 09:28:09.385 -05:00 [INF] Successfully processed SAML response Microsoft.IdentityModel.Tokens.Saml2.Saml2Id and authenticated [email protected]

但是,当我进入SamlLoginCallback方法时,此调用获得的AuthenticateResult中不存在此身份验证信息:

 var authenticateResult = await HttpContext.AuthenticateAsync(ApplicationSamlConstants.External);

我对身份验证结果对象的自定义日志记录信息如下:

2020-09-14 09:28:09.432 -05:00 [ERR] SAML Authentication Failure: authenticateResult.Failure (Exception object) is null; 
No @R_1_4045@ion was returned for the authentication scheme; 
authenticateResult.Principal is null; 
authenticateResult.Properties is null.
authenticateResult.Ticket is null.

出什么问题了?

解决方法

这里的根本原因最终是Okta使用的Url与我们的重定向逻辑中的代码存在差异的结果。 URL匹配,但大小写不匹配。这会导致Cookie无法被后来调用的方法读取,这些方法被发送到另一个URL,即使该区别只是路径的大小写不同。一旦确保所有路径完全匹配(一直到套管),它便开始工作。