Dynamically Reloading Auth Providers

Hello,

We have the need to dynamically load authentication providers upon request and we wonder how we should do it in the best possible way.

Our scenario is a bit weird because of some legacy third party systems but I´ll try to explain it:

  • Our api acts as a component in our legacy system
  • Our legacy system authenticates users using OpenId
  • Our legacy system is basically a separate cluster per customer (and thus a separate identity provider per customer)

Our new system holds configuration on which of these legacy identityproviders it trusts. So this is a dynamically changing list (we add and remove trusted tenants).

We have tried to get the following to work:

  1. When a request comes to /auth/dynamicprovider.{tenantid}
  2. If the tenant oauth config is not loaded, we load it (ie load on first request or on config update)
  3. Then we start the OAuth sequence for the request

To add to the complexity, our app is running in a clustered environment so different ServiceStack nodes can have different OAuth providers loaded.

Our problems comes to the reloading part. We get errors like:

Could not register Request ‘ServiceStack.Authenticate’ with service ‘ServiceStack.Auth.AuthenticateService’ as it has already been assigned to another service.

When trying to reload our new providerlist. We do this in a feature with these two methods:

  RemoveAuthFeatureIncludingPlugins();
  AddAuthFeaturePlugin(authFeature);

Which looks like this:

private void AddAuthFeaturePlugin(IPlugin authFeature)
    {
      // Reload plugin if it´s already loaded to refresh it´s settings
      // Reload the plugin
      Log.Information("Reloading the AuthFeature plugin");

      // Add new auth feature
      _appHost.LoadPlugin(authFeature);
    }

    private void RemoveAuthFeatureIncludingPlugins()
    {
      Log.Information("Removing old AuthFeatures and connected plugins");

      // Remove all authfeature instances
      _appHost.Plugins
        .Where(p => p is AuthFeature)
        .Cast<AuthFeature>()
        .ToList().ForEach(authFeature =>
        {
          // Remove plugins that belong to the authfeature
          authFeature.RegisterPlugins.ForEach(p => _appHost.Plugins.Remove(p));
          _appHost.Plugins.Remove(authFeature);
        }
      );
    }

We get into a situation now with occasional 401s and can´t really determine the cause, but as far as I understand it´s quite a twisted scenario we´re trying to pull off. So any suggestions on alternate approaches are appreciated. Or if we´re missing something blantantly stupid in order to get this reloadning of the authfeatre to work (or more correct, to be able too add and remove authproviders dynamically).

You need to change your design, ServiceStack has always been for configuration to remain immutable after AppHost Configure() as ServiceStack does not support dynamically loading plugins or mutating configuration after the AppHost has been initialized.

Any dynamism should be in your Service or dependency implementations, not in mutating the ServiceStack Framework configuration at runtime.

We´re thinking of implementing our own Authenticate attribute (override the existing one) and place the dynaic parts there. Would that be a feasible approach?

Yeah that should work.

Checking AuthenticateAttribute.cs it seems to have an ExecuteAsync method but I can´t find it in v4.5.14, only the non async version. Is this correct? If so, when will the async version be released?

The sync existing filter attributes still exist but we’ve switched all built-in features over to use the async filters. So you can work off the existing v4.5.14 AuthenticateAttribute or use the pre-release ServiceStack v5 on MyGet and base it off the latest AuthenticateAttribute.