Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
602 views
in Technique[技术] by (71.8m points)

asp.net core - AuthenticateResult.Succeeded is false with Okta and Sustainsys.SAML2

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: enter image description here

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?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...