New: Setting to disable authentication for local addresses

(cherry picked from commit b154b00c6156512e7fbd0a2c4833c116a74f23ca)
sonarr-pull-b154b00c
Mark McDowall 2 years ago committed by Bogdan
parent ce820f6f73
commit 03ed01e7d8

@ -17,6 +17,11 @@ const authenticationMethodOptions = [
{ key: 'forms', value: 'Forms (Login Page)' }
];
const authenticationRequiredOptions = [
{ key: 'enabled', value: 'Enabled' },
{ key: 'disabledForLocalAddresses', value: 'Disabled for Local Addresses' }
];
const certificateValidationOptions = [
{ key: 'enabled', value: 'Enabled' },
{ key: 'disabledForLocalAddresses', value: 'Disabled for Local Addresses' },
@ -68,6 +73,7 @@ class SecuritySettings extends Component {
const {
authenticationMethod,
authenticationRequired,
username,
password,
apiKey,
@ -94,7 +100,24 @@ class SecuritySettings extends Component {
</FormGroup>
{
authenticationEnabled &&
authenticationEnabled ?
<FormGroup>
<FormLabel>Authentication Required</FormLabel>
<FormInputGroup
type={inputTypes.SELECT}
name="authenticationRequired"
values={authenticationRequiredOptions}
helpText="Change which requests authentication is required for. Do not change unless you understand the risks."
onChange={onInputChange}
{...authenticationRequired}
/>
</FormGroup> :
null
}
{
authenticationEnabled ?
<FormGroup>
<FormLabel>
{translate('Username')}
@ -106,11 +129,12 @@ class SecuritySettings extends Component {
onChange={onInputChange}
{...username}
/>
</FormGroup>
</FormGroup> :
null
}
{
authenticationEnabled &&
authenticationEnabled ?
<FormGroup>
<FormLabel>
{translate('Password')}
@ -122,7 +146,8 @@ class SecuritySettings extends Component {
onChange={onInputChange}
{...password}
/>
</FormGroup>
</FormGroup> :
null
}
<FormGroup>

@ -46,7 +46,7 @@ namespace NzbDrone.Automation.Test
_runner = new NzbDroneRunner(LogManager.GetCurrentClassLogger(), null);
_runner.KillAll();
_runner.Start();
_runner.Start(true);
driver.Url = "http://localhost:8787";

@ -0,0 +1,8 @@
namespace NzbDrone.Core.Authentication
{
public enum AuthenticationRequiredType
{
Enabled = 0,
DisabledForLocalAddresses = 1
}
}

@ -1,9 +1,10 @@
namespace NzbDrone.Core.Authentication
namespace NzbDrone.Core.Authentication
{
public enum AuthenticationType
{
None = 0,
Basic = 1,
Forms = 2
Forms = 2,
External = 3
}
}

@ -32,6 +32,7 @@ namespace NzbDrone.Core.Configuration
bool EnableSsl { get; }
bool LaunchBrowser { get; }
AuthenticationType AuthenticationMethod { get; }
AuthenticationRequiredType AuthenticationRequired { get; }
bool AnalyticsEnabled { get; }
string LogLevel { get; }
string ConsoleLogLevel { get; }
@ -190,6 +191,8 @@ namespace NzbDrone.Core.Configuration
}
}
public AuthenticationRequiredType AuthenticationRequired => GetValueEnum("AuthenticationRequired", AuthenticationRequiredType.Enabled);
public bool AnalyticsEnabled => GetValueBoolean("AnalyticsEnabled", true, persist: false);
// TODO: Change back to "master" for the first stable release

@ -171,6 +171,8 @@ namespace NzbDrone.Host
.PersistKeysToFileSystem(new DirectoryInfo(Configuration["dataProtectionFolder"]));
services.AddSingleton<IAuthorizationPolicyProvider, UiAuthorizationPolicyProvider>();
services.AddSingleton<IAuthorizationHandler, UiAuthorizationHandler>();
services.AddAuthorization(options =>
{
options.AddPolicy("SignalR", policy =>

@ -38,12 +38,12 @@ namespace NzbDrone.Test.Common
Port = port;
}
public void Start()
public void Start(bool enableAuth = false)
{
AppData = Path.Combine(TestContext.CurrentContext.TestDirectory, "_intg_" + TestBase.GetUID());
Directory.CreateDirectory(AppData);
GenerateConfigFile();
GenerateConfigFile(enableAuth);
string readarrConsoleExe;
if (OsInfo.IsWindows)
@ -178,7 +178,7 @@ namespace NzbDrone.Test.Common
}
}
private void GenerateConfigFile()
private void GenerateConfigFile(bool enableAuth)
{
var configFile = Path.Combine(AppData, "config.xml");
@ -191,6 +191,8 @@ namespace NzbDrone.Test.Common
new XElement(nameof(ConfigFileProvider.ApiKey), apiKey),
new XElement(nameof(ConfigFileProvider.LogLevel), "trace"),
new XElement(nameof(ConfigFileProvider.AnalyticsEnabled), false),
new XElement(nameof(ConfigFileProvider.AuthenticationMethod), enableAuth ? "Forms" : "None"),
new XElement(nameof(ConfigFileProvider.AuthenticationRequired), "DisabledForLocalAddresses"),
new XElement(nameof(ConfigFileProvider.Port), Port)));
var data = xDoc.ToString();

@ -15,6 +15,7 @@ namespace Readarr.Api.V1.Config
public bool EnableSsl { get; set; }
public bool LaunchBrowser { get; set; }
public AuthenticationType AuthenticationMethod { get; set; }
public AuthenticationRequiredType AuthenticationRequired { get; set; }
public bool AnalyticsEnabled { get; set; }
public string Username { get; set; }
public string Password { get; set; }
@ -57,6 +58,7 @@ namespace Readarr.Api.V1.Config
EnableSsl = model.EnableSsl,
LaunchBrowser = model.LaunchBrowser,
AuthenticationMethod = model.AuthenticationMethod,
AuthenticationRequired = model.AuthenticationRequired,
AnalyticsEnabled = model.AnalyticsEnabled,
//Username

@ -13,6 +13,7 @@ namespace Readarr.Http.Authentication
public class ApiKeyAuthenticationOptions : AuthenticationSchemeOptions
{
public const string DefaultScheme = "API Key";
public string Scheme => DefaultScheme;
public string AuthenticationType = DefaultScheme;

@ -22,10 +22,16 @@ namespace Readarr.Http.Authentication
return authenticationBuilder.AddScheme<AuthenticationSchemeOptions, NoAuthenticationHandler>(name, options => { });
}
public static AuthenticationBuilder AddExternal(this AuthenticationBuilder authenticationBuilder, string name)
{
return authenticationBuilder.AddScheme<AuthenticationSchemeOptions, NoAuthenticationHandler>(name, options => { });
}
public static AuthenticationBuilder AddAppAuthentication(this IServiceCollection services)
{
return services.AddAuthentication()
.AddNone(AuthenticationType.None.ToString())
.AddExternal(AuthenticationType.External.ToString())
.AddBasic(AuthenticationType.Basic.ToString())
.AddCookie(AuthenticationType.Forms.ToString(), options =>
{

@ -0,0 +1,8 @@
using Microsoft.AspNetCore.Authorization.Infrastructure;
namespace NzbDrone.Http.Authentication
{
public class BypassableDenyAnonymousAuthorizationRequirement : DenyAnonymousAuthorizationRequirement
{
}
}

@ -0,0 +1,45 @@
using System.Net;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using NzbDrone.Common.Extensions;
using NzbDrone.Core.Authentication;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Configuration.Events;
using NzbDrone.Core.Messaging.Events;
using Readarr.Http.Extensions;
namespace NzbDrone.Http.Authentication
{
public class UiAuthorizationHandler : AuthorizationHandler<BypassableDenyAnonymousAuthorizationRequirement>, IAuthorizationRequirement, IHandle<ConfigSavedEvent>
{
private readonly IConfigFileProvider _configService;
private static AuthenticationRequiredType _authenticationRequired;
public UiAuthorizationHandler(IConfigFileProvider configService)
{
_configService = configService;
_authenticationRequired = configService.AuthenticationRequired;
}
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, BypassableDenyAnonymousAuthorizationRequirement requirement)
{
if (_authenticationRequired == AuthenticationRequiredType.DisabledForLocalAddresses)
{
if (context.Resource is HttpContext httpContext &&
IPAddress.TryParse(httpContext.GetRemoteIP(), out var ipAddress) &&
ipAddress.IsLocalAddress())
{
context.Succeed(requirement);
}
}
return Task.CompletedTask;
}
public void Handle(ConfigSavedEvent message)
{
_authenticationRequired = _configService.AuthenticationRequired;
}
}
}

@ -29,7 +29,8 @@ namespace NzbDrone.Http.Authentication
if (policyName.Equals(POLICY_NAME, StringComparison.OrdinalIgnoreCase))
{
var policy = new AuthorizationPolicyBuilder(_config.AuthenticationMethod.ToString())
.RequireAuthenticatedUser();
.AddRequirements(new BypassableDenyAnonymousAuthorizationRequirement());
return Task.FromResult(policy.Build());
}

Loading…
Cancel
Save