Authority url validator

This commit is contained in:
Amelia 2025-06-30 14:33:10 +02:00
parent 5480df4cfb
commit 1180d518a2
No known key found for this signature in database
GPG key ID: D6D0ECE365407EAA
9 changed files with 103 additions and 16 deletions

View file

@ -21,6 +21,14 @@
<input id="oid-authority" class="form-control"
formControlName="authority" type="text"
[class.is-invalid]="formControl.invalid && !formControl.untouched">
@if (settingsForm.dirty || !settingsForm.untouched) {
<div id="oidc-authority-validations" class="invalid-feedback">
@if (formControl.errors?.invalidUri) {
<div>{{t('invalidUri')}}</div>
}
</div>
}
</ng-template>
</app-setting-item>
}

View file

@ -2,6 +2,8 @@ import {ChangeDetectorRef, Component, OnInit} from '@angular/core';
import {TranslocoDirective} from "@jsverse/transloco";
import {ServerSettings} from "../_models/server-settings";
import {
AbstractControl,
AsyncValidatorFn,
FormControl,
FormGroup,
ReactiveFormsModule,
@ -12,6 +14,7 @@ import {SettingsService} from "../settings.service";
import {OidcConfig} from "../_models/oidc-config";
import {SettingItemComponent} from "../../settings/_components/setting-item/setting-item.component";
import {SettingSwitchComponent} from "../../settings/_components/setting-switch/setting-switch.component";
import {map, of} from "rxjs";
@Component({
selector: 'app-manage-open-idconnect',
@ -42,9 +45,7 @@ export class ManageOpenIDConnectComponent implements OnInit {
this.serverSettings = data;
this.oidcSettings = this.serverSettings.oidcConfig;
// TODO: Validator for authority, /.well-known/openid-configuration endpoint must be reachable
this.settingsForm.addControl('authority', new FormControl(this.oidcSettings.authority, []));
this.settingsForm.addControl('authority', new FormControl(this.oidcSettings.authority, [], [this.authorityValidator()]));
this.settingsForm.addControl('clientId', new FormControl(this.oidcSettings.clientId, [this.requiredIf('authority')]));
this.settingsForm.addControl('provisionAccounts', new FormControl(this.oidcSettings.provisionAccounts, []));
this.settingsForm.addControl('requireVerifiedEmail', new FormControl(this.oidcSettings.requireVerifiedEmail, []));
@ -72,6 +73,31 @@ export class ManageOpenIDConnectComponent implements OnInit {
})
}
authorityValidator(): AsyncValidatorFn {
return (control: AbstractControl) => {
let uri: string = control.value;
if (!uri || uri.trim().length === 0) {
return of(null);
}
try {
new URL(uri);
} catch {
return of({'invalidUri': {'uri': uri}} as ValidationErrors)
}
if (uri.endsWith('/')) {
uri = uri.substring(0, uri.length - 1);
}
return this.settingsService.ifValidAuthority(uri).pipe(map(ok => {
if (ok) return null;
return {'invalidUri': {'uri': uri}} as ValidationErrors;
}));
}
}
requiredIf(other: string): ValidatorFn {
return (control): ValidationErrors | null => {
const otherControl = this.settingsForm.get(other);

View file

@ -78,6 +78,11 @@ export class SettingsService {
isValidCronExpression(val: string) {
if (val === '' || val === undefined || val === null) return of(false);
return this.http.get<string>(this.baseUrl + 'settings/is-valid-cron?cronExpression=' + val, TextResonse).pipe(map(d => d === 'true'));
}
ifValidAuthority(authority: string) {
if (authority === '' || authority === undefined || authority === null) return of(false);
return this.http.post<boolean>(this.baseUrl + 'oidc/is-valid-authority', {authority});
}
}

View file

@ -17,10 +17,11 @@
"settings": {
"save": "{{common.save}}",
"notice": "Notice",
"restart-required": "Changing OpenID Connect settings requires a restart",
"restart-required": "Changing OpenID Connect Authority requires a restart",
"provider": "Provider",
"behaviour": "Behaviour",
"field-required": "{{name}} is required when {{other}} is set",
"invalidUri": "The provider URL is not valid",
"authority": "Authority",
"authority-tooltip": "The URL to your OpenID Connect provider",