using System; using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc.Filters; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; using Umbraco.Core; using Umbraco.Core.BackOffice; using Umbraco.Core.Security; using Umbraco.Core.Serialization; using Umbraco.Infrastructure.BackOffice; using Umbraco.Net; using Umbraco.Web.BackOffice.Filters; using Umbraco.Web.BackOffice.Security; using Umbraco.Web.Common.AspNetCore; using Umbraco.Web.Common.Security; namespace Umbraco.Extensions { public static class BackOfficeServiceCollectionExtensions { /// /// Adds the services required for using Umbraco back office Identity /// /// public static void AddUmbracoBackOfficeIdentity(this IServiceCollection services) { services.AddDataProtection(); services.BuildUmbracoBackOfficeIdentity() .AddDefaultTokenProviders() .AddUserStore() .AddUserManager() .AddSignInManager() .AddClaimsPrincipalFactory>(); // Configure the options specifically for the UmbracoBackOfficeIdentityOptions instance services.ConfigureOptions(); services.ConfigureOptions(); } private static BackOfficeIdentityBuilder BuildUmbracoBackOfficeIdentity(this IServiceCollection services) { // Borrowed from https://github.com/dotnet/aspnetcore/blob/master/src/Identity/Extensions.Core/src/IdentityServiceCollectionExtensions.cs#L33 // The reason we need our own is because the Identity system doesn't cater easily for multiple identity systems and particularly being // able to configure IdentityOptions to a specific provider since there is no named options. So we have strongly typed options // and strongly typed ILookupNormalizer and IdentityErrorDescriber since those are 'global' and we need to be unintrusive. // TODO: Could move all of this to BackOfficeComposer? // Services used by identity services.TryAddScoped, UserValidator>(); services.TryAddScoped, PasswordValidator>(); services.TryAddScoped>( services => new BackOfficePasswordHasher( new LegacyPasswordSecurity(), services.GetRequiredService())); services.TryAddScoped, DefaultUserConfirmation>(); services.TryAddScoped, UserClaimsPrincipalFactory>(); // CUSTOM: services.TryAddScoped(); services.TryAddScoped(); services.TryAddScoped(); services.TryAddSingleton(); /* * IdentityBuilderExtensions.AddUserManager adds UserManager to service collection * To validate the container the following registrations are required (dependencies of UserManager) * Perhaps we shouldn't be registering UserManager at all and only registering/depending the UmbracoBackOffice prefixed types. */ services.TryAddScoped(); services.TryAddScoped(); return new BackOfficeIdentityBuilder(services); } } }