Merge pull request #2181 from BnMcG/2179-authentication-tests

Test Jellyfin.Api authentication handling
pull/2278/head
Vasily 5 years ago committed by GitHub
commit c6484c0220
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -0,0 +1,175 @@
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> _jellyfinAuthServiceMock;
private readonly Mock<IOptionsMonitor<AuthenticationSchemeOptions>> _optionsMonitorMock;
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()
{
var fixtureCustomizations = new AutoMoqCustomization
{
ConfigureMembers = true
};
_fixture = new Fixture().Customize(fixtureCustomizations);
AllowFixtureCircularDependencies();
_jellyfinAuthServiceMock = _fixture.Freeze<Mock<IAuthService>>();
_optionsMonitorMock = _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);
_optionsMonitorMock.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()
{
_jellyfinAuthServiceMock.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>();
_jellyfinAuthServiceMock.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;
_jellyfinAuthServiceMock.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());
}
}
}

@ -0,0 +1,77 @@
using System.Collections.Generic;
using System.Security.Claims;
using System.Threading.Tasks;
using AutoFixture;
using AutoFixture.AutoMoq;
using Jellyfin.Api.Auth.FirstTimeSetupOrElevatedPolicy;
using Jellyfin.Api.Constants;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Model.Configuration;
using Microsoft.AspNetCore.Authorization;
using Moq;
using Xunit;
namespace Jellyfin.Api.Tests.Auth.FirstTimeSetupOrElevatedPolicy
{
public class FirstTimeSetupOrElevatedHandlerTests
{
private readonly Mock<IConfigurationManager> _configurationManagerMock;
private readonly List<IAuthorizationRequirement> _requirements;
private readonly FirstTimeSetupOrElevatedHandler _sut;
public FirstTimeSetupOrElevatedHandlerTests()
{
var fixture = new Fixture().Customize(new AutoMoqCustomization());
_configurationManagerMock = fixture.Freeze<Mock<IConfigurationManager>>();
_requirements = new List<IAuthorizationRequirement> {new FirstTimeSetupOrElevatedRequirement()};
_sut = fixture.Create<FirstTimeSetupOrElevatedHandler>();
}
[Theory]
[InlineData(UserRoles.Administrator)]
[InlineData(UserRoles.Guest)]
[InlineData(UserRoles.User)]
public async Task ShouldSucceedIfStartupWizardIncomplete(string userRole)
{
SetupConfigurationManager(false);
var user = SetupUser(userRole);
var context = new AuthorizationHandlerContext(_requirements, user, null);
await _sut.HandleAsync(context);
Assert.True(context.HasSucceeded);
}
[Theory]
[InlineData(UserRoles.Administrator, true)]
[InlineData(UserRoles.Guest, false)]
[InlineData(UserRoles.User, false)]
public async Task ShouldRequireAdministratorIfStartupWizardComplete(string userRole, bool shouldSucceed)
{
SetupConfigurationManager(true);
var user = SetupUser(userRole);
var context = new AuthorizationHandlerContext(_requirements, user, null);
await _sut.HandleAsync(context);
Assert.Equal(shouldSucceed, context.HasSucceeded);
}
private static ClaimsPrincipal SetupUser(string role)
{
var claims = new[] {new Claim(ClaimTypes.Role, role)};
var identity = new ClaimsIdentity(claims);
return new ClaimsPrincipal(identity);
}
private void SetupConfigurationManager(bool startupWizardCompleted)
{
var commonConfiguration = new BaseApplicationConfiguration
{
IsStartupWizardCompleted = startupWizardCompleted
};
_configurationManagerMock.Setup(c => c.CommonConfiguration)
.Returns(commonConfiguration);
}
}
}

@ -0,0 +1,38 @@
using System.Collections.Generic;
using System.Security.Claims;
using System.Threading.Tasks;
using Jellyfin.Api.Auth.RequiresElevationPolicy;
using Jellyfin.Api.Constants;
using Microsoft.AspNetCore.Authorization;
using Xunit;
namespace Jellyfin.Api.Tests.Auth.RequiresElevationPolicy
{
public class RequiresElevationHandlerTests
{
private readonly RequiresElevationHandler _sut;
public RequiresElevationHandlerTests()
{
_sut = new RequiresElevationHandler();
}
[Theory]
[InlineData(UserRoles.Administrator, true)]
[InlineData(UserRoles.User, false)]
[InlineData(UserRoles.Guest, false)]
public async Task ShouldHandleRolesCorrectly(string role, bool shouldSucceed)
{
var requirements = new List<IAuthorizationRequirement> {new RequiresElevationRequirement()};
var claims = new[] {new Claim(ClaimTypes.Role, role)};
var identity = new ClaimsIdentity(claims);
var user = new ClaimsPrincipal(identity);
var context = new AuthorizationHandlerContext(requirements, user, null);
await _sut.HandleAsync(context);
Assert.Equal(shouldSucceed, context.HasSucceeded);
}
}
}

@ -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,7 @@
<ItemGroup>
<ProjectReference Include="../../MediaBrowser.Api/MediaBrowser.Api.csproj" />
<ProjectReference Include="../../Jellyfin.Api/Jellyfin.Api.csproj" />
</ItemGroup>
</Project>

Loading…
Cancel
Save