Skip to content

Commit cba163c

Browse files
Add ElasticsearchIndexingAuthorizationHandler (Lombiq Technologies: OSOE-925) (OrchardCMS#18855)
--------- Co-authored-by: Mike Alhayek <mike@crestapps.com>
1 parent c35fbdb commit cba163c

File tree

6 files changed

+94
-26
lines changed

6 files changed

+94
-26
lines changed
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
using Microsoft.AspNetCore.Identity;
2+
using Microsoft.Extensions.DependencyInjection;
3+
using OrchardCore.Data.Migration;
4+
using OrchardCore.Environment.Shell;
5+
using OrchardCore.Environment.Shell.Scope;
6+
using OrchardCore.Indexing;
7+
using OrchardCore.Indexing.Core;
8+
using OrchardCore.Security;
9+
using OrchardCore.Security.Services;
10+
using static OrchardCore.Search.Elasticsearch.ElasticsearchIndexPermissionHelper;
11+
12+
namespace OrchardCore.Search.Elasticsearch.Migrations;
13+
14+
internal sealed class PermissionMigrations : DataMigration
15+
{
16+
private readonly ShellSettings _shellSettings;
17+
18+
public PermissionMigrations(ShellSettings shellSettings) =>
19+
_shellSettings = shellSettings;
20+
21+
public int Create()
22+
{
23+
if (!_shellSettings.IsInitializing())
24+
{
25+
ShellScope.AddDeferredTask(ReplaceObsoletePermissionsAsync);
26+
}
27+
28+
return 1;
29+
}
30+
31+
/// <summary>
32+
/// Selects the roles that need to be updated, and replaces their <c>QueryElasticsearch{0}Index</c> permissions with
33+
/// the equivalent <c>QueryIndex_{0}</c> permissions.
34+
/// </summary>
35+
private static async Task ReplaceObsoletePermissionsAsync(ShellScope shellScope)
36+
{
37+
var indexProfileManager = shellScope.ServiceProvider.GetRequiredService<IIndexProfileManager>();
38+
var roleService = shellScope.ServiceProvider.GetRequiredService<IRoleService>();
39+
var roleStore = shellScope.ServiceProvider.GetRequiredService<IRoleStore<IRole>>();
40+
41+
var allRoles = await roleService.GetRolesAsync();
42+
var rolesToUpdate = allRoles
43+
.Where(role => role is Role)
44+
.Cast<Role>()
45+
.Where(role => role.RoleClaims.Any(IsElasticsearchIndexPermissionClaim))
46+
.ToList();
47+
48+
foreach (var role in rolesToUpdate)
49+
{
50+
foreach (var claim in role.RoleClaims.Where(IsElasticsearchIndexPermissionClaim))
51+
{
52+
var name = GetIndexNameFromPermissionName(claim.ClaimValue);
53+
var indexProfile = await indexProfileManager.FindByNameAndProviderAsync(
54+
name,
55+
ElasticsearchConstants.ProviderName);
56+
57+
if (indexProfile != null)
58+
{
59+
claim.ClaimValue = IndexingPermissions.CreateDynamicPermission(indexProfile).Name;
60+
}
61+
}
62+
63+
await roleStore.UpdateAsync(role, CancellationToken.None);
64+
}
65+
}
66+
}

src/OrchardCore.Modules/OrchardCore.Search.Elasticsearch/PermissionProvider.cs

Lines changed: 7 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,17 @@
1-
using OrchardCore.Indexing;
21
using OrchardCore.Security.Permissions;
32

43
namespace OrchardCore.Search.Elasticsearch;
54

65
public sealed class PermissionProvider : IPermissionProvider
76
{
8-
private readonly IIndexProfileStore _indexStore;
9-
10-
public PermissionProvider(IIndexProfileStore indexStore)
11-
{
12-
_indexStore = indexStore;
13-
}
14-
15-
public async Task<IEnumerable<Permission>> GetPermissionsAsync()
16-
{
17-
var permissions = new List<Permission>()
18-
{
19-
ElasticsearchPermissions.ManageElasticIndexes,
20-
ElasticsearchPermissions.QueryElasticApi,
21-
};
22-
23-
var elasticIndexSettings = await _indexStore.GetByProviderAsync(ElasticsearchConstants.ProviderName);
24-
25-
foreach (var index in elasticIndexSettings)
26-
{
27-
permissions.Add(ElasticsearchIndexPermissionHelper.GetElasticIndexPermission(index.IndexName));
28-
}
7+
private readonly IEnumerable<Permission> _allPermissions =
8+
[
9+
ElasticsearchPermissions.ManageElasticIndexes,
10+
ElasticsearchPermissions.QueryElasticApi,
11+
];
2912

30-
return permissions;
31-
}
13+
public Task<IEnumerable<Permission>> GetPermissionsAsync() =>
14+
Task.FromResult(_allPermissions);
3215

3316
public IEnumerable<PermissionStereotype> GetDefaultStereotypes() =>
3417
[

src/OrchardCore.Modules/OrchardCore.Search.Elasticsearch/Startup.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ public override void ConfigureServices(IServiceCollection services)
6969
services.AddDisplayDriver<IndexProfile, ElasticsearchIndexProfileDisplayDriver>();
7070

7171
services.AddIndexProfileHandler<ElasticsearchIndexProfileHandler>();
72+
services.AddDataMigration<PermissionMigrations>();
7273
}
7374
}
7475

src/OrchardCore/OrchardCore.Indexing.Core/IndexingPermissions.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ public static Permission CreateDynamicPermission(IndexProfile indexProfile)
2121

2222
return _permissions.GetOrAdd(indexProfile.Id, indexId => new Permission(
2323
string.Format(_indexPermissionTemplate.Name, indexProfile.Name),
24-
string.Format(_indexPermissionTemplate.Description, indexProfile.Name), _indexPermissionTemplate.ImpliedBy));
24+
string.Format(_indexPermissionTemplate.Description, indexProfile.Name),
25+
_indexPermissionTemplate.ImpliedBy));
2526
}
2627
}

src/OrchardCore/OrchardCore.Search.Elasticsearch.Core/ElasticsearchIndexPermissionHelper.cs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,22 @@
1+
using OrchardCore.Indexing.Core;
2+
using OrchardCore.Modules;
3+
using OrchardCore.Security;
14
using System.Collections.Concurrent;
25
using OrchardCore.Security.Permissions;
36

47
namespace OrchardCore.Search.Elasticsearch;
58

69
public static class ElasticsearchIndexPermissionHelper
710
{
8-
private static readonly Permission _indexPermissionTemplate = new("QueryElasticsearch{0}Index", "Query Elasticsearch {0} Index", [Permissions.ManageElasticIndexes]);
11+
private const string PermissionNamePrefix = "QueryElasticsearch";
12+
private const string PermissionNameSuffix = "Index";
13+
14+
private static readonly Permission _indexPermissionTemplate =
15+
new(PermissionNamePrefix + "{0}" + PermissionNameSuffix, "Query Elasticsearch {0} Index", [Permissions.ManageElasticIndexes]);
916

1017
private static readonly ConcurrentDictionary<string, Permission> _permissions = [];
1118

19+
[Obsolete($"Use {nameof(IndexingPermissions)}.{nameof(IndexingPermissions.CreateDynamicPermission)} instead.")]
1220
public static Permission GetElasticIndexPermission(string indexName)
1321
{
1422
ArgumentException.ThrowIfNullOrEmpty(indexName);
@@ -18,4 +26,12 @@ public static Permission GetElasticIndexPermission(string indexName)
1826
string.Format(_indexPermissionTemplate.Description, indexName),
1927
_indexPermissionTemplate.ImpliedBy));
2028
}
29+
30+
internal static bool IsElasticsearchIndexPermissionClaim(RoleClaim claim) =>
31+
claim.ClaimType == nameof(Permission) &&
32+
claim.ClaimValue.StartsWithOrdinalIgnoreCase(PermissionNamePrefix) &&
33+
claim.ClaimValue.EndsWithOrdinalIgnoreCase(PermissionNameSuffix);
34+
35+
internal static string GetIndexNameFromPermissionName(string permissionName) =>
36+
permissionName[PermissionNamePrefix.Length .. ^PermissionNameSuffix.Length];
2137
}

src/OrchardCore/OrchardCore.Search.Elasticsearch.Core/OrchardCore.Search.Elasticsearch.Core.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
<ProjectReference Include="..\OrchardCore.Indexing.Core\OrchardCore.Indexing.Core.csproj" />
3131
<ProjectReference Include="..\OrchardCore.Liquid.Abstractions\OrchardCore.Liquid.Abstractions.csproj" />
3232
<ProjectReference Include="..\OrchardCore.Queries.Abstractions\OrchardCore.Queries.Abstractions.csproj" />
33+
<ProjectReference Include="..\OrchardCore.Roles.Abstractions\OrchardCore.Roles.Abstractions.csproj" />
3334
<ProjectReference Include="..\OrchardCore.Search.Abstractions\OrchardCore.Search.Abstractions.csproj" />
3435
</ItemGroup>
3536

0 commit comments

Comments
 (0)