Reputation: 4970
Problem
I'm trying to implement login and logout using an external IdP in a .NET 8 application with Sustainsys.Saml2.AspNetCore2
(Version=2.10.0)
.
/Saml2/Logout
./Saml2/Logout
returns 404
, and even though I created an action method on this endpoint, the request seems to be intercepted by the authentication middleware.Configuration in Startup.cs
var saml2Options = Configuration.GetSection("Authentication:Saml2").Get<Saml2Settings>();
services.AddAuthentication(options =>
{
options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = Saml2Defaults.Scheme;
})
.AddCookie(CookieAuthenticationDefaults.AuthenticationScheme)
.AddSaml2(options =>
{
options.SPOptions.EntityId = new EntityId(saml2Options.EntityId);
LoadCertificate(options, saml2Options.Certificate);
options.IdentityProviders.Add(new IdentityProvider(
new EntityId(saml2Options.IdentityProvider.EntityId),
options.SPOptions)
{
MetadataLocation = saml2Options.IdentityProvider.MetadataLocation,
LoadMetadata = true
});
});
Logout Action Method This method initiates federated logout by sending a SAML LogoutRequest.
[HttpPost]
public IActionResult ExecuteLogout()
{
var props = new AuthenticationProperties
{
RedirectUri = "/"
};
var user = HttpContext.User;
var sessionIndex = user.FindFirst(Saml2ClaimTypes.SessionIndex)?.Value;
if (!string.IsNullOrEmpty(sessionIndex))
{
props.Items.Add(Saml2ClaimTypes.SessionIndex, sessionIndex);
}
var logoutNameIdentifier = user.FindFirst(Saml2ClaimTypes.LogoutNameIdentifier)?.Value;
if (!string.IsNullOrEmpty(logoutNameIdentifier))
{
props.Items.Add(Saml2ClaimTypes.LogoutNameIdentifier, logoutNameIdentifier);
}
return SignOut(props, Saml2Defaults.Scheme);
}
Attempted Fix: Creating an Action for /Saml2/Logout
Even though I created an explicit controller method for handling /Saml2/Logout, it never gets called
.
[AllowAnonymous]
[Route("Saml2")]
public class LoggedOutController : Controller
{
private readonly ILogger<LoggedOutController> logger;
private readonly Saml2Settings samlSettings;
public LoggedOutController(ILogger<LoggedOutController> logger, IOptions<Saml2Settings> samlSettingsOptions)
{
this.logger = logger;
this.samlSettings = samlSettingsOptions.Value;
}
[AllowAnonymous]
[HttpGet("Logout")]
public IActionResult Logout([FromQuery] string SAMLResponse)
{
logger.LogInformation($"User logged out. Saml response: {SAMLResponse}");
return View("Logout");
}
}
Any advice would be greatly appreciated!
Update: here is how the certificate is loaded
private static void LoadCertificate(Saml2Options options, CertificateSettings certSettings)
{
var store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
try
{
store.Open(OpenFlags.ReadOnly);
var certificates = store.Certificates.Find(
X509FindType.FindBySubjectName, certSettings.SubjectName, false);
if (certificates.Count > 0)
{
options.SPOptions.ServiceCertificates.Add(certificates[0]);
}
else
{
throw new InvalidOperationException("Required certificate not found.");
}
}
finally
{
store.Close();
}
}
Upvotes: 0
Views: 41