Prechádzať zdrojové kódy

Wrote tests to cover CustomAuthenticationHandler

Ben Magee 5 rokov pred
rodič
commit
f47c7959af

+ 170 - 0
tests/Jellyfin.Api.Tests/Auth/CustomAuthenticationHandlerTests.cs

@@ -0,0 +1,170 @@
+using System;
+using System.Linq;
+using System.Security.Claims;
+using System.Text.Encodings.Web;
+using System.Threading.Tasks;
+using AutoFixture;
+using AutoFixture.AutoMoq;
+using Jellyfin.Api.Auth;
+using Jellyfin.Api.Constants;
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Net;
+using Microsoft.AspNetCore.Authentication;
+using Microsoft.AspNetCore.Http;
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Logging.Abstractions;
+using Microsoft.Extensions.Options;
+using Moq;
+using Xunit;
+
+namespace Jellyfin.Api.Tests.Auth
+{
+    public class CustomAuthenticationHandlerTests
+    {
+        private readonly IFixture _fixture;
+
+        private readonly Mock<IAuthService> _authServiceMock;
+        private readonly Mock<IOptionsMonitor<AuthenticationSchemeOptions>> _optionsMock;
+        private readonly Mock<ISystemClock> _clockMock;
+        private readonly Mock<IServiceProvider> _serviceProviderMock;
+        private readonly Mock<IAuthenticationService> _authenticationServiceMock;
+        private readonly UrlEncoder _urlEncoder;
+        private readonly HttpContext _context;
+
+        private readonly CustomAuthenticationHandler _sut;
+        private readonly AuthenticationScheme _scheme;
+
+        public CustomAuthenticationHandlerTests()
+        {
+            _fixture = new Fixture().Customize(new AutoMoqCustomization {ConfigureMembers = true});
+            AllowFixtureCircularDependencies();
+
+            _authServiceMock = _fixture.Freeze<Mock<IAuthService>>();
+            _optionsMock = _fixture.Freeze<Mock<IOptionsMonitor<AuthenticationSchemeOptions>>>();
+            _clockMock = _fixture.Freeze<Mock<ISystemClock>>();
+            _serviceProviderMock = _fixture.Freeze<Mock<IServiceProvider>>();
+            _authenticationServiceMock = _fixture.Freeze<Mock<IAuthenticationService>>();
+            _fixture.Register<ILoggerFactory>(() => new NullLoggerFactory());
+
+            _urlEncoder = UrlEncoder.Default;
+
+            _serviceProviderMock.Setup(s => s.GetService(typeof(IAuthenticationService)))
+                .Returns(_authenticationServiceMock.Object);
+
+            _optionsMock.Setup(o => o.Get(It.IsAny<string>()))
+                .Returns(new AuthenticationSchemeOptions
+                {
+                    ForwardAuthenticate = null
+                });
+
+            _context = new DefaultHttpContext
+            {
+                RequestServices = _serviceProviderMock.Object
+            };
+
+            _scheme = new AuthenticationScheme(
+                _fixture.Create<string>(),
+                null,
+                typeof(CustomAuthenticationHandler));
+
+            _sut = _fixture.Create<CustomAuthenticationHandler>();
+            _sut.InitializeAsync(_scheme, _context).Wait();
+        }
+
+        [Fact]
+        public async Task HandleAuthenticateAsyncShouldFailWithNullUser()
+        {
+            _authServiceMock.Setup(
+                    a => a.Authenticate(
+                        It.IsAny<HttpRequest>(),
+                        It.IsAny<AuthenticatedAttribute>()))
+                .Returns((User) null);
+
+            var authenticateResult = await _sut.AuthenticateAsync();
+
+            Assert.False(authenticateResult.Succeeded);
+            Assert.Equal("Invalid user", authenticateResult.Failure.Message);
+        }
+
+        [Fact]
+        public async Task HandleAuthenticateAsyncShouldFailOnSecurityException()
+        {
+            var errorMessage = _fixture.Create<string>();
+
+            _authServiceMock.Setup(
+                    a => a.Authenticate(
+                        It.IsAny<HttpRequest>(),
+                        It.IsAny<AuthenticatedAttribute>()))
+                .Throws(new SecurityException(errorMessage));
+
+            var authenticateResult = await _sut.AuthenticateAsync();
+
+            Assert.False(authenticateResult.Succeeded);
+            Assert.Equal(errorMessage, authenticateResult.Failure.Message);
+        }
+
+        [Fact]
+        public async Task HandleAuthenticateAsyncShouldSucceedWithUser()
+        {
+            SetupUser();
+            var authenticateResult = await _sut.AuthenticateAsync();
+
+            Assert.True(authenticateResult.Succeeded);
+            Assert.Null(authenticateResult.Failure);
+        }
+
+        [Fact]
+        public async Task HandleAuthenticateAsyncShouldAssignNameClaim()
+        {
+            var user = SetupUser();
+            var authenticateResult = await _sut.AuthenticateAsync();
+
+            Assert.True(authenticateResult.Principal.HasClaim(ClaimTypes.Name, user.Name));
+        }
+
+        [Theory]
+        [InlineData(true)]
+        [InlineData(false)]
+        public async Task HandleAuthenticateAsyncShouldAssignRoleClaim(bool isAdmin)
+        {
+            var user = SetupUser(isAdmin);
+            var authenticateResult = await _sut.AuthenticateAsync();
+
+            var expectedRole = user.Policy.IsAdministrator ? UserRoles.Administrator : UserRoles.User;
+            Assert.True(authenticateResult.Principal.HasClaim(ClaimTypes.Role, expectedRole));
+        }
+
+        [Fact]
+        public async Task HandleAuthenticateAsyncShouldAssignTicketCorrectScheme()
+        {
+            SetupUser();
+            var authenticatedResult = await _sut.AuthenticateAsync();
+
+            Assert.Equal(_scheme.Name, authenticatedResult.Ticket.AuthenticationScheme);
+        }
+
+        private User SetupUser(bool isAdmin=false)
+        {
+            var user = _fixture.Create<User>();
+            user.Policy.IsAdministrator = isAdmin;
+
+            _authServiceMock.Setup(
+                    a => a.Authenticate(
+                        It.IsAny<HttpRequest>(),
+                        It.IsAny<AuthenticatedAttribute>()))
+                .Returns(user);
+
+            return user;
+        }
+
+        private void AllowFixtureCircularDependencies()
+        {
+            // A circular dependency exists in the User entity around parent folders,
+            // this allows Autofixture to generate a User regardless, rather than throw
+            // an error.
+            _fixture.Behaviors.OfType<ThrowingRecursionBehavior>().ToList()
+                .ForEach(b => _fixture.Behaviors.Remove(b));
+            _fixture.Behaviors.Add(new OmitOnRecursionBehavior());
+        }
+    }
+}

+ 11 - 0
tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj

@@ -6,6 +6,10 @@
   </PropertyGroup>
 
   <ItemGroup>
+    <PackageReference Include="AutoFixture" Version="4.11.0" />
+    <PackageReference Include="AutoFixture.AutoMoq" Version="4.11.0" />
+    <PackageReference Include="AutoFixture.Xunit2" Version="4.11.0" />
+    <PackageReference Include="Microsoft.Extensions.Options" Version="3.0.1" />
     <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.4.0" />
     <PackageReference Include="xunit" Version="2.4.1" />
     <PackageReference Include="xunit.runner.visualstudio" Version="2.4.1" />
@@ -15,6 +19,13 @@
 
   <ItemGroup>
     <ProjectReference Include="../../MediaBrowser.Api/MediaBrowser.Api.csproj" />
+    <ProjectReference Include="..\..\Jellyfin.Api\Jellyfin.Api.csproj" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <Reference Include="Microsoft.AspNetCore.Authentication, Version=3.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60">
+      <HintPath>..\..\..\..\..\..\usr\local\share\dotnet\packs\Microsoft.AspNetCore.App.Ref\3.0.0\ref\netcoreapp3.0\Microsoft.AspNetCore.Authentication.dll</HintPath>
+    </Reference>
   </ItemGroup>
 
 </Project>