Skip to content

Commit e971368

Browse files
committed
Refactor update client and update tests. Add E2E test for token validation
1 parent f373a5b commit e971368

File tree

13 files changed

+228
-56
lines changed

13 files changed

+228
-56
lines changed

src/config/backend/EdFi.DmsConfigurationService.Backend.Keycloak/KeycloakClientRepository.cs

Lines changed: 45 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -185,10 +185,9 @@ public async Task<ClientClientsResult> GetAllClientsAsync()
185185

186186
private async Task CheckAndCreateClientScopeAsync(string scope)
187187
{
188-
var clientScopes = await _keycloakClient.GetClientScopesAsync(_realm);
189-
ClientScope? clientScope = clientScopes.FirstOrDefault(x => x.Name.Equals(scope));
188+
bool scopeExists = await ClientScopeExistsAsync(scope);
190189

191-
if (clientScope is null)
190+
if (!scopeExists)
192191
{
193192
await _keycloakClient.CreateClientScopeAsync(
194193
_realm,
@@ -218,6 +217,13 @@ await _keycloakClient.CreateClientScopeAsync(
218217
}
219218
}
220219

220+
private async Task<bool> ClientScopeExistsAsync(string scope)
221+
{
222+
var clientScopes = await _keycloakClient.GetClientScopesAsync(_realm);
223+
ClientScope? clientScope = clientScopes.FirstOrDefault(x => x.Name.Equals(scope));
224+
return clientScope != null;
225+
}
226+
221227
private static IdentityProviderError ExceptionToKeycloakError(FlurlHttpException ex)
222228
{
223229
return ex.StatusCode switch
@@ -241,16 +247,44 @@ string scope
241247
var client = await _keycloakClient.GetClientAsync(_realm, clientUuid);
242248
if (client != null)
243249
{
244-
client.Name = displayName;
245-
client.DefaultClientScopes = [scope];
246250
await CheckAndCreateClientScopeAsync(scope);
247-
await _keycloakClient.UpdateClientAsync(_realm, clientUuid, client);
248-
return new ClientUpdateResult.Success();
249-
}
250-
else
251-
{
252-
return new ClientUpdateResult.FailureNotFound($"Client {clientUuid} not found.");
251+
var scopeExists = await ClientScopeExistsAsync(scope);
252+
if (scopeExists)
253+
{
254+
// Delete the existing client
255+
await _keycloakClient.DeleteClientAsync(_realm, clientUuid);
256+
Client newClient = new()
257+
{
258+
ClientId = client.ClientId,
259+
Enabled = true,
260+
Secret = client.Secret,
261+
Name = displayName,
262+
ServiceAccountsEnabled = true,
263+
DefaultClientScopes = [scope],
264+
ProtocolMappers = client.ProtocolMappers,
265+
};
266+
// Re-create the client
267+
string? newClientId = await _keycloakClient.CreateClientAndRetrieveClientIdAsync(
268+
_realm,
269+
newClient
270+
);
271+
if (!string.IsNullOrEmpty(newClientId))
272+
{
273+
return new ClientUpdateResult.Success(Guid.Parse(newClientId));
274+
}
275+
}
276+
else
277+
{
278+
var scopeNotFound = $"Scope {scope} not found";
279+
logger.LogError(message: scopeNotFound);
280+
return new ClientUpdateResult.FailureIdentityProvider(
281+
new IdentityProviderError(scopeNotFound)
282+
);
283+
}
253284
}
285+
286+
logger.LogError("Update client failure");
287+
return new ClientUpdateResult.FailureUnknown($"Error while updating the client: {displayName}");
254288
}
255289
catch (FlurlHttpException ex)
256290
{

src/config/backend/EdFi.DmsConfigurationService.Backend.Postgresql.Test.Integration/ApplicationTests.cs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,10 @@ public async Task Should_get_and_failure_reference_not_found_and_invalid_vendor_
179179
EducationOrganizationIds = [],
180180
};
181181

182-
var applicationUpdateResult = await _applicationRepository.UpdateApplication(applicationUpdate);
182+
var applicationUpdateResult = await _applicationRepository.UpdateApplication(
183+
applicationUpdate,
184+
new ApiClientCommand { ClientId = Guid.NewGuid().ToString(), ClientUuid = Guid.NewGuid() }
185+
);
183186
applicationUpdateResult.Should().BeOfType<ApplicationUpdateResult.FailureVendorNotFound>();
184187
}
185188
}
@@ -235,7 +238,8 @@ public async Task SetUp()
235238
ClaimSetName = command.ClaimSetName,
236239
EducationOrganizationIds = command.EducationOrganizationIds,
237240
VendorId = command.VendorId,
238-
}
241+
},
242+
new ApiClientCommand { ClientId = Guid.NewGuid().ToString(), ClientUuid = Guid.NewGuid() }
239243
);
240244
vendorUpdateResult.Should().BeOfType<ApplicationUpdateResult.Success>();
241245
}

src/config/backend/EdFi.DmsConfigurationService.Backend.Postgresql.Test.Integration/ClaimSetTests.cs

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ public class InsertTest : ClaimSetTests
2727
[SetUp]
2828
public async Task Setup()
2929
{
30-
ClaimSetInsertCommand claimSet = new() { Name = "Test ClaimSet" };
30+
ClaimSetInsertCommand claimSet = new() { Name = "Test-ClaimSet" };
3131

3232
var result = await _repository.InsertClaimSet(claimSet);
3333
result.Should().BeOfType<ClaimSetInsertResult.Success>();
@@ -49,7 +49,7 @@ public async Task Should_get_test_claimSet_from_get_all()
4949
claimSetFromDb.Should().BeOfType<ClaimSetResponseReduced>();
5050

5151
var reducedResponse = (ClaimSetResponseReduced)claimSetFromDb;
52-
reducedResponse.Name.Should().Be("Test ClaimSet");
52+
reducedResponse.Name.Should().Be("Test-ClaimSet");
5353
}
5454

5555
[Test]
@@ -62,13 +62,13 @@ public async Task Should_get_test_claimSet_from_get_by_id()
6262
claimSetFromDb.Should().BeOfType<ClaimSetResponseReduced>();
6363

6464
var reducedResponse = (ClaimSetResponseReduced)claimSetFromDb;
65-
reducedResponse.Name.Should().Be("Test ClaimSet");
65+
reducedResponse.Name.Should().Be("Test-ClaimSet");
6666
}
6767

6868
[Test]
6969
public async Task Should_get_duplicate_failure()
7070
{
71-
ClaimSetInsertCommand claimSetDup = new() { Name = "Test ClaimSet" };
71+
ClaimSetInsertCommand claimSetDup = new() { Name = "Test-ClaimSet" };
7272

7373
var resultDup = await _repository.InsertClaimSet(claimSetDup);
7474
resultDup.Should().BeOfType<ClaimSetInsertResult.FailureDuplicateClaimSetName>();
@@ -84,15 +84,15 @@ public class UpdateTests : ClaimSetTests
8484
[SetUp]
8585
public async Task Setup()
8686
{
87-
_insertClaimSet = new ClaimSetInsertCommand() { Name = "Test Insert ClaimSet" };
87+
_insertClaimSet = new ClaimSetInsertCommand() { Name = "Test-Insert-ClaimSet" };
8888

89-
_updateClaimSet = new ClaimSetUpdateCommand() { Name = "Test Update ClaimSet" };
89+
_updateClaimSet = new ClaimSetUpdateCommand() { Name = "Test-Update-ClaimSet" };
9090

9191
var insertResult = await _repository.InsertClaimSet(_insertClaimSet);
9292
insertResult.Should().BeOfType<ClaimSetInsertResult.Success>();
9393

9494
_updateClaimSet.Id = (insertResult as ClaimSetInsertResult.Success)!.Id;
95-
_updateClaimSet.Name = "Test Update ClaimSet";
95+
_updateClaimSet.Name = "Test-Update-ClaimSet";
9696

9797
var updateResult = await _repository.UpdateClaimSet(_updateClaimSet);
9898
updateResult.Should().BeOfType<ClaimSetUpdateResult.Success>();
@@ -112,7 +112,7 @@ public async Task Should_get_update_claimSet_from_get_all()
112112
claimSetFromDb.Should().BeOfType<ClaimSetResponseReduced>();
113113

114114
var reducedResponse = (ClaimSetResponseReduced)claimSetFromDb;
115-
reducedResponse.Name.Should().Be("Test Update ClaimSet");
115+
reducedResponse.Name.Should().Be("Test-Update-ClaimSet");
116116
}
117117

118118
[Test]
@@ -125,7 +125,7 @@ public async Task Should_get_test_claimSet_from_get_by_id()
125125
claimSetFromDb.Should().BeOfType<ClaimSetResponseReduced>();
126126

127127
var reducedResponse = (ClaimSetResponseReduced)claimSetFromDb;
128-
reducedResponse.Name.Should().Be("Test Update ClaimSet");
128+
reducedResponse.Name.Should().Be("Test-Update-ClaimSet");
129129
}
130130
}
131131

@@ -139,12 +139,12 @@ public class DeleteTests : ClaimSetTests
139139
public async Task Setup()
140140
{
141141
var insertResult1 = await _repository.InsertClaimSet(
142-
new ClaimSetInsertCommand() { Name = "Test One" }
142+
new ClaimSetInsertCommand() { Name = "Test-One" }
143143
);
144144
_id1 = ((ClaimSetInsertResult.Success)insertResult1).Id;
145145

146146
var insertResult2 = await _repository.InsertClaimSet(
147-
new ClaimSetInsertCommand() { Name = "Test Two" }
147+
new ClaimSetInsertCommand() { Name = "Test-Two" }
148148
);
149149
_id2 = ((ClaimSetInsertResult.Success)insertResult2).Id;
150150

@@ -180,7 +180,7 @@ public class ExportTest : ClaimSetTests
180180
[SetUp]
181181
public async Task Setup()
182182
{
183-
ClaimSetInsertCommand claimSet = new() { Name = "Test Export ClaimSet" };
183+
ClaimSetInsertCommand claimSet = new() { Name = "Test-Export-ClaimSet" };
184184

185185
var result = await _repository.InsertClaimSet(claimSet);
186186
result.Should().BeOfType<ClaimSetInsertResult.Success>();
@@ -195,7 +195,7 @@ public async Task Should_export_claimSet()
195195
result.Should().BeOfType<ClaimSetExportResult.Success>();
196196

197197
var valueFromDb = ((ClaimSetExportResult.Success)result).ClaimSetExportResponse;
198-
valueFromDb.Name.Should().Be("Test Export ClaimSet");
198+
valueFromDb.Name.Should().Be("Test-Export-ClaimSet");
199199
}
200200
}
201201

@@ -233,7 +233,7 @@ public async Task Setup()
233233

234234
ClaimSetImportCommand claimSet = new()
235235
{
236-
Name = "Test Import ClaimSet",
236+
Name = "Test-Import-ClaimSet",
237237
ResourceClaims = resourceClaims,
238238
};
239239

@@ -262,7 +262,7 @@ public async Task Should_get_test_claimSet_from_get_by_id()
262262
claimSetFromDb.Should().BeOfType<ClaimSetResponse>();
263263

264264
var response = (ClaimSetResponse)claimSetFromDb;
265-
response.Name.Should().Be("Test Import ClaimSet");
265+
response.Name.Should().Be("Test-Import-ClaimSet");
266266
response.ResourceClaims.Should().NotBeNull();
267267
}
268268

@@ -295,7 +295,7 @@ public async Task Should_get_duplicate_failure()
295295

296296
ClaimSetImportCommand claimSetDup = new()
297297
{
298-
Name = "Test Import ClaimSet",
298+
Name = "Test-Import-ClaimSet",
299299
ResourceClaims = resourceClaims,
300300
};
301301

@@ -313,14 +313,14 @@ public class CopyTest : ClaimSetTests
313313
[SetUp]
314314
public async Task Setup()
315315
{
316-
ClaimSetInsertCommand claimSet = new() { Name = "Original ClaimSet" };
316+
ClaimSetInsertCommand claimSet = new() { Name = "Original-ClaimSet" };
317317

318318
var result = await _repository.InsertClaimSet(claimSet);
319319
result.Should().BeOfType<ClaimSetInsertResult.Success>();
320320
_id = (result as ClaimSetInsertResult.Success)!.Id;
321321
_id.Should().BeGreaterThan(0);
322322

323-
ClaimSetCopyCommand command = new() { OriginalId = _id, Name = "Copy Test ClaimSet" };
323+
ClaimSetCopyCommand command = new() { OriginalId = _id, Name = "Copy-Test-ClaimSet" };
324324

325325
var copy = await _repository.Copy(command);
326326
copy.Should().BeOfType<ClaimSetCopyResult.Success>();
@@ -347,7 +347,7 @@ public async Task Should_get_claimSet_from_get_by_id()
347347
claimSetFromDb1.Should().BeOfType<ClaimSetResponseReduced>();
348348

349349
var reducedResponse1 = (ClaimSetResponseReduced)claimSetFromDb1;
350-
reducedResponse1.Name.Should().Be("Original ClaimSet");
350+
reducedResponse1.Name.Should().Be("Original-ClaimSet");
351351

352352
var getByIdResult2 = await _repository.GetClaimSet(_idCopy, false);
353353
getByIdResult2.Should().BeOfType<ClaimSetGetResult.Success>();
@@ -356,7 +356,7 @@ public async Task Should_get_claimSet_from_get_by_id()
356356
claimSetFromDb2.Should().BeOfType<ClaimSetResponseReduced>();
357357

358358
var reducedResponse2 = (ClaimSetResponseReduced)claimSetFromDb2;
359-
reducedResponse2.Name.Should().Be("Copy Test ClaimSet");
359+
reducedResponse2.Name.Should().Be("Copy-Test-ClaimSet");
360360
}
361361
}
362362
}

src/config/backend/EdFi.DmsConfigurationService.Backend.Postgresql/Repositories/ApplicationRepository.cs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ ILogger<ApplicationRepository> logger
2121
{
2222
public async Task<ApplicationInsertResult> InsertApplication(
2323
ApplicationInsertCommand command,
24-
ApiClientInsertCommand clientCommand
24+
ApiClientCommand clientCommand
2525
)
2626
{
2727
await using var connection = new NpgsqlConnection(databaseOptions.Value.DatabaseConnection);
@@ -174,7 +174,10 @@ FROM dmscs.Application a
174174
}
175175
}
176176

177-
public async Task<ApplicationUpdateResult> UpdateApplication(ApplicationUpdateCommand command)
177+
public async Task<ApplicationUpdateResult> UpdateApplication(
178+
ApplicationUpdateCommand command,
179+
ApiClientCommand clientCommand
180+
)
178181
{
179182
await using var connection = new NpgsqlConnection(databaseOptions.Value.DatabaseConnection);
180183
await connection.OpenAsync();
@@ -209,6 +212,14 @@ INSERT INTO dmscs.ApplicationEducationOrganization (ApplicationId, EducationOrga
209212
});
210213

211214
await connection.ExecuteAsync(sql, educationOrganizations);
215+
216+
string updateApiClientsql = """
217+
UPDATE dmscs.ApiClient
218+
SET ClientUuid=@ClientUuid WHERE ClientId = @ClientId;
219+
""";
220+
221+
await connection.ExecuteAsync(updateApiClientsql, clientCommand);
222+
212223
await transaction.CommitAsync();
213224

214225
return new ApplicationUpdateResult.Success();

src/config/backend/EdFi.DmsConfigurationService.Backend/Repositories/IApplicationRepository.cs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
// The Ed-Fi Alliance licenses this file to you under the Apache License, Version 2.0.
44
// See the LICENSE and NOTICES files in the project root for more information.
55

6-
using EdFi.DmsConfigurationService.DataModel;
76
using EdFi.DmsConfigurationService.DataModel.Model;
87
using EdFi.DmsConfigurationService.DataModel.Model.Application;
98

@@ -13,11 +12,14 @@ public interface IApplicationRepository
1312
{
1413
Task<ApplicationInsertResult> InsertApplication(
1514
ApplicationInsertCommand command,
16-
ApiClientInsertCommand clientCommand
15+
ApiClientCommand clientCommand
1716
);
1817
Task<ApplicationQueryResult> QueryApplication(PagingQuery query);
1918
Task<ApplicationGetResult> GetApplication(long id);
20-
Task<ApplicationUpdateResult> UpdateApplication(ApplicationUpdateCommand command);
19+
Task<ApplicationUpdateResult> UpdateApplication(
20+
ApplicationUpdateCommand command,
21+
ApiClientCommand clientCommand
22+
);
2123
Task<ApplicationDeleteResult> DeleteApplication(long id);
2224
Task<ApplicationApiClientsResult> GetApplicationApiClients(long id);
2325
}

src/config/backend/EdFi.DmsConfigurationService.Backend/Repositories/IClientRepository.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ public record FailureUnknown(string FailureMessage) : ClientResetResult();
5353

5454
public record ClientUpdateResult
5555
{
56-
public record Success() : ClientUpdateResult;
56+
public record Success(Guid ClientUuid) : ClientUpdateResult;
5757

5858
public record FailureIdentityProvider(IdentityProviderError IdentityProviderError) : ClientUpdateResult();
5959

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
namespace EdFi.DmsConfigurationService.DataModel.Model.Application;
77

8-
public class ApiClientInsertCommand
8+
public class ApiClientCommand
99
{
1010
public required string ClientId { get; set; }
1111
public required Guid ClientUuid { get; set; }

0 commit comments

Comments
 (0)