Skip to content

Commit

Permalink
IEventSecretCodeProvider
Browse files Browse the repository at this point in the history
  • Loading branch information
martinothamar committed Oct 30, 2024
1 parent 44563ec commit b539175
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 66 deletions.
11 changes: 5 additions & 6 deletions src/Altinn.App.Api/Controllers/EventsReceiverController.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
#nullable disable
using System.Text.Json;
using Altinn.App.Core.Configuration;
using Altinn.App.Core.Features;
Expand All @@ -17,21 +16,20 @@ public class EventsReceiverController : ControllerBase
{
private readonly IEventHandlerResolver _eventHandlerResolver;
private readonly ILogger _logger;
private readonly IEventSecretCodeProvider _secretCodeProvider;
private readonly AppImplementationFactory _appImplementationFactory;

/// <summary>
/// Initializes a new instance of the <see cref="EventsReceiverController"/> class.
/// </summary>
public EventsReceiverController(
IEventHandlerResolver eventHandlerResolver,
ILogger<EventsReceiverController> logger,
IOptions<PlatformSettings> options,
IEventSecretCodeProvider secretCodeProvider
IServiceProvider serviceProvider
)
{
_eventHandlerResolver = eventHandlerResolver;
_logger = logger;
_secretCodeProvider = secretCodeProvider;
_appImplementationFactory = serviceProvider.GetRequiredService<AppImplementationFactory>();
}

/// <summary>
Expand All @@ -44,7 +42,8 @@ IEventSecretCodeProvider secretCodeProvider
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
public async Task<ActionResult> Post([FromQuery] string code, [FromBody] CloudEvent cloudEvent)
{
if (await _secretCodeProvider.GetSecretCode() != code)
var secretCodeProvider = _appImplementationFactory.GetRequired<IEventSecretCodeProvider>();
if (await secretCodeProvider.GetSecretCode() != code)
{
return Unauthorized();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@
using System.Text.Json;
using Altinn.App.Core.Configuration;
using Altinn.App.Core.Constants;
using Altinn.App.Core.Features;
using Altinn.App.Core.Helpers;
using Altinn.App.Core.Internal.Events;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;

Expand All @@ -19,7 +21,7 @@ public class EventsSubscriptionClient : IEventsSubscription

private readonly GeneralSettings _generalSettings;
private readonly HttpClient _client;
private readonly IEventSecretCodeProvider _secretCodeProvider;
private readonly AppImplementationFactory _appImplementationFactory;
private readonly ILogger<EventsSubscriptionClient> _logger;

/// <summary>
Expand All @@ -29,7 +31,7 @@ public EventsSubscriptionClient(
IOptions<PlatformSettings> platformSettings,
HttpClient httpClient,
IOptions<GeneralSettings> generalSettings,
IEventSecretCodeProvider secretCodeProvider,
IServiceProvider serviceProvider,
ILogger<EventsSubscriptionClient> logger
)
{
Expand All @@ -38,7 +40,7 @@ ILogger<EventsSubscriptionClient> logger
httpClient.DefaultRequestHeaders.Add(General.SubscriptionKeyHeaderName, platformSettings.Value.SubscriptionKey);
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
_client = httpClient;
_secretCodeProvider = secretCodeProvider;
_appImplementationFactory = serviceProvider.GetRequiredService<AppImplementationFactory>();
_logger = logger;
}

Expand All @@ -54,10 +56,11 @@ public async Task<Subscription> AddSubscription(string org, string app, string e
{
var appBaseUrl = _generalSettings.FormattedExternalAppBaseUrl(new Models.AppIdentifier(org, app));

var secretCodeProvider = _appImplementationFactory.GetRequired<IEventSecretCodeProvider>();
var subscriptionRequest = new SubscriptionRequest()
{
TypeFilter = eventType,
EndPoint = new Uri($"{appBaseUrl}api/v1/eventsreceiver?code={await _secretCodeProvider.GetSecretCode()}"),
EndPoint = new Uri($"{appBaseUrl}api/v1/eventsreceiver?code={await secretCodeProvider.GetSecretCode()}"),
SourceFilter = new Uri(appBaseUrl.TrimEnd('/')) // The event system is requireing the source filter to be without trailing slash
};

Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
using Altinn.App.Core.Features;

namespace Altinn.App.Core.Internal.Events;

/// <summary>
Expand All @@ -6,6 +8,7 @@ namespace Altinn.App.Core.Internal.Events;
/// the subscription to the Event system and returned back when posting
/// the event to the app. If the code is the same the event is accepted.
/// </summary>
[ImplementableByApps]
public interface IEventSecretCodeProvider
{
/// <summary>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,85 +1,78 @@
#nullable disable
using System.Net;
using System.Text.Json;
using Altinn.App.Core.Configuration;
using Altinn.App.Core.Features;
using Altinn.App.Core.Infrastructure.Clients.Events;
using Altinn.App.Core.Internal.Events;
using FluentAssertions;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Microsoft.Extensions.Logging.Abstractions;
using Moq;
using Moq.Protected;
using Xunit.Abstractions;

namespace Altinn.App.PlatformServices.Tests.Infrastructure.Clients;

public class EventsSubscriptionClientTests
{
private readonly ITestOutputHelper _testOutputHelper;

public EventsSubscriptionClientTests(ITestOutputHelper testOutputHelper)
private sealed record Fixture(IServiceProvider ServiceProvider) : IDisposable
{
_testOutputHelper = testOutputHelper;
public EventsSubscriptionClient Client =>
(EventsSubscriptionClient)ServiceProvider.GetRequiredService<IEventsSubscription>();

public static Fixture Create()
{
var services = new ServiceCollection();
services.AddTestAppImplementationFactory();
services.AddLogging(logging => logging.AddProvider(NullLoggerProvider.Instance));
services.Configure<GeneralSettings>(s => s.HostName = "at22.altinn.cloud");
services.Configure<PlatformSettings>(s =>
{
s.ApiEventsEndpoint = "http://localhost:5101/events/api/v1/";
s.SubscriptionKey = "key";
});

Subscription subscriptionContent = new() { Id = 123 };
HttpResponseMessage httpResponseMessage = new HttpResponseMessage
{
StatusCode = HttpStatusCode.OK,
Content = new StringContent(JsonSerializer.Serialize(subscriptionContent))
};
Mock<HttpMessageHandler> handlerMock = new();
handlerMock
.Protected()
.Setup<Task<HttpResponseMessage>>(
"SendAsync",
ItExpr.IsAny<HttpRequestMessage>(),
ItExpr.IsAny<CancellationToken>()
)
.ReturnsAsync(httpResponseMessage);
HttpClient httpClient = new HttpClient(handlerMock.Object);
services.AddSingleton(httpClient);

services.AddTransient<IEventSecretCodeProvider, TestSecretCodeProvider>();
services.AddTransient<IEventsSubscription, EventsSubscriptionClient>();
return new Fixture(
services.BuildServiceProvider(
new ServiceProviderOptions { ValidateOnBuild = true, ValidateScopes = true }
)
);
}

public void Dispose() => (ServiceProvider as IDisposable)?.Dispose();
}

[Fact]
public async Task AddSubscription_ShouldReturnOk()
{
EventsSubscriptionClient client = GetEventSubscriptonClient();
using var fixture = Fixture.Create();
EventsSubscriptionClient client = fixture.Client;

Subscription subscription = await client.AddSubscription("ttd", "test-app", "app.events.type");

subscription.Should().NotBeNull();
}

private static EventsSubscriptionClient GetEventSubscriptonClient()
{
IEventSecretCodeProvider secretCodeProvider = new TestSecretCodeProvider();
Mock<ILogger<EventsSubscriptionClient>> loggerMock = new();

IOptions<PlatformSettings> platformSettings = Microsoft.Extensions.Options.Options.Create(
new PlatformSettings()
{
ApiEventsEndpoint = "http://localhost:5101/events/api/v1/",
SubscriptionKey = "key"
}
);

IOptions<GeneralSettings> generalSettings = Microsoft.Extensions.Options.Options.Create(
new GeneralSettings { HostName = "at22.altinn.cloud" }
);

Subscription subscriptionContent = new() { Id = 123 };

HttpResponseMessage httpResponseMessage = new HttpResponseMessage
{
StatusCode = HttpStatusCode.OK,
Content = new StringContent(JsonSerializer.Serialize(subscriptionContent))
};

Mock<HttpMessageHandler> handlerMock = new();
handlerMock
.Protected()
.Setup<Task<HttpResponseMessage>>(
"SendAsync",
ItExpr.IsAny<HttpRequestMessage>(),
ItExpr.IsAny<CancellationToken>()
)
.ReturnsAsync(httpResponseMessage);

HttpClient httpClient = new HttpClient(handlerMock.Object);

var client = new EventsSubscriptionClient(
platformSettings,
httpClient,
generalSettings,
secretCodeProvider,
loggerMock.Object
);

return client;
}

public class TestSecretCodeProvider : IEventSecretCodeProvider
{
public Task<string> GetSecretCode()
Expand Down

0 comments on commit b539175

Please sign in to comment.