feat: manage restrictions in console (#6965)

* feat: return 404 or 409 if org reg disallowed

* fix: system limit permissions

* feat: add iam limits api

* feat: disallow public org registrations on default instance

* add integration test

* test: integration

* fix test

* docs: describe public org registrations

* avoid updating docs deps

* fix system limits integration test

* silence integration tests

* fix linting

* ignore strange linter complaints

* review

* improve reset properties naming

* redefine the api

* use restrictions aggregate

* test query

* simplify and test projection

* test commands

* fix unit tests

* move integration test

* support restrictions on default instance

* also test GetRestrictions

* self review

* lint

* abstract away resource owner

* fix tests

* configure supported languages

* fix allowed languages

* fix tests

* default lang must not be restricted

* preferred language must be allowed

* change preferred languages

* check languages everywhere

* lint

* test command side

* lint

* add integration test

* add integration test

* restrict supported ui locales

* lint

* lint

* cleanup

* lint

* allow undefined preferred language

* fix integration tests

* update main

* fix env var

* ignore linter

* ignore linter

* improve integration test config

* reduce cognitive complexity

* compile

* fix(console): switch back to saved language

* feat(API): get allowed languages

* fix(console): only make allowed languages selectable

* warn when editing not allowed languages

* feat: manage restrictions in console

* check for duplicates

* remove useless restriction checks

* review

* revert restriction renaming

* manage languages

* fix language restrictions

* lint

* generate

* allow custom texts for supported langs for now

* fix tests

* cleanup

* cleanup

* cleanup

* lint

* unsupported preferred lang is allowed

* fix integration test

* allow unsupported preferred languages

* lint

* fix languages lists

* simplify default language selection

* translate

* discard

* lint

* load languages for tests

* load languages

* lint

* cleanup

* lint

* cleanup

* get allowed only on admin

* cleanup

* reduce flakiness on very limited postgres

* simplify langSvc

* refactor according to suggestions in pr

* lint

* improve ux

* update central allowed languages

* set first allowed language as default

* readd lost translations

* disable sorting disallowed languages

* fix permissions

* lint

* selectionchange for language in msg texts

* initialize login texts

* init message texts

* lint

* fix drag and drop list styles

* start from 1

* cleanup

* prettier

* correct orgdefaultlabel

* unsubscribe

* lint

* docs: describe language settings

---------

Co-authored-by: peintnermax <max@caos.ch>
This commit is contained in:
Elio Bischof
2023-12-07 13:31:01 +01:00
committed by GitHub
parent 3842319d07
commit d639c5200a
34 changed files with 961 additions and 449 deletions

View File

@@ -1,27 +0,0 @@
<h2>{{ 'SETTING.DEFAULTLANGUAGE' | translate }}</h2>
<div class="spinner-wr">
<mat-spinner diameter="30" *ngIf="loading" color="primary"></mat-spinner>
</div>
<cnsl-form-field class="default-language" label="Default Language" required="true">
<cnsl-label>{{ 'SETTING.DEFAULTLANGUAGE' | translate }}</cnsl-label>
<mat-select [(ngModel)]="defaultLanguage" [disabled]="(['iam.policy.write'] | hasRole | async) === false">
<mat-option *ngFor="let lang of defaultLanguageOptions" [value]="lang">
{{ lang }} - {{ 'SETTING.LANGUAGE.' + lang | translate }}
</mat-option>
</mat-select>
</cnsl-form-field>
<div class="general-btn-container">
<button
class="save-button"
(click)="savePolicy()"
color="primary"
type="submit"
mat-raised-button
[disabled]="(['iam.policy.write'] | hasRole | async) === false"
>
{{ 'ACTIONS.SAVE' | translate }}
</button>
</div>

View File

@@ -1,18 +0,0 @@
.spinner-wr {
margin: 0.5rem 0;
}
.default-language {
max-width: 400px;
display: block;
}
.general-btn-container {
display: flex;
justify-content: flex-start;
margin-top: 1rem;
.save-button {
display: block;
}
}

View File

@@ -1,56 +0,0 @@
import { Component, OnInit } from '@angular/core';
import { SetDefaultLanguageResponse } from 'src/app/proto/generated/zitadel/admin_pb';
import { AdminService } from 'src/app/services/admin.service';
import { ToastService } from 'src/app/services/toast.service';
@Component({
selector: 'cnsl-general-settings',
templateUrl: './general-settings.component.html',
styleUrls: ['./general-settings.component.scss'],
})
export class GeneralSettingsComponent implements OnInit {
public defaultLanguage: string = '';
public defaultLanguageOptions: string[] = [];
public loading: boolean = false;
constructor(
private service: AdminService,
private toast: ToastService,
) {}
ngOnInit(): void {
this.fetchData();
}
private fetchData(): void {
this.service.getDefaultLanguage().then((langResp) => {
this.defaultLanguage = langResp.language;
});
this.service.getAllowedLanguages().then((supportedResp) => {
this.defaultLanguageOptions = supportedResp.languagesList;
});
}
private updateData(): Promise<SetDefaultLanguageResponse.AsObject> {
return (this.service as AdminService).setDefaultLanguage(this.defaultLanguage);
}
public savePolicy(): void {
const prom = this.updateData();
this.loading = true;
if (prom) {
prom
.then(() => {
this.toast.showInfo('POLICY.LOGIN_POLICY.SAVED', true);
this.loading = false;
setTimeout(() => {
this.fetchData();
}, 2000);
})
.catch((error) => {
this.loading = false;
this.toast.showError(error);
});
}
}
}

View File

@@ -1,29 +0,0 @@
import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { MatButtonModule } from '@angular/material/button';
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
import { MatSelectModule } from '@angular/material/select';
import { TranslateModule } from '@ngx-translate/core';
import { HasRolePipeModule } from 'src/app/pipes/has-role-pipe/has-role-pipe.module';
import { CardModule } from '../../card/card.module';
import { FormFieldModule } from '../../form-field/form-field.module';
import { GeneralSettingsComponent } from './general-settings.component';
@NgModule({
declarations: [GeneralSettingsComponent],
imports: [
CommonModule,
CardModule,
FormsModule,
MatButtonModule,
FormFieldModule,
MatProgressSpinnerModule,
MatSelectModule,
HasRolePipeModule,
TranslateModule,
],
exports: [GeneralSettingsComponent],
})
export class GeneralSettingsModule {}

View File

@@ -0,0 +1,135 @@
<h2>{{ 'SETTING.LANGUAGES.TITLE' | translate }}</h2>
<div class="spinner-wr">
<mat-spinner diameter="30" *ngIf="loading" color="primary"></mat-spinner>
</div>
<div>
<form class="languages-container-wrapper">
<div class="languages-container">
<div
class="languages-list"
cdkDropList
id="allowed"
[cdkDropListConnectedTo]="['notallowed']"
(cdkDropListDropped)="drop($event)"
[cdkDropListData]="(localState$ | async)!.allowed"
>
<div class="languages-top-row">
<span class="label">{{ 'SETTING.LANGUAGES.ALLOWED' | translate }}</span>
<button
class="list-button"
[disabled]="(canWriteRestrictions$ | async) === false"
(click)="allowAll()"
mat-stroked-button
>
<div class="cnsl-action-button">
<i class="las la-object-group"></i><span>{{ 'SETTING.LANGUAGES.ALLOW_ALL' | translate }}</span>
</div>
</button>
</div>
<div class="languages-drop-target">
<div
class="card languages-box"
*ngFor="let lang of (localState$ | async)!.allowed; index as i"
[cdkDragData]="lang"
cdkDrag
[cdkDragDisabled]="(canWriteRestrictions$ | async) === false"
mat-list-item
>
<span class="index">{{ i + 1 }}</span>
<span class="locale">{{ lang }}</span>
<span class="lang">{{ 'SETTING.LANGUAGES.OPTIONS.' + lang | translate }} </span>
<span *ngIf="lang === (defaultLang$ | async)" class="state orgdefaultlabel">{{
'SETTING.LANGUAGES.DEFAULT' | translate
}}</span>
<button
(click)="$event.stopPropagation()"
*ngIf="lang !== (defaultLang$ | async) && (isRemotelyAllowed$(lang) | async) === true"
mat-icon-button
class="more-button"
[matMenuTriggerFor]="actions"
data-e2e="table-actions-button"
>
<mat-icon>more_vert</mat-icon>
</button>
<mat-menu #actions="matMenu" xPosition="before" class="language-actions-menu">
<button
menuActions
mat-menu-item
(click)="setDefaultLang(lang)"
[disabled]="(canWriteDefaultLanguage$ | async) === false"
>
{{ 'SETTING.LANGUAGES.SETASDEFAULT' | translate }}
</button>
</mat-menu>
</div>
</div>
</div>
</div>
<div class="languages-container">
<div
class="languages-list"
cdkDropList
id="notallowed"
[cdkDropListConnectedTo]="['allowed']"
(cdkDropListDropped)="drop($event)"
[cdkDropListData]="(localState$ | async)!.notAllowed"
[cdkDropListEnterPredicate]="defaultLangPredicate"
cdkDropListSortingDisabled
>
<div class="languages-top-row">
<span class="label">{{ 'SETTING.LANGUAGES.NOT_ALLOWED' | translate }}</span>
<button
class="list-button"
[disabled]="(canWriteRestrictions$ | async) === false"
(click)="disallowAll()"
mat-stroked-button
>
<div class="cnsl-action-button">
<i class="las la-object-group"></i><span>{{ 'SETTING.LANGUAGES.DISALLOW_ALL' | translate }}</span>
</div>
</button>
</div>
<div class="languages-drop-target">
<div
class="card languages-box"
*ngFor="let lang of (localState$ | async)!.notAllowed"
[cdkDragData]="lang"
cdkDrag
[cdkDragDisabled]="(canWriteRestrictions$ | async) === false"
mat-list-item
>
<span class="locale">{{ lang }}</span>
<span class="lang">{{ 'SETTING.LANGUAGES.OPTIONS.' + lang | translate }} </span>
</div>
</div>
</div>
</div>
<div class="general-btn-container">
<button
class="reset-button"
[disabled]="(canWriteRestrictions$ | async) === false"
(click)="discard()"
color="message-text-warn"
mat-stroked-button
>
<div class="cnsl-action-button">
<i class="las la-history"></i><span>{{ 'ACTIONS.UNSAVED.DIALOG.DISCARD' | translate }}</span>
</div>
</button>
<button
class="save-button"
color="primary"
type="submit"
(click)="submit()"
mat-raised-button
[disabled]="(canWriteRestrictions$ | async) === false"
>
{{ 'ACTIONS.SAVE' | translate }}
</button>
</div>
</form>
</div>

View File

@@ -0,0 +1,112 @@
.languages-container-wrapper {
display: grid;
grid-template-columns: 1fr 1fr;
column-gap: 2rem;
@media only screen and (max-width: 700px) {
grid-template-columns: 1fr;
}
.languages-container {
display: inline-block;
max-width: 400px;
vertical-align: top;
width: 100%;
.spinner-wr {
margin: 0.5rem 0;
}
.default-language {
max-width: 400px;
display: block;
}
}
.general-btn-container {
display: flex;
justify-content: flex-start;
margin-top: 1rem;
.save-button {
display: block;
margin-left: 1rem;
}
}
}
.languages-list {
overflow: hidden;
display: block;
height: 100%;
.languages-top-row {
display: flex;
flex-direction: row;
align-items: center;
margin-bottom: 1rem;
margin-top: 1.5rem;
.label {
margin-right: 1rem;
flex: 1;
white-space: nowrap;
}
.list-button {
white-space: nowrap;
}
}
}
.languages-box {
position: relative;
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
padding: 0.5rem 0.5rem 0.5rem 2rem;
height: 56px;
cursor: move;
margin: 2px 0;
.index {
position: absolute;
top: 4px;
left: 4px;
opacity: 0.5;
font-size: 10px;
}
.locale {
width: 35px;
margin-right: 1rem;
}
.lang {
flex: 1;
}
[hoveractions] {
display: none;
}
.more-button {
height: 40px;
width: 40px;
display: flex;
align-items: center;
justify-content: center;
padding: 0;
}
&:hover {
[hoveractions] {
display: flex;
}
}
.defaultlanglabel {
margin-left: 0.5rem;
}
}

View File

@@ -1,19 +1,19 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { GeneralSettingsComponent } from './general-settings.component';
import { LanguageSettingsComponent } from './language-settings.component';
describe('GeneralSettingsComponent', () => {
let component: GeneralSettingsComponent;
let fixture: ComponentFixture<GeneralSettingsComponent>;
describe('LanguageSettingsComponent', () => {
let component: LanguageSettingsComponent;
let fixture: ComponentFixture<LanguageSettingsComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [GeneralSettingsComponent],
declarations: [LanguageSettingsComponent],
}).compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(GeneralSettingsComponent);
fixture = TestBed.createComponent(LanguageSettingsComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});

View File

@@ -0,0 +1,116 @@
import { ChangeDetectorRef, Component, OnInit } from '@angular/core';
import { AdminService } from 'src/app/services/admin.service';
import { ToastService } from 'src/app/services/toast.service';
import { UntypedFormBuilder } from '@angular/forms';
import { LanguagesService } from '../../../services/languages.service';
import { BehaviorSubject, concat, forkJoin, from, Observable, of, Subject, switchMap, take, takeUntil } from 'rxjs';
import { GrpcAuthService } from '../../../services/grpc-auth.service';
import { CdkDrag, CdkDragDrop, moveItemInArray, transferArrayItem } from '@angular/cdk/drag-drop';
import { catchError, map } from 'rxjs/operators';
interface State {
allowed: string[];
notAllowed: string[];
}
@Component({
selector: 'cnsl-language-settings',
templateUrl: './language-settings.component.html',
styleUrls: ['./language-settings.component.scss'],
})
export class LanguageSettingsComponent {
public canWriteRestrictions$: Observable<boolean> = this.authService.isAllowed(['iam.restrictions.write']);
public canWriteDefaultLanguage$: Observable<boolean> = this.authService.isAllowed(['iam.write']);
public localState$ = new BehaviorSubject<State>({ allowed: [], notAllowed: [] });
public remoteState$ = new BehaviorSubject<State>({ allowed: [], notAllowed: [] });
public defaultLang$ = new BehaviorSubject<string>('');
public loading: boolean = false;
constructor(
private service: AdminService,
private toast: ToastService,
private langSvc: LanguagesService,
private authService: GrpcAuthService,
) {
const sub = forkJoin([
langSvc.allowed$.pipe(take(1)),
langSvc.notAllowed$.pipe(take(1)),
from(this.service.getDefaultLanguage()).pipe(take(1)),
]).subscribe({
next: ([allowed, notAllowed, { language: defaultLang }]) => {
this.defaultLang$.next(defaultLang);
this.remoteState$.next({ notAllowed: [...notAllowed], ...{ allowed: [...allowed] } });
this.localState$.next({ notAllowed: [...notAllowed], ...{ allowed: [...allowed] } });
},
error: this.toast.showError,
complete: () => {
sub.unsubscribe();
},
});
}
drop(event: CdkDragDrop<string[]>) {
if (event.previousContainer === event.container) {
moveItemInArray(event.container.data, event.previousIndex, event.currentIndex);
} else {
transferArrayItem(event.previousContainer.data, event.container.data, event.previousIndex, event.currentIndex);
}
}
public defaultLangPredicate = (lang: CdkDrag<string>) => {
return !!lang?.data && lang.data !== this.defaultLang$.value;
};
public isRemotelyAllowed$(lang: string): Observable<boolean> {
return this.remoteState$.pipe(map(({ allowed }) => allowed.includes(lang)));
}
public allowAll(): void {
this.localState$.next({ allowed: [...this.allLocalLangs()], notAllowed: [] });
}
public disallowAll(): void {
const disallowed = this.allLocalLangs().filter((lang) => lang !== this.defaultLang$.value);
this.localState$.next({ allowed: [this.defaultLang$.value], notAllowed: disallowed });
}
public submit(): void {
const { allowed, notAllowed } = this.localState$.value;
const sub = from(this.service.setRestrictions(undefined, allowed)).subscribe({
next: () => {
this.remoteState$.next({
allowed: [...allowed],
notAllowed: [...notAllowed],
});
this.langSvc.newAllowed(allowed);
this.toast.showInfo('SETTING.LANGUAGES.ALLOWED_SAVED', true);
},
error: this.toast.showError,
complete: () => {
sub.unsubscribe();
},
});
}
public discard(): void {
this.localState$.next(this.remoteState$.value);
}
public setDefaultLang(lang: string): void {
const sub = from(this.service.setDefaultLanguage(lang)).subscribe({
next: () => {
this.defaultLang$.next(lang);
this.toast.showInfo('SETTING.LANGUAGES.DEFAULT_SAVED', true);
},
error: this.toast.showError,
complete: () => {
sub.unsubscribe();
},
});
}
private allLocalLangs(): string[] {
return [...this.localState$.value.allowed, ...this.localState$.value.notAllowed];
}
}

View File

@@ -0,0 +1,46 @@
import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { MatButtonModule } from '@angular/material/button';
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
import { MatSelectModule } from '@angular/material/select';
import { TranslateModule } from '@ngx-translate/core';
import { HasRolePipeModule } from 'src/app/pipes/has-role-pipe/has-role-pipe.module';
import { CardModule } from '../../card/card.module';
import { FormFieldModule } from '../../form-field/form-field.module';
import { LanguageSettingsComponent } from './language-settings.component';
import { MatListModule } from '@angular/material/list';
import { MatFormFieldModule } from '@angular/material/form-field';
import { DragDropModule } from '@angular/cdk/drag-drop';
import { MatRadioModule } from '@angular/material/radio';
import { MatTooltipModule } from '@angular/material/tooltip';
import { TableActionsModule } from '../../table-actions/table-actions.module';
import { MatMenuModule } from '@angular/material/menu';
import { MatIconModule } from '@angular/material/icon';
@NgModule({
declarations: [LanguageSettingsComponent],
imports: [
CommonModule,
CardModule,
FormsModule,
ReactiveFormsModule,
MatFormFieldModule,
MatButtonModule,
MatSelectModule,
FormFieldModule,
MatProgressSpinnerModule,
MatSelectModule,
HasRolePipeModule,
TranslateModule,
MatListModule,
DragDropModule,
MatRadioModule,
MatTooltipModule,
MatMenuModule,
MatIconModule,
],
exports: [LanguageSettingsComponent],
})
export class LanguageSettingsModule {}

View File

@@ -242,14 +242,20 @@
| async) === false
"
>
{{ 'POLICY.DATA.ALLOWREGISTER' | translate }}
{{ 'POLICY.DATA.ALLOWREGISTERUSERS' | translate }}
</mat-checkbox>
</div>
<div class="login-policy-row">
<mat-checkbox
class="login-policy-toggle"
color="primary"
ngDefaultControl
[(ngModel)]="allowOrgRegistration"
*ngIf="serviceType === PolicyComponentServiceType.ADMIN"
[disabled]="(['iam.restrictions.write'] | hasRole | async) === false"
>
{{ 'POLICY.DATA.ALLOWREGISTERORGS' | translate }}
</mat-checkbox>
<!-- <ng-template #regInfo>
<cnsl-info-section class="info">
{{ 'POLICY.DATA.ALLOWREGISTER_DESC' | translate }}
</cnsl-info-section>
</ng-template> -->
</div>
<div class="login-policy-row">
<mat-checkbox
@@ -428,6 +434,7 @@
type="submit"
mat-raised-button
[disabled]="
(['iam.restrictions.write'] | hasRole | async) === false &&
([
serviceType === PolicyComponentServiceType.ADMIN
? 'iam.policy.write'

View File

@@ -1,8 +1,8 @@
import { Component, Injector, Input, OnInit, Type } from '@angular/core';
import { Component, Injector, Input, OnDestroy, OnInit, Type } from '@angular/core';
import { AbstractControl, UntypedFormBuilder, UntypedFormGroup } from '@angular/forms';
import { MatDialog } from '@angular/material/dialog';
import { Duration } from 'google-protobuf/google/protobuf/duration_pb';
import { take } from 'rxjs';
import { firstValueFrom, forkJoin, from, Observable, of, Subject, take } from 'rxjs';
import {
GetLoginPolicyResponse as AdminGetLoginPolicyResponse,
UpdateLoginPolicyRequest,
@@ -24,19 +24,21 @@ import { InfoSectionType } from '../../info-section/info-section.component';
import { WarnDialogComponent } from '../../warn-dialog/warn-dialog.component';
import { PolicyComponentServiceType } from '../policy-component-types.enum';
import { LoginMethodComponentType } from './factor-table/factor-table.component';
import { catchError, map, takeUntil } from 'rxjs/operators';
@Component({
selector: 'cnsl-login-policy',
templateUrl: './login-policy.component.html',
styleUrls: ['./login-policy.component.scss'],
})
export class LoginPolicyComponent implements OnInit {
export class LoginPolicyComponent implements OnInit, OnDestroy {
public LoginMethodComponentType: any = LoginMethodComponentType;
public passwordlessTypes: Array<PasswordlessType> = [
PasswordlessType.PASSWORDLESS_TYPE_NOT_ALLOWED,
PasswordlessType.PASSWORDLESS_TYPE_ALLOWED,
];
public loginData?: LoginPolicy.AsObject;
public allowOrgRegistration: boolean = false;
public service!: ManagementService | AdminService;
public PolicyComponentServiceType: any = PolicyComponentServiceType;
@@ -52,6 +54,8 @@ export class LoginPolicyComponent implements OnInit {
secondFactorCheckLifetime: [{ disabled: true }, [requiredValidator]],
multiFactorCheckLifetime: [{ disabled: true }, [requiredValidator]],
});
private destroy$: Subject<void> = new Subject();
constructor(
private toast: ToastService,
private injector: Injector,
@@ -60,43 +64,59 @@ export class LoginPolicyComponent implements OnInit {
private dialog: MatDialog,
) {}
ngOnDestroy(): void {
this.destroy$.next();
this.destroy$.complete();
}
public fetchData(): void {
this.getData()
.then((resp) => {
if (resp.policy) {
this.loginData = resp.policy;
this.loading = false;
const data$ = forkJoin([
this.serviceType === PolicyComponentServiceType.ADMIN
? from((this.service as AdminService).getRestrictions()).pipe(
map(({ disallowPublicOrgRegistration }) => disallowPublicOrgRegistration),
)
: of(true),
from(this.getData()),
]);
this.passwordCheckLifetime?.setValue(
this.loginData.passwordCheckLifetime?.seconds ? this.loginData.passwordCheckLifetime?.seconds / 60 / 60 : 0,
);
this.externalLoginCheckLifetime?.setValue(
this.loginData.externalLoginCheckLifetime?.seconds
? this.loginData.externalLoginCheckLifetime?.seconds / 60 / 60
: 0,
);
this.mfaInitSkipLifetime?.setValue(
this.loginData.mfaInitSkipLifetime?.seconds ? this.loginData.mfaInitSkipLifetime?.seconds / 60 / 60 : 0,
);
this.secondFactorCheckLifetime?.setValue(
this.loginData.secondFactorCheckLifetime?.seconds
? this.loginData.secondFactorCheckLifetime?.seconds / 60 / 60
: 0,
);
this.multiFactorCheckLifetime?.setValue(
this.loginData.multiFactorCheckLifetime?.seconds
? this.loginData.multiFactorCheckLifetime?.seconds / 60 / 60
: 0,
);
const sub = data$.pipe(takeUntil(this.destroy$)).subscribe({
next: ([disallowPublicOrgRegistration, resp]) => {
this.allowOrgRegistration = !disallowPublicOrgRegistration;
if (!resp.policy) {
return;
}
})
.catch((error) => {
this.toast.showError(error);
});
this.loginData = resp.policy;
this.loading = false;
this.passwordCheckLifetime?.setValue(
this.loginData.passwordCheckLifetime?.seconds ? this.loginData.passwordCheckLifetime?.seconds / 60 / 60 : 0,
);
this.externalLoginCheckLifetime?.setValue(
this.loginData.externalLoginCheckLifetime?.seconds
? this.loginData.externalLoginCheckLifetime?.seconds / 60 / 60
: 0,
);
this.mfaInitSkipLifetime?.setValue(
this.loginData.mfaInitSkipLifetime?.seconds ? this.loginData.mfaInitSkipLifetime?.seconds / 60 / 60 : 0,
);
this.secondFactorCheckLifetime?.setValue(
this.loginData.secondFactorCheckLifetime?.seconds
? this.loginData.secondFactorCheckLifetime?.seconds / 60 / 60
: 0,
);
this.multiFactorCheckLifetime?.setValue(
this.loginData.multiFactorCheckLifetime?.seconds ? this.loginData.multiFactorCheckLifetime?.seconds / 60 / 60 : 0,
);
},
error: this.toast.showError,
complete: () => {
sub.unsubscribe();
},
});
}
public ngOnInit(): void {
@@ -142,7 +162,9 @@ export class LoginPolicyComponent implements OnInit {
}
}
private async updateData(): Promise<UpdateLoginPolicyResponse.AsObject> {
private async updateData(): Promise<any> {
const calls: Observable<any>[] = [];
if (this.loginData) {
switch (this.serviceType) {
case PolicyComponentServiceType.MGMT:
@@ -179,7 +201,8 @@ export class LoginPolicyComponent implements OnInit {
mgmtreq.setIgnoreUnknownUsernames(this.loginData.ignoreUnknownUsernames);
mgmtreq.setDefaultRedirectUri(this.loginData.defaultRedirectUri);
return (this.service as ManagementService).addCustomLoginPolicy(mgmtreq);
calls.push(from((this.service as ManagementService).addCustomLoginPolicy(mgmtreq)));
break;
} else {
const mgmtreq = new UpdateCustomLoginPolicyRequest();
mgmtreq.setAllowExternalIdp(this.loginData.allowExternalIdp);
@@ -211,7 +234,8 @@ export class LoginPolicyComponent implements OnInit {
mgmtreq.setIgnoreUnknownUsernames(this.loginData.ignoreUnknownUsernames);
mgmtreq.setDefaultRedirectUri(this.loginData.defaultRedirectUri);
return (this.service as ManagementService).updateCustomLoginPolicy(mgmtreq);
calls.push(from((this.service as ManagementService).updateCustomLoginPolicy(mgmtreq)));
break;
}
case PolicyComponentServiceType.ADMIN:
const adminreq = new UpdateLoginPolicyRequest();
@@ -243,11 +267,21 @@ export class LoginPolicyComponent implements OnInit {
adminreq.setIgnoreUnknownUsernames(this.loginData.ignoreUnknownUsernames);
adminreq.setDefaultRedirectUri(this.loginData.defaultRedirectUri);
return (this.service as AdminService).updateLoginPolicy(adminreq);
calls.push(from((this.service as AdminService).setRestrictions(!this.allowOrgRegistration)));
calls.push(from((this.service as AdminService).updateLoginPolicy(adminreq)));
break;
}
} else {
return Promise.reject();
calls.push(from(Promise.reject()));
}
return firstValueFrom(
forkJoin(calls).pipe(
catchError((error, caught) => {
// We just ignore the policy not changed error!
return (error as { message: string }).message.includes('INSTANCE-5M9vdd') ? of(true) : caught;
}),
),
);
}
public savePolicy(): void {

View File

@@ -6,9 +6,6 @@
[settingsList]="settingsList"
queryParam="id"
>
<ng-container *ngIf="currentSetting === 'general' && serviceType === PolicyComponentServiceType.ADMIN">
<cnsl-general-settings></cnsl-general-settings>
</ng-container>
<ng-container *ngIf="currentSetting === 'complexity'">
<cnsl-password-complexity-policy [serviceType]="serviceType"></cnsl-password-complexity-policy>
</ng-container>
@@ -57,4 +54,7 @@
<ng-container *ngIf="currentSetting === 'privacypolicy'">
<cnsl-privacy-policy [serviceType]="serviceType"></cnsl-privacy-policy>
</ng-container>
<ng-container *ngIf="currentSetting === 'languages' && serviceType === PolicyComponentServiceType.ADMIN">
<cnsl-language-settings></cnsl-language-settings>
</ng-container>
</cnsl-sidenav>

View File

@@ -7,7 +7,7 @@ import { HasRolePipeModule } from 'src/app/pipes/has-role-pipe/has-role-pipe.mod
import { CardModule } from '../card/card.module';
import DomainsModule from '../domains/domains.module';
import { DomainPolicyModule } from '../policies/domain-policy/domain-policy.module';
import { GeneralSettingsModule } from '../policies/general-settings/general-settings.module';
import { LanguageSettingsModule } from '../policies/language-settings/language-settings.module';
import { IdpSettingsModule } from '../policies/idp-settings/idp-settings.module';
import { LoginPolicyModule } from '../policies/login-policy/login-policy.module';
import { LoginTextsPolicyModule } from '../policies/login-texts/login-texts.module';
@@ -36,7 +36,7 @@ import { SettingsListComponent } from './settings-list.component';
PasswordComplexityPolicyModule,
PasswordLockoutPolicyModule,
PrivateLabelingPolicyModule,
GeneralSettingsModule,
LanguageSettingsModule,
NotificationPolicyModule,
IdpSettingsModule,
PrivacyPolicyModule,

View File

@@ -1,9 +1,9 @@
import { PolicyComponentServiceType } from '../policies/policy-component-types.enum';
import { SidenavSetting } from '../sidenav/sidenav.component';
export const GENERAL: SidenavSetting = {
id: 'general',
i18nKey: 'SETTINGS.LIST.GENERAL',
export const LANGUAGES: SidenavSetting = {
id: 'languages',
i18nKey: 'SETTINGS.LIST.LANGUAGES',
requiredRoles: {
[PolicyComponentServiceType.ADMIN]: ['iam.policy.read'],
},

View File

@@ -10,7 +10,7 @@ import {
BRANDING,
COMPLEXITY,
DOMAIN,
GENERAL,
LANGUAGES,
IDP,
LOCKOUT,
LOGIN,
@@ -34,7 +34,6 @@ export class InstanceSettingsComponent implements OnInit, OnDestroy {
public id: string = '';
public PolicyComponentServiceType: any = PolicyComponentServiceType;
public defaultSettingsList: SidenavSetting[] = [
GENERAL,
// notifications
// { showWarn: true, ...NOTIFICATIONS },
NOTIFICATIONS,
@@ -53,6 +52,7 @@ export class InstanceSettingsComponent implements OnInit, OnDestroy {
LOGINTEXTS,
// others
PRIVACYPOLICY,
LANGUAGES,
OIDC,
SECRETS,
SECURITY,

View File

@@ -128,6 +128,7 @@ import {
GetPrivacyPolicyResponse,
GetProviderByIDRequest,
GetProviderByIDResponse,
GetRestrictionsResponse,
GetSecretGeneratorRequest,
GetSecretGeneratorResponse,
GetSecurityPolicyRequest,
@@ -194,6 +195,7 @@ import {
ResetCustomDomainPolicyToDefaultResponse,
ResetCustomLoginTextsToDefaultRequest,
ResetCustomLoginTextsToDefaultResponse,
SelectLanguages,
SetCustomLoginTextsRequest,
SetCustomLoginTextsResponse,
SetDefaultDomainClaimedMessageTextRequest,
@@ -218,6 +220,8 @@ import {
SetDefaultVerifyPhoneMessageTextResponse,
SetDefaultVerifySMSOTPMessageTextRequest,
SetDefaultVerifySMSOTPMessageTextResponse,
SetRestrictionsRequest,
SetRestrictionsResponse,
SetSecurityPolicyRequest,
SetSecurityPolicyResponse,
SetUpOrgRequest,
@@ -830,6 +834,29 @@ export class AdminService {
return this.grpcService.admin.setDefaultLanguage(req, null).then((resp) => resp.toObject());
}
/* restrictions */
public getRestrictions(): Promise<GetRestrictionsResponse.AsObject> {
const req = new GetDefaultLanguageRequest();
return this.grpcService.admin.getRestrictions(req, null).then((resp) => resp.toObject());
}
public setRestrictions(
disallowPublicOrgRegistration?: boolean,
allowedLanguages?: string[],
): Promise<SetRestrictionsResponse.AsObject> {
const req = new SetRestrictionsRequest();
if (disallowPublicOrgRegistration !== undefined) {
req.setDisallowPublicOrgRegistration(disallowPublicOrgRegistration);
}
if (allowedLanguages !== undefined) {
const langs = new SelectLanguages();
langs.setListList(allowedLanguages);
req.setAllowedLanguages(langs);
}
return this.grpcService.admin.setRestrictions(req, null).then((resp) => resp.toObject());
}
/* notification policy */
public getNotificationPolicy(): Promise<GetNotificationPolicyResponse.AsObject> {

View File

@@ -36,7 +36,6 @@ export class LanguagesService {
});
}
// TODO: call this in https://github.com/zitadel/zitadel/pull/6965
public newAllowed(languages: string[]) {
this.allowedSubject$.next(languages);
}

View File

@@ -36,7 +36,7 @@ export class ToastService {
}
}
public showError(error: any | string, isGrpc: boolean = true, i18nKey: boolean = false): void {
public showError = (error: any | string, isGrpc: boolean = true, i18nKey: boolean = false) => {
if (isGrpc) {
const { message, code, metadata } = error;
if (code !== 16) {
@@ -57,7 +57,7 @@ export class ToastService {
} else {
this.showMessage(error as string, '', false);
}
}
};
private showMessage(message: string, action: string, success: boolean): Observable<void> {
const ref = this.snackBar.open(message, action, {

View File

@@ -1014,7 +1014,7 @@
"DESCRIPTION": "Тези настройки разширяват и презаписват настройките на вашия екземпляр."
},
"LIST": {
"GENERAL": "Общ",
"LANGUAGES": "Езици",
"LOGIN": "Поведение при влизане и сигурност",
"LOCKOUT": "Блокиране",
"COMPLEXITY": "Сложност на паролата",
@@ -1043,22 +1043,32 @@
}
},
"SETTING": {
"DEFAULTLANGUAGE": "Език по подразбиране",
"LANGUAGE": {
"de": "Deutsch",
"en": "Английски",
"es": "Español",
"fr": "Français",
"it": "Италиано",
"ja": "日本語",
"pl": "Полски",
"zh": "简体中文",
"bg": "Български",
"pt": "Portuguese",
"mk": "Македонски",
"cs": "Čeština",
"ru": "Русский",
"nl": "Nederlands"
"LANGUAGES": {
"TITLE": "Настройки на езика",
"DEFAULT": "Език по подразбиране",
"ALLOWED": "Разрешени езици",
"NOT_ALLOWED": "Не са разрешени езици",
"ALLOW_ALL": "Разрешете всички езици",
"DISALLOW_ALL": "Забранете всички езици",
"SETASDEFAULT": "Задайте като език по подразбиране",
"DEFAULT_SAVED": "Езикът по подразбиране е запазен успешно.",
"ALLOWED_SAVED": "Разрешените езици са запазени успешно.",
"OPTIONS": {
"de": "Deutsch",
"en": "Английски",
"es": "Español",
"fr": "Français",
"it": "Италиано",
"ja": "日本語",
"pl": "Полски",
"zh": "简体中文",
"bg": "Български",
"pt": "Portuguese",
"mk": "Македонски",
"cs": "Čeština",
"ru": "Русский",
"nl": "Nederlands"
}
},
"SMTP": {
"TITLE": "SMTP настройки",
@@ -1371,7 +1381,8 @@
"SMTPSENDERADDRESSMATCHESINSTANCEDOMAIN": "SMTP адресът на изпращача съвпада с домейна на екземпляра",
"ALLOWUSERNAMEPASSWORD": "Потребителско име Паролата е разрешена",
"ALLOWEXTERNALIDP": "Допуска се външен IDP",
"ALLOWREGISTER": "Регистрацията е разрешена",
"ALLOWREGISTERUSERS": "Регистрирайте потребители",
"ALLOWREGISTERORGS": "Регистрирайте организации",
"ALLOWUSERNAMEPASSWORD_DESC": "Разрешено е конвенционалното влизане с потребителско име и парола.",
"ALLOWEXTERNALIDP_DESC": "Входът е разрешен за основните доставчици на самоличност",
"ALLOWREGISTER_DESC": "Ако опцията е избрана, в входа се появява допълнителна стъпка за регистрация на потребител.",

View File

@@ -1021,7 +1021,7 @@
"DESCRIPTION": "Tato nastavení rozšiřují a přepisují nastavení vaší instance."
},
"LIST": {
"GENERAL": "Obecné",
"LANGUAGES": "Jazyky",
"LOGIN": "Chování při přihlášení a bezpečnost",
"LOCKOUT": "Blokování",
"COMPLEXITY": "Složitost hesla",
@@ -1050,22 +1050,32 @@
}
},
"SETTING": {
"DEFAULTLANGUAGE": "Výchozí jazyk",
"LANGUAGE": {
"de": "Deutsch",
"en": "English",
"es": "Español",
"fr": "Français",
"it": "Italiano",
"ja": "日本語",
"pl": "Polski",
"zh": "简体中文",
"bg": "Български",
"pt": "Portuguese",
"mk": "Македонски",
"cs": "Čeština",
"ru": "Русский",
"nl": "Nederlands"
"LANGUAGES": {
"TITLE": "Nastavení jazyka",
"DEFAULT": "Výchozí jazyk",
"ALLOWED": "Povolené jazyky",
"NOT_ALLOWED": "Nepovolené jazyky",
"ALLOW_ALL": "Povolit všechny jazyky",
"DISALLOW_ALL": "Zakázat všechny jazyky",
"SETASDEFAULT": "Nastavit jako výchozí",
"DEFAULT_SAVED": "Výchozí jazyk byl úspěšně nastaven.",
"ALLOWED_SAVED": "Povolené jazyky byly úspěšně nastaveny.",
"OPTIONS": {
"de": "Deutsch",
"en": "English",
"es": "Español",
"fr": "Français",
"it": "Italiano",
"ja": "日本語",
"pl": "Polski",
"zh": "简体中文",
"bg": "Български",
"pt": "Portuguese",
"mk": "Македонски",
"cs": "Čeština",
"ru": "Русский",
"nl": "Nederlands"
}
},
"SMTP": {
"TITLE": "Nastavení SMTP",
@@ -1379,6 +1389,8 @@
"ALLOWUSERNAMEPASSWORD": "Povoleno uživatelské jméno a heslo",
"ALLOWEXTERNALIDP": "Povoleno externí IDP",
"ALLOWREGISTER": "Registrace povolena",
"ALLOWREGISTERUSERS": "Registrace uživatelů povolena",
"ALLOWREGISTERORGS": "Registrace organizací povolena",
"ALLOWUSERNAMEPASSWORD_DESC": "Je povoleno klasické přihlášení s uživatelským jménem a heslem.",
"ALLOWEXTERNALIDP_DESC": "Přihlášení je povoleno pro níže uvedené poskytovatele identity.",
"ALLOWREGISTER_DESC": "Pokud je možnost vybrána, objeví se při přihlášení další krok pro registraci uživatele.",

View File

@@ -1020,7 +1020,7 @@
"DESCRIPTION": "Diese Einstellungen erweitern bzw. überschreiben die Einstellungen Ihrer Instanz."
},
"LIST": {
"GENERAL": "Allgemein",
"LANGUAGES": "Sprachen",
"LOGIN": "Loginverhalten und Sicherheit",
"LOCKOUT": "Sperrmechanismen",
"COMPLEXITY": "Passwordkomplexität",
@@ -1049,22 +1049,32 @@
}
},
"SETTING": {
"DEFAULTLANGUAGE": "Standardsprache",
"LANGUAGE": {
"de": "Deutsch",
"en": "English",
"es": "Español",
"fr": "Français",
"it": "Italiano",
"ja": "日本語",
"pl": "Polski",
"zh": "简体中文",
"bg": "Български",
"pt": "Portuguese",
"mk": "Македонски",
"cs": "Čeština",
"ru": "Русский",
"nl": "Nederlands"
"LANGUAGES": {
"TITLE": "Spracheinstellungen",
"DEFAULT": "Standardsprache",
"ALLOWED": "Erlaubte Sprachen",
"NOT_ALLOWED": "Nicht erlaubte Sprachen",
"ALLOW_ALL": "Alle Sprachen erlauben",
"DISALLOW_ALL": "Alle Sprachen verbieten",
"SETASDEFAULT": "Als Standard setzen",
"DEFAULT_SAVED": "Standard Sprache gesetzt",
"ALLOWED_SAVED": "Erlaubte Sprachen gesetzt",
"OPTIONS": {
"de": "Deutsch",
"en": "English",
"es": "Español",
"fr": "Français",
"it": "Italiano",
"ja": "日本語",
"pl": "Polski",
"zh": "简体中文",
"bg": "Български",
"pt": "Portuguese",
"mk": "Македонски",
"cs": "Čeština",
"ru": "Русский",
"nl": "Nederlands"
}
},
"SMTP": {
"TITLE": "SMTP Einstellungen",
@@ -1377,7 +1387,8 @@
"SMTPSENDERADDRESSMATCHESINSTANCEDOMAIN": "SMTP Sender Adresse entspricht Instanzdomain",
"ALLOWUSERNAMEPASSWORD": "Benutzername Passwort erlaubt",
"ALLOWEXTERNALIDP": "Externer IDP erlaubt",
"ALLOWREGISTER": "Registrieren erlaubt",
"ALLOWREGISTERUSERS": "Benutzerregistrierung erlaubt",
"ALLOWREGISTERORGS": "Organisationsregistrierung erlaubt",
"ALLOWUSERNAMEPASSWORD_DESC": "Der konventionelle Login mit Benutzername und Passwort wird erlaubt.",
"ALLOWEXTERNALIDP_DESC": "Der Login wird für die darunter liegenden Identitätsanbieter erlaubt.",
"ALLOWREGISTER_DESC": "Ist die Option gewählt, erscheint im Login ein zusätzlicher Schritt zum Registrieren eines Benutzers.",

View File

@@ -1021,7 +1021,7 @@
"DESCRIPTION": "These settings extend and overwrite your instance settings."
},
"LIST": {
"GENERAL": "General",
"LANGUAGES": "Languages",
"LOGIN": "Login Behavior and Security",
"LOCKOUT": "Lockout",
"COMPLEXITY": "Password complexity",
@@ -1050,22 +1050,32 @@
}
},
"SETTING": {
"DEFAULTLANGUAGE": "Default Language",
"LANGUAGE": {
"de": "Deutsch",
"en": "English",
"es": "Español",
"fr": "Français",
"it": "Italiano",
"ja": "日本語",
"pl": "Polski",
"zh": "简体中文",
"bg": "Български",
"pt": "Portuguese",
"mk": "Македонски",
"cs": "Čeština",
"ru": "Русский",
"nl": "Nederlands"
"LANGUAGES": {
"TITLE": "Language Settings",
"DEFAULT": "Default Language",
"ALLOWED": "Allowed Languages",
"NOT_ALLOWED": "Not Allowed Languages",
"ALLOW_ALL": "Allow All",
"DISALLOW_ALL": "Disallow All",
"SETASDEFAULT": "Set as Default Language",
"DEFAULT_SAVED": "Default Language saved",
"ALLOWED_SAVED": "Allowed Languages saved",
"OPTIONS": {
"de": "Deutsch",
"en": "English",
"es": "Español",
"fr": "Français",
"it": "Italiano",
"ja": "日本語",
"pl": "Polski",
"zh": "简体中文",
"bg": "Български",
"pt": "Portuguese",
"mk": "Македонски",
"cs": "Čeština",
"ru": "Русский",
"nl": "Nederlands"
}
},
"SMTP": {
"TITLE": "SMTP Settings",
@@ -1378,7 +1388,8 @@
"SMTPSENDERADDRESSMATCHESINSTANCEDOMAIN": "SMTP Sender Address matches Instance Domain",
"ALLOWUSERNAMEPASSWORD": "Username Password allowed",
"ALLOWEXTERNALIDP": "External IDP allowed",
"ALLOWREGISTER": "Register allowed",
"ALLOWREGISTERUSERS": "Register users allowed",
"ALLOWREGISTERORGS": "Register organizations allowed",
"ALLOWUSERNAMEPASSWORD_DESC": "The conventional login with user name and password is allowed.",
"ALLOWEXTERNALIDP_DESC": "The login is allowed for the underlying identity providers",
"ALLOWREGISTER_DESC": "If the option is selected, an additional step for registering a user appears in the login.",

View File

@@ -1021,7 +1021,7 @@
"DESCRIPTION": "Estas configuraciones amplían y sobrescriben tus configuraciones de instancia."
},
"LIST": {
"GENERAL": "General",
"LANGUAGES": "Idiomas",
"LOGIN": "Comportamiento del inicio de sesión y de la seguridad",
"LOCKOUT": "Bloqueo",
"COMPLEXITY": "Complejidad de contraseña",
@@ -1050,22 +1050,32 @@
}
},
"SETTING": {
"DEFAULTLANGUAGE": "Idioma por defecto",
"LANGUAGE": {
"de": "Deutsch",
"en": "English",
"es": "Español",
"fr": "Français",
"it": "Italiano",
"ja": "日本語",
"pl": "Polski",
"zh": "简体中文",
"bg": "Български",
"pt": "Portuguese",
"mk": "Македонски",
"cs": "Čeština",
"ru": "Русский",
"nl": "Nederlands"
"LANGUAGES": {
"TITLE": "Ajustes de idioma",
"DEFAULT": "Idioma predeterminado",
"ALLOWED": "Idiomas permitidos",
"NOT_ALLOWED": "Idiomas no permitidos",
"ALLOW_ALL": "Permitir todos los idiomas",
"DISALLOW_ALL": "No permitir ningún idioma",
"SETASDEFAULT": "Establecer como idioma predeterminado",
"DEFAULT_SAVED": "Idioma predeterminado guardado",
"ALLOWED_SAVED": "Idiomas permitidos guardados",
"OPTIONS": {
"de": "Deutsch",
"en": "English",
"es": "Español",
"fr": "Français",
"it": "Italiano",
"ja": "日本語",
"pl": "Polski",
"zh": "简体中文",
"bg": "Български",
"pt": "Portuguese",
"mk": "Македонски",
"cs": "Čeština",
"ru": "Русский",
"nl": "Nederlands"
}
},
"SMTP": {
"TITLE": "Ajustes SMTP",
@@ -1378,7 +1388,8 @@
"SMTPSENDERADDRESSMATCHESINSTANCEDOMAIN": "La dirección del remitente SMTP coincide con el dominio de la instancia",
"ALLOWUSERNAMEPASSWORD": "Nombre de usuario y contraseña permitido",
"ALLOWEXTERNALIDP": "Permitido IDP externo",
"ALLOWREGISTER": "Registro permitido",
"ALLOWREGISTERUSERS": "Registro de usuarios permitido",
"ALLOWREGISTERORGS": "Registro de organizaciones permitido",
"ALLOWUSERNAMEPASSWORD_DESC": "El inicio de sesión convencional con nombre de usuario y contraseña está permitido.",
"ALLOWEXTERNALIDP_DESC": "El inicio de sesión está permitido para los proveedores de identidad subyacentes",
"ALLOWREGISTER_DESC": "Si esta opción es seleccionada, aparece un paso adicional durante el inicio de sesión para registrar un usuario.",

View File

@@ -1020,7 +1020,7 @@
"DESCRIPTION": "Ces paramètres étendent et remplacent les paramètres de votre instance."
},
"LIST": {
"GENERAL": "Général",
"LANGUAGES": "Langues",
"LOGIN": "Comportement de connexion et sécurité",
"LOCKOUT": "Verrouillage",
"COMPLEXITY": "Complexité du mot de passe",
@@ -1049,22 +1049,32 @@
}
},
"SETTING": {
"DEFAULTLANGUAGE": "Langue par défaut",
"LANGUAGE": {
"de": "Deutsch",
"en": "English",
"es": "Español",
"fr": "Français",
"it": "Italiano",
"ja": "日本語",
"pl": "Polski",
"zh": "简体中文",
"bg": "Български",
"pt": "Portuguese",
"mk": "Македонски",
"cs": "Čeština",
"ru": "Русский",
"nl": "Nederlands"
"LANGUAGES": {
"TITLE": "Paramètres de langue",
"DEFAULT": "Langue par défaut",
"ALLOWED": "Langues autorisées",
"NOT_ALLOWED": "Langues non autorisées",
"ALLOW_ALL": "Autoriser toutes les langues",
"DISALLOW_ALL": "Interdire toutes les langues",
"SETASDEFAULT": "Définir comme langue par défaut",
"DEFAULT_SAVED": "Langue par défaut enregistrée",
"ALLOWED_SAVED": "Langues autorisées enregistrées",
"OPTIONS": {
"de": "Deutsch",
"en": "English",
"es": "Español",
"fr": "Français",
"it": "Italiano",
"ja": "日本語",
"pl": "Polski",
"zh": "简体中文",
"bg": "Български",
"pt": "Portuguese",
"mk": "Македонски",
"cs": "Čeština",
"ru": "Русский",
"nl": "Nederlands"
}
},
"SMTP": {
"TITLE": "Paramètres SMTP",
@@ -1377,7 +1387,8 @@
"SMTPSENDERADDRESSMATCHESINSTANCEDOMAIN": "L'adresse de l'expéditeur SMTP correspond au domaine de l'instance",
"ALLOWUSERNAMEPASSWORD": "Nom d'utilisateur Mot de passe autorisé",
"ALLOWEXTERNALIDP": "IDP externe autorisé",
"ALLOWREGISTER": "Enregistrement autorisé",
"ALLOWREGISTERUSERS": "Enregistrer les utilisateurs autorisés",
"ALLOWREGISTERORGS": "Enregistrer les organisations autorisées",
"ALLOWUSERNAMEPASSWORD_DESC": "La connexion classique avec nom d'utilisateur et mot de passe est autorisée.",
"ALLOWEXTERNALIDP_DESC": "La connexion est autorisée pour les fournisseurs d'identité sous-jacents",
"ALLOWREGISTER_DESC": "Si l'option est sélectionnée, une étape supplémentaire pour l'enregistrement d'un utilisateur apparaît dans la connexion.",

View File

@@ -1020,7 +1020,7 @@
"DESCRIPTION": "Queste impostazioni si applicheranno alla organizzazione corrente."
},
"LIST": {
"GENERAL": "Generale",
"LANGUAGES": "Lingue",
"LOGIN": "Comportamento login e sicurezza",
"LOCKOUT": "Meccanismi di bloccaggio",
"COMPLEXITY": "Complessità della password",
@@ -1049,22 +1049,32 @@
}
},
"SETTING": {
"DEFAULTLANGUAGE": "Lingua standard",
"LANGUAGE": {
"de": "Deutsch",
"en": "English",
"es": "Español",
"fr": "Français",
"it": "Italiano",
"ja": "日本語",
"pl": "Polski",
"zh": "简体中文",
"bg": "Български",
"pt": "Portuguese",
"mk": "Македонски",
"cs": "Čeština",
"ru": "Русский",
"nl": "Nederlands"
"LANGUAGES": {
"TITLE": "Impostazioni della lingua",
"DEFAULT": "Lingua predefinita",
"ALLOWED": "Lingue consentite",
"NOT_ALLOWED": "Lingue non consentite",
"ALLOW_ALL": "Consenti tutte le lingue",
"DISALLOW_ALL": "Non consentire tutte le lingue",
"SETASDEFAULT": "Imposta come lingua predefinita",
"DEFAULT_SAVED": "Lingua predefinita salvata",
"ALLOWED_SAVED": "Lingue consentite salvate",
"OPTIONS": {
"de": "Deutsch",
"en": "English",
"es": "Español",
"fr": "Français",
"it": "Italiano",
"ja": "日本語",
"pl": "Polski",
"zh": "简体中文",
"bg": "Български",
"pt": "Portuguese",
"mk": "Македонски",
"cs": "Čeština",
"ru": "Русский",
"nl": "Nederlands"
}
},
"SMTP": {
"TITLE": "Impostazioni SMTP",
@@ -1377,7 +1387,8 @@
"SMTPSENDERADDRESSMATCHESINSTANCEDOMAIN": "L'indirizzo mittente SMTP corrisponde al dominio dell'istanza",
"ALLOWUSERNAMEPASSWORD": "Autenticazione classica con password consentita",
"ALLOWEXTERNALIDP": "IDP esterno consentito",
"ALLOWREGISTER": "Registrazione consentita",
"ALLOWREGISTERUSERS": "Registrazione utenti consentita",
"ALLOWREGISTERORGS": "Registrazione organizzazioni consentita",
"ALLOWUSERNAMEPASSWORD_DESC": "Autenticazione classica con nome utente e password \u00e8 permessa.",
"ALLOWEXTERNALIDP_DESC": "Il login \u00e8 permesso per gli IDP sottostanti",
"ALLOWREGISTER_DESC": "Se l'opzione \u00e8 selezionata, nel login apparirà un passo aggiuntivo per la registrazione di un utente.",

View File

@@ -1021,7 +1021,7 @@
"DESCRIPTION": "これらの設定は、インスタンス設定を拡張・上書きします。"
},
"LIST": {
"GENERAL": "全般",
"LANGUAGES": "一般設定",
"LOGIN": "ログイン動作とセキュリティ",
"LOCKOUT": "ロックアウト",
"COMPLEXITY": "パスワードの複雑さ",
@@ -1050,22 +1050,32 @@
}
},
"SETTING": {
"DEFAULTLANGUAGE": "デフォルトの言語",
"LANGUAGE": {
"de": "Deutsch",
"en": "English",
"es": "Español",
"fr": "Français",
"it": "Italiano",
"ja": "日本語",
"pl": "Polski",
"zh": "简体中文",
"bg": "Български",
"pt": "Portuguese",
"mk": "Македонски",
"cs": "Čeština",
"ru": "Русский",
"nl": "Nederlands"
"LANGUAGES": {
"TITLE": "言語設定",
"DEFAULT": "デフォルト言語",
"ALLOWED": "許可された言語",
"NOT_ALLOWED": "許可されていない言語",
"ALLOW_ALL": "すべての言語を許可する",
"DISALLOW_ALL": "すべての言語を許可しない",
"SETASDEFAULT": "デフォルト言語として設定する",
"DEFAULT_SAVED": "デフォルト言語が保存されました",
"ALLOWED_SAVED": "許可された言語が保存されました",
"OPTIONS": {
"de": "Deutsch",
"en": "English",
"es": "Español",
"fr": "Français",
"it": "Italiano",
"ja": "日本語",
"pl": "Polski",
"zh": "简体中文",
"bg": "Български",
"pt": "Portuguese",
"mk": "Македонски",
"cs": "Čeština",
"ru": "Русский",
"nl": "Nederlands"
}
},
"SMTP": {
"TITLE": "SMTP設定",
@@ -1373,7 +1383,8 @@
"SMTPSENDERADDRESSMATCHESINSTANCEDOMAIN": "SMTP送信者アドレスはインスタンスドメインに一致しています",
"ALLOWUSERNAMEPASSWORD": "ユーザー名とパスワードを許可",
"ALLOWEXTERNALIDP": "外部IDPを許可",
"ALLOWREGISTER": "登録を許可",
"ALLOWREGISTERUSERS": "ユーザーの登録を許可",
"ALLOWREGISTERORGS": "組織の登録を許可",
"ALLOWUSERNAMEPASSWORD_DESC": "ユーザー名とパスワードを使用した従来のログインを許可します。",
"ALLOWEXTERNALIDP_DESC": "基礎となるIDプロバイダーにログインを許可します。",
"ALLOWREGISTER_DESC": "このオプションが選択されている場合、ユーザーを登録するための追加のステップがログインに表示されます。",

View File

@@ -1022,7 +1022,7 @@
"DESCRIPTION": "Овие подесувања ги прошируваат и препишуваат подесувањата на вашата инстанца."
},
"LIST": {
"GENERAL": "Генерални",
"LANGUAGES": "Општо",
"LOGIN": "Правила и безбедност при најава",
"LOCKOUT": "Забрана на пристап",
"COMPLEXITY": "Сложеност на лозинката",
@@ -1051,22 +1051,32 @@
}
},
"SETTING": {
"DEFAULTLANGUAGE": "Стандарден јазик",
"LANGUAGE": {
"de": "Deutsch",
"en": "English",
"es": "Español",
"fr": "Français",
"it": "Italiano",
"ja": "日本語",
"pl": "Polski",
"zh": "简体中文",
"bg": "Български",
"pt": "Portuguese",
"mk": "Македонски",
"cs": "Čeština",
"ru": "Русский",
"nl": "Nederlands"
"LANGUAGES": {
"TITLE": "Подесувања за јазик",
"DEFAULT": "Стандарден јазик",
"ALLOWED": "Дозволени јазици",
"NOT_ALLOWED": "Не дозволени јазици",
"ALLOW_ALL": "Дозволи ги сите јазици",
"DISALLOW_ALL": "Забрани ги сите јазици",
"SETASDEFAULT": "Постави како стандарден јазик",
"DEFAULT_SAVED": "Стандардниот јазик е зачуван",
"ALLOWED_SAVED": "Дозволените јазици се зачувани",
"OPTIONS": {
"de": "Deutsch",
"en": "English",
"es": "Español",
"fr": "Français",
"it": "Italiano",
"ja": "日本語",
"pl": "Polski",
"zh": "简体中文",
"bg": "Български",
"pt": "Portuguese",
"mk": "Македонски",
"cs": "Čeština",
"ru": "Русский",
"nl": "Nederlands"
}
},
"SMTP": {
"TITLE": "SMTP подесувања",
@@ -1379,7 +1389,8 @@
"SMTPSENDERADDRESSMATCHESINSTANCEDOMAIN": "SMTP адресата на испраќачот се поклопува со доменот на инстанцата",
"ALLOWUSERNAMEPASSWORD": "Дозволено корисничко име и лозинка",
"ALLOWEXTERNALIDP": "Дозволен надворешен IDP",
"ALLOWREGISTER": "Дозволена регистрација",
"ALLOWREGISTERUSERS": "Дозволена регистрација на корисници",
"ALLOWREGISTERORGS": "Дозволена регистрација на организации",
"ALLOWUSERNAMEPASSWORD_DESC": "Дозволена е конвенционална најава со корисничко име и лозинка.",
"ALLOWEXTERNALIDP_DESC": "Најавата е дозволена за поддржуваните IDPs",
"ALLOWREGISTER_DESC": "Доколку е избрана опцијата, се прикажува дополнителен чекор за регистрирање на корисник во најавата.",

View File

@@ -1021,7 +1021,7 @@
"DESCRIPTION": "Deze instellingen breiden uw instantie instellingen uit en overschrijven deze."
},
"LIST": {
"GENERAL": "Algemeen",
"LANGUAGES": "Talen",
"LOGIN": "Login Gedrag en Beveiliging",
"LOCKOUT": "Lockout",
"COMPLEXITY": "Wachtwoord complexiteit",
@@ -1050,22 +1050,32 @@
}
},
"SETTING": {
"DEFAULTLANGUAGE": "Standaard Taal",
"LANGUAGE": {
"de": "Deutsch",
"en": "Engels",
"es": "Español",
"fr": "Français",
"it": "Italiano",
"ja": "日本語",
"pl": "Polski",
"zh": "简体中文",
"bg": "Български",
"pt": "Portugees",
"mk": "Македонски",
"cs": "Čeština",
"ru": "Русский",
"nl": "Nederlands"
"LANGUAGES": {
"TITLE": "Taalinstellingen",
"DEFAULT": "Standaardtaal",
"ALLOWED": "Toegestane Talen",
"NOT_ALLOWED": "Niet Toegestane Talen",
"ALLOW_ALL": "Sta alle talen toe",
"DISALLOW_ALL": "Sta geen talen toe",
"SETASDEFAULT": "Stel in als standaardtaal",
"DEFAULT_SAVED": "Standaardtaal opgeslagen",
"ALLOWED_SAVED": "Toegestane talen opgeslagen",
"OPTIONS": {
"de": "Deutsch",
"en": "Engels",
"es": "Español",
"fr": "Français",
"it": "Italiano",
"ja": "日本語",
"pl": "Polski",
"zh": "简体中文",
"bg": "Български",
"pt": "Portugees",
"mk": "Македонски",
"cs": "Čeština",
"ru": "Русский",
"nl": "Nederlands"
}
},
"SMTP": {
"TITLE": "SMTP Instellingen",
@@ -1378,7 +1388,8 @@
"SMTPSENDERADDRESSMATCHESINSTANCEDOMAIN": "SMTP Afzender Adres komt overeen met Instantie Domein",
"ALLOWUSERNAMEPASSWORD": "Gebruikersnaam Wachtwoord toegestaan",
"ALLOWEXTERNALIDP": "Externe IDP toegestaan",
"ALLOWREGISTER": "Registratie toegestaan",
"ALLOWREGISTERUSERS": "Gebruikersregistratie toegestaan",
"ALLOWREGISTERORGS": "Organisatieregistratie toegestaan",
"ALLOWUSERNAMEPASSWORD_DESC": "De conventionele login met gebruikersnaam en wachtwoord is toegestaan.",
"ALLOWEXTERNALIDP_DESC": "De login is toegestaan voor de onderliggende identiteitsproviders",
"ALLOWREGISTER_DESC": "Als de optie is geselecteerd, verschijnt er een extra stap voor het registreren van een gebruiker in het login proces.",

View File

@@ -1020,7 +1020,7 @@
"DESCRIPTION": "Te ustawienia rozszerzają i nadpisują ustawienia instancji."
},
"LIST": {
"GENERAL": "Ogólne",
"LANGUAGES": "Języki",
"LOGIN": "Zachowanie logowania i bezpieczeństwo",
"LOCKOUT": "Blokada",
"COMPLEXITY": "Złożoność hasła",
@@ -1049,22 +1049,32 @@
}
},
"SETTING": {
"DEFAULTLANGUAGE": "Domyślny język",
"LANGUAGE": {
"de": "Deutsch",
"en": "English",
"es": "Español",
"fr": "Français",
"it": "Italiano",
"ja": "日本語",
"pl": "Polski",
"zh": "简体中文",
"bg": "Български",
"pt": "Portuguese",
"mk": "Македонски",
"cs": "Čeština",
"ru": "Русский",
"nl": "Nederlands"
"LANGUAGES": {
"TITLE": "Ustawienia językowe",
"DEFAULT": "Domyślny język",
"ALLOWED": "Dozwolone języki",
"NOT_ALLOWED": "Niedozwolone języki",
"ALLOW_ALL": "Zezwól na wszystkie języki",
"DISALLOW_ALL": "Zabroń wszystkich języków",
"SETASDEFAULT": "Ustaw jako domyślny język",
"DEFAULT_SAVED": "Domyślny język zapisany",
"ALLOWED_SAVED": "Dozwolone języki zapisane",
"OPTIONS": {
"de": "Deutsch",
"en": "English",
"es": "Español",
"fr": "Français",
"it": "Italiano",
"ja": "日本語",
"pl": "Polski",
"zh": "简体中文",
"bg": "Български",
"pt": "Portuguese",
"mk": "Македонски",
"cs": "Čeština",
"ru": "Русский",
"nl": "Nederlands"
}
},
"SMTP": {
"TITLE": "Ustawienia SMTP",
@@ -1377,7 +1387,8 @@
"SMTPSENDERADDRESSMATCHESINSTANCEDOMAIN": "Adres nadawcy SMTP pasuje do domeny instancji",
"ALLOWUSERNAMEPASSWORD": "Zezwól na użycie nazwy użytkownika i hasła",
"ALLOWEXTERNALIDP": "Zezwól na zewnętrznego dostawcę tożsamości",
"ALLOWREGISTER": "Zezwól na rejestrację",
"ALLOWREGISTERUSERS": "Zezwól na rejestrację użytkowników",
"ALLOWREGISTERORGS": "Zezwól na rejestrację organizacji",
"ALLOWUSERNAMEPASSWORD_DESC": "Zwykłe logowanie za pomocą nazwy użytkownika i hasła jest dozwolone.",
"ALLOWEXTERNALIDP_DESC": "Logowanie jest dozwolone dla dostawców tożsamości podstawowych",
"ALLOWREGISTER_DESC": "Jeśli ta opcja jest zaznaczona, pojawi się dodatkowy krok rejestracji użytkownika w procesie logowania.",

View File

@@ -1022,7 +1022,7 @@
"DESCRIPTION": "Essas configurações estendem e sobrescrevem as configurações da sua instância."
},
"LIST": {
"GENERAL": "Geral",
"LANGUAGES": "Idiomas",
"LOGIN": "Comportamento de Login e Segurança",
"LOCKOUT": "Bloqueio",
"COMPLEXITY": "Complexidade de Senha",
@@ -1051,22 +1051,32 @@
}
},
"SETTING": {
"DEFAULTLANGUAGE": "Idioma padrão",
"LANGUAGE": {
"de": "Deutsch",
"en": "English",
"es": "Español",
"fr": "Français",
"it": "Italiano",
"ja": "日本語",
"pl": "Polski",
"zh": "简体中文",
"bg": "Български",
"pt": "Portuguese",
"mk": "Македонски",
"cs": "Čeština",
"ru": "Русский",
"nl": "Nederlands"
"LANGUAGES": {
"TITLE": "Configurações de Idioma",
"DEFAULT": "Idioma Padrão",
"ALLOWED": "Idiomas Permitidos",
"NOT_ALLOWED": "Idiomas Não Permitidos",
"ALLOW_ALL": "Permitir Todos os Idiomas",
"DISALLOW_ALL": "Não Permitir Todos os Idiomas",
"SETASDEFAULT": "Definir como Idioma Padrão",
"DEFAULT_SAVED": "Idioma Padrão salvo",
"ALLOWED_SAVED": "Idiomas Permitidos salvos",
"OPTIONS": {
"de": "Deutsch",
"en": "English",
"es": "Español",
"fr": "Français",
"it": "Italiano",
"ja": "日本語",
"pl": "Polski",
"zh": "简体中文",
"bg": "Български",
"pt": "Portuguese",
"mk": "Македонски",
"cs": "Čeština",
"ru": "Русский",
"nl": "Nederlands"
}
},
"SMTP": {
"TITLE": "Configurações SMTP",
@@ -1379,7 +1389,8 @@
"SMTPSENDERADDRESSMATCHESINSTANCEDOMAIN": "O endereço do remetente do SMTP corresponde ao domínio da Instância",
"ALLOWUSERNAMEPASSWORD": "Permitir usuário e senha",
"ALLOWEXTERNALIDP": "Permitir provedor de ID externo",
"ALLOWREGISTER": "Permitir registro",
"ALLOWREGISTERUSERS": "Permitir registro de usuários",
"ALLOWREGISTERORGS": "Permitir registro de organizações",
"ALLOWUSERNAMEPASSWORD_DESC": "O login convencional com nome de usuário e senha é permitido.",
"ALLOWEXTERNALIDP_DESC": "O login é permitido para os provedores de identidade subjacentes",
"ALLOWREGISTER_DESC": "Se a opção estiver selecionada, uma etapa adicional para registrar um usuário aparecerá no login.",

View File

@@ -1017,7 +1017,7 @@
"DESCRIPTION": "Эти настройки расширяют и перезаписывают настройки вашего экземпляра."
},
"LIST": {
"GENERAL": "Общие",
"LANGUAGES": "Языки",
"LOGIN": "Поведение при входе и безопасность",
"LOCKOUT": "Блокировка",
"COMPLEXITY": "Сложность пароля",
@@ -1043,21 +1043,31 @@
}
},
"SETTING": {
"DEFAULTLANGUAGE": "Язык по умолчанию",
"LANGUAGE": {
"de": "Deutsch",
"en": "English",
"es": "Español",
"fr": "Français",
"it": "Italiano",
"ja": "日本語",
"pl": "Polski",
"zh": "简体中文",
"bg": "Български",
"pt": "Portuguese",
"mk": "Македонски",
"ru": "Русский",
"nl": "Nederlands"
"LANGUAGES": {
"TITLE": "Настройки языка",
"DEFAULT": "Язык по умолчанию",
"ALLOWED": "Разрешенные языки",
"NOT_ALLOWED": "Неразрешенные языки",
"ALLOW_ALL": "Разрешить все языки",
"DISALLOW_ALL": "Запретить все языки",
"SETASDEFAULT": "Установить как язык по умолчанию",
"DEFAULT_SAVED": "Язык по умолчанию сохранен",
"ALLOWED_SAVED": "Разрешенные языки сохранены",
"OPTIONS": {
"de": "Deutsch",
"en": "English",
"es": "Español",
"fr": "Français",
"it": "Italiano",
"ja": "日本語",
"pl": "Polski",
"zh": "简体中文",
"bg": "Български",
"pt": "Portuguese",
"mk": "Македонски",
"ru": "Русский",
"nl": "Nederlands"
}
},
"SMTP": {
"TITLE": "Настройки SMTP",
@@ -1364,7 +1374,8 @@
"SMTPSENDERADDRESSMATCHESINSTANCEDOMAIN": "Адрес отправителя SMTP соответствует домену экземпляра",
"ALLOWUSERNAMEPASSWORD": "Вход с паролем разрешен",
"ALLOWEXTERNALIDP": "Внешний поставщик разрешен",
"ALLOWREGISTER": "Регистрация разрешена",
"ALLOWREGISTERUSERS": "Регистрация пользователей разрешена",
"ALLOWREGISTERORGS": "Регистрация организаций разрешена",
"ALLOWUSERNAMEPASSWORD_DESC": "Разрешен обычный вход в систему с использованием имени пользователя и паролем.",
"ALLOWEXTERNALIDP_DESC": "Вход разрешен для базовых поставщиков удостоверений.",
"ALLOWREGISTER_DESC": "Если опция выбрана, в логине появляется дополнительный шаг для регистрации пользователя.",

View File

@@ -1020,7 +1020,7 @@
"DESCRIPTION": "这些设置将扩展或覆盖您的实例设置。"
},
"LIST": {
"GENERAL": "通用",
"LANGUAGES": "语言",
"LOGIN": "登录行为和安全",
"LOCKOUT": "安全锁策略",
"COMPLEXITY": "密码复杂性",
@@ -1049,22 +1049,32 @@
}
},
"SETTING": {
"DEFAULTLANGUAGE": "默认语言",
"LANGUAGE": {
"de": "Deutsch",
"en": "English",
"es": "Español",
"fr": "Français",
"it": "Italiano",
"ja": "日本語",
"pl": "Polski",
"zh": "简体中文",
"bg": "Български",
"pt": "Portuguese",
"mk": "Македонски",
"cs": "Čeština",
"ru": "Русский",
"nl": "Nederlands"
"LANGUAGES": {
"TITLE": "语言设置",
"DEFAULT": "默认语言",
"ALLOWED": "允许的语言",
"NOT_ALLOWED": "不允许的语言",
"ALLOW_ALL": "允许所有语言",
"DISALLOW_ALL": "禁止所有语言",
"SETASDEFAULT": "设置为默认语言",
"DEFAULT_SAVED": "默认语言已保存",
"ALLOWED_SAVED": "允许的语言已保存",
"OPTIONS": {
"de": "Deutsch",
"en": "English",
"es": "Español",
"fr": "Français",
"it": "Italiano",
"ja": "日本語",
"pl": "Polski",
"zh": "简体中文",
"bg": "Български",
"pt": "Portuguese",
"mk": "Македонски",
"cs": "Čeština",
"ru": "Русский",
"nl": "Nederlands"
}
},
"SMTP": {
"TITLE": "SMTP 设置",
@@ -1376,7 +1386,8 @@
"SMTPSENDERADDRESSMATCHESINSTANCEDOMAIN": "SMTP 发件人地址与实例域名匹配",
"ALLOWUSERNAMEPASSWORD": "允许用户名密码",
"ALLOWEXTERNALIDP": "允许外部身份提供者",
"ALLOWREGISTER": "允许注册",
"ALLOWREGISTERUSERS": "允许注册用户",
"ALLOWREGISTERORGS": "允许注册组织",
"ALLOWUSERNAMEPASSWORD_DESC": "允许使用用户名和密码进行登录。",
"ALLOWEXTERNALIDP_DESC": "允许外部身份提供者进行登录",
"ALLOWREGISTER_DESC": "如果选择了该选项,登录中会出现一个用于注册用户的附加步骤。",