Skip to content

Commit

Permalink
fix: update scheme provider to support decorator pattern (#551)
Browse files Browse the repository at this point in the history
* These changes decorate the IAuthenticationSchemeProvider so that the decorated class's GetScheme method will be used.

* Update documentation on class constructors

Co-authored-by: Alex Casciani <acasciani@mindex.com>
  • Loading branch information
acasciani and acasciani-mindex authored Apr 5, 2022
1 parent 0d82131 commit ead052a
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -194,10 +194,8 @@ public static FinbuckleMultiTenantBuilder<TTenantInfo> WithPerTenantAuthenticati
"WithPerTenantAuthenticationCore() must be called after AddAuthentication() in ConfigureServices.");
builder.Services.DecorateService<IAuthenticationService, MultiTenantAuthenticationService<TTenantInfo>>();

// Replace IAuthenticationSchemeProvider so that the options aren't
// cached and can be used per-tenant.
builder.Services.Replace(ServiceDescriptor
.Singleton<IAuthenticationSchemeProvider, MultiTenantAuthenticationSchemeProvider>());
// We need to "decorate" IAuthenticationScheme provider.
builder.Services.DecorateService<IAuthenticationSchemeProvider, MultiTenantAuthenticationSchemeProvider>();

return builder;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,24 +19,29 @@ namespace Finbuckle.MultiTenant.AspNetCore
/// </summary>
internal class MultiTenantAuthenticationSchemeProvider : IAuthenticationSchemeProvider
{
private readonly IAuthenticationSchemeProvider _inner;

/// <summary>
/// Creates an instance of <see cref="MultiTenantAuthenticationSchemeProvider"/>
/// using the specified <paramref name="options"/>,
/// using the specified <paramref name="options"/> and decorates the existing <paramref name="inner"/>.
/// </summary>
/// <param name="inner">The <see cref="IAuthenticationSchemeProvider"/> to decorate.</param>
/// <param name="options">The <see cref="AuthenticationOptions"/> options.</param>
public MultiTenantAuthenticationSchemeProvider(IOptions<AuthenticationOptions> options)
: this(options, new Dictionary<string, AuthenticationScheme>(StringComparer.Ordinal))
public MultiTenantAuthenticationSchemeProvider(IAuthenticationSchemeProvider inner, IOptions<AuthenticationOptions> options)
: this(inner, options, new Dictionary<string, AuthenticationScheme>(StringComparer.Ordinal))
{
}

/// <summary>
/// Creates an instance of <see cref="MultiTenantAuthenticationSchemeProvider"/>
/// using the specified <paramref name="options"/> and <paramref name="schemes"/>.
/// using the specified <paramref name="options"/> and <paramref name="schemes"/>. This instance decorates the existing <paramref name="inner"/>.
/// </summary>
/// <param name="inner">The <see cref="IAuthenticationSchemeProvider"/> to decorate.</param>
/// <param name="options">The <see cref="AuthenticationOptions"/> options.</param>
/// <param name="schemes">The dictionary used to store authentication schemes.</param>
public MultiTenantAuthenticationSchemeProvider(IOptions<AuthenticationOptions> options, IDictionary<string, AuthenticationScheme> schemes)
public MultiTenantAuthenticationSchemeProvider(IAuthenticationSchemeProvider inner, IOptions<AuthenticationOptions> options, IDictionary<string, AuthenticationScheme> schemes)
{
_inner = inner;
_optionsProvider = options;

_schemes = schemes ?? throw new ArgumentNullException(nameof(schemes));
Expand Down Expand Up @@ -122,8 +127,22 @@ public MultiTenantAuthenticationSchemeProvider(IOptions<AuthenticationOptions> o
/// </summary>
/// <param name="name">The name of the authenticationScheme.</param>
/// <returns>The scheme or null if not found.</returns>
public virtual Task<AuthenticationScheme?> GetSchemeAsync(string name)
=> Task.FromResult(_schemes.ContainsKey(name) ? _schemes[name] : null);
public virtual async Task<AuthenticationScheme?> GetSchemeAsync(string name)
{
AuthenticationScheme? scheme = null;

if (_inner != null)
{
scheme = await _inner.GetSchemeAsync(name);
}

if (scheme == null)
{
scheme = _schemes.ContainsKey(name) ? _schemes[name] : null;
}

return scheme;
}

/// <summary>
/// Returns the scheme for this tenants in priority order for request handling.
Expand Down

0 comments on commit ead052a

Please sign in to comment.