mirror of
https://github.com/zitadel/zitadel.git
synced 2025-01-14 11:44:16 +00:00
Merge branch 'main' into next
This commit is contained in:
commit
af24208b38
@ -39,16 +39,15 @@ Telemetry:
|
||||
|
||||
# Port ZITADEL will listen on
|
||||
Port: 8080 # ZITADEL_PORT
|
||||
# Port ZITADEL is exposed on, it can differ from port e.g. if you proxy the traffic
|
||||
# !!! Changing this after the initial setup breaks your system !!!
|
||||
# ExternalPort is the port on which end users access ZITADEL.
|
||||
# It can differ from Port e.g. if a reverse proxy forwards the traffic to ZITADEL
|
||||
# Read more about external access: https://zitadel.com/docs/self-hosting/manage/custom-domain
|
||||
ExternalPort: 8080 # ZITADEL_EXTERNALPORT
|
||||
# Domain/hostname ZITADEL is exposed externally
|
||||
# !!! Changing this after the initial setup breaks your system !!!
|
||||
# ExternalPort is the domain on which end users access ZITADEL.
|
||||
# Read more about external access: https://zitadel.com/docs/self-hosting/manage/custom-domain
|
||||
ExternalDomain: localhost # ZITADEL_EXTERNALDOMAIN
|
||||
# specifies if ZITADEL is exposed externally through TLS
|
||||
# this must be set to true even if TLS is not enabled on ZITADEL itself
|
||||
# but TLS traffic is terminated on a reverse proxy
|
||||
# !!! Changing this after the initial setup breaks your system !!!
|
||||
# ExternalSecure specifies if ZITADEL is exposed externally using HTTPS or HTTP.
|
||||
# Read more about external access: https://zitadel.com/docs/self-hosting/manage/custom-domain
|
||||
ExternalSecure: true # ZITADEL_EXTERNALSECURE
|
||||
TLS:
|
||||
# If enabled, ZITADEL will serve all traffic over TLS (HTTPS and gRPC)
|
||||
|
@ -9,12 +9,14 @@ import (
|
||||
|
||||
internal_authz "github.com/zitadel/zitadel/internal/api/authz"
|
||||
"github.com/zitadel/zitadel/internal/config/hook"
|
||||
"github.com/zitadel/zitadel/internal/config/network"
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
Log *logging.Config
|
||||
Port uint16
|
||||
TLS network.TLS
|
||||
}
|
||||
|
||||
func MustNewConfig(v *viper.Viper) *Config {
|
||||
|
@ -1,6 +1,7 @@
|
||||
package ready
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
@ -26,7 +27,13 @@ func New() *cobra.Command {
|
||||
}
|
||||
|
||||
func ready(config *Config) bool {
|
||||
res, err := http.Get("http://" + net.JoinHostPort("localhost", strconv.Itoa(int(config.Port))) + "/debug/ready")
|
||||
scheme := "https"
|
||||
if !config.TLS.Enabled {
|
||||
scheme = "http"
|
||||
}
|
||||
// Checking the TLS cert is not in the scope of the readiness check
|
||||
httpClient := http.Client{Transport: &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: true}}}
|
||||
res, err := httpClient.Get(scheme + "://" + net.JoinHostPort("localhost", strconv.Itoa(int(config.Port))) + "/debug/ready")
|
||||
if err != nil {
|
||||
logging.WithError(err).Warn("ready check failed")
|
||||
return false
|
||||
|
@ -367,16 +367,16 @@ func startAPIs(
|
||||
return fmt.Errorf("error starting admin repo: %w", err)
|
||||
}
|
||||
|
||||
if err := apis.RegisterServer(ctx, system.CreateServer(commands, queries, config.Database.DatabaseName(), config.DefaultInstance, config.ExternalDomain)); err != nil {
|
||||
if err := apis.RegisterServer(ctx, system.CreateServer(commands, queries, config.Database.DatabaseName(), config.DefaultInstance, config.ExternalDomain), tlsConfig); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := apis.RegisterServer(ctx, admin.CreateServer(config.Database.DatabaseName(), commands, queries, config.SystemDefaults, config.ExternalSecure, keys.User, config.AuditLogRetention)); err != nil {
|
||||
if err := apis.RegisterServer(ctx, admin.CreateServer(config.Database.DatabaseName(), commands, queries, config.SystemDefaults, config.ExternalSecure, keys.User, config.AuditLogRetention), tlsConfig); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := apis.RegisterServer(ctx, management.CreateServer(commands, queries, config.SystemDefaults, keys.User, config.ExternalSecure)); err != nil {
|
||||
if err := apis.RegisterServer(ctx, management.CreateServer(commands, queries, config.SystemDefaults, keys.User, config.ExternalSecure), tlsConfig); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := apis.RegisterServer(ctx, auth.CreateServer(commands, queries, authRepo, config.SystemDefaults, keys.User, config.ExternalSecure)); err != nil {
|
||||
if err := apis.RegisterServer(ctx, auth.CreateServer(commands, queries, authRepo, config.SystemDefaults, keys.User, config.ExternalSecure), tlsConfig); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := apis.RegisterService(ctx, user_v2.CreateServer(commands, queries, keys.User, keys.IDPConfig, idp.CallbackURL(config.ExternalSecure), idp.SAMLRootURL(config.ExternalSecure))); err != nil {
|
||||
|
@ -25,6 +25,9 @@
|
||||
"@angular/router": "^16.2.5",
|
||||
"@angular/service-worker": "^16.2.5",
|
||||
"@ctrl/ngx-codemirror": "^6.1.0",
|
||||
"@fortawesome/angular-fontawesome": "^0.13.0",
|
||||
"@fortawesome/fontawesome-svg-core": "^6.4.2",
|
||||
"@fortawesome/free-brands-svg-icons": "^6.4.2",
|
||||
"@grpc/grpc-js": "^1.9.3",
|
||||
"@ngx-translate/core": "^14.0.0",
|
||||
"angular-oauth2-oidc": "^15.0.1",
|
||||
|
@ -2,6 +2,7 @@ import { CommonModule, registerLocaleData } from '@angular/common';
|
||||
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
|
||||
import localeBg from '@angular/common/locales/bg';
|
||||
import localeDe from '@angular/common/locales/de';
|
||||
import localeCs from '@angular/common/locales/cs';
|
||||
import localeEn from '@angular/common/locales/en';
|
||||
import localeEs from '@angular/common/locales/es';
|
||||
import localeFr from '@angular/common/locales/fr';
|
||||
@ -11,6 +12,7 @@ import localeMk from '@angular/common/locales/mk';
|
||||
import localePl from '@angular/common/locales/pl';
|
||||
import localePt from '@angular/common/locales/pt';
|
||||
import localeZh from '@angular/common/locales/zh';
|
||||
import localeRu from '@angular/common/locales/ru';
|
||||
import { APP_INITIALIZER, NgModule } from '@angular/core';
|
||||
import { MatNativeDateModule } from '@angular/material/core';
|
||||
import { MatDialogModule } from '@angular/material/dialog';
|
||||
@ -89,6 +91,10 @@ registerLocaleData(localePt);
|
||||
i18nIsoCountries.registerLocale(require('i18n-iso-countries/langs/pt.json'));
|
||||
registerLocaleData(localeMk);
|
||||
i18nIsoCountries.registerLocale(require('i18n-iso-countries/langs/mk.json'));
|
||||
registerLocaleData(localeRu);
|
||||
i18nIsoCountries.registerLocale(require('i18n-iso-countries/langs/ru.json'));
|
||||
registerLocaleData(localeCs);
|
||||
i18nIsoCountries.registerLocale(require('i18n-iso-countries/langs/cs.json'));
|
||||
|
||||
export class WebpackTranslateLoader implements TranslateLoader {
|
||||
getTranslation(lang: string): Observable<any> {
|
||||
|
@ -17,7 +17,7 @@
|
||||
<i class="text-3xl lab la-github"></i>
|
||||
</a>
|
||||
<a target="_blank" rel="noreferrer" href="https://twitter.com/zitadel">
|
||||
<i class="text-3xl lab la-twitter"></i>
|
||||
<fa-icon [icon]="faXTwitter" size="xl"></fa-icon>
|
||||
</a>
|
||||
<a target="_blank" rel="noreferrer" href="https://www.linkedin.com/company/zitadel/">
|
||||
<i class="text-3xl lab la-linkedin"></i>
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { PrivacyPolicy } from 'src/app/proto/generated/zitadel/policy_pb';
|
||||
import { GrpcAuthService } from 'src/app/services/grpc-auth.service';
|
||||
import { faXTwitter } from '@fortawesome/free-brands-svg-icons';
|
||||
|
||||
@Component({
|
||||
selector: 'cnsl-footer',
|
||||
@ -9,6 +10,7 @@ import { GrpcAuthService } from 'src/app/services/grpc-auth.service';
|
||||
})
|
||||
export class FooterComponent implements OnInit {
|
||||
public policy?: PrivacyPolicy.AsObject;
|
||||
public faXTwitter = faXTwitter;
|
||||
constructor(public authService: GrpcAuthService) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
|
@ -4,10 +4,11 @@ import { TranslateModule } from '@ngx-translate/core';
|
||||
|
||||
import { ThemeSettingModule } from '../theme-setting/theme-setting.module';
|
||||
import { FooterComponent } from './footer.component';
|
||||
import { FontAwesomeModule } from '@fortawesome/angular-fontawesome';
|
||||
|
||||
@NgModule({
|
||||
declarations: [FooterComponent],
|
||||
imports: [CommonModule, TranslateModule, ThemeSettingModule],
|
||||
imports: [CommonModule, TranslateModule, ThemeSettingModule, FontAwesomeModule],
|
||||
exports: [FooterComponent],
|
||||
})
|
||||
export class FooterModule {}
|
||||
|
@ -85,6 +85,10 @@
|
||||
<img class="idp-logo apple light" src="./assets/images/idp/apple.svg" alt="apple" />
|
||||
Apple
|
||||
</div>
|
||||
<div class="idp-table-provider-type" *ngSwitchCase="ProviderType.PROVIDER_TYPE_SAML">
|
||||
<img class="idp-logo" src="./assets/images/idp/saml-icon.svg" alt="saml" />
|
||||
SAML SP
|
||||
</div>
|
||||
<div class="idp-table-provider-type" *ngSwitchDefault>coming soon</div>
|
||||
</div>
|
||||
</td>
|
||||
|
@ -263,6 +263,8 @@ export class IdpTableComponent implements OnInit, OnDestroy {
|
||||
return [row.owner === IDPOwnerType.IDP_OWNER_TYPE_SYSTEM ? '/instance' : '/org', 'provider', 'github', row.id];
|
||||
case ProviderType.PROVIDER_TYPE_APPLE:
|
||||
return [row.owner === IDPOwnerType.IDP_OWNER_TYPE_SYSTEM ? '/instance' : '/org', 'provider', 'apple', row.id];
|
||||
case ProviderType.PROVIDER_TYPE_SAML:
|
||||
return [row.owner === IDPOwnerType.IDP_OWNER_TYPE_SYSTEM ? '/instance' : '/org', 'provider', 'saml', row.id];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -196,4 +196,20 @@
|
||||
<span class="title">Active Directory / LDAP</span>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<a
|
||||
class="item card"
|
||||
[routerLink]="
|
||||
serviceType === PolicyComponentServiceType.ADMIN
|
||||
? ['/instance', 'provider', 'saml', 'create']
|
||||
: serviceType === PolicyComponentServiceType.MGMT
|
||||
? ['/org', 'provider', 'saml', 'create']
|
||||
: []
|
||||
"
|
||||
>
|
||||
<img class="idp-logo" src="./assets/images/idp/saml-icon.svg" alt="oauth" />
|
||||
<div class="text-container">
|
||||
<span class="title">SAML SP</span>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
|
@ -146,7 +146,6 @@ export class ProviderJWTComponent {
|
||||
req.setJwtEndpoint(this.jwtEndpoint?.value);
|
||||
req.setKeysEndpoint(this.keysEndpoint?.value);
|
||||
req.setProviderOptions(this.options);
|
||||
|
||||
this.loading = true;
|
||||
this.service
|
||||
.addJWTProvider(req)
|
||||
|
@ -0,0 +1,68 @@
|
||||
<cnsl-create-layout
|
||||
title="{{ id ? ('IDP.DETAIL.TITLE' | translate) : ('IDP.CREATE.TITLE' | translate) }}"
|
||||
(closed)="close()"
|
||||
>
|
||||
<div class="identity-provider-create-content">
|
||||
<div class="title-row">
|
||||
<img class="idp-logo" src="./assets/images/idp/saml-icon.svg" alt="saml" />
|
||||
<h1>{{ 'IDP.CREATE.SAML.TITLE' | translate }}</h1>
|
||||
<mat-spinner diameter="25" *ngIf="loading" color="primary"></mat-spinner>
|
||||
</div>
|
||||
|
||||
<p class="identity-provider-desc cnsl-secondary-text">
|
||||
{{ !provider ? ('IDP.CREATE.SAML.DESCRIPTION' | translate) : ('IDP.DETAIL.DESCRIPTION' | translate) }}
|
||||
</p>
|
||||
|
||||
<form [formGroup]="form" (ngSubmit)="submitForm()">
|
||||
<div class="identity-provider-content">
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ 'IDP.NAME' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="name" />
|
||||
</cnsl-form-field>
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ 'IDP.SAML.METADATAXML' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="metadataXml" />
|
||||
</cnsl-form-field>
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ 'IDP.SAML.METADATAURL' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="metadataUrl" />
|
||||
</cnsl-form-field>
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ 'IDP.SAML.BINDING' | translate }}</cnsl-label>
|
||||
<mat-select formControlName="binding">
|
||||
<mat-option *ngFor="let binding of bindingValues" [value]="binding">{{ binding }}</mat-option>
|
||||
</mat-select>
|
||||
</cnsl-form-field>
|
||||
|
||||
<mat-checkbox formControlName="withSignedRequest">{{ 'IDP.SAML.SIGNEDREQUEST' | translate }}</mat-checkbox>
|
||||
</div>
|
||||
|
||||
<div class="identity-provider-optional-h-wrapper">
|
||||
<h2>{{ 'IDP.OPTIONAL' | translate }}</h2>
|
||||
<button (click)="showOptional = !showOptional" type="button" mat-icon-button>
|
||||
<mat-icon *ngIf="showOptional">keyboard_arrow_up</mat-icon
|
||||
><mat-icon *ngIf="!showOptional">keyboard_arrow_down</mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
<div *ngIf="showOptional">
|
||||
<cnsl-provider-options
|
||||
[initialOptions]="provider?.config?.options"
|
||||
(optionsChanged)="options = $event"
|
||||
></cnsl-provider-options>
|
||||
</div>
|
||||
|
||||
<div class="identity-provider-create-actions">
|
||||
<button
|
||||
color="primary"
|
||||
mat-raised-button
|
||||
class="continue-button"
|
||||
[disabled]="form.invalid || form.disabled"
|
||||
type="submit"
|
||||
>
|
||||
<span *ngIf="id">{{ 'ACTIONS.SAVE' | translate }}</span>
|
||||
<span *ngIf="!id">{{ 'ACTIONS.CREATE' | translate }}</span>
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</cnsl-create-layout>
|
@ -0,0 +1,21 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { ProviderSamlSpComponent } from './provider-saml-sp.component';
|
||||
|
||||
describe('ProviderSamlSpComponent', () => {
|
||||
let component: ProviderSamlSpComponent;
|
||||
let fixture: ComponentFixture<ProviderSamlSpComponent>;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ProviderSamlSpComponent],
|
||||
});
|
||||
fixture = TestBed.createComponent(ProviderSamlSpComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@ -0,0 +1,224 @@
|
||||
import { Component, Injector, Type } from '@angular/core';
|
||||
import { Location } from '@angular/common';
|
||||
import { Options, Provider } from '../../../proto/generated/zitadel/idp_pb';
|
||||
import { AbstractControl, FormGroup, UntypedFormControl, UntypedFormGroup } from '@angular/forms';
|
||||
import { PolicyComponentServiceType } from '../../policies/policy-component-types.enum';
|
||||
import { ManagementService } from '../../../services/mgmt.service';
|
||||
import { AdminService } from '../../../services/admin.service';
|
||||
import { ToastService } from '../../../services/toast.service';
|
||||
import { GrpcAuthService } from '../../../services/grpc-auth.service';
|
||||
import { take } from 'rxjs';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { Breadcrumb, BreadcrumbService, BreadcrumbType } from '../../../services/breadcrumb.service';
|
||||
import { requiredValidator } from '../../form-field/validators/validators';
|
||||
import {
|
||||
AddSAMLProviderRequest as AdminAddSAMLProviderRequest,
|
||||
GetProviderByIDRequest as AdminGetProviderByIDRequest,
|
||||
UpdateSAMLProviderRequest as AdminUpdateSAMLProviderRequest,
|
||||
} from 'src/app/proto/generated/zitadel/admin_pb';
|
||||
import {
|
||||
AddSAMLProviderRequest as MgmtAddSAMLProviderRequest,
|
||||
GetProviderByIDRequest as MgmtGetProviderByIDRequest,
|
||||
UpdateSAMLProviderRequest as MgmtUpdateSAMLProviderRequest,
|
||||
} from 'src/app/proto/generated/zitadel/management_pb';
|
||||
import * as zitadel_idp_pb from '../../../proto/generated/zitadel/idp_pb';
|
||||
|
||||
@Component({
|
||||
selector: 'cnsl-provider-saml-sp',
|
||||
templateUrl: './provider-saml-sp.component.html',
|
||||
styleUrls: ['./provider-saml-sp.component.scss'],
|
||||
})
|
||||
export class ProviderSamlSpComponent {
|
||||
public id: string | null = '';
|
||||
public loading: boolean = false;
|
||||
public provider?: Provider.AsObject;
|
||||
public form!: FormGroup;
|
||||
public showOptional: boolean = false;
|
||||
public options: Options = new Options().setIsCreationAllowed(true).setIsLinkingAllowed(true);
|
||||
public serviceType: PolicyComponentServiceType = PolicyComponentServiceType.MGMT;
|
||||
private service!: ManagementService | AdminService;
|
||||
|
||||
bindingValues: string[] = Object.keys(zitadel_idp_pb.SAMLBinding);
|
||||
|
||||
constructor(
|
||||
private _location: Location,
|
||||
private toast: ToastService,
|
||||
private authService: GrpcAuthService,
|
||||
private route: ActivatedRoute,
|
||||
private injector: Injector,
|
||||
private breadcrumbService: BreadcrumbService,
|
||||
) {
|
||||
this._buildBreadcrumbs();
|
||||
this._initializeForm();
|
||||
this._checkFormPermissions();
|
||||
}
|
||||
|
||||
private _initializeForm(): void {
|
||||
this.form = new UntypedFormGroup({
|
||||
name: new UntypedFormControl('', [requiredValidator]),
|
||||
metadataXml: new UntypedFormControl('', [requiredValidator]),
|
||||
metadataUrl: new UntypedFormControl('', [requiredValidator]),
|
||||
binding: new UntypedFormControl(this.bindingValues[0], [requiredValidator]),
|
||||
withSignedRequest: new UntypedFormControl(true, [requiredValidator]),
|
||||
});
|
||||
}
|
||||
|
||||
private _checkFormPermissions(): void {
|
||||
this.authService
|
||||
.isAllowed(
|
||||
this.serviceType === PolicyComponentServiceType.ADMIN
|
||||
? ['iam.idp.write']
|
||||
: this.serviceType === PolicyComponentServiceType.MGMT
|
||||
? ['org.idp.write']
|
||||
: [],
|
||||
)
|
||||
.pipe(take(1))
|
||||
.subscribe((allowed) => {
|
||||
if (allowed) {
|
||||
this.form.enable();
|
||||
} else {
|
||||
this.form.disable();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private _buildBreadcrumbs(): void {
|
||||
this.route.data.pipe(take(1)).subscribe((data) => {
|
||||
this.serviceType = data['serviceType'];
|
||||
switch (this.serviceType) {
|
||||
case PolicyComponentServiceType.MGMT:
|
||||
this.service = this.injector.get(ManagementService as Type<ManagementService>);
|
||||
|
||||
const bread: Breadcrumb = {
|
||||
type: BreadcrumbType.ORG,
|
||||
routerLink: ['/org'],
|
||||
};
|
||||
|
||||
this.breadcrumbService.setBreadcrumb([bread]);
|
||||
break;
|
||||
case PolicyComponentServiceType.ADMIN:
|
||||
this.service = this.injector.get(AdminService as Type<AdminService>);
|
||||
|
||||
const iamBread = new Breadcrumb({
|
||||
type: BreadcrumbType.ORG,
|
||||
name: 'Instance',
|
||||
routerLink: ['/instance'],
|
||||
});
|
||||
this.breadcrumbService.setBreadcrumb([iamBread]);
|
||||
break;
|
||||
}
|
||||
|
||||
this.id = this.route.snapshot.paramMap.get('id');
|
||||
if (this.id) {
|
||||
this.getData(this.id);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public updateSAMLProvider(): void {
|
||||
if (this.provider) {
|
||||
const req =
|
||||
this.serviceType === PolicyComponentServiceType.MGMT
|
||||
? new MgmtUpdateSAMLProviderRequest()
|
||||
: new AdminUpdateSAMLProviderRequest();
|
||||
req.setId(this.provider.id);
|
||||
req.setName(this.name?.value);
|
||||
req.setMetadataUrl(this.metadataUrl?.value);
|
||||
req.setMetadataXml(this.metadataXml?.value);
|
||||
// @ts-ignore
|
||||
req.setBinding(zitadel_idp_pb.SAMLBinding[`${this.biding?.value}`]);
|
||||
req.setProviderOptions(this.options);
|
||||
|
||||
this.loading = true;
|
||||
this.service
|
||||
.updateSAMLProvider(req)
|
||||
.then((idp) => {
|
||||
setTimeout(() => {
|
||||
this.loading = false;
|
||||
this.close();
|
||||
}, 2000);
|
||||
})
|
||||
.catch((error) => {
|
||||
this.toast.showError(error);
|
||||
this.loading = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public addSAMLProvider(): void {
|
||||
const req =
|
||||
this.serviceType === PolicyComponentServiceType.MGMT
|
||||
? new MgmtAddSAMLProviderRequest()
|
||||
: new AdminAddSAMLProviderRequest();
|
||||
req.setName(this.name?.value);
|
||||
req.setMetadataUrl(this.metadataUrl?.value);
|
||||
req.setMetadataXml(this.metadataXml?.value);
|
||||
req.setProviderOptions(this.options);
|
||||
// @ts-ignore
|
||||
req.setBinding(zitadel_idp_pb.SAMLBinding[`${this.biding?.value}`]);
|
||||
req.setWithSignedRequest(this.withSignedRequest?.value);
|
||||
this.loading = true;
|
||||
this.service
|
||||
.addSAMLProvider(req)
|
||||
.then((idp) => {
|
||||
setTimeout(() => {
|
||||
this.loading = false;
|
||||
this.close();
|
||||
}, 2000);
|
||||
})
|
||||
.catch((error) => {
|
||||
this.toast.showError(error);
|
||||
this.loading = false;
|
||||
});
|
||||
}
|
||||
|
||||
public submitForm(): void {
|
||||
this.provider ? this.updateSAMLProvider() : this.addSAMLProvider();
|
||||
}
|
||||
|
||||
private getData(id: string): void {
|
||||
const req =
|
||||
this.serviceType === PolicyComponentServiceType.ADMIN
|
||||
? new AdminGetProviderByIDRequest()
|
||||
: new MgmtGetProviderByIDRequest();
|
||||
req.setId(id);
|
||||
this.service
|
||||
.getProviderByID(req)
|
||||
.then((resp) => {
|
||||
this.provider = resp.idp;
|
||||
this.loading = false;
|
||||
if (this.provider?.config?.saml) {
|
||||
this.form.patchValue(this.provider.config.saml);
|
||||
this.name?.setValue(this.provider.name);
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
this.toast.showError(error);
|
||||
this.loading = false;
|
||||
});
|
||||
}
|
||||
|
||||
close(): void {
|
||||
this._location.back();
|
||||
}
|
||||
|
||||
private get name(): AbstractControl | null {
|
||||
return this.form.get('name');
|
||||
}
|
||||
|
||||
private get metadataXml(): AbstractControl | null {
|
||||
return this.form.get('metadataXml');
|
||||
}
|
||||
|
||||
private get metadataUrl(): AbstractControl | null {
|
||||
return this.form.get('metadataUrl');
|
||||
}
|
||||
|
||||
private get biding(): AbstractControl | null {
|
||||
return this.form.get('binding');
|
||||
}
|
||||
|
||||
private get withSignedRequest(): AbstractControl | null {
|
||||
return this.form.get('withSignedRequest');
|
||||
}
|
||||
}
|
@ -13,6 +13,7 @@ import { ProviderJWTComponent } from './provider-jwt/provider-jwt.component';
|
||||
import { ProviderLDAPComponent } from './provider-ldap/provider-ldap.component';
|
||||
import { ProviderOAuthComponent } from './provider-oauth/provider-oauth.component';
|
||||
import { ProviderOIDCComponent } from './provider-oidc/provider-oidc.component';
|
||||
import { ProviderSamlSpComponent } from './provider-saml-sp/provider-saml-sp.component';
|
||||
|
||||
const typeMap = {
|
||||
[ProviderType.PROVIDER_TYPE_AZURE_AD]: { path: 'azure-ad', component: ProviderAzureADComponent },
|
||||
@ -29,6 +30,7 @@ const typeMap = {
|
||||
[ProviderType.PROVIDER_TYPE_OIDC]: { path: 'oidc', component: ProviderOIDCComponent },
|
||||
[ProviderType.PROVIDER_TYPE_LDAP]: { path: 'ldap', component: ProviderLDAPComponent },
|
||||
[ProviderType.PROVIDER_TYPE_APPLE]: { path: 'apple', component: ProviderAppleComponent },
|
||||
[ProviderType.PROVIDER_TYPE_SAML]: { path: 'saml', component: ProviderSamlSpComponent },
|
||||
};
|
||||
|
||||
const routes: Routes = Object.entries(typeMap).map(([key, value]) => {
|
||||
|
@ -29,6 +29,7 @@ import { ProviderLDAPComponent } from './provider-ldap/provider-ldap.component';
|
||||
import { ProviderOAuthComponent } from './provider-oauth/provider-oauth.component';
|
||||
import { ProviderOIDCComponent } from './provider-oidc/provider-oidc.component';
|
||||
import { ProvidersRoutingModule } from './providers-routing.module';
|
||||
import { ProviderSamlSpComponent } from './provider-saml-sp/provider-saml-sp.component';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
@ -45,6 +46,7 @@ import { ProvidersRoutingModule } from './providers-routing.module';
|
||||
ProviderOAuthComponent,
|
||||
ProviderLDAPComponent,
|
||||
ProviderAppleComponent,
|
||||
ProviderSamlSpComponent,
|
||||
],
|
||||
imports: [
|
||||
ProvidersRoutingModule,
|
||||
|
@ -40,6 +40,8 @@ import {
|
||||
AddNotificationPolicyResponse,
|
||||
AddOIDCSettingsRequest,
|
||||
AddOIDCSettingsResponse,
|
||||
AddSAMLProviderRequest,
|
||||
AddSAMLProviderResponse,
|
||||
AddSecondFactorToLoginPolicyRequest,
|
||||
AddSecondFactorToLoginPolicyResponse,
|
||||
AddSMSProviderTwilioRequest,
|
||||
@ -262,6 +264,8 @@ import {
|
||||
UpdatePasswordComplexityPolicyResponse,
|
||||
UpdatePrivacyPolicyRequest,
|
||||
UpdatePrivacyPolicyResponse,
|
||||
UpdateSAMLProviderRequest,
|
||||
UpdateSAMLProviderResponse,
|
||||
UpdateSecretGeneratorRequest,
|
||||
UpdateSecretGeneratorResponse,
|
||||
UpdateSMSProviderTwilioRequest,
|
||||
@ -1170,6 +1174,14 @@ export class AdminService {
|
||||
return this.grpcService.admin.updateJWTProvider(req, null).then((resp) => resp.toObject());
|
||||
}
|
||||
|
||||
public addSAMLProvider(req: AddSAMLProviderRequest): Promise<AddSAMLProviderResponse.AsObject> {
|
||||
return this.grpcService.admin.addSAMLProvider(req, null).then((resp) => resp.toObject());
|
||||
}
|
||||
|
||||
public updateSAMLProvider(req: UpdateSAMLProviderRequest): Promise<UpdateSAMLProviderResponse.AsObject> {
|
||||
return this.grpcService.admin.updateSAMLProvider(req, null).then((resp) => resp.toObject());
|
||||
}
|
||||
|
||||
public addGitHubEnterpriseServerProvider(
|
||||
req: AddGitHubEnterpriseServerProviderRequest,
|
||||
): Promise<AddGitHubEnterpriseServerProviderResponse.AsObject> {
|
||||
|
@ -83,6 +83,8 @@ import {
|
||||
AddProjectRoleResponse,
|
||||
AddSAMLAppRequest,
|
||||
AddSAMLAppResponse,
|
||||
AddSAMLProviderRequest,
|
||||
AddSAMLProviderResponse,
|
||||
AddSecondFactorToLoginPolicyRequest,
|
||||
AddSecondFactorToLoginPolicyResponse,
|
||||
AddUserGrantRequest,
|
||||
@ -511,6 +513,8 @@ import {
|
||||
UpdateProjectRoleResponse,
|
||||
UpdateSAMLAppConfigRequest,
|
||||
UpdateSAMLAppConfigResponse,
|
||||
UpdateSAMLProviderRequest,
|
||||
UpdateSAMLProviderResponse,
|
||||
UpdateUserGrantRequest,
|
||||
UpdateUserGrantResponse,
|
||||
UpdateUserNameRequest,
|
||||
@ -1037,6 +1041,14 @@ export class ManagementService {
|
||||
return this.grpcService.mgmt.updateJWTProvider(req, null).then((resp) => resp.toObject());
|
||||
}
|
||||
|
||||
public addSAMLProvider(req: AddSAMLProviderRequest): Promise<AddSAMLProviderResponse.AsObject> {
|
||||
return this.grpcService.mgmt.addSAMLProvider(req, null).then((resp) => resp.toObject());
|
||||
}
|
||||
|
||||
public updateSAMLProvider(req: UpdateSAMLProviderRequest): Promise<UpdateSAMLProviderResponse.AsObject> {
|
||||
return this.grpcService.mgmt.updateSAMLProvider(req, null).then((resp) => resp.toObject());
|
||||
}
|
||||
|
||||
public addGitHubEnterpriseServerProvider(
|
||||
req: AddGitHubEnterpriseServerProviderRequest,
|
||||
): Promise<AddGitHubEnterpriseServerProviderResponse.AsObject> {
|
||||
|
@ -1,3 +1,3 @@
|
||||
export const supportedLanguages = ['de', 'en', 'es', 'fr', 'it', 'ja', 'pl', 'zh', 'bg', 'pt', 'mk'];
|
||||
export const supportedLanguagesRegexp: RegExp = /de|en|es|fr|it|ja|pl|zh|bg|pt|mk/;
|
||||
export const supportedLanguages = ['de', 'en', 'es', 'fr', 'it', 'ja', 'pl', 'zh', 'bg', 'pt', 'mk', 'cs', 'ru'];
|
||||
export const supportedLanguagesRegexp: RegExp = /de|en|es|fr|it|ja|pl|zh|bg|pt|mk|cs|ru/;
|
||||
export const fallbackLanguage: string = 'en';
|
||||
|
@ -1053,7 +1053,9 @@
|
||||
"zh": "简体中文",
|
||||
"bg": "Български",
|
||||
"pt": "Portuguese",
|
||||
"mk": "Македонски"
|
||||
"mk": "Македонски",
|
||||
"cs": "Čeština",
|
||||
"ru": "Русский"
|
||||
},
|
||||
"SMTP": {
|
||||
"TITLE": "SMTP настройки",
|
||||
@ -1264,7 +1266,9 @@
|
||||
"zh": "简体中文",
|
||||
"bg": "Български",
|
||||
"pt": "Portuguese",
|
||||
"mk": "Македонски"
|
||||
"mk": "Македонски",
|
||||
"cs": "Čeština",
|
||||
"ru": "Русский"
|
||||
},
|
||||
"KEYS": {
|
||||
"emailVerificationDoneText": "Проверката на имейл е извършена",
|
||||
@ -2149,7 +2153,9 @@
|
||||
"zh": "简体中文",
|
||||
"bg": "Български",
|
||||
"pt": "португалски",
|
||||
"mk": "Македонски"
|
||||
"mk": "Македонски",
|
||||
"cs": "Čeština",
|
||||
"ru": "Русский"
|
||||
},
|
||||
"MEMBER": {
|
||||
"ADD": "Добавяне на мениджър",
|
||||
|
2251
console/src/assets/i18n/cs.json
Normal file
2251
console/src/assets/i18n/cs.json
Normal file
File diff suppressed because it is too large
Load Diff
@ -1059,7 +1059,9 @@
|
||||
"zh": "简体中文",
|
||||
"bg": "Български",
|
||||
"pt": "Portuguese",
|
||||
"mk": "Македонски"
|
||||
"mk": "Македонски",
|
||||
"cs": "Čeština",
|
||||
"ru": "Русский"
|
||||
},
|
||||
"SMTP": {
|
||||
"TITLE": "SMTP Einstellungen",
|
||||
@ -1270,7 +1272,9 @@
|
||||
"zh": "简体中文",
|
||||
"bg": "Български",
|
||||
"pt": "Portuguese",
|
||||
"mk": "Македонски"
|
||||
"mk": "Македонски",
|
||||
"cs": "Čeština",
|
||||
"ru": "Русский"
|
||||
},
|
||||
"KEYS": {
|
||||
"emailVerificationDoneText": "Email Verification erfolgreich",
|
||||
@ -2158,7 +2162,9 @@
|
||||
"zh": "简体中文",
|
||||
"bg": "Български",
|
||||
"pt": "Portuguese",
|
||||
"mk": "Македонски"
|
||||
"mk": "Македонски",
|
||||
"cs": "Čeština",
|
||||
"ru": "Русский"
|
||||
},
|
||||
"MEMBER": {
|
||||
"ADD": "Manager hinzufügen",
|
||||
|
@ -1060,7 +1060,9 @@
|
||||
"zh": "简体中文",
|
||||
"bg": "Български",
|
||||
"pt": "Portuguese",
|
||||
"mk": "Македонски"
|
||||
"mk": "Македонски",
|
||||
"cs": "Čeština",
|
||||
"ru": "Русский"
|
||||
},
|
||||
"SMTP": {
|
||||
"TITLE": "SMTP Settings",
|
||||
@ -1271,7 +1273,9 @@
|
||||
"zh": "简体中文",
|
||||
"bg": "Български",
|
||||
"pt": "Portuguese",
|
||||
"mk": "Македонски"
|
||||
"mk": "Македонски",
|
||||
"cs": "Čeština",
|
||||
"ru": "Русский"
|
||||
},
|
||||
"KEYS": {
|
||||
"emailVerificationDoneText": "Email verification done",
|
||||
@ -1726,6 +1730,10 @@
|
||||
"APPLE": {
|
||||
"TITLE": "Sign in with Apple",
|
||||
"DESCRIPTION": "Enter the credentials for your Apple Provider"
|
||||
},
|
||||
"SAML": {
|
||||
"TITLE": "Sign in with Saml SP",
|
||||
"DESCRIPTION": "Enter the credentials for your SAML Provider"
|
||||
}
|
||||
},
|
||||
"DETAIL": {
|
||||
@ -1847,6 +1855,12 @@
|
||||
"UPLOADPRIVATEKEY": "Upload Private Key",
|
||||
"KEYMAXSIZEEXCEEDED": "Maximum size of 5kB exceeded."
|
||||
},
|
||||
"SAML": {
|
||||
"METADATAXML": "Metadata Xml",
|
||||
"METADATAURL": "Metadata URL",
|
||||
"BINDING": "Binding",
|
||||
"SIGNEDREQUEST": "Signed Request"
|
||||
},
|
||||
"TOAST": {
|
||||
"SAVED": "Successfully saved.",
|
||||
"REACTIVATED": "Idp reactivated.",
|
||||
@ -2167,7 +2181,9 @@
|
||||
"zh": "简体中文",
|
||||
"bg": "Български",
|
||||
"pt": "Portuguese",
|
||||
"mk": "Македонски"
|
||||
"mk": "Македонски",
|
||||
"cs": "Čeština",
|
||||
"ru": "Русский"
|
||||
},
|
||||
"MEMBER": {
|
||||
"ADD": "Add a Manager",
|
||||
|
@ -1060,7 +1060,9 @@
|
||||
"zh": "简体中文",
|
||||
"bg": "Български",
|
||||
"pt": "Portuguese",
|
||||
"mk": "Македонски"
|
||||
"mk": "Македонски",
|
||||
"cs": "Čeština",
|
||||
"ru": "Русский"
|
||||
},
|
||||
"SMTP": {
|
||||
"TITLE": "Ajustes SMTP",
|
||||
@ -1271,7 +1273,9 @@
|
||||
"zh": "简体中文",
|
||||
"bg": "Български",
|
||||
"pt": "Portuguese",
|
||||
"mk": "Македонски"
|
||||
"mk": "Македонски",
|
||||
"cs": "Čeština",
|
||||
"ru": "Русский"
|
||||
},
|
||||
"KEYS": {
|
||||
"emailVerificationDoneText": "Verificación de email realizada",
|
||||
@ -2155,7 +2159,9 @@
|
||||
"zh": "简体中文",
|
||||
"bg": "Български",
|
||||
"pt": "Portuguese",
|
||||
"mk": "Македонски"
|
||||
"mk": "Македонски",
|
||||
"cs": "Čeština",
|
||||
"ru": "Русский"
|
||||
},
|
||||
"MEMBER": {
|
||||
"ADD": "Añadir un Mánager",
|
||||
|
@ -1059,7 +1059,9 @@
|
||||
"zh": "简体中文",
|
||||
"bg": "Български",
|
||||
"pt": "Portuguese",
|
||||
"mk": "Македонски"
|
||||
"mk": "Македонски",
|
||||
"cs": "Čeština",
|
||||
"ru": "Русский"
|
||||
},
|
||||
"SMTP": {
|
||||
"TITLE": "Paramètres SMTP",
|
||||
@ -1270,7 +1272,9 @@
|
||||
"zh": "简体中文",
|
||||
"bg": "Български",
|
||||
"pt": "Portuguese",
|
||||
"mk": "Македонски"
|
||||
"mk": "Македонски",
|
||||
"cs": "Čeština",
|
||||
"ru": "Русский"
|
||||
},
|
||||
"KEYS": {
|
||||
"emailVerificationDoneText": "Vérification de l'email effectuée",
|
||||
@ -2159,7 +2163,9 @@
|
||||
"zh": "简体中文",
|
||||
"bg": "Български",
|
||||
"pt": "Portuguese",
|
||||
"mk": "Македонски"
|
||||
"mk": "Македонски",
|
||||
"cs": "Čeština",
|
||||
"ru": "Русский"
|
||||
},
|
||||
"MEMBER": {
|
||||
"ADD": "Ajouter un manager",
|
||||
|
@ -1059,7 +1059,9 @@
|
||||
"zh": "简体中文",
|
||||
"bg": "Български",
|
||||
"pt": "Portuguese",
|
||||
"mk": "Македонски"
|
||||
"mk": "Македонски",
|
||||
"cs": "Čeština",
|
||||
"ru": "Русский"
|
||||
},
|
||||
"SMTP": {
|
||||
"TITLE": "Impostazioni SMTP",
|
||||
@ -1270,7 +1272,9 @@
|
||||
"zh": "简体中文",
|
||||
"bg": "Български",
|
||||
"pt": "Portuguese",
|
||||
"mk": "Македонски"
|
||||
"mk": "Македонски",
|
||||
"cs": "Čeština",
|
||||
"ru": "Русский"
|
||||
},
|
||||
"KEYS": {
|
||||
"emailVerificationDoneText": "Verifica dell'e-mail terminata con successo.",
|
||||
@ -2159,7 +2163,9 @@
|
||||
"zh": "简体中文",
|
||||
"bg": "Български",
|
||||
"pt": "Portuguese",
|
||||
"mk": "Македонски"
|
||||
"mk": "Македонски",
|
||||
"cs": "Čeština",
|
||||
"ru": "Русский"
|
||||
},
|
||||
"MEMBER": {
|
||||
"ADD": "Aggiungi un manager",
|
||||
|
@ -1060,7 +1060,9 @@
|
||||
"zh": "简体中文",
|
||||
"bg": "Български",
|
||||
"pt": "Portuguese",
|
||||
"mk": "Македонски"
|
||||
"mk": "Македонски",
|
||||
"cs": "Čeština",
|
||||
"ru": "Русский"
|
||||
},
|
||||
"SMTP": {
|
||||
"TITLE": "SMTP設定",
|
||||
@ -1266,7 +1268,9 @@
|
||||
"zh": "简体中文",
|
||||
"bg": "Български",
|
||||
"pt": "Portuguese",
|
||||
"mk": "Македонски"
|
||||
"mk": "Македонски",
|
||||
"cs": "Čeština",
|
||||
"ru": "Русский"
|
||||
},
|
||||
"KEYS": {
|
||||
"emailVerificationDoneText": "メール認証が完了しました",
|
||||
@ -2150,7 +2154,9 @@
|
||||
"zh": "简体中文",
|
||||
"bg": "Български",
|
||||
"pt": "Portuguese",
|
||||
"mk": "Македонски"
|
||||
"mk": "Македонски",
|
||||
"cs": "Čeština",
|
||||
"ru": "Русский"
|
||||
},
|
||||
"MEMBER": {
|
||||
"ADD": "マネージャーを追加する",
|
||||
|
@ -1061,7 +1061,9 @@
|
||||
"zh": "简体中文",
|
||||
"bg": "Български",
|
||||
"pt": "Portuguese",
|
||||
"mk": "Македонски"
|
||||
"mk": "Македонски",
|
||||
"cs": "Čeština",
|
||||
"ru": "Русский"
|
||||
},
|
||||
"SMTP": {
|
||||
"TITLE": "SMTP подесувања",
|
||||
@ -1272,7 +1274,9 @@
|
||||
"zh": "简体中文",
|
||||
"bg": "Български",
|
||||
"pt": "Portuguese",
|
||||
"mk": "Македонски"
|
||||
"mk": "Македонски",
|
||||
"cs": "Čeština",
|
||||
"ru": "Русский"
|
||||
},
|
||||
"KEYS": {
|
||||
"emailVerificationDoneText": "Е-поштата е верифицирана",
|
||||
@ -2156,7 +2160,9 @@
|
||||
"zh": "简体中文",
|
||||
"bg": "Български",
|
||||
"pt": "Portuguese",
|
||||
"mk": "Македонски"
|
||||
"mk": "Македонски",
|
||||
"cs": "Čeština",
|
||||
"ru": "Русский"
|
||||
},
|
||||
"MEMBER": {
|
||||
"ADD": "Додај Менаџер",
|
||||
|
@ -1059,7 +1059,9 @@
|
||||
"zh": "简体中文",
|
||||
"bg": "Български",
|
||||
"pt": "Portuguese",
|
||||
"mk": "Македонски"
|
||||
"mk": "Македонски",
|
||||
"cs": "Čeština",
|
||||
"ru": "Русский"
|
||||
},
|
||||
"SMTP": {
|
||||
"TITLE": "Ustawienia SMTP",
|
||||
@ -1270,7 +1272,9 @@
|
||||
"zh": "简体中文",
|
||||
"bg": "Български",
|
||||
"pt": "Portuguese",
|
||||
"mk": "Македонски"
|
||||
"mk": "Македонски",
|
||||
"cs": "Čeština",
|
||||
"ru": "Русский"
|
||||
},
|
||||
"KEYS": {
|
||||
"emailVerificationDoneText": "Weryfikacja adresu e-mail zakończona",
|
||||
@ -2159,7 +2163,9 @@
|
||||
"zh": "简体中文",
|
||||
"bg": "Български",
|
||||
"pt": "Portuguese",
|
||||
"mk": "Македонски"
|
||||
"mk": "Македонски",
|
||||
"cs": "Čeština",
|
||||
"ru": "Русский"
|
||||
},
|
||||
"MEMBER": {
|
||||
"ADD": "Dodaj managera",
|
||||
|
@ -1061,7 +1061,9 @@
|
||||
"zh": "简体中文",
|
||||
"bg": "Български",
|
||||
"pt": "Portuguese",
|
||||
"mk": "Македонски"
|
||||
"mk": "Македонски",
|
||||
"cs": "Čeština",
|
||||
"ru": "Русский"
|
||||
},
|
||||
"SMTP": {
|
||||
"TITLE": "Configurações SMTP",
|
||||
@ -1272,7 +1274,9 @@
|
||||
"zh": "简体中文",
|
||||
"bg": "Български",
|
||||
"pt": "Portuguese",
|
||||
"mk": "Македонски"
|
||||
"mk": "Македонски",
|
||||
"cs": "Čeština",
|
||||
"ru": "Русский"
|
||||
},
|
||||
"KEYS": {
|
||||
"emailVerificationDoneText": "Verificação de email concluída",
|
||||
@ -2154,7 +2158,9 @@
|
||||
"zh": "简体中文",
|
||||
"bg": "Български",
|
||||
"pt": "Portuguese",
|
||||
"mk": "Македонски"
|
||||
"mk": "Македонски",
|
||||
"cs": "Čeština",
|
||||
"ru": "Русский"
|
||||
},
|
||||
"MEMBER": {
|
||||
"ADD": "Adicionar um Gerente",
|
||||
|
2228
console/src/assets/i18n/ru.json
Normal file
2228
console/src/assets/i18n/ru.json
Normal file
File diff suppressed because it is too large
Load Diff
@ -1059,7 +1059,9 @@
|
||||
"zh": "简体中文",
|
||||
"bg": "Български",
|
||||
"pt": "Portuguese",
|
||||
"mk": "Македонски"
|
||||
"mk": "Македонски",
|
||||
"cs": "Čeština",
|
||||
"ru": "Русский"
|
||||
},
|
||||
"SMTP": {
|
||||
"TITLE": "SMTP 设置",
|
||||
@ -1269,7 +1271,9 @@
|
||||
"zh": "简体中文",
|
||||
"bg": "Български",
|
||||
"pt": "Portuguese",
|
||||
"mk": "Македонски"
|
||||
"mk": "Македонски",
|
||||
"cs": "Čeština",
|
||||
"ru": "Русский"
|
||||
},
|
||||
"KEYS": {
|
||||
"emailVerificationDoneText": "电子邮件验证完成",
|
||||
@ -2158,7 +2162,9 @@
|
||||
"zh": "简体中文",
|
||||
"bg": "Български",
|
||||
"pt": "Portuguese",
|
||||
"mk": "Македонски"
|
||||
"mk": "Македонски",
|
||||
"cs": "Čeština",
|
||||
"ru": "Русский"
|
||||
},
|
||||
"MEMBER": {
|
||||
"ADD": "添加管理者",
|
||||
|
9
console/src/assets/images/idp/saml-icon.svg
Normal file
9
console/src/assets/images/idp/saml-icon.svg
Normal file
@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||
<svg width="800px" height="800px" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" fill="none">
|
||||
<g fill="#C22E33">
|
||||
<path d="M7.754 2l.463.41c.343.304.687.607 1.026.915C11.44 5.32 13.3 7.565 14.7 10.149c.072.132.137.268.202.403l.098.203-.108.057-.081-.115-.21-.299-.147-.214c-1.019-1.479-2.04-2.96-3.442-4.145a6.563 6.563 0 00-1.393-.904c-1.014-.485-1.916-.291-2.69.505-.736.757-1.118 1.697-1.463 2.653-.045.123-.092.245-.139.367l-.082.215-.172-.055c.1-.348.192-.698.284-1.049.21-.795.42-1.59.712-2.356.31-.816.702-1.603 1.093-2.39.169-.341.338-.682.5-1.025h.092z"/>
|
||||
<path d="M8.448 11.822c-1.626.77-5.56 1.564-7.426 1.36C.717 11.576 3.71 4.05 5.18 2.91l-.095.218a4.638 4.638 0 01-.138.303l-.066.129c-.76 1.462-1.519 2.926-1.908 4.53a7.482 7.482 0 00-.228 1.689c-.01 1.34.824 2.252 2.217 2.309.67.027 1.347-.043 2.023-.114.294-.03.587-.061.88-.084.108-.008.214-.021.352-.039l.231-.028z"/>
|
||||
<path d="M3.825 14.781c-.445.034-.89.068-1.333.108 4.097.39 8.03-.277 11.91-1.644-1.265-2.23-2.97-3.991-4.952-5.522.026.098.084.169.141.239l.048.06c.17.226.348.448.527.67.409.509.818 1.018 1.126 1.578.778 1.42.356 2.648-1.168 3.296-1.002.427-2.097.718-3.18.892-1.03.164-2.075.243-3.119.323z"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 1.3 KiB |
@ -2047,6 +2047,32 @@
|
||||
resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.50.0.tgz#9e93b850f0f3fa35f5fa59adfd03adae8488e484"
|
||||
integrity sha512-NCC3zz2+nvYd+Ckfh87rA47zfu2QsQpvc6k1yzTk+b9KzRj0wkGa8LSoGOXN6Zv4lRf/EIoZ80biDh9HOI+RNQ==
|
||||
|
||||
"@fortawesome/angular-fontawesome@^0.13.0":
|
||||
version "0.13.0"
|
||||
resolved "https://registry.yarnpkg.com/@fortawesome/angular-fontawesome/-/angular-fontawesome-0.13.0.tgz#3e343ff5ea62934cb0309a52bbf732adecf216fc"
|
||||
integrity sha512-gzSPRdveOXNO7NIiMgTyB46aiHG0i98KinnAEqHXi8qzraM/kCcHn/0y3f4MhemX6kftwsFli0IU8RyHmtXlSQ==
|
||||
dependencies:
|
||||
tslib "^2.4.1"
|
||||
|
||||
"@fortawesome/fontawesome-common-types@6.4.2":
|
||||
version "6.4.2"
|
||||
resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.4.2.tgz#1766039cad33f8ad87f9467b98e0d18fbc8f01c5"
|
||||
integrity sha512-1DgP7f+XQIJbLFCTX1V2QnxVmpLdKdzzo2k8EmvDOePfchaIGQ9eCHj2up3/jNEbZuBqel5OxiaOJf37TWauRA==
|
||||
|
||||
"@fortawesome/fontawesome-svg-core@^6.4.2":
|
||||
version "6.4.2"
|
||||
resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.4.2.tgz#37f4507d5ec645c8b50df6db14eced32a6f9be09"
|
||||
integrity sha512-gjYDSKv3TrM2sLTOKBc5rH9ckje8Wrwgx1CxAPbN5N3Fm4prfi7NsJVWd1jklp7i5uSCVwhZS5qlhMXqLrpAIg==
|
||||
dependencies:
|
||||
"@fortawesome/fontawesome-common-types" "6.4.2"
|
||||
|
||||
"@fortawesome/free-brands-svg-icons@^6.4.2":
|
||||
version "6.4.2"
|
||||
resolved "https://registry.yarnpkg.com/@fortawesome/free-brands-svg-icons/-/free-brands-svg-icons-6.4.2.tgz#9b8e78066ea6dd563da5dfa686615791d0f7cc71"
|
||||
integrity sha512-LKOwJX0I7+mR/cvvf6qIiqcERbdnY+24zgpUSouySml+5w8B4BJOx8EhDR/FTKAu06W12fmUIcv6lzPSwYKGGg==
|
||||
dependencies:
|
||||
"@fortawesome/fontawesome-common-types" "6.4.2"
|
||||
|
||||
"@gar/promisify@^1.1.3":
|
||||
version "1.1.3"
|
||||
resolved "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz"
|
||||
|
@ -43,7 +43,7 @@ Per default you will only search for users within the selected organization. If
|
||||
## Configure roles
|
||||
|
||||
If you run a self hosted ZITADEL istance you can define your custom roles by overwriting the defaults.yaml
|
||||
In the InternalAuthZ section you will find all the roles and which permissions the have.
|
||||
In the InternalAuthZ section you will find all the roles and which permissions they have.
|
||||
|
||||
Example:
|
||||
```bash
|
||||
@ -53,4 +53,4 @@ InternalAuthZ:
|
||||
Permissions:
|
||||
- "iam.read"
|
||||
- "iam.write"
|
||||
```
|
||||
```
|
||||
|
@ -45,6 +45,8 @@ ZITADEL is available in the following languages
|
||||
- Bulgarian (bg)
|
||||
- Portuguese (pt)
|
||||
- Macedonian (mk)
|
||||
- Czech (cs)
|
||||
- Russina (ru)
|
||||
|
||||
A language is displayed based on your agent's language header. The default language is English.
|
||||
|
||||
|
@ -1,31 +1,65 @@
|
||||
---
|
||||
title: Run ZITADEL on a Custom Domain
|
||||
sidebar: Custom Domain
|
||||
title: External ZITADEL Access
|
||||
sidebar_label: Instance Not Found
|
||||
---
|
||||
|
||||
# Run ZITADEL on a (Sub)domain of Your Choice
|
||||
## Why do I get an "Instance not found" error?
|
||||
|
||||
Also, ZITADEL has the [concept of virtual instances](/concepts/structure/instance#multiple-virtual-instances).
|
||||
It uses a requests Host header to determine which virtual instance to use.
|
||||
This is useful for multi-tenancy and resource sharing, for example in SaaS scenarios.
|
||||
For most cases however, ZITADEL should run on exactly one domain.
|
||||
|
||||
This guide assumes you are already familiar with [configuring ZITADEL](./configure).
|
||||
|
||||
You most probably need to configure these fields for making ZITADEL work on your custom domain.
|
||||
|
||||
## Standard Config
|
||||
|
||||
For security reasons, ZITADEL only serves requests sent to the expected protocol, host and port.
|
||||
If not using localhost as ExternalDomain, ExternalSecure must be true and you need to serve the ZITADEL console over HTTPS.
|
||||
ZITADEL only serves requests sent to the expected protocol, host and port.
|
||||
For local testing purposes, you can use following configuration:
|
||||
|
||||
```yaml
|
||||
ExternalSecure: true
|
||||
ExternalDomain: 'zitadel.my.domain'
|
||||
ExternalPort: 443
|
||||
ExternalDomain: localhost
|
||||
ExternalPort: 8080
|
||||
ExternalSecure: false
|
||||
```
|
||||
|
||||
## Database Initialization Steps Config
|
||||
For productive setups however, we recommend using HTTPS and a custom domain:
|
||||
|
||||
ZITADEL creates random subdomains for each instance created.
|
||||
However, for the first instance, this is most probably not the desired behavior.
|
||||
In this case the `ExternalDomain`-field of the configuration is used.
|
||||
```yaml
|
||||
ExternalDomain: 'zitadel.my.domain'
|
||||
ExternalPort: 443
|
||||
ExternalSecure: true
|
||||
```
|
||||
|
||||
## Example
|
||||
## Changing ExternalDomain, ExternalPort or ExternalSecure
|
||||
|
||||
You can change the ExternalDomain, ExternalPort and ExternalSecure configuration options at any time.
|
||||
However, for ZITADEL to be able to pick up the changes, [you need to rerun ZITADELs setup phase](/self-hosting/manage/updating_scaling#the-setup-phase).
|
||||
|
||||
## Running ZITADEL behind a Reverse Proxy
|
||||
|
||||
If you run ZITADEL behind a reverse proxy, you need to ensure that it sends the correct request headers to ZITADEL.
|
||||
The proxy must either ensure that
|
||||
- the original *Host* header value is assigned to the *Forwarded* headers host directive.
|
||||
- the original requests *Host* header value is unchanged by the proxy.
|
||||
|
||||
Check out the [reverse proxy configuration examples](/self-hosting/manage/reverseproxy/reverse_proxy) for more information.
|
||||
|
||||
## Organization Domains
|
||||
|
||||
Note that by default, you cannot access ZITADEL at an organizations domain.
|
||||
Organization level domains [are intended for routing users by their login methods to their correct organization](http://localhost:3000/docs/guides/solution-scenarios/domain-discovery).
|
||||
|
||||
However, if you want to access ZITADEL at an organization domain, [you can add additional domains using the System API](/apis/resources/system/system-service-add-domain#adds-a-domain-to-an-instance).
|
||||
Be aware that you won't automatically have the organizations context when you access ZITADEL like this.
|
||||
|
||||
## Generated Subdomains
|
||||
|
||||
ZITADEL creates random subdomains for [each new virtual instance](/concepts/structure/instance#multiple-virtual-instances).
|
||||
You can immediately access the ZITADEL Console an APIs using these subdomains without further actions.
|
||||
|
||||
## More Information
|
||||
|
||||
- [Check out the production-near loadbalancing example with Traefik](/self-hosting/deploy/loadbalancing-example)
|
||||
- [Explore some concrete proxy configuration examples for ZITADEL using the domain 127.0.0.1.sslip.io](/self-hosting/manage/reverseproxy/reverse_proxy)
|
||||
|
||||
Go to the [loadbalancing example with Traefik](/docs/self-hosting/deploy/loadbalancing-example) for seeing a working example configuration.
|
||||
|
@ -1,3 +0,0 @@
|
||||
:::caution
|
||||
|
||||
[The Cloudflare tunnel client currently has an issue which allows it not to force HTTP/2 usage towards the origin.](https://github.com/cloudflare/cloudflared/issues/682)
|
@ -1,166 +0,0 @@
|
||||
## TLS mode external
|
||||
|
||||
```
|
||||
LoadModule mpm_event_module modules/mod_mpm_event.so
|
||||
LoadModule authn_file_module modules/mod_authn_file.so
|
||||
LoadModule authn_core_module modules/mod_authn_core.so
|
||||
LoadModule authz_host_module modules/mod_authz_host.so
|
||||
LoadModule authz_groupfile_module modules/mod_authz_groupfile.so
|
||||
LoadModule authz_user_module modules/mod_authz_user.so
|
||||
LoadModule authz_core_module modules/mod_authz_core.so
|
||||
LoadModule access_compat_module modules/mod_access_compat.so
|
||||
LoadModule auth_basic_module modules/mod_auth_basic.so
|
||||
LoadModule reqtimeout_module modules/mod_reqtimeout.so
|
||||
LoadModule filter_module modules/mod_filter.so
|
||||
LoadModule mime_module modules/mod_mime.so
|
||||
LoadModule log_config_module modules/mod_log_config.so
|
||||
LoadModule env_module modules/mod_env.so
|
||||
LoadModule headers_module modules/mod_headers.so
|
||||
LoadModule setenvif_module modules/mod_setenvif.so
|
||||
LoadModule version_module modules/mod_version.so
|
||||
LoadModule proxy_module modules/mod_proxy.so
|
||||
LoadModule proxy_http_module modules/mod_proxy_http.so
|
||||
LoadModule ssl_module modules/mod_ssl.so
|
||||
LoadModule proxy_http2_module modules/mod_proxy_http2.so
|
||||
LoadModule unixd_module modules/mod_unixd.so
|
||||
LoadModule status_module modules/mod_status.so
|
||||
LoadModule autoindex_module modules/mod_autoindex.so
|
||||
LoadModule dir_module modules/mod_dir.so
|
||||
LoadModule alias_module modules/mod_alias.so
|
||||
LoadModule rewrite_module modules/mod_rewrite.so
|
||||
|
||||
ServerRoot "/usr/local/apache2"
|
||||
LogLevel warn
|
||||
ErrorLog /proc/self/fd/2
|
||||
CustomLog /proc/self/fd/1 "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\""
|
||||
|
||||
ServerName my.domain
|
||||
Listen 80
|
||||
Listen 443
|
||||
|
||||
SSLRandomSeed startup builtin
|
||||
SSLRandomSeed connect builtin
|
||||
|
||||
<VirtualHost *:80>
|
||||
ServerName my.domain
|
||||
RewriteEngine On
|
||||
RewriteCond %{HTTPS} off
|
||||
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI}
|
||||
</VirtualHost>
|
||||
|
||||
<VirtualHost *:443>
|
||||
ServerName my.domain
|
||||
ProxyPreserveHost On
|
||||
SSLCertificateFile /certs/server.crt
|
||||
SSLCertificateKeyFile /certs/server.key
|
||||
ProxyPass / h2c://localhost:8080/
|
||||
ProxyPassReverse / h2c://localhost:8080/
|
||||
</VirtualHost>
|
||||
```
|
||||
|
||||
## TLS mode enabled
|
||||
|
||||
```
|
||||
LoadModule mpm_event_module modules/mod_mpm_event.so
|
||||
LoadModule authn_file_module modules/mod_authn_file.so
|
||||
LoadModule authn_core_module modules/mod_authn_core.so
|
||||
LoadModule authz_host_module modules/mod_authz_host.so
|
||||
LoadModule authz_groupfile_module modules/mod_authz_groupfile.so
|
||||
LoadModule authz_user_module modules/mod_authz_user.so
|
||||
LoadModule authz_core_module modules/mod_authz_core.so
|
||||
LoadModule access_compat_module modules/mod_access_compat.so
|
||||
LoadModule auth_basic_module modules/mod_auth_basic.so
|
||||
LoadModule reqtimeout_module modules/mod_reqtimeout.so
|
||||
LoadModule filter_module modules/mod_filter.so
|
||||
LoadModule mime_module modules/mod_mime.so
|
||||
LoadModule log_config_module modules/mod_log_config.so
|
||||
LoadModule env_module modules/mod_env.so
|
||||
LoadModule headers_module modules/mod_headers.so
|
||||
LoadModule setenvif_module modules/mod_setenvif.so
|
||||
LoadModule version_module modules/mod_version.so
|
||||
LoadModule proxy_module modules/mod_proxy.so
|
||||
LoadModule proxy_http_module modules/mod_proxy_http.so
|
||||
LoadModule ssl_module modules/mod_ssl.so
|
||||
LoadModule proxy_http2_module modules/mod_proxy_http2.so
|
||||
LoadModule unixd_module modules/mod_unixd.so
|
||||
LoadModule status_module modules/mod_status.so
|
||||
LoadModule autoindex_module modules/mod_autoindex.so
|
||||
LoadModule dir_module modules/mod_dir.so
|
||||
LoadModule alias_module modules/mod_alias.so
|
||||
LoadModule rewrite_module modules/mod_rewrite.so
|
||||
LoadModule http2_module modules/mod_http2.so
|
||||
|
||||
ServerRoot "/usr/local/apache2"
|
||||
LogLevel debug
|
||||
ErrorLog /proc/self/fd/2
|
||||
CustomLog /proc/self/fd/1 "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\""
|
||||
|
||||
ServerName my.domain
|
||||
Listen 80
|
||||
Listen 443
|
||||
|
||||
SSLRandomSeed startup builtin
|
||||
SSLRandomSeed connect builtin
|
||||
|
||||
<VirtualHost *:80>
|
||||
RewriteEngine On
|
||||
RewriteCond %{HTTPS} off
|
||||
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI}
|
||||
</VirtualHost>
|
||||
|
||||
<VirtualHost *:443>
|
||||
ProxyPreserveHost On
|
||||
SSLEngine on
|
||||
SSLProxyEngine on
|
||||
SSLCertificateFile /certs/server.crt
|
||||
SSLCertificateKeyFile /certs/server.key
|
||||
ProxyPass / h2://localhost:8080/
|
||||
</VirtualHost>
|
||||
```
|
||||
|
||||
## TLS mode disabled
|
||||
|
||||
```
|
||||
LoadModule mpm_event_module modules/mod_mpm_event.so
|
||||
LoadModule authn_file_module modules/mod_authn_file.so
|
||||
LoadModule authn_core_module modules/mod_authn_core.so
|
||||
LoadModule authz_host_module modules/mod_authz_host.so
|
||||
LoadModule authz_groupfile_module modules/mod_authz_groupfile.so
|
||||
LoadModule authz_user_module modules/mod_authz_user.so
|
||||
LoadModule authz_core_module modules/mod_authz_core.so
|
||||
LoadModule access_compat_module modules/mod_access_compat.so
|
||||
LoadModule auth_basic_module modules/mod_auth_basic.so
|
||||
LoadModule reqtimeout_module modules/mod_reqtimeout.so
|
||||
LoadModule filter_module modules/mod_filter.so
|
||||
LoadModule mime_module modules/mod_mime.so
|
||||
LoadModule log_config_module modules/mod_log_config.so
|
||||
LoadModule env_module modules/mod_env.so
|
||||
LoadModule headers_module modules/mod_headers.so
|
||||
LoadModule setenvif_module modules/mod_setenvif.so
|
||||
LoadModule version_module modules/mod_version.so
|
||||
LoadModule proxy_module modules/mod_proxy.so
|
||||
LoadModule proxy_http_module modules/mod_proxy_http.so
|
||||
LoadModule ssl_module modules/mod_ssl.so
|
||||
LoadModule proxy_http2_module modules/mod_proxy_http2.so
|
||||
LoadModule unixd_module modules/mod_unixd.so
|
||||
LoadModule status_module modules/mod_status.so
|
||||
LoadModule autoindex_module modules/mod_autoindex.so
|
||||
LoadModule dir_module modules/mod_dir.so
|
||||
LoadModule alias_module modules/mod_alias.so
|
||||
LoadModule rewrite_module modules/mod_rewrite.so
|
||||
|
||||
ServerRoot "/usr/local/apache2"
|
||||
LogLevel warn
|
||||
ErrorLog /proc/self/fd/2
|
||||
CustomLog /proc/self/fd/1 "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\""
|
||||
|
||||
ServerName my.domain
|
||||
Listen 80
|
||||
|
||||
<VirtualHost *:80>
|
||||
ServerName my.domain
|
||||
ProxyPreserveHost On
|
||||
ProxyPass / h2c://localhost:8080/
|
||||
ProxyPassReverse / h2c://localhost:8080/
|
||||
</VirtualHost>
|
||||
```
|
@ -1,4 +0,0 @@
|
||||
## More information
|
||||
|
||||
- [You can read here about the TLS Modes](/self-hosting/manage/tls_modes)
|
||||
- [And here about how ZITADEL makes use of HTTP/2](/self-hosting/manage/http2)
|
@ -1,95 +0,0 @@
|
||||
## TLS mode external
|
||||
|
||||
```
|
||||
worker_processes 1;
|
||||
events {
|
||||
worker_connections 1024;
|
||||
}
|
||||
|
||||
http {
|
||||
server {
|
||||
listen 443;
|
||||
|
||||
ssl_certificate ssl/certificate.pem;
|
||||
ssl_certificate_key ssl/key.pem;
|
||||
|
||||
location / {
|
||||
grpc_pass grpc://localhost:8080;
|
||||
grpc_set_header Host $host;
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
:::info
|
||||
If another port than the default HTTPS port 443 is used replace
|
||||
|
||||
` grpc_set_header Host $host;`
|
||||
|
||||
with
|
||||
|
||||
` grpc_set_header Host $host:$server_port;`
|
||||
:::
|
||||
|
||||
## TLS mode enabled
|
||||
|
||||
```
|
||||
worker_processes 1;
|
||||
events {
|
||||
worker_connections 1024;
|
||||
}
|
||||
|
||||
http {
|
||||
server {
|
||||
listen 443;
|
||||
|
||||
ssl_certificate ssl/certificate.pem;
|
||||
ssl_certificate_key ssl/key.pem;
|
||||
|
||||
location / {
|
||||
grpc_pass grpcs://localhost:8080;
|
||||
grpc_set_header Host $host;
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
:::info
|
||||
If another port than the default HTTPS port 443 is used replace
|
||||
|
||||
` grpc_set_header Host $host;`
|
||||
|
||||
with
|
||||
|
||||
` grpc_set_header Host $host:$server_port;`
|
||||
:::
|
||||
|
||||
## TLS mode disabled
|
||||
|
||||
```
|
||||
worker_processes 1;
|
||||
events {
|
||||
worker_connections 1024;
|
||||
}
|
||||
|
||||
http {
|
||||
server {
|
||||
listen 80;
|
||||
|
||||
location / {
|
||||
grpc_pass grpc://localhost:8080;
|
||||
grpc_set_header Host $host;
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
:::info
|
||||
If another port than the default HTTP port 80 is used replace
|
||||
|
||||
` grpc_set_header Host $host;`
|
||||
|
||||
with
|
||||
|
||||
` grpc_set_header Host $host:$server_port;`
|
||||
:::
|
@ -0,0 +1,2 @@
|
||||
- [Read more about ZITADELs TLS Modes](/self-hosting/manage/tls_modes)
|
||||
- [Read more about how ZITADEL uses HTTP/2](/self-hosting/manage/http2)
|
@ -0,0 +1,16 @@
|
||||
import CodeBlock from '@theme/CodeBlock';
|
||||
import ComposeYaml from "!!raw-loader!./docker-compose.yaml";
|
||||
|
||||
<>With these examples, you create and run a minimal {props.link} configuration for ZITADEL with <a href="https://docs.docker.com/compose">Docker Compose</a>.
|
||||
Whereas the guide focuses on the configuration for {props.link}, you can inspect the configurations for ZITADEL and the database in the base Docker Compose file.</>
|
||||
<details>
|
||||
<summary>base docker-compose.yaml</summary>
|
||||
<CodeBlock language="yaml">{ComposeYaml}</CodeBlock>
|
||||
</details>
|
||||
|
||||
<>For running {props.link}, you will extend the base Docker Compose file with the {props.link} specific Docker Compose file.</>
|
||||
|
||||
<details>
|
||||
<summary>specific docker-compose.yaml</summary>
|
||||
<CodeBlock language="yaml">{props.compose}</CodeBlock>
|
||||
</details>
|
@ -0,0 +1,90 @@
|
||||
import CodeBlock from '@theme/CodeBlock';
|
||||
|
||||
export const Description = ({mode, link}) => {
|
||||
let desc
|
||||
switch (mode) {
|
||||
case "disabled":
|
||||
desc = <>Neither {link} nor ZITADEL terminates TLS.
|
||||
Nevertheless, {link} forwards unencrypted HTTP/2 traffic, aka h2c, to ZITADEL.</>;
|
||||
break;
|
||||
case "external":
|
||||
desc = <>{link} terminates TLS and forwards the requests to ZITADEL via unencrypted h2c.
|
||||
This example uses an unsafe self-signed certificate for {link}</>;
|
||||
break;
|
||||
case "enabled":
|
||||
desc = <>{link} terminates TLS and forwards the requests to ZITADEL via encrypted HTTP/2.
|
||||
This example uses an unsafe self-signed certificate for {link} and the same for ZITADEL.</>;
|
||||
break;
|
||||
}
|
||||
return (
|
||||
<>
|
||||
{desc}
|
||||
<>By executing the commands below, you will download the files necessary to run ZITADEL behind {link} with the following config:</>
|
||||
</>)
|
||||
}
|
||||
|
||||
export const Commands = ({mode, name, lower, configfilename}) => {
|
||||
let genCert = '# Generate a self signed certificate and key.\nopenssl req -x509 -batch -subj "/CN=127.0.0.1.sslip.io/O=ZITADEL Demo" -nodes -newkey rsa:2048 -keyout ./selfsigned.key -out ./selfsigned.crt\n\n';
|
||||
let connPort = "443"
|
||||
let connInsecureFlag = "--insecure "
|
||||
let connScheme = "https"
|
||||
let grpcPlainTextFlag = ""
|
||||
if (mode === "disabled") {
|
||||
genCert = ''
|
||||
connPort = "80"
|
||||
grpcPlainTextFlag = "--plaintext "
|
||||
connScheme = "http"
|
||||
// We only need that flag for TLS connections with the self-signed cert
|
||||
connInsecureFlag = ""
|
||||
}
|
||||
return (
|
||||
<div>
|
||||
<CodeBlock language="bash">
|
||||
{'# Download the configuration files.'}{'\n'}
|
||||
{'export ZITADEL_CONFIG_FILES=https://raw.githubusercontent.com/zitadel/zitadel/main/docs/docs/self-hosting/manage/reverseproxy\n'}
|
||||
{`wget $\{ZITADEL_CONFIG_FILES\}/docker-compose.yaml -O docker-compose-base.yaml`}{'\n'}
|
||||
{'wget $\{ZITADEL_CONFIG_FILES\}/'}{lower}{'/docker-compose.yaml -O docker-compose-'}{lower}{'.yaml'}{'\n'}
|
||||
{'wget $\{ZITADEL_CONFIG_FILES\}/'}{lower}{'/'}{configfilename}{' -O '}{configfilename}{'\n'}
|
||||
{'\n'}
|
||||
{genCert}
|
||||
{'# Run the database, ZITADEL and '}{name}{'.'}{'\n'}
|
||||
{'docker compose --file docker-compose-base.yaml --file docker-compose-'}{lower}{'.yaml up --detach proxy-'}{mode}{'-tls'}{'\n'}
|
||||
{'\n'}
|
||||
{'# Test that gRPC and HTTP APIs work. Empty brackets like {} means success.\n'}
|
||||
{'sleep 3\n'}
|
||||
{'grpcurl '}{connInsecureFlag}{grpcPlainTextFlag}{'127.0.0.1.sslip.io:'}{connPort}{' zitadel.admin.v1.AdminService/Healthz\n'}
|
||||
{'curl '}{connInsecureFlag}{connScheme}{'://127.0.0.1.sslip.io:'}{connPort}{'/admin/v1/healthz\n'}
|
||||
</CodeBlock>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export const LoginURL = ({mode}) => {
|
||||
let scheme = "https";
|
||||
if (mode === "disabled") {
|
||||
scheme = "http"
|
||||
}
|
||||
const url = scheme + "://127.0.0.1.sslip.io/ui/console";
|
||||
return <a href={url}>{url}</a>
|
||||
}
|
||||
|
||||
<Description mode={props.mode} name={props.providername} link={props.link}/>
|
||||
|
||||
<details open>
|
||||
<summary>{props.configfilename}</summary>
|
||||
<CodeBlock>{props.configfilecontent}</CodeBlock>
|
||||
</details>
|
||||
|
||||
<Commands mode={props.mode} name={props.providername} lower={props.lower} configfilename={props.configfilename}/>
|
||||
|
||||
<>When the docker compose command exits successfully, go to <LoginURL mode={props.mode}/> and log in:</>
|
||||
|
||||
- **username**: *zitadel-admin@<span></span>zitadel.127.0.0.1.sslip.io*
|
||||
- **password**: *Password1!*
|
||||
|
||||
If the console loads normally, you know that the HTTP and gRPC-Web and gRPC APIs are working correctly.
|
||||
|
||||
<CodeBlock language="bash">
|
||||
{'# You can now stop the database, ZITADEL and '}{props.providername}{'.'}{'\n'}
|
||||
{'docker compose --file docker-compose-base.yaml --file docker-compose-'}{props.lower}{'.yaml down'}{'\n'}
|
||||
</CodeBlock>
|
@ -1,150 +0,0 @@
|
||||
## TLS mode external
|
||||
|
||||
```yaml
|
||||
entrypoints:
|
||||
web:
|
||||
address: ":80"
|
||||
websecure:
|
||||
address: ":443"
|
||||
tls:
|
||||
stores:
|
||||
default:
|
||||
defaultCertificate:
|
||||
providers:
|
||||
file:
|
||||
filename: /etc/traefik/traefik.yaml
|
||||
http:
|
||||
middlewares:
|
||||
zitadel:
|
||||
headers:
|
||||
isDevelopment: false
|
||||
allowedHosts:
|
||||
- 'localhost'
|
||||
customRequestHeaders:
|
||||
:authority: 'localhost'
|
||||
redirect-to-https:
|
||||
redirectScheme:
|
||||
scheme: https
|
||||
port: 443
|
||||
permanent: true
|
||||
routers:
|
||||
router0:
|
||||
entryPoints:
|
||||
- web
|
||||
middlewares:
|
||||
- redirect-to-https
|
||||
rule: 'HostRegexp(`localhost`, `{subdomain:[a-z]+}.localhost`)'
|
||||
service: zitadel
|
||||
router1:
|
||||
entryPoints:
|
||||
- websecure
|
||||
service: zitadel
|
||||
middlewares:
|
||||
- zitadel
|
||||
rule: 'HostRegexp(`localhost`, `{subdomain:[a-z]+}.localhost`)'
|
||||
tls:
|
||||
domains:
|
||||
- main: "localhost"
|
||||
sans:
|
||||
- "*.localhost"
|
||||
- "localhost"
|
||||
services:
|
||||
zitadel:
|
||||
loadBalancer:
|
||||
servers:
|
||||
- url: h2c://localhost:8080
|
||||
passHostHeader: true
|
||||
```
|
||||
|
||||
## TLS mode enabled
|
||||
|
||||
```yaml
|
||||
entrypoints:
|
||||
web:
|
||||
address: ":80"
|
||||
websecure:
|
||||
address: ":443"
|
||||
tls:
|
||||
stores:
|
||||
default:
|
||||
defaultCertificate:
|
||||
providers:
|
||||
file:
|
||||
filename: /etc/traefik/traefik.yaml
|
||||
http:
|
||||
middlewares:
|
||||
zitadel:
|
||||
headers:
|
||||
isDevelopment: false
|
||||
allowedHosts:
|
||||
- 'localhost'
|
||||
customRequestHeaders:
|
||||
:authority: 'localhost'
|
||||
redirect-to-https:
|
||||
redirectScheme:
|
||||
scheme: https
|
||||
port: 443
|
||||
permanent: true
|
||||
routers:
|
||||
router0:
|
||||
entryPoints:
|
||||
- web
|
||||
middlewares:
|
||||
- redirect-to-https
|
||||
rule: 'HostRegexp(`localhost`, `{subdomain:[a-z]+}.localhost`)'
|
||||
service: zitadel
|
||||
# The actual ZITADEL router
|
||||
router1:
|
||||
entryPoints:
|
||||
- websecure
|
||||
service: zitadel
|
||||
middlewares:
|
||||
- zitadel
|
||||
rule: 'HostRegexp(`localhost`, `{subdomain:[a-z]+}.localhost`)'
|
||||
tls:
|
||||
domains:
|
||||
- main: "localhost"
|
||||
sans:
|
||||
- "*.localhost"
|
||||
- "localhost"
|
||||
services:
|
||||
zitadel:
|
||||
loadBalancer:
|
||||
servers:
|
||||
- url: https://localhost:8080
|
||||
passHostHeader: true
|
||||
```
|
||||
|
||||
## TLS mode disabled
|
||||
|
||||
```yaml
|
||||
entrypoints:
|
||||
web:
|
||||
address: ":80"
|
||||
providers:
|
||||
file:
|
||||
filename: /etc/traefik/traefik.yaml
|
||||
http:
|
||||
middlewares:
|
||||
zitadel:
|
||||
headers:
|
||||
isDevelopment: false
|
||||
allowedHosts:
|
||||
- 'localhost'
|
||||
customRequestHeaders:
|
||||
:authority: 'localhost'
|
||||
routers:
|
||||
router0:
|
||||
entryPoints:
|
||||
- web
|
||||
middlewares:
|
||||
- redirect-to-https
|
||||
rule: 'HostRegexp(`localhost`, `{subdomain:[a-z]+}.localhost`)'
|
||||
service: zitadel
|
||||
services:
|
||||
zitadel:
|
||||
loadBalancer:
|
||||
servers:
|
||||
- url: h2c://localhost:8080
|
||||
passHostHeader: true
|
||||
```
|
38
docs/docs/self-hosting/manage/reverseproxy/caddy/caddy.mdx
Normal file
38
docs/docs/self-hosting/manage/reverseproxy/caddy/caddy.mdx
Normal file
@ -0,0 +1,38 @@
|
||||
---
|
||||
title: Configure ZITADEL with Caddy
|
||||
sidebar_label: Caddy
|
||||
---
|
||||
|
||||
import ProxyGuideOverview from '../_proxy_guide_overview.mdx';
|
||||
import ProxyGuideTLSMode from '../_proxy_guide_tls_mode.mdx';
|
||||
import ProxyGuideMore from '../_proxy_guide_more.mdx';
|
||||
import Compose from "!!raw-loader!./docker-compose.yaml";
|
||||
import ConfigDisabled from "!!raw-loader!./disabled-tls.Caddyfile";
|
||||
import ConfigExternal from "!!raw-loader!./external-tls.Caddyfile";
|
||||
import ConfigEnabled from "!!raw-loader!./enabled-tls.Caddyfile";
|
||||
|
||||
export const providername = 'Caddy';
|
||||
export const lower = "caddy";
|
||||
export const link = <a href="https://caddyserver.com/">{providername}</a>
|
||||
|
||||
<ProxyGuideOverview link={link} compose={Compose}></ProxyGuideOverview>
|
||||
|
||||
You can either setup your environment for <a href={'#tls-mode-external'}>TLS mode external</a> or <a href={'#tls-mode-enabled'}>TLS mode enabled</a>.
|
||||
|
||||
<!-- grpc NOT WORKING
|
||||
## TLS mode disabled
|
||||
|
||||
<ProxyGuideTLSMode mode="disabled" configfilename="disabled-tls.Caddyfile" configfilecontent={ConfigDisabled} providername={providername} link={link} lower={lower}></ProxyGuideTLSMode>
|
||||
-->
|
||||
|
||||
## TLS mode external
|
||||
|
||||
<ProxyGuideTLSMode mode="external" configfilename="external-tls.Caddyfile" configfilecontent={ConfigExternal} providername={providername} link={link} lower={lower}></ProxyGuideTLSMode>
|
||||
|
||||
## TLS mode enabled
|
||||
|
||||
<ProxyGuideTLSMode mode="enabled" configfilename="enabled-tls.Caddyfile" configfilecontent={ConfigEnabled} providername={providername} link={link} lower={lower}></ProxyGuideTLSMode>
|
||||
|
||||
## More Information
|
||||
|
||||
<ProxyGuideMore></ProxyGuideMore>
|
@ -0,0 +1,3 @@
|
||||
http://127.0.0.1.sslip.io {
|
||||
reverse_proxy h2c://zitadel-disabled-tls:8080
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
|
||||
proxy-disabled-tls:
|
||||
image: "caddy:2.7.5-alpine"
|
||||
volumes:
|
||||
- "./disabled-tls.Caddyfile:/etc/caddy/Caddyfile:ro"
|
||||
ports:
|
||||
- "80:80"
|
||||
depends_on:
|
||||
zitadel-disabled-tls:
|
||||
condition: 'service_healthy'
|
||||
|
||||
proxy-external-tls:
|
||||
image: "caddy:2.7.5-alpine"
|
||||
volumes:
|
||||
- "./external-tls.Caddyfile:/etc/caddy/Caddyfile:ro"
|
||||
- "./selfsigned.crt:/etc/certs/selfsigned.crt:ro"
|
||||
- "./selfsigned.key:/etc/certs/selfsigned.key:ro"
|
||||
ports:
|
||||
- "443:443"
|
||||
depends_on:
|
||||
zitadel-external-tls:
|
||||
condition: 'service_healthy'
|
||||
|
||||
proxy-enabled-tls:
|
||||
image: "caddy:2.7.5-alpine"
|
||||
volumes:
|
||||
- "./enabled-tls.Caddyfile:/etc/caddy/Caddyfile:ro"
|
||||
- "./selfsigned.crt:/etc/certs/selfsigned.crt:ro"
|
||||
- "./selfsigned.key:/etc/certs/selfsigned.key:ro"
|
||||
ports:
|
||||
- "443:443"
|
||||
depends_on:
|
||||
zitadel-enabled-tls:
|
||||
condition: 'service_healthy'
|
@ -0,0 +1,8 @@
|
||||
https://127.0.0.1.sslip.io {
|
||||
tls /etc/certs/selfsigned.crt /etc/certs/selfsigned.key
|
||||
reverse_proxy https://zitadel-enabled-tls:8080 {
|
||||
transport http {
|
||||
tls_insecure_skip_verify
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
https://127.0.0.1.sslip.io {
|
||||
tls /etc/certs/selfsigned.crt /etc/certs/selfsigned.key
|
||||
reverse_proxy h2c://zitadel-external-tls:8080
|
||||
}
|
@ -1,3 +1,8 @@
|
||||
---
|
||||
title: Configure ZITADEL with Cloudflare
|
||||
sidebar_label: Cloudflare
|
||||
---
|
||||
|
||||
## Settings
|
||||
|
||||
- [Make sure HTTP/2 is enabled](https://support.cloudflare.com/hc/en-us/articles/200168076-Understanding-Cloudflare-HTTP-2-and-HTTP-3-Support)
|
@ -0,0 +1,8 @@
|
||||
---
|
||||
title: Configure ZITADEL with Cloudflare Tunnel
|
||||
sidebar_label: Cloudflare Tunnel
|
||||
---
|
||||
|
||||
:::caution
|
||||
|
||||
[The Cloudflare tunnel client currently has an issue which disallows it to force HTTP/2 usage towards the origin.](https://github.com/cloudflare/cloudflared/issues/682)
|
@ -0,0 +1,90 @@
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
|
||||
zitadel-disabled-tls:
|
||||
extends:
|
||||
service: zitadel-init
|
||||
command: 'start-from-setup --masterkey "MasterkeyNeedsToHave32Characters" --config /zitadel.yaml --steps /zitadel.yaml'
|
||||
environment:
|
||||
- ZITADEL_EXTERNALPORT=80
|
||||
- ZITADEL_EXTERNALSECURE=false
|
||||
- ZITADEL_TLS_ENABLED=false
|
||||
depends_on:
|
||||
zitadel-init:
|
||||
condition: 'service_completed_successfully'
|
||||
db:
|
||||
condition: 'service_healthy'
|
||||
|
||||
zitadel-external-tls:
|
||||
extends:
|
||||
service: zitadel-init
|
||||
command: 'start-from-setup --masterkey "MasterkeyNeedsToHave32Characters" --config /zitadel.yaml --steps /zitadel.yaml'
|
||||
environment:
|
||||
- ZITADEL_EXTERNALPORT=443
|
||||
- ZITADEL_EXTERNALSECURE=true
|
||||
- ZITADEL_TLS_ENABLED=false
|
||||
depends_on:
|
||||
zitadel-init:
|
||||
condition: 'service_completed_successfully'
|
||||
db:
|
||||
condition: 'service_healthy'
|
||||
|
||||
zitadel-enabled-tls:
|
||||
extends:
|
||||
service: zitadel-init
|
||||
command: 'start-from-setup --masterkey "MasterkeyNeedsToHave32Characters" --config /zitadel.yaml --steps /zitadel.yaml'
|
||||
environment:
|
||||
- ZITADEL_EXTERNALPORT=443
|
||||
- ZITADEL_EXTERNALSECURE=true
|
||||
- ZITADEL_TLS_ENABLED=true
|
||||
- ZITADEL_TLS_CERTPATH=/etc/certs/selfsigned.crt
|
||||
- ZITADEL_TLS_KEYPATH=/etc/certs/selfsigned.key
|
||||
volumes:
|
||||
- ./selfsigned.crt:/etc/certs/selfsigned.crt
|
||||
- ./selfsigned.key:/etc/certs/selfsigned.key
|
||||
depends_on:
|
||||
zitadel-init:
|
||||
condition: 'service_completed_successfully'
|
||||
db:
|
||||
condition: 'service_healthy'
|
||||
|
||||
zitadel-init:
|
||||
user: '$UID'
|
||||
image: '${ZITADEL_IMAGE:-ghcr.io/zitadel/zitadel:latest}'
|
||||
command: 'init --config /zitadel.yaml'
|
||||
depends_on:
|
||||
db:
|
||||
condition: 'service_healthy'
|
||||
environment:
|
||||
# Using an external domain other than localhost proofs, that the proxy configuration works.
|
||||
# If ZITADEL can't resolve a requests original host to this domain,
|
||||
# it will return a 404 Instance not found error.
|
||||
- ZITADEL_EXTERNALDOMAIN=127.0.0.1.sslip.io
|
||||
# ZITADEL accesses the database via the docker network.
|
||||
- ZITADEL_DATABASE_COCKROACH_HOST=db
|
||||
# In case something doesn't work as expected,
|
||||
# it can be handy to be able to read the access logs.
|
||||
- ZITADEL_LOGSTORE_ACCESS_STDOUT_ENABLED=true
|
||||
# For convenience, ZITADEL should not ask to change the initial admin users password.
|
||||
- ZITADEL_FIRSTINSTANCE_ORG_HUMAN_PASSWORDCHANGEREQUIRED=false
|
||||
healthcheck:
|
||||
test: ["CMD", "/app/zitadel", "ready"]
|
||||
interval: '10s'
|
||||
timeout: '5s'
|
||||
retries: 5
|
||||
start_period: '10s'
|
||||
|
||||
db:
|
||||
restart: 'always'
|
||||
image: 'cockroachdb/cockroach:latest'
|
||||
command: 'start-single-node --insecure --http-addr :9090'
|
||||
healthcheck:
|
||||
test: ['CMD', 'curl', '-f', 'http://localhost:9090/health?ready=1']
|
||||
interval: '10s'
|
||||
timeout: '30s'
|
||||
retries: 5
|
||||
start_period: '20s'
|
||||
ports:
|
||||
- "26257:26257"
|
||||
- "9090:9090"
|
@ -0,0 +1,37 @@
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
|
||||
proxy-disabled-tls:
|
||||
image: "httpd:2.4.58-alpine"
|
||||
volumes:
|
||||
- "./httpd-disabled-tls.conf:/usr/local/apache2/conf/httpd.conf"
|
||||
ports:
|
||||
- "80:80"
|
||||
depends_on:
|
||||
zitadel-disabled-tls:
|
||||
condition: 'service_healthy'
|
||||
|
||||
proxy-external-tls:
|
||||
image: "httpd:2.4.58-alpine"
|
||||
volumes:
|
||||
- "./httpd-external-tls.conf:/usr/local/apache2/conf/httpd.conf"
|
||||
- "./selfsigned.crt:/etc/certs/selfsigned.crt:ro"
|
||||
- "./selfsigned.key:/etc/certs/selfsigned.key:ro"
|
||||
ports:
|
||||
- "443:443"
|
||||
depends_on:
|
||||
zitadel-external-tls:
|
||||
condition: 'service_healthy'
|
||||
|
||||
proxy-enabled-tls:
|
||||
image: "httpd:2.4.58-alpine"
|
||||
volumes:
|
||||
- "./httpd-enabled-tls.conf:/usr/local/apache2/conf/httpd.conf"
|
||||
- "./selfsigned.crt:/etc/certs/selfsigned.crt:ro"
|
||||
- "./selfsigned.key:/etc/certs/selfsigned.key:ro"
|
||||
ports:
|
||||
- "443:443"
|
||||
depends_on:
|
||||
zitadel-enabled-tls:
|
||||
condition: 'service_healthy'
|
@ -0,0 +1,39 @@
|
||||
LoadModule mpm_event_module modules/mod_mpm_event.so
|
||||
LoadModule authn_file_module modules/mod_authn_file.so
|
||||
LoadModule authn_core_module modules/mod_authn_core.so
|
||||
LoadModule authz_host_module modules/mod_authz_host.so
|
||||
LoadModule authz_groupfile_module modules/mod_authz_groupfile.so
|
||||
LoadModule authz_user_module modules/mod_authz_user.so
|
||||
LoadModule authz_core_module modules/mod_authz_core.so
|
||||
LoadModule access_compat_module modules/mod_access_compat.so
|
||||
LoadModule auth_basic_module modules/mod_auth_basic.so
|
||||
LoadModule reqtimeout_module modules/mod_reqtimeout.so
|
||||
LoadModule filter_module modules/mod_filter.so
|
||||
LoadModule mime_module modules/mod_mime.so
|
||||
LoadModule log_config_module modules/mod_log_config.so
|
||||
LoadModule env_module modules/mod_env.so
|
||||
LoadModule headers_module modules/mod_headers.so
|
||||
LoadModule setenvif_module modules/mod_setenvif.so
|
||||
LoadModule version_module modules/mod_version.so
|
||||
LoadModule proxy_module modules/mod_proxy.so
|
||||
LoadModule proxy_http_module modules/mod_proxy_http.so
|
||||
LoadModule ssl_module modules/mod_ssl.so
|
||||
LoadModule proxy_http2_module modules/mod_proxy_http2.so
|
||||
LoadModule unixd_module modules/mod_unixd.so
|
||||
LoadModule status_module modules/mod_status.so
|
||||
LoadModule autoindex_module modules/mod_autoindex.so
|
||||
LoadModule dir_module modules/mod_dir.so
|
||||
LoadModule alias_module modules/mod_alias.so
|
||||
LoadModule rewrite_module modules/mod_rewrite.so
|
||||
|
||||
ServerRoot "/usr/local/apache2"
|
||||
LogLevel debug
|
||||
ErrorLog /proc/self/fd/2
|
||||
CustomLog /proc/self/fd/1 "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\""
|
||||
|
||||
Listen 80
|
||||
|
||||
<VirtualHost *:80>
|
||||
ProxyPass / h2c://zitadel-disabled-tls:8080/
|
||||
ProxyPreserveHost on
|
||||
</VirtualHost>
|
@ -0,0 +1,47 @@
|
||||
LoadModule mpm_event_module modules/mod_mpm_event.so
|
||||
LoadModule authn_file_module modules/mod_authn_file.so
|
||||
LoadModule authn_core_module modules/mod_authn_core.so
|
||||
LoadModule authz_host_module modules/mod_authz_host.so
|
||||
LoadModule authz_groupfile_module modules/mod_authz_groupfile.so
|
||||
LoadModule authz_user_module modules/mod_authz_user.so
|
||||
LoadModule authz_core_module modules/mod_authz_core.so
|
||||
LoadModule access_compat_module modules/mod_access_compat.so
|
||||
LoadModule auth_basic_module modules/mod_auth_basic.so
|
||||
LoadModule reqtimeout_module modules/mod_reqtimeout.so
|
||||
LoadModule filter_module modules/mod_filter.so
|
||||
LoadModule mime_module modules/mod_mime.so
|
||||
LoadModule log_config_module modules/mod_log_config.so
|
||||
LoadModule env_module modules/mod_env.so
|
||||
LoadModule headers_module modules/mod_headers.so
|
||||
LoadModule setenvif_module modules/mod_setenvif.so
|
||||
LoadModule version_module modules/mod_version.so
|
||||
LoadModule proxy_module modules/mod_proxy.so
|
||||
LoadModule proxy_http_module modules/mod_proxy_http.so
|
||||
LoadModule ssl_module modules/mod_ssl.so
|
||||
LoadModule proxy_http2_module modules/mod_proxy_http2.so
|
||||
LoadModule unixd_module modules/mod_unixd.so
|
||||
LoadModule status_module modules/mod_status.so
|
||||
LoadModule autoindex_module modules/mod_autoindex.so
|
||||
LoadModule dir_module modules/mod_dir.so
|
||||
LoadModule alias_module modules/mod_alias.so
|
||||
LoadModule rewrite_module modules/mod_rewrite.so
|
||||
LoadModule http2_module modules/mod_http2.so
|
||||
|
||||
ServerRoot "/usr/local/apache2"
|
||||
LogLevel debug
|
||||
ErrorLog /proc/self/fd/2
|
||||
CustomLog /proc/self/fd/1 "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\""
|
||||
|
||||
Listen 443
|
||||
|
||||
SSLRandomSeed startup builtin
|
||||
SSLRandomSeed connect builtin
|
||||
|
||||
<VirtualHost *:443>
|
||||
ProxyPass / h2://zitadel-enabled-tls:8080/
|
||||
ProxyPreserveHost on
|
||||
SSLEngine on
|
||||
SSLProxyEngine on
|
||||
SSLCertificateFile /etc/certs/selfsigned.crt
|
||||
SSLCertificateKeyFile /etc/certs/selfsigned.key
|
||||
</VirtualHost>
|
@ -0,0 +1,43 @@
|
||||
LoadModule mpm_event_module modules/mod_mpm_event.so
|
||||
LoadModule authn_file_module modules/mod_authn_file.so
|
||||
LoadModule authn_core_module modules/mod_authn_core.so
|
||||
LoadModule authz_host_module modules/mod_authz_host.so
|
||||
LoadModule authz_groupfile_module modules/mod_authz_groupfile.so
|
||||
LoadModule authz_user_module modules/mod_authz_user.so
|
||||
LoadModule authz_core_module modules/mod_authz_core.so
|
||||
LoadModule access_compat_module modules/mod_access_compat.so
|
||||
LoadModule auth_basic_module modules/mod_auth_basic.so
|
||||
LoadModule reqtimeout_module modules/mod_reqtimeout.so
|
||||
LoadModule filter_module modules/mod_filter.so
|
||||
LoadModule mime_module modules/mod_mime.so
|
||||
LoadModule log_config_module modules/mod_log_config.so
|
||||
LoadModule env_module modules/mod_env.so
|
||||
LoadModule headers_module modules/mod_headers.so
|
||||
LoadModule setenvif_module modules/mod_setenvif.so
|
||||
LoadModule version_module modules/mod_version.so
|
||||
LoadModule proxy_module modules/mod_proxy.so
|
||||
LoadModule proxy_http_module modules/mod_proxy_http.so
|
||||
LoadModule ssl_module modules/mod_ssl.so
|
||||
LoadModule proxy_http2_module modules/mod_proxy_http2.so
|
||||
LoadModule unixd_module modules/mod_unixd.so
|
||||
LoadModule status_module modules/mod_status.so
|
||||
LoadModule autoindex_module modules/mod_autoindex.so
|
||||
LoadModule dir_module modules/mod_dir.so
|
||||
LoadModule alias_module modules/mod_alias.so
|
||||
LoadModule rewrite_module modules/mod_rewrite.so
|
||||
LoadModule http2_module modules/mod_http2.so
|
||||
|
||||
LogLevel debug
|
||||
ErrorLog /proc/self/fd/2
|
||||
CustomLog /proc/self/fd/1 "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\""
|
||||
|
||||
Listen 443
|
||||
|
||||
<VirtualHost *:443>
|
||||
ProxyPass / h2c://zitadel-external-tls:8080/
|
||||
ProxyPassReverse / h2c://zitadel-external-tls:8080/
|
||||
ProxyPreserveHost on
|
||||
SSLEngine on
|
||||
SSLCertificateFile /etc/certs/selfsigned.crt
|
||||
SSLCertificateKeyFile /etc/certs/selfsigned.key
|
||||
</VirtualHost>
|
38
docs/docs/self-hosting/manage/reverseproxy/httpd/httpd.mdx
Normal file
38
docs/docs/self-hosting/manage/reverseproxy/httpd/httpd.mdx
Normal file
@ -0,0 +1,38 @@
|
||||
---
|
||||
title: Configure ZITADEL with Apache httpd
|
||||
sidebar_label: Apache httpd
|
||||
---
|
||||
|
||||
import ProxyGuideOverview from '../_proxy_guide_overview.mdx';
|
||||
import ProxyGuideTLSMode from '../_proxy_guide_tls_mode.mdx';
|
||||
import Compose from "!!raw-loader!./docker-compose.yaml";
|
||||
import ConfigDisabled from "!!raw-loader!./httpd-disabled-tls.conf";
|
||||
import ConfigExternal from "!!raw-loader!./httpd-external-tls.conf";
|
||||
import ConfigEnabled from "!!raw-loader!./httpd-enabled-tls.conf";
|
||||
|
||||
export const providername = "Apache httpd";
|
||||
export const lower = "httpd";
|
||||
export const link = <a href="https://httpd.apache.org//">{providername}</a>
|
||||
|
||||
<ProxyGuideOverview link={link} compose={Compose}></ProxyGuideOverview>
|
||||
|
||||
You can either setup your environment for <a href={'#tls-mode-disabled'}>TLS mode disabled</a>, <a href={'#tls-mode-external'}>TLS mode external</a> or <a href={'#tls-mode-enabled'}>TLS mode enabled</a>.
|
||||
|
||||
## TLS mode disabled
|
||||
|
||||
<!-- grpc NOT WORKING -->
|
||||
<ProxyGuideTLSMode mode="disabled" configfilename="httpd-disabled-tls.conf" configfilecontent={ConfigDisabled} providername={providername} link={link} lower={lower}></ProxyGuideTLSMode>
|
||||
|
||||
## TLS mode external
|
||||
|
||||
<!-- grpc NOT WORKING -->
|
||||
<ProxyGuideTLSMode mode="external" configfilename="httpd-external-tls.conf" configfilecontent={ConfigExternal} providername={providername} link={link} lower={lower}></ProxyGuideTLSMode>
|
||||
|
||||
## TLS mode enabled
|
||||
|
||||
<!-- grpc NOT WORKING -->
|
||||
<ProxyGuideTLSMode mode="enabled" configfilename="httpd-enabled-tls.conf" configfilecontent={ConfigEnabled} providername={providername} link={link} lower={lower}></ProxyGuideTLSMode>
|
||||
|
||||
## More Information
|
||||
|
||||
<ProxyGuideMore></ProxyGuideMore>
|
@ -0,0 +1,37 @@
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
|
||||
proxy-disabled-tls:
|
||||
image: "nginx:1.25.3-alpine"
|
||||
volumes:
|
||||
- "./nginx-disabled-tls.conf:/etc/nginx/nginx.conf:ro"
|
||||
ports:
|
||||
- "80:80"
|
||||
depends_on:
|
||||
zitadel-disabled-tls:
|
||||
condition: 'service_healthy'
|
||||
|
||||
proxy-external-tls:
|
||||
image: "nginx:1.25.3-alpine"
|
||||
volumes:
|
||||
- "./nginx-external-tls.conf:/etc/nginx/nginx.conf:ro"
|
||||
- "./selfsigned.crt:/etc/certs/selfsigned.crt:ro"
|
||||
- "./selfsigned.key:/etc/certs/selfsigned.key:ro"
|
||||
ports:
|
||||
- "443:443"
|
||||
depends_on:
|
||||
zitadel-external-tls:
|
||||
condition: 'service_healthy'
|
||||
|
||||
proxy-enabled-tls:
|
||||
image: "nginx:1.25.3-alpine"
|
||||
volumes:
|
||||
- "./nginx-enabled-tls.conf:/etc/nginx/nginx.conf:ro"
|
||||
- "./selfsigned.crt:/etc/certs/selfsigned.crt:ro"
|
||||
- "./selfsigned.key:/etc/certs/selfsigned.key:ro"
|
||||
ports:
|
||||
- "443:443"
|
||||
depends_on:
|
||||
zitadel-enabled-tls:
|
||||
condition: 'service_healthy'
|
@ -0,0 +1,13 @@
|
||||
events {
|
||||
worker_connections 1024;
|
||||
}
|
||||
http {
|
||||
server {
|
||||
listen 80;
|
||||
http2 on;
|
||||
location / {
|
||||
grpc_pass grpc://zitadel-disabled-tls:8080;
|
||||
grpc_set_header Host $host:$server_port;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
events {
|
||||
worker_connections 1024;
|
||||
}
|
||||
http {
|
||||
server {
|
||||
listen 443 ssl;
|
||||
http2 on;
|
||||
ssl_certificate /etc/certs/selfsigned.crt;
|
||||
ssl_certificate_key /etc/certs/selfsigned.key;
|
||||
location / {
|
||||
grpc_pass grpcs://zitadel-enabled-tls:8080;
|
||||
grpc_set_header Host $host:$server_port;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
events {
|
||||
worker_connections 1024;
|
||||
}
|
||||
http {
|
||||
server {
|
||||
listen 443 ssl;
|
||||
http2 on;
|
||||
ssl_certificate /etc/certs/selfsigned.crt;
|
||||
ssl_certificate_key /etc/certs/selfsigned.key;
|
||||
location / {
|
||||
grpc_pass grpc://zitadel-external-tls:8080;
|
||||
grpc_set_header Host $host:$server_port;
|
||||
}
|
||||
}
|
||||
}
|
35
docs/docs/self-hosting/manage/reverseproxy/nginx/nginx.mdx
Normal file
35
docs/docs/self-hosting/manage/reverseproxy/nginx/nginx.mdx
Normal file
@ -0,0 +1,35 @@
|
||||
---
|
||||
title: Configure ZITADEL with NGINX
|
||||
sidebar_label: NGINX
|
||||
---
|
||||
|
||||
import ProxyGuideOverview from '../_proxy_guide_overview.mdx';
|
||||
import ProxyGuideTLSMode from '../_proxy_guide_tls_mode.mdx';
|
||||
import Compose from "!!raw-loader!./docker-compose.yaml";
|
||||
import ConfigDisabled from "!!raw-loader!./nginx-disabled-tls.conf";
|
||||
import ConfigExternal from "!!raw-loader!./nginx-external-tls.conf";
|
||||
import ConfigEnabled from "!!raw-loader!./nginx-enabled-tls.conf";
|
||||
|
||||
export const providername = 'NGINX';
|
||||
export const lower = "nginx";
|
||||
export const link = <a href="https://nginx.com/">{providername}</a>;
|
||||
|
||||
<ProxyGuideOverview link={link} compose={Compose}></ProxyGuideOverview>
|
||||
|
||||
You can either setup your environment for <a href={'#tls-mode-disabled'}>TLS mode disabled</a>, <a href={'#tls-mode-external'}>TLS mode external</a> or <a href={'#tls-mode-enabled'}>TLS mode enabled</a>.
|
||||
|
||||
## TLS mode disabled
|
||||
|
||||
<ProxyGuideTLSMode mode="disabled" configfilename="nginx-disabled-tls.conf" configfilecontent={ConfigDisabled} providername={providername} link={link} lower={lower}></ProxyGuideTLSMode>
|
||||
|
||||
## TLS mode external
|
||||
|
||||
<ProxyGuideTLSMode mode="external" configfilename="nginx-external-tls.conf" configfilecontent={ConfigExternal} providername={providername} link={link} lower={lower}></ProxyGuideTLSMode>
|
||||
|
||||
## TLS mode enabled
|
||||
|
||||
<ProxyGuideTLSMode mode="enabled" configfilename="nginx-enabled-tls.conf" configfilecontent={ConfigEnabled} providername={providername} link={link} lower={lower}></ProxyGuideTLSMode>
|
||||
|
||||
## More Information
|
||||
|
||||
<ProxyGuideMore></ProxyGuideMore>
|
@ -2,58 +2,13 @@
|
||||
title: Reverse Proxy Configuration
|
||||
---
|
||||
|
||||
import Tabs from "@theme/Tabs";
|
||||
import TabItem from "@theme/TabItem";
|
||||
import Zcloud from "./_zitadel_cloud.mdx";
|
||||
import Nginx from "./_nginx.mdx";
|
||||
import Traefik from "./_traefik.mdx";
|
||||
import Caddy from "./_caddy.mdx";
|
||||
import Httpd from "./_httpd.mdx";
|
||||
import Cftunnel from "./_cloudflare_tunnel.mdx";
|
||||
import Cloudflare from "./_cloudflare.mdx";
|
||||
import More from "./_more.mdx";
|
||||
Check out one of the following guides to configure your favorite reverse proxy:
|
||||
|
||||
# Proxy Configuration
|
||||
- [Traefik](/self-hosting/manage/reverseproxy/traefik)
|
||||
- [NGINX](/self-hosting/manage/reverseproxy/nginx)
|
||||
- [Caddy](/self-hosting/manage/reverseproxy/caddy)
|
||||
<!-- grpc NOT WORKING - [Apache httpd](/self-hosting/manage/reverseproxy/httpd) -->
|
||||
- [Cloudflare](/self-hosting/manage/reverseproxy/cloudflare)
|
||||
- [Cloudflare Tunnel](/self-hosting/manage/reverseproxy/cloudflare_tunnel)
|
||||
- [Fronting ZITADEL Cloud](/self-hosting/manage/reverseproxy/zitadel_cloud)
|
||||
|
||||
<Tabs
|
||||
groupId="proxy-vendor"
|
||||
default="zcloud"
|
||||
values={[
|
||||
{ label: "ZITADEL Cloud", value: "zcloud" },
|
||||
{ label: "NGINX", value: "nginx" },
|
||||
{ label: "Traefik", value: "traefik" },
|
||||
{ label: "Caddy", value: "caddy" },
|
||||
{ label: "Apache httpd", value: "httpd" },
|
||||
{ label: "Cloudflare Tunnel", value: "cftunnel" },
|
||||
{ label: "Cloudflare", value: "cf" },
|
||||
]}
|
||||
>
|
||||
<TabItem value="zcloud">
|
||||
<Zcloud />
|
||||
<More />
|
||||
</TabItem>
|
||||
<TabItem value="nginx">
|
||||
<Nginx />
|
||||
<More />
|
||||
</TabItem>
|
||||
<TabItem value="traefik">
|
||||
<Traefik />
|
||||
<More />
|
||||
</TabItem>
|
||||
<TabItem value="caddy">
|
||||
<Caddy />
|
||||
<More />
|
||||
</TabItem>
|
||||
<TabItem value="httpd">
|
||||
<Httpd />
|
||||
<More />
|
||||
</TabItem>
|
||||
<TabItem value="cftunnel">
|
||||
<Cftunnel />
|
||||
<More />
|
||||
</TabItem>
|
||||
<TabItem value="cf">
|
||||
<Cloudflare />
|
||||
<More />
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
@ -0,0 +1,37 @@
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
|
||||
proxy-disabled-tls:
|
||||
image: "traefik:v2.10.5"
|
||||
volumes:
|
||||
- "./traefik-disabled-tls.yaml:/etc/traefik/traefik.yaml:ro"
|
||||
ports:
|
||||
- "80:80"
|
||||
depends_on:
|
||||
zitadel-disabled-tls:
|
||||
condition: 'service_healthy'
|
||||
|
||||
proxy-external-tls:
|
||||
image: "traefik:v2.10.5"
|
||||
volumes:
|
||||
- "./traefik-external-tls.yaml:/etc/traefik/traefik.yaml:ro"
|
||||
- "./selfsigned.crt:/etc/certs/selfsigned.crt:ro"
|
||||
- "./selfsigned.key:/etc/certs/selfsigned.key:ro"
|
||||
ports:
|
||||
- "443:443"
|
||||
depends_on:
|
||||
zitadel-external-tls:
|
||||
condition: 'service_healthy'
|
||||
|
||||
proxy-enabled-tls:
|
||||
image: "traefik:v2.10.5"
|
||||
volumes:
|
||||
- "./traefik-enabled-tls.yaml:/etc/traefik/traefik.yaml:ro"
|
||||
- "./selfsigned.crt:/etc/certs/selfsigned.crt:ro"
|
||||
- "./selfsigned.key:/etc/certs/selfsigned.key:ro"
|
||||
ports:
|
||||
- "443:443"
|
||||
depends_on:
|
||||
zitadel-enabled-tls:
|
||||
condition: 'service_healthy'
|
@ -0,0 +1,20 @@
|
||||
log:
|
||||
level: "DEBUG"
|
||||
providers:
|
||||
file:
|
||||
filename: "/etc/traefik/traefik.yaml"
|
||||
entrypoints:
|
||||
web:
|
||||
address: ":80"
|
||||
http:
|
||||
routers:
|
||||
router:
|
||||
entryPoints:
|
||||
- "web"
|
||||
service: "zitadel"
|
||||
rule: 'PathPrefix(`/`)'
|
||||
services:
|
||||
zitadel:
|
||||
loadBalancer:
|
||||
servers:
|
||||
- url: "h2c://zitadel-disabled-tls:8080"
|
@ -0,0 +1,31 @@
|
||||
log:
|
||||
level: "DEBUG"
|
||||
providers:
|
||||
file:
|
||||
filename: "/etc/traefik/traefik.yaml"
|
||||
entrypoints:
|
||||
web:
|
||||
address: ":443"
|
||||
http:
|
||||
routers:
|
||||
router:
|
||||
entryPoints:
|
||||
- "web"
|
||||
service: "zitadel"
|
||||
rule: 'PathPrefix(`/`)'
|
||||
tls: {}
|
||||
services:
|
||||
zitadel:
|
||||
loadBalancer:
|
||||
serversTransport: "zitadel"
|
||||
servers:
|
||||
- url: "https://zitadel-enabled-tls:8080"
|
||||
serversTransports:
|
||||
zitadel:
|
||||
insecureSkipVerify: true
|
||||
tls:
|
||||
stores:
|
||||
default:
|
||||
defaultCertificate:
|
||||
certFile: /etc/certs/selfsigned.crt
|
||||
keyFile: /etc/certs/selfsigned.key
|
@ -0,0 +1,27 @@
|
||||
log:
|
||||
level: "DEBUG"
|
||||
providers:
|
||||
file:
|
||||
filename: "/etc/traefik/traefik.yaml"
|
||||
entrypoints:
|
||||
web:
|
||||
address: ":443"
|
||||
http:
|
||||
routers:
|
||||
router:
|
||||
entryPoints:
|
||||
- "web"
|
||||
service: "zitadel"
|
||||
rule: 'PathPrefix(`/`)'
|
||||
tls: {}
|
||||
services:
|
||||
zitadel:
|
||||
loadBalancer:
|
||||
servers:
|
||||
- url: "h2c://zitadel-external-tls:8080"
|
||||
tls:
|
||||
stores:
|
||||
default:
|
||||
defaultCertificate:
|
||||
certFile: /etc/certs/selfsigned.crt
|
||||
keyFile: /etc/certs/selfsigned.key
|
@ -0,0 +1,35 @@
|
||||
---
|
||||
title: Configure ZITADEL with Traefik
|
||||
sidebar_label: Traefik
|
||||
---
|
||||
|
||||
import ProxyGuideOverview from '../_proxy_guide_overview.mdx';
|
||||
import ProxyGuideTLSMode from '../_proxy_guide_tls_mode.mdx';
|
||||
import Compose from "!!raw-loader!./docker-compose.yaml";
|
||||
import ConfigDisabled from "!!raw-loader!./traefik-disabled-tls.yaml";
|
||||
import ConfigExternal from "!!raw-loader!./traefik-external-tls.yaml";
|
||||
import ConfigEnabled from "!!raw-loader!./traefik-enabled-tls.yaml";
|
||||
|
||||
export const providername = 'Traefik';
|
||||
export const lower = "traefik";
|
||||
export const link = <a href="https://doc.traefik.io/traefik/">{providername}</a>;
|
||||
|
||||
<ProxyGuideOverview link={link} compose={Compose}></ProxyGuideOverview>
|
||||
|
||||
You can either setup your environment for <a href={'#tls-mode-disabled'}>TLS mode disabled</a>, <a href={'#tls-mode-external'}>TLS mode external</a> or <a href={'#tls-mode-enabled'}>TLS mode enabled</a>.
|
||||
|
||||
## TLS mode disabled
|
||||
|
||||
<ProxyGuideTLSMode mode="disabled" configfilename="traefik-disabled-tls.yaml" configfilecontent={ConfigDisabled} providername={providername} link={link} lower={lower}></ProxyGuideTLSMode>
|
||||
|
||||
## TLS mode external
|
||||
|
||||
<ProxyGuideTLSMode mode="external" configfilename="traefik-external-tls.yaml" configfilecontent={ConfigExternal} providername={providername} link={link} lower={lower}></ProxyGuideTLSMode>
|
||||
|
||||
## TLS mode enabled
|
||||
|
||||
<ProxyGuideTLSMode mode="enabled" configfilename="traefik-enabled-tls.yaml" configfilecontent={ConfigEnabled} providername={providername} link={link} lower={lower}></ProxyGuideTLSMode>
|
||||
|
||||
## More Information
|
||||
|
||||
<ProxyGuideMore></ProxyGuideMore>
|
@ -1,3 +1,8 @@
|
||||
---
|
||||
title: Front ZITADEL Cloud with a CDN, WAF or Reverse Proxy
|
||||
sidebar_label: Fronting ZITADEL Cloud
|
||||
---
|
||||
|
||||
## Fronting ZITADEL Cloud
|
||||
|
||||
You can use your reverseproxy, content delivery network (CDN) or web application firewall (WAF) to front ZITADEL Cloud.
|
@ -2,8 +2,8 @@
|
||||
title: TLS Modes
|
||||
---
|
||||
|
||||
To allow ZITADEL to be run on any kind of infrastructure it allows to configure on how tho handle TLS connections.
|
||||
There are three mode of operation: `external`, `enabled`, `disabled`.
|
||||
To run ZITADEL on any kind of infrastructure, you can configure on how to handle TLS connections.
|
||||
There are three modes of operation: `disabled`, `external`, `enabled`.
|
||||
|
||||
Generally this command is set as argument while starting ZITADEL. For example like this:
|
||||
|
||||
@ -11,6 +11,16 @@ Generally this command is set as argument while starting ZITADEL. For example li
|
||||
zitadel start-from-init --masterkey "MasterkeyNeedsToHave32Characters" --tlsMode disabled
|
||||
```
|
||||
|
||||
## Disabled
|
||||
|
||||
With the mode `disabled`, you instruct ZITADEL to await all connections with plain http without TLS.
|
||||
|
||||
:::caution
|
||||
|
||||
Be aware this is not a secure setup and should only be used for test systems!
|
||||
|
||||
:::
|
||||
|
||||
## External
|
||||
|
||||
The mode `external` allows you to configure ZITADEL in such a way that it will instruct its clients to use https.
|
||||
@ -19,8 +29,8 @@ However ZITADEL delegates the management of TLS connections to a reverseproxy, w
|
||||
## Enabled
|
||||
|
||||
When using the mode `enabled` ZITADEL is setup to await incoming connections in an encrypted fashion.
|
||||
Wether it is from a client directly, a reverseproxy or web application firewall.
|
||||
This allows http connections to be secured at the transport level the whole way.
|
||||
Whether it is from a client directly, a reverse proxy or web application firewall.
|
||||
This allows HTTP connections to be secured at the transport level the whole way.
|
||||
|
||||
If you use the mode `enabled` you need to configure ZITADEL with the necessary TLS settings.
|
||||
|
||||
@ -42,17 +52,10 @@ TLS:
|
||||
Cert: #<bas64 encoded content of a pem file>
|
||||
```
|
||||
|
||||
## Disabled
|
||||
## More Information
|
||||
|
||||
With the mode `disabled` ZITADEL is instructed to await all connections with plain http without TLS.
|
||||
Beware that ZITADEL uses HTTP/2 for all its connections.
|
||||
If you are using the mode `external` or `disabled` make sure to verify h2c compatibility.
|
||||
|
||||
:::caution
|
||||
|
||||
Be aware this is not a secure setup and should only be used for test systems!
|
||||
|
||||
:::
|
||||
|
||||
## HTTP/2
|
||||
|
||||
To allow ZITADEL to function properly please make sure that HTTP/2 is enabled. If you are using the mode `external` or `disabled` make sure to verify h2c compatibilty.
|
||||
You can read more about how ZITADEL utilizes in our [HTTP/2 docs](/self-hosting/manage/http2).
|
||||
- [Read more abouth how ZITADEL utilizes HTTP/2](/self-hosting/manage/http2).
|
||||
- [Explore some concrete proxy configuration examples for ZITADEL](/self-hosting/manage/reverseproxy/reverse_proxy).
|
||||
|
@ -61,6 +61,8 @@ ZITADEL uses the privileged and preexisting database user configured in `Databas
|
||||
- If not already done, it grants the necessary permissions ZITADEL needs to the non privileged user.
|
||||
- If they don’t exist already, it creates all schemas and some basic tables.
|
||||
|
||||
The init phase is idempotent if executed with the same binary version.
|
||||
|
||||
### The Setup Phase
|
||||
|
||||
During `zitadel setup`, ZITADEL creates projection tables and migrates existing data.
|
||||
@ -70,7 +72,10 @@ When deploying a new ZITADEL version,
|
||||
make sure the setup phase runs before you roll out the new `zitadel start` processes.
|
||||
The setup phase is executed in subsequent steps
|
||||
whereas a new version's execution takes over where the last execution stopped.
|
||||
Therefore, configuration changes relevant for the setup phase won’t take effect in regard to the setup execution.
|
||||
|
||||
Some configuration changes are only applied during the setup phase, like ExternalDomain, ExternalPort and ExternalSecure.
|
||||
|
||||
The setup phase is idempotent if executed with the same binary version.
|
||||
|
||||
### The Runtime Phase
|
||||
|
||||
|
@ -4,7 +4,7 @@ title: Technical Advisory 10002
|
||||
|
||||
## Date and Version
|
||||
|
||||
Version: TBD
|
||||
Version: 2.40.0
|
||||
|
||||
Date: Calendar week 44
|
||||
|
||||
|
@ -67,7 +67,7 @@ We understand that these advisories may include breaking changes, and we aim to
|
||||
facing UI yourself and not use ZITADELs console UI.
|
||||
ZITADEL hosted Login-UI is not affected by this change.
|
||||
</td>
|
||||
<td>TBD</td>
|
||||
<td>2.40.0</td>
|
||||
<td>Calendar week 44</td>
|
||||
</tr>
|
||||
<tr>
|
||||
|
@ -658,7 +658,24 @@ module.exports = {
|
||||
"self-hosting/manage/production",
|
||||
"self-hosting/manage/productionchecklist",
|
||||
"self-hosting/manage/configure/configure",
|
||||
"self-hosting/manage/reverseproxy/reverse_proxy",
|
||||
{
|
||||
type: "category",
|
||||
collapsed: false,
|
||||
label: "Reverse Proxy",
|
||||
link: {
|
||||
type: "doc",
|
||||
id: "self-hosting/manage/reverseproxy/reverse_proxy",
|
||||
},
|
||||
items: [
|
||||
"self-hosting/manage/reverseproxy/traefik/traefik",
|
||||
"self-hosting/manage/reverseproxy/nginx/nginx",
|
||||
"self-hosting/manage/reverseproxy/caddy/caddy",
|
||||
// "self-hosting/manage/reverseproxy/httpd/httpd", grpc NOT WORKING
|
||||
"self-hosting/manage/reverseproxy/cloudflare/cloudflare",
|
||||
"self-hosting/manage/reverseproxy/cloudflare_tunnel/cloudflare_tunnel",
|
||||
"self-hosting/manage/reverseproxy/zitadel_cloud/zitadel_cloud",
|
||||
],
|
||||
},
|
||||
"self-hosting/manage/custom-domain",
|
||||
"self-hosting/manage/http2",
|
||||
"self-hosting/manage/tls_modes",
|
||||
|
@ -22,7 +22,7 @@ services:
|
||||
ports:
|
||||
- "8080:8080"
|
||||
healthcheck:
|
||||
test: ["CMD", "/app/zitadel", "ready"]
|
||||
test: ["CMD", "/app/zitadel", "ready", "--config", "/zitadel.yaml" ]
|
||||
interval: '10s'
|
||||
timeout: '5s'
|
||||
retries: 5
|
||||
|
@ -63,7 +63,7 @@ func New(
|
||||
}
|
||||
|
||||
api.grpcServer = server.CreateServer(api.verifier, authZ, queries, http2HostName, tlsConfig, accessInterceptor.AccessService())
|
||||
api.grpcGateway, err = server.CreateGateway(ctx, port, http1HostName, accessInterceptor)
|
||||
api.grpcGateway, err = server.CreateGateway(ctx, port, http1HostName, accessInterceptor, tlsConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -80,7 +80,7 @@ func New(
|
||||
// creates a new grpc gateway and registers it as a separate http handler
|
||||
//
|
||||
// used for v1 api (system, admin, mgmt, auth)
|
||||
func (a *API) RegisterServer(ctx context.Context, grpcServer server.WithGatewayPrefix) error {
|
||||
func (a *API) RegisterServer(ctx context.Context, grpcServer server.WithGatewayPrefix, tlsConfig *tls.Config) error {
|
||||
grpcServer.RegisterServer(a.grpcServer)
|
||||
handler, prefix, err := server.CreateGatewayWithPrefix(
|
||||
ctx,
|
||||
@ -89,6 +89,7 @@ func (a *API) RegisterServer(ctx context.Context, grpcServer server.WithGatewayP
|
||||
a.http1HostName,
|
||||
a.accessInterceptor,
|
||||
a.queries,
|
||||
tlsConfig,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -60,7 +60,6 @@ func eventRequestToFilter(ctx context.Context, req *admin_pb.ListEventsRequest)
|
||||
AwaitOpenTransactions().
|
||||
ResourceOwner(req.ResourceOwner).
|
||||
EditorUser(req.EditorUserId).
|
||||
CreationDateAfter(req.CreationDate.AsTime()).
|
||||
SequenceGreater(req.Sequence)
|
||||
|
||||
if len(aggregateIDs) > 0 || len(aggregateTypes) > 0 || len(eventTypes) > 0 {
|
||||
@ -71,8 +70,11 @@ func eventRequestToFilter(ctx context.Context, req *admin_pb.ListEventsRequest)
|
||||
Builder()
|
||||
}
|
||||
|
||||
if req.Asc {
|
||||
if req.GetAsc() {
|
||||
builder.OrderAsc()
|
||||
builder.CreationDateAfter(req.CreationDate.AsTime())
|
||||
} else {
|
||||
builder.CreationDateBefore(req.CreationDate.AsTime())
|
||||
}
|
||||
|
||||
return builder, nil
|
||||
|
@ -24,7 +24,7 @@ import (
|
||||
|
||||
func ListUsersRequestToModel(req *mgmt_pb.ListUsersRequest) (*query.UserSearchQueries, error) {
|
||||
offset, limit, asc := object.ListQueryToModel(req.Query)
|
||||
queries, err := user_grpc.UserQueriesToQuery(req.Queries)
|
||||
queries, err := user_grpc.UserQueriesToQuery(req.Queries, 0 /*start from level 0*/)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
@ -9,6 +10,7 @@ import (
|
||||
"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
|
||||
"github.com/zitadel/logging"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/credentials"
|
||||
"google.golang.org/grpc/credentials/insecure"
|
||||
healthpb "google.golang.org/grpc/health/grpc_health_v1"
|
||||
"google.golang.org/protobuf/encoding/protojson"
|
||||
@ -89,10 +91,11 @@ func CreateGatewayWithPrefix(
|
||||
http1HostName string,
|
||||
accessInterceptor *http_mw.AccessInterceptor,
|
||||
queries *query.Queries,
|
||||
tlsConfig *tls.Config,
|
||||
) (http.Handler, string, error) {
|
||||
runtimeMux := runtime.NewServeMux(serveMuxOptions...)
|
||||
opts := []grpc.DialOption{
|
||||
grpc.WithTransportCredentials(insecure.NewCredentials()),
|
||||
grpc.WithTransportCredentials(grpcCredentials(tlsConfig)),
|
||||
grpc.WithUnaryInterceptor(client_middleware.DefaultTracingClient()),
|
||||
}
|
||||
connection, err := dial(ctx, port, opts)
|
||||
@ -106,11 +109,17 @@ func CreateGatewayWithPrefix(
|
||||
return addInterceptors(runtimeMux, http1HostName, accessInterceptor, queries), g.GatewayPathPrefix(), nil
|
||||
}
|
||||
|
||||
func CreateGateway(ctx context.Context, port uint16, http1HostName string, accessInterceptor *http_mw.AccessInterceptor) (*Gateway, error) {
|
||||
func CreateGateway(
|
||||
ctx context.Context,
|
||||
port uint16,
|
||||
http1HostName string,
|
||||
accessInterceptor *http_mw.AccessInterceptor,
|
||||
tlsConfig *tls.Config,
|
||||
) (*Gateway, error) {
|
||||
connection, err := dial(ctx,
|
||||
port,
|
||||
[]grpc.DialOption{
|
||||
grpc.WithTransportCredentials(insecure.NewCredentials()),
|
||||
grpc.WithTransportCredentials(grpcCredentials(tlsConfig)),
|
||||
grpc.WithUnaryInterceptor(client_middleware.DefaultTracingClient()),
|
||||
})
|
||||
if err != nil {
|
||||
@ -217,3 +226,15 @@ func (r *cookieResponseWriter) WriteHeader(status int) {
|
||||
}
|
||||
r.ResponseWriter.WriteHeader(status)
|
||||
}
|
||||
|
||||
func grpcCredentials(tlsConfig *tls.Config) credentials.TransportCredentials {
|
||||
creds := insecure.NewCredentials()
|
||||
if tlsConfig != nil {
|
||||
tlsConfigClone := tlsConfig.Clone()
|
||||
// We don't want to verify the certificate of the internal grpc server
|
||||
// That's up to the client who called the gRPC gateway
|
||||
tlsConfigClone.InsecureSkipVerify = true
|
||||
creds = credentials.NewTLS(tlsConfigClone)
|
||||
}
|
||||
return creds
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"net"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"google.golang.org/protobuf/types/known/structpb"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
@ -17,9 +18,20 @@ import (
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
caos_errs "github.com/zitadel/zitadel/internal/errors"
|
||||
"github.com/zitadel/zitadel/internal/query"
|
||||
objpb "github.com/zitadel/zitadel/pkg/grpc/object"
|
||||
session "github.com/zitadel/zitadel/pkg/grpc/session/v2beta"
|
||||
)
|
||||
|
||||
var (
|
||||
timestampComparisons = map[objpb.TimestampQueryMethod]query.TimestampComparison{
|
||||
objpb.TimestampQueryMethod_TIMESTAMP_QUERY_METHOD_EQUALS: query.TimestampEquals,
|
||||
objpb.TimestampQueryMethod_TIMESTAMP_QUERY_METHOD_GREATER: query.TimestampGreater,
|
||||
objpb.TimestampQueryMethod_TIMESTAMP_QUERY_METHOD_GREATER_OR_EQUALS: query.TimestampGreaterOrEquals,
|
||||
objpb.TimestampQueryMethod_TIMESTAMP_QUERY_METHOD_LESS: query.TimestampLess,
|
||||
objpb.TimestampQueryMethod_TIMESTAMP_QUERY_METHOD_LESS_OR_EQUALS: query.TimestampLessOrEquals,
|
||||
}
|
||||
)
|
||||
|
||||
func (s *Server) GetSession(ctx context.Context, req *session.GetSessionRequest) (*session.GetSessionResponse, error) {
|
||||
res, err := s.query.SessionByID(ctx, true, req.GetSessionId(), req.GetSessionToken())
|
||||
if err != nil {
|
||||
@ -46,7 +58,7 @@ func (s *Server) ListSessions(ctx context.Context, req *session.ListSessionsRequ
|
||||
}
|
||||
|
||||
func (s *Server) CreateSession(ctx context.Context, req *session.CreateSessionRequest) (*session.CreateSessionResponse, error) {
|
||||
checks, metadata, userAgent, err := s.createSessionRequestToCommand(ctx, req)
|
||||
checks, metadata, userAgent, lifetime, err := s.createSessionRequestToCommand(ctx, req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -55,7 +67,7 @@ func (s *Server) CreateSession(ctx context.Context, req *session.CreateSessionRe
|
||||
return nil, err
|
||||
}
|
||||
|
||||
set, err := s.command.CreateSession(ctx, cmds, metadata, userAgent)
|
||||
set, err := s.command.CreateSession(ctx, cmds, metadata, userAgent, lifetime)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -78,7 +90,7 @@ func (s *Server) SetSession(ctx context.Context, req *session.SetSessionRequest)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
set, err := s.command.UpdateSession(ctx, req.GetSessionId(), req.GetSessionToken(), cmds, req.GetMetadata())
|
||||
set, err := s.command.UpdateSession(ctx, req.GetSessionId(), req.GetSessionToken(), cmds, req.GetMetadata(), req.GetLifetime().AsDuration())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -113,13 +125,14 @@ func sessionsToPb(sessions []*query.Session) []*session.Session {
|
||||
|
||||
func sessionToPb(s *query.Session) *session.Session {
|
||||
return &session.Session{
|
||||
Id: s.ID,
|
||||
CreationDate: timestamppb.New(s.CreationDate),
|
||||
ChangeDate: timestamppb.New(s.ChangeDate),
|
||||
Sequence: s.Sequence,
|
||||
Factors: factorsToPb(s),
|
||||
Metadata: s.Metadata,
|
||||
UserAgent: userAgentToPb(s.UserAgent),
|
||||
Id: s.ID,
|
||||
CreationDate: timestamppb.New(s.CreationDate),
|
||||
ChangeDate: timestamppb.New(s.ChangeDate),
|
||||
Sequence: s.Sequence,
|
||||
Factors: factorsToPb(s),
|
||||
Metadata: s.Metadata,
|
||||
UserAgent: userAgentToPb(s.UserAgent),
|
||||
ExpirationDate: expirationToPb(s.Expiration),
|
||||
}
|
||||
}
|
||||
|
||||
@ -147,6 +160,13 @@ func userAgentToPb(ua domain.UserAgent) *session.UserAgent {
|
||||
return out
|
||||
}
|
||||
|
||||
func expirationToPb(expiration time.Time) *timestamppb.Timestamp {
|
||||
if expiration.IsZero() {
|
||||
return nil
|
||||
}
|
||||
return timestamppb.New(expiration)
|
||||
}
|
||||
|
||||
func factorsToPb(s *query.Session) *session.Factors {
|
||||
user := userFactorToPb(s.UserFactor)
|
||||
if user == nil {
|
||||
@ -231,9 +251,10 @@ func listSessionsRequestToQuery(ctx context.Context, req *session.ListSessionsRe
|
||||
}
|
||||
return &query.SessionsSearchQueries{
|
||||
SearchRequest: query.SearchRequest{
|
||||
Offset: offset,
|
||||
Limit: limit,
|
||||
Asc: asc,
|
||||
Offset: offset,
|
||||
Limit: limit,
|
||||
Asc: asc,
|
||||
SortingColumn: fieldNameToSessionColumn(req.GetSortingColumn()),
|
||||
},
|
||||
Queries: queries,
|
||||
}, nil
|
||||
@ -241,8 +262,8 @@ func listSessionsRequestToQuery(ctx context.Context, req *session.ListSessionsRe
|
||||
|
||||
func sessionQueriesToQuery(ctx context.Context, queries []*session.SearchQuery) (_ []query.SearchQuery, err error) {
|
||||
q := make([]query.SearchQuery, len(queries)+1)
|
||||
for i, query := range queries {
|
||||
q[i], err = sessionQueryToQuery(query)
|
||||
for i, v := range queries {
|
||||
q[i], err = sessionQueryToQuery(v)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -255,10 +276,14 @@ func sessionQueriesToQuery(ctx context.Context, queries []*session.SearchQuery)
|
||||
return q, nil
|
||||
}
|
||||
|
||||
func sessionQueryToQuery(query *session.SearchQuery) (query.SearchQuery, error) {
|
||||
switch q := query.Query.(type) {
|
||||
func sessionQueryToQuery(sq *session.SearchQuery) (query.SearchQuery, error) {
|
||||
switch q := sq.Query.(type) {
|
||||
case *session.SearchQuery_IdsQuery:
|
||||
return idsQueryToQuery(q.IdsQuery)
|
||||
case *session.SearchQuery_UserIdQuery:
|
||||
return query.NewUserIDSearchQuery(q.UserIdQuery.GetId())
|
||||
case *session.SearchQuery_CreationDateQuery:
|
||||
return creationDateQueryToQuery(q.CreationDateQuery)
|
||||
default:
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "GRPC-Sfefs", "List.Query.Invalid")
|
||||
}
|
||||
@ -268,12 +293,26 @@ func idsQueryToQuery(q *session.IDsQuery) (query.SearchQuery, error) {
|
||||
return query.NewSessionIDsSearchQuery(q.Ids)
|
||||
}
|
||||
|
||||
func (s *Server) createSessionRequestToCommand(ctx context.Context, req *session.CreateSessionRequest) ([]command.SessionCommand, map[string][]byte, *domain.UserAgent, error) {
|
||||
func creationDateQueryToQuery(q *session.CreationDateQuery) (query.SearchQuery, error) {
|
||||
comparison := timestampComparisons[q.GetMethod()]
|
||||
return query.NewCreationDateQuery(q.GetCreationDate().AsTime(), comparison)
|
||||
}
|
||||
|
||||
func fieldNameToSessionColumn(field session.SessionFieldName) query.Column {
|
||||
switch field {
|
||||
case session.SessionFieldName_SESSION_FIELD_NAME_CREATION_DATE:
|
||||
return query.SessionColumnCreationDate
|
||||
default:
|
||||
return query.Column{}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) createSessionRequestToCommand(ctx context.Context, req *session.CreateSessionRequest) ([]command.SessionCommand, map[string][]byte, *domain.UserAgent, time.Duration, error) {
|
||||
checks, err := s.checksToCommand(ctx, req.Checks)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
return nil, nil, nil, 0, err
|
||||
}
|
||||
return checks, req.GetMetadata(), userAgentToCommand(req.GetUserAgent()), nil
|
||||
return checks, req.GetMetadata(), userAgentToCommand(req.GetUserAgent()), req.GetLifetime().AsDuration(), nil
|
||||
}
|
||||
|
||||
func userAgentToCommand(userAgent *session.UserAgent) *domain.UserAgent {
|
||||
|
@ -15,6 +15,7 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
"google.golang.org/grpc/metadata"
|
||||
"google.golang.org/protobuf/proto"
|
||||
"google.golang.org/protobuf/types/known/durationpb"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/integration"
|
||||
object "github.com/zitadel/zitadel/pkg/grpc/object/v2beta"
|
||||
@ -54,7 +55,7 @@ func TestMain(m *testing.M) {
|
||||
}())
|
||||
}
|
||||
|
||||
func verifyCurrentSession(t testing.TB, id, token string, sequence uint64, window time.Duration, metadata map[string][]byte, userAgent *session.UserAgent, factors ...wantFactor) *session.Session {
|
||||
func verifyCurrentSession(t testing.TB, id, token string, sequence uint64, window time.Duration, metadata map[string][]byte, userAgent *session.UserAgent, expirationWindow time.Duration, factors ...wantFactor) *session.Session {
|
||||
t.Helper()
|
||||
require.NotEmpty(t, id)
|
||||
require.NotEmpty(t, token)
|
||||
@ -75,6 +76,11 @@ func verifyCurrentSession(t testing.TB, id, token string, sequence uint64, windo
|
||||
if !proto.Equal(userAgent, s.GetUserAgent()) {
|
||||
t.Errorf("user agent =\n%v\nwant\n%v", s.GetUserAgent(), userAgent)
|
||||
}
|
||||
if expirationWindow == 0 {
|
||||
assert.Nil(t, s.GetExpirationDate())
|
||||
} else {
|
||||
assert.WithinRange(t, s.GetExpirationDate().AsTime(), time.Now().Add(-expirationWindow), time.Now().Add(expirationWindow))
|
||||
}
|
||||
|
||||
verifyFactors(t, s.GetFactors(), window, factors)
|
||||
return s
|
||||
@ -137,12 +143,13 @@ func verifyFactors(t testing.TB, factors *session.Factors, window time.Duration,
|
||||
|
||||
func TestServer_CreateSession(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
req *session.CreateSessionRequest
|
||||
want *session.CreateSessionResponse
|
||||
wantErr bool
|
||||
wantFactors []wantFactor
|
||||
wantUserAgent *session.UserAgent
|
||||
name string
|
||||
req *session.CreateSessionRequest
|
||||
want *session.CreateSessionResponse
|
||||
wantErr bool
|
||||
wantFactors []wantFactor
|
||||
wantUserAgent *session.UserAgent
|
||||
wantExpirationWindow time.Duration
|
||||
}{
|
||||
{
|
||||
name: "empty session",
|
||||
@ -182,6 +189,27 @@ func TestServer_CreateSession(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "negative lifetime",
|
||||
req: &session.CreateSessionRequest{
|
||||
Metadata: map[string][]byte{"foo": []byte("bar")},
|
||||
Lifetime: durationpb.New(-5 * time.Minute),
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "lifetime",
|
||||
req: &session.CreateSessionRequest{
|
||||
Metadata: map[string][]byte{"foo": []byte("bar")},
|
||||
Lifetime: durationpb.New(5 * time.Minute),
|
||||
},
|
||||
want: &session.CreateSessionResponse{
|
||||
Details: &object.Details{
|
||||
ResourceOwner: Tester.Organisation.ID,
|
||||
},
|
||||
},
|
||||
wantExpirationWindow: 5 * time.Minute,
|
||||
},
|
||||
{
|
||||
name: "with user",
|
||||
req: &session.CreateSessionRequest{
|
||||
@ -253,7 +281,7 @@ func TestServer_CreateSession(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
integration.AssertDetails(t, tt.want, got)
|
||||
|
||||
verifyCurrentSession(t, got.GetSessionId(), got.GetSessionToken(), got.GetDetails().GetSequence(), time.Minute, tt.req.GetMetadata(), tt.wantUserAgent, tt.wantFactors...)
|
||||
verifyCurrentSession(t, got.GetSessionId(), got.GetSessionToken(), got.GetDetails().GetSequence(), time.Minute, tt.req.GetMetadata(), tt.wantUserAgent, tt.wantExpirationWindow, tt.wantFactors...)
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -276,7 +304,7 @@ func TestServer_CreateSession_webauthn(t *testing.T) {
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
verifyCurrentSession(t, createResp.GetSessionId(), createResp.GetSessionToken(), createResp.GetDetails().GetSequence(), time.Minute, nil, nil)
|
||||
verifyCurrentSession(t, createResp.GetSessionId(), createResp.GetSessionToken(), createResp.GetDetails().GetSequence(), time.Minute, nil, nil, 0)
|
||||
|
||||
assertionData, err := Tester.WebAuthN.CreateAssertionResponse(createResp.GetChallenges().GetWebAuthN().GetPublicKeyCredentialRequestOptions(), true)
|
||||
require.NoError(t, err)
|
||||
@ -292,7 +320,7 @@ func TestServer_CreateSession_webauthn(t *testing.T) {
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
verifyCurrentSession(t, createResp.GetSessionId(), updateResp.GetSessionToken(), updateResp.GetDetails().GetSequence(), time.Minute, nil, nil, wantUserFactor, wantWebAuthNFactorUserVerified)
|
||||
verifyCurrentSession(t, createResp.GetSessionId(), updateResp.GetSessionToken(), updateResp.GetDetails().GetSequence(), time.Minute, nil, nil, 0, wantUserFactor, wantWebAuthNFactorUserVerified)
|
||||
}
|
||||
|
||||
func TestServer_CreateSession_successfulIntent(t *testing.T) {
|
||||
@ -308,7 +336,7 @@ func TestServer_CreateSession_successfulIntent(t *testing.T) {
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
verifyCurrentSession(t, createResp.GetSessionId(), createResp.GetSessionToken(), createResp.GetDetails().GetSequence(), time.Minute, nil, nil)
|
||||
verifyCurrentSession(t, createResp.GetSessionId(), createResp.GetSessionToken(), createResp.GetDetails().GetSequence(), time.Minute, nil, nil, 0)
|
||||
|
||||
intentID, token, _, _ := Tester.CreateSuccessfulOAuthIntent(t, idpID, User.GetUserId(), "id")
|
||||
updateResp, err := Client.SetSession(CTX, &session.SetSessionRequest{
|
||||
@ -322,7 +350,7 @@ func TestServer_CreateSession_successfulIntent(t *testing.T) {
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
verifyCurrentSession(t, createResp.GetSessionId(), updateResp.GetSessionToken(), updateResp.GetDetails().GetSequence(), time.Minute, nil, nil, wantUserFactor, wantIntentFactor)
|
||||
verifyCurrentSession(t, createResp.GetSessionId(), updateResp.GetSessionToken(), updateResp.GetDetails().GetSequence(), time.Minute, nil, nil, 0, wantUserFactor, wantIntentFactor)
|
||||
}
|
||||
|
||||
func TestServer_CreateSession_successfulIntentUnknownUserID(t *testing.T) {
|
||||
@ -338,7 +366,7 @@ func TestServer_CreateSession_successfulIntentUnknownUserID(t *testing.T) {
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
verifyCurrentSession(t, createResp.GetSessionId(), createResp.GetSessionToken(), createResp.GetDetails().GetSequence(), time.Minute, nil, nil)
|
||||
verifyCurrentSession(t, createResp.GetSessionId(), createResp.GetSessionToken(), createResp.GetDetails().GetSequence(), time.Minute, nil, nil, 0)
|
||||
|
||||
idpUserID := "id"
|
||||
intentID, token, _, _ := Tester.CreateSuccessfulOAuthIntent(t, idpID, "", idpUserID)
|
||||
@ -365,7 +393,7 @@ func TestServer_CreateSession_successfulIntentUnknownUserID(t *testing.T) {
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
verifyCurrentSession(t, createResp.GetSessionId(), updateResp.GetSessionToken(), updateResp.GetDetails().GetSequence(), time.Minute, nil, nil, wantUserFactor, wantIntentFactor)
|
||||
verifyCurrentSession(t, createResp.GetSessionId(), updateResp.GetSessionToken(), updateResp.GetDetails().GetSequence(), time.Minute, nil, nil, 0, wantUserFactor, wantIntentFactor)
|
||||
}
|
||||
|
||||
func TestServer_CreateSession_startedIntentFalseToken(t *testing.T) {
|
||||
@ -381,7 +409,7 @@ func TestServer_CreateSession_startedIntentFalseToken(t *testing.T) {
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
verifyCurrentSession(t, createResp.GetSessionId(), createResp.GetSessionToken(), createResp.GetDetails().GetSequence(), time.Minute, nil, nil)
|
||||
verifyCurrentSession(t, createResp.GetSessionId(), createResp.GetSessionToken(), createResp.GetDetails().GetSequence(), time.Minute, nil, nil, 0)
|
||||
|
||||
intentID := Tester.CreateIntent(t, idpID)
|
||||
_, err = Client.SetSession(CTX, &session.SetSessionRequest{
|
||||
@ -433,7 +461,7 @@ func TestServer_SetSession_flow(t *testing.T) {
|
||||
createResp, err := Client.CreateSession(CTX, &session.CreateSessionRequest{})
|
||||
require.NoError(t, err)
|
||||
sessionToken := createResp.GetSessionToken()
|
||||
verifyCurrentSession(t, createResp.GetSessionId(), sessionToken, createResp.GetDetails().GetSequence(), time.Minute, nil, nil)
|
||||
verifyCurrentSession(t, createResp.GetSessionId(), sessionToken, createResp.GetDetails().GetSequence(), time.Minute, nil, nil, 0)
|
||||
|
||||
t.Run("check user", func(t *testing.T) {
|
||||
resp, err := Client.SetSession(CTX, &session.SetSessionRequest{
|
||||
@ -449,7 +477,7 @@ func TestServer_SetSession_flow(t *testing.T) {
|
||||
})
|
||||
require.NoError(t, err)
|
||||
sessionToken = resp.GetSessionToken()
|
||||
verifyCurrentSession(t, createResp.GetSessionId(), sessionToken, resp.GetDetails().GetSequence(), time.Minute, nil, nil, wantUserFactor)
|
||||
verifyCurrentSession(t, createResp.GetSessionId(), sessionToken, resp.GetDetails().GetSequence(), time.Minute, nil, nil, 0, wantUserFactor)
|
||||
})
|
||||
|
||||
t.Run("check webauthn, user verified (passkey)", func(t *testing.T) {
|
||||
@ -464,7 +492,7 @@ func TestServer_SetSession_flow(t *testing.T) {
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
verifyCurrentSession(t, createResp.GetSessionId(), resp.GetSessionToken(), resp.GetDetails().GetSequence(), time.Minute, nil, nil)
|
||||
verifyCurrentSession(t, createResp.GetSessionId(), resp.GetSessionToken(), resp.GetDetails().GetSequence(), time.Minute, nil, nil, 0)
|
||||
sessionToken = resp.GetSessionToken()
|
||||
|
||||
assertionData, err := Tester.WebAuthN.CreateAssertionResponse(resp.GetChallenges().GetWebAuthN().GetPublicKeyCredentialRequestOptions(), true)
|
||||
@ -481,7 +509,7 @@ func TestServer_SetSession_flow(t *testing.T) {
|
||||
})
|
||||
require.NoError(t, err)
|
||||
sessionToken = resp.GetSessionToken()
|
||||
verifyCurrentSession(t, createResp.GetSessionId(), sessionToken, resp.GetDetails().GetSequence(), time.Minute, nil, nil, wantUserFactor, wantWebAuthNFactorUserVerified)
|
||||
verifyCurrentSession(t, createResp.GetSessionId(), sessionToken, resp.GetDetails().GetSequence(), time.Minute, nil, nil, 0, wantUserFactor, wantWebAuthNFactorUserVerified)
|
||||
})
|
||||
|
||||
userAuthCtx := Tester.WithAuthorizationToken(CTX, sessionToken)
|
||||
@ -508,7 +536,7 @@ func TestServer_SetSession_flow(t *testing.T) {
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
verifyCurrentSession(t, createResp.GetSessionId(), resp.GetSessionToken(), resp.GetDetails().GetSequence(), time.Minute, nil, nil)
|
||||
verifyCurrentSession(t, createResp.GetSessionId(), resp.GetSessionToken(), resp.GetDetails().GetSequence(), time.Minute, nil, nil, 0)
|
||||
sessionToken = resp.GetSessionToken()
|
||||
|
||||
assertionData, err := Tester.WebAuthN.CreateAssertionResponse(resp.GetChallenges().GetWebAuthN().GetPublicKeyCredentialRequestOptions(), false)
|
||||
@ -525,7 +553,7 @@ func TestServer_SetSession_flow(t *testing.T) {
|
||||
})
|
||||
require.NoError(t, err)
|
||||
sessionToken = resp.GetSessionToken()
|
||||
verifyCurrentSession(t, createResp.GetSessionId(), sessionToken, resp.GetDetails().GetSequence(), time.Minute, nil, nil, wantUserFactor, wantWebAuthNFactor)
|
||||
verifyCurrentSession(t, createResp.GetSessionId(), sessionToken, resp.GetDetails().GetSequence(), time.Minute, nil, nil, 0, wantUserFactor, wantWebAuthNFactor)
|
||||
})
|
||||
}
|
||||
})
|
||||
@ -544,7 +572,7 @@ func TestServer_SetSession_flow(t *testing.T) {
|
||||
})
|
||||
require.NoError(t, err)
|
||||
sessionToken = resp.GetSessionToken()
|
||||
verifyCurrentSession(t, createResp.GetSessionId(), sessionToken, resp.GetDetails().GetSequence(), time.Minute, nil, nil, wantUserFactor, wantWebAuthNFactor, wantTOTPFactor)
|
||||
verifyCurrentSession(t, createResp.GetSessionId(), sessionToken, resp.GetDetails().GetSequence(), time.Minute, nil, nil, 0, wantUserFactor, wantWebAuthNFactor, wantTOTPFactor)
|
||||
})
|
||||
|
||||
t.Run("check OTP SMS", func(t *testing.T) {
|
||||
@ -556,7 +584,7 @@ func TestServer_SetSession_flow(t *testing.T) {
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
verifyCurrentSession(t, createResp.GetSessionId(), resp.GetSessionToken(), resp.GetDetails().GetSequence(), time.Minute, nil, nil)
|
||||
verifyCurrentSession(t, createResp.GetSessionId(), resp.GetSessionToken(), resp.GetDetails().GetSequence(), time.Minute, nil, nil, 0)
|
||||
sessionToken = resp.GetSessionToken()
|
||||
|
||||
otp := resp.GetChallenges().GetOtpSms()
|
||||
@ -573,7 +601,7 @@ func TestServer_SetSession_flow(t *testing.T) {
|
||||
})
|
||||
require.NoError(t, err)
|
||||
sessionToken = resp.GetSessionToken()
|
||||
verifyCurrentSession(t, createResp.GetSessionId(), sessionToken, resp.GetDetails().GetSequence(), time.Minute, nil, nil, wantUserFactor, wantWebAuthNFactor, wantOTPSMSFactor)
|
||||
verifyCurrentSession(t, createResp.GetSessionId(), sessionToken, resp.GetDetails().GetSequence(), time.Minute, nil, nil, 0, wantUserFactor, wantWebAuthNFactor, wantOTPSMSFactor)
|
||||
})
|
||||
|
||||
t.Run("check OTP Email", func(t *testing.T) {
|
||||
@ -587,7 +615,7 @@ func TestServer_SetSession_flow(t *testing.T) {
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
verifyCurrentSession(t, createResp.GetSessionId(), resp.GetSessionToken(), resp.GetDetails().GetSequence(), time.Minute, nil, nil)
|
||||
verifyCurrentSession(t, createResp.GetSessionId(), resp.GetSessionToken(), resp.GetDetails().GetSequence(), time.Minute, nil, nil, 0)
|
||||
sessionToken = resp.GetSessionToken()
|
||||
|
||||
otp := resp.GetChallenges().GetOtpEmail()
|
||||
@ -604,10 +632,34 @@ func TestServer_SetSession_flow(t *testing.T) {
|
||||
})
|
||||
require.NoError(t, err)
|
||||
sessionToken = resp.GetSessionToken()
|
||||
verifyCurrentSession(t, createResp.GetSessionId(), sessionToken, resp.GetDetails().GetSequence(), time.Minute, nil, nil, wantUserFactor, wantWebAuthNFactor, wantOTPEmailFactor)
|
||||
verifyCurrentSession(t, createResp.GetSessionId(), sessionToken, resp.GetDetails().GetSequence(), time.Minute, nil, nil, 0, wantUserFactor, wantWebAuthNFactor, wantOTPEmailFactor)
|
||||
})
|
||||
}
|
||||
|
||||
func TestServer_SetSession_expired(t *testing.T) {
|
||||
createResp, err := Client.CreateSession(CTX, &session.CreateSessionRequest{
|
||||
Lifetime: durationpb.New(20 * time.Second),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
// test session token works
|
||||
sessionResp, err := Tester.Client.SessionV2.SetSession(CTX, &session.SetSessionRequest{
|
||||
SessionId: createResp.GetSessionId(),
|
||||
SessionToken: createResp.GetSessionToken(),
|
||||
Lifetime: durationpb.New(20 * time.Second),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
// ensure session expires and does not work anymore
|
||||
time.Sleep(20 * time.Second)
|
||||
_, err = Tester.Client.SessionV2.SetSession(CTX, &session.SetSessionRequest{
|
||||
SessionId: createResp.GetSessionId(),
|
||||
SessionToken: sessionResp.GetSessionToken(),
|
||||
Lifetime: durationpb.New(20 * time.Second),
|
||||
})
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
func Test_ZITADEL_API_missing_authentication(t *testing.T) {
|
||||
// create new, empty session
|
||||
createResp, err := Client.CreateSession(CTX, &session.CreateSessionRequest{})
|
||||
@ -629,7 +681,7 @@ func Test_ZITADEL_API_missing_mfa(t *testing.T) {
|
||||
}
|
||||
|
||||
func Test_ZITADEL_API_success(t *testing.T) {
|
||||
id, token, _, _ := Tester.CreateVerfiedWebAuthNSession(t, CTX, User.GetUserId())
|
||||
id, token, _, _ := Tester.CreateVerifiedWebAuthNSession(t, CTX, User.GetUserId())
|
||||
|
||||
ctx := Tester.WithAuthorizationToken(context.Background(), token)
|
||||
sessionResp, err := Tester.Client.SessionV2.GetSession(ctx, &session.GetSessionRequest{SessionId: id})
|
||||
@ -641,7 +693,7 @@ func Test_ZITADEL_API_success(t *testing.T) {
|
||||
}
|
||||
|
||||
func Test_ZITADEL_API_session_not_found(t *testing.T) {
|
||||
id, token, _, _ := Tester.CreateVerfiedWebAuthNSession(t, CTX, User.GetUserId())
|
||||
id, token, _, _ := Tester.CreateVerifiedWebAuthNSession(t, CTX, User.GetUserId())
|
||||
|
||||
// test session token works
|
||||
ctx := Tester.WithAuthorizationToken(context.Background(), token)
|
||||
@ -658,3 +710,18 @@ func Test_ZITADEL_API_session_not_found(t *testing.T) {
|
||||
_, err = Tester.Client.SessionV2.GetSession(ctx, &session.GetSessionRequest{SessionId: id})
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
func Test_ZITADEL_API_session_expired(t *testing.T) {
|
||||
id, token, _, _ := Tester.CreateVerifiedWebAuthNSessionWithLifetime(t, CTX, User.GetUserId(), 20*time.Second)
|
||||
|
||||
// test session token works
|
||||
ctx := Tester.WithAuthorizationToken(context.Background(), token)
|
||||
_, err := Tester.Client.SessionV2.GetSession(ctx, &session.GetSessionRequest{SessionId: id})
|
||||
require.NoError(t, err)
|
||||
|
||||
// ensure session expires and does not work anymore
|
||||
time.Sleep(20 * time.Second)
|
||||
sessionResp, err := Tester.Client.SessionV2.GetSession(ctx, &session.GetSessionRequest{SessionId: id})
|
||||
require.Error(t, err)
|
||||
require.Nil(t, sessionResp)
|
||||
}
|
||||
|
@ -14,6 +14,7 @@ import (
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/authz"
|
||||
objpb "github.com/zitadel/zitadel/pkg/grpc/object"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
caos_errs "github.com/zitadel/zitadel/internal/errors"
|
||||
@ -22,12 +23,16 @@ import (
|
||||
session "github.com/zitadel/zitadel/pkg/grpc/session/v2beta"
|
||||
)
|
||||
|
||||
var (
|
||||
creationDate = time.Date(2023, 10, 10, 14, 15, 0, 0, time.UTC)
|
||||
)
|
||||
|
||||
func Test_sessionsToPb(t *testing.T) {
|
||||
now := time.Now()
|
||||
past := now.Add(-time.Hour)
|
||||
|
||||
sessions := []*query.Session{
|
||||
{ // no factor, with user agent
|
||||
{ // no factor, with user agent and expiration
|
||||
ID: "999",
|
||||
CreationDate: now,
|
||||
ChangeDate: now,
|
||||
@ -42,6 +47,7 @@ func Test_sessionsToPb(t *testing.T) {
|
||||
IP: net.IPv4(1, 2, 3, 4),
|
||||
Header: http.Header{"foo": []string{"foo", "bar"}},
|
||||
},
|
||||
Expiration: now,
|
||||
},
|
||||
{ // user factor
|
||||
ID: "999",
|
||||
@ -124,7 +130,7 @@ func Test_sessionsToPb(t *testing.T) {
|
||||
}
|
||||
|
||||
want := []*session.Session{
|
||||
{ // no factor, with user agent
|
||||
{ // no factor, with user agent and expiration
|
||||
Id: "999",
|
||||
CreationDate: timestamppb.New(now),
|
||||
ChangeDate: timestamppb.New(now),
|
||||
@ -139,6 +145,7 @@ func Test_sessionsToPb(t *testing.T) {
|
||||
"foo": {Values: []string{"foo", "bar"}},
|
||||
},
|
||||
},
|
||||
ExpirationDate: timestamppb.New(now),
|
||||
},
|
||||
{ // user factor
|
||||
Id: "999",
|
||||
@ -307,11 +314,18 @@ func mustNewListQuery(t testing.TB, column query.Column, list []any, compare que
|
||||
return q
|
||||
}
|
||||
|
||||
func mustNewTimestampQuery(t testing.TB, column query.Column, ts time.Time, compare query.TimestampComparison) query.SearchQuery {
|
||||
q, err := query.NewTimestampQuery(column, ts, compare)
|
||||
require.NoError(t, err)
|
||||
return q
|
||||
}
|
||||
|
||||
func Test_listSessionsRequestToQuery(t *testing.T) {
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
req *session.ListSessionsRequest
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
@ -335,6 +349,26 @@ func Test_listSessionsRequestToQuery(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "default request with sorting column",
|
||||
args: args{
|
||||
ctx: authz.NewMockContext("123", "456", "789"),
|
||||
req: &session.ListSessionsRequest{
|
||||
SortingColumn: session.SessionFieldName_SESSION_FIELD_NAME_CREATION_DATE,
|
||||
},
|
||||
},
|
||||
want: &query.SessionsSearchQueries{
|
||||
SearchRequest: query.SearchRequest{
|
||||
Offset: 0,
|
||||
Limit: 0,
|
||||
SortingColumn: query.SessionColumnCreationDate,
|
||||
Asc: false,
|
||||
},
|
||||
Queries: []query.SearchQuery{
|
||||
mustNewTextQuery(t, query.SessionColumnCreator, "789", query.TextEquals),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "with list query and sessions",
|
||||
args: args{
|
||||
@ -356,6 +390,17 @@ func Test_listSessionsRequestToQuery(t *testing.T) {
|
||||
Ids: []string{"4", "5", "6"},
|
||||
},
|
||||
}},
|
||||
{Query: &session.SearchQuery_UserIdQuery{
|
||||
UserIdQuery: &session.UserIDQuery{
|
||||
Id: "10",
|
||||
},
|
||||
}},
|
||||
{Query: &session.SearchQuery_CreationDateQuery{
|
||||
CreationDateQuery: &session.CreationDateQuery{
|
||||
CreationDate: timestamppb.New(creationDate),
|
||||
Method: objpb.TimestampQueryMethod_TIMESTAMP_QUERY_METHOD_GREATER,
|
||||
},
|
||||
}},
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -368,6 +413,8 @@ func Test_listSessionsRequestToQuery(t *testing.T) {
|
||||
Queries: []query.SearchQuery{
|
||||
mustNewListQuery(t, query.SessionColumnID, []interface{}{"1", "2", "3"}, query.ListIn),
|
||||
mustNewListQuery(t, query.SessionColumnID, []interface{}{"4", "5", "6"}, query.ListIn),
|
||||
mustNewTextQuery(t, query.SessionColumnUserID, "10", query.TextEquals),
|
||||
mustNewTimestampQuery(t, query.SessionColumnCreationDate, creationDate, query.TimestampGreater),
|
||||
mustNewTextQuery(t, query.SessionColumnCreator, "789", query.TextEquals),
|
||||
},
|
||||
},
|
||||
@ -485,7 +532,7 @@ func Test_sessionQueryToQuery(t *testing.T) {
|
||||
wantErr: caos_errs.ThrowInvalidArgument(nil, "GRPC-Sfefs", "List.Query.Invalid"),
|
||||
},
|
||||
{
|
||||
name: "query",
|
||||
name: "ids query",
|
||||
args: args{&session.SearchQuery{
|
||||
Query: &session.SearchQuery_IdsQuery{
|
||||
IdsQuery: &session.IDsQuery{
|
||||
@ -495,6 +542,40 @@ func Test_sessionQueryToQuery(t *testing.T) {
|
||||
}},
|
||||
want: mustNewListQuery(t, query.SessionColumnID, []interface{}{"1", "2", "3"}, query.ListIn),
|
||||
},
|
||||
{
|
||||
name: "user id query",
|
||||
args: args{&session.SearchQuery{
|
||||
Query: &session.SearchQuery_UserIdQuery{
|
||||
UserIdQuery: &session.UserIDQuery{
|
||||
Id: "10",
|
||||
},
|
||||
},
|
||||
}},
|
||||
want: mustNewTextQuery(t, query.SessionColumnUserID, "10", query.TextEquals),
|
||||
},
|
||||
{
|
||||
name: "creation date query",
|
||||
args: args{&session.SearchQuery{
|
||||
Query: &session.SearchQuery_CreationDateQuery{
|
||||
CreationDateQuery: &session.CreationDateQuery{
|
||||
CreationDate: timestamppb.New(creationDate),
|
||||
Method: objpb.TimestampQueryMethod_TIMESTAMP_QUERY_METHOD_LESS,
|
||||
},
|
||||
},
|
||||
}},
|
||||
want: mustNewTimestampQuery(t, query.SessionColumnCreationDate, creationDate, query.TimestampLess),
|
||||
},
|
||||
{
|
||||
name: "creation date query with default method",
|
||||
args: args{&session.SearchQuery{
|
||||
Query: &session.SearchQuery_CreationDateQuery{
|
||||
CreationDateQuery: &session.CreationDateQuery{
|
||||
CreationDate: timestamppb.New(creationDate),
|
||||
},
|
||||
},
|
||||
}},
|
||||
want: mustNewTimestampQuery(t, query.SessionColumnCreationDate, creationDate, query.TimestampEquals),
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
|
@ -7,10 +7,10 @@ import (
|
||||
user_pb "github.com/zitadel/zitadel/pkg/grpc/user"
|
||||
)
|
||||
|
||||
func UserQueriesToQuery(queries []*user_pb.SearchQuery) (_ []query.SearchQuery, err error) {
|
||||
func UserQueriesToQuery(queries []*user_pb.SearchQuery, level uint8) (_ []query.SearchQuery, err error) {
|
||||
q := make([]query.SearchQuery, len(queries))
|
||||
for i, query := range queries {
|
||||
q[i], err = UserQueryToQuery(query)
|
||||
q[i], err = UserQueryToQuery(query, level)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -18,7 +18,11 @@ func UserQueriesToQuery(queries []*user_pb.SearchQuery) (_ []query.SearchQuery,
|
||||
return q, nil
|
||||
}
|
||||
|
||||
func UserQueryToQuery(query *user_pb.SearchQuery) (query.SearchQuery, error) {
|
||||
func UserQueryToQuery(query *user_pb.SearchQuery, level uint8) (query.SearchQuery, error) {
|
||||
if level > 20 {
|
||||
// can't go deeper than 20 levels of nesting.
|
||||
return nil, errors.ThrowInvalidArgument(nil, "USER-zsQ97", "Errors.User.TooManyNestingLevels")
|
||||
}
|
||||
switch q := query.Query.(type) {
|
||||
case *user_pb.SearchQuery_UserNameQuery:
|
||||
return UserNameQueryToQuery(q.UserNameQuery)
|
||||
@ -42,6 +46,12 @@ func UserQueryToQuery(query *user_pb.SearchQuery) (query.SearchQuery, error) {
|
||||
return ResourceOwnerQueryToQuery(q.ResourceOwner)
|
||||
case *user_pb.SearchQuery_InUserIdsQuery:
|
||||
return InUserIdsQueryToQuery(q.InUserIdsQuery)
|
||||
case *user_pb.SearchQuery_OrQuery:
|
||||
return OrQueryToQuery(q.OrQuery, level)
|
||||
case *user_pb.SearchQuery_AndQuery:
|
||||
return AndQueryToQuery(q.AndQuery, level)
|
||||
case *user_pb.SearchQuery_NotQuery:
|
||||
return NotQueryToQuery(q.NotQuery, level)
|
||||
default:
|
||||
return nil, errors.ThrowInvalidArgument(nil, "GRPC-vR9nC", "List.Query.Invalid")
|
||||
}
|
||||
@ -90,3 +100,24 @@ func ResourceOwnerQueryToQuery(q *user_pb.ResourceOwnerQuery) (query.SearchQuery
|
||||
func InUserIdsQueryToQuery(q *user_pb.InUserIDQuery) (query.SearchQuery, error) {
|
||||
return query.NewUserInUserIdsSearchQuery(q.UserIds)
|
||||
}
|
||||
func OrQueryToQuery(q *user_pb.OrQuery, level uint8) (query.SearchQuery, error) {
|
||||
mappedQueries, err := UserQueriesToQuery(q.Queries, level+1)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return query.NewUserOrSearchQuery(mappedQueries)
|
||||
}
|
||||
func AndQueryToQuery(q *user_pb.AndQuery, level uint8) (query.SearchQuery, error) {
|
||||
mappedQueries, err := UserQueriesToQuery(q.Queries, level+1)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return query.NewUserAndSearchQuery(mappedQueries)
|
||||
}
|
||||
func NotQueryToQuery(q *user_pb.NotQuery, level uint8) (query.SearchQuery, error) {
|
||||
mappedQuery, err := UserQueryToQuery(q.Query, level+1)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return query.NewUserNotSearchQuery(mappedQuery)
|
||||
}
|
||||
|
@ -16,13 +16,13 @@ import (
|
||||
func TestServer_AddOTPSMS(t *testing.T) {
|
||||
userID := Tester.CreateHumanUser(CTX).GetUserId()
|
||||
Tester.RegisterUserPasskey(CTX, userID)
|
||||
_, sessionToken, _, _ := Tester.CreateVerfiedWebAuthNSession(t, CTX, userID)
|
||||
_, sessionToken, _, _ := Tester.CreateVerifiedWebAuthNSession(t, CTX, userID)
|
||||
|
||||
// TODO: add when phone can be added to user
|
||||
/*
|
||||
userIDPhone := Tester.CreateHumanUser(CTX).GetUserId()
|
||||
Tester.RegisterUserPasskey(CTX, userIDPhone)
|
||||
_, sessionTokenPhone, _, _ := Tester.CreateVerfiedWebAuthNSession(t, CTX, userIDPhone)
|
||||
_, sessionTokenPhone, _, _ := Tester.CreateVerifiedWebAuthNSession(t, CTX, userIDPhone)
|
||||
*/
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
@ -99,7 +99,7 @@ func TestServer_RemoveOTPSMS(t *testing.T) {
|
||||
/*
|
||||
userID := Tester.CreateHumanUser(CTX).GetUserId()
|
||||
Tester.RegisterUserPasskey(CTX, userID)
|
||||
_, sessionToken, _, _ := Tester.CreateVerfiedWebAuthNSession(t, CTX, userID)
|
||||
_, sessionToken, _, _ := Tester.CreateVerifiedWebAuthNSession(t, CTX, userID)
|
||||
*/
|
||||
|
||||
type args struct {
|
||||
@ -157,7 +157,7 @@ func TestServer_RemoveOTPSMS(t *testing.T) {
|
||||
func TestServer_AddOTPEmail(t *testing.T) {
|
||||
userID := Tester.CreateHumanUser(CTX).GetUserId()
|
||||
Tester.RegisterUserPasskey(CTX, userID)
|
||||
_, sessionToken, _, _ := Tester.CreateVerfiedWebAuthNSession(t, CTX, userID)
|
||||
_, sessionToken, _, _ := Tester.CreateVerifiedWebAuthNSession(t, CTX, userID)
|
||||
|
||||
userVerified := Tester.CreateHumanUser(CTX)
|
||||
_, err := Tester.Client.UserV2.VerifyEmail(CTX, &user.VerifyEmailRequest{
|
||||
@ -166,7 +166,7 @@ func TestServer_AddOTPEmail(t *testing.T) {
|
||||
})
|
||||
require.NoError(t, err)
|
||||
Tester.RegisterUserPasskey(CTX, userVerified.GetUserId())
|
||||
_, sessionTokenVerified, _, _ := Tester.CreateVerfiedWebAuthNSession(t, CTX, userVerified.GetUserId())
|
||||
_, sessionTokenVerified, _, _ := Tester.CreateVerifiedWebAuthNSession(t, CTX, userVerified.GetUserId())
|
||||
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
@ -238,11 +238,11 @@ func TestServer_AddOTPEmail(t *testing.T) {
|
||||
func TestServer_RemoveOTPEmail(t *testing.T) {
|
||||
userID := Tester.CreateHumanUser(CTX).GetUserId()
|
||||
Tester.RegisterUserPasskey(CTX, userID)
|
||||
_, sessionToken, _, _ := Tester.CreateVerfiedWebAuthNSession(t, CTX, userID)
|
||||
_, sessionToken, _, _ := Tester.CreateVerifiedWebAuthNSession(t, CTX, userID)
|
||||
|
||||
userVerified := Tester.CreateHumanUser(CTX)
|
||||
Tester.RegisterUserPasskey(CTX, userVerified.GetUserId())
|
||||
_, sessionTokenVerified, _, _ := Tester.CreateVerfiedWebAuthNSession(t, CTX, userVerified.GetUserId())
|
||||
_, sessionTokenVerified, _, _ := Tester.CreateVerifiedWebAuthNSession(t, CTX, userVerified.GetUserId())
|
||||
userVerifiedCtx := Tester.WithAuthorizationToken(context.Background(), sessionTokenVerified)
|
||||
_, err := Tester.Client.UserV2.VerifyEmail(userVerifiedCtx, &user.VerifyEmailRequest{
|
||||
UserId: userVerified.GetUserId(),
|
||||
|
@ -36,7 +36,7 @@ func TestOPStorage_CreateAuthRequest(t *testing.T) {
|
||||
func TestOPStorage_CreateAccessToken_code(t *testing.T) {
|
||||
clientID := createClient(t)
|
||||
authRequestID := createAuthRequest(t, clientID, redirectURI)
|
||||
sessionID, sessionToken, startTime, changeTime := Tester.CreateVerfiedWebAuthNSession(t, CTXLOGIN, User.GetUserId())
|
||||
sessionID, sessionToken, startTime, changeTime := Tester.CreateVerifiedWebAuthNSession(t, CTXLOGIN, User.GetUserId())
|
||||
linkResp, err := Tester.Client.OIDCv2.CreateCallback(CTXLOGIN, &oidc_pb.CreateCallbackRequest{
|
||||
AuthRequestId: authRequestID,
|
||||
CallbackKind: &oidc_pb.CreateCallbackRequest_Session{
|
||||
@ -75,7 +75,7 @@ func TestOPStorage_CreateAccessToken_code(t *testing.T) {
|
||||
func TestOPStorage_CreateAccessToken_implicit(t *testing.T) {
|
||||
clientID := createImplicitClient(t)
|
||||
authRequestID := createAuthRequestImplicit(t, clientID, redirectURIImplicit)
|
||||
sessionID, sessionToken, startTime, changeTime := Tester.CreateVerfiedWebAuthNSession(t, CTXLOGIN, User.GetUserId())
|
||||
sessionID, sessionToken, startTime, changeTime := Tester.CreateVerifiedWebAuthNSession(t, CTXLOGIN, User.GetUserId())
|
||||
linkResp, err := Tester.Client.OIDCv2.CreateCallback(CTXLOGIN, &oidc_pb.CreateCallbackRequest{
|
||||
AuthRequestId: authRequestID,
|
||||
CallbackKind: &oidc_pb.CreateCallbackRequest_Session{
|
||||
@ -125,7 +125,7 @@ func TestOPStorage_CreateAccessToken_implicit(t *testing.T) {
|
||||
func TestOPStorage_CreateAccessAndRefreshTokens_code(t *testing.T) {
|
||||
clientID := createClient(t)
|
||||
authRequestID := createAuthRequest(t, clientID, redirectURI, oidc.ScopeOpenID, oidc.ScopeOfflineAccess)
|
||||
sessionID, sessionToken, startTime, changeTime := Tester.CreateVerfiedWebAuthNSession(t, CTXLOGIN, User.GetUserId())
|
||||
sessionID, sessionToken, startTime, changeTime := Tester.CreateVerifiedWebAuthNSession(t, CTXLOGIN, User.GetUserId())
|
||||
linkResp, err := Tester.Client.OIDCv2.CreateCallback(CTXLOGIN, &oidc_pb.CreateCallbackRequest{
|
||||
AuthRequestId: authRequestID,
|
||||
CallbackKind: &oidc_pb.CreateCallbackRequest_Session{
|
||||
@ -150,7 +150,7 @@ func TestOPStorage_CreateAccessAndRefreshTokens_refresh(t *testing.T) {
|
||||
provider, err := Tester.CreateRelyingParty(CTX, clientID, redirectURI)
|
||||
require.NoError(t, err)
|
||||
authRequestID := createAuthRequest(t, clientID, redirectURI, oidc.ScopeOpenID, oidc.ScopeOfflineAccess)
|
||||
sessionID, sessionToken, startTime, changeTime := Tester.CreateVerfiedWebAuthNSession(t, CTXLOGIN, User.GetUserId())
|
||||
sessionID, sessionToken, startTime, changeTime := Tester.CreateVerifiedWebAuthNSession(t, CTXLOGIN, User.GetUserId())
|
||||
linkResp, err := Tester.Client.OIDCv2.CreateCallback(CTXLOGIN, &oidc_pb.CreateCallbackRequest{
|
||||
AuthRequestId: authRequestID,
|
||||
CallbackKind: &oidc_pb.CreateCallbackRequest_Session{
|
||||
@ -186,7 +186,7 @@ func TestOPStorage_RevokeToken_access_token(t *testing.T) {
|
||||
provider, err := Tester.CreateRelyingParty(CTX, clientID, redirectURI)
|
||||
require.NoError(t, err)
|
||||
authRequestID := createAuthRequest(t, clientID, redirectURI, oidc.ScopeOpenID, oidc.ScopeOfflineAccess)
|
||||
sessionID, sessionToken, startTime, changeTime := Tester.CreateVerfiedWebAuthNSession(t, CTXLOGIN, User.GetUserId())
|
||||
sessionID, sessionToken, startTime, changeTime := Tester.CreateVerifiedWebAuthNSession(t, CTXLOGIN, User.GetUserId())
|
||||
linkResp, err := Tester.Client.OIDCv2.CreateCallback(CTXLOGIN, &oidc_pb.CreateCallbackRequest{
|
||||
AuthRequestId: authRequestID,
|
||||
CallbackKind: &oidc_pb.CreateCallbackRequest_Session{
|
||||
@ -229,7 +229,7 @@ func TestOPStorage_RevokeToken_access_token_invalid_token_hint_type(t *testing.T
|
||||
provider, err := Tester.CreateRelyingParty(CTX, clientID, redirectURI)
|
||||
require.NoError(t, err)
|
||||
authRequestID := createAuthRequest(t, clientID, redirectURI, oidc.ScopeOpenID, oidc.ScopeOfflineAccess)
|
||||
sessionID, sessionToken, startTime, changeTime := Tester.CreateVerfiedWebAuthNSession(t, CTXLOGIN, User.GetUserId())
|
||||
sessionID, sessionToken, startTime, changeTime := Tester.CreateVerifiedWebAuthNSession(t, CTXLOGIN, User.GetUserId())
|
||||
linkResp, err := Tester.Client.OIDCv2.CreateCallback(CTXLOGIN, &oidc_pb.CreateCallbackRequest{
|
||||
AuthRequestId: authRequestID,
|
||||
CallbackKind: &oidc_pb.CreateCallbackRequest_Session{
|
||||
@ -266,7 +266,7 @@ func TestOPStorage_RevokeToken_refresh_token(t *testing.T) {
|
||||
provider, err := Tester.CreateRelyingParty(CTX, clientID, redirectURI)
|
||||
require.NoError(t, err)
|
||||
authRequestID := createAuthRequest(t, clientID, redirectURI, oidc.ScopeOpenID, oidc.ScopeOfflineAccess)
|
||||
sessionID, sessionToken, startTime, changeTime := Tester.CreateVerfiedWebAuthNSession(t, CTXLOGIN, User.GetUserId())
|
||||
sessionID, sessionToken, startTime, changeTime := Tester.CreateVerifiedWebAuthNSession(t, CTXLOGIN, User.GetUserId())
|
||||
linkResp, err := Tester.Client.OIDCv2.CreateCallback(CTXLOGIN, &oidc_pb.CreateCallbackRequest{
|
||||
AuthRequestId: authRequestID,
|
||||
CallbackKind: &oidc_pb.CreateCallbackRequest_Session{
|
||||
@ -309,7 +309,7 @@ func TestOPStorage_RevokeToken_refresh_token_invalid_token_type_hint(t *testing.
|
||||
provider, err := Tester.CreateRelyingParty(CTX, clientID, redirectURI)
|
||||
require.NoError(t, err)
|
||||
authRequestID := createAuthRequest(t, clientID, redirectURI, oidc.ScopeOpenID, oidc.ScopeOfflineAccess)
|
||||
sessionID, sessionToken, startTime, changeTime := Tester.CreateVerfiedWebAuthNSession(t, CTXLOGIN, User.GetUserId())
|
||||
sessionID, sessionToken, startTime, changeTime := Tester.CreateVerifiedWebAuthNSession(t, CTXLOGIN, User.GetUserId())
|
||||
linkResp, err := Tester.Client.OIDCv2.CreateCallback(CTXLOGIN, &oidc_pb.CreateCallbackRequest{
|
||||
AuthRequestId: authRequestID,
|
||||
CallbackKind: &oidc_pb.CreateCallbackRequest_Session{
|
||||
@ -344,7 +344,7 @@ func TestOPStorage_RevokeToken_refresh_token_invalid_token_type_hint(t *testing.
|
||||
func TestOPStorage_RevokeToken_invalid_client(t *testing.T) {
|
||||
clientID := createClient(t)
|
||||
authRequestID := createAuthRequest(t, clientID, redirectURI, oidc.ScopeOpenID, oidc.ScopeOfflineAccess)
|
||||
sessionID, sessionToken, startTime, changeTime := Tester.CreateVerfiedWebAuthNSession(t, CTXLOGIN, User.GetUserId())
|
||||
sessionID, sessionToken, startTime, changeTime := Tester.CreateVerifiedWebAuthNSession(t, CTXLOGIN, User.GetUserId())
|
||||
linkResp, err := Tester.Client.OIDCv2.CreateCallback(CTXLOGIN, &oidc_pb.CreateCallbackRequest{
|
||||
AuthRequestId: authRequestID,
|
||||
CallbackKind: &oidc_pb.CreateCallbackRequest_Session{
|
||||
@ -376,7 +376,7 @@ func TestOPStorage_TerminateSession(t *testing.T) {
|
||||
provider, err := Tester.CreateRelyingParty(CTX, clientID, redirectURI)
|
||||
require.NoError(t, err)
|
||||
authRequestID := createAuthRequest(t, clientID, redirectURI)
|
||||
sessionID, sessionToken, startTime, changeTime := Tester.CreateVerfiedWebAuthNSession(t, CTXLOGIN, User.GetUserId())
|
||||
sessionID, sessionToken, startTime, changeTime := Tester.CreateVerifiedWebAuthNSession(t, CTXLOGIN, User.GetUserId())
|
||||
linkResp, err := Tester.Client.OIDCv2.CreateCallback(CTXLOGIN, &oidc_pb.CreateCallbackRequest{
|
||||
AuthRequestId: authRequestID,
|
||||
CallbackKind: &oidc_pb.CreateCallbackRequest_Session{
|
||||
@ -413,7 +413,7 @@ func TestOPStorage_TerminateSession_refresh_grant(t *testing.T) {
|
||||
provider, err := Tester.CreateRelyingParty(CTX, clientID, redirectURI)
|
||||
require.NoError(t, err)
|
||||
authRequestID := createAuthRequest(t, clientID, redirectURI, oidc.ScopeOpenID, oidc.ScopeOfflineAccess)
|
||||
sessionID, sessionToken, startTime, changeTime := Tester.CreateVerfiedWebAuthNSession(t, CTXLOGIN, User.GetUserId())
|
||||
sessionID, sessionToken, startTime, changeTime := Tester.CreateVerifiedWebAuthNSession(t, CTXLOGIN, User.GetUserId())
|
||||
linkResp, err := Tester.Client.OIDCv2.CreateCallback(CTXLOGIN, &oidc_pb.CreateCallbackRequest{
|
||||
AuthRequestId: authRequestID,
|
||||
CallbackKind: &oidc_pb.CreateCallbackRequest_Session{
|
||||
@ -457,7 +457,7 @@ func TestOPStorage_TerminateSession_empty_id_token_hint(t *testing.T) {
|
||||
provider, err := Tester.CreateRelyingParty(CTX, clientID, redirectURI)
|
||||
require.NoError(t, err)
|
||||
authRequestID := createAuthRequest(t, clientID, redirectURI)
|
||||
sessionID, sessionToken, startTime, changeTime := Tester.CreateVerfiedWebAuthNSession(t, CTXLOGIN, User.GetUserId())
|
||||
sessionID, sessionToken, startTime, changeTime := Tester.CreateVerifiedWebAuthNSession(t, CTXLOGIN, User.GetUserId())
|
||||
linkResp, err := Tester.Client.OIDCv2.CreateCallback(CTXLOGIN, &oidc_pb.CreateCallbackRequest{
|
||||
AuthRequestId: authRequestID,
|
||||
CallbackKind: &oidc_pb.CreateCallbackRequest_Session{
|
||||
|
@ -21,7 +21,7 @@ import (
|
||||
func TestOPStorage_SetUserinfoFromToken(t *testing.T) {
|
||||
clientID := createClient(t)
|
||||
authRequestID := createAuthRequest(t, clientID, redirectURI, oidc.ScopeOpenID, oidc.ScopeProfile, oidc.ScopeEmail, oidc.ScopeOfflineAccess)
|
||||
sessionID, sessionToken, startTime, changeTime := Tester.CreateVerfiedWebAuthNSession(t, CTXLOGIN, User.GetUserId())
|
||||
sessionID, sessionToken, startTime, changeTime := Tester.CreateVerifiedWebAuthNSession(t, CTXLOGIN, User.GetUserId())
|
||||
linkResp, err := Tester.Client.OIDCv2.CreateCallback(CTXLOGIN, &oidc_pb.CreateCallbackRequest{
|
||||
AuthRequestId: authRequestID,
|
||||
CallbackKind: &oidc_pb.CreateCallbackRequest_Session{
|
||||
@ -67,7 +67,7 @@ func TestOPStorage_SetIntrospectionFromToken(t *testing.T) {
|
||||
|
||||
scope := []string{oidc.ScopeOpenID, oidc.ScopeProfile, oidc.ScopeEmail, oidc.ScopeOfflineAccess}
|
||||
authRequestID := createAuthRequest(t, app.GetClientId(), redirectURI, scope...)
|
||||
sessionID, sessionToken, startTime, changeTime := Tester.CreateVerfiedWebAuthNSession(t, CTXLOGIN, User.GetUserId())
|
||||
sessionID, sessionToken, startTime, changeTime := Tester.CreateVerifiedWebAuthNSession(t, CTXLOGIN, User.GetUserId())
|
||||
linkResp, err := Tester.Client.OIDCv2.CreateCallback(CTXLOGIN, &oidc_pb.CreateCallbackRequest{
|
||||
AuthRequestId: authRequestID,
|
||||
CallbackKind: &oidc_pb.CreateCallbackRequest_Session{
|
||||
|
@ -57,7 +57,7 @@ func TestMain(m *testing.M) {
|
||||
func Test_ZITADEL_API_missing_audience_scope(t *testing.T) {
|
||||
clientID := createClient(t)
|
||||
authRequestID := createAuthRequest(t, clientID, redirectURI, oidc.ScopeOpenID)
|
||||
sessionID, sessionToken, startTime, changeTime := Tester.CreateVerfiedWebAuthNSession(t, CTXLOGIN, User.GetUserId())
|
||||
sessionID, sessionToken, startTime, changeTime := Tester.CreateVerifiedWebAuthNSession(t, CTXLOGIN, User.GetUserId())
|
||||
linkResp, err := Tester.Client.OIDCv2.CreateCallback(CTXLOGIN, &oidc_pb.CreateCallbackRequest{
|
||||
AuthRequestId: authRequestID,
|
||||
CallbackKind: &oidc_pb.CreateCallbackRequest_Session{
|
||||
@ -148,7 +148,7 @@ func Test_ZITADEL_API_missing_mfa(t *testing.T) {
|
||||
func Test_ZITADEL_API_success(t *testing.T) {
|
||||
clientID := createClient(t)
|
||||
authRequestID := createAuthRequest(t, clientID, redirectURI, oidc.ScopeOpenID, zitadelAudienceScope)
|
||||
sessionID, sessionToken, startTime, changeTime := Tester.CreateVerfiedWebAuthNSession(t, CTXLOGIN, User.GetUserId())
|
||||
sessionID, sessionToken, startTime, changeTime := Tester.CreateVerifiedWebAuthNSession(t, CTXLOGIN, User.GetUserId())
|
||||
linkResp, err := Tester.Client.OIDCv2.CreateCallback(CTXLOGIN, &oidc_pb.CreateCallbackRequest{
|
||||
AuthRequestId: authRequestID,
|
||||
CallbackKind: &oidc_pb.CreateCallbackRequest_Session{
|
||||
@ -177,7 +177,7 @@ func Test_ZITADEL_API_success(t *testing.T) {
|
||||
func Test_ZITADEL_API_inactive_access_token(t *testing.T) {
|
||||
clientID := createClient(t)
|
||||
authRequestID := createAuthRequest(t, clientID, redirectURI, oidc.ScopeOpenID, oidc.ScopeOfflineAccess, zitadelAudienceScope)
|
||||
sessionID, sessionToken, startTime, changeTime := Tester.CreateVerfiedWebAuthNSession(t, CTXLOGIN, User.GetUserId())
|
||||
sessionID, sessionToken, startTime, changeTime := Tester.CreateVerifiedWebAuthNSession(t, CTXLOGIN, User.GetUserId())
|
||||
linkResp, err := Tester.Client.OIDCv2.CreateCallback(CTXLOGIN, &oidc_pb.CreateCallbackRequest{
|
||||
AuthRequestId: authRequestID,
|
||||
CallbackKind: &oidc_pb.CreateCallbackRequest_Session{
|
||||
@ -219,7 +219,7 @@ func Test_ZITADEL_API_terminated_session(t *testing.T) {
|
||||
provider, err := Tester.CreateRelyingParty(CTX, clientID, redirectURI)
|
||||
require.NoError(t, err)
|
||||
authRequestID := createAuthRequest(t, clientID, redirectURI, oidc.ScopeOpenID, oidc.ScopeOfflineAccess, zitadelAudienceScope)
|
||||
sessionID, sessionToken, startTime, changeTime := Tester.CreateVerfiedWebAuthNSession(t, CTXLOGIN, User.GetUserId())
|
||||
sessionID, sessionToken, startTime, changeTime := Tester.CreateVerifiedWebAuthNSession(t, CTXLOGIN, User.GetUserId())
|
||||
linkResp, err := Tester.Client.OIDCv2.CreateCallback(CTXLOGIN, &oidc_pb.CreateCallbackRequest{
|
||||
AuthRequestId: authRequestID,
|
||||
CallbackKind: &oidc_pb.CreateCallbackRequest_Session{
|
||||
|
@ -119,7 +119,8 @@ func NewServer(
|
||||
}
|
||||
|
||||
server := &Server{
|
||||
LegacyServer: op.NewLegacyServer(provider, endpoints(config.CustomEndpoints)),
|
||||
LegacyServer: op.NewLegacyServer(provider, endpoints(config.CustomEndpoints)),
|
||||
signingKeyAlgorithm: config.SigningKeyAlgorithm,
|
||||
}
|
||||
metricTypes := []metrics.MetricType{metrics.MetricTypeRequestCount, metrics.MetricTypeStatusCode, metrics.MetricTypeTotalCount}
|
||||
server.Handler = op.RegisterLegacyServer(server, op.WithHTTPMiddleware(
|
||||
|
@ -6,12 +6,14 @@ import (
|
||||
|
||||
"github.com/zitadel/oidc/v3/pkg/oidc"
|
||||
"github.com/zitadel/oidc/v3/pkg/op"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/telemetry/tracing"
|
||||
)
|
||||
|
||||
type Server struct {
|
||||
http.Handler
|
||||
*op.LegacyServer
|
||||
signingKeyAlgorithm string
|
||||
}
|
||||
|
||||
func endpoints(endpointConfig *EndpointConfig) op.Endpoints {
|
||||
@ -79,7 +81,7 @@ func (s *Server) Discovery(ctx context.Context, r *op.Request[struct{}]) (_ *op.
|
||||
ctx, span := tracing.NewSpan(ctx)
|
||||
defer func() { span.EndWithError(err) }()
|
||||
|
||||
return s.LegacyServer.Discovery(ctx, r)
|
||||
return op.NewResponse(s.createDiscoveryConfig(ctx)), nil
|
||||
}
|
||||
|
||||
func (s *Server) Keys(ctx context.Context, r *op.Request[struct{}]) (_ *op.Response, err error) {
|
||||
@ -186,3 +188,34 @@ func (s *Server) EndSession(ctx context.Context, r *op.Request[oidc.EndSessionRe
|
||||
|
||||
return s.LegacyServer.EndSession(ctx, r)
|
||||
}
|
||||
|
||||
func (s *Server) createDiscoveryConfig(ctx context.Context) *oidc.DiscoveryConfiguration {
|
||||
issuer := op.IssuerFromContext(ctx)
|
||||
return &oidc.DiscoveryConfiguration{
|
||||
Issuer: issuer,
|
||||
AuthorizationEndpoint: s.Endpoints().Authorization.Absolute(issuer),
|
||||
TokenEndpoint: s.Endpoints().Token.Absolute(issuer),
|
||||
IntrospectionEndpoint: s.Endpoints().Introspection.Absolute(issuer),
|
||||
UserinfoEndpoint: s.Endpoints().Userinfo.Absolute(issuer),
|
||||
RevocationEndpoint: s.Endpoints().Revocation.Absolute(issuer),
|
||||
EndSessionEndpoint: s.Endpoints().EndSession.Absolute(issuer),
|
||||
JwksURI: s.Endpoints().JwksURI.Absolute(issuer),
|
||||
DeviceAuthorizationEndpoint: s.Endpoints().DeviceAuthorization.Absolute(issuer),
|
||||
ScopesSupported: op.Scopes(s.Provider()),
|
||||
ResponseTypesSupported: op.ResponseTypes(s.Provider()),
|
||||
GrantTypesSupported: op.GrantTypes(s.Provider()),
|
||||
SubjectTypesSupported: op.SubjectTypes(s.Provider()),
|
||||
IDTokenSigningAlgValuesSupported: []string{s.signingKeyAlgorithm},
|
||||
RequestObjectSigningAlgValuesSupported: op.RequestObjectSigAlgorithms(s.Provider()),
|
||||
TokenEndpointAuthMethodsSupported: op.AuthMethodsTokenEndpoint(s.Provider()),
|
||||
TokenEndpointAuthSigningAlgValuesSupported: op.TokenSigAlgorithms(s.Provider()),
|
||||
IntrospectionEndpointAuthSigningAlgValuesSupported: op.IntrospectionSigAlgorithms(s.Provider()),
|
||||
IntrospectionEndpointAuthMethodsSupported: op.AuthMethodsIntrospectionEndpoint(s.Provider()),
|
||||
RevocationEndpointAuthSigningAlgValuesSupported: op.RevocationSigAlgorithms(s.Provider()),
|
||||
RevocationEndpointAuthMethodsSupported: op.AuthMethodsRevocationEndpoint(s.Provider()),
|
||||
ClaimsSupported: op.SupportedClaims(s.Provider()),
|
||||
CodeChallengeMethodsSupported: op.CodeChallengeMethods(s.Provider()),
|
||||
UILocalesSupported: s.Provider().SupportedUILocales(),
|
||||
RequestParameterSupported: s.Provider().RequestObjectSupported(),
|
||||
}
|
||||
}
|
||||
|
119
internal/api/oidc/server_test.go
Normal file
119
internal/api/oidc/server_test.go
Normal file
@ -0,0 +1,119 @@
|
||||
package oidc
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/zitadel/oidc/v3/pkg/oidc"
|
||||
"github.com/zitadel/oidc/v3/pkg/op"
|
||||
"golang.org/x/text/language"
|
||||
)
|
||||
|
||||
func TestServer_createDiscoveryConfig(t *testing.T) {
|
||||
type fields struct {
|
||||
LegacyServer *op.LegacyServer
|
||||
signingKeyAlgorithm string
|
||||
}
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
args args
|
||||
want *oidc.DiscoveryConfiguration
|
||||
}{
|
||||
{
|
||||
"config",
|
||||
fields{
|
||||
LegacyServer: op.NewLegacyServer(
|
||||
func() *op.Provider {
|
||||
provider, _ := op.NewForwardedOpenIDProvider("path",
|
||||
&op.Config{
|
||||
CodeMethodS256: true,
|
||||
AuthMethodPost: true,
|
||||
AuthMethodPrivateKeyJWT: true,
|
||||
GrantTypeRefreshToken: true,
|
||||
RequestObjectSupported: true,
|
||||
SupportedUILocales: []language.Tag{language.English, language.German},
|
||||
},
|
||||
nil,
|
||||
)
|
||||
return provider
|
||||
}(),
|
||||
op.Endpoints{
|
||||
Authorization: op.NewEndpoint("auth"),
|
||||
Token: op.NewEndpoint("token"),
|
||||
Introspection: op.NewEndpoint("introspect"),
|
||||
Userinfo: op.NewEndpoint("userinfo"),
|
||||
Revocation: op.NewEndpoint("revoke"),
|
||||
EndSession: op.NewEndpoint("logout"),
|
||||
JwksURI: op.NewEndpoint("keys"),
|
||||
DeviceAuthorization: op.NewEndpoint("device"),
|
||||
},
|
||||
),
|
||||
signingKeyAlgorithm: "RS256",
|
||||
},
|
||||
args{
|
||||
ctx: op.ContextWithIssuer(context.Background(), "https://issuer.com"),
|
||||
},
|
||||
&oidc.DiscoveryConfiguration{
|
||||
Issuer: "https://issuer.com",
|
||||
AuthorizationEndpoint: "https://issuer.com/auth",
|
||||
TokenEndpoint: "https://issuer.com/token",
|
||||
IntrospectionEndpoint: "https://issuer.com/introspect",
|
||||
UserinfoEndpoint: "https://issuer.com/userinfo",
|
||||
RevocationEndpoint: "https://issuer.com/revoke",
|
||||
EndSessionEndpoint: "https://issuer.com/logout",
|
||||
DeviceAuthorizationEndpoint: "https://issuer.com/device",
|
||||
CheckSessionIframe: "",
|
||||
JwksURI: "https://issuer.com/keys",
|
||||
RegistrationEndpoint: "",
|
||||
ScopesSupported: []string{oidc.ScopeOpenID, oidc.ScopeProfile, oidc.ScopeEmail, oidc.ScopePhone, oidc.ScopeAddress, oidc.ScopeOfflineAccess},
|
||||
ResponseTypesSupported: []string{string(oidc.ResponseTypeCode), string(oidc.ResponseTypeIDTokenOnly), string(oidc.ResponseTypeIDToken)},
|
||||
ResponseModesSupported: nil,
|
||||
GrantTypesSupported: []oidc.GrantType{oidc.GrantTypeCode, oidc.GrantTypeImplicit, oidc.GrantTypeRefreshToken, oidc.GrantTypeBearer},
|
||||
ACRValuesSupported: nil,
|
||||
SubjectTypesSupported: []string{"public"},
|
||||
IDTokenSigningAlgValuesSupported: []string{"RS256"},
|
||||
IDTokenEncryptionAlgValuesSupported: nil,
|
||||
IDTokenEncryptionEncValuesSupported: nil,
|
||||
UserinfoSigningAlgValuesSupported: nil,
|
||||
UserinfoEncryptionAlgValuesSupported: nil,
|
||||
UserinfoEncryptionEncValuesSupported: nil,
|
||||
RequestObjectSigningAlgValuesSupported: []string{"RS256"},
|
||||
RequestObjectEncryptionAlgValuesSupported: nil,
|
||||
RequestObjectEncryptionEncValuesSupported: nil,
|
||||
TokenEndpointAuthMethodsSupported: []oidc.AuthMethod{oidc.AuthMethodNone, oidc.AuthMethodBasic, oidc.AuthMethodPost, oidc.AuthMethodPrivateKeyJWT},
|
||||
TokenEndpointAuthSigningAlgValuesSupported: []string{"RS256"},
|
||||
RevocationEndpointAuthMethodsSupported: []oidc.AuthMethod{oidc.AuthMethodNone, oidc.AuthMethodBasic, oidc.AuthMethodPost, oidc.AuthMethodPrivateKeyJWT},
|
||||
RevocationEndpointAuthSigningAlgValuesSupported: []string{"RS256"},
|
||||
IntrospectionEndpointAuthMethodsSupported: []oidc.AuthMethod{oidc.AuthMethodBasic, oidc.AuthMethodPrivateKeyJWT},
|
||||
IntrospectionEndpointAuthSigningAlgValuesSupported: []string{"RS256"},
|
||||
DisplayValuesSupported: nil,
|
||||
ClaimTypesSupported: nil,
|
||||
ClaimsSupported: []string{"sub", "aud", "exp", "iat", "iss", "auth_time", "nonce", "acr", "amr", "c_hash", "at_hash", "act", "scopes", "client_id", "azp", "preferred_username", "name", "family_name", "given_name", "locale", "email", "email_verified", "phone_number", "phone_number_verified"},
|
||||
ClaimsParameterSupported: false,
|
||||
CodeChallengeMethodsSupported: []oidc.CodeChallengeMethod{"S256"},
|
||||
ServiceDocumentation: "",
|
||||
ClaimsLocalesSupported: nil,
|
||||
UILocalesSupported: []language.Tag{language.English, language.German},
|
||||
RequestParameterSupported: true,
|
||||
RequestURIParameterSupported: false,
|
||||
RequireRequestURIRegistration: false,
|
||||
OPPolicyURI: "",
|
||||
OPTermsOfServiceURI: "",
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
s := &Server{
|
||||
LegacyServer: tt.fields.LegacyServer,
|
||||
signingKeyAlgorithm: tt.fields.signingKeyAlgorithm,
|
||||
}
|
||||
assert.Equalf(t, tt.want, s.createDiscoveryConfig(tt.args.ctx), "createDiscoveryConfig(%v)", tt.args.ctx)
|
||||
})
|
||||
}
|
||||
}
|
@ -242,6 +242,8 @@ RegistrationUser:
|
||||
Bulgarian: Български
|
||||
Portuguese: Português
|
||||
Macedonian: Македонски
|
||||
Czech: Čeština
|
||||
Russian: Русский
|
||||
GenderLabel: Пол
|
||||
Female: Женски пол
|
||||
Male: Мъжки
|
||||
@ -277,6 +279,8 @@ ExternalRegistrationUserOverview:
|
||||
Bulgarian: Български
|
||||
Portuguese: Português
|
||||
Macedonian: Македонски
|
||||
Czech: Čeština
|
||||
Russian: Русский
|
||||
TosAndPrivacyLabel: Правила и условия
|
||||
TosConfirm: Приемам
|
||||
TosLinkText: TOS
|
||||
@ -336,7 +340,8 @@ ExternalNotFound:
|
||||
Bulgarian: Български
|
||||
Portuguese: Português
|
||||
Macedonian: Македонски
|
||||
|
||||
Czech: Čeština
|
||||
Russian: Русский
|
||||
DeviceAuth:
|
||||
Title: Упълномощаване на устройството
|
||||
UserCode:
|
||||
|
487
internal/api/ui/login/static/i18n/cs.yaml
Normal file
487
internal/api/ui/login/static/i18n/cs.yaml
Normal file
@ -0,0 +1,487 @@
|
||||
Login:
|
||||
Title: Vítejte zpět!
|
||||
Description: Zadejte své přihlašovací údaje.
|
||||
TitleLinking: Přihlášení pro propojení uživatele
|
||||
DescriptionLinking: Zadejte své přihlašovací údaje pro propojení vašeho externího účtu.
|
||||
LoginNameLabel: Přihlašovací jméno
|
||||
UsernamePlaceHolder: uživatelské jméno
|
||||
LoginnamePlaceHolder: uzivatelskejmeno@doména
|
||||
ExternalUserDescription: Přihlášení s externím účtem.
|
||||
MustBeMemberOfOrg: Uživatel musí být členem organizace {{.OrgName}}.
|
||||
RegisterButtonText: Registrovat
|
||||
NextButtonText: Další
|
||||
|
||||
LDAP:
|
||||
Title: Přihlášení
|
||||
Description: Zadejte své přihlašovací údaje.
|
||||
LoginNameLabel: Přihlašovací jméno
|
||||
PasswordLabel: Heslo
|
||||
NextButtonText: Další
|
||||
|
||||
SelectAccount:
|
||||
Title: Vyberte účet
|
||||
Description: Použijte svůj účet
|
||||
TitleLinking: Vyberte účet pro propojení uživatele
|
||||
DescriptionLinking: Vyberte účet pro propojení s vaším externím uživatelem.
|
||||
OtherUser: Jiný uživatel
|
||||
SessionState0: aktivní
|
||||
SessionState1: Odhlášen
|
||||
MustBeMemberOfOrg: Uživatel musí být členem organizace {{.OrgName}}.
|
||||
|
||||
Password:
|
||||
Title: Heslo
|
||||
Description: Zadejte své přihlašovací údaje.
|
||||
PasswordLabel: Heslo
|
||||
MinLength: Minimální délka
|
||||
HasUppercase: Velké písmeno
|
||||
HasLowercase: Malé písmeno
|
||||
HasNumber: Číslo
|
||||
HasSymbol: Symbol
|
||||
Confirmation: Potvrzení shody
|
||||
ResetLinkText: Obnovit heslo
|
||||
BackButtonText: Zpět
|
||||
NextButtonText: Další
|
||||
|
||||
UsernameChange:
|
||||
Title: Změna uživatelského jména
|
||||
Description: Nastavte své nové uživatelské jméno
|
||||
UsernameLabel: Uživatelské jméno
|
||||
CancelButtonText: Zrušit
|
||||
NextButtonText: Další
|
||||
|
||||
UsernameChangeDone:
|
||||
Title: Uživatelské jméno bylo změněno
|
||||
Description: Vaše uživatelské jméno bylo úspěšně změněno.
|
||||
NextButtonText: Další
|
||||
|
||||
InitPassword:
|
||||
Title: Nastavit heslo
|
||||
Description: Obdrželi jste kód, který musíte vložit níže, abyste nastavili své nové heslo.
|
||||
CodeLabel: Kód
|
||||
NewPasswordLabel: Nové heslo
|
||||
NewPasswordConfirmLabel: Potvrzení hesla
|
||||
ResendButtonText: Znovu poslat kód
|
||||
NextButtonText: Další
|
||||
|
||||
InitPasswordDone:
|
||||
Title: Heslo nastaveno
|
||||
Description: Heslo bylo úspěšně nastaveno
|
||||
NextButtonText: Další
|
||||
CancelButtonText: Zrušit
|
||||
|
||||
InitUser:
|
||||
Title: Aktivovat uživatele
|
||||
Description: Ověřte váš e-mail pomocí níže uvedeného kódu a nastavte své heslo.
|
||||
CodeLabel: Kód
|
||||
NewPasswordLabel: Nové heslo
|
||||
NewPasswordConfirm: Potvrzení hesla
|
||||
NextButtonText: Další
|
||||
ResendButtonText: Znovu poslat kód
|
||||
|
||||
InitUserDone:
|
||||
Title: Uživatel aktivován
|
||||
Description: E-mail ověřen a heslo úspěšně nastaveno
|
||||
NextButtonText: Další
|
||||
CancelButtonText: Zrušit
|
||||
|
||||
InitMFAPrompt:
|
||||
Title: Nastavení 2-faktorové autentizace
|
||||
Description: 2-faktorová autentizace vám poskytuje další zabezpečení pro váš uživatelský účet. Tím je zajištěno, že k vašemu účtu máte přístup pouze vy.
|
||||
Provider0: Aplikace pro ověřování (např. Google/Microsoft Authenticator, Authy)
|
||||
Provider1: Zařízením závislé (např. FaceID, Windows Hello, Otisk prstu)
|
||||
Provider3: OTP SMS
|
||||
Provider4: OTP E-mail
|
||||
NextButtonText: Další
|
||||
SkipButtonText: Přeskočit
|
||||
|
||||
InitMFAOTP:
|
||||
Title: 2-Faktorové ověření
|
||||
Description: Vytvořte svou 2-faktorovou autentizaci. Stáhněte si ověřovací aplikaci, pokud ji ještě nemáte.
|
||||
OTPDescription: Naskenujte kód svou ověřovací aplikací (např. Google/Microsoft Authenticator, Authy) nebo zkopírujte tajemství a vložte níže vygenerovaný kód.
|
||||
SecretLabel: Tajemství
|
||||
CodeLabel: Kód
|
||||
NextButtonText: Další
|
||||
CancelButtonText: Zrušit
|
||||
|
||||
InitMFAOTPSMS:
|
||||
Title: 2-Faktorové ověření
|
||||
DescriptionPhone: Vytvořte svou 2-faktorovou autentizaci. Zadejte své telefonní číslo k jeho ověření.
|
||||
DescriptionCode: Vytvořte svou 2-faktorovou autentizaci. Zadejte obdržený kód k ověření vašeho telefonního čísla.
|
||||
PhoneLabel: Telefon
|
||||
CodeLabel: Kód
|
||||
EditButtonText: Upravit
|
||||
ResendButtonText: Znovu poslat kód
|
||||
NextButtonText: Další
|
||||
|
||||
InitMFAU2F:
|
||||
Title: Přidat bezpečnostní klíč
|
||||
Description: Bezpečnostní klíč je ověřovací metoda, která může být integrována do vašeho telefonu, používat Bluetooth nebo se přímo zapojit do USB portu vašeho počítače.
|
||||
TokenNameLabel: Název bezpečnostního klíče / zařízení
|
||||
NotSupported: WebAuthN není podporován vaším prohlížečem. Ujistěte se, že máte aktuální verzi, nebo použijte jiný (např. Chrome, Safari, Firefox)
|
||||
RegisterTokenButtonText: Přidat bezpečnostní klíč
|
||||
ErrorRetry: Zkuste to znovu, vytvořte novou výzvu nebo vyberte jinou metodu.
|
||||
|
||||
InitMFADone:
|
||||
Title: 2-Faktor ověřen
|
||||
Description: Skvělé! Úspěšně jste nastavili svou 2-faktorovou autentizaci a váš účet je nyní mnohem bezpečnější. Faktor musí být zadán při každém přihlášení.
|
||||
NextButtonText: Další
|
||||
CancelButtonText: Zrušit
|
||||
|
||||
MFAProvider:
|
||||
Provider0: Aplikace pro ověřování (např. Google/Microsoft Authenticator, Authy)
|
||||
Provider1: Zařízením závislé (např. FaceID, Windows Hello, Otisk prstu)
|
||||
Provider3: OTP SMS
|
||||
Provider4: OTP E-mail
|
||||
ChooseOther: nebo vyberte jinou možnost
|
||||
|
||||
VerifyMFAOTP:
|
||||
Title: Ověřte 2-Faktor
|
||||
Description: Ověřte váš druhý faktor
|
||||
CodeLabel: Kód
|
||||
NextButtonText: Další
|
||||
|
||||
VerifyOTP:
|
||||
Title: Ověřte 2-Faktor
|
||||
Description: Ověřte váš druhý faktor
|
||||
CodeLabel: Kód
|
||||
ResendButtonText: Znovu poslat kód
|
||||
NextButtonText: Další
|
||||
|
||||
VerifyMFAU2F:
|
||||
Title: 2-Faktorové ověření
|
||||
Description: Ověřte váš 2-Faktor pomocí registrovaného zařízení (např. FaceID, Windows Hello, Otisk prstu)
|
||||
NotSupported: WebAuthN není podporován vaším prohlížečem. Ujistěte se, že používáte nejnovější verzi, nebo změňte prohlížeč na podporovaný (Chrome, Safari, Firefox)
|
||||
ErrorRetry: Zkuste to znovu, vytvořte nový požadavek nebo vyberte jinou metodu.
|
||||
ValidateTokenButtonText: Ověřte 2-Faktor
|
||||
|
||||
Passwordless:
|
||||
Title: Bezheslové přihlášení
|
||||
Description: Přihlaste se pomocí ověřovacích metod poskytnutých vaším zařízením, jako je FaceID, Windows Hello nebo Otisk prstu.
|
||||
NotSupported: WebAuthN není podporován vaším prohlížečem. Ujistěte se, že máte aktuální verzi, nebo použijte jiný (např. Chrome, Safari, Firefox).
|
||||
ErrorRetry: Zkuste to znovu, vytvořte novou výzvu nebo vyberte jinou metodu.
|
||||
LoginWithPwButtonText: Přihlásit se heslem
|
||||
ValidateTokenButtonText: Přihlásit se bez hesla
|
||||
|
||||
PasswordlessPrompt:
|
||||
Title: Nastavení bezheslového přihlášení
|
||||
Description: Chcete nastavit přihlášení bez hesla? (Ověřovací metody vašeho zařízení, jako je FaceID, Windows Hello nebo Otisk prstu)
|
||||
DescriptionInit: Musíte nastavit přihlášení bez hesla. Použijte odkaz, který jste obdrželi, pro registraci vašeho zařízení.
|
||||
PasswordlessButtonText: Přihlásit se bez hesla
|
||||
NextButtonText: Další
|
||||
SkipButtonText: Přeskočit
|
||||
|
||||
PasswordlessRegistration:
|
||||
Title: Nastavení bezheslového přihlášení
|
||||
Description: Přidejte své ověření zadáním názvu (např. MůjMobil, MacBook atd.) a poté kliknutím na tlačítko 'Registrovat bez hesla' níže.
|
||||
TokenNameLabel: Název zařízení
|
||||
NotSupported: WebAuthN není podporován vaším prohlížečem. Ujistěte se, že máte aktuální verzi, nebo použijte jiný (např. Chrome, Safari, Firefox).
|
||||
RegisterTokenButtonText: Registrovat bez hesla
|
||||
ErrorRetry: Zkuste to znovu, vytvořte novou výzvu nebo vyberte jinou metodu.
|
||||
|
||||
PasswordlessRegistrationDone:
|
||||
Title: Nastavení bezheslového přihlášení dokončeno
|
||||
Description: Zařízení pro přihlášení bez hesla úspěšně přidáno.
|
||||
DescriptionClose: Nyní můžete toto okno zavřít.
|
||||
NextButtonText: Další
|
||||
CancelButtonText: Zrušit
|
||||
|
||||
PasswordChange:
|
||||
Title: Změna hesla
|
||||
Description: Změňte si heslo. Zadejte své staré a nové heslo.
|
||||
OldPasswordLabel: Staré heslo
|
||||
NewPasswordLabel: Nové heslo
|
||||
NewPasswordConfirmLabel: Potvrzení hesla
|
||||
CancelButtonText: Zrušit
|
||||
NextButtonText: Další
|
||||
Footer: Patička
|
||||
|
||||
PasswordChangeDone:
|
||||
Title: Změna hesla
|
||||
Description: Vaše heslo bylo úspěšně změněno.
|
||||
NextButtonText: Další
|
||||
|
||||
PasswordResetDone:
|
||||
Title: Odkaz na resetování hesla odeslán
|
||||
Description: Pro dokončení změny hesla zkontrolujte váš e-mail a postupujte podle instrukcí.
|
||||
NextButtonText: Další
|
||||
|
||||
EmailVerification:
|
||||
Title: Ověření e-mailu
|
||||
Description: Poslali jsme vám e-mail pro ověření vaší adresy. Zadejte kód do níže uvedeného formuláře.
|
||||
CodeLabel: Kód
|
||||
NextButtonText: Další
|
||||
ResendButtonText: Znovu poslat kód
|
||||
|
||||
EmailVerificationDone:
|
||||
Title: Ověření e-mailu
|
||||
Description: Vaše e-mailová adresa byla úspěšně ověřena.
|
||||
NextButtonText: Další
|
||||
CancelButtonText: Zrušit
|
||||
LoginButtonText: Přihlásit se
|
||||
|
||||
RegisterOption:
|
||||
Title: Možnosti registrace
|
||||
Description: Vyberte si, jak se chcete zaregistrovat
|
||||
RegisterUsernamePasswordButtonText: Pomocí uživatelského jména a hesla
|
||||
ExternalLoginDescription: nebo se zaregistrujte s externím uživatelem
|
||||
LoginButtonText: Přihlásit se
|
||||
|
||||
RegistrationUser:
|
||||
Title: Registrace
|
||||
Description: Zadejte své uživatelské údaje. Váš e-mail bude použit jako vaše přihlašovací jméno.
|
||||
DescriptionOrgRegister: Zadejte své uživatelské údaje.
|
||||
EmailLabel: E-mail
|
||||
UsernameLabel: Uživatelské jméno
|
||||
FirstnameLabel: Křestní jméno
|
||||
LastnameLabel: Příjmení
|
||||
LanguageLabel: Jazyk
|
||||
German: Deutsch
|
||||
English: English
|
||||
Italian: Italiano
|
||||
French: Français
|
||||
Chinese: 简体中文
|
||||
Polish: Polski
|
||||
Japanese: 日本語
|
||||
Spanish: Español
|
||||
Bulgarian: Български
|
||||
Portuguese: Português
|
||||
Macedonian: Македонски
|
||||
Czech: Čeština
|
||||
Russian: Русский
|
||||
GenderLabel: Pohlaví
|
||||
Female: Žena
|
||||
Male: Muž
|
||||
Diverse: různorodé / X
|
||||
PasswordLabel: Heslo
|
||||
PasswordConfirmLabel: Potvrzení hesla
|
||||
TosAndPrivacyLabel: Obchodní podmínky
|
||||
TosConfirm: Souhlasím s
|
||||
TosLinkText: obchodními podmínkami
|
||||
PrivacyConfirm: Souhlasím se
|
||||
PrivacyLinkText: zásadami ochrany osobních údajů
|
||||
ExternalLogin: nebo se zaregistrujte s externím uživatelem
|
||||
BackButtonText: Přihlásit se
|
||||
NextButtonText: Další
|
||||
|
||||
ExternalRegistrationUserOverview:
|
||||
Title: Registrace externího uživatele
|
||||
Description: Vaše uživatelské údaje byly převzaty z vybraného poskytovatele. Nyní je můžete změnit nebo doplnit.
|
||||
EmailLabel: E-mail
|
||||
UsernameLabel: Uživatelské jméno
|
||||
FirstnameLabel: Křestní jméno
|
||||
LastnameLabel: Příjmení
|
||||
NicknameLabel: Přezdívka
|
||||
PhoneLabel: Telefonní číslo
|
||||
LanguageLabel: Jazyk
|
||||
German: Deutsch
|
||||
English: English
|
||||
Italian: Italiano
|
||||
French: Français
|
||||
Chinese: 简体中文
|
||||
Polish: Polski
|
||||
Japanese: 日本語
|
||||
Spanish: Español
|
||||
Bulgarian: Български
|
||||
Portuguese: Português
|
||||
Macedonian: Македонски
|
||||
Czech: Čeština
|
||||
Russian: Русский
|
||||
TosAndPrivacyLabel: Obchodní podmínky
|
||||
TosConfirm: Souhlasím s
|
||||
TosLinkText: obchodními podmínkami
|
||||
PrivacyConfirm: Souhlasím se
|
||||
PrivacyLinkText: zásadami ochrany osobních údajů
|
||||
ExternalLogin: nebo se zaregistrujte s externím uživatelem
|
||||
BackButtonText: Zpět
|
||||
NextButtonText: Uložit
|
||||
|
||||
RegistrationOrg:
|
||||
Title: Registrace organizace
|
||||
Description: Zadejte název vaší organizace a uživatelské údaje.
|
||||
OrgNameLabel: Název organizace
|
||||
EmailLabel: E-mail
|
||||
UsernameLabel: Uživatelské jméno
|
||||
FirstnameLabel: Křestní jméno
|
||||
LastnameLabel: Příjmení
|
||||
PasswordLabel: Heslo
|
||||
PasswordConfirmLabel: Potvrzení hesla
|
||||
TosAndPrivacyLabel: Obchodní podmínky
|
||||
TosConfirm: Souhlasím s
|
||||
TosLinkText: obchodními podmínkami
|
||||
PrivacyConfirm: Souhlasím se
|
||||
PrivacyLinkText: zásadami ochrany osobních údajů
|
||||
SaveButtonText: Vytvořit organizaci
|
||||
|
||||
LoginSuccess:
|
||||
Title: Úspěšné přihlášení
|
||||
AutoRedirectDescription: Budete automaticky přesměrováni zpět do vaší aplikace. Pokud ne, klikněte na tlačítko níže. Poté můžete okno zavřít.
|
||||
RedirectedDescription: Nyní můžete okno zavřít.
|
||||
NextButtonText: Další
|
||||
|
||||
LogoutDone:
|
||||
Title: Odhlášení proběhlo úspěšně
|
||||
Description: Byli jste úspěšně odhlášeni.
|
||||
LoginButtonText: Přihlásit se
|
||||
|
||||
LinkingUsersDone:
|
||||
Title: Propojení uživatele
|
||||
Description: Uživatel propojen.
|
||||
CancelButtonText: Zrušit
|
||||
NextButtonText: Další
|
||||
|
||||
ExternalNotFound:
|
||||
Title: Externí uživatel nenalezen
|
||||
Description: Externí uživatel nebyl nalezen. Chcete propojit svého uživatele nebo automaticky zaregistrovat nového?
|
||||
LinkButtonText: Propojit
|
||||
AutoRegisterButtonText: Registrovat
|
||||
TosAndPrivacyLabel: Obchodní podmínky
|
||||
TosConfirm: Souhlasím s
|
||||
TosLinkText: obchodními podmínkami
|
||||
PrivacyConfirm: Souhlasím s
|
||||
PrivacyLinkText: zásadami ochrany osobních údajů
|
||||
German: Deutsch
|
||||
English: English
|
||||
Italian: Italiano
|
||||
French: Français
|
||||
Chinese: 简体中文
|
||||
Polish: Polski
|
||||
Japanese: 日本語
|
||||
Spanish: Español
|
||||
Bulgarian: Български
|
||||
Portuguese: Português
|
||||
Macedonian: Македонски
|
||||
Czech: Čeština
|
||||
Russian: Русский
|
||||
DeviceAuth:
|
||||
Title: Autorizace zařízení
|
||||
UserCode:
|
||||
Label: Uživatelský kód
|
||||
Description: Zadejte uživatelský kód zobrazený na zařízení.
|
||||
ButtonNext: Další
|
||||
Action:
|
||||
Description: Povolte přístup zařízení.
|
||||
GrantDevice: chystáte se povolit zařízení
|
||||
AccessToScopes: přístup k následujícím rozsahům
|
||||
Button:
|
||||
Allow: Povolit
|
||||
Deny: Zamítnout
|
||||
Done:
|
||||
Description: Hotovo.
|
||||
Approved: Autorizace zařízení schválena. Nyní se můžete vrátit k zařízení.
|
||||
Denied: Autorizace zařízení zamítnuta. Nyní se můžete vrátit k zařízení.
|
||||
|
||||
Footer:
|
||||
PoweredBy: Provozováno pomocí
|
||||
Tos: Obchodní podmínky
|
||||
PrivacyPolicy: Zásady ochrany osobních údajů
|
||||
Help: Pomoc
|
||||
SupportEmail: E-mailová podpora
|
||||
|
||||
SignIn: Přihlašte se pomocí {{.Provider}}
|
||||
|
||||
Errors:
|
||||
Internal: Došlo k interní chybě
|
||||
AuthRequest:
|
||||
NotFound: Authrequest nebyl nalezen
|
||||
UserAgentNotCorresponding: User Agent neodpovídá
|
||||
UserAgentNotFound: ID User Agenta nebylo nalezeno
|
||||
TokenNotFound: Token nebyl nalezen
|
||||
RequestTypeNotSupported: Typ požadavku není podporován
|
||||
MissingParameters: Chybějící požadované parametry
|
||||
User:
|
||||
NotFound: Uživatel nebyl nalezen
|
||||
AlreadyExists: Uživatel již existuje
|
||||
Inactive: Uživatel je neaktivní
|
||||
NotFoundOnOrg: Uživatel nebyl nalezen ve zvolené organizaci
|
||||
NotAllowedOrg: Uživatel není členem požadované organizace
|
||||
NotMatchingUserID: ID uživatele a uživatele v authrequestu se neshodují
|
||||
UserIDMissing: ID uživatele chybí
|
||||
Invalid: Neplatná uživatelská data
|
||||
DomainNotAllowedAsUsername: Doména je již rezervována a nelze ji použít jako uživatelské jméno
|
||||
NotAllowedToLink: Uživatel nemá povoleno propojení s externím poskytovatelem přihlášení
|
||||
Profile:
|
||||
NotFound: Profil nenalezen
|
||||
NotChanged: Profil nebyl změněn
|
||||
Empty: Profil je prázdný
|
||||
FirstNameEmpty: Jméno v profilu je prázdné
|
||||
LastNameEmpty: Příjmení v profilu je prázdné
|
||||
IDMissing: Chybí ID profilu
|
||||
Email:
|
||||
NotFound: E-mail nenalezen
|
||||
Invalid: E-mail je neplatný
|
||||
AlreadyVerified: E-mail je již ověřen
|
||||
NotChanged: E-mail nebyl změněn
|
||||
Empty: E-mail je prázdný
|
||||
IDMissing: Chybí ID e-mailu
|
||||
Phone:
|
||||
NotFound: Telefon nenalezen
|
||||
Invalid: Telefon je neplatný
|
||||
AlreadyVerified: Telefon již byl ověřen
|
||||
Empty: Telefon je prázdný
|
||||
NotChanged: Telefon nebyl změněn
|
||||
Address:
|
||||
NotFound: Adresa nenalezena
|
||||
NotChanged: Adresa nebyla změněna
|
||||
Username:
|
||||
AlreadyExists: Uživatelské jméno již je obsazené
|
||||
Reserved: Uživatelské jméno není volné
|
||||
Empty: Uživatelské jméno je prázdné
|
||||
Password:
|
||||
ConfirmationWrong: Potvrzení hesla je nesprávné
|
||||
Empty: Heslo je prázdné
|
||||
Invalid: Heslo je neplatné
|
||||
InvalidAndLocked: Heslo je neplatné a uživatel je uzamčen, kontaktujte svého správce.
|
||||
NotChanged: Nové heslo nesmí být stejné jako stávající heslo
|
||||
UsernameOrPassword:
|
||||
Invalid: Uživatelské jméno nebo heslo je neplatné
|
||||
PasswordComplexityPolicy:
|
||||
NotFound: Zásady složitosti hesla nenalezeny
|
||||
MinLength: Heslo je příliš krátké
|
||||
HasLower: Heslo musí obsahovat malé písmeno
|
||||
HasUpper: Heslo musí obsahovat velké písmeno
|
||||
HasNumber: Heslo musí obsahovat číslo
|
||||
HasSymbol: Heslo musí obsahovat symbol
|
||||
Code:
|
||||
Expired: Kód vypršel
|
||||
Invalid: Kód je neplatný
|
||||
Empty: Kód je prázdný
|
||||
CryptoCodeNil: Krypto kód je nulový
|
||||
NotFound: Kód nebyl nalezen
|
||||
GeneratorAlgNotSupported: Nepodporovaný algoritmus generátoru
|
||||
EmailVerify:
|
||||
UserIDEmpty: ID uživatele je prázdné
|
||||
ExternalData:
|
||||
CouldNotRead: Externí data nebylo možné správně přečíst
|
||||
MFA:
|
||||
NoProviders: Žádní dostupní poskytovatelé vícefaktorového ověřování
|
||||
OTP:
|
||||
AlreadyReady: Vícefaktorové OTP (jednorázové heslo) je již nastaveno
|
||||
NotExisting: Vícefaktorové OTP (jednorázové heslo) neexistuje
|
||||
InvalidCode: Neplatný kód
|
||||
NotReady: Vícefaktorové OTP (jednorázové heslo) není připraveno
|
||||
Locked: Uživatel je uzamčen
|
||||
SomethingWentWrong: Něco se pokazilo
|
||||
NotActive: Uživatel není aktivní
|
||||
ExternalIDP:
|
||||
IDPTypeNotImplemented: Typ IDP není implementován
|
||||
NotAllowed: Externí poskytovatel přihlášení není povolen
|
||||
IDPConfigIDEmpty: ID konfigurace poskytovatele identity je prázdné
|
||||
ExternalUserIDEmpty: Externí ID uživatele je prázdné
|
||||
UserDisplayNameEmpty: Zobrazované jméno uživatele je prázdné
|
||||
NoExternalUserData: Nebyla přijata žádná externí uživatelská data
|
||||
CreationNotAllowed: Vytvoření nového uživatele není na tomto poskytovateli povoleno
|
||||
LinkingNotAllowed: Propojení uživatele není na tomto poskytovateli povoleno
|
||||
GrantRequired: Přihlášení není možné. Uživatel musí mít alespoň jeden oprávnění na aplikaci. Prosím, kontaktujte svého správce.
|
||||
ProjectRequired: Přihlášení není možné. Organizace uživatele musí být přidělena k projektu. Prosím, kontaktujte svého správce.
|
||||
IdentityProvider:
|
||||
InvalidConfig: Konfigurace poskytovatele identity je neplatná
|
||||
IAM:
|
||||
LockoutPolicy:
|
||||
NotExisting: Zásady uzamčení neexistují
|
||||
Org:
|
||||
LoginPolicy:
|
||||
RegistrationNotAllowed: Registrace není povolena
|
||||
DeviceAuth:
|
||||
NotExisting: Kód uživatelského zařízení neexistuje
|
||||
|
||||
optional: (volitelné)
|
@ -245,6 +245,8 @@ RegistrationUser:
|
||||
Bulgarian: Български
|
||||
Portuguese: Português
|
||||
Macedonian: Македонски
|
||||
Czech: Čeština
|
||||
Russian: Русский
|
||||
GenderLabel: Geschlecht
|
||||
Female: weiblich
|
||||
Male: männlich
|
||||
@ -281,6 +283,8 @@ ExternalRegistrationUserOverview:
|
||||
Bulgarian: Български
|
||||
Portuguese: Português
|
||||
Macedonian: Македонски
|
||||
Czech: Čeština
|
||||
Russian: Русский
|
||||
TosAndPrivacyLabel: Allgemeine Geschäftsbedingungen und Datenschutz
|
||||
TosConfirm: Ich akzeptiere die
|
||||
TosLinkText: AGB
|
||||
@ -345,7 +349,8 @@ ExternalNotFound:
|
||||
Bulgarian: Български
|
||||
Portuguese: Português
|
||||
Macedonian: Македонски
|
||||
|
||||
Czech: Čeština
|
||||
Russian: Русский
|
||||
DeviceAuth:
|
||||
Title: Gerätezulassung
|
||||
UserCode:
|
||||
|
@ -246,6 +246,8 @@ RegistrationUser:
|
||||
Bulgarian: Български
|
||||
Portuguese: Português
|
||||
Macedonian: Македонски
|
||||
Czech: Čeština
|
||||
Russian: Русский
|
||||
GenderLabel: Gender
|
||||
Female: Female
|
||||
Male: Male
|
||||
@ -282,6 +284,8 @@ ExternalRegistrationUserOverview:
|
||||
Bulgarian: Български
|
||||
Portuguese: Português
|
||||
Macedonian: Македонски
|
||||
Czech: Čeština
|
||||
Russian: Русский
|
||||
TosAndPrivacyLabel: Terms and conditions
|
||||
TosConfirm: I accept the
|
||||
TosLinkText: TOS
|
||||
@ -346,7 +350,8 @@ ExternalNotFound:
|
||||
Bulgarian: Български
|
||||
Portuguese: Português
|
||||
Macedonian: Македонски
|
||||
|
||||
Czech: Čeština
|
||||
Russian: Русский
|
||||
DeviceAuth:
|
||||
Title: Device Authorization
|
||||
UserCode:
|
||||
|
@ -246,6 +246,8 @@ RegistrationUser:
|
||||
Bulgarian: Български
|
||||
Portuguese: Português
|
||||
Macedonian: Македонски
|
||||
Czech: Čeština
|
||||
Russian: Русский
|
||||
GenderLabel: Género
|
||||
Female: Mujer
|
||||
Male: Hombre
|
||||
@ -282,6 +284,8 @@ ExternalRegistrationUserOverview:
|
||||
Bulgarian: Български
|
||||
Portuguese: Português
|
||||
Macedonian: Македонски
|
||||
Czech: Čeština
|
||||
Russian: Русский
|
||||
TosAndPrivacyLabel: Términos y condiciones
|
||||
TosConfirm: Acepto los
|
||||
TosLinkText: TDS
|
||||
@ -346,6 +350,8 @@ ExternalNotFound:
|
||||
Bulgarian: Български
|
||||
Portuguese: Português
|
||||
Macedonian: Македонски
|
||||
Czech: Čeština
|
||||
Russian: Русский
|
||||
|
||||
Footer:
|
||||
PoweredBy: Powered By
|
||||
|
@ -246,6 +246,8 @@ RegistrationUser:
|
||||
Bulgarian: Български
|
||||
Portuguese: Português
|
||||
Macedonian: Македонски
|
||||
Czech: Čeština
|
||||
Russian: Русский
|
||||
GenderLabel: Genre
|
||||
Female: Femme
|
||||
Male: Homme
|
||||
@ -282,6 +284,8 @@ ExternalRegistrationUserOverview:
|
||||
Bulgarian: Български
|
||||
Portuguese: Português
|
||||
Macedonian: Македонски
|
||||
Czech: Čeština
|
||||
Russian: Русский
|
||||
TosAndPrivacyLabel: Termes et conditions
|
||||
TosConfirm: J'accepte les
|
||||
TosLinkText: TOS
|
||||
@ -346,6 +350,8 @@ ExternalNotFound:
|
||||
Bulgarian: Български
|
||||
Portuguese: Português
|
||||
Macedonian: Македонски
|
||||
Czech: Čeština
|
||||
Russian: Русский
|
||||
|
||||
DeviceAuth:
|
||||
Title: Autorisation de l'appareil
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user