Merge branch 'main' into next

# Conflicts:
#	cmd/setup/config.go
#	cmd/setup/setup.go
This commit is contained in:
Livio Spring 2024-01-22 07:36:22 +01:00
commit 50faf37921
No known key found for this signature in database
GPG Key ID: 26BB1C2FA5952CF0
244 changed files with 6671 additions and 2762 deletions

View File

@ -48,6 +48,7 @@ jobs:
go_version: "1.21"
core_cache_key: ${{ needs.core.outputs.cache_key }}
core_cache_path: ${{ needs.core.outputs.cache_path }}
crdb_version: "23.1.13"
core-integration-test:
needs: core

View File

@ -12,6 +12,9 @@ on:
core_cache_path:
required: true
type: string
crdb_version:
required: false
type: string
jobs:
test:
@ -51,7 +54,7 @@ jobs:
-
name: test
if: ${{ steps.cache.outputs.cache-hit != 'true' }}
run: make core_unit_test
run: export ZITADEL_CRDB_VERSION="${{ inputs.crdb_version }}" && make core_unit_test
-
name: publish coverage
uses: codecov/codecov-action@v3.1.4

View File

@ -28,10 +28,10 @@ core_static:
.PHONY: core_generate_all
core_generate_all:
go install github.com/dmarkham/enumer@v1.5.9
go install github.com/rakyll/statik@v0.1.7
go install go.uber.org/mock/mockgen@v0.3.0
go install golang.org/x/tools/cmd/stringer@v0.15.0
go install github.com/dmarkham/enumer@v1.5.9 # https://pkg.go.dev/github.com/dmarkham/enumer?tab=versions
go install github.com/rakyll/statik@v0.1.7 # https://pkg.go.dev/github.com/rakyll/statik?tab=versions
go install go.uber.org/mock/mockgen@v0.4.0 # https://pkg.go.dev/go.uber.org/mock/mockgen?tab=versions
go install golang.org/x/tools/cmd/stringer@v0.17.0 # https://pkg.go.dev/golang.org/x/tools/cmd/stringer?tab=versions
go generate ./...
.PHONY: core_assets
@ -52,12 +52,12 @@ endif
.PHONY: core_grpc_dependencies
core_grpc_dependencies:
go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.31
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@v1.3
go install github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-grpc-gateway@v2.18.1
go install github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2@v2.18.1
go install github.com/envoyproxy/protoc-gen-validate@v1.0.2
go install github.com/bufbuild/buf/cmd/buf@v1.27.2
go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.32 # https://pkg.go.dev/google.golang.org/protobuf/cmd/protoc-gen-go?tab=versions
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@v1.3 # https://pkg.go.dev/google.golang.org/grpc/cmd/protoc-gen-go-grpc?tab=versions
go install github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-grpc-gateway@v2.19.0 # https://pkg.go.dev/github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-grpc-gateway?tab=versions
go install github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2@v2.19.0 # https://pkg.go.dev/github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2?tab=versions
go install github.com/envoyproxy/protoc-gen-validate@v1.0.3 # https://pkg.go.dev/github.com/envoyproxy/protoc-gen-validate?tab=versions
go install github.com/bufbuild/buf/cmd/buf@v1.28.1 # https://pkg.go.dev/github.com/bufbuild/buf/cmd/buf?tab=versions
.PHONY: core_api
core_api: core_api_generator core_grpc_dependencies

View File

@ -830,6 +830,9 @@ DefaultInstance:
# A value of "0s" means that all events are available.
# If this value is set, it overwrites the system default unless it is not reset via the admin API.
AuditLogRetention: # ZITADEL_DEFAULTINSTANCE_LIMITS_AUDITLOGRETENTION
# If Block is true, all requests except to /ui/console or the system API are blocked and /ui/login is redirected to /ui/console.
# /ui/console shows a message that the instance is blocked with a link to Console.InstanceManagementURL
Block: # ZITADEL_DEFAULTINSTANCE_LIMITS_BLOCK
Restrictions:
# DisallowPublicOrgRegistration defines if ZITADEL should expose the endpoint /ui/login/register/org
# If it is true, the endpoint returns the HTTP status 404 on GET requests, and 409 on POST requests.
@ -862,7 +865,8 @@ DefaultInstance:
# ResetInterval: 720h # 30 days
# # Amount defines the number of units for this quota
# Amount: 25000
# # Limit defines whether ZITADEL should block further usage when the configured amount is used
# # Limit defines whether ZITADEL should block further authenticated requests when the configured amount is used.
# # If you not only want to block authenticated requests but also authentication itself, consider using the system APIs SetLimits method.
# Limit: false
# # Notifications are emitted by ZITADEL when certain quota percentages are reached
# Notifications:

View File

@ -39,7 +39,7 @@ func New() *cobra.Command {
Long: `Sets up the minimum requirements to start ZITADEL.
Prerequisites:
- cockroachdb
- cockroachDB
The user provided by flags needs privileges to
- create the database if it does not exist

View File

@ -17,10 +17,10 @@ func newDatabase() *cobra.Command {
Short: "initialize only the database",
Long: `Sets up the ZITADEL database.
Prereqesits:
Prerequisites:
- cockroachDB or postgreSQL
The user provided by flags needs priviledge to
The user provided by flags needs privileges to
- create the database if it does not exist
- see other users and create a new one if the user does not exist
- grant all rights of the ZITADEL database to the user created if not yet set

View File

@ -17,7 +17,7 @@ func newGrant() *cobra.Command {
Short: "set ALL grant to user",
Long: `Sets ALL grant to the database user.
Prereqesits:
Prerequisites:
- cockroachDB or postgreSQL
`,
Run: func(cmd *cobra.Command, args []string) {

View File

@ -17,10 +17,10 @@ func newUser() *cobra.Command {
Short: "initialize only the database user",
Long: `Sets up the ZITADEL database user.
Prereqesits:
- cockroachDB or postreSQL
Prerequisites:
- cockroachDB or postgreSQL
The user provided by flags needs priviledge to
The user provided by flags needs privileges to
- create the database if it does not exist
- see other users and create a new one if the user does not exist
- grant all rights of the ZITADEL database to the user created if not yet set

View File

@ -19,7 +19,7 @@ func newZitadel() *cobra.Command {
Short: "initialize ZITADEL internals",
Long: `initialize ZITADEL internals.
Prereqesits:
Prerequisites:
- cockroachDB or postgreSQL with user and database
`,
Run: func(cmd *cobra.Command, args []string) {

26
cmd/setup/21.go Normal file
View File

@ -0,0 +1,26 @@
package setup
import (
"context"
_ "embed"
"github.com/zitadel/zitadel/internal/database"
)
var (
//go:embed 21.sql
addBlockFieldToLimits string
)
type AddBlockFieldToLimits struct {
dbClient *database.DB
}
func (mig *AddBlockFieldToLimits) Execute(ctx context.Context) error {
_, err := mig.dbClient.ExecContext(ctx, addBlockFieldToLimits)
return err
}
func (mig *AddBlockFieldToLimits) String() string {
return "21_add_block_field_to_limits"
}

1
cmd/setup/21.sql Normal file
View File

@ -0,0 +1 @@
ALTER TABLE IF EXISTS projections.limits ADD COLUMN IF NOT EXISTS block BOOLEAN;

View File

@ -42,10 +42,10 @@ func Cleanup(config *Config) {
es := eventstore.NewEventstore(config.Eventstore)
migration.RegisterMappers(es)
step, err := migration.LatestStep(ctx, es)
step, err := migration.LastStuckStep(ctx, es)
logging.OnError(err).Fatal("unable to query latest migration")
if step.BaseEvent.EventType != migration.StartedType {
if step == nil {
logging.Info("there is no stuck migration please run `zitadel setup`")
return
}

View File

@ -78,6 +78,7 @@ type Steps struct {
s18AddLowerFieldsToLoginNames *AddLowerFieldsToLoginNames
s19AddCurrentStatesIndex *AddCurrentSequencesIndex
s20AddByUserSessionIndex *AddByUserIndexToSession
s21AddBlockFieldToLimits *AddBlockFieldToLimits
}
type encryptionKeyConfig struct {

View File

@ -20,14 +20,11 @@ type externalConfigChange struct {
defaults systemdefaults.SystemDefaults
}
func (mig *externalConfigChange) SetLastExecution(lastRun map[string]interface{}) {
func (mig *externalConfigChange) Check(lastRun map[string]interface{}) bool {
mig.currentExternalDomain, _ = lastRun["externalDomain"].(string)
externalPort, _ := lastRun["externalPort"].(float64)
mig.currentExternalPort = uint16(externalPort)
mig.currentExternalSecure, _ = lastRun["externalSecure"].(bool)
}
func (mig *externalConfigChange) Check() bool {
return mig.currentExternalSecure != mig.ExternalSecure ||
mig.currentExternalPort != mig.ExternalPort ||
mig.currentExternalDomain != mig.ExternalDomain

View File

@ -8,18 +8,14 @@ import (
)
type projectionTables struct {
es *eventstore.Eventstore
currentVersion string
es *eventstore.Eventstore
Version string `json:"version"`
}
func (mig *projectionTables) SetLastExecution(lastRun map[string]interface{}) {
mig.currentVersion, _ = lastRun["version"].(string)
}
func (mig *projectionTables) Check() bool {
return mig.currentVersion != mig.Version
func (mig *projectionTables) Check(lastRun map[string]interface{}) bool {
currentVersion, _ := lastRun["version"].(string)
return currentVersion != mig.Version
}
func (mig *projectionTables) Execute(ctx context.Context) error {

View File

@ -111,6 +111,7 @@ func Setup(config *Config, steps *Steps, masterKey string) {
steps.s18AddLowerFieldsToLoginNames = &AddLowerFieldsToLoginNames{dbClient: queryDBClient}
steps.s19AddCurrentStatesIndex = &AddCurrentSequencesIndex{dbClient: queryDBClient}
steps.s20AddByUserSessionIndex = &AddByUserIndexToSession{dbClient: queryDBClient}
steps.s21AddBlockFieldToLimits = &AddBlockFieldToLimits{dbClient: queryDBClient}
err = projection.Create(ctx, projectionDBClient, eventstoreClient, config.Projections, nil, nil, nil)
logging.OnError(err).Fatal("unable to start projections")
@ -165,9 +166,11 @@ func Setup(config *Config, steps *Steps, masterKey string) {
logging.OnError(err).Fatalf("unable to migrate repeatable step: %s", repeatableStep.String())
}
// This step is executed after the repeatable steps because it adds fields to the login_names3 projection
// These steps are executed after the repeatable steps because they add fields projections
err = migration.Migrate(ctx, eventstoreClient, steps.s18AddLowerFieldsToLoginNames)
logging.WithFields("name", steps.s18AddLowerFieldsToLoginNames.String()).OnError(err).Fatal("migration failed")
err = migration.Migrate(ctx, eventstoreClient, steps.s21AddBlockFieldToLimits)
logging.WithFields("name", steps.s21AddBlockFieldToLimits.String()).OnError(err).Fatal("migration failed")
}
func readStmt(fs embed.FS, folder, typ, filename string) (string, error) {

View File

@ -384,10 +384,10 @@ func startAPIs(
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 {
if err := apis.RegisterService(ctx, user_v2.CreateServer(commands, queries, keys.User, keys.IDPConfig, idp.CallbackURL(config.ExternalSecure), idp.SAMLRootURL(config.ExternalSecure), assets.AssetAPI(config.ExternalSecure), permissionCheck)); err != nil {
return err
}
if err := apis.RegisterService(ctx, session.CreateServer(commands, queries, permissionCheck)); err != nil {
if err := apis.RegisterService(ctx, session.CreateServer(commands, queries)); err != nil {
return err
}
@ -439,14 +439,14 @@ func startAPIs(
return fmt.Errorf("unable to start console: %w", err)
}
apis.RegisterHandlerOnPrefix(console.HandlerPrefix, c)
consolePath := console.HandlerPrefix + "/"
l, err := login.CreateLogin(
config.Login,
commands,
queries,
authRepo,
store,
console.HandlerPrefix+"/",
consolePath,
oidcServer.AuthCallbackURL(),
provider.AuthCallbackURL(samlProvider),
config.ExternalSecure,
@ -455,7 +455,7 @@ func startAPIs(
provider.NewIssuerInterceptor(samlProvider.IssuerFromRequest).Handler,
instanceInterceptor.Handler,
assetsCache.Handler,
limitingAccessInterceptor.WithoutLimiting().Handle,
limitingAccessInterceptor.WithRedirect(consolePath).Handle,
keys.User,
keys.IDPConfig,
keys.CSRFCookieKey,

View File

@ -36,11 +36,11 @@
"codemirror": "^5.65.8",
"cors": "^2.8.5",
"file-saver": "^2.0.5",
"flag-icons": "^6.7.0",
"flag-icons": "^7.1.0",
"google-proto-files": "^4.0.0",
"google-protobuf": "^3.21.2",
"grpc-web": "^1.4.1",
"i18n-iso-countries": "^7.6.0",
"i18n-iso-countries": "^7.7.0",
"libphonenumber-js": "^1.10.49",
"material-design-icons-iconfont": "^6.1.1",
"moment": "^2.29.4",
@ -49,8 +49,8 @@
"rxjs": "~7.8.0",
"tinycolor2": "^1.6.0",
"tslib": "^2.6.2",
"uuid": "^9.0.0",
"zone.js": "~0.13.1"
"uuid": "^9.0.1",
"zone.js": "~0.13.3"
},
"devDependencies": {
"@angular-devkit/build-angular": "^16.2.2",
@ -65,13 +65,13 @@
"@bufbuild/buf": "^1.23.1",
"@types/file-saver": "^2.0.7",
"@types/google-protobuf": "^3.15.3",
"@types/jasmine": "~4.3.6",
"@types/jasminewd2": "~2.0.10",
"@types/jasmine": "~5.1.4",
"@types/jasminewd2": "~2.0.13",
"@types/jsonwebtoken": "^9.0.5",
"@types/node": "^20.7.0",
"@types/opentype.js": "^1.3.4",
"@types/opentype.js": "^1.3.8",
"@types/qrcode": "^1.5.2",
"@types/uuid": "^9.0.2",
"@types/uuid": "^9.0.7",
"@typescript-eslint/eslint-plugin": "^5.59.11",
"@typescript-eslint/parser": "^5.60.1",
"codelyzer": "^6.0.2",
@ -83,8 +83,8 @@
"karma-coverage-istanbul-reporter": "^3.0.3",
"karma-jasmine": "^5.1.0",
"karma-jasmine-html-reporter": "^2.1.0",
"prettier": "^3.0.3",
"prettier-plugin-organize-imports": "^3.2.2",
"prettier": "^3.1.1",
"prettier-plugin-organize-imports": "^3.2.4",
"protractor": "~7.0.0",
"typescript": "^5.1.6"
}

View File

@ -265,7 +265,12 @@ export class AppComponent implements OnDestroy {
}
public changedOrg(org: Org.AsObject): void {
this.router.navigate(['/org']);
// Reference: https://stackoverflow.com/a/58114797
const currentUrl = this.router.url;
this.router.navigateByUrl('/', { skipLocationChange: true }).then(() => {
// We use navigateByUrl as our urls may have queryParams
this.router.navigateByUrl(currentUrl);
});
}
private setLanguage(): void {

View File

@ -24,8 +24,8 @@
creationType === CreationType.PROJECT_OWNED
? ProjectAutocompleteType.PROJECT_OWNED
: creationType === CreationType.PROJECT_GRANTED
? ProjectAutocompleteType.PROJECT_GRANTED
: undefined
? ProjectAutocompleteType.PROJECT_GRANTED
: undefined
"
>
</cnsl-search-project-autocomplete>

View File

@ -180,13 +180,13 @@ export class CnslFormFieldComponent extends CnslFormFieldBase implements OnDestr
validationErrors: combined[0],
}
: combined[1]
? <Help>{
type: 'errors',
}
: <Help>{
type: 'hints',
validationErrors: undefined,
};
? <Help>{
type: 'errors',
}
: <Help>{
type: 'hints',
validationErrors: undefined,
};
}),
);
this._changeDetectorRef.markForCheck();

View File

@ -83,3 +83,23 @@ function i18nErr(err: ValidationErrors | null | undefined, i18nKey: string, para
};
}
}
const isFieldEmpty = (fieldName: string, g: AbstractControl) => {
const field = g.get(fieldName)?.value;
if (typeof field === 'number') {
return field && field >= 0 ? true : false;
}
if (typeof field === 'string') {
return field && field.length > 0 ? true : false;
}
return false;
};
// Reference: https://stackoverflow.com/a/56057955
export function atLeastOneIsFilled(...fields: string[]): ValidationErrors | null {
return (g: AbstractControl): ValidationErrors | null => {
return fields.some((fieldName) => isFieldEmpty(fieldName, g))
? null
: ({ atLeastOne: 'At least one field has to be provided.' } as ValidationErrors);
};
}

View File

@ -141,8 +141,8 @@
serviceType === PolicyComponentServiceType.ADMIN
? 'iam.idp.write'
: serviceType === PolicyComponentServiceType.MGMT
? 'org.idp.write'
: ''
? 'org.idp.write'
: ''
]
| hasRole
| async) === false
@ -161,8 +161,8 @@
serviceType === PolicyComponentServiceType.ADMIN
? 'iam.idp.write'
: serviceType === PolicyComponentServiceType.MGMT
? 'org.idp.write'
: ''
? 'org.idp.write'
: ''
]
| hasRole
| async) === false
@ -185,8 +185,8 @@
serviceType === PolicyComponentServiceType.ADMIN
? 'iam.idp.write'
: serviceType === PolicyComponentServiceType.MGMT
? 'org.idp.write'
: ''
? 'org.idp.write'
: ''
]
| hasRole
| async) === false

View File

@ -16,8 +16,8 @@
serviceType === PolicyComponentServiceType.ADMIN
? 'iam.policy.write'
: serviceType === PolicyComponentServiceType.MGMT
? 'policy.write'
: ''
? 'policy.write'
: ''
]
| hasRole
| async) === false
@ -38,8 +38,8 @@
serviceType === PolicyComponentServiceType.ADMIN
? 'iam.policy.write'
: serviceType === PolicyComponentServiceType.MGMT
? 'policy.write'
: ''
? 'policy.write'
: ''
]
| hasRole
| async) === false
@ -57,21 +57,21 @@
<div class="left-right">
<div *ngIf="domainData.userLoginMustBeDomain"><small>domain</small><span>acme.com</span></div>
<div *ngIf="domainData.userLoginMustBeDomain"><small>username</small><span>john</span></div>
<div *ngIf="domainData.userLoginMustBeDomain"><small>loginname</small><span>john@acme.com</span></div>
<div *ngIf="domainData.userLoginMustBeDomain"><small>loginname</small><span>john&#64;acme.com</span></div>
<div *ngIf="!domainData.userLoginMustBeDomain"><small>domain</small><span>acme.com</span></div>
<div *ngIf="!domainData.userLoginMustBeDomain"><small>username</small><span>john@acme.com</span></div>
<div *ngIf="!domainData.userLoginMustBeDomain"><small>loginname</small><span>john@acme.com</span></div>
<div *ngIf="!domainData.userLoginMustBeDomain"><small>username</small><span>john&#64;acme.com</span></div>
<div *ngIf="!domainData.userLoginMustBeDomain"><small>loginname</small><span>john&#64;acme.com</span></div>
</div>
<i class="las la-arrow-right"></i>
<div class="left-right">
<div *ngIf="domainData.userLoginMustBeDomain"><small>domain</small><span>acme.com</span></div>
<div *ngIf="domainData.userLoginMustBeDomain"><small>username</small><span>john@acme.com</span></div>
<div *ngIf="domainData.userLoginMustBeDomain"><small>loginname</small><span>john@acme.com</span></div>
<div *ngIf="domainData.userLoginMustBeDomain"><small>username</small><span>john&#64;acme.com</span></div>
<div *ngIf="domainData.userLoginMustBeDomain"><small>loginname</small><span>john&#64;acme.com</span></div>
<div *ngIf="!domainData.userLoginMustBeDomain"><small>domain</small><span>acme.com</span></div>
<div *ngIf="!domainData.userLoginMustBeDomain"><small>username</small><span>john</span></div>
<div *ngIf="!domainData.userLoginMustBeDomain"><small>loginname</small><span>john@acme.com</span></div>
<div *ngIf="!domainData.userLoginMustBeDomain"><small>loginname</small><span>john&#64;acme.com</span></div>
</div>
</div>
</div>
@ -88,8 +88,8 @@
serviceType === PolicyComponentServiceType.ADMIN
? 'iam.policy.write'
: serviceType === PolicyComponentServiceType.MGMT
? 'policy.write'
: ''
? 'policy.write'
: ''
]
| hasRole
| async) === false
@ -110,8 +110,8 @@
serviceType === PolicyComponentServiceType.ADMIN
? 'iam.policy.write'
: serviceType === PolicyComponentServiceType.MGMT
? 'policy.write'
: ''
? 'policy.write'
: ''
]
| hasRole
| async) === false
@ -133,8 +133,8 @@
serviceType === PolicyComponentServiceType.ADMIN
? 'iam.policy.write'
: serviceType === PolicyComponentServiceType.MGMT
? 'policy.write'
: ''
? 'policy.write'
: ''
]
| hasRole
| async) === false

View File

@ -14,8 +14,8 @@
serviceType === PolicyComponentServiceType.ADMIN
? ['/instance', 'provider', 'google', 'create']
: serviceType === PolicyComponentServiceType.MGMT
? ['/org', 'provider', 'google', 'create']
: []
? ['/org', 'provider', 'google', 'create']
: []
"
>
<img class="idp-logo" src="./assets/images/idp/google.png" alt="google" />
@ -30,8 +30,8 @@
serviceType === PolicyComponentServiceType.ADMIN
? ['/instance', 'provider', 'azure-ad', 'create']
: serviceType === PolicyComponentServiceType.MGMT
? ['/org', 'provider', 'azure-ad', 'create']
: []
? ['/org', 'provider', 'azure-ad', 'create']
: []
"
>
<img class="idp-logo" src="./assets/images/idp/ms.svg" alt="microsoft" />
@ -47,8 +47,8 @@
serviceType === PolicyComponentServiceType.ADMIN
? ['/instance', 'provider', 'github', 'create']
: serviceType === PolicyComponentServiceType.MGMT
? ['/org', 'provider', 'github', 'create']
: []
? ['/org', 'provider', 'github', 'create']
: []
"
>
<img class="idp-logo dark" src="./assets/images/idp/github-dark.svg" alt="GitHub" />
@ -65,8 +65,8 @@
serviceType === PolicyComponentServiceType.ADMIN
? ['/instance', 'provider', 'github-es', 'create']
: serviceType === PolicyComponentServiceType.MGMT
? ['/org', 'provider', 'github-es', 'create']
: []
? ['/org', 'provider', 'github-es', 'create']
: []
"
>
<img class="idp-logo dark" src="./assets/images/idp/github-dark.svg" alt="GitHub" />
@ -83,8 +83,8 @@
serviceType === PolicyComponentServiceType.ADMIN
? ['/instance', 'provider', 'gitlab', 'create']
: serviceType === PolicyComponentServiceType.MGMT
? ['/org', 'provider', 'gitlab', 'create']
: []
? ['/org', 'provider', 'gitlab', 'create']
: []
"
>
<img class="idp-logo" src="./assets/images/idp/gitlab.svg" alt="GitLab" />
@ -99,8 +99,8 @@
serviceType === PolicyComponentServiceType.ADMIN
? ['/instance', 'provider', 'gitlab-self-hosted', 'create']
: serviceType === PolicyComponentServiceType.MGMT
? ['/org', 'provider', 'gitlab-self-hosted', 'create']
: []
? ['/org', 'provider', 'gitlab-self-hosted', 'create']
: []
"
>
<img class="idp-logo" src="./assets/images/idp/gitlab.svg" alt="GitLab" />
@ -115,8 +115,8 @@
serviceType === PolicyComponentServiceType.ADMIN
? ['/instance', 'provider', 'apple', 'create']
: serviceType === PolicyComponentServiceType.MGMT
? ['/org', 'provider', 'apple', 'create']
: []
? ['/org', 'provider', 'apple', 'create']
: []
"
>
<img class="idp-logo apple dark" src="./assets/images/idp/apple-dark.svg" alt="Apple" />
@ -132,8 +132,8 @@
serviceType === PolicyComponentServiceType.ADMIN
? ['/instance', 'provider', 'oidc', 'create']
: serviceType === PolicyComponentServiceType.MGMT
? ['/org', 'provider', 'oidc', 'create']
: []
? ['/org', 'provider', 'oidc', 'create']
: []
"
>
<div class="idp-icon">
@ -150,8 +150,8 @@
serviceType === PolicyComponentServiceType.ADMIN
? ['/instance', 'provider', 'oauth', 'create']
: serviceType === PolicyComponentServiceType.MGMT
? ['/org', 'provider', 'oauth', 'create']
: []
? ['/org', 'provider', 'oauth', 'create']
: []
"
>
<img class="idp-logo" src="./assets/images/idp/oauth.svg" alt="oauth" />
@ -167,8 +167,8 @@
serviceType === PolicyComponentServiceType.ADMIN
? ['/instance', 'provider', 'jwt', 'create']
: serviceType === PolicyComponentServiceType.MGMT
? ['/org', 'provider', 'jwt', 'create']
: []
? ['/org', 'provider', 'jwt', 'create']
: []
"
>
<div class="idp-icon">
@ -185,8 +185,8 @@
serviceType === PolicyComponentServiceType.ADMIN
? ['/instance', 'provider', 'ldap', 'create']
: serviceType === PolicyComponentServiceType.MGMT
? ['/org', 'provider', 'ldap', 'create']
: []
? ['/org', 'provider', 'ldap', 'create']
: []
"
>
<div class="idp-icon">
@ -203,8 +203,8 @@
serviceType === PolicyComponentServiceType.ADMIN
? ['/instance', 'provider', 'saml', 'create']
: serviceType === PolicyComponentServiceType.MGMT
? ['/org', 'provider', 'saml', 'create']
: []
? ['/org', 'provider', 'saml', 'create']
: []
"
>
<img class="idp-logo" src="./assets/images/idp/saml-icon.svg" alt="oauth" />

View File

@ -12,8 +12,8 @@
(data.componentType === LoginMethodComponentType.SecondFactor
? 'MFA.SECONDFACTORTYPES.'
: LoginMethodComponentType.MultiFactor
? 'MFA.MULTIFACTORTYPES.'
: '') + mfa | translate
? 'MFA.MULTIFACTORTYPES.'
: '') + mfa | translate
}}
</mat-option>
</mat-select>

View File

@ -9,8 +9,8 @@
(componentType === LoginMethodComponentType.SecondFactor
? 'MFA.SECONDFACTORTYPES.'
: LoginMethodComponentType.MultiFactor
? 'MFA.MULTIFACTORTYPES.'
: '') + mfa | translate
? 'MFA.MULTIFACTORTYPES.'
: '') + mfa | translate
}}
</span>

View File

@ -150,13 +150,13 @@ export class FactorTableComponent {
this.componentType === LoginMethodComponentType.MultiFactor
? [MultiFactorType.MULTI_FACTOR_TYPE_U2F_WITH_VERIFICATION]
: this.componentType === LoginMethodComponentType.SecondFactor
? [
SecondFactorType.SECOND_FACTOR_TYPE_U2F,
SecondFactorType.SECOND_FACTOR_TYPE_OTP,
SecondFactorType.SECOND_FACTOR_TYPE_OTP_SMS,
SecondFactorType.SECOND_FACTOR_TYPE_OTP_EMAIL,
]
: [];
? [
SecondFactorType.SECOND_FACTOR_TYPE_U2F,
SecondFactorType.SECOND_FACTOR_TYPE_OTP,
SecondFactorType.SECOND_FACTOR_TYPE_OTP_SMS,
SecondFactorType.SECOND_FACTOR_TYPE_OTP_EMAIL,
]
: [];
const filtered = (allTypes as Array<MultiFactorType | SecondFactorType>).filter((type) => !this.list.includes(type));

View File

@ -34,8 +34,8 @@
serviceType === PolicyComponentServiceType.ADMIN
? 'iam.policy.write'
: serviceType === PolicyComponentServiceType.MGMT
? 'policy.write'
: ''
? 'policy.write'
: ''
]
| hasRole
| async) === false
@ -62,8 +62,8 @@
serviceType === PolicyComponentServiceType.ADMIN
? 'iam.policy.write'
: serviceType === PolicyComponentServiceType.MGMT
? 'policy.write'
: ''
? 'policy.write'
: ''
]
| hasRole
| async) === false
@ -89,8 +89,8 @@
serviceType === PolicyComponentServiceType.ADMIN
? 'iam.policy.write'
: serviceType === PolicyComponentServiceType.MGMT
? 'policy.write'
: ''
? 'policy.write'
: ''
]
| hasRole
| async) === false
@ -111,8 +111,8 @@
serviceType === PolicyComponentServiceType.ADMIN
? 'iam.policy.write'
: serviceType === PolicyComponentServiceType.MGMT
? 'policy.write'
: ''
? 'policy.write'
: ''
]
| hasRole
| async) === false
@ -134,8 +134,8 @@
serviceType === PolicyComponentServiceType.ADMIN
? 'iam.policy.write'
: serviceType === PolicyComponentServiceType.MGMT
? 'policy.write'
: ''
? 'policy.write'
: ''
]
| hasRole
| async) === false
@ -210,8 +210,8 @@
serviceType === PolicyComponentServiceType.ADMIN
? 'iam.policy.write'
: serviceType === PolicyComponentServiceType.MGMT
? 'policy.write'
: ''
? 'policy.write'
: ''
]
| hasRole
| async) === false
@ -235,8 +235,8 @@
serviceType === PolicyComponentServiceType.ADMIN
? 'iam.policy.write'
: serviceType === PolicyComponentServiceType.MGMT
? 'policy.write'
: ''
? 'policy.write'
: ''
]
| hasRole
| async) === false
@ -268,8 +268,8 @@
serviceType === PolicyComponentServiceType.ADMIN
? 'iam.policy.write'
: serviceType === PolicyComponentServiceType.MGMT
? 'policy.write'
: ''
? 'policy.write'
: ''
]
| hasRole
| async) === false
@ -296,8 +296,8 @@
serviceType === PolicyComponentServiceType.ADMIN
? 'iam.policy.write'
: serviceType === PolicyComponentServiceType.MGMT
? 'policy.write'
: ''
? 'policy.write'
: ''
]
| hasRole
| async) === false
@ -324,8 +324,8 @@
serviceType === PolicyComponentServiceType.ADMIN
? 'iam.policy.write'
: serviceType === PolicyComponentServiceType.MGMT
? 'policy.write'
: ''
? 'policy.write'
: ''
]
| hasRole
| async) === false
@ -346,8 +346,8 @@
serviceType === PolicyComponentServiceType.ADMIN
? 'iam.policy.write'
: serviceType === PolicyComponentServiceType.MGMT
? 'policy.write'
: ''
? 'policy.write'
: ''
]
| hasRole
| async) === false
@ -368,8 +368,8 @@
serviceType === PolicyComponentServiceType.ADMIN
? 'iam.policy.write'
: serviceType === PolicyComponentServiceType.MGMT
? 'policy.write'
: ''
? 'policy.write'
: ''
]
| hasRole
| async) === false
@ -390,8 +390,8 @@
serviceType === PolicyComponentServiceType.ADMIN
? 'iam.policy.write'
: serviceType === PolicyComponentServiceType.MGMT
? 'policy.write'
: ''
? 'policy.write'
: ''
]
| hasRole
| async) === false
@ -413,8 +413,8 @@
serviceType === PolicyComponentServiceType.ADMIN
? 'iam.policy.write'
: serviceType === PolicyComponentServiceType.MGMT
? 'policy.write'
: ''
? 'policy.write'
: ''
]
| hasRole
| async) === false
@ -439,8 +439,8 @@
serviceType === PolicyComponentServiceType.ADMIN
? 'iam.policy.write'
: serviceType === PolicyComponentServiceType.MGMT
? 'policy.write'
: ''
? 'policy.write'
: ''
]
| hasRole
| async) === false

View File

@ -25,6 +25,15 @@ import { WarnDialogComponent } from '../../warn-dialog/warn-dialog.component';
import { PolicyComponentServiceType } from '../policy-component-types.enum';
import { LoginMethodComponentType } from './factor-table/factor-table.component';
import { catchError, map, takeUntil } from 'rxjs/operators';
import { error } from 'console';
const minValueValidator = (minValue: number) => (control: AbstractControl) => {
const value = control.value;
if (value !== null && value < minValue) {
return { minValue: true, message: `Minimum value allowed is ${minValue}.` };
}
return null;
};
@Component({
selector: 'cnsl-login-policy',
@ -48,11 +57,11 @@ export class LoginPolicyComponent implements OnInit, OnDestroy {
public InfoSectionType: any = InfoSectionType;
public PasswordlessType: any = PasswordlessType;
public lifetimeForm: UntypedFormGroup = this.fb.group({
passwordCheckLifetime: [{ disabled: true }, [requiredValidator]],
externalLoginCheckLifetime: [{ disabled: true }, [requiredValidator]],
mfaInitSkipLifetime: [{ disabled: true }, [requiredValidator]],
secondFactorCheckLifetime: [{ disabled: true }, [requiredValidator]],
multiFactorCheckLifetime: [{ disabled: true }, [requiredValidator]],
passwordCheckLifetime: [{ disabled: true }, [requiredValidator, minValueValidator(1)]],
externalLoginCheckLifetime: [{ disabled: true }, [requiredValidator, minValueValidator(1)]],
mfaInitSkipLifetime: [{ disabled: true }, [requiredValidator, minValueValidator(0)]],
secondFactorCheckLifetime: [{ disabled: true }, [requiredValidator, minValueValidator(1)]],
multiFactorCheckLifetime: [{ disabled: true }, [requiredValidator, minValueValidator(1)]],
});
private destroy$: Subject<void> = new Subject();
@ -142,8 +151,8 @@ export class LoginPolicyComponent implements OnInit, OnDestroy {
this.serviceType === PolicyComponentServiceType.ADMIN
? ['iam.policy.write']
: this.serviceType === PolicyComponentServiceType.MGMT
? ['policy.write']
: [],
? ['policy.write']
: [],
)
.pipe(take(1))
.subscribe((allowed) => {
@ -285,6 +294,12 @@ export class LoginPolicyComponent implements OnInit, OnDestroy {
}
public savePolicy(): void {
if (this.lifetimeForm.invalid) {
// Display error message
this.toast.showError('POLICY.LOGIN_POLICY.LIFETIME_INVALID', false, true);
return;
}
this.updateData()
.then(() => {
this.toast.showInfo('POLICY.LOGIN_POLICY.SAVED', true);

View File

@ -134,8 +134,8 @@ export class LoginTextsComponent implements OnInit, OnDestroy {
this.serviceType === PolicyComponentServiceType.ADMIN
? 'iam.policy.write'
: this.serviceType === PolicyComponentServiceType.MGMT
? 'policy.write'
: '',
? 'policy.write'
: '',
]);
constructor(
private authService: GrpcAuthService,

View File

@ -552,8 +552,8 @@ export class MessageTextsComponent implements OnInit, OnDestroy {
this.serviceType === PolicyComponentServiceType.ADMIN
? 'iam.policy.write'
: this.serviceType === PolicyComponentServiceType.MGMT
? 'policy.write'
: '',
? 'policy.write'
: '',
]);
constructor(

View File

@ -42,8 +42,8 @@ export class PrivacyPolicyComponent implements OnInit, OnDestroy {
this.serviceType === PolicyComponentServiceType.ADMIN
? 'iam.policy.write'
: this.serviceType === PolicyComponentServiceType.MGMT
? 'policy.write'
: '',
? 'policy.write'
: '',
]);
public LANGPLACEHOLDER: string = '{{.Lang}}';

View File

@ -46,8 +46,8 @@
serviceType === PolicyComponentServiceType.ADMIN
? 'iam.policy.write'
: serviceType === PolicyComponentServiceType.MGMT
? 'policy.write'
: ''
? 'policy.write'
: ''
]
| hasRole
| async) === false
@ -150,8 +150,8 @@
serviceType === PolicyComponentServiceType.ADMIN
? 'iam.policy.delete'
: serviceType === PolicyComponentServiceType.MGMT
? 'policy.delete'
: ''
? 'policy.delete'
: ''
]
| hasRole
| async) === false
@ -174,8 +174,8 @@
serviceType === PolicyComponentServiceType.ADMIN
? 'iam.policy.write'
: serviceType === PolicyComponentServiceType.MGMT
? 'policy.write'
: ''
? 'policy.write'
: ''
]
| hasRole
| async) === false
@ -224,8 +224,8 @@
? previewData.logoUrlDark
: previewData.logoUrl
: theme === Theme.DARK
? data.logoUrlDark
: data.logoUrl as logoSrc;
? data.logoUrlDark
: data.logoUrl as logoSrc;
else addLogoButton
"
>
@ -241,8 +241,8 @@
serviceType === PolicyComponentServiceType.ADMIN
? 'iam.policy.write'
: serviceType === PolicyComponentServiceType.MGMT
? 'policy.write'
: ''
? 'policy.write'
: ''
]
| hasRole
| async) === false
@ -271,8 +271,8 @@
serviceType === PolicyComponentServiceType.ADMIN
? 'iam.policy.write'
: serviceType === PolicyComponentServiceType.MGMT
? 'policy.write'
: ''
? 'policy.write'
: ''
]
| hasRole
| async) === false
@ -295,8 +295,8 @@
? previewData.iconUrlDark
: previewData.iconUrl
: theme === Theme.DARK
? data.iconUrlDark
: data.iconUrl as iconSrc;
? data.iconUrlDark
: data.iconUrl as iconSrc;
else addIconButton
"
>
@ -312,8 +312,8 @@
serviceType === PolicyComponentServiceType.ADMIN
? 'iam.policy.write'
: serviceType === PolicyComponentServiceType.MGMT
? 'policy.write'
: ''
? 'policy.write'
: ''
]
| hasRole
| async) === false
@ -342,8 +342,8 @@
serviceType === PolicyComponentServiceType.ADMIN
? 'iam.policy.write'
: serviceType === PolicyComponentServiceType.MGMT
? 'policy.write'
: ''
? 'policy.write'
: ''
]
| hasRole
| async) === false
@ -385,8 +385,8 @@
serviceType === PolicyComponentServiceType.ADMIN
? 'iam.policy.write'
: serviceType === PolicyComponentServiceType.MGMT
? 'policy.write'
: ''
? 'policy.write'
: ''
]
| hasRole
| async) === false
@ -407,8 +407,8 @@
serviceType === PolicyComponentServiceType.ADMIN
? 'iam.policy.write'
: serviceType === PolicyComponentServiceType.MGMT
? 'policy.write'
: ''
? 'policy.write'
: ''
]
| hasRole
| async) === false
@ -430,8 +430,8 @@
serviceType === PolicyComponentServiceType.ADMIN
? 'iam.policy.write'
: serviceType === PolicyComponentServiceType.MGMT
? 'policy.write'
: ''
? 'policy.write'
: ''
]
| hasRole
| async) === false
@ -453,8 +453,8 @@
serviceType === PolicyComponentServiceType.ADMIN
? 'iam.policy.write'
: serviceType === PolicyComponentServiceType.MGMT
? 'policy.write'
: ''
? 'policy.write'
: ''
]
| hasRole
| async) === false
@ -480,8 +480,8 @@
serviceType === PolicyComponentServiceType.ADMIN
? 'iam.policy.write'
: serviceType === PolicyComponentServiceType.MGMT
? 'policy.write'
: ''
? 'policy.write'
: ''
]
| hasRole
| async) === false
@ -502,8 +502,8 @@
serviceType === PolicyComponentServiceType.ADMIN
? 'iam.policy.write'
: serviceType === PolicyComponentServiceType.MGMT
? 'policy.write'
: ''
? 'policy.write'
: ''
]
| hasRole
| async) === false
@ -525,8 +525,8 @@
serviceType === PolicyComponentServiceType.ADMIN
? 'iam.policy.write'
: serviceType === PolicyComponentServiceType.MGMT
? 'policy.write'
: ''
? 'policy.write'
: ''
]
| hasRole
| async) === false
@ -547,8 +547,8 @@
serviceType === PolicyComponentServiceType.ADMIN
? 'iam.policy.write'
: serviceType === PolicyComponentServiceType.MGMT
? 'policy.write'
: ''
? 'policy.write'
: ''
]
| hasRole
| async) === false
@ -592,8 +592,8 @@
serviceType === PolicyComponentServiceType.ADMIN
? 'iam.policy.write'
: serviceType === PolicyComponentServiceType.MGMT
? 'policy.write'
: ''
? 'policy.write'
: ''
]
| hasRole
| async) === false
@ -630,8 +630,8 @@
serviceType === PolicyComponentServiceType.ADMIN
? 'iam.policy.write'
: serviceType === PolicyComponentServiceType.MGMT
? 'policy.write'
: ''
? 'policy.write'
: ''
]
| hasRole
| async) === false
@ -669,8 +669,8 @@
serviceType === PolicyComponentServiceType.ADMIN
? 'iam.policy.write'
: serviceType === PolicyComponentServiceType.MGMT
? 'policy.write'
: ''
? 'policy.write'
: ''
]
| hasRole
| async) === false
@ -697,8 +697,8 @@
serviceType === PolicyComponentServiceType.ADMIN
? 'iam.policy.write'
: serviceType === PolicyComponentServiceType.MGMT
? 'policy.write'
: ''
? 'policy.write'
: ''
]
| hasRole
| async) === false

View File

@ -46,8 +46,8 @@ export class ProjectMembersDataSource extends DataSource<Member.AsObject> {
projectType === ProjectType.PROJECTTYPE_OWNED
? this.service.listProjectMembers(projectId, pageSize, offset)
: projectType === ProjectType.PROJECTTYPE_GRANTED && grantId
? this.service.listProjectGrantMembers(projectId, grantId, pageSize, offset)
: undefined;
? this.service.listProjectGrantMembers(projectId, grantId, pageSize, offset)
: undefined;
if (promise) {
from(promise)
.pipe(

View File

@ -23,8 +23,8 @@
'project.member.write:' + (projectType === ProjectType.PROJECTTYPE_OWNED)
? $any(project)?.id
: projectType === ProjectType.PROJECTTYPE_GRANTED
? $any(project)?.projectId
: ''
? $any(project)?.projectId
: ''
]
| hasRole
| async
@ -35,8 +35,8 @@
'project.member.delete:' + (projectType === ProjectType.PROJECTTYPE_OWNED)
? $any(project)?.id
: projectType === ProjectType.PROJECTTYPE_GRANTED
? $any(project)?.projectId
: ''
? $any(project)?.projectId
: ''
]
| hasRole
| async
@ -50,8 +50,8 @@
'project.member.delete:' + (projectType === ProjectType.PROJECTTYPE_OWNED)
? $any(project)?.id
: projectType === ProjectType.PROJECTTYPE_GRANTED
? $any(project)?.projectId
: '',
? $any(project)?.projectId
: '',
'project.member.delete'
]"
>
@ -74,8 +74,8 @@
'project.member.write:' + (projectType === ProjectType.PROJECTTYPE_OWNED)
? $any(project)?.id
: projectType === ProjectType.PROJECTTYPE_GRANTED
? $any(project)?.projectId
: '',
? $any(project)?.projectId
: '',
'project.member.write'
]"
>

View File

@ -69,8 +69,8 @@ export class ProviderAppleComponent {
this.serviceType === PolicyComponentServiceType.ADMIN
? ['iam.idp.write']
: this.serviceType === PolicyComponentServiceType.MGMT
? ['org.idp.write']
: [],
? ['org.idp.write']
: [],
)
.pipe(take(1))
.subscribe((allowed) => {

View File

@ -76,8 +76,8 @@ export class ProviderAzureADComponent {
this.serviceType === PolicyComponentServiceType.ADMIN
? ['iam.idp.write']
: this.serviceType === PolicyComponentServiceType.MGMT
? ['org.idp.write']
: [],
? ['org.idp.write']
: [],
)
.pipe(take(1))
.subscribe((allowed) => {

View File

@ -67,8 +67,8 @@ export class ProviderGithubESComponent {
this.serviceType === PolicyComponentServiceType.ADMIN
? ['iam.idp.write']
: this.serviceType === PolicyComponentServiceType.MGMT
? ['org.idp.write']
: [],
? ['org.idp.write']
: [],
)
.pipe(take(1))
.subscribe((allowed) => {

View File

@ -65,8 +65,8 @@ export class ProviderGithubComponent {
this.serviceType === PolicyComponentServiceType.ADMIN
? ['iam.idp.write']
: this.serviceType === PolicyComponentServiceType.MGMT
? ['org.idp.write']
: [],
? ['org.idp.write']
: [],
)
.pipe(take(1))
.subscribe((allowed) => {

View File

@ -66,8 +66,8 @@ export class ProviderGitlabSelfHostedComponent {
this.serviceType === PolicyComponentServiceType.ADMIN
? ['iam.idp.write']
: this.serviceType === PolicyComponentServiceType.MGMT
? ['org.idp.write']
: [],
? ['org.idp.write']
: [],
)
.pipe(take(1))
.subscribe((allowed) => {

View File

@ -65,8 +65,8 @@ export class ProviderGitlabComponent {
this.serviceType === PolicyComponentServiceType.ADMIN
? ['iam.idp.write']
: this.serviceType === PolicyComponentServiceType.MGMT
? ['org.idp.write']
: [],
? ['org.idp.write']
: [],
)
.pipe(take(1))
.subscribe((allowed) => {

View File

@ -65,8 +65,8 @@ export class ProviderGoogleComponent {
this.serviceType === PolicyComponentServiceType.ADMIN
? ['iam.idp.write']
: this.serviceType === PolicyComponentServiceType.MGMT
? ['org.idp.write']
: [],
? ['org.idp.write']
: [],
)
.pipe(take(1))
.subscribe((allowed) => {

View File

@ -95,8 +95,8 @@ export class ProviderJWTComponent {
this.serviceType === PolicyComponentServiceType.ADMIN
? ['iam.idp.write']
: this.serviceType === PolicyComponentServiceType.MGMT
? ['org.idp.write']
: [],
? ['org.idp.write']
: [],
)
.pipe(take(1))
.subscribe((allowed) => {

View File

@ -69,8 +69,8 @@ export class ProviderLDAPComponent {
this.serviceType === PolicyComponentServiceType.ADMIN
? ['iam.idp.write']
: this.serviceType === PolicyComponentServiceType.MGMT
? ['org.idp.write']
: [],
? ['org.idp.write']
: [],
)
.pipe(take(1))
.subscribe((allowed) => {

View File

@ -68,8 +68,8 @@ export class ProviderOAuthComponent {
this.serviceType === PolicyComponentServiceType.ADMIN
? ['iam.idp.write']
: this.serviceType === PolicyComponentServiceType.MGMT
? ['org.idp.write']
: [],
? ['org.idp.write']
: [],
)
.pipe(take(1))
.subscribe((allowed) => {

View File

@ -21,7 +21,12 @@
</cnsl-form-field>
<cnsl-form-field class="formfield">
<cnsl-label>{{ 'IDP.SAML.METADATAXML' | translate }}</cnsl-label>
<input cnslInput formControlName="metadataXml" />
<textarea
cnslInput
formControlName="metadataXml"
placeholder="base64 encoded metadata xml"
class="metadata-xml"
></textarea>
</cnsl-form-field>
<cnsl-form-field class="formfield">
<cnsl-label>{{ 'IDP.SAML.METADATAURL' | translate }}</cnsl-label>
@ -29,7 +34,7 @@
</cnsl-form-field>
<cnsl-form-field class="formfield">
<cnsl-label>{{ 'IDP.SAML.BINDING' | translate }}</cnsl-label>
<mat-select formControlName="binding">
<mat-select formControlName="binding" [compareWith]="compareBinding">
<mat-option *ngFor="let binding of bindingValues" [value]="binding">{{ binding }}</mat-option>
</mat-select>
</cnsl-form-field>

View File

@ -0,0 +1,3 @@
.metadata-xml {
min-height: 200px;
}

View File

@ -1,6 +1,6 @@
import { Component, Injector, Type } from '@angular/core';
import { Location } from '@angular/common';
import { Options, Provider } from '../../../proto/generated/zitadel/idp_pb';
import { Options, Provider, SAMLBinding } 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';
@ -10,7 +10,7 @@ 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 { atLeastOneIsFilled, requiredValidator } from '../../form-field/validators/validators';
import {
AddSAMLProviderRequest as AdminAddSAMLProviderRequest,
GetProviderByIDRequest as AdminGetProviderByIDRequest,
@ -21,7 +21,6 @@ import {
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',
@ -38,7 +37,7 @@ export class ProviderSamlSpComponent {
public serviceType: PolicyComponentServiceType = PolicyComponentServiceType.MGMT;
private service!: ManagementService | AdminService;
bindingValues: string[] = Object.keys(zitadel_idp_pb.SAMLBinding);
bindingValues: string[] = Object.keys(SAMLBinding);
constructor(
private _location: Location,
@ -54,13 +53,16 @@ export class ProviderSamlSpComponent {
}
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]),
});
this.form = new UntypedFormGroup(
{
name: new UntypedFormControl('', [requiredValidator]),
metadataXml: new UntypedFormControl('', []),
metadataUrl: new UntypedFormControl('', []),
binding: new UntypedFormControl(this.bindingValues[0], [requiredValidator]),
withSignedRequest: new UntypedFormControl(true, [requiredValidator]),
},
atLeastOneIsFilled('metadataXml', 'metadataUrl'),
);
}
private _checkFormPermissions(): void {
@ -69,8 +71,8 @@ export class ProviderSamlSpComponent {
this.serviceType === PolicyComponentServiceType.ADMIN
? ['iam.idp.write']
: this.serviceType === PolicyComponentServiceType.MGMT
? ['org.idp.write']
: [],
? ['org.idp.write']
: [],
)
.pipe(take(1))
.subscribe((allowed) => {
@ -121,18 +123,23 @@ export class ProviderSamlSpComponent {
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);
if (this.metadataXml?.value) {
req.setMetadataXml(this.metadataXml?.value);
} else {
req.setMetadataUrl(this.metadataUrl?.value);
}
req.setWithSignedRequest(this.withSignedRequest?.value);
// @ts-ignore
req.setBinding(zitadel_idp_pb.SAMLBinding[`${this.biding?.value}`]);
req.setBinding(SAMLBinding[this.binding?.value]);
req.setProviderOptions(this.options);
this.loading = true;
this.service
.updateSAMLProvider(req)
.then((idp) => {
.then(() => {
setTimeout(() => {
this.loading = false;
this.close();
@ -151,16 +158,19 @@ export class ProviderSamlSpComponent {
? new MgmtAddSAMLProviderRequest()
: new AdminAddSAMLProviderRequest();
req.setName(this.name?.value);
req.setMetadataUrl(this.metadataUrl?.value);
req.setMetadataXml(this.metadataXml?.value);
if (this.metadataXml?.value) {
req.setMetadataXml(this.metadataXml?.value);
} else {
req.setMetadataUrl(this.metadataUrl?.value);
}
req.setProviderOptions(this.options);
// @ts-ignore
req.setBinding(zitadel_idp_pb.SAMLBinding[`${this.biding?.value}`]);
req.setBinding(SAMLBinding[this.binding?.value]);
req.setWithSignedRequest(this.withSignedRequest?.value);
this.loading = true;
this.service
.addSAMLProvider(req)
.then((idp) => {
.then(() => {
setTimeout(() => {
this.loading = false;
this.close();
@ -187,9 +197,9 @@ export class ProviderSamlSpComponent {
.then((resp) => {
this.provider = resp.idp;
this.loading = false;
this.name?.setValue(this.provider?.name);
if (this.provider?.config?.saml) {
this.form.patchValue(this.provider.config.saml);
this.name?.setValue(this.provider.name);
}
})
.catch((error) => {
@ -202,6 +212,13 @@ export class ProviderSamlSpComponent {
this._location.back();
}
compareBinding(value: string, index: number) {
if (value) {
return value === Object.keys(SAMLBinding)[index];
}
return false;
}
private get name(): AbstractControl | null {
return this.form.get('name');
}
@ -214,7 +231,7 @@ export class ProviderSamlSpComponent {
return this.form.get('metadataUrl');
}
private get biding(): AbstractControl | null {
private get binding(): AbstractControl | null {
return this.form.get('binding');
}

View File

@ -167,8 +167,8 @@ export class SearchProjectAutocompleteComponent implements OnInit, OnDestroy {
const type = (p as Project.AsObject).id
? ProjectType.PROJECTTYPE_OWNED
: (p as GrantedProject.AsObject).projectId
? ProjectType.PROJECTTYPE_GRANTED
: ProjectType.PROJECTTYPE_OWNED;
? ProjectType.PROJECTTYPE_GRANTED
: ProjectType.PROJECTTYPE_OWNED;
this.selectionChanged.emit({
project: p,

View File

@ -10,8 +10,8 @@
type === PolicyComponentServiceType.ADMIN
? setting.iamWithRole
: type === PolicyComponentServiceType.MGMT
? setting.orgWithRole
: []
? setting.orgWithRole
: []
"
>
<div class="p-item card" @policy data-e2e="policy-card">
@ -35,8 +35,8 @@
type === PolicyComponentServiceType.ADMIN
? setting.iamRouterLink
: type === PolicyComponentServiceType.MGMT
? setting.orgRouterLink
: null
? setting.orgRouterLink
: null
"
[queryParams]="setting.queryParams"
mat-stroked-button

View File

@ -69,8 +69,8 @@
((context === UserGrantContext.OWNED_PROJECT
? ['user.grant.write:' + row?.projectId]
: context === UserGrantContext.GRANTED_PROJECT
? ['user.grant.write:' + row?.id]
: []
? ['user.grant.write:' + row?.id]
: []
)
| hasRole
| async)

View File

@ -8,10 +8,10 @@
? 4
: 3
: appType?.value?.createType === AppCreateType.API
? 3
: appType?.value?.createType === AppCreateType.SAML
? 3
: 0
? 3
: appType?.value?.createType === AppCreateType.SAML
? 3
: 0
: 0
"
[currentCreateStep]="currentCreateStep"

View File

@ -261,8 +261,8 @@
"DESCRIPTION": "Щракнете върху бутона по-долу, за да влезете отново."
},
"EXHAUSTED": {
"TITLE": "Вашата квота за удостоверени заявки е изчерпана.",
"DESCRIPTION": ремахнете или увеличете ограничението на квотата за този екземпляр на ZITADEL."
"TITLE": "Вашият екземпляр е блокиран.",
"DESCRIPTION": опитайте администратора на вашия екземпляр ZITADEL да актуализира абонамента."
},
"INVALID_FORMAT": "Форматирането е невалидно.",
"NOTANEMAIL": "Дадената стойност не е имейл адрес.",
@ -1244,6 +1244,7 @@
"DESCRIPTIONCREATEMGMT": "Потребителите могат да избират от наличните доставчици на идентичност по-долу. ",
"ADVANCED": "Разширено",
"LIFETIMEDURATIONS": "Продължителност на влизане",
"LIFETIME_INVALID": "Формулярът съдържа невалидни стойности.",
"SAVED": "Запазено успешно!"
},
"PRIVACY_POLICY": {

View File

@ -268,8 +268,8 @@
"DESCRIPTION": "Klikněte na tlačítko níže pro opětovné přihlášení."
},
"EXHAUSTED": {
"TITLE": "Vyčerpali jste kvótu pro autentizované požadavky.",
"DESCRIPTION": "Odstraňte nebo zvyšte limit kvóty pro tuto instanci ZITADEL."
"TITLE": "Vaše instance je blokována.",
"DESCRIPTION": "Požádejte svého správce instance ZITADEL, aby aktualizoval předplatné."
},
"INVALID_FORMAT": "Formát je neplatný.",
"NOTANEMAIL": "Zadaná hodnota není e-mailová adresa.",
@ -1251,6 +1251,7 @@
"DESCRIPTIONCREATEMGMT": "Uživatelé si mohou vybrat z dostupných poskytovatelů identity níže. Poznámka: Můžete použít poskytovatele nastavené systémem, jakož i poskytovatele nastavené pouze pro vaši organizaci.",
"ADVANCED": "Pokročilé",
"LIFETIMEDURATIONS": "Doba trvání přihlášení",
"LIFETIME_INVALID": "Formulář obsahuje neplatné hodnoty.",
"SAVED": "Úspěšně uloženo!"
},
"PRIVACY_POLICY": {

View File

@ -267,8 +267,8 @@
"DESCRIPTION": "Klicke auf \"Einloggen\", um Dich erneut anzumelden."
},
"EXHAUSTED": {
"TITLE": "Dein Kontingent an authentifizierten Anfragen is erschöpft.",
"DESCRIPTION": "Lösche oder erhöhe die Grenze für diese ZITADEL Instanz."
"TITLE": "Deine Instanz ist blockiert.",
"DESCRIPTION": "Bitte kontaktiere den Administrator deiner ZITADEL Instanz."
},
"INVALID_FORMAT": "Das Format is ungültig.",
"NOTANEMAIL": "Der eingegebene Wert ist keine E-Mail Adresse.",
@ -1250,6 +1250,7 @@
"DESCRIPTIONCREATEMGMT": "Nutzer können sich mit den verfügbaren Idps authentifizieren. Achtung: Es kann zwischen System- und organisationsspezifischen Providern gewählt werden.",
"ADVANCED": "Erweitert",
"LIFETIMEDURATIONS": "Login Lifetimes",
"LIFETIME_INVALID": "Login Lifetimes sind ungültig.",
"SAVED": "Erfolgreich gespeichert."
},
"PRIVACY_POLICY": {

View File

@ -268,8 +268,8 @@
"DESCRIPTION": "Click the button below to log in again."
},
"EXHAUSTED": {
"TITLE": "Your quota for authenticated requests is exhausted.",
"DESCRIPTION": "Remove or increase the quota limit for this ZITADEL instance."
"TITLE": "Your instance is blocked.",
"DESCRIPTION": "Ask your ZITADEL instance administrator to update the subscription."
},
"INVALID_FORMAT": "The formatting is invalid.",
"NOTANEMAIL": "The given value is not an e-mail address.",
@ -1251,6 +1251,7 @@
"DESCRIPTIONCREATEMGMT": "Users can choose from the available identity providers below. Note: You can use System-set providers as well as providers set for your organization only.",
"ADVANCED": "Advanced",
"LIFETIMEDURATIONS": "Login Lifetimes",
"LIFETIME_INVALID": "Form contains invalid value(s).",
"SAVED": "Saved successfully!"
},
"PRIVACY_POLICY": {

View File

@ -268,8 +268,8 @@
"DESCRIPTION": "Haz clic en el botón más abajo para iniciar sesión otra vez."
},
"EXHAUSTED": {
"TITLE": "Su cuota de solicitudes autenticadas se ha agotado.",
"DESCRIPTION": "Borrar o aumentar el límite de esta instancia de ZITADEL."
"TITLE": "Tu instancia está bloqueada.",
"DESCRIPTION": "Pide a tu administrador de instancia de ZITADEL que actualice la suscripción."
},
"INVALID_FORMAT": "El formato no es valido.",
"NOTANEMAIL": "El valor proporcionado no es una dirección de email.",
@ -1252,6 +1252,7 @@
"DESCRIPTIONCREATEMGMT": "Los usuarios pueden elegir entre los siguientes proveedores de identidad. Nota: Puedes usar los proveedores integrados en el sistema así como sólo los proveedores configurados para tu organización.",
"ADVANCED": "Avanzado",
"LIFETIMEDURATIONS": "Tiempos de vida de los inicios de sesión",
"LIFETIME_INVALID": "El formulario contiene valores no válidos.",
"SAVED": "¡Guardado con éxito!"
},
"PRIVACY_POLICY": {

View File

@ -267,8 +267,8 @@
"DESCRIPTION": "Cliquez sur le bouton ci-dessous pour vous reconnecter."
},
"EXHAUSTED": {
"TITLE": "Ton quota de demandes authentifiées est épuisé.",
"DESCRIPTION": "Supprimez ou augmentez la limite de cette instance ZITADEL."
"TITLE": "Votre instance est bloquée.",
"DESCRIPTION": "Demandez à votre administrateur d'instance ZITADEL de mettre à jour l'abonnement."
},
"INVALID_FORMAT": "Le format n'est pas valide",
"NOTANEMAIL": "La valeur donnée n'est pas une adresse e-mail",
@ -1250,6 +1250,7 @@
"DESCRIPTIONCREATEMGMT": "Les utilisateurs peuvent choisir parmi les fournisseurs d'identité disponibles ci-dessous. Note",
"ADVANCED": "Avancé",
"LIFETIMEDURATIONS": "Durée de vie des connexions",
"LIFETIME_INVALID": "Le formulaire contient des valeurs non valides.",
"SAVED": "Enregistré avec succès !"
},
"PRIVACY_POLICY": {

View File

@ -266,8 +266,8 @@
"DESCRIPTION": "Clicca il pulsante per richiedere una nuova sessione."
},
"EXHAUSTED": {
"TITLE": "La quota di richieste autenticate è esaurita.",
"DESCRIPTION": "Cancellare o aumentare il limite per questa istanza ZITADEL."
"TITLE": "La tua istanza è bloccata.",
"DESCRIPTION": "Chiedi all'amministratore dell'istanza ZITADEL di aggiornare l'abbonamento."
},
"INVALID_FORMAT": "Il formato non è valido.",
"NOTANEMAIL": "Il valore dato non \u00e8 un indirizzo e-mail.",
@ -1250,6 +1250,7 @@
"DESCRIPTIONCREATEMGMT": "Gli utenti possono scegliere tra gli IDP disponibili qui sotto. Nota: puoi usare i provider impostati nel sistema e quelli impostati della tua organizzazione.",
"ADVANCED": "Impostazioni avanzate",
"LIFETIMEDURATIONS": "Login Lifetimes",
"LIFETIME_INVALID": "Login Lifetimes non sono validi",
"SAVED": "Salvato con successo!"
},
"PRIVACY_POLICY": {

View File

@ -268,8 +268,8 @@
"DESCRIPTION": "下のボタンをクリックして、もう一度ログインする。"
},
"EXHAUSTED": {
"TITLE": "認証されたリクエストのクォータを使い果たしました",
"DESCRIPTION": "このZITADELインスタンスの制限を削除または増加させる"
"TITLE": "あなたのインスタンスはブロックされています。",
"DESCRIPTION": "ZITADELインスタンス管理者にサブスクリプションの更新を依頼してください。"
},
"INVALID_FORMAT": "不正なフォーマットです",
"NOTANEMAIL": "入力された値がメールアドレスではありません。",
@ -1247,6 +1247,7 @@
"DESCRIPTIONCREATEMGMT": "ユーザーは、以下の利用可能なIDプロバイダーから選択できます。注システムセットプロバイダーと、組織用に設定されたプロバイダーのみを使用できます。",
"ADVANCED": "高度",
"LIFETIMEDURATIONS": "ログインライフタイム",
"LIFETIME_INVALID": "フォームに無効な値が含まれています。",
"SAVED": "正常に保存されました!"
},
"PRIVACY_POLICY": {

View File

@ -268,8 +268,8 @@
"DESCRIPTION": "Кликнете на копчето подолу за повторна најава."
},
"EXHAUSTED": {
"TITLE": "Вашиот квота за автентицирани барања е надмината.",
"DESCRIPTION": "Отстранете или зголемете ја квотата за оваа ZITADEL инстанца."
"TITLE": "Вашиот авторизациски токен е истечен.",
"DESCRIPTION": "Кликнете на копчето подолу за повторна најава."
},
"INVALID_FORMAT": "Невалиден формат.",
"NOTANEMAIL": "Внесената вредност не е е-пошта.",
@ -1252,6 +1252,7 @@
"DESCRIPTIONCREATEMGMT": "Корисниците можат да избираат од достапните IDPs подолу. Забелешка: Можете да користите системски поставени IDPs, како и IDPs поставени само за вашата организација.",
"ADVANCED": "Напредно",
"LIFETIMEDURATIONS": "Време на траење на најавата",
"LIFETIME_INVALID": "Формуларот содржи неважечки вредности.",
"SAVED": "Успешно зачувано!"
},
"PRIVACY_POLICY": {

View File

@ -268,8 +268,8 @@
"DESCRIPTION": "Klik op de knop hieronder om opnieuw in te loggen."
},
"EXHAUSTED": {
"TITLE": "Uw quotum voor geauthenticeerde aanvragen is opgebruikt.",
"DESCRIPTION": "Verwijder of verhoog het quotumlimiet voor deze ZITADEL-instantie."
"TITLE": "Uw instantie is geblokkeerd.",
"DESCRIPTION": "Vraag uw ZITADEL instantiebeheerder om het abonnement bij te werken."
},
"INVALID_FORMAT": "De opmaak is ongeldig.",
"NOTANEMAIL": "De opgegeven waarde is geen e-mailadres.",
@ -1251,6 +1251,7 @@
"DESCRIPTIONCREATEMGMT": "Gebruikers kunnen kiezen uit de beschikbare identiteitsproviders hieronder. Opmerking: U kunt systeem ingestelde providers gebruiken evenals providers die alleen voor uw organisatie zijn ingesteld.",
"ADVANCED": "Geavanceerd",
"LIFETIMEDURATIONS": "Login Levensduur",
"LIFETIME_INVALID": "Formulier bevat ongeldige waarde(n).",
"SAVED": "Succesvol opgeslagen!"
},
"PRIVACY_POLICY": {

View File

@ -267,8 +267,8 @@
"DESCRIPTION": "Kliknij przycisk poniżej, aby ponownie się zalogować."
},
"EXHAUSTED": {
"TITLE": "Twój limit uwierzytelnionych wniosków został wyczerpany.",
"DESCRIPTION": "Usuń lub zwiększ limit dla tej instancji ZITADEL."
"TITLE": "Twoja instancja jest zablokowana.",
"DESCRIPTION": "Poproś administratora swojej instancji ZITADEL o aktualizację subskrypcji."
},
"INVALID_FORMAT": "Format jest nieprawidłowy.",
"NOTANEMAIL": "Podana wartość nie jest adresem e-mail.",
@ -1250,6 +1250,7 @@
"DESCRIPTIONCREATEMGMT": "Użytkownicy mogą wybrać z dostępnych poniżej dostawców tożsamości. Uwaga: Możesz korzystać z dostawców ustawionych przez system lub tylko dla twojej organizacji.",
"ADVANCED": "Zaawansowane",
"LIFETIMEDURATIONS": "Czasy trwania logowania",
"LIFETIME_INVALID": "Formularz zawiera nieprawidłowe wartości.",
"SAVED": "Pomyślnie zapisano!"
},
"PRIVACY_POLICY": {

View File

@ -268,8 +268,8 @@
"DESCRIPTION": "Clique no botão abaixo para fazer login novamente."
},
"EXHAUSTED": {
"TITLE": "Sua cota para solicitações autenticadas está esgotada.",
"DESCRIPTION": "Remova ou aumente o limite de cota para esta instância ZITADEL."
"TITLE": "Sua instância está bloqueada.",
"DESCRIPTION": "Peça ao administrador da sua instância ZITADEL para atualizar a assinatura."
},
"INVALID_FORMAT": "O formato é inválido.",
"NOTANEMAIL": "O valor fornecido não é um endereço de e-mail.",
@ -1252,6 +1252,7 @@
"DESCRIPTIONCREATEMGMT": "Os usuários podem escolher entre os provedores de identidade disponíveis abaixo. Observação: você também pode usar provedores definidos pelo sistema e provedores definidos apenas para sua organização.",
"ADVANCED": "Avançado",
"LIFETIMEDURATIONS": "Duração do login",
"LIFETIME_INVALID": "O formulário contém valores inválidos.",
"SAVED": "Salvo com sucesso!"
},
"PRIVACY_POLICY": {

View File

@ -264,8 +264,8 @@
"DESCRIPTION": "Нажмите кнопку ниже, чтобы войти снова."
},
"EXHAUSTED": {
"TITLE": "Ваша квота на аутентифицированные запросы исчерпана.",
"DESCRIPTION": "Удалите или увеличьте лимит квоты для этого экземпляра ZITADEL."
"TITLE": "Ваш экземпляр заблокирован.",
"DESCRIPTION": "Попросите администратора вашего экземпляра ZITADEL обновить подписку."
},
"INVALID_FORMAT": "Форматирование неверно.",
"NOTANEMAIL": "Данное значение не является адресом электронной почты.",
@ -1237,6 +1237,7 @@
"DESCRIPTIONCREATEMGMT": "Пользователи могут выбирать из доступных поставщиков удостоверений, указанных ниже. Примечание. Вы можете использовать поставщиков, установленных системой, а также поставщиков, установленных только для вашей организации.",
"ADVANCED": "Продвинутые настройки",
"LIFETIMEDURATIONS": "Время входа в систему",
"LIFETIME_INVALID": "Formularul conține valori nevalide.",
"SAVED": "Успешно сохранено!"
},
"PRIVACY_POLICY": {

View File

@ -267,8 +267,8 @@
"DESCRIPTION": "点击下方按钮再次登录。"
},
"EXHAUSTED": {
"TITLE": "你的认证请求配额已用完.",
"DESCRIPTION": "删除或增加这个ZITADEL实例的限制。"
"TITLE": "您的实例已被阻止。",
"DESCRIPTION": "请联系您的 ZITADEL 实例管理员以更新订阅。"
},
"INVALID_FORMAT": "格式是无效的。",
"NOTANEMAIL": "给定的值不是合法电子邮件地址。",
@ -1249,6 +1249,7 @@
"DESCRIPTIONCREATEMGMT": "用户可以从以下可用的身份提供者中进行选择。注意:您可为系统设置提供者也可以仅为您的组织单独设置提供者。",
"ADVANCED": "高级设置",
"LIFETIMEDURATIONS": "登录状态有效期",
"LIFETIME_INVALID": "表单包含无效值。",
"SAVED": "保存成功!"
},
"PRIVACY_POLICY": {

View File

@ -3305,15 +3305,15 @@
dependencies:
"@types/node" "*"
"@types/jasmine@*", "@types/jasmine@~4.3.6":
version "4.3.6"
resolved "https://registry.yarnpkg.com/@types/jasmine/-/jasmine-4.3.6.tgz#d9855fa9f808138488784610f888046bb9a59aff"
integrity sha512-3N0FpQTeiWjm+Oo1WUYWguUS7E6JLceiGTriFrG8k5PU7zRLJCzLcWURU3wjMbZGS//a2/LgjsnO3QxIlwxt9g==
"@types/jasmine@*", "@types/jasmine@~5.1.4":
version "5.1.4"
resolved "https://registry.yarnpkg.com/@types/jasmine/-/jasmine-5.1.4.tgz#0de3f6ca753e10d1600ce1864ae42cfd47cf9924"
integrity sha512-px7OMFO/ncXxixDe1zR13V1iycqWae0MxTaw62RpFlksUi5QuNWgQJFkTQjIOvrmutJbI7Fp2Y2N1F6D2R4G6w==
"@types/jasminewd2@~2.0.10":
version "2.0.10"
resolved "https://registry.npmjs.org/@types/jasminewd2/-/jasminewd2-2.0.10.tgz"
integrity sha512-J7mDz7ovjwjc+Y9rR9rY53hFWKATcIkrr9DwQWmOas4/pnIPJTXawnzjwpHm3RSxz/e3ZVUvQ7cRbd5UQLo10g==
"@types/jasminewd2@~2.0.13":
version "2.0.13"
resolved "https://registry.yarnpkg.com/@types/jasminewd2/-/jasminewd2-2.0.13.tgz#0b60c1fcd06277ea97efbbad5a02e0c1a4a8996a"
integrity sha512-aJ3wj8tXMpBrzQ5ghIaqMisD8C3FIrcO6sDKHqFbuqAsI7yOxj0fA7MrRCPLZHIVUjERIwsMmGn/vB0UQ9u0Hg==
dependencies:
"@types/jasmine" "*"
@ -3344,10 +3344,10 @@
resolved "https://registry.yarnpkg.com/@types/node/-/node-20.7.0.tgz#c03de4572f114a940bc2ca909a33ddb2b925e470"
integrity sha512-zI22/pJW2wUZOVyguFaUL1HABdmSVxpXrzIqkjsHmyUjNhPoWM1CKfvVuXfetHhIok4RY573cqS0mZ1SJEnoTg==
"@types/opentype.js@^1.3.4":
version "1.3.4"
resolved "https://registry.npmjs.org/@types/opentype.js/-/opentype.js-1.3.4.tgz"
integrity sha512-6fbXi67I07ugNM+FExwJnfuui2hD7hraD6nqjr3UnqsbBpxSkrtmO6tBubPdNAjqRT9TVkquVkNS9IkgTtq6/w==
"@types/opentype.js@^1.3.8":
version "1.3.8"
resolved "https://registry.yarnpkg.com/@types/opentype.js/-/opentype.js-1.3.8.tgz#741be92429d1c2d64b5fa79cf692f74b49d6007f"
integrity sha512-H6qeTp03jrknklSn4bpT1/9+1xCAEIU2CnjcWPkicJy8A1SKuthanbvoHYMiv79/2W3Xn1XE4gfSJFzt2U3JSw==
"@types/q@^0.0.32":
version "0.0.32"
@ -3430,10 +3430,10 @@
dependencies:
"@types/estree" "*"
"@types/uuid@^9.0.2":
version "9.0.2"
resolved "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.2.tgz"
integrity sha512-kNnC1GFBLuhImSnV7w4njQkUiJi0ZXUycu1rUaouPqiKlXkh77JKgdRnTAp1x5eBwcIwbtI+3otwzuIDEuDoxQ==
"@types/uuid@^9.0.7":
version "9.0.7"
resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-9.0.7.tgz#b14cebc75455eeeb160d5fe23c2fcc0c64f724d8"
integrity sha512-WUtIVRUZ9i5dYXefDEAI7sh9/O7jGvHg7Df/5O/gtH3Yabe5odI3UWopVR1qbPXQtvOxWu3mM4XxlYeZtMWF4g==
"@types/ws@^8.5.5":
version "8.5.5"
@ -5705,10 +5705,10 @@ find-up@^6.3.0:
locate-path "^7.1.0"
path-exists "^5.0.0"
flag-icons@^6.7.0:
version "6.9.3"
resolved "https://registry.npmjs.org/flag-icons/-/flag-icons-6.9.3.tgz"
integrity sha512-HIU4V8342pmBjk+zlvq0jGyHEifyP9976ynzQw8sLeONNcyMxW5I+NWY9OWGMrd9lkFjgfcnvRdD3MGd1ihHzQ==
flag-icons@^7.1.0:
version "7.1.0"
resolved "https://registry.yarnpkg.com/flag-icons/-/flag-icons-7.1.0.tgz#6898ae3b3a57e5a363e12478c1ef384aa62d641f"
integrity sha512-AH4v++19bpC5P3Wh767top4wylJYJCWkFnvNiDqGHDxqSqdMZ49jpLXp8PWBHTTXaNQ+/A+QPrOwyiIGaiIhmw==
flat-cache@^3.0.4:
version "3.0.4"
@ -6269,10 +6269,10 @@ humanize-ms@^1.2.1:
dependencies:
ms "^2.0.0"
i18n-iso-countries@^7.6.0:
version "7.6.0"
resolved "https://registry.npmjs.org/i18n-iso-countries/-/i18n-iso-countries-7.6.0.tgz"
integrity sha512-HPKjOUKS0BkjiY4ayrsuFbu7Ock++pXLs+FAOYl4WfTL5L0ploEH68fiRAP6Zev5g/jvMFt54KcPGJcb942wbg==
i18n-iso-countries@^7.7.0:
version "7.7.0"
resolved "https://registry.yarnpkg.com/i18n-iso-countries/-/i18n-iso-countries-7.7.0.tgz#33a0974d6ffbe864fb853325de3afb4717c54b52"
integrity sha512-07zMatrSsR1Z+cnxW//7s14Xf4v5g6U6ORHPaH8+Ox4uPqV+y46Uq78veYV8H1DKTr76EfdjSeaTxHpnaYq+bw==
dependencies:
diacritics "1.3.0"
@ -8105,15 +8105,15 @@ prelude-ls@^1.2.1:
resolved "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz"
integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==
prettier-plugin-organize-imports@^3.2.2:
version "3.2.2"
resolved "https://registry.npmjs.org/prettier-plugin-organize-imports/-/prettier-plugin-organize-imports-3.2.2.tgz"
integrity sha512-e97lE6odGSiHonHJMTYC0q0iLXQyw0u5z/PJpvP/3vRy6/Zi9kLBwFAbEGjDzIowpjQv8b+J04PDamoUSQbzGA==
prettier-plugin-organize-imports@^3.2.4:
version "3.2.4"
resolved "https://registry.yarnpkg.com/prettier-plugin-organize-imports/-/prettier-plugin-organize-imports-3.2.4.tgz#77967f69d335e9c8e6e5d224074609309c62845e"
integrity sha512-6m8WBhIp0dfwu0SkgfOxJqh+HpdyfqSSLfKKRZSFbDuEQXDDndb8fTpRWkUrX/uBenkex3MgnVk0J3b3Y5byog==
prettier@^3.0.3:
version "3.0.3"
resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.0.3.tgz#432a51f7ba422d1469096c0fdc28e235db8f9643"
integrity sha512-L/4pUDMxcNa8R/EthV08Zt42WBO4h1rarVtK0K+QJG0X187OLo7l699jWw0GKuwzkPQ//jMFA/8Xm6Fh3J/DAg==
prettier@^3.1.1:
version "3.1.1"
resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.1.1.tgz#6ba9f23165d690b6cbdaa88cb0807278f7019848"
integrity sha512-22UbSzg8luF4UuZtzgiUOfcGM8s4tjBv6dJRT7j275NXsy2jb4aJa4NNveul5x4eqlF1wuhuR2RElK71RvmVaw==
pretty-bytes@^5.3.0:
version "5.6.0"
@ -9506,10 +9506,10 @@ uuid@^8.3.2:
resolved "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz"
integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==
uuid@^9.0.0:
version "9.0.0"
resolved "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz"
integrity sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==
uuid@^9.0.1:
version "9.0.1"
resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.1.tgz#e188d4c8853cc722220392c424cd637f32293f30"
integrity sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==
v8-compile-cache@2.3.0:
version "2.3.0"
@ -9984,9 +9984,9 @@ zone.js@~0.10.3:
resolved "https://registry.npmjs.org/zone.js/-/zone.js-0.10.3.tgz"
integrity sha512-LXVLVEq0NNOqK/fLJo3d0kfzd4sxwn2/h67/02pjCjfKDxgx1i9QqpvtHD8CrBnSSwMw5+dy11O7FRX5mkO7Cg==
zone.js@~0.13.1:
version "0.13.1"
resolved "https://registry.npmjs.org/zone.js/-/zone.js-0.13.1.tgz"
integrity sha512-+bIeDAFEBYuXRuU3qGQvzdPap+N1zjM4KkBAiiQuVVCrHrhjDuY6VkUhNa5+U27+9w0q3fbKiMCbpJ0XzMmSWA==
zone.js@~0.13.3:
version "0.13.3"
resolved "https://registry.yarnpkg.com/zone.js/-/zone.js-0.13.3.tgz#344c24098fa047eda6427a4c7ed486e391fd67b5"
integrity sha512-MKPbmZie6fASC/ps4dkmIhaT5eonHkEt6eAy80K42tAm0G2W+AahLJjbfi6X9NPdciOE9GRFTTM8u2IiF6O3ww==
dependencies:
tslib "^2.3.0"

View File

@ -8,11 +8,13 @@ To add a new site to the already existing structure simply save the `md` file in
## Installation
Install dependencies with
```
yarn install
```
## Generate
then run
```
yarn generate
@ -21,10 +23,18 @@ yarn generate
## Local Development
Start a local development server with
```
yarn start
```
When working on the API docs, run a local development server with
```
yarn start:api
```
## Container Image
If you just want to start docusaurus locally without installing node you can fallback to our container image.

View File

@ -4,9 +4,9 @@ title: Complement Token Flow
This flow is executed during the creation of tokens and token introspection.
## Pre Userinfo creation
## Pre Userinfo creation (id_token / userinfo / introspection endpoint)
This trigger is called before userinfo are set in the token or response.
This trigger is called before userinfo are set in the id_token or userinfo and introspection endpoint response.
### Parameters of Pre Userinfo creation

View File

@ -68,8 +68,31 @@ Please check below the matrix for an overview where which scope is asserted.
## Custom Claims
Custom claims are being inserted into user tokens in addition to the standard claims.
Your app can use custom claims to handle more complex scenarios, such as restricting access based on these claims.
You can add custom claims using the [complement token flow](/docs/apis/actions/complement-token) of the [actions feature](/docs/apis/actions/introduction).
Multiple examples of Actions that result in custom claims can be found in our [Marketplace for ZITADEL Actions](https://github.com/zitadel/actions).
### Static values as custom claim
```javascript reference
https://github.com/zitadel/actions/blob/de69b56f6d0463817953b59a52ffd6afc6a366fb/examples/add_claim.js#L9-L11
```
### Metadata as custom claim
```javascript reference
https://github.com/zitadel/actions/blob/main/examples/add_metadata.js#L9-L15
```
### Format roles claims
```javascript reference
https://github.com/zitadel/actions/blob/main/examples/custom_roles.js#L20-L33
```
## Reserved Claims
ZITADEL reserves some claims to assert certain data. Please check out the [reserved scopes](scopes#reserved-scopes).

View File

@ -57,4 +57,13 @@ Regardless of the error, the used http error code will be '200', which represent
response will contain a StatusCode include a message which provides more information if an error occurred.
**Link to
spec** [Assertions and Protocols for the OASIS Security Assertion Markup Language (SAML) V2.0 Errata Composite](https://www.oasis-open.org/committees/download.php/35711/sstc-saml-core-errata-2.0-wd-06-diff.pdf)
spec** [Assertions and Protocols for the OASIS Security Assertion Markup Language (SAML) V2.0 Errata Composite](https://www.oasis-open.org/committees/download.php/35711/sstc-saml-core-errata-2.0-wd-06-diff.pdf)
## Custom attributes
Custom attributes are being inserted into SAML response if not already present.
Your app can use custom claims to handle more complex scenarios, such as restricting access based on these claims.
You can add custom attributes using the [complement SAMLresponse](/docs/apis/actions/customize-samlresponse) of the [actions feature](/docs/apis/actions/introduction).
Examples of Actions that result in custom attributes can be found in our [Marketplace for ZITADEL Actions](https://github.com/zitadel/actions).

View File

@ -101,16 +101,16 @@ Our examples cover a range of programming languages and frameworks, so no matter
</td>
<td>Java Spring Boot Web</td>
<td><a href="https://github.com/zitadel/zitadel-java" target="_blank"><i class="lab la-github"></i></a></td>
<td></td>
<td><a href="/examples/login/java-spring">Guide</a></td>
<td></td>
</tr>
<tr>
<td width="100px">
<img src="/docs/img/tech/php.svg" alt="php"/>
</td>
<td>PHP Web</td>
<td></td>
<td></td>
<td>Symfony PHP Framework</td>
<td><a href="https://github.com/zitadel/example-symfony-oidc" target="_blank"><i class="lab la-github"></i></a></td>
<td><a href="/examples/login/symfony">Guide</a></td>
<td></td>
</tr>
<tr>
@ -174,9 +174,9 @@ Our examples cover a range of programming languages and frameworks, so no matter
<td>
<img src="/docs/img/tech/nodejs.svg" alt="node"/>
</td>
<td>NodeJS</td>
<td></td>
<td></td>
<td>Node.js NestJS API</td>
<td><a href="https://github.com/ehwplus/zitadel-nodejs-nestjs" target="_blank"><i class="lab la-github"></i></a></td>
<td><a href="./secure-api/nodejs-nestjs">Guide</a></td>
<td></td>
</tr>
<tr>
@ -194,7 +194,7 @@ Our examples cover a range of programming languages and frameworks, so no matter
</td>
<td>Java Spring Boot API</td>
<td><a href="https://github.com/zitadel/zitadel-java" target="_blank"><i class="lab la-github"></i></a></td>
<td></td>
<td><a href="/examples/login/java-spring">Guide</a></td>
<td></td>
</tr>
</table>

View File

@ -161,7 +161,7 @@ This line automatically refreshes a token before it expires.
Congratulations! You have successfully integrated your Angular application with ZITADEL!
If you get stuck, consider checking out our [example](https://github.com/zitadel/zitadel-angular) application. This application includes all the funcationalities mentioned in this quickstart. You can start by cloning the repository and replacing the _AuthConfig_ in the _AppModule_ with your own configuration. If you face issues, contact us or raise an issue on [GitHub](https://github.com/zitadel/zitadel).
If you get stuck, consider checking out our [example](https://github.com/zitadel/zitadel-angular) application. This application includes all the functionalities mentioned in this quick-start. You can start by cloning the repository and replacing the _AuthConfig_ in the _AppModule_ with your own configuration. If you face issues, contact us or raise an issue on [GitHub](https://github.com/zitadel/zitadel).
![App in console](/img/angular/app-screen.png)

View File

@ -0,0 +1,177 @@
---
title: ZITADEL with Java Spring Boot
sidebar_label: Java Spring Boot
---
This integration guide demonstrates the recommended way to incorporate ZITADEL into your Spring Boot web application.
It explains how to enable user login in your application and how to fetch data from the user info endpoint.
By the end of this guide, your application will have login functionality and will be able to access the current user's profile.
:::info
This documentation references our [example](https://github.com/zitadel/zitadel-java) on GitHub.
You can either create your own application or directly run the example by providing the necessary arguments.
:::
## Set up application
Before we begin developing our application, we need to perform a few configuration steps in the ZITADEL Console.
You'll need to provide some information about your app. We recommend creating a new app to start from scratch. Navigate to your Project, then add a new application at the top of the page.
Select the **Web** application type and continue.
![Create app in console](/img/java-spring/app-create.png)
We recommend that you use [Proof Key for Code Exchange (PKCE)](/apis/openidoauth/grant-types#proof-key-for-code-exchange) for all applications.
![Create app in console - set auth method](/img/java-spring/app-create-auth.png)
### Redirect URIs
The Redirect URIs field tells ZITADEL where it's allowed to redirect users after authentication. For development, you can set dev mode to `true` to enable insecure HTTP and redirect to a `localhost` URI.
The Post-logout redirect send the users back to a route on your application after they have logged out.
:::info
If you are following along with the [example](https://github.com/zitadel/zitadel-java), set the dev mode to `true`, the Redirect URIs to `http://localhost:18080/webapp/login/oauth2/code/zitadel` and Post redirect URI to `http://localhost:18080/webapp`.
:::
![Create app in console - set redirectURI](/img/java-spring/app-create-redirect.png)
Continue and create the application.
### Client ID
After successful creation of the app, a pop-up will appear displaying the app's client ID. Copy the client ID, as you will need it to configure your Java client.
![Create app in console - copy client_id](/img/java-spring/app-create-clientid.png)
## Spring setup
Now that you have configured your web application on the ZITADEL side, you can proceed with the integration of your Spring client.
This guide will reference the [example repository](https://github.com/zitadel/zitadel-java) and explain the necessary steps taken in there.
If your starting from scratch, you can use the Spring Initializer with the [following setup](https://start.spring.io/#!type=maven-project&language=java&platformVersion=3.2.1&packaging=jar&jvmVersion=17&dependencies=web,thymeleaf,security,oauth2-client,lombok) as a base.
### Support classes
To be able to take the most out of ZITADELs RBAC, we first need to create a GrantedAuthoritiesMapper, that will map the role claims (`urn:zitadel:iam:org:project:roles`)
into Spring Security `authiorities`, which can be used later on to determine the granted permissions.
So in your application, create a 'support/zitadel' package and in there the `ZitadelGrantedAuthoritiesMapper.java`:
```java reference
https://github.com/zitadel/zitadel-java/blob/main/web/src/main/java/demo/support/zitadel/ZitadelGrantedAuthoritiesMapper.java
```
The following two classes will provide you the possibility to access and use the user's token for requests to another API, e.g. the Spring Boot API example.
Directly create them in the `support` package.
```java reference
https://github.com/zitadel/zitadel-java/blob/main/web/src/main/java/demo/support/TokenAccessor.java
```
```java reference
https://github.com/zitadel/zitadel-java/blob/main/web/src/main/java/demo/support/AccessTokenInterceptor.java
```
### Application server configuration
As we have now our support classes, we can now create and configure the application server (and API client) itself.
In a new `config` package, create first the `WebClientConfig.java`, which will provide a RestTemplate using the previously created AccessTokenInterceptor:
```java reference
https://github.com/zitadel/zitadel-java/blob/main/web/src/main/java/demo/config/WebClientConfig.java
```
Additionally also create the `WebSecurityConfig.java` in the same package. This class will take care of the authentication, redirecting the user to the login,
mapping the claims (using the ZitadelGrantedAuthoritiesMapper) and also provide the possibility for logout:
```java reference
https://github.com/zitadel/zitadel-java/blob/main/web/src/main/java/demo/config/WebSecurityConfig.java
```
For the authentication (and the server in general) to work, the application needs some configuration, so please provide the following to your `application.yml` (resources folder):
```yaml reference
https://github.com/zitadel/zitadel-java/blob/main/web/src/main/resources/application.yml
```
Note that both the `issuer-uri` as well as the `client-id` are only placeholders. You can either change them in here using the values provided by ZITADEL
or pass them later on as arguments when starting the application.
### Add pages to your application
To be able to serve these pages create a `templates` directory in the `resources` folder.
Now create three HTML files in the new `templates` folder and copy the content of the examples:
**index.html**
The home page will display the Userinfo from the authentication context and the granted roles / Spring security authorities.
```html reference
https://github.com/zitadel/zitadel-java/blob/main/web/src/main/resources/templates/index.html
```
**fragments.html**
The navigation to switch between the home and tasks page and allows the user to logout.
```html reference
https://github.com/zitadel/zitadel-java/blob/main/web/src/main/resources/templates/fragments.html
```
**tasks.html**
The tasks page allows to interact with the Spring Boot API example and display / add new tasks.
```html reference
https://github.com/zitadel/zitadel-java/blob/main/web/src/main/resources/templates/tasks.html
```
**UiController**
To serve these pages and handler their actions, you finally need a `UiController.java`:
```java reference
https://github.com/zitadel/zitadel-java/blob/main/web/src/main/java/demo/web/UiController.java
```
### Start your application
In case you've created your own application and depending on your development setup you might need to build the application first:
```bash
mvn clean package -DskipTests
```
You will need to provide the `issuer-uri` (your ZITADEL domain) and the `client-id` previously created:
```bash
java \
-Dspring.security.oauth2.client.provider.zitadel.issuer-uri=<see configuration above> \
-Dspring.security.oauth2.client.registration.zitadel.client-id=<see configuration above> \
-jar web/target/web-0.0.2-SNAPSHOT.jar
```
This could look like:
```bash
java \
-Dspring.security.oauth2.client.provider.zitadel.issuer-uri=https://my-domain.zitadel.cloud \
-Dspring.security.oauth2.client.registration.zitadel.client-id=243861220627644836@example \
-jar web/target/web-0.0.2-SNAPSHOT.jar
```
If you then visit on <http://localhost:18080/webapp> you should directly be redirected to your ZITADEL instance.
After login with your existing user you will be presented the profile page:
![Profile Page](/img/java-spring/app-profile.png)
## Completion
Congratulations! You have successfully integrated your Spring Boot web application with ZITADEL!
If you get stuck, consider checking out our [example](https://github.com/zitadel/zitadel-java) application.
This application includes all the functionalities mentioned in this quickstart.
You can directly start it with your own configuration. If you face issues, contact us or raise an issue on [GitHub](https://github.com/zitadel/zitadel-java/issues).

View File

@ -0,0 +1,408 @@
---
title: ZITADEL with Symfony PHP
sidebar_label: Symfony
---
This integration guide demonstrates the recommended way to incorporate ZITADEL into your Symfony PHP application.
It explains how to enable user login in your application and how to fetch data from the user info endpoint.
By the end of this guide, your application will have login functionality with basic role mapping, access the current user's profile and a user list accessible by admins.
:::info
This documentation references our [example](https://github.com/zitadel/example-symfony-oidc) on GitHub.
:::
## ZITADEL setup
Before we can start building our application, we have to do a few configuration steps in ZITADEL Console.
### Project roles
The Example expects [user roles](guides/integrate/retrieve-user-roles) to be returned after login.
Symfony uses `ROLE_USER` format.
The application will take care of upper-casing and prefixing for us.
Inside ZITADEL, you can use regular lower-case role names without prefixes, if you prefer.
> Symfony automatically assigns `ROLE_USER` to any authenticated user.
In your project settings make sure the "Assert Roles On Authentication" is enabled.
![Project settings in console](/img/symfony/project-settings.png)
In the project Role tab, add 2 special roles:
- `admin`: Assigned to users that need access to the user list.
- `foo`: Random role for display purposes
A `user` role is not required. This role is assumed by default for any authenticated user in Symfony.
![Project roles in console](/img/symfony/project-roles.png)
Finally, we can assign the roles to users in the project's authorizations tab.
![Project authorizations in console](/img/symfony/project-authorizations.png)
### Set up application and obtain secrets
Next you will need to provide some information about your app.
In your Project, add a new application at the top of the page.
Select Web application type and continue.
We use [Authorization Code](/apis/openidoauth/grant-types#authorization-code)for our Symfony application.
![Create app in console](/img/symfony/app-create.png)
Select `CODE` in the next step. This makes sure you still get a secret. Note that the secret never gets exposed on the browser and is therefore kept in a confidential environment. Safe the generated
![Configure app authentication method in console](/img/symfony/app-auth-method.png)
With the Redirect URIs field, you tell ZITADEL where it is allowed to redirect users to after authentication. For development, you can set dev mode to `true` to enable insecure HTTP and redirect to a `localhost` URI.
For the example application we are writing use:
- `http://localhost:8000/login_check` as Redirect URI
- `http://localhost:8000/logout` as post-logout URI.
![Configure app redirects console](/img/symfony/app-redirects.png)
After the final step you are presented with a client ID and secret.
Copy and paste them to a safe location for later use by the application.
The secret will not be displayed again, but you can regenerate one if you loose it.
## Setup new Symfony application
Now that you have configured your web application on the ZITADEL side, you can proceed with the integration of your Symfony client.
The example is build on a [generated Symfony web app](https://symfony.com/doc/current/setup.html#creating-symfony-applications), using the following command:
:::info
Skip this step if you are connecting ZITADEL to an existing application.
:::
```bash
symfony new my_project_directory --version="7.0.*" --webapp
cd my_project_directory
```
:::info
The remainder of this guide assumes a Symfony project which already includes all web app bundles, such as security, routing and ORM.
If you are using this guide against an existing project you must make sure the required bundles are installed using the `composer require` command.
:::
### Install Symfony dependencies
To connect with ZITADEL through OpenID connect, you need to install the [Symfony OIDC bundle](https://github.com/Drenso/symfony-oidc). Run the following command:
```bash
composer require drenso/symfony-oidc-bundle
```
## Define the Symfony app
### Create a User class
First, we need to create a User class for the database, so we can persist user info between requests. In this case you don't need password authentication.
Email addresses are not unique for ZITADEL users. There can be multiple user accounts with the same email address.
See [User Constraints](https://zitadel.com/docs/concepts/structure/users#constraints) for more details.
We will use the User Info `sub` claim as unique "display" name for the user. `sub` equals the unique User ID from ZITADEL.
This creates a User Repository and Entity that implements the `UserInterface`:
:::info
You can skip this step, if you already have an existing User object in your project.
:::
```bash
php bin/console make:user
The name of the security user class (e.g. User) [User]:
> User
Do you want to store user data in the database (via Doctrine)? (yes/no) [yes]:
> yes
Enter a property name that will be the unique "display" name for the user (e.g. email, username, uuid) [email]:
> sub
Will this app need to hash/check user passwords? Choose No if passwords are not needed or will be checked/hashed by some other system (e.g. a single sign-on server).
Does this app need to hash/check user passwords? (yes/no) [yes]:
> no
```
Next, extend the User Entity with properties that we will obtain from ZITADEL and use in the application later.
> None of the following properties are required for authentication, but show how we can map User Info to a Symfony User Entity later. You can adjust the properties how you wish for your application.
```bash
php bin/console make:entity
Class name of the entity to create or update (e.g. GrumpyElephant):
> User
Your entity already exists! So let's add some new fields!
New property name (press <return> to stop adding fields):
> display_name
Field type (enter ? to see all types) [string]:
> string
Field length [255]:
> 255
Can this field be null in the database (nullable) (yes/no) [no]:
> yes
updated: src/Entity/User.php
Add another property? Enter the property name (or press <return> to stop adding fields):
> full_name
Field type (enter ? to see all types) [string]:
> string
Field length [255]:
>
Can this field be null in the database (nullable) (yes/no) [no]:
> yes
updated: src/Entity/User.php
Add another property? Enter the property name (or press <return> to stop adding fields):
> email
Field type (enter ? to see all types) [string]:
> string
Field length [255]:
> 255
Can this field be null in the database (nullable) (yes/no) [no]:
> yes
updated: src/Entity/User.php
Add another property? Enter the property name (or press <return> to stop adding fields):
> email_verified
Field type (enter ? to see all types) [string]:
> boolean
Can this field be null in the database (nullable) (yes/no) [no]:
> yes
updated: src/Entity/User.php
Add another property? Enter the property name (or press <return> to stop adding fields):
> created_at
Field type (enter ? to see all types) [datetime_immutable]:
> datetime_immutable
Can this field be null in the database (nullable) (yes/no) [no]:
> no
updated: src/Entity/User.php
Add another property? Enter the property name (or press <return> to stop adding fields):
> updated_at
Field type (enter ? to see all types) [datetime_immutable]:
> datetime_immutable
Can this field be null in the database (nullable) (yes/no) [no]:
> no
updated: src/Entity/User.php
Add another property? Enter the property name (or press <return> to stop adding fields):
>
Success!
```
Now edit `src/Entity/User.php` to add some methods to pretty-print user data later in this example. Add import near the top of the file:
```php
use DateTimeInterface;
```
And extend the User class with this methods:
```php
class User implements UserInterface
{
...
public function implodeRoles(): string
{
return implode(', ', $this->getRoles());
}
public function formatCreatedAt(): string
{
return $this->created_at->format(DateTimeInterface::W3C);
}
public function formatUpdatedAt(): string
{
return $this->updated_at->format(DateTimeInterface::W3C);
}
}
```
When you are done, the User Entity should look something like:
```php reference
https://github.com/zitadel/example-symfony-oidc/blob/main/src/Entity/User.php
```
Edit the User Repository to have a `findOneBySub` method, used later for OIDC User Info updates.
```php reference
https://github.com/zitadel/example-symfony-oidc/blob/main/src/Repository/UserRepository.php
```
### Create a Security Provider
Next you will need to create a Security Provider that integrates the OIDC flow between Symfony and ZITADEL.
Create a `ZitadelUserProvider` which implements `UserProviderInterface`, `OidcUserProviderInterface` and `LoggerAwareInterface`.
`LoggerAwareInterface` is optional if you want debug logging.
> We called this a `ZitadelUserProvider` because it carries a custom scope and claim mapping from ZITADEL roles to the Symfony role system.
```php reference
https://github.com/zitadel/example-symfony-oidc/blob/main/src/Security/ZitadelUserProvider.php
```
You can customize the User Info that is obtained and stored by adjusting the `SCOPES` constant, the `updateUserEntity` method and the User Entity.
### Controllers and templates
We need to create couple of Controllers and templates to define the app.
#### Index
The index controller serves a public page on the `/` route and provides some basic links to the authenticated sections of the app.
```php reference
https://github.com/zitadel/example-symfony-oidc/blob/main/src/Controller/IndexController.php
```
The index template:
```twig reference
https://github.com/zitadel/example-symfony-oidc/blob/main/templates/index.html.twig
```
#### Login
The login controller initiates the OIDC login flow by creating a Auth request and redirecting the user to ZITADEL.
```php reference
https://github.com/zitadel/example-symfony-oidc/blob/main/src/Controller/LoginController.php
```
#### Profile
The profile controller displays User Info of the currently authenticated user.
Any authenticated user will have access to this page.
```php reference
https://github.com/zitadel/example-symfony-oidc/blob/main/src/Controller/ProfileController.php
```
The profile template maps the User Entity to a HTML page.
```twig reference
https://github.com/zitadel/example-symfony-oidc/blob/main/templates/profile.html.twig
```
#### User list
The user list controller displays all users from the database, that were created during OIDC login.
Only users with an admin role will have access to this page.
```php reference
https://github.com/zitadel/example-symfony-oidc/blob/main/src/Controller/UserListController.php
```
```twig reference
https://github.com/zitadel/example-symfony-oidc/blob/main/templates/user_list.html.twig
```
## Configure and run the application
:::warning
Never store and commit secrets in a `.env` file. Use a `env.local` file instead and make sure the file is in `.gitignore`.
:::
### Database
Make sure you have a database configured in `.env` or `.env.local`. This example uses a local sqlite file to simplify setup:
```sh
DATABASE_URL="sqlite:///%kernel.project_dir%/var/data.db"
```
Create and run migrations:
```bash
php bin/console make:migration
php bin/console doctrine:migrations:migrate
```
### Security
A firewall needs to be defined along with roles based access control rules.
In the following example we define the `zitadel_user_provider` as the security class we wrote earlier. We configure the main firewall to use the `zitadel_user_provider` and listen for logout requests on the `/logout` path. We tell the oidc module to enable End Session support.
In the `access_control` section we protect the `/users` and `/profile` routes based on roles. Roles are mapped from ZITADEL to Symfony in the `ZitadelUserProvider` we wrote earlier.
```yaml reference
https://github.com/zitadel/example-symfony-oidc/blob/main/config/packages/security.yaml
```
### OIDC
The generated [`dresno_oidc.yaml`](https://github.com/zitadel/example-symfony-oidc/blob/main/config/packages/drenso_oidc.yaml) file can be edited to customize behavior of the OIDC bundle. For this example we stick with the default and use environment variables to connect to ZITADEL.
Edit `.env.local` to contain the details from the [Application setup section](#set-up-application-and-obtain-keys).
```sh
OIDC_WELL_KNOWN_URL="https://tims-zitadel-instance-oj7iry.zitadel.cloud/.well-known/openid-configuration"
OIDC_CLIENT_ID="248680248240075805@dev"
OIDC_CLIENT_SECRET="BJPhEJULSUXseC4geqg5Yg4wWMoy7RgZKar86mbIpt8ZekC5kixMzYGcXLDeeJv7"
```
> The well-known URL needs to be adjusted to your own instance domain.
Activate the route that is used as callback by the OIDC bundle:
```yaml reference
https://github.com/zitadel/example-symfony-oidc/blob/main/config/routes.yaml#L6-L7
```
### Run
You can use a local Symfony server to test the application.
```bash
symfony server:start --no-tls
```
Visit http://localhost:8000 and click around.
When you go to profile you will be redirected to login your user on ZITADEL.
After login you should see some profile data of the current user.
Upon clicking logout you are redirected to the homepage.
Now you can click "users" and login with an account that has the admin role.
## Completion
Congratulations! You have successfully integrated your Symfony application with ZITADEL!
If you get stuck, consider checking out our [example](https://github.com/zitadel/example-symfony-oidc) application. This application includes all the functionalities mentioned in this quick-start. You can start by cloning the repository and defining a `.env.local` with your settings. If you face issues, contact us or raise an issue on [GitHub](https://github.com/zitadel/example-symfony-oidc/issues).
### What's next?
Now that you have enabled authentication, it's time for you to add more authorizations to your application using ZITADEL APIs. To do this, you can refer to the [docs](/apis/introduction) or check out the ZITADEL Console code on [GitHub](https://github.com/zitadel/zitadel) which uses gRPC and OpenAPI to access data.

View File

@ -0,0 +1,129 @@
---
title: ZITADEL with Vue
sidebar_label: Vue
---
This integration guide demonstrates the recommended way to incorporate ZITADEL into your Vue application.
It explains how to enable user login in your application and how to fetch data from the user info endpoint.
By the end of this guide, your application will have login functionality and will be able to access the current user's profile.
:::tip
This documentation references our [example](https://github.com/zitadel/zitadel-vue) on GitHub.
It also uses the @zitadel/vue package with its default configuration.
:::
## Set up application and obtain keys
Before we begin developing our application, we need to perform a few configuration steps in the ZITADEL Console.
You'll need to provide some information about your app.
We recommend creating a new app to start from scratch.
Navigate to your project, then add a new application at the top of the page.
Select the **User Agent** application type and continue.
We recommend that you use [Proof Key for Code Exchange (PKCE)](/apis/openidoauth/grant-types#proof-key-for-code-exchange) for all single page applications.
![Create app in console](/img/vue/app-create.png)
### Redirect URIs
The redirect URIs field tells ZITADEL where it's allowed to redirect users after authentication. For development, you can set dev mode to `true` to enable insecure HTTP and redirect to a `localhost` URI.
The post logout redirect sends your users back to a public route on your application after they have logged out.
:::tip
If you are following along with the [example](https://github.com/zitadel/zitadel-vue), set the dev mode switch to `true`.
Configure a redirect URIs to *http:/<span></span>/localhost:5173/auth/signinwin/zitadel* and a post redirect URI to *http:/<span></span>/localhost:5173/*.
:::
Continue and create the application.
### Refresh Token and Client ID
After successful creation of the app, make sure you tick the checkbox to enable refresh tokens.
Also copy the client ID, as you will need it to configure your Vue client.
![Tick refresh token checkbox](/img/vue/tick-refresh-token.png)
## Create a project role "admin" and assign it to your user
Also note the projects resource ID, as you will need it to configure your Vue client.
![Create project role "admin"](/img/vue/project-role.png)
![Assign the "admin" role to your user](/img/vue/project-authz.png)
## Vue setup
Now that you have configured your web application on the ZITADEL side, you can proceed with the integration of your Vue client.
### Install Vue dependencies
To conveniently connect with ZITADEL, you can install the [@zitadel/vue NPM package](https://www.npmjs.com/package/@zitadel/vue). Run the following command:
```bash
npm install --save @zitadel/vue
```
### Create and configure the auth service
The @zitadel/vue package provides a `createZITADELAuth()` function which sets some defaults and calls the underlying [vue-oidc-client packages](https://github.com/soukoku/vue-oidc-client) `createOidcAuth()` function.
You can overwrite all the defaults with the aguments you pass to `createZITADELAuth()`.
Export the object returned from `createZITADELAuth()`
```ts reference
https://github.com/zitadel/zitadel-vue/blob/main/src/services/zitadelAuth.ts
```
### Register the auth service in your global variables when bootstrapping Vue
```ts reference
https://github.com/zitadel/zitadel-vue/blob/main/src/main.ts
```
### Add three new views to your application
The restricted admin view will only be shown if the user is authenticated and has the role "admin" in the apps project in ZITADEL.
```ts reference
https://github.com/zitadel/zitadel-vue/blob/main/src/views/Admin.vue
```
The restricted login view is shown to all authenticated users.
It prints all the information it gets from the token and from the user info endpoint.
```ts reference
https://github.com/zitadel/zitadel-vue/blob/main/src/views/Login.vue
```
The public no access view is shown to authenticated users who navigate to a page they don't have access to based on their roles.
```ts reference
https://github.com/zitadel/zitadel-vue/blob/main/src/views/NoAccess.vue
```
### Add protected routes to your new pages as well as a Signout link
Note that we conditionally render the admin view or the no access view based on the user's roles.
```ts reference
https://github.com/zitadel/zitadel-vue/blob/main/src/router/index.ts
```
## Completion
Congratulations! You have successfully integrated your Vue application with ZITADEL!
If you get stuck, consider checking out the [ZITADEL Vue example application](https://github.com/zitadel/zitadel-vue).
This application includes all the functionalities mentioned in this quickstart.
You can start by cloning the repository and change the arguments to createZITADELAuth so they fit your requirements.
If you face issues, contact us or [raise an issue on GitHub](https://github.com/zitadel/zitadel-vue/issues).
![App in console](/img/vue/app-screen.png)
### What's next?
Now that you have enabled authentication, you are ready to call add authorization to your application using ZITADEL APIs.
To do this, [refer to the API docs](/apis/introduction) or check out [the ZITADEL Console code on GitHub](https://github.com/zitadel/zitadel) which uses gRPC to access data.
For more information on how to create an Vue application, you can refer to [Vue](https://vuejs.org/guide/quick-start.html).
If you want to learn more about the libraries wrapped by [@zitadel/vue](https://www.npmjs.com/package/@zitadel/vue), [read the docs for vue-oidc-client](https://github.com/soukoku/vue-oidc-client/wiki/V1-Docs).

View File

@ -9,16 +9,17 @@ Management for resources.
## ZITADEL SDKs
| Language / Framework | Link Github | User Authentication | Manage resources | Notes |
|----------------------|---------------------------------------------------------------|-----------------------------------------------------------|------------------|-------------|
| .NET | [zitadel-net](https://github.com/smartive/zitadel-net) | ✔️ | ✔️ | `community` |
| Elixir | [zitadel_api](https://github.com/jshmrtn/zitadel_api) | ✔️ | ✔️ | `community` |
| Go | [zitadel-go](https://github.com/zitadel/zitadel-go) | 🚧 [WIP](https://github.com/zitadel/zitadel-go/tree/next) | ✔️ | `official` |
| JVM | 🚧 [WIP](https://github.com/zitadel/zitadel/discussions/3650) | ❓ | ❓ | TBD |
| Python | 🚧 [WIP](https://github.com/zitadel/zitadel/issues/3675) | ❓ | ❓ | TBD |
| NodeJS | [@zitadel/node](https://www.npmjs.com/package/@zitadel/node) | ❌ | ✔️ | `community` |
| Dart | [zitadel-dart](https://github.com/smartive/zitadel-dart) | ❌ | ✔️ | `community` |
| Rust | [zitadel-rust](https://github.com/smartive/zitadel-rust) | ✔️ | ✔️ | `community` |
| Language / Framework | Link Github | User Authentication | Manage resources | Notes |
|----------------------|---------------------------------------------------------------|-----------------------------------------------------------|------------------|-------------------|
| Go | [zitadel-go](https://github.com/zitadel/zitadel-go) | 🚧 [WIP](https://github.com/zitadel/zitadel-go/tree/next) | ✔️ | `official` |
| Vue | [zitadel-vue](https://github.com/zitadel/zitadel-vue) | ✔️ | ❌ | `official` |
| .NET | [zitadel-net](https://github.com/smartive/zitadel-net) | ✔️ | ✔️ | `community` |
| Elixir | [zitadel_api](https://github.com/jshmrtn/zitadel_api) | ✔️ | ✔️ | `community` |
| NodeJS | [@zitadel/node](https://www.npmjs.com/package/@zitadel/node) | ❌ | ✔️ | `community` |
| Dart | [zitadel-dart](https://github.com/smartive/zitadel-dart) | ❌ | ✔️ | `community` |
| Rust | [zitadel-rust](https://github.com/smartive/zitadel-rust) | ✔️ | ✔️ | `community` |
| JVM | 🚧 [WIP](https://github.com/zitadel/zitadel/discussions/3650) | ❓ | ❓ | TBD |
| Python | 🚧 [WIP](https://github.com/zitadel/zitadel/issues/3675) | ❓ | ❓ | TBD |
## Missing SDK

View File

@ -0,0 +1,283 @@
---
title: ZITADEL with Java Spring Boot
sidebar_label: Java Spring Boot
---
This integration guide shows you how to integrate **ZITADEL** into your Java Spring Boot API. It demonstrates how to secure your API using
OAuth 2 Token Introspection.
At the end of the guide you should have an API with a protected endpoint.
:::info
This documentation references our [example](https://github.com/zitadel/zitadel-java) on GitHub.
You can either create your own application or directly run the example by providing the necessary arguments.
:::
## Set up application
Before we begin developing our API, we need to perform a few configuration steps in the ZITADEL Console.
You'll need to provide some information about your app. We recommend creating a new app to start from scratch. Navigate to your Project, then add a new application at the top of the page.
Select the **API** application type and continue.
![Create app in console](/img/java-spring/api-create.png)
Select Basic Auth for authenticating at the Introspection Endpoint.
![Create app in console](/img/java-spring/api-create-auth.png)
After successful creation of the app, a pop-up will appear displaying the app's client ID. Copy the client ID and secret, as you will need it to configure your Java client.
![Create api key in console](/img/java-spring/api-create-clientid-secret.png)
## Spring Setup
Now that you have configured your web application on the ZITADEL side, you can proceed with the integration of your Spring client.
This guide will reference the [example repository](https://github.com/zitadel/zitadel-java) and explain the necessary steps taken in there.
If your starting from scratch, you can use the Spring Initializer with the [following setup](https://start.spring.io/#!type=maven-project&language=java&platformVersion=3.2.1&packaging=jar&jvmVersion=17&dependencies=web,lombok,oauth2-resource-server) as a base.
### Support class
To be able to take the most out of ZITADELs RBAC, we first need to create a CustomAuthorityOpaqueTokenIntrospector, that will
customize the introspection behaviour and map the role claims (`urn:zitadel:iam:org:project:roles`)
into Spring Security `authiorities`, which can be used later on to determine the granted permissions.
So in your application, create a `support/zitadel` package and in there the `CustomAuthorityOpaqueTokenIntrospector.java`:
```java reference
https://github.com/zitadel/zitadel-java/blob/main/api/src/main/java/demo/app/support/zitadel/CustomAuthorityOpaqueTokenIntrospector.java
```
### Application server configuration
As we have now our support class, we can now create and configure the application server itself.
In a new `config` package, create the `WebSecurityConfig.java`.
This class will take care of the authorization by require the calls on `/api/tasks` to be authorized. Any other endpoint will be public by default.
It will also use the just created CustomAuthorityOpaqueTokenIntrospector for the introspection call:
```java reference
https://github.com/zitadel/zitadel-java/blob/main/api/src/main/java/demo/app/config/WebSecurityConfig.java
```
For the authorization (and the server in general) to work, the application needs some configuration, so please provide the following to your `application.yml` (resources folder):
```yaml reference
https://github.com/zitadel/zitadel-java/blob/main/api/src/main/resources/application.yml
```
Note that the `introspection-uri`, `client-id` and `client-secret` are only placeholders. You can either change them in here using the values provided by ZITADEL
or pass them later on as arguments when starting the application.
### Create example API
Create a `api` package with a `ExampleController.java` file with the content below. This will create an API with three endpoints / methods:
- `/api/healthz`: can be called by anyone and always returns `OK`
- `/api/tasks (GET)`: requires authorization and returns the available tasks
- `/api/tasks (POST)`: requires authorization with granted `admin` role and adds the task to the list
If authorization is required, the token must not be expired and the API has to be part of the audience (either client_id or project_id).
For tests we will use a Personal Access Token or the [Java Spring web example](../login/java-spring).
```java reference
https://github.com/zitadel/zitadel-java/blob/main/api/src/main/java/demo/app/api/ExampleController.java
```
## Test API
In case you've created your own application and depending on your development setup you might need to build the application first:
```bash
mvn clean package -DskipTests
```
You will need to provide the `introspection-uri` (your ZITADEL domain> /oauth/v2/introspect), the `client-id` and `client-secret` previously created:
```bash
java \
-Dspring.security.oauth2.resourceserver.opaquetoken.introspection-uri=<see configuration above> \
-Dspring.security.oauth2.resourceserver.opaquetoken.client-id=<see configuration above> \
-Dspring.security.oauth2.resourceserver.opaquetoken.client-secret=<see configuration above> \
-jar api/target/api-0.0.2-SNAPSHOT.jar
```
This could look like:
```bash
java \
-Dspring.security.oauth2.resourceserver.opaquetoken.introspection-uri=https://my-domain.zitadel.cloud/oauth/v2/introspect \
-Dspring.security.oauth2.resourceserver.opaquetoken.client-id=243861220627644836@example \
-Dspring.security.oauth2.resourceserver.opaquetoken.client-secret=WJKLF3kfPOi3optkg9vi3jmfjv8oj32nfiäohj!FSC09RWUSR \
-jar web/target/web-0.0.2-SNAPSHOT.jar
```
### Public endpoint
Now you can call the API by browser or curl. Try the healthz endpoint first:
```bash
curl -i http://localhost:18090/api/healthz
```
it should return something like:
```
HTTP/1.1 200
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
X-Content-Type-Options: nosniff
X-XSS-Protection: 0
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-Frame-Options: DENY
Content-Type: text/plain;charset=UTF-8
Content-Length: 2
Date: Mon, 15 Jan 2024 09:07:21 GMT
OK
```
### Task list
and the task list endpoint:
```bash
curl -i http://localhost:18090/api/tasks
```
it will return:
```
HTTP/1.1 401
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
WWW-Authenticate: Bearer
X-Content-Type-Options: nosniff
X-XSS-Protection: 0
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-Frame-Options: DENY
Content-Length: 0
Date: Mon, 15 Jan 2024 09:07:55 GMT
```
Get a valid access_token for the API. You can either achieve this by getting an access token with the project_id in the audience
(e.g. by using the [Spring Boot web example](../login/java-spring)) use a PAT of a service account.
If you provide a valid Bearer Token:
```bash
curl -i -H "Authorization: Bearer ${token}" http://localhost:18090/api/tasks
```
it will return an empty list:
```
HTTP/1.1 200
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
X-Content-Type-Options: nosniff
X-XSS-Protection: 0
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-Frame-Options: DENY
Content-Type: application/json
Transfer-Encoding: chunked
Date: Mon, 15 Jan 2024 09:15:10 GMT
[]
```
### Try to add a new task
Let's see what happens if you call the tasks endpoint:
```bash
curl -i -X POST -H "Authorization: Bearer ${token}" -H "Content-Type: application/json" --data 'my new task' http://localhost:18090/api/tasks
```
it will complain with a permission denied (missing `admin` role):
```
HTTP/1.1 403
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
WWW-Authenticate: Bearer error="insufficient_scope", error_description="The request requires higher privileges than provided by the access token.", error_uri="https://tools.ietf.org/html/rfc6750#section-3.1"
X-Content-Type-Options: nosniff
X-XSS-Protection: 0
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-Frame-Options: DENY
Content-Length: 0
Date: Mon, 15 Jan 2024 09:24:39 GMT
```
### Add admin role
So let's create the role and grant it to the user. To do so, go to your project in ZITADEL Console
and create the role by selecting `Roles` in the navigation and then clicking on the `New Role` button.
Finally, create the role as shown below:
![Create project role in console](/img/java-spring/api-project-role.png)
After you have created the role, let's grant it the user, who requested the tasks.
Click on `Authorization` in the navigation and create a new one by selecting the user and the `admin` role.
After successful creation, it should look like:
![Created authorization in console](/img/java-spring/api-project-auth.png)
So you should now be able to add a new task:
```bash
curl -i -X POST -H "Authorization: Bearer ${token}" -H "Content-Type: application/json" --data 'my new task' http://localhost:18090/api/tasks
```
which will report back the successful addition:
```
HTTP/1.1 200
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
X-Content-Type-Options: nosniff
X-XSS-Protection: 0
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-Frame-Options: DENY
Content-Type: application/json
Content-Length: 10
Date: Mon, 15 Jan 2024 09:26:11 GMT
task added
```
Let's now retrieve the task list again:
```bash
curl -i -H "Authorization: Bearer ${token}" http://localhost:18090/api/tasks
```
As you can see your new task is listed:
```
HTTP/1.1 200
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
X-Content-Type-Options: nosniff
X-XSS-Protection: 0
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-Frame-Options: DENY
Content-Type: application/json
Transfer-Encoding: chunked
Date: Mon, 15 Jan 2024 09:26:48 GMT
["my new task"]
```

View File

@ -0,0 +1,71 @@
---
title: ZITADEL with Node.js
sidebar_label: Node.js
---
# ZITADEL with Node.js (NestJS)
This documentation section guides you through the process of integrating ZITADEL into your Node.js backend using the NestJS framework. The provided example demonstrates authentication using an OIDC (OAuth2) token introspection strategy with a ZITADEL service account for machine-to-machine communication.
## Overview
The NestJS API includes a single secured route that prints "Hello World!" when authenticated. The API expects an authorization header with a valid JWT, serving as a bearer token to authenticate the user when calling the API. The API will validate the access token on the [introspect endpoint](https://zitadel.com/docs/apis/openidoauth/endpoints#introspection_endpoint) and receive the user from ZITADEL.
The API application utilizes [JWT with Private Key](https://zitadel.com/docs/apis/openidoauth/authn-methods#jwt-with-private-key) for authentication against ZITADEL and accessing the introspection endpoint. Make sure to create an API Application within Zitadel and download the JSON. In this instance, we use this service account, so make sure to provide the secrets in the example application via environmental variables.
## Overview
The NestJS API includes a private endpoint `GET http://localhost:${APP_PORT}/api/v1/app`, which returns "Hello World" when authenticated. The authentication is performed using a JWT obtained through the token introspection strategy.
## Running the Example
### Prerequisites
Make sure you have Node.js and npm installed on your machine.
### ZITADEL Configuration for the API
1. Create a ZITADEL instance and a project by following the steps [here](https://zitadel.com/docs/guides/start/quickstart#2-create-your-first-instance).
2. Set up an API application within your project:
- Create a new application of type "API" with authentication method "Private Key".
- Create a and save the Private Key JSON file.
### Create and Run the API
Clone or download the [example repository](https://github.com/ehwplus/zitadel-nodejs-nestjs):
```bash
git clone https://github.com/ehwplus/zitadel-nodejs-nestjs && cd zitadel-nodejs-nestjs
```
and follow the instructions here: https://github.com/ehwplus/zitadel-nodejs-nestjs/blob/main/README.md#installation
### Test the API
Call the API without authorization headers:
```bash
curl --request GET \
--url http://localhost:${APP_PORT}/api/v1/app
```
You should get a response with Status Code 401 and an error message.
Now, add an authorization header with a valid JWT obtained through ZITADEL:
```bash
export JWT=your-valid-jwt
curl --request GET \
--url http://localhost:${APP_PORT}/api/v1/app \
--header "authorization: Bearer $JWT"
```
You should now receive a response with Status Code 200 and the message:
```json
"Hello World!"
```
Congratulations! You have successfully integrated ZITADEL authentication into your NestJS API using the Token Introspection strategy.

View File

@ -31,9 +31,11 @@ curl --request POST \
--header 'Authorization: Bearer '"$TOKEN"''\
--header 'Content-Type: application/json' \
--data '{
"idp_id": "$IDP_ID",
"successUrl": "https://custom.com/login/idp/success",
"failureUrl": "https://custom.com/login/idp/fail"
"idpId": "$IDP_ID",
"urls": {
"successUrl": "https://custom.com/login/idp/success",
"failureUrl": "https://custom.com/login/idp/fail"
}
}'
```

View File

@ -13,10 +13,11 @@ At the moment we provide only "Credit Card" payment
Once a payment method is configured, it can be selected directly in the instance creation process.
## Customer
## Customer
To be able to create correct billings we will need some customer information from you.
This includes the following fields:
- Name
- Country
- Email address
@ -25,6 +26,16 @@ This includes the following fields:
- Postal Code
- City
## Tax ID
If available, enter your tax ID type and VAT number.
The tax ID will be shown on the invoice.
:::info Reverse Charge
When you enter the tax ID we will automatically calculate taxability.
Depending on your billing address we will mark the invoice as reverse charge.
:::
## Update Billing Information
You will only need to add billing information if your instance is in the paid tier. There are two options on how to add your billing info.
@ -32,7 +43,6 @@ You will only need to add billing information if your instance is in the paid ti
2. Go to the billing menu and add a new payment method. You will be able to choose the added method, when upgrading the instance to the paid tier.
3. Add the billing information directly during the upgrade process.
## Invoices
We show all you invoices, and you are able to download them directly in the Customer Portal.

View File

@ -0,0 +1,42 @@
---
title: Settings
---
Manage your team, email subscriptions, and billing information on the [Settings](https://zitadel.com/admin/settings) page.
## Team name
Change your ZITADEL Cloud team name by entering a new name.
Confirm the changes by clicking the Change button.
## Notifications and newsletters
You can subscribe and unsubscribe to notifications and newsletters:
- Onboarding: Welcome information for new users
- Newsletter: Regular newsletter on ZITADEL
- Product News: Receive product updates
- Security: Receive notifications related to security issues
:::info Technical Advisories
If you want to stay up to date on our technical advisories, we recommend [subscribing here to the mailing list](https://zitadel.com/docs/support/technical_advisory#subscribe-to-our-mailing-list).
Technical advisories are notices that report major issues with ZITADEL Self-Hosted or the ZITADEL Cloud platform that could potentially impact security or stability in production environments.
:::
You can also manage your subscriptions by clicking the unsubscribe link in the emails.
:::info Mandatory Information
We are required to inform you about changes to the terms of service or based on regulatory requirements. You can't unsubscribe to these notifications.
:::
## Delete team
Permanently delete your ZITADEL Cloud account.
This will delete your team and delete all associated information.
Click **Delete Account** and confirm the next step.
## Update billing information
Refer to the [billing guide](./billing.md).

View File

@ -105,7 +105,7 @@ Go to the "Advanced" section, per default login with phone number should be allo
## Embedding ZITADEL in an iFrame
To maximise the security during login and in the Console UI, ZITADEL follows security best practices by setting a
Content-Security-Policy (CSP) and X-Frame-Options:
Content-Security-Policy (CSP), X-Frame-Options and cookies with SameSite Lax:
```
Content-Security-Policy: frame-ancestors 'none'
@ -136,7 +136,13 @@ This will change the CSP to the following:
Content-Security-Policy: frame-ancestors https://custom-domain.com
```
and remove the X-Frame-Options header.
remove the X-Frame-Options header and change the SameSite to `None`.
:::note
Please note, that SameSite None requires the cookie to be flagged `secure`, which means it must be sent over TLS (HTTPS) or localhost.
This also means that domains other than localhost must use TLS for this option to work.
This is due to browser restrictions: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#none
:::
### Disable Multi-factor (MFA) Prompt

View File

@ -1,6 +1,6 @@
---
title: Frontend and Back-end API Communication in ZITADEL
sidebar_label: Frontent and API Communcation
sidebar_label: Frontend and API Communication
---
This guide contains a use case and ZITADEL integration.

View File

@ -32,7 +32,7 @@ Service users that authenticate or access the management API are counted against
### Active external identity providers
To calculate the monthly amount we take maximum activated external identity providers on each day over a given month.
To calculate the monthly amount we take the sum of activated external identity providers over all instances on each day and calculate the average over a given month, rounded up to the next integer.
Excluded are configured identity providers that are not activated.
### Action minutes

View File

@ -31,7 +31,7 @@ Support features for ZITADEL Cloud subscriptions are as follows:
Subscription Plans | Free | Production | Enterprise Cloud
--- | --- | --- | ---
[Support hours](#support-hours) | Business hours | Business hours | bespoke (up to 24x7)
[Response Time](#slo---initial-response-time) (Severity 1) | Best effort | 48 business hours | bespoke (as low as 30min)
[Response Time](#slo---initial-response-time) (Severity 1) | n/a | 48 business hours | bespoke (as low as 30min)
[Community support](#community-support) | yes | yes | yes
[Professional support](#professional-support) | no | yes | yes
[Enterprise supported features](/docs/support/software-release-cycles-support.md#enterprise-supported) | no | no | yes
@ -101,6 +101,9 @@ If we fail to provide the initial response time objective, you will be entitled
Community support for ZITADEL is available on our website, our [public chat](https://zitadel.com/chat), and [GitHub](https://github.com/zitadel/).
We do only guarantee response times to Tickets reported via [professional support](#professional-support) channels only.
If you are an eligible customer, please use Tickets for critical or urgent issues.
#### Professional support
- Support is available in English

View File

@ -3,91 +3,6 @@ title: Set up ZITADEL on Kubernetes
sidebar_label: Kubernetes
---
import Disclaimer from './_disclaimer.mdx'
import DefaultUser from './_defaultuser.mdx'
import Next from './_next.mdx'
import NoteInstanceNotFound from './troubleshooting/_note_instance_not_found.mdx';
For getting started with an easily testable insecure setup with Postgres, follow the [Insecure Postgres Example](https://github.com/zitadel/zitadel-charts/tree/main/examples/1-postgres-insecure).
Installation and configuration details are described in the [open source ZITADEL charts repo](https://github.com/zitadel/zitadel-charts).
By default, the chart installs a secure and highly available ZITADEL instance.
For running an easily testable, insecure, non-HA ZITADEL instance, run the following commands.
## Add the Helm Repositories for CockroachDB and ZITADEL
```bash
helm repo add cockroachdb https://charts.cockroachdb.com/
helm repo add zitadel https://charts.zitadel.com
```
After you have your repositories added,
you can setup ZITADEL and either
- initialize an [IAM owner who is a human user](#setup-zitadel-and-a-human-admin) or
- initialize an [IAM owner who is a service account](#setup-zitadel-and-a-service-account-admin)
## Setup ZITADEL and a Human Admin
```bash
# Install CockroachDB
helm install crdb cockroachdb/cockroachdb \
--set fullnameOverride=crdb \
--set conf.single-node=true \
--set statefulset.replicas=1
# Install ZITADEL
helm install my-zitadel zitadel/zitadel \
--set zitadel.masterkey="MasterkeyNeedsToHave32Characters" \
--set zitadel.configmapConfig.ExternalSecure=false \
--set zitadel.configmapConfig.TLS.Enabled=false \
--set zitadel.secretConfig.Database.cockroach.User.Password="a-zitadel-db-user-password" \
--set replicaCount=1
# Make ZITADEL locally accessible
kubectl port-forward svc/my-zitadel 8080
```
<DefaultUser components={props.components} />
<NoteInstanceNotFound/>
## Setup ZITADEL and a Service Account Admin
With this setup, you don't create a human user that has the IAM_OWNER role.
Instead, you create a service account that has the IAM_OWNER role.
ZITADEL will also create a key for your, with which you can authenticate to the ZITADEL API.
For example, you can install ZITADEL and seemlessly provision ZITADEL resources after installation using [Terraform](/docs/guides/manage/terraform/basics.md).
:::caution
With this setup you only get a key for a service account. Logging in at ZITADEL using the login screen is not possible until you create a user with the ZITADEL API.
:::
```bash
# Install CockroachDB
helm install crdb cockroachdb/cockroachdb \
--set fullnameOverride=crdb \
--set conf.single-node=true \
--set statefulset.replicas=1
# Install ZITADEL
helm install my-zitadel zitadel/zitadel \
--set zitadel.masterkey="MasterkeyNeedsToHave32Characters" \
--set zitadel.configmapConfig.ExternalSecure=false \
--set zitadel.configmapConfig.TLS.Enabled=false \
--set zitadel.secretConfig.Database.cockroach.User.Password="a-zitadel-db-user-password" \
--set replicaCount=1 \
--set zitadel.configmapConfig.FirstInstance.Org.Machine.Machine.Username="zitadel-admin-sa" \
--set zitadel.configmapConfig.FirstInstance.Org.Machine.Machine.Name="Admin" \
--set zitadel.configmapConfig.FirstInstance.Org.Machine.MachineKey.Type=1
# Make ZITADEL locally accessible
kubectl port-forward svc/my-zitadel 8080
```
When Helm is done, you can print your service account key from a Kubernetes secret:
```bash
kubectl get secret zitadel-admin-sa -o jsonpath='{ .data.zitadel-admin-sa\.json }' | base64 --decode
```
<Next components={props.components} />
<Disclaimer components={props.components} />
For more information and configuration examples, go to the [ZITADEL charts repo](https://github.com/zitadel/zitadel-charts).

View File

@ -7,6 +7,26 @@ If you have a self-hosted ZITADEL environment, you can limit the usage of your [
For example, if you provide your customers [their own virtual instances](/concepts/structure/instance#multiple-virtual-instances) with access on their own domains, you can design a pricing model based on the usage of their instances.
The usage control features are currently limited to the instance level only.
## Block Instances
You can block an instance using the [system API](/category/apis/resources/system/limits).
Most requests to a blocked instance are rejected with the HTTP status *429 Too Many Requests* or the gRPC status *8 Resource Exhausted*.
However, requests to the [system API](/apis/introduction#system) are still allowed.
Requests to paths with the prefix */ui/login* return a redirect with HTTP status *302 Found* to */ui/console*, where the user is guided to *InstanceManagementURL*.
Blocked HTTP requests additionally set a cookie to make it easy to block traffic before it reaches your ZITADEL runtime, for example with a WAF rule.
You can block new instances by default using the *DefaultInstance.Limits.Block* runtime configuration.
The following snippets shows the default YAML:
```yaml
DefaultInstance:
Limits:
# If Block is true, all requests except to /ui/console or the system API are blocked and /ui/login is redirected to /ui/console.
# /ui/console shows a message that the instance is blocked with a link to Console.InstanceManagementURL
Block: # ZITADEL_DEFAULTINSTANCE_LIMITS_BLOCK
```
## Limit Audit Trails
You can restrict the maximum age of events returned by the following APIs:
@ -107,8 +127,9 @@ DefaultInstance:
### Exhausted Authenticated Requests
If a quota is configured to limit requests and the quotas amount is exhausted, all further requests are blocked except requests to the System API.
Also, a cookie is set, to make it easier to block further traffic before it reaches your ZITADEL runtime.
If a quota is configured to limit requests and the quotas amount is exhausted, all further authenticated requests are blocked except requests to the [system API](/apis/introduction#system).
Also, a cookie is set, to make it easier to block further traffic before it reaches your ZITADEL runtime, for example with a WAF rule.
The console is still served, but it only shows a dialog that says that the instance is blocked with a link to *InstanceManagementURL*.
### Exhausted Action Run Seconds

View File

@ -73,3 +73,40 @@ The WebFinger requirement and setup is a step a user has to take outside of thei
On their custom domain, e.g example.com, users need to host a WebFinger endpoint at https://example.com/.well-known/webfinger. When queried, this endpoint returns a JSON response detailing the issuer. Users would need to host the endpoint with the link to the ZITADEL issuer. Tailscale only looks up this endpoint once when a user signs up, and will only look up this endpoint again if the user needs to make a configuration change to their identity provider.
The requirements and a set up guide is detailed in the [Tailscale documentation](https://tailscale.com/kb/1240/sso-custom-oidc/).
## Login not possible. The organization of the user must be granted to the project
![Organization must be granted Error](/img/support/login_not_possible_error.png)
ZITADEL is not only capable of handling authentication but also authorization.
This error message tells you, that a project grant is missing from the owner organization to the organization of the authenticating user.
You do have two organizations, an owner (Organization A) and a customer (Organization B).
The Organization A owns a Project, and has to grant it to Organization B, so users are allowed to authenticate.
The error message is shown to users of Organization B that the permission is required, but the project is not granted to Organization B.
![Project Grant Missing](/img/support/project_grant_missing.png)
You do have two possibilities.
1. Disable the permission check
2. Give the permission to the organization
### Disable the permission check
1. Go to the organization, who owns the project, where the user tries to authenticate.
2. Navigate to the general settings of the needed project
3. Disable "Check for Project on Authentication"
![Project Settings](/img/support/check_for_project_on_authentication.png)
### Give the needed permission to the organization
1. Go to the organization, who owns the project, where the user tries to authenticate.
2. Navigate to the grants page of the needed project
3. Click on the "New" button
4. Search for the organization to which you want to grant the project (e.g Organization B)
5. Select the roles you want to grant
6. Click save
![Project Grant for Organization B](/img/support/project_grant_for_customer_b.png)

View File

@ -178,7 +178,7 @@ module.exports = {
selector: "div#",
},
prism: {
additionalLanguages: ["csharp", "dart", "groovy", "regex"],
additionalLanguages: ["csharp", "dart", "groovy", "regex", "java", "php"],
},
colorMode: {
defaultMode: "dark",

View File

@ -33,7 +33,7 @@
"docusaurus-plugin-openapi-docs": "^1.7.3",
"docusaurus-theme-openapi-docs": "^1.7.3",
"mdx-mermaid": "^1.1.0",
"postcss": "^8.4.19",
"postcss": "^8.4.31",
"raw-loader": "^4.0.2",
"react": "17.0.2",
"react-copy-to-clipboard": "^5.1.0",

View File

@ -11,11 +11,14 @@ module.exports = {
type: "category",
label: "Frontend",
items: [
"examples/login/angular",
"examples/login/react",
"examples/login/vue",
"examples/login/angular",
"examples/login/flutter",
"examples/login/nextjs",
"examples/login/go",
"examples/login/symfony",
"examples/login/java-spring",
],
collapsed: true,
},
@ -25,7 +28,9 @@ module.exports = {
items: [
"examples/secure-api/go",
"examples/secure-api/python-flask",
"examples/secure-api/dot-net"
"examples/secure-api/dot-net",
"examples/secure-api/nodejs-nestjs",
"examples/secure-api/java-spring",
],
collapsed: true,
},
@ -38,15 +43,15 @@ module.exports = {
items: [
"examples/introduction",
{
type: 'link',
label: 'Frontend', // The link label
href: '/examples/introduction#frontend', // The internal path
type: "link",
label: "Frontend", // The link label
href: "/examples/introduction#frontend", // The internal path
},
{
type: 'link',
label: 'Backend', // The link label
href: '/examples/introduction#backend', // The internal path
}
type: "link",
label: "Backend", // The link label
href: "/examples/introduction#backend", // The internal path
},
],
collapsed: true,
},
@ -128,9 +133,9 @@ module.exports = {
"guides/migrate/sources/zitadel",
"guides/migrate/sources/auth0",
"guides/migrate/sources/keycloak",
]
],
},
]
],
},
{
type: "category",
@ -151,8 +156,7 @@ module.exports = {
type: "generated-index",
title: "Authenticate Human Users",
slug: "guides/integrate/human-users",
description:
"How to authenticate human users with OpenID Connect",
description: "How to authenticate human users with OpenID Connect",
},
items: [
"guides/integrate/login-users",
@ -197,9 +201,7 @@ module.exports = {
type: "category",
label: "Role Management",
collapsed: true,
items: [
"guides/integrate/retrieve-user-roles"
],
items: ["guides/integrate/retrieve-user-roles"],
},
{
type: "category",
@ -209,8 +211,7 @@ module.exports = {
title: "Build your own Login UI",
slug: "/guides/integrate/login-ui",
description:
"In the following guides you will learn how to create your own login UI with our APIs. The different scenarios like username/password, external identity provider, etc. will be shown."
"In the following guides you will learn how to create your own login UI with our APIs. The different scenarios like username/password, external identity provider, etc. will be shown.",
},
collapsed: true,
items: [
@ -221,7 +222,7 @@ module.exports = {
"guides/integrate/login-ui/select-account",
"guides/integrate/login-ui/password-reset",
"guides/integrate/login-ui/logout",
"guides/integrate/login-ui/oidc-standard"
"guides/integrate/login-ui/oidc-standard",
],
},
{
@ -229,11 +230,11 @@ module.exports = {
label: "Configure Identity Providers",
link: {
type: "generated-index",
title: "Let Users Login with Preferred Identity Provider in ZITADEL",
title:
"Let Users Login with Preferred Identity Provider in ZITADEL",
slug: "/guides/integrate/identity-providers",
description:
"In the following guides you will learn how to configure and setup your preferred external identity provider in ZITADEL.",
},
collapsed: true,
items: [
@ -255,9 +256,9 @@ module.exports = {
collapsed: true,
items: [
{
type: 'link',
label: 'Authenticate Service Users',
href: '/guides/integrate/serviceusers',
type: "link",
label: "Authenticate Service Users",
href: "/guides/integrate/serviceusers",
},
"guides/integrate/access-zitadel-apis",
"guides/integrate/access-zitadel-system-api",
@ -282,48 +283,47 @@ module.exports = {
slug: "/guides/integrate/services",
description:
"With the guides in this section you will learn how to integrate ZITADEL with your services.",
},
collapsed: true,
items: [
{
type: 'autogenerated',
dirName: 'guides/integrate/services',
type: "autogenerated",
dirName: "guides/integrate/services",
},
{
type: 'link',
label: 'Bold BI (boldbi.com)',
href: 'https://support.boldbi.com/kb/article/13708/how-to-configure-zitadel-oauth-login-in-bold-bi',
type: "link",
label: "Bold BI (boldbi.com)",
href: "https://support.boldbi.com/kb/article/13708/how-to-configure-zitadel-oauth-login-in-bold-bi",
},
{
type: 'link',
label: 'Cloudflare workers',
href: 'https://zitadel.com/blog/increase-spa-security-with-cloudflare-workers',
type: "link",
label: "Cloudflare workers",
href: "https://zitadel.com/blog/increase-spa-security-with-cloudflare-workers",
},
{
type: 'link',
label: 'Firezone (firezone.dev)',
href: 'https://www.firezone.dev/docs/authenticate/oidc/zitadel',
type: "link",
label: "Firezone (firezone.dev)",
href: "https://www.firezone.dev/docs/authenticate/oidc/zitadel",
},
{
type: 'link',
label: 'Nextcloud',
href: 'https://zitadel.com/blog/zitadel-as-sso-provider-for-selfhosting',
type: "link",
label: "Nextcloud",
href: "https://zitadel.com/blog/zitadel-as-sso-provider-for-selfhosting",
},
{
type: 'link',
label: 'Netbird (netbird.io)',
href: 'https://docs.netbird.io/selfhosted/identity-providers',
type: "link",
label: "Netbird (netbird.io)",
href: "https://docs.netbird.io/selfhosted/identity-providers",
},
{
type: 'link',
label: 'Psono (psono.com)',
href: 'https://doc.psono.com/admin/configuration/oidc-zitadel.html',
type: "link",
label: "Psono (psono.com)",
href: "https://doc.psono.com/admin/configuration/oidc-zitadel.html",
},
{
type: 'link',
label: 'Zoho Desk (zoho.com)',
href: 'https://help.zoho.com/portal/en/kb/desk/user-management-and-security/data-security/articles/setting-up-saml-single-signon-for-help-center#Zitadel_IDP',
type: "link",
label: "Zoho Desk (zoho.com)",
href: "https://help.zoho.com/portal/en/kb/desk/user-management-and-security/data-security/articles/setting-up-saml-single-signon-for-help-center#Zitadel_IDP",
},
],
},
@ -336,18 +336,17 @@ module.exports = {
slug: "/guides/integrate/tools",
description:
"With the guides in this section you will learn how to integrate ZITADEL with your favorite tools.",
},
collapsed: true,
items: [
{
type: 'link',
label: 'Argo CD',
href: 'https://argo-cd.readthedocs.io/en/latest/operator-manual/user-management/zitadel/',
type: "link",
label: "Argo CD",
href: "https://argo-cd.readthedocs.io/en/latest/operator-manual/user-management/zitadel/",
},
"guides/integrate/tools/apache2",
"guides/integrate/authenticated-mongodb-charts",
"examples/identity-proxy/oauth2-proxy"
"examples/identity-proxy/oauth2-proxy",
],
},
],
@ -398,7 +397,7 @@ module.exports = {
"concepts/features/actions",
"concepts/features/audit-trail",
"concepts/features/selfservice",
]
],
},
{
type: "category",
@ -418,7 +417,7 @@ module.exports = {
"concepts/eventstore/implementation",
],
},
]
],
},
{
type: "category",
@ -428,26 +427,26 @@ module.exports = {
"support/software-release-cycles-support",
"support/troubleshooting",
{
type: 'link',
label: 'Support Service Descriptions',
href: '/legal/service-description/support-services',
type: "link",
label: "Support Service Descriptions",
href: "/legal/service-description/support-services",
},
{
type: 'category',
type: "category",
label: "Technical Advisory",
link: {
type: 'doc',
id: 'support/technical_advisory',
type: "doc",
id: "support/technical_advisory",
},
collapsed: true,
items: [
{
type: 'autogenerated',
dirName: 'support/advisory',
},
{
type: "autogenerated",
dirName: "support/advisory",
},
],
},
]
],
},
],
apis: [
@ -460,8 +459,7 @@ module.exports = {
type: "generated-index",
title: "Core Resources",
slug: "/apis/resources/",
description:
"Resource based API definitions",
description: "Resource based API definitions",
},
items: [
{
@ -473,7 +471,6 @@ module.exports = {
slug: "/apis/resources/auth",
description:
"The authentication API (aka Auth API) is used for all operations on the currently logged in user. The user id is taken from the sub claim in the token.",
},
items: require("./docs/apis/resources/auth/sidebar.js"),
},
@ -523,8 +520,8 @@ module.exports = {
title: "User Service API (Beta)",
slug: "/apis/resources/user_service",
description:
"This API is intended to manage users in a ZITADEL instance.\n"+
"\n"+
"This API is intended to manage users in a ZITADEL instance.\n" +
"\n" +
"This project is in beta state. It can AND will continue breaking until the services provide the same functionality as the current login.",
},
items: require("./docs/apis/resources/user_service/sidebar.js"),
@ -537,8 +534,8 @@ module.exports = {
title: "Session Service API (Beta)",
slug: "/apis/resources/session_service",
description:
"This API is intended to manage sessions in a ZITADEL instance.\n"+
"\n"+
"This API is intended to manage sessions in a ZITADEL instance.\n" +
"\n" +
"This project is in beta state. It can AND will continue breaking until the services provide the same functionality as the current login.",
},
items: require("./docs/apis/resources/session_service/sidebar.js"),
@ -551,8 +548,8 @@ module.exports = {
title: "OIDC Service API (Beta)",
slug: "/apis/resources/oidc_service",
description:
"Get OIDC Auth Request details and create callback URLs.\n"+
"\n"+
"Get OIDC Auth Request details and create callback URLs.\n" +
"\n" +
"This project is in beta state. It can AND will continue breaking until the services provide the same functionality as the current login.",
},
items: require("./docs/apis/resources/oidc_service/sidebar.js"),
@ -565,8 +562,8 @@ module.exports = {
title: "Settings Service API (Beta)",
slug: "/apis/resources/settings_service",
description:
"This API is intended to manage settings in a ZITADEL instance.\n"+
"\n"+
"This API is intended to manage settings in a ZITADEL instance.\n" +
"\n" +
"This project is in beta state. It can AND will continue to break until the services provide the same functionality as the current login.",
},
items: require("./docs/apis/resources/settings_service/sidebar.js"),
@ -577,7 +574,7 @@ module.exports = {
collapsed: true,
items: ["apis/assets/assets"],
},
]
],
},
{
type: "category",
@ -617,12 +614,12 @@ module.exports = {
"apis/actions/complement-token",
"apis/actions/customize-samlresponse",
"apis/actions/objects",
]
],
},
{
type: "doc",
label: "gRPC Status Codes",
id: "apis/statuscodes"
id: "apis/statuscodes",
},
{
type: "category",
@ -631,9 +628,9 @@ module.exports = {
items: ["apis/observability/metrics", "apis/observability/health"],
},
{
type: 'link',
label: 'Rate Limits (Cloud)', // The link label
href: '/legal/policies/rate-limit-policy', // The internal path
type: "link",
label: "Rate Limits (Cloud)", // The link label
href: "/legal/policies/rate-limit-policy", // The internal path
},
],
selfHosting: [
@ -649,7 +646,7 @@ module.exports = {
"self-hosting/deploy/knative",
"self-hosting/deploy/kubernetes",
"self-hosting/deploy/loadbalancing-example/loadbalancing-example",
"self-hosting/deploy/troubleshooting/troubleshooting"
"self-hosting/deploy/troubleshooting/troubleshooting",
],
},
{
@ -672,7 +669,7 @@ module.exports = {
"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/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",
@ -683,7 +680,7 @@ module.exports = {
"self-hosting/manage/tls_modes",
"self-hosting/manage/database/database",
"self-hosting/manage/updating_scaling",
"self-hosting/manage/usage_control"
"self-hosting/manage/usage_control",
],
},
],
@ -712,13 +709,14 @@ module.exports = {
type: "generated-index",
title: "Service description",
slug: "/legal/service-description",
description: "Description of services and service levels for ZITADEL Cloud and Enterprise subscriptions.",
description:
"Description of services and service levels for ZITADEL Cloud and Enterprise subscriptions.",
},
items: [
{
type: 'autogenerated',
dirName: 'legal/service-description',
}
type: "autogenerated",
dirName: "legal/service-description",
},
],
},
{
@ -729,16 +727,17 @@ module.exports = {
type: "generated-index",
title: "Policies",
slug: "/legal/policies",
description: "Policies and guidelines in addition to our terms of services.",
description:
"Policies and guidelines in addition to our terms of services.",
},
items: [
{
type: 'autogenerated',
dirName: 'legal/policies',
}
]
type: "autogenerated",
dirName: "legal/policies",
},
],
},
]
],
},
],
};

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 178 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 161 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Some files were not shown because too many files have changed in this diff Show More