Merge pull request #4116 from cvium/add_known_proxies
Add Known Proxies to system configuration
This commit is contained in:
commit
4447589460
|
@ -28,7 +28,7 @@ namespace Emby.Server.Implementations.HttpServer.Security
|
|||
var authorization = _authContext.GetAuthorizationInfo(requestContext);
|
||||
|
||||
var user = authorization.User;
|
||||
return _sessionManager.LogSessionActivity(authorization.Client, authorization.Version, authorization.DeviceId, authorization.Device, requestContext.Request.RemoteIp(), user);
|
||||
return _sessionManager.LogSessionActivity(authorization.Client, authorization.Version, authorization.DeviceId, authorization.Device, requestContext.GetNormalizedRemoteIp(), user);
|
||||
}
|
||||
|
||||
public SessionInfo GetSession(object requestContext)
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
using System.Security.Claims;
|
||||
using Jellyfin.Api.Helpers;
|
||||
using Jellyfin.Data.Enums;
|
||||
using MediaBrowser.Common.Extensions;
|
||||
using MediaBrowser.Common.Net;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
|
@ -69,7 +70,7 @@ namespace Jellyfin.Api.Auth
|
|||
return false;
|
||||
}
|
||||
|
||||
var ip = RequestHelpers.NormalizeIp(_httpContextAccessor.HttpContext.Connection.RemoteIpAddress).ToString();
|
||||
var ip = _httpContextAccessor.HttpContext.GetNormalizedRemoteIp();
|
||||
var isInLocalNetwork = _networkManager.IsInLocalNetwork(ip);
|
||||
// User cannot access remotely and user is remote
|
||||
if (!user.HasPermission(PermissionKind.EnableRemoteAccess) && !isInLocalNetwork)
|
||||
|
|
|
@ -9,6 +9,7 @@ using Jellyfin.Api.Constants;
|
|||
using Jellyfin.Api.Helpers;
|
||||
using Jellyfin.Api.Models.MediaInfoDtos;
|
||||
using Jellyfin.Api.Models.VideoDtos;
|
||||
using MediaBrowser.Common.Extensions;
|
||||
using MediaBrowser.Controller.Devices;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.Net;
|
||||
|
@ -165,7 +166,7 @@ namespace Jellyfin.Api.Controllers
|
|||
enableTranscoding,
|
||||
allowVideoStreamCopy,
|
||||
allowAudioStreamCopy,
|
||||
Request.HttpContext.Connection.RemoteIpAddress.ToString());
|
||||
Request.HttpContext.GetNormalizedRemoteIp());
|
||||
}
|
||||
|
||||
_mediaInfoHelper.SortMediaSources(info, maxStreamingBitrate);
|
||||
|
|
|
@ -9,6 +9,7 @@ using System.Threading.Tasks;
|
|||
using Jellyfin.Api.Attributes;
|
||||
using Jellyfin.Api.Constants;
|
||||
using MediaBrowser.Common.Configuration;
|
||||
using MediaBrowser.Common.Extensions;
|
||||
using MediaBrowser.Common.Net;
|
||||
using MediaBrowser.Controller;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
|
@ -178,8 +179,8 @@ namespace Jellyfin.Api.Controllers
|
|||
{
|
||||
return new EndPointInfo
|
||||
{
|
||||
IsLocal = Request.HttpContext.Connection.LocalIpAddress.Equals(Request.HttpContext.Connection.RemoteIpAddress),
|
||||
IsInNetwork = _network.IsInLocalNetwork(Request.HttpContext.Connection.RemoteIpAddress.ToString())
|
||||
IsLocal = HttpContext.IsLocal(),
|
||||
IsInNetwork = _network.IsInLocalNetwork(HttpContext.GetNormalizedRemoteIp())
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ using Jellyfin.Api.Attributes;
|
|||
using Jellyfin.Api.Constants;
|
||||
using Jellyfin.Api.Helpers;
|
||||
using Jellyfin.Api.Models.StreamingDtos;
|
||||
using MediaBrowser.Common.Extensions;
|
||||
using MediaBrowser.Controller.Devices;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.MediaEncoding;
|
||||
|
@ -160,7 +161,7 @@ namespace Jellyfin.Api.Controllers
|
|||
true,
|
||||
true,
|
||||
true,
|
||||
Request.HttpContext.Connection.RemoteIpAddress.ToString());
|
||||
Request.HttpContext.GetNormalizedRemoteIp());
|
||||
}
|
||||
|
||||
_mediaInfoHelper.SortMediaSources(info, maxStreamingBitrate);
|
||||
|
|
|
@ -7,6 +7,7 @@ using Jellyfin.Api.Constants;
|
|||
using Jellyfin.Api.Helpers;
|
||||
using Jellyfin.Api.Models.UserDtos;
|
||||
using Jellyfin.Data.Enums;
|
||||
using MediaBrowser.Common.Extensions;
|
||||
using MediaBrowser.Common.Net;
|
||||
using MediaBrowser.Controller.Authentication;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
|
@ -117,7 +118,7 @@ namespace Jellyfin.Api.Controllers
|
|||
return NotFound("User not found");
|
||||
}
|
||||
|
||||
var result = _userManager.GetUserDto(user, HttpContext.Connection.RemoteIpAddress.ToString());
|
||||
var result = _userManager.GetUserDto(user, HttpContext.GetNormalizedRemoteIp());
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -203,7 +204,7 @@ namespace Jellyfin.Api.Controllers
|
|||
DeviceName = auth.Device,
|
||||
Password = request.Pw,
|
||||
PasswordSha1 = request.Password,
|
||||
RemoteEndPoint = HttpContext.Connection.RemoteIpAddress.ToString(),
|
||||
RemoteEndPoint = HttpContext.GetNormalizedRemoteIp(),
|
||||
Username = request.Username
|
||||
}).ConfigureAwait(false);
|
||||
|
||||
|
@ -212,7 +213,7 @@ namespace Jellyfin.Api.Controllers
|
|||
catch (SecurityException e)
|
||||
{
|
||||
// rethrow adding IP address to message
|
||||
throw new SecurityException($"[{HttpContext.Connection.RemoteIpAddress}] {e.Message}", e);
|
||||
throw new SecurityException($"[{HttpContext.GetNormalizedRemoteIp()}] {e.Message}", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -246,7 +247,7 @@ namespace Jellyfin.Api.Controllers
|
|||
catch (SecurityException e)
|
||||
{
|
||||
// rethrow adding IP address to message
|
||||
throw new SecurityException($"[{HttpContext.Connection.RemoteIpAddress}] {e.Message}", e);
|
||||
throw new SecurityException($"[{HttpContext.GetNormalizedRemoteIp()}] {e.Message}", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -290,7 +291,7 @@ namespace Jellyfin.Api.Controllers
|
|||
user.Username,
|
||||
request.CurrentPw,
|
||||
request.CurrentPw,
|
||||
HttpContext.Connection.RemoteIpAddress.ToString(),
|
||||
HttpContext.GetNormalizedRemoteIp(),
|
||||
false).ConfigureAwait(false);
|
||||
|
||||
if (success == null)
|
||||
|
@ -496,7 +497,7 @@ namespace Jellyfin.Api.Controllers
|
|||
await _userManager.ChangePassword(newUser, request.Password).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
var result = _userManager.GetUserDto(newUser, HttpContext.Connection.RemoteIpAddress.ToString());
|
||||
var result = _userManager.GetUserDto(newUser, HttpContext.GetNormalizedRemoteIp());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@ -511,8 +512,8 @@ namespace Jellyfin.Api.Controllers
|
|||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
public async Task<ActionResult<ForgotPasswordResult>> ForgotPassword([FromBody] string? enteredUsername)
|
||||
{
|
||||
var isLocal = HttpContext.Connection.RemoteIpAddress.Equals(HttpContext.Connection.LocalIpAddress)
|
||||
|| _networkManager.IsInLocalNetwork(HttpContext.Connection.RemoteIpAddress.ToString());
|
||||
var isLocal = HttpContext.IsLocal()
|
||||
|| _networkManager.IsInLocalNetwork(HttpContext.GetNormalizedRemoteIp());
|
||||
|
||||
var result = await _userManager.StartForgotPasswordProcess(enteredUsername, isLocal).ConfigureAwait(false);
|
||||
|
||||
|
@ -559,7 +560,7 @@ namespace Jellyfin.Api.Controllers
|
|||
|
||||
if (filterByNetwork)
|
||||
{
|
||||
if (!_networkManager.IsInLocalNetwork(HttpContext.Connection.RemoteIpAddress.ToString()))
|
||||
if (!_networkManager.IsInLocalNetwork(HttpContext.GetNormalizedRemoteIp()))
|
||||
{
|
||||
users = users.Where(i => i.HasPermission(PermissionKind.EnableRemoteAccess));
|
||||
}
|
||||
|
@ -567,7 +568,7 @@ namespace Jellyfin.Api.Controllers
|
|||
|
||||
var result = users
|
||||
.OrderBy(u => u.Username)
|
||||
.Select(i => _userManager.GetUserDto(i, HttpContext.Connection.RemoteIpAddress.ToString()));
|
||||
.Select(i => _userManager.GetUserDto(i, HttpContext.GetNormalizedRemoteIp()));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ using System.Text;
|
|||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Jellyfin.Api.Models.StreamingDtos;
|
||||
using MediaBrowser.Common.Extensions;
|
||||
using MediaBrowser.Common.Net;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Controller.Devices;
|
||||
|
@ -198,12 +199,12 @@ namespace Jellyfin.Api.Helpers
|
|||
|
||||
if (!string.IsNullOrWhiteSpace(subtitleGroup))
|
||||
{
|
||||
AddSubtitles(state, subtitleStreams, builder, _httpContextAccessor.HttpContext.Request.HttpContext.User);
|
||||
AddSubtitles(state, subtitleStreams, builder, _httpContextAccessor.HttpContext.User);
|
||||
}
|
||||
|
||||
AppendPlaylist(builder, state, playlistUrl, totalBitrate, subtitleGroup);
|
||||
|
||||
if (EnableAdaptiveBitrateStreaming(state, isLiveStream, enableAdaptiveBitrateStreaming, _httpContextAccessor.HttpContext.Request.HttpContext.Connection.RemoteIpAddress))
|
||||
if (EnableAdaptiveBitrateStreaming(state, isLiveStream, enableAdaptiveBitrateStreaming, _httpContextAccessor.HttpContext.GetNormalizedRemoteIp()))
|
||||
{
|
||||
var requestedVideoBitrate = state.VideoRequest == null ? 0 : state.VideoRequest.VideoBitRate ?? 0;
|
||||
|
||||
|
@ -334,11 +335,10 @@ namespace Jellyfin.Api.Helpers
|
|||
}
|
||||
}
|
||||
|
||||
private bool EnableAdaptiveBitrateStreaming(StreamState state, bool isLiveStream, bool enableAdaptiveBitrateStreaming, IPAddress ipAddress)
|
||||
private bool EnableAdaptiveBitrateStreaming(StreamState state, bool isLiveStream, bool enableAdaptiveBitrateStreaming, string ipAddress)
|
||||
{
|
||||
// Within the local network this will likely do more harm than good.
|
||||
var ip = RequestHelpers.NormalizeIp(ipAddress).ToString();
|
||||
if (_networkManager.IsInLocalNetwork(ip))
|
||||
if (_networkManager.IsInLocalNetwork(ipAddress))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ using System.Threading;
|
|||
using System.Threading.Tasks;
|
||||
using Jellyfin.Data.Entities;
|
||||
using Jellyfin.Data.Enums;
|
||||
using MediaBrowser.Common.Extensions;
|
||||
using MediaBrowser.Common.Net;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Controller.Devices;
|
||||
|
@ -498,7 +499,7 @@ namespace Jellyfin.Api.Helpers
|
|||
true,
|
||||
true,
|
||||
true,
|
||||
httpRequest.HttpContext.Connection.RemoteIpAddress.ToString());
|
||||
httpRequest.HttpContext.GetNormalizedRemoteIp());
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -3,6 +3,7 @@ using System.Collections.Generic;
|
|||
using System.Linq;
|
||||
using System.Net;
|
||||
using Jellyfin.Data.Enums;
|
||||
using MediaBrowser.Common.Extensions;
|
||||
using MediaBrowser.Controller.Net;
|
||||
using MediaBrowser.Controller.Session;
|
||||
using MediaBrowser.Model.Querying;
|
||||
|
@ -119,7 +120,7 @@ namespace Jellyfin.Api.Helpers
|
|||
authorization.Version,
|
||||
authorization.DeviceId,
|
||||
authorization.Device,
|
||||
request.HttpContext.Connection.RemoteIpAddress.ToString(),
|
||||
request.HttpContext.GetNormalizedRemoteIp(),
|
||||
user);
|
||||
|
||||
if (session == null)
|
||||
|
@ -172,10 +173,5 @@ namespace Jellyfin.Api.Helpers
|
|||
.Select(i => i!.Value)
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
internal static IPAddress NormalizeIp(IPAddress ip)
|
||||
{
|
||||
return ip.IsIPv4MappedToIPv6 ? ip.MapToIPv4() : ip;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Reflection;
|
||||
using Jellyfin.Api.Auth;
|
||||
using Jellyfin.Api.Auth.DefaultAuthorizationPolicy;
|
||||
|
@ -28,6 +29,7 @@ using Microsoft.AspNetCore.HttpOverrides;
|
|||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.OpenApi.Models;
|
||||
using Swashbuckle.AspNetCore.SwaggerGen;
|
||||
using AuthenticationSchemes = Jellyfin.Api.Constants.AuthenticationSchemes;
|
||||
|
||||
namespace Jellyfin.Server.Extensions
|
||||
{
|
||||
|
@ -136,8 +138,9 @@ namespace Jellyfin.Server.Extensions
|
|||
/// </summary>
|
||||
/// <param name="serviceCollection">The service collection.</param>
|
||||
/// <param name="pluginAssemblies">An IEnumerable containing all plugin assemblies with API controllers.</param>
|
||||
/// <param name="knownProxies">A list of all known proxies to trust for X-Forwarded-For.</param>
|
||||
/// <returns>The MVC builder.</returns>
|
||||
public static IMvcBuilder AddJellyfinApi(this IServiceCollection serviceCollection, IEnumerable<Assembly> pluginAssemblies)
|
||||
public static IMvcBuilder AddJellyfinApi(this IServiceCollection serviceCollection, IEnumerable<Assembly> pluginAssemblies, IReadOnlyList<string> knownProxies)
|
||||
{
|
||||
IMvcBuilder mvcBuilder = serviceCollection
|
||||
.AddCors()
|
||||
|
@ -145,6 +148,13 @@ namespace Jellyfin.Server.Extensions
|
|||
.Configure<ForwardedHeadersOptions>(options =>
|
||||
{
|
||||
options.ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
|
||||
for (var i = 0; i < knownProxies.Count; i++)
|
||||
{
|
||||
if (IPAddress.TryParse(knownProxies[i], out var address))
|
||||
{
|
||||
options.KnownProxies.Add(address);
|
||||
}
|
||||
}
|
||||
})
|
||||
.AddMvc(opts =>
|
||||
{
|
||||
|
|
|
@ -32,13 +32,13 @@ namespace Jellyfin.Server.Middleware
|
|||
/// <returns>The async task.</returns>
|
||||
public async Task Invoke(HttpContext httpContext, INetworkManager networkManager, IServerConfigurationManager serverConfigurationManager)
|
||||
{
|
||||
if (httpContext.Request.IsLocal())
|
||||
if (httpContext.IsLocal())
|
||||
{
|
||||
await _next(httpContext).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
var remoteIp = httpContext.Request.RemoteIp();
|
||||
var remoteIp = httpContext.GetNormalizedRemoteIp();
|
||||
|
||||
if (serverConfigurationManager.Configuration.EnableRemoteAccess)
|
||||
{
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Common.Extensions;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Http.Extensions;
|
||||
|
@ -69,7 +70,7 @@ namespace Jellyfin.Server.Middleware
|
|||
_logger.LogWarning(
|
||||
"Slow HTTP Response from {url} to {remoteIp} in {elapsed:g} with Status Code {statusCode}",
|
||||
context.Request.GetDisplayUrl(),
|
||||
context.Connection.RemoteIpAddress,
|
||||
context.GetNormalizedRemoteIp(),
|
||||
watch.Elapsed,
|
||||
context.Response.StatusCode);
|
||||
}
|
||||
|
|
|
@ -52,7 +52,7 @@ namespace Jellyfin.Server
|
|||
{
|
||||
options.HttpsPort = _serverApplicationHost.HttpsPort;
|
||||
});
|
||||
services.AddJellyfinApi(_serverApplicationHost.GetApiPluginAssemblies());
|
||||
services.AddJellyfinApi(_serverApplicationHost.GetApiPluginAssemblies(), _serverConfigurationManager.Configuration.KnownProxies);
|
||||
|
||||
services.AddJellyfinApiSwagger();
|
||||
|
||||
|
@ -103,6 +103,7 @@ namespace Jellyfin.Server
|
|||
mainApp.UseDeveloperExceptionPage();
|
||||
}
|
||||
|
||||
mainApp.UseForwardedHeaders();
|
||||
mainApp.UseMiddleware<ExceptionMiddleware>();
|
||||
|
||||
mainApp.UseMiddleware<ResponseTimeMiddleware>();
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
using System.Net;
|
||||
using MediaBrowser.Common.Net;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace MediaBrowser.Common.Extensions
|
||||
|
@ -10,54 +9,33 @@ namespace MediaBrowser.Common.Extensions
|
|||
public static class HttpContextExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Checks the origin of the HTTP request.
|
||||
/// Checks the origin of the HTTP context.
|
||||
/// </summary>
|
||||
/// <param name="request">The incoming HTTP request.</param>
|
||||
/// <param name="context">The incoming HTTP context.</param>
|
||||
/// <returns><c>true</c> if the request is coming from LAN, <c>false</c> otherwise.</returns>
|
||||
public static bool IsLocal(this HttpRequest request)
|
||||
public static bool IsLocal(this HttpContext context)
|
||||
{
|
||||
return (request.HttpContext.Connection.LocalIpAddress == null
|
||||
&& request.HttpContext.Connection.RemoteIpAddress == null)
|
||||
|| request.HttpContext.Connection.LocalIpAddress.Equals(request.HttpContext.Connection.RemoteIpAddress);
|
||||
return (context.Connection.LocalIpAddress == null
|
||||
&& context.Connection.RemoteIpAddress == null)
|
||||
|| context.Connection.LocalIpAddress.Equals(context.Connection.RemoteIpAddress);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Extracts the remote IP address of the caller of the HTTP request.
|
||||
/// Extracts the remote IP address of the caller of the HTTP context.
|
||||
/// </summary>
|
||||
/// <param name="request">The HTTP request.</param>
|
||||
/// <param name="context">The HTTP context.</param>
|
||||
/// <returns>The remote caller IP address.</returns>
|
||||
public static string RemoteIp(this HttpRequest request)
|
||||
public static string GetNormalizedRemoteIp(this HttpContext context)
|
||||
{
|
||||
var cachedRemoteIp = request.HttpContext.Items["RemoteIp"]?.ToString();
|
||||
if (!string.IsNullOrEmpty(cachedRemoteIp))
|
||||
{
|
||||
return cachedRemoteIp;
|
||||
}
|
||||
|
||||
IPAddress ip;
|
||||
|
||||
// "Real" remote ip might be in X-Forwarded-For of X-Real-Ip
|
||||
// (if the server is behind a reverse proxy for example)
|
||||
if (!IPAddress.TryParse(request.Headers[CustomHeaderNames.XForwardedFor].ToString(), out ip))
|
||||
{
|
||||
if (!IPAddress.TryParse(request.Headers[CustomHeaderNames.XRealIP].ToString(), out ip))
|
||||
{
|
||||
ip = request.HttpContext.Connection.RemoteIpAddress;
|
||||
|
||||
// Default to the loopback address if no RemoteIpAddress is specified (i.e. during integration tests)
|
||||
ip ??= IPAddress.Loopback;
|
||||
}
|
||||
}
|
||||
// Default to the loopback address if no RemoteIpAddress is specified (i.e. during integration tests)
|
||||
var ip = context.Connection.RemoteIpAddress ?? IPAddress.Loopback;
|
||||
|
||||
if (ip.IsIPv4MappedToIPv6)
|
||||
{
|
||||
ip = ip.MapToIPv4();
|
||||
}
|
||||
|
||||
var normalizedIp = ip.ToString();
|
||||
|
||||
request.HttpContext.Items["RemoteIp"] = normalizedIp;
|
||||
return normalizedIp;
|
||||
return ip.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -268,6 +268,11 @@ namespace MediaBrowser.Model.Configuration
|
|||
/// </summary>
|
||||
public string[] CorsHosts { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the known proxies.
|
||||
/// </summary>
|
||||
public string[] KnownProxies { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ServerConfiguration" /> class.
|
||||
/// </summary>
|
||||
|
@ -378,6 +383,7 @@ namespace MediaBrowser.Model.Configuration
|
|||
EnableSlowResponseWarning = true;
|
||||
SlowResponseThresholdMs = 500;
|
||||
CorsHosts = new[] { "*" };
|
||||
KnownProxies = Array.Empty<string>();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user