[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:
@@ -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>
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user