using System;
using System.Diagnostics;
using Microsoft.AspNetCore.Authentication;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Options;
using Constants = Umbraco.Cms.Core.Constants;
namespace Umbraco.Cms.Web.BackOffice.Security
{
///
/// Custom used to associate external logins with umbraco external login options
///
public class BackOfficeAuthenticationBuilder : AuthenticationBuilder
{
private readonly Action _loginProviderOptions;
public BackOfficeAuthenticationBuilder(
IServiceCollection services,
Action loginProviderOptions = null)
: base(services)
=> _loginProviderOptions = loginProviderOptions ?? (x => { });
public string SchemeForBackOffice(string scheme)
=> Constants.Security.BackOfficeExternalAuthenticationTypePrefix + scheme;
///
/// Overridden to track the final authenticationScheme being registered for the external login
///
///
///
///
///
///
///
public override AuthenticationBuilder AddRemoteScheme(string authenticationScheme, string displayName, Action configureOptions)
{
// Validate that the prefix is set
if (!authenticationScheme.StartsWith(Constants.Security.BackOfficeExternalAuthenticationTypePrefix))
{
throw new InvalidOperationException($"The {nameof(authenticationScheme)} is not prefixed with {Constants.Security.BackOfficeExternalAuthenticationTypePrefix}. The scheme must be created with a call to the method {nameof(SchemeForBackOffice)}");
}
// add our login provider to the container along with a custom options configuration
Services.Configure(authenticationScheme, _loginProviderOptions);
base.Services.AddSingleton(services =>
{
return new BackOfficeExternalLoginProvider(
authenticationScheme,
services.GetRequiredService>());
});
Services.TryAddEnumerable(ServiceDescriptor.Singleton, EnsureBackOfficeScheme>());
return base.AddRemoteScheme(authenticationScheme, displayName, configureOptions);
}
// TODO: We could override and throw NotImplementedException for other methods?
// Ensures that the sign in scheme is always the Umbraco back office external type
private class EnsureBackOfficeScheme : IPostConfigureOptions where TOptions : RemoteAuthenticationOptions
{
public void PostConfigure(string name, TOptions options)
{
options.SignInScheme = Constants.Security.BackOfficeExternalAuthenticationType;
}
}
}
}