fix(console): move org domains into settings page of the organization (#6612)

* fix: hide domains settings for unauthorized users

* refine sidenav object mapping

* move domains to settings

* change docs

* set anchor to list element

* remove canwrite check in ngif

---------

Co-authored-by: Miguel A. C <doncicuto@gmail.com>
This commit is contained in:
Max Peintner 2023-09-29 09:31:35 +02:00 committed by GitHub
parent eb31c2a3be
commit d01f4d229f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
42 changed files with 161 additions and 202 deletions

View File

@ -158,14 +158,6 @@ const routes: Routes = [
requiresAll: true,
},
},
{
path: 'domains',
loadChildren: () => import('./pages/domains/domains.module'),
canActivate: [AuthGuard, RoleGuard],
data: {
roles: ['org.read'],
},
},
{
path: 'org-settings',
loadChildren: () => import('./pages/org-settings/org-settings.module'),

View File

@ -0,0 +1,67 @@
<ng-container *ngIf="['org.write$'] | hasRole as canwrite$">
<div class="domain-top-view">
<div>
<div class="domain-title-row">
<h2>{{ 'ORG.DOMAINS.TITLE' | translate }}</h2>
<a
mat-icon-button
href="https://zitadel.com/docs/guides/manage/console/organizations#how-zitadel-handles-usernames"
rel="noreferrer"
target="_blank"
>
<i class="las la-info-circle"></i>
</a>
</div>
<p class="desc cnsl-secondary-text">{{ 'ORG.DOMAINS.DESCRIPTION' | translate }}</p>
</div>
<span class="fill-space"></span>
<button
[disabled]="(canwrite$ | async) === false"
matTooltip="Add domain"
mat-raised-button
color="primary"
class="cnsl-action-button"
(click)="addNewDomain()"
>
<mat-icon>add</mat-icon>
<span>{{ 'ACTIONS.NEW' | translate }}</span>
<cnsl-action-keys (actionTriggered)="addNewDomain()"> </cnsl-action-keys>
</button>
</div>
<cnsl-card *ngFor="let domain of domains" class="domain-card">
<div class="domain">
<span class="title">{{ domain.domainName }}</span>
<i matTooltip="verified" *ngIf="domain.isVerified" class="verified las la-check-circle"></i>
<i matTooltip="primary" *ngIf="domain.isPrimary" class="primary las la-star"></i>
<a
*ngIf="domain.isVerified && !domain.isPrimary && (canwrite$ | async)"
class="primaryset"
(click)="setPrimary(domain)"
>{{ 'ORG.DOMAINS.SETPRIMARY' | translate }}</a
>
<span class="fill-space"></span>
<button
mat-icon-button
[disabled]="(canwrite$ | async) === false || domain.isVerified"
*ngIf="verifyOrgDomains"
(click)="verifyDomain(domain)"
>
<i class="las la-pen"></i>
</button>
<button
class="domain-rem-button"
[disabled]="(canwrite$ | async) === false || domain.isPrimary"
matTooltip="Remove domain"
color="warn"
mat-icon-button
(click)="removeDomain(domain.domainName)"
>
<i class="las la-trash"></i>
</button>
</div>
</cnsl-card>
</ng-container>

View File

@ -1,7 +1,6 @@
.domain-top-view {
display: flex;
align-items: center;
padding-top: 2rem;
.domain-title-row {
display: flex;

View File

@ -14,13 +14,11 @@ import { HasRolePipeModule } from 'src/app/pipes/has-role-pipe/has-role-pipe.mod
import { AddDomainDialogModule } from './add-domain-dialog/add-domain-dialog.module';
import { DomainVerificationComponent } from './domain-verification/domain-verification.component';
import { DomainsRoutingModule } from './domains-routing.module';
import { DomainsComponent } from './domains.component';
@NgModule({
declarations: [DomainsComponent, DomainVerificationComponent],
imports: [
DomainsRoutingModule,
AddDomainDialogModule,
CommonModule,
MatIconModule,
@ -36,5 +34,6 @@ import { DomainsComponent } from './domains.component';
InfoSectionModule,
MatProgressSpinnerModule,
],
exports: [DomainsComponent],
})
export default class DomainsModule {}

View File

@ -177,17 +177,6 @@
</a>
</ng-template>
<ng-template cnslHasRole [hasRole]="['org.read']">
<a
class="nav-item"
[routerLinkActive]="['active']"
[routerLink]="['/domains']"
[routerLinkActiveOptions]="{ exact: true }"
>
<span class="label">{{ 'MENU.DOMAINS' | translate }}</span>
</a>
</ng-template>
<ng-template cnslHasRole [hasRole]="['org.read']">
<a
class="nav-item"

View File

@ -5,7 +5,6 @@
<h2>{{ 'POLICY.DOMAIN_POLICY.TITLE' | translate }}</h2>
<cnsl-info-section *ngIf="isDefault"> {{ 'POLICY.DEFAULTLABEL' | translate }}</cnsl-info-section>
<!-- <ng-template cnslHasRole [hasRole]="['domain.policy.delete']"> -->
<button
*ngIf="serviceType === PolicyComponentServiceType.MGMT && !isDefault"
matTooltip="{{ 'POLICY.RESET' | translate }}"
@ -26,7 +25,6 @@
>
{{ 'POLICY.RESET' | translate }}
</button>
<!-- </ng-template> -->
<div class="domain-policy-content" *ngIf="domainData">
<div class="row">

View File

@ -18,6 +18,9 @@
<ng-container *ngIf="currentSetting === 'login'">
<cnsl-login-policy [serviceType]="serviceType"></cnsl-login-policy>
</ng-container>
<ng-container *ngIf="currentSetting === 'verified_domains'">
<cnsl-domains></cnsl-domains>
</ng-container>
<ng-container *ngIf="currentSetting === 'domain' && (['iam.policy.write'] | hasRole | async) === true">
<cnsl-domain-policy [serviceType]="serviceType"></cnsl-domain-policy>
</ng-container>

View File

@ -5,6 +5,7 @@ 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 DomainsModule from '../domains/domains.module';
import { DomainPolicyModule } from '../policies/domain-policy/domain-policy.module';
import { GeneralSettingsModule } from '../policies/general-settings/general-settings.module';
import { IdpSettingsModule } from '../policies/idp-settings/idp-settings.module';
@ -40,6 +41,7 @@ import { SettingsListComponent } from './settings-list.component';
PrivacyPolicyModule,
MessageTextsPolicyModule,
SecurityPolicyModule,
DomainsModule,
LoginTextsPolicyModule,
DomainPolicyModule,
TranslateModule,

View File

@ -43,6 +43,15 @@ export const LOGIN: SidenavSetting = {
},
};
export const VERIFIED_DOMAINS: SidenavSetting = {
id: 'verified_domains',
i18nKey: 'SETTINGS.LIST.VERIFIED_DOMAINS',
groupI18nKey: 'SETTINGS.GROUPS.DOMAIN',
requiredRoles: {
[PolicyComponentServiceType.MGMT]: ['org.read'],
},
};
export const DOMAIN: SidenavSetting = {
id: 'domain',
i18nKey: 'SETTINGS.LIST.DOMAIN',

View File

@ -1,17 +0,0 @@
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { DomainsComponent } from './domains.component';
const routes: Routes = [
{
path: '',
component: DomainsComponent,
},
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule],
})
export class DomainsRoutingModule {}

View File

@ -1,69 +0,0 @@
<div class="max-width-container">
<ng-container *ngIf="['org.write$'] | hasRole as canwrite$">
<div class="domain-top-view">
<div>
<div class="domain-title-row">
<h1>{{ 'ORG.DOMAINS.TITLE' | translate }}</h1>
<a
mat-icon-button
href="https://zitadel.com/docs/guides/manage/console/organizations#how-zitadel-handles-usernames"
rel="noreferrer"
target="_blank"
>
<i class="las la-info-circle"></i>
</a>
</div>
<p class="desc cnsl-secondary-text">{{ 'ORG.DOMAINS.DESCRIPTION' | translate }}</p>
</div>
<span class="fill-space"></span>
<button
[disabled]="(canwrite$ | async) === false"
matTooltip="Add domain"
mat-raised-button
color="primary"
class="cnsl-action-button"
(click)="addNewDomain()"
>
<mat-icon>add</mat-icon>
<span>{{ 'ACTIONS.NEW' | translate }}</span>
<cnsl-action-keys (actionTriggered)="addNewDomain()"> </cnsl-action-keys>
</button>
</div>
<cnsl-card *ngFor="let domain of domains" class="domain-card">
<div class="domain">
<span class="title">{{ domain.domainName }}</span>
<i matTooltip="verified" *ngIf="domain.isVerified" class="verified las la-check-circle"></i>
<i matTooltip="primary" *ngIf="domain.isPrimary" class="primary las la-star"></i>
<a
*ngIf="domain.isVerified && !domain.isPrimary && (canwrite$ | async)"
class="primaryset"
(click)="setPrimary(domain)"
>{{ 'ORG.DOMAINS.SETPRIMARY' | translate }}</a
>
<span class="fill-space"></span>
<button
mat-icon-button
[disabled]="(canwrite$ | async) === false || domain.isVerified"
*ngIf="(canwrite$ | async) && verifyOrgDomains"
(click)="verifyDomain(domain)"
>
<i class="las la-pen"></i>
</button>
<button
class="domain-rem-button"
[disabled]="(canwrite$ | async) === false || domain.isPrimary"
matTooltip="Remove domain"
color="warn"
mat-icon-button
(click)="removeDomain(domain.domainName)"
>
<i class="las la-trash"></i>
</button>
</div>
</cnsl-card>
</ng-container>
</div>

View File

@ -8,9 +8,11 @@
</div>
<span class="fill-space"></span>
</div>
<cnsl-settings-list
[selectedId]="id"
[serviceType]="PolicyComponentServiceType.ADMIN"
[settingsList]="settingsList"
></cnsl-settings-list>
<ng-container *ngIf="settingsList | async as list">
<cnsl-settings-list
[selectedId]="id"
[serviceType]="PolicyComponentServiceType.ADMIN"
[settingsList]="list"
></cnsl-settings-list>
</ng-container>
</div>

View File

@ -1,6 +1,6 @@
import { Component, OnDestroy, OnInit } from '@angular/core';
import { ActivatedRoute, Params } from '@angular/router';
import { Subject, takeUntil } from 'rxjs';
import { Observable, of, Subject, takeUntil } from 'rxjs';
import { PolicyComponentServiceType } from 'src/app/modules/policies/policy-component-types.enum';
import { SidenavSetting } from 'src/app/modules/sidenav/sidenav.component';
import { Breadcrumb, BreadcrumbService, BreadcrumbType } from 'src/app/services/breadcrumb.service';
@ -22,7 +22,6 @@ import {
SECRETS,
SECURITY,
} from '../../modules/settings-list/settings';
import { checkSettingsPermissions } from '../org-settings/org-settings.component';
@Component({
selector: 'cnsl-instance-settings',
@ -55,7 +54,7 @@ export class InstanceSettingsComponent implements OnInit, OnDestroy {
SECURITY,
];
public settingsList: SidenavSetting[] = [];
public settingsList: Observable<SidenavSetting[]> = of([]);
private destroy$: Subject<void> = new Subject();
constructor(
@ -81,13 +80,7 @@ export class InstanceSettingsComponent implements OnInit, OnDestroy {
}
ngOnInit(): void {
checkSettingsPermissions(this.defaultSettingsList, PolicyComponentServiceType.ADMIN, this.authService).subscribe(
(allowed) => {
this.settingsList = this.defaultSettingsList.filter((setting, index) => {
return allowed[index];
});
},
);
this.settingsList = this.authService.isAllowedMapper(this.defaultSettingsList, (setting) => setting.requiredRoles.admin);
}
ngOnDestroy(): void {

View File

@ -8,9 +8,11 @@
</div>
<span class="fill-space"></span>
</div>
<cnsl-settings-list
[selectedId]="id"
[serviceType]="PolicyComponentServiceType.MGMT"
[settingsList]="settingsList"
></cnsl-settings-list>
<ng-container *ngIf="settingsList | async as list">
<cnsl-settings-list
[selectedId]="id"
[serviceType]="PolicyComponentServiceType.MGMT"
[settingsList]="list"
></cnsl-settings-list>
</ng-container>
</div>

View File

@ -1,6 +1,6 @@
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute, Params } from '@angular/router';
import { forkJoin, of, take } from 'rxjs';
import { Observable, of, take } from 'rxjs';
import { PolicyComponentServiceType } from 'src/app/modules/policies/policy-component-types.enum';
import { SidenavSetting } from 'src/app/modules/sidenav/sidenav.component';
import { Breadcrumb, BreadcrumbService, BreadcrumbType } from 'src/app/services/breadcrumb.service';
@ -17,6 +17,7 @@ import {
MESSAGETEXTS,
NOTIFICATION_POLICY,
PRIVACYPOLICY,
VERIFIED_DOMAINS,
} from '../../modules/settings-list/settings';
@Component({
@ -34,6 +35,7 @@ export class OrgSettingsComponent implements OnInit {
COMPLEXITY,
LOCKOUT,
NOTIFICATION_POLICY,
VERIFIED_DOMAINS,
DOMAIN,
BRANDING,
MESSAGETEXTS,
@ -41,7 +43,7 @@ export class OrgSettingsComponent implements OnInit {
PRIVACYPOLICY,
];
public settingsList: SidenavSetting[] = [];
public settingsList: Observable<Array<SidenavSetting>> = of([]);
constructor(
breadcrumbService: BreadcrumbService,
@ -65,40 +67,8 @@ export class OrgSettingsComponent implements OnInit {
}
ngOnInit(): void {
checkSettingsPermissions(this.defaultSettingsList, PolicyComponentServiceType.MGMT, this.authService).subscribe(
(allowed) => {
this.settingsList = this.defaultSettingsList.filter((setting, index) => {
return allowed[index];
});
},
);
this.settingsList = this.authService
.isAllowedMapper(this.defaultSettingsList, (setting) => setting.requiredRoles.mgmt)
.pipe(take(1));
}
}
// Return a Observables<boolean>[] that will wait till all service calls are finished to then check if user is allowed to see a setting
export function checkSettingsPermissions(settings: SidenavSetting[], serviceType: string, authService: GrpcAuthService) {
return forkJoin(
settings
.filter((setting) => {
if (serviceType === PolicyComponentServiceType.ADMIN) {
return setting.requiredRoles && setting.requiredRoles.admin;
} else {
return setting.requiredRoles && setting.requiredRoles.mgmt;
}
})
.map((setting) => {
if (!setting.requiredRoles) {
return of(true);
}
if (!setting.requiredRoles.mgmt) {
return of(true);
}
if (setting.requiredRoles.mgmt) {
return authService.isAllowed(setting.requiredRoles.mgmt).pipe(take(1));
}
return of(false);
}),
);
}

View File

@ -309,10 +309,7 @@ export class GrpcAuthService {
filter(([hL, p]) => {
return hL === true && !!p.length;
}),
map(([_, zroles]) => {
const what = this.hasRoles(zroles, roles, requiresAll);
return what;
}),
map(([_, zroles]) => this.hasRoles(zroles, roles, requiresAll)),
distinctUntilChanged(),
);
} else {
@ -320,6 +317,31 @@ export class GrpcAuthService {
}
}
/**
* filters objects based on roles
* @param objects array of objects
* @param mapper mapping function which maps to a string[] or Regexp[] of roles
* @param requiresAll wheter all, or just a single roles is required to fulfill
*/
public isAllowedMapper<T>(
objects: T[],
mapper: (attr: any) => string[] | RegExp[],
requiresAll: boolean = false,
): Observable<T[]> {
return this.fetchedZitadelPermissions.pipe(
withLatestFrom(this.zitadelPermissions),
filter(([hL, p]) => {
return hL === true && !!p.length;
}),
map(([_, zroles]) => {
return objects.filter((obj) => {
const roles = mapper(obj);
return this.hasRoles(zroles, roles, requiresAll);
});
}),
);
}
/**
* returns true if user has one of the provided roles
* @param userRoles roles of the user

View File

@ -95,7 +95,6 @@
"EVENTS": "Събития",
"FAILEDEVENTS": "Неуспешни събития",
"ORGANIZATION": "Организация",
"DOMAINS": "Домейни",
"PROJECT": "Проекти",
"PROJECTOVERVIEW": "Преглед",
"PROJECTGRANTS": "Грантове",
@ -947,7 +946,7 @@
},
"DOMAINS": {
"NEW": "Добавете домейн",
"TITLE": "Домейни",
"TITLE": "Проверени домейни",
"DESCRIPTION": "Конфигурирайте вашите домейни. ",
"SETPRIMARY": "Задайте като основен",
"DELETE": {
@ -1017,6 +1016,7 @@
"NOTIFICATIONS_DESC": "Настройки за SMTP и SMS",
"MESSAGETEXTS": "Текстове на съобщения",
"IDP": "Доставчици на идентичност",
"VERIFIED_DOMAINS": "Проверени домейни",
"DOMAIN": "Настройки на домейна",
"LOGINTEXTS": "Текстове на интерфейса за влизане",
"BRANDING": "Брандиране",

View File

@ -95,7 +95,6 @@
"EVENTS": "Events",
"FAILEDEVENTS": "Fehlerhafte Events",
"ORGANIZATION": "Organisation",
"DOMAINS": "Domänen",
"PROJECT": "Projekte",
"PROJECTOVERVIEW": "Übersicht",
"PROJECTGRANTS": "Berechtigte Organisationen",
@ -953,7 +952,7 @@
},
"DOMAINS": {
"NEW": "Domain hinzufügen",
"TITLE": "Domänen",
"TITLE": "Verifizierte Domains",
"DESCRIPTION": "Konfiguriere die Domains, die für Domain discovery und als Suffix für die Benutzer verwendet werden können.",
"SETPRIMARY": "Primäre Domain setzen",
"DELETE": {
@ -1023,6 +1022,7 @@
"NOTIFICATIONS_DESC": "SMTP und SMS Einstellungen",
"MESSAGETEXTS": "Benachrichtigungstexte",
"IDP": "Identitätsanbieter",
"VERIFIED_DOMAINS": "Verifizierte Domains",
"DOMAIN": "Domain Einstellungen",
"LOGINTEXTS": "Login Interface Texte",
"BRANDING": "Branding",

View File

@ -95,7 +95,6 @@
"EVENTS": "Events",
"FAILEDEVENTS": "Failed Events",
"ORGANIZATION": "Organization",
"DOMAINS": "Domains",
"PROJECT": "Projects",
"PROJECTOVERVIEW": "Overview",
"PROJECTGRANTS": "Grants",
@ -954,7 +953,7 @@
},
"DOMAINS": {
"NEW": "Add Domain",
"TITLE": "Domains",
"TITLE": "Verified domains",
"DESCRIPTION": "Configure your organization domains. This domain can be used for domain discovery and username suffixing.",
"SETPRIMARY": "Set as Primary",
"DELETE": {
@ -1024,6 +1023,7 @@
"NOTIFICATIONS_DESC": "SMTP and SMS Settings",
"MESSAGETEXTS": "Message Texts",
"IDP": "Identity Providers",
"VERIFIED_DOMAINS": "Verified domains",
"DOMAIN": "Domain settings",
"LOGINTEXTS": "Login Interface Texts",
"BRANDING": "Branding",

View File

@ -95,7 +95,6 @@
"EVENTS": "Eventos",
"FAILEDEVENTS": "Eventos fallidos",
"ORGANIZATION": "Organización",
"DOMAINS": "Dominios",
"PROJECT": "Proyectos",
"PROJECTOVERVIEW": "Resumen",
"PROJECTGRANTS": "Concesiones",
@ -954,7 +953,7 @@
},
"DOMAINS": {
"NEW": "Añadir dominio",
"TITLE": "Dominios",
"TITLE": "Dominios verificados",
"DESCRIPTION": "Configura tus dominios. Este dominio puede usarse para iniciar sesión con tus usuarios.",
"SETPRIMARY": "Establecer como primario",
"DELETE": {
@ -1024,6 +1023,7 @@
"NOTIFICATIONS_DESC": "Ajustes SMTP y SMS",
"MESSAGETEXTS": "Mensajes de texto",
"IDP": "Proveedores de identidad",
"VERIFIED_DOMAINS": "Dominios verificados",
"DOMAIN": "Ajustes de dominio",
"LOGINTEXTS": "Textos de interfaz de inicio de sesión",
"BRANDING": "Imagen de marca",

View File

@ -95,7 +95,6 @@
"EVENTS": "Événements",
"FAILEDEVENTS": "Événements échoués",
"ORGANIZATION": "Organisation",
"DOMAINS": "Domaines",
"PROJECT": "Projets",
"PROJECTOVERVIEW": "Vue d'ensemble",
"PROJECTGRANTS": "Subventions",
@ -953,7 +952,7 @@
},
"DOMAINS": {
"NEW": "Ajouter un domaine",
"TITLE": "Domaines",
"TITLE": "Domaines vérifiés",
"DESCRIPTION": "Configurez vos domaines. Ce domaine peut être utilisé pour se connecter avec vos utilisateurs.",
"SETPRIMARY": "Définir comme primaire",
"DELETE": {
@ -1023,6 +1022,7 @@
"NOTIFICATIONS_DESC": "Paramètres SMTP et SMS",
"MESSAGETEXTS": "Textes des messages",
"IDP": "Fournisseurs d'identité",
"VERIFIED_DAMAINS": "Domaines vérifiés",
"DOMAIN": "Paramètres du domaine",
"LOGINTEXTS": "Textes de l'interface de connexion",
"BRANDING": "Image de marque",

View File

@ -95,7 +95,6 @@
"EVENTS": "Eventi",
"FAILEDEVENTS": "Eventi falliti",
"ORGANIZATION": "Organizzazione",
"DOMAINS": "Domini",
"PROJECT": "Progetti",
"PROJECTOVERVIEW": "Progetto",
"PROJECTGRANTS": "Organizzazioni ammissibili",
@ -953,7 +952,7 @@
},
"DOMAINS": {
"NEW": "Aggiungi dominio",
"TITLE": "Domini",
"TITLE": "Domini verificati",
"DESCRIPTION": "Configura i tuoi domini. Questo dominio pu\u00f2 essere utilizzato per accedere con i tuoi utenti.",
"SETPRIMARY": "Impostato come primario",
"DELETE": {
@ -1023,6 +1022,7 @@
"NOTIFICATIONS_DESC": "Impostazioni SMTP e SMS",
"MESSAGETEXTS": "Testi di notifica",
"IDP": "Fornitori di identità",
"VERIFIED_DAMAINS": "Domini verificati",
"DOMAIN": "Impostazioni del dominio",
"LOGINTEXTS": "Testi dell'interfaccia login",
"BRANDING": "Branding",

View File

@ -95,7 +95,6 @@
"EVENTS": "イベント",
"FAILEDEVENTS": "失敗したイベント",
"ORGANIZATION": "組織",
"DOMAINS": "ドメイン",
"PROJECT": "プロジェクト",
"PROJECTOVERVIEW": "概要",
"PROJECTGRANTS": "グラント",
@ -954,7 +953,7 @@
},
"DOMAINS": {
"NEW": "ドメインを追加する",
"TITLE": "ドメイン",
"TITLE": "検証済みドメイン",
"DESCRIPTION": "ドメインを設定します。このドメインは、ユーザーのログインで使用できます。",
"SETPRIMARY": "プライマリとして設定する",
"DELETE": {
@ -1024,6 +1023,7 @@
"NOTIFICATIONS_DESC": "SMTPおよびSMS設定",
"MESSAGETEXTS": "メッセージテキスト",
"IDP": "IDプロバイダー",
"VERIFIED_DAMAINS": "検証済みドメイン",
"DOMAIN": "ドメイン設定",
"LOGINTEXTS": "ログイン画面のテキスト",
"BRANDING": "ブランディング",

View File

@ -95,7 +95,6 @@
"EVENTS": "Настани",
"FAILEDEVENTS": "Неуспешни настани",
"ORGANIZATION": "Организација",
"DOMAINS": "Домени",
"PROJECT": "Проекти",
"PROJECTOVERVIEW": "Преглед",
"PROJECTGRANTS": "Овластувања",
@ -954,7 +953,7 @@
},
"DOMAINS": {
"NEW": "Додади домен",
"TITLE": "Домени",
"TITLE": "Потврдени домени",
"DESCRIPTION": "Конфигурирајте ги вашите домени. Овој домен може да се користи за најава на вашите корисници.",
"SETPRIMARY": "Постави како основен",
"DELETE": {
@ -1025,6 +1024,7 @@
"NOTIFICATIONS_DESC": "Подесувања за SMTP и SMS",
"MESSAGETEXTS": "Текстови на пораки",
"IDP": "Identity Providers",
"VERIFIED_DAMAINS": "Потврдени домени",
"DOMAIN": "Подесувања за домен",
"LOGINTEXTS": "Текстови на интерфејс за најава",
"BRANDING": "Брендирање",

View File

@ -95,7 +95,6 @@
"EVENTS": "Zdarzenia",
"FAILEDEVENTS": "Nieudane Zdarzenia",
"ORGANIZATION": "Organizacja",
"DOMAINS": "Domeny",
"PROJECT": "Projekty",
"PROJECTOVERVIEW": "Przegląd",
"PROJECTGRANTS": "Uprawnienia",
@ -953,7 +952,7 @@
},
"DOMAINS": {
"NEW": "Dodaj domenę",
"TITLE": "Domeny",
"TITLE": "Zweryfikowane domeny",
"DESCRIPTION": "Skonfiguruj swoje domeny. Ta domena może być używana do logowania się z Twoimi użytkownikami.",
"SETPRIMARY": "Ustaw jako główną",
"DELETE": {
@ -1023,6 +1022,7 @@
"NOTIFICATIONS_DESC": "Ustawienia SMTP i SMS",
"MESSAGETEXTS": "Teksty wiadomości",
"IDP": "Dostawcy tożsamości",
"VERIFIED_DAMAINS": "Zweryfikowane domeny",
"DOMAIN": "Ustawienia domeny",
"LOGINTEXTS": "Teksty interfejsu logowania",
"BRANDING": "Marka",

View File

@ -95,7 +95,6 @@
"EVENTS": "Eventos",
"FAILEDEVENTS": "Eventos com Falha",
"ORGANIZATION": "Organização",
"DOMAINS": "Domínios",
"PROJECT": "Projetos",
"PROJECTOVERVIEW": "Visão Geral",
"PROJECTGRANTS": "Autorizações",
@ -954,7 +953,7 @@
},
"DOMAINS": {
"NEW": "Adicionar Domínio",
"TITLE": "Domínios",
"TITLE": "Domínios verificados",
"DESCRIPTION": "Configure seus domínios. Este domínio pode ser usado para o login dos seus usuários.",
"SETPRIMARY": "Definir como Principal",
"DELETE": {
@ -1025,6 +1024,7 @@
"NOTIFICATIONS_DESC": "Configurações de SMTP e SMS",
"MESSAGETEXTS": "Textos de Mensagem",
"IDP": "Provedores de Identidade",
"VERIFIED_DAMAINS": "Domínios verificados",
"DOMAIN": "Configurações de Domínio",
"LOGINTEXTS": "Textos da Interface de Login",
"BRANDING": "Marca",

View File

@ -95,7 +95,6 @@
"EVENTS": "活动",
"FAILEDEVENTS": "失败事件",
"ORGANIZATION": "组织",
"DOMAINS": "域名",
"PROJECT": "项目",
"PROJECTOVERVIEW": "概览",
"PROJECTGRANTS": "授予",
@ -953,7 +952,7 @@
},
"DOMAINS": {
"NEW": "添加域名",
"TITLE": "域名",
"TITLE": "已验证的域名",
"DESCRIPTION": "配置您的域名。此域名可用于您的用户登录。",
"SETPRIMARY": "设置为主域名",
"DELETE": {
@ -1023,6 +1022,7 @@
"NOTIFICATIONS_DESC": "SMTP 和 SMS 设置",
"MESSAGETEXTS": "消息文本",
"IDP": "身份提供者",
"VERIFIED_DAMAINS": "已验证的域名",
"DOMAIN": "域名设置",
"LOGINTEXTS": "登录界面文本",
"BRANDING": "品牌标识",

View File

@ -72,14 +72,12 @@ Please note that domain verification also removes the logonname from all users,
You can also disable domain verification with DNS challenge in the [instance settings](/docs/guides/manage/console/instance-settings#domain-settings).
:::
1. Browse to your organization
2. Click **Add Domain**
1. Browse to your organization settings
2. Select the menu entry **Verified domains**
3. To start the domain verification click the domain name and a dialog will appear, where you can choose between DNS or HTTP challenge methods.
4. For example, create a TXT record with your DNS provider for the used domain and click verify. ZITADEL will then proceed and check your DNS.
5. When the verification is successful you have the option to activate the domain by clicking **Set as primary**
![Verify Domain](/img/console_verify_domain.gif)
:::caution
Do not delete the verification code, as ZITADEL will re-check the ownership of your domain from time to time
:::
@ -95,6 +93,7 @@ Those settings are the same as on your instance.
- [**Identity Providers**](./instance-settings#identity-providers): Define IDPs which are available for all organizations
- [**Password Complexity**](./instance-settings#password-complexity): Requirements for Passwords ex. Symbols, Numbers, min length and more.
- [**Lockout**](./instance-settings#lockout): Set the maximum attempts a user can try to enter the password. When the number is exceeded, the user gets locked out and has to be unlocked.
- [**Verified domains**](/docs/guides/manage/console/organizations#verify-your-domain-name): This is where you manage your organization specific domains which can be used to build usernames
- [**Domain settings**](./instance-settings#domain-settings): Whether users use their email or the generated username to login. Other Validation, SMTP settings
- [**Branding**](./instance-settings#branding): Appearance of the login interface.
- [**Message Texts**](./instance-settings#message-texts): Text and internationalization for emails
@ -105,20 +104,19 @@ If you need custom branding on a organization (for example in a B2B scenario, wh
The behaviour of the login page, applyling custom design, is then defined on your projects detail page. Read more about it [here](./projects#branding)
## Show Organization Login
As you should know by now ZITADEL knows the concept of Organizations.
You can define [default settings](/docs/guides/manage/console/instance-settings) for your ZITADEL, or you can overwrite them for an [Organization](#organization-settings).
Per default the ZITADEL Login will always show what is defined per default. As soon as the Organization context is given, the settings defined on the specific organization can be triggered.
This means when you want to trigger the settings of an organization directly, make sure to send the organization scope in the authentication request.
``` bash
```bash
urn:zitadel:iam:org:id:{id}
```
Read more about the [scopes](/docs/apis/openidoauth/scopes#reserved-scopes) or try it out in our [OIDC Playground](/docs/apis/openidoauth/authrequest).
## Default organization
On the instance settings page ($YOUR_DOMAIN//ui/console/orgs) you can set an organization as default organization.

View File

@ -88,7 +88,7 @@ Make sure to [Force MFA](/docs/guides/manage/console/instance-settings#multifact
### Verify domains
Switch to the organization **Alpha** and select the tab "Domains".
Switch to the organization **Alpha** and navigate to the settings and "Verified domains".
Verify the domain alpha.com following the [organization guide](/docs/guides/manage/console/organizations#domain-verification-and-primary-domain).
Do the same for the **Beta** organization.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 MiB