Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Known Proxies to system configuration #4116

Merged
merged 3 commits into from Sep 10, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -28,7 +28,7 @@ public SessionInfo GetSession(HttpContext requestContext)
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)
Expand Down
3 changes: 2 additions & 1 deletion Jellyfin.Api/Auth/BaseAuthorizationHandler.cs
@@ -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;
Expand Down Expand Up @@ -69,7 +70,7 @@ public abstract class BaseAuthorizationHandler<T> : AuthorizationHandler<T>
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)
Expand Down
3 changes: 2 additions & 1 deletion Jellyfin.Api/Controllers/MediaInfoController.cs
Expand Up @@ -8,6 +8,7 @@
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;
Expand Down Expand Up @@ -164,7 +165,7 @@ public async Task<ActionResult<PlaybackInfoResponse>> GetPlaybackInfo([FromRoute
enableTranscoding,
allowVideoStreamCopy,
allowAudioStreamCopy,
Request.HttpContext.Connection.RemoteIpAddress.ToString());
Request.HttpContext.GetNormalizedRemoteIp());
}

_mediaInfoHelper.SortMediaSources(info, maxStreamingBitrate);
Expand Down
5 changes: 3 additions & 2 deletions Jellyfin.Api/Controllers/SystemController.cs
Expand Up @@ -7,6 +7,7 @@
using System.Threading.Tasks;
using Jellyfin.Api.Constants;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.Extensions;
using MediaBrowser.Common.Net;
using MediaBrowser.Controller;
using MediaBrowser.Controller.Configuration;
Expand Down Expand Up @@ -176,8 +177,8 @@ public ActionResult<EndPointInfo> GetEndpointInfo()
{
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())
};
}

Expand Down
3 changes: 2 additions & 1 deletion Jellyfin.Api/Controllers/UniversalAudioController.cs
Expand Up @@ -7,6 +7,7 @@
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;
Expand Down Expand Up @@ -158,7 +159,7 @@ public class UniversalAudioController : BaseJellyfinApiController
true,
true,
true,
Request.HttpContext.Connection.RemoteIpAddress.ToString());
Request.HttpContext.GetNormalizedRemoteIp());
}

_mediaInfoHelper.SortMediaSources(info, maxStreamingBitrate);
Expand Down
21 changes: 11 additions & 10 deletions Jellyfin.Api/Controllers/UserController.cs
Expand Up @@ -7,6 +7,7 @@
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;
Expand Down Expand Up @@ -117,7 +118,7 @@ public ActionResult<UserDto> GetUserById([FromRoute, Required] Guid userId)
return NotFound("User not found");
}

var result = _userManager.GetUserDto(user, HttpContext.Connection.RemoteIpAddress.ToString());
var result = _userManager.GetUserDto(user, HttpContext.GetNormalizedRemoteIp());
return result;
}

Expand Down Expand Up @@ -203,7 +204,7 @@ public async Task<ActionResult<AuthenticationResult>> AuthenticateUserByName([Fr
DeviceName = auth.Device,
Password = request.Pw,
PasswordSha1 = request.Password,
RemoteEndPoint = HttpContext.Connection.RemoteIpAddress.ToString(),
RemoteEndPoint = HttpContext.GetNormalizedRemoteIp(),
Username = request.Username
}).ConfigureAwait(false);

Expand All @@ -212,7 +213,7 @@ public async Task<ActionResult<AuthenticationResult>> AuthenticateUserByName([Fr
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);
}
}

Expand Down Expand Up @@ -246,7 +247,7 @@ public async Task<ActionResult<AuthenticationResult>> AuthenticateWithQuickConne
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);
}
}

Expand Down Expand Up @@ -290,7 +291,7 @@ public async Task<ActionResult<AuthenticationResult>> AuthenticateWithQuickConne
user.Username,
request.CurrentPw,
request.CurrentPw,
HttpContext.Connection.RemoteIpAddress.ToString(),
HttpContext.GetNormalizedRemoteIp(),
false).ConfigureAwait(false);

if (success == null)
Expand Down Expand Up @@ -496,7 +497,7 @@ public async Task<ActionResult<UserDto>> CreateUserByName([FromBody] CreateUserB
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;
}
Expand All @@ -511,8 +512,8 @@ public async Task<ActionResult<UserDto>> CreateUserByName([FromBody] CreateUserB
[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);

Expand Down Expand Up @@ -559,15 +560,15 @@ private IEnumerable<UserDto> Get(bool? isHidden, bool? isDisabled, bool filterBy

if (filterByNetwork)
{
if (!_networkManager.IsInLocalNetwork(HttpContext.Connection.RemoteIpAddress.ToString()))
if (!_networkManager.IsInLocalNetwork(HttpContext.GetNormalizedRemoteIp()))
{
users = users.Where(i => i.HasPermission(PermissionKind.EnableRemoteAccess));
}
}

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;
}
Expand Down
10 changes: 5 additions & 5 deletions Jellyfin.Api/Helpers/DynamicHlsHelper.cs
Expand Up @@ -8,6 +8,7 @@
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;
Expand Down Expand Up @@ -198,12 +199,12 @@ public class DynamicHlsHelper

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;

Expand Down Expand Up @@ -334,11 +335,10 @@ private void AppendPlaylistFramerateField(StringBuilder builder, StreamState sta
}
}

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;
}
Expand Down
3 changes: 2 additions & 1 deletion Jellyfin.Api/Helpers/MediaInfoHelper.cs
Expand Up @@ -6,6 +6,7 @@
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;
Expand Down Expand Up @@ -498,7 +499,7 @@ public async Task<LiveStreamResponse> OpenMediaSource(HttpRequest httpRequest, L
true,
true,
true,
httpRequest.HttpContext.Connection.RemoteIpAddress.ToString());
httpRequest.HttpContext.GetNormalizedRemoteIp());
}
else
{
Expand Down
8 changes: 2 additions & 6 deletions Jellyfin.Api/Helpers/RequestHelpers.cs
Expand Up @@ -3,6 +3,7 @@
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;
Expand Down Expand Up @@ -119,7 +120,7 @@ internal static SessionInfo GetSession(ISessionManager sessionManager, IAuthoriz
authorization.Version,
authorization.DeviceId,
authorization.Device,
request.HttpContext.Connection.RemoteIpAddress.ToString(),
request.HttpContext.GetNormalizedRemoteIp(),
user);

if (session == null)
Expand Down Expand Up @@ -172,10 +173,5 @@ internal static ItemFields[] GetItemFields(string? fields)
.Select(i => i!.Value)
.ToArray();
}

internal static IPAddress NormalizeIp(IPAddress ip)
{
return ip.IsIPv4MappedToIPv6 ? ip.MapToIPv4() : ip;
}
}
}
13 changes: 11 additions & 2 deletions Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs
Expand Up @@ -2,6 +2,7 @@
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;
Expand All @@ -17,7 +18,6 @@
using Jellyfin.Api.Controllers;
using Jellyfin.Server.Configuration;
using Jellyfin.Server.Formatters;
using Jellyfin.Server.Middleware;
using MediaBrowser.Common.Json;
using MediaBrowser.Model.Entities;
using Microsoft.AspNetCore.Authentication;
Expand All @@ -28,6 +28,7 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.SwaggerGen;
using AuthenticationSchemes = Jellyfin.Api.Constants.AuthenticationSchemes;

namespace Jellyfin.Server.Extensions
{
Expand Down Expand Up @@ -136,15 +137,23 @@ public static AuthenticationBuilder AddCustomAuthentication(this IServiceCollect
/// </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()
.AddTransient<ICorsPolicyProvider, CorsPolicyProvider>()
.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 =>
{
Expand Down
Expand Up @@ -32,13 +32,13 @@ public IpBasedAccessValidationMiddleware(RequestDelegate next)
/// <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)
{
Expand Down
3 changes: 2 additions & 1 deletion Jellyfin.Server/Middleware/ResponseTimeMiddleware.cs
@@ -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;
Expand Down Expand Up @@ -69,7 +70,7 @@ private void LogWarning(HttpContext context, Stopwatch watch)
_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);
}
Expand Down
3 changes: 2 additions & 1 deletion Jellyfin.Server/Startup.cs
Expand Up @@ -52,7 +52,7 @@ public void ConfigureServices(IServiceCollection services)
{
options.HttpsPort = _serverApplicationHost.HttpsPort;
});
services.AddJellyfinApi(_serverApplicationHost.GetApiPluginAssemblies());
services.AddJellyfinApi(_serverApplicationHost.GetApiPluginAssemblies(), _serverConfigurationManager.Configuration.KnownProxies);

services.AddJellyfinApiSwagger();

Expand Down Expand Up @@ -103,6 +103,7 @@ public void ConfigureServices(IServiceCollection services)
mainApp.UseDeveloperExceptionPage();
}

mainApp.UseForwardedHeaders();
mainApp.UseMiddleware<ExceptionMiddleware>();

mainApp.UseMiddleware<ResponseTimeMiddleware>();
Expand Down