mirror of
https://github.com/zitadel/zitadel.git
synced 2025-08-12 01:47:33 +00:00
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:
@@ -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")
|
||||
|
@@ -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]{
|
||||
|
@@ -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")
|
||||
|
23
internal/query/embed/introspection_client_by_id.sql
Normal file
23
internal/query/embed/introspection_client_by_id.sql
Normal 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;
|
92
internal/query/embed/userinfo_by_id.sql
Normal file
92
internal/query/embed/userinfo_by_id.sql
Normal 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"}')
|
@@ -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}
|
||||
}
|
||||
|
@@ -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' " +
|
||||
|
63
internal/query/introspection.go
Normal file
63
internal/query/introspection.go
Normal 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
|
||||
}
|
108
internal/query/introspection_test.go
Normal file
108
internal/query/introspection_test.go
Normal 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)
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
@@ -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
|
||||
}
|
||||
|
@@ -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)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@@ -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 " +
|
||||
|
@@ -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 " +
|
||||
|
@@ -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 " +
|
||||
|
@@ -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),
|
||||
|
@@ -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",
|
||||
|
@@ -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})),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
@@ -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),
|
||||
|
@@ -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})),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
@@ -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",
|
||||
},
|
||||
|
@@ -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",
|
||||
},
|
||||
|
@@ -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()
|
||||
}
|
||||
|
@@ -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,
|
||||
|
@@ -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{
|
||||
|
47
internal/query/testdata/userinfo_human.json
vendored
Normal file
47
internal/query/testdata/userinfo_human.json
vendored
Normal 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
|
||||
}
|
86
internal/query/testdata/userinfo_human_grants.json
vendored
Normal file
86
internal/query/testdata/userinfo_human_grants.json
vendored
Normal 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"
|
||||
}
|
||||
]
|
||||
}
|
30
internal/query/testdata/userinfo_human_no_md.json
vendored
Normal file
30
internal/query/testdata/userinfo_human_no_md.json
vendored
Normal 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
|
||||
}
|
40
internal/query/testdata/userinfo_machine.json
vendored
Normal file
40
internal/query/testdata/userinfo_machine.json
vendored
Normal 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
|
||||
}
|
6
internal/query/testdata/userinfo_not_found.json
vendored
Normal file
6
internal/query/testdata/userinfo_not_found.json
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"user": null,
|
||||
"org": null,
|
||||
"metadata": null,
|
||||
"user_grants": null
|
||||
}
|
@@ -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) {
|
||||
|
@@ -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")
|
||||
|
@@ -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{
|
||||
|
@@ -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 {
|
||||
|
@@ -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" +
|
||||
|
@@ -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")
|
||||
|
@@ -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",
|
||||
|
@@ -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",
|
||||
|
76
internal/query/userinfo.go
Normal file
76
internal/query/userinfo.go
Normal 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"`
|
||||
}
|
336
internal/query/userinfo_test.go
Normal file
336
internal/query/userinfo_test.go
Normal 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)
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user