* fix(security): prevent unauthenticated IDP-linking account takeover
Two distinct defects allowed an attacker to bind their own external
identity to a victim's account and, because external IDP links are
globally unique (first claim wins), hijack the victim's future
federated logins.
LoginV2: resolveUserIdFromSession returned the session's user id after
only a null check, trusting an "identify-only" session (login name
submitted, no verified primary factor). An unauthenticated attacker who
knew a victim's login name could drive explicit linking against that
session. Gate it on isSessionValid so only a fully authenticated
session can link.
Backend: AddUserIDPLink skipped the user-write permission check when the
caller targeted their own account (userID == ctx user). Because the
external subject is caller-supplied and unverified, this let any
authenticated user self-link an unproven identity. Make the permission
check unconditional. The login/federation flow uses a service account
(userID != ctx user) and already took the permission branch, so it is
unaffected; verified self-service linking goes through the IDP-intent
flow.
Adds a LoginV2 regression test (identify-only session is rejected) and
the first command-level test for AddUserIDPLink (self-link without
permission is denied).
Co-Authored-By: Claude Opus 4.8 <[email protected]>
* test(user_idp_link): address review on AddUserIDPLink hardening
- add success regression cases for AddUserIDPLink (self-link with
permission, other-user link with permission) so the login-client and
managed-admin paths are pinned and the assert.NoError branch is live
- add an integration case: UserCTX self-linking on its own account is
now denied
- document the intentional no-permission-check invariant on
BulkAddedUserIDPLinks (verified Login V1 flow only; not API-exposed)
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Claude-Session: https://claude.ai/code/session_01RUhwzSqHhycHNAJEfMcrdd
* fix(login): authorize IDP linking via enrollment guard, not isSessionValid
Replace the isSessionValid gate in resolveUserIdFromSession with
getEnrollmentAuthorizationError. isSessionValid requires a verified
primary factor, which rejected the legitimate "link an IDP as the first
authenticator" onboarding flow (a freshly verified user with no
credentials yet). The enrollment guard authorizes when the session has a
verified, non-expired primary factor OR the user has zero auth methods
and passed the user-verification check (email/invite-code proof bound to
the browser fingerprint) — closing the identify-only ATO while preserving
first-authenticator linking.
Replace the single mocked rejection test with four that run the real
guard: identify-only + has credentials -> rejected; identify-only + no
credentials + no verification check -> rejected; expired primary factor
-> rejected; identify-only + no credentials + verification check ->
allowed.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Claude-Session: https://claude.ai/code/session_01T24WwsRLbaC7aHxBmyznnd
---------
Co-authored-by: Claude Opus 4.8 <[email protected]>
# Which Problems Are Solved
As of now, **automatic creation** and **automatic linking options** were
only considered if the corresponding **allowed option** (account
creation / linking allowed) was enabled.
With this PR, this is no longer needed and allows administrators to
address cases, where only an **automatic creation** is allowed, but
users themselves should not be allowed to **manually** create new
accounts using an identity provider or edit the information during the
process.
Also, allowing users to only link to the proposed existing account is
now possible with an enabled **automatic linking option**, while
disabling **account linking allowed**.
# How the Problems Are Solved
- Check for **automatic** options without the corresponding **allowed**
option.
- added technical advisory to notify about the possible behavior change
# Additional Changes
- display the error message on the IdP linking step in the login UI (in
case there is one)
- display an error in case no option is possible
- exchanged deprecated `eventstoreExpect` with `expectEventstore` in
touched test files
# Additional Context
closes https://github.com/zitadel/zitadel/issues/7393
---------
Co-authored-by: Stefan Benz <[email protected]>
# Which Problems Are Solved
The current v3alpha actions APIs don't exactly adhere to the [new
resources API
design](https://zitadel.com/docs/apis/v3#standard-resources).
# How the Problems Are Solved
- **Improved ID access**: The aggregate ID is added to the resource
details object, so accessing resource IDs and constructing proto
messages for resources is easier
- **Explicit Instances**: Optionally, the instance can be explicitly
given in each request
- **Pagination**: A default search limit and a max search limit are
added to the defaults.yaml. They apply to the new v3 APIs (currently
only actions). The search query defaults are changed to ascending by
creation date, because this makes the pagination results the most
deterministic. The creation date is also added to the object details.
The bug with updated creation dates is fixed for executions and targets.
- **Removed Sequences**: Removed Sequence from object details and
ProcessedSequence from search details
# Additional Changes
Object details IDs are checked in unit test only if an empty ID is
expected. Centralizing the details check also makes this internal object
more flexible for future evolutions.
# Additional Context
- Closes#8169
- Depends on https://github.com/zitadel/zitadel/pull/8225
---------
Co-authored-by: Silvan <[email protected]>
Co-authored-by: Stefan Benz <[email protected]>
# Which Problems Are Solved
The v2beta services are stable but not GA.
# How the Problems Are Solved
The v2beta services are copied to v2. The corresponding v1 and v2beta
services are deprecated.
# Additional Context
Closes#7236
---------
Co-authored-by: Elio Bischof <[email protected]>
This implementation increases parallel write capabilities of the eventstore.
Please have a look at the technical advisories: [05](https://zitadel.com/docs/support/advisory/a10005) and [06](https://zitadel.com/docs/support/advisory/a10006).
The implementation of eventstore.push is rewritten and stored events are migrated to a new table `eventstore.events2`.
If you are using cockroach: make sure that the database user of ZITADEL has `VIEWACTIVITY` grant. This is used to query events.
* fix: restrict AllowRegistration check to local registration
* add comment
* add additional tests
* hide registration fields if no registration allowed
* fix: always allow linking and creation of external idps on users in userV2 and admin import
* chore: exclude console dist and node_module folders from cache
* chore: include node_module folders into cache again
* linting
(cherry picked from commit 66772ad0dd)
* feat: migrate external id
* implement tests and some renaming
* fix projection
* cleanup
* i18n
* fix event type
* handle migration for new services as well
* typo
(cherry picked from commit 45262e6829)
* fix(user): move check if user is existing from user idp link
* fix(user): correct unit tests for user link bulk
* fix(user): correct placement of existing user check for user link
Co-authored-by: Silvan <[email protected]>
* fix: rename iam command side to instance
* fix: rename iam command side to instance
* fix: rename iam command side to instance
* fix: rename iam command side to instance
* fix: rename orgiampolicy to domain policy
* fix: merge conflicts
* fix: protos
* fix: md files
* implement deprecated org iam policy again
Co-authored-by: Livio Amstutz <[email protected]>