1
0
Files
common/UnitTests/AspNetCore/Attributes/BasicAuthenticationAttributeTests.cs
2022-08-07 20:57:11 +02:00

351 lines
10 KiB
C#

using System;
using System.Collections.Generic;
using System.Net;
using System.Security.Claims;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using AMWD.Common.AspNetCore.BasicAuthentication;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Abstractions;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.Primitives;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
namespace UnitTests.AspNetCore.Attributes
{
[TestClass]
[System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
public class BasicAuthenticationAttributeTests
{
private Mock<IHeaderDictionary> requestHeaderMock;
private Mock<IHeaderDictionary> responseHeaderMock;
private Mock<HttpRequest> requestMock;
private Mock<HttpResponse> responseMock;
private Mock<HttpContext> contextMock;
private Dictionary<string, string> requestHeaders;
private string validatorRealm;
private ClaimsPrincipal validatorResult;
private string responseHeaderAuthCallback;
[TestInitialize]
public void InitializeTest()
{
requestHeaders = new Dictionary<string, string>();
validatorRealm = null;
validatorResult = null;
responseHeaderAuthCallback = null;
}
[TestMethod]
public async Task ShouldValidateViaUsernamePassword()
{
// arrange
var attribute = new BasicAuthenticationAttribute
{
Username = "user",
Password = "password"
};
requestHeaders.Add("Authorization", $"Basic {Convert.ToBase64String(Encoding.UTF8.GetBytes($"{attribute.Username}:{attribute.Password}"))}");
var context = GetContext();
// act
await attribute.OnAuthorizationAsync(context);
// assert
Assert.IsNull(context.Result);
Assert.IsTrue(string.IsNullOrWhiteSpace(responseHeaderAuthCallback));
}
[TestMethod]
public async Task ShouldValidateViaValidator()
{
// arrange
var attribute = new BasicAuthenticationAttribute();
requestHeaders.Add("Authorization", $"Basic {Convert.ToBase64String(Encoding.UTF8.GetBytes($"{attribute.Username}:{attribute.Password}"))}");
validatorResult = new ClaimsPrincipal();
var context = GetContext(hasValidator: true);
// act
await attribute.OnAuthorizationAsync(context);
// assert
Assert.IsNull(context.Result);
Assert.IsTrue(string.IsNullOrWhiteSpace(responseHeaderAuthCallback));
}
[TestMethod]
public async Task ShouldAllowAnonymous()
{
// arrange
var attribute = new BasicAuthenticationAttribute
{
Username = "user",
Password = "password"
};
var context = GetContext(isAnonymousAllowed: true);
// act
await attribute.OnAuthorizationAsync(context);
// assert
Assert.IsNull(context.Result);
Assert.IsTrue(string.IsNullOrWhiteSpace(responseHeaderAuthCallback));
}
[TestMethod]
public async Task ShouldAskOnUsernamePasswordWithoutRealm()
{
// arrange
var attribute = new BasicAuthenticationAttribute
{
Username = "user",
Password = "password"
};
var context = GetContext();
// act
await attribute.OnAuthorizationAsync(context);
// assert
Assert.IsNotNull(context.Result);
Assert.IsTrue(context.Result is StatusCodeResult);
Assert.AreEqual(401, ((StatusCodeResult)context.Result).StatusCode);
Assert.IsFalse(string.IsNullOrWhiteSpace(responseHeaderAuthCallback));
Assert.AreEqual("Basic", responseHeaderAuthCallback);
}
[TestMethod]
public async Task ShouldAskOnUsernamePasswordWithRealm()
{
// arrange
var attribute = new BasicAuthenticationAttribute
{
Username = "user",
Password = "password",
Realm = "re:al\"m"
};
var context = GetContext();
// act
await attribute.OnAuthorizationAsync(context);
// assert
Assert.IsNotNull(context.Result);
Assert.IsTrue(context.Result is StatusCodeResult);
Assert.AreEqual(401, ((StatusCodeResult)context.Result).StatusCode);
Assert.IsFalse(string.IsNullOrWhiteSpace(responseHeaderAuthCallback));
Assert.AreEqual("Basic realm=\"re:alm\"", responseHeaderAuthCallback);
}
[TestMethod]
public async Task ShouldAskOnUsernamePasswordWrongUser()
{
// arrange
var attribute = new BasicAuthenticationAttribute
{
Username = "user",
Password = "password"
};
requestHeaders.Add("Authorization", $"Basic {Convert.ToBase64String(Encoding.UTF8.GetBytes($"{attribute.Username}a:{attribute.Password}"))}");
var context = GetContext();
// act
await attribute.OnAuthorizationAsync(context);
// assert
Assert.IsNotNull(context.Result);
Assert.IsTrue(context.Result is StatusCodeResult);
Assert.AreEqual(401, ((StatusCodeResult)context.Result).StatusCode);
Assert.IsFalse(string.IsNullOrWhiteSpace(responseHeaderAuthCallback));
Assert.AreEqual("Basic", responseHeaderAuthCallback);
}
[TestMethod]
public async Task ShouldAskOnUsernamePasswordWrongPassword()
{
// arrange
var attribute = new BasicAuthenticationAttribute
{
Username = "user",
Password = "password"
};
requestHeaders.Add("Authorization", $"Basic {Convert.ToBase64String(Encoding.UTF8.GetBytes($"{attribute.Username}:{attribute.Password}a"))}");
var context = GetContext();
// act
await attribute.OnAuthorizationAsync(context);
// assert
Assert.IsNotNull(context.Result);
Assert.IsTrue(context.Result is StatusCodeResult);
Assert.AreEqual(401, ((StatusCodeResult)context.Result).StatusCode);
Assert.IsFalse(string.IsNullOrWhiteSpace(responseHeaderAuthCallback));
Assert.AreEqual("Basic", responseHeaderAuthCallback);
}
[TestMethod]
public async Task ShouldAskOnValidatorWithRealmOnAttribute()
{
// arrange
var attribute = new BasicAuthenticationAttribute
{
Realm = "attribute"
};
requestHeaders.Add("Authorization", $"Basic {Convert.ToBase64String(Encoding.UTF8.GetBytes($"{attribute.Username}:{attribute.Password}"))}");
var context = GetContext(hasValidator: true);
// act
await attribute.OnAuthorizationAsync(context);
// assert
Assert.IsNotNull(context.Result);
Assert.IsTrue(context.Result is StatusCodeResult);
Assert.AreEqual(401, ((StatusCodeResult)context.Result).StatusCode);
Assert.IsFalse(string.IsNullOrWhiteSpace(responseHeaderAuthCallback));
Assert.AreEqual("Basic realm=\"attribute\"", responseHeaderAuthCallback);
}
[TestMethod]
public async Task ShouldAskOnValidatorWithRealmOnValidator()
{
// arrange
validatorRealm = "validator";
var attribute = new BasicAuthenticationAttribute();
requestHeaders.Add("Authorization", $"Basic {Convert.ToBase64String(Encoding.UTF8.GetBytes($"{attribute.Username}:{attribute.Password}"))}");
var context = GetContext(hasValidator: true);
// act
await attribute.OnAuthorizationAsync(context);
// assert
Assert.IsNotNull(context.Result);
Assert.IsTrue(context.Result is StatusCodeResult);
Assert.AreEqual(401, ((StatusCodeResult)context.Result).StatusCode);
Assert.IsFalse(string.IsNullOrWhiteSpace(responseHeaderAuthCallback));
Assert.AreEqual("Basic realm=\"validator\"", responseHeaderAuthCallback);
}
[TestMethod]
public async Task ShouldReturnInternalError()
{
// arrange
var attribute = new BasicAuthenticationAttribute();
requestHeaders.Add("Authorization", $"Basic {Convert.ToBase64String(Encoding.UTF8.GetBytes($"{attribute.Username}"))}");
var context = GetContext();
// act
await attribute.OnAuthorizationAsync(context);
// assert
Assert.IsNotNull(context.Result);
Assert.IsTrue(context.Result is StatusCodeResult);
Assert.AreEqual(500, ((StatusCodeResult)context.Result).StatusCode);
}
private AuthorizationFilterContext GetContext(bool isAnonymousAllowed = false, bool hasValidator = false)
{
requestHeaderMock = new Mock<IHeaderDictionary>();
foreach (var header in requestHeaders)
{
requestHeaderMock
.Setup(h => h.ContainsKey(header.Key))
.Returns(true);
requestHeaderMock
.Setup(h => h[header.Key])
.Returns(header.Value);
}
responseHeaderMock = new Mock<IHeaderDictionary>();
responseHeaderMock
.SetupSet(h => h["WWW-Authenticate"] = It.IsAny<StringValues>())
.Callback<string, StringValues>((key, value) =>
{
responseHeaderAuthCallback = value;
});
requestMock = new Mock<HttpRequest>();
requestMock
.Setup(r => r.Headers)
.Returns(requestHeaderMock.Object);
responseMock = new Mock<HttpResponse>();
responseMock
.Setup(r => r.Headers)
.Returns(responseHeaderMock.Object);
var requestServicesMock = new Mock<IServiceProvider>();
if (hasValidator)
{
var validatorMock = new Mock<IBasicAuthenticationValidator>();
validatorMock
.Setup(v => v.Realm)
.Returns(validatorRealm);
validatorMock
.Setup(v => v.ValidateAsync(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<IPAddress>(), It.IsAny<CancellationToken>()))
.ReturnsAsync(validatorResult);
requestServicesMock
.Setup(rs => rs.GetService(typeof(IBasicAuthenticationValidator)))
.Returns(validatorMock.Object);
}
var connectionInfoMock = new Mock<ConnectionInfo>();
connectionInfoMock
.Setup(ci => ci.RemoteIpAddress)
.Returns(IPAddress.Loopback);
contextMock = new Mock<HttpContext>();
contextMock
.Setup(c => c.Request)
.Returns(requestMock.Object);
contextMock
.Setup(c => c.Response)
.Returns(responseMock.Object);
contextMock
.Setup(c => c.RequestServices)
.Returns(requestServicesMock.Object);
contextMock
.Setup(c => c.Connection)
.Returns(connectionInfoMock.Object);
contextMock
.Setup(c => c.RequestAborted)
.Returns(CancellationToken.None);
var routeDataMock = new Mock<RouteData>();
var actionDescriptor = new ActionDescriptor
{
EndpointMetadata = new List<object>()
};
if (isAnonymousAllowed)
actionDescriptor.EndpointMetadata.Add(new AllowAnonymousAttribute());
return new AuthorizationFilterContext(new ActionContext
{
HttpContext = contextMock.Object,
RouteData = routeDataMock.Object,
ActionDescriptor = actionDescriptor,
}, new List<IFilterMetadata>());
}
}
}