Commit Graph
100 Commits
Author SHA1 Message Date
Tim MöhlmannandGitHub f27ca69749 fix(query): distinct count in user list (#10840)
# Which Problems Are Solved

When listing / searching users, each user got multiplied by the amount
of metadata entries they have, towards the `total_results` count. In
PostgreSQL the `COUNT(*) OVER()` window function does not support
`DISTINCT`. Even tho the query did a distinct select, the count would
still include duplicates.

# How the Problems Are Solved

Wrap the original query in a sub-select, so that the `DISTINCT` gets
handled before the count window function is executed in the outer
function. Filters, permission and solting is applied to the inner query.
Offset, limit and count are applied to the outer query.

# Additional Changes

- none

# Additional Context

- Closes https://github.com/zitadel/zitadel/issues/10825
- Backport to 4v
2025-10-14 09:43:59 +00:00
Tim MöhlmannandGitHub fcb05fd561 feat(relational): command permission check (#10771)
# Which Problems Are Solved

There is no implementation of the permission framework in the new
command pattern. We risk forgetting permission options as we are already
migrating the service layer to the new pattern.

# How the Problems Are Solved

Use an permission checker interface, which will be a sub-interface of
the Permission Repository. The permission checker is passed in the
command executor and invoker as part of the command options. From here
the implementation can call the correct permission method.

This PR proposes a check method for each
[level](https://github.com/zitadel/zitadel/wiki/Internal-AuthZ#levels).

# Additional Changes

- none 

# Additional Context

- Draft design:
https://github.com/zitadel/zitadel/wiki/Internal-AuthZ#enforcement
- Related for queries: https://github.com/zitadel/zitadel/pull/10756
2025-10-13 17:04:39 +02:00
Tim MöhlmannandGitHub a45908b364 feat(rt): project repository (#10789)
# Which Problems Are Solved

Add projects to the relational tables

# How the Problems Are Solved

- Define table migrations
- Define and implement Project and Project Role repositories.
- Provide projection handlers to populate the relational tables.

# Additional Changes

- Statement Builder now has a constructor which allows setting of a base
query with arguments.
- Certain operations, like Get, Update and Delete require the Primary
Key to be set as conditions. However, this requires knowledge of the
implementation and table definition. This PR proposes an additional
condition for repositories: `PrimaryKeyCondition`. This gives clarity on
the required IDs for these operations.
- Added couple of helpers to the repository package, to allow more DRY
code.
- getOne / getMany: generic functions for query execution and scanning.
- checkRestrictingColumns, checkPkCondition: simplify condition
checking, instead of using ladders of conditionals.
- Added a couple of helpers to the repository test package:
  - Transaction, savepoint and rollback helpers.
- Create instance and organization helpers for objects that depend on
them (like projects).

# Additional Context

- after https://github.com/zitadel/zitadel/pull/10809
- closes #10765
2025-10-01 09:47:04 +00:00
Tim MöhlmannandGitHub c7b333fb95 fix(rt): allow duplicate query arguments (#10809) 2025-09-27 15:16:15 +02:00
Tim MöhlmannandGitHub 5ba016e123 fix(rt): release client after migration (#10788)
#  Which Problems Are Solved

Relation table migrations do not release the client after migrations are
done.

# How the Problems Are Solved

Defer releasing of the client after acquire.

# Additional Changes

- rename two filenames with typos.

# Additional Context

- none
2025-09-25 07:46:06 +00:00
Tim MöhlmannandGitHub adc8fb2013 feat(repository): add permission check option (#10756) 2025-09-19 15:08:58 +00:00
Tim MöhlmannandGitHub f6f37d3a31 fix(cache): use key versioning (#10657)
# Which Problems Are Solved

Cached object may have a different schema between Zitadel versions.

# How the Problems Are Solved

Use the curent build version in DB based cache connectors PostgreSQL and
Redis.

# Additional Changes

- Cleanup the ZitadelVersion field from the authz Instance
- Solve potential race condition on global variables in build package.

# Additional Context

- Closes https://github.com/zitadel/zitadel/issues/10648
- Obsoletes https://github.com/zitadel/zitadel/pull/10646
- Needs to be back-ported to v4 over
https://github.com/zitadel/zitadel/pull/10645
2025-09-15 09:51:54 +00:00
Tim MöhlmannandGitHub 54554b8fb9 perf: drop instance position index (#10626)
# Which Problems Are Solved

There was an left-behind index introduced to optimize the old and
removed event execution handler. The index confuses prostgres and it
sometimes picks this index in favor of the projection specific index.
This sometimes leads to bad query performance in the projectio handlers.

# How the Problems Are Solved

Drop the index

# Additional Changes

- none

# Additional Context

- Forgotten in https://github.com/zitadel/zitadel/pull/10564
2025-09-10 09:26:22 +00:00
4440579f0a chore(deps): update to latest 1.24 go toolchain (#10667)
# Which Problems Are Solved

Update the Go toolchain to the latest bugfix release, so we include
latest security fixes in the standard library.

# How the Problems Are Solved

Set the toolchain directive to 1.24.7

# Additional Changes

- go mod tidy

# Additional Context

- https://go.dev/doc/devel/release#go1.24.0

Co-authored-by: Marco A. <[email protected]>
2025-09-08 09:32:36 +00:00
Tim MöhlmannandGitHub a06ae2c835 perf(cache): use redis unlink for key deletion (#10658)
# Which Problems Are Solved

The usage of the Redis `DEL` command showed blocking and slowdowns
during load-tests.

# How the Problems Are Solved

Use [`UNLINK`](https://redis.io/docs/latest/commands/UNLINK/) instead.

# Additional Changes

- none

# Additional Context

- closes https://github.com/zitadel/zitadel/issues/8930
2025-09-08 08:21:32 +00:00
a9ebc06c77 perf(actionsv2): execution target router (#10564)
# Which Problems Are Solved

The event execution system currently uses a projection handler that
subscribes to and processes all events for all instances. This creates a
high static cost because the system over-fetches event data, handling
many events that are not needed by most instances. This inefficiency is
also reflected in high "rows returned" metrics in the database.

# How the Problems Are Solved

Eliminate the use of a project handler. Instead, events for which
"execution targets" are defined, are directly pushed to the queue by the
eventstore. A Router is populated in the Instance object in the authz
middleware.

- By joining the execution targets to the instance, no additional
queries are needed anymore.
- As part of the instance object, execution targets are now cached as
well.
- Events are queued within the same transaction, giving transactional
guarantees on delivery.
- Uses the "insert many fast` variant of River. Multiple jobs are queued
in a single round-trip to the database.
- Fix compatibility with PostgreSQL 15

# Additional Changes

- The signing key was stored as plain-text in the river job payload in
the DB. This violated our [Secrets
Storage](https://zitadel.com/docs/concepts/architecture/secrets#secrets-storage)
principle. This change removed the field and only uses the encrypted
version of the signing key.
- Fixed the target ordering from descending to ascending.
- Some minor linter warnings on the use of `io.WriteString()`.

# Additional Context

- Introduced in https://github.com/zitadel/zitadel/pull/9249
- Closes https://github.com/zitadel/zitadel/issues/10553
- Closes https://github.com/zitadel/zitadel/issues/9832
- Closes https://github.com/zitadel/zitadel/issues/10372
- Closes https://github.com/zitadel/zitadel/issues/10492

---------

Co-authored-by: Stefan Benz <[email protected]>
2025-09-01 07:21:10 +02:00
Tim MöhlmannandGitHub 4cee0fec09 chore(ci): increase build-debug timeout (#10523)
# Which Problems Are Solved

Docker image build on arm64 was timing out on multiple occasions.

# How the Problems Are Solved

Increase the Debug job timeout from 3 to 5 minutes.

# Additional Changes

- none

# Additional Context

-
https://github.com/zitadel/zitadel/actions/runs/17091081442/job/48465066443
-
https://github.com/zitadel/zitadel/actions/runs/17071852582/job/48466980148
-
https://github.com/zitadel/zitadel/actions/runs/17071852582/job/48403039843
2025-08-20 09:03:00 +00:00
Tim MöhlmannandGitHub 26ec29a513 chore(deps): upgrade oidc and chi for dependabot alert (#10160)
# Which Problems Are Solved

Solve dependabot alerts for Go packages.

# How the Problems Are Solved

- Upgrade to latest github.com/zitadel/oidc, which already pulls the
fixed version of chi.
- Upgrade mapstructure

# Additional Changes

- none

# Additional Context

- https://github.com/zitadel/zitadel/security/dependabot/323
- https://github.com/zitadel/zitadel/security/dependabot/324
2025-07-04 11:14:37 +00:00
4cd52f33eb chore(oidc): remove feature flag for introspection triggers (#10132)
# Which Problems Are Solved

Remove the feature flag that allowed triggers in introspection. This
option was a fallback in case introspection would not function properly
without triggers. The API documentation asked for anyone using this flag
to raise an issue. No such issue was received, hence we concluded it is
safe to remove it.

# How the Problems Are Solved

- Remove flags from the system and instance level feature APIs.
- Remove trigger functions that are no longer used
- Adjust tests that used the flag.

# Additional Changes

- none

# Additional Context

- Closes #10026 
- Flag was introduced in #7356

---------

Co-authored-by: Silvan <[email protected]>
2025-06-30 05:48:04 +00:00
Tim MöhlmannandGitHub 016676e1dc chore(oidc): graduate webkey to stable (#10122)
# Which Problems Are Solved

Stabilize the usage of webkeys.

# How the Problems Are Solved

- Remove all legacy signing key code from the OIDC API
- Remove the webkey feature flag from proto
- Remove the webkey feature flag from console
- Cleanup documentation

# Additional Changes

- Resolved some canonical header linter errors in OIDC
- Use the constant for `projections.lock` in the saml package.

# Additional Context

- Closes #10029
- After #10105
- After #10061
2025-06-26 19:17:45 +03:00
1ebbe275b9 chore(oidc): remove legacy storage methods (#10061)
# Which Problems Are Solved

Stabilize the optimized introspection code and cleanup unused code.

# How the Problems Are Solved

- `oidc_legacy_introspection` feature flag is removed and reserved.
- `OPStorage` which are no longer needed have their bodies removed.
- The method definitions need to remain in place so the interface
remains implemented.
  - A panic is thrown in case any such method is still called

# Additional Changes

- A number of `OPStorage` methods related to token creation were already
unused. These are also cleaned up.

# Additional Context

- Closes #10027 
- #7822

---------

Co-authored-by: Livio Spring <[email protected]>
2025-06-26 08:08:37 +00:00
Tim MöhlmannandGitHub fa9de9a0f1 feat: generate webkeys setup step (#10105)
# Which Problems Are Solved

We are preparing to roll-out and stabilize webkeys in the next version
of Zitadel. Before removing legacy signing-key code, we must ensure all
existing instances have their webkeys generated.

# How the Problems Are Solved

Add a setup step which generate 2 webkeys for each existing instance
that didn't have webkeys yet.

# Additional Changes

Return an error from the config type-switch, when the type is unknown.

# Additional Context

- Part 1/2 of https://github.com/zitadel/zitadel/issues/10029
- Should be back-ported to v3
2025-06-24 11:41:41 +02:00
Tim MöhlmannandGitHub b9c1cdf4ad feat(projections): resource counters (#9979)
# Which Problems Are Solved

Add the ability to keep track of the current counts of projection
resources. We want to prevent calling `SELECT COUNT(*)` on tables, as
that forces a full scan and sudden spikes of DB resource uses.

# How the Problems Are Solved

- A resource_counts table is added
- Triggers that increment and decrement the counted values on inserts
and deletes
- Triggers that delete all counts of a table when the source table is
TRUNCATEd. This is not in the business logic, but prevents wrong counts
in case someone want to force a re-projection.
- Triggers that delete all counts if the parent resource is deleted
- Script to pre-populate the resource_counts table when a new source
table is added.

The triggers are reusable for any type of resource, in case we choose to
add more in the future.
Counts are aggregated by a given parent. Currently only `instance` and
`organization` are defined as possible parent. This can later be
extended to other types, such as `project`, should the need arise.

I deliberately chose to use `parent_id` to distinguish from the
de-factor `resource_owner` which is usually an organization ID. For
example:

- For users the parent is an organization and the `parent_id` matches
`resource_owner`.
- For organizations the parent is an instance, but the `resource_owner`
is the `org_id`. In this case the `parent_id` is the `instance_id`.
- Applications would have a similar problem, where the parent is a
project, but the `resource_owner` is the `org_id`


# Additional Context

Closes https://github.com/zitadel/zitadel/issues/9957
2025-06-03 14:15:30 +00:00
Tim MöhlmannandGitHub 4480cfcf56 docs(advisory): position precision fix (#9882)
# Which Problems Are Solved

We are deploying precision fixes on the `position` values of the
eventstore. The fix itself might break systems that were already
affected by the bug.

# How the Problems Are Solved

Add a technical advisory that explains background and steps to fix the
Zitadel database when affected.

# Additional Context

- Original issue: [8671](https://github.com/zitadel/zitadel/issues/8671)
- Follow-up issue:
[8863](https://github.com/zitadel/zitadel/issues/8863)
- Re-fix: https://github.com/zitadel/zitadel/pull/9881
2025-05-16 10:41:35 +02:00
Tim MöhlmannandGitHub bb56b362a7 perf(eventstore): add instance position index (#9837)
# Which Problems Are Solved

Some projection queries took a long time to run. It seems that 1 or more
queries couldn't make proper use of the `es_projection` index. This
might be because of a specific complexity aggregate_type and event_type
arguments, making the index unfeasible for postgres.

# How the Problems Are Solved

Following the index recommendation, add and index that covers just
instance_id and position.

# Additional Changes

- none

# Additional Context

- Related to https://github.com/zitadel/zitadel/issues/9832
2025-05-02 13:40:22 +02:00
Tim MöhlmannandGitHub 0465d5093e fix(features): remove the improved performance enumer (#9819)
# Which Problems Are Solved

Instance that had improved performance flags set, got event errors when
getting instance features. This is because the improved performance
flags were marshalled using the enumerated integers, but now needed to
be unmashalled using the added UnmarshallText method.

# How the Problems Are Solved

- Remove emnumer generation

# Additional Changes

- none

# Additional Context

- reported on QA
- Backport to next-rc / v3
2025-04-30 08:26:04 +00:00
91bc71db74 fix(instance): add web key generation to instance defaults (#9815)
# Which Problems Are Solved

Webkeys were not generated with new instances when the webkey feature
flag was enabled for instance defaults. This would cause a redirect loop
with console for new instances on QA / coud.

# How the Problems Are Solved

- uncomment the webkeys section on defaults.yaml
- Fix field naming of webkey config

# Additional Changes

- Add all available features as comments.
- Make the improved performance type enum parsable from the config,
untill now they were just ints.
- Running of the enumer command created missing enum entries for feature
keys.

# Additional Context

- Needs to be back-ported to v3 / next-rc

Co-authored-by: Livio Spring <[email protected]>
2025-04-29 14:54:53 +00:00
Tim MöhlmannandGitHub 658ca3606b feat(permissions): project member permission filter (#9757)
# Which Problems Are Solved

Add the possibility to filter project resources based on project member
roles.

# How the Problems Are Solved

Extend and refactor existing Pl/PgSQL functions to implement the
following:

- Solve O(n) complexity in returned resources IDs by returning a boolean
filter for instance level permissions.
- Individually permitted orgs are returned only if there was no instance
permission
- Individually permitted projects are returned only if there was no
instance permission
- Because of the multiple filter terms, use `INNER JOIN`s instead of
`WHERE` clauses.

# Additional Changes

- system permission function no longer query the organization view and
therefore can be `immutable`, giving big performance benefits for
frequently reused system users. (like our hosted login in Zitadel cloud)
- The permitted org and project functions are now defined as `stable`
because the don't modify on-disk data. This might give a small
performance gain
- The Pl/PgSQL functions are now tested using Go unit tests.

# Additional Context

- Depends on https://github.com/zitadel/zitadel/pull/9677
- Part of https://github.com/zitadel/zitadel/issues/9188
- Closes https://github.com/zitadel/zitadel/issues/9190
2025-04-22 08:42:59 +00:00
Tim MöhlmannandGitHub a2f60f2e7a perf(query): org permission function for resources (#9677)
# Which Problems Are Solved

Classic permission checks execute for every returned row on resource
based search APIs. Complete background and problem definition can be
found here: https://github.com/zitadel/zitadel/issues/9188

# How the Problems Are Solved

- PermissionClause function now support dynamic query building, so it
supports multiple cases.
- PermissionClause is applied to all list resources which support org
level permissions.
- Wrap permission logic into wrapper functions so we keep the business
logic clean.

# Additional Changes

- Handle org ID optimization in the query package, so it is reusable for
all resources, instead of extracting the filter in the API.
- Cleanup and test system user conversion in the authz package. (context
middleware)
- Fix: `core_integration_db_up` make recipe was missing the postgres
service.

# Additional Context

- Related to https://github.com/zitadel/zitadel/issues/9190
2025-04-15 18:38:25 +02:00
c3258ecf78 chore(deps): upgrade go mods from zitadel organization (#9601)
# Which Problems Are Solved

Outdated dependencies foir packages developed by Zitadel.
Some of them included important security updates from sub-dependencies.

# How the Problems Are Solved

Upgrade all packages under `github.com/zitadel/*` to the latest released
version.

# Additional Changes

- The `github.com/superseriousbusiness/exifremove` was removed from
Github. We copied the cached go mod code to
https://github.com/zitadel/exifremove and use this module now.

# Additional Context

- Related to https://github.com/zitadel/zitadel/issues/9422
- Closes https://github.com/zitadel/zitadel/issues/9443

---------

Co-authored-by: Livio Spring <[email protected]>
2025-03-24 06:03:24 +00:00
e670b9126c fix(permissions): chunked synchronization of role permission events (#9403)
# Which Problems Are Solved

Setup fails to push all role permission events when running Zitadel with
CockroachDB. `TransactionRetryError`s were visible in logs which finally
times out the setup job with `timeout: context deadline exceeded`

# How the Problems Are Solved

As suggested in the [Cockroach documentation](timeout: context deadline
exceeded), _"break down larger transactions"_. The commands to be pushed
for the role permissions are chunked in 50 events per push. This
chunking is only done with CockroachDB.

# Additional Changes

- gci run fixed some unrelated imports
- access to `command.Commands` for the setup job, so we can reuse the
sync logic.

# Additional Context

Closes #9293

---------

Co-authored-by: Silvan <[email protected]>
2025-02-26 16:06:50 +00:00
bcc6a689fa fix(setup): use template for in_tx_order type (#9346)
# Which Problems Are Solved

Systems running with PostgreSQL before Zitadel v2.39 are likely to have
a wrong type for the `in_tx_order` column in the `eventstore.event2`
table. The migration at the time used the `event_sequence` as default
value without typecast, which results in a `bigint` type for that
column. However, when creating the table from scratch, we explicitly
specify the type to be `integer`.

Starting from Zitadel v2.67 we use a Pl/PgSQL function to push events.
The function requires the types from `eventstore.events2` to the same as
the `select` destinations used in the function. In the function
`in_tx_order` is also expected to by of `integer` type.

CochroachDB systems are not affected because `bigint` is an alias to the
`int` type. In other words, CockroachDB uses `int8` when specifying type
`int`. Therefore the types already match.

# How the Problems Are Solved

Retrieve the actual column type currently in use. A template is used to
assign the type to the `ordinality` column returned as `in_tx_order`.

# Additional Changes

- Detailed logging on migration failure

# Additional Context

- Closes #9180

---------

Co-authored-by: Silvan <[email protected]>
2025-02-12 11:06:34 +00:00
Tim MöhlmannandGitHub b6841251b1 feat(users/v2): return prompt information (#9255)
# Which Problems Are Solved

Add the ability to update the timestamp when MFA initialization was last
skipped.
Get User By ID now also returns the timestamps when MFA setup was last
skipped.

# How the Problems Are Solved

- Add a `HumanMFAInitSkipped` method to the `users/v2` API.
- MFA skipped was already projected in the `auth.users3` table. In this
PR the same column is added to the users projection. Event handling is
kept the same as in the `UserView`:

<details>


https://github.com/zitadel/zitadel/blob/62804ca45f804322e54831aeb2c9be9128ae60ca/internal/user/repository/view/model/user.go#L243-L377

</details>

# Additional Changes

- none

# Additional Context

- Closes https://github.com/zitadel/zitadel/issues/9197
2025-01-29 15:12:31 +00:00
Tim MöhlmannandGitHub ec5f18c168 fix(setup): split membership fields migration (#9230)
# Which Problems Are Solved

The membership fields migration timed out in certain cases. It also
tried to migrate instances which were already removed.

# How the Problems Are Solved

Revert the previous fix that combined the repeatable step for multiple
fill triggers. The membeship migration is now single-run as it might
take a lot of time. It is not worth making it repeatable. Instance IDs
of removed instances are skipped.

# Additional Changes

None

# Additional Context

Introduced in https://github.com/zitadel/zitadel/pull/9199
2025-01-24 11:24:35 +01:00
Tim MöhlmannandGitHub 94cbf97534 fix(permissions_v2): add membership fields migration (#9199)
# Which Problems Are Solved

Memberships did not have a fields table fill migration.

# How the Problems Are Solved

Add filling of membership fields to the repeatable steps.

# Additional Changes

- Use the same repeatable step for multiple fill fields handlers.
- Fix an error for PostgreSQL 15 where a subquery in a `FROM` clause
needs an alias ing the `permitted_orgs` function.

# Additional Context

- Part of https://github.com/zitadel/zitadel/issues/9188
- Introduced in https://github.com/zitadel/zitadel/pull/9152
2025-01-17 16:16:26 +01:00
Tim MöhlmannandGitHub 3f6ea78c87 perf: role permissions in database (#9152)
# Which Problems Are Solved

Currently ZITADEL defines organization and instance member roles and
permissions in defaults.yaml. The permission check is done on API call
level. For example: "is this user allowed to make this call on this
org". This makes sense on the V1 API where the API is permission-level
shaped. For example, a search for users always happens in the context of
the organization. (Either the organization the calling user belongs to,
or through member ship and the x-zitadel-orgid header.

However, for resource based APIs we must be able to resolve permissions
by object. For example, an IAM_OWNER listing users should be able to get
all users in an instance based on the query filters. Alternatively a
user may have user.read permissions on one or more orgs. They should be
able to read just those users.

# How the Problems Are Solved

## Role permission mapping

The role permission mappings defined from `defaults.yaml` or local
config override are synchronized to the database on every run of
`zitadel setup`:

- A single query per **aggregate** builds a list of `add` and `remove`
actions needed to reach the desired state or role permission mappings
from the config.
- The required events based on the actions are pushed to the event
store.
- Events define search fields so that permission checking can use the
indices and is strongly consistent for both query and command sides.

The migration is split in the following aggregates:

- System aggregate for for roles prefixed with `SYSTEM`
- Each instance for roles not prefixed with `SYSTEM`. This is in
anticipation of instance level management over the API.

## Membership

Current instance / org / project membership events now have field table
definitions. Like the role permissions this ensures strong consistency
while still being able to use the indices of the fields table. A
migration is provided to fill the membership fields.

## Permission check

I aimed keeping the mental overhead to the developer to a minimal. The
provided implementation only provides a permission check for list
queries for org level resources, for example users. In the `query`
package there is a simple helper function `wherePermittedOrgs` which
makes sure the underlying database function is called as part of the
`SELECT` query and the permitted organizations are part of the `WHERE`
clause. This makes sure results from non-permitted organizations are
omitted. Under the hood:

- A Pg/PlSQL function searches for a list of organization IDs the passed
user has the passed permission.
- When the user has the permission on instance level, it returns early
with all organizations.
- The functions uses a number of views. The views help mapping the
fields entries into relational data and simplify the code use for the
function. The views provide some pre-filters which allow proper index
usage once the final `WHERE` clauses are set by the function.

# Additional Changes



# Additional Context

Closes #9032
Closes https://github.com/zitadel/zitadel/issues/9014

https://github.com/zitadel/zitadel/issues/9188 defines follow-ups for
the new permission framework based on this concept.
2025-01-16 10:09:15 +00:00
df2c6f1d4c perf(eventstore): optimize commands to events function (#9092)
# Which Problems Are Solved

We were seeing high query costs in a the lateral join executed in the
commands_to_events procedural function in the database. The high cost
resulted in incremental CPU usage as a load test continued and less
req/sec handled, sarting at 836 and ending at 130 req/sec.

# How the Problems Are Solved

1. Set `PARALLEL SAFE`. I noticed that this option defaults to `UNSAFE`.
But it's actually safe if the function doesn't `INSERT`
2. Set the returned `ROWS 10` parameter.
3. Function is re-written in Pl/PgSQL so that we eliminate expensive
joins.
4. Introduced an intermediate state that does `SELECT DISTINCT` for the
aggregate so that we don't have to do an expensive lateral join.

# Additional Changes

Use a `COALESCE` to get the owner from the last event, instead of a
`CASE` switch.

# Additional Context

- Function was introduced in
https://github.com/zitadel/zitadel/pull/8816
- Closes https://github.com/zitadel/zitadel/issues/8352

---------

Co-authored-by: Silvan <[email protected]>
2025-01-08 11:59:44 +00:00
Tim MöhlmannandGitHub db8d794794 fix(oidc): ignore algorithm for legacy signer (#9148)
# Which Problems Are Solved

It was possible to set a diffent algorithm for the legacy signer. This
is not supported howerver and breaks the token endpoint.

# How the Problems Are Solved

Remove the OIDC.SigningKeyAlgorithm config option and hard-code RS256
for the legacy signer.

# Additional Changes

- none

# Additional Context

Only RS256 is supported by the legacy signer. It was mentioned in the
comment of the config not to use it and use the webkeys resource
instead.

- closes #9121
2025-01-08 08:40:33 +00:00
Tim MöhlmannandGitHub 56427cca50 fix(cache): convert expiry to number (#9143)
# Which Problems Are Solved

When `LastUseAge` was configured properly, the Redis LUA script uses
manual cleanup for `MaxAge` based expiry. The expiry obtained from Redis
apears to be a string and was compared to an int, resulting in a script
error.

# How the Problems Are Solved

Convert expiry to number.

# Additional Changes

- none

# Additional Context

- Introduced in #8822
- LastUseAge was fixed in #9097
- closes https://github.com/zitadel/zitadel/issues/9140
2025-01-07 12:51:06 +01:00
Tim MöhlmannandGitHub da706a8b30 fix(setup): make step 39 repeatable (#9085)
# Which Problems Are Solved

When downgrading zitadel and upgrading it again, it might be that orgs
deleted in this period still have stale entries in the fields table.

# How the Problems Are Solved

- Make the cleanup repeatable
- Scope the query by instance so that an index is used.
2024-12-18 16:48:22 +01:00
Tim MöhlmannandGitHub 6f6e2234eb fix(migrations): clean stale org fields using events (#9051)
# Which Problems Are Solved

Migration step 39 is supposed to cleanup stale organization entries in
the eventstore.fields table. In order to do this it used the projection
to check which orgs still exist.

During initial setup of ZITADEL the first instance with the organization
is created. Howevet, the projections are filled after all migrations are
done. With the organization projection empty, the fields of the first
org would be deleted.

This was discovered during development of a new field type. The
accosiated events did not yet have any projection based filled assigned.
It seems fields with a pre-fill projection are somehow restored.
Therefore a restoration migration isn't required IMO.

# How the Problems Are Solved

Query the event store for `org.removed` events instead. This has the
drawback of using a sequential scan on the eventstore, making the
migration more expensive.

# Additional Changes

- none

# Additional Context

- Introduced in https://github.com/zitadel/zitadel/pull/8946
2024-12-12 18:37:18 +02:00
Tim MöhlmannandGitHub 83bdaf43c3 docs(events-api): user auth example using OIDC session events (#9020)
# Which Problems Are Solved

Integration guide with event API examples used outdated
`user.token.added` events which are no longer produced by ZITADEL.

# How the Problems Are Solved

Modify the example to use events from the `oidc_session` aggregate.

# Additional Changes

- Add a TODO for related SAML events.

# Additional Context

- Related to https://github.com/zitadel/zitadel/issues/8983
2024-12-10 10:54:07 +00:00
Tim MöhlmannandGitHub ee7beca61f fix(cache): ignore NOSCRIPT errors in redis circuit breaker (#9022)
# Which Problems Are Solved

When Zitadel starts the first time with a configured Redis cache, the
circuit break would open on the first requests, with no explanatory
error and only log-lines explaining the state of the Circuit breaker.

Using a debugger, `NOSCRIPT No matching script. Please use EVAL.` was
found the be passed to `Limiter.ReportResult`. This error is actually
retried by go-redis after a
[`Script.Run`](https://pkg.go.dev/github.com/redis/go-redis/[email protected]#Script.Run):

> Run optimistically uses EVALSHA to run the script. If script does not
exist it is retried using EVAL.

# How the Problems Are Solved

Add the `NOSCRIPT` error prefix to the whitelist.

# Additional Changes

- none

# Additional Context

- Introduced in: https://github.com/zitadel/zitadel/pull/8890
- Workaround for: https://github.com/redis/go-redis/issues/3203
2024-12-09 08:20:21 +00:00
a81d42a61a fix(eventstore): set created filters to exclusion sub-query (#9019)
# Which Problems Are Solved

In eventstore queries with aggregate ID exclusion filters, filters on
events creation date where not passed to the sub-query. This results in
a high amount of returned rows from the sub-query and high overall query
cost.

# How the Problems Are Solved

When CreatedAfter and CreatedBefore are used on the global search query,
copy those filters to the sub-query. We already did this for the
position column filter.

# Additional Changes

- none

# Additional Context

- Introduced in https://github.com/zitadel/zitadel/pull/8940

Co-authored-by: Livio Spring <[email protected]>
2024-12-06 11:20:10 +01:00
Tim MöhlmannandGitHub 4413efd82c chore: remove parallel running in integration tests (#8904)
# Which Problems Are Solved

Integration tests are flaky due to eventual consistency.

# How the Problems Are Solved

Remove t.Parallel so that less concurrent requests on multiple instance
happen. This allows the projections to catch up more easily.

# Additional Changes

- none

# Additional Context

- none
2024-11-27 15:32:13 +01:00
ccef67cefa fix(eventstore): cleanup org fields on remove (#8946)
# Which Problems Are Solved

When an org is removed, the corresponding fields are not deleted. This
creates issues, such as recreating a new org with the same verified
domain.

# How the Problems Are Solved

Remove the search fields by the org aggregate, instead of just setting
the removed state.

# Additional Changes

- Cleanup migration script that removed current stale fields.

# Additional Context

- Closes https://github.com/zitadel/zitadel/issues/8943
- Related to https://github.com/zitadel/zitadel/pull/8790

---------

Co-authored-by: Silvan <[email protected]>
2024-11-26 15:26:41 +00:00
ff70ede7c7 feat(eventstore): exclude aggregate IDs when event_type occurred (#8940)
# Which Problems Are Solved

For truly event-based notification handler, we need to be able to filter
out events of aggregates which are already handled. For example when an
event like `notify.success` or `notify.failed` was created on an
aggregate, we no longer require events from that aggregate ID.

# How the Problems Are Solved

Extend the query builder to use a `NOT IN` clause which excludes
aggregate IDs when they have certain events for a certain aggregate
type. For optimization and proper index usages, certain filters are
inherited from the parent query, such as:

- Instance ID
- Instance IDs
- Position offset

This is a prettified query as used by the unit tests:

```sql
SELECT created_at, event_type, "sequence", "position", payload, creator, "owner", instance_id, aggregate_type, aggregate_id, revision
FROM eventstore.events2
WHERE instance_id = $1
    AND aggregate_type = $2 
    AND event_type = $3
    AND "position" > $4
    AND aggregate_id NOT IN (
        SELECT aggregate_id
        FROM eventstore.events2
        WHERE aggregate_type = $5
        AND event_type = ANY($6)
        AND instance_id = $7
        AND "position" > $8
    )
ORDER BY "position" DESC, in_tx_order DESC
LIMIT $9
```

I used this query to run it against the `oidc_session` aggregate looking
for added events, excluding aggregates where a token was revoked,
against a recent position. It fully used index scans:

<details>

```json
[
  {
    "Plan": {
      "Node Type": "Index Scan",
      "Parallel Aware": false,
      "Async Capable": false,
      "Scan Direction": "Forward",
      "Index Name": "es_projection",
      "Relation Name": "events2",
      "Alias": "events2",
      "Actual Rows": 2,
      "Actual Loops": 1,
      "Index Cond": "((instance_id = '286399006995644420'::text) AND (aggregate_type = 'oidc_session'::text) AND (event_type = 'oidc_session.added'::text) AND (\"position\" > 1731582100.784168))",
      "Rows Removed by Index Recheck": 0,
      "Filter": "(NOT (hashed SubPlan 1))",
      "Rows Removed by Filter": 1,
      "Plans": [
        {
          "Node Type": "Index Scan",
          "Parent Relationship": "SubPlan",
          "Subplan Name": "SubPlan 1",
          "Parallel Aware": false,
          "Async Capable": false,
          "Scan Direction": "Forward",
          "Index Name": "es_projection",
          "Relation Name": "events2",
          "Alias": "events2_1",
          "Actual Rows": 1,
          "Actual Loops": 1,
          "Index Cond": "((instance_id = '286399006995644420'::text) AND (aggregate_type = 'oidc_session'::text) AND (event_type = 'oidc_session.access_token.revoked'::text) AND (\"position\" > 1731582100.784168))",
          "Rows Removed by Index Recheck": 0
        }
      ]
    },
    "Triggers": [
    ]
  }
]
```

</details>

# Additional Changes

- None

# Additional Context

- Related to https://github.com/zitadel/zitadel/issues/8931

---------

Co-authored-by: adlerhurst <[email protected]>
2024-11-25 15:25:11 +00:00
Tim MöhlmannandGitHub d4389ab359 feat(eventstore): add row locking option (#8939)
# Which Problems Are Solved

We need a reliable way to lock events that are being processed as part
of a job queue. For example in the notification handlers.

# How the Problems Are Solved

Allow setting `FOR UPDATE [ NOWAIT | SKIP LOCKED ]` to the eventstore
query builder using an open transaction.

- NOWAIT returns an errors if the lock cannot be obtained
- SKIP LOCKED only returns row which are not locked.
- Default is to wait for the lock to be released.

# Additional Changes

- none

# Additional Context

- [Locking
docs](https://www.postgresql.org/docs/17/sql-select.html#SQL-FOR-UPDATE-SHARE)
- Related to https://github.com/zitadel/zitadel/issues/8931
2024-11-21 14:46:30 +00:00
Tim MöhlmannandGitHub c165ed07f4 feat(cache): organization (#8903)
# Which Problems Are Solved

Organizations are ofter searched for by ID or primary domain. This
results in many redundant queries, resulting in a performance impact.

# How the Problems Are Solved

Cache Organizaion objects by ID and primary domain.

# Additional Changes

- Adjust integration test config to use all types of cache.
- Adjust integration test lifetimes so the pruner has something to do
while the tests run.

# Additional Context

- Closes #8865
- After #8902
2024-11-21 08:05:03 +02:00
Tim MöhlmannandGitHub c31b5df73b docs: add caches documentation (#8902)
# Which Problems Are Solved

Explain the usage of the new cache mechanisms.

# How the Problems Are Solved

Provide a dedicated page on caches with reference to `defaults.yaml`.

# Additional Changes

- Fix a broken link tag in token exchange docs.

# Additional Context

- Closes #8855
2024-11-19 10:56:10 +01:00
Tim MöhlmannandGitHub 65e24b67da chore(load-test): disable userinfo after JWT profile (#8927)
# Which Problems Are Solved

Load-test requires single endpoint to be used for each test type.

# How the Problems Are Solved

Remove userinfo call from machine tests.

# Additional Changes

- Add load-test/.env to gitignore.

# Additional Context

- Related to #4424
2024-11-19 09:53:07 +01:00
Tim MöhlmannandGitHub b77901cb4b fix(cache): unset client and user names in defaults (#8901)
# Which Problems Are Solved

By having default entries in the `Username` and `ClientName` fields, it
was not possible to unset there parameters. Unsetting them is required
for GCP connections

# How the Problems Are Solved

Set the fields to empty strings.

# Additional Changes

- none

# Additional Context

- none
2024-11-13 21:18:47 +00:00
Tim MöhlmannandGitHub 3b7b0c69e6 feat(cache): redis circuit breaker (#8890)
# Which Problems Are Solved

If a redis cache has connection issues or any other type of permament
error,
it tanks the responsiveness of ZITADEL.
We currently do not support things like Redis cluster or sentinel. So
adding a simple redis cache improves performance but introduces a single
point of failure.

# How the Problems Are Solved

Implement a [circuit
breaker](https://learn.microsoft.com/en-us/previous-versions/msp-n-p/dn589784(v=pandp.10)?redirectedfrom=MSDN)
as
[`redis.Limiter`](https://pkg.go.dev/github.com/redis/go-redis/v9#Limiter)
by wrapping sony's [gobreaker](https://github.com/sony/gobreaker)
package. This package is picked as it seems well maintained and we
already use their `sonyflake` package

# Additional Changes

- The unit tests constructed an unused `redis.Client` and didn't cleanup
the connector. This is now fixed.

# Additional Context

Closes #8864
2024-11-13 19:11:48 +01:00
Tim MöhlmannandGitHub 778b4041ca fix(oidc): do not return access token for response type id_token (#8777)
# Which Problems Are Solved

Do not return an access token for implicit flow from v1 login, if the
`response_type` is `id_token`

# How the Problems Are Solved

Do not create the access token event if if the `response_type` is
`id_token`.

# Additional Changes

Token endpoint calls without auth request, such as machine users, token
exchange and refresh token, do not have a `response_type`. For such
calls the `OIDCResponseTypeUnspecified` enum is added at a `-1` offset,
in order not to break existing client configs.

# Additional Context

- https://discord.com/channels/927474939156643850/1294001717725237298
- Fixes https://github.com/zitadel/zitadel/issues/8776
2024-11-12 15:20:48 +00:00
Tim MöhlmannandGitHub 250f2344c8 feat(cache): redis cache (#8822)
# Which Problems Are Solved

Add a cache implementation using Redis single mode. This does not add
support for Redis Cluster or sentinel.

# How the Problems Are Solved

Added the `internal/cache/redis` package. All operations occur
atomically, including setting of secondary indexes, using LUA scripts
where needed.

The [`miniredis`](https://github.com/alicebob/miniredis) package is used
to run unit tests.

# Additional Changes

- Move connector code to `internal/cache/connector/...` and remove
duplicate code from `query` and `command` packages.
- Fix a missed invalidation on the restrictions projection

# Additional Context

Closes #8130
2024-11-04 10:44:51 +00:00
Tim MöhlmannandGitHub 9cf67f30b8 fix(milestones): offset the type enum (#8849)
# Which Problems Are Solved

Migration of milestones failed on our QA due to the new milestone Type
enum being 0-indexed. The valid range was 0 till 5, inclusive. While on
the previous zitadel version this was 1 till 6, inclusive.

# How the Problems Are Solved

Offset the first constant with `1`.

# Additional Changes

- none

# Additional Context

Introduced in https://github.com/zitadel/zitadel/pull/8788
2024-10-31 12:03:40 +01:00
Tim MöhlmannandGitHub 32bad3feb3 perf(milestones): refactor (#8788)
# Which Problems Are Solved

Milestones used existing events from a number of aggregates. OIDC
session is one of them. We noticed in load-tests that the reduction of
the oidc_session.added event into the milestone projection is a costly
business with payload based conditionals. A milestone is reached once,
but even then we remain subscribed to the OIDC events. This requires the
projections.current_states to be updated continuously.


# How the Problems Are Solved

The milestone creation is refactored to use dedicated events instead.
The command side decides when a milestone is reached and creates the
reached event once for each milestone when required.

# Additional Changes

In order to prevent reached milestones being created twice, a migration
script is provided. When the old `projections.milestones` table exist,
the state is read from there and `v2` milestone aggregate events are
created, with the original reached and pushed dates.

# Additional Context

- Closes https://github.com/zitadel/zitadel/issues/8800
2024-10-28 08:29:34 +00:00
Tim MöhlmannandGitHub 4ebc23aa1f fix(load-test): correct k6 command (#8760) 2024-10-15 14:26:16 +02:00
Tim MöhlmannandGitHub 17303d1524 perf(milestones): remove legacy token event reducer (#8747)
# Which Problems Are Solved

Since the optiimzation of the token endpoint, we longer push the
`user.token.added` event. However, the milestone projection keeps
quering for it, including a payload query.

This incured a static waste of DB resources.

# How the Problems Are Solved

Remove the `user.token.added` event reducer from the milestone
projection

# Additional Changes

- none

# Additional Context

- Related to https://github.com/zitadel/zitadel/issues/8742. Other
changes ommitted so this PR can be backported to stable.
2024-10-09 08:00:07 +00:00
Tim MöhlmannandGitHub a84b259e8c perf(oidc): nest position clause for session terminated query (#8738)
# Which Problems Are Solved

Optimize the query that checks for terminated sessions in the access
token verifier. The verifier is used in auth middleware, userinfo and
introspection.


# How the Problems Are Solved

The previous implementation built a query for certain events and then
appended a single `PositionAfter` clause. This caused the postgreSQL
planner to use indexes only for the instance ID, aggregate IDs,
aggregate types and event types. Followed by an expensive sequential
scan for the position. This resulting in internal over-fetching of rows
before the final filter was applied.


![Screenshot_20241007_105803](https://github.com/user-attachments/assets/f2d91976-be87-428b-b604-a211399b821c)

Furthermore, the query was searching for events which are not always
applicable. For example, there was always a session ID search and if
there was a user ID, we would also search for a browser fingerprint in
event payload (expensive). Even if those argument string would be empty.

This PR changes:

1. Nest the position query, so that a full `instance_id, aggregate_id,
aggregate_type, event_type, "position"` index can be matched.
2. Redefine the `es_wm` index to include the `position` column.
3. Only search for events for the IDs that actually have a value. Do not
search (noop) if none of session ID, user ID or fingerpint ID are set.

New query plan:


![Screenshot_20241007_110648](https://github.com/user-attachments/assets/c3234c33-1b76-4b33-a4a9-796f69f3d775)


# Additional Changes

- cleanup how we load multi-statement migrations and make that a bit
more reusable.

# Additional Context

- Related to https://github.com/zitadel/zitadel/issues/7639
2024-10-07 12:49:55 +00:00
25dc7bfe72 perf(cache): pgx pool connector (#8703)
# Which Problems Are Solved

Cache implementation using a PGX connection pool.

# How the Problems Are Solved

Defines a new schema `cache` in the zitadel database.
A table for string keys and a table for objects is defined.
For postgreSQL, tables are unlogged and partitioned by cache name for
performance.

Cockroach does not have unlogged tables and partitioning is an
enterprise feature that uses alternative syntax combined with sharding.
Regular tables are used here.

# Additional Changes

- `postgres.Config` can return a pxg pool. See following discussion

# Additional Context

- Part of https://github.com/zitadel/zitadel/issues/8648
- Closes https://github.com/zitadel/zitadel/issues/8647

---------

Co-authored-by: Silvan <[email protected]>
2024-10-04 13:15:41 +00:00
63d733b3a2 perf(oidc): disable push of user token meta-event (#8691)
# Which Problems Are Solved

When executing many concurrent authentication requests on a single
machine user, there were performance issues. As the same aggregate is
being searched and written to concurrently, we traced it down to a
locking issue on the used index.
We already optimized the token endpoint by creating a separate OIDC
aggregate.

At the time we decided to push a single event to the user aggregate, for
the user audit log. See [technical advisory
10010](https://zitadel.com/docs/support/advisory/a10010) for more
details.

However, a recent security fix introduced an additional search query on
the user aggregate, causing the locking issue we found.

# How the Problems Are Solved

Add a feature flag which disables pushing of the `user.token.v2.added`.
The event has no importance and was only added for informational
purposes on the user objects. The `oidc_session.access_token.added` is
the actual payload event and is pushed on the OIDC session aggregate and
can still be used for audit trail.

# Additional Changes

- Fix an event mapper type for
`SystemOIDCSingleV1SessionTerminationEventType`

# Additional Context

- Reported by support request
- https://github.com/zitadel/zitadel/pull/7822 changed the token
aggregate
- https://github.com/zitadel/zitadel/pull/8631 introduced user state
check

Load test trace graph with `user.token.v2.added` **enabled**. Query
times are steadily increasing:


![image](https://github.com/user-attachments/assets/4aa25055-8721-4e93-b695-625560979909)

Load test trace graph with `user.token.v2.added` **disabled**. Query
times constant:


![image](https://github.com/user-attachments/assets/a7657f6c-0c55-401b-8291-453da5d5caf9)

---------

Co-authored-by: Livio Spring <[email protected]>
2024-09-26 13:55:41 +00:00
Tim MöhlmannandGitHub 4eaa3163b6 feat(storage): generic cache interface (#8628)
# Which Problems Are Solved

We identified the need of caching.
Currently we have a number of places where we use different ways of
caching, like go maps or LRU.
We might also want shared chaches in the future, like Redis-based or in
special SQL tables.

# How the Problems Are Solved

Define a generic Cache interface which allows different implementations.

- A noop implementation is provided and enabled as.
- An implementation using go maps is provided
  - disabled in defaults.yaml
  - enabled in integration tests
- Authz middleware instance objects are cached using the interface.

# Additional Changes

- Enabled integration test command raceflag
- Fix a race condition in the limits integration test client
- Fix a number of flaky integration tests. (Because zitadel is super
fast now!) 🎸 🚀

# Additional Context

Related to https://github.com/zitadel/zitadel/issues/8648
2024-09-25 21:40:21 +02:00
Tim MöhlmannandGitHub aeb379e7de fix(eventstore): revert precise decimal (#8527) (#8679) 2024-09-24 18:43:29 +02:00
77aa02a521 fix(projection): increase transaction duration (#8632)
# Which Problems Are Solved

Reduce the chance for projection dead-locks. Increasing or disabling the
projection transaction duration solved dead-locks in all reported cases.

# How the Problems Are Solved

Increase the default transaction duration to 1 minute.
Due to the high value it is functionally similar to disabling,
however it still provides a safety net for transaction that do freeze,
perhaps due to connection issues with the database.


# Additional Changes

- Integration test uses default.
- Technical advisory

# Additional Context

- Related to https://github.com/zitadel/zitadel/issues/8517

---------

Co-authored-by: Silvan <[email protected]>
2024-09-17 10:08:13 +00:00
Tim MöhlmannandGitHub 3b140a67c8 fix(oidc): always set sub claim (#8598)
# Which Problems Are Solved

When the `openid` scope was not requested, as is possible in machine
authentication, we didn't set the `sub` (subject) claim to tokens and
possibly also userInfo and introspection.

This fix always sets the `sub` claim for all cases.

# How the Problems Are Solved

Set the `Subject` field to regardless of passed scopes.

# Additional Changes

- none

# Additional Context

According to standards:

- [RFC9068 - JSON Web Token (JWT) Profile for OAuth 2.0 Access
Tokens](https://datatracker.ietf.org/doc/html/rfc9068#name-data-structure)
this claim is **required**.
- [RFC7667 - OAuth 2.0 Token
Introspection](https://datatracker.ietf.org/doc/html/rfc7662#section-2.2)
the claim is optional, however there is no correlation to the `openid`
or OpenID Connect. Therefore it doesn't harm to always return this
claim.
- [OpenID connect, User Info
Response](https://openid.net/specs/openid-connect-core-1_0.html#UserInfoResponse):
"The sub (subject) Claim **MUST** always be returned in the UserInfo
Response."

Closes https://github.com/zitadel/zitadel/issues/8591
2024-09-12 12:36:33 +00:00
Tim MöhlmannandGitHub d8a71d217c test: upload integration server logs as artifacts (#8600)
# Which Problems Are Solved

Upload the integration test server logs as artifacts, even if the tests
fail.
Before this change logs where printed through the Makefile.
However if a test would fail, the logs wouldn't get printed.

# How the Problems Are Solved

- Add an extra build step that pushes `tmp/zitadel.log` and
`tmp/race.log.$pid` to artificats storage.
- Logs are no longer printed in the `core_integration_reports` Makefile
recipe.

# Additional Changes

Do not remove coverage data when generating the coverage report in
`core_integration_reports`. This is to prevent future "File not found"
erros when running the command repeatedly.

# Additional Context

Reported as internal feedback
2024-09-11 17:51:18 +00:00
Tim MöhlmannandGitHub 02c78a19c6 fix(actions-v3): check feature flag on list methods (#8595)
# Which Problems Are Solved

In actions/v3 there was no check for the feature flag on any of the:

- ListExecutionFunctions
- ListExecutionMethods
- ListExecutionServices

In the integration tests `ensureFeatureEnabled` relies on
`ListExecutionMethods` to return an error if the feature is not enabled.
This fix makes the test wait untill the feature is fully projected.

# How the Problems Are Solved

Add the feature check to all of the above methods.

# Additional Changes

- none

# Additional Context

Flaky introduced in https://github.com/zitadel/zitadel/pull/8407
2024-09-11 09:43:44 +00:00
Tim MöhlmannandGitHub 58a7eb1f26 perf(oidc): remove get user by ID from jwt profile grant (#8580)
# Which Problems Are Solved

Improve performance by removing a GetUserByID call. The call also
executed a Trigger on projections, which significantly impacted
concurrent requests.

# How the Problems Are Solved

Token creation needs information from the user, such as the resource
owner and access token type.

For client credentials this is solved in a single search. By getting the
user by username (`client_id`), the user details and secret were
obtained in a single query. After that verification and token creation
can proceed. For JWT profile it is a bit more complex. We didn't know
anything about the user until after JWT verification.
The verification did a query for the AuthN key and after that we did a
GetUserByID to get remaining details.

This change uses a joined query when the OIDC library calls the
`GetKeyByIDAndClientID` method on the token storage. The found user
details are set to the verifieer object and returned after verification
is completed.
It is safe because the `jwtProfileKeyStorage` is a single-use object as
a wrapper around `query.Queries`.
This way getting the public key and user details are obtained in a
single query.

# Additional Changes

- Correctly set the `client_id` field with machine's username.

# Additional Context

- Related to: https://github.com/zitadel/zitadel/issues/8352
2024-09-11 12:04:09 +03:00
Tim MöhlmannandGitHub 3aba942162 feat: add debug events API (#8533)
# Which Problems Are Solved

Add a debug API which allows pushing a set of events to be reduced in a
dedicated projection.
The events can carry a sleep duration which simulates a slow query
during projection handling.

# How the Problems Are Solved

- `CreateDebugEvents` allows pushing multiple events which simulate the
lifecycle of a resource. Each event has a `projectionSleep` field, which
issues a `pg_sleep()` statement query in the projection handler :
  - Add
  - Change
  - Remove
- `ListDebugEventsStates` list the current state of the projection,
optionally with a Trigger
- `GetDebugEventsStateByID` get the current state of the aggregate ID in
the projection, optionally with a Trigger


# Additional Changes

- none

# Additional Context

-  Allows reproduction of https://github.com/zitadel/zitadel/issues/8517
2024-09-11 08:24:00 +00:00
a569501108 chore(test): set connection lifetimes for postgresql (#8586)
# Which Problems Are Solved

defaults.yaml only specifies defaults for cockroach. Therefore, options
omitted for postgresql are actually set to `0`.
This means that the connections timeouts are set to `0` and connections
were not reused, resulting in a performance penalty while running the
integration tests.

# How the Problems Are Solved

Set MaxConnLifeTime and MaxConnIdleTime options in postgres


# Additional Changes

- none

# Additional Context

- none

Co-authored-by: Silvan <[email protected]>
Co-authored-by: Livio Spring <[email protected]>
2024-09-11 07:45:02 +00:00
328c409271 fix(oidc): roles in service user ID token (#8561)
# Which Problems Are Solved

Return the user's project roles when the
`urn:zitadel:iam:org:projects:roles` scope is requested.
We alreayd returned it for access tokens, now also ID tokens.

# How the Problems Are Solved

Set `idTokenRoleAssertion` to `true` when calling
`accessTokenResponseFromSession` for service users. This parameter is
normally set to the client config. However, service user authentication
does not have a client.

# Additional Changes

- none

# Additional Context

- Introduced in https://github.com/zitadel/zitadel/pull/8046
- Closes https://github.com/zitadel/zitadel/issues/8107

Co-authored-by: Livio Spring <[email protected]>
2024-09-11 04:45:59 +00:00
622a176be4 fix(tests): check eventual web key state (#8587)
# Which Problems Are Solved

Deal with eventual consistency in the webkey integration tests.

# How the Problems Are Solved

Use an eventual with T for the list state check.

# Additional Changes

- none

# Additional Context

- none

---------

Co-authored-by: Livio Spring <[email protected]>
2024-09-10 11:15:25 +00:00
d2e0ac07f1 chore(tests): use a coverage server binary (#8407)
# Which Problems Are Solved

Use a single server instance for API integration tests. This optimizes
the time taken for the integration test pipeline,
because it allows running tests on multiple packages in parallel. Also,
it saves time by not start and stopping a zitadel server for every
package.

# How the Problems Are Solved

- Build a binary with `go build -race -cover ....`
- Integration tests only construct clients. The server remains running
in the background.
- The integration package and tested packages now fully utilize the API.
No more direct database access trough `query` and `command` packages.
- Use Makefile recipes to setup, start and stop the server in the
background.
- The binary has the race detector enabled
- Init and setup jobs are configured to halt immediately on race
condition
- Because the server runs in the background, races are only logged. When
the server is stopped and race logs exist, the Makefile recipe will
throw an error and print the logs.
- Makefile recipes include logic to print logs and convert coverage
reports after the server is stopped.
- Some tests need a downstream HTTP server to make requests, like quota
and milestones. A new `integration/sink` package creates an HTTP server
and uses websockets to forward HTTP request back to the test packages.
The package API uses Go channels for abstraction and easy usage.

# Additional Changes

- Integration test files already used the `//go:build integration`
directive. In order to properly split integration from unit tests,
integration test files need to be in a `integration_test` subdirectory
of their package.
- `UseIsolatedInstance` used to overwrite the `Tester.Client` for each
instance. Now a `Instance` object is returned with a gRPC client that is
connected to the isolated instance's hostname.
- The `Tester` type is now `Instance`. The object is created for the
first instance, used by default in any test. Isolated instances are also
`Instance` objects and therefore benefit from the same methods and
values. The first instance and any other us capable of creating an
isolated instance over the system API.
- All test packages run in an Isolated instance by calling
`NewInstance()`
- Individual tests that use an isolated instance use `t.Parallel()`

# Additional Context

- Closes #6684
- https://go.dev/doc/articles/race_detector
- https://go.dev/doc/build-cover

---------

Co-authored-by: Stefan Benz <[email protected]>
2024-09-06 14:47:57 +02:00
2981ff04da docs(oidc): web keys (#8508)
# Which Problems Are Solved

Explain the web key implementation and usage in zitadel.

# How the Problems Are Solved

Add documentation

# Additional Changes

- none

# Additional Context

- Related to https://github.com/zitadel/zitadel/issues/7809
- Example cURL commands are broken:
https://github.com/zitadel/zitadel/issues/8507

---------

Co-authored-by: Livio Spring <[email protected]>
2024-09-06 08:58:06 +02:00
Tim MöhlmannandGitHub 90b908c361 fix(oidc): don't push introspection client events (#8481)
# Which Problems Are Solved

Do not push secret succeeded and failed events for API and OIDC clients
on the introspection endpoint.
On instances where introspection was fequently called, the pushed events
created issues on duplicate primary keys, due to collisions on the
`sequence` column in the eventstore. As the event pusher retries on this
collision and we pushed above mentioned events async, it would create a
backpressure of concurrent pushers and effectively cripple an instance.

We considered that pushing these events have little value with regards
to the audit trail, as we do not push similar events when client
assertion is used. Also, before #7657 the events were defined, but not
pushed.

# How the Problems Are Solved

- Removed API secret check succeeded and faild event definitions
- Removed OIDC secret check succeeded and faild event definitions
- Push only Hash Updated event when needed

# Additional Changes

- None

# Additional Context

- Fixes https://github.com/zitadel/zitadel/issues/8479
- Closes https://github.com/zitadel/zitadel/issues/8430
- Intoduced in https://github.com/zitadel/zitadel/pull/7657
2024-08-28 18:19:50 +00:00
Tim MöhlmannandGitHub fd0c15dd4f feat(oidc): use web keys for token signing and verification (#8449)
# Which Problems Are Solved

Use web keys, managed by the `resources/v3alpha/web_keys` API, for OIDC
token signing and verification,
as well as serving the public web keys on the jwks / keys endpoint.
Response header on the keys endpoint now allows caching of the response.
This is now "safe" to do since keys can be created ahead of time and
caches have sufficient time to pickup the change before keys get
enabled.

# How the Problems Are Solved

- The web key format is used in the `getSignerOnce` function in the
`api/oidc` package.
- The public key cache is changed to get and store web keys.
- The jwks / keys endpoint returns the combined set of valid "legacy"
public keys and all available web keys.
- Cache-Control max-age default to 5 minutes and is configured in
`defaults.yaml`.

When the web keys feature is enabled, fallback mechanisms are in place
to obtain and convert "legacy" `query.PublicKey` as web keys when
needed. This allows transitioning to the feature without invalidating
existing tokens. A small performance overhead may be noticed on the keys
endpoint, because 2 queries need to be run sequentially. This will
disappear once the feature is stable and the legacy code gets cleaned
up.

# Additional Changes

- Extend legacy key lifetimes so that tests can be run on an existing
database with more than 6 hours apart.
- Discovery endpoint returns all supported algorithms when the Web Key
feature is enabled.

# Additional Context

- Closes https://github.com/zitadel/zitadel/issues/8031
- Part of https://github.com/zitadel/zitadel/issues/7809
- After https://github.com/zitadel/oidc/pull/637
- After https://github.com/zitadel/oidc/pull/638
2024-08-23 14:43:46 +02:00
5fd2061770 feat(oidc): allow returning of parent errors to client (#8376)
# Which Problems Are Solved

Currently the OIDC API of ZITADEL only prints parent errors to the logs.
Where 4xx status are typically warn level and 5xx error level. This
makes it hard to debug certain errors for client in multi-instance
environments like ZITADEL cloud, where there is no direct access to
logs. In case of support requests we often can't correlate past
log-lines to the error that was reported.

This change adds the possibility to return the parent error in the
response to the OIDC client. For the moment this only applies to JSON
body responses, not error redirects to the RP.

# How the Problems Are Solved

- New instance-level feature flag: `debug_oidc_parent_error`
- Use the new `WithReturnParentToClient()` function from the oidc lib
introduced in https://github.com/zitadel/oidc/pull/629 for all cases
where `WithParent` was already used and the request context is
available.

# Additional Changes

none

# Additional Context

- Depends on: https://github.com/zitadel/oidc/pull/629
- Related to: https://github.com/zitadel/zitadel/issues/8362

---------

Co-authored-by: Livio Spring <[email protected]>
2024-08-20 06:45:24 +00:00
10d5fc6184 test: no location header in response (#8441)
# Which Problems Are Solved

Sometimes integrations tests are failing with an error `http: no
location header in response`. The underlying cause was hidden, as in
some tests we assumed a 3xx range response but got a 4xx response
instead. No assertion on the status code was made, resulting in the
above error message on calling `resp.Location()`.

The underlying issue, the application not found in the projection, is
also fixed.

# How the Problems Are Solved

This change adds a check for the status code and returns the response
body if the response is not in the 3xx status code range.

Helper function that create applications now do an additional
`GetAppByID` in a retry loop to ensure consitency in the projection
before proceeding with tests.

# Additional Changes

- none

# Additional Context

- Pipline failures were observed, no issue was created
- Cherry-picked form WIP #8407

Co-authored-by: Livio Spring <[email protected]>
2024-08-17 14:48:06 +00:00
Tim MöhlmannandGitHub ab4daa0ebb fix(webkeys): remove include private key from projection index (#8436)
# Which Problems Are Solved

When Web keys with a large RSA Bitsize were generated, the new web key
did not get projected.
Zitadel logs printed the following errors:

```
time="2024-08-15T09:18:47Z" level=debug msg="execution of statements failed" caller="/home/tim/Repositories/zitadel/zitadel/internal/eventstore/handler/v2/handler.go:518" error="statement failed: ID=CRDB-pKtsr Message=exec failed Parent=(ERROR: index row size 3400 exceeds btree version 4 maximum 2704 for index \"web_keys_web_key_state_idx\" (SQLSTATE 54000))" lastProcessedIndex=-1 projection=projections.web_keys
```


# How the Problems Are Solved

Remove the the `WithInclude` option with the Private key from the
`web_keys` projection index and bump the projection version.

# Additional Changes

- Correct RPC summaries for documentation
- Fix docs slug in sidebar.js

# Additional Context

- Found during release review.
2024-08-16 11:41:09 +00:00
64a3bb3149 feat(v3alpha): web key resource (#8262)
# Which Problems Are Solved

Implement a new API service that allows management of OIDC signing web
keys.
This allows users to manage rotation of the instance level keys. which
are currently managed based on expiry.

The API accepts the generation of the following key types and
parameters:

- RSA keys with 2048, 3072 or 4096 bit in size and:
  - Signing with SHA-256 (RS256)
  - Signing with SHA-384 (RS384)
  - Signing with SHA-512 (RS512)
- ECDSA keys with
  - P256 curve
  - P384 curve
  - P512 curve
- ED25519 keys

# How the Problems Are Solved

Keys are serialized for storage using the JSON web key format from the
`jose` library. This is the format that will be used by OIDC for
signing, verification and publication.

Each instance can have a number of key pairs. All existing public keys
are meant to be used for token verification and publication the keys
endpoint. Keys can be activated and the active private key is meant to
sign new tokens. There is always exactly 1 active signing key:

1. When the first key for an instance is generated, it is automatically
activated.
2. Activation of the next key automatically deactivates the previously
active key.
3. Keys cannot be manually deactivated from the API
4. Active keys cannot be deleted

# Additional Changes

- Query methods that later will be used by the OIDC package are already
implemented. Preparation for #8031
- Fix indentation in french translation for instance event
- Move user_schema translations to consistent positions in all
translation files

# Additional Context

- Closes #8030
- Part of #7809

---------

Co-authored-by: Elio Bischof <[email protected]>
2024-08-14 14:18:14 +00:00
Tim MöhlmannandGitHub fcda6580ff fix(query): print log line on secret generator error (#8424)
# Which Problems Are Solved

Log some details when a secret generator is not found.
This should help us debugging such issue.

# How the Problems Are Solved

When a secret generator by type query fails,
we log the generator type and instance id for which
the generator was requested.

# Additional Changes

- none

# Additional Context

- Related to https://github.com/zitadel/zitadel/issues/8379
- Also encountered in https://github.com/zitadel/zitadel/pull/8407
2024-08-13 14:52:43 +02:00
Tim MöhlmannandGitHub 4e3fd305ab fix(crypto): reject decrypted strings with non-UTF8 characters. (#8374)
# Which Problems Are Solved

We noticed logging where 500: Internal Server errors were returned from
the token endpoint, mostly for the `refresh_token` grant. The error was
thrown by the database as it received non-UTF8 strings for token IDs

Zitadel uses symmetric encryption for opaque tokens, including refresh
tokens. Encrypted values are base64 encoded. It appeared to be possible
to send garbage base64 to the token endpoint, which will pass decryption
and string-splitting. In those cases the resulting ID is not a valid
UTF-8 string.

Invalid non-UTF8 strings are now rejected during token decryption.

# How the Problems Are Solved

- `AESCrypto.DecryptString()` checks if the decrypted bytes only contain
valid UTF-8 characters before converting them into a string.
- `AESCrypto.Decrypt()` is unmodified and still allows decryption on
non-UTF8 byte strings.
- `FromRefreshToken` now uses `DecryptString` instead of `Decrypt`

# Additional Changes

- Unit tests added for `FromRefreshToken` and
`AESCrypto.DecryptString()`.
- Fuzz tests added for `FromRefreshToken` and
`AESCrypto.DecryptString()`. This was to pinpoint the problem
- Testdata with values that resulted in invalid strings are committed.
In the pipeline this results in the Fuzz tests to execute as regular
unit-test cases. As we don't use the `-fuzz` flag in the pipeline no
further fuzzing is performed.

# Additional Context

- Closes #7765
- https://go.dev/doc/tutorial/fuzz
2024-08-02 08:38:37 +00:00
7967e6f98b perf(import): optimize search for domains claimed by other organizations (#8200)
# Which Problems Are Solved

Improve the performance of human imports by optimizing the query that
finds domains claimed by other organizations.

# How the Problems Are Solved

Use the fields search table introduced in
https://github.com/zitadel/zitadel/pull/8191 by storing each
organization domain as Object ID and the verified status as field value.

# Additional Changes

- Feature flag for this optimization

# Additional Context

- Performance improvements for import are evaluated and acted upon
internally at the moment

---------

Co-authored-by: adlerhurst <[email protected]>
2024-07-05 09:36:00 +02:00
ecfb9d0d6d perf(command): user grant pre-condition check using the search table (#8230)
# Which Problems Are Solved

Imporve the performance of user grant addition, especially for import.

# How the Problems Are Solved

Use the search table to query for the project grant state. 
This could easily be done by making the search used in
`checkProjectGrantPreCondition` reusable.

# Additional Changes

Chanded event declerations to `const` in the
`internal/repository/project` package.

# Additional Context

- Performance improvements for import are evaluated and acted upon
internally at the moment

---------

Co-authored-by: adlerhurst <[email protected]>
Co-authored-by: Livio Spring <[email protected]>
2024-07-04 16:18:43 +00:00
Tim MöhlmannandGitHub dc170dc46e feat(crypto): support md5 plain for imported password hashes (#8189)
# Which Problems Are Solved

Allow verification of imported passwords hashed with plain md5, without
salt. These are password digests typically created by one of:

- `printf "password" | md5sum` on most linux systems.
- PHP's `md5("password")`
- Python3's `hashlib.md5(b"password").hexdigest()`

# How the Problems Are Solved

- Upgrade passwap to
[v0.6.0](https://github.com/zitadel/passwap/releases/tag/v0.6.0)
- Add md5plain as a new verfier option in `defaults.yaml`

# Additional Changes

- Updated documentation to explain difference between `md5` (crypt) and
`md5plain` verifiers.

# Additional Context

- Requested by customer for import case
2024-06-25 11:10:49 +03:00
Tim MöhlmannandGitHub 669ac6bda2 perf(import): do not check for existing grant ID (#8164)
# Which Problems Are Solved

Improve the performance of the `admin/v1/import` API endpoint.
Specifaclly the import of large amount of project grants.

# How the Problems Are Solved

`AddProjectGrantWithID` and `AddProjectGrantMember` methods of
`Commands` used to get the current state of the Writemodel to check if
the current GrantID or the combination of GrantID & UserID wasn't
already used. However, the Added events already have protection against
duplication by the `UniqueConstaint` methods.

The queries become very slow when there is a great amount of project
grants. Because all the events are pushed to the aggregate ID of the
project, we had to obtain all related project events, including events
of grantIDs we do not care about. This O(n) duration for bached import
jobs adding many organization granted to a single project.

This change removes the unnecesary state query to improve performance.

# Additional Changes

- Add integration tests for import

# Additional Context

- reported internally
2024-06-20 13:31:58 +00:00
Tim MöhlmannandGitHub f9742a58f4 fix(import): add tracing spans to all import related functions (#8160)
# Which Problems Are Solved

This fix adds tracing spans to all V1 API import related functions. This
is to troubleshoot import related performance issues reported to us.

# How the Problems Are Solved

Add a tracing span to `api/grpc/admin/import.go` and all related
functions that are called in the `command` package.

# Additional Changes

- none

# Additional Context

- Reported by internal communication
2024-06-19 12:56:33 +02:00
1aa8c49e41 fix(oidc): store requested response_mode (#8145)
# Which Problems Are Solved

Zitadel never stored or returned the requested `response_mode` in oidc
Auth Requests. This caused the oidc library to fallback to the default
based on the response_type.

# How the Problems Are Solved

- Store the `response_mode` in the Auth request repo
- Store the `response_mode` in the Auth request v2 events
- Return the `resonse_mode` from the Auth Request v1 and v2
`ResponseMode()` methods. (Was hard-coded to an empty string)

# Additional Changes

- Populate the `response_modes_supported` to the oidc Discovery
Configuration. When it was empty, the standard specifies the default of
`query` and `fragment`. However, our oidc library also supports
`form_post` and by this fix, zitadel now also supports this.

# Additional Context

- Closes #6586
- Reported
https://discord.com/channels/927474939156643850/1151508313717084220

---------

Co-authored-by: Livio Spring <[email protected]>
2024-06-17 09:50:12 +00:00
Tim MöhlmannandGitHub 120ed0af73 feat(oidc): organization roles scope (#8120)
# Which Problems Are Solved

An admin / application might want to be able to reduce the amount of
roles returned in the token, for example if a user is granted to many
organizations or for specific cases where the application want to narrow
down the access for that token to a specific organization or multiple.
This can now be achieved by providing a scope with the id of the
organization, resp. multiple scopes for every organization, which should
be included.

```
urn:zitadel:iam:org:roles🆔{orgID}
```

**Note:** the new scope does not work when Introspection / Userinfo are
set to legacy mode.

# How the Problems Are Solved

The user info query now has two variants:

1. Variant that returns all organization authorization grants if the new
scope wasn't provided for backward compatibility.
2. Variant that filters the organizations based on the IDs passed in one
or more of the above scopes and returns only those authorization grants.

The query is defined as a `text/template` and both variants are rendered
once in package `init()`.

# Additional Changes

- In the integration tests `assertProjectRoleClaims` now also checks the
org IDs in the roles.

# Additional Context

- Closes #7996
2024-06-14 10:00:43 +02:00
Tim MöhlmannandGitHub 81cc7c62cb fix(oidc): upgrade zitadel/oidc to allow scope without openid (#8109)
# Which Problems Are Solved

Drop the requirement of the `openid` scope in all auth and token request
types.

# How the Problems Are Solved

This change upgrades the oidc package to include
https://github.com/zitadel/oidc/pull/613.

# Additional Changes

- Fix a typo in a go doc string
- upgrade otel modules to match the version from oidc.

# Additional Context

- https://github.com/zitadel/zitadel/pull/7822 started doing scope
validation for machine user authentication on the token endpoint.
- https://github.com/zitadel/zitadel/discussions/8068 reports breakage
of machine authentication without `openid` scope.
- Merge after https://github.com/zitadel/oidc/pull/613 is released.
2024-06-13 09:32:27 +00:00
Tim MöhlmannandGitHub f5e9d4f57f fix(oidc): IDP and machine user auth methods (#7992)
# Which Problems Are Solved

After https://github.com/zitadel/zitadel/pull/7822 was merged we
discovered that
v2 tokens that where obtained through an IDP using the v1 login, can't
be used for
zitadel API calls.

- Because we used to store the AMR claim on the auth request, but
internally use the domain.UserAuthMethod type. AMR has no notion of an
IDP login, so that "factor" was lost
during conversion. Rendering those v2 tokens invalid on the zitadel API.
- A wrong check on machine user tokens falsly allowed some tokens to be
valid
- The client ID was set to tokens from client credentials and JWT
profile, which made client queries fail in the validation middleware.
The middleware expects client ID unset for machine users.

# How the Problems Are Solved

Store the domain.AuthMethods directly in  the auth requests and session,
instead of using AMR claims with lossy conversion.

- IDPs have seperate auth method, which is not an AMR claim
- Machine users are treated specialy, eg auth methods are not required.
- Do not set the client ID for client credentials and JWT profile

# Additional Changes

Cleaned up mostly unused `oidc.getInfoFromRequest()`.

# Additional Context

- Bugs were introduced in https://github.com/zitadel/zitadel/pull/7822
and not yet part of a release.
- Reported internally.
2024-05-23 05:35:10 +00:00
Tim MöhlmannandGitHub 5b1160de1e feat(session): allow update of session without token (#7963)
# Which Problems Are Solved

The session update requires the current session token as argument.
Since this adds extra complexity but no real additional security and
prevents case like magic links, we want to remove this requirement.

We still require the session token on other resouces / endpoints, e.g.
for finalizing the auth request or on idp intents.

# How the Problems Are Solved

- Removed the session token verifier in the Update Session GRPc call.
- Removed the session token from login UI examples session update calls

# Additional Changes

- none

# Additional Context

- Closes #7883
2024-05-22 05:56:11 +00:00
8e0c8393e9 perf(oidc): optimize token creation (#7822)
* implement code exchange

* port tokenexchange to v2 tokens

* implement refresh token

* implement client credentials

* implement jwt profile

* implement device token

* cleanup unused code

* fix current unit tests

* add user agent unit test

* unit test domain package

* need refresh token as argument

* test commands create oidc session

* test commands device auth

* fix device auth build error

* implicit for oidc session API

* implement authorize callback handler for legacy implicit mode

* upgrade oidc module to working draft

* add missing auth methods and time

* handle all errors in defer

* do not fail auth request on error

the oauth2 Go client automagically retries on any error. If we fail the auth request on the first error, the next attempt will always fail with the Errors.AuthRequest.NoCode, because the auth request state is already set to failed.
The original error is then already lost and the oauth2 library does not return the original error.

Therefore we should not fail the auth request.

Might be worth discussing and perhaps send a bug report to Oauth2?

* fix code flow tests by explicitly setting code exchanged

* fix unit tests in command package

* return allowed scope from client credential client

* add device auth done reducer

* carry nonce thru session into ID token

* fix token exchange integration tests

* allow project role scope prefix in client credentials client

* gci formatting

* do not return refresh token in client credentials and jwt profile

* check org scope

* solve linting issue on authorize callback error

* end session based on v2 session ID

* use preferred language and user agent ID for v2 access tokens

* pin oidc v3.23.2

* add integration test for jwt profile and client credentials with org scopes

* refresh token v1 to v2

* add user token v2 audit event

* add activity trigger

* cleanup and set panics for unused methods

* use the encrypted code for v1 auth request get by code

* add missing event translation

* fix pipeline errors (hopefully)

* fix another test

* revert pointer usage of preferred language

* solve browser info panic in device auth

* remove duplicate entries in AMRToAuthMethodTypes to prevent future `mfa` claim

* revoke v1 refresh token to prevent reuse

* fix terminate oidc session

* always return a new refresh toke in refresh token grant

---------

Co-authored-by: Livio Spring <[email protected]>
2024-05-16 07:07:56 +02:00
Tim MöhlmannandGitHub 029a6d393a fix(crdb): obtain latest sequences when the tx is retried (#7795) 2024-04-18 13:07:05 +00:00
dbb824a73f chore(oidc): add refresh token error integration test (#7766)
We are trying to reproduce a few 500 responses we observe on zitadel cloud's token endpoint.
As in the past these were caused by wrongly encoded or encrypted refresh tokens, I created a integration test which tries to reproduce 500 errors by sending invalid refresh tokens.

The added test does not reproduce 500s, all returned errors are in the 400 range as they should. However, as the test is already written, we might as well include them.

Related to #7765

Co-authored-by: Livio Spring <[email protected]>
2024-04-17 08:38:03 +00:00
9ccbbe05bc fix(oidc): roles in userinfo for client credentials token (#7763)
* fix(oidc): roles in userinfo for client credentials token

When tokens were obtained using the client credentials grant,
with audience and role scopes, userinfo would not return the role claims. This had multiple causes:

1. There is no auth request flow, so for legacy userinfo project data was never attached to the token
2. For optimized userinfo, there is no client ID that maps to an application. The client ID for client credentials is the machine user's name. There we can't obtain a project ID. When the project ID remained empty, we always ignored the roleAudience.

This PR fixes situation 2, by always taking the roleAudience into account, even when the projectID is empty. The code responsible for the bug is also refactored to be more readable and understandable, including additional godoc.

The fix only applies to the optimized userinfo code introduced in #7706 and released in v2.50 (currently in RC). Therefore it can't be back-ported to earlier versions.

Fixes #6662

* chore(deps): update all go deps (#7764)

This change updates all go modules, including oidc, a major version of go-jose and the go 1.22 release.

* Revert "chore(deps): update all go deps" (#7772)

Revert "chore(deps): update all go deps (#7764)"

This reverts commit 6893e7d060a953d595a18ff8daa979834c4324d5.

---------

Co-authored-by: Livio Spring <[email protected]>
2024-04-16 13:02:38 +00:00
Tim MöhlmannandGitHub be00e3861a fix(oidc): make device auth audience and scope nullable (#7777)
This fixes the projection of events that have a null audience or scope.
As audience was added in v2.50, legacy events do not have an audience, this made replay of the old events not possible after an upgrade.
2024-04-16 10:34:38 +02:00
Tim MöhlmannandGitHub fe9bb49caa chore(deps): update all go deps (#7773)
This change updates all go modules, including oidc, a major version of go-jose and the go 1.22 release.
2024-04-15 09:17:36 +00:00
Tim MöhlmannandGitHub b3e3239d76 chore(oidc): add additional spans to userinfo code paths (#7749) 2024-04-10 17:05:13 +02:00
Tim MöhlmannandGitHub 6a51c4b0f5 feat(oidc): optimize the userinfo endpoint (#7706)
* feat(oidc): optimize the userinfo endpoint

* store project ID in the access token

* query for projectID if not in token

* add scope based tests

* Revert "store project ID in the access token"

This reverts commit 5f0262f23988e7f62d415d0e4a02a705f6ad5197.

* query project role assertion

* use project role assertion setting to return roles

* workaround eventual consistency and handle PAT

* do not append empty project id
2024-04-09 15:15:35 +02:00
Tim MöhlmannandGitHub c8e0b30e17 fix(oidc): return bad request for base64 errors (#7730)
* fix(oidc): return bad request for base64 errors

We've recently noticed an increased amount of 500: internal server error status returns on zitadel cloud.
The source of these errors appear to be erroneous input in fields that are supposed to be bas64 formatted.

```
time=2024-04-08T14:05:47.600Z level=ERROR msg="request error" oidc_error.parent="ID=OIDC-AhX2u Message=Errors.Internal Parent=(illegal base64 data at input byte 8)" oidc_error.description=Errors.Internal oidc_error.type=server_error status_code=500
```

Within the possible code paths of the token endpoint there are a couple of uses of base64.Encoding.DecodeString of which a returned error was not properly wrapped, but returned as-is.
This causes the oidc error handler to return a 500 with the `OIDC-AhX2u` ID.
We were not able to pinpoint the exact errors that are happening to any one call of `DecodeString`.

This fix wraps all errors from `DecodeString` so that proper 400: bad request is returned with information about the error. Each wrapper now has an unique error ID, so that logs will contain the source of the error as well.

This bug was reported internally by the ops team.

* catch op.ErrInvalidRefreshToken
2024-04-09 08:42:59 +02:00
2089992d75 feat(crypto): use passwap for machine and app secrets (#7657)
* feat(crypto): use passwap for machine and app secrets

* fix command package tests

* add hash generator command test

* naming convention, fix query tests

* rename PasswordHasher and cleanup start commands

* add reducer tests

* fix intergration tests, cleanup old config

* add app secret unit tests

* solve setup panics

* fix push of updated events

* add missing event translations

* update documentation

* solve linter errors

* remove nolint:SA1019 as it doesn't seem to help anyway

* add nolint to deprecated filter usage

* update users migration version

* remove unused ClientSecret from APIConfigChangedEvent

---------

Co-authored-by: Livio Spring <[email protected]>
2024-04-05 09:35:49 +00:00
9b3f3e4cd9 fix(idp): do not call userinfo when mapping from ID token is configured (#7696)
* fix(idp): do not call userinfo when mapping from ID token is configured

This change prevents the call of the Userinfo endpoint of a OIDC IDP if the IDP is configured to use the ID token for user information instead.
A unit test has been added to confirm the corrected behavior.

Closes #7373

* video for e2e

---------

Co-authored-by: Livio Spring <[email protected]>
2024-04-04 05:41:44 +00:00
25ef3da9d5 refactor(fmt): run gci on complete project (#7557)
chore(fmt): run gci on complete project

Fix global import formatting in go code by running the `gci` command. This allows us to just use the command directly, instead of fixing the import order manually for the linter, on each PR.

Co-authored-by: Elio Bischof <[email protected]>
2024-04-03 10:43:43 +00:00