Skip to content

Commit 4e988af

Browse files
FrostyApeOneFrostyApeOne
authored andcommitted
Simplified auto registration handler service registration and removed stale user roles from the OBO token
1 parent cdd3a6e commit 4e988af

File tree

4 files changed

+28
-35
lines changed

4 files changed

+28
-35
lines changed

src/DfE.ExternalApplications.Application/Users/Queries/ExchangeTokenQueryHandler.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,14 @@ public async Task<ExchangeTokenDto> Handle(ExchangeTokenQuery req, CancellationT
7575
// Merge Azure Entra service roles, avoiding duplicates
7676
foreach (var svcRole in svcRoles)
7777
{
78+
var isExcludedRole =
79+
(svcRole.Type == ClaimTypes.Role || svcRole.Type == "roles") &&
80+
(svcRole.Value.Equals("Admin", StringComparison.OrdinalIgnoreCase) ||
81+
svcRole.Value.Equals("User", StringComparison.OrdinalIgnoreCase));
82+
83+
if (isExcludedRole)
84+
continue;
85+
7886
if (!identity.HasClaim(c => c.Type == svcRole.Type && c.Value == svcRole.Value))
7987
{
8088
identity.AddClaim(svcRole);

src/GovUK.Dfe.ExternalApplications.Api.Client/Extensions/ServiceCollectionExtensions.cs

Lines changed: 4 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -58,30 +58,15 @@ public static IServiceCollection AddExternalApplicationsApiClient<TClientInterfa
5858
serviceProvider.GetRequiredService<ITokenStateManager>(),
5959
serviceProvider.GetRequiredService<ILogger<TokenExchangeHandler>>());
6060
});
61-
61+
6262
// Register UserAutoRegistrationHandler for auto-registering new users
6363
if (apiSettings.AutoRegisterUsers)
6464
{
65-
// Register a dedicated IUsersClient for the auto-registration handler
66-
// This uses Azure token (not OBO) to call the register endpoint
67-
services.AddHttpClient<IUsersClient, UsersClient>("UsersClient_ForRegistration", (httpClient, serviceProvider) =>
68-
{
69-
httpClient.BaseAddress = new Uri(apiSettings.BaseUrl!);
70-
return ActivatorUtilities.CreateInstance<UsersClient>(
71-
serviceProvider, httpClient, apiSettings.BaseUrl!);
72-
})
73-
.AddHttpMessageHandler<AzureBearerTokenHandler>(); // Uses Azure token, not OBO
74-
65+
// Simple registration; the handler manually uses IHttpClientFactory and sets Azure token
7566
services.AddTransient<UserAutoRegistrationHandler>(serviceProvider =>
7667
{
77-
// Get the dedicated UsersClient for registration (with Azure token)
78-
var httpClientFactory = serviceProvider.GetRequiredService<IHttpClientFactory>();
79-
var httpClient = httpClientFactory.CreateClient("UsersClient_ForRegistration");
80-
var usersClient = ActivatorUtilities.CreateInstance<UsersClient>(
81-
serviceProvider, httpClient, apiSettings.BaseUrl!);
82-
8368
return new UserAutoRegistrationHandler(
84-
usersClient,
69+
serviceProvider.GetRequiredService<IHttpClientFactory>(),
8570
serviceProvider.GetRequiredService<ITokenStateManager>(),
8671
serviceProvider.GetRequiredService<ITokenAcquisitionService>(),
8772
serviceProvider.GetRequiredService<IHttpContextAccessor>(),
@@ -117,7 +102,7 @@ public static IServiceCollection AddExternalApplicationsApiClient<TClientInterfa
117102
{
118103
// Tokens client always uses Azure token (for exchange endpoint authentication)
119104
builder.AddHttpMessageHandler<AzureBearerTokenHandler>();
120-
105+
121106
// Add auto-registration handler BEFORE token exchange
122107
// This intercepts "user not found" errors and auto-registers the user
123108
if (apiSettings.AutoRegisterUsers)

src/GovUK.Dfe.ExternalApplications.Api.Client/Security/TokenExchangeHandler.cs

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,12 @@
1-
using System;
1+
using GovUK.Dfe.CoreLibs.Contracts.ExternalApplications.Models.Request;
2+
using GovUK.Dfe.CoreLibs.Http.Models;
3+
using GovUK.Dfe.ExternalApplications.Api.Client.Contracts;
4+
using Microsoft.AspNetCore.Http;
5+
using Microsoft.Extensions.Logging;
26
using System.Diagnostics.CodeAnalysis;
37
using System.Net;
4-
using System.Net.Http;
58
using System.Text;
69
using System.Text.Json;
7-
using System.Threading;
8-
using System.Threading.Tasks;
9-
using Microsoft.AspNetCore.Authentication;
10-
using Microsoft.AspNetCore.Http;
11-
using Microsoft.Extensions.Logging;
12-
using GovUK.Dfe.CoreLibs.Http.Models;
13-
using GovUK.Dfe.CoreLibs.Contracts.ExternalApplications.Models.Request;
14-
using GovUK.Dfe.ExternalApplications.Api.Client.Contracts;
1510

1611
namespace GovUK.Dfe.ExternalApplications.Api.Client.Security;
1712

src/GovUK.Dfe.ExternalApplications.Api.Client/Security/UserAutoRegistrationHandler.cs

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
using GovUK.Dfe.CoreLibs.Http.Models;
1414
using GovUK.Dfe.CoreLibs.Contracts.ExternalApplications.Models.Request;
1515
using GovUK.Dfe.ExternalApplications.Api.Client.Contracts;
16+
using System.Net.Http.Headers;
1617
using GovUK.Dfe.ExternalApplications.Api.Client.Settings;
1718

1819
namespace GovUK.Dfe.ExternalApplications.Api.Client.Security;
@@ -24,7 +25,7 @@ namespace GovUK.Dfe.ExternalApplications.Api.Client.Security;
2425
[ExcludeFromCodeCoverage]
2526
public class UserAutoRegistrationHandler : DelegatingHandler
2627
{
27-
private readonly IUsersClient _usersClient;
28+
private readonly IHttpClientFactory _httpClientFactory;
2829
private readonly ITokenStateManager _tokenStateManager;
2930
private readonly ITokenAcquisitionService _tokenAcquisitionService;
3031
private readonly IHttpContextAccessor _httpContextAccessor;
@@ -33,14 +34,14 @@ public class UserAutoRegistrationHandler : DelegatingHandler
3334
private readonly SemaphoreSlim _registrationLock = new(1, 1);
3435

3536
public UserAutoRegistrationHandler(
36-
IUsersClient usersClient,
37+
IHttpClientFactory httpClientFactory,
3738
ITokenStateManager tokenStateManager,
3839
ITokenAcquisitionService tokenAcquisitionService,
3940
IHttpContextAccessor httpContextAccessor,
4041
ApiClientSettings settings,
4142
ILogger<UserAutoRegistrationHandler> logger)
4243
{
43-
_usersClient = usersClient;
44+
_httpClientFactory = httpClientFactory;
4445
_tokenStateManager = tokenStateManager;
4546
_tokenAcquisitionService = tokenAcquisitionService;
4647
_httpContextAccessor = httpContextAccessor;
@@ -184,9 +185,13 @@ private async Task<bool> TryAutoRegisterUserAsync(CancellationToken cancellation
184185
TemplateId = templateId.Value
185186
};
186187

187-
// Call the register endpoint
188-
// Note: IUsersClient is configured with AzureBearerTokenHandler, so it will use the Azure token
189-
var result = await _usersClient.RegisterUserAsync(registerRequest, cancellationToken);
188+
// Call the register endpoint using a local client with Azure token only for this request
189+
var client = _httpClientFactory.CreateClient();
190+
client.BaseAddress = new Uri(_settings.BaseUrl!);
191+
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", azureToken);
192+
193+
var usersClient = new UsersClient(_settings.BaseUrl!, client);
194+
var result = await usersClient.RegisterUserAsync(registerRequest, cancellationToken);
190195

191196
_logger.LogInformation("User auto-registered successfully: {UserId} - {Email}",
192197
result.UserId, result.Email);

0 commit comments

Comments
 (0)