using System.Threading.Tasks; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Moq; using NUnit.Framework; using Strata.Analytics.Api.Authorization; using Strata.Analytics.Biz.DataSources.Services; using Strata.Analytics.Biz.DataSources.Models; using Strata.Testing.Categories; using System.Security.Claims; using FluentAssertions; using Microsoft.AspNetCore.Http.Features; using System.IO; using System.Text; using Newtonsoft.Json; namespace Strata.Analytics.Test.Unit.Api.Authorization { [NUnit.Framework.Category(TestCategory.Unit)] [Parallelizable(ParallelScope.Self)] public class DataSourceMinimumRoleHandlerTest { [Test] public async Task Handler_Fails_GivenDataSourceIdNotInRouteAndNotInBody() { // arrange var mockDataSourceService = new Mock(); var mockHttpContextAccessor = new Mock(); var httpContext = new DefaultHttpContext(); mockHttpContextAccessor.Setup(_ => _.HttpContext).Returns(httpContext); var authorizationHandlerContext = GetMockAuthorizationHandlerContext(DataSourceRole.Viewer); var handler = new DataSourceMinimumRoleHandler(mockDataSourceService.Object, mockHttpContextAccessor.Object); // act await handler.HandleAsync(authorizationHandlerContext); // assert authorizationHandlerContext.HasSucceeded.Should().BeFalse(); } [Test] public async Task Handler_Succeeds_GivenDataSourceIdNotInRouteButInBody() { // arrange var dataSourceService = GetMockDataSourceService(DataSourceRole.Viewer); var httpContextAccessor = GetMockHttpContextAccessor(false, true); var authorizationHandlerContext = GetMockAuthorizationHandlerContext(DataSourceRole.Viewer); var handler = new DataSourceMinimumRoleHandler(dataSourceService, httpContextAccessor); // act await handler.HandleAsync(authorizationHandlerContext); // assert authorizationHandlerContext.HasSucceeded.Should().BeTrue(); } [Test] public async Task Handler_Succeeds_GivenDataSourceIdInRouteAndInBody() { // arrange var dataSourceService = GetMockDataSourceService(DataSourceRole.Viewer); var httpContextAccessor = GetMockHttpContextAccessor(true, true); var authorizationHandlerContext = GetMockAuthorizationHandlerContext(DataSourceRole.Viewer); var handler = new DataSourceMinimumRoleHandler(dataSourceService, httpContextAccessor); // act await handler.HandleAsync(authorizationHandlerContext); // assert authorizationHandlerContext.HasSucceeded.Should().BeTrue(); } [TestCase(DataSourceRole.Viewer, DataSourceRole.Viewer)] [TestCase(DataSourceRole.Viewer, DataSourceRole.Editor)] [TestCase(DataSourceRole.Editor, DataSourceRole.Editor)] public async Task Handler_Succeeds_GivenUserHasMinimumAccess(DataSourceRole minimumDataSourceRole, DataSourceRole userDataSourceRole) { // arrange var dataSourceService = GetMockDataSourceService(userDataSourceRole); var httpContextAccessor = GetMockHttpContextAccessor(); var authorizationHandlerContext = GetMockAuthorizationHandlerContext(minimumDataSourceRole); var handler = new DataSourceMinimumRoleHandler(dataSourceService, httpContextAccessor); // act await handler.HandleAsync(authorizationHandlerContext); // assert authorizationHandlerContext.HasSucceeded.Should().BeTrue(); } [TestCase(DataSourceRole.Editor, DataSourceRole.Viewer)] public async Task Handler_Fails_GivenUserDoesNotHaveMinimumAccess(DataSourceRole minimumDataSourceRole, DataSourceRole userDataSourceRole) { // arrange var dataSourceService = GetMockDataSourceService(userDataSourceRole); var httpContextAccessor = GetMockHttpContextAccessor(); var authorizationHandlerContext = GetMockAuthorizationHandlerContext(minimumDataSourceRole); var handler = new DataSourceMinimumRoleHandler(dataSourceService, httpContextAccessor); // act await handler.HandleAsync(authorizationHandlerContext); // assert authorizationHandlerContext.HasSucceeded.Should().BeFalse(); } private IDataSourceService GetMockDataSourceService(DataSourceRole userDataSourceRole) { var mockDataSourceService = new Mock(); mockDataSourceService.Setup(service => service.GetCurrentUserRoleAsync(5, System.Threading.CancellationToken.None)) .ReturnsAsync(userDataSourceRole); return mockDataSourceService.Object; } private IHttpContextAccessor GetMockHttpContextAccessor(bool dataSourceIdInRoute = true, bool dataSourceIdInBody = false) { var mockHttpContextAccessor = new Mock(); var features = new FeatureCollection(); if (dataSourceIdInRoute) { var routeFeature = new RouteValuesFeature(); routeFeature.RouteValues.Add("dataSourceId", 5); features.Set(routeFeature); } if (dataSourceIdInBody) { var bytes = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(new { dataSourceId = 5 })); var ms = new MemoryStream(bytes); var request = new HttpRequestFeature() { Body = ms }; request.Headers["Content-Type"] = "application/json"; features.Set(request); } var httpContext = new DefaultHttpContext(features); mockHttpContextAccessor.Setup(_ => _.HttpContext).Returns(httpContext); return mockHttpContextAccessor.Object; } private AuthorizationHandlerContext GetMockAuthorizationHandlerContext(DataSourceRole minimumDataSourceRole) { var requirement = new DataSourceMinimumRoleRequirement(minimumDataSourceRole); var user = new ClaimsPrincipal( new ClaimsIdentity( new Claim[] { }, "Basic")); return new AuthorizationHandlerContext(new[] { requirement }, user, null); } } }