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

Categories

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

asp.net core - IdP Initiated Login with Sustainsys.SAML2 - AuthenticateResult Has No Information

This ticket continues the saga started here: AuthenticateResult.Succeeded is false with Okta and Sustainsys.SAML2. Please see that ticket for basic setup information.

All is working fine now, for SP-Initiated login. But the same issue is happening for IdP-initiated login.

Here is the text of a log file - the initial entries are from the Sustainsys code, and the last one ("SAML Authentication Failure") is from custom code I wrote to debug the issue in the callback method:

2020-09-15 16:01:40.574 -05:00 [DBG] Received unsolicited Saml Response Microsoft.IdentityModel.Tokens.Saml2.Saml2Id which is allowed for idp http://www.okta.com/exk1jic9zn7QommF00h8
2020-09-15 16:01:40.590 -05:00 [DBG] Signature validation passed for Saml Response Microsoft.IdentityModel.Tokens.Saml2.Saml2Id
2020-09-15 16:01:40.652 -05:00 [DBG] Extracted SAML assertion id16338952065129118260692652
2020-09-15 16:01:40.652 -05:00 [INF] Successfully processed SAML response Microsoft.IdentityModel.Tokens.Saml2.Saml2Id and authenticated [email protected]
2020-09-15 16:01:41.433 -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.

The logging above is from an Okta IdP, but I also get the same exact result when I configure the application to use the test IdP (i.e., https://stubidp.sustainsys.com/).

Note, however, that it works fine in my Visual Studio 2019 development environment, and also works fine when deployed to a local IIS instance on my desktop.

The problem only arises when the same code is deployed to a production VM. This makes me suspect that it is something particular to the VM environment (as the last issue was), but I am at a loss on how to investigate further.

Any help would be most appreciated. Thanks!

Update: Here is the updated code from the Startup, if useful:

var usingSAML = Configuration.GetValue<bool>("Authentication:UseSAML");
      var usingJWT = Configuration.GetValue<bool>("Authentication:UseJWT");
      AuthenticationBuilder authBuilder = null;

      if (usingSAML)
      {
        // added to address bug with Okta integration 
        // see https://www.developreference.com/article/10349604/Sustainsys+SAML2+Sample+for+ASP.NET+Core+WebAPI+without+Identity
        // and https://stackoverflow.com/questions/63853661/authenticateresult-succeeded-is-false-with-okta-and-sustainsys-saml2/63890322#63890322
        services.AddDataProtection()
          .PersistKeysToFileSystem(new DirectoryInfo("Logs"));

        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"]);
          var allowIdpInitiated = Configuration.GetValue<bool>("Saml:AllowIdPInitiated"); 
          if (allowIdpInitiated)
          {
            var siteRoot = this.Configuration["Saml:SiteRoot"];
            var siteRootEncoded = WebUtility.UrlEncode(siteRoot);           
            var returnUrl = string.Format("{0}/api/Security/SamlLoginCallback?returnUrl={1}", siteRoot, siteRootEncoded);
            options.SPOptions.ReturnUrl = new System.Uri(returnUrl);
          }   
          options.IdentityProviders.Add(
              new IdentityProvider(
                  new EntityId(this.Configuration["Saml:IDPEntityId"]), options.SPOptions)
              {
                MetadataLocation = this.Configuration["Saml:IDPMetaDataBaseUrl"],
                LoadMetadata = true,
                AllowUnsolicitedAuthnResponse = allowIdpInitiated
              });
          options.SPOptions.ServiceCertificates.Add(new X509Certificate2(this.Configuration["Saml:CertificateFileName"]));
        });
      }

Update: I found that, using the test IdP (https://stubidp.sustainsys.com/), changing the case of the Assertion Consumer Service Url to match the case used in the audience field changes the behavior. When this happens, instead of getting the null values in the AuthenticateResult, I am redirected back to the IdP as if I were doing a SP-initiated login. Still not the desired behavior, of course.

Note, however, that case makes no difference at all on my local PC (Windows 10 professional). It only behaves differently on the server.)

See Question&Answers more detail:os

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

1 Answer

0 votes
by (71.8m points)

This root cause here was ultimately caused by differences in the case of the Url to which Okta initially posted and the case of the URL used in some redirections. 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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to WuJiGu Developer Q&A Community for programmer and developer-Open, Learning and Share
...