[v14] Fix multiple upgrader issues (#16339)

* Made previewhubupdater work with full cache refreshes

* Make signout_Async available on coreSignInManager

* Allow Migrations to signout the logged in user

* Adding a guid to a user requires resignin

* Added a token revoke mechanism during migrations

* Revert "Make signout_Async available on coreSignInManager"

This reverts commit b103cf119a505e61de659dc206f6c85c2a27f2d5.

* Revert add allRefreshed on preview hub

Clarified with a comment

* Updated failing test setups

---------

Co-authored-by: Sven Geusens <sge@umbraco.dk>
This commit is contained in:
Sven Geusens
2024-05-27 07:17:45 +02:00
committed by GitHub
parent c083b3bc8a
commit e5e87c96db
5 changed files with 63 additions and 6 deletions

View File

@@ -91,6 +91,11 @@ public abstract partial class MigrationBase : IDiscoverable
/// </summary>
public bool RebuildCache { get; set; }
/// <summary>
/// If this is set to true, all backoffice client tokens will be revoked upon successful completion of the migration.
/// </summary>
public bool InvalidateBackofficeUserAccess { get; set; }
/// <summary>
/// Runs the migration.
/// </summary>

View File

@@ -1,11 +1,15 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using OpenIddict.Abstractions;
using Org.BouncyCastle.Utilities;
using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Cache;
using Umbraco.Cms.Core.DependencyInjection;
using Umbraco.Cms.Core.Migrations;
using Umbraco.Cms.Core.Models.Membership;
using Umbraco.Cms.Core.PublishedCache;
using Umbraco.Cms.Core.Scoping;
using Umbraco.Cms.Core.Security;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Infrastructure.Persistence;
using Umbraco.Cms.Infrastructure.Scoping;
@@ -42,10 +46,12 @@ public class MigrationPlanExecutor : IMigrationPlanExecutor
private readonly IUmbracoDatabaseFactory _databaseFactory;
private readonly IPublishedSnapshotService _publishedSnapshotService;
private readonly IKeyValueService _keyValueService;
private readonly IServiceScopeFactory _serviceScopeFactory;
private readonly DistributedCache _distributedCache;
private readonly IScopeAccessor _scopeAccessor;
private readonly ICoreScopeProvider _scopeProvider;
private bool _rebuildCache;
private bool _invalidateBackofficeUserAccess;
public MigrationPlanExecutor(
ICoreScopeProvider scopeProvider,
@@ -55,7 +61,8 @@ public class MigrationPlanExecutor : IMigrationPlanExecutor
IUmbracoDatabaseFactory databaseFactory,
IPublishedSnapshotService publishedSnapshotService,
DistributedCache distributedCache,
IKeyValueService keyValueService)
IKeyValueService keyValueService,
IServiceScopeFactory serviceScopeFactory)
{
_scopeProvider = scopeProvider;
_scopeAccessor = scopeAccessor;
@@ -64,6 +71,7 @@ public class MigrationPlanExecutor : IMigrationPlanExecutor
_databaseFactory = databaseFactory;
_publishedSnapshotService = publishedSnapshotService;
_keyValueService = keyValueService;
_serviceScopeFactory = serviceScopeFactory;
_distributedCache = distributedCache;
_logger = _loggerFactory.CreateLogger<MigrationPlanExecutor>();
}
@@ -85,7 +93,8 @@ public class MigrationPlanExecutor : IMigrationPlanExecutor
StaticServiceProvider.Instance.GetRequiredService<IUmbracoDatabaseFactory>(),
StaticServiceProvider.Instance.GetRequiredService<IPublishedSnapshotService>(),
StaticServiceProvider.Instance.GetRequiredService<DistributedCache>(),
StaticServiceProvider.Instance.GetRequiredService<IKeyValueService>())
StaticServiceProvider.Instance.GetRequiredService<IKeyValueService>(),
StaticServiceProvider.Instance.GetRequiredService<IServiceScopeFactory>())
{
}
@@ -103,8 +112,8 @@ public class MigrationPlanExecutor : IMigrationPlanExecutor
StaticServiceProvider.Instance.GetRequiredService<IUmbracoDatabaseFactory>(),
StaticServiceProvider.Instance.GetRequiredService<IPublishedSnapshotService>(),
StaticServiceProvider.Instance.GetRequiredService<DistributedCache>(),
StaticServiceProvider.Instance.GetRequiredService<IKeyValueService>()
)
StaticServiceProvider.Instance.GetRequiredService<IKeyValueService>(),
StaticServiceProvider.Instance.GetRequiredService<IServiceScopeFactory>())
{
}
@@ -135,6 +144,12 @@ public class MigrationPlanExecutor : IMigrationPlanExecutor
RebuildCache();
}
// If any completed migration requires us to sign out the user we'll do that.
if (_invalidateBackofficeUserAccess)
{
RevokeBackofficeTokens().GetAwaiter().GetResult(); // should async all the way up at some point
}
return result;
}
@@ -320,6 +335,11 @@ public class MigrationPlanExecutor : IMigrationPlanExecutor
{
_rebuildCache = true;
}
if (migration.InvalidateBackofficeUserAccess)
{
_invalidateBackofficeUserAccess = true;
}
}
private void RebuildCache()
@@ -327,4 +347,31 @@ public class MigrationPlanExecutor : IMigrationPlanExecutor
_publishedSnapshotService.RebuildAll();
_distributedCache.RefreshAllPublishedSnapshot();
}
private async Task RevokeBackofficeTokens()
{
using IServiceScope scope = _serviceScopeFactory.CreateScope();
IOpenIddictApplicationManager openIddictApplicationManager = scope.ServiceProvider.GetRequiredService<IOpenIddictApplicationManager>();
var backOfficeClient = await openIddictApplicationManager.FindByClientIdAsync(Constants.OAuthClientIds.BackOffice);
if (backOfficeClient is null)
{
_logger.LogWarning("Could not get the openIddict Application for {backofficeClientId}. Canceling token revocation. Users might have to manually log out to get proper access to the backoffice", Constants.OAuthClientIds.BackOffice);
return;
}
var backOfficeClientId = await openIddictApplicationManager.GetIdAsync(backOfficeClient);
if (backOfficeClientId is null)
{
_logger.LogWarning("Could not extract the clientId from the openIddict backofficelient Application. Canceling token revocation. Users might have to manually log out to get proper access to the backoffice", Constants.OAuthClientIds.BackOffice);
return;
}
IOpenIddictTokenManager tokenManager = scope.ServiceProvider.GetRequiredService<IOpenIddictTokenManager>();
var tokens = await tokenManager.FindByApplicationIdAsync(backOfficeClientId).ToArrayAsync();
foreach (var token in tokens)
{
await tokenManager.DeleteAsync(token);
}
}
}

View File

@@ -26,6 +26,7 @@ internal class AddGuidsToUsers : UnscopedMigrationBase
protected override void Migrate()
{
InvalidateBackofficeUserAccess = true;
using IScope scope = _scopeProvider.CreateScope();
using IDisposable notificationSuppression = scope.Notifications.Suppress();
ScopeDatabase(scope);

View File

@@ -2,6 +2,7 @@
// See LICENSE for more details.
using System.Linq;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Moq;
using NUnit.Framework;
@@ -35,6 +36,7 @@ public class AdvancedMigrationTests : UmbracoIntegrationTest
private IMigrationBuilder MigrationBuilder => GetRequiredService<IMigrationBuilder>();
private IUmbracoDatabaseFactory UmbracoDatabaseFactory => GetRequiredService<IUmbracoDatabaseFactory>();
private IPublishedSnapshotService PublishedSnapshotService => GetRequiredService<IPublishedSnapshotService>();
private IServiceScopeFactory ServiceScopeFactory => GetRequiredService<IServiceScopeFactory>();
private DistributedCache DistributedCache => GetRequiredService<DistributedCache>();
private IMigrationPlanExecutor MigrationPlanExecutor => new MigrationPlanExecutor(
CoreScopeProvider,
@@ -44,7 +46,8 @@ public class AdvancedMigrationTests : UmbracoIntegrationTest
UmbracoDatabaseFactory,
PublishedSnapshotService,
DistributedCache,
Mock.Of<IKeyValueService>());
Mock.Of<IKeyValueService>(),
ServiceScopeFactory);
[Test]
public void CreateTableOfTDto()

View File

@@ -3,6 +3,7 @@
using System.Collections.Generic;
using System.Linq;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options;
using Moq;
@@ -76,7 +77,7 @@ public class MigrationPlanTests
loggerFactory,
migrationBuilder,
databaseFactory,
Mock.Of<IPublishedSnapshotService>(), distributedCache, Mock.Of<IKeyValueService>());
Mock.Of<IPublishedSnapshotService>(), distributedCache, Mock.Of<IKeyValueService>(), Mock.Of<IServiceScopeFactory>());
var plan = new MigrationPlan("default")
.From(string.Empty)