diff --git a/build/local/environment.json b/build/local/environment.json deleted file mode 100644 index 914a5c4c02..0000000000 --- a/build/local/environment.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "authServiceUrl": "http://localhost:50000", - "mgmtServiceUrl": "http://localhost:50000", - "adminServiceUrl": "http://localhost:50000", - "issuer": "http://localhost:50002/oauth/v2", - "clientid": "@zitadel" -} diff --git a/cmd/admin/setup/01_sql/auth.sql b/cmd/admin/setup/01_sql/auth.sql index a96dc84ae1..2f0e62d502 100644 --- a/cmd/admin/setup/01_sql/auth.sql +++ b/cmd/admin/setup/01_sql/auth.sql @@ -127,6 +127,7 @@ CREATE TABLE auth.tokens ( audience STRING[] NULL, preferred_language STRING NULL, refresh_token_id STRING NULL, + is_pat BOOL NOT NULL DEFAULT false, instance_id STRING NULL, PRIMARY KEY (id), diff --git a/cmd/admin/setup/steps.yaml b/cmd/admin/setup/steps.yaml index a7c44bf530..6088ecdcb7 100644 --- a/cmd/admin/setup/steps.yaml +++ b/cmd/admin/setup/steps.yaml @@ -22,7 +22,7 @@ S2DefaultInstance: PasswordAgePolicy: ExpireWarnDays: 0 MaxAgeDays: 0 - OrgIAMPolicy: + DomainPolicy: UserLoginMustBeDomain: true LoginPolicy: AllowUsernamePassword: true diff --git a/cmd/admin/start/config.go b/cmd/admin/start/config.go index bd941bcbc5..be4f0a5b24 100644 --- a/cmd/admin/start/config.go +++ b/cmd/admin/start/config.go @@ -2,6 +2,8 @@ package start import ( "github.com/caos/logging" + "github.com/spf13/viper" + admin_es "github.com/caos/zitadel/internal/admin/repository/eventsourcing" internal_authz "github.com/caos/zitadel/internal/api/authz" "github.com/caos/zitadel/internal/api/http/middleware" @@ -16,7 +18,6 @@ import ( "github.com/caos/zitadel/internal/notification" "github.com/caos/zitadel/internal/query/projection" static_config "github.com/caos/zitadel/internal/static/config" - "github.com/spf13/viper" ) type Config struct { @@ -25,6 +26,8 @@ type Config struct { ExternalPort uint16 ExternalDomain string ExternalSecure bool + HTTP2HostHeader string + HTTP1HostHeader string Database database.Config Projections projection.Config AuthZ authz.Config diff --git a/cmd/admin/start/start.go b/cmd/admin/start/start.go index f8f7acab05..ccb7317d8a 100644 --- a/cmd/admin/start/start.go +++ b/cmd/admin/start/start.go @@ -4,7 +4,6 @@ import ( "context" "database/sql" _ "embed" - "errors" "fmt" "net" "net/http" @@ -139,7 +138,7 @@ func startAPIs(ctx context.Context, router *mux.Router, commands *command.Comman } verifier := internal_authz.Start(repo) - apis := api.New(config.Port, router, &repo, config.InternalAuthZ, config.ExternalSecure) + apis := api.New(config.Port, router, &repo, config.InternalAuthZ, config.ExternalSecure, config.HTTP2HostHeader) authRepo, err := auth_es.Start(config.Auth, config.SystemDefaults, commands, queries, dbClient, assets.HandlerPrefix, keys.OIDC, keys.User) if err != nil { return fmt.Errorf("error starting auth repo: %w", err) @@ -164,9 +163,10 @@ func startAPIs(ctx context.Context, router *mux.Router, commands *command.Comman if err != nil { return err } + instanceInterceptor := middleware.InstanceInterceptor(queries, config.HTTP1HostHeader) issuer := oidc.Issuer(config.ExternalDomain, config.ExternalPort, config.ExternalSecure) - oidcProvider, err := oidc.NewProvider(ctx, config.OIDC, issuer, login.DefaultLoggedOutPath, commands, queries, authRepo, config.SystemDefaults.KeyConfig, keys.OIDC, keys.OIDCKey, eventstore, dbClient, keyChan, userAgentInterceptor) + oidcProvider, err := oidc.NewProvider(ctx, config.OIDC, issuer, login.DefaultLoggedOutPath, commands, queries, authRepo, config.SystemDefaults.KeyConfig, keys.OIDC, keys.OIDCKey, eventstore, dbClient, keyChan, userAgentInterceptor, instanceInterceptor.Handler) if err != nil { return fmt.Errorf("unable to start oidc provider: %w", err) } @@ -178,18 +178,14 @@ func startAPIs(ctx context.Context, router *mux.Router, commands *command.Comman } apis.RegisterHandler(openapi.HandlerPrefix, openAPIHandler) - consoleID, err := consoleClientID(ctx, queries) - if err != nil { - return fmt.Errorf("unable to get client_id for console: %w", err) - } baseURL := http_util.BuildHTTP(config.ExternalDomain, config.ExternalPort, config.ExternalSecure) - c, err := console.Start(config.Console, config.ExternalDomain, baseURL, issuer, consoleID) + c, err := console.Start(config.Console, config.ExternalDomain, baseURL, issuer, instanceInterceptor.Handler) if err != nil { return fmt.Errorf("unable to start console: %w", err) } apis.RegisterHandler(console.HandlerPrefix, c) - l, err := login.CreateLogin(config.Login, commands, queries, authRepo, store, config.SystemDefaults, console.HandlerPrefix, config.ExternalDomain, baseURL, oidc.AuthCallback, config.ExternalSecure, userAgentInterceptor, keys.User, keys.IDPConfig, keys.CSRFCookieKey) + l, err := login.CreateLogin(config.Login, commands, queries, authRepo, store, config.SystemDefaults, console.HandlerPrefix, config.ExternalDomain, baseURL, oidc.AuthCallback, config.ExternalSecure, userAgentInterceptor, instanceInterceptor.Handler, keys.User, keys.IDPConfig, keys.CSRFCookieKey) if err != nil { return fmt.Errorf("unable to start login: %w", err) } @@ -236,29 +232,3 @@ func shutdownServer(ctx context.Context, server *http.Server) error { logging.New().Info("server shutdown gracefully") return nil } - -//TODO:!!??!! -func consoleClientID(ctx context.Context, queries *query.Queries) (string, error) { - iam, err := queries.Instance(ctx) - if err != nil { - return "", err - } - projectID, err := query.NewAppProjectIDSearchQuery(iam.IAMProjectID) - if err != nil { - return "", err - } - name, err := query.NewAppNameSearchQuery(query.TextContainsIgnoreCase, "console") //TODO:!!??!! - if err != nil { - return "", err - } - apps, err := queries.SearchApps(ctx, &query.AppSearchQueries{ - Queries: []query.SearchQuery{projectID, name}, - }) - if err != nil { - return "", err - } - if len(apps.Apps) != 1 || apps.Apps[0].OIDCConfig == nil { - return "", errors.New("invalid app") - } - return apps.Apps[0].OIDCConfig.ClientID, nil -} diff --git a/cmd/defaults.yaml b/cmd/defaults.yaml index 6faf23e62f..5f25a723fa 100644 --- a/cmd/defaults.yaml +++ b/cmd/defaults.yaml @@ -7,6 +7,8 @@ Port: 8080 ExternalPort: 8080 ExternalDomain: localhost ExternalSecure: true +HTTP2HostHeader: ":authority" +HTTP1HostHeader: "host" Database: Host: localhost @@ -181,3 +183,399 @@ SystemDefaults: PublicKeyLifetime: 30h SigningKeyRotationCheck: 10s SigningKeyGracefulPeriod: 10m + +InternalAuthZ: + RolePermissionMappings: + - Role: 'IAM_OWNER' + Permissions: + - "iam.read" + - "iam.write" + - "iam.features.read" + - "iam.features.write" + - "iam.policy.read" + - "iam.policy.write" + - "iam.policy.delete" + - "iam.member.read" + - "iam.member.write" + - "iam.member.delete" + - "iam.idp.read" + - "iam.idp.write" + - "iam.idp.delete" + - "iam.action.read" + - "iam.action.write" + - "iam.action.delete" + - "iam.flow.read" + - "iam.flow.write" + - "iam.flow.delete" + - "org.read" + - "org.global.read" + - "org.create" + - "org.write" + - "org.member.read" + - "org.member.write" + - "org.member.delete" + - "org.idp.read" + - "org.idp.write" + - "org.idp.delete" + - "org.action.read" + - "org.action.write" + - "org.action.delete" + - "org.flow.read" + - "org.flow.write" + - "org.flow.delete" + - "user.read" + - "user.global.read" + - "user.write" + - "user.delete" + - "user.grant.read" + - "user.grant.write" + - "user.grant.delete" + - "user.membership.read" + - "user.credential.write" + - "features.read" + - "policy.read" + - "policy.write" + - "policy.delete" + - "project.read" + - "project.create" + - "project.write" + - "project.delete" + - "project.member.read" + - "project.member.write" + - "project.member.delete" + - "project.role.read" + - "project.role.write" + - "project.role.delete" + - "project.app.read" + - "project.app.write" + - "project.app.delete" + - "project.grant.read" + - "project.grant.write" + - "project.grant.delete" + - "project.grant.member.read" + - "project.grant.member.write" + - "project.grant.member.delete" + - Role: 'IAM_OWNER_VIEWER' + Permissions: + - "iam.read" + - "iam.features.read" + - "iam.policy.read" + - "iam.member.read" + - "iam.idp.read" + - "iam.action.read" + - "iam.flow.read" + - "org.read" + - "org.member.read" + - "org.idp.read" + - "org.action.read" + - "org.flow.read" + - "user.read" + - "user.global.read" + - "user.grant.read" + - "user.membership.read" + - "features.read" + - "policy.read" + - "project.read" + - "project.member.read" + - "project.role.read" + - "project.app.read" + - "project.grant.read" + - "project.grant.member.read" + - Role: 'IAM_ORG_MANAGER' + Permissions: + - "org.read" + - "org.global.read" + - "org.create" + - "org.write" + - "org.member.read" + - "org.member.write" + - "org.member.delete" + - "org.idp.read" + - "org.idp.write" + - "org.idp.delete" + - "org.action.read" + - "org.action.write" + - "org.action.delete" + - "org.flow.read" + - "org.flow.write" + - "org.flow.delete" + - "user.read" + - "user.global.read" + - "user.write" + - "user.delete" + - "user.grant.read" + - "user.grant.write" + - "user.grant.delete" + - "user.membership.read" + - "user.credential.write" + - "features.read" + - "policy.read" + - "policy.write" + - "policy.delete" + - "project.read" + - "project.create" + - "project.write" + - "project.delete" + - "project.member.read" + - "project.member.write" + - "project.member.delete" + - "project.role.read" + - "project.role.write" + - "project.role.delete" + - "project.app.read" + - "project.app.write" + - "project.app.delete" + - "project.grant.read" + - "project.grant.write" + - "project.grant.delete" + - "project.grant.member.read" + - "project.grant.member.write" + - "project.grant.member.delete" + - Role: 'IAM_USER_MANAGER' + Permissions: + - "org.read" + - "org.global.read" + - "org.member.read" + - "org.member.delete" + - "user.read" + - "user.global.read" + - "user.write" + - "user.delete" + - "user.grant.read" + - "user.grant.write" + - "user.grant.delete" + - "user.membership.read" + - "features.read" + - "project.read" + - "project.member.read" + - "project.role.read" + - "project.app.read" + - "project.grant.read" + - "project.grant.write" + - "project.grant.delete" + - "project.grant.member.read" + - Role: 'ORG_OWNER' + Permissions: + - "org.read" + - "org.global.read" + - "org.create" + - "org.write" + - "org.member.read" + - "org.member.write" + - "org.member.delete" + - "org.idp.read" + - "org.idp.write" + - "org.idp.delete" + - "org.action.read" + - "org.action.write" + - "org.action.delete" + - "org.flow.read" + - "org.flow.write" + - "org.flow.delete" + - "user.read" + - "user.global.read" + - "user.write" + - "user.delete" + - "user.grant.read" + - "user.grant.write" + - "user.grant.delete" + - "user.membership.read" + - "user.credential.write" + - "features.read" + - "policy.read" + - "policy.write" + - "policy.delete" + - "project.read" + - "project.create" + - "project.write" + - "project.delete" + - "project.member.read" + - "project.member.write" + - "project.member.delete" + - "project.role.read" + - "project.role.write" + - "project.role.delete" + - "project.app.read" + - "project.app.write" + - "project.grant.read" + - "project.grant.write" + - "project.grant.delete" + - "project.grant.member.read" + - "project.grant.member.write" + - "project.grant.member.delete" + - Role: 'ORG_USER_MANAGER' + Permissions: + - "user.read" + - "user.global.read" + - "user.write" + - "user.delete" + - "user.grant.read" + - "user.grant.write" + - "user.grant.delete" + - "user.membership.read" + - "project.read" + - "project.role.read" + - Role: 'ORG_OWNER_VIEWER' + Permissions: + - "org.read" + - "org.member.read" + - "org.idp.read" + - "org.action.read" + - "org.flow.read" + - "user.read" + - "user.global.read" + - "user.grant.read" + - "user.membership.read" + - "features.read" + - "policy.read" + - "project.read" + - "project.member.read" + - "project.role.read" + - "project.app.read" + - "project.grant.read" + - "project.grant.member.read" + - "project.grant.user.grant.read" + - Role: 'ORG_USER_PERMISSION_EDITOR' + Permissions: + - "org.read" + - "org.member.read" + - "user.read" + - "user.global.read" + - "user.grant.read" + - "user.grant.write" + - "user.grant.delete" + - "policy.read" + - "project.read" + - "project.member.read" + - "project.role.read" + - "project.app.read" + - "project.grant.read" + - "project.grant.member.read" + - Role: 'ORG_PROJECT_PERMISSION_EDITOR' + Permissions: + - "org.read" + - "org.member.read" + - "user.read" + - "user.global.read" + - "user.grant.read" + - "user.grant.write" + - "user.grant.delete" + - "policy.read" + - "project.read" + - "project.member.read" + - "project.role.read" + - "project.app.read" + - "project.grant.read" + - "project.grant.write" + - "project.grant.delete" + - "project.grant.member.read" + - Role: 'ORG_PROJECT_CREATOR' + Permissions: + - "user.global.read" + - "policy.read" + - "project.read:self" + - "project.create" + - Role: 'PROJECT_OWNER' + Permissions: + - "org.global.read" + - "policy.read" + - "project.read" + - "project.write" + - "project.delete" + - "project.member.read" + - "project.member.write" + - "project.member.delete" + - "project.role.read" + - "project.role.write" + - "project.role.delete" + - "project.app.read" + - "project.app.write" + - "project.app.delete" + - "project.grant.read" + - "project.grant.write" + - "project.grant.delete" + - "project.grant.member.read" + - "project.grant.member.write" + - "project.grant.member.delete" + - "user.read" + - "user.global.read" + - "user.grant.read" + - "user.grant.write" + - "user.grant.delete" + - "user.membership.read" + - Role: 'PROJECT_OWNER_VIEWER' + Permissions: + - "policy.read" + - "project.read" + - "project.member.read" + - "project.role.read" + - "project.app.read" + - "project.grant.read" + - "project.grant.member.read" + - "user.read" + - "user.global.read" + - "user.grant.read" + - "user.membership.read" + - Role: 'SELF_MANAGEMENT_GLOBAL' + Permissions: + - "org.create" + - "policy.read" + - "user.self.delete" + - Role: 'PROJECT_OWNER_GLOBAL' + Permissions: + - "org.global.read" + - "policy.read" + - "project.read" + - "project.write" + - "project.delete" + - "project.member.read" + - "project.member.write" + - "project.member.delete" + - "project.role.read" + - "project.role.write" + - "project.role.delete" + - "project.app.read" + - "project.app.write" + - "project.app.delete" + - "user.global.read" + - "user.grant.read" + - "user.grant.write" + - "user.grant.delete" + - "user.membership.read" + - Role: 'PROJECT_OWNER_VIEWER_GLOBAL' + Permissions: + - "policy.read" + - "project.read" + - "project.member.read" + - "project.role.read" + - "project.app.read" + - "project.grant.read" + - "project.grant.member.read" + - "user.global.read" + - "user.grant.read" + - "user.membership.read" + - Role: 'PROJECT_GRANT_OWNER' + Permissions: + - "policy.read" + - "org.global.read" + - "project.read" + - "project.grant.read" + - "project.grant.member.read" + - "project.grant.member.write" + - "project.grant.member.delete" + - "user.read" + - "user.global.read" + - "user.grant.read" + - "user.grant.write" + - "user.grant.delete" + - "user.membership.read" + - Role: 'PROJECT_GRANT_OWNER_VIEWER' + Permissions: + - "policy.read" + - "project.read" + - "project.grant.read" + - "project.grant.member.read" + - "user.read" + - "user.global.read" + - "user.grant.read" + - "user.membership.read" diff --git a/console/src/app/modules/info-row/info-row.component.ts b/console/src/app/modules/info-row/info-row.component.ts index 474dc3afd3..42d4cfac4b 100644 --- a/console/src/app/modules/info-row/info-row.component.ts +++ b/console/src/app/modules/info-row/info-row.component.ts @@ -29,9 +29,7 @@ export class InfoRowComponent implements OnInit { .toPromise().then((env: any) => { this.environmentMap = { issuer: env.issuer, - adminServiceUrl: env.adminServiceUrl, - mgmtServiceUrl: env.mgmtServiceUrl, - authServiceUrl: env.adminServiceUrl, + api: env.api, }; }); } diff --git a/console/src/app/services/asset.service.ts b/console/src/app/services/asset.service.ts index c165f5050f..2fd59ed4d8 100644 --- a/console/src/app/services/asset.service.ts +++ b/console/src/app/services/asset.service.ts @@ -84,9 +84,8 @@ export class AssetService { .get('./assets/environment.json') .toPromise() .then((data: any) => { - if (data && data.assetServiceUrl) { - console.log(data.assetServiceUrl); - return data.assetServiceUrl; + if (data && data.api) { + return data.api; } }) .catch((error) => { diff --git a/console/src/app/services/grpc.service.ts b/console/src/app/services/grpc.service.ts index d851d397e7..5b665c6c87 100644 --- a/console/src/app/services/grpc.service.ts +++ b/console/src/app/services/grpc.service.ts @@ -34,7 +34,7 @@ export class GrpcService { .get('./assets/environment.json') .toPromise() .then((data: any) => { - if (data && data.authServiceUrl && data.mgmtServiceUrl && data.issuer) { + if (data && data.api && data.issuer) { const interceptors = { unaryInterceptors: [ new OrgInterceptor(this.storageService), @@ -44,20 +44,19 @@ export class GrpcService { }; this.auth = new AuthServiceClient( - data.authServiceUrl, + data.api, null, // @ts-ignore interceptors, ); this.mgmt = new ManagementServiceClient( - data.mgmtServiceUrl, + data.api, null, // @ts-ignore interceptors, ); this.admin = new AdminServiceClient( - // TODO: replace with service url - data.mgmtServiceUrl, + data.api, null, // @ts-ignore interceptors, diff --git a/console/src/app/services/subscription.service.ts b/console/src/app/services/subscription.service.ts index f138d9d830..520d6be149 100644 --- a/console/src/app/services/subscription.service.ts +++ b/console/src/app/services/subscription.service.ts @@ -26,7 +26,7 @@ export class SubscriptionService { return this.http.get('./assets/environment.json') .toPromise().then((data: any) => { if (data && data.subscriptionServiceUrl) { - const serviceUrl = data.subscriptionServiceUrl; + const serviceUrl = data.api; const accessToken = this.storageService.getItem(accessTokenStorageKey); return this.http.get(`${serviceUrl}/redirect`, { headers: { @@ -48,7 +48,7 @@ export class SubscriptionService { return this.http.get('./assets/environment.json') .toPromise().then((data: any) => { if (data && data.subscriptionServiceUrl) { - const serviceUrl = data.subscriptionServiceUrl; + const serviceUrl = data.api; const accessToken = this.storageService.getItem(accessTokenStorageKey); return this.http.get(`${serviceUrl}/customer`, { headers: { @@ -68,7 +68,7 @@ export class SubscriptionService { return this.http.get('./assets/environment.json') .toPromise().then((data: any) => { if (data && data.subscriptionServiceUrl) { - const serviceUrl = data.subscriptionServiceUrl; + const serviceUrl = data.api; const accessToken = this.storageService.getItem(accessTokenStorageKey); return this.http.post(`${serviceUrl}/customer`, body, { headers: { diff --git a/console/src/assets/environment.json b/console/src/assets/environment.json index 2e91c42371..67a823885c 100644 --- a/console/src/assets/environment.json +++ b/console/src/assets/environment.json @@ -1,9 +1,5 @@ { - "authServiceUrl": "https://api.zitadel.dev", - "mgmtServiceUrl": "https://api.zitadel.dev", - "adminServiceUrl": "https://api.zitadel.dev", - "subscriptionServiceUrl": "https://sub.zitadel.dev", - "assetServiceUrl": "https://api.zitadel.dev", + "api": "https://api.zitadel.dev", "issuer": "https://issuer.zitadel.dev", "clientid": "70669160379706195@zitadel" } diff --git a/internal/api/api.go b/internal/api/api.go index 53f4223fc6..50070f87bd 100644 --- a/internal/api/api.go +++ b/internal/api/api.go @@ -44,6 +44,7 @@ func New( }, authZ internal_authz.Config, externalSecure bool, + http2HostName string, ) *API { verifier := internal_authz.Start(repo) api := &API{ @@ -53,7 +54,7 @@ func New( router: router, externalSecure: externalSecure, } - api.grpcServer = server.CreateServer(api.verifier, authZ, repo.Queries) + api.grpcServer = server.CreateServer(api.verifier, authZ, repo.Queries, http2HostName) api.routeGRPC() api.RegisterHandler("/debug", api.healthHandler()) diff --git a/internal/api/authz/context.go b/internal/api/authz/context.go index 0570e3f546..20534c3c67 100644 --- a/internal/api/authz/context.go +++ b/internal/api/authz/context.go @@ -31,10 +31,6 @@ func (ctxData CtxData) IsZero() bool { return ctxData.UserID == "" || ctxData.OrgID == "" } -type Instance struct { - ID string -} - type Grants []*Grant type Grant struct { @@ -116,15 +112,6 @@ func GetCtxData(ctx context.Context) CtxData { return ctxData } -func GetInstance(ctx context.Context) Instance { - instance, _ := ctx.Value(instanceKey).(Instance) - return instance -} - -func WithInstance(ctx context.Context, instance Instance) context.Context { - return context.WithValue(ctx, instanceKey, instance) -} - func GetRequestPermissionsFromCtx(ctx context.Context) []string { ctxPermission, _ := ctx.Value(requestPermissionsKey).([]string) return ctxPermission diff --git a/internal/api/authz/instance.go b/internal/api/authz/instance.go new file mode 100644 index 0000000000..5978eabb6f --- /dev/null +++ b/internal/api/authz/instance.go @@ -0,0 +1,51 @@ +package authz + +import ( + "context" +) + +var ( + emptyInstance = &instance{} +) + +type Instance interface { + InstanceID() string + ProjectID() string + ConsoleClientID() string +} + +type InstanceVerifier interface { + InstanceByHost(context.Context, string) (Instance, error) +} + +type instance struct { + ID string +} + +func (i *instance) InstanceID() string { + return i.ID +} + +func (i *instance) ProjectID() string { + return "" +} + +func (i *instance) ConsoleClientID() string { + return "" +} + +func GetInstance(ctx context.Context) Instance { + instance, ok := ctx.Value(instanceKey).(Instance) + if !ok { + return emptyInstance + } + return instance +} + +func WithInstance(ctx context.Context, instance Instance) context.Context { + return context.WithValue(ctx, instanceKey, instance) +} + +func WithInstanceID(ctx context.Context, id string) context.Context { + return context.WithValue(ctx, instanceKey, &instance{ID: id}) +} diff --git a/internal/api/authz/instance_test.go b/internal/api/authz/instance_test.go new file mode 100644 index 0000000000..1e2c625d73 --- /dev/null +++ b/internal/api/authz/instance_test.go @@ -0,0 +1,80 @@ +package authz + +import ( + "context" + "testing" + + "github.com/stretchr/testify/assert" +) + +func Test_Instance(t *testing.T) { + type args struct { + ctx context.Context + } + type res struct { + instanceID string + projectID string + consoleID string + } + tests := []struct { + name string + args args + res res + }{ + { + "empty context", + args{ + context.Background(), + }, + res{ + instanceID: "", + projectID: "", + consoleID: "", + }, + }, + { + "WithInstanceID", + args{ + WithInstanceID(context.Background(), "id"), + }, + res{ + instanceID: "id", + projectID: "", + consoleID: "", + }, + }, + { + "WithInstance", + args{ + WithInstance(context.Background(), &mockInstance{}), + }, + res{ + instanceID: "instanceID", + projectID: "projectID", + consoleID: "consoleID", + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := GetInstance(tt.args.ctx) + assert.Equal(t, tt.res.instanceID, got.InstanceID()) + assert.Equal(t, tt.res.projectID, got.ProjectID()) + assert.Equal(t, tt.res.consoleID, got.ConsoleClientID()) + }) + } +} + +type mockInstance struct{} + +func (m *mockInstance) InstanceID() string { + return "instanceID" +} + +func (m *mockInstance) ProjectID() string { + return "projectID" +} + +func (m *mockInstance) ConsoleClientID() string { + return "consoleID" +} diff --git a/internal/api/grpc/auth/user.go b/internal/api/grpc/auth/user.go index f6662dac4a..106e78b0bd 100644 --- a/internal/api/grpc/auth/user.go +++ b/internal/api/grpc/auth/user.go @@ -152,14 +152,10 @@ func (s *Server) ListMyProjectOrgs(ctx context.Context, req *auth_pb.ListMyProje return nil, err } - iam, err := s.query.Instance(ctx) - if err != nil { - return nil, err - } ctxData := authz.GetCtxData(ctx) //client of user is not in project of ZITADEL - if ctxData.ProjectID != iam.IAMProjectID { + if ctxData.ProjectID != authz.GetInstance(ctx).ProjectID() { userGrantProjectID, err := query.NewUserGrantProjectIDSearchQuery(ctxData.ProjectID) if err != nil { return nil, err diff --git a/internal/api/grpc/server/middleware/instance_interceptor.go b/internal/api/grpc/server/middleware/instance_interceptor.go new file mode 100644 index 0000000000..3d4fa4af18 --- /dev/null +++ b/internal/api/grpc/server/middleware/instance_interceptor.go @@ -0,0 +1,50 @@ +package middleware + +import ( + "context" + "fmt" + + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" + "google.golang.org/grpc/status" + + "github.com/caos/zitadel/internal/api/authz" +) + +type InstanceVerifier interface { + GetInstance(ctx context.Context) +} + +func InstanceInterceptor(verifier authz.InstanceVerifier, headerName string) grpc.UnaryServerInterceptor { + return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) { + return setInstance(ctx, req, info, handler, verifier, headerName) + } +} + +func setInstance(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler, verifier authz.InstanceVerifier, headerName string) (_ interface{}, err error) { + host, err := hostNameFromContext(ctx, headerName) + if err != nil { + return nil, status.Error(codes.PermissionDenied, err.Error()) + } + instance, err := verifier.InstanceByHost(ctx, host) + if err != nil { + return nil, status.Error(codes.PermissionDenied, err.Error()) + } + return handler(authz.WithInstance(ctx, instance), req) +} + +func hostNameFromContext(ctx context.Context, headerName string) (string, error) { + md, ok := metadata.FromIncomingContext(ctx) + if !ok { + return "", fmt.Errorf("cannot read metadata") + } + host, ok := md[headerName] + if !ok { + return "", fmt.Errorf("cannot find header: %v", headerName) + } + if len(host) != 1 { + return "", fmt.Errorf("invalid host header: %v", host) + } + return host[0], nil +} diff --git a/internal/api/grpc/server/middleware/instance_interceptor_test.go b/internal/api/grpc/server/middleware/instance_interceptor_test.go new file mode 100644 index 0000000000..6ecdcbcf9f --- /dev/null +++ b/internal/api/grpc/server/middleware/instance_interceptor_test.go @@ -0,0 +1,174 @@ +package middleware + +import ( + "context" + "fmt" + "reflect" + "testing" + + "google.golang.org/grpc" + "google.golang.org/grpc/metadata" + + "github.com/caos/zitadel/internal/api/authz" +) + +func Test_hostNameFromContext(t *testing.T) { + type args struct { + ctx context.Context + headerName string + } + type res struct { + want string + err bool + } + tests := []struct { + name string + args args + res res + }{ + { + "empty context, error", + args{ + ctx: context.Background(), + headerName: "header", + }, + res{ + want: "", + err: true, + }, + }, + { + "header not found", + args{ + ctx: metadata.NewIncomingContext(context.Background(), nil), + headerName: "header", + }, + res{ + want: "", + err: true, + }, + }, + { + "header not found", + args{ + ctx: metadata.NewIncomingContext(context.Background(), metadata.Pairs("header", "value")), + headerName: "header", + }, + res{ + want: "value", + err: false, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := hostNameFromContext(tt.args.ctx, tt.args.headerName) + if (err != nil) != tt.res.err { + t.Errorf("hostNameFromContext() error = %v, wantErr %v", err, tt.res.err) + return + } + if got != tt.res.want { + t.Errorf("hostNameFromContext() got = %v, want %v", got, tt.res.want) + } + }) + } +} + +func Test_setInstance(t *testing.T) { + type args struct { + ctx context.Context + req interface{} + info *grpc.UnaryServerInfo + handler grpc.UnaryHandler + verifier authz.InstanceVerifier + headerName string + } + type res struct { + want interface{} + err bool + } + tests := []struct { + name string + args args + res res + }{ + { + "hostname not found, error", + args{ + ctx: context.Background(), + }, + res{ + want: nil, + err: true, + }, + }, + { + "invalid host, error", + args{ + ctx: metadata.NewIncomingContext(context.Background(), metadata.Pairs("header", "host2")), + req: &mockRequest{}, + verifier: &mockInstanceVerifier{"host"}, + headerName: "header", + }, + res{ + want: nil, + err: true, + }, + }, + { + "valid host", + args{ + ctx: metadata.NewIncomingContext(context.Background(), metadata.Pairs("header", "host")), + req: &mockRequest{}, + verifier: &mockInstanceVerifier{"host"}, + headerName: "header", + handler: func(ctx context.Context, req interface{}) (interface{}, error) { + return req, nil + }, + }, + res{ + want: &mockRequest{}, + err: false, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := setInstance(tt.args.ctx, tt.args.req, tt.args.info, tt.args.handler, tt.args.verifier, tt.args.headerName) + if (err != nil) != tt.res.err { + t.Errorf("setInstance() error = %v, wantErr %v", err, tt.res.err) + return + } + if !reflect.DeepEqual(got, tt.res.want) { + t.Errorf("setInstance() got = %v, want %v", got, tt.res.want) + } + }) + } +} + +type mockRequest struct{} + +type mockInstanceVerifier struct { + host string +} + +func (m *mockInstanceVerifier) InstanceByHost(ctx context.Context, host string) (authz.Instance, error) { + if host != m.host { + return nil, fmt.Errorf("invalid host") + } + return &mockInstance{}, nil +} + +type mockInstance struct{} + +func (m *mockInstance) InstanceID() string { + return "instanceID" +} + +func (m *mockInstance) ProjectID() string { + return "projectID" +} + +func (m *mockInstance) ConsoleClientID() string { + return "consoleClientID" +} diff --git a/internal/api/grpc/server/server.go b/internal/api/grpc/server/server.go index 2776831607..2be5603e83 100644 --- a/internal/api/grpc/server/server.go +++ b/internal/api/grpc/server/server.go @@ -20,7 +20,7 @@ type Server interface { AuthMethods() authz.MethodMapping } -func CreateServer(verifier *authz.TokenVerifier, authConfig authz.Config, queries *query.Queries) *grpc.Server { +func CreateServer(verifier *authz.TokenVerifier, authConfig authz.Config, queries *query.Queries, hostHeaderName string) *grpc.Server { metricTypes := []metrics.MetricType{metrics.MetricTypeTotalCount, metrics.MetricTypeRequestCount, metrics.MetricTypeStatusCode} return grpc.NewServer( grpc.UnaryInterceptor( @@ -30,6 +30,7 @@ func CreateServer(verifier *authz.TokenVerifier, authConfig authz.Config, querie middleware.SentryHandler(), middleware.NoCacheInterceptor(), middleware.ErrorHandler(), + middleware.InstanceInterceptor(queries, hostHeaderName), middleware.AuthorizationInterceptor(verifier, authConfig), middleware.TranslationHandler(queries), middleware.ValidationHandler(), diff --git a/internal/api/http/middleware/instance_interceptor.go b/internal/api/http/middleware/instance_interceptor.go new file mode 100644 index 0000000000..6dc3a16670 --- /dev/null +++ b/internal/api/http/middleware/instance_interceptor.go @@ -0,0 +1,65 @@ +package middleware + +import ( + "context" + "fmt" + "net/http" + + "github.com/caos/zitadel/internal/api/authz" + "github.com/caos/zitadel/internal/telemetry/tracing" +) + +type instanceInterceptor struct { + verifier authz.InstanceVerifier + headerName string +} + +func InstanceInterceptor(verifier authz.InstanceVerifier, headerName string) *instanceInterceptor { + return &instanceInterceptor{ + verifier: verifier, + headerName: headerName, + } +} + +func (a *instanceInterceptor) Handler(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + ctx, err := setInstance(r, a.verifier, a.headerName) + if err != nil { + http.Error(w, err.Error(), http.StatusUnauthorized) + return + } + r = r.WithContext(ctx) + next.ServeHTTP(w, r) + }) +} + +func (a *instanceInterceptor) HandlerFunc(next http.HandlerFunc) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + ctx, err := setInstance(r, a.verifier, a.headerName) + if err != nil { + http.Error(w, err.Error(), http.StatusForbidden) + return + } + r = r.WithContext(ctx) + next.ServeHTTP(w, r) + } +} + +func setInstance(r *http.Request, verifier authz.InstanceVerifier, headerName string) (_ context.Context, err error) { + ctx := r.Context() + + authCtx, span := tracing.NewServerInterceptorSpan(ctx) + defer func() { span.EndWithError(err) }() + + host := r.Header.Get(headerName) + if host == "" { + return nil, fmt.Errorf("host header %s not found", headerName) + } + + instance, err := verifier.InstanceByHost(authCtx, host) + if err != nil { + return nil, err + } + span.End() + return authz.WithInstance(ctx, instance), nil +} diff --git a/internal/api/http/middleware/instance_interceptor_test.go b/internal/api/http/middleware/instance_interceptor_test.go new file mode 100644 index 0000000000..83778fae98 --- /dev/null +++ b/internal/api/http/middleware/instance_interceptor_test.go @@ -0,0 +1,258 @@ +package middleware + +import ( + "context" + "fmt" + "net/http" + "net/http/httptest" + "reflect" + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/caos/zitadel/internal/api/authz" +) + +func Test_instanceInterceptor_Handler(t *testing.T) { + type fields struct { + verifier authz.InstanceVerifier + headerName string + } + type args struct { + request *http.Request + } + type res struct { + statusCode int + context context.Context + } + tests := []struct { + name string + fields fields + args args + res res + }{ + { + "setInstance error", + fields{ + verifier: &mockInstanceVerifier{}, + headerName: "header", + }, + args{ + request: httptest.NewRequest("", "/url", nil), + }, + res{ + statusCode: 403, + context: nil, + }, + }, + { + "setInstance ok", + fields{ + verifier: &mockInstanceVerifier{"host"}, + headerName: "header", + }, + args{ + request: func() *http.Request { + r := httptest.NewRequest("", "/url", nil) + r.Header.Set("header", "host") + return r + }(), + }, + res{ + statusCode: 200, + context: authz.WithInstance(context.Background(), &mockInstance{}), + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + a := &instanceInterceptor{ + verifier: tt.fields.verifier, + headerName: tt.fields.headerName, + } + next := &testHandler{} + got := a.HandlerFunc(next.ServeHTTP) + rr := httptest.NewRecorder() + got.ServeHTTP(rr, tt.args.request) + assert.Equal(t, tt.res.statusCode, rr.Code) + assert.Equal(t, tt.res.context, next.context) + }) + } +} + +func Test_instanceInterceptor_HandlerFunc(t *testing.T) { + type fields struct { + verifier authz.InstanceVerifier + headerName string + } + type args struct { + request *http.Request + } + type res struct { + statusCode int + context context.Context + } + tests := []struct { + name string + fields fields + args args + res res + }{ + { + "setInstance error", + fields{ + verifier: &mockInstanceVerifier{}, + headerName: "header", + }, + args{ + request: httptest.NewRequest("", "/url", nil), + }, + res{ + statusCode: 403, + context: nil, + }, + }, + { + "setInstance ok", + fields{ + verifier: &mockInstanceVerifier{"host"}, + headerName: "header", + }, + args{ + request: func() *http.Request { + r := httptest.NewRequest("", "/url", nil) + r.Header.Set("header", "host") + return r + }(), + }, + res{ + statusCode: 200, + context: authz.WithInstance(context.Background(), &mockInstance{}), + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + a := &instanceInterceptor{ + verifier: tt.fields.verifier, + headerName: tt.fields.headerName, + } + next := &testHandler{} + got := a.HandlerFunc(next.ServeHTTP) + rr := httptest.NewRecorder() + got.ServeHTTP(rr, tt.args.request) + assert.Equal(t, tt.res.statusCode, rr.Code) + assert.Equal(t, tt.res.context, next.context) + }) + } +} + +func Test_setInstance(t *testing.T) { + type args struct { + r *http.Request + verifier authz.InstanceVerifier + headerName string + } + type res struct { + want context.Context + err bool + } + tests := []struct { + name string + args args + res res + }{ + { + "hostname not found, error", + args{ + r: func() *http.Request { + r := httptest.NewRequest("", "/url", nil) + return r + }(), + verifier: &mockInstanceVerifier{}, + headerName: "", + }, + res{ + want: nil, + err: true, + }, + }, + { + "invalid host, error", + args{ + r: func() *http.Request { + r := httptest.NewRequest("", "/url", nil) + r.Header.Set("header", "host2") + return r + }(), + verifier: &mockInstanceVerifier{"host"}, + headerName: "header", + }, + res{ + want: nil, + err: true, + }, + }, + { + "valid host", + args{ + r: func() *http.Request { + r := httptest.NewRequest("", "/url", nil) + r.Header.Set("header", "host") + return r + }(), + verifier: &mockInstanceVerifier{"host"}, + headerName: "header", + }, + res{ + want: authz.WithInstance(context.Background(), &mockInstance{}), + err: false, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := setInstance(tt.args.r, tt.args.verifier, tt.args.headerName) + if (err != nil) != tt.res.err { + t.Errorf("setInstance() error = %v, wantErr %v", err, tt.res.err) + return + } + if !reflect.DeepEqual(got, tt.res.want) { + t.Errorf("setInstance() got = %v, want %v", got, tt.res.want) + } + }) + } +} + +type testHandler struct { + context context.Context +} + +func (t *testHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { + t.context = r.Context() +} + +type mockInstanceVerifier struct { + host string +} + +func (m *mockInstanceVerifier) InstanceByHost(ctx context.Context, host string) (authz.Instance, error) { + if host != m.host { + return nil, fmt.Errorf("invalid host") + } + return &mockInstance{}, nil +} + +type mockInstance struct{} + +func (m *mockInstance) InstanceID() string { + return "instanceID" +} + +func (m *mockInstance) ProjectID() string { + return "projectID" +} + +func (m *mockInstance) ConsoleClientID() string { + return "consoleClientID" +} diff --git a/internal/api/oidc/auth_request.go b/internal/api/oidc/auth_request.go index 5bde39d1ee..50c355e821 100644 --- a/internal/api/oidc/auth_request.go +++ b/internal/api/oidc/auth_request.go @@ -46,7 +46,7 @@ func (o *OPStorage) AuthRequestByID(ctx context.Context, id string) (_ op.AuthRe if !ok { return nil, errors.ThrowPreconditionFailed(nil, "OIDC-D3g21", "no user agent id") } - instanceID := authz.GetInstance(ctx).ID + instanceID := authz.GetInstance(ctx).InstanceID() resp, err := o.repo.AuthRequestByIDCheckLoggedIn(ctx, id, userAgentID, instanceID) if err != nil { return nil, err @@ -58,7 +58,7 @@ func (o *OPStorage) AuthRequestByCode(ctx context.Context, code string) (_ op.Au ctx, span := tracing.NewSpan(ctx) defer func() { span.EndWithError(err) }() - instanceID := authz.GetInstance(ctx).ID + instanceID := authz.GetInstance(ctx).InstanceID() resp, err := o.repo.AuthRequestByCode(ctx, code, instanceID) if err != nil { return nil, err @@ -73,7 +73,7 @@ func (o *OPStorage) SaveAuthCode(ctx context.Context, id, code string) (err erro if !ok { return errors.ThrowPreconditionFailed(nil, "OIDC-Dgus2", "no user agent id") } - instanceID := authz.GetInstance(ctx).ID + instanceID := authz.GetInstance(ctx).InstanceID() return o.repo.SaveAuthCode(ctx, id, code, userAgentID, instanceID) } @@ -81,7 +81,7 @@ func (o *OPStorage) DeleteAuthRequest(ctx context.Context, id string) (err error ctx, span := tracing.NewSpan(ctx) defer func() { span.EndWithError(err) }() - instanceID := authz.GetInstance(ctx).ID + instanceID := authz.GetInstance(ctx).InstanceID() return o.repo.DeleteAuthRequest(ctx, id, instanceID) } diff --git a/internal/api/oidc/auth_request_converter.go b/internal/api/oidc/auth_request_converter.go index 3af880deed..3b0966505c 100644 --- a/internal/api/oidc/auth_request_converter.go +++ b/internal/api/oidc/auth_request_converter.go @@ -133,7 +133,7 @@ func CreateAuthRequestToBusiness(ctx context.Context, authReq *oidc.AuthRequest, SelectedIDPConfigID: GetSelectedIDPIDFromScopes(authReq.Scopes), MaxAuthAge: MaxAgeToBusiness(authReq.MaxAge), UserID: userID, - InstanceID: authz.GetInstance(ctx).ID, + InstanceID: authz.GetInstance(ctx).InstanceID(), Request: &domain.AuthRequestOIDC{ Scopes: authReq.Scopes, ResponseType: ResponseTypeToBusiness(authReq.ResponseType), diff --git a/internal/api/oidc/op.go b/internal/api/oidc/op.go index 2169b48dc1..13f15ea0ca 100644 --- a/internal/api/oidc/op.go +++ b/internal/api/oidc/op.go @@ -83,13 +83,13 @@ type OPStorage struct { assetAPIPrefix string } -func NewProvider(ctx context.Context, config Config, issuer, defaultLogoutRedirectURI string, command *command.Commands, query *query.Queries, repo repository.Repository, keyConfig systemdefaults.KeyConfig, encryptionAlg crypto.EncryptionAlgorithm, cryptoKey []byte, es *eventstore.Eventstore, projections *sql.DB, keyChan <-chan interface{}, userAgentCookie func(http.Handler) http.Handler) (op.OpenIDProvider, error) { +func NewProvider(ctx context.Context, config Config, issuer, defaultLogoutRedirectURI string, command *command.Commands, query *query.Queries, repo repository.Repository, keyConfig systemdefaults.KeyConfig, encryptionAlg crypto.EncryptionAlgorithm, cryptoKey []byte, es *eventstore.Eventstore, projections *sql.DB, keyChan <-chan interface{}, userAgentCookie, instanceHandler func(http.Handler) http.Handler) (op.OpenIDProvider, error) { opConfig, err := createOPConfig(config, issuer, defaultLogoutRedirectURI, cryptoKey) if err != nil { return nil, caos_errs.ThrowInternal(err, "OIDC-EGrqd", "cannot create op config: %w") } storage := newStorage(config, command, query, repo, keyConfig, encryptionAlg, es, projections, keyChan) - options, err := createOptions(config, userAgentCookie) + options, err := createOptions(config, userAgentCookie, instanceHandler) if err != nil { return nil, caos_errs.ThrowInternal(err, "OIDC-D3gq1", "cannot create options: %w") } @@ -131,12 +131,13 @@ func createOPConfig(config Config, issuer, defaultLogoutRedirectURI string, cryp return opConfig, nil } -func createOptions(config Config, userAgentCookie func(http.Handler) http.Handler) ([]op.Option, error) { +func createOptions(config Config, userAgentCookie, instanceHandler func(http.Handler) http.Handler) ([]op.Option, error) { metricTypes := []metrics.MetricType{metrics.MetricTypeRequestCount, metrics.MetricTypeStatusCode, metrics.MetricTypeTotalCount} interceptor := op.WithHttpInterceptors( middleware.MetricsHandler(metricTypes), middleware.TelemetryHandler(), middleware.NoCacheInterceptor, + instanceHandler, userAgentCookie, http_utils.CopyHeadersToContext, ) diff --git a/internal/api/ui/console/console.go b/internal/api/ui/console/console.go index 543c5f8049..a4b30d14c7 100644 --- a/internal/api/ui/console/console.go +++ b/internal/api/ui/console/console.go @@ -11,6 +11,8 @@ import ( "github.com/caos/logging" + "github.com/caos/zitadel/internal/api/authz" + "github.com/caos/zitadel/internal/api/http/middleware" ) @@ -51,12 +53,7 @@ func (i *spaHandler) Open(name string) (http.File, error) { return i.fileSystem.Open("/index.html") } -func Start(config Config, domain, url, issuer, clientID string) (http.Handler, error) { - environmentJSON, err := createEnvironmentJSON(url, issuer, clientID) - if err != nil { - return nil, fmt.Errorf("unable to marshal env for console: %w", err) - } - +func Start(config Config, domain, url, issuer string, instanceHandler func(http.Handler) http.Handler) (http.Handler, error) { consoleDir := consoleDefaultDir if config.ConsoleOverwriteDir != "" { consoleDir = config.ConsoleOverwriteDir @@ -73,10 +70,20 @@ func Start(config Config, domain, url, issuer, clientID string) (http.Handler, e handler := &http.ServeMux{} handler.Handle("/", cache(security(http.FileServer(&spaHandler{consoleHTTPDir})))) - handler.Handle(envRequestPath, cache(security(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - _, err := w.Write(environmentJSON) + handler.Handle(envRequestPath, instanceHandler(cache(security(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + instance := authz.GetInstance(r.Context()) + if instance.InstanceID() == "" { + http.Error(w, "empty instanceID", http.StatusInternalServerError) + return + } + environmentJSON, err := createEnvironmentJSON(url, issuer, instance.ConsoleClientID()) + if err != nil { + http.Error(w, fmt.Sprintf("unable to marshal env for console: %v", err), http.StatusInternalServerError) + return + } + _, err = w.Write(environmentJSON) logging.OnError(err).Error("error serving environment.json") - })))) + }))))) return handler, nil } @@ -92,23 +99,15 @@ func csp(zitadelDomain string) *middleware.CSP { return &csp } -func createEnvironmentJSON(url, issuer, clientID string) ([]byte, error) { +func createEnvironmentJSON(api, issuer, clientID string) ([]byte, error) { environment := struct { - AuthServiceUrl string `json:"authServiceUrl,omitempty"` - MgmtServiceUrl string `json:"mgmtServiceUrl,omitempty"` - AdminServiceUrl string `json:"adminServiceUrl,omitempty"` - SubscriptionServiceUrl string `json:"subscriptionServiceUrl,omitempty"` - AssetServiceUrl string `json:"assetServiceUrl,omitempty"` - Issuer string `json:"issuer,omitempty"` - ClientID string `json:"clientid,omitempty"` + API string `json:"api,omitempty"` + Issuer string `json:"issuer,omitempty"` + ClientID string `json:"clientid,omitempty"` }{ - AuthServiceUrl: url, - MgmtServiceUrl: url, - AdminServiceUrl: url, - SubscriptionServiceUrl: url, - AssetServiceUrl: url, - Issuer: issuer, - ClientID: clientID, + API: api, + Issuer: issuer, + ClientID: clientID, } return json.Marshal(environment) } diff --git a/internal/api/ui/login/auth_request.go b/internal/api/ui/login/auth_request.go index 241aa958de..12dfbc7b8d 100644 --- a/internal/api/ui/login/auth_request.go +++ b/internal/api/ui/login/auth_request.go @@ -20,7 +20,7 @@ func (l *Login) getAuthRequest(r *http.Request) (*domain.AuthRequest, error) { return nil, nil } userAgentID, _ := http_mw.UserAgentIDFromCtx(r.Context()) - instanceID := authz.GetInstance(r.Context()).ID + instanceID := authz.GetInstance(r.Context()).InstanceID() return l.authRepo.AuthRequestByID(r.Context(), authRequestID, userAgentID, instanceID) } diff --git a/internal/api/ui/login/external_login_handler.go b/internal/api/ui/login/external_login_handler.go index a1154d7fbe..2cd8b756b8 100644 --- a/internal/api/ui/login/external_login_handler.go +++ b/internal/api/ui/login/external_login_handler.go @@ -89,7 +89,7 @@ func (l *Login) handleIDP(w http.ResponseWriter, r *http.Request, authReq *domai return } userAgentID, _ := http_mw.UserAgentIDFromCtx(r.Context()) - instanceID := authz.GetInstance(r.Context()).ID + instanceID := authz.GetInstance(r.Context()).InstanceID() err = l.authRepo.SelectExternalIDP(r.Context(), authReq.ID, idpConfig.IDPConfigID, userAgentID, instanceID) if err != nil { l.renderLogin(w, r, authReq, err) @@ -142,7 +142,7 @@ func (l *Login) handleExternalLoginCallback(w http.ResponseWriter, r *http.Reque return } userAgentID, _ := http_mw.UserAgentIDFromCtx(r.Context()) - instanceID := authz.GetInstance(r.Context()).ID + instanceID := authz.GetInstance(r.Context()).InstanceID() authReq, err := l.authRepo.AuthRequestByID(r.Context(), data.State, userAgentID, instanceID) if err != nil { l.renderError(w, r, authReq, err) @@ -202,7 +202,7 @@ func (l *Login) handleExternalUserAuthenticated(w http.ResponseWriter, r *http.R return } - instanceID := authz.GetInstance(r.Context()).ID + instanceID := authz.GetInstance(r.Context()).InstanceID() err = l.authRepo.CheckExternalUserLogin(setContext(r.Context(), ""), authReq.ID, userAgentID, instanceID, externalUser, domain.BrowserInfoFromRequest(r)) if err != nil { if errors.IsNotFound(err) { @@ -329,7 +329,7 @@ func (l *Login) handleExternalNotFoundOptionCheck(w http.ResponseWriter, r *http return } else if data.ResetLinking { userAgentID, _ := http_mw.UserAgentIDFromCtx(r.Context()) - instanceID := authz.GetInstance(r.Context()).ID + instanceID := authz.GetInstance(r.Context()).InstanceID() err = l.authRepo.ResetLinkingUsers(r.Context(), authReq.ID, userAgentID, instanceID) if err != nil { l.renderExternalNotFoundOption(w, r, authReq, nil, nil, nil, nil, err) @@ -368,7 +368,7 @@ func (l *Login) handleAutoRegister(w http.ResponseWriter, r *http.Request, authR } userAgentID, _ := http_mw.UserAgentIDFromCtx(r.Context()) - instanceID := authz.GetInstance(r.Context()).ID + instanceID := authz.GetInstance(r.Context()).InstanceID() if len(authReq.LinkingUsers) == 0 { l.renderError(w, r, authReq, caos_errors.ThrowPreconditionFailed(nil, "LOGIN-asfg3", "Errors.ExternalIDP.NoExternalUserData")) return diff --git a/internal/api/ui/login/external_register_handler.go b/internal/api/ui/login/external_register_handler.go index 28a31265e7..994f802186 100644 --- a/internal/api/ui/login/external_register_handler.go +++ b/internal/api/ui/login/external_register_handler.go @@ -68,7 +68,7 @@ func (l *Login) handleExternalRegister(w http.ResponseWriter, r *http.Request) { return } userAgentID, _ := http_mw.UserAgentIDFromCtx(r.Context()) - instanceID := authz.GetInstance(r.Context()).ID + instanceID := authz.GetInstance(r.Context()).InstanceID() err = l.authRepo.SelectExternalIDP(r.Context(), authReq.ID, idpConfig.IDPConfigID, userAgentID, instanceID) if err != nil { l.renderLogin(w, r, authReq, err) @@ -89,7 +89,7 @@ func (l *Login) handleExternalRegisterCallback(w http.ResponseWriter, r *http.Re return } userAgentID, _ := http_mw.UserAgentIDFromCtx(r.Context()) - instanceID := authz.GetInstance(r.Context()).ID + instanceID := authz.GetInstance(r.Context()).InstanceID() authReq, err := l.authRepo.AuthRequestByID(r.Context(), data.State, userAgentID, instanceID) if err != nil { l.renderError(w, r, authReq, err) diff --git a/internal/api/ui/login/jwt_handler.go b/internal/api/ui/login/jwt_handler.go index 5b54662a13..9c5ae01bdb 100644 --- a/internal/api/ui/login/jwt_handler.go +++ b/internal/api/ui/login/jwt_handler.go @@ -45,7 +45,7 @@ func (l *Login) handleJWTRequest(w http.ResponseWriter, r *http.Request) { l.renderError(w, r, nil, err) return } - instanceID := authz.GetInstance(r.Context()).ID + instanceID := authz.GetInstance(r.Context()).InstanceID() authReq, err := l.authRepo.AuthRequestByID(r.Context(), data.AuthRequestID, userAgentID, instanceID) if err != nil { l.renderError(w, r, authReq, err) @@ -209,7 +209,7 @@ func (l *Login) handleJWTCallback(w http.ResponseWriter, r *http.Request) { l.renderError(w, r, nil, err) return } - instanceID := authz.GetInstance(r.Context()).ID + instanceID := authz.GetInstance(r.Context()).InstanceID() authReq, err := l.authRepo.AuthRequestByID(r.Context(), data.AuthRequestID, userAgentID, instanceID) if err != nil { l.renderError(w, r, authReq, err) diff --git a/internal/api/ui/login/link_users_handler.go b/internal/api/ui/login/link_users_handler.go index e45a5b63c0..dd9b498e33 100644 --- a/internal/api/ui/login/link_users_handler.go +++ b/internal/api/ui/login/link_users_handler.go @@ -14,7 +14,7 @@ const ( func (l *Login) linkUsers(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, err error) { userAgentID, _ := http_mw.UserAgentIDFromCtx(r.Context()) - instanceID := authz.GetInstance(r.Context()).ID + instanceID := authz.GetInstance(r.Context()).InstanceID() err = l.authRepo.LinkExternalUsers(setContext(r.Context(), authReq.UserOrgID), authReq.ID, userAgentID, instanceID, domain.BrowserInfoFromRequest(r)) l.renderLinkUsersDone(w, r, authReq, err) } diff --git a/internal/api/ui/login/login.go b/internal/api/ui/login/login.go index 5f68288305..8d85e122ee 100644 --- a/internal/api/ui/login/login.go +++ b/internal/api/ui/login/login.go @@ -66,7 +66,8 @@ func CreateLogin(config Config, baseURL, oidcAuthCallbackURL string, externalSecure bool, - userAgentCookie mux.MiddlewareFunc, + userAgentCookie, + instanceHandler mux.MiddlewareFunc, userCodeAlg crypto.EncryptionAlgorithm, idpConfigAlg crypto.EncryptionAlgorithm, csrfCookieKey []byte, @@ -104,7 +105,7 @@ func CreateLogin(config Config, return nil, fmt.Errorf("unable to create cacheInterceptor: %w", err) } security := middleware.SecurityHeaders(csp(), login.cspErrorHandler) - login.router = CreateRouter(login, statikFS, csrfInterceptor, cacheInterceptor, security, userAgentCookie, middleware.TelemetryHandler(EndpointResources)) + login.router = CreateRouter(login, statikFS, instanceHandler, csrfInterceptor, cacheInterceptor, security, userAgentCookie, middleware.TelemetryHandler(EndpointResources)) login.renderer = CreateRenderer(HandlerPrefix, statikFS, staticStorage, config.LanguageCookieName, systemDefaults.DefaultLanguage) login.parser = form.NewParser() return login, nil diff --git a/internal/api/ui/login/login_handler.go b/internal/api/ui/login/login_handler.go index 4f9107fe89..c98cebd3e1 100644 --- a/internal/api/ui/login/login_handler.go +++ b/internal/api/ui/login/login_handler.go @@ -60,7 +60,7 @@ func (l *Login) handleLoginNameCheck(w http.ResponseWriter, r *http.Request) { return } userAgentID, _ := http_mw.UserAgentIDFromCtx(r.Context()) - instanceID := authz.GetInstance(r.Context()).ID + instanceID := authz.GetInstance(r.Context()).InstanceID() loginName := data.LoginName err = l.authRepo.CheckLoginName(r.Context(), authReq.ID, loginName, userAgentID, instanceID) if err != nil { diff --git a/internal/api/ui/login/mfa_verify_handler.go b/internal/api/ui/login/mfa_verify_handler.go index 9b7fc1a755..175c280434 100644 --- a/internal/api/ui/login/mfa_verify_handler.go +++ b/internal/api/ui/login/mfa_verify_handler.go @@ -36,7 +36,7 @@ func (l *Login) handleMFAVerify(w http.ResponseWriter, r *http.Request) { } if data.MFAType == domain.MFATypeOTP { userAgentID, _ := http_mw.UserAgentIDFromCtx(r.Context()) - instanceID := authz.GetInstance(r.Context()).ID + instanceID := authz.GetInstance(r.Context()).InstanceID() err = l.authRepo.VerifyMFAOTP(setContext(r.Context(), authReq.UserOrgID), authReq.ID, authReq.UserID, authReq.UserOrgID, data.Code, userAgentID, instanceID, domain.BrowserInfoFromRequest(r)) if err != nil { l.renderMFAVerifySelected(w, r, authReq, step, domain.MFATypeOTP, err) diff --git a/internal/api/ui/login/mfa_verify_u2f_handler.go b/internal/api/ui/login/mfa_verify_u2f_handler.go index 33c982f4b3..1a61aae52e 100644 --- a/internal/api/ui/login/mfa_verify_u2f_handler.go +++ b/internal/api/ui/login/mfa_verify_u2f_handler.go @@ -30,7 +30,7 @@ func (l *Login) renderU2FVerification(w http.ResponseWriter, r *http.Request, au var webAuthNLogin *domain.WebAuthNLogin if err == nil { userAgentID, _ := http_mw.UserAgentIDFromCtx(r.Context()) - instanceID := authz.GetInstance(r.Context()).ID + instanceID := authz.GetInstance(r.Context()).InstanceID() webAuthNLogin, err = l.authRepo.BeginMFAU2FLogin(setContext(r.Context(), authReq.UserOrgID), authReq.UserID, authReq.UserOrgID, authReq.ID, userAgentID, instanceID) } if err != nil { @@ -72,7 +72,7 @@ func (l *Login) handleU2FVerification(w http.ResponseWriter, r *http.Request) { return } userAgentID, _ := http_mw.UserAgentIDFromCtx(r.Context()) - instanceID := authz.GetInstance(r.Context()).ID + instanceID := authz.GetInstance(r.Context()).InstanceID() err = l.authRepo.VerifyMFAU2F(setContext(r.Context(), authReq.UserOrgID), authReq.UserID, authReq.UserOrgID, authReq.ID, userAgentID, instanceID, credData, domain.BrowserInfoFromRequest(r)) if err != nil { l.renderU2FVerification(w, r, authReq, step.MFAProviders, err) diff --git a/internal/api/ui/login/register_handler.go b/internal/api/ui/login/register_handler.go index c6e3ff29ed..2c47c989dd 100644 --- a/internal/api/ui/login/register_handler.go +++ b/internal/api/ui/login/register_handler.go @@ -95,7 +95,7 @@ func (l *Login) handleRegisterCheck(w http.ResponseWriter, r *http.Request) { return } userAgentID, _ := http_mw.UserAgentIDFromCtx(r.Context()) - instanceID := authz.GetInstance(r.Context()).ID + instanceID := authz.GetInstance(r.Context()).InstanceID() err = l.authRepo.SelectUser(r.Context(), authRequest.ID, user.AggregateID, userAgentID, instanceID) if err != nil { l.renderRegister(w, r, authRequest, data, err) diff --git a/internal/api/ui/login/select_user_handler.go b/internal/api/ui/login/select_user_handler.go index 99efecbfe2..b2f2597837 100644 --- a/internal/api/ui/login/select_user_handler.go +++ b/internal/api/ui/login/select_user_handler.go @@ -39,7 +39,7 @@ func (l *Login) handleSelectUser(w http.ResponseWriter, r *http.Request) { return } userAgentID, _ := http_mw.UserAgentIDFromCtx(r.Context()) - instanceID := authz.GetInstance(r.Context()).ID + instanceID := authz.GetInstance(r.Context()).InstanceID() err = l.authRepo.SelectUser(r.Context(), authSession.ID, data.UserID, userAgentID, instanceID) if err != nil { l.renderError(w, r, authSession, err) diff --git a/internal/auth/repository/eventsourcing/eventstore/auth_request.go b/internal/auth/repository/eventsourcing/eventstore/auth_request.go index 085154b503..98c848ab55 100644 --- a/internal/auth/repository/eventsourcing/eventstore/auth_request.go +++ b/internal/auth/repository/eventsourcing/eventstore/auth_request.go @@ -1145,7 +1145,7 @@ func activeUserByID(ctx context.Context, userViewProvider userViewProvider, user if !(user.State == user_model.UserStateActive || user.State == user_model.UserStateInitial) { return nil, errors.ThrowPreconditionFailed(nil, "EVENT-FJ262", "Errors.User.NotActive") } - org, err := queries.OrgByID(context.TODO(), user.ResourceOwner) + org, err := queries.OrgByID(ctx, user.ResourceOwner) if err != nil { return nil, err } diff --git a/internal/auth/repository/eventsourcing/handler/handler.go b/internal/auth/repository/eventsourcing/handler/handler.go index 895782e93b..463d0b7830 100644 --- a/internal/auth/repository/eventsourcing/handler/handler.go +++ b/internal/auth/repository/eventsourcing/handler/handler.go @@ -73,5 +73,5 @@ func (h *handler) QueryLimit() uint64 { } func withInstanceID(ctx context.Context, instanceID string) context.Context { - return authz.WithInstance(ctx, authz.Instance{ID: instanceID}) + return authz.WithInstanceID(ctx, instanceID) } diff --git a/internal/auth_request/repository/cache/cache.go b/internal/auth_request/repository/cache/cache.go index 83d8726e91..f311d79891 100644 --- a/internal/auth_request/repository/cache/cache.go +++ b/internal/auth_request/repository/cache/cache.go @@ -35,18 +35,18 @@ func (c *AuthRequestCache) GetAuthRequestByCode(_ context.Context, code, instanc } func (c *AuthRequestCache) SaveAuthRequest(_ context.Context, request *domain.AuthRequest) error { - return c.saveAuthRequest(request, "INSERT INTO auth.auth_requests (id, request, instance_id, creation_date, change_date, request_type) VALUES($1, $2, $3, $3, $4, $5)", request.CreationDate, request.InstanceID, request.Request.Type()) + return c.saveAuthRequest(request, "INSERT INTO auth.auth_requests (id, request, instance_id, creation_date, change_date, request_type) VALUES($1, $2, $3, $4, $4, $5)", request.CreationDate, request.Request.Type()) } func (c *AuthRequestCache) UpdateAuthRequest(_ context.Context, request *domain.AuthRequest) error { if request.ChangeDate.IsZero() { request.ChangeDate = time.Now() } - return c.saveAuthRequest(request, "UPDATE auth.auth_requests SET request = $2, instance_id = $3 change_date = $4, code = $5 WHERE id = $1", request.ChangeDate, request.InstanceID, request.Code) + return c.saveAuthRequest(request, "UPDATE auth.auth_requests SET request = $2, instance_id = $3, change_date = $4, code = $5 WHERE id = $1", request.ChangeDate, request.Code) } func (c *AuthRequestCache) DeleteAuthRequest(_ context.Context, id, instanceID string) error { - _, err := c.client.Exec("DELETE FROM auth.auth_requests WHERE instance = $1 and id = $2", instanceID, id) + _, err := c.client.Exec("DELETE FROM auth.auth_requests WHERE instance_id = $1 and id = $2", instanceID, id) if err != nil { return caos_errs.ThrowInternal(err, "CACHE-dsHw3", "unable to delete auth request") } @@ -56,7 +56,7 @@ func (c *AuthRequestCache) DeleteAuthRequest(_ context.Context, id, instanceID s func (c *AuthRequestCache) getAuthRequest(key, value, instanceID string) (*domain.AuthRequest, error) { var b []byte var requestType domain.AuthRequestType - query := fmt.Sprintf("SELECT request, request_type FROM auth.auth_requests WHERE instance = $1 and %s = $2", key) + query := fmt.Sprintf("SELECT request, request_type FROM auth.auth_requests WHERE instance_id = $1 and %s = $2", key) err := c.client.QueryRow(query, instanceID, value).Scan(&b, &requestType) if err != nil { if errors.Is(err, sql.ErrNoRows) { @@ -74,18 +74,14 @@ func (c *AuthRequestCache) getAuthRequest(key, value, instanceID string) (*domai return request, nil } -func (c *AuthRequestCache) saveAuthRequest(request *domain.AuthRequest, query string, date time.Time, instanceID string, param interface{}) error { +func (c *AuthRequestCache) saveAuthRequest(request *domain.AuthRequest, query string, date time.Time, param interface{}) error { b, err := json.Marshal(request) if err != nil { return caos_errs.ThrowInternal(err, "CACHE-os0GH", "Errors.Internal") } - stmt, err := c.client.Prepare(query) + _, err = c.client.Exec(query, request.ID, b, request.InstanceID, date, param) if err != nil { return caos_errs.ThrowInternal(err, "CACHE-su3GK", "Errors.Internal") } - _, err = stmt.Exec(request.ID, b, date, instanceID, param) - if err != nil { - return caos_errs.ThrowInternal(err, "CACHE-sj8iS", "Errors.Internal") - } return nil } diff --git a/internal/authz/repository/eventsourcing/eventstore/token_verifier.go b/internal/authz/repository/eventsourcing/eventstore/token_verifier.go index f0d75ef011..d2404d2164 100644 --- a/internal/authz/repository/eventsourcing/eventstore/token_verifier.go +++ b/internal/authz/repository/eventsourcing/eventstore/token_verifier.go @@ -98,7 +98,7 @@ func (repo *TokenVerifierRepo) VerifyAccessToken(ctx context.Context, tokenStrin } func (repo *TokenVerifierRepo) ProjectIDAndOriginsByClientID(ctx context.Context, clientID string) (projectID string, origins []string, err error) { - app, err := repo.View.ApplicationByOIDCClientID(clientID) + app, err := repo.View.ApplicationByOIDCClientID(ctx, clientID) if err != nil { return "", nil, err } diff --git a/internal/authz/repository/eventsourcing/eventstore/user_membership.go b/internal/authz/repository/eventsourcing/eventstore/user_membership.go index 411787ab2c..fd3bce964f 100644 --- a/internal/authz/repository/eventsourcing/eventstore/user_membership.go +++ b/internal/authz/repository/eventsourcing/eventstore/user_membership.go @@ -44,7 +44,7 @@ func (repo *UserMembershipRepo) searchUserMemberships(ctx context.Context) ([]*u { Key: user_model.UserMembershipSearchKeyInstanceID, Method: domain.SearchMethodEquals, - Value: instance.ID, + Value: instance.InstanceID(), }, }, }) @@ -66,7 +66,7 @@ func (repo *UserMembershipRepo) searchUserMemberships(ctx context.Context) ([]*u { Key: user_model.UserMembershipSearchKeyInstanceID, Method: domain.SearchMethodEquals, - Value: instance.ID, + Value: instance.InstanceID(), }, }, }) diff --git a/internal/authz/repository/eventsourcing/view/application.go b/internal/authz/repository/eventsourcing/view/application.go index 1281fe2d49..4cb1ea5511 100644 --- a/internal/authz/repository/eventsourcing/view/application.go +++ b/internal/authz/repository/eventsourcing/view/application.go @@ -8,8 +8,8 @@ import ( "github.com/caos/zitadel/internal/telemetry/tracing" ) -func (v *View) ApplicationByOIDCClientID(clientID string) (*query.App, error) { - return v.Query.AppByOIDCClientID(context.TODO(), clientID) +func (v *View) ApplicationByOIDCClientID(ctx context.Context, clientID string) (*query.App, error) { + return v.Query.AppByOIDCClientID(ctx, clientID) } func (v *View) ApplicationByProjecIDAndAppName(ctx context.Context, projectID, appName string) (_ *query.App, err error) { diff --git a/internal/command/v2/instance.go b/internal/command/v2/instance.go index 815aee041b..d733a55f5b 100644 --- a/internal/command/v2/instance.go +++ b/internal/command/v2/instance.go @@ -61,6 +61,19 @@ type InstanceSetup struct { PrivacyLink string HelpLink string } + LabelPolicy struct { + PrimaryColor string + BackgroundColor string + WarnColor string + FontColor string + PrimaryColorDark string + BackgroundColorDark string + WarnColorDark string + FontColorDark string + HideLoginNameSuffix bool + ErrorMsgPopup bool + DisableWatermark bool + } LockoutPolicy struct { MaxAttempts uint64 ShouldShowLockoutFailure bool @@ -134,7 +147,7 @@ func (command *Command) SetUpInstance(ctx context.Context, setup *InstanceSetup) // if err != nil { // return nil, err // } - ctx = authz.SetCtxData(authz.WithInstance(ctx, authz.Instance{ID: "system"}), authz.CtxData{OrgID: domain.IAMID, ResourceOwner: domain.IAMID}) + ctx = authz.SetCtxData(authz.WithInstanceID(ctx, "system"), authz.CtxData{OrgID: domain.IAMID, ResourceOwner: domain.IAMID}) orgID, err := id.SonyFlakeGenerator.Next() if err != nil { @@ -196,6 +209,22 @@ func (command *Command) SetUpInstance(ctx context.Context, setup *InstanceSetup) AddPrivacyPolicy(instanceAgg, setup.PrivacyPolicy.TOSLink, setup.PrivacyPolicy.PrivacyLink, setup.PrivacyPolicy.HelpLink), AddDefaultLockoutPolicy(instanceAgg, setup.LockoutPolicy.MaxAttempts, setup.LockoutPolicy.ShouldShowLockoutFailure), + AddDefaultLabelPolicy( + instanceAgg, + setup.LabelPolicy.PrimaryColor, + setup.LabelPolicy.BackgroundColor, + setup.LabelPolicy.WarnColor, + setup.LabelPolicy.FontColor, + setup.LabelPolicy.PrimaryColorDark, + setup.LabelPolicy.BackgroundColorDark, + setup.LabelPolicy.WarnColorDark, + setup.LabelPolicy.FontColorDark, + setup.LabelPolicy.HideLoginNameSuffix, + setup.LabelPolicy.ErrorMsgPopup, + setup.LabelPolicy.DisableWatermark, + ), + ActivateDefaultLabelPolicy(instanceAgg), + AddEmailTemplate(instanceAgg, setup.EmailTemplate), } @@ -207,9 +236,9 @@ func (command *Command) SetUpInstance(ctx context.Context, setup *InstanceSetup) AddOrg(orgAgg, setup.Org.Name, command.iamDomain), AddHumanCommand(userAgg, &setup.Org.Human, command.userPasswordAlg), AddOrgMember(orgAgg, userID, domain.RoleOrgOwner), + AddInstanceMember(instanceAgg, userID, domain.RoleIAMOwner), AddProject(projectAgg, zitadelProjectName, userID, false, false, false, domain.PrivateLabelingSettingUnspecified), - SetIAMProject(instanceAgg, projectAgg.ID), AddAPIApp( @@ -260,6 +289,7 @@ func (command *Command) SetUpInstance(ctx context.Context, setup *InstanceSetup) 0, nil, ), + SetIAMConsoleID(instanceAgg, setup.Zitadel.consoleClientID), ) cmds, err := preparation.PrepareCommands(ctx, command.es.Filter, validations...) @@ -278,7 +308,7 @@ func (command *Command) SetUpInstance(ctx context.Context, setup *InstanceSetup) }, nil } -//SetIAMProject defines the commands to set the id of the IAM project onto the instance +//SetIAMProject defines the command to set the id of the IAM project onto the instance func SetIAMProject(a *instance.Aggregate, projectID string) preparation.Validation { return func() (preparation.CreateCommands, error) { return func(ctx context.Context, filter preparation.FilterToQueryReducer) ([]eventstore.Command, error) { @@ -288,3 +318,14 @@ func SetIAMProject(a *instance.Aggregate, projectID string) preparation.Validati }, nil } } + +//SetIAMConsoleID defines the command to set the clientID of the Console App onto the instance +func SetIAMConsoleID(a *instance.Aggregate, clientID string) preparation.Validation { + return func() (preparation.CreateCommands, error) { + return func(ctx context.Context, filter preparation.FilterToQueryReducer) ([]eventstore.Command, error) { + return []eventstore.Command{ + instance.NewIAMConsoleSetEvent(ctx, &a.Aggregate, clientID), + }, nil + }, nil + } +} diff --git a/internal/command/v2/instance_label_policy.go b/internal/command/v2/instance_label_policy.go index 3946a3408a..e48609108d 100644 --- a/internal/command/v2/instance_label_policy.go +++ b/internal/command/v2/instance_label_policy.go @@ -43,3 +43,16 @@ func AddDefaultLabelPolicy( }, nil } } + +func ActivateDefaultLabelPolicy( + a *instance.Aggregate, +) preparation.Validation { + return func() (preparation.CreateCommands, error) { + return func(ctx context.Context, filter preparation.FilterToQueryReducer) ([]eventstore.Command, error) { + //TODO: check if already exists + return []eventstore.Command{ + instance.NewLabelPolicyActivatedEvent(ctx, &a.Aggregate), + }, nil + }, nil + } +} diff --git a/internal/command/v2/instance_member.go b/internal/command/v2/instance_member.go new file mode 100644 index 0000000000..537fac2698 --- /dev/null +++ b/internal/command/v2/instance_member.go @@ -0,0 +1,64 @@ +package command + +import ( + "context" + + "github.com/caos/zitadel/internal/command/v2/preparation" + "github.com/caos/zitadel/internal/errors" + "github.com/caos/zitadel/internal/eventstore" + "github.com/caos/zitadel/internal/repository/instance" +) + +func AddInstanceMember(a *instance.Aggregate, userID string, roles ...string) preparation.Validation { + return func() (preparation.CreateCommands, error) { + if userID == "" { + return nil, errors.ThrowInvalidArgument(nil, "INSTA-SDSfs", "Errors.Invalid.Argument") + } + // TODO: check roles + return func(ctx context.Context, filter preparation.FilterToQueryReducer) ([]eventstore.Command, error) { + if exists, err := ExistsUser(ctx, filter, userID, ""); err != nil || !exists { + return nil, errors.ThrowNotFound(err, "INSTA-GSXOn", "Errors.User.NotFound") + } + if isMember, err := IsInstanceMember(ctx, filter, a.ID, userID); err != nil || isMember { + return nil, errors.ThrowAlreadyExists(err, "INSTA-pFDwe", "Errors.Instance.Member.AlreadyExists") + } + return []eventstore.Command{instance.NewMemberAddedEvent(ctx, &a.Aggregate, userID, roles...)}, nil + }, + nil + } +} + +func IsInstanceMember(ctx context.Context, filter preparation.FilterToQueryReducer, instanceID, userID string) (isMember bool, err error) { + events, err := filter(ctx, eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent). + OrderAsc(). + AddQuery(). + AggregateIDs(instanceID). + AggregateTypes(instance.AggregateType). + EventTypes( + instance.MemberAddedEventType, + instance.MemberRemovedEventType, + instance.MemberCascadeRemovedEventType, + ).Builder()) + if err != nil { + return false, err + } + + for _, event := range events { + switch e := event.(type) { + case *instance.MemberAddedEvent: + if e.UserID == userID { + isMember = true + } + case *instance.MemberRemovedEvent: + if e.UserID == userID { + isMember = false + } + case *instance.MemberCascadeRemovedEvent: + if e.UserID == userID { + isMember = false + } + } + } + + return isMember, nil +} diff --git a/internal/eventstore/aggregate.go b/internal/eventstore/aggregate.go index 6b061399d5..4e3025cd8d 100644 --- a/internal/eventstore/aggregate.go +++ b/internal/eventstore/aggregate.go @@ -21,7 +21,7 @@ func NewAggregate( ID: id, Type: typ, ResourceOwner: authz.GetCtxData(ctx).OrgID, - InstanceID: authz.GetInstance(ctx).ID, + InstanceID: authz.GetInstance(ctx).InstanceID(), Version: version, } diff --git a/internal/eventstore/eventstore.go b/internal/eventstore/eventstore.go index a71dcdd7e4..9f367f9674 100644 --- a/internal/eventstore/eventstore.go +++ b/internal/eventstore/eventstore.go @@ -41,7 +41,7 @@ func (es *Eventstore) Health(ctx context.Context) error { //Push pushes the events in a single transaction // an event needs at least an aggregate func (es *Eventstore) Push(ctx context.Context, cmds ...Command) ([]Event, error) { - events, constraints, err := commandsToRepository(authz.GetInstance(ctx).ID, cmds) + events, constraints, err := commandsToRepository(authz.GetInstance(ctx).InstanceID(), cmds) if err != nil { return nil, err } @@ -114,7 +114,7 @@ func uniqueConstraintsToRepository(instanceID string, constraints []*EventUnique //Filter filters the stored events based on the searchQuery // and maps the events to the defined event structs func (es *Eventstore) Filter(ctx context.Context, queryFactory *SearchQueryBuilder) ([]Event, error) { - query, err := queryFactory.build(authz.GetInstance(ctx).ID) + query, err := queryFactory.build(authz.GetInstance(ctx).InstanceID()) if err != nil { return nil, err } @@ -171,7 +171,7 @@ func (es *Eventstore) FilterToReducer(ctx context.Context, searchQuery *SearchQu //LatestSequence filters the latest sequence for the given search query func (es *Eventstore) LatestSequence(ctx context.Context, queryFactory *SearchQueryBuilder) (uint64, error) { - query, err := queryFactory.build(authz.GetInstance(ctx).ID) + query, err := queryFactory.build(authz.GetInstance(ctx).InstanceID()) if err != nil { return 0, err } diff --git a/internal/eventstore/v1/models/aggregate_creator.go b/internal/eventstore/v1/models/aggregate_creator.go index a2e112bdea..6819e5cbd8 100644 --- a/internal/eventstore/v1/models/aggregate_creator.go +++ b/internal/eventstore/v1/models/aggregate_creator.go @@ -21,7 +21,7 @@ func (c *AggregateCreator) NewAggregate(ctx context.Context, id string, typ Aggr instance := authz.GetInstance(ctx) editorUser := ctxData.UserID resourceOwner := ctxData.OrgID - instanceID := instance.ID + instanceID := instance.InstanceID() aggregate := &Aggregate{ ID: id, diff --git a/internal/notification/repository/eventsourcing/handler/notify_user.go b/internal/notification/repository/eventsourcing/handler/notify_user.go index 0e2d4f4f42..8aeb3bcfa1 100644 --- a/internal/notification/repository/eventsourcing/handler/notify_user.go +++ b/internal/notification/repository/eventsourcing/handler/notify_user.go @@ -251,7 +251,7 @@ func (u *NotifyUser) loginNameInformation(ctx context.Context, orgID string) (us return false, "", nil, err } if org.DomainPolicy == nil { - policy, err := u.queries.DefaultDomainPolicy(authz.WithInstance(ctx, authz.Instance{ID: org.InstanceID})) + policy, err := u.queries.DefaultDomainPolicy(authz.WithInstanceID(ctx, org.InstanceID)) if err != nil { return false, "", nil, err } diff --git a/internal/query/action.go b/internal/query/action.go index e493086088..061b87ebf1 100644 --- a/internal/query/action.go +++ b/internal/query/action.go @@ -101,7 +101,7 @@ func (q *Queries) SearchActions(ctx context.Context, queries *ActionSearchQuerie query, scan := prepareActionsQuery() stmt, args, err := queries.toQuery(query). Where(sq.Eq{ - ActionColumnInstanceID.identifier(): authz.GetInstance(ctx).ID, + ActionColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), }). ToSql() if err != nil { @@ -126,7 +126,7 @@ func (q *Queries) GetActionByID(ctx context.Context, id string, orgID string) (* sq.Eq{ ActionColumnID.identifier(): id, ActionColumnResourceOwner.identifier(): orgID, - ActionColumnInstanceID.identifier(): authz.GetInstance(ctx).ID, + ActionColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), }).ToSql() if err != nil { return nil, errors.ThrowInternal(err, "QUERY-Dgff3", "Errors.Query.SQLStatement") diff --git a/internal/query/action_flow.go b/internal/query/action_flow.go index b6a663fe37..d0046c70bb 100644 --- a/internal/query/action_flow.go +++ b/internal/query/action_flow.go @@ -68,7 +68,7 @@ func (q *Queries) GetFlow(ctx context.Context, flowType domain.FlowType, orgID s sq.Eq{ FlowsTriggersColumnFlowType.identifier(): flowType, FlowsTriggersColumnResourceOwner.identifier(): orgID, - FlowsTriggersColumnInstanceID.identifier(): authz.GetInstance(ctx).ID, + FlowsTriggersColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), }).ToSql() if err != nil { return nil, errors.ThrowInvalidArgument(err, "QUERY-HBRh3", "Errors.Query.InvalidRequest") @@ -88,7 +88,7 @@ func (q *Queries) GetActiveActionsByFlowAndTriggerType(ctx context.Context, flow FlowsTriggersColumnFlowType.identifier(): flowType, FlowsTriggersColumnTriggerType.identifier(): triggerType, FlowsTriggersColumnResourceOwner.identifier(): orgID, - FlowsTriggersColumnInstanceID.identifier(): authz.GetInstance(ctx).ID, + FlowsTriggersColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), ActionColumnState.identifier(): domain.ActionStateActive, }, ).ToSql() @@ -108,7 +108,7 @@ func (q *Queries) GetFlowTypesOfActionID(ctx context.Context, actionID string) ( query, args, err := stmt.Where( sq.Eq{ FlowsTriggersColumnActionID.identifier(): actionID, - FlowsTriggersColumnInstanceID.identifier(): authz.GetInstance(ctx).ID, + FlowsTriggersColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), }, ).ToSql() if err != nil { diff --git a/internal/query/app.go b/internal/query/app.go index 3ad0a96e93..6f4ccacc49 100644 --- a/internal/query/app.go +++ b/internal/query/app.go @@ -212,7 +212,7 @@ func (q *Queries) AppByProjectAndAppID(ctx context.Context, projectID, appID str sq.Eq{ AppColumnID.identifier(): appID, AppColumnProjectID.identifier(): projectID, - AppColumnInstanceID.identifier(): authz.GetInstance(ctx).ID, + AppColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), }, ).ToSql() if err != nil { @@ -228,7 +228,7 @@ func (q *Queries) AppByID(ctx context.Context, appID string) (*App, error) { query, args, err := stmt.Where( sq.Eq{ AppColumnID.identifier(): appID, - AppColumnInstanceID.identifier(): authz.GetInstance(ctx).ID, + AppColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), }, ).ToSql() if err != nil { @@ -244,7 +244,7 @@ func (q *Queries) ProjectIDFromOIDCClientID(ctx context.Context, appID string) ( query, args, err := stmt.Where( sq.Eq{ AppOIDCConfigColumnClientID.identifier(): appID, - AppColumnInstanceID.identifier(): authz.GetInstance(ctx).ID, + AppColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), }, ).ToSql() if err != nil { @@ -259,7 +259,7 @@ func (q *Queries) ProjectIDFromClientID(ctx context.Context, appID string) (stri stmt, scan := prepareProjectIDByAppQuery() query, args, err := stmt.Where( sq.And{ - sq.Eq{AppColumnInstanceID.identifier(): authz.GetInstance(ctx).ID}, + sq.Eq{AppColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID()}, sq.Or{ sq.Eq{AppOIDCConfigColumnClientID.identifier(): appID}, sq.Eq{AppAPIConfigColumnClientID.identifier(): appID}, @@ -279,7 +279,7 @@ func (q *Queries) ProjectByOIDCClientID(ctx context.Context, id string) (*Projec query, args, err := stmt.Where( sq.Eq{ AppOIDCConfigColumnClientID.identifier(): id, - AppColumnInstanceID.identifier(): authz.GetInstance(ctx).ID, + AppColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), }, ).ToSql() if err != nil { @@ -295,7 +295,7 @@ func (q *Queries) AppByOIDCClientID(ctx context.Context, clientID string) (*App, query, args, err := stmt.Where( sq.Eq{ AppOIDCConfigColumnClientID.identifier(): clientID, - AppColumnInstanceID.identifier(): authz.GetInstance(ctx).ID, + AppColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), }, ).ToSql() if err != nil { @@ -310,7 +310,7 @@ func (q *Queries) AppByClientID(ctx context.Context, clientID string) (*App, err stmt, scan := prepareAppQuery() query, args, err := stmt.Where( sq.And{ - sq.Eq{AppColumnInstanceID.identifier(): authz.GetInstance(ctx).ID}, + sq.Eq{AppColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID()}, sq.Or{ sq.Eq{AppOIDCConfigColumnClientID.identifier(): clientID}, sq.Eq{AppAPIConfigColumnClientID.identifier(): clientID}, @@ -329,7 +329,7 @@ func (q *Queries) SearchApps(ctx context.Context, queries *AppSearchQueries) (*A query, scan := prepareAppsQuery() stmt, args, err := queries.toQuery(query). Where( - sq.Eq{AppColumnInstanceID.identifier(): authz.GetInstance(ctx).ID}, + sq.Eq{AppColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID()}, ).ToSql() if err != nil { return nil, errors.ThrowInvalidArgument(err, "QUERY-fajp8", "Errors.Query.InvalidRequest") @@ -351,7 +351,7 @@ func (q *Queries) SearchClientIDs(ctx context.Context, queries *AppSearchQueries query, scan := prepareClientIDsQuery() stmt, args, err := queries.toQuery(query). Where( - sq.Eq{AppColumnInstanceID.identifier(): authz.GetInstance(ctx).ID}, + sq.Eq{AppColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID()}, ).ToSql() if err != nil { return nil, errors.ThrowInvalidArgument(err, "QUERY-fajp8", "Errors.Query.InvalidRequest") diff --git a/internal/query/authn_key.go b/internal/query/authn_key.go index e5c5050671..c392ff8e4c 100644 --- a/internal/query/authn_key.go +++ b/internal/query/authn_key.go @@ -103,7 +103,7 @@ func (q *Queries) SearchAuthNKeys(ctx context.Context, queries *AuthNKeySearchQu stmt, args, err := query.Where( sq.Eq{ AuthNKeyColumnEnabled.identifier(): true, - AuthNKeyColumnInstanceID.identifier(): authz.GetInstance(ctx).ID, + AuthNKeyColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), }, ).ToSql() if err != nil { @@ -131,7 +131,7 @@ func (q *Queries) GetAuthNKeyByID(ctx context.Context, id string, queries ...Sea sq.Eq{ AuthNKeyColumnID.identifier(): id, AuthNKeyColumnEnabled.identifier(): true, - AuthNKeyColumnInstanceID.identifier(): authz.GetInstance(ctx).ID, + AuthNKeyColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), }).ToSql() if err != nil { return nil, errors.ThrowInternal(err, "QUERY-AGhg4", "Errors.Query.SQLStatement") @@ -149,7 +149,7 @@ func (q *Queries) GetAuthNKeyPublicKeyByIDAndIdentifier(ctx context.Context, id AuthNKeyColumnID.identifier(): id, AuthNKeyColumnIdentifier.identifier(): identifier, AuthNKeyColumnEnabled.identifier(): true, - AuthNKeyColumnInstanceID.identifier(): authz.GetInstance(ctx).ID, + AuthNKeyColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), }, sq.Gt{ AuthNKeyColumnExpiration.identifier(): time.Now(), diff --git a/internal/query/custom_text.go b/internal/query/custom_text.go index a938e51497..be8753b9a0 100644 --- a/internal/query/custom_text.go +++ b/internal/query/custom_text.go @@ -86,7 +86,7 @@ func (q *Queries) CustomTextList(ctx context.Context, aggregateID, template, lan CustomTextColAggregateID.identifier(): aggregateID, CustomTextColTemplate.identifier(): template, CustomTextColLanguage.identifier(): language, - CustomTextColInstanceID.identifier(): authz.GetInstance(ctx).ID, + CustomTextColInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), }, ).ToSql() if err != nil { @@ -111,7 +111,7 @@ func (q *Queries) CustomTextListByTemplate(ctx context.Context, aggregateID, tem sq.Eq{ CustomTextColAggregateID.identifier(): aggregateID, CustomTextColTemplate.identifier(): template, - CustomTextColInstanceID.identifier(): authz.GetInstance(ctx).ID, + CustomTextColInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), }, ).ToSql() if err != nil { diff --git a/internal/query/features.go b/internal/query/features.go index 6cc4cd2002..0b61e1f6f0 100644 --- a/internal/query/features.go +++ b/internal/query/features.go @@ -163,7 +163,7 @@ func (q *Queries) FeaturesByOrgID(ctx context.Context, orgID string) (*Features, stmt, args, err := query.Where( sq.And{ sq.Eq{ - FeatureColumnInstanceID.identifier(): authz.GetInstance(ctx).ID, + FeatureColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), }, sq.Or{ sq.Eq{ @@ -188,7 +188,7 @@ func (q *Queries) DefaultFeatures(ctx context.Context) (*Features, error) { query, scan := prepareFeaturesQuery() stmt, args, err := query.Where(sq.Eq{ FeatureColumnAggregateID.identifier(): domain.IAMID, - FeatureColumnInstanceID.identifier(): authz.GetInstance(ctx).ID, + FeatureColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), }).ToSql() if err != nil { return nil, errors.ThrowInternal(err, "QUERY-1Ndlg", "Errors.Query.SQLStatement") diff --git a/internal/query/iam_member.go b/internal/query/iam_member.go index 6ac7733c72..fbb8dd42a9 100644 --- a/internal/query/iam_member.go +++ b/internal/query/iam_member.go @@ -65,7 +65,7 @@ func (q *Queries) IAMMembers(ctx context.Context, queries *IAMMembersQuery) (*Me query, scan := prepareInstanceMembersQuery() stmt, args, err := queries.toQuery(query). Where(sq.Eq{ - InstanceMemberInstanceID.identifier(): authz.GetInstance(ctx).ID, + InstanceMemberInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), }).ToSql() if err != nil { return nil, errors.ThrowInvalidArgument(err, "QUERY-USNwM", "Errors.Query.InvalidRequest") diff --git a/internal/query/idp.go b/internal/query/idp.go index f62e577d3e..81bcbbac85 100644 --- a/internal/query/idp.go +++ b/internal/query/idp.go @@ -186,7 +186,7 @@ func (q *Queries) IDPByIDAndResourceOwner(ctx context.Context, id, resourceOwner sq.And{ sq.Eq{ IDPIDCol.identifier(): id, - IDPInstanceIDCol.identifier(): authz.GetInstance(ctx).ID, + IDPInstanceIDCol.identifier(): authz.GetInstance(ctx).InstanceID(), }, sq.Or{ sq.Eq{ @@ -211,7 +211,7 @@ func (q *Queries) IDPs(ctx context.Context, queries *IDPSearchQueries) (idps *ID query, scan := prepareIDPsQuery() stmt, args, err := queries.toQuery(query). Where(sq.Eq{ - IDPInstanceIDCol.identifier(): authz.GetInstance(ctx).ID, + IDPInstanceIDCol.identifier(): authz.GetInstance(ctx).InstanceID(), }).ToSql() if err != nil { return nil, errors.ThrowInvalidArgument(err, "QUERY-X6X7y", "Errors.Query.InvalidRequest") diff --git a/internal/query/idp_login_policy_link.go b/internal/query/idp_login_policy_link.go index c6d243044d..1c4ab00457 100644 --- a/internal/query/idp_login_policy_link.go +++ b/internal/query/idp_login_policy_link.go @@ -75,7 +75,7 @@ func (q *Queries) IDPLoginPolicyLinks(ctx context.Context, resourceOwner string, stmt, args, err := queries.toQuery(query).Where( sq.Eq{ IDPLoginPolicyLinkResourceOwnerCol.identifier(): resourceOwner, - IDPLoginPolicyLinkInstanceIDCol.identifier(): authz.GetInstance(ctx).ID, + IDPLoginPolicyLinkInstanceIDCol.identifier(): authz.GetInstance(ctx).InstanceID(), }, ).ToSql() if err != nil { diff --git a/internal/query/idp_user_link.go b/internal/query/idp_user_link.go index 59d69940ca..fad6ba22b4 100644 --- a/internal/query/idp_user_link.go +++ b/internal/query/idp_user_link.go @@ -86,7 +86,7 @@ func (q *Queries) IDPUserLinks(ctx context.Context, queries *IDPUserLinksSearchQ query, scan := prepareIDPUserLinksQuery() stmt, args, err := queries.toQuery(query). Where(sq.Eq{ - IDPUserLinkInstanceIDCol.identifier(): authz.GetInstance(ctx).ID, + IDPUserLinkInstanceIDCol.identifier(): authz.GetInstance(ctx).InstanceID(), }).ToSql() if err != nil { return nil, errors.ThrowInvalidArgument(err, "QUERY-4zzFK", "Errors.Query.InvalidRequest") diff --git a/internal/query/instance.go b/internal/query/instance.go index 625c5aa1a6..cdddc0dadd 100644 --- a/internal/query/instance.go +++ b/internal/query/instance.go @@ -39,6 +39,10 @@ var ( name: projection.InstanceColumnProjectID, table: instanceTable, } + InstanceColumnConsoleID = Column{ + name: projection.InstanceColumnConsoleID, + table: instanceTable, + } InstanceColumnSetupStarted = Column{ name: projection.InstanceColumnSetUpStarted, table: instanceTable, @@ -60,11 +64,24 @@ type Instance struct { GlobalOrgID string IAMProjectID string + ConsoleID string DefaultLanguage language.Tag SetupStarted domain.Step SetupDone domain.Step } +func (i *Instance) InstanceID() string { + return i.ID +} + +func (i *Instance) ProjectID() string { + return i.IAMProjectID +} + +func (i *Instance) ConsoleClientID() string { + return i.ConsoleID +} + type InstanceSearchQueries struct { SearchRequest Queries []SearchQuery @@ -81,7 +98,7 @@ func (q *InstanceSearchQueries) toQuery(query sq.SelectBuilder) sq.SelectBuilder func (q *Queries) Instance(ctx context.Context) (*Instance, error) { stmt, scan := prepareIAMQuery() query, args, err := stmt.Where(sq.Eq{ - InstanceColumnID.identifier(): authz.GetInstance(ctx).ID, + InstanceColumnID.identifier(): authz.GetInstance(ctx).InstanceID(), }).ToSql() if err != nil { return nil, errors.ThrowInternal(err, "QUERY-d9ngs", "Errors.Query.SQLStatement") @@ -91,6 +108,19 @@ func (q *Queries) Instance(ctx context.Context) (*Instance, error) { return scan(row) } +func (q *Queries) InstanceByHost(ctx context.Context, host string) (authz.Instance, error) { + stmt, scan := prepareIAMQuery() + query, args, err := stmt.Where(sq.Eq{ + InstanceColumnID.identifier(): "system", //TODO: change column to domain when available + }).ToSql() + if err != nil { + return nil, errors.ThrowInternal(err, "QUERY-SAfg2", "Errors.Query.SQLStatement") + } + + row := q.client.QueryRowContext(ctx, query, args...) + return scan(row) +} + func (q *Queries) GetDefaultLanguage(ctx context.Context) language.Tag { iam, err := q.Instance(ctx) if err != nil { @@ -106,6 +136,7 @@ func prepareIAMQuery() (sq.SelectBuilder, func(*sql.Row) (*Instance, error)) { InstanceColumnSequence.identifier(), InstanceColumnGlobalOrgID.identifier(), InstanceColumnProjectID.identifier(), + InstanceColumnConsoleID.identifier(), InstanceColumnSetupStarted.identifier(), InstanceColumnSetupDone.identifier(), InstanceColumnDefaultLanguage.identifier(), @@ -120,6 +151,7 @@ func prepareIAMQuery() (sq.SelectBuilder, func(*sql.Row) (*Instance, error)) { &iam.Sequence, &iam.GlobalOrgID, &iam.IAMProjectID, + &iam.ConsoleID, &iam.SetupStarted, &iam.SetupDone, &lang, diff --git a/internal/query/instance_test.go b/internal/query/instance_test.go index 31100dcb01..3757cc7179 100644 --- a/internal/query/instance_test.go +++ b/internal/query/instance_test.go @@ -35,6 +35,7 @@ func Test_InstancePrepares(t *testing.T) { ` projections.instances.sequence,`+ ` projections.instances.global_org_id,`+ ` projections.instances.iam_project_id,`+ + ` projections.instances.console_client_id,`+ ` projections.instances.setup_started,`+ ` projections.instances.setup_done,`+ ` projections.instances.default_language`+ @@ -61,6 +62,7 @@ func Test_InstancePrepares(t *testing.T) { ` projections.instances.sequence,`+ ` projections.instances.global_org_id,`+ ` projections.instances.iam_project_id,`+ + ` projections.instances.console_client_id,`+ ` projections.instances.setup_started,`+ ` projections.instances.setup_done,`+ ` projections.instances.default_language`+ @@ -71,6 +73,7 @@ func Test_InstancePrepares(t *testing.T) { "sequence", "global_org_id", "iam_project_id", + "console_client_id", "setup_started", "setup_done", "default_language", @@ -81,6 +84,7 @@ func Test_InstancePrepares(t *testing.T) { uint64(20211108), "global-org-id", "project-id", + "client-id", domain.Step2, domain.Step1, "en", @@ -93,6 +97,7 @@ func Test_InstancePrepares(t *testing.T) { Sequence: 20211108, GlobalOrgID: "global-org-id", IAMProjectID: "project-id", + ConsoleID: "client-id", SetupStarted: domain.Step2, SetupDone: domain.Step1, DefaultLanguage: language.English, @@ -108,6 +113,7 @@ func Test_InstancePrepares(t *testing.T) { ` projections.instances.sequence,`+ ` projections.instances.global_org_id,`+ ` projections.instances.iam_project_id,`+ + ` projections.instances.console_client_id,`+ ` projections.instances.setup_started,`+ ` projections.instances.setup_done,`+ ` projections.instances.default_language`+ diff --git a/internal/query/key.go b/internal/query/key.go index 762fe887d9..a941b4d202 100644 --- a/internal/query/key.go +++ b/internal/query/key.go @@ -181,7 +181,7 @@ func (q *Queries) ActivePublicKeys(ctx context.Context, t time.Time) (*PublicKey stmt, args, err := query.Where( sq.And{ sq.Eq{ - KeyColInstanceID.identifier(): authz.GetInstance(ctx).ID, + KeyColInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), }, sq.Gt{ KeyPublicColExpiry.identifier(): t, @@ -212,7 +212,7 @@ func (q *Queries) ActivePrivateSigningKey(ctx context.Context, t time.Time) (*Pr sq.And{ sq.Eq{ KeyColUse.identifier(): domain.KeyUsageSigning, - KeyColInstanceID.identifier(): authz.GetInstance(ctx).ID, + KeyColInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), }, sq.Gt{ KeyPrivateColExpiry.identifier(): t, diff --git a/internal/query/label_policy.go b/internal/query/label_policy.go index 7abce67ceb..77a8e6881f 100644 --- a/internal/query/label_policy.go +++ b/internal/query/label_policy.go @@ -54,7 +54,7 @@ func (q *Queries) ActiveLabelPolicyByOrg(ctx context.Context, orgID string) (*La }, sq.Eq{ LabelPolicyColState.identifier(): domain.LabelPolicyStateActive, - LabelPolicyColInstanceID.identifier(): authz.GetInstance(ctx).ID, + LabelPolicyColInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), }, }). OrderBy(LabelPolicyColIsDefault.identifier()). @@ -81,7 +81,7 @@ func (q *Queries) PreviewLabelPolicyByOrg(ctx context.Context, orgID string) (*L }, sq.Eq{ LabelPolicyColState.identifier(): domain.LabelPolicyStatePreview, - LabelPolicyColInstanceID.identifier(): authz.GetInstance(ctx).ID, + LabelPolicyColInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), }, }). OrderBy(LabelPolicyColIsDefault.identifier()). @@ -99,7 +99,7 @@ func (q *Queries) DefaultActiveLabelPolicy(ctx context.Context) (*LabelPolicy, e query, args, err := stmt.Where(sq.Eq{ LabelPolicyColID.identifier(): domain.IAMID, LabelPolicyColState.identifier(): domain.LabelPolicyStateActive, - LabelPolicyColInstanceID.identifier(): authz.GetInstance(ctx).ID, + LabelPolicyColInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), }). OrderBy(LabelPolicyColIsDefault.identifier()). Limit(1).ToSql() @@ -116,7 +116,7 @@ func (q *Queries) DefaultPreviewLabelPolicy(ctx context.Context) (*LabelPolicy, query, args, err := stmt.Where(sq.Eq{ LabelPolicyColID.identifier(): domain.IAMID, LabelPolicyColState.identifier(): domain.LabelPolicyStatePreview, - LabelPolicyColInstanceID.identifier(): authz.GetInstance(ctx).ID, + LabelPolicyColInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), }). OrderBy(LabelPolicyColIsDefault.identifier()). Limit(1).ToSql() diff --git a/internal/query/lockout_policy.go b/internal/query/lockout_policy.go index fb7edb5860..e526a396aa 100644 --- a/internal/query/lockout_policy.go +++ b/internal/query/lockout_policy.go @@ -80,7 +80,7 @@ func (q *Queries) LockoutPolicyByOrg(ctx context.Context, orgID string) (*Lockou query, args, err := stmt.Where( sq.And{ sq.Eq{ - LockoutColInstanceID.identifier(): authz.GetInstance(ctx).ID, + LockoutColInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), }, sq.Or{ sq.Eq{ @@ -105,7 +105,7 @@ func (q *Queries) DefaultLockoutPolicy(ctx context.Context) (*LockoutPolicy, err stmt, scan := prepareLockoutPolicyQuery() query, args, err := stmt.Where(sq.Eq{ LockoutColID.identifier(): domain.IAMID, - LockoutColInstanceID.identifier(): authz.GetInstance(ctx).ID, + LockoutColInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), }). OrderBy(LockoutColIsDefault.identifier()). Limit(1).ToSql() diff --git a/internal/query/login_policy.go b/internal/query/login_policy.go index 8a3d2535d8..bb7ea90c9b 100644 --- a/internal/query/login_policy.go +++ b/internal/query/login_policy.go @@ -134,7 +134,7 @@ func (q *Queries) LoginPolicyByID(ctx context.Context, orgID string) (*LoginPoli stmt, args, err := query.Where( sq.And{ sq.Eq{ - LoginPolicyColumnInstanceID.identifier(): authz.GetInstance(ctx).ID, + LoginPolicyColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), }, sq.Or{ sq.Eq{ @@ -159,7 +159,7 @@ func (q *Queries) DefaultLoginPolicy(ctx context.Context) (*LoginPolicy, error) query, scan := prepareLoginPolicyQuery() stmt, args, err := query.Where(sq.Eq{ LoginPolicyColumnOrgID.identifier(): domain.IAMID, - LoginPolicyColumnInstanceID.identifier(): authz.GetInstance(ctx).ID, + LoginPolicyColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), }).OrderBy(LoginPolicyColumnIsDefault.identifier()).ToSql() if err != nil { return nil, errors.ThrowInternal(err, "QUERY-t4TBK", "Errors.Query.SQLStatement") @@ -174,7 +174,7 @@ func (q *Queries) SecondFactorsByOrg(ctx context.Context, orgID string) (*Second stmt, args, err := query.Where( sq.And{ sq.Eq{ - LoginPolicyColumnInstanceID.identifier(): authz.GetInstance(ctx).ID, + LoginPolicyColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), }, sq.Or{ sq.Eq{ @@ -204,7 +204,7 @@ func (q *Queries) DefaultSecondFactors(ctx context.Context) (*SecondFactors, err query, scan := prepareLoginPolicy2FAsQuery() stmt, args, err := query.Where(sq.Eq{ LoginPolicyColumnOrgID.identifier(): domain.IAMID, - LoginPolicyColumnInstanceID.identifier(): authz.GetInstance(ctx).ID, + LoginPolicyColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), }).OrderBy(LoginPolicyColumnIsDefault.identifier()).ToSql() if err != nil { return nil, errors.ThrowInternal(err, "QUERY-CZ2Nv", "Errors.Query.SQLStatement") @@ -224,7 +224,7 @@ func (q *Queries) MultiFactorsByOrg(ctx context.Context, orgID string) (*MultiFa stmt, args, err := query.Where( sq.And{ sq.Eq{ - LoginPolicyColumnInstanceID.identifier(): authz.GetInstance(ctx).ID, + LoginPolicyColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), }, sq.Or{ sq.Eq{ @@ -254,7 +254,7 @@ func (q *Queries) DefaultMultiFactors(ctx context.Context) (*MultiFactors, error query, scan := prepareLoginPolicyMFAsQuery() stmt, args, err := query.Where(sq.Eq{ LoginPolicyColumnOrgID.identifier(): domain.IAMID, - LoginPolicyColumnInstanceID.identifier(): authz.GetInstance(ctx).ID, + LoginPolicyColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), }).OrderBy(LoginPolicyColumnIsDefault.identifier()).ToSql() if err != nil { return nil, errors.ThrowInternal(err, "QUERY-WxYjr", "Errors.Query.SQLStatement") diff --git a/internal/query/mail_template.go b/internal/query/mail_template.go index df5450306b..8600a672c7 100644 --- a/internal/query/mail_template.go +++ b/internal/query/mail_template.go @@ -68,7 +68,7 @@ func (q *Queries) MailTemplateByOrg(ctx context.Context, orgID string) (*MailTem query, args, err := stmt.Where( sq.And{ sq.Eq{ - MailTemplateColInstanceID.identifier(): authz.GetInstance(ctx).ID, + MailTemplateColInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), }, sq.Or{ sq.Eq{ @@ -93,7 +93,7 @@ func (q *Queries) DefaultMailTemplate(ctx context.Context) (*MailTemplate, error stmt, scan := prepareMailTemplateQuery() query, args, err := stmt.Where(sq.Eq{ MailTemplateColAggregateID.identifier(): domain.IAMID, - MailTemplateColInstanceID.identifier(): authz.GetInstance(ctx).ID, + MailTemplateColInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), }). OrderBy(MailTemplateColIsDefault.identifier()). Limit(1).ToSql() diff --git a/internal/query/message_text.go b/internal/query/message_text.go index 45c5bf7c3f..798dbe6aec 100644 --- a/internal/query/message_text.go +++ b/internal/query/message_text.go @@ -122,7 +122,7 @@ func (q *Queries) MessageTextByOrg(ctx context.Context, orgID string) (*MessageT query, args, err := stmt.Where( sq.And{ sq.Eq{ - MessageTextColInstanceID.identifier(): authz.GetInstance(ctx).ID, + MessageTextColInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), }, sq.Or{ sq.Eq{ @@ -147,7 +147,7 @@ func (q *Queries) DefaultMessageText(ctx context.Context) (*MessageText, error) stmt, scan := prepareMessageTextQuery() query, args, err := stmt.Where(sq.Eq{ MessageTextColAggregateID.identifier(): domain.IAMID, - MessageTextColInstanceID.identifier(): authz.GetInstance(ctx).ID, + MessageTextColInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), }). Limit(1).ToSql() if err != nil { @@ -177,7 +177,7 @@ func (q *Queries) CustomMessageTextByTypeAndLanguage(ctx context.Context, aggreg MessageTextColLanguage.identifier(): language, MessageTextColType.identifier(): messageType, MessageTextColAggregateID.identifier(): aggregateID, - MessageTextColInstanceID.identifier(): authz.GetInstance(ctx).ID, + MessageTextColInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), }, ). OrderBy(MessageTextColAggregateID.identifier()). diff --git a/internal/query/notification_provider.go b/internal/query/notification_provider.go index aa2ca80049..f0559d41e3 100644 --- a/internal/query/notification_provider.go +++ b/internal/query/notification_provider.go @@ -73,7 +73,7 @@ func (q *Queries) NotificationProviderByIDAndType(ctx context.Context, aggID str stmt, args, err := query.Where( sq.And{ sq.Eq{ - NotificationProviderColumnInstanceID.identifier(): authz.GetInstance(ctx).ID, + NotificationProviderColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), }, sq.Or{ sq.Eq{ diff --git a/internal/query/oidc_settings.go b/internal/query/oidc_settings.go index be0d96f02d..73eab0ae4a 100644 --- a/internal/query/oidc_settings.go +++ b/internal/query/oidc_settings.go @@ -76,7 +76,7 @@ func (q *Queries) OIDCSettingsByAggID(ctx context.Context, aggregateID string) ( stmt, scan := prepareOIDCSettingsQuery() query, args, err := stmt.Where(sq.Eq{ OIDCSettingsColumnAggregateID.identifier(): aggregateID, - OIDCSettingsColumnInstanceID.identifier(): authz.GetInstance(ctx).ID, + OIDCSettingsColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), }).ToSql() if err != nil { return nil, errors.ThrowInternal(err, "QUERY-s9nle", "Errors.Query.SQLStatment") diff --git a/internal/query/org.go b/internal/query/org.go index 9f6e18e212..bc5230b817 100644 --- a/internal/query/org.go +++ b/internal/query/org.go @@ -90,7 +90,7 @@ func (q *Queries) OrgByID(ctx context.Context, id string) (*Org, error) { stmt, scan := prepareOrgQuery() query, args, err := stmt.Where(sq.Eq{ OrgColumnID.identifier(): id, - OrgColumnInstanceID.identifier(): authz.GetInstance(ctx).ID, + OrgColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), }).ToSql() if err != nil { return nil, errors.ThrowInternal(err, "QUERY-AWx52", "Errors.Query.SQLStatement") @@ -104,7 +104,7 @@ func (q *Queries) OrgByDomainGlobal(ctx context.Context, domain string) (*Org, e stmt, scan := prepareOrgQuery() query, args, err := stmt.Where(sq.Eq{ OrgColumnDomain.identifier(): domain, - OrgColumnInstanceID.identifier(): authz.GetInstance(ctx).ID, + OrgColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), }).ToSql() if err != nil { return nil, errors.ThrowInternal(err, "QUERY-TYUCE", "Errors.Query.SQLStatement") @@ -119,7 +119,7 @@ func (q *Queries) IsOrgUnique(ctx context.Context, name, domain string) (isUniqu stmt, args, err := query.Where( sq.And{ sq.Eq{ - OrgColumnInstanceID.identifier(): authz.GetInstance(ctx).ID, + OrgColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), }, sq.Or{ sq.Eq{ @@ -147,7 +147,7 @@ func (q *Queries) SearchOrgs(ctx context.Context, queries *OrgSearchQueries) (or query, scan := prepareOrgsQuery() stmt, args, err := queries.toQuery(query). Where(sq.Eq{ - OrgColumnInstanceID.identifier(): authz.GetInstance(ctx).ID, + OrgColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), }).ToSql() if err != nil { return nil, errors.ThrowInvalidArgument(err, "QUERY-wQ3by", "Errors.Query.InvalidRequest") diff --git a/internal/query/org_domain.go b/internal/query/org_domain.go index b8c85eb7c1..496b4d2d62 100644 --- a/internal/query/org_domain.go +++ b/internal/query/org_domain.go @@ -58,7 +58,7 @@ func (q *Queries) SearchOrgDomains(ctx context.Context, queries *OrgDomainSearch query, scan := prepareDomainsQuery() stmt, args, err := queries.toQuery(query). Where(sq.Eq{ - OrgDomainInstanceIDCol.identifier(): authz.GetInstance(ctx).ID, + OrgDomainInstanceIDCol.identifier(): authz.GetInstance(ctx).InstanceID(), }).ToSql() if err != nil { return nil, errors.ThrowInvalidArgument(err, "QUERY-ZRfj1", "Errors.Query.SQLStatement") diff --git a/internal/query/org_iam_policy.go b/internal/query/org_iam_policy.go index 4034b6a4ca..8ce31406d6 100644 --- a/internal/query/org_iam_policy.go +++ b/internal/query/org_iam_policy.go @@ -75,7 +75,7 @@ func (q *Queries) DomainPolicyByOrg(ctx context.Context, orgID string) (*DomainP query, args, err := stmt.Where( sq.And{ sq.Eq{ - DomainPolicyColInstanceID.identifier(): authz.GetInstance(ctx).ID, + DomainPolicyColInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), }, sq.Or{ sq.Eq{ @@ -100,7 +100,7 @@ func (q *Queries) DefaultDomainPolicy(ctx context.Context) (*DomainPolicy, error stmt, scan := prepareDomainPolicyQuery() query, args, err := stmt.Where(sq.Eq{ DomainPolicyColID.identifier(): domain.IAMID, - DomainPolicyColInstanceID.identifier(): authz.GetInstance(ctx).ID, + DomainPolicyColInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), }). OrderBy(DomainPolicyColIsDefault.identifier()). Limit(1).ToSql() diff --git a/internal/query/org_member.go b/internal/query/org_member.go index 6c6794f8de..54387edf46 100644 --- a/internal/query/org_member.go +++ b/internal/query/org_member.go @@ -66,7 +66,7 @@ func (q *Queries) OrgMembers(ctx context.Context, queries *OrgMembersQuery) (*Me query, scan := prepareOrgMembersQuery() stmt, args, err := queries.toQuery(query). Where(sq.Eq{ - OrgMemberInstanceID.identifier(): authz.GetInstance(ctx).ID, + OrgMemberInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), }).ToSql() if err != nil { return nil, errors.ThrowInvalidArgument(err, "QUERY-PDAVB", "Errors.Query.InvalidRequest") diff --git a/internal/query/password_age_policy.go b/internal/query/password_age_policy.go index 1658e68650..0f963e190c 100644 --- a/internal/query/password_age_policy.go +++ b/internal/query/password_age_policy.go @@ -79,7 +79,7 @@ func (q *Queries) PasswordAgePolicyByOrg(ctx context.Context, orgID string) (*Pa query, args, err := stmt.Where( sq.And{ sq.Eq{ - PasswordAgeColInstanceID.identifier(): authz.GetInstance(ctx).ID, + PasswordAgeColInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), }, sq.Or{ sq.Eq{ diff --git a/internal/query/password_complexity_policy.go b/internal/query/password_complexity_policy.go index f2d4be0a08..c3042187ec 100644 --- a/internal/query/password_complexity_policy.go +++ b/internal/query/password_complexity_policy.go @@ -36,7 +36,7 @@ func (q *Queries) PasswordComplexityPolicyByOrg(ctx context.Context, orgID strin query, args, err := stmt.Where( sq.And{ sq.Eq{ - PasswordComplexityColInstanceID.identifier(): authz.GetInstance(ctx).ID, + PasswordComplexityColInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), }, sq.Or{ sq.Eq{ @@ -61,7 +61,7 @@ func (q *Queries) DefaultPasswordComplexityPolicy(ctx context.Context) (*Passwor stmt, scan := preparePasswordComplexityPolicyQuery() query, args, err := stmt.Where(sq.Eq{ PasswordComplexityColID.identifier(): domain.IAMID, - PasswordComplexityColInstanceID.identifier(): authz.GetInstance(ctx).ID, + PasswordComplexityColInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), }). OrderBy(PasswordComplexityColIsDefault.identifier()). Limit(1).ToSql() diff --git a/internal/query/privacy_policy.go b/internal/query/privacy_policy.go index b8544706df..135e9f16d1 100644 --- a/internal/query/privacy_policy.go +++ b/internal/query/privacy_policy.go @@ -84,7 +84,7 @@ func (q *Queries) PrivacyPolicyByOrg(ctx context.Context, orgID string) (*Privac query, args, err := stmt.Where( sq.And{ sq.Eq{ - PrivacyColInstanceID.identifier(): authz.GetInstance(ctx).ID, + PrivacyColInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), }, sq.Or{ sq.Eq{ @@ -109,7 +109,7 @@ func (q *Queries) DefaultPrivacyPolicy(ctx context.Context) (*PrivacyPolicy, err stmt, scan := preparePrivacyPolicyQuery() query, args, err := stmt.Where(sq.Eq{ PrivacyColID.identifier(): domain.IAMID, - PrivacyColInstanceID.identifier(): authz.GetInstance(ctx).ID, + PrivacyColInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), }). OrderBy(PrivacyColIsDefault.identifier()). Limit(1).ToSql() diff --git a/internal/query/project.go b/internal/query/project.go index 910b7678f3..fbad437b0b 100644 --- a/internal/query/project.go +++ b/internal/query/project.go @@ -102,7 +102,7 @@ func (q *Queries) ProjectByID(ctx context.Context, id string) (*Project, error) stmt, scan := prepareProjectQuery() query, args, err := stmt.Where(sq.Eq{ ProjectColumnID.identifier(): id, - ProjectColumnInstanceID.identifier(): authz.GetInstance(ctx).ID, + ProjectColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), }).ToSql() if err != nil { return nil, errors.ThrowInternal(err, "QUERY-2m00Q", "Errors.Query.SQLStatment") @@ -121,7 +121,7 @@ func (q *Queries) SearchProjects(ctx context.Context, queries *ProjectSearchQuer query, scan := prepareProjectsQuery() stmt, args, err := queries.toQuery(query). Where(sq.Eq{ - ProjectColumnInstanceID.identifier(): authz.GetInstance(ctx).ID, + ProjectColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), }).ToSql() if err != nil { return nil, errors.ThrowInvalidArgument(err, "QUERY-fn9ew", "Errors.Query.InvalidRequest") diff --git a/internal/query/project_grant.go b/internal/query/project_grant.go index e21f1565ed..9c6a06e3a1 100644 --- a/internal/query/project_grant.go +++ b/internal/query/project_grant.go @@ -109,7 +109,7 @@ func (q *Queries) ProjectGrantByID(ctx context.Context, id string) (*ProjectGran stmt, scan := prepareProjectGrantQuery() query, args, err := stmt.Where(sq.Eq{ ProjectGrantColumnGrantID.identifier(): id, - ProjectGrantColumnInstanceID.identifier(): authz.GetInstance(ctx).ID, + ProjectGrantColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), }).ToSql() if err != nil { return nil, errors.ThrowInternal(err, "QUERY-Nf93d", "Errors.Query.SQLStatment") @@ -124,7 +124,7 @@ func (q *Queries) ProjectGrantByIDAndGrantedOrg(ctx context.Context, id, granted query, args, err := stmt.Where(sq.Eq{ ProjectGrantColumnGrantID.identifier(): id, ProjectGrantColumnGrantedOrgID.identifier(): grantedOrg, - ProjectGrantColumnInstanceID.identifier(): authz.GetInstance(ctx).ID, + ProjectGrantColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), }).ToSql() if err != nil { return nil, errors.ThrowInternal(err, "QUERY-MO9fs", "Errors.Query.SQLStatment") @@ -143,7 +143,7 @@ func (q *Queries) SearchProjectGrants(ctx context.Context, queries *ProjectGrant query, scan := prepareProjectGrantsQuery() stmt, args, err := queries.toQuery(query). Where(sq.Eq{ - ProjectGrantColumnInstanceID.identifier(): authz.GetInstance(ctx).ID, + ProjectGrantColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), }).ToSql() if err != nil { return nil, errors.ThrowInvalidArgument(err, "QUERY-N9fsg", "Errors.Query.InvalidRequest") diff --git a/internal/query/project_grant_member.go b/internal/query/project_grant_member.go index 4673bc6db9..48fac10ebd 100644 --- a/internal/query/project_grant_member.go +++ b/internal/query/project_grant_member.go @@ -80,7 +80,7 @@ func (q *Queries) ProjectGrantMembers(ctx context.Context, queries *ProjectGrant query, scan := prepareProjectGrantMembersQuery() stmt, args, err := queries.toQuery(query). Where(sq.Eq{ - ProjectGrantMemberInstanceID.identifier(): authz.GetInstance(ctx).ID, + ProjectGrantMemberInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), }).ToSql() if err != nil { return nil, errors.ThrowInvalidArgument(err, "QUERY-USNwM", "Errors.Query.InvalidRequest") diff --git a/internal/query/project_member.go b/internal/query/project_member.go index 919508bb53..8c6613fc6d 100644 --- a/internal/query/project_member.go +++ b/internal/query/project_member.go @@ -67,7 +67,7 @@ func (q *Queries) ProjectMembers(ctx context.Context, queries *ProjectMembersQue query, scan := prepareProjectMembersQuery() stmt, args, err := queries.toQuery(query). Where(sq.Eq{ - ProjectMemberInstanceID.identifier(): authz.GetInstance(ctx).ID, + ProjectMemberInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), }).ToSql() if err != nil { return nil, errors.ThrowInvalidArgument(err, "QUERY-T8CuT", "Errors.Query.InvalidRequest") diff --git a/internal/query/project_role.go b/internal/query/project_role.go index 3e6043699b..80173084ff 100644 --- a/internal/query/project_role.go +++ b/internal/query/project_role.go @@ -87,7 +87,7 @@ func (q *Queries) ProjectRoleByID(ctx context.Context, projectID, key string) (* Where(sq.Eq{ ProjectRoleColumnProjectID.identifier(): projectID, ProjectRoleColumnKey.identifier(): key, - ProjectRoleColumnInstanceID.identifier(): authz.GetInstance(ctx).ID, + ProjectRoleColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), }).ToSql() if err != nil { return nil, errors.ThrowInternal(err, "QUERY-2N0fs", "Errors.Query.SQLStatment") @@ -106,7 +106,7 @@ func (q *Queries) SearchProjectRoles(ctx context.Context, queries *ProjectRoleSe query, scan := prepareProjectRolesQuery() stmt, args, err := queries.toQuery(query). Where(sq.Eq{ - ProjectRoleColumnInstanceID.identifier(): authz.GetInstance(ctx).ID, + ProjectRoleColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), }).ToSql() if err != nil { return nil, errors.ThrowInvalidArgument(err, "QUERY-3N9ff", "Errors.Query.InvalidRequest") @@ -136,7 +136,7 @@ func (q *Queries) SearchGrantedProjectRoles(ctx context.Context, grantID, grante query, scan := prepareProjectRolesQuery() stmt, args, err := queries.toQuery(query). Where(sq.Eq{ - ProjectRoleColumnInstanceID.identifier(): authz.GetInstance(ctx).ID, + ProjectRoleColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), }).ToSql() if err != nil { return nil, errors.ThrowInvalidArgument(err, "QUERY-3N9ff", "Errors.Query.InvalidRequest") diff --git a/internal/query/projection/instance.go b/internal/query/projection/instance.go index fbed932852..ededbd3ae7 100644 --- a/internal/query/projection/instance.go +++ b/internal/query/projection/instance.go @@ -17,6 +17,7 @@ const ( InstanceColumnChangeDate = "change_date" InstanceColumnGlobalOrgID = "global_org_id" InstanceColumnProjectID = "iam_project_id" + InstanceColumnConsoleID = "console_client_id" InstanceColumnSequence = "sequence" InstanceColumnSetUpStarted = "setup_started" InstanceColumnSetUpDone = "setup_done" @@ -37,6 +38,7 @@ func NewInstanceProjection(ctx context.Context, config crdb.StatementHandlerConf crdb.NewColumn(InstanceColumnChangeDate, crdb.ColumnTypeTimestamp), crdb.NewColumn(InstanceColumnGlobalOrgID, crdb.ColumnTypeText, crdb.Default("")), crdb.NewColumn(InstanceColumnProjectID, crdb.ColumnTypeText, crdb.Default("")), + crdb.NewColumn(InstanceColumnConsoleID, crdb.ColumnTypeText, crdb.Default("")), crdb.NewColumn(InstanceColumnSequence, crdb.ColumnTypeInt64), crdb.NewColumn(InstanceColumnSetUpStarted, crdb.ColumnTypeInt64, crdb.Default(0)), crdb.NewColumn(InstanceColumnSetUpDone, crdb.ColumnTypeInt64, crdb.Default(0)), @@ -62,6 +64,10 @@ func (p *InstanceProjection) reducers() []handler.AggregateReducer { Event: instance.ProjectSetEventType, Reduce: p.reduceIAMProjectSet, }, + { + Event: instance.ConsoleSetEventType, + Reduce: p.reduceConsoleSet, + }, { Event: instance.DefaultLanguageSetEventType, Reduce: p.reduceDefaultLanguageSet, @@ -111,6 +117,22 @@ func (p *InstanceProjection) reduceIAMProjectSet(event eventstore.Event) (*handl ), nil } +func (p *InstanceProjection) reduceConsoleSet(event eventstore.Event) (*handler.Statement, error) { + e, ok := event.(*instance.ConsoleSetEvent) + if !ok { + return nil, errors.ThrowInvalidArgumentf(nil, "HANDL-Dgf11", "reduce.wrong.event.type %s", instance.ConsoleSetEventType) + } + return crdb.NewUpsertStatement( + e, + []handler.Column{ + handler.NewCol(InstanceColumnID, e.Aggregate().InstanceID), + handler.NewCol(InstanceColumnChangeDate, e.CreationDate()), + handler.NewCol(InstanceColumnSequence, e.Sequence()), + handler.NewCol(InstanceColumnConsoleID, e.ClientID), + }, + ), nil +} + func (p *InstanceProjection) reduceDefaultLanguageSet(event eventstore.Event) (*handler.Statement, error) { e, ok := event.(*instance.DefaultLanguageSetEvent) if !ok { diff --git a/internal/query/projection/instance_member.go b/internal/query/projection/instance_member.go index 3cb42ca536..1eb12b0e8f 100644 --- a/internal/query/projection/instance_member.go +++ b/internal/query/projection/instance_member.go @@ -14,7 +14,7 @@ import ( const ( InstanceMemberProjectionTable = "projections.instance_members" - InstanceMemberIAMIDCol = "instance_id" + InstanceMemberIAMIDCol = "id" ) type InstanceMemberProjection struct { diff --git a/internal/query/projection/instance_member_test.go b/internal/query/projection/instance_member_test.go index 2ce24994dd..9fee91d542 100644 --- a/internal/query/projection/instance_member_test.go +++ b/internal/query/projection/instance_member_test.go @@ -44,7 +44,7 @@ func TestInstanceMemberProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "INSERT INTO projections.instance_members (user_id, roles, creation_date, change_date, sequence, resource_owner, instance_id, instance_id) VALUES ($1, $2, $3, $4, $5, $6, $7, $8)", + expectedStmt: "INSERT INTO projections.instance_members (user_id, roles, creation_date, change_date, sequence, resource_owner, instance_id, id) VALUES ($1, $2, $3, $4, $5, $6, $7, $8)", expectedArgs: []interface{}{ "user-id", pq.StringArray{"role"}, diff --git a/internal/query/projection/login_name.go b/internal/query/projection/login_name.go index 17d7704e75..308ec9a813 100644 --- a/internal/query/projection/login_name.go +++ b/internal/query/projection/login_name.go @@ -107,7 +107,7 @@ func NewLoginNameProjection(ctx context.Context, config crdb.StatementHandlerCon ), crdb.NewSuffixedTable([]*crdb.Column{ crdb.NewColumn(LoginNameDomainNameCol, crdb.ColumnTypeText), - crdb.NewColumn(LoginNameDomainIsPrimaryCol, crdb.ColumnTypeBool), + crdb.NewColumn(LoginNameDomainIsPrimaryCol, crdb.ColumnTypeBool, crdb.Default(false)), crdb.NewColumn(LoginNameDomainResourceOwnerCol, crdb.ColumnTypeText), crdb.NewColumn(LoginNameDomainInstanceIDCol, crdb.ColumnTypeText), }, diff --git a/internal/query/projection/login_policy.go b/internal/query/projection/login_policy.go index 1c38bb5810..5a26f0b950 100644 --- a/internal/query/projection/login_policy.go +++ b/internal/query/projection/login_policy.go @@ -56,8 +56,8 @@ func NewLoginPolicyProjection(ctx context.Context, config crdb.StatementHandlerC crdb.NewColumn(LoginPolicyAllowUsernamePasswordCol, crdb.ColumnTypeBool), crdb.NewColumn(LoginPolicyAllowExternalIDPsCol, crdb.ColumnTypeBool), crdb.NewColumn(LoginPolicyForceMFACol, crdb.ColumnTypeBool), - crdb.NewColumn(LoginPolicy2FAsCol, crdb.ColumnTypeEnumArray), - crdb.NewColumn(LoginPolicyMFAsCol, crdb.ColumnTypeEnumArray), + crdb.NewColumn(LoginPolicy2FAsCol, crdb.ColumnTypeEnumArray, crdb.Nullable()), + crdb.NewColumn(LoginPolicyMFAsCol, crdb.ColumnTypeEnumArray, crdb.Nullable()), crdb.NewColumn(LoginPolicyPasswordlessTypeCol, crdb.ColumnTypeEnum), crdb.NewColumn(LoginPolicyHidePWResetCol, crdb.ColumnTypeBool), crdb.NewColumn(PasswordCheckLifetimeCol, crdb.ColumnTypeInt64), diff --git a/internal/query/projection/message_texts.go b/internal/query/projection/message_texts.go index a7e8e10aa2..811171f860 100644 --- a/internal/query/projection/message_texts.go +++ b/internal/query/projection/message_texts.go @@ -51,13 +51,13 @@ func NewMessageTextProjection(ctx context.Context, config crdb.StatementHandlerC crdb.NewColumn(MessageTextStateCol, crdb.ColumnTypeEnum), crdb.NewColumn(MessageTextTypeCol, crdb.ColumnTypeText), crdb.NewColumn(MessageTextLanguageCol, crdb.ColumnTypeText), - crdb.NewColumn(MessageTextTitleCol, crdb.ColumnTypeBool), - crdb.NewColumn(MessageTextPreHeaderCol, crdb.ColumnTypeBool), - crdb.NewColumn(MessageTextSubjectCol, crdb.ColumnTypeBool), - crdb.NewColumn(MessageTextGreetingCol, crdb.ColumnTypeBool), - crdb.NewColumn(MessageTextTextCol, crdb.ColumnTypeBool), - crdb.NewColumn(MessageTextButtonTextCol, crdb.ColumnTypeBool), - crdb.NewColumn(MessageTextFooterCol, crdb.ColumnTypeBool), + crdb.NewColumn(MessageTextTitleCol, crdb.ColumnTypeText, crdb.Nullable()), + crdb.NewColumn(MessageTextPreHeaderCol, crdb.ColumnTypeText, crdb.Nullable()), + crdb.NewColumn(MessageTextSubjectCol, crdb.ColumnTypeText, crdb.Nullable()), + crdb.NewColumn(MessageTextGreetingCol, crdb.ColumnTypeText, crdb.Nullable()), + crdb.NewColumn(MessageTextTextCol, crdb.ColumnTypeText, crdb.Nullable()), + crdb.NewColumn(MessageTextButtonTextCol, crdb.ColumnTypeText, crdb.Nullable()), + crdb.NewColumn(MessageTextFooterCol, crdb.ColumnTypeText, crdb.Nullable()), }, crdb.NewPrimaryKey(MessageTextInstanceIDCol, MessageTextAggregateIDCol, MessageTextTypeCol, MessageTextLanguageCol), ), diff --git a/internal/query/projection/org.go b/internal/query/projection/org.go index 8eb82e2fd7..0bc72d1fe4 100644 --- a/internal/query/projection/org.go +++ b/internal/query/projection/org.go @@ -43,7 +43,7 @@ func NewOrgProjection(ctx context.Context, config crdb.StatementHandlerConfig) * crdb.NewColumn(OrgColumnState, crdb.ColumnTypeEnum), crdb.NewColumn(OrgColumnSequence, crdb.ColumnTypeInt64), crdb.NewColumn(OrgColumnName, crdb.ColumnTypeText), - crdb.NewColumn(OrgColumnDomain, crdb.ColumnTypeText), + crdb.NewColumn(OrgColumnDomain, crdb.ColumnTypeText, crdb.Default("")), }, crdb.NewPrimaryKey(OrgColumnInstanceID, OrgColumnID), crdb.WithIndex(crdb.NewIndex("domain_idx", []string{OrgColumnDomain})), diff --git a/internal/query/projection/user.go b/internal/query/projection/user.go index 3c453974e9..7ad568471a 100644 --- a/internal/query/projection/user.go +++ b/internal/query/projection/user.go @@ -86,7 +86,7 @@ func NewUserProjection(ctx context.Context, config crdb.StatementHandlerConfig) crdb.NewColumn(HumanNickNameCol, crdb.ColumnTypeText, crdb.Nullable()), crdb.NewColumn(HumanDisplayNameCol, crdb.ColumnTypeText, crdb.Nullable()), crdb.NewColumn(HumanPreferredLanguageCol, crdb.ColumnTypeText, crdb.Nullable()), - crdb.NewColumn(HumanGenderCol, crdb.ColumnTypeEnum), + crdb.NewColumn(HumanGenderCol, crdb.ColumnTypeEnum, crdb.Nullable()), crdb.NewColumn(HumanAvatarURLCol, crdb.ColumnTypeText, crdb.Nullable()), crdb.NewColumn(HumanEmailCol, crdb.ColumnTypeText), crdb.NewColumn(HumanIsEmailVerifiedCol, crdb.ColumnTypeBool, crdb.Default(false)), diff --git a/internal/query/secret_generators.go b/internal/query/secret_generators.go index c8c7c963e2..8ce6a768ff 100644 --- a/internal/query/secret_generators.go +++ b/internal/query/secret_generators.go @@ -137,7 +137,7 @@ func (q *Queries) SecretGeneratorByType(ctx context.Context, generatorType domai stmt, scan := prepareSecretGeneratorQuery() query, args, err := stmt.Where(sq.Eq{ SecretGeneratorColumnGeneratorType.identifier(): generatorType, - SecretGeneratorColumnInstanceID.identifier(): authz.GetInstance(ctx).ID, + SecretGeneratorColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), }).ToSql() if err != nil { return nil, errors.ThrowInternal(err, "QUERY-3k99f", "Errors.Query.SQLStatment") @@ -151,7 +151,7 @@ func (q *Queries) SearchSecretGenerators(ctx context.Context, queries *SecretGen query, scan := prepareSecretGeneratorsQuery() stmt, args, err := queries.toQuery(query). Where(sq.Eq{ - SecretGeneratorColumnInstanceID.identifier(): authz.GetInstance(ctx).ID, + SecretGeneratorColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), }).ToSql() if err != nil { return nil, errors.ThrowInvalidArgument(err, "QUERY-sn9lw", "Errors.Query.InvalidRequest") diff --git a/internal/query/sms.go b/internal/query/sms.go index 6e7451f94c..94b02e9b74 100644 --- a/internal/query/sms.go +++ b/internal/query/sms.go @@ -116,7 +116,7 @@ func (q *Queries) SMSProviderConfigByID(ctx context.Context, id string) (*SMSCon query, args, err := stmt.Where( sq.Eq{ SMSConfigColumnID.identifier(): id, - SMSConfigColumnInstanceID.identifier(): authz.GetInstance(ctx).ID, + SMSConfigColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), }, ).ToSql() if err != nil { @@ -131,7 +131,7 @@ func (q *Queries) SearchSMSConfigs(ctx context.Context, queries *SMSConfigsSearc query, scan := prepareSMSConfigsQuery() stmt, args, err := queries.toQuery(query). Where(sq.Eq{ - SMSConfigColumnInstanceID.identifier(): authz.GetInstance(ctx).ID, + SMSConfigColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), }).ToSql() if err != nil { return nil, errors.ThrowInvalidArgument(err, "QUERY-sn9Jf", "Errors.Query.InvalidRequest") diff --git a/internal/query/smtp.go b/internal/query/smtp.go index 69372d200e..030bfd4c34 100644 --- a/internal/query/smtp.go +++ b/internal/query/smtp.go @@ -94,7 +94,7 @@ func (q *Queries) SMTPConfigByAggregateID(ctx context.Context, aggregateID strin stmt, scan := prepareSMTPConfigQuery() query, args, err := stmt.Where(sq.Eq{ SMTPConfigColumnAggregateID.identifier(): aggregateID, - SMTPConfigColumnInstanceID.identifier(): authz.GetInstance(ctx).ID, + SMTPConfigColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), }).ToSql() if err != nil { return nil, errors.ThrowInternal(err, "QUERY-3m9sl", "Errors.Query.SQLStatment") diff --git a/internal/query/user.go b/internal/query/user.go index 5efb7186af..7379b4b9b2 100644 --- a/internal/query/user.go +++ b/internal/query/user.go @@ -231,7 +231,7 @@ var ( ) func (q *Queries) GetUserByID(ctx context.Context, userID string, queries ...SearchQuery) (*User, error) { - instanceID := authz.GetInstance(ctx).ID + instanceID := authz.GetInstance(ctx).InstanceID() query, scan := prepareUserQuery(instanceID) for _, q := range queries { query = q.toQuery(query) @@ -249,7 +249,7 @@ func (q *Queries) GetUserByID(ctx context.Context, userID string, queries ...Sea } func (q *Queries) GetUser(ctx context.Context, queries ...SearchQuery) (*User, error) { - instanceID := authz.GetInstance(ctx).ID + instanceID := authz.GetInstance(ctx).InstanceID() query, scan := prepareUserQuery(instanceID) for _, q := range queries { query = q.toQuery(query) @@ -272,7 +272,7 @@ func (q *Queries) GetHumanProfile(ctx context.Context, userID string, queries .. } stmt, args, err := query.Where(sq.Eq{ UserIDCol.identifier(): userID, - UserInstanceIDCol.identifier(): authz.GetInstance(ctx).ID, + UserInstanceIDCol.identifier(): authz.GetInstance(ctx).InstanceID(), }).ToSql() if err != nil { return nil, errors.ThrowInternal(err, "QUERY-Dgbg2", "Errors.Query.SQLStatment") @@ -289,7 +289,7 @@ func (q *Queries) GetHumanEmail(ctx context.Context, userID string, queries ...S } stmt, args, err := query.Where(sq.Eq{ UserIDCol.identifier(): userID, - UserInstanceIDCol.identifier(): authz.GetInstance(ctx).ID, + UserInstanceIDCol.identifier(): authz.GetInstance(ctx).InstanceID(), }).ToSql() if err != nil { return nil, errors.ThrowInternal(err, "QUERY-BHhj3", "Errors.Query.SQLStatment") @@ -306,7 +306,7 @@ func (q *Queries) GetHumanPhone(ctx context.Context, userID string, queries ...S } stmt, args, err := query.Where(sq.Eq{ UserIDCol.identifier(): userID, - UserInstanceIDCol.identifier(): authz.GetInstance(ctx).ID, + UserInstanceIDCol.identifier(): authz.GetInstance(ctx).InstanceID(), }).ToSql() if err != nil { return nil, errors.ThrowInternal(err, "QUERY-Dg43g", "Errors.Query.SQLStatment") @@ -320,7 +320,7 @@ func (q *Queries) SearchUsers(ctx context.Context, queries *UserSearchQueries) ( query, scan := prepareUsersQuery() stmt, args, err := queries.toQuery(query). Where(sq.Eq{ - UserInstanceIDCol.identifier(): authz.GetInstance(ctx).ID, + UserInstanceIDCol.identifier(): authz.GetInstance(ctx).InstanceID(), }).ToSql() if err != nil { return nil, errors.ThrowInternal(err, "QUERY-Dgbg2", "Errors.Query.SQLStatment") @@ -366,7 +366,7 @@ func (q *Queries) IsUserUnique(ctx context.Context, username, email, resourceOwn query = q.toQuery(query) } stmt, args, err := query.Where(sq.Eq{ - UserInstanceIDCol.identifier(): authz.GetInstance(ctx).ID, + UserInstanceIDCol.identifier(): authz.GetInstance(ctx).InstanceID(), }).ToSql() if err != nil { return false, errors.ThrowInternal(err, "QUERY-Dg43g", "Errors.Query.SQLStatment") @@ -437,7 +437,7 @@ func NewUserLoginNamesSearchQuery(value string) (SearchQuery, error) { } func prepareUserQuery(instanceID string) (sq.SelectBuilder, func(*sql.Row) (*User, error)) { - loginNamesQuery, _, err := sq.Select( + loginNamesQuery, loginNamesArgs, err := sq.Select( userLoginNamesUserIDCol.identifier(), "ARRAY_AGG("+userLoginNamesNameCol.identifier()+") as "+userLoginNamesListCol.name). From(userLoginNamesTable.identifier()). @@ -489,7 +489,7 @@ func prepareUserQuery(instanceID string) (sq.SelectBuilder, func(*sql.Row) (*Use From(userTable.identifier()). LeftJoin(join(HumanUserIDCol, UserIDCol)). LeftJoin(join(MachineUserIDCol, UserIDCol)). - LeftJoin("("+loginNamesQuery+") as "+userLoginNamesTable.alias+" on "+userLoginNamesUserIDCol.identifier()+" = "+UserIDCol.identifier()). + LeftJoin("("+loginNamesQuery+") as "+userLoginNamesTable.alias+" on "+userLoginNamesUserIDCol.identifier()+" = "+UserIDCol.identifier(), loginNamesArgs...). LeftJoin("("+preferredLoginNameQuery+") as "+userPreferredLoginNameTable.alias+" on "+userPreferredLoginNameUserIDCol.identifier()+" = "+UserIDCol.identifier(), preferredLoginNameArgs...). PlaceholderFormat(sq.Dollar), func(row *sql.Row) (*User, error) { diff --git a/internal/query/user_auth_method.go b/internal/query/user_auth_method.go index 7919cd5ad6..fed4528830 100644 --- a/internal/query/user_auth_method.go +++ b/internal/query/user_auth_method.go @@ -91,7 +91,7 @@ func (q *Queries) UserAuthMethodByIDs(ctx context.Context, userID, tokenID, reso UserAuthMethodColumnTokenID.identifier(): tokenID, UserAuthMethodColumnResourceOwner.identifier(): resourceOwner, UserAuthMethodColumnMethodType.identifier(): methodType, - UserAuthMethodColumnInstanceID.identifier(): authz.GetInstance(ctx).ID, + UserAuthMethodColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), }).ToSql() if err != nil { return nil, errors.ThrowInternal(err, "QUERY-2m00Q", "Errors.Query.SQLStatment") @@ -105,7 +105,7 @@ func (q *Queries) SearchUserAuthMethods(ctx context.Context, queries *UserAuthMe query, scan := prepareUserAuthMethodsQuery() stmt, args, err := queries.toQuery(query). Where(sq.Eq{ - UserAuthMethodColumnInstanceID.identifier(): authz.GetInstance(ctx).ID, + UserAuthMethodColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), }).ToSql() if err != nil { return nil, errors.ThrowInvalidArgument(err, "QUERY-j9NJd", "Errors.Query.InvalidRequest") diff --git a/internal/query/user_grant.go b/internal/query/user_grant.go index dd9d0f8bde..3827bbe9c6 100644 --- a/internal/query/user_grant.go +++ b/internal/query/user_grant.go @@ -199,7 +199,7 @@ func (q *Queries) UserGrant(ctx context.Context, queries ...SearchQuery) (*UserG } stmt, args, err := query. Where(sq.Eq{ - UserGrantInstanceID.identifier(): authz.GetInstance(ctx).ID, + UserGrantInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), }).ToSql() if err != nil { return nil, errors.ThrowInternal(err, "QUERY-Fa1KW", "Errors.Query.SQLStatement") @@ -213,7 +213,7 @@ func (q *Queries) UserGrants(ctx context.Context, queries *UserGrantsQueries) (* query, scan := prepareUserGrantsQuery() stmt, args, err := queries.toQuery(query). Where(sq.Eq{ - UserGrantInstanceID.identifier(): authz.GetInstance(ctx).ID, + UserGrantInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), }).ToSql() if err != nil { return nil, errors.ThrowInternal(err, "QUERY-wXnQR", "Errors.Query.SQLStatement") diff --git a/internal/query/user_membership.go b/internal/query/user_membership.go index 34cc55f989..711e724239 100644 --- a/internal/query/user_membership.go +++ b/internal/query/user_membership.go @@ -102,7 +102,7 @@ func (q *Queries) Memberships(ctx context.Context, queries *MembershipSearchQuer query, scan := prepareMembershipsQuery() stmt, args, err := queries.toQuery(query). Where(sq.Eq{ - membershipInstanceID.identifier(): authz.GetInstance(ctx).ID, + membershipInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), }).ToSql() if err != nil { return nil, errors.ThrowInvalidArgument(err, "QUERY-T84X9", "Errors.Query.InvalidRequest") @@ -289,6 +289,7 @@ func prepareOrgMember() string { OrgMemberChangeDate.identifier(), OrgMemberSequence.identifier(), OrgMemberResourceOwner.identifier(), + OrgMemberInstanceID.identifier(), OrgMemberOrgID.identifier(), "NULL::STRING AS "+membershipIAMID.name, "NULL::STRING AS "+membershipProjectID.name, @@ -305,6 +306,7 @@ func prepareIAMMember() string { InstanceMemberChangeDate.identifier(), InstanceMemberSequence.identifier(), InstanceMemberResourceOwner.identifier(), + InstanceMemberInstanceID.identifier(), "NULL::STRING AS "+membershipOrgID.name, InstanceMemberIAMID.identifier(), "NULL::STRING AS "+membershipProjectID.name, @@ -321,6 +323,7 @@ func prepareProjectMember() string { ProjectMemberChangeDate.identifier(), ProjectMemberSequence.identifier(), ProjectMemberResourceOwner.identifier(), + ProjectMemberInstanceID.identifier(), "NULL::STRING AS "+membershipOrgID.name, "NULL::STRING AS "+membershipIAMID.name, ProjectMemberProjectID.identifier(), @@ -338,6 +341,7 @@ func prepareProjectGrantMember() string { ProjectGrantMemberChangeDate.identifier(), ProjectGrantMemberSequence.identifier(), ProjectGrantMemberResourceOwner.identifier(), + ProjectGrantMemberInstanceID.identifier(), "NULL::STRING AS "+membershipOrgID.name, "NULL::STRING AS "+membershipIAMID.name, ProjectGrantMemberProjectID.identifier(), diff --git a/internal/query/user_membership_test.go b/internal/query/user_membership_test.go index d0ea061cc9..8f160680bd 100644 --- a/internal/query/user_membership_test.go +++ b/internal/query/user_membership_test.go @@ -20,7 +20,7 @@ var ( ", memberships.sequence" + ", memberships.resource_owner" + ", memberships.org_id" + - ", memberships.instance_id" + + ", memberships.id" + ", memberships.project_id" + ", memberships.grant_id" + ", projections.projects.name" + @@ -33,8 +33,9 @@ var ( ", members.change_date" + ", members.sequence" + ", members.resource_owner" + + ", members.instance_id" + ", members.org_id" + - ", NULL::STRING AS instance_id" + + ", NULL::STRING AS id" + ", NULL::STRING AS project_id" + ", NULL::STRING AS grant_id" + " FROM projections.org_members as members" + @@ -45,8 +46,9 @@ var ( ", members.change_date" + ", members.sequence" + ", members.resource_owner" + - ", NULL::STRING AS org_id" + ", members.instance_id" + + ", NULL::STRING AS org_id" + + ", members.id" + ", NULL::STRING AS project_id" + ", NULL::STRING AS grant_id" + " FROM projections.instance_members as members" + @@ -57,8 +59,9 @@ var ( ", members.change_date" + ", members.sequence" + ", members.resource_owner" + + ", members.instance_id" + ", NULL::STRING AS org_id" + - ", NULL::STRING AS instance_id" + + ", NULL::STRING AS id" + ", members.project_id" + ", NULL::STRING AS grant_id" + " FROM projections.project_members as members" + @@ -69,8 +72,9 @@ var ( ", members.change_date" + ", members.sequence" + ", members.resource_owner" + + ", members.instance_id" + ", NULL::STRING AS org_id" + - ", NULL::STRING AS instance_id" + + ", NULL::STRING AS id" + ", members.project_id" + ", members.grant_id" + " FROM projections.project_grant_members as members" + diff --git a/internal/query/user_metadata.go b/internal/query/user_metadata.go index a29ce2b2da..9daf0a2895 100644 --- a/internal/query/user_metadata.go +++ b/internal/query/user_metadata.go @@ -80,7 +80,7 @@ func (q *Queries) GetUserMetadataByKey(ctx context.Context, userID, key string, sq.Eq{ UserMetadataUserIDCol.identifier(): userID, UserMetadataKeyCol.identifier(): key, - UserMetadataInstanceIDCol.identifier(): authz.GetInstance(ctx).ID, + UserMetadataInstanceIDCol.identifier(): authz.GetInstance(ctx).InstanceID(), }).ToSql() if err != nil { return nil, errors.ThrowInternal(err, "QUERY-aDGG2", "Errors.Query.SQLStatment") @@ -95,7 +95,7 @@ func (q *Queries) SearchUserMetadata(ctx context.Context, userID string, queries stmt, args, err := queries.toQuery(query).Where( sq.Eq{ UserMetadataUserIDCol.identifier(): userID, - UserMetadataInstanceIDCol.identifier(): authz.GetInstance(ctx).ID, + UserMetadataInstanceIDCol.identifier(): authz.GetInstance(ctx).InstanceID(), }). ToSql() if err != nil { diff --git a/internal/query/user_personal_access_token.go b/internal/query/user_personal_access_token.go index 02d62939d7..0476667640 100644 --- a/internal/query/user_personal_access_token.go +++ b/internal/query/user_personal_access_token.go @@ -87,7 +87,7 @@ func (q *Queries) PersonalAccessTokenByID(ctx context.Context, id string, querie } stmt, args, err := query.Where(sq.Eq{ PersonalAccessTokenColumnID.identifier(): id, - PersonalAccessTokenColumnInstanceID.identifier(): authz.GetInstance(ctx).ID, + PersonalAccessTokenColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), }).ToSql() if err != nil { return nil, errors.ThrowInternal(err, "QUERY-Dgfb4", "Errors.Query.SQLStatment") @@ -101,7 +101,7 @@ func (q *Queries) SearchPersonalAccessTokens(ctx context.Context, queries *Perso query, scan := preparePersonalAccessTokensQuery() stmt, args, err := queries.toQuery(query). Where(sq.Eq{ - PersonalAccessTokenColumnInstanceID.identifier(): authz.GetInstance(ctx).ID, + PersonalAccessTokenColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), }).ToSql() if err != nil { return nil, errors.ThrowInvalidArgument(err, "QUERY-Hjw2w", "Errors.Query.InvalidRequest") diff --git a/internal/repository/instance/event_iam_project_set.go b/internal/repository/instance/event_iam_project_set.go index 5a4a78c360..47d79ad674 100644 --- a/internal/repository/instance/event_iam_project_set.go +++ b/internal/repository/instance/event_iam_project_set.go @@ -11,7 +11,8 @@ import ( ) const ( - ProjectSetEventType eventstore.EventType = "iam.project.iam.set" + ProjectSetEventType eventstore.EventType = "instance.iam.project.set" + ConsoleSetEventType eventstore.EventType = "instance.iam.console.set" ) type ProjectSetEvent struct { @@ -54,3 +55,44 @@ func ProjectSetMapper(event *repository.Event) (eventstore.Event, error) { return e, nil } + +type ConsoleSetEvent struct { + eventstore.BaseEvent `json:"-"` + + ClientID string `json:"clientId"` +} + +func (e *ConsoleSetEvent) Data() interface{} { + return e +} + +func (e *ConsoleSetEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint { + return nil +} + +func NewIAMConsoleSetEvent( + ctx context.Context, + aggregate *eventstore.Aggregate, + clientID string, +) *ConsoleSetEvent { + return &ConsoleSetEvent{ + BaseEvent: *eventstore.NewBaseEventForPush( + ctx, + aggregate, + ConsoleSetEventType, + ), + ClientID: clientID, + } +} + +func ConsoleSetMapper(event *repository.Event) (eventstore.Event, error) { + e := &ConsoleSetEvent{ + BaseEvent: *eventstore.BaseEventFromRepo(event), + } + err := json.Unmarshal(event.Data, e) + if err != nil { + return nil, errors.ThrowInternal(err, "IAM-cdFZH", "unable to unmarshal console set") + } + + return e, nil +} diff --git a/internal/repository/instance/eventstore.go b/internal/repository/instance/eventstore.go index 5ac37b6814..5ea7659afb 100644 --- a/internal/repository/instance/eventstore.go +++ b/internal/repository/instance/eventstore.go @@ -9,6 +9,7 @@ func RegisterEventMappers(es *eventstore.Eventstore) { RegisterFilterEventMapper(SetupDoneEventType, SetupStepMapper). RegisterFilterEventMapper(GlobalOrgSetEventType, GlobalOrgSetMapper). RegisterFilterEventMapper(ProjectSetEventType, ProjectSetMapper). + RegisterFilterEventMapper(ConsoleSetEventType, ConsoleSetMapper). RegisterFilterEventMapper(DefaultLanguageSetEventType, DefaultLanguageSetMapper). RegisterFilterEventMapper(SecretGeneratorAddedEventType, SecretGeneratorAddedEventMapper). RegisterFilterEventMapper(SecretGeneratorChangedEventType, SecretGeneratorChangedEventMapper).