Search code examples
asp.net-coresustainsys-saml2

Sustainsys.Saml2.AspNetCore2 - User, claims are null after coming back from IdP


I am attempting to hook up Sustainsys.Saml2 in a new .NET Core project, but having some issues with the User/claims being null after the ACS call completes.

Going to list out the packages I'm using, just for background, .NET 6.0 with:

package list

After reviewing the Sample and Source from the github, the relevant code in my Program.cs file is:

builder.Services.AddIdentity<ApplicationUser, IdentityRole>()
    .AddEntityFrameworkStores<{...context...}>()
    .AddDefaultTokenProviders();

builder.Services.AddAuthentication(opt =>
{
    // Default scheme that maintains session is cookies.
    opt.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;

    // If there's a challenge to sign in, use the Saml2 scheme.
    opt.DefaultChallengeScheme = Saml2Defaults.Scheme;
})
.AddCookie()
.AddSaml2(opt =>
{
    // Us; the Service Provider
    opt.SPOptions.EntityId = new EntityId("https://localhost:34287/Saml2");

    // Single logout messages should be signed according to the SAML2 standard, so we need
    // to add a certificate for our app to sign logout messages with to enable logout functionality.
    opt.SPOptions.ServiceCertificates.Add(new X509Certificate2("Sustainsys.Saml2.Tests.pfx"));

    // Them; the Identify Provider
    opt.IdentityProviders.Add(

        // Fake IdP for testing
        new IdentityProvider(new EntityId("https://stubidp.sustainsys.com/Metadata"), opt.SPOptions)
        {
            LoadMetadata = true
        });
});

Lastly, my AccountController is below:

public AccountController(IConfiguration configuration, SignInManager<ApplicationUser> signInManager, ILogger<AccountController> logger)
{
    _configuration = configuration;
    _signInManager = signInManager;
    _logger = logger;
}

[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Login()
{
    // Automatic handling is to redirect back to same page after successful
    // login. We don't want that on explicit login.
    var props = new AuthenticationProperties
    {
        RedirectUri = "/"
    };

    return Challenge(props, Saml2Defaults.Scheme);
}

When I hit the login button, Saml2 is logging the following:

info: Sustainsys.Saml2.AspNetCore2.Saml2Handler[0]
      Initiating login to https://stubidp.sustainsys.com/Metadata
info: Sustainsys.Saml2.AspNetCore2.Saml2Handler[0]
      Successfully processed SAML response id84814e90fa344d05876556797416dc41 and authenticated AdminAlmighty

so it seems as though it's working, without errors, but my User.Identity doesn't get populated at all, and the user IsAuthenticated property doesn't get set either.

I just am not really sure what I might be doing wrong or misunderstanding. The goal is to make my application act as the SP for a single external IdP.


Solution

  • The problem is caused by scheme mis-match.

    Asp.Net Identity has their own names for the schemes (and for the actual cookies).

    When using Asp.Net Identity you have to use those scheme names and not the default scheme names. What happens here is that the sign in manager signs in using Asp.Net Identity cookie scheme name, while the authentication mechanism is set up to use the default cookie scheme name to establish the session.

    If your application should be an SP of a single Idp there is no need for Asp.Net Identity, I would suggest dropping it. Asp.Net Identity is useful when you own the account database and need to handle multiple upstream identity providers as well as do identity/claims translations/mappings.