Cleanup login page, custom button text
This commit is contained in:
parent
54fb4c7a8a
commit
4c0faa755d
12 changed files with 76 additions and 32 deletions
|
@ -3,12 +3,8 @@ using API.Entities.Enums;
|
||||||
|
|
||||||
namespace API.DTOs.Settings;
|
namespace API.DTOs.Settings;
|
||||||
|
|
||||||
public class OidcConfigDto
|
public record OidcConfigDto: OidcPublicConfigDto
|
||||||
{
|
{
|
||||||
/// <inheritdoc cref="ServerSettingKey.OidcAuthority"/>
|
|
||||||
public string? Authority { get; set; }
|
|
||||||
/// <inheritdoc cref="ServerSettingKey.OidcClientId"/>
|
|
||||||
public string? ClientId { get; set; }
|
|
||||||
/// <inheritdoc cref="ServerSettingKey.OidcProvisionAccounts"/>
|
/// <inheritdoc cref="ServerSettingKey.OidcProvisionAccounts"/>
|
||||||
public bool ProvisionAccounts { get; set; }
|
public bool ProvisionAccounts { get; set; }
|
||||||
/// <inheritdoc cref="ServerSettingKey.OidcRequireVerifiedEmail"/>
|
/// <inheritdoc cref="ServerSettingKey.OidcRequireVerifiedEmail"/>
|
||||||
|
@ -16,12 +12,9 @@ public class OidcConfigDto
|
||||||
/// <inheritdoc cref="ServerSettingKey.OidcProvisionUserSettings"/>
|
/// <inheritdoc cref="ServerSettingKey.OidcProvisionUserSettings"/>
|
||||||
public bool ProvisionUserSettings { get; set; }
|
public bool ProvisionUserSettings { get; set; }
|
||||||
/// <inheritdoc cref="ServerSettingKey.OidcAutoLogin"/>
|
/// <inheritdoc cref="ServerSettingKey.OidcAutoLogin"/>
|
||||||
public bool AutoLogin { get; set; }
|
|
||||||
/// <inheritdoc cref="ServerSettingKey.DisablePasswordAuthentication"/>
|
|
||||||
public bool DisablePasswordAuthentication { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns true if the <see cref="Authority"/> has been set
|
/// Returns true if the <see cref="OidcPublicConfigDto.Authority"/> has been set
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool Enabled => Authority != "";
|
public bool Enabled => Authority != "";
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +1,18 @@
|
||||||
#nullable enable
|
#nullable enable
|
||||||
|
using API.Entities.Enums;
|
||||||
|
|
||||||
namespace API.DTOs.Settings;
|
namespace API.DTOs.Settings;
|
||||||
|
|
||||||
public sealed record OidcPublicConfigDto
|
public record OidcPublicConfigDto
|
||||||
{
|
{
|
||||||
/// <inheritdoc cref="OidcConfigDto.Authority"/>
|
/// <inheritdoc cref="ServerSettingKey.OidcAuthority"/>
|
||||||
public string? Authority { get; set; }
|
public string? Authority { get; set; }
|
||||||
/// <inheritdoc cref="OidcConfigDto.ClientId"/>
|
/// <inheritdoc cref="ServerSettingKey.OidcClientId"/>
|
||||||
public string? ClientId { get; set; }
|
public string? ClientId { get; set; }
|
||||||
/// <inheritdoc cref="OidcConfigDto.AutoLogin"/>
|
/// <inheritdoc cref="ServerSettingKey.OidcAutoLogin"/>
|
||||||
public bool AutoLogin { get; set; }
|
public bool AutoLogin { get; set; }
|
||||||
/// <inheritdoc cref="OidcConfigDto.DisablePasswordAuthentication"/>
|
/// <inheritdoc cref="ServerSettingKey.DisablePasswordAuthentication"/>
|
||||||
public bool DisablePasswordAuthentication { get; set; }
|
public bool DisablePasswordAuthentication { get; set; }
|
||||||
|
/// <inheritdoc cref="ServerSettingKey.OidcProviderName"/>
|
||||||
|
public string ProviderName { get; set; } = string.Empty;
|
||||||
}
|
}
|
||||||
|
|
|
@ -259,6 +259,7 @@ public static class Seed
|
||||||
new() { Key = ServerSettingKey.OidcRequireVerifiedEmail, Value = "true"},
|
new() { Key = ServerSettingKey.OidcRequireVerifiedEmail, Value = "true"},
|
||||||
new() { Key = ServerSettingKey.OidcProvisionUserSettings, Value = "false"},
|
new() { Key = ServerSettingKey.OidcProvisionUserSettings, Value = "false"},
|
||||||
new() { Key = ServerSettingKey.DisablePasswordAuthentication, Value = "false"},
|
new() { Key = ServerSettingKey.DisablePasswordAuthentication, Value = "false"},
|
||||||
|
new() { Key = ServerSettingKey.OidcProviderName, Value = "OpenID Connect"},
|
||||||
|
|
||||||
new() {Key = ServerSettingKey.EmailHost, Value = string.Empty},
|
new() {Key = ServerSettingKey.EmailHost, Value = string.Empty},
|
||||||
new() {Key = ServerSettingKey.EmailPort, Value = string.Empty},
|
new() {Key = ServerSettingKey.EmailPort, Value = string.Empty},
|
||||||
|
|
|
@ -232,4 +232,10 @@ public enum ServerSettingKey
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Description("DisablePasswordAuthentication")]
|
[Description("DisablePasswordAuthentication")]
|
||||||
DisablePasswordAuthentication = 46,
|
DisablePasswordAuthentication = 46,
|
||||||
|
/// <summary>
|
||||||
|
/// Name of your provider, used to display on the login screen
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>Default to OpenID Connect</remarks>
|
||||||
|
[Description("OidcProviderName")]
|
||||||
|
OidcProviderName = 47,
|
||||||
}
|
}
|
||||||
|
|
|
@ -157,6 +157,10 @@ public class ServerSettingConverter : ITypeConverter<IEnumerable<ServerSetting>,
|
||||||
destination.OidcConfig ??= new OidcConfigDto();
|
destination.OidcConfig ??= new OidcConfigDto();
|
||||||
destination.OidcConfig.DisablePasswordAuthentication = bool.Parse(row.Value);
|
destination.OidcConfig.DisablePasswordAuthentication = bool.Parse(row.Value);
|
||||||
break;
|
break;
|
||||||
|
case ServerSettingKey.OidcProviderName:
|
||||||
|
destination.OidcConfig ??= new OidcConfigDto();
|
||||||
|
destination.OidcConfig.ProviderName = row.Value;
|
||||||
|
break;
|
||||||
case ServerSettingKey.LicenseKey:
|
case ServerSettingKey.LicenseKey:
|
||||||
case ServerSettingKey.EnableAuthentication:
|
case ServerSettingKey.EnableAuthentication:
|
||||||
case ServerSettingKey.EmailServiceUrl:
|
case ServerSettingKey.EmailServiceUrl:
|
||||||
|
|
|
@ -464,6 +464,13 @@ public class SettingsService : ISettingsService
|
||||||
_unitOfWork.SettingsRepository.Update(setting);
|
_unitOfWork.SettingsRepository.Update(setting);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (setting.Key == ServerSettingKey.OidcProviderName &&
|
||||||
|
updateSettingsDto.OidcConfig.ProviderName + string.Empty != setting.Value)
|
||||||
|
{
|
||||||
|
setting.Value = updateSettingsDto.OidcConfig.ProviderName + string.Empty;
|
||||||
|
_unitOfWork.SettingsRepository.Update(setting);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateEmailSettings(ServerSetting setting, ServerSettingDto updateSettingsDto)
|
private void UpdateEmailSettings(ServerSetting setting, ServerSettingDto updateSettingsDto)
|
||||||
|
|
|
@ -7,6 +7,7 @@ export interface OidcConfig {
|
||||||
provisionUserSettings: boolean;
|
provisionUserSettings: boolean;
|
||||||
autoLogin: boolean;
|
autoLogin: boolean;
|
||||||
disablePasswordAuthentication: boolean;
|
disablePasswordAuthentication: boolean;
|
||||||
|
providerName: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface OidcPublicConfig {
|
export interface OidcPublicConfig {
|
||||||
|
@ -14,4 +15,5 @@ export interface OidcPublicConfig {
|
||||||
clientId: string;
|
clientId: string;
|
||||||
autoLogin: boolean;
|
autoLogin: boolean;
|
||||||
disablePasswordAuthentication: boolean;
|
disablePasswordAuthentication: boolean;
|
||||||
|
providerName: string;
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h4>{{t('provider')}}</h4>
|
<h4>{{t('provider')}}</h4>
|
||||||
|
<div class="text-muted">{{t('manual-save')}}</div>
|
||||||
<ng-container>
|
<ng-container>
|
||||||
<div class="row g-0 mt-4 mb-4">
|
<div class="row g-0 mt-4 mb-4">
|
||||||
@if (settingsForm.get('authority'); as formControl) {
|
@if (settingsForm.get('authority'); as formControl) {
|
||||||
|
@ -62,8 +63,22 @@
|
||||||
|
|
||||||
<div class="setting-section-break"></div>
|
<div class="setting-section-break"></div>
|
||||||
<h4>{{t('behaviour')}}</h4>
|
<h4>{{t('behaviour')}}</h4>
|
||||||
|
|
||||||
<ng-container>
|
<ng-container>
|
||||||
|
<div class="row g-0 mt-4 mb-4">
|
||||||
|
@if (settingsForm.get('providerName'); as formControl) {
|
||||||
|
<app-setting-item [title]="t('providerName')" [subtitle]="t('providerName-tooltip')">
|
||||||
|
<ng-template #view>
|
||||||
|
{{formControl.value}}
|
||||||
|
</ng-template>
|
||||||
|
<ng-template #edit>
|
||||||
|
<input id="oid-providerName" aria-describedby="oidc-providerName-validations" class="form-control"
|
||||||
|
formControlName="providerName" type="text"
|
||||||
|
[class.is-invalid]="formControl.invalid && !formControl.untouched">
|
||||||
|
</ng-template>
|
||||||
|
</app-setting-item>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="row g-0 mt-4 mb-4">
|
<div class="row g-0 mt-4 mb-4">
|
||||||
@if(settingsForm.get('provisionAccounts'); as formControl) {
|
@if(settingsForm.get('provisionAccounts'); as formControl) {
|
||||||
<app-setting-switch [title]="t('provisionAccounts')" [subtitle]="t('provisionAccounts-tooltip')">
|
<app-setting-switch [title]="t('provisionAccounts')" [subtitle]="t('provisionAccounts-tooltip')">
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import {ChangeDetectorRef, Component, OnInit} from '@angular/core';
|
import {ChangeDetectorRef, Component, DestroyRef, OnInit} from '@angular/core';
|
||||||
import {TranslocoDirective} from "@jsverse/transloco";
|
import {TranslocoDirective} from "@jsverse/transloco";
|
||||||
import {ServerSettings} from "../_models/server-settings";
|
import {ServerSettings} from "../_models/server-settings";
|
||||||
import {
|
import {
|
||||||
|
@ -14,7 +14,8 @@ import {SettingsService} from "../settings.service";
|
||||||
import {OidcConfig} from "../_models/oidc-config";
|
import {OidcConfig} from "../_models/oidc-config";
|
||||||
import {SettingItemComponent} from "../../settings/_components/setting-item/setting-item.component";
|
import {SettingItemComponent} from "../../settings/_components/setting-item/setting-item.component";
|
||||||
import {SettingSwitchComponent} from "../../settings/_components/setting-switch/setting-switch.component";
|
import {SettingSwitchComponent} from "../../settings/_components/setting-switch/setting-switch.component";
|
||||||
import {map, of} from "rxjs";
|
import {debounceTime, distinctUntilChanged, filter, map, of, switchMap, tap} from "rxjs";
|
||||||
|
import {takeUntilDestroyed} from "@angular/core/rxjs-interop";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-manage-open-idconnect',
|
selector: 'app-manage-open-idconnect',
|
||||||
|
@ -36,6 +37,7 @@ export class ManageOpenIDConnectComponent implements OnInit {
|
||||||
constructor(
|
constructor(
|
||||||
private settingsService: SettingsService,
|
private settingsService: SettingsService,
|
||||||
private cdRef: ChangeDetectorRef,
|
private cdRef: ChangeDetectorRef,
|
||||||
|
private destroyRef: DestroyRef,
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,12 +54,27 @@ export class ManageOpenIDConnectComponent implements OnInit {
|
||||||
this.settingsForm.addControl('provisionUserSettings', new FormControl(this.oidcSettings.provisionUserSettings, []));
|
this.settingsForm.addControl('provisionUserSettings', new FormControl(this.oidcSettings.provisionUserSettings, []));
|
||||||
this.settingsForm.addControl('autoLogin', new FormControl(this.oidcSettings.autoLogin, []));
|
this.settingsForm.addControl('autoLogin', new FormControl(this.oidcSettings.autoLogin, []));
|
||||||
this.settingsForm.addControl('disablePasswordAuthentication', new FormControl(this.oidcSettings.disablePasswordAuthentication, []));
|
this.settingsForm.addControl('disablePasswordAuthentication', new FormControl(this.oidcSettings.disablePasswordAuthentication, []));
|
||||||
|
this.settingsForm.addControl('providerName', new FormControl(this.oidcSettings.providerName, []));
|
||||||
this.cdRef.markForCheck();
|
this.cdRef.markForCheck();
|
||||||
|
|
||||||
|
this.settingsForm.valueChanges.pipe(
|
||||||
|
debounceTime(300),
|
||||||
|
distinctUntilChanged(),
|
||||||
|
takeUntilDestroyed(this.destroyRef),
|
||||||
|
filter(() => {
|
||||||
|
// Do not auto save when provider settings have changed
|
||||||
|
const settings: OidcConfig = this.settingsForm.getRawValue();
|
||||||
|
return settings.authority == this.oidcSettings.authority && settings.clientId == this.oidcSettings.clientId;
|
||||||
|
}),
|
||||||
|
tap(() => this.save())
|
||||||
|
).subscribe();
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
save() {
|
save() {
|
||||||
|
if (!this.settingsForm.valid) return;
|
||||||
|
|
||||||
const data = this.settingsForm.getRawValue();
|
const data = this.settingsForm.getRawValue();
|
||||||
const newSettings = Object.assign({}, this.serverSettings);
|
const newSettings = Object.assign({}, this.serverSettings);
|
||||||
newSettings.oidcConfig = data as OidcConfig;
|
newSettings.oidcConfig = data as OidcConfig;
|
||||||
|
|
|
@ -42,16 +42,9 @@
|
||||||
class="d-inline-block"
|
class="d-inline-block"
|
||||||
style="object-fit: contain;"
|
style="object-fit: contain;"
|
||||||
/>
|
/>
|
||||||
{{t('oidc')}}
|
{{oidcService.settings()?.providerName || t('oidc')}}
|
||||||
</button>
|
</button>
|
||||||
}
|
}
|
||||||
|
|
||||||
@if (!showPasswordLogin()) {
|
|
||||||
<div class="text-muted mt-2">
|
|
||||||
{{t('bypass')}}
|
|
||||||
<span class="text-muted clickable" (click)="forceShowPasswordLogin.set(true)">{{t('here')}}</span>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</ng-container>
|
</ng-container>
|
||||||
</app-splash-container>
|
</app-splash-container>
|
||||||
|
|
|
@ -59,9 +59,9 @@ export class UserLoginComponent implements OnInit {
|
||||||
* undefined until query params are read
|
* undefined until query params are read
|
||||||
*/
|
*/
|
||||||
skipAutoLogin = signal<boolean | undefined>(undefined);
|
skipAutoLogin = signal<boolean | undefined>(undefined);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Display the login form, regardless if the password authentication is disabled (admins can still log in)
|
* Display the login form, regardless if the password authentication is disabled (admins can still log in)
|
||||||
|
* Set from query
|
||||||
*/
|
*/
|
||||||
forceShowPasswordLogin = signal(false);
|
forceShowPasswordLogin = signal(false);
|
||||||
/**
|
/**
|
||||||
|
@ -121,6 +121,7 @@ export class UserLoginComponent implements OnInit {
|
||||||
}
|
}
|
||||||
|
|
||||||
this.skipAutoLogin.set(params.get('skipAutoLogin') === 'true')
|
this.skipAutoLogin.set(params.get('skipAutoLogin') === 'true')
|
||||||
|
this.forceShowPasswordLogin.set(params.get('forceShowPassword') === 'true');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,9 +6,7 @@
|
||||||
"password-validation": "{{validation.password-validation}}",
|
"password-validation": "{{validation.password-validation}}",
|
||||||
"forgot-password": "Forgot Password?",
|
"forgot-password": "Forgot Password?",
|
||||||
"submit": "Sign in",
|
"submit": "Sign in",
|
||||||
"oidc": "Log in with OpenID Connect",
|
"oidc": "OpenID Connect"
|
||||||
"bypass": "Password login has been disabled. Bypass ",
|
|
||||||
"here": "here"
|
|
||||||
},
|
},
|
||||||
|
|
||||||
"oidc": {
|
"oidc": {
|
||||||
|
@ -18,11 +16,12 @@
|
||||||
"settings": {
|
"settings": {
|
||||||
"save": "{{common.save}}",
|
"save": "{{common.save}}",
|
||||||
"notice": "Notice",
|
"notice": "Notice",
|
||||||
"restart-required": "Changing OpenID Connect Authority requires a restart",
|
"restart-required": "Changing Authority, or Client ID requires a manual restart of Kavita to take effect.",
|
||||||
"provider": "Provider",
|
"provider": "Provider",
|
||||||
"behaviour": "Behaviour",
|
"behaviour": "Behaviour",
|
||||||
"field-required": "{{name}} is required when {{other}} is set",
|
"field-required": "{{name}} is required when {{other}} is set",
|
||||||
"invalidUri": "The provider URL is not valid",
|
"invalidUri": "The provider URL is not valid",
|
||||||
|
"manual-save": "Changing provider settings requires a manual save",
|
||||||
|
|
||||||
"authority": "Authority",
|
"authority": "Authority",
|
||||||
"authority-tooltip": "The URL to your OpenID Connect provider",
|
"authority-tooltip": "The URL to your OpenID Connect provider",
|
||||||
|
@ -37,7 +36,9 @@
|
||||||
"autoLogin": "Auto login",
|
"autoLogin": "Auto login",
|
||||||
"autoLogin-tooltip": "Auto redirect to OpenID Connect provider when opening the login screen",
|
"autoLogin-tooltip": "Auto redirect to OpenID Connect provider when opening the login screen",
|
||||||
"disablePasswordAuthentication": "Disable password authentication",
|
"disablePasswordAuthentication": "Disable password authentication",
|
||||||
"disablePasswordAuthentication-tooltip": "Users with the admin role can bypass this restriction"
|
"disablePasswordAuthentication-tooltip": "Users with the admin role can bypass this restriction",
|
||||||
|
"providerName": "Provider name",
|
||||||
|
"providerName-tooltip": "Name show on the login screen"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue