Okta 和 Sustainsys.SAML2 的 AuthenticateResult.Succeeded 为假 [英] AuthenticateResult.Succeeded is false with Okta and Sustainsys.SAML2

查看:24
本文介绍了Okta 和 Sustainsys.SAML2 的 AuthenticateResult.Succeeded 为假的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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

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

public void ConfigureServices(IServiceCollection services){//[剪辑]如果(使用 SAML){services.Configure(options =>{//需要 SameSiteMode.None 才能支持 SAML SSO.options.MinimumSameSitePolicy = SameSiteMode.None;options.CheckConsentNeeded = 上下文 =>错误的;//一些较旧的浏览器不支持 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 =>{//参见 https://stackoverflow.com/questions/46243697/asp-net-core-persistent-authentication-custom-cookie-authenticationoptions.ExpireTimeSpan = new System.TimeSpan(365, 0, 0, 0, 0);options.AccessDeniedPath = new PathString("/login");options.LoginPath = new PathString("/login");}).AddCookie(ApplicationSamlConstants.Application).AddCookie(ApplicationSamlConstants.External).AddSaml2(选项=>{options.SPOptions.EntityId = new EntityId(this.Configuration[Saml:SPEntityId"]);options.IdentityProviders.Add(新身份提供者(新 EntityId(this.Configuration["Saml:IDPEntityId"]), options.SPOptions){MetadataLocation = this.Configuration[Saml:IDPMetaDataBaseUrl"],加载元数据 = 真,});options.SPOptions.ServiceCertificates.Add(new X509Certificate2(this.Configuration[Saml:CertificateFileName"]));});}//[剪辑]}

更新:我修改了代码以捕获更多日志信息,我发现在 Saml2/Acs 端点,用户正在接受身份验证.在日志文件中,我看到:

2020-09-14 09:28:09.307 -05:00 [DBG] 签名验证通过了 Saml 响应 Microsoft.IdentityModel.Tokens.Saml2.Saml2Id2020-09-14 09:28:09.369 -05:00 [DBG] 提取的 SAML 断言 id16228944165055934699991422020-09-14 09:28:09.385 -05:00 [INF] 成功处理 SAML 响应 Microsoft.IdentityModel.Tokens.Saml2.Saml2Id 和经过身份验证的 bankoetest@sfi.cloud

但是,当我到达 SamlLoginCallback 方法时,此身份验证信息并未出现在此调用获得的 AuthenticateResult 中:

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

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

2020-09-14 09:28:09.432 -05:00 [ERR] SAML 认证失败:authenticateResult.Failure(异常对象)为空;没有返回身份验证方案的信息;authenticationResult.Principal 为空;authenticationResult.Properties 为空.authenticationResult.Ticket 为空.

可能出了什么问题?

解决方案

这里的根本原因最终是 Okta 使用的 Url 与我们在重定向逻辑中的代码的情况不同的结果.URL 匹配,但大小写不匹配.这导致 cookie 无法被稍后调用的方法读取,这些方法被发送到不同的 URL,即使区别仅在于路径的大小写.一旦我们确保所有路径精确匹配,直到外壳,它就开始工作了.

I have a .Net Core 2 application which leverages Sustainsys.Saml2.AspNetCor2 (2.7.0). The front end is an Angular application. The SAML approach I'm taking is based on, and very similar to, the approach taken in this reference implementation: https://github.com/hmacat/Saml2WebAPIAndAngularSpaExample

*Everything works fine with the test IDP (https://stubidp.sustainsys.com).

But when we try to integrate with Okta, the AuthenticateResult.Succeeded property in the callback method (see below) is always false, even though the SAML posted to the ASC endpoint appears to indicate a successful authentication. We are not seeing any errors at all. It's just not succeeding.

(Note that my company does not have access to Okta - that is maintained by a partner company.)

Here is the server code in the controller:

[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
  
   }

Here is a screenshot of some of the SAML sent by Okta, captured using the Chrome extension, SAML-tracer:

I don't know how to investigate this further. Any help would be most appreciated!

In the ConfigureServices method, in case it's useful, I have the following (in relevant part):

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, 0, 0, 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]
}

UPDATE: I modified the code to capture more logging information, and what I have found is that, at the Saml2/Acs endpoint, the user is being authenticated. In the log files, I see this:

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 bankoetest@sfi.cloud

However, when I get to the SamlLoginCallback method, this authentication information is not present in the AuthenticateResult obtained by this call:

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

My custom logging information for the authentication result object looks like this:

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

What could be going wrong?

解决方案

The root cause here was ultimately the result of differences in the case of the Url used by Okta vs our code in redirect logic. The URLs matched, but the case did not. This caused cookies to be unreadable by later-invoked methods which were being sent to a URL which was different, even though the difference was only in the casing of the path. Once we made sure that all paths matched exactly, down to the casing, it started working.

这篇关于Okta 和 Sustainsys.SAML2 的 AuthenticateResult.Succeeded 为假的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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