How to change OAuth provider configs after ASP.NET Core app startup

Viewed 146

On startup of my ASP.NET Core web app (which uses IdentityServer 4), in the ConfigureServices method I register external identity providers that I want to enable SSO for via OAuth2 and OIDC.

services
    .AddAuthentication(options =>
    {
        options.DefaultAuthenticateScheme = authenticationScheme;
        options.DefaultScheme = authenticationScheme;
    })
    .AddOAuthSsoIdentityProviders(ssoIdentityProviders);

internal static AuthenticationBuilder AddOAuthSsoIdentityProviders(this AuthenticationBuilder authenticationBuilder, List<IdentityProvider> ssoIdentityProviders)
{
    var oAuthSsoIdentityProviders = ssoIdentityProviders
        .Where(idp => idp.SsoFlowType == SsoFlowType.Oidc || idp.SsoFlowType == SsoFlowType.OAuth2)
        .ToList();
    foreach (var ssoIdentityProvider in oAuthSsoIdentityProviders)
    {
        switch (ssoIdentityProvider.SsoFlowType)
        {
            case SsoFlowType.Oidc:
                authenticationBuilder.AddOpenIdConnect(ssoIdentityProvider.SsoCode, options => SetOidcOptions(ssoIdentityProvider, options));
                break;
            case SsoFlowType.OAuth2:
                authenticationBuilder.AddOAuth(ssoIdentityProvider.SsoCode, options => SetOAuth2Options(ssoIdentityProvider, options));
                break;
        }
    }
    return authenticationBuilder;
}

This works great, however our site admins need the ability to update the configurations of these external identity providers. For example, they may want to add a new partner or change the authentication request url of an existing one. Currently we have to recycle our ASP.NET Core website's app pool to have it re-run the startup code and update the settings. This obviously isn't a good solution, so I'm wondering how we can add or modify these configurations after startup?

1 Answers

I was able to figure it out...

In Startup.cs, register the relevant services for DI:

services
    .AddSingleton<OpenIdConnectPostConfigureOptions>()
    .AddSingleton<OAuthPostConfigureOptions<OAuthOptions, OAuthHandler<OAuthOptions>>>();

In SsoController.cs I then have an endpoint for refreshing the config of a given identity provider:

private readonly OpenIdConnectPostConfigureOptions _oidcPostConfigureOptions;
private readonly IOptionsMonitorCache<OpenIdConnectOptions> _oidcOptionsCache;
private readonly OAuthPostConfigureOptions<OAuthOptions, OAuthHandler<OAuthOptions>> _oauthPostConfigureOptions;
private readonly IOptionsMonitorCache<OAuthOptions> _oauthOptionsCache;

public SsoController(
        OpenIdConnectPostConfigureOptions oidcPostConfigureOptions,
        IOptionsMonitorCache<OpenIdConnectOptions> oidcOptionsCache,
        OAuthPostConfigureOptions<OAuthOptions, OAuthHandler<OAuthOptions>> oauthPostConfigureOptions,
        IOptionsMonitorCache<OAuthOptions> oauthOptionsCache)
{
    _oidcPostConfigureOptions = oidcPostConfigureOptions;
    _oidcOptionsCache = oidcOptionsCache;
    _oauthPostConfigureOptions = oauthPostConfigureOptions;
    _oauthOptionsCache = oauthOptionsCache;
}

[HttpPost("refresh-config/{ssoIdentityProviderId:int}")]
public IActionResult RefreshConfig(int ssoIdentityProviderId)
{
    var ssoIdentityProvider = SingleSignOnStore.Model.Instance.GetIdentityProvider(ssoIdentityProviderId);
    if (ssoIdentityProvider == null)
        return NotFound();

    switch (ssoIdentityProvider.SsoFlowType)
    {
        case SsoFlowType.Oidc:
            var oidcOptions = new OpenIdConnectOptions();
            StartupSsoExtensions.SetOidcOptions(ssoIdentityProvider, oidcOptions);
            _oidcPostConfigureOptions.PostConfigure(ssoIdentityProvider.SsoCode, oidcOptions);
            _oidcOptionsCache.TryRemove(ssoIdentityProvider.SsoCode);
            _oidcOptionsCache.TryAdd(ssoIdentityProvider.SsoCode, oidcOptions);
            break;
        case SsoFlowType.OAuth2:
            var oauth2Options = new OAuthOptions();
            StartupSsoExtensions.SetOAuth2Options(ssoIdentityProvider, oauth2Options);
            _oauthPostConfigureOptions.PostConfigure(ssoIdentityProvider.SsoCode, oauth2Options);
            _oauthOptionsCache.TryRemove(ssoIdentityProvider.SsoCode);
            _oauthOptionsCache.TryAdd(ssoIdentityProvider.SsoCode, oauth2Options);
            break;
        /*case SsoFlowType.SamlNew:
            var samlOptions = new OAuthOptions();
            StartupSsoExtensions.SetSamlOptions(ssoIdentityProvider, samlOptions);
            _samlPostConfigureOptions.PostConfigure(ssoIdentityProvider.SsoCode, samlOptions);
            break;*/
    }
}
Related