From c8de3fb097f437fdf9c73b937106a0e2ce8a2b74 Mon Sep 17 00:00:00 2001 From: Joseph Milazzo Date: Mon, 31 Jan 2022 05:42:06 -0800 Subject: [PATCH] Remove No Authentication mode from Kavita (#1006) * Moved the Server Settings out into a button on nav header * Refactored Mange Users page to the new design (skeleton). Implemented skeleton code for Invite User. * Hashed out more of the code, but need to move all the email code to a Kavita controlled API server due to password credentials. * Cleaned up some warnings * When no user exists for an api key in Plugin controller, throw 401. * Hooked in the ability to check if the Kavita instance can be accessed externally so we can determine if the user can invite or not. * Hooked up some logic if the user's server isn't accessible, then default to old flow * Basic flow is working for confirm email. Needs validation, error handling, etc. * Refactored Password validation to account service * Cleaned up the code in confirm-email to work much better. * Refactored the login page to have a container functionality, so we can reuse the styles on multiple pages (registration pages). Hooked up the code for confirm email. * Messy code, but making progress. Refactored Register to be used only for first time user registration. Added a new register component to handle first time flow only. * Invite works much better, still needs a bit of work for non-accessible server setup. Started work on underlying manage users page to meet new design. * Changed (you) to a star to indicate who you're logged in as. * Inviting a user is now working and tested fully. * Removed the register member component as we now have invite and confirm components. * Editing a user is now working. Username change and Role/Library access from within one screen. Email changing is on hold. * Cleaned up code for edit user and disabled email field for now. * Cleaned up the code to indicate changing a user's email is not possible. * Implemented a migration for existing accounts so they can validate their emails and still login. * Change url for email server * Implemented the ability to resend an email confirmation code (or regenerate for non accessible servers). Fixed an overflow on the confirm dialog. * Removed all code around disabling authentication. Users that were already disabled can look up their password on the wiki. --- API/Controllers/AccountController.cs | 8 - API/Controllers/SettingsController.cs | 34 +---- API/Controllers/UsersController.cs | 16 -- API/DTOs/Settings/ServerSettingDTO.cs | 5 - API/Entities/Enums/ServerSettingKey.cs | 1 + .../Converters/ServerSettingConverter.cs | 3 - API/Services/DirectoryService.cs | 5 +- .../src/app/admin/_models/server-settings.ts | 1 - .../manage-settings.component.html | 9 -- .../manage-settings.component.ts | 14 -- UI/Web/src/app/admin/settings.service.ts | 6 - UI/Web/src/app/app.module.ts | 2 + .../app/registration/registration.module.ts | 3 + .../app/user-login/user-login.component.html | 56 +++---- .../app/user-login/user-login.component.scss | 137 +++++++++--------- .../app/user-login/user-login.component.ts | 81 ++--------- .../user-preferences.component.html | 5 +- .../user-preferences.component.ts | 4 - 18 files changed, 117 insertions(+), 273 deletions(-) diff --git a/API/Controllers/AccountController.cs b/API/Controllers/AccountController.cs index ada167f1a..0905fe2f2 100644 --- a/API/Controllers/AccountController.cs +++ b/API/Controllers/AccountController.cs @@ -191,14 +191,6 @@ namespace API.Controllers "You are missing an email on your account. Please wait while we migrate your account."); } - var isAdmin = await _unitOfWork.UserRepository.IsUserAdminAsync(user); - var settings = await _unitOfWork.SettingsRepository.GetSettingsDtoAsync(); - if (!settings.EnableAuthentication && !isAdmin) - { - _logger.LogDebug("User {UserName} is logging in with authentication disabled", loginDto.Username); - loginDto.Password = AccountService.DefaultPassword; - } - var result = await _signInManager .CheckPasswordSignInAsync(user, loginDto.Password, false); diff --git a/API/Controllers/SettingsController.cs b/API/Controllers/SettingsController.cs index 76b30acf8..ec6be6145 100644 --- a/API/Controllers/SettingsController.cs +++ b/API/Controllers/SettingsController.cs @@ -23,17 +23,15 @@ namespace API.Controllers private readonly ILogger _logger; private readonly IUnitOfWork _unitOfWork; private readonly ITaskScheduler _taskScheduler; - private readonly IAccountService _accountService; private readonly IDirectoryService _directoryService; private readonly IMapper _mapper; public SettingsController(ILogger logger, IUnitOfWork unitOfWork, ITaskScheduler taskScheduler, - IAccountService accountService, IDirectoryService directoryService, IMapper mapper) + IDirectoryService directoryService, IMapper mapper) { _logger = logger; _unitOfWork = unitOfWork; _taskScheduler = taskScheduler; - _accountService = accountService; _directoryService = directoryService; _mapper = mapper; } @@ -84,7 +82,6 @@ namespace API.Controllers // We do not allow CacheDirectory changes, so we will ignore. var currentSettings = await _unitOfWork.SettingsRepository.GetSettingsAsync(); - var updateAuthentication = false; var updateBookmarks = false; var originalBookmarkDirectory = _directoryService.BookmarkDirectory; @@ -163,13 +160,6 @@ namespace API.Controllers } - if (setting.Key == ServerSettingKey.EnableAuthentication && updateSettingsDto.EnableAuthentication + string.Empty != setting.Value) - { - setting.Value = updateSettingsDto.EnableAuthentication + string.Empty; - _unitOfWork.SettingsRepository.Update(setting); - updateAuthentication = true; - } - if (setting.Key == ServerSettingKey.AllowStatCollection && updateSettingsDto.AllowStatCollection + string.Empty != setting.Value) { setting.Value = updateSettingsDto.AllowStatCollection + string.Empty; @@ -191,21 +181,6 @@ namespace API.Controllers { await _unitOfWork.CommitAsync(); - if (updateAuthentication) - { - var users = await _unitOfWork.UserRepository.GetNonAdminUsersAsync(); - foreach (var user in users) - { - var errors = await _accountService.ChangeUserPassword(user, AccountService.DefaultPassword); - if (!errors.Any()) continue; - - await _unitOfWork.RollbackAsync(); - return BadRequest(errors); - } - - _logger.LogInformation("Server authentication changed. Updated all non-admins to default password"); - } - if (updateBookmarks) { _directoryService.ExistOrCreate(bookmarkDirectory); @@ -253,12 +228,5 @@ namespace API.Controllers var settingsDto = await _unitOfWork.SettingsRepository.GetSettingsDtoAsync(); return Ok(settingsDto.EnableOpds); } - - [HttpGet("authentication-enabled")] - public async Task> GetAuthenticationEnabled() - { - var settingsDto = await _unitOfWork.SettingsRepository.GetSettingsDtoAsync(); - return Ok(settingsDto.EnableAuthentication); - } } } diff --git a/API/Controllers/UsersController.cs b/API/Controllers/UsersController.cs index 2f469309e..dd6e975ab 100644 --- a/API/Controllers/UsersController.cs +++ b/API/Controllers/UsersController.cs @@ -47,21 +47,6 @@ namespace API.Controllers } - - [AllowAnonymous] - [HttpGet("names")] - public async Task>> GetUserNames() - { - // This is only for disabled auth flow - being removed - var setting = await _unitOfWork.SettingsRepository.GetSettingsDtoAsync(); - if (setting.EnableAuthentication) - { - return Unauthorized("This API cannot be used given your server's configuration"); - } - var members = await _unitOfWork.UserRepository.GetEmailConfirmedMemberDtosAsync(); - return Ok(members.Select(m => m.Username)); - } - [HttpGet("has-reading-progress")] public async Task> HasReadingProgress(int libraryId) { @@ -104,6 +89,5 @@ namespace API.Controllers return BadRequest("There was an issue saving preferences."); } - } } diff --git a/API/DTOs/Settings/ServerSettingDTO.cs b/API/DTOs/Settings/ServerSettingDTO.cs index 4004c65b1..e8abd2b74 100644 --- a/API/DTOs/Settings/ServerSettingDTO.cs +++ b/API/DTOs/Settings/ServerSettingDTO.cs @@ -23,11 +23,6 @@ namespace API.DTOs.Settings /// Enables OPDS connections to be made to the server. /// public bool EnableOpds { get; set; } - - /// - /// Enables Authentication on the server. Defaults to true. - /// - public bool EnableAuthentication { get; set; } /// /// Base Url for the kavita. Requires restart to take effect. /// diff --git a/API/Entities/Enums/ServerSettingKey.cs b/API/Entities/Enums/ServerSettingKey.cs index 80484d693..809115da9 100644 --- a/API/Entities/Enums/ServerSettingKey.cs +++ b/API/Entities/Enums/ServerSettingKey.cs @@ -47,6 +47,7 @@ namespace API.Entities.Enums /// /// Is Authentication needed for non-admin accounts /// + /// Deprecated. This is no longer used v0.5.1+. Assume Authentication is always in effect [Description("EnableAuthentication")] EnableAuthentication = 8, /// diff --git a/API/Helpers/Converters/ServerSettingConverter.cs b/API/Helpers/Converters/ServerSettingConverter.cs index 50a839010..77ce9891f 100644 --- a/API/Helpers/Converters/ServerSettingConverter.cs +++ b/API/Helpers/Converters/ServerSettingConverter.cs @@ -36,9 +36,6 @@ namespace API.Helpers.Converters case ServerSettingKey.EnableOpds: destination.EnableOpds = bool.Parse(row.Value); break; - case ServerSettingKey.EnableAuthentication: - destination.EnableAuthentication = bool.Parse(row.Value); - break; case ServerSettingKey.BaseUrl: destination.BaseUrl = row.Value; break; diff --git a/API/Services/DirectoryService.cs b/API/Services/DirectoryService.cs index 4862e40d8..c47b3469c 100644 --- a/API/Services/DirectoryService.cs +++ b/API/Services/DirectoryService.cs @@ -1,4 +1,5 @@ using System; +using System.Collections; using System.Collections.Generic; using System.Collections.Immutable; using System.IO; @@ -6,7 +7,7 @@ using System.IO.Abstractions; using System.Linq; using System.Text.RegularExpressions; using System.Threading.Tasks; -using API.Entities.Enums; +using API.Comparators; using API.Extensions; using Microsoft.Extensions.Logging; @@ -681,7 +682,7 @@ namespace API.Services FileSystem.Path.Join(directoryName, "test.txt"), string.Empty); } - catch (Exception) + catch (Exception ex) { ClearAndDeleteDirectory(directoryName); return false; diff --git a/UI/Web/src/app/admin/_models/server-settings.ts b/UI/Web/src/app/admin/_models/server-settings.ts index 1f5b398e9..95efc5aa7 100644 --- a/UI/Web/src/app/admin/_models/server-settings.ts +++ b/UI/Web/src/app/admin/_models/server-settings.ts @@ -6,7 +6,6 @@ export interface ServerSettings { port: number; allowStatCollection: boolean; enableOpds: boolean; - enableAuthentication: boolean; baseUrl: string; bookmarksDirectory: string; } diff --git a/UI/Web/src/app/admin/manage-settings/manage-settings.component.html b/UI/Web/src/app/admin/manage-settings/manage-settings.component.html index ecda0b4ac..a2daf69f6 100644 --- a/UI/Web/src/app/admin/manage-settings/manage-settings.component.html +++ b/UI/Web/src/app/admin/manage-settings/manage-settings.component.html @@ -65,15 +65,6 @@ -
- -

By disabling authentication, all non-admin users will be able to login by just their username. No password will be required to authenticate.

-
- - -
-
-

Reoccuring Tasks

  diff --git a/UI/Web/src/app/admin/manage-settings/manage-settings.component.ts b/UI/Web/src/app/admin/manage-settings/manage-settings.component.ts index eadfe5b71..acc336689 100644 --- a/UI/Web/src/app/admin/manage-settings/manage-settings.component.ts +++ b/UI/Web/src/app/admin/manage-settings/manage-settings.component.ts @@ -40,7 +40,6 @@ export class ManageSettingsComponent implements OnInit { this.settingsForm.addControl('loggingLevel', new FormControl(this.serverSettings.loggingLevel, [Validators.required])); this.settingsForm.addControl('allowStatCollection', new FormControl(this.serverSettings.allowStatCollection, [Validators.required])); this.settingsForm.addControl('enableOpds', new FormControl(this.serverSettings.enableOpds, [Validators.required])); - this.settingsForm.addControl('enableAuthentication', new FormControl(this.serverSettings.enableAuthentication, [Validators.required])); this.settingsForm.addControl('baseUrl', new FormControl(this.serverSettings.baseUrl, [Validators.required])); }); } @@ -54,29 +53,16 @@ export class ManageSettingsComponent implements OnInit { this.settingsForm.get('loggingLevel')?.setValue(this.serverSettings.loggingLevel); this.settingsForm.get('allowStatCollection')?.setValue(this.serverSettings.allowStatCollection); this.settingsForm.get('enableOpds')?.setValue(this.serverSettings.enableOpds); - this.settingsForm.get('enableAuthentication')?.setValue(this.serverSettings.enableAuthentication); this.settingsForm.get('baseUrl')?.setValue(this.serverSettings.baseUrl); } async saveSettings() { const modelSettings = this.settingsForm.value; - if (this.settingsForm.get('enableAuthentication')?.dirty && this.settingsForm.get('enableAuthentication')?.value === false) { - if (!await this.confirmService.confirm('Disabling Authentication opens your server up to unauthorized access and possible hacking. Are you sure you want to continue with this?')) { - return; - } - } - - const informUserAfterAuthenticationEnabled = this.settingsForm.get('enableAuthentication')?.dirty && this.settingsForm.get('enableAuthentication')?.value && !this.serverSettings.enableAuthentication; - this.settingsService.updateServerSettings(modelSettings).pipe(take(1)).subscribe(async (settings: ServerSettings) => { this.serverSettings = settings; this.resetForm(); this.toastr.success('Server settings updated'); - - if (informUserAfterAuthenticationEnabled) { - await this.confirmService.alert('You have just re-enabled authentication. All non-admin users have been re-assigned a password of "[k.2@RZ!mxCQkJzE". This is a publicly known password. Please change their users passwords or request them to.'); - } }, (err: any) => { console.error('error: ', err); }); diff --git a/UI/Web/src/app/admin/settings.service.ts b/UI/Web/src/app/admin/settings.service.ts index 646fde087..92ae8b5c7 100644 --- a/UI/Web/src/app/admin/settings.service.ts +++ b/UI/Web/src/app/admin/settings.service.ts @@ -40,10 +40,4 @@ export class SettingsService { getOpdsEnabled() { return this.http.get(this.baseUrl + 'settings/opds-enabled', {responseType: 'text' as 'json'}); } - - getAuthenticationEnabled() { - return this.http.get(this.baseUrl + 'settings/authentication-enabled', {responseType: 'text' as 'json'}).pipe(map((res: string) => { - return res === 'true'; - })); - } } diff --git a/UI/Web/src/app/app.module.ts b/UI/Web/src/app/app.module.ts index 89be77453..ea7a64fa0 100644 --- a/UI/Web/src/app/app.module.ts +++ b/UI/Web/src/app/app.module.ts @@ -36,6 +36,7 @@ import { PersonRolePipe } from './person-role.pipe'; import { SeriesMetadataDetailComponent } from './series-metadata-detail/series-metadata-detail.component'; import { AllSeriesComponent } from './all-series/all-series.component'; import { PublicationStatusPipe } from './publication-status.pipe'; +import { RegistrationModule } from './registration/registration.module'; @NgModule({ @@ -80,6 +81,7 @@ import { PublicationStatusPipe } from './publication-status.pipe'; CardsModule, CollectionsModule, ReadingListModule, + RegistrationModule, ToastrModule.forRoot({ positionClass: 'toast-bottom-right', diff --git a/UI/Web/src/app/registration/registration.module.ts b/UI/Web/src/app/registration/registration.module.ts index 91f5dc3df..1e1f89c38 100644 --- a/UI/Web/src/app/registration/registration.module.ts +++ b/UI/Web/src/app/registration/registration.module.ts @@ -24,6 +24,9 @@ import { ConfirmMigrationEmailComponent } from './confirm-migration-email/confir RegistrationRoutingModule, NgbTooltipModule, ReactiveFormsModule + ], + exports: [ + SplashContainerComponent ] }) export class RegistrationModule { } diff --git a/UI/Web/src/app/user-login/user-login.component.html b/UI/Web/src/app/user-login/user-login.component.html index e3cd003a9..c595203c1 100644 --- a/UI/Web/src/app/user-login/user-login.component.html +++ b/UI/Web/src/app/user-login/user-login.component.html @@ -1,38 +1,24 @@ -