Currently I am trying to work on .AddOpenIdConnect() but each config would be different for each request based on the parameter/client. I have tried IConfigureNamedOptions but it seems it's only run/compiled during startup
public class ConfigureTenantOpenIdConnectOptions : IConfigureNamedOptions<OpenIdConnectOptions>
{
private const string LoginOnMicrosoft = "login.microsoftonline";
private readonly IHttpContextAccessor _httpContextAccessor;
IDataProtectionProvider _rootProvider;
public ConfigureTenantOpenIdConnectOptions(IHttpContextAccessor httpContextAccessor, IDataProtectionProvider rootProvider)
{
_httpContextAccessor = httpContextAccessor;
_rootProvider = rootProvider;
}
public void Configure(string name, OpenIdConnectOptions options)
{
if(name == "tenant")
{
var context = _httpContextAccessor.HttpContext;
// var tenantId = context.Items["TenantId"]?.ToString();
var selectedIdp = context.Items["SelectedIdp"]?.ToString();
var CurrentTenant = context.Items["CurrentTenant"] as Tenant;
if (selectedIdp == null || CurrentTenant == null)
return;
var currentSSO = MultiTenancyUtil.GetCurrentSSOInfo(CurrentTenant.TenantInfo, selectedIdp);
var authScheme = MultiTenancyUtil.GetAuthenticationScheme(currentSSO);
switch (authScheme)
{
case OpenIdConnectDefaults.AuthenticationScheme:
options = MultiTenancyUtil.CreateOIDCOption(_rootProvider, CurrentTenant, selectedIdp, _httpContextAccessor.HttpContext);
break;
default:
break;
}
}
}
}}
I have also tried but it seems the changes here only applied at the next request. for example I click SSO Microsoft, go back, then click SSO Google, it will redirect to the Microsoft url. Now, I dont want to redirect manually from the controller and do HttpContext.ChallengeAsync because I use multi container
.AddOpenIdConnect(options =>
{
options.Events.OnRedirectToIdentityProvider = async context =>
{
// var tenantId = context.HttpContext.Items[Constants.HTTP_CONTEXT_TENANT]?.ToString();
var tenantContext = context.HttpContext.RequestServices.GetRequiredService<ITenantContext>();
var tenantStore = context.HttpContext.RequestServices.GetRequiredService<ITenantStore>();
var currentTenant = tenantContext.CurrentTenant;
var erroruri = $"{context.HttpContext.Request.Host}/{currentTenant.TenantCode}/Error";
var pProviderName = context.HttpContext.Items["SelectedIdp"]?.ToString();
currentTenant.TenantInfo = await tenantStore.GetTenantInfoAsync(currentTenant.TenantCode);
var ssoInfo = currentTenant.TenantInfo?.SSOs?.FirstOrDefault(c => c.Enabled && c.Name == pProviderName)
?? throw new InvalidOperationException("SSOInfo not found");
var clid = ssoInfo?.ClientID;
var clse = ssoInfo?.ClientSecret;
context.ProtocolMessage.ClientId = clid;
context.ProtocolMessage.ClientSecret = clse;
var configurationManager = new ConfigurationManager<OpenIdConnectConfiguration>
(stsDiscoveryEndpoint, new OpenIdConnectConfigurationRetriever());
options.ConfigurationManager = configurationManager;
options.Authority = ssoInfo.Domain;
await Task.CompletedTask;
};
}
Any info if I can do SSO with dynamic config in 1 request?
Currently I am trying to work on .AddOpenIdConnect() but each config would be different for each request based on the parameter/client. I have tried IConfigureNamedOptions but it seems it's only run/compiled during startup
public class ConfigureTenantOpenIdConnectOptions : IConfigureNamedOptions<OpenIdConnectOptions>
{
private const string LoginOnMicrosoft = "login.microsoftonline.com";
private readonly IHttpContextAccessor _httpContextAccessor;
IDataProtectionProvider _rootProvider;
public ConfigureTenantOpenIdConnectOptions(IHttpContextAccessor httpContextAccessor, IDataProtectionProvider rootProvider)
{
_httpContextAccessor = httpContextAccessor;
_rootProvider = rootProvider;
}
public void Configure(string name, OpenIdConnectOptions options)
{
if(name == "tenant")
{
var context = _httpContextAccessor.HttpContext;
// var tenantId = context.Items["TenantId"]?.ToString();
var selectedIdp = context.Items["SelectedIdp"]?.ToString();
var CurrentTenant = context.Items["CurrentTenant"] as Tenant;
if (selectedIdp == null || CurrentTenant == null)
return;
var currentSSO = MultiTenancyUtil.GetCurrentSSOInfo(CurrentTenant.TenantInfo, selectedIdp);
var authScheme = MultiTenancyUtil.GetAuthenticationScheme(currentSSO);
switch (authScheme)
{
case OpenIdConnectDefaults.AuthenticationScheme:
options = MultiTenancyUtil.CreateOIDCOption(_rootProvider, CurrentTenant, selectedIdp, _httpContextAccessor.HttpContext);
break;
default:
break;
}
}
}
}}
I have also tried but it seems the changes here only applied at the next request. for example I click SSO Microsoft, go back, then click SSO Google, it will redirect to the Microsoft url. Now, I dont want to redirect manually from the controller and do HttpContext.ChallengeAsync because I use multi container
.AddOpenIdConnect(options =>
{
options.Events.OnRedirectToIdentityProvider = async context =>
{
// var tenantId = context.HttpContext.Items[Constants.HTTP_CONTEXT_TENANT]?.ToString();
var tenantContext = context.HttpContext.RequestServices.GetRequiredService<ITenantContext>();
var tenantStore = context.HttpContext.RequestServices.GetRequiredService<ITenantStore>();
var currentTenant = tenantContext.CurrentTenant;
var erroruri = $"{context.HttpContext.Request.Host}/{currentTenant.TenantCode}/Error";
var pProviderName = context.HttpContext.Items["SelectedIdp"]?.ToString();
currentTenant.TenantInfo = await tenantStore.GetTenantInfoAsync(currentTenant.TenantCode);
var ssoInfo = currentTenant.TenantInfo?.SSOs?.FirstOrDefault(c => c.Enabled && c.Name == pProviderName)
?? throw new InvalidOperationException("SSOInfo not found");
var clid = ssoInfo?.ClientID;
var clse = ssoInfo?.ClientSecret;
context.ProtocolMessage.ClientId = clid;
context.ProtocolMessage.ClientSecret = clse;
var configurationManager = new ConfigurationManager<OpenIdConnectConfiguration>
(stsDiscoveryEndpoint, new OpenIdConnectConfigurationRetriever());
options.ConfigurationManager = configurationManager;
options.Authority = ssoInfo.Domain;
await Task.CompletedTask;
};
}
Any info if I can do SSO with dynamic config in 1 request?
I managed to find the answer. When we want to change the Options, it needs to be done before the OpenID Connect middleware processed its initial logic. this can be done like this
services.AddScoped<IOptionsMonitor<OpenIdConnectOptions>, CustomOpenIdConnectOptionsProvider>();
this way the options will be initiated before the UseAuthentication()
public class CustomOpenIdConnectOptionsProvider : IOptionsMonitor<OpenIdConnectOptions>
{
public OpenIdConnectOptions Get(string name)
{
var startupOption = _options.Get(name);
var newOption = GetOptions();
if (newOption == null)
return startupOption;
return newOption;
}
private OpenIdConnectOptions GetOptions()
{
var context = _httpContextAccessor.HttpContext;
var selectedIdp = context.Request.Query["provider"].ToString();
var currentTenant = _tenantContext.CurrentTenant;
currentTenant.TenantInfo = _tenantStore.GetTenantInfoAsync(currentTenant.TenantCode).GetAwaiter().GetResult();
if (string.IsNullOrEmpty(selectedIdp) || currentTenant == null)
return null;
var currentSSO = MultiTenancyUtil.GetCurrentSSOInfo(currentTenant.TenantInfo, selectedIdp);
var authScheme = MultiTenancyUtil.GetAuthenticationScheme(currentSSO);
if (authScheme != OpenIdConnectDefaults.AuthenticationScheme)
return null;
var _oidc = MultiTenancyUtil.CreateOIDCOption(_rootProvider, currentTenant, selectedIdp, _httpContextAccessor);
return _oidc;
}
}