Skip to content

Commit

Permalink
Fixed - Organisation API Key Authorisation (#722)
Browse files Browse the repository at this point in the history
* Fixed - Organisation Api Key Authorisation

* Fixed unit test
  • Loading branch information
dharmverma authored Oct 7, 2024
1 parent 032ac6e commit d88a7d9
Show file tree
Hide file tree
Showing 7 changed files with 131 additions and 18 deletions.
Original file line number Diff line number Diff line change
@@ -1,24 +1,47 @@
using CO.CDP.Authentication;
using CO.CDP.OrganisationInformation.Persistence;
using CO.CDP.TestKit.Mvc;
using FluentAssertions;
using Microsoft.Extensions.DependencyInjection;
using Moq;
using Xunit.Abstractions;

namespace CO.CDP.DataSharing.WebApiClient.Tests;

public class DataSharingClientIntegrationTest(ITestOutputHelper testOutputHelper)
public class DataSharingClientIntegrationTest
{
private readonly TestWebApplicationFactory<Program> _factory = new(builder =>
private readonly Mock<IShareCodeRepository> _shareCodeRepository = new();
private readonly Mock<IClaimService> _claimService = new();

private readonly HttpClient _httpClient;

public DataSharingClientIntegrationTest(ITestOutputHelper testOutputHelper)
{
builder.ConfigureInMemoryDbContext<OrganisationInformationContext>();
builder.ConfigureLogging(testOutputHelper);
});
TestWebApplicationFactory<Program> _factory = new(builder =>
{
builder.ConfigureInMemoryDbContext<OrganisationInformationContext>();
builder.ConfigureLogging(testOutputHelper);
builder.ConfigureServices((_, s) =>
{
s.AddScoped(_ => _shareCodeRepository.Object);
s.AddScoped(_ => _claimService.Object);
});
});

_httpClient = _factory.CreateClient();
}

[Fact]
public async Task ItTalksToTheDataSharingApi()
{
IDataSharingClient client = new DataSharingClient("https://localhost", _factory.CreateClient());
IDataSharingClient client = new DataSharingClient("https://localhost", _httpClient);

var shareCode = "HDJ2123F";
var organisationId = Guid.NewGuid();
_claimService.Setup(c => c.GetOrganisationId()).Returns(organisationId);
_shareCodeRepository.Setup(s => s.OrganisationShareCodeExistsAsync(organisationId, shareCode)).ReturnsAsync(true);

Func<Task> act = async () => { await client.GetSharedDataAsync("HDJ2123F"); };
Func<Task> act = async () => { await client.GetSharedDataAsync(shareCode); };

var exception = await act.Should().ThrowAsync<ApiException<ProblemDetails>>();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,52 @@
using FluentAssertions;
using Moq;
using CO.CDP.DataSharing.WebApi.Extensions;
using CO.CDP.Authentication;

namespace CO.CDP.DataSharing.WebApi.Tests.UseCase;

public class GetShareCodeVerifyUseCaseTest() : IClassFixture<AutoMapperFixture>
public class GetShareCodeVerifyUseCaseTest : IClassFixture<AutoMapperFixture>
{
private readonly Mock<IFormRepository> _formRepository = new();
private readonly Mock<IShareCodeRepository> _shareCodeRepository = new();
private GetShareCodeVerifyUseCase UseCase => new(_shareCodeRepository.Object);
private readonly Mock<IClaimService> _claimService = new();
private GetShareCodeVerifyUseCase UseCase => new(_shareCodeRepository.Object, _claimService.Object);

[Fact]
public async Task ThrowsUserUnauthorizedException_WhenRequestedUserOrganisationAndShareCodeRequestedNotFound()
{
var shareCode = "dummy_code";

var organisationId = Guid.NewGuid();
_claimService.Setup(c => c.GetOrganisationId()).Returns(organisationId);
_shareCodeRepository.Setup(s => s.OrganisationShareCodeExistsAsync(organisationId, shareCode)).ReturnsAsync(false);

var response = async () => await UseCase.Execute(
new ShareVerificationRequest { FormVersionId = "1.0", ShareCode = shareCode });

await response.Should().ThrowAsync<UserUnauthorizedException>();
}

[Fact]
public async Task ThrowsUserUnauthorizedException_WhenRequestedUserOrganisationInNotInTheClaim()
{
_claimService.Setup(c => c.GetOrganisationId()).Returns((Guid?)null);

var response = async () => await UseCase.Execute(
new ShareVerificationRequest { FormVersionId = "1.0", ShareCode = "dummy_code" });

await response.Should().ThrowAsync<UserUnauthorizedException>();
}

[Fact]
public async Task ThrowsSharedConsentNotFoundException_WhenShareCodeRequestedNotFound()
{
var formVersionId = "default";
var shareCode = ShareCodeExtensions.GenerateShareCode();

var organisationId = Guid.NewGuid();
_claimService.Setup(c => c.GetOrganisationId()).Returns(organisationId);
_shareCodeRepository.Setup(s => s.OrganisationShareCodeExistsAsync(organisationId, shareCode)).ReturnsAsync(true);

var shareVerificationRequest = EntityFactory.GetShareVerificationRequest(formVersionId: formVersionId, shareCode: shareCode);

var response = async () => await UseCase.Execute(shareVerificationRequest);
Expand All @@ -33,6 +64,10 @@ public async Task ReturnsTrue_WhenShareVerificationRequestForValidExistingShareC
var formVersionId = "V1.0";
var shareCode = ShareCodeExtensions.GenerateShareCode();

var organisationId = Guid.NewGuid();
_claimService.Setup(c => c.GetOrganisationId()).Returns(organisationId);
_shareCodeRepository.Setup(s => s.OrganisationShareCodeExistsAsync(organisationId, shareCode)).ReturnsAsync(true);

var shareVerificationRequest = EntityFactory.GetShareVerificationRequest(formVersionId: formVersionId, shareCode: shareCode);

_shareCodeRepository.Setup(r => r.GetShareCodeVerifyAsync(shareVerificationRequest.FormVersionId, shareVerificationRequest.ShareCode)).ReturnsAsync(true);
Expand All @@ -41,8 +76,8 @@ public async Task ReturnsTrue_WhenShareVerificationRequestForValidExistingShareC

response.Should().NotBeNull();

response.As<CO.CDP.DataSharing.WebApi.Model.ShareVerificationReceipt>().ShareCode.Should().Be(shareVerificationRequest.ShareCode);
response.As<CO.CDP.DataSharing.WebApi.Model.ShareVerificationReceipt>().FormVersionId.Should().Be(shareVerificationRequest.FormVersionId);
response.As<CO.CDP.DataSharing.WebApi.Model.ShareVerificationReceipt>().IsLatest.Should().Be(true);
response.As<ShareVerificationReceipt>().ShareCode.Should().Be(shareVerificationRequest.ShareCode);
response.As<ShareVerificationReceipt>().FormVersionId.Should().Be(shareVerificationRequest.FormVersionId);
response.As<ShareVerificationReceipt>().IsLatest.Should().Be(true);
}
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using CO.CDP.Authentication;
using CO.CDP.DataSharing.WebApi.Model;
using CO.CDP.DataSharing.WebApi.Tests.AutoMapper;
using CO.CDP.DataSharing.WebApi.UseCase;
Expand All @@ -13,17 +14,46 @@ public class GetSharedDataUseCaseTest : IClassFixture<AutoMapperFixture>
{
private readonly Mock<IShareCodeRepository> _shareCodeRepository = new();
private readonly Mock<IOrganisationRepository> _organisationRepository = new();
private readonly Mock<IClaimService> _claimService = new();
private readonly GetSharedDataUseCase _useCase;

public GetSharedDataUseCaseTest(AutoMapperFixture mapperFixture)
{
_useCase = new GetSharedDataUseCase(_shareCodeRepository.Object, _organisationRepository.Object, mapperFixture.Mapper);
var organisationId = Guid.NewGuid();
_claimService.Setup(c => c.GetOrganisationId()).Returns(organisationId);
_shareCodeRepository.Setup(s => s.OrganisationShareCodeExistsAsync(organisationId, It.IsAny<string>())).ReturnsAsync(true);

_useCase = new GetSharedDataUseCase(_shareCodeRepository.Object, _organisationRepository.Object, _claimService.Object, mapperFixture.Mapper);
}

[Fact]
public async Task ThrowsUserUnauthorizedException_WhenRequestedUserOrganisationAndShareCodeRequestedNotFound()
{
var shareCode = "dummy_code";

var organisationId = Guid.NewGuid();
_claimService.Setup(c => c.GetOrganisationId()).Returns(organisationId);
_shareCodeRepository.Setup(s => s.OrganisationShareCodeExistsAsync(organisationId, shareCode)).ReturnsAsync(false);

var response = async () => await _useCase.Execute(shareCode);

await response.Should().ThrowAsync<UserUnauthorizedException>();
}

[Fact]
public async Task ThrowsUserUnauthorizedException_WhenRequestedUserOrganisationInNotInTheClaim()
{
_claimService.Setup(c => c.GetOrganisationId()).Returns((Guid?)null);

var response = async () => await _useCase.Execute("dummy_code");

await response.Should().ThrowAsync<UserUnauthorizedException>();
}

[Fact]
public async Task ItReturnsMappedSupplierInformationWhenSharedConsentIsFound()
{
var (shareCode, organisationId, organisationGuid, formId) = SetupTestData();
var (shareCode, _, organisationGuid, _) = SetupTestData();

var result = await _useCase.Execute(shareCode);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,23 @@
using CO.CDP.Authentication;
using CO.CDP.DataSharing.WebApi.Model;
using CO.CDP.OrganisationInformation.Persistence;

namespace CO.CDP.DataSharing.WebApi.UseCase;

public class GetShareCodeVerifyUseCase(
IShareCodeRepository shareCodeRepository)
IShareCodeRepository shareCodeRepository,
IClaimService claimService)
: IUseCase<ShareVerificationRequest,
ShareVerificationReceipt>
{
public async Task<ShareVerificationReceipt> Execute(ShareVerificationRequest shareRequest)
{
var organisationId = claimService.GetOrganisationId();
if (organisationId == null || await shareCodeRepository.OrganisationShareCodeExistsAsync(organisationId.Value, shareRequest.ShareCode) == false)
{
throw new UserUnauthorizedException();
}

var details = await shareCodeRepository.GetShareCodeVerifyAsync(shareRequest.FormVersionId, shareRequest.ShareCode);

if (details == null)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using AutoMapper;
using CO.CDP.Authentication;
using CO.CDP.DataSharing.WebApi.Model;
using CO.CDP.OrganisationInformation;
using CO.CDP.OrganisationInformation.Persistence;
Expand All @@ -9,11 +10,18 @@ namespace CO.CDP.DataSharing.WebApi.UseCase;
public class GetSharedDataUseCase(
IShareCodeRepository shareCodeRepository,
IOrganisationRepository organisationRepository,
IClaimService claimService,
IMapper mapper)
: IUseCase<string, SupplierInformation?>
{
public async Task<SupplierInformation?> Execute(string sharecode)
{
var organisationId = claimService.GetOrganisationId();
if (organisationId == null || await shareCodeRepository.OrganisationShareCodeExistsAsync(organisationId.Value, sharecode) == false)
{
throw new UserUnauthorizedException();
}

var sharedConsent = await shareCodeRepository.GetByShareCode(sharecode)
?? throw new ShareCodeNotFoundException(Constants.ShareCodeNotFoundExceptionMessage);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,13 @@ namespace CO.CDP.OrganisationInformation.Persistence;

public class DatabaseShareCodeRepository(OrganisationInformationContext context) : IShareCodeRepository
{
public async Task<bool> OrganisationShareCodeExistsAsync(Guid organisationId, string shareCode)
{
return await context.Set<SharedConsent>()
.Where(x => x.Organisation.Guid == organisationId && x.ShareCode == shareCode)
.AnyAsync();
}

public async Task<IEnumerable<SharedConsent>> GetShareCodesAsync(Guid organisationId)
{
return await context.Set<SharedConsent>()
Expand Down Expand Up @@ -89,7 +96,7 @@ join o in context.Organisations on s.OrganisationId equals o.Id
};
}

public async Task<Boolean?> GetShareCodeVerifyAsync(string formVersionId, string shareCode)
public async Task<bool?> GetShareCodeVerifyAsync(string formVersionId, string shareCode)
{
// Get FormId and Organisation based on ShareCode and FormVersionId
var query = from s in context.SharedConsents
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
using CO.CDP.OrganisationInformation.Persistence.Forms;

namespace CO.CDP.OrganisationInformation.Persistence;

public interface IShareCodeRepository : IDisposable
{
Task<bool> OrganisationShareCodeExistsAsync(Guid organisationId, string shareCode);
Task<IEnumerable<SharedConsent>> GetShareCodesAsync(Guid organisationId);
Task<SharedConsent?> GetSharedConsentDraftAsync(Guid formId, Guid organisationId);
Task<SharedConsent?> GetByShareCode(string sharecode);
Task<SharedConsentDetails?> GetShareCodeDetailsAsync(Guid organisationId, string shareCode);
Task<Boolean?> GetShareCodeVerifyAsync(string formVersionId, string shareCode);
Task<bool?> GetShareCodeVerifyAsync(string formVersionId, string shareCode);
}

0 comments on commit d88a7d9

Please sign in to comment.