Skip to content

Commit

Permalink
LNK-2926: Anonymous Access Fix DEV (#528)
Browse files Browse the repository at this point in the history
### 🛠 Description of Changes

Please provide a high-level overview of the changes included in this PR.

### 🧪 Testing Performed

Please describe the testing that was performed on the changes included
in this PR.


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- **New Features**
- Enhanced configuration options for LinkBearerService, allowing
flexible setup for authentication.
- Conditional logic for token retrieval based on anonymous access
settings.

- **Bug Fixes**
- Improved error handling for missing signing keys when anonymous access
is not allowed.

- **Documentation**
- Updated environment variables in the `docker-compose.yml` for the
`bff` service to reflect changes in token generation settings.

- **Tests**
- Added support for mocking LinkBearerServiceOptions in tests to verify
authentication scenarios.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
  • Loading branch information
seanmcilvenna authored Oct 30, 2024
2 parents 7494f73 + 1666e2e commit 938f422
Show file tree
Hide file tree
Showing 5 changed files with 45 additions and 22 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ public static IServiceCollection AddLinkBearerServiceAuthentication(this IServic
options?.Invoke(linkBearerServiceOptions);

//add token commands
services.AddOptions<LinkBearerServiceOptions>().Configure(options);
services.AddTransient<ICreateSystemToken, CreateSystemToken>();
services.AddTransient<ICreateUserToken, CreateUserToken>();

Expand Down
24 changes: 18 additions & 6 deletions DotNet/Shared/Application/Services/TenantApiService.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using LantanaGroup.Link.Shared.Application.Interfaces.Services.Security.Token;
using LantanaGroup.Link.Shared.Application.Extensions.Security;
using LantanaGroup.Link.Shared.Application.Interfaces.Services.Security.Token;
using LantanaGroup.Link.Shared.Application.Models.Configs;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
Expand All @@ -15,14 +16,22 @@ public class TenantApiService : ITenantApiService
private readonly IOptions<ServiceRegistry> _serviceRegistry;
private readonly IOptions<LinkTokenServiceSettings> _linkTokenServiceConfig;
private readonly ICreateSystemToken _createSystemToken;
private readonly IOptions<BackendAuthenticationServiceExtension.LinkBearerServiceOptions> _linkBearerServiceOptions;

public TenantApiService(ILogger<TenantApiService> logger, IHttpClientFactory httpClientFactory, IOptions<ServiceRegistry> serviceRegistry, IOptions<LinkTokenServiceSettings> linkTokenServiceConfig, ICreateSystemToken createSystemToken)
public TenantApiService(
ILogger<TenantApiService> logger,
IHttpClientFactory httpClientFactory,
IOptions<ServiceRegistry> serviceRegistry,
IOptions<LinkTokenServiceSettings> linkTokenServiceConfig,
ICreateSystemToken createSystemToken,
IOptions<BackendAuthenticationServiceExtension.LinkBearerServiceOptions> linkBearerServiceOptions)
{
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
_httpClientFactory = httpClientFactory ?? throw new ArgumentNullException(nameof(httpClientFactory));
_serviceRegistry = serviceRegistry ?? throw new ArgumentNullException(nameof(serviceRegistry));
_linkTokenServiceConfig = linkTokenServiceConfig ?? throw new ArgumentNullException(nameof(linkTokenServiceConfig));
_createSystemToken = createSystemToken ?? throw new ArgumentNullException(nameof(createSystemToken));
_linkBearerServiceOptions = linkBearerServiceOptions ?? throw new ArgumentNullException(nameof(linkBearerServiceOptions));
}

public async Task<bool> CheckFacilityExists(string facilityId, CancellationToken cancellationToken = default)
Expand All @@ -49,13 +58,16 @@ public async Task<bool> CheckFacilityExists(string facilityId, CancellationToken
_logger.LogInformation("Checking if facility ({1}) exists in Tenant Service. Endpoint: {2}", sanitizedFacilityId, endpoint);

//TODO: add method to get key that includes looking at redis for future use case
if (_linkTokenServiceConfig.Value.SigningKey is null)
if (!_linkBearerServiceOptions.Value.AllowAnonymous && _linkTokenServiceConfig.Value.SigningKey is null)
throw new Exception("Link Token Service Signing Key is missing.");

//get link token
var token = await _createSystemToken.ExecuteAsync(_linkTokenServiceConfig.Value.SigningKey, 2);
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);

if (!_linkBearerServiceOptions.Value.AllowAnonymous)
{
var token = await _createSystemToken.ExecuteAsync(_linkTokenServiceConfig.Value.SigningKey, 2);
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
}

var response = await httpClient.GetAsync(endpoint, cancellationToken);

if (response.IsSuccessStatusCode)
Expand Down
26 changes: 13 additions & 13 deletions DotNet/Tenant/Services/FacilityConfigurationService.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using LantanaGroup.Link.Shared.Application.Interfaces;
using LantanaGroup.Link.Shared.Application.Enums;
using LantanaGroup.Link.Shared.Application.Enums;
using LantanaGroup.Link.Shared.Application.Models;
using LantanaGroup.Link.Shared.Application.Models.Configs;
using LantanaGroup.Link.Shared.Application.Models.Kafka;
Expand All @@ -17,9 +16,7 @@
using static LantanaGroup.Link.Tenant.Entities.ScheduledTaskModel;
using LantanaGroup.Link.Shared.Application.Interfaces.Services.Security.Token;
using LantanaGroup.Link.Shared.Application.Models.Responses;
using System.Linq.Expressions;
using Confluent.Kafka;

using static LantanaGroup.Link.Shared.Application.Extensions.Security.BackendAuthenticationServiceExtension;

namespace LantanaGroup.Link.Tenant.Services
{
Expand All @@ -35,6 +32,7 @@ public class FacilityConfigurationService
private readonly IOptions<MeasureConfig> _measureConfig;
private readonly IOptions<LinkTokenServiceSettings> _linkTokenServiceConfig;
private readonly ICreateSystemToken _createSystemToken;
private readonly IOptions<LinkBearerServiceOptions> _linkBearerServiceOptions;

static FacilityConfigurationService()
{
Expand All @@ -43,7 +41,7 @@ static FacilityConfigurationService()
}


public FacilityConfigurationService(IFacilityConfigurationRepo facilityConfigurationRepo, ILogger<FacilityConfigurationService> logger, CreateAuditEventCommand createAuditEventCommand, IOptions<ServiceRegistry> serviceRegistry, IOptions<MeasureConfig> measureConfig, HttpClient httpClient, IOptions<LinkTokenServiceSettings> linkTokenServiceConfig, ICreateSystemToken createSystemToken)
public FacilityConfigurationService(IFacilityConfigurationRepo facilityConfigurationRepo, ILogger<FacilityConfigurationService> logger, CreateAuditEventCommand createAuditEventCommand, IOptions<ServiceRegistry> serviceRegistry, IOptions<MeasureConfig> measureConfig, HttpClient httpClient, IOptions<LinkTokenServiceSettings> linkTokenServiceConfig, ICreateSystemToken createSystemToken, IOptions<LinkBearerServiceOptions> linkBearerServiceOptions)
{
_facilityConfigurationRepo = facilityConfigurationRepo;
_serviceRegistry = serviceRegistry ?? throw new ArgumentNullException(nameof(serviceRegistry));
Expand All @@ -53,6 +51,7 @@ public FacilityConfigurationService(IFacilityConfigurationRepo facilityConfigura
_createAuditEventCommand = createAuditEventCommand;
_linkTokenServiceConfig = linkTokenServiceConfig ?? throw new ArgumentNullException(nameof(linkTokenServiceConfig));
_createSystemToken = createSystemToken ?? throw new ArgumentNullException(nameof(createSystemToken));
_linkBearerServiceOptions = linkBearerServiceOptions ?? throw new ArgumentNullException(nameof(linkBearerServiceOptions));
}

public async Task<List<FacilityConfigModel>> GetAllFacilities(CancellationToken cancellationToken = default)
Expand Down Expand Up @@ -413,15 +412,16 @@ private async Task checkIfMeasureEvalExists(ReportTypeSchedule reportTypeSchedul

string requestUrl = _serviceRegistry.Value.MeasureServiceUrl + $"/api/measure-definition/{reportTypeSchedule.ReportType}";

//TODO: add method to get key that includes looking at redis for future use case
if (_linkTokenServiceConfig.Value.SigningKey is null)
throw new Exception("Link Token Service Signing Key is missing.");


//get link token
var token = await _createSystemToken.ExecuteAsync(_linkTokenServiceConfig.Value.SigningKey, 2);
if (!_linkBearerServiceOptions.Value.AllowAnonymous)
{
//TODO: add method to get key that includes looking at redis for future use case
if (_linkTokenServiceConfig.Value.SigningKey is null) throw new Exception("Link Token Service Signing Key is missing.");

var token = await _createSystemToken.ExecuteAsync(_linkTokenServiceConfig.Value.SigningKey, 2);
_httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
}

_httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
var response = _httpClient.GetAsync(requestUrl).Result;

// check respone status code
Expand Down
12 changes: 11 additions & 1 deletion DotNet/TenantTests/CreateFacilityConfigurationTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,15 @@
using Moq;
using Moq.AutoMock;
using static LantanaGroup.Link.Tenant.Entities.ScheduledTaskModel;
using static LantanaGroup.Link.Shared.Application.Extensions.Security.BackendAuthenticationServiceExtension;

namespace TenantTests
{
public class CreateFacilityConfigurationTests
{
private FacilityConfigModel? _model;
private ServiceRegistry? _serviceRegistry;
private LinkBearerServiceOptions _linkBearerServiceOptions;
private const string facilityId = "TestFacility_002";
private const string facilityName = "TestFacility_002";
private static readonly List<ScheduledTaskModel> scheduledTaskModels = new List<ScheduledTaskModel>();
Expand Down Expand Up @@ -52,9 +54,17 @@ public async Task TestCreateFacility()

_model.ScheduledTasks.AddRange(scheduledTaskModels);

_linkBearerServiceOptions = new LinkBearerServiceOptions()
{
AllowAnonymous = true
};

_mocker = new AutoMocker();

_service = _mocker.CreateInstance<FacilityConfigurationService>();
Mock<IOptions<LinkBearerServiceOptions>> _mockLinkBearerServiceOptions = _mocker.GetMock<IOptions<LinkBearerServiceOptions>>();
_mockLinkBearerServiceOptions.Setup(p => p.Value).Returns(_linkBearerServiceOptions);

_service = _mocker.CreateInstance<FacilityConfigurationService>();

_ = _mocker.GetMock<IFacilityConfigurationRepo>()
.Setup(p => p.AddAsync(_model, CancellationToken.None)).ReturnsAsync(_model);
Expand Down
4 changes: 2 additions & 2 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -406,8 +406,8 @@ services:
Cache__Enabled: true
EnableIntegrationFeature: true
ProblemDetails__IncludeExceptionDetails: false
LinkTokenService__EnableTokenGenerationEndpoint: true
LinkTokenService__Authority:
LinkTokenService__EnableTokenGenerationEndpoint: false
LinkTokenService__Authority: placeholder
LinkTokenService__LinkAdminEmail:
LinkTokenService__TokenLifeSpan: 10
Authentication__EnableAnonymousAccess: true
Expand Down

0 comments on commit 938f422

Please sign in to comment.