57 lines
2.0 KiB
C#
57 lines
2.0 KiB
C#
using System.Reflection;
|
|
using ErsatzTV.Controllers.Api;
|
|
using ErsatzTV.Filters;
|
|
using Microsoft.AspNetCore.Mvc;
|
|
using Microsoft.AspNetCore.Mvc.Routing;
|
|
using NUnit.Framework;
|
|
using Shouldly;
|
|
|
|
namespace ErsatzTV.Tests.Controllers;
|
|
|
|
[TestFixture]
|
|
public class CollectionControllerSecurityTests
|
|
{
|
|
[TestCase(typeof(CollectionController))]
|
|
[TestCase(typeof(SmartCollectionController))]
|
|
public void Controller_Should_Apply_ApiKeyAuthorizationFilter(Type controllerType)
|
|
{
|
|
ServiceFilterAttribute? filter = controllerType
|
|
.GetCustomAttributes<ServiceFilterAttribute>(inherit: true)
|
|
.SingleOrDefault(a => a.ServiceType == typeof(ApiKeyAuthorizationFilter));
|
|
|
|
filter.ShouldNotBeNull($"{controllerType.Name} must carry ApiKeyAuthorizationFilter at the class level");
|
|
}
|
|
|
|
[TestCase(typeof(CollectionController))]
|
|
[TestCase(typeof(SmartCollectionController))]
|
|
public void Every_Mutating_Action_Should_Be_Protected(Type controllerType)
|
|
{
|
|
MethodInfo[] actions = controllerType
|
|
.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly);
|
|
|
|
bool controllerHasFilter = controllerType
|
|
.GetCustomAttributes<ServiceFilterAttribute>(inherit: true)
|
|
.Any(a => a.ServiceType == typeof(ApiKeyAuthorizationFilter));
|
|
|
|
foreach (MethodInfo action in actions)
|
|
{
|
|
bool isMutating = action
|
|
.GetCustomAttributes<HttpMethodAttribute>(inherit: true)
|
|
.SelectMany(a => a.HttpMethods)
|
|
.Any(m => m is "POST" or "PUT" or "PATCH" or "DELETE");
|
|
|
|
if (!isMutating)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
bool actionHasFilter = action
|
|
.GetCustomAttributes<ServiceFilterAttribute>(inherit: true)
|
|
.Any(a => a.ServiceType == typeof(ApiKeyAuthorizationFilter));
|
|
|
|
(controllerHasFilter || actionHasFilter)
|
|
.ShouldBeTrue($"Mutating action {controllerType.Name}.{action.Name} is not protected");
|
|
}
|
|
}
|
|
}
|