diff --git a/.devcontainer/base/Dockerfile b/.devcontainer/base/Dockerfile index 0b26761986..2fdb0a1082 100644 --- a/.devcontainer/base/Dockerfile +++ b/.devcontainer/base/Dockerfile @@ -16,4 +16,4 @@ RUN apt-get update && \ COPY --chown=node:node commands /commands -USER node \ No newline at end of file +USER node diff --git a/.devcontainer/base/docker-compose.yaml b/.devcontainer/base/docker-compose.yaml index 1fba6d30d7..dbc24ac75d 100644 --- a/.devcontainer/base/docker-compose.yaml +++ b/.devcontainer/base/docker-compose.yaml @@ -3,7 +3,7 @@ services: devcontainer: container_name: devcontainer build: - context: ../base + context: . volumes: - ../../:/workspaces:cached command: sleep infinity diff --git a/.devcontainer/login-acceptance/docker-compose.yaml b/.devcontainer/login-acceptance/docker-compose.yaml index d9c6388da0..a7ca7309ea 100644 --- a/.devcontainer/login-acceptance/docker-compose.yaml +++ b/.devcontainer/login-acceptance/docker-compose.yaml @@ -178,4 +178,3 @@ services: # depends_on: # configure-login: # condition: "service_completed_successfully" - diff --git a/.github/workflows/login-container.yml b/.github/workflows/login-container.yml index fd493fcdd1..50bd3b5516 100644 --- a/.github/workflows/login-container.yml +++ b/.github/workflows/login-container.yml @@ -13,7 +13,7 @@ on: outputs: login_build_image: description: 'The full image tag of the standalone login image' - value: ${{ jobs.login-container.outputs.login_build_image }} + value: ${{ inputs.login_build_image_name }}:${{ github.sha }} permissions: packages: write @@ -34,19 +34,6 @@ jobs: login_build_image: ${{ steps.short-sha.outputs.login_build_image }} steps: - uses: actions/checkout@v4 - - name: Get short SHA - id: short-sha - run: | - if [ "${{ github.event_name }}" = "pull_request" ]; then - # For PRs: Use the HEAD SHA (not the merge commit) - SHORT_SHA=$(echo "${{ github.event.pull_request.head.sha }}" | cut -c1-7) - else - # For pushes: Use the current commit - SHORT_SHA=$(echo "${{ github.sha }}" | cut -c1-7) - fi - echo "short_sha=$SHORT_SHA" >> $GITHUB_OUTPUT - echo "login_build_image=${{ inputs.login_build_image_name }}:$SHORT_SHA" >> $GITHUB_OUTPUT - echo "Short SHA: $SHORT_SHA" - name: Login meta id: login-meta uses: docker/metadata-action@v5 @@ -56,7 +43,7 @@ jobs: annotations: | manifest:org.opencontainers.image.licenses=MIT tags: | - type=raw,value=${{ steps.short-sha.outputs.short_sha }} + type=sha,prefix=,format=long - name: Login to Docker registry uses: docker/login-action@v3 with: diff --git a/.github/workflows/login-integration-test.yml b/.github/workflows/login-integration-test.yml index 31a203a96a..df586d99dc 100644 --- a/.github/workflows/login-integration-test.yml +++ b/.github/workflows/login-integration-test.yml @@ -42,7 +42,7 @@ jobs: run: docker compose --file .devcontainer/login-integration/docker-compose.yaml ps - name: Print Config if: failure() - run: COMPOSE_BAKE=1 docker compose --file .devcontainer/base/docker-compose.yaml --file .devcontainer/login-integration/docker-compose.yaml config login-integration + run: COMPOSE_BAKE=1 docker compose --file .devcontainer/login-integration/docker-compose.yaml config login-integration env: LOGIN_TAG: ${{ inputs.login_build_image }} - name: Show Container Logs diff --git a/cmd/defaults.yaml b/cmd/defaults.yaml index 5b3c91ec6f..e123caeed1 100644 --- a/cmd/defaults.yaml +++ b/cmd/defaults.yaml @@ -524,7 +524,7 @@ OIDC: PollInterval: 5s # ZITADEL_OIDC_DEVICEAUTH_POLLINTERVAL UserCode: CharSet: "BCDFGHJKLMNPQRSTVWXZ" # ZITADEL_OIDC_DEVICEAUTH_USERCODE_CHARSET - CharAmount: 8 # ZITADEL_OIDC_DEVICEAUTH_USERCODE_CHARARMOUNT + CharAmount: 8 # ZITADEL_OIDC_DEVICEAUTH_USERCODE_CHARAMOUNT DashInterval: 4 # ZITADEL_OIDC_DEVICEAUTH_USERCODE_DASHINTERVAL DefaultLoginURLV2: "/ui/v2/login/login?authRequest=" # ZITADEL_OIDC_DEFAULTLOGINURLV2 DefaultLogoutURLV2: "/ui/v2/login/logout?post_logout_redirect=" # ZITADEL_OIDC_DEFAULTLOGOUTURLV2 diff --git a/console/src/app/pages/projects/apps/app-detail/app-detail.component.ts b/console/src/app/pages/projects/apps/app-detail/app-detail.component.ts index 4b11f0171c..236a83b706 100644 --- a/console/src/app/pages/projects/apps/app-detail/app-detail.component.ts +++ b/console/src/app/pages/projects/apps/app-detail/app-detail.component.ts @@ -423,6 +423,7 @@ export class AppDetailComponent implements OnInit, OnDestroy { if (allowed) { this.oidcForm.enable(); + this.oidcForm.controls['clientId'].disable(); this.oidcTokenForm.enable(); this.apiForm.enable(); this.samlForm.enable(); diff --git a/docs/src/components/authrequest.jsx b/docs/src/components/authrequest.jsx index f864b1cbbb..4beab34e76 100644 --- a/docs/src/components/authrequest.jsx +++ b/docs/src/components/authrequest.jsx @@ -1,4 +1,4 @@ -import React, { Fragment, useContext, useEffect, useState } from "react"; +import { Fragment, useContext, useEffect, useState } from "react"; import { AuthRequestContext } from "../utils/authrequest"; import { Listbox } from "@headlessui/react"; import { Transition } from "@headlessui/react"; @@ -115,6 +115,14 @@ export function SetAuthRequest() { }`, ]; + const scopeExplanations = new Map([ + ['urn:zitadel:iam:org:project:id:zitadel:aud', 'Requested projectid will be added to the audience of the access token.'], + ['urn:zitadel:iam:user:metadata', 'Metadata of the user will be included in the token. The values are base64 encoded.'], + [`urn:zitadel:iam:org:id:${ + organizationId ? organizationId : "[organizationId]" + }`, 'Enforce that the user is a member of the selected organization.'] + ]); + const [scopeState, setScopeState] = useState( [true, true, true, false, false, false, false, false] // new Array(allScopes.length).fill(false) @@ -161,8 +169,13 @@ export function SetAuthRequest() { return input; }; - useEffect(async () => { - setCodeChallenge(await encodeCodeChallenge(codeVerifier)); + useEffect(() => { + const updateCodeChallange = async () => { + const newCodeChallange = await encodeCodeChallenge(codeVerifier) + setCodeChallenge(newCodeChallange); + } + + updateCodeChallange(); }, [codeVerifier]); useEffect(() => { @@ -559,6 +572,7 @@ export function SetAuthRequest() { name="scopes" value={`${scope}`} checked={scopeState[scopeIndex]} + disabled={scope === 'openid'} onChange={() => { toggleScope(scopeIndex); }} @@ -571,6 +585,11 @@ export function SetAuthRequest() { ) : null} + {scopeExplanations.has(scope) && ( + + {scopeExplanations.get(scope)} + + )} ); })} diff --git a/docs/src/pages/index.js b/docs/src/pages/index.js index 630a7d4fbd..729688a43b 100644 --- a/docs/src/pages/index.js +++ b/docs/src/pages/index.js @@ -4,7 +4,6 @@ import useDocusaurusContext from "@docusaurus/useDocusaurusContext"; import Layout from "@theme/Layout"; import ThemedImage from "@theme/ThemedImage"; import clsx from "clsx"; -import React from "react"; import Column from "../components/column"; import { diff --git a/docs/src/utils/authrequest.js b/docs/src/utils/authrequest.js index ee709ebabb..1a0ceba28c 100644 --- a/docs/src/utils/authrequest.js +++ b/docs/src/utils/authrequest.js @@ -1,4 +1,4 @@ -import React, { useState, useEffect } from "react"; +import React, { useEffect, useState } from "react"; export const AuthRequestContext = React.createContext(null); @@ -34,7 +34,7 @@ export default ({ children }) => { const id_token_hint = params.get("id_token_hint"); const organization_id = params.get("organization_id"); - setInstance(instance_param ?? "https://mydomain-xyza.zitadel.cloud/"); + setInstance(instance_param ?? "http://localhost:8080/"); setClientId(client_id ?? "170086824411201793@yourapp"); setRedirectUri( redirect_uri ?? "http://localhost:8080/api/auth/callback/zitadel" diff --git a/internal/notification/handlers/user_notifier.go b/internal/notification/handlers/user_notifier.go index 6ca753caa9..6880d63bff 100644 --- a/internal/notification/handlers/user_notifier.go +++ b/internal/notification/handlers/user_notifier.go @@ -7,6 +7,7 @@ import ( http_util "github.com/zitadel/zitadel/internal/api/http" "github.com/zitadel/zitadel/internal/api/ui/console" "github.com/zitadel/zitadel/internal/api/ui/login" + "github.com/zitadel/zitadel/internal/command" "github.com/zitadel/zitadel/internal/domain" "github.com/zitadel/zitadel/internal/eventstore" "github.com/zitadel/zitadel/internal/eventstore/handler/v2" @@ -417,12 +418,14 @@ func (u *userNotifier) reduceSessionOTPSMSChallenged(event eventstore.Event) (*h if alreadyHandled { return nil } - s, err := u.queries.SessionByID(ctx, true, e.Aggregate().ID, "", nil) + + ctx, err = u.queries.Origin(ctx, e) if err != nil { return err } - ctx, err = u.queries.Origin(ctx, e) + sessionWriteModel := command.NewSessionWriteModel(e.Aggregate().ID, e.Aggregate().InstanceID) + err = u.queries.es.FilterToQueryReducer(ctx, sessionWriteModel) if err != nil { return err } @@ -432,8 +435,8 @@ func (u *userNotifier) reduceSessionOTPSMSChallenged(event eventstore.Event) (*h return u.queue.Insert(ctx, ¬ification.Request{ Aggregate: e.Aggregate(), - UserID: s.UserFactor.UserID, - UserResourceOwner: s.UserFactor.ResourceOwner, + UserID: sessionWriteModel.UserID, + UserResourceOwner: sessionWriteModel.UserResourceOwner, TriggeredAtOrigin: http_util.DomainContext(ctx).Origin(), EventType: e.EventType, NotificationType: domain.NotificationTypeSms, diff --git a/internal/notification/handlers/user_notifier_test.go b/internal/notification/handlers/user_notifier_test.go index 874fbdf9af..eae40472e3 100644 --- a/internal/notification/handlers/user_notifier_test.go +++ b/internal/notification/handlers/user_notifier_test.go @@ -1349,19 +1349,12 @@ func Test_userNotifier_reduceOTPSMSChallenged(t *testing.T) { test: func(ctrl *gomock.Controller, queries *mock.MockQueries, queue *mock.MockQueue) (f fields, a args, w want) { testCode := "testcode" _, code := cryptoValue(t, ctrl, testCode) - queries.EXPECT().SessionByID(gomock.Any(), gomock.Any(), sessionID, gomock.Any(), nil).Return(&query.Session{ - ID: sessionID, - ResourceOwner: instanceID, - UserFactor: query.SessionUserFactor{ - UserID: userID, - ResourceOwner: orgID, - }, - }, nil) + queue.EXPECT().Insert( gomock.Any(), ¬ification.Request{ - UserID: userID, - UserResourceOwner: orgID, + UserID: "", // Empty since no session events are provided + UserResourceOwner: "", // Empty since no session events are provided TriggeredAtOrigin: eventOrigin, URLTemplate: "", Code: code, @@ -1387,11 +1380,15 @@ func Test_userNotifier_reduceOTPSMSChallenged(t *testing.T) { gomock.Any(), gomock.Any(), ).Return(nil) + + mockQuerier := es_repo_mock.NewMockQuerier(ctrl) + mockQuerier.EXPECT().FilterToReducer(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).AnyTimes() + return fields{ queries: queries, queue: queue, es: eventstore.NewEventstore(&eventstore.Config{ - Querier: es_repo_mock.NewRepo(t).ExpectFilterEvents().MockQuerier, + Querier: mockQuerier, }), }, args{ event: &session.OTPSMSChallengedEvent{ @@ -1421,19 +1418,12 @@ func Test_userNotifier_reduceOTPSMSChallenged(t *testing.T) { IsPrimary: true, }}, }, nil) - queries.EXPECT().SessionByID(gomock.Any(), gomock.Any(), sessionID, gomock.Any(), nil).Return(&query.Session{ - ID: sessionID, - ResourceOwner: instanceID, - UserFactor: query.SessionUserFactor{ - UserID: userID, - ResourceOwner: orgID, - }, - }, nil) + queue.EXPECT().Insert( gomock.Any(), ¬ification.Request{ - UserID: userID, - UserResourceOwner: orgID, + UserID: "", // Empty since no session events are provided + UserResourceOwner: "", // Empty since no session events are provided TriggeredAtOrigin: fmt.Sprintf("%s://%s:%d", externalProtocol, instancePrimaryDomain, externalPort), URLTemplate: "", Code: code, @@ -1459,11 +1449,15 @@ func Test_userNotifier_reduceOTPSMSChallenged(t *testing.T) { gomock.Any(), gomock.Any(), ).Return(nil) + + mockQuerier := es_repo_mock.NewMockQuerier(ctrl) + mockQuerier.EXPECT().FilterToReducer(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).AnyTimes() + return fields{ queries: queries, queue: queue, es: eventstore.NewEventstore(&eventstore.Config{ - Querier: es_repo_mock.NewRepo(t).ExpectFilterEvents().MockQuerier, + Querier: mockQuerier, }), }, args{ event: &session.OTPSMSChallengedEvent{ @@ -1484,19 +1478,11 @@ func Test_userNotifier_reduceOTPSMSChallenged(t *testing.T) { { name: "external code", test: func(ctrl *gomock.Controller, queries *mock.MockQueries, queue *mock.MockQueue) (f fields, a args, w want) { - queries.EXPECT().SessionByID(gomock.Any(), gomock.Any(), sessionID, gomock.Any(), nil).Return(&query.Session{ - ID: sessionID, - ResourceOwner: instanceID, - UserFactor: query.SessionUserFactor{ - UserID: userID, - ResourceOwner: orgID, - }, - }, nil) queue.EXPECT().Insert( gomock.Any(), ¬ification.Request{ - UserID: userID, - UserResourceOwner: orgID, + UserID: "", // Empty since no session events are provided + UserResourceOwner: "", // Empty since no session events are provided TriggeredAtOrigin: eventOrigin, URLTemplate: "", Code: nil, @@ -1522,11 +1508,15 @@ func Test_userNotifier_reduceOTPSMSChallenged(t *testing.T) { gomock.Any(), gomock.Any(), ).Return(nil) + + mockQuerier := es_repo_mock.NewMockQuerier(ctrl) + mockQuerier.EXPECT().FilterToReducer(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).AnyTimes() + return fields{ queries: queries, queue: queue, es: eventstore.NewEventstore(&eventstore.Config{ - Querier: es_repo_mock.NewRepo(t).ExpectFilterEvents().MockQuerier, + Querier: mockQuerier, }), }, args{ event: &session.OTPSMSChallengedEvent{