Fix unattented admin install

This commit is contained in:
Bjarke Berg
2021-03-03 19:48:01 +01:00
parent aa9ff2e670
commit 008fd4271c
4 changed files with 74 additions and 51 deletions

View File

@@ -1,6 +1,7 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Composing;
@@ -10,7 +11,6 @@ using Umbraco.Cms.Core.Logging;
using Umbraco.Cms.Core.Runtime;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Infrastructure.Persistence;
using Constants = Umbraco.Cms.Core.Constants;
namespace Umbraco.Cms.Infrastructure.Runtime
{
@@ -25,6 +25,7 @@ namespace Umbraco.Cms.Infrastructure.Runtime
private readonly IUmbracoDatabaseFactory _databaseFactory;
private readonly IEventAggregator _eventAggregator;
private readonly IHostingEnvironment _hostingEnvironment;
private readonly IServiceScopeFactory _serviceScopeFactory;
/// <summary>
/// Initializes a new instance of the <see cref="CoreRuntime"/> class.
@@ -38,7 +39,8 @@ namespace Umbraco.Cms.Infrastructure.Runtime
IMainDom mainDom,
IUmbracoDatabaseFactory databaseFactory,
IEventAggregator eventAggregator,
IHostingEnvironment hostingEnvironment)
IHostingEnvironment hostingEnvironment,
IServiceScopeFactory serviceScopeFactory)
{
State = state;
_loggerFactory = loggerFactory;
@@ -49,6 +51,7 @@ namespace Umbraco.Cms.Infrastructure.Runtime
_databaseFactory = databaseFactory;
_eventAggregator = eventAggregator;
_hostingEnvironment = hostingEnvironment;
_serviceScopeFactory = serviceScopeFactory;
_logger = _loggerFactory.CreateLogger<CoreRuntime>();
}
@@ -60,6 +63,8 @@ namespace Umbraco.Cms.Infrastructure.Runtime
/// <inheritdoc/>
public async Task StartAsync(CancellationToken cancellationToken)
{
using IServiceScope scope = _serviceScopeFactory.CreateScope();
StaticApplicationLogging.Initialize(_loggerFactory);
AppDomain.CurrentDomain.UnhandledException += (_, args) =>

View File

@@ -198,7 +198,7 @@ namespace Umbraco.Cms.Core
Reason = reason;
}
public async void DoUnattendedInstall()
public void DoUnattendedInstall()
{
// unattended install is not enabled
if (_globalSettings.InstallUnattended == false) return;
@@ -239,7 +239,7 @@ namespace Umbraco.Cms.Core
// Emit an event with EventAggregator that unattended install completed
// Then this event can be listened for and create an unattended user
await _eventAggregator.PublishAsync(new UnattendedInstallNotification());
_eventAggregator.Publish(new UnattendedInstallNotification());
}
catch (Exception ex)

View File

@@ -271,7 +271,7 @@ namespace Umbraco.Extensions
builder.Services.AddUnique<InstallAreaRoutes>();
@@ -298,7 +298,7 @@ namespace Umbraco.Extensions
public static IUmbracoBuilder AddUnattedInstallCreateUser(this IUmbracoBuilder builder)
{
builder.AddNotificationHandler<UnattendedInstallNotification, CreateUnattendedUserNotificationHandler>();
builder.AddNotificationAsyncHandler<UnattendedInstallNotification, CreateUnattendedUserNotificationHandler>();
//builder.AddNotificationHandler<UmbracoApplicationStarting, CreateUnattendedUserNotificationHandler>();
return builder;
}

View File

@@ -1,81 +1,99 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Umbraco.Cms.Core.Configuration.Models;
using Umbraco.Cms.Core.Events;
using Umbraco.Cms.Core.Models.Membership;
using Umbraco.Cms.Core.Security;
using Umbraco.Cms.Core.Services;
using Umbraco.Core.Events;
using Umbraco.Extensions;
namespace Umbraco.Cms.Web.Common.Install
{
public class CreateUnattendedUserNotificationHandler : INotificationHandler<UnattendedInstallNotification>
public class CreateUnattendedUserNotificationHandler : INotificationAsyncHandler<UnattendedInstallNotification>
{
private readonly GlobalSettings _globalSettings;
private readonly IUserService _userService;
private readonly IServiceScopeFactory _serviceScopeFactory;
public CreateUnattendedUserNotificationHandler(IOptions<GlobalSettings> globalSettings, IUserService userService)
public CreateUnattendedUserNotificationHandler(IOptions<GlobalSettings> globalSettings, IUserService userService, IServiceScopeFactory serviceScopeFactory)
{
_globalSettings = globalSettings.Value;
_userService = userService;
_serviceScopeFactory = serviceScopeFactory;
}
/// Listening for when the UnattendedInstallNotification fired after a sucessfulk
/// </summary>
/// <param name="notification"></param>
public async void Handle(UnattendedInstallNotification notification)
public async Task HandleAsync(UnattendedInstallNotification notification, CancellationToken cancellationToken)
{
// Ensure we have the setting enabled (Sanity check)
// In theory this should always be true as the event only fired when a sucessfull
if (_globalSettings.InstallUnattended == false)
return;
var unattendedName = _globalSettings.UnattendedUserName;
var unattendedEmail = _globalSettings.UnattendedUserEmail;
var unattendedPassword = _globalSettings.UnattendedUserPassword;
// Ensure we have the setting enabled (Sanity check)
// In theory this should always be true as the event only fired when a sucessfull
if (_globalSettings.InstallUnattended == false)
{
return;
}
// Missing configuration values (json, env variables etc)
if (unattendedName.IsNullOrWhiteSpace()
|| unattendedEmail.IsNullOrWhiteSpace()
|| unattendedPassword.IsNullOrWhiteSpace())
{
return;
}
var unattendedName = _globalSettings.UnattendedUserName;
var unattendedEmail = _globalSettings.UnattendedUserEmail;
var unattendedPassword = _globalSettings.UnattendedUserPassword;
var admin = _userService.GetUserById(Core.Constants.Security.SuperUserId);
if (admin == null)
{
throw new InvalidOperationException("Could not find the super user!");
}
// Missing configuration values (json, env variables etc)
if (unattendedName.IsNullOrWhiteSpace()
|| unattendedEmail.IsNullOrWhiteSpace()
|| unattendedPassword.IsNullOrWhiteSpace())
{
return;
}
// User email/login has already been modified
if (admin.Email == unattendedEmail)
return;
IUser admin = _userService.GetUserById(Core.Constants.Security.SuperUserId);
if (admin == null)
{
throw new InvalidOperationException("Could not find the super user!");
}
// Update name, email & login & save user
admin.Name = unattendedName.Trim();
admin.Email = unattendedEmail.Trim();
admin.Username = unattendedEmail.Trim();
_userService.Save(admin);
// User email/login has already been modified
if (admin.Email == unattendedEmail)
{
return;
}
// Change Password for the default user we ship out of the box
// Uses same approach as NewInstall Step
// Update name, email & login & save user
admin.Name = unattendedName.Trim();
admin.Email = unattendedEmail.Trim();
admin.Username = unattendedEmail.Trim();
_userService.Save(admin);
// TODO: usermanager why you no inject?!
// Change Password for the default user we ship out of the box
// Uses same approach as NewInstall Step
//var membershipUser = await _userManager.FindByIdAsync(Core.Constants.Security.SuperUserId.ToString());
//if (membershipUser == null)
//{
// throw new InvalidOperationException($"No user found in membership provider with id of {Core.Constants.Security.SuperUserId}.");
//}
// TODO: usermanager why you no inject?!
using IServiceScope scope = _serviceScopeFactory.CreateScope();
IBackOfficeUserManager backOfficeUserManager = scope.ServiceProvider.GetRequiredService<IBackOfficeUserManager>();
BackOfficeIdentityUser membershipUser = await backOfficeUserManager.FindByIdAsync(Core.Constants.Security.SuperUserId.ToString());
if (membershipUser == null)
{
throw new InvalidOperationException($"No user found in membership provider with id of {Core.Constants.Security.SuperUserId}.");
}
////To change the password here we actually need to reset it since we don't have an old one to use to change
//var resetToken = await _userManager.GeneratePasswordResetTokenAsync(membershipUser);
//if (string.IsNullOrWhiteSpace(resetToken))
// throw new InvalidOperationException("Could not reset password: unable to generate internal reset token");
//To change the password here we actually need to reset it since we don't have an old one to use to change
var resetToken = await backOfficeUserManager.GeneratePasswordResetTokenAsync(membershipUser);
if (string.IsNullOrWhiteSpace(resetToken))
{
throw new InvalidOperationException("Could not reset password: unable to generate internal reset token");
}
//var resetResult = await _userManager.ChangePasswordWithResetAsync(membershipUser.Id, resetToken, unattendedPassword.Trim());
//if (!resetResult.Succeeded)
// throw new InvalidOperationException("Could not reset password: " + string.Join(", ", resetResult.Errors.ToErrorMessage()));
IdentityResult resetResult = await backOfficeUserManager.ChangePasswordWithResetAsync(membershipUser.Id, resetToken, unattendedPassword.Trim());
if (!resetResult.Succeeded)
{
throw new InvalidOperationException("Could not reset password: " + string.Join(", ", resetResult.Errors.ToErrorMessage()));
}
}
}