Skip to content

Commit c38d4e9

Browse files
Phil91ntruchsess
andauthored
feat(seeding): make seeder configureable (#1174)
Refs: #1172 Co-authored-by: Norbert Truchsess <[email protected]> Reviewed-By: Evelyn Gurschler <[email protected]> Reviewed-By: Norbert Truchsess <[email protected]>
1 parent d8633e3 commit c38d4e9

27 files changed

+2214
-367
lines changed

src/keycloak/Keycloak.Seeding/BusinessLogic/AuthenticationFlowsUpdater.cs

Lines changed: 86 additions & 86 deletions
Large diffs are not rendered by default.

src/keycloak/Keycloak.Seeding/BusinessLogic/ClientScopeMapperUpdater.cs

Lines changed: 20 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -22,27 +22,22 @@
2222
using Org.Eclipse.TractusX.Portal.Backend.Keycloak.Factory;
2323
using Org.Eclipse.TractusX.Portal.Backend.Keycloak.Library;
2424
using Org.Eclipse.TractusX.Portal.Backend.Keycloak.Library.Models.Roles;
25+
using Org.Eclipse.TractusX.Portal.Backend.Keycloak.Seeding.Extensions;
26+
using Org.Eclipse.TractusX.Portal.Backend.Keycloak.Seeding.Models;
2527

2628
namespace Org.Eclipse.TractusX.Portal.Backend.Keycloak.Seeding.BusinessLogic;
2729

28-
public class ClientScopeMapperUpdater : IClientScopeMapperUpdater
30+
public class ClientScopeMapperUpdater(IKeycloakFactory keycloakFactory, ISeedDataHandler seedDataHandler)
31+
: IClientScopeMapperUpdater
2932
{
30-
private readonly IKeycloakFactory _keycloakFactory;
31-
private readonly ISeedDataHandler _seedData;
32-
33-
public ClientScopeMapperUpdater(IKeycloakFactory keycloakFactory, ISeedDataHandler seedDataHandler)
34-
{
35-
_keycloakFactory = keycloakFactory;
36-
_seedData = seedDataHandler;
37-
}
38-
3933
public async Task UpdateClientScopeMapper(string instanceName, CancellationToken cancellationToken)
4034
{
41-
var keycloak = _keycloakFactory.CreateKeycloakClient(instanceName);
42-
var realm = _seedData.Realm;
35+
var keycloak = keycloakFactory.CreateKeycloakClient(instanceName);
36+
var realm = seedDataHandler.Realm;
37+
var seederConfig = seedDataHandler.GetSpecificConfiguration(ConfigurationKey.ClientScopes);
4338

4439
var clients = await keycloak.GetClientsAsync(realm, null, true, cancellationToken).ConfigureAwait(ConfigureAwaitOptions.None);
45-
foreach (var (clientName, mappingModels) in _seedData.ClientScopeMappings)
40+
foreach (var (clientName, mappingModels) in seedDataHandler.ClientScopeMappings)
4641
{
4742
var client = clients.SingleOrDefault(x => x.ClientId == clientName);
4843
if (client?.Id is null)
@@ -60,17 +55,23 @@ public async Task UpdateClientScopeMapper(string instanceName, CancellationToken
6055
}
6156
var clientRoles = await keycloak.GetClientRolesScopeMappingsForClientAsync(realm, clientScope.Id, client.Id, cancellationToken).ConfigureAwait(ConfigureAwaitOptions.None);
6257
var mappingModelRoles = mappingModel.Roles?.Select(roleName => roles.SingleOrDefault(r => r.Name == roleName) ?? throw new ConflictException($"No role with name {roleName} found")) ?? Enumerable.Empty<Role>();
63-
await AddAndDeleteRoles(keycloak, realm, clientScope.Id, client.Id, clientRoles, mappingModelRoles, cancellationToken).ConfigureAwait(ConfigureAwaitOptions.None);
58+
await AddAndDeleteRoles(keycloak, realm, clientScope.Id, client.Id, clientRoles, mappingModelRoles, seederConfig, cancellationToken).ConfigureAwait(ConfigureAwaitOptions.None);
6459
}
6560
}
6661
}
6762

68-
private static async Task AddAndDeleteRoles(KeycloakClient keycloak, string realm, string clientScopeId, string clientId, IEnumerable<Role> roles, IEnumerable<Role> updateRoles, CancellationToken cancellationToken)
63+
private static async Task AddAndDeleteRoles(KeycloakClient keycloak, string realm, string clientScopeId, string clientId, IEnumerable<Role> roles, IEnumerable<Role> updateRoles, KeycloakSeederConfigModel seederConfig, CancellationToken cancellationToken)
6964
{
70-
await updateRoles.ExceptBy(roles.Select(role => role.Name), roleModel => roleModel.Name).IfAnyAwait(rolesToAdd =>
71-
keycloak.AddClientRolesScopeMappingToClientAsync(realm, clientScopeId, clientId, rolesToAdd, cancellationToken)).ConfigureAwait(false);
65+
await updateRoles
66+
.Where(x => seederConfig.ModificationAllowed(ModificationType.Create, x.Name))
67+
.ExceptBy(roles.Select(role => role.Name), roleModel => roleModel.Name)
68+
.IfAnyAwait(rolesToAdd =>
69+
keycloak.AddClientRolesScopeMappingToClientAsync(realm, clientScopeId, clientId, rolesToAdd, cancellationToken)).ConfigureAwait(false);
7270

73-
await roles.ExceptBy(updateRoles.Select(roleModel => roleModel.Name), role => role.Name).IfAnyAwait(rolesToDelete =>
74-
keycloak.RemoveClientRolesFromClientScopeForClientAsync(realm, clientScopeId, clientId, rolesToDelete, cancellationToken)).ConfigureAwait(false);
71+
await roles
72+
.Where(x => seederConfig.ModificationAllowed(ModificationType.Delete, x.Name))
73+
.ExceptBy(updateRoles.Select(roleModel => roleModel.Name), role => role.Name)
74+
.IfAnyAwait(rolesToDelete =>
75+
keycloak.RemoveClientRolesFromClientScopeForClientAsync(realm, clientScopeId, clientId, rolesToDelete, cancellationToken)).ConfigureAwait(false);
7576
}
7677
}

src/keycloak/Keycloak.Seeding/BusinessLogic/ClientScopesUpdater.cs

Lines changed: 49 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -22,37 +22,38 @@
2222
using Org.Eclipse.TractusX.Portal.Backend.Keycloak.Library;
2323
using Org.Eclipse.TractusX.Portal.Backend.Keycloak.Library.Models.ClientScopes;
2424
using Org.Eclipse.TractusX.Portal.Backend.Keycloak.Library.Models.ProtocolMappers;
25+
using Org.Eclipse.TractusX.Portal.Backend.Keycloak.Seeding.Extensions;
2526
using Org.Eclipse.TractusX.Portal.Backend.Keycloak.Seeding.Models;
2627

2728
namespace Org.Eclipse.TractusX.Portal.Backend.Keycloak.Seeding.BusinessLogic;
2829

29-
public class ClientScopesUpdater : IClientScopesUpdater
30+
public class ClientScopesUpdater(IKeycloakFactory keycloakFactory, ISeedDataHandler seedDataHandler)
31+
: IClientScopesUpdater
3032
{
31-
private readonly IKeycloakFactory _keycloakFactory;
32-
private readonly ISeedDataHandler _seedData;
33-
34-
public ClientScopesUpdater(IKeycloakFactory keycloakFactory, ISeedDataHandler seedDataHandler)
35-
{
36-
_keycloakFactory = keycloakFactory;
37-
_seedData = seedDataHandler;
38-
}
39-
4033
public async Task UpdateClientScopes(string instanceName, CancellationToken cancellationToken)
4134
{
42-
var keycloak = _keycloakFactory.CreateKeycloakClient(instanceName);
43-
var realm = _seedData.Realm;
35+
var keycloak = keycloakFactory.CreateKeycloakClient(instanceName);
36+
var realm = seedDataHandler.Realm;
37+
var seederConfig = seedDataHandler.GetSpecificConfiguration(ConfigurationKey.ClientScopes);
4438

4539
var clientScopes = await keycloak.GetClientScopesAsync(realm, cancellationToken).ConfigureAwait(ConfigureAwaitOptions.None);
46-
var seedClientScopes = _seedData.ClientScopes;
40+
var seedClientScopes = seedDataHandler.ClientScopes;
4741

48-
await RemoveObsoleteClientScopes(keycloak, realm, clientScopes, seedClientScopes, cancellationToken).ConfigureAwait(ConfigureAwaitOptions.None);
49-
await CreateMissingClientScopes(keycloak, realm, clientScopes, seedClientScopes, cancellationToken).ConfigureAwait(ConfigureAwaitOptions.None);
50-
await UpdateExistingClientScopes(keycloak, realm, clientScopes, seedClientScopes, cancellationToken).ConfigureAwait(ConfigureAwaitOptions.None);
42+
await CheckAndExecute(ModificationType.Delete, keycloak, realm, clientScopes, seedClientScopes, seederConfig, cancellationToken, RemoveObsoleteClientScopes).ConfigureAwait(ConfigureAwaitOptions.None);
43+
await CheckAndExecute(ModificationType.Create, keycloak, realm, clientScopes, seedClientScopes, seederConfig, cancellationToken, CreateMissingClientScopes).ConfigureAwait(ConfigureAwaitOptions.None);
44+
await CheckAndExecute(ModificationType.Update, keycloak, realm, clientScopes, seedClientScopes, seederConfig, cancellationToken, UpdateExistingClientScopes).ConfigureAwait(ConfigureAwaitOptions.None);
5145
}
5246

53-
private static async Task RemoveObsoleteClientScopes(KeycloakClient keycloak, string realm, IEnumerable<ClientScope> clientScopes, IEnumerable<ClientScopeModel> seedClientScopes, CancellationToken cancellationToken)
47+
private static Task CheckAndExecute(ModificationType modificationType, KeycloakClient keycloak, string realm, IEnumerable<ClientScope> clientScopes, IEnumerable<ClientScopeModel> seedClientScopes, KeycloakSeederConfigModel seederConfig, CancellationToken cancellationToken, Func<KeycloakClient, string, IEnumerable<ClientScope>, IEnumerable<ClientScopeModel>, KeycloakSeederConfigModel, CancellationToken, Task> executeLogic) =>
48+
seederConfig.ModificationAllowed(modificationType)
49+
? executeLogic(keycloak, realm, clientScopes, seedClientScopes, seederConfig, cancellationToken)
50+
: Task.CompletedTask;
51+
52+
private static async Task RemoveObsoleteClientScopes(KeycloakClient keycloak, string realm, IEnumerable<ClientScope> clientScopes, IEnumerable<ClientScopeModel> seedClientScopes, KeycloakSeederConfigModel seederConfig, CancellationToken cancellationToken)
5453
{
55-
foreach (var deleteScope in clientScopes.ExceptBy(seedClientScopes.Select(x => x.Name), x => x.Name))
54+
foreach (var deleteScope in clientScopes
55+
.Where(x => seederConfig.ModificationAllowed(ModificationType.Delete, x.Name))
56+
.ExceptBy(seedClientScopes.Select(x => x.Name), x => x.Name))
5657
{
5758
await keycloak.DeleteClientScopeAsync(
5859
realm,
@@ -61,32 +62,38 @@ await keycloak.DeleteClientScopeAsync(
6162
}
6263
}
6364

64-
private static async Task CreateMissingClientScopes(KeycloakClient keycloak, string realm, IEnumerable<ClientScope> clientScopes, IEnumerable<ClientScopeModel> seedClientScopes, CancellationToken cancellationToken)
65+
private static async Task CreateMissingClientScopes(KeycloakClient keycloak, string realm, IEnumerable<ClientScope> clientScopes, IEnumerable<ClientScopeModel> seedClientScopes, KeycloakSeederConfigModel seederConfig, CancellationToken cancellationToken)
6566
{
66-
foreach (var addScope in seedClientScopes.ExceptBy(clientScopes.Select(x => x.Name), x => x.Name))
67+
foreach (var addScope in seedClientScopes
68+
.Where(x => seederConfig.ModificationAllowed(ModificationType.Create, x.Name))
69+
.ExceptBy(clientScopes.Select(x => x.Name), x => x.Name))
6770
{
6871
await keycloak.CreateClientScopeAsync(realm, CreateClientScope(null, addScope, true), cancellationToken).ConfigureAwait(ConfigureAwaitOptions.None);
6972
}
7073
}
7174

72-
private static async Task UpdateExistingClientScopes(KeycloakClient keycloak, string realm, IEnumerable<ClientScope> clientScopes, IEnumerable<ClientScopeModel> seedClientScopes, CancellationToken cancellationToken)
75+
private static async Task UpdateExistingClientScopes(KeycloakClient keycloak, string realm, IEnumerable<ClientScope> clientScopes, IEnumerable<ClientScopeModel> seedClientScopes, KeycloakSeederConfigModel seederConfig, CancellationToken cancellationToken)
7376
{
7477
foreach (var (clientScope, update) in clientScopes
78+
.Where(x => seederConfig.ModificationAllowed(ModificationType.Update, x.Name))
7579
.Join(
7680
seedClientScopes,
7781
x => x.Name,
7882
x => x.Name,
7983
(clientScope, update) => (ClientScope: clientScope, Update: update)))
8084
{
81-
await UpdateClientScopeWithProtocolMappers(keycloak, realm, clientScope, update, cancellationToken).ConfigureAwait(ConfigureAwaitOptions.None);
85+
await UpdateClientScopeWithProtocolMappers(keycloak, realm, clientScope, update, seederConfig, cancellationToken).ConfigureAwait(ConfigureAwaitOptions.None);
8286
}
8387
}
8488

85-
private static async Task UpdateClientScopeWithProtocolMappers(KeycloakClient keycloak, string realm, ClientScope clientScope, ClientScopeModel update, CancellationToken cancellationToken)
89+
private static async Task UpdateClientScopeWithProtocolMappers(KeycloakClient keycloak, string realm, ClientScope clientScope, ClientScopeModel update, KeycloakSeederConfigModel seederConfig, CancellationToken cancellationToken)
8690
{
8791
if (clientScope.Id == null)
8892
throw new ConflictException($"clientScope.Id is null: {clientScope.Name}");
8993

94+
if (clientScope.Name == null)
95+
throw new ConflictException($"clientScope.Name is null: {clientScope.Name}");
96+
9097
if (!CompareClientScope(clientScope, update))
9198
{
9299
await keycloak.UpdateClientScopeAsync(
@@ -99,14 +106,16 @@ await keycloak.UpdateClientScopeAsync(
99106
var mappers = clientScope.ProtocolMappers ?? Enumerable.Empty<ProtocolMapper>();
100107
var updateMappers = update.ProtocolMappers ?? Enumerable.Empty<ProtocolMapperModel>();
101108

102-
await DeleteObsoleteProtocolMappers(keycloak, realm, clientScope.Id, mappers, updateMappers, cancellationToken).ConfigureAwait(ConfigureAwaitOptions.None);
103-
await CreateMissingProtocolMappers(keycloak, realm, clientScope.Id, mappers, updateMappers, cancellationToken).ConfigureAwait(ConfigureAwaitOptions.None);
104-
await UpdateExistingProtocolMappers(keycloak, realm, clientScope.Id, mappers, updateMappers, cancellationToken).ConfigureAwait(ConfigureAwaitOptions.None);
109+
await DeleteObsoleteProtocolMappers(keycloak, realm, clientScope.Name, clientScope.Id, mappers, updateMappers, seederConfig, cancellationToken).ConfigureAwait(ConfigureAwaitOptions.None);
110+
await CreateMissingProtocolMappers(keycloak, realm, clientScope.Name, clientScope.Id, mappers, updateMappers, seederConfig, cancellationToken).ConfigureAwait(ConfigureAwaitOptions.None);
111+
await UpdateExistingProtocolMappers(keycloak, realm, clientScope.Name, clientScope.Id, mappers, updateMappers, seederConfig, cancellationToken).ConfigureAwait(ConfigureAwaitOptions.None);
105112
}
106113

107-
private static async Task DeleteObsoleteProtocolMappers(KeycloakClient keycloak, string realm, string clientScopeId, IEnumerable<ProtocolMapper> mappers, IEnumerable<ProtocolMapperModel> updateMappers, CancellationToken cancellationToken)
114+
private static async Task DeleteObsoleteProtocolMappers(KeycloakClient keycloak, string realm, string clientScopeName, string clientScopeId, IEnumerable<ProtocolMapper> mappers, IEnumerable<ProtocolMapperModel> updateMappers, KeycloakSeederConfigModel seederConfig, CancellationToken cancellationToken)
108115
{
109-
foreach (var mapper in mappers.ExceptBy(updateMappers.Select(x => x.Name), x => x.Name))
116+
foreach (var mapper in mappers
117+
.Where(x => seederConfig.ModificationAllowed(clientScopeName, ConfigurationKey.ProtocolMappers, ModificationType.Delete, x.Name))
118+
.ExceptBy(updateMappers.Select(x => x.Name), x => x.Name))
110119
{
111120
await keycloak.DeleteProtocolMapperAsync(
112121
realm,
@@ -116,9 +125,11 @@ await keycloak.DeleteProtocolMapperAsync(
116125
}
117126
}
118127

119-
private static async Task CreateMissingProtocolMappers(KeycloakClient keycloak, string realm, string clientScopeId, IEnumerable<ProtocolMapper> mappers, IEnumerable<ProtocolMapperModel> updateMappers, CancellationToken cancellationToken)
128+
private static async Task CreateMissingProtocolMappers(KeycloakClient keycloak, string realm, string clientScopeName, string clientScopeId, IEnumerable<ProtocolMapper> mappers, IEnumerable<ProtocolMapperModel> updateMappers, KeycloakSeederConfigModel seederConfig, CancellationToken cancellationToken)
120129
{
121-
foreach (var update in updateMappers.ExceptBy(mappers.Select(x => x.Name), x => x.Name))
130+
foreach (var update in updateMappers
131+
.Where(x => seederConfig.ModificationAllowed(clientScopeName, ConfigurationKey.ProtocolMappers, ModificationType.Create, x.Name))
132+
.ExceptBy(mappers.Select(x => x.Name), x => x.Name))
122133
{
123134
await keycloak.CreateProtocolMapperAsync(
124135
realm,
@@ -128,13 +139,15 @@ await keycloak.CreateProtocolMapperAsync(
128139
}
129140
}
130141

131-
private static async Task UpdateExistingProtocolMappers(KeycloakClient keycloak, string realm, string clientScopeId, IEnumerable<ProtocolMapper> mappers, IEnumerable<ProtocolMapperModel> updateMappers, CancellationToken cancellationToken)
142+
private static async Task UpdateExistingProtocolMappers(KeycloakClient keycloak, string realm, string clientScopeName, string clientScopeId, IEnumerable<ProtocolMapper> mappers, IEnumerable<ProtocolMapperModel> updateMappers, KeycloakSeederConfigModel seederConfig, CancellationToken cancellationToken)
132143
{
133-
foreach (var (mapper, update) in mappers.Join(
134-
updateMappers,
135-
x => x.Name,
136-
x => x.Name,
137-
(mapper, update) => (Mapper: mapper, Update: update))
144+
foreach (var (mapper, update) in mappers
145+
.Where(x => seederConfig.ModificationAllowed(clientScopeName, ConfigurationKey.ProtocolMappers, ModificationType.Update, x.Name))
146+
.Join(
147+
updateMappers,
148+
x => x.Name,
149+
x => x.Name,
150+
(mapper, update) => (Mapper: mapper, Update: update))
138151
.Where(x => !ProtocolMappersUpdater.CompareProtocolMapper(x.Mapper, x.Update)))
139152
{
140153
await keycloak.UpdateProtocolMapperAsync(

0 commit comments

Comments
 (0)