We are upgrading our existing Identity Server solution form ID4 to Duende Identity Server with .net 6.0
We also use RSK's SAML plugin for Duende Identity Server.
Right now I'm trying to create our own SAML Identity Provider store, instead of the In memory store provided.
The issue I'm facing is the SAML 2p Authentication Handler is throwing a null reference exception when calling the "HandleChallengeAsync(AuthenticationProperties properties)" method. But it doesn't tell me what the null reference is in relation to.
While stepping through the code using the InMemory implementation everything works. I'm attaching the code to create the SamlDynamicIdentityProvider as well as the exception.
Saml IdP Store
public class SamlIdPStore : SamlDynamicIdentityProvider, IIdentityProviderStore
{
private readonly ILogger _logger;
private readonly IEnumerable<IdentityProvider> _providers;
/*
public SamlIdPStore(ILogger logger)
{
_logger = logger;
}
*/
public SamlIdPStore(IEnumerable<IdentityProvider> providers, ILogger logger)
{
_logger = logger;
_providers = providers;
}
public async Task<IEnumerable<IdentityProviderName>> GetAllSchemeNamesAsync()
{
var samlIdPConfigs = await SamlIdPConfigurationManagerFactory.GetAllSamlIdPConfigs();
var identityProviderNames = new List<IdentityProviderName>();
foreach (var samlIdPConfig in samlIdPConfigs)
{
var identityProviderName = new IdentityProviderName()
{
DisplayName = samlIdPConfig.DisplayName,
Enabled = true,
Scheme = samlIdPConfig.AuthenticationScheme
};
identityProviderNames.Add(identityProviderName);
}
return identityProviderNames;
}
public async Task<IdentityProvider> GetBySchemeAsync(string scheme)
{
var samlIdentityProvider = await SamlIdPConfigurationManagerFactory.GetSamlIdPConfig(scheme);
var identityProvider = new IdentityProvider("saml2p")
{
Scheme = scheme,
DisplayName = samlIdentityProvider.DisplayName,
Enabled = true
};
var samlDynamicProvider = Saml2p.CreateDynamicProviderFromConfig(samlIdentityProvider, _logger);
identityProvider.Properties = samlDynamicProvider.Properties;
return identityProvider;
}
}
The exception We're getting is -
System.NullReferenceException: Object reference not set to an instance of an object.
at Rsk.AspNetCore.Authentication.Saml2p.Saml2pAuthenticationHandler.HandleChallengeAsync(AuthenticationProperties properties)
at Microsoft.AspNetCore.Authentication.AuthenticationHandler`1.ChallengeAsync(AuthenticationProperties properties)
at Microsoft.AspNetCore.Authentication.AuthenticationService.ChallengeAsync(HttpContext context, String scheme, AuthenticationProperties properties)
at Microsoft.AspNetCore.Mvc.ChallengeResult.ExecuteResultAsync(ActionContext context)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeResultAsync>g__Logged|22_0(ResourceInvoker invoker, IActionResult result)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResultFilterAsync>g__Awaited|30_0[TFilter,TFilterAsync](ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResultExecutedContextSealed context)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.ResultNext[TFilter,TFilterAsync](State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeResultFilters()
--- End of stack trace from previous location ---
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResourceFilter>g__Awaited|25_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResourceExecutedContextSealed context)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeFilterPipelineAsync()
--- End of stack trace from previous location ---
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Logged|17_1(ResourceInvoker invoker)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Logged|17_1(ResourceInvoker invoker)
at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
at Rsk.Saml.Hosting.IdentityServerSamlMiddleware.Invoke(HttpContext context, ISamlEndpointRouter router, ISamlEventService eventService, SamlIdpOptions options)
at Duende.IdentityServer.Hosting.IdentityServerMiddleware.Invoke(HttpContext context, IEndpointRouter router, IUserSession session, IEventService events, IIssuerNameService issuerNameService, IBackChannelLogoutService backChannelLogoutService) in /_/src/IdentityServer/Hosting/IdentityServerMiddleware.cs:line 102
at Duende.IdentityServer.Hosting.MutualTlsEndpointMiddleware.Invoke(HttpContext context, IAuthenticationSchemeProvider schemes) in /_/src/IdentityServer/Hosting/MutualTlsEndpointMiddleware.cs:line 94
at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
at Duende.IdentityServer.Hosting.DynamicProviders.DynamicSchemeAuthenticationMiddleware.Invoke(HttpContext context) in /_/src/IdentityServer/Hosting/DynamicProviders/DynamicSchemes/DynamicSchemeAuthenticationMiddleware.cs:line 47
at Duende.IdentityServer.Hosting.BaseUrlMiddleware.Invoke(HttpContext context) in /_/src/IdentityServer/Hosting/BaseUrlMiddleware.cs:line 27
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
In Memory Implementation
public static IIdentityServerBuilder AddSaml2pIdPFromConfiguration(this IIdentityServerBuilder builder,
ISamlIdpConfigurationManager idpConfigManager,
ILogger logger)
{
if (builder == null)
{
throw new ArgumentNullException(nameof(builder));
}
//only create the SAML IDP if we have a valid key in the config file
if (string.IsNullOrWhiteSpace(ConfigSettings.SamlLicenseKey))
{
return builder;
}
try
{
builder.AddSamlDynamicProvider(options =>
{
options.Licensee = ConfigSettings.SamlLicensee;
options.LicenseKey = ConfigSettings.SamlLicenseKey;
});
// add saml2p as defined by each configuration in the saml configuation file
var samlDynamicIdentityProviders = new List<SamlDynamicIdentityProvider>();
foreach (var samlIdpConfig in idpConfigManager.GetIdpConfigurations())
{
var samlDynamicIdentityProvider = CreateDynamicProviderFromConfig(samlIdpConfig,logger);
samlDynamicIdentityProviders.Add(samlDynamicIdentityProvider);
}
builder.AddInMemoryIdentityProviders(samlDynamicIdentityProviders);
//builder.AddIdentityProviderStore<SamlIdPStore>();
}
catch (Exception ex)
{
logger?.LogError(ex, $"Error adding SAML2P idp configuration");
}
return builder;
}
Any help would be greatly appreciated.
Thanks, Gautham