diff --git a/frontend/src/Settings/General/SecuritySettings.js b/frontend/src/Settings/General/SecuritySettings.js index 8e2597741..dcac948a7 100644 --- a/frontend/src/Settings/General/SecuritySettings.js +++ b/frontend/src/Settings/General/SecuritySettings.js @@ -30,7 +30,9 @@ export const authenticationMethodOptions = [ key: 'basic', get value() { return translate('AuthBasic'); - } + }, + isDisabled: true, + isHidden: true }, { key: 'forms', diff --git a/src/NzbDrone.Core/Authentication/AuthenticationType.cs b/src/NzbDrone.Core/Authentication/AuthenticationType.cs index ca408774b..6748ff0a3 100644 --- a/src/NzbDrone.Core/Authentication/AuthenticationType.cs +++ b/src/NzbDrone.Core/Authentication/AuthenticationType.cs @@ -1,8 +1,11 @@ +using System; + namespace NzbDrone.Core.Authentication { public enum AuthenticationType { None = 0, + [Obsolete("Use Forms authentication instead")] Basic = 1, Forms = 2, External = 3 diff --git a/src/NzbDrone.Core/Configuration/ConfigFileProvider.cs b/src/NzbDrone.Core/Configuration/ConfigFileProvider.cs index f4715b203..4776240fc 100644 --- a/src/NzbDrone.Core/Configuration/ConfigFileProvider.cs +++ b/src/NzbDrone.Core/Configuration/ConfigFileProvider.cs @@ -207,8 +207,8 @@ namespace NzbDrone.Core.Configuration if (enabled) { - SetValue("AuthenticationMethod", AuthenticationType.Basic); - return AuthenticationType.Basic; + SetValue("AuthenticationMethod", AuthenticationType.Forms); + return AuthenticationType.Forms; } return Enum.TryParse(_authOptions.Method, out var enumValue) diff --git a/src/Prowlarr.Api.V1/Config/HostConfigController.cs b/src/Prowlarr.Api.V1/Config/HostConfigController.cs index a844f8d2e..0b4594499 100644 --- a/src/Prowlarr.Api.V1/Config/HostConfigController.cs +++ b/src/Prowlarr.Api.V1/Config/HostConfigController.cs @@ -41,10 +41,14 @@ namespace Prowlarr.Api.V1.Config SharedValidator.RuleFor(c => c.UrlBase).ValidUrlBase(); SharedValidator.RuleFor(c => c.InstanceName).ContainsProwlarr().When(c => c.InstanceName.IsNotNullOrWhiteSpace()); - SharedValidator.RuleFor(c => c.Username).NotEmpty().When(c => c.AuthenticationMethod == AuthenticationType.Basic || - c.AuthenticationMethod == AuthenticationType.Forms); - SharedValidator.RuleFor(c => c.Password).NotEmpty().When(c => c.AuthenticationMethod == AuthenticationType.Basic || - c.AuthenticationMethod == AuthenticationType.Forms); + SharedValidator.RuleFor(c => c.Username).NotEmpty().When(c => c.AuthenticationMethod == AuthenticationType.Forms); + SharedValidator.RuleFor(c => c.Password).NotEmpty().When(c => c.AuthenticationMethod == AuthenticationType.Forms); + + SharedValidator.RuleFor(c => c.AuthenticationMethod) +#pragma warning disable CS0618 // Type or member is obsolete + .NotEqual(AuthenticationType.Basic) +#pragma warning restore CS0618 // Type or member is obsolete + .WithMessage("'Basic' is no longer supported, switch to 'Forms' instead."); SharedValidator.RuleFor(c => c.PasswordConfirmation) .Must((resource, p) => IsMatchingPassword(resource)).WithMessage("Must match Password"); diff --git a/src/Prowlarr.Http/Authentication/AuthenticationBuilderExtensions.cs b/src/Prowlarr.Http/Authentication/AuthenticationBuilderExtensions.cs index 318f22929..c79245991 100644 --- a/src/Prowlarr.Http/Authentication/AuthenticationBuilderExtensions.cs +++ b/src/Prowlarr.Http/Authentication/AuthenticationBuilderExtensions.cs @@ -18,11 +18,6 @@ namespace Prowlarr.Http.Authentication return authenticationBuilder.AddScheme(name, options); } - public static AuthenticationBuilder AddBasic(this AuthenticationBuilder authenticationBuilder, string name) - { - return authenticationBuilder.AddScheme(name, options => { }); - } - public static AuthenticationBuilder AddNone(this AuthenticationBuilder authenticationBuilder, string name) { return authenticationBuilder.AddScheme(name, options => { }); @@ -54,7 +49,9 @@ namespace Prowlarr.Http.Authentication return services.AddAuthentication() .AddNone(AuthenticationType.None.ToString()) .AddExternal(AuthenticationType.External.ToString()) - .AddBasic(AuthenticationType.Basic.ToString()) +#pragma warning disable CS0618 // Type or member is obsolete + .AddCookie(AuthenticationType.Basic.ToString()) +#pragma warning restore CS0618 // Type or member is obsolete .AddCookie(AuthenticationType.Forms.ToString()) .AddApiKey("API", options => { diff --git a/src/Prowlarr.Http/Authentication/BasicAuthenticationHandler.cs b/src/Prowlarr.Http/Authentication/BasicAuthenticationHandler.cs deleted file mode 100644 index 60b7b3fd8..000000000 --- a/src/Prowlarr.Http/Authentication/BasicAuthenticationHandler.cs +++ /dev/null @@ -1,84 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Security.Claims; -using System.Text; -using System.Text.Encodings.Web; -using System.Text.RegularExpressions; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Authentication; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; -using NzbDrone.Common.EnvironmentInfo; -using NzbDrone.Core.Authentication; - -namespace Prowlarr.Http.Authentication -{ - public class BasicAuthenticationHandler : AuthenticationHandler - { - private readonly IAuthenticationService _authService; - - public BasicAuthenticationHandler(IAuthenticationService authService, - IOptionsMonitor options, - ILoggerFactory logger, - UrlEncoder encoder) - : base(options, logger, encoder) - { - _authService = authService; - } - - protected override Task HandleAuthenticateAsync() - { - if (!Request.Headers.ContainsKey("Authorization")) - { - return Task.FromResult(AuthenticateResult.Fail("Authorization header missing.")); - } - - // Get authorization key - var authorizationHeader = Request.Headers["Authorization"].ToString(); - var authHeaderRegex = new Regex(@"Basic (.*)"); - - if (!authHeaderRegex.IsMatch(authorizationHeader)) - { - return Task.FromResult(AuthenticateResult.Fail("Authorization code not formatted properly.")); - } - - var authBase64 = Encoding.UTF8.GetString(Convert.FromBase64String(authHeaderRegex.Replace(authorizationHeader, "$1"))); - var authSplit = authBase64.Split(':', 2); - var authUsername = authSplit[0]; - var authPassword = authSplit.Length > 1 ? authSplit[1] : throw new Exception("Unable to get password"); - - var user = _authService.Login(Request, authUsername, authPassword); - - if (user == null) - { - return Task.FromResult(AuthenticateResult.Fail("The username or password is not correct.")); - } - - var claims = new List - { - new Claim("user", user.Username), - new Claim("identifier", user.Identifier.ToString()), - new Claim("AuthType", AuthenticationType.Basic.ToString()) - }; - - var identity = new ClaimsIdentity(claims, "Basic", "user", "identifier"); - var principal = new ClaimsPrincipal(identity); - var ticket = new AuthenticationTicket(principal, "Basic"); - - return Task.FromResult(AuthenticateResult.Success(ticket)); - } - - protected override Task HandleChallengeAsync(AuthenticationProperties properties) - { - Response.Headers["WWW-Authenticate"] = $"Basic realm=\"{BuildInfo.AppName}\""; - Response.StatusCode = 401; - return Task.CompletedTask; - } - - protected override Task HandleForbiddenAsync(AuthenticationProperties properties) - { - Response.StatusCode = 403; - return Task.CompletedTask; - } - } -}