perf(oidc): optimize the introspection endpoint (#6909)

* get key by id and cache them

* userinfo from events for v2 tokens

* improve keyset caching

* concurrent token and client checks

* client and project in single query

* logging and otel

* drop owner_removed column on apps and authN tables

* userinfo and project roles in go routines

* get  oidc user info from projections and add actions

* add avatar URL

* some cleanup

* pull oidc work branch

* remove storage from server

* add config flag for experimental introspection

* legacy introspection flag

* drop owner_removed column on user projections

* drop owner_removed column on useer_metadata

* query userinfo unit test

* query introspection client test

* add user_grants to the userinfo query

* handle PAT scopes

* bring triggers back

* test instance keys query

* add userinfo unit tests

* unit test keys

* go mod tidy

* solve some bugs

* fix missing preferred login name

* do not run triggers in go routines, they seem to deadlock

* initialize the trigger handlers late with a sync.OnceValue

* Revert "do not run triggers in go routines, they seem to deadlock"

This reverts commit 2a03da2127.

* add missing translations

* chore: update go version for linting

* pin oidc version

* parse a global time location for query test

* fix linter complains

* upgrade go lint

* fix more linting issues

---------

Co-authored-by: Stefan Benz <46600784+stebenz@users.noreply.github.com>
This commit is contained in:
Tim Möhlmann
2023-11-21 14:11:38 +02:00
committed by GitHub
parent ad3563d58b
commit ba9b807854
103 changed files with 3528 additions and 808 deletions

View File

@@ -126,10 +126,6 @@ var (
name: projection.AppColumnSequence,
table: appsTable,
}
AppColumnOwnerRemoved = Column{
name: projection.AppColumnOwnerRemoved,
table: appsTable,
}
)
var (
@@ -249,7 +245,7 @@ var (
}
)
func (q *Queries) AppByProjectAndAppID(ctx context.Context, shouldTriggerBulk bool, projectID, appID string, withOwnerRemoved bool) (app *App, err error) {
func (q *Queries) AppByProjectAndAppID(ctx context.Context, shouldTriggerBulk bool, projectID, appID string) (app *App, err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }()
@@ -266,9 +262,6 @@ func (q *Queries) AppByProjectAndAppID(ctx context.Context, shouldTriggerBulk bo
AppColumnProjectID.identifier(): projectID,
AppColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(),
}
if !withOwnerRemoved {
eq[AppColumnOwnerRemoved.identifier()] = false
}
query, args, err := stmt.Where(eq).ToSql()
if err != nil {
return nil, errors.ThrowInternal(err, "QUERY-AFDgg", "Errors.Query.SQLStatement")
@@ -281,7 +274,7 @@ func (q *Queries) AppByProjectAndAppID(ctx context.Context, shouldTriggerBulk bo
return app, err
}
func (q *Queries) AppByID(ctx context.Context, appID string, withOwnerRemoved bool) (app *App, err error) {
func (q *Queries) AppByID(ctx context.Context, appID string) (app *App, err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }()
@@ -290,9 +283,6 @@ func (q *Queries) AppByID(ctx context.Context, appID string, withOwnerRemoved bo
AppColumnID.identifier(): appID,
AppColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(),
}
if !withOwnerRemoved {
eq[AppColumnOwnerRemoved.identifier()] = false
}
query, args, err := stmt.Where(eq).ToSql()
if err != nil {
return nil, errors.ThrowInternal(err, "QUERY-immt9", "Errors.Query.SQLStatement")
@@ -305,7 +295,7 @@ func (q *Queries) AppByID(ctx context.Context, appID string, withOwnerRemoved bo
return app, err
}
func (q *Queries) AppBySAMLEntityID(ctx context.Context, entityID string, withOwnerRemoved bool) (app *App, err error) {
func (q *Queries) AppBySAMLEntityID(ctx context.Context, entityID string) (app *App, err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }()
@@ -314,9 +304,6 @@ func (q *Queries) AppBySAMLEntityID(ctx context.Context, entityID string, withOw
AppSAMLConfigColumnEntityID.identifier(): entityID,
AppColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(),
}
if !withOwnerRemoved {
eq[AppColumnOwnerRemoved.identifier()] = false
}
query, args, err := stmt.Where(eq).ToSql()
if err != nil {
return nil, errors.ThrowInternal(err, "QUERY-JgUop", "Errors.Query.SQLStatement")
@@ -354,7 +341,7 @@ func (q *Queries) ProjectByClientID(ctx context.Context, appID string) (project
return project, err
}
func (q *Queries) ProjectIDFromOIDCClientID(ctx context.Context, appID string, withOwnerRemoved bool) (id string, err error) {
func (q *Queries) ProjectIDFromOIDCClientID(ctx context.Context, appID string) (id string, err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }()
@@ -363,9 +350,6 @@ func (q *Queries) ProjectIDFromOIDCClientID(ctx context.Context, appID string, w
AppOIDCConfigColumnClientID.identifier(): appID,
AppColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(),
}
if !withOwnerRemoved {
eq[AppColumnOwnerRemoved.identifier()] = false
}
query, args, err := stmt.Where(eq).ToSql()
if err != nil {
return "", errors.ThrowInternal(err, "QUERY-7d92U", "Errors.Query.SQLStatement")
@@ -378,15 +362,12 @@ func (q *Queries) ProjectIDFromOIDCClientID(ctx context.Context, appID string, w
return id, err
}
func (q *Queries) ProjectIDFromClientID(ctx context.Context, appID string, withOwnerRemoved bool) (id string, err error) {
func (q *Queries) ProjectIDFromClientID(ctx context.Context, appID string) (id string, err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }()
stmt, scan := prepareProjectIDByAppQuery(ctx, q.client)
eq := sq.Eq{AppColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID()}
if !withOwnerRemoved {
eq[AppColumnOwnerRemoved.identifier()] = false
}
where := sq.And{
eq,
sq.Or{
@@ -407,7 +388,7 @@ func (q *Queries) ProjectIDFromClientID(ctx context.Context, appID string, withO
return id, err
}
func (q *Queries) ProjectByOIDCClientID(ctx context.Context, id string, withOwnerRemoved bool) (project *Project, err error) {
func (q *Queries) ProjectByOIDCClientID(ctx context.Context, id string) (project *Project, err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }()
@@ -416,9 +397,6 @@ func (q *Queries) ProjectByOIDCClientID(ctx context.Context, id string, withOwne
AppOIDCConfigColumnClientID.identifier(): id,
AppColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(),
}
if !withOwnerRemoved {
eq[AppColumnOwnerRemoved.identifier()] = false
}
query, args, err := stmt.Where(eq).ToSql()
if err != nil {
return nil, errors.ThrowInternal(err, "QUERY-XhJi4", "Errors.Query.SQLStatement")
@@ -431,7 +409,7 @@ func (q *Queries) ProjectByOIDCClientID(ctx context.Context, id string, withOwne
return project, err
}
func (q *Queries) AppByOIDCClientID(ctx context.Context, clientID string, withOwnerRemoved bool) (app *App, err error) {
func (q *Queries) AppByOIDCClientID(ctx context.Context, clientID string) (app *App, err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }()
@@ -440,9 +418,6 @@ func (q *Queries) AppByOIDCClientID(ctx context.Context, clientID string, withOw
AppOIDCConfigColumnClientID.identifier(): clientID,
AppColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(),
}
if !withOwnerRemoved {
eq[AppColumnOwnerRemoved.identifier()] = false
}
query, args, err := stmt.Where(eq).ToSql()
if err != nil {
return nil, errors.ThrowInternal(err, "QUERY-JgVop", "Errors.Query.SQLStatement")
@@ -455,15 +430,12 @@ func (q *Queries) AppByOIDCClientID(ctx context.Context, clientID string, withOw
return app, err
}
func (q *Queries) AppByClientID(ctx context.Context, clientID string, withOwnerRemoved bool) (app *App, err error) {
func (q *Queries) AppByClientID(ctx context.Context, clientID string) (app *App, err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }()
stmt, scan := prepareAppQuery(ctx, q.client)
eq := sq.Eq{AppColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID()}
if !withOwnerRemoved {
eq[AppColumnOwnerRemoved.identifier()] = false
}
query, args, err := stmt.Where(sq.And{
eq,
sq.Or{
@@ -488,9 +460,6 @@ func (q *Queries) SearchApps(ctx context.Context, queries *AppSearchQueries, wit
query, scan := prepareAppsQuery(ctx, q.client)
eq := sq.Eq{AppColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID()}
if !withOwnerRemoved {
eq[AppColumnOwnerRemoved.identifier()] = false
}
stmt, args, err := queries.toQuery(query).Where(eq).ToSql()
if err != nil {
return nil, errors.ThrowInvalidArgument(err, "QUERY-fajp8", "Errors.Query.InvalidRequest")
@@ -507,15 +476,12 @@ func (q *Queries) SearchApps(ctx context.Context, queries *AppSearchQueries, wit
return apps, err
}
func (q *Queries) SearchClientIDs(ctx context.Context, queries *AppSearchQueries, withOwnerRemoved bool) (ids []string, err error) {
func (q *Queries) SearchClientIDs(ctx context.Context, queries *AppSearchQueries) (ids []string, err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }()
query, scan := prepareClientIDsQuery(ctx, q.client)
eq := sq.Eq{AppColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID()}
if !withOwnerRemoved {
eq[AppColumnOwnerRemoved.identifier()] = false
}
stmt, args, err := queries.toQuery(query).Where(eq).ToSql()
if err != nil {
return nil, errors.ThrowInvalidArgument(err, "QUERY-fajp8", "Errors.Query.InvalidRequest")

View File

@@ -15,98 +15,98 @@ import (
)
var (
expectedAppQuery = regexp.QuoteMeta(`SELECT projections.apps5.id,` +
` projections.apps5.name,` +
` projections.apps5.project_id,` +
` projections.apps5.creation_date,` +
` projections.apps5.change_date,` +
` projections.apps5.resource_owner,` +
` projections.apps5.state,` +
` projections.apps5.sequence,` +
expectedAppQuery = regexp.QuoteMeta(`SELECT projections.apps6.id,` +
` projections.apps6.name,` +
` projections.apps6.project_id,` +
` projections.apps6.creation_date,` +
` projections.apps6.change_date,` +
` projections.apps6.resource_owner,` +
` projections.apps6.state,` +
` projections.apps6.sequence,` +
// api config
` projections.apps5_api_configs.app_id,` +
` projections.apps5_api_configs.client_id,` +
` projections.apps5_api_configs.auth_method,` +
` projections.apps6_api_configs.app_id,` +
` projections.apps6_api_configs.client_id,` +
` projections.apps6_api_configs.auth_method,` +
// oidc config
` projections.apps5_oidc_configs.app_id,` +
` projections.apps5_oidc_configs.version,` +
` projections.apps5_oidc_configs.client_id,` +
` projections.apps5_oidc_configs.redirect_uris,` +
` projections.apps5_oidc_configs.response_types,` +
` projections.apps5_oidc_configs.grant_types,` +
` projections.apps5_oidc_configs.application_type,` +
` projections.apps5_oidc_configs.auth_method_type,` +
` projections.apps5_oidc_configs.post_logout_redirect_uris,` +
` projections.apps5_oidc_configs.is_dev_mode,` +
` projections.apps5_oidc_configs.access_token_type,` +
` projections.apps5_oidc_configs.access_token_role_assertion,` +
` projections.apps5_oidc_configs.id_token_role_assertion,` +
` projections.apps5_oidc_configs.id_token_userinfo_assertion,` +
` projections.apps5_oidc_configs.clock_skew,` +
` projections.apps5_oidc_configs.additional_origins,` +
` projections.apps5_oidc_configs.skip_native_app_success_page,` +
` projections.apps6_oidc_configs.app_id,` +
` projections.apps6_oidc_configs.version,` +
` projections.apps6_oidc_configs.client_id,` +
` projections.apps6_oidc_configs.redirect_uris,` +
` projections.apps6_oidc_configs.response_types,` +
` projections.apps6_oidc_configs.grant_types,` +
` projections.apps6_oidc_configs.application_type,` +
` projections.apps6_oidc_configs.auth_method_type,` +
` projections.apps6_oidc_configs.post_logout_redirect_uris,` +
` projections.apps6_oidc_configs.is_dev_mode,` +
` projections.apps6_oidc_configs.access_token_type,` +
` projections.apps6_oidc_configs.access_token_role_assertion,` +
` projections.apps6_oidc_configs.id_token_role_assertion,` +
` projections.apps6_oidc_configs.id_token_userinfo_assertion,` +
` projections.apps6_oidc_configs.clock_skew,` +
` projections.apps6_oidc_configs.additional_origins,` +
` projections.apps6_oidc_configs.skip_native_app_success_page,` +
//saml config
` projections.apps5_saml_configs.app_id,` +
` projections.apps5_saml_configs.entity_id,` +
` projections.apps5_saml_configs.metadata,` +
` projections.apps5_saml_configs.metadata_url` +
` FROM projections.apps5` +
` LEFT JOIN projections.apps5_api_configs ON projections.apps5.id = projections.apps5_api_configs.app_id AND projections.apps5.instance_id = projections.apps5_api_configs.instance_id` +
` LEFT JOIN projections.apps5_oidc_configs ON projections.apps5.id = projections.apps5_oidc_configs.app_id AND projections.apps5.instance_id = projections.apps5_oidc_configs.instance_id` +
` LEFT JOIN projections.apps5_saml_configs ON projections.apps5.id = projections.apps5_saml_configs.app_id AND projections.apps5.instance_id = projections.apps5_saml_configs.instance_id` +
` projections.apps6_saml_configs.app_id,` +
` projections.apps6_saml_configs.entity_id,` +
` projections.apps6_saml_configs.metadata,` +
` projections.apps6_saml_configs.metadata_url` +
` FROM projections.apps6` +
` LEFT JOIN projections.apps6_api_configs ON projections.apps6.id = projections.apps6_api_configs.app_id AND projections.apps6.instance_id = projections.apps6_api_configs.instance_id` +
` LEFT JOIN projections.apps6_oidc_configs ON projections.apps6.id = projections.apps6_oidc_configs.app_id AND projections.apps6.instance_id = projections.apps6_oidc_configs.instance_id` +
` LEFT JOIN projections.apps6_saml_configs ON projections.apps6.id = projections.apps6_saml_configs.app_id AND projections.apps6.instance_id = projections.apps6_saml_configs.instance_id` +
` AS OF SYSTEM TIME '-1 ms'`)
expectedAppsQuery = regexp.QuoteMeta(`SELECT projections.apps5.id,` +
` projections.apps5.name,` +
` projections.apps5.project_id,` +
` projections.apps5.creation_date,` +
` projections.apps5.change_date,` +
` projections.apps5.resource_owner,` +
` projections.apps5.state,` +
` projections.apps5.sequence,` +
expectedAppsQuery = regexp.QuoteMeta(`SELECT projections.apps6.id,` +
` projections.apps6.name,` +
` projections.apps6.project_id,` +
` projections.apps6.creation_date,` +
` projections.apps6.change_date,` +
` projections.apps6.resource_owner,` +
` projections.apps6.state,` +
` projections.apps6.sequence,` +
// api config
` projections.apps5_api_configs.app_id,` +
` projections.apps5_api_configs.client_id,` +
` projections.apps5_api_configs.auth_method,` +
` projections.apps6_api_configs.app_id,` +
` projections.apps6_api_configs.client_id,` +
` projections.apps6_api_configs.auth_method,` +
// oidc config
` projections.apps5_oidc_configs.app_id,` +
` projections.apps5_oidc_configs.version,` +
` projections.apps5_oidc_configs.client_id,` +
` projections.apps5_oidc_configs.redirect_uris,` +
` projections.apps5_oidc_configs.response_types,` +
` projections.apps5_oidc_configs.grant_types,` +
` projections.apps5_oidc_configs.application_type,` +
` projections.apps5_oidc_configs.auth_method_type,` +
` projections.apps5_oidc_configs.post_logout_redirect_uris,` +
` projections.apps5_oidc_configs.is_dev_mode,` +
` projections.apps5_oidc_configs.access_token_type,` +
` projections.apps5_oidc_configs.access_token_role_assertion,` +
` projections.apps5_oidc_configs.id_token_role_assertion,` +
` projections.apps5_oidc_configs.id_token_userinfo_assertion,` +
` projections.apps5_oidc_configs.clock_skew,` +
` projections.apps5_oidc_configs.additional_origins,` +
` projections.apps5_oidc_configs.skip_native_app_success_page,` +
` projections.apps6_oidc_configs.app_id,` +
` projections.apps6_oidc_configs.version,` +
` projections.apps6_oidc_configs.client_id,` +
` projections.apps6_oidc_configs.redirect_uris,` +
` projections.apps6_oidc_configs.response_types,` +
` projections.apps6_oidc_configs.grant_types,` +
` projections.apps6_oidc_configs.application_type,` +
` projections.apps6_oidc_configs.auth_method_type,` +
` projections.apps6_oidc_configs.post_logout_redirect_uris,` +
` projections.apps6_oidc_configs.is_dev_mode,` +
` projections.apps6_oidc_configs.access_token_type,` +
` projections.apps6_oidc_configs.access_token_role_assertion,` +
` projections.apps6_oidc_configs.id_token_role_assertion,` +
` projections.apps6_oidc_configs.id_token_userinfo_assertion,` +
` projections.apps6_oidc_configs.clock_skew,` +
` projections.apps6_oidc_configs.additional_origins,` +
` projections.apps6_oidc_configs.skip_native_app_success_page,` +
//saml config
` projections.apps5_saml_configs.app_id,` +
` projections.apps5_saml_configs.entity_id,` +
` projections.apps5_saml_configs.metadata,` +
` projections.apps5_saml_configs.metadata_url,` +
` projections.apps6_saml_configs.app_id,` +
` projections.apps6_saml_configs.entity_id,` +
` projections.apps6_saml_configs.metadata,` +
` projections.apps6_saml_configs.metadata_url,` +
` COUNT(*) OVER ()` +
` FROM projections.apps5` +
` LEFT JOIN projections.apps5_api_configs ON projections.apps5.id = projections.apps5_api_configs.app_id AND projections.apps5.instance_id = projections.apps5_api_configs.instance_id` +
` LEFT JOIN projections.apps5_oidc_configs ON projections.apps5.id = projections.apps5_oidc_configs.app_id AND projections.apps5.instance_id = projections.apps5_oidc_configs.instance_id` +
` LEFT JOIN projections.apps5_saml_configs ON projections.apps5.id = projections.apps5_saml_configs.app_id AND projections.apps5.instance_id = projections.apps5_saml_configs.instance_id` +
` FROM projections.apps6` +
` LEFT JOIN projections.apps6_api_configs ON projections.apps6.id = projections.apps6_api_configs.app_id AND projections.apps6.instance_id = projections.apps6_api_configs.instance_id` +
` LEFT JOIN projections.apps6_oidc_configs ON projections.apps6.id = projections.apps6_oidc_configs.app_id AND projections.apps6.instance_id = projections.apps6_oidc_configs.instance_id` +
` LEFT JOIN projections.apps6_saml_configs ON projections.apps6.id = projections.apps6_saml_configs.app_id AND projections.apps6.instance_id = projections.apps6_saml_configs.instance_id` +
` AS OF SYSTEM TIME '-1 ms'`)
expectedAppIDsQuery = regexp.QuoteMeta(`SELECT projections.apps5_api_configs.client_id,` +
` projections.apps5_oidc_configs.client_id` +
` FROM projections.apps5` +
` LEFT JOIN projections.apps5_api_configs ON projections.apps5.id = projections.apps5_api_configs.app_id AND projections.apps5.instance_id = projections.apps5_api_configs.instance_id` +
` LEFT JOIN projections.apps5_oidc_configs ON projections.apps5.id = projections.apps5_oidc_configs.app_id AND projections.apps5.instance_id = projections.apps5_oidc_configs.instance_id` +
expectedAppIDsQuery = regexp.QuoteMeta(`SELECT projections.apps6_api_configs.client_id,` +
` projections.apps6_oidc_configs.client_id` +
` FROM projections.apps6` +
` LEFT JOIN projections.apps6_api_configs ON projections.apps6.id = projections.apps6_api_configs.app_id AND projections.apps6.instance_id = projections.apps6_api_configs.instance_id` +
` LEFT JOIN projections.apps6_oidc_configs ON projections.apps6.id = projections.apps6_oidc_configs.app_id AND projections.apps6.instance_id = projections.apps6_oidc_configs.instance_id` +
` AS OF SYSTEM TIME '-1 ms'`)
expectedProjectIDByAppQuery = regexp.QuoteMeta(`SELECT projections.apps5.project_id` +
` FROM projections.apps5` +
` LEFT JOIN projections.apps5_api_configs ON projections.apps5.id = projections.apps5_api_configs.app_id AND projections.apps5.instance_id = projections.apps5_api_configs.instance_id` +
` LEFT JOIN projections.apps5_oidc_configs ON projections.apps5.id = projections.apps5_oidc_configs.app_id AND projections.apps5.instance_id = projections.apps5_oidc_configs.instance_id` +
` LEFT JOIN projections.apps5_saml_configs ON projections.apps5.id = projections.apps5_saml_configs.app_id AND projections.apps5.instance_id = projections.apps5_saml_configs.instance_id` +
expectedProjectIDByAppQuery = regexp.QuoteMeta(`SELECT projections.apps6.project_id` +
` FROM projections.apps6` +
` LEFT JOIN projections.apps6_api_configs ON projections.apps6.id = projections.apps6_api_configs.app_id AND projections.apps6.instance_id = projections.apps6_api_configs.instance_id` +
` LEFT JOIN projections.apps6_oidc_configs ON projections.apps6.id = projections.apps6_oidc_configs.app_id AND projections.apps6.instance_id = projections.apps6_oidc_configs.instance_id` +
` LEFT JOIN projections.apps6_saml_configs ON projections.apps6.id = projections.apps6_saml_configs.app_id AND projections.apps6.instance_id = projections.apps6_saml_configs.instance_id` +
` AS OF SYSTEM TIME '-1 ms'`)
expectedProjectByAppQuery = regexp.QuoteMeta(`SELECT projections.projects4.id,` +
` projections.projects4.creation_date,` +
@@ -120,10 +120,10 @@ var (
` projections.projects4.has_project_check,` +
` projections.projects4.private_labeling_setting` +
` FROM projections.projects4` +
` JOIN projections.apps5 ON projections.projects4.id = projections.apps5.project_id AND projections.projects4.instance_id = projections.apps5.instance_id` +
` LEFT JOIN projections.apps5_api_configs ON projections.apps5.id = projections.apps5_api_configs.app_id AND projections.apps5.instance_id = projections.apps5_api_configs.instance_id` +
` LEFT JOIN projections.apps5_oidc_configs ON projections.apps5.id = projections.apps5_oidc_configs.app_id AND projections.apps5.instance_id = projections.apps5_oidc_configs.instance_id` +
` LEFT JOIN projections.apps5_saml_configs ON projections.apps5.id = projections.apps5_saml_configs.app_id AND projections.apps5.instance_id = projections.apps5_saml_configs.instance_id` +
` JOIN projections.apps6 ON projections.projects4.id = projections.apps6.project_id AND projections.projects4.instance_id = projections.apps6.instance_id` +
` LEFT JOIN projections.apps6_api_configs ON projections.apps6.id = projections.apps6_api_configs.app_id AND projections.apps6.instance_id = projections.apps6_api_configs.instance_id` +
` LEFT JOIN projections.apps6_oidc_configs ON projections.apps6.id = projections.apps6_oidc_configs.app_id AND projections.apps6.instance_id = projections.apps6_oidc_configs.instance_id` +
` LEFT JOIN projections.apps6_saml_configs ON projections.apps6.id = projections.apps6_saml_configs.app_id AND projections.apps6.instance_id = projections.apps6_saml_configs.instance_id` +
` AS OF SYSTEM TIME '-1 ms'`)
appCols = database.TextArray[string]{

View File

@@ -76,10 +76,6 @@ var (
name: projection.AuthNKeyEnabledCol,
table: authNKeyTable,
}
AuthNKeyOwnerRemovedCol = Column{
name: projection.AuthNKeyOwnerRemovedCol,
table: authNKeyTable,
}
)
type AuthNKeys struct {
@@ -139,9 +135,6 @@ func (q *Queries) SearchAuthNKeys(ctx context.Context, queries *AuthNKeySearchQu
AuthNKeyColumnEnabled.identifier(): true,
AuthNKeyColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(),
}
if !withOwnerRemoved {
eq[AuthNKeyOwnerRemovedCol.identifier()] = false
}
stmt, args, err := query.Where(eq).ToSql()
if err != nil {
return nil, errors.ThrowInvalidArgument(err, "QUERY-SAf3f", "Errors.Query.InvalidRequest")
@@ -159,7 +152,7 @@ func (q *Queries) SearchAuthNKeys(ctx context.Context, queries *AuthNKeySearchQu
return authNKeys, err
}
func (q *Queries) SearchAuthNKeysData(ctx context.Context, queries *AuthNKeySearchQueries, withOwnerRemoved bool) (authNKeys *AuthNKeysData, err error) {
func (q *Queries) SearchAuthNKeysData(ctx context.Context, queries *AuthNKeySearchQueries) (authNKeys *AuthNKeysData, err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }()
@@ -169,9 +162,6 @@ func (q *Queries) SearchAuthNKeysData(ctx context.Context, queries *AuthNKeySear
AuthNKeyColumnEnabled.identifier(): true,
AuthNKeyColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(),
}
if !withOwnerRemoved {
eq[AuthNKeyOwnerRemovedCol.identifier()] = false
}
stmt, args, err := query.Where(eq).ToSql()
if err != nil {
return nil, errors.ThrowInvalidArgument(err, "QUERY-SAg3f", "Errors.Query.InvalidRequest")
@@ -188,7 +178,7 @@ func (q *Queries) SearchAuthNKeysData(ctx context.Context, queries *AuthNKeySear
return authNKeys, err
}
func (q *Queries) GetAuthNKeyByID(ctx context.Context, shouldTriggerBulk bool, id string, withOwnerRemoved bool, queries ...SearchQuery) (key *AuthNKey, err error) {
func (q *Queries) GetAuthNKeyByID(ctx context.Context, shouldTriggerBulk bool, id string, queries ...SearchQuery) (key *AuthNKey, err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }()
@@ -208,9 +198,6 @@ func (q *Queries) GetAuthNKeyByID(ctx context.Context, shouldTriggerBulk bool, i
AuthNKeyColumnEnabled.identifier(): true,
AuthNKeyColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(),
}
if !withOwnerRemoved {
eq[AuthNKeyOwnerRemovedCol.identifier()] = false
}
stmt, args, err := query.Where(eq).ToSql()
if err != nil {
return nil, errors.ThrowInternal(err, "QUERY-AGhg4", "Errors.Query.SQLStatement")
@@ -239,20 +226,6 @@ func (q *Queries) GetAuthNKeyPublicKeyByIDAndIdentifier(ctx context.Context, id
AuthNKeyColumnExpiration.identifier(): time.Now(),
},
}
if !withOwnerRemoved {
eq = sq.And{
sq.Eq{
AuthNKeyColumnID.identifier(): id,
AuthNKeyColumnIdentifier.identifier(): identifier,
AuthNKeyColumnEnabled.identifier(): true,
AuthNKeyColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(),
AuthNKeyOwnerRemovedCol.identifier(): false,
},
sq.Gt{
AuthNKeyColumnExpiration.identifier(): time.Now(),
},
}
}
query, args, err := stmt.Where(eq).ToSql()
if err != nil {
return nil, errors.ThrowInternal(err, "QUERY-DAb32", "Errors.Query.SQLStatement")

View File

@@ -0,0 +1,23 @@
with config as (
select app_id, client_id, client_secret
from projections.apps6_api_configs
where instance_id = $1
and client_id = $2
union
select app_id, client_id, client_secret
from projections.apps6_oidc_configs
where instance_id = $1
and client_id = $2
),
keys as (
select identifier as client_id, json_object_agg(id, encode(public_key, 'base64')) as public_keys
from projections.authn_keys2
where $3 = true -- when argument is false, don't waste time on trying to query for keys.
and instance_id = $1
and identifier = $2
and expiration > current_timestamp
group by identifier
)
select config.client_id, config.client_secret, apps.project_id, keys.public_keys from config
join projections.apps6 apps on apps.id = config.app_id
left join keys on keys.client_id = config.client_id;

View File

@@ -0,0 +1,92 @@
-- deallocate q;
-- prepare q (text, text, text[]) as
with usr as (
select u.id, u.creation_date, u.change_date, u.sequence, u.state, u.resource_owner, u.username, n.login_name as preferred_login_name
from projections.users9 u
left join projections.login_names3 n on u.id = n.user_id and u.instance_id = n.instance_id
where u.id = $1
and u.instance_id = $2
and n.is_primary = true
),
human as (
select $1 as user_id, row_to_json(r) as human from (
select first_name, last_name, nick_name, display_name, avatar_key, email, is_email_verified, phone, is_phone_verified
from projections.users9_humans
where user_id = $1
and instance_id = $2
) r
),
machine as (
select $1 as user_id, row_to_json(r) as machine from (
select name, description
from projections.users9_machines
where user_id = $1
and instance_id = $2
) r
),
-- find the user's metadata
metadata as (
select json_agg(row_to_json(r)) as metadata from (
select creation_date, change_date, sequence, resource_owner, key, encode(value, 'base64') as value
from projections.user_metadata5
where user_id = $1
and instance_id = $2
) r
),
-- get all user grants, needed for the orgs query
user_grants as (
select id, grant_id, state, creation_date, change_date, sequence, user_id, roles, resource_owner, project_id
from projections.user_grants3
where user_id = $1
and instance_id = $2
and project_id = any($3)
),
-- filter all orgs we are interested in.
orgs as (
select id, name, primary_domain
from projections.orgs1
where id in (
select resource_owner from user_grants
union
select resource_owner from usr
)
and instance_id = $2
),
-- find the user's org
user_org as (
select row_to_json(r) as organization from (
select name, primary_domain
from orgs o
join usr u on o.id = u.resource_owner
) r
),
-- join user grants to orgs, projects and user
grants as (
select json_agg(row_to_json(r)) as grants from (
select g.*,
o.name as org_name, o.primary_domain as org_primary_domain,
p.name as project_name, u.resource_owner as user_resource_owner
from user_grants g
left join orgs o on o.id = g.resource_owner
left join projections.projects4 p on p.id = g.project_id
left join usr u on u.id = g.user_id
where p.instance_id = $2
) r
)
-- build the final result JSON
select json_build_object(
'user', (
select row_to_json(r) as usr from (
select u.*, h.human, m.machine
from usr u
left join human h on u.id = h.user_id
left join machine m on u.id = m.user_id
) r
),
'org', (select organization from user_org),
'metadata', (select metadata from metadata),
'user_grants', (select grants from grants)
);
-- execute q('231965491734773762','230690539048009730', '{"236645808328409090","240762134579904514"}')

View File

@@ -120,7 +120,7 @@ func (q *Queries) convertEvent(ctx context.Context, event eventstore.Event, user
}
func (q *Queries) editorUserByID(ctx context.Context, userID string) *EventEditor {
user, err := q.GetUserByID(ctx, false, userID, false)
user, err := q.GetUserByID(ctx, false, userID)
if err != nil {
return &EventEditor{ID: userID}
}

View File

@@ -21,21 +21,21 @@ var (
", members.user_id" +
", members.roles" +
", projections.login_names3.login_name" +
", projections.users8_humans.email" +
", projections.users8_humans.first_name" +
", projections.users8_humans.last_name" +
", projections.users8_humans.display_name" +
", projections.users8_machines.name" +
", projections.users8_humans.avatar_key" +
", projections.users8.type" +
", projections.users9_humans.email" +
", projections.users9_humans.first_name" +
", projections.users9_humans.last_name" +
", projections.users9_humans.display_name" +
", projections.users9_machines.name" +
", projections.users9_humans.avatar_key" +
", projections.users9.type" +
", COUNT(*) OVER () " +
"FROM projections.instance_members4 AS members " +
"LEFT JOIN projections.users8_humans " +
"ON members.user_id = projections.users8_humans.user_id AND members.instance_id = projections.users8_humans.instance_id " +
"LEFT JOIN projections.users8_machines " +
"ON members.user_id = projections.users8_machines.user_id AND members.instance_id = projections.users8_machines.instance_id " +
"LEFT JOIN projections.users8 " +
"ON members.user_id = projections.users8.id AND members.instance_id = projections.users8.instance_id " +
"LEFT JOIN projections.users9_humans " +
"ON members.user_id = projections.users9_humans.user_id AND members.instance_id = projections.users9_humans.instance_id " +
"LEFT JOIN projections.users9_machines " +
"ON members.user_id = projections.users9_machines.user_id AND members.instance_id = projections.users9_machines.instance_id " +
"LEFT JOIN projections.users9 " +
"ON members.user_id = projections.users9.id AND members.instance_id = projections.users9.instance_id " +
"LEFT JOIN projections.login_names3 " +
"ON members.user_id = projections.login_names3.user_id AND members.instance_id = projections.login_names3.instance_id " +
"AS OF SYSTEM TIME '-1 ms' " +

View File

@@ -0,0 +1,63 @@
package query
import (
"context"
"database/sql"
_ "embed"
"sync"
"github.com/zitadel/zitadel/internal/api/authz"
"github.com/zitadel/zitadel/internal/crypto"
"github.com/zitadel/zitadel/internal/database"
"github.com/zitadel/zitadel/internal/eventstore/handler/v2"
"github.com/zitadel/zitadel/internal/query/projection"
"github.com/zitadel/zitadel/internal/telemetry/tracing"
)
// introspectionTriggerHandlers slice can only be created after zitadel
// is fully initialized, otherwise the handlers are nil.
// OnceValue takes care of creating the slice on the first request
// and than will always return the same slice on subsequent requests.
var introspectionTriggerHandlers = sync.OnceValue(func() []*handler.Handler {
return append(oidcUserInfoTriggerHandlers(),
projection.AppProjection,
projection.OIDCSettingsProjection,
projection.AuthNKeyProjection,
)
})
func TriggerIntrospectionProjections(ctx context.Context) {
triggerBatch(ctx, introspectionTriggerHandlers()...)
}
type IntrospectionClient struct {
ClientID string
ClientSecret *crypto.CryptoValue
ProjectID string
PublicKeys database.Map[[]byte]
}
//go:embed embed/introspection_client_by_id.sql
var introspectionClientByIDQuery string
func (q *Queries) GetIntrospectionClientByID(ctx context.Context, clientID string, getKeys bool) (_ *IntrospectionClient, err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }()
var (
instanceID = authz.GetInstance(ctx).InstanceID()
client = new(IntrospectionClient)
)
err = q.client.QueryRowContext(ctx, func(row *sql.Row) error {
return row.Scan(&client.ClientID, &client.ClientSecret, &client.ProjectID, &client.PublicKeys)
},
introspectionClientByIDQuery,
instanceID, clientID, getKeys,
)
if err != nil {
return nil, err
}
return client, nil
}

View File

@@ -0,0 +1,108 @@
package query
import (
"database/sql"
"database/sql/driver"
_ "embed"
"encoding/json"
"regexp"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/zitadel/zitadel/internal/api/authz"
"github.com/zitadel/zitadel/internal/crypto"
"github.com/zitadel/zitadel/internal/database"
)
func TestQueries_GetIntrospectionClientByID(t *testing.T) {
secret := &crypto.CryptoValue{
CryptoType: crypto.TypeHash,
Algorithm: "alg",
KeyID: "keyID",
Crypted: []byte("secret"),
}
encSecret, err := json.Marshal(secret)
require.NoError(t, err)
pubkeys := database.Map[[]byte]{
"key1": {1, 2, 3},
"key2": {4, 5, 6},
}
encPubkeys, err := pubkeys.Value()
require.NoError(t, err)
expQuery := regexp.QuoteMeta(introspectionClientByIDQuery)
type args struct {
clientID string
getKeys bool
}
tests := []struct {
name string
args args
mock sqlExpectation
want *IntrospectionClient
wantErr error
}{
{
name: "query error",
args: args{
clientID: "clientID",
getKeys: false,
},
mock: mockQueryErr(expQuery, sql.ErrConnDone, "instanceID", "clientID", false),
wantErr: sql.ErrConnDone,
},
{
name: "success, secret",
args: args{
clientID: "clientID",
getKeys: false,
},
mock: mockQuery(expQuery,
[]string{"client_id", "client_secret", "project_id", "public_keys"},
[]driver.Value{"clientID", encSecret, "projectID", nil},
"instanceID", "clientID", false),
want: &IntrospectionClient{
ClientID: "clientID",
ClientSecret: secret,
ProjectID: "projectID",
PublicKeys: nil,
},
},
{
name: "success, keys",
args: args{
clientID: "clientID",
getKeys: true,
},
mock: mockQuery(expQuery,
[]string{"client_id", "client_secret", "project_id", "public_keys"},
[]driver.Value{"clientID", nil, "projectID", encPubkeys},
"instanceID", "clientID", true),
want: &IntrospectionClient{
ClientID: "clientID",
ClientSecret: nil,
ProjectID: "projectID",
PublicKeys: pubkeys,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
execMock(t, tt.mock, func(db *sql.DB) {
q := &Queries{
client: &database.DB{
DB: db,
Database: &prepareDB{},
},
}
ctx := authz.NewMockContext("instanceID", "orgID", "userID")
got, err := q.GetIntrospectionClientByID(ctx, tt.args.clientID, tt.args.getKeys)
require.ErrorIs(t, err, tt.wantErr)
assert.Equal(t, tt.want, got)
})
})
}
}

View File

@@ -13,7 +13,9 @@ import (
"github.com/zitadel/zitadel/internal/crypto"
"github.com/zitadel/zitadel/internal/domain"
"github.com/zitadel/zitadel/internal/errors"
"github.com/zitadel/zitadel/internal/eventstore"
"github.com/zitadel/zitadel/internal/query/projection"
"github.com/zitadel/zitadel/internal/repository/keypair"
"github.com/zitadel/zitadel/internal/telemetry/tracing"
)
@@ -349,3 +351,88 @@ func preparePrivateKeysQuery(ctx context.Context, db prepareDatabase) (sq.Select
}, nil
}
}
type PublicKeyReadModel struct {
eventstore.ReadModel
Algorithm string
Key *crypto.CryptoValue
Expiry time.Time
Usage domain.KeyUsage
}
func NewPublicKeyReadModel(keyID, resourceOwner string) *PublicKeyReadModel {
return &PublicKeyReadModel{
ReadModel: eventstore.ReadModel{
AggregateID: keyID,
ResourceOwner: resourceOwner,
},
}
}
func (wm *PublicKeyReadModel) AppendEvents(events ...eventstore.Event) {
wm.ReadModel.AppendEvents(events...)
}
func (wm *PublicKeyReadModel) Reduce() error {
for _, event := range wm.Events {
switch e := event.(type) {
case *keypair.AddedEvent:
wm.Algorithm = e.Algorithm
wm.Key = e.PublicKey.Key
wm.Expiry = e.PublicKey.Expiry
wm.Usage = e.Usage
default:
}
}
return wm.ReadModel.Reduce()
}
func (wm *PublicKeyReadModel) Query() *eventstore.SearchQueryBuilder {
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent).
AwaitOpenTransactions().
ResourceOwner(wm.ResourceOwner).
AddQuery().
AggregateTypes(keypair.AggregateType).
AggregateIDs(wm.AggregateID).
EventTypes(keypair.AddedEventType).
Builder()
}
func (q *Queries) GetActivePublicKeyByID(ctx context.Context, keyID string, current time.Time) (_ PublicKey, err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }()
model := NewPublicKeyReadModel(keyID, authz.GetInstance(ctx).InstanceID())
if err := q.eventstore.FilterToQueryReducer(ctx, model); err != nil {
return nil, err
}
if model.Algorithm == "" || model.Key == nil {
return nil, errors.ThrowNotFound(err, "QUERY-Ahf7x", "Errors.Key.NotFound")
}
if model.Expiry.Before(current) {
return nil, errors.ThrowInvalidArgument(err, "QUERY-ciF4k", "Errors.Key.ExpireBeforeNow")
}
keyValue, err := crypto.Decrypt(model.Key, q.keyEncryptionAlgorithm)
if err != nil {
return nil, errors.ThrowInternal(err, "QUERY-Ie4oh", "Errors.Internal")
}
publicKey, err := crypto.BytesToPublicKey(keyValue)
if err != nil {
return nil, errors.ThrowInternal(err, "QUERY-Kai2Z", "Errors.Internal")
}
return &rsaPublicKey{
key: key{
id: model.AggregateID,
creationDate: model.CreationDate,
changeDate: model.ChangeDate,
sequence: model.ProcessedSequence,
resourceOwner: model.ResourceOwner,
algorithm: model.Algorithm,
use: model.Usage,
},
expiry: model.Expiry,
publicKey: publicKey,
}, nil
}

View File

@@ -1,18 +1,28 @@
package query
import (
"context"
"crypto/rsa"
"database/sql"
"database/sql/driver"
"errors"
"fmt"
"io"
"math/big"
"regexp"
"testing"
"time"
"github.com/golang/mock/gomock"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/zitadel/zitadel/internal/api/authz"
"github.com/zitadel/zitadel/internal/crypto"
"github.com/zitadel/zitadel/internal/domain"
errs "github.com/zitadel/zitadel/internal/errors"
"github.com/zitadel/zitadel/internal/eventstore"
key_repo "github.com/zitadel/zitadel/internal/repository/keypair"
)
var (
@@ -247,3 +257,232 @@ func fromBase16(base16 string) *big.Int {
}
return i
}
const pubKey = `-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAs38btwb3c7r0tMaQpGvB
mY+mPwMU/LpfuPoC0k2t4RsKp0fv40SMl50CRrHgk395wch8PMPYbl3+8TtYAJuy
rFALIj3Ff1UcKIk0hOH5DDsfh7/q2wFuncTmS6bifYo8CfSq2vDGnM7nZnEvxY/M
fSydZdcmIqlkUpfQmtzExw9+tSe5Dxq6gn5JtlGgLgZGt69r5iMMrTEGhhVAXzNu
MZbmlCoBru+rC8ITlTX/0V1ZcsSbL8tYWhthyu9x6yjo1bH85wiVI4gs0MhU8f2a
+kjL/KGZbR14Ua2eo6tonBZLC5DHWM2TkYXgRCDPufjcgmzN0Lm91E4P8KvBcvly
6QIDAQAB
-----END PUBLIC KEY-----
`
func TestQueries_GetActivePublicKeyByID(t *testing.T) {
now := time.Now()
future := now.Add(time.Hour)
tests := []struct {
name string
eventstore func(*testing.T) *eventstore.Eventstore
encryption func(*testing.T) *crypto.MockEncryptionAlgorithm
want *rsaPublicKey
wantErr error
}{
{
name: "filter error",
eventstore: expectEventstore(
expectFilterError(io.ErrClosedPipe),
),
wantErr: io.ErrClosedPipe,
},
{
name: "not found error",
eventstore: expectEventstore(
expectFilter(),
),
wantErr: errs.ThrowNotFound(nil, "QUERY-Ahf7x", "Errors.Key.NotFound"),
},
{
name: "expired error",
eventstore: expectEventstore(
expectFilter(
eventFromEventPusher(key_repo.NewAddedEvent(context.Background(),
&eventstore.Aggregate{
ID: "keyID",
Type: key_repo.AggregateType,
ResourceOwner: "instanceID",
InstanceID: "instanceID",
Version: key_repo.AggregateVersion,
},
domain.KeyUsageSigning, "alg",
&crypto.CryptoValue{
CryptoType: crypto.TypeEncryption,
Algorithm: "alg",
KeyID: "keyID",
Crypted: []byte("private"),
},
&crypto.CryptoValue{
CryptoType: crypto.TypeEncryption,
Algorithm: "alg",
KeyID: "keyID",
Crypted: []byte("public"),
},
now.Add(-time.Hour),
now.Add(-time.Hour),
)),
),
),
wantErr: errs.ThrowInvalidArgument(nil, "QUERY-ciF4k", "Errors.Key.ExpireBeforeNow"),
},
{
name: "decrypt error",
eventstore: expectEventstore(
expectFilter(
eventFromEventPusher(key_repo.NewAddedEvent(context.Background(),
&eventstore.Aggregate{
ID: "keyID",
Type: key_repo.AggregateType,
ResourceOwner: "instanceID",
InstanceID: "instanceID",
Version: key_repo.AggregateVersion,
},
domain.KeyUsageSigning, "alg",
&crypto.CryptoValue{
CryptoType: crypto.TypeEncryption,
Algorithm: "alg",
KeyID: "keyID",
Crypted: []byte("private"),
},
&crypto.CryptoValue{
CryptoType: crypto.TypeEncryption,
Algorithm: "alg",
KeyID: "keyID",
Crypted: []byte("public"),
},
future,
future,
)),
),
),
encryption: func(t *testing.T) *crypto.MockEncryptionAlgorithm {
encryption := crypto.NewMockEncryptionAlgorithm(gomock.NewController(t))
expect := encryption.EXPECT()
expect.Algorithm().Return("alg")
expect.DecryptionKeyIDs().Return([]string{})
return encryption
},
wantErr: errs.ThrowInternal(nil, "QUERY-Ie4oh", "Errors.Internal"),
},
{
name: "parse error",
eventstore: expectEventstore(
expectFilter(
eventFromEventPusher(key_repo.NewAddedEvent(context.Background(),
&eventstore.Aggregate{
ID: "keyID",
Type: key_repo.AggregateType,
ResourceOwner: "instanceID",
InstanceID: "instanceID",
Version: key_repo.AggregateVersion,
},
domain.KeyUsageSigning, "alg",
&crypto.CryptoValue{
CryptoType: crypto.TypeEncryption,
Algorithm: "alg",
KeyID: "keyID",
Crypted: []byte("private"),
},
&crypto.CryptoValue{
CryptoType: crypto.TypeEncryption,
Algorithm: "alg",
KeyID: "keyID",
Crypted: []byte("public"),
},
future,
future,
)),
),
),
encryption: func(t *testing.T) *crypto.MockEncryptionAlgorithm {
encryption := crypto.NewMockEncryptionAlgorithm(gomock.NewController(t))
expect := encryption.EXPECT()
expect.Algorithm().Return("alg")
expect.DecryptionKeyIDs().Return([]string{"keyID"})
expect.Decrypt([]byte("public"), "keyID").Return([]byte("foo"), nil)
return encryption
},
wantErr: errs.ThrowInternal(nil, "QUERY-Kai2Z", "Errors.Internal"),
},
{
name: "success",
eventstore: expectEventstore(
expectFilter(
eventFromEventPusher(key_repo.NewAddedEvent(context.Background(),
&eventstore.Aggregate{
ID: "keyID",
Type: key_repo.AggregateType,
ResourceOwner: "instanceID",
InstanceID: "instanceID",
Version: key_repo.AggregateVersion,
},
domain.KeyUsageSigning, "alg",
&crypto.CryptoValue{
CryptoType: crypto.TypeEncryption,
Algorithm: "alg",
KeyID: "keyID",
Crypted: []byte("private"),
},
&crypto.CryptoValue{
CryptoType: crypto.TypeEncryption,
Algorithm: "alg",
KeyID: "keyID",
Crypted: []byte("public"),
},
future,
future,
)),
),
),
encryption: func(t *testing.T) *crypto.MockEncryptionAlgorithm {
encryption := crypto.NewMockEncryptionAlgorithm(gomock.NewController(t))
expect := encryption.EXPECT()
expect.Algorithm().Return("alg")
expect.DecryptionKeyIDs().Return([]string{"keyID"})
expect.Decrypt([]byte("public"), "keyID").Return([]byte(pubKey), nil)
return encryption
},
want: &rsaPublicKey{
key: key{
id: "keyID",
resourceOwner: "instanceID",
algorithm: "alg",
use: domain.KeyUsageSigning,
},
expiry: future,
publicKey: func() *rsa.PublicKey {
publicKey, err := crypto.BytesToPublicKey([]byte(pubKey))
if err != nil {
panic(err)
}
return publicKey
}(),
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
q := &Queries{
eventstore: tt.eventstore(t),
}
if tt.encryption != nil {
q.keyEncryptionAlgorithm = tt.encryption(t)
}
ctx := authz.NewMockContext("instanceID", "orgID", "loginClient")
key, err := q.GetActivePublicKeyByID(ctx, "keyID", now)
if tt.wantErr != nil {
require.ErrorIs(t, err, tt.wantErr)
return
}
require.NoError(t, err)
require.NotNil(t, key)
got := key.(*rsaPublicKey)
assert.WithinDuration(t, tt.want.expiry, got.expiry, time.Second)
tt.want.expiry = time.Time{}
got.expiry = time.Time{}
assert.Equal(t, tt.want, got)
})
}
}

View File

@@ -21,24 +21,24 @@ var (
", members.user_id" +
", members.roles" +
", projections.login_names3.login_name" +
", projections.users8_humans.email" +
", projections.users8_humans.first_name" +
", projections.users8_humans.last_name" +
", projections.users8_humans.display_name" +
", projections.users8_machines.name" +
", projections.users8_humans.avatar_key" +
", projections.users8.type" +
", projections.users9_humans.email" +
", projections.users9_humans.first_name" +
", projections.users9_humans.last_name" +
", projections.users9_humans.display_name" +
", projections.users9_machines.name" +
", projections.users9_humans.avatar_key" +
", projections.users9.type" +
", COUNT(*) OVER () " +
"FROM projections.org_members4 AS members " +
"LEFT JOIN projections.users8_humans " +
"ON members.user_id = projections.users8_humans.user_id " +
"AND members.instance_id = projections.users8_humans.instance_id " +
"LEFT JOIN projections.users8_machines " +
"ON members.user_id = projections.users8_machines.user_id " +
"AND members.instance_id = projections.users8_machines.instance_id " +
"LEFT JOIN projections.users8 " +
"ON members.user_id = projections.users8.id " +
"AND members.instance_id = projections.users8.instance_id " +
"LEFT JOIN projections.users9_humans " +
"ON members.user_id = projections.users9_humans.user_id " +
"AND members.instance_id = projections.users9_humans.instance_id " +
"LEFT JOIN projections.users9_machines " +
"ON members.user_id = projections.users9_machines.user_id " +
"AND members.instance_id = projections.users9_machines.instance_id " +
"LEFT JOIN projections.users9 " +
"ON members.user_id = projections.users9.id " +
"AND members.instance_id = projections.users9.instance_id " +
"LEFT JOIN projections.login_names3 " +
"ON members.user_id = projections.login_names3.user_id " +
"AND members.instance_id = projections.login_names3.instance_id " +

View File

@@ -21,24 +21,24 @@ var (
", members.user_id" +
", members.roles" +
", projections.login_names3.login_name" +
", projections.users8_humans.email" +
", projections.users8_humans.first_name" +
", projections.users8_humans.last_name" +
", projections.users8_humans.display_name" +
", projections.users8_machines.name" +
", projections.users8_humans.avatar_key" +
", projections.users8.type" +
", projections.users9_humans.email" +
", projections.users9_humans.first_name" +
", projections.users9_humans.last_name" +
", projections.users9_humans.display_name" +
", projections.users9_machines.name" +
", projections.users9_humans.avatar_key" +
", projections.users9.type" +
", COUNT(*) OVER () " +
"FROM projections.project_grant_members4 AS members " +
"LEFT JOIN projections.users8_humans " +
"ON members.user_id = projections.users8_humans.user_id " +
"AND members.instance_id = projections.users8_humans.instance_id " +
"LEFT JOIN projections.users8_machines " +
"ON members.user_id = projections.users8_machines.user_id " +
"AND members.instance_id = projections.users8_machines.instance_id " +
"LEFT JOIN projections.users8 " +
"ON members.user_id = projections.users8.id " +
"AND members.instance_id = projections.users8.instance_id " +
"LEFT JOIN projections.users9_humans " +
"ON members.user_id = projections.users9_humans.user_id " +
"AND members.instance_id = projections.users9_humans.instance_id " +
"LEFT JOIN projections.users9_machines " +
"ON members.user_id = projections.users9_machines.user_id " +
"AND members.instance_id = projections.users9_machines.instance_id " +
"LEFT JOIN projections.users9 " +
"ON members.user_id = projections.users9.id " +
"AND members.instance_id = projections.users9.instance_id " +
"LEFT JOIN projections.login_names3 " +
"ON members.user_id = projections.login_names3.user_id " +
"AND members.instance_id = projections.login_names3.instance_id " +

View File

@@ -21,24 +21,24 @@ var (
", members.user_id" +
", members.roles" +
", projections.login_names3.login_name" +
", projections.users8_humans.email" +
", projections.users8_humans.first_name" +
", projections.users8_humans.last_name" +
", projections.users8_humans.display_name" +
", projections.users8_machines.name" +
", projections.users8_humans.avatar_key" +
", projections.users8.type" +
", projections.users9_humans.email" +
", projections.users9_humans.first_name" +
", projections.users9_humans.last_name" +
", projections.users9_humans.display_name" +
", projections.users9_machines.name" +
", projections.users9_humans.avatar_key" +
", projections.users9.type" +
", COUNT(*) OVER () " +
"FROM projections.project_members4 AS members " +
"LEFT JOIN projections.users8_humans " +
"ON members.user_id = projections.users8_humans.user_id " +
"AND members.instance_id = projections.users8_humans.instance_id " +
"LEFT JOIN projections.users8_machines " +
"ON members.user_id = projections.users8_machines.user_id " +
"AND members.instance_id = projections.users8_machines.instance_id " +
"LEFT JOIN projections.users8 " +
"ON members.user_id = projections.users8.id " +
"AND members.instance_id = projections.users8.instance_id " +
"LEFT JOIN projections.users9_humans " +
"ON members.user_id = projections.users9_humans.user_id " +
"AND members.instance_id = projections.users9_humans.instance_id " +
"LEFT JOIN projections.users9_machines " +
"ON members.user_id = projections.users9_machines.user_id " +
"AND members.instance_id = projections.users9_machines.instance_id " +
"LEFT JOIN projections.users9 " +
"ON members.user_id = projections.users9.id " +
"AND members.instance_id = projections.users9.instance_id " +
"LEFT JOIN projections.login_names3 " +
"ON members.user_id = projections.login_names3.user_id " +
"AND members.instance_id = projections.login_names3.instance_id " +

View File

@@ -15,7 +15,7 @@ import (
)
const (
AppProjectionTable = "projections.apps5"
AppProjectionTable = "projections.apps6"
AppAPITable = AppProjectionTable + "_" + appAPITableSuffix
AppOIDCTable = AppProjectionTable + "_" + appOIDCTableSuffix
AppSAMLTable = AppProjectionTable + "_" + appSAMLTableSuffix
@@ -29,7 +29,6 @@ const (
AppColumnInstanceID = "instance_id"
AppColumnState = "state"
AppColumnSequence = "sequence"
AppColumnOwnerRemoved = "owner_removed"
appAPITableSuffix = "api_configs"
AppAPIConfigColumnAppID = "app_id"
@@ -89,11 +88,9 @@ func (*appProjection) Init() *old_handler.Check {
handler.NewColumn(AppColumnInstanceID, handler.ColumnTypeText),
handler.NewColumn(AppColumnState, handler.ColumnTypeEnum),
handler.NewColumn(AppColumnSequence, handler.ColumnTypeInt64),
handler.NewColumn(AppColumnOwnerRemoved, handler.ColumnTypeBool, handler.Default(false)),
},
handler.NewPrimaryKey(AppColumnInstanceID, AppColumnID),
handler.WithIndex(handler.NewIndex("project_id", []string{AppColumnProjectID})),
handler.WithIndex(handler.NewIndex("owner_removed", []string{AppColumnOwnerRemoved})),
),
handler.NewSuffixedTable([]*handler.InitColumn{
handler.NewColumn(AppAPIConfigColumnAppID, handler.ColumnTypeText),

View File

@@ -46,7 +46,7 @@ func TestAppProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
expectedStmt: "INSERT INTO projections.apps5 (id, name, project_id, creation_date, change_date, resource_owner, instance_id, state, sequence) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)",
expectedStmt: "INSERT INTO projections.apps6 (id, name, project_id, creation_date, change_date, resource_owner, instance_id, state, sequence) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)",
expectedArgs: []interface{}{
"app-id",
"my-app",
@@ -83,7 +83,7 @@ func TestAppProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
expectedStmt: "UPDATE projections.apps5 SET (name, change_date, sequence) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)",
expectedStmt: "UPDATE projections.apps6 SET (name, change_date, sequence) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)",
expectedArgs: []interface{}{
"my-app",
anyArg{},
@@ -136,7 +136,7 @@ func TestAppProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
expectedStmt: "UPDATE projections.apps5 SET (state, change_date, sequence) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)",
expectedStmt: "UPDATE projections.apps6 SET (state, change_date, sequence) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)",
expectedArgs: []interface{}{
domain.AppStateInactive,
anyArg{},
@@ -168,7 +168,7 @@ func TestAppProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
expectedStmt: "UPDATE projections.apps5 SET (state, change_date, sequence) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)",
expectedStmt: "UPDATE projections.apps6 SET (state, change_date, sequence) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)",
expectedArgs: []interface{}{
domain.AppStateActive,
anyArg{},
@@ -200,7 +200,7 @@ func TestAppProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
expectedStmt: "DELETE FROM projections.apps5 WHERE (id = $1) AND (instance_id = $2)",
expectedStmt: "DELETE FROM projections.apps6 WHERE (id = $1) AND (instance_id = $2)",
expectedArgs: []interface{}{
"app-id",
"instance-id",
@@ -227,7 +227,7 @@ func TestAppProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
expectedStmt: "DELETE FROM projections.apps5 WHERE (project_id = $1) AND (instance_id = $2)",
expectedStmt: "DELETE FROM projections.apps6 WHERE (project_id = $1) AND (instance_id = $2)",
expectedArgs: []interface{}{
"agg-id",
"instance-id",
@@ -254,7 +254,7 @@ func TestAppProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
expectedStmt: "DELETE FROM projections.apps5 WHERE (instance_id = $1)",
expectedStmt: "DELETE FROM projections.apps6 WHERE (instance_id = $1)",
expectedArgs: []interface{}{
"agg-id",
},
@@ -285,7 +285,7 @@ func TestAppProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
expectedStmt: "INSERT INTO projections.apps5_api_configs (app_id, instance_id, client_id, client_secret, auth_method) VALUES ($1, $2, $3, $4, $5)",
expectedStmt: "INSERT INTO projections.apps6_api_configs (app_id, instance_id, client_id, client_secret, auth_method) VALUES ($1, $2, $3, $4, $5)",
expectedArgs: []interface{}{
"app-id",
"instance-id",
@@ -295,7 +295,7 @@ func TestAppProjection_reduces(t *testing.T) {
},
},
{
expectedStmt: "UPDATE projections.apps5 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)",
expectedStmt: "UPDATE projections.apps6 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)",
expectedArgs: []interface{}{
anyArg{},
uint64(15),
@@ -329,7 +329,7 @@ func TestAppProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
expectedStmt: "UPDATE projections.apps5_api_configs SET (client_secret, auth_method) = ($1, $2) WHERE (app_id = $3) AND (instance_id = $4)",
expectedStmt: "UPDATE projections.apps6_api_configs SET (client_secret, auth_method) = ($1, $2) WHERE (app_id = $3) AND (instance_id = $4)",
expectedArgs: []interface{}{
anyArg{},
domain.APIAuthMethodTypePrivateKeyJWT,
@@ -338,7 +338,7 @@ func TestAppProjection_reduces(t *testing.T) {
},
},
{
expectedStmt: "UPDATE projections.apps5 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)",
expectedStmt: "UPDATE projections.apps6 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)",
expectedArgs: []interface{}{
anyArg{},
uint64(15),
@@ -391,7 +391,7 @@ func TestAppProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
expectedStmt: "UPDATE projections.apps5_api_configs SET client_secret = $1 WHERE (app_id = $2) AND (instance_id = $3)",
expectedStmt: "UPDATE projections.apps6_api_configs SET client_secret = $1 WHERE (app_id = $2) AND (instance_id = $3)",
expectedArgs: []interface{}{
anyArg{},
"app-id",
@@ -399,7 +399,7 @@ func TestAppProjection_reduces(t *testing.T) {
},
},
{
expectedStmt: "UPDATE projections.apps5 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)",
expectedStmt: "UPDATE projections.apps6 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)",
expectedArgs: []interface{}{
anyArg{},
uint64(15),
@@ -447,7 +447,7 @@ func TestAppProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
expectedStmt: "INSERT INTO projections.apps5_oidc_configs (app_id, instance_id, version, client_id, client_secret, redirect_uris, response_types, grant_types, application_type, auth_method_type, post_logout_redirect_uris, is_dev_mode, access_token_type, access_token_role_assertion, id_token_role_assertion, id_token_userinfo_assertion, clock_skew, additional_origins, skip_native_app_success_page) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19)",
expectedStmt: "INSERT INTO projections.apps6_oidc_configs (app_id, instance_id, version, client_id, client_secret, redirect_uris, response_types, grant_types, application_type, auth_method_type, post_logout_redirect_uris, is_dev_mode, access_token_type, access_token_role_assertion, id_token_role_assertion, id_token_userinfo_assertion, clock_skew, additional_origins, skip_native_app_success_page) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19)",
expectedArgs: []interface{}{
"app-id",
"instance-id",
@@ -471,7 +471,7 @@ func TestAppProjection_reduces(t *testing.T) {
},
},
{
expectedStmt: "UPDATE projections.apps5 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)",
expectedStmt: "UPDATE projections.apps6 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)",
expectedArgs: []interface{}{
anyArg{},
uint64(15),
@@ -518,7 +518,7 @@ func TestAppProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
expectedStmt: "UPDATE projections.apps5_oidc_configs SET (version, redirect_uris, response_types, grant_types, application_type, auth_method_type, post_logout_redirect_uris, is_dev_mode, access_token_type, access_token_role_assertion, id_token_role_assertion, id_token_userinfo_assertion, clock_skew, additional_origins, skip_native_app_success_page) = ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15) WHERE (app_id = $16) AND (instance_id = $17)",
expectedStmt: "UPDATE projections.apps6_oidc_configs SET (version, redirect_uris, response_types, grant_types, application_type, auth_method_type, post_logout_redirect_uris, is_dev_mode, access_token_type, access_token_role_assertion, id_token_role_assertion, id_token_userinfo_assertion, clock_skew, additional_origins, skip_native_app_success_page) = ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15) WHERE (app_id = $16) AND (instance_id = $17)",
expectedArgs: []interface{}{
domain.OIDCVersionV1,
database.TextArray[string]{"redirect.one.ch", "redirect.two.ch"},
@@ -540,7 +540,7 @@ func TestAppProjection_reduces(t *testing.T) {
},
},
{
expectedStmt: "UPDATE projections.apps5 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)",
expectedStmt: "UPDATE projections.apps6 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)",
expectedArgs: []interface{}{
anyArg{},
uint64(15),
@@ -593,7 +593,7 @@ func TestAppProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
expectedStmt: "UPDATE projections.apps5_oidc_configs SET client_secret = $1 WHERE (app_id = $2) AND (instance_id = $3)",
expectedStmt: "UPDATE projections.apps6_oidc_configs SET client_secret = $1 WHERE (app_id = $2) AND (instance_id = $3)",
expectedArgs: []interface{}{
anyArg{},
"app-id",
@@ -601,7 +601,7 @@ func TestAppProjection_reduces(t *testing.T) {
},
},
{
expectedStmt: "UPDATE projections.apps5 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)",
expectedStmt: "UPDATE projections.apps6 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)",
expectedArgs: []interface{}{
anyArg{},
uint64(15),
@@ -630,7 +630,7 @@ func TestAppProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
expectedStmt: "DELETE FROM projections.apps5 WHERE (instance_id = $1) AND (resource_owner = $2)",
expectedStmt: "DELETE FROM projections.apps6 WHERE (instance_id = $1) AND (resource_owner = $2)",
expectedArgs: []interface{}{
"instance-id",
"agg-id",

View File

@@ -30,7 +30,6 @@ const (
AuthNKeyPublicKeyCol = "public_key"
AuthNKeyTypeCol = "type"
AuthNKeyEnabledCol = "enabled"
AuthNKeyOwnerRemovedCol = "owner_removed"
)
type authNKeyProjection struct{}
@@ -59,12 +58,10 @@ func (*authNKeyProjection) Init() *old_handler.Check {
handler.NewColumn(AuthNKeyPublicKeyCol, handler.ColumnTypeBytes),
handler.NewColumn(AuthNKeyEnabledCol, handler.ColumnTypeBool, handler.Default(true)),
handler.NewColumn(AuthNKeyTypeCol, handler.ColumnTypeEnum, handler.Default(0)),
handler.NewColumn(AuthNKeyOwnerRemovedCol, handler.ColumnTypeBool, handler.Default(false)),
},
handler.NewPrimaryKey(AuthNKeyInstanceIDCol, AuthNKeyIDCol),
handler.WithIndex(handler.NewIndex("enabled", []string{AuthNKeyEnabledCol})),
handler.WithIndex(handler.NewIndex("identifier", []string{AuthNKeyIdentifierCol})),
handler.WithIndex(handler.NewIndex("owner_removed", []string{AuthNKeyOwnerRemovedCol})),
),
)
}

View File

@@ -15,7 +15,7 @@ import (
)
const (
UserTable = "projections.users8"
UserTable = "projections.users9"
UserHumanTable = UserTable + "_" + UserHumanSuffix
UserMachineTable = UserTable + "_" + UserMachineSuffix
UserNotifyTable = UserTable + "_" + UserNotifySuffix
@@ -29,7 +29,6 @@ const (
UserInstanceIDCol = "instance_id"
UserUsernameCol = "username"
UserTypeCol = "type"
UserOwnerRemovedCol = "owner_removed"
UserHumanSuffix = "humans"
HumanUserIDCol = "user_id"
@@ -94,12 +93,10 @@ func (*userProjection) Init() *old_handler.Check {
handler.NewColumn(UserInstanceIDCol, handler.ColumnTypeText),
handler.NewColumn(UserUsernameCol, handler.ColumnTypeText),
handler.NewColumn(UserTypeCol, handler.ColumnTypeEnum),
handler.NewColumn(UserOwnerRemovedCol, handler.ColumnTypeBool, handler.Default(false)),
},
handler.NewPrimaryKey(UserInstanceIDCol, UserIDCol),
handler.WithIndex(handler.NewIndex("username", []string{UserUsernameCol})),
handler.WithIndex(handler.NewIndex("resource_owner", []string{UserResourceOwnerCol})),
handler.WithIndex(handler.NewIndex("owner_removed", []string{UserOwnerRemovedCol})),
),
handler.NewSuffixedTable([]*handler.InitColumn{
handler.NewColumn(HumanUserIDCol, handler.ColumnTypeText),

View File

@@ -13,7 +13,7 @@ import (
)
const (
UserMetadataProjectionTable = "projections.user_metadata4"
UserMetadataProjectionTable = "projections.user_metadata5"
UserMetadataColumnUserID = "user_id"
UserMetadataColumnCreationDate = "creation_date"
@@ -23,7 +23,6 @@ const (
UserMetadataColumnInstanceID = "instance_id"
UserMetadataColumnKey = "key"
UserMetadataColumnValue = "value"
UserMetadataColumnOwnerRemoved = "owner_removed"
)
type userMetadataProjection struct{}
@@ -47,11 +46,9 @@ func (*userMetadataProjection) Init() *old_handler.Check {
handler.NewColumn(UserMetadataColumnInstanceID, handler.ColumnTypeText),
handler.NewColumn(UserMetadataColumnKey, handler.ColumnTypeText),
handler.NewColumn(UserMetadataColumnValue, handler.ColumnTypeBytes, handler.Nullable()),
handler.NewColumn(UserMetadataColumnOwnerRemoved, handler.ColumnTypeBool, handler.Default(false)),
},
handler.NewPrimaryKey(UserMetadataColumnInstanceID, UserMetadataColumnUserID, UserMetadataColumnKey),
handler.WithIndex(handler.NewIndex("resource_owner", []string{UserGrantResourceOwner})),
handler.WithIndex(handler.NewIndex("owner_removed", []string{UserMetadataColumnOwnerRemoved})),
),
)
}

View File

@@ -41,7 +41,7 @@ func TestUserMetadataProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
expectedStmt: "INSERT INTO projections.user_metadata4 (instance_id, user_id, key, resource_owner, creation_date, change_date, sequence, value) VALUES ($1, $2, $3, $4, $5, $6, $7, $8) ON CONFLICT (instance_id, user_id, key) DO UPDATE SET (resource_owner, creation_date, change_date, sequence, value) = (EXCLUDED.resource_owner, EXCLUDED.creation_date, EXCLUDED.change_date, EXCLUDED.sequence, EXCLUDED.value)",
expectedStmt: "INSERT INTO projections.user_metadata5 (instance_id, user_id, key, resource_owner, creation_date, change_date, sequence, value) VALUES ($1, $2, $3, $4, $5, $6, $7, $8) ON CONFLICT (instance_id, user_id, key) DO UPDATE SET (resource_owner, creation_date, change_date, sequence, value) = (EXCLUDED.resource_owner, EXCLUDED.creation_date, EXCLUDED.change_date, EXCLUDED.sequence, EXCLUDED.value)",
expectedArgs: []interface{}{
"instance-id",
"agg-id",
@@ -76,7 +76,7 @@ func TestUserMetadataProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
expectedStmt: "DELETE FROM projections.user_metadata4 WHERE (user_id = $1) AND (key = $2) AND (instance_id = $3)",
expectedStmt: "DELETE FROM projections.user_metadata5 WHERE (user_id = $1) AND (key = $2) AND (instance_id = $3)",
expectedArgs: []interface{}{
"agg-id",
"key",
@@ -104,7 +104,7 @@ func TestUserMetadataProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
expectedStmt: "DELETE FROM projections.user_metadata4 WHERE (user_id = $1) AND (instance_id = $2)",
expectedStmt: "DELETE FROM projections.user_metadata5 WHERE (user_id = $1) AND (instance_id = $2)",
expectedArgs: []interface{}{
"agg-id",
"instance-id",
@@ -131,7 +131,7 @@ func TestUserMetadataProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
expectedStmt: "DELETE FROM projections.user_metadata4 WHERE (user_id = $1) AND (instance_id = $2)",
expectedStmt: "DELETE FROM projections.user_metadata5 WHERE (user_id = $1) AND (instance_id = $2)",
expectedArgs: []interface{}{
"agg-id",
"instance-id",
@@ -158,7 +158,7 @@ func TestUserMetadataProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
expectedStmt: "DELETE FROM projections.user_metadata4 WHERE (instance_id = $1) AND (resource_owner = $2)",
expectedStmt: "DELETE FROM projections.user_metadata5 WHERE (instance_id = $1) AND (resource_owner = $2)",
expectedArgs: []interface{}{
"instance-id",
"agg-id",
@@ -185,7 +185,7 @@ func TestUserMetadataProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
expectedStmt: "DELETE FROM projections.user_metadata4 WHERE (instance_id = $1)",
expectedStmt: "DELETE FROM projections.user_metadata5 WHERE (instance_id = $1)",
expectedArgs: []interface{}{
"agg-id",
},

View File

@@ -50,7 +50,7 @@ func TestUserProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
expectedStmt: "INSERT INTO projections.users8 (id, creation_date, change_date, resource_owner, instance_id, state, sequence, username, type) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)",
expectedStmt: "INSERT INTO projections.users9 (id, creation_date, change_date, resource_owner, instance_id, state, sequence, username, type) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)",
expectedArgs: []interface{}{
"agg-id",
anyArg{},
@@ -64,7 +64,7 @@ func TestUserProjection_reduces(t *testing.T) {
},
},
{
expectedStmt: "INSERT INTO projections.users8_humans (user_id, instance_id, first_name, last_name, nick_name, display_name, preferred_language, gender, email, phone) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)",
expectedStmt: "INSERT INTO projections.users9_humans (user_id, instance_id, first_name, last_name, nick_name, display_name, preferred_language, gender, email, phone) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)",
expectedArgs: []interface{}{
"agg-id",
"instance-id",
@@ -79,7 +79,7 @@ func TestUserProjection_reduces(t *testing.T) {
},
},
{
expectedStmt: "INSERT INTO projections.users8_notifications (user_id, instance_id, last_email, last_phone, password_set) VALUES ($1, $2, $3, $4, $5)",
expectedStmt: "INSERT INTO projections.users9_notifications (user_id, instance_id, last_email, last_phone, password_set) VALUES ($1, $2, $3, $4, $5)",
expectedArgs: []interface{}{
"agg-id",
"instance-id",
@@ -119,7 +119,7 @@ func TestUserProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
expectedStmt: "INSERT INTO projections.users8 (id, creation_date, change_date, resource_owner, instance_id, state, sequence, username, type) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)",
expectedStmt: "INSERT INTO projections.users9 (id, creation_date, change_date, resource_owner, instance_id, state, sequence, username, type) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)",
expectedArgs: []interface{}{
"agg-id",
anyArg{},
@@ -133,7 +133,7 @@ func TestUserProjection_reduces(t *testing.T) {
},
},
{
expectedStmt: "INSERT INTO projections.users8_humans (user_id, instance_id, first_name, last_name, nick_name, display_name, preferred_language, gender, email, phone) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)",
expectedStmt: "INSERT INTO projections.users9_humans (user_id, instance_id, first_name, last_name, nick_name, display_name, preferred_language, gender, email, phone) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)",
expectedArgs: []interface{}{
"agg-id",
"instance-id",
@@ -148,7 +148,7 @@ func TestUserProjection_reduces(t *testing.T) {
},
},
{
expectedStmt: "INSERT INTO projections.users8_notifications (user_id, instance_id, last_email, last_phone, password_set) VALUES ($1, $2, $3, $4, $5)",
expectedStmt: "INSERT INTO projections.users9_notifications (user_id, instance_id, last_email, last_phone, password_set) VALUES ($1, $2, $3, $4, $5)",
expectedArgs: []interface{}{
"agg-id",
"instance-id",
@@ -183,7 +183,7 @@ func TestUserProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
expectedStmt: "INSERT INTO projections.users8 (id, creation_date, change_date, resource_owner, instance_id, state, sequence, username, type) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)",
expectedStmt: "INSERT INTO projections.users9 (id, creation_date, change_date, resource_owner, instance_id, state, sequence, username, type) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)",
expectedArgs: []interface{}{
"agg-id",
anyArg{},
@@ -197,7 +197,7 @@ func TestUserProjection_reduces(t *testing.T) {
},
},
{
expectedStmt: "INSERT INTO projections.users8_humans (user_id, instance_id, first_name, last_name, nick_name, display_name, preferred_language, gender, email, phone) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)",
expectedStmt: "INSERT INTO projections.users9_humans (user_id, instance_id, first_name, last_name, nick_name, display_name, preferred_language, gender, email, phone) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)",
expectedArgs: []interface{}{
"agg-id",
"instance-id",
@@ -212,7 +212,7 @@ func TestUserProjection_reduces(t *testing.T) {
},
},
{
expectedStmt: "INSERT INTO projections.users8_notifications (user_id, instance_id, last_email, last_phone, password_set) VALUES ($1, $2, $3, $4, $5)",
expectedStmt: "INSERT INTO projections.users9_notifications (user_id, instance_id, last_email, last_phone, password_set) VALUES ($1, $2, $3, $4, $5)",
expectedArgs: []interface{}{
"agg-id",
"instance-id",
@@ -252,7 +252,7 @@ func TestUserProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
expectedStmt: "INSERT INTO projections.users8 (id, creation_date, change_date, resource_owner, instance_id, state, sequence, username, type) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)",
expectedStmt: "INSERT INTO projections.users9 (id, creation_date, change_date, resource_owner, instance_id, state, sequence, username, type) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)",
expectedArgs: []interface{}{
"agg-id",
anyArg{},
@@ -266,7 +266,7 @@ func TestUserProjection_reduces(t *testing.T) {
},
},
{
expectedStmt: "INSERT INTO projections.users8_humans (user_id, instance_id, first_name, last_name, nick_name, display_name, preferred_language, gender, email, phone) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)",
expectedStmt: "INSERT INTO projections.users9_humans (user_id, instance_id, first_name, last_name, nick_name, display_name, preferred_language, gender, email, phone) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)",
expectedArgs: []interface{}{
"agg-id",
"instance-id",
@@ -281,7 +281,7 @@ func TestUserProjection_reduces(t *testing.T) {
},
},
{
expectedStmt: "INSERT INTO projections.users8_notifications (user_id, instance_id, last_email, last_phone, password_set) VALUES ($1, $2, $3, $4, $5)",
expectedStmt: "INSERT INTO projections.users9_notifications (user_id, instance_id, last_email, last_phone, password_set) VALUES ($1, $2, $3, $4, $5)",
expectedArgs: []interface{}{
"agg-id",
"instance-id",
@@ -321,7 +321,7 @@ func TestUserProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
expectedStmt: "INSERT INTO projections.users8 (id, creation_date, change_date, resource_owner, instance_id, state, sequence, username, type) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)",
expectedStmt: "INSERT INTO projections.users9 (id, creation_date, change_date, resource_owner, instance_id, state, sequence, username, type) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)",
expectedArgs: []interface{}{
"agg-id",
anyArg{},
@@ -335,7 +335,7 @@ func TestUserProjection_reduces(t *testing.T) {
},
},
{
expectedStmt: "INSERT INTO projections.users8_humans (user_id, instance_id, first_name, last_name, nick_name, display_name, preferred_language, gender, email, phone) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)",
expectedStmt: "INSERT INTO projections.users9_humans (user_id, instance_id, first_name, last_name, nick_name, display_name, preferred_language, gender, email, phone) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)",
expectedArgs: []interface{}{
"agg-id",
"instance-id",
@@ -350,7 +350,7 @@ func TestUserProjection_reduces(t *testing.T) {
},
},
{
expectedStmt: "INSERT INTO projections.users8_notifications (user_id, instance_id, last_email, last_phone, password_set) VALUES ($1, $2, $3, $4, $5)",
expectedStmt: "INSERT INTO projections.users9_notifications (user_id, instance_id, last_email, last_phone, password_set) VALUES ($1, $2, $3, $4, $5)",
expectedArgs: []interface{}{
"agg-id",
"instance-id",
@@ -385,7 +385,7 @@ func TestUserProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
expectedStmt: "INSERT INTO projections.users8 (id, creation_date, change_date, resource_owner, instance_id, state, sequence, username, type) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)",
expectedStmt: "INSERT INTO projections.users9 (id, creation_date, change_date, resource_owner, instance_id, state, sequence, username, type) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)",
expectedArgs: []interface{}{
"agg-id",
anyArg{},
@@ -399,7 +399,7 @@ func TestUserProjection_reduces(t *testing.T) {
},
},
{
expectedStmt: "INSERT INTO projections.users8_humans (user_id, instance_id, first_name, last_name, nick_name, display_name, preferred_language, gender, email, phone) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)",
expectedStmt: "INSERT INTO projections.users9_humans (user_id, instance_id, first_name, last_name, nick_name, display_name, preferred_language, gender, email, phone) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)",
expectedArgs: []interface{}{
"agg-id",
"instance-id",
@@ -414,7 +414,7 @@ func TestUserProjection_reduces(t *testing.T) {
},
},
{
expectedStmt: "INSERT INTO projections.users8_notifications (user_id, instance_id, last_email, last_phone, password_set) VALUES ($1, $2, $3, $4, $5)",
expectedStmt: "INSERT INTO projections.users9_notifications (user_id, instance_id, last_email, last_phone, password_set) VALUES ($1, $2, $3, $4, $5)",
expectedArgs: []interface{}{
"agg-id",
"instance-id",
@@ -444,7 +444,7 @@ func TestUserProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
expectedStmt: "UPDATE projections.users8 SET state = $1 WHERE (id = $2) AND (instance_id = $3)",
expectedStmt: "UPDATE projections.users9 SET state = $1 WHERE (id = $2) AND (instance_id = $3)",
expectedArgs: []interface{}{
domain.UserStateInitial,
"agg-id",
@@ -472,7 +472,7 @@ func TestUserProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
expectedStmt: "UPDATE projections.users8 SET state = $1 WHERE (id = $2) AND (instance_id = $3)",
expectedStmt: "UPDATE projections.users9 SET state = $1 WHERE (id = $2) AND (instance_id = $3)",
expectedArgs: []interface{}{
domain.UserStateInitial,
"agg-id",
@@ -500,7 +500,7 @@ func TestUserProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
expectedStmt: "UPDATE projections.users8 SET state = $1 WHERE (id = $2) AND (instance_id = $3)",
expectedStmt: "UPDATE projections.users9 SET state = $1 WHERE (id = $2) AND (instance_id = $3)",
expectedArgs: []interface{}{
domain.UserStateActive,
"agg-id",
@@ -528,7 +528,7 @@ func TestUserProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
expectedStmt: "UPDATE projections.users8 SET state = $1 WHERE (id = $2) AND (instance_id = $3)",
expectedStmt: "UPDATE projections.users9 SET state = $1 WHERE (id = $2) AND (instance_id = $3)",
expectedArgs: []interface{}{
domain.UserStateActive,
"agg-id",
@@ -556,7 +556,7 @@ func TestUserProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
expectedStmt: "UPDATE projections.users8 SET (change_date, state, sequence) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)",
expectedStmt: "UPDATE projections.users9 SET (change_date, state, sequence) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)",
expectedArgs: []interface{}{
anyArg{},
domain.UserStateLocked,
@@ -586,7 +586,7 @@ func TestUserProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
expectedStmt: "UPDATE projections.users8 SET (change_date, state, sequence) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)",
expectedStmt: "UPDATE projections.users9 SET (change_date, state, sequence) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)",
expectedArgs: []interface{}{
anyArg{},
domain.UserStateActive,
@@ -616,7 +616,7 @@ func TestUserProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
expectedStmt: "UPDATE projections.users8 SET (change_date, state, sequence) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)",
expectedStmt: "UPDATE projections.users9 SET (change_date, state, sequence) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)",
expectedArgs: []interface{}{
anyArg{},
domain.UserStateInactive,
@@ -646,7 +646,7 @@ func TestUserProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
expectedStmt: "UPDATE projections.users8 SET (change_date, state, sequence) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)",
expectedStmt: "UPDATE projections.users9 SET (change_date, state, sequence) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)",
expectedArgs: []interface{}{
anyArg{},
domain.UserStateActive,
@@ -676,7 +676,7 @@ func TestUserProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
expectedStmt: "DELETE FROM projections.users8 WHERE (id = $1) AND (instance_id = $2)",
expectedStmt: "DELETE FROM projections.users9 WHERE (id = $1) AND (instance_id = $2)",
expectedArgs: []interface{}{
"agg-id",
"instance-id",
@@ -705,7 +705,7 @@ func TestUserProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
expectedStmt: "UPDATE projections.users8 SET (change_date, username, sequence) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)",
expectedStmt: "UPDATE projections.users9 SET (change_date, username, sequence) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)",
expectedArgs: []interface{}{
anyArg{},
"username",
@@ -737,7 +737,7 @@ func TestUserProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
expectedStmt: "UPDATE projections.users8 SET (change_date, username, sequence) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)",
expectedStmt: "UPDATE projections.users9 SET (change_date, username, sequence) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)",
expectedArgs: []interface{}{
anyArg{},
"id@temporary.domain",
@@ -774,7 +774,7 @@ func TestUserProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
expectedStmt: "UPDATE projections.users8 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)",
expectedStmt: "UPDATE projections.users9 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)",
expectedArgs: []interface{}{
anyArg{},
uint64(15),
@@ -783,7 +783,7 @@ func TestUserProjection_reduces(t *testing.T) {
},
},
{
expectedStmt: "UPDATE projections.users8_humans SET (first_name, last_name, nick_name, display_name, preferred_language, gender) = ($1, $2, $3, $4, $5, $6) WHERE (user_id = $7) AND (instance_id = $8)",
expectedStmt: "UPDATE projections.users9_humans SET (first_name, last_name, nick_name, display_name, preferred_language, gender) = ($1, $2, $3, $4, $5, $6) WHERE (user_id = $7) AND (instance_id = $8)",
expectedArgs: []interface{}{
"first-name",
"last-name",
@@ -823,7 +823,7 @@ func TestUserProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
expectedStmt: "UPDATE projections.users8 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)",
expectedStmt: "UPDATE projections.users9 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)",
expectedArgs: []interface{}{
anyArg{},
uint64(15),
@@ -832,7 +832,7 @@ func TestUserProjection_reduces(t *testing.T) {
},
},
{
expectedStmt: "UPDATE projections.users8_humans SET (first_name, last_name, nick_name, display_name, preferred_language, gender) = ($1, $2, $3, $4, $5, $6) WHERE (user_id = $7) AND (instance_id = $8)",
expectedStmt: "UPDATE projections.users9_humans SET (first_name, last_name, nick_name, display_name, preferred_language, gender) = ($1, $2, $3, $4, $5, $6) WHERE (user_id = $7) AND (instance_id = $8)",
expectedArgs: []interface{}{
"first-name",
"last-name",
@@ -867,7 +867,7 @@ func TestUserProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
expectedStmt: "UPDATE projections.users8 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)",
expectedStmt: "UPDATE projections.users9 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)",
expectedArgs: []interface{}{
anyArg{},
uint64(15),
@@ -876,7 +876,7 @@ func TestUserProjection_reduces(t *testing.T) {
},
},
{
expectedStmt: "UPDATE projections.users8_humans SET (phone, is_phone_verified) = ($1, $2) WHERE (user_id = $3) AND (instance_id = $4)",
expectedStmt: "UPDATE projections.users9_humans SET (phone, is_phone_verified) = ($1, $2) WHERE (user_id = $3) AND (instance_id = $4)",
expectedArgs: []interface{}{
domain.PhoneNumber("+41 00 000 00 00"),
false,
@@ -885,7 +885,7 @@ func TestUserProjection_reduces(t *testing.T) {
},
},
{
expectedStmt: "UPDATE projections.users8_notifications SET last_phone = $1 WHERE (user_id = $2) AND (instance_id = $3)",
expectedStmt: "UPDATE projections.users9_notifications SET last_phone = $1 WHERE (user_id = $2) AND (instance_id = $3)",
expectedArgs: []interface{}{
&sql.NullString{String: "+41 00 000 00 00", Valid: true},
"agg-id",
@@ -915,7 +915,7 @@ func TestUserProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
expectedStmt: "UPDATE projections.users8 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)",
expectedStmt: "UPDATE projections.users9 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)",
expectedArgs: []interface{}{
anyArg{},
uint64(15),
@@ -924,7 +924,7 @@ func TestUserProjection_reduces(t *testing.T) {
},
},
{
expectedStmt: "UPDATE projections.users8_humans SET (phone, is_phone_verified) = ($1, $2) WHERE (user_id = $3) AND (instance_id = $4)",
expectedStmt: "UPDATE projections.users9_humans SET (phone, is_phone_verified) = ($1, $2) WHERE (user_id = $3) AND (instance_id = $4)",
expectedArgs: []interface{}{
domain.PhoneNumber("+41 00 000 00 00"),
false,
@@ -933,7 +933,7 @@ func TestUserProjection_reduces(t *testing.T) {
},
},
{
expectedStmt: "UPDATE projections.users8_notifications SET last_phone = $1 WHERE (user_id = $2) AND (instance_id = $3)",
expectedStmt: "UPDATE projections.users9_notifications SET last_phone = $1 WHERE (user_id = $2) AND (instance_id = $3)",
expectedArgs: []interface{}{
&sql.NullString{String: "+41 00 000 00 00", Valid: true},
"agg-id",
@@ -961,7 +961,7 @@ func TestUserProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
expectedStmt: "UPDATE projections.users8 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)",
expectedStmt: "UPDATE projections.users9 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)",
expectedArgs: []interface{}{
anyArg{},
uint64(15),
@@ -970,7 +970,7 @@ func TestUserProjection_reduces(t *testing.T) {
},
},
{
expectedStmt: "UPDATE projections.users8_humans SET (phone, is_phone_verified) = ($1, $2) WHERE (user_id = $3) AND (instance_id = $4)",
expectedStmt: "UPDATE projections.users9_humans SET (phone, is_phone_verified) = ($1, $2) WHERE (user_id = $3) AND (instance_id = $4)",
expectedArgs: []interface{}{
nil,
nil,
@@ -979,7 +979,7 @@ func TestUserProjection_reduces(t *testing.T) {
},
},
{
expectedStmt: "UPDATE projections.users8_notifications SET (last_phone, verified_phone) = ($1, $2) WHERE (user_id = $3) AND (instance_id = $4)",
expectedStmt: "UPDATE projections.users9_notifications SET (last_phone, verified_phone) = ($1, $2) WHERE (user_id = $3) AND (instance_id = $4)",
expectedArgs: []interface{}{
nil,
nil,
@@ -1008,7 +1008,7 @@ func TestUserProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
expectedStmt: "UPDATE projections.users8 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)",
expectedStmt: "UPDATE projections.users9 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)",
expectedArgs: []interface{}{
anyArg{},
uint64(15),
@@ -1017,7 +1017,7 @@ func TestUserProjection_reduces(t *testing.T) {
},
},
{
expectedStmt: "UPDATE projections.users8_humans SET (phone, is_phone_verified) = ($1, $2) WHERE (user_id = $3) AND (instance_id = $4)",
expectedStmt: "UPDATE projections.users9_humans SET (phone, is_phone_verified) = ($1, $2) WHERE (user_id = $3) AND (instance_id = $4)",
expectedArgs: []interface{}{
nil,
nil,
@@ -1026,7 +1026,7 @@ func TestUserProjection_reduces(t *testing.T) {
},
},
{
expectedStmt: "UPDATE projections.users8_notifications SET (last_phone, verified_phone) = ($1, $2) WHERE (user_id = $3) AND (instance_id = $4)",
expectedStmt: "UPDATE projections.users9_notifications SET (last_phone, verified_phone) = ($1, $2) WHERE (user_id = $3) AND (instance_id = $4)",
expectedArgs: []interface{}{
nil,
nil,
@@ -1055,7 +1055,7 @@ func TestUserProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
expectedStmt: "UPDATE projections.users8 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)",
expectedStmt: "UPDATE projections.users9 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)",
expectedArgs: []interface{}{
anyArg{},
uint64(15),
@@ -1064,7 +1064,7 @@ func TestUserProjection_reduces(t *testing.T) {
},
},
{
expectedStmt: "UPDATE projections.users8_humans SET is_phone_verified = $1 WHERE (user_id = $2) AND (instance_id = $3)",
expectedStmt: "UPDATE projections.users9_humans SET is_phone_verified = $1 WHERE (user_id = $2) AND (instance_id = $3)",
expectedArgs: []interface{}{
true,
"agg-id",
@@ -1072,7 +1072,7 @@ func TestUserProjection_reduces(t *testing.T) {
},
},
{
expectedStmt: "UPDATE projections.users8_notifications SET verified_phone = last_phone WHERE (user_id = $1) AND (instance_id = $2)",
expectedStmt: "UPDATE projections.users9_notifications SET verified_phone = last_phone WHERE (user_id = $1) AND (instance_id = $2)",
expectedArgs: []interface{}{
"agg-id",
"instance-id",
@@ -1099,7 +1099,7 @@ func TestUserProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
expectedStmt: "UPDATE projections.users8 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)",
expectedStmt: "UPDATE projections.users9 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)",
expectedArgs: []interface{}{
anyArg{},
uint64(15),
@@ -1108,7 +1108,7 @@ func TestUserProjection_reduces(t *testing.T) {
},
},
{
expectedStmt: "UPDATE projections.users8_humans SET is_phone_verified = $1 WHERE (user_id = $2) AND (instance_id = $3)",
expectedStmt: "UPDATE projections.users9_humans SET is_phone_verified = $1 WHERE (user_id = $2) AND (instance_id = $3)",
expectedArgs: []interface{}{
true,
"agg-id",
@@ -1116,7 +1116,7 @@ func TestUserProjection_reduces(t *testing.T) {
},
},
{
expectedStmt: "UPDATE projections.users8_notifications SET verified_phone = last_phone WHERE (user_id = $1) AND (instance_id = $2)",
expectedStmt: "UPDATE projections.users9_notifications SET verified_phone = last_phone WHERE (user_id = $1) AND (instance_id = $2)",
expectedArgs: []interface{}{
"agg-id",
"instance-id",
@@ -1145,7 +1145,7 @@ func TestUserProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
expectedStmt: "UPDATE projections.users8 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)",
expectedStmt: "UPDATE projections.users9 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)",
expectedArgs: []interface{}{
anyArg{},
uint64(15),
@@ -1154,7 +1154,7 @@ func TestUserProjection_reduces(t *testing.T) {
},
},
{
expectedStmt: "UPDATE projections.users8_humans SET (email, is_email_verified) = ($1, $2) WHERE (user_id = $3) AND (instance_id = $4)",
expectedStmt: "UPDATE projections.users9_humans SET (email, is_email_verified) = ($1, $2) WHERE (user_id = $3) AND (instance_id = $4)",
expectedArgs: []interface{}{
domain.EmailAddress("email@zitadel.com"),
false,
@@ -1163,7 +1163,7 @@ func TestUserProjection_reduces(t *testing.T) {
},
},
{
expectedStmt: "UPDATE projections.users8_notifications SET last_email = $1 WHERE (user_id = $2) AND (instance_id = $3)",
expectedStmt: "UPDATE projections.users9_notifications SET last_email = $1 WHERE (user_id = $2) AND (instance_id = $3)",
expectedArgs: []interface{}{
&sql.NullString{String: "email@zitadel.com", Valid: true},
"agg-id",
@@ -1193,7 +1193,7 @@ func TestUserProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
expectedStmt: "UPDATE projections.users8 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)",
expectedStmt: "UPDATE projections.users9 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)",
expectedArgs: []interface{}{
anyArg{},
uint64(15),
@@ -1202,7 +1202,7 @@ func TestUserProjection_reduces(t *testing.T) {
},
},
{
expectedStmt: "UPDATE projections.users8_humans SET (email, is_email_verified) = ($1, $2) WHERE (user_id = $3) AND (instance_id = $4)",
expectedStmt: "UPDATE projections.users9_humans SET (email, is_email_verified) = ($1, $2) WHERE (user_id = $3) AND (instance_id = $4)",
expectedArgs: []interface{}{
domain.EmailAddress("email@zitadel.com"),
false,
@@ -1211,7 +1211,7 @@ func TestUserProjection_reduces(t *testing.T) {
},
},
{
expectedStmt: "UPDATE projections.users8_notifications SET last_email = $1 WHERE (user_id = $2) AND (instance_id = $3)",
expectedStmt: "UPDATE projections.users9_notifications SET last_email = $1 WHERE (user_id = $2) AND (instance_id = $3)",
expectedArgs: []interface{}{
&sql.NullString{String: "email@zitadel.com", Valid: true},
"agg-id",
@@ -1239,7 +1239,7 @@ func TestUserProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
expectedStmt: "UPDATE projections.users8 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)",
expectedStmt: "UPDATE projections.users9 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)",
expectedArgs: []interface{}{
anyArg{},
uint64(15),
@@ -1248,7 +1248,7 @@ func TestUserProjection_reduces(t *testing.T) {
},
},
{
expectedStmt: "UPDATE projections.users8_humans SET is_email_verified = $1 WHERE (user_id = $2) AND (instance_id = $3)",
expectedStmt: "UPDATE projections.users9_humans SET is_email_verified = $1 WHERE (user_id = $2) AND (instance_id = $3)",
expectedArgs: []interface{}{
true,
"agg-id",
@@ -1256,7 +1256,7 @@ func TestUserProjection_reduces(t *testing.T) {
},
},
{
expectedStmt: "UPDATE projections.users8_notifications SET verified_email = last_email WHERE (user_id = $1) AND (instance_id = $2)",
expectedStmt: "UPDATE projections.users9_notifications SET verified_email = last_email WHERE (user_id = $1) AND (instance_id = $2)",
expectedArgs: []interface{}{
"agg-id",
"instance-id",
@@ -1283,7 +1283,7 @@ func TestUserProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
expectedStmt: "UPDATE projections.users8 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)",
expectedStmt: "UPDATE projections.users9 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)",
expectedArgs: []interface{}{
anyArg{},
uint64(15),
@@ -1292,7 +1292,7 @@ func TestUserProjection_reduces(t *testing.T) {
},
},
{
expectedStmt: "UPDATE projections.users8_humans SET is_email_verified = $1 WHERE (user_id = $2) AND (instance_id = $3)",
expectedStmt: "UPDATE projections.users9_humans SET is_email_verified = $1 WHERE (user_id = $2) AND (instance_id = $3)",
expectedArgs: []interface{}{
true,
"agg-id",
@@ -1300,7 +1300,7 @@ func TestUserProjection_reduces(t *testing.T) {
},
},
{
expectedStmt: "UPDATE projections.users8_notifications SET verified_email = last_email WHERE (user_id = $1) AND (instance_id = $2)",
expectedStmt: "UPDATE projections.users9_notifications SET verified_email = last_email WHERE (user_id = $1) AND (instance_id = $2)",
expectedArgs: []interface{}{
"agg-id",
"instance-id",
@@ -1329,7 +1329,7 @@ func TestUserProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
expectedStmt: "UPDATE projections.users8 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)",
expectedStmt: "UPDATE projections.users9 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)",
expectedArgs: []interface{}{
anyArg{},
uint64(15),
@@ -1338,7 +1338,7 @@ func TestUserProjection_reduces(t *testing.T) {
},
},
{
expectedStmt: "UPDATE projections.users8_humans SET avatar_key = $1 WHERE (user_id = $2) AND (instance_id = $3)",
expectedStmt: "UPDATE projections.users9_humans SET avatar_key = $1 WHERE (user_id = $2) AND (instance_id = $3)",
expectedArgs: []interface{}{
"users/agg-id/avatar",
"agg-id",
@@ -1366,7 +1366,7 @@ func TestUserProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
expectedStmt: "UPDATE projections.users8 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)",
expectedStmt: "UPDATE projections.users9 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)",
expectedArgs: []interface{}{
anyArg{},
uint64(15),
@@ -1375,7 +1375,7 @@ func TestUserProjection_reduces(t *testing.T) {
},
},
{
expectedStmt: "UPDATE projections.users8_humans SET avatar_key = $1 WHERE (user_id = $2) AND (instance_id = $3)",
expectedStmt: "UPDATE projections.users9_humans SET avatar_key = $1 WHERE (user_id = $2) AND (instance_id = $3)",
expectedArgs: []interface{}{
nil,
"agg-id",
@@ -1406,7 +1406,7 @@ func TestUserProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
expectedStmt: "INSERT INTO projections.users8 (id, creation_date, change_date, resource_owner, instance_id, state, sequence, username, type) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)",
expectedStmt: "INSERT INTO projections.users9 (id, creation_date, change_date, resource_owner, instance_id, state, sequence, username, type) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)",
expectedArgs: []interface{}{
"agg-id",
anyArg{},
@@ -1420,7 +1420,7 @@ func TestUserProjection_reduces(t *testing.T) {
},
},
{
expectedStmt: "INSERT INTO projections.users8_machines (user_id, instance_id, name, description, access_token_type) VALUES ($1, $2, $3, $4, $5)",
expectedStmt: "INSERT INTO projections.users9_machines (user_id, instance_id, name, description, access_token_type) VALUES ($1, $2, $3, $4, $5)",
expectedArgs: []interface{}{
"agg-id",
"instance-id",
@@ -1454,7 +1454,7 @@ func TestUserProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
expectedStmt: "INSERT INTO projections.users8 (id, creation_date, change_date, resource_owner, instance_id, state, sequence, username, type) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)",
expectedStmt: "INSERT INTO projections.users9 (id, creation_date, change_date, resource_owner, instance_id, state, sequence, username, type) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)",
expectedArgs: []interface{}{
"agg-id",
anyArg{},
@@ -1468,7 +1468,7 @@ func TestUserProjection_reduces(t *testing.T) {
},
},
{
expectedStmt: "INSERT INTO projections.users8_machines (user_id, instance_id, name, description, access_token_type) VALUES ($1, $2, $3, $4, $5)",
expectedStmt: "INSERT INTO projections.users9_machines (user_id, instance_id, name, description, access_token_type) VALUES ($1, $2, $3, $4, $5)",
expectedArgs: []interface{}{
"agg-id",
"instance-id",
@@ -1501,7 +1501,7 @@ func TestUserProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
expectedStmt: "UPDATE projections.users8 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)",
expectedStmt: "UPDATE projections.users9 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)",
expectedArgs: []interface{}{
anyArg{},
uint64(15),
@@ -1510,7 +1510,7 @@ func TestUserProjection_reduces(t *testing.T) {
},
},
{
expectedStmt: "UPDATE projections.users8_machines SET (name, description) = ($1, $2) WHERE (user_id = $3) AND (instance_id = $4)",
expectedStmt: "UPDATE projections.users9_machines SET (name, description) = ($1, $2) WHERE (user_id = $3) AND (instance_id = $4)",
expectedArgs: []interface{}{
"machine-name",
"description",
@@ -1541,7 +1541,7 @@ func TestUserProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
expectedStmt: "UPDATE projections.users8 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)",
expectedStmt: "UPDATE projections.users9 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)",
expectedArgs: []interface{}{
anyArg{},
uint64(15),
@@ -1550,7 +1550,7 @@ func TestUserProjection_reduces(t *testing.T) {
},
},
{
expectedStmt: "UPDATE projections.users8_machines SET name = $1 WHERE (user_id = $2) AND (instance_id = $3)",
expectedStmt: "UPDATE projections.users9_machines SET name = $1 WHERE (user_id = $2) AND (instance_id = $3)",
expectedArgs: []interface{}{
"machine-name",
"agg-id",
@@ -1580,7 +1580,7 @@ func TestUserProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
expectedStmt: "UPDATE projections.users8 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)",
expectedStmt: "UPDATE projections.users9 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)",
expectedArgs: []interface{}{
anyArg{},
uint64(15),
@@ -1589,7 +1589,7 @@ func TestUserProjection_reduces(t *testing.T) {
},
},
{
expectedStmt: "UPDATE projections.users8_machines SET description = $1 WHERE (user_id = $2) AND (instance_id = $3)",
expectedStmt: "UPDATE projections.users9_machines SET description = $1 WHERE (user_id = $2) AND (instance_id = $3)",
expectedArgs: []interface{}{
"description",
"agg-id",
@@ -1638,7 +1638,7 @@ func TestUserProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
expectedStmt: "UPDATE projections.users8 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)",
expectedStmt: "UPDATE projections.users9 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)",
expectedArgs: []interface{}{
anyArg{},
uint64(15),
@@ -1647,7 +1647,7 @@ func TestUserProjection_reduces(t *testing.T) {
},
},
{
expectedStmt: "UPDATE projections.users8_machines SET has_secret = $1 WHERE (user_id = $2) AND (instance_id = $3)",
expectedStmt: "UPDATE projections.users9_machines SET has_secret = $1 WHERE (user_id = $2) AND (instance_id = $3)",
expectedArgs: []interface{}{
true,
"agg-id",
@@ -1675,7 +1675,7 @@ func TestUserProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
expectedStmt: "UPDATE projections.users8 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)",
expectedStmt: "UPDATE projections.users9 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)",
expectedArgs: []interface{}{
anyArg{},
uint64(15),
@@ -1684,7 +1684,7 @@ func TestUserProjection_reduces(t *testing.T) {
},
},
{
expectedStmt: "UPDATE projections.users8_machines SET has_secret = $1 WHERE (user_id = $2) AND (instance_id = $3)",
expectedStmt: "UPDATE projections.users9_machines SET has_secret = $1 WHERE (user_id = $2) AND (instance_id = $3)",
expectedArgs: []interface{}{
false,
"agg-id",
@@ -1712,7 +1712,7 @@ func TestUserProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
expectedStmt: "DELETE FROM projections.users8 WHERE (instance_id = $1) AND (resource_owner = $2)",
expectedStmt: "DELETE FROM projections.users9 WHERE (instance_id = $1) AND (resource_owner = $2)",
expectedArgs: []interface{}{
"instance-id",
"agg-id",
@@ -1739,7 +1739,7 @@ func TestUserProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
expectedStmt: "DELETE FROM projections.users8 WHERE (instance_id = $1)",
expectedStmt: "DELETE FROM projections.users9 WHERE (instance_id = $1)",
expectedArgs: []interface{}{
"agg-id",
},

View File

@@ -9,15 +9,16 @@ import (
"time"
"github.com/rakyll/statik/fs"
"github.com/zitadel/logging"
"golang.org/x/text/language"
"github.com/zitadel/zitadel/internal/api/authz"
internal_authz "github.com/zitadel/zitadel/internal/api/authz"
sd "github.com/zitadel/zitadel/internal/config/systemdefaults"
"github.com/zitadel/zitadel/internal/crypto"
"github.com/zitadel/zitadel/internal/database"
"github.com/zitadel/zitadel/internal/domain"
"github.com/zitadel/zitadel/internal/eventstore"
"github.com/zitadel/zitadel/internal/eventstore/handler/v2"
"github.com/zitadel/zitadel/internal/query/projection"
"github.com/zitadel/zitadel/internal/repository/action"
"github.com/zitadel/zitadel/internal/repository/authrequest"
@@ -32,15 +33,17 @@ import (
"github.com/zitadel/zitadel/internal/repository/session"
usr_repo "github.com/zitadel/zitadel/internal/repository/user"
"github.com/zitadel/zitadel/internal/repository/usergrant"
"github.com/zitadel/zitadel/internal/telemetry/tracing"
)
type Queries struct {
eventstore *eventstore.Eventstore
client *database.DB
idpConfigEncryption crypto.EncryptionAlgorithm
sessionTokenVerifier func(ctx context.Context, sessionToken string, sessionID string, tokenID string) (err error)
checkPermission domain.PermissionCheck
keyEncryptionAlgorithm crypto.EncryptionAlgorithm
idpConfigEncryption crypto.EncryptionAlgorithm
sessionTokenVerifier func(ctx context.Context, sessionToken string, sessionID string, tokenID string) (err error)
checkPermission domain.PermissionCheck
DefaultLanguage language.Tag
LoginDir http.FileSystem
@@ -65,7 +68,7 @@ func StartQueries(
sessionTokenVerifier func(ctx context.Context, sessionToken string, sessionID string, tokenID string) (err error),
permissionCheck func(q *Queries) domain.PermissionCheck,
defaultAuditLogRetention time.Duration,
systemAPIUsers map[string]*internal_authz.SystemAPIUser,
systemAPIUsers map[string]*authz.SystemAPIUser,
) (repo *Queries, err error) {
statikLoginFS, err := fs.NewWithNamespace("login")
if err != nil {
@@ -86,8 +89,16 @@ func StartQueries(
LoginTranslationFileContents: make(map[string][]byte),
NotificationTranslationFileContents: make(map[string][]byte),
zitadelRoles: zitadelRoles,
keyEncryptionAlgorithm: keyEncryptionAlgorithm,
idpConfigEncryption: idpConfigEncryption,
sessionTokenVerifier: sessionTokenVerifier,
defaultAuditLogRetention: defaultAuditLogRetention,
multifactors: domain.MultifactorConfigs{
OTP: domain.OTPConfig{
CryptoMFA: otpEncryption,
Issuer: defaults.Multifactors.OTP.Issuer,
},
},
defaultAuditLogRetention: defaultAuditLogRetention,
}
iam_repo.RegisterEventMappers(repo.eventstore)
usr_repo.RegisterEventMappers(repo.eventstore)
@@ -103,14 +114,6 @@ func StartQueries(
quota.RegisterEventMappers(repo.eventstore)
limits.RegisterEventMappers(repo.eventstore)
repo.idpConfigEncryption = idpConfigEncryption
repo.multifactors = domain.MultifactorConfigs{
OTP: domain.OTPConfig{
CryptoMFA: otpEncryption,
Issuer: defaults.Multifactors.OTP.Issuer,
},
}
repo.checkPermission = permissionCheck(repo)
err = projection.Create(ctx, sqlClient, es, projections, keyEncryptionAlgorithm, certEncryptionAlgorithm, systemAPIUsers)
@@ -145,3 +148,24 @@ func init() {
&authRequestByIDQuery,
)
}
// triggerBatch calls Trigger on every handler in a separate Go routine.
// The returned context is the context returned by the Trigger that finishes last.
func triggerBatch(ctx context.Context, handlers ...*handler.Handler) {
var wg sync.WaitGroup
wg.Add(len(handlers))
for _, h := range handlers {
go func(ctx context.Context, h *handler.Handler) {
name := h.ProjectionName()
_, traceSpan := tracing.NewNamedSpan(ctx, fmt.Sprintf("Trigger%s", name))
_, err := h.Trigger(ctx, handler.WithAwaitRunning())
logging.OnError(err).WithField("projection", name).Debug("trigger failed")
traceSpan.EndWithError(err)
wg.Done()
}(ctx, h)
}
wg.Wait()
}

View File

@@ -1,11 +1,92 @@
package query
import (
"database/sql"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/zitadel/zitadel/internal/eventstore"
"github.com/zitadel/zitadel/internal/eventstore/repository"
"github.com/zitadel/zitadel/internal/eventstore/repository/mock"
action_repo "github.com/zitadel/zitadel/internal/repository/action"
"github.com/zitadel/zitadel/internal/repository/authrequest"
"github.com/zitadel/zitadel/internal/repository/feature"
"github.com/zitadel/zitadel/internal/repository/idpintent"
iam_repo "github.com/zitadel/zitadel/internal/repository/instance"
key_repo "github.com/zitadel/zitadel/internal/repository/keypair"
"github.com/zitadel/zitadel/internal/repository/limits"
"github.com/zitadel/zitadel/internal/repository/oidcsession"
"github.com/zitadel/zitadel/internal/repository/org"
proj_repo "github.com/zitadel/zitadel/internal/repository/project"
quota_repo "github.com/zitadel/zitadel/internal/repository/quota"
"github.com/zitadel/zitadel/internal/repository/session"
usr_repo "github.com/zitadel/zitadel/internal/repository/user"
"github.com/zitadel/zitadel/internal/repository/usergrant"
)
type expect func(mockRepository *mock.MockRepository)
func expectEventstore(expects ...expect) func(*testing.T) *eventstore.Eventstore {
return func(t *testing.T) *eventstore.Eventstore {
m := mock.NewRepo(t)
for _, e := range expects {
e(m)
}
es := eventstore.NewEventstore(
&eventstore.Config{
Querier: m.MockQuerier,
Pusher: m.MockPusher,
},
)
iam_repo.RegisterEventMappers(es)
org.RegisterEventMappers(es)
usr_repo.RegisterEventMappers(es)
proj_repo.RegisterEventMappers(es)
usergrant.RegisterEventMappers(es)
key_repo.RegisterEventMappers(es)
action_repo.RegisterEventMappers(es)
session.RegisterEventMappers(es)
idpintent.RegisterEventMappers(es)
authrequest.RegisterEventMappers(es)
oidcsession.RegisterEventMappers(es)
quota_repo.RegisterEventMappers(es)
limits.RegisterEventMappers(es)
feature.RegisterEventMappers(es)
return es
}
}
func expectFilter(events ...eventstore.Event) expect {
return func(m *mock.MockRepository) {
m.ExpectFilterEvents(events...)
}
}
func expectFilterError(err error) expect {
return func(m *mock.MockRepository) {
m.ExpectFilterEventsError(err)
}
}
func eventFromEventPusher(event eventstore.Command) *repository.Event {
data, _ := eventstore.EventData(event)
return &repository.Event{
InstanceID: event.Aggregate().InstanceID,
ID: "",
Seq: 0,
CreationDate: time.Time{},
Typ: event.Type(),
Data: data,
EditorUser: event.Creator(),
Version: event.Aggregate().Version,
AggregateID: event.Aggregate().ID,
AggregateType: event.Aggregate().Type,
ResourceOwner: sql.NullString{String: event.Aggregate().ResourceOwner, Valid: event.Aggregate().ResourceOwner != ""},
Constraints: event.UniqueConstraints(),
}
}
func Test_cleanStaticQueries(t *testing.T) {
query := `select
foo,

View File

@@ -31,7 +31,7 @@ var (
` projections.sessions8.user_resource_owner,` +
` projections.sessions8.user_checked_at,` +
` projections.login_names3.login_name,` +
` projections.users8_humans.display_name,` +
` projections.users9_humans.display_name,` +
` projections.sessions8.password_checked_at,` +
` projections.sessions8.intent_checked_at,` +
` projections.sessions8.webauthn_checked_at,` +
@@ -48,8 +48,8 @@ var (
` projections.sessions8.expiration` +
` FROM projections.sessions8` +
` LEFT JOIN projections.login_names3 ON projections.sessions8.user_id = projections.login_names3.user_id AND projections.sessions8.instance_id = projections.login_names3.instance_id` +
` LEFT JOIN projections.users8_humans ON projections.sessions8.user_id = projections.users8_humans.user_id AND projections.sessions8.instance_id = projections.users8_humans.instance_id` +
` LEFT JOIN projections.users8 ON projections.sessions8.user_id = projections.users8.id AND projections.sessions8.instance_id = projections.users8.instance_id` +
` LEFT JOIN projections.users9_humans ON projections.sessions8.user_id = projections.users9_humans.user_id AND projections.sessions8.instance_id = projections.users9_humans.instance_id` +
` LEFT JOIN projections.users9 ON projections.sessions8.user_id = projections.users9.id AND projections.sessions8.instance_id = projections.users9.instance_id` +
` AS OF SYSTEM TIME '-1 ms'`)
expectedSessionsQuery = regexp.QuoteMeta(`SELECT projections.sessions8.id,` +
` projections.sessions8.creation_date,` +
@@ -62,7 +62,7 @@ var (
` projections.sessions8.user_resource_owner,` +
` projections.sessions8.user_checked_at,` +
` projections.login_names3.login_name,` +
` projections.users8_humans.display_name,` +
` projections.users9_humans.display_name,` +
` projections.sessions8.password_checked_at,` +
` projections.sessions8.intent_checked_at,` +
` projections.sessions8.webauthn_checked_at,` +
@@ -75,8 +75,8 @@ var (
` COUNT(*) OVER ()` +
` FROM projections.sessions8` +
` LEFT JOIN projections.login_names3 ON projections.sessions8.user_id = projections.login_names3.user_id AND projections.sessions8.instance_id = projections.login_names3.instance_id` +
` LEFT JOIN projections.users8_humans ON projections.sessions8.user_id = projections.users8_humans.user_id AND projections.sessions8.instance_id = projections.users8_humans.instance_id` +
` LEFT JOIN projections.users8 ON projections.sessions8.user_id = projections.users8.id AND projections.sessions8.instance_id = projections.users8.instance_id` +
` LEFT JOIN projections.users9_humans ON projections.sessions8.user_id = projections.users9_humans.user_id AND projections.sessions8.instance_id = projections.users9_humans.instance_id` +
` LEFT JOIN projections.users9 ON projections.sessions8.user_id = projections.users9.id AND projections.sessions8.instance_id = projections.users9.instance_id` +
` AS OF SYSTEM TIME '-1 ms'`)
sessionCols = []string{

View File

@@ -0,0 +1,47 @@
{
"user": {
"id": "231965491734773762",
"creation_date": "2023-09-15T06:10:07.434142+00:00",
"change_date": "2023-11-14T13:27:02.072318+00:00",
"sequence": 1148,
"state": 1,
"resource_owner": "231848297847848962",
"username": "tim+tesmail@zitadel.com",
"preferred_login_name": "tim+tesmail@zitadel.com@demo.localhost",
"human": {
"first_name": "Tim",
"last_name": "Mohlmann",
"nick_name": "muhlemmer",
"display_name": "Tim Mohlmann",
"avatar_key": null,
"email": "tim+tesmail@zitadel.com",
"is_email_verified": true,
"phone": "+40123456789",
"is_phone_verified": false
},
"machine": null
},
"org": {
"name": "demo",
"primary_domain": "demo.localhost"
},
"metadata": [
{
"creation_date": "2023-11-14T13:26:03.553702+00:00",
"change_date": "2023-11-14T13:26:03.553702+00:00",
"sequence": 1147,
"resource_owner": "231848297847848962",
"key": "bar",
"value": "Zm9v"
},
{
"creation_date": "2023-11-14T13:25:57.171368+00:00",
"change_date": "2023-11-14T13:25:57.171368+00:00",
"sequence": 1146,
"resource_owner": "231848297847848962",
"key": "foo",
"value": "YmFy"
}
],
"user_grants": null
}

View File

@@ -0,0 +1,86 @@
{
"user": {
"id": "231965491734773762",
"creation_date": "2023-09-15T06:10:07.434142+00:00",
"change_date": "2023-11-14T13:27:02.072318+00:00",
"sequence": 1148,
"state": 1,
"resource_owner": "231848297847848962",
"username": "tim+tesmail@zitadel.com",
"preferred_login_name": "tim+tesmail@zitadel.com@demo.localhost",
"human": {
"first_name": "Tim",
"last_name": "Mohlmann",
"nick_name": "muhlemmer",
"display_name": "Tim Mohlmann",
"avatar_key": null,
"email": "tim+tesmail@zitadel.com",
"is_email_verified": true,
"phone": "+40123456789",
"is_phone_verified": false
},
"machine": null
},
"org": {
"name": "demo",
"primary_domain": "demo.localhost"
},
"metadata": [
{
"creation_date": "2023-11-14T13:26:03.553702+00:00",
"change_date": "2023-11-14T13:26:03.553702+00:00",
"sequence": 1147,
"resource_owner": "231848297847848962",
"key": "bar",
"value": "Zm9v"
},
{
"creation_date": "2023-11-14T13:25:57.171368+00:00",
"change_date": "2023-11-14T13:25:57.171368+00:00",
"sequence": 1146,
"resource_owner": "231848297847848962",
"key": "foo",
"value": "YmFy"
}
],
"user_grants": [
{
"id": "240749256523120642",
"grant_id": "",
"state": 1,
"creation_date": "2023-11-14T20:28:59.168208+00:00",
"change_date": "2023-11-14T20:50:58.822391+00:00",
"sequence": 2,
"user_id": "231965491734773762",
"roles": [
"role1",
"role2"
],
"resource_owner": "231848297847848962",
"project_id": "236645808328409090",
"org_name": "demo",
"org_primary_domain": "demo.localhost",
"project_name": "tests",
"user_resource_owner": "231848297847848962"
},
{
"id": "240762315572510722",
"grant_id": "",
"state": 1,
"creation_date": "2023-11-14T22:38:42.967317+00:00",
"change_date": "2023-11-14T22:38:42.967317+00:00",
"sequence": 1,
"user_id": "231965491734773762",
"roles": [
"role3",
"role4"
],
"resource_owner": "231848297847848962",
"project_id": "240762134579904514",
"org_name": "demo",
"org_primary_domain": "demo.localhost",
"project_name": "tests2",
"user_resource_owner": "231848297847848962"
}
]
}

View File

@@ -0,0 +1,30 @@
{
"user": {
"id": "231965491734773762",
"creation_date": "2023-09-15T06:10:07.434142+00:00",
"change_date": "2023-11-14T13:27:02.072318+00:00",
"sequence": 1148,
"state": 1,
"resource_owner": "231848297847848962",
"username": "tim+tesmail@zitadel.com",
"preferred_login_name": "tim+tesmail@zitadel.com@demo.localhost",
"human": {
"first_name": "Tim",
"last_name": "Mohlmann",
"nick_name": "muhlemmer",
"display_name": "Tim Mohlmann",
"avatar_key": null,
"email": "tim+tesmail@zitadel.com",
"is_email_verified": true,
"phone": "+40123456789",
"is_phone_verified": false
},
"machine": null
},
"org": {
"name": "demo",
"primary_domain": "demo.localhost"
},
"metadata": null,
"user_grants": null
}

View File

@@ -0,0 +1,40 @@
{
"user": {
"id": "240707570677841922",
"creation_date": "2023-11-14T13:34:52.473732+00:00",
"change_date": "2023-11-14T13:35:02.861342+00:00",
"sequence": 2,
"state": 1,
"resource_owner": "231848297847848962",
"username": "tests",
"preferred_login_name": "tests@demo.localhost",
"human": null,
"machine": {
"name": "tests",
"description": "My test service user"
}
},
"org": {
"name": "demo",
"primary_domain": "demo.localhost"
},
"metadata": [
{
"creation_date": "2023-11-14T13:35:30.126849+00:00",
"change_date": "2023-11-14T13:35:30.126849+00:00",
"sequence": 3,
"resource_owner": "231848297847848962",
"key": "first",
"value": "SGVsbG8gV29ybGQh"
},
{
"creation_date": "2023-11-14T13:35:44.028343+00:00",
"change_date": "2023-11-14T13:35:44.028343+00:00",
"sequence": 4,
"resource_owner": "231848297847848962",
"key": "second",
"value": "QnllIFdvcmxkIQ=="
}
],
"user_grants": null
}

View File

@@ -0,0 +1,6 @@
{
"user": null,
"org": null,
"metadata": null,
"user_grants": null
}

View File

@@ -5,11 +5,9 @@ import (
"database/sql"
errs "errors"
"strings"
"sync"
"time"
sq "github.com/Masterminds/squirrel"
"github.com/zitadel/logging"
"golang.org/x/text/language"
"github.com/zitadel/zitadel/internal/api/authz"
@@ -17,7 +15,6 @@ import (
"github.com/zitadel/zitadel/internal/database"
"github.com/zitadel/zitadel/internal/domain"
"github.com/zitadel/zitadel/internal/errors"
"github.com/zitadel/zitadel/internal/eventstore/handler/v2"
"github.com/zitadel/zitadel/internal/query/projection"
"github.com/zitadel/zitadel/internal/telemetry/tracing"
)
@@ -28,32 +25,32 @@ type Users struct {
}
type User struct {
ID string
CreationDate time.Time
ChangeDate time.Time
ResourceOwner string
Sequence uint64
State domain.UserState
Type domain.UserType
Username string
LoginNames database.TextArray[string]
PreferredLoginName string
Human *Human
Machine *Machine
ID string `json:"id,omitempty"`
CreationDate time.Time `json:"creation_date,omitempty"`
ChangeDate time.Time `json:"change_date,omitempty"`
ResourceOwner string `json:"resource_owner,omitempty"`
Sequence uint64 `json:"sequence,omitempty"`
State domain.UserState `json:"state,omitempty"`
Type domain.UserType `json:"type,omitempty"`
Username string `json:"username,omitempty"`
LoginNames database.TextArray[string] `json:"login_names,omitempty"`
PreferredLoginName string `json:"preferred_login_name,omitempty"`
Human *Human `json:"human,omitempty"`
Machine *Machine `json:"machine,omitempty"`
}
type Human struct {
FirstName string
LastName string
NickName string
DisplayName string
AvatarKey string
PreferredLanguage language.Tag
Gender domain.Gender
Email domain.EmailAddress
IsEmailVerified bool
Phone domain.PhoneNumber
IsPhoneVerified bool
FirstName string `json:"first_name,omitempty"`
LastName string `json:"last_name,omitempty"`
NickName string `json:"nick_name,omitempty"`
DisplayName string `json:"display_name,omitempty"`
AvatarKey string `json:"avatar_key,omitempty"`
PreferredLanguage language.Tag `json:"preferred_language,omitempty"`
Gender domain.Gender `json:"gender,omitempty"`
Email domain.EmailAddress `json:"email,omitempty"`
IsEmailVerified bool `json:"is_email_verified,omitempty"`
Phone domain.PhoneNumber `json:"phone,omitempty"`
IsPhoneVerified bool `json:"is_phone_verified,omitempty"`
}
type Profile struct {
@@ -92,10 +89,10 @@ type Phone struct {
}
type Machine struct {
Name string
Description string
HasSecret bool
AccessTokenType domain.OIDCTokenType
Name string `json:"name,omitempty"`
Description string `json:"description,omitempty"`
HasSecret bool `json:"has_secret,omitempty"`
AccessTokenType domain.OIDCTokenType `json:"access_token_type,omitempty"`
}
type NotifyUser struct {
@@ -170,10 +167,6 @@ var (
name: projection.UserTypeCol,
table: userTable,
}
UserOwnerRemovedCol = Column{
name: projection.UserOwnerRemovedCol,
table: userTable,
}
userLoginNamesTable = loginNameTable.setAlias("login_names")
userLoginNamesUserIDCol = LoginNameUserIDCol.setTable(userLoginNamesTable)
@@ -320,11 +313,7 @@ var (
}
)
func addUserWithoutOwnerRemoved(eq map[string]interface{}) {
eq[UserOwnerRemovedCol.identifier()] = false
}
func (q *Queries) GetUserByID(ctx context.Context, shouldTriggerBulk bool, userID string, withOwnerRemoved bool, queries ...SearchQuery) (user *User, err error) {
func (q *Queries) GetUserByID(ctx context.Context, shouldTriggerBulk bool, userID string, queries ...SearchQuery) (user *User, err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }()
@@ -340,9 +329,6 @@ func (q *Queries) GetUserByID(ctx context.Context, shouldTriggerBulk bool, userI
UserIDCol.identifier(): userID,
UserInstanceIDCol.identifier(): authz.GetInstance(ctx).InstanceID(),
}
if !withOwnerRemoved {
addUserWithoutOwnerRemoved(eq)
}
stmt, args, err := query.Where(eq).ToSql()
if err != nil {
return nil, errors.ThrowInternal(err, "QUERY-FBg21", "Errors.Query.SQLStatment")
@@ -355,7 +341,7 @@ func (q *Queries) GetUserByID(ctx context.Context, shouldTriggerBulk bool, userI
return user, err
}
func (q *Queries) GetUser(ctx context.Context, shouldTriggerBulk bool, withOwnerRemoved bool, queries ...SearchQuery) (user *User, err error) {
func (q *Queries) GetUser(ctx context.Context, shouldTriggerBulk bool, queries ...SearchQuery) (user *User, err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }()
@@ -370,9 +356,6 @@ func (q *Queries) GetUser(ctx context.Context, shouldTriggerBulk bool, withOwner
eq := sq.Eq{
UserInstanceIDCol.identifier(): authz.GetInstance(ctx).InstanceID(),
}
if !withOwnerRemoved {
addUserWithoutOwnerRemoved(eq)
}
stmt, args, err := query.Where(eq).ToSql()
if err != nil {
return nil, errors.ThrowInternal(err, "QUERY-Dnhr2", "Errors.Query.SQLStatment")
@@ -385,7 +368,7 @@ func (q *Queries) GetUser(ctx context.Context, shouldTriggerBulk bool, withOwner
return user, err
}
func (q *Queries) GetHumanProfile(ctx context.Context, userID string, withOwnerRemoved bool, queries ...SearchQuery) (profile *Profile, err error) {
func (q *Queries) GetHumanProfile(ctx context.Context, userID string, queries ...SearchQuery) (profile *Profile, err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }()
@@ -397,9 +380,6 @@ func (q *Queries) GetHumanProfile(ctx context.Context, userID string, withOwnerR
UserIDCol.identifier(): userID,
UserInstanceIDCol.identifier(): authz.GetInstance(ctx).InstanceID(),
}
if !withOwnerRemoved {
eq[UserOwnerRemovedCol.identifier()] = false
}
stmt, args, err := query.Where(eq).ToSql()
if err != nil {
return nil, errors.ThrowInternal(err, "QUERY-Dgbg2", "Errors.Query.SQLStatment")
@@ -412,7 +392,7 @@ func (q *Queries) GetHumanProfile(ctx context.Context, userID string, withOwnerR
return profile, err
}
func (q *Queries) GetHumanEmail(ctx context.Context, userID string, withOwnerRemoved bool, queries ...SearchQuery) (email *Email, err error) {
func (q *Queries) GetHumanEmail(ctx context.Context, userID string, queries ...SearchQuery) (email *Email, err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }()
@@ -424,9 +404,6 @@ func (q *Queries) GetHumanEmail(ctx context.Context, userID string, withOwnerRem
UserIDCol.identifier(): userID,
UserInstanceIDCol.identifier(): authz.GetInstance(ctx).InstanceID(),
}
if !withOwnerRemoved {
eq[UserOwnerRemovedCol.identifier()] = false
}
stmt, args, err := query.Where(eq).ToSql()
if err != nil {
return nil, errors.ThrowInternal(err, "QUERY-BHhj3", "Errors.Query.SQLStatment")
@@ -439,7 +416,7 @@ func (q *Queries) GetHumanEmail(ctx context.Context, userID string, withOwnerRem
return email, err
}
func (q *Queries) GetHumanPhone(ctx context.Context, userID string, withOwnerRemoved bool, queries ...SearchQuery) (phone *Phone, err error) {
func (q *Queries) GetHumanPhone(ctx context.Context, userID string, queries ...SearchQuery) (phone *Phone, err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }()
@@ -451,9 +428,6 @@ func (q *Queries) GetHumanPhone(ctx context.Context, userID string, withOwnerRem
UserIDCol.identifier(): userID,
UserInstanceIDCol.identifier(): authz.GetInstance(ctx).InstanceID(),
}
if !withOwnerRemoved {
eq[UserOwnerRemovedCol.identifier()] = false
}
stmt, args, err := query.Where(eq).ToSql()
if err != nil {
return nil, errors.ThrowInternal(err, "QUERY-Dg43g", "Errors.Query.SQLStatment")
@@ -466,7 +440,7 @@ func (q *Queries) GetHumanPhone(ctx context.Context, userID string, withOwnerRem
return phone, err
}
func (q *Queries) GetNotifyUserByID(ctx context.Context, shouldTriggered bool, userID string, withOwnerRemoved bool, queries ...SearchQuery) (user *NotifyUser, err error) {
func (q *Queries) GetNotifyUserByID(ctx context.Context, shouldTriggered bool, userID string, queries ...SearchQuery) (user *NotifyUser, err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }()
@@ -482,9 +456,6 @@ func (q *Queries) GetNotifyUserByID(ctx context.Context, shouldTriggered bool, u
UserIDCol.identifier(): userID,
UserInstanceIDCol.identifier(): authz.GetInstance(ctx).InstanceID(),
}
if !withOwnerRemoved {
addUserWithoutOwnerRemoved(eq)
}
stmt, args, err := query.Where(eq).ToSql()
if err != nil {
return nil, errors.ThrowInternal(err, "QUERY-Err3g", "Errors.Query.SQLStatment")
@@ -497,7 +468,7 @@ func (q *Queries) GetNotifyUserByID(ctx context.Context, shouldTriggered bool, u
return user, err
}
func (q *Queries) GetNotifyUser(ctx context.Context, shouldTriggered bool, withOwnerRemoved bool, queries ...SearchQuery) (user *NotifyUser, err error) {
func (q *Queries) GetNotifyUser(ctx context.Context, shouldTriggered bool, queries ...SearchQuery) (user *NotifyUser, err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }()
@@ -512,9 +483,6 @@ func (q *Queries) GetNotifyUser(ctx context.Context, shouldTriggered bool, withO
eq := sq.Eq{
UserInstanceIDCol.identifier(): authz.GetInstance(ctx).InstanceID(),
}
if !withOwnerRemoved {
addUserWithoutOwnerRemoved(eq)
}
stmt, args, err := query.Where(eq).ToSql()
if err != nil {
return nil, errors.ThrowInternal(err, "QUERY-Err3g", "Errors.Query.SQLStatment")
@@ -527,15 +495,12 @@ func (q *Queries) GetNotifyUser(ctx context.Context, shouldTriggered bool, withO
return user, err
}
func (q *Queries) SearchUsers(ctx context.Context, queries *UserSearchQueries, withOwnerRemoved bool) (users *Users, err error) {
func (q *Queries) SearchUsers(ctx context.Context, queries *UserSearchQueries) (users *Users, err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }()
query, scan := prepareUsersQuery(ctx, q.client)
eq := sq.Eq{UserInstanceIDCol.identifier(): authz.GetInstance(ctx).InstanceID()}
if !withOwnerRemoved {
addUserWithoutOwnerRemoved(eq)
}
stmt, args, err := queries.toQuery(query).Where(eq).
ToSql()
if err != nil {
@@ -554,7 +519,7 @@ func (q *Queries) SearchUsers(ctx context.Context, queries *UserSearchQueries, w
return users, err
}
func (q *Queries) IsUserUnique(ctx context.Context, username, email, resourceOwner string, withOwnerRemoved bool) (isUnique bool, err error) {
func (q *Queries) IsUserUnique(ctx context.Context, username, email, resourceOwner string) (isUnique bool, err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }()
@@ -585,9 +550,6 @@ func (q *Queries) IsUserUnique(ctx context.Context, username, email, resourceOwn
query = q.toQuery(query)
}
eq := sq.Eq{UserInstanceIDCol.identifier(): authz.GetInstance(ctx).InstanceID()}
if !withOwnerRemoved {
eq[UserOwnerRemovedCol.identifier()] = false
}
stmt, args, err := query.Where(eq).ToSql()
if err != nil {
return false, errors.ThrowInternal(err, "QUERY-Dg43g", "Errors.Query.SQLStatment")
@@ -715,23 +677,7 @@ func NewUserLoginNameExistsQuery(value string, comparison TextComparison) (Searc
}
func triggerUserProjections(ctx context.Context) {
wg := sync.WaitGroup{}
wg.Add(2)
func() {
_, traceSpan := tracing.NewNamedSpan(ctx, "TriggerUserProjection")
_, err := projection.UserProjection.Trigger(ctx, handler.WithAwaitRunning())
logging.OnError(err).Debug("trigger failed")
traceSpan.EndWithError(err)
wg.Done()
}()
func() {
_, traceSpan := tracing.NewNamedSpan(ctx, "TriggerLoginNameProjection")
_, err := projection.LoginNameProjection.Trigger(ctx, handler.WithAwaitRunning())
traceSpan.EndWithError(err)
logging.OnError(err).Debug("trigger failed")
wg.Done()
}()
wg.Wait()
triggerBatch(ctx, projection.UserProjection, projection.LoginNameProjection)
}
func prepareLoginNamesQuery() (string, []interface{}, error) {

View File

@@ -141,7 +141,7 @@ func (q *Queries) SearchUserAuthMethods(ctx context.Context, queries *UserAuthMe
return userAuthMethods, err
}
func (q *Queries) ListActiveUserAuthMethodTypes(ctx context.Context, userID string, withOwnerRemoved bool) (userAuthMethodTypes *AuthMethodTypes, err error) {
func (q *Queries) ListActiveUserAuthMethodTypes(ctx context.Context, userID string) (userAuthMethodTypes *AuthMethodTypes, err error) {
ctxData := authz.GetCtxData(ctx)
if ctxData.UserID != userID {
if err := q.checkPermission(ctx, domain.PermissionUserRead, ctxData.OrgID, userID); err != nil {
@@ -156,9 +156,6 @@ func (q *Queries) ListActiveUserAuthMethodTypes(ctx context.Context, userID stri
UserIDCol.identifier(): userID,
UserInstanceIDCol.identifier(): authz.GetInstance(ctx).InstanceID(),
}
if !withOwnerRemoved {
eq[UserOwnerRemovedCol.identifier()] = false
}
stmt, args, err := query.Where(eq).ToSql()
if err != nil {
return nil, errors.ThrowInvalidArgument(err, "QUERY-Sfdrg", "Errors.Query.InvalidRequest")
@@ -175,7 +172,7 @@ func (q *Queries) ListActiveUserAuthMethodTypes(ctx context.Context, userID stri
return userAuthMethodTypes, err
}
func (q *Queries) ListUserAuthMethodTypesRequired(ctx context.Context, userID string, withOwnerRemoved bool) (userAuthMethodTypes []domain.UserAuthMethodType, forceMFA, forceMFALocalOnly bool, err error) {
func (q *Queries) ListUserAuthMethodTypesRequired(ctx context.Context, userID string) (userAuthMethodTypes []domain.UserAuthMethodType, forceMFA, forceMFALocalOnly bool, err error) {
ctxData := authz.GetCtxData(ctx)
if ctxData.UserID != userID {
if err := q.checkPermission(ctx, domain.PermissionUserRead, ctxData.OrgID, userID); err != nil {
@@ -190,9 +187,6 @@ func (q *Queries) ListUserAuthMethodTypesRequired(ctx context.Context, userID st
UserIDCol.identifier(): userID,
UserInstanceIDCol.identifier(): authz.GetInstance(ctx).InstanceID(),
}
if !withOwnerRemoved {
eq[UserOwnerRemovedCol.identifier()] = false
}
stmt, args, err := query.Where(eq).ToSql()
if err != nil {
return nil, false, false, errors.ThrowInvalidArgument(err, "QUERY-E5ut4", "Errors.Query.InvalidRequest")

View File

@@ -39,38 +39,38 @@ var (
"method_type",
"count",
}
prepareActiveAuthMethodTypesStmt = `SELECT projections.users8_notifications.password_set,` +
prepareActiveAuthMethodTypesStmt = `SELECT projections.users9_notifications.password_set,` +
` auth_method_types.method_type,` +
` user_idps_count.count` +
` FROM projections.users8` +
` LEFT JOIN projections.users8_notifications ON projections.users8.id = projections.users8_notifications.user_id AND projections.users8.instance_id = projections.users8_notifications.instance_id` +
` FROM projections.users9` +
` LEFT JOIN projections.users9_notifications ON projections.users9.id = projections.users9_notifications.user_id AND projections.users9.instance_id = projections.users9_notifications.instance_id` +
` LEFT JOIN (SELECT DISTINCT(auth_method_types.method_type), auth_method_types.user_id, auth_method_types.instance_id FROM projections.user_auth_methods4 AS auth_method_types` +
` WHERE auth_method_types.state = $1) AS auth_method_types` +
` ON auth_method_types.user_id = projections.users8.id AND auth_method_types.instance_id = projections.users8.instance_id` +
` ON auth_method_types.user_id = projections.users9.id AND auth_method_types.instance_id = projections.users9.instance_id` +
` LEFT JOIN (SELECT user_idps_count.user_id, user_idps_count.instance_id, COUNT(user_idps_count.user_id) AS count FROM projections.idp_user_links3 AS user_idps_count` +
` GROUP BY user_idps_count.user_id, user_idps_count.instance_id) AS user_idps_count` +
` ON user_idps_count.user_id = projections.users8.id AND user_idps_count.instance_id = projections.users8.instance_id` +
` ON user_idps_count.user_id = projections.users9.id AND user_idps_count.instance_id = projections.users9.instance_id` +
` AS OF SYSTEM TIME '-1 ms`
prepareActiveAuthMethodTypesCols = []string{
"password_set",
"method_type",
"idps_count",
}
prepareAuthMethodTypesRequiredStmt = `SELECT projections.users8_notifications.password_set,` +
prepareAuthMethodTypesRequiredStmt = `SELECT projections.users9_notifications.password_set,` +
` auth_method_types.method_type,` +
` user_idps_count.count,` +
` auth_methods_force_mfa.force_mfa,` +
` auth_methods_force_mfa.force_mfa_local_only` +
` FROM projections.users8` +
` LEFT JOIN projections.users8_notifications ON projections.users8.id = projections.users8_notifications.user_id AND projections.users8.instance_id = projections.users8_notifications.instance_id` +
` FROM projections.users9` +
` LEFT JOIN projections.users9_notifications ON projections.users9.id = projections.users9_notifications.user_id AND projections.users9.instance_id = projections.users9_notifications.instance_id` +
` LEFT JOIN (SELECT DISTINCT(auth_method_types.method_type), auth_method_types.user_id, auth_method_types.instance_id FROM projections.user_auth_methods4 AS auth_method_types` +
` WHERE auth_method_types.state = $1) AS auth_method_types` +
` ON auth_method_types.user_id = projections.users8.id AND auth_method_types.instance_id = projections.users8.instance_id` +
` ON auth_method_types.user_id = projections.users9.id AND auth_method_types.instance_id = projections.users9.instance_id` +
` LEFT JOIN (SELECT user_idps_count.user_id, user_idps_count.instance_id, COUNT(user_idps_count.user_id) AS count FROM projections.idp_user_links3 AS user_idps_count` +
` GROUP BY user_idps_count.user_id, user_idps_count.instance_id) AS user_idps_count` +
` ON user_idps_count.user_id = projections.users8.id AND user_idps_count.instance_id = projections.users8.instance_id` +
` ON user_idps_count.user_id = projections.users9.id AND user_idps_count.instance_id = projections.users9.instance_id` +
` LEFT JOIN (SELECT auth_methods_force_mfa.force_mfa, auth_methods_force_mfa.force_mfa_local_only, auth_methods_force_mfa.instance_id, auth_methods_force_mfa.aggregate_id FROM projections.login_policies5 AS auth_methods_force_mfa ORDER BY auth_methods_force_mfa.is_default) AS auth_methods_force_mfa` +
` ON (auth_methods_force_mfa.aggregate_id = projections.users8.instance_id OR auth_methods_force_mfa.aggregate_id = projections.users8.resource_owner) AND auth_methods_force_mfa.instance_id = projections.users8.instance_id` +
` ON (auth_methods_force_mfa.aggregate_id = projections.users9.instance_id OR auth_methods_force_mfa.aggregate_id = projections.users9.resource_owner) AND auth_methods_force_mfa.instance_id = projections.users9.instance_id` +
` AS OF SYSTEM TIME '-1 ms
`
prepareAuthMethodTypesRequiredCols = []string{

View File

@@ -22,32 +22,32 @@ import (
type UserGrant struct {
// ID represents the aggregate id (id of the user grant)
ID string
CreationDate time.Time
ChangeDate time.Time
Sequence uint64
Roles database.TextArray[string]
ID string `json:"id,omitempty"`
CreationDate time.Time `json:"creation_date,omitempty"`
ChangeDate time.Time `json:"change_date,omitempty"`
Sequence uint64 `json:"sequence,omitempty"`
Roles database.TextArray[string] `json:"roles,omitempty"`
// GrantID represents the project grant id
GrantID string
State domain.UserGrantState
GrantID string `json:"grant_id,omitempty"`
State domain.UserGrantState `json:"state,omitempty"`
UserID string
Username string
UserType domain.UserType
UserResourceOwner string
FirstName string
LastName string
Email string
DisplayName string
AvatarURL string
PreferredLoginName string
UserID string `json:"user_id,omitempty"`
Username string `json:"username,omitempty"`
UserType domain.UserType `json:"user_type,omitempty"`
UserResourceOwner string `json:"user_resource_owner,omitempty"`
FirstName string `json:"first_name,omitempty"`
LastName string `json:"last_name,omitempty"`
Email string `json:"email,omitempty"`
DisplayName string `json:"display_name,omitempty"`
AvatarURL string `json:"avatar_url,omitempty"`
PreferredLoginName string `json:"preferred_login_name,omitempty"`
ResourceOwner string
OrgName string
OrgPrimaryDomain string
ResourceOwner string `json:"resource_owner,omitempty"`
OrgName string `json:"org_name,omitempty"`
OrgPrimaryDomain string `json:"org_primary_domain,omitempty"`
ProjectID string
ProjectName string
ProjectID string `json:"project_id,omitempty"`
ProjectName string `json:"project_name,omitempty"`
}
type UserGrants struct {

View File

@@ -23,14 +23,14 @@ var (
", projections.user_grants3.roles" +
", projections.user_grants3.state" +
", projections.user_grants3.user_id" +
", projections.users8.username" +
", projections.users8.type" +
", projections.users8.resource_owner" +
", projections.users8_humans.first_name" +
", projections.users8_humans.last_name" +
", projections.users8_humans.email" +
", projections.users8_humans.display_name" +
", projections.users8_humans.avatar_key" +
", projections.users9.username" +
", projections.users9.type" +
", projections.users9.resource_owner" +
", projections.users9_humans.first_name" +
", projections.users9_humans.last_name" +
", projections.users9_humans.email" +
", projections.users9_humans.display_name" +
", projections.users9_humans.avatar_key" +
", projections.login_names3.login_name" +
", projections.user_grants3.resource_owner" +
", projections.orgs1.name" +
@@ -38,8 +38,8 @@ var (
", projections.user_grants3.project_id" +
", projections.projects4.name" +
" FROM projections.user_grants3" +
" LEFT JOIN projections.users8 ON projections.user_grants3.user_id = projections.users8.id AND projections.user_grants3.instance_id = projections.users8.instance_id" +
" LEFT JOIN projections.users8_humans ON projections.user_grants3.user_id = projections.users8_humans.user_id AND projections.user_grants3.instance_id = projections.users8_humans.instance_id" +
" LEFT JOIN projections.users9 ON projections.user_grants3.user_id = projections.users9.id AND projections.user_grants3.instance_id = projections.users9.instance_id" +
" LEFT JOIN projections.users9_humans ON projections.user_grants3.user_id = projections.users9_humans.user_id AND projections.user_grants3.instance_id = projections.users9_humans.instance_id" +
" LEFT JOIN projections.orgs1 ON projections.user_grants3.resource_owner = projections.orgs1.id AND projections.user_grants3.instance_id = projections.orgs1.instance_id" +
" LEFT JOIN projections.projects4 ON projections.user_grants3.project_id = projections.projects4.id AND projections.user_grants3.instance_id = projections.projects4.instance_id" +
" LEFT JOIN projections.login_names3 ON projections.user_grants3.user_id = projections.login_names3.user_id AND projections.user_grants3.instance_id = projections.login_names3.instance_id" +
@@ -78,14 +78,14 @@ var (
", projections.user_grants3.roles" +
", projections.user_grants3.state" +
", projections.user_grants3.user_id" +
", projections.users8.username" +
", projections.users8.type" +
", projections.users8.resource_owner" +
", projections.users8_humans.first_name" +
", projections.users8_humans.last_name" +
", projections.users8_humans.email" +
", projections.users8_humans.display_name" +
", projections.users8_humans.avatar_key" +
", projections.users9.username" +
", projections.users9.type" +
", projections.users9.resource_owner" +
", projections.users9_humans.first_name" +
", projections.users9_humans.last_name" +
", projections.users9_humans.email" +
", projections.users9_humans.display_name" +
", projections.users9_humans.avatar_key" +
", projections.login_names3.login_name" +
", projections.user_grants3.resource_owner" +
", projections.orgs1.name" +
@@ -94,8 +94,8 @@ var (
", projections.projects4.name" +
", COUNT(*) OVER ()" +
" FROM projections.user_grants3" +
" LEFT JOIN projections.users8 ON projections.user_grants3.user_id = projections.users8.id AND projections.user_grants3.instance_id = projections.users8.instance_id" +
" LEFT JOIN projections.users8_humans ON projections.user_grants3.user_id = projections.users8_humans.user_id AND projections.user_grants3.instance_id = projections.users8_humans.instance_id" +
" LEFT JOIN projections.users9 ON projections.user_grants3.user_id = projections.users9.id AND projections.user_grants3.instance_id = projections.users9.instance_id" +
" LEFT JOIN projections.users9_humans ON projections.user_grants3.user_id = projections.users9_humans.user_id AND projections.user_grants3.instance_id = projections.users9_humans.instance_id" +
" LEFT JOIN projections.orgs1 ON projections.user_grants3.resource_owner = projections.orgs1.id AND projections.user_grants3.instance_id = projections.orgs1.instance_id" +
" LEFT JOIN projections.projects4 ON projections.user_grants3.project_id = projections.projects4.id AND projections.user_grants3.instance_id = projections.projects4.instance_id" +
" LEFT JOIN projections.login_names3 ON projections.user_grants3.user_id = projections.login_names3.user_id AND projections.user_grants3.instance_id = projections.login_names3.instance_id" +

View File

@@ -24,12 +24,12 @@ type UserMetadataList struct {
}
type UserMetadata struct {
CreationDate time.Time
ChangeDate time.Time
ResourceOwner string
Sequence uint64
Key string
Value []byte
CreationDate time.Time `json:"creation_date,omitempty"`
ChangeDate time.Time `json:"change_date,omitempty"`
ResourceOwner string `json:"resource_owner,omitempty"`
Sequence uint64 `json:"sequence,omitempty"`
Key string `json:"key,omitempty"`
Value []byte `json:"value,omitempty"`
}
type UserMetadataSearchQueries struct {
@@ -74,10 +74,6 @@ var (
name: projection.UserMetadataColumnValue,
table: userMetadataTable,
}
UserMetadataOwnerRemovedCol = Column{
name: projection.UserMetadataColumnOwnerRemoved,
table: userMetadataTable,
}
)
func (q *Queries) GetUserMetadataByKey(ctx context.Context, shouldTriggerBulk bool, userID, key string, withOwnerRemoved bool, queries ...SearchQuery) (metadata *UserMetadata, err error) {
@@ -100,9 +96,6 @@ func (q *Queries) GetUserMetadataByKey(ctx context.Context, shouldTriggerBulk bo
UserMetadataKeyCol.identifier(): key,
UserMetadataInstanceIDCol.identifier(): authz.GetInstance(ctx).InstanceID(),
}
if !withOwnerRemoved {
eq[UserMetadataOwnerRemovedCol.identifier()] = false
}
stmt, args, err := query.Where(eq).ToSql()
if err != nil {
return nil, errors.ThrowInternal(err, "QUERY-aDGG2", "Errors.Query.SQLStatment")
@@ -131,9 +124,6 @@ func (q *Queries) SearchUserMetadata(ctx context.Context, shouldTriggerBulk bool
UserMetadataUserIDCol.identifier(): userID,
UserMetadataInstanceIDCol.identifier(): authz.GetInstance(ctx).InstanceID(),
}
if !withOwnerRemoved {
eq[UserMetadataOwnerRemovedCol.identifier()] = false
}
stmt, args, err := queries.toQuery(query).Where(eq).ToSql()
if err != nil {
return nil, errors.ThrowInternal(err, "QUERY-Egbgd", "Errors.Query.SQLStatment")

View File

@@ -12,13 +12,13 @@ import (
)
var (
userMetadataQuery = `SELECT projections.user_metadata4.creation_date,` +
` projections.user_metadata4.change_date,` +
` projections.user_metadata4.resource_owner,` +
` projections.user_metadata4.sequence,` +
` projections.user_metadata4.key,` +
` projections.user_metadata4.value` +
` FROM projections.user_metadata4` +
userMetadataQuery = `SELECT projections.user_metadata5.creation_date,` +
` projections.user_metadata5.change_date,` +
` projections.user_metadata5.resource_owner,` +
` projections.user_metadata5.sequence,` +
` projections.user_metadata5.key,` +
` projections.user_metadata5.value` +
` FROM projections.user_metadata5` +
` AS OF SYSTEM TIME '-1 ms'`
userMetadataCols = []string{
"creation_date",
@@ -28,14 +28,14 @@ var (
"key",
"value",
}
userMetadataListQuery = `SELECT projections.user_metadata4.creation_date,` +
` projections.user_metadata4.change_date,` +
` projections.user_metadata4.resource_owner,` +
` projections.user_metadata4.sequence,` +
` projections.user_metadata4.key,` +
` projections.user_metadata4.value,` +
userMetadataListQuery = `SELECT projections.user_metadata5.creation_date,` +
` projections.user_metadata5.change_date,` +
` projections.user_metadata5.resource_owner,` +
` projections.user_metadata5.sequence,` +
` projections.user_metadata5.key,` +
` projections.user_metadata5.value,` +
` COUNT(*) OVER ()` +
` FROM projections.user_metadata4`
` FROM projections.user_metadata5`
userMetadataListCols = []string{
"creation_date",
"change_date",

View File

@@ -22,43 +22,43 @@ var (
preferredLoginNameQuery = `SELECT preferred_login_name.user_id, preferred_login_name.login_name, preferred_login_name.instance_id` +
` FROM projections.login_names3 AS preferred_login_name` +
` WHERE preferred_login_name.is_primary = $1`
userQuery = `SELECT projections.users8.id,` +
` projections.users8.creation_date,` +
` projections.users8.change_date,` +
` projections.users8.resource_owner,` +
` projections.users8.sequence,` +
` projections.users8.state,` +
` projections.users8.type,` +
` projections.users8.username,` +
userQuery = `SELECT projections.users9.id,` +
` projections.users9.creation_date,` +
` projections.users9.change_date,` +
` projections.users9.resource_owner,` +
` projections.users9.sequence,` +
` projections.users9.state,` +
` projections.users9.type,` +
` projections.users9.username,` +
` login_names.loginnames,` +
` preferred_login_name.login_name,` +
` projections.users8_humans.user_id,` +
` projections.users8_humans.first_name,` +
` projections.users8_humans.last_name,` +
` projections.users8_humans.nick_name,` +
` projections.users8_humans.display_name,` +
` projections.users8_humans.preferred_language,` +
` projections.users8_humans.gender,` +
` projections.users8_humans.avatar_key,` +
` projections.users8_humans.email,` +
` projections.users8_humans.is_email_verified,` +
` projections.users8_humans.phone,` +
` projections.users8_humans.is_phone_verified,` +
` projections.users8_machines.user_id,` +
` projections.users8_machines.name,` +
` projections.users8_machines.description,` +
` projections.users8_machines.has_secret,` +
` projections.users8_machines.access_token_type,` +
` projections.users9_humans.user_id,` +
` projections.users9_humans.first_name,` +
` projections.users9_humans.last_name,` +
` projections.users9_humans.nick_name,` +
` projections.users9_humans.display_name,` +
` projections.users9_humans.preferred_language,` +
` projections.users9_humans.gender,` +
` projections.users9_humans.avatar_key,` +
` projections.users9_humans.email,` +
` projections.users9_humans.is_email_verified,` +
` projections.users9_humans.phone,` +
` projections.users9_humans.is_phone_verified,` +
` projections.users9_machines.user_id,` +
` projections.users9_machines.name,` +
` projections.users9_machines.description,` +
` projections.users9_machines.has_secret,` +
` projections.users9_machines.access_token_type,` +
` COUNT(*) OVER ()` +
` FROM projections.users8` +
` LEFT JOIN projections.users8_humans ON projections.users8.id = projections.users8_humans.user_id AND projections.users8.instance_id = projections.users8_humans.instance_id` +
` LEFT JOIN projections.users8_machines ON projections.users8.id = projections.users8_machines.user_id AND projections.users8.instance_id = projections.users8_machines.instance_id` +
` FROM projections.users9` +
` LEFT JOIN projections.users9_humans ON projections.users9.id = projections.users9_humans.user_id AND projections.users9.instance_id = projections.users9_humans.instance_id` +
` LEFT JOIN projections.users9_machines ON projections.users9.id = projections.users9_machines.user_id AND projections.users9.instance_id = projections.users9_machines.instance_id` +
` LEFT JOIN` +
` (` + loginNamesQuery + `) AS login_names` +
` ON login_names.user_id = projections.users8.id AND login_names.instance_id = projections.users8.instance_id` +
` ON login_names.user_id = projections.users9.id AND login_names.instance_id = projections.users9.instance_id` +
` LEFT JOIN` +
` (` + preferredLoginNameQuery + `) AS preferred_login_name` +
` ON preferred_login_name.user_id = projections.users8.id AND preferred_login_name.instance_id = projections.users8.instance_id` +
` ON preferred_login_name.user_id = projections.users9.id AND preferred_login_name.instance_id = projections.users9.instance_id` +
` AS OF SYSTEM TIME '-1 ms'`
userCols = []string{
"id",
@@ -92,21 +92,21 @@ var (
"access_token_type",
"count",
}
profileQuery = `SELECT projections.users8.id,` +
` projections.users8.creation_date,` +
` projections.users8.change_date,` +
` projections.users8.resource_owner,` +
` projections.users8.sequence,` +
` projections.users8_humans.user_id,` +
` projections.users8_humans.first_name,` +
` projections.users8_humans.last_name,` +
` projections.users8_humans.nick_name,` +
` projections.users8_humans.display_name,` +
` projections.users8_humans.preferred_language,` +
` projections.users8_humans.gender,` +
` projections.users8_humans.avatar_key` +
` FROM projections.users8` +
` LEFT JOIN projections.users8_humans ON projections.users8.id = projections.users8_humans.user_id AND projections.users8.instance_id = projections.users8_humans.instance_id` +
profileQuery = `SELECT projections.users9.id,` +
` projections.users9.creation_date,` +
` projections.users9.change_date,` +
` projections.users9.resource_owner,` +
` projections.users9.sequence,` +
` projections.users9_humans.user_id,` +
` projections.users9_humans.first_name,` +
` projections.users9_humans.last_name,` +
` projections.users9_humans.nick_name,` +
` projections.users9_humans.display_name,` +
` projections.users9_humans.preferred_language,` +
` projections.users9_humans.gender,` +
` projections.users9_humans.avatar_key` +
` FROM projections.users9` +
` LEFT JOIN projections.users9_humans ON projections.users9.id = projections.users9_humans.user_id AND projections.users9.instance_id = projections.users9_humans.instance_id` +
` AS OF SYSTEM TIME '-1 ms'`
profileCols = []string{
"id",
@@ -123,16 +123,16 @@ var (
"gender",
"avatar_key",
}
emailQuery = `SELECT projections.users8.id,` +
` projections.users8.creation_date,` +
` projections.users8.change_date,` +
` projections.users8.resource_owner,` +
` projections.users8.sequence,` +
` projections.users8_humans.user_id,` +
` projections.users8_humans.email,` +
` projections.users8_humans.is_email_verified` +
` FROM projections.users8` +
` LEFT JOIN projections.users8_humans ON projections.users8.id = projections.users8_humans.user_id AND projections.users8.instance_id = projections.users8_humans.instance_id` +
emailQuery = `SELECT projections.users9.id,` +
` projections.users9.creation_date,` +
` projections.users9.change_date,` +
` projections.users9.resource_owner,` +
` projections.users9.sequence,` +
` projections.users9_humans.user_id,` +
` projections.users9_humans.email,` +
` projections.users9_humans.is_email_verified` +
` FROM projections.users9` +
` LEFT JOIN projections.users9_humans ON projections.users9.id = projections.users9_humans.user_id AND projections.users9.instance_id = projections.users9_humans.instance_id` +
` AS OF SYSTEM TIME '-1 ms'`
emailCols = []string{
"id",
@@ -144,16 +144,16 @@ var (
"email",
"is_email_verified",
}
phoneQuery = `SELECT projections.users8.id,` +
` projections.users8.creation_date,` +
` projections.users8.change_date,` +
` projections.users8.resource_owner,` +
` projections.users8.sequence,` +
` projections.users8_humans.user_id,` +
` projections.users8_humans.phone,` +
` projections.users8_humans.is_phone_verified` +
` FROM projections.users8` +
` LEFT JOIN projections.users8_humans ON projections.users8.id = projections.users8_humans.user_id AND projections.users8.instance_id = projections.users8_humans.instance_id` +
phoneQuery = `SELECT projections.users9.id,` +
` projections.users9.creation_date,` +
` projections.users9.change_date,` +
` projections.users9.resource_owner,` +
` projections.users9.sequence,` +
` projections.users9_humans.user_id,` +
` projections.users9_humans.phone,` +
` projections.users9_humans.is_phone_verified` +
` FROM projections.users9` +
` LEFT JOIN projections.users9_humans ON projections.users9.id = projections.users9_humans.user_id AND projections.users9.instance_id = projections.users9_humans.instance_id` +
` AS OF SYSTEM TIME '-1 ms'`
phoneCols = []string{
"id",
@@ -165,14 +165,14 @@ var (
"phone",
"is_phone_verified",
}
userUniqueQuery = `SELECT projections.users8.id,` +
` projections.users8.state,` +
` projections.users8.username,` +
` projections.users8_humans.user_id,` +
` projections.users8_humans.email,` +
` projections.users8_humans.is_email_verified` +
` FROM projections.users8` +
` LEFT JOIN projections.users8_humans ON projections.users8.id = projections.users8_humans.user_id AND projections.users8.instance_id = projections.users8_humans.instance_id` +
userUniqueQuery = `SELECT projections.users9.id,` +
` projections.users9.state,` +
` projections.users9.username,` +
` projections.users9_humans.user_id,` +
` projections.users9_humans.email,` +
` projections.users9_humans.is_email_verified` +
` FROM projections.users9` +
` LEFT JOIN projections.users9_humans ON projections.users9.id = projections.users9_humans.user_id AND projections.users9.instance_id = projections.users9_humans.instance_id` +
` AS OF SYSTEM TIME '-1 ms'`
userUniqueCols = []string{
"id",
@@ -182,40 +182,40 @@ var (
"email",
"is_email_verified",
}
notifyUserQuery = `SELECT projections.users8.id,` +
` projections.users8.creation_date,` +
` projections.users8.change_date,` +
` projections.users8.resource_owner,` +
` projections.users8.sequence,` +
` projections.users8.state,` +
` projections.users8.type,` +
` projections.users8.username,` +
notifyUserQuery = `SELECT projections.users9.id,` +
` projections.users9.creation_date,` +
` projections.users9.change_date,` +
` projections.users9.resource_owner,` +
` projections.users9.sequence,` +
` projections.users9.state,` +
` projections.users9.type,` +
` projections.users9.username,` +
` login_names.loginnames,` +
` preferred_login_name.login_name,` +
` projections.users8_humans.user_id,` +
` projections.users8_humans.first_name,` +
` projections.users8_humans.last_name,` +
` projections.users8_humans.nick_name,` +
` projections.users8_humans.display_name,` +
` projections.users8_humans.preferred_language,` +
` projections.users8_humans.gender,` +
` projections.users8_humans.avatar_key,` +
` projections.users8_notifications.user_id,` +
` projections.users8_notifications.last_email,` +
` projections.users8_notifications.verified_email,` +
` projections.users8_notifications.last_phone,` +
` projections.users8_notifications.verified_phone,` +
` projections.users8_notifications.password_set,` +
` projections.users9_humans.user_id,` +
` projections.users9_humans.first_name,` +
` projections.users9_humans.last_name,` +
` projections.users9_humans.nick_name,` +
` projections.users9_humans.display_name,` +
` projections.users9_humans.preferred_language,` +
` projections.users9_humans.gender,` +
` projections.users9_humans.avatar_key,` +
` projections.users9_notifications.user_id,` +
` projections.users9_notifications.last_email,` +
` projections.users9_notifications.verified_email,` +
` projections.users9_notifications.last_phone,` +
` projections.users9_notifications.verified_phone,` +
` projections.users9_notifications.password_set,` +
` COUNT(*) OVER ()` +
` FROM projections.users8` +
` LEFT JOIN projections.users8_humans ON projections.users8.id = projections.users8_humans.user_id AND projections.users8.instance_id = projections.users8_humans.instance_id` +
` LEFT JOIN projections.users8_notifications ON projections.users8.id = projections.users8_notifications.user_id AND projections.users8.instance_id = projections.users8_notifications.instance_id` +
` FROM projections.users9` +
` LEFT JOIN projections.users9_humans ON projections.users9.id = projections.users9_humans.user_id AND projections.users9.instance_id = projections.users9_humans.instance_id` +
` LEFT JOIN projections.users9_notifications ON projections.users9.id = projections.users9_notifications.user_id AND projections.users9.instance_id = projections.users9_notifications.instance_id` +
` LEFT JOIN` +
` (` + loginNamesQuery + `) AS login_names` +
` ON login_names.user_id = projections.users8.id AND login_names.instance_id = projections.users8.instance_id` +
` ON login_names.user_id = projections.users9.id AND login_names.instance_id = projections.users9.instance_id` +
` LEFT JOIN` +
` (` + preferredLoginNameQuery + `) AS preferred_login_name` +
` ON preferred_login_name.user_id = projections.users8.id AND preferred_login_name.instance_id = projections.users8.instance_id` +
` ON preferred_login_name.user_id = projections.users9.id AND preferred_login_name.instance_id = projections.users9.instance_id` +
` AS OF SYSTEM TIME '-1 ms'`
notifyUserCols = []string{
"id",
@@ -246,43 +246,43 @@ var (
"password_set",
"count",
}
usersQuery = `SELECT projections.users8.id,` +
` projections.users8.creation_date,` +
` projections.users8.change_date,` +
` projections.users8.resource_owner,` +
` projections.users8.sequence,` +
` projections.users8.state,` +
` projections.users8.type,` +
` projections.users8.username,` +
usersQuery = `SELECT projections.users9.id,` +
` projections.users9.creation_date,` +
` projections.users9.change_date,` +
` projections.users9.resource_owner,` +
` projections.users9.sequence,` +
` projections.users9.state,` +
` projections.users9.type,` +
` projections.users9.username,` +
` login_names.loginnames,` +
` preferred_login_name.login_name,` +
` projections.users8_humans.user_id,` +
` projections.users8_humans.first_name,` +
` projections.users8_humans.last_name,` +
` projections.users8_humans.nick_name,` +
` projections.users8_humans.display_name,` +
` projections.users8_humans.preferred_language,` +
` projections.users8_humans.gender,` +
` projections.users8_humans.avatar_key,` +
` projections.users8_humans.email,` +
` projections.users8_humans.is_email_verified,` +
` projections.users8_humans.phone,` +
` projections.users8_humans.is_phone_verified,` +
` projections.users8_machines.user_id,` +
` projections.users8_machines.name,` +
` projections.users8_machines.description,` +
` projections.users8_machines.has_secret,` +
` projections.users8_machines.access_token_type,` +
` projections.users9_humans.user_id,` +
` projections.users9_humans.first_name,` +
` projections.users9_humans.last_name,` +
` projections.users9_humans.nick_name,` +
` projections.users9_humans.display_name,` +
` projections.users9_humans.preferred_language,` +
` projections.users9_humans.gender,` +
` projections.users9_humans.avatar_key,` +
` projections.users9_humans.email,` +
` projections.users9_humans.is_email_verified,` +
` projections.users9_humans.phone,` +
` projections.users9_humans.is_phone_verified,` +
` projections.users9_machines.user_id,` +
` projections.users9_machines.name,` +
` projections.users9_machines.description,` +
` projections.users9_machines.has_secret,` +
` projections.users9_machines.access_token_type,` +
` COUNT(*) OVER ()` +
` FROM projections.users8` +
` LEFT JOIN projections.users8_humans ON projections.users8.id = projections.users8_humans.user_id AND projections.users8.instance_id = projections.users8_humans.instance_id` +
` LEFT JOIN projections.users8_machines ON projections.users8.id = projections.users8_machines.user_id AND projections.users8.instance_id = projections.users8_machines.instance_id` +
` FROM projections.users9` +
` LEFT JOIN projections.users9_humans ON projections.users9.id = projections.users9_humans.user_id AND projections.users9.instance_id = projections.users9_humans.instance_id` +
` LEFT JOIN projections.users9_machines ON projections.users9.id = projections.users9_machines.user_id AND projections.users9.instance_id = projections.users9_machines.instance_id` +
` LEFT JOIN` +
` (` + loginNamesQuery + `) AS login_names` +
` ON login_names.user_id = projections.users8.id AND login_names.instance_id = projections.users8.instance_id` +
` ON login_names.user_id = projections.users9.id AND login_names.instance_id = projections.users9.instance_id` +
` LEFT JOIN` +
` (` + preferredLoginNameQuery + `) AS preferred_login_name` +
` ON preferred_login_name.user_id = projections.users8.id AND preferred_login_name.instance_id = projections.users8.instance_id` +
` ON preferred_login_name.user_id = projections.users9.id AND preferred_login_name.instance_id = projections.users9.instance_id` +
` AS OF SYSTEM TIME '-1 ms'`
usersCols = []string{
"id",

View File

@@ -0,0 +1,76 @@
package query
import (
"context"
"database/sql"
_ "embed"
"encoding/json"
"sync"
"github.com/zitadel/zitadel/internal/api/authz"
"github.com/zitadel/zitadel/internal/database"
"github.com/zitadel/zitadel/internal/errors"
"github.com/zitadel/zitadel/internal/eventstore/handler/v2"
"github.com/zitadel/zitadel/internal/query/projection"
"github.com/zitadel/zitadel/internal/telemetry/tracing"
)
// oidcUserInfoTriggerHandlers slice can only be created after zitadel
// is fully initialized, otherwise the handlers are nil.
// OnceValue takes care of creating the slice on the first request
// and than will always return the same slice on subsequent requests.
var oidcUserInfoTriggerHandlers = sync.OnceValue(func() []*handler.Handler {
return []*handler.Handler{
projection.UserProjection,
projection.UserMetadataProjection,
projection.UserGrantProjection,
projection.OrgProjection,
projection.ProjectProjection,
}
})
func TriggerOIDCUserInfoProjections(ctx context.Context) {
triggerBatch(ctx, oidcUserInfoTriggerHandlers()...)
}
//go:embed embed/userinfo_by_id.sql
var oidcUserInfoQuery string
func (q *Queries) GetOIDCUserInfo(ctx context.Context, userID string, roleAudience []string) (_ *OIDCUserInfo, err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }()
var data []byte
err = q.client.QueryRowContext(ctx, func(row *sql.Row) error {
return row.Scan(&data)
},
oidcUserInfoQuery,
userID, authz.GetInstance(ctx).InstanceID(), database.TextArray[string](roleAudience),
)
if err != nil {
return nil, errors.ThrowInternal(err, "QUERY-Oath6", "Errors.Internal")
}
userInfo := new(OIDCUserInfo)
if err = json.Unmarshal(data, userInfo); err != nil {
return nil, errors.ThrowInternal(err, "QUERY-Vohs6", "Errors.Internal")
}
if userInfo.User == nil {
return nil, errors.ThrowNotFound(nil, "QUERY-ahs4S", "Errors.User.NotFound")
}
return userInfo, nil
}
type OIDCUserInfo struct {
User *User `json:"user,omitempty"`
Metadata []UserMetadata `json:"metadata,omitempty"`
Org *UserInfoOrg `json:"org,omitempty"`
UserGrants []UserGrant `json:"user_grants,omitempty"`
}
type UserInfoOrg struct {
ID string `json:"id,omitempty"`
Name string `json:"name,omitempty"`
PrimaryDomain string `json:"primary_domain,omitempty"`
}

View File

@@ -0,0 +1,336 @@
package query
import (
"database/sql"
"database/sql/driver"
_ "embed"
"encoding/json"
"regexp"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/zitadel/zitadel/internal/api/authz"
"github.com/zitadel/zitadel/internal/database"
"github.com/zitadel/zitadel/internal/errors"
)
var (
//go:embed testdata/userinfo_not_found.json
testdataUserInfoNotFound string
//go:embed testdata/userinfo_human_no_md.json
testdataUserInfoHumanNoMD string
//go:embed testdata/userinfo_human.json
testdataUserInfoHuman string
//go:embed testdata/userinfo_human_grants.json
testdataUserInfoHumanGrants string
//go:embed testdata/userinfo_machine.json
testdataUserInfoMachine string
// timeLocation does a single parse of the testdata and extracts a time.Location,
// so that it may be used during test assertion.
// Because depending on the environment json.Unmarshal parses
// the 00:00 timezones differently.
// On my local system is parses to an empty timezone with 0 offset,
// but in github action is pares into UTC.
timeLocation = func() *time.Location {
referenceInfo := new(OIDCUserInfo)
err := json.Unmarshal([]byte(testdataUserInfoHumanNoMD), referenceInfo)
if err != nil {
panic(err)
}
return referenceInfo.User.CreationDate.Location()
}()
)
func TestQueries_GetOIDCUserInfo(t *testing.T) {
expQuery := regexp.QuoteMeta(oidcUserInfoQuery)
type args struct {
userID string
roleAudience []string
}
tests := []struct {
name string
args args
mock sqlExpectation
want *OIDCUserInfo
wantErr error
}{
{
name: "query error",
args: args{
userID: "231965491734773762",
},
mock: mockQueryErr(expQuery, sql.ErrConnDone, "231965491734773762", "instanceID", nil),
wantErr: sql.ErrConnDone,
},
{
name: "unmarshal error",
args: args{
userID: "231965491734773762",
},
mock: mockQuery(expQuery, []string{"json_build_object"}, []driver.Value{`~~~`}, "231965491734773762", "instanceID", nil),
wantErr: errors.ThrowInternal(nil, "QUERY-Vohs6", "Errors.Internal"),
},
{
name: "user not found",
args: args{
userID: "231965491734773762",
},
mock: mockQuery(expQuery, []string{"json_build_object"}, []driver.Value{testdataUserInfoNotFound}, "231965491734773762", "instanceID", nil),
wantErr: errors.ThrowNotFound(nil, "QUERY-ahs4S", "Errors.User.NotFound"),
},
{
name: "human without metadata",
args: args{
userID: "231965491734773762",
},
mock: mockQuery(expQuery, []string{"json_build_object"}, []driver.Value{testdataUserInfoHumanNoMD}, "231965491734773762", "instanceID", nil),
want: &OIDCUserInfo{
User: &User{
ID: "231965491734773762",
CreationDate: time.Date(2023, time.September, 15, 6, 10, 7, 434142000, timeLocation),
ChangeDate: time.Date(2023, time.November, 14, 13, 27, 2, 72318000, timeLocation),
Sequence: 1148,
State: 1,
ResourceOwner: "231848297847848962",
Username: "tim+tesmail@zitadel.com",
PreferredLoginName: "tim+tesmail@zitadel.com@demo.localhost",
Human: &Human{
FirstName: "Tim",
LastName: "Mohlmann",
NickName: "muhlemmer",
DisplayName: "Tim Mohlmann",
AvatarKey: "",
Email: "tim+tesmail@zitadel.com",
IsEmailVerified: true,
Phone: "+40123456789",
IsPhoneVerified: false,
},
Machine: nil,
},
Org: &UserInfoOrg{
Name: "demo",
PrimaryDomain: "demo.localhost",
},
Metadata: nil,
},
},
{
name: "human with metadata",
args: args{
userID: "231965491734773762",
},
mock: mockQuery(expQuery, []string{"json_build_object"}, []driver.Value{testdataUserInfoHuman}, "231965491734773762", "instanceID", nil),
want: &OIDCUserInfo{
User: &User{
ID: "231965491734773762",
CreationDate: time.Date(2023, time.September, 15, 6, 10, 7, 434142000, timeLocation),
ChangeDate: time.Date(2023, time.November, 14, 13, 27, 2, 72318000, timeLocation),
Sequence: 1148,
State: 1,
ResourceOwner: "231848297847848962",
Username: "tim+tesmail@zitadel.com",
PreferredLoginName: "tim+tesmail@zitadel.com@demo.localhost",
Human: &Human{
FirstName: "Tim",
LastName: "Mohlmann",
NickName: "muhlemmer",
DisplayName: "Tim Mohlmann",
AvatarKey: "",
Email: "tim+tesmail@zitadel.com",
IsEmailVerified: true,
Phone: "+40123456789",
IsPhoneVerified: false,
},
Machine: nil,
},
Org: &UserInfoOrg{
Name: "demo",
PrimaryDomain: "demo.localhost",
},
Metadata: []UserMetadata{
{
CreationDate: time.Date(2023, time.November, 14, 13, 26, 3, 553702000, timeLocation),
ChangeDate: time.Date(2023, time.November, 14, 13, 26, 3, 553702000, timeLocation),
Sequence: 1147,
ResourceOwner: "231848297847848962",
Key: "bar",
Value: []byte("foo"),
},
{
CreationDate: time.Date(2023, time.November, 14, 13, 25, 57, 171368000, timeLocation),
ChangeDate: time.Date(2023, time.November, 14, 13, 25, 57, 171368000, timeLocation),
Sequence: 1146,
ResourceOwner: "231848297847848962",
Key: "foo",
Value: []byte("bar"),
},
},
},
},
{
name: "human with metadata and grants",
args: args{
userID: "231965491734773762",
roleAudience: []string{"236645808328409090", "240762134579904514"},
},
mock: mockQuery(expQuery,
[]string{"json_build_object"},
[]driver.Value{testdataUserInfoHumanGrants},
"231965491734773762", "instanceID", database.TextArray[string]{"236645808328409090", "240762134579904514"},
),
want: &OIDCUserInfo{
User: &User{
ID: "231965491734773762",
CreationDate: time.Date(2023, time.September, 15, 6, 10, 7, 434142000, timeLocation),
ChangeDate: time.Date(2023, time.November, 14, 13, 27, 2, 72318000, timeLocation),
Sequence: 1148,
State: 1,
ResourceOwner: "231848297847848962",
Username: "tim+tesmail@zitadel.com",
PreferredLoginName: "tim+tesmail@zitadel.com@demo.localhost",
Human: &Human{
FirstName: "Tim",
LastName: "Mohlmann",
NickName: "muhlemmer",
DisplayName: "Tim Mohlmann",
AvatarKey: "",
Email: "tim+tesmail@zitadel.com",
IsEmailVerified: true,
Phone: "+40123456789",
IsPhoneVerified: false,
},
Machine: nil,
},
Org: &UserInfoOrg{
Name: "demo",
PrimaryDomain: "demo.localhost",
},
Metadata: []UserMetadata{
{
CreationDate: time.Date(2023, time.November, 14, 13, 26, 3, 553702000, timeLocation),
ChangeDate: time.Date(2023, time.November, 14, 13, 26, 3, 553702000, timeLocation),
Sequence: 1147,
ResourceOwner: "231848297847848962",
Key: "bar",
Value: []byte("foo"),
},
{
CreationDate: time.Date(2023, time.November, 14, 13, 25, 57, 171368000, timeLocation),
ChangeDate: time.Date(2023, time.November, 14, 13, 25, 57, 171368000, timeLocation),
Sequence: 1146,
ResourceOwner: "231848297847848962",
Key: "foo",
Value: []byte("bar"),
},
},
UserGrants: []UserGrant{
{
ID: "240749256523120642",
GrantID: "",
State: 1,
CreationDate: time.Date(2023, time.November, 14, 20, 28, 59, 168208000, timeLocation),
ChangeDate: time.Date(2023, time.November, 14, 20, 50, 58, 822391000, timeLocation),
Sequence: 2,
UserID: "231965491734773762",
Roles: []string{
"role1",
"role2",
},
ResourceOwner: "231848297847848962",
ProjectID: "236645808328409090",
OrgName: "demo",
OrgPrimaryDomain: "demo.localhost",
ProjectName: "tests",
UserResourceOwner: "231848297847848962",
},
{
ID: "240762315572510722",
GrantID: "",
State: 1,
CreationDate: time.Date(2023, time.November, 14, 22, 38, 42, 967317000, timeLocation),
ChangeDate: time.Date(2023, time.November, 14, 22, 38, 42, 967317000, timeLocation),
Sequence: 1,
UserID: "231965491734773762",
Roles: []string{
"role3",
"role4",
},
ResourceOwner: "231848297847848962",
ProjectID: "240762134579904514",
OrgName: "demo",
OrgPrimaryDomain: "demo.localhost",
ProjectName: "tests2",
UserResourceOwner: "231848297847848962",
},
},
},
},
{
name: "machine with metadata",
args: args{
userID: "240707570677841922",
},
mock: mockQuery(expQuery, []string{"json_build_object"}, []driver.Value{testdataUserInfoMachine}, "240707570677841922", "instanceID", nil),
want: &OIDCUserInfo{
User: &User{
ID: "240707570677841922",
CreationDate: time.Date(2023, time.November, 14, 13, 34, 52, 473732000, timeLocation),
ChangeDate: time.Date(2023, time.November, 14, 13, 35, 2, 861342000, timeLocation),
Sequence: 2,
State: 1,
ResourceOwner: "231848297847848962",
Username: "tests",
PreferredLoginName: "tests@demo.localhost",
Human: nil,
Machine: &Machine{
Name: "tests",
Description: "My test service user",
},
},
Org: &UserInfoOrg{
Name: "demo",
PrimaryDomain: "demo.localhost",
},
Metadata: []UserMetadata{
{
CreationDate: time.Date(2023, time.November, 14, 13, 35, 30, 126849000, timeLocation),
ChangeDate: time.Date(2023, time.November, 14, 13, 35, 30, 126849000, timeLocation),
Sequence: 3,
ResourceOwner: "231848297847848962",
Key: "first",
Value: []byte("Hello World!"),
},
{
CreationDate: time.Date(2023, time.November, 14, 13, 35, 44, 28343000, timeLocation),
ChangeDate: time.Date(2023, time.November, 14, 13, 35, 44, 28343000, timeLocation),
Sequence: 4,
ResourceOwner: "231848297847848962",
Key: "second",
Value: []byte("Bye World!"),
},
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
execMock(t, tt.mock, func(db *sql.DB) {
q := &Queries{
client: &database.DB{
DB: db,
Database: &prepareDB{},
},
}
ctx := authz.NewMockContext("instanceID", "orgID", "loginClient")
got, err := q.GetOIDCUserInfo(ctx, tt.args.userID, tt.args.roleAudience)
require.ErrorIs(t, err, tt.wantErr)
assert.Equal(t, tt.want, got)
})
})
}
}