diff options
Diffstat (limited to 'tests/Jellyfin.Api.Tests/Auth/CustomAuthenticationHandlerTests.cs')
| -rw-r--r-- | tests/Jellyfin.Api.Tests/Auth/CustomAuthenticationHandlerTests.cs | 154 |
1 files changed, 154 insertions, 0 deletions
diff --git a/tests/Jellyfin.Api.Tests/Auth/CustomAuthenticationHandlerTests.cs b/tests/Jellyfin.Api.Tests/Auth/CustomAuthenticationHandlerTests.cs new file mode 100644 index 000000000..cd03958b6 --- /dev/null +++ b/tests/Jellyfin.Api.Tests/Auth/CustomAuthenticationHandlerTests.cs @@ -0,0 +1,154 @@ +using System; +using System.Linq; +using System.Security.Claims; +using System.Threading.Tasks; +using AutoFixture; +using AutoFixture.AutoMoq; +using Jellyfin.Api.Auth; +using Jellyfin.Api.Constants; +using Jellyfin.Data.Entities; +using Jellyfin.Data.Enums; +using MediaBrowser.Controller.Authentication; +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 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>>(); + var optionsMonitorMock = _fixture.Freeze<Mock<IOptionsMonitor<AuthenticationSchemeOptions>>>(); + var serviceProviderMock = _fixture.Freeze<Mock<IServiceProvider>>(); + var authenticationServiceMock = _fixture.Freeze<Mock<IAuthenticationService>>(); + _fixture.Register<ILoggerFactory>(() => new NullLoggerFactory()); + + serviceProviderMock.Setup(s => s.GetService(typeof(IAuthenticationService))) + .Returns(authenticationServiceMock.Object); + + optionsMonitorMock.Setup(o => o.Get(It.IsAny<string>())) + .Returns(new AuthenticationSchemeOptions + { + ForwardAuthenticate = null + }); + + HttpContext 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 HandleAuthenticateAsyncShouldProvideNoResultOnAuthenticationException() + { + var errorMessage = _fixture.Create<string>(); + + _jellyfinAuthServiceMock.Setup( + a => a.Authenticate( + It.IsAny<HttpRequest>())) + .Throws(new AuthenticationException(errorMessage)); + + var authenticateResult = await _sut.AuthenticateAsync(); + + Assert.False(authenticateResult.Succeeded); + Assert.True(authenticateResult.None); + } + + [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 authorizationInfo = SetupUser(); + var authenticateResult = await _sut.AuthenticateAsync(); + + Assert.True(authenticateResult.Principal?.HasClaim(ClaimTypes.Name, authorizationInfo.User.Username)); + } + + [Theory] + [InlineData(true)] + [InlineData(false)] + public async Task HandleAuthenticateAsyncShouldAssignRoleClaim(bool isAdmin) + { + var authorizationInfo = SetupUser(isAdmin); + var authenticateResult = await _sut.AuthenticateAsync(); + + var expectedRole = authorizationInfo.User.HasPermission(PermissionKind.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 AuthorizationInfo SetupUser(bool isAdmin = false) + { + var authorizationInfo = _fixture.Create<AuthorizationInfo>(); + authorizationInfo.User = _fixture.Create<User>(); + authorizationInfo.User.AddDefaultPermissions(); + authorizationInfo.User.AddDefaultPreferences(); + authorizationInfo.User.SetPermission(PermissionKind.IsAdministrator, isAdmin); + authorizationInfo.IsApiKey = false; + + _jellyfinAuthServiceMock.Setup( + a => a.Authenticate( + It.IsAny<HttpRequest>())) + .Returns(Task.FromResult(authorizationInfo)); + + return authorizationInfo; + } + + 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()); + } + } +} |
