diff --git a/Emby.Server.Implementations/HttpServer/Security/AuthorizationContext.cs b/Emby.Server.Implementations/HttpServer/Security/AuthorizationContext.cs index 6b4588dbc..7a83b7213 100644 --- a/Emby.Server.Implementations/HttpServer/Security/AuthorizationContext.cs +++ b/Emby.Server.Implementations/HttpServer/Security/AuthorizationContext.cs @@ -263,26 +263,9 @@ namespace Emby.Server.Implementations.HttpServer.Security return null; } - // Remove uptil the first space + // Remove up until the first space authorizationHeader = parts[1]; - parts = GetParts(authorizationHeader); - - var result = new Dictionary(StringComparer.OrdinalIgnoreCase); - - foreach (var item in parts) - { - var param = item.Trim().Split('=', 2); - - var value = param[1].Trim('"'); - result[param[0]] = NormalizeValue(value); - } - - return result; - } - - private static string NormalizeValue(string value) - { - return string.IsNullOrEmpty(value) ? value : WebUtility.UrlDecode(value); + return GetParts(authorizationHeader); } /// @@ -290,13 +273,15 @@ namespace Emby.Server.Implementations.HttpServer.Security /// /// The authorization header. /// string - public static string[] GetParts(string authtorizationHeader) + public static Dictionary GetParts(string authtorizationHeader) { - var result = new List(); + var result = new Dictionary(); var escapeChars = new[] { '"', ',' }; var escaped = false; int start = 0; int i = 0; + string key = string.Empty; + while (i < authtorizationHeader.Length) { var token = authtorizationHeader[i]; @@ -309,12 +294,18 @@ namespace Emby.Server.Implementations.HttpServer.Security // Meeting a comma after a closing escape char means the value is complete if (start < i) { - result.Add(WebUtility.UrlDecode(authtorizationHeader[start..(i)])); + result[key] = WebUtility.UrlDecode(authtorizationHeader[start..i].Trim('"')); + key = string.Empty; } start = i + 1; } } + else if (!escaped && token == '=') + { + key = authtorizationHeader[start.. i]; + start = i + 1; + } i++; } @@ -322,10 +313,10 @@ namespace Emby.Server.Implementations.HttpServer.Security // Add last value if (start < i) { - result.Add(WebUtility.UrlDecode(authtorizationHeader[start..(i)])); + result[key] = WebUtility.UrlDecode(authtorizationHeader[start..i].Trim('"')); } - return result.ToArray(); + return result; } } } diff --git a/tests/Jellyfin.Api.Tests/Auth/DefaultAuthorizationPolicy/DefaultAuthorizationHandlerTests.cs b/tests/Jellyfin.Api.Tests/Auth/DefaultAuthorizationPolicy/DefaultAuthorizationHandlerTests.cs index a62fd8d5a..5387922ab 100644 --- a/tests/Jellyfin.Api.Tests/Auth/DefaultAuthorizationPolicy/DefaultAuthorizationHandlerTests.cs +++ b/tests/Jellyfin.Api.Tests/Auth/DefaultAuthorizationPolicy/DefaultAuthorizationHandlerTests.cs @@ -1,7 +1,8 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Threading.Tasks; using AutoFixture; using AutoFixture.AutoMoq; +using Emby.Server.Implementations.HttpServer.Security; using Jellyfin.Api.Auth.DefaultAuthorizationPolicy; using Jellyfin.Api.Constants; using MediaBrowser.Common.Configuration; @@ -49,5 +50,16 @@ namespace Jellyfin.Api.Tests.Auth.DefaultAuthorizationPolicy await _sut.HandleAsync(context); Assert.True(context.HasSucceeded); } + + [Theory] + [InlineData("x=\"123,123\",y=\"123\"", "x", "123,123")] + [InlineData("x=\"ab\"", "x", "ab")] + [InlineData("param=Hörbücher", "param", "Hörbücher")] + [InlineData("param=%22%Hörbücher", "param", "\"%Hörbücher")] + public void TestAuthHeaders(string input, string key, string value) + { + var dict = AuthorizationContext.GetParts(input); + Assert.True(string.Equals(dict[key], value, System.StringComparison.Ordinal)); + } } }