Skip to content

Commit

Permalink
Added function for processing authorization event (#31)
Browse files Browse the repository at this point in the history
* Added function for processing authorization event

* code smells

* Added function tests

* added more unit tests for function app

* Excluded contextrequest from code coverage

* Fix datetime issue in unit tests

---------

Co-authored-by: acn-dgopa <acn-dgopa@dev-acn-tje-14>
  • Loading branch information
acn-dgopa and acn-dgopa authored Sep 7, 2023
1 parent c111191 commit 969573d
Show file tree
Hide file tree
Showing 16 changed files with 727 additions and 13 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>

<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.5.0" />
<PackageReference Include="Moq" Version="4.20.69" />
<PackageReference Include="xunit" Version="2.4.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="coverlet.collector" Version="3.2.0">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\src\Functions\Altinn.Auth.AuditLog.Functions\Altinn.Auth.AuditLog.Functions.csproj" />
</ItemGroup>

</Project>
148 changes: 148 additions & 0 deletions Altinn.Auth.AuditLog.Functions.Tests/Clients/AuditLogClientTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
using Altinn.Auth.AuditLog.Functions.Clients;
using Altinn.Auth.AuditLog.Functions.Clients.Interfaces;
using Altinn.Auth.AuditLog.Functions.Configuration;
using Altinn.Auth.AuditLog.Functions.Models;
using Altinn.Auth.AuditLog.Functions.Tests.Helpers;
using Azure.Messaging;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Moq;
using Moq.Protected;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;

namespace Altinn.Auth.AuditLog.Functions.Tests.Clients
{
public class AuditLogClientTest
{
Mock<ILogger<IAuditLogClient>> _loggerMock = new Mock<ILogger<IAuditLogClient>>();
IOptions<PlatformSettings> _platformSettings = Options.Create(new PlatformSettings
{
AuditLogApiEndpoint = "https://platform.test.altinn.cloud/"
});

private readonly AuthenticationEvent authenticationEvent = new AuthenticationEvent()
{
UserId = "20000003",
Created = DateTime.UtcNow,
AuthenticationMethod = "BankId",
EventType = "LoggedIn",
SessionId = "83343b4c-865d-4e6c-888d-33bc7533ea2d",
AuthenticationLevel = "4",
};

/// <summary>
/// Verify that the endpoint the client sends a request to is set correctly
/// </summary>
[Fact]
public async Task SaveAuthenticationEvent_SuccessResponse()
{
// Arrange
var handlerMock = CreateMessageHandlerMock(
"https://platform.test.altinn.cloud/auditlog/api/v1/authenticationevent",
HttpStatusCode.OK);

var client = new AuditLogClient(_loggerMock.Object, new HttpClient(handlerMock.Object), _platformSettings);
// Act
await client.SaveAuthenticationEvent(authenticationEvent);

// Assert
handlerMock.VerifyAll();
}

[Fact]
public async Task SaveAuthenticationEvent_NonSuccessResponse_ErrorLoggedAndExceptionThrown()
{
// Arrange
var handlerMock = CreateMessageHandlerMock(
"https://platform.test.altinn.cloud/auditlog/api/v1/authenticationevent",
HttpStatusCode.ServiceUnavailable);

var client = CreateTestInstance(handlerMock.Object);

// Act

await Assert.ThrowsAsync<HttpRequestException>(async () => await client.SaveAuthenticationEvent(authenticationEvent));

// Assert
handlerMock.VerifyAll();
_loggerMock.Verify(x => x.Log(
LogLevel.Error,
It.IsAny<EventId>(),
It.Is<It.IsAnyType>((v, t) => v.ToString().Contains("SaveAuthenticationEvent failed with status code ServiceUnavailable")),
It.IsAny<Exception>(),
(Func<It.IsAnyType, Exception, string>)It.IsAny<object>()), Times.Once);
}

/// <summary>
/// Verify that the endpoint the client sends a request to is set correctly
/// </summary>
[Fact]
public async Task SaveAuthorizationEvent_SuccessResponse()
{
// Arrange
var handlerMock = CreateMessageHandlerMock(
"https://platform.test.altinn.cloud/auditlog/api/v1/authorizationevent",
HttpStatusCode.OK);

var client = new AuditLogClient(_loggerMock.Object, new HttpClient(handlerMock.Object), _platformSettings);
// Act
await client.SaveAuthorizationEvent(TestDataHelper.GetAuthorizationEvent());

// Assert
handlerMock.VerifyAll();
}

[Fact]
public async Task SaveAuthorizationEvent_NonSuccessResponse_ErrorLoggedAndExceptionThrown()
{
// Arrange
var handlerMock = CreateMessageHandlerMock(
"https://platform.test.altinn.cloud/auditlog/api/v1/authorizationevent",
HttpStatusCode.ServiceUnavailable);

var client = CreateTestInstance(handlerMock.Object);

// Act

await Assert.ThrowsAsync<HttpRequestException>(async () => await client.SaveAuthorizationEvent(TestDataHelper.GetAuthorizationEvent()));

// Assert
handlerMock.VerifyAll();
_loggerMock.Verify(x => x.Log(
LogLevel.Error,
It.IsAny<EventId>(),
It.Is<It.IsAnyType>((v, t) => v.ToString().Contains("SaveAuthorizationEvent failed with status code ServiceUnavailable")),
It.IsAny<Exception>(),
(Func<It.IsAnyType, Exception, string>)It.IsAny<object>()), Times.Once);
}

private static Mock<HttpMessageHandler> CreateMessageHandlerMock(string clientEndpoint, HttpStatusCode statusCode)
{
var messageHandlerMock = new Mock<HttpMessageHandler>(MockBehavior.Strict);

messageHandlerMock.Protected()
.Setup<Task<HttpResponseMessage>>("SendAsync", ItExpr.Is<HttpRequestMessage>(rm => rm.RequestUri.Equals(clientEndpoint)), ItExpr.IsAny<CancellationToken>())
.ReturnsAsync((HttpRequestMessage request, CancellationToken token) =>
{
var response = new HttpResponseMessage(statusCode);
return response;
})
.Verifiable();

return messageHandlerMock;
}

private AuditLogClient CreateTestInstance(HttpMessageHandler messageHandlerMock)
{
return new AuditLogClient(
_loggerMock.Object,
new HttpClient(messageHandlerMock),
_platformSettings);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
using Altinn.Auth.AuditLog.Functions.Clients.Interfaces;
using Altinn.Auth.AuditLog.Functions.Models;
using Altinn.Auth.AuditLog.Functions.Tests.Helpers;
using Altinn.Auth.AuditLog.Functions.Tests.Utils;
using Azure.Messaging;
using Microsoft.Extensions.Logging;
using Moq;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Altinn.Auth.AuditLog.Functions.Tests.Functions
{
public class AuthorizationEventsProcessorTest
{
Mock<ILogger<AuthorizationEventsProcessor>> _loggerMock = new Mock<ILogger<AuthorizationEventsProcessor>>();

[Fact]
public async Task Run_ConfirmDeserializationOfAuthorizationEvent()
{

// Arrange
string serializedAuthorizationEvent = "{" +
"\"TimeStamp\":\"0001-01-01T00:00:00\",\"SubjectUserId\":\"2000000\",\"SubjectParty\":\"\"," +
"\"ResourcePartyId\":\"1000\",\"Resource\":\"taxreport\",\"InstanceId\":\"1000/26133fb5-a9f2-45d4-90b1-f6d93ad40713\"," +
"\"Operation\":\"read\",\"TimeToDelete\":\"\",\"IpAdress\":\"192.0.2.1\"," +
"\"ContextRequestJson\":{\"ReturnPolicyIdList\":false," +
"\"AccessSubject\":[{\"Attribute\":[{\"Id\":\"urn:altinn:userid\",\"Value\":\"1\",\"DataType\":null,\"IncludeInResult\":false}," +
"{\"Id\":\"urn:altinn:role\",\"Value\":\"dagl\",\"DataType\":null,\"IncludeInResult\":false}," +
"{\"Id\":\"urn:altinn:role\",\"Value\":\"utinn\",\"DataType\":null,\"IncludeInResult\":false}]}]," +
"\"Action\":[{\"Attribute\":[{\"Id\":\"urn:oasis:names:tc:xacml:1.0:action:action-id\",\"Value\":\"read\"," +
"\"DataType\":\"http://www.w3.org/2001/XMLSchema#string\",\"IncludeInResult\":false}]}]," +
"\"Resources\":[{\"Attribute\":[{\"Id\":\"urn:altinn:instance-id\",\"Value\":\"1000/26133fb5-a9f2-45d4-90b1-f6d93ad40713\"," +
"\"DataType\":null,\"IncludeInResult\":true},{\"Id\":\"urn:altinn:org\",\"Value\":\"skd\"," +
"\"DataType\":null,\"IncludeInResult\":false},{\"Id\":\"urn:altinn:app\",\"Value\":\"taxreport\"," +
"\"DataType\":null,\"IncludeInResult\":false},{\"Id\":\"urn:altinn:partyid\",\"Value\":\"1000\"," +
"\"DataType\":null,\"IncludeInResult\":false},{\"Id\":\"urn:altinn:task\",\"Value\":\"formfilling\"," +
"\"DataType\":null,\"IncludeInResult\":false}]}]}}\r\n";

Mock<IAuditLogClient> clientMock = new();
clientMock.Setup(c => c.SaveAuthorizationEvent(It.Is<AuthorizationEvent>(c => AssertExpectedAuthorizationEvent(c, TestDataHelper.GetAuthorizationEvent()))))
.Returns(Task.CompletedTask);

AuthorizationEventsProcessor sut = new AuthorizationEventsProcessor(clientMock.Object);

// Act
await sut.Run(serializedAuthorizationEvent, null);

// Assert

clientMock.VerifyAll();
}

private static bool AssertExpectedAuthorizationEvent(AuthorizationEvent actualAuthorizationEvent, AuthorizationEvent expectedAuthorizationEvent)
{
Assert.Equal(expectedAuthorizationEvent.InstanceId, actualAuthorizationEvent.InstanceId);
Assert.Equal(expectedAuthorizationEvent.Operation, actualAuthorizationEvent.Operation);
Assert.Equal(expectedAuthorizationEvent.Resource, actualAuthorizationEvent.Resource);
Assert.Equal(expectedAuthorizationEvent.IpAdress, actualAuthorizationEvent.IpAdress);
Assert.Equal(expectedAuthorizationEvent.TimeToDelete, actualAuthorizationEvent.TimeToDelete);
Assert.Equal(expectedAuthorizationEvent.TimeStamp, actualAuthorizationEvent.TimeStamp);
AssertionUtil.AssertCollections(expectedAuthorizationEvent.ContextRequestJson.Action, actualAuthorizationEvent.ContextRequestJson.Action, AssertionUtil.AssertRuleEqual);
AssertionUtil.AssertCollections(expectedAuthorizationEvent.ContextRequestJson.AccessSubject, actualAuthorizationEvent.ContextRequestJson.AccessSubject, AssertionUtil.AssertRuleEqual);
AssertionUtil.AssertCollections(expectedAuthorizationEvent.ContextRequestJson.Resources, actualAuthorizationEvent.ContextRequestJson.Resources, AssertionUtil.AssertRuleEqual);
Assert.Equal(expectedAuthorizationEvent.ContextRequestJson.ReturnPolicyIdList, actualAuthorizationEvent.ContextRequestJson.ReturnPolicyIdList);
return true;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
using Altinn.Auth.AuditLog.Functions.Clients.Interfaces;
using Altinn.Auth.AuditLog.Functions.Models;
using Azure.Messaging;
using Microsoft.Extensions.Logging;
using Moq;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Altinn.Auth.AuditLog.Functions.Tests.Functions
{
public class EventsProcessorTest
{
Mock<ILogger<EventsProcessor>> _loggerMock = new Mock<ILogger<EventsProcessor>>();

[Fact]
public async Task Run_ConfirmDeserializationOfAuthenticationEvent()
{

// Arrange
string serializedAuthenticationEvent = "{\"Created\":\"2023-09-07T06:24:43.971899Z\",\"UserId\":\"20000003\",\"SupplierId\":null,\"EventType\":\"LoggedIn\",\"OrgNumber\":null,\"AuthenticationMethod\":\"BankId\",\"AuthenticationLevel\":\"4\",\"SessionId\":\"83343b4c-865d-4e6c-888d-33bc7533ea2d\"}\r\n";

AuthenticationEvent expectedAuthenticationEvent = new AuthenticationEvent()
{
UserId = "20000003",
Created = DateTimeOffset.Parse("2023-09-07T06:24:43.971899Z").UtcDateTime,
AuthenticationMethod = "BankId",
EventType = "LoggedIn",
SessionId = "83343b4c-865d-4e6c-888d-33bc7533ea2d",
AuthenticationLevel = "4",
};

Mock<IAuditLogClient> clientMock = new();
clientMock.Setup(c => c.SaveAuthenticationEvent(It.Is<AuthenticationEvent>(c => AssertExpectedAuthenticationEvent(c, expectedAuthenticationEvent))))
.Returns(Task.CompletedTask);

EventsProcessor sut = new EventsProcessor(_loggerMock.Object, clientMock.Object);

// Act
await sut.Run(serializedAuthenticationEvent, null);

// Assert

clientMock.VerifyAll();
}

private static bool AssertExpectedAuthenticationEvent(AuthenticationEvent actualAuthenticationEvent, AuthenticationEvent expectedAuthenticationEvent)
{
Assert.Equal(expectedAuthenticationEvent.SessionId, actualAuthenticationEvent.SessionId);
Assert.Equal(expectedAuthenticationEvent.AuthenticationLevel, actualAuthenticationEvent.AuthenticationLevel);
Assert.Equal(expectedAuthenticationEvent.AuthenticationMethod, actualAuthenticationEvent.AuthenticationMethod);
Assert.Equal(expectedAuthenticationEvent.Created, actualAuthenticationEvent.Created);
Assert.Equal(expectedAuthenticationEvent.EventType, actualAuthenticationEvent.EventType);
Assert.Equal(expectedAuthenticationEvent.OrgNumber, actualAuthenticationEvent.OrgNumber);
Assert.Equal(expectedAuthenticationEvent.SupplierId, actualAuthenticationEvent.SupplierId);
Assert.Equal(expectedAuthenticationEvent.UserId, actualAuthenticationEvent.UserId);
return true;
}
}
}
Loading

0 comments on commit 969573d

Please sign in to comment.