feat: exchange gRPC server implementation to connectRPC (#10145)

# Which Problems Are Solved

The current maintained gRPC server in combination with a REST (grpc)
gateway is getting harder and harder to maintain. Additionally, there
have been and still are issues with supporting / displaying `oneOf`s
correctly.
We therefore decided to exchange the server implementation to
connectRPC, which apart from supporting connect as protocol, also also
"standard" gRCP clients as well as HTTP/1.1 / rest like clients, e.g.
curl directly call the server without any additional gateway.

# How the Problems Are Solved

- All v2 services are moved to connectRPC implementation. (v1 services
are still served as pure grpc servers)
- All gRPC server interceptors were migrated / copied to a corresponding
connectRPC interceptor.
- API.ListGrpcServices and API. ListGrpcMethods were changed to include
the connect services and endpoints.
- gRPC server reflection was changed to a `StaticReflector` using the
`ListGrpcServices` list.
- The `grpc.Server` interfaces was split into different combinations to
be able to handle the different cases (grpc server and prefixed gateway,
connect server with grpc gateway, connect server only, ...)
- Docs of services serving connectRPC only with no additional gateway
(instance, webkey, project, app, org v2 beta) are changed to expose that
- since the plugin is not yet available on buf, we download it using
`postinstall` hook of the docs

# Additional Changes

- WebKey service is added as v2 service (in addition to the current
v2beta)

# Additional Context

closes #9483

---------

Co-authored-by: Elio Bischof <elio@zitadel.com>
This commit is contained in:
Livio Spring
2025-07-04 10:06:20 -04:00
committed by GitHub
parent 82cd1cee08
commit 9ebf2316c6
133 changed files with 5191 additions and 1187 deletions

View File

@@ -25,6 +25,7 @@ env:
internal/api/assets/router.go internal/api/assets/router.go
openapi/v2 openapi/v2
pkg/grpc/**/*.pb.* pkg/grpc/**/*.pb.*
pkg/grpc/**/*.connect.go
jobs: jobs:
build: build:

1
.gitignore vendored
View File

@@ -52,6 +52,7 @@ console/src/app/proto/generated/
!pkg/grpc/protoc/v2/options.pb.go !pkg/grpc/protoc/v2/options.pb.go
**.proto.mock.go **.proto.mock.go
**.pb.*.go **.pb.*.go
pkg/**/**.connect.go
**.gen.go **.gen.go
openapi/**/*.json openapi/**/*.json
/internal/api/assets/authz.go /internal/api/assets/authz.go

View File

@@ -78,12 +78,13 @@ core_grpc_dependencies:
go install github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2@v2.22.0 # https://pkg.go.dev/github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2?tab=versions go install github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2@v2.22.0 # https://pkg.go.dev/github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2?tab=versions
go install github.com/envoyproxy/protoc-gen-validate@v1.1.0 # https://pkg.go.dev/github.com/envoyproxy/protoc-gen-validate?tab=versions go install github.com/envoyproxy/protoc-gen-validate@v1.1.0 # https://pkg.go.dev/github.com/envoyproxy/protoc-gen-validate?tab=versions
go install github.com/bufbuild/buf/cmd/buf@v1.45.0 # https://pkg.go.dev/github.com/bufbuild/buf/cmd/buf?tab=versions go install github.com/bufbuild/buf/cmd/buf@v1.45.0 # https://pkg.go.dev/github.com/bufbuild/buf/cmd/buf?tab=versions
go install connectrpc.com/connect/cmd/protoc-gen-connect-go@v1.18.1 # https://pkg.go.dev/connectrpc.com/connect/cmd/protoc-gen-connect-go?tab=versions
.PHONY: core_api .PHONY: core_api
core_api: core_api_generator core_grpc_dependencies core_api: core_api_generator core_grpc_dependencies
buf generate buf generate
mkdir -p pkg/grpc mkdir -p pkg/grpc
cp -r .artifacts/grpc/github.com/zitadel/zitadel/pkg/grpc/* pkg/grpc/ cp -r .artifacts/grpc/github.com/zitadel/zitadel/pkg/grpc/** pkg/grpc/
mkdir -p openapi/v2/zitadel mkdir -p openapi/v2/zitadel
cp -r .artifacts/grpc/zitadel/ openapi/v2/zitadel cp -r .artifacts/grpc/zitadel/ openapi/v2/zitadel

View File

@@ -19,3 +19,5 @@ plugins:
out: .artifacts/grpc out: .artifacts/grpc
- plugin: zitadel - plugin: zitadel
out: .artifacts/grpc out: .artifacts/grpc
- plugin: connect-go
out: .artifacts/grpc

View File

@@ -59,7 +59,8 @@ import (
"github.com/zitadel/zitadel/internal/api/grpc/system" "github.com/zitadel/zitadel/internal/api/grpc/system"
user_v2 "github.com/zitadel/zitadel/internal/api/grpc/user/v2" user_v2 "github.com/zitadel/zitadel/internal/api/grpc/user/v2"
user_v2beta "github.com/zitadel/zitadel/internal/api/grpc/user/v2beta" user_v2beta "github.com/zitadel/zitadel/internal/api/grpc/user/v2beta"
webkey "github.com/zitadel/zitadel/internal/api/grpc/webkey/v2beta" webkey_v2 "github.com/zitadel/zitadel/internal/api/grpc/webkey/v2"
webkey_v2beta "github.com/zitadel/zitadel/internal/api/grpc/webkey/v2beta"
http_util "github.com/zitadel/zitadel/internal/api/http" http_util "github.com/zitadel/zitadel/internal/api/http"
"github.com/zitadel/zitadel/internal/api/http/middleware" "github.com/zitadel/zitadel/internal/api/http/middleware"
"github.com/zitadel/zitadel/internal/api/idp" "github.com/zitadel/zitadel/internal/api/idp"
@@ -515,7 +516,10 @@ func startAPIs(
if err := apis.RegisterService(ctx, user_v3_alpha.CreateServer(commands)); err != nil { if err := apis.RegisterService(ctx, user_v3_alpha.CreateServer(commands)); err != nil {
return nil, err return nil, err
} }
if err := apis.RegisterService(ctx, webkey.CreateServer(commands, queries)); err != nil { if err := apis.RegisterService(ctx, webkey_v2beta.CreateServer(commands, queries)); err != nil {
return nil, err
}
if err := apis.RegisterService(ctx, webkey_v2.CreateServer(commands, queries)); err != nil {
return nil, err return nil, err
} }
if err := apis.RegisterService(ctx, debug_events.CreateServer(commands, queries)); err != nil { if err := apis.RegisterService(ctx, debug_events.CreateServer(commands, queries)); err != nil {

1
docs/.gitignore vendored
View File

@@ -27,3 +27,4 @@ npm-debug.log*
yarn-debug.log* yarn-debug.log*
yarn-error.log* yarn-error.log*
.vercel .vercel
/protoc-gen-connect-openapi*

3
docs/base.yaml Normal file
View File

@@ -0,0 +1,3 @@
openapi: 3.1.0
info:
version: v2

View File

@@ -1,11 +1,18 @@
# buf.gen.yaml # buf.gen.yaml
version: v1 version: v2
managed: managed:
enabled: true enabled: true
plugins: plugins:
- plugin: buf.build/grpc-ecosystem/openapiv2 - remote: buf.build/grpc-ecosystem/openapiv2
out: .artifacts/openapi out: .artifacts/openapi
opt: opt:
- allow_delete_body - allow_delete_body
- remove_internal_comments=true - remove_internal_comments=true
- preserve_rpc_order=true - preserve_rpc_order=true
- local: ./protoc-gen-connect-openapi
out: .artifacts/openapi3
strategy: all
opt:
- short-service-tags
- ignore-googleapi-http
- base=base.yaml

View File

@@ -337,7 +337,7 @@ module.exports = {
}, },
webkey_v2: { webkey_v2: {
specPath: specPath:
".artifacts/openapi/zitadel/webkey/v2beta/webkey_service.swagger.json", ".artifacts/openapi3/zitadel/webkey/v2/webkey_service.openapi.yaml",
outputDir: "docs/apis/resources/webkey_service_v2", outputDir: "docs/apis/resources/webkey_service_v2",
sidebarOptions: { sidebarOptions: {
groupPathsBy: "tag", groupPathsBy: "tag",
@@ -373,7 +373,7 @@ module.exports = {
}, },
org_v2beta: { org_v2beta: {
specPath: specPath:
".artifacts/openapi/zitadel/org/v2beta/org_service.swagger.json", ".artifacts/openapi3/zitadel/org/v2beta/org_service.openapi.yaml",
outputDir: "docs/apis/resources/org_service_v2beta", outputDir: "docs/apis/resources/org_service_v2beta",
sidebarOptions: { sidebarOptions: {
groupPathsBy: "tag", groupPathsBy: "tag",
@@ -382,16 +382,24 @@ module.exports = {
}, },
project_v2beta: { project_v2beta: {
specPath: specPath:
".artifacts/openapi/zitadel/project/v2beta/project_service.swagger.json", ".artifacts/openapi3/zitadel/project/v2beta/project_service.openapi.yaml",
outputDir: "docs/apis/resources/project_service_v2", outputDir: "docs/apis/resources/project_service_v2",
sidebarOptions: { sidebarOptions: {
groupPathsBy: "tag", groupPathsBy: "tag",
categoryLinkSource: "auto", categoryLinkSource: "auto",
}, },
}, },
application_v2: {
specPath: ".artifacts/openapi3/zitadel/app/v2beta/app_service.openapi.yaml",
outputDir: "docs/apis/resources/application_service_v2",
sidebarOptions: {
groupPathsBy: "tag",
categoryLinkSource: "auto",
},
},
instance_v2: { instance_v2: {
specPath: specPath:
".artifacts/openapi/zitadel/instance/v2beta/instance_service.swagger.json", ".artifacts/openapi3/zitadel/instance/v2beta/instance_service.openapi.yaml",
outputDir: "docs/apis/resources/instance_service_v2", outputDir: "docs/apis/resources/instance_service_v2",
sidebarOptions: { sidebarOptions: {
groupPathsBy: "tag", groupPathsBy: "tag",

View File

@@ -18,7 +18,8 @@
"generate:apidocs": "docusaurus gen-api-docs all", "generate:apidocs": "docusaurus gen-api-docs all",
"generate:configdocs": "cp -r ../cmd/defaults.yaml ./docs/self-hosting/manage/configure/ && cp -r ../cmd/setup/steps.yaml ./docs/self-hosting/manage/configure/", "generate:configdocs": "cp -r ../cmd/defaults.yaml ./docs/self-hosting/manage/configure/ && cp -r ../cmd/setup/steps.yaml ./docs/self-hosting/manage/configure/",
"generate:re-gen": "yarn generate:clean-all && yarn generate", "generate:re-gen": "yarn generate:clean-all && yarn generate",
"generate:clean-all": "docusaurus clean-api-docs all" "generate:clean-all": "docusaurus clean-api-docs all",
"postinstall": "sh ./plugin-download.sh"
}, },
"dependencies": { "dependencies": {
"@bufbuild/buf": "^1.14.0", "@bufbuild/buf": "^1.14.0",

21
docs/plugin-download.sh Normal file
View File

@@ -0,0 +1,21 @@
echo $(uname -m)
if [ "$(uname)" = "Darwin" ]; then
curl -L -o protoc-gen-connect-openapi.tar.gz https://github.com/sudorandom/protoc-gen-connect-openapi/releases/download/v0.18.0/protoc-gen-connect-openapi_0.18.0_darwin_all.tar.gz
else
ARCH=$(uname -m)
case $ARCH in
x86_64)
ARCH="amd64"
;;
aarch64|arm64)
ARCH="arm64"
;;
*)
echo "Unsupported architecture: $ARCH"
exit 1
;;
esac
curl -L -o protoc-gen-connect-openapi.tar.gz https://github.com/sudorandom/protoc-gen-connect-openapi/releases/download/v0.18.0/protoc-gen-connect-openapi_0.18.0_linux_${ARCH}.tar.gz
fi
tar -xvf protoc-gen-connect-openapi.tar.gz

View File

@@ -16,6 +16,7 @@ const sidebar_api_actions_v2 = require("./docs/apis/resources/action_service_v2/
const sidebar_api_project_service_v2 = require("./docs/apis/resources/project_service_v2/sidebar.ts").default const sidebar_api_project_service_v2 = require("./docs/apis/resources/project_service_v2/sidebar.ts").default
const sidebar_api_webkey_service_v2 = require("./docs/apis/resources/webkey_service_v2/sidebar.ts").default const sidebar_api_webkey_service_v2 = require("./docs/apis/resources/webkey_service_v2/sidebar.ts").default
const sidebar_api_instance_service_v2 = require("./docs/apis/resources/instance_service_v2/sidebar.ts").default const sidebar_api_instance_service_v2 = require("./docs/apis/resources/instance_service_v2/sidebar.ts").default
const sidebar_api_app_v2 = require("./docs/apis/resources/application_service_v2/sidebar.ts").default
module.exports = { module.exports = {
guides: [ guides: [
@@ -806,6 +807,18 @@ module.exports = {
}, },
items: sidebar_api_org_service_v2, items: sidebar_api_org_service_v2,
}, },
{
type: "category",
label: "Organization (Beta)",
link: {
type: "generated-index",
title: "Organization Service beta API",
slug: "/apis/resources/org_service/v2beta",
description:
"This API is intended to manage organizations for ZITADEL. \n",
},
items: sidebar_api_org_service_v2beta,
},
{ {
type: "category", type: "category",
label: "Identity Provider", label: "Identity Provider",
@@ -820,19 +833,15 @@ module.exports = {
}, },
{ {
type: "category", type: "category",
label: "Web key (Beta)", label: "Web Key",
link: { link: {
type: "generated-index", type: "generated-index",
title: "Web Key Service API (Beta)", title: "Web Key Service API",
slug: "/apis/resources/webkey_service_v2", slug: "/apis/resources/webkey_service_v2",
description: description:
"This API is intended to manage web keys for a ZITADEL instance, used to sign and validate OIDC tokens.\n" + "This API is intended to manage web keys for a ZITADEL instance, used to sign and validate OIDC tokens.\n" +
"\n" +
"This service is in beta state. It can AND will continue breaking until a stable version is released.\n"+
"\n"+ "\n"+
"The public key endpoint (outside of this service) is used to retrieve the public keys of the active and inactive keys.\n"+ "The public key endpoint (outside of this service) is used to retrieve the public keys of the active and inactive keys.\n",
"\n"+
"Please make sure to enable the `web_key` feature flag on your instance to use this service and that you're running ZITADEL V3.",
}, },
items: sidebar_api_webkey_service_v2 items: sidebar_api_webkey_service_v2
}, },
@@ -857,6 +866,54 @@ module.exports = {
}, },
items: sidebar_api_actions_v2, items: sidebar_api_actions_v2,
}, },
{
type: "category",
label: "Project (Beta)",
link: {
type: "generated-index",
title: "Project Service API (Beta)",
slug: "/apis/resources/project_service_v2",
description:
"This API is intended to manage projects and subresources for ZITADEL. \n" +
"\n" +
"This service is in beta state. It can AND will continue breaking until a stable version is released.",
},
items: sidebar_api_project_service_v2,
},
{
type: "category",
label: "Instance (Beta)",
link: {
type: "generated-index",
title: "Instance Service API (Beta)",
slug: "/apis/resources/instance_service_v2",
description:
"This API is intended to manage instances, custom domains and trusted domains in ZITADEL.\n" +
"\n" +
"This service is in beta state. It can AND will continue breaking until a stable version is released.\n"+
"\n" +
"This v2 of the API provides the same functionalities as the v1, but organised on a per resource basis.\n" +
"The whole functionality related to domains (custom and trusted) has been moved under this instance API."
,
},
items: sidebar_api_instance_service_v2,
},
{
type: "category",
label: "App (Beta)",
link: {
type: "generated-index",
title: "Application Service API (Beta)",
slug: "/apis/resources/application_service_v2",
description:
"This API lets you manage Zitadel applications (API, SAML, OIDC).\n"+
"\n"+
"The API offers generic endpoints that work for all app types (API, SAML, OIDC), "+
"\n"+
"This API is in beta state. It can AND will continue breaking until a stable version is released.\n"
},
items: sidebar_api_app_v2,
},
], ],
}, },
{ {

View File

@@ -6121,6 +6121,11 @@ caniuse-lite@^1.0.30001702, caniuse-lite@^1.0.30001718:
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001724.tgz#312e163553dd70d2c0fb603d74810c85d8ed94a0" resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001724.tgz#312e163553dd70d2c0fb603d74810c85d8ed94a0"
integrity sha512-WqJo7p0TbHDOythNTqYujmaJTvtYRZrjpP8TCvH6Vb9CYJerJNKamKzIWOM4BkQatWj9H2lYulpdAQNBe7QhNA== integrity sha512-WqJo7p0TbHDOythNTqYujmaJTvtYRZrjpP8TCvH6Vb9CYJerJNKamKzIWOM4BkQatWj9H2lYulpdAQNBe7QhNA==
caniuse-lite@^1.0.30001716:
version "1.0.30001726"
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001726.tgz#a15bd87d5a4bf01f6b6f70ae7c97fdfd28b5ae47"
integrity sha512-VQAUIUzBiZ/UnlM28fSp2CRF3ivUn1BWEvxMcVTNwpw91Py1pGbPIyIKtd+tzct9C3ouceCVdGAXxZOpZAsgdw==
ccount@^2.0.0: ccount@^2.0.0:
version "2.0.1" version "2.0.1"
resolved "https://registry.yarnpkg.com/ccount/-/ccount-2.0.1.tgz#17a3bf82302e0870d6da43a01311a8bc02a3ecf5" resolved "https://registry.yarnpkg.com/ccount/-/ccount-2.0.1.tgz#17a3bf82302e0870d6da43a01311a8bc02a3ecf5"
@@ -7503,6 +7508,11 @@ electron-to-chromium@^1.4.796:
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.803.tgz#cf55808a5ee12e2a2778bbe8cdc941ef87c2093b" resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.803.tgz#cf55808a5ee12e2a2778bbe8cdc941ef87c2093b"
integrity sha512-61H9mLzGOCLLVsnLiRzCbc63uldP0AniRYPV3hbGVtONA1pI7qSGILdbofR7A8TMbOypDocEAjH/e+9k1QIe3g== integrity sha512-61H9mLzGOCLLVsnLiRzCbc63uldP0AniRYPV3hbGVtONA1pI7qSGILdbofR7A8TMbOypDocEAjH/e+9k1QIe3g==
electron-to-chromium@^1.5.149:
version "1.5.178"
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.178.tgz#6fc4d69eb5275bb13068931448fd822458901fbb"
integrity sha512-wObbz/ar3Bc6e4X5vf0iO8xTN8YAjN/tgiAOJLr7yjYFtP9wAjq8Mb5h0yn6kResir+VYx2DXBj9NNobs0ETSA==
electron-to-chromium@^1.5.160: electron-to-chromium@^1.5.160:
version "1.5.172" version "1.5.172"
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.172.tgz#fe1d99028d8d6321668d0f1fed61d99ac896259c" resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.172.tgz#fe1d99028d8d6321668d0f1fed61d99ac896259c"

2
go.mod
View File

@@ -7,6 +7,8 @@ toolchain go1.24.1
require ( require (
cloud.google.com/go/profiler v0.4.2 cloud.google.com/go/profiler v0.4.2
cloud.google.com/go/storage v1.54.0 cloud.google.com/go/storage v1.54.0
connectrpc.com/connect v1.18.1
connectrpc.com/grpcreflect v1.3.0
dario.cat/mergo v1.0.2 dario.cat/mergo v1.0.2
github.com/BurntSushi/toml v1.5.0 github.com/BurntSushi/toml v1.5.0
github.com/DATA-DOG/go-sqlmock v1.5.2 github.com/DATA-DOG/go-sqlmock v1.5.2

4
go.sum
View File

@@ -24,6 +24,10 @@ cloud.google.com/go/storage v1.54.0 h1:Du3XEyliAiftfyW0bwfdppm2MMLdpVAfiIg4T2nAI
cloud.google.com/go/storage v1.54.0/go.mod h1:hIi9Boe8cHxTyaeqh7KMMwKg088VblFK46C2x/BWaZE= cloud.google.com/go/storage v1.54.0/go.mod h1:hIi9Boe8cHxTyaeqh7KMMwKg088VblFK46C2x/BWaZE=
cloud.google.com/go/trace v1.11.3 h1:c+I4YFjxRQjvAhRmSsmjpASUKq88chOX854ied0K/pE= cloud.google.com/go/trace v1.11.3 h1:c+I4YFjxRQjvAhRmSsmjpASUKq88chOX854ied0K/pE=
cloud.google.com/go/trace v1.11.3/go.mod h1:pt7zCYiDSQjC9Y2oqCsh9jF4GStB/hmjrYLsxRR27q8= cloud.google.com/go/trace v1.11.3/go.mod h1:pt7zCYiDSQjC9Y2oqCsh9jF4GStB/hmjrYLsxRR27q8=
connectrpc.com/connect v1.18.1 h1:PAg7CjSAGvscaf6YZKUefjoih5Z/qYkyaTrBW8xvYPw=
connectrpc.com/connect v1.18.1/go.mod h1:0292hj1rnx8oFrStN7cB4jjVBeqs+Yx5yDIC2prWDO8=
connectrpc.com/grpcreflect v1.3.0 h1:Y4V+ACf8/vOb1XOc251Qun7jMB75gCUNw6llvB9csXc=
connectrpc.com/grpcreflect v1.3.0/go.mod h1:nfloOtCS8VUQOQ1+GTdFzVg2CJo4ZGaat8JIovCtDYs=
dario.cat/mergo v1.0.2 h1:85+piFYR1tMbRrLcDwR18y4UKJ3aH1Tbzi24VRW1TK8= dario.cat/mergo v1.0.2 h1:85+piFYR1tMbRrLcDwR18y4UKJ3aH1Tbzi24VRW1TK8=
dario.cat/mergo v1.0.2/go.mod h1:E/hbnu0NxMFBjpMIE34DRGLWqDy0g5FuKDhCb31ngxA= dario.cat/mergo v1.0.2/go.mod h1:E/hbnu0NxMFBjpMIE34DRGLWqDy0g5FuKDhCb31ngxA=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=

View File

@@ -7,16 +7,18 @@ import (
"sort" "sort"
"strings" "strings"
"connectrpc.com/grpcreflect"
"github.com/gorilla/mux" "github.com/gorilla/mux"
"github.com/improbable-eng/grpc-web/go/grpcweb" "github.com/improbable-eng/grpc-web/go/grpcweb"
"github.com/zitadel/logging" "github.com/zitadel/logging"
"google.golang.org/grpc" "google.golang.org/grpc"
"google.golang.org/grpc/health" "google.golang.org/grpc/health"
healthpb "google.golang.org/grpc/health/grpc_health_v1" healthpb "google.golang.org/grpc/health/grpc_health_v1"
"google.golang.org/grpc/reflection"
"github.com/zitadel/zitadel/internal/api/authz" "github.com/zitadel/zitadel/internal/api/authz"
grpc_api "github.com/zitadel/zitadel/internal/api/grpc"
"github.com/zitadel/zitadel/internal/api/grpc/server" "github.com/zitadel/zitadel/internal/api/grpc/server"
"github.com/zitadel/zitadel/internal/api/grpc/server/connect_middleware"
http_util "github.com/zitadel/zitadel/internal/api/http" http_util "github.com/zitadel/zitadel/internal/api/http"
http_mw "github.com/zitadel/zitadel/internal/api/http/middleware" http_mw "github.com/zitadel/zitadel/internal/api/http/middleware"
"github.com/zitadel/zitadel/internal/api/ui/login" "github.com/zitadel/zitadel/internal/api/ui/login"
@@ -24,10 +26,16 @@ import (
"github.com/zitadel/zitadel/internal/telemetry/metrics" "github.com/zitadel/zitadel/internal/telemetry/metrics"
"github.com/zitadel/zitadel/internal/telemetry/tracing" "github.com/zitadel/zitadel/internal/telemetry/tracing"
"github.com/zitadel/zitadel/internal/zerrors" "github.com/zitadel/zitadel/internal/zerrors"
system_pb "github.com/zitadel/zitadel/pkg/grpc/system"
)
var (
metricTypes = []metrics.MetricType{metrics.MetricTypeTotalCount, metrics.MetricTypeRequestCount, metrics.MetricTypeStatusCode}
) )
type API struct { type API struct {
port uint16 port uint16
externalDomain string
grpcServer *grpc.Server grpcServer *grpc.Server
verifier authz.APITokenVerifier verifier authz.APITokenVerifier
health healthCheck health healthCheck
@@ -37,16 +45,23 @@ type API struct {
healthServer *health.Server healthServer *health.Server
accessInterceptor *http_mw.AccessInterceptor accessInterceptor *http_mw.AccessInterceptor
queries *query.Queries queries *query.Queries
authConfig authz.Config
systemAuthZ authz.Config
connectServices map[string][]string
} }
func (a *API) ListGrpcServices() []string { func (a *API) ListGrpcServices() []string {
serviceInfo := a.grpcServer.GetServiceInfo() serviceInfo := a.grpcServer.GetServiceInfo()
services := make([]string, len(serviceInfo)) services := make([]string, len(serviceInfo)+len(a.connectServices))
i := 0 i := 0
for servicename := range serviceInfo { for servicename := range serviceInfo {
services[i] = servicename services[i] = servicename
i++ i++
} }
for prefix := range a.connectServices {
services[i] = strings.Trim(prefix, "/")
i++
}
sort.Strings(services) sort.Strings(services)
return services return services
} }
@@ -59,6 +74,11 @@ func (a *API) ListGrpcMethods() []string {
methods = append(methods, "/"+servicename+"/"+method.Name) methods = append(methods, "/"+servicename+"/"+method.Name)
} }
} }
for service, methodList := range a.connectServices {
for _, method := range methodList {
methods = append(methods, service+method)
}
}
sort.Strings(methods) sort.Strings(methods)
return methods return methods
} }
@@ -82,12 +102,16 @@ func New(
) (_ *API, err error) { ) (_ *API, err error) {
api := &API{ api := &API{
port: port, port: port,
externalDomain: externalDomain,
verifier: verifier, verifier: verifier,
health: queries, health: queries,
router: router, router: router,
queries: queries, queries: queries,
accessInterceptor: accessInterceptor, accessInterceptor: accessInterceptor,
hostHeaders: hostHeaders, hostHeaders: hostHeaders,
authConfig: authZ,
systemAuthZ: systemAuthz,
connectServices: make(map[string][]string),
} }
api.grpcServer = server.CreateServer(api.verifier, systemAuthz, authZ, queries, externalDomain, tlsConfig, accessInterceptor.AccessService()) api.grpcServer = server.CreateServer(api.verifier, systemAuthz, authZ, queries, externalDomain, tlsConfig, accessInterceptor.AccessService())
@@ -100,10 +124,15 @@ func New(
api.RegisterHandlerOnPrefix("/debug", api.healthHandler()) api.RegisterHandlerOnPrefix("/debug", api.healthHandler())
api.router.Handle("/", http.RedirectHandler(login.HandlerPrefix, http.StatusFound)) api.router.Handle("/", http.RedirectHandler(login.HandlerPrefix, http.StatusFound))
reflection.Register(api.grpcServer)
return api, nil return api, nil
} }
func (a *API) serverReflection() {
reflector := grpcreflect.NewStaticReflector(a.ListGrpcServices()...)
a.RegisterHandlerOnPrefix(grpcreflect.NewHandlerV1(reflector))
a.RegisterHandlerOnPrefix(grpcreflect.NewHandlerV1Alpha(reflector))
}
// RegisterServer registers a grpc service on the grpc server, // RegisterServer registers a grpc service on the grpc server,
// creates a new grpc gateway and registers it as a separate http handler // creates a new grpc gateway and registers it as a separate http handler
// //
@@ -131,17 +160,50 @@ func (a *API) RegisterServer(ctx context.Context, grpcServer server.WithGatewayP
// and its gateway on the gateway handler // and its gateway on the gateway handler
// //
// used for >= v2 api (e.g. user, session, ...) // used for >= v2 api (e.g. user, session, ...)
func (a *API) RegisterService(ctx context.Context, grpcServer server.Server) error { func (a *API) RegisterService(ctx context.Context, srv server.Server) error {
grpcServer.RegisterServer(a.grpcServer) switch service := srv.(type) {
err := server.RegisterGateway(ctx, a.grpcGateway, grpcServer) case server.GrpcServer:
service.RegisterServer(a.grpcServer)
case server.ConnectServer:
a.registerConnectServer(service)
}
if withGateway, ok := srv.(server.WithGateway); ok {
err := server.RegisterGateway(ctx, a.grpcGateway, withGateway)
if err != nil { if err != nil {
return err return err
} }
a.verifier.RegisterServer(grpcServer.AppName(), grpcServer.MethodPrefix(), grpcServer.AuthMethods()) }
a.healthServer.SetServingStatus(grpcServer.MethodPrefix(), healthpb.HealthCheckResponse_SERVING) a.verifier.RegisterServer(srv.AppName(), srv.MethodPrefix(), srv.AuthMethods())
a.healthServer.SetServingStatus(srv.MethodPrefix(), healthpb.HealthCheckResponse_SERVING)
return nil return nil
} }
func (a *API) registerConnectServer(service server.ConnectServer) {
prefix, handler := service.RegisterConnectServer(
connect_middleware.CallDurationHandler(),
connect_middleware.MetricsHandler(metricTypes, grpc_api.Probes...),
connect_middleware.NoCacheInterceptor(),
connect_middleware.InstanceInterceptor(a.queries, a.externalDomain, system_pb.SystemService_ServiceDesc.ServiceName, healthpb.Health_ServiceDesc.ServiceName),
connect_middleware.AccessStorageInterceptor(a.accessInterceptor.AccessService()),
connect_middleware.ErrorHandler(),
connect_middleware.LimitsInterceptor(system_pb.SystemService_ServiceDesc.ServiceName),
connect_middleware.AuthorizationInterceptor(a.verifier, a.systemAuthZ, a.authConfig),
connect_middleware.TranslationHandler(),
connect_middleware.QuotaExhaustedInterceptor(a.accessInterceptor.AccessService(), system_pb.SystemService_ServiceDesc.ServiceName),
connect_middleware.ExecutionHandler(a.queries),
connect_middleware.ValidationHandler(),
connect_middleware.ServiceHandler(),
connect_middleware.ActivityInterceptor(),
)
methods := service.FileDescriptor().Services().Get(0).Methods()
methodNames := make([]string, methods.Len())
for i := 0; i < methods.Len(); i++ {
methodNames[i] = string(methods.Get(i).Name())
}
a.connectServices[prefix] = methodNames
a.RegisterHandlerPrefixes(handler, prefix)
}
// HandleFunc allows registering a [http.HandlerFunc] on an exact // HandleFunc allows registering a [http.HandlerFunc] on an exact
// path, instead of prefix like RegisterHandlerOnPrefix. // path, instead of prefix like RegisterHandlerOnPrefix.
func (a *API) HandleFunc(path string, f http.HandlerFunc) { func (a *API) HandleFunc(path string, f http.HandlerFunc) {
@@ -173,6 +235,9 @@ func (a *API) registerHealthServer() {
} }
func (a *API) RouteGRPC() { func (a *API) RouteGRPC() {
// since all services are now registered, we can build the grpc server reflection and register the handler
a.serverReflection()
http2Route := a.router. http2Route := a.router.
MatcherFunc(func(r *http.Request, _ *mux.RouteMatch) bool { MatcherFunc(func(r *http.Request, _ *mux.RouteMatch) bool {
return r.ProtoMajor == 2 return r.ProtoMajor == 2

View File

@@ -3,6 +3,7 @@ package action
import ( import (
"context" "context"
"connectrpc.com/connect"
"google.golang.org/protobuf/types/known/timestamppb" "google.golang.org/protobuf/types/known/timestamppb"
"github.com/zitadel/zitadel/internal/api/authz" "github.com/zitadel/zitadel/internal/api/authz"
@@ -13,8 +14,8 @@ import (
action "github.com/zitadel/zitadel/pkg/grpc/action/v2beta" action "github.com/zitadel/zitadel/pkg/grpc/action/v2beta"
) )
func (s *Server) SetExecution(ctx context.Context, req *action.SetExecutionRequest) (*action.SetExecutionResponse, error) { func (s *Server) SetExecution(ctx context.Context, req *connect.Request[action.SetExecutionRequest]) (*connect.Response[action.SetExecutionResponse], error) {
reqTargets := req.GetTargets() reqTargets := req.Msg.GetTargets()
targets := make([]*execution.Target, len(reqTargets)) targets := make([]*execution.Target, len(reqTargets))
for i, target := range reqTargets { for i, target := range reqTargets {
targets[i] = &execution.Target{Type: domain.ExecutionTargetTypeTarget, Target: target} targets[i] = &execution.Target{Type: domain.ExecutionTargetTypeTarget, Target: target}
@@ -25,7 +26,7 @@ func (s *Server) SetExecution(ctx context.Context, req *action.SetExecutionReque
var err error var err error
var details *domain.ObjectDetails var details *domain.ObjectDetails
instanceID := authz.GetInstance(ctx).InstanceID() instanceID := authz.GetInstance(ctx).InstanceID()
switch t := req.GetCondition().GetConditionType().(type) { switch t := req.Msg.GetCondition().GetConditionType().(type) {
case *action.Condition_Request: case *action.Condition_Request:
cond := executionConditionFromRequest(t.Request) cond := executionConditionFromRequest(t.Request)
details, err = s.command.SetExecutionRequest(ctx, cond, set, instanceID) details, err = s.command.SetExecutionRequest(ctx, cond, set, instanceID)
@@ -43,27 +44,27 @@ func (s *Server) SetExecution(ctx context.Context, req *action.SetExecutionReque
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &action.SetExecutionResponse{ return connect.NewResponse(&action.SetExecutionResponse{
SetDate: timestamppb.New(details.EventDate), SetDate: timestamppb.New(details.EventDate),
}, nil }), nil
} }
func (s *Server) ListExecutionFunctions(ctx context.Context, _ *action.ListExecutionFunctionsRequest) (*action.ListExecutionFunctionsResponse, error) { func (s *Server) ListExecutionFunctions(ctx context.Context, _ *connect.Request[action.ListExecutionFunctionsRequest]) (*connect.Response[action.ListExecutionFunctionsResponse], error) {
return &action.ListExecutionFunctionsResponse{ return connect.NewResponse(&action.ListExecutionFunctionsResponse{
Functions: s.ListActionFunctions(), Functions: s.ListActionFunctions(),
}, nil }), nil
} }
func (s *Server) ListExecutionMethods(ctx context.Context, _ *action.ListExecutionMethodsRequest) (*action.ListExecutionMethodsResponse, error) { func (s *Server) ListExecutionMethods(ctx context.Context, _ *connect.Request[action.ListExecutionMethodsRequest]) (*connect.Response[action.ListExecutionMethodsResponse], error) {
return &action.ListExecutionMethodsResponse{ return connect.NewResponse(&action.ListExecutionMethodsResponse{
Methods: s.ListGRPCMethods(), Methods: s.ListGRPCMethods(),
}, nil }), nil
} }
func (s *Server) ListExecutionServices(ctx context.Context, _ *action.ListExecutionServicesRequest) (*action.ListExecutionServicesResponse, error) { func (s *Server) ListExecutionServices(ctx context.Context, _ *connect.Request[action.ListExecutionServicesRequest]) (*connect.Response[action.ListExecutionServicesResponse], error) {
return &action.ListExecutionServicesResponse{ return connect.NewResponse(&action.ListExecutionServicesResponse{
Services: s.ListGRPCServices(), Services: s.ListGRPCServices(),
}, nil }), nil
} }
func executionConditionFromRequest(request *action.RequestExecution) *command.ExecutionAPICondition { func executionConditionFromRequest(request *action.RequestExecution) *command.ExecutionAPICondition {

View File

@@ -4,6 +4,7 @@ import (
"context" "context"
"strings" "strings"
"connectrpc.com/connect"
"google.golang.org/protobuf/types/known/durationpb" "google.golang.org/protobuf/types/known/durationpb"
"google.golang.org/protobuf/types/known/timestamppb" "google.golang.org/protobuf/types/known/timestamppb"
@@ -22,14 +23,14 @@ const (
conditionIDEventGroupSegmentCount = 1 conditionIDEventGroupSegmentCount = 1
) )
func (s *Server) GetTarget(ctx context.Context, req *action.GetTargetRequest) (*action.GetTargetResponse, error) { func (s *Server) GetTarget(ctx context.Context, req *connect.Request[action.GetTargetRequest]) (*connect.Response[action.GetTargetResponse], error) {
resp, err := s.query.GetTargetByID(ctx, req.GetId()) resp, err := s.query.GetTargetByID(ctx, req.Msg.GetId())
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &action.GetTargetResponse{ return connect.NewResponse(&action.GetTargetResponse{
Target: targetToPb(resp), Target: targetToPb(resp),
}, nil }), nil
} }
type InstanceContext interface { type InstanceContext interface {
@@ -41,8 +42,8 @@ type Context interface {
GetOwner() InstanceContext GetOwner() InstanceContext
} }
func (s *Server) ListTargets(ctx context.Context, req *action.ListTargetsRequest) (*action.ListTargetsResponse, error) { func (s *Server) ListTargets(ctx context.Context, req *connect.Request[action.ListTargetsRequest]) (*connect.Response[action.ListTargetsResponse], error) {
queries, err := s.ListTargetsRequestToModel(req) queries, err := s.ListTargetsRequestToModel(req.Msg)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -50,14 +51,14 @@ func (s *Server) ListTargets(ctx context.Context, req *action.ListTargetsRequest
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &action.ListTargetsResponse{ return connect.NewResponse(&action.ListTargetsResponse{
Result: targetsToPb(resp.Targets), Result: targetsToPb(resp.Targets),
Pagination: filter.QueryToPaginationPb(queries.SearchRequest, resp.SearchResponse), Pagination: filter.QueryToPaginationPb(queries.SearchRequest, resp.SearchResponse),
}, nil }), nil
} }
func (s *Server) ListExecutions(ctx context.Context, req *action.ListExecutionsRequest) (*action.ListExecutionsResponse, error) { func (s *Server) ListExecutions(ctx context.Context, req *connect.Request[action.ListExecutionsRequest]) (*connect.Response[action.ListExecutionsResponse], error) {
queries, err := s.ListExecutionsRequestToModel(req) queries, err := s.ListExecutionsRequestToModel(req.Msg)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -65,10 +66,10 @@ func (s *Server) ListExecutions(ctx context.Context, req *action.ListExecutionsR
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &action.ListExecutionsResponse{ return connect.NewResponse(&action.ListExecutionsResponse{
Result: executionsToPb(resp.Executions), Result: executionsToPb(resp.Executions),
Pagination: filter.QueryToPaginationPb(queries.SearchRequest, resp.SearchResponse), Pagination: filter.QueryToPaginationPb(queries.SearchRequest, resp.SearchResponse),
}, nil }), nil
} }
func targetsToPb(targets []*query.Target) []*action.Target { func targetsToPb(targets []*query.Target) []*action.Target {

View File

@@ -1,7 +1,10 @@
package action package action
import ( import (
"google.golang.org/grpc" "net/http"
"connectrpc.com/connect"
"google.golang.org/protobuf/reflect/protoreflect"
"github.com/zitadel/zitadel/internal/api/authz" "github.com/zitadel/zitadel/internal/api/authz"
"github.com/zitadel/zitadel/internal/api/grpc/server" "github.com/zitadel/zitadel/internal/api/grpc/server"
@@ -9,12 +12,12 @@ import (
"github.com/zitadel/zitadel/internal/config/systemdefaults" "github.com/zitadel/zitadel/internal/config/systemdefaults"
"github.com/zitadel/zitadel/internal/query" "github.com/zitadel/zitadel/internal/query"
action "github.com/zitadel/zitadel/pkg/grpc/action/v2beta" action "github.com/zitadel/zitadel/pkg/grpc/action/v2beta"
"github.com/zitadel/zitadel/pkg/grpc/action/v2beta/actionconnect"
) )
var _ action.ActionServiceServer = (*Server)(nil) var _ actionconnect.ActionServiceHandler = (*Server)(nil)
type Server struct { type Server struct {
action.UnimplementedActionServiceServer
systemDefaults systemdefaults.SystemDefaults systemDefaults systemdefaults.SystemDefaults
command *command.Commands command *command.Commands
query *query.Queries query *query.Queries
@@ -43,8 +46,12 @@ func CreateServer(
} }
} }
func (s *Server) RegisterServer(grpcServer *grpc.Server) { func (s *Server) RegisterConnectServer(interceptors ...connect.Interceptor) (string, http.Handler) {
action.RegisterActionServiceServer(grpcServer, s) return actionconnect.NewActionServiceHandler(s, connect.WithInterceptors(interceptors...))
}
func (s *Server) FileDescriptor() protoreflect.FileDescriptor {
return action.File_zitadel_action_v2beta_action_service_proto
} }
func (s *Server) AppName() string { func (s *Server) AppName() string {

View File

@@ -3,6 +3,7 @@ package action
import ( import (
"context" "context"
"connectrpc.com/connect"
"github.com/muhlemmer/gu" "github.com/muhlemmer/gu"
"google.golang.org/protobuf/types/known/timestamppb" "google.golang.org/protobuf/types/known/timestamppb"
@@ -13,8 +14,8 @@ import (
action "github.com/zitadel/zitadel/pkg/grpc/action/v2beta" action "github.com/zitadel/zitadel/pkg/grpc/action/v2beta"
) )
func (s *Server) CreateTarget(ctx context.Context, req *action.CreateTargetRequest) (*action.CreateTargetResponse, error) { func (s *Server) CreateTarget(ctx context.Context, req *connect.Request[action.CreateTargetRequest]) (*connect.Response[action.CreateTargetResponse], error) {
add := createTargetToCommand(req) add := createTargetToCommand(req.Msg)
instanceID := authz.GetInstance(ctx).InstanceID() instanceID := authz.GetInstance(ctx).InstanceID()
createdAt, err := s.command.AddTarget(ctx, add, instanceID) createdAt, err := s.command.AddTarget(ctx, add, instanceID)
if err != nil { if err != nil {
@@ -24,16 +25,16 @@ func (s *Server) CreateTarget(ctx context.Context, req *action.CreateTargetReque
if !createdAt.IsZero() { if !createdAt.IsZero() {
creationDate = timestamppb.New(createdAt) creationDate = timestamppb.New(createdAt)
} }
return &action.CreateTargetResponse{ return connect.NewResponse(&action.CreateTargetResponse{
Id: add.AggregateID, Id: add.AggregateID,
CreationDate: creationDate, CreationDate: creationDate,
SigningKey: add.SigningKey, SigningKey: add.SigningKey,
}, nil }), nil
} }
func (s *Server) UpdateTarget(ctx context.Context, req *action.UpdateTargetRequest) (*action.UpdateTargetResponse, error) { func (s *Server) UpdateTarget(ctx context.Context, req *connect.Request[action.UpdateTargetRequest]) (*connect.Response[action.UpdateTargetResponse], error) {
instanceID := authz.GetInstance(ctx).InstanceID() instanceID := authz.GetInstance(ctx).InstanceID()
update := updateTargetToCommand(req) update := updateTargetToCommand(req.Msg)
changedAt, err := s.command.ChangeTarget(ctx, update, instanceID) changedAt, err := s.command.ChangeTarget(ctx, update, instanceID)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -42,15 +43,15 @@ func (s *Server) UpdateTarget(ctx context.Context, req *action.UpdateTargetReque
if !changedAt.IsZero() { if !changedAt.IsZero() {
changeDate = timestamppb.New(changedAt) changeDate = timestamppb.New(changedAt)
} }
return &action.UpdateTargetResponse{ return connect.NewResponse(&action.UpdateTargetResponse{
ChangeDate: changeDate, ChangeDate: changeDate,
SigningKey: update.SigningKey, SigningKey: update.SigningKey,
}, nil }), nil
} }
func (s *Server) DeleteTarget(ctx context.Context, req *action.DeleteTargetRequest) (*action.DeleteTargetResponse, error) { func (s *Server) DeleteTarget(ctx context.Context, req *connect.Request[action.DeleteTargetRequest]) (*connect.Response[action.DeleteTargetResponse], error) {
instanceID := authz.GetInstance(ctx).InstanceID() instanceID := authz.GetInstance(ctx).InstanceID()
deletedAt, err := s.command.DeleteTarget(ctx, req.GetId(), instanceID) deletedAt, err := s.command.DeleteTarget(ctx, req.Msg.GetId(), instanceID)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -58,9 +59,9 @@ func (s *Server) DeleteTarget(ctx context.Context, req *action.DeleteTargetReque
if !deletedAt.IsZero() { if !deletedAt.IsZero() {
deletionDate = timestamppb.New(deletedAt) deletionDate = timestamppb.New(deletedAt)
} }
return &action.DeleteTargetResponse{ return connect.NewResponse(&action.DeleteTargetResponse{
DeletionDate: deletionDate, DeletionDate: deletionDate,
}, nil }), nil
} }
func createTargetToCommand(req *action.CreateTargetRequest) *command.AddTarget { func createTargetToCommand(req *action.CreateTargetRequest) *command.AddTarget {

View File

@@ -5,6 +5,7 @@ import (
"strings" "strings"
"time" "time"
"connectrpc.com/connect"
"google.golang.org/protobuf/types/known/timestamppb" "google.golang.org/protobuf/types/known/timestamppb"
"github.com/zitadel/zitadel/internal/api/grpc/app/v2beta/convert" "github.com/zitadel/zitadel/internal/api/grpc/app/v2beta/convert"
@@ -13,15 +14,15 @@ import (
app "github.com/zitadel/zitadel/pkg/grpc/app/v2beta" app "github.com/zitadel/zitadel/pkg/grpc/app/v2beta"
) )
func (s *Server) CreateApplication(ctx context.Context, req *app.CreateApplicationRequest) (*app.CreateApplicationResponse, error) { func (s *Server) CreateApplication(ctx context.Context, req *connect.Request[app.CreateApplicationRequest]) (*connect.Response[app.CreateApplicationResponse], error) {
switch t := req.GetCreationRequestType().(type) { switch t := req.Msg.GetCreationRequestType().(type) {
case *app.CreateApplicationRequest_ApiRequest: case *app.CreateApplicationRequest_ApiRequest:
apiApp, err := s.command.AddAPIApplication(ctx, convert.CreateAPIApplicationRequestToDomain(req.GetName(), req.GetProjectId(), req.GetId(), t.ApiRequest), "") apiApp, err := s.command.AddAPIApplication(ctx, convert.CreateAPIApplicationRequestToDomain(req.Msg.GetName(), req.Msg.GetProjectId(), req.Msg.GetId(), t.ApiRequest), "")
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &app.CreateApplicationResponse{ return connect.NewResponse(&app.CreateApplicationResponse{
AppId: apiApp.AppID, AppId: apiApp.AppID,
CreationDate: timestamppb.New(apiApp.ChangeDate), CreationDate: timestamppb.New(apiApp.ChangeDate),
CreationResponseType: &app.CreateApplicationResponse_ApiResponse{ CreationResponseType: &app.CreateApplicationResponse_ApiResponse{
@@ -30,10 +31,10 @@ func (s *Server) CreateApplication(ctx context.Context, req *app.CreateApplicati
ClientSecret: apiApp.ClientSecretString, ClientSecret: apiApp.ClientSecretString,
}, },
}, },
}, nil }), nil
case *app.CreateApplicationRequest_OidcRequest: case *app.CreateApplicationRequest_OidcRequest:
oidcAppRequest, err := convert.CreateOIDCAppRequestToDomain(req.GetName(), req.GetProjectId(), req.GetOidcRequest()) oidcAppRequest, err := convert.CreateOIDCAppRequestToDomain(req.Msg.GetName(), req.Msg.GetProjectId(), req.Msg.GetOidcRequest())
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -43,7 +44,7 @@ func (s *Server) CreateApplication(ctx context.Context, req *app.CreateApplicati
return nil, err return nil, err
} }
return &app.CreateApplicationResponse{ return connect.NewResponse(&app.CreateApplicationResponse{
AppId: oidcApp.AppID, AppId: oidcApp.AppID,
CreationDate: timestamppb.New(oidcApp.ChangeDate), CreationDate: timestamppb.New(oidcApp.ChangeDate),
CreationResponseType: &app.CreateApplicationResponse_OidcResponse{ CreationResponseType: &app.CreateApplicationResponse_OidcResponse{
@@ -54,10 +55,10 @@ func (s *Server) CreateApplication(ctx context.Context, req *app.CreateApplicati
ComplianceProblems: convert.ComplianceProblemsToLocalizedMessages(oidcApp.Compliance.Problems), ComplianceProblems: convert.ComplianceProblemsToLocalizedMessages(oidcApp.Compliance.Problems),
}, },
}, },
}, nil }), nil
case *app.CreateApplicationRequest_SamlRequest: case *app.CreateApplicationRequest_SamlRequest:
samlAppRequest, err := convert.CreateSAMLAppRequestToDomain(req.GetName(), req.GetProjectId(), req.GetSamlRequest()) samlAppRequest, err := convert.CreateSAMLAppRequestToDomain(req.Msg.GetName(), req.Msg.GetProjectId(), req.Msg.GetSamlRequest())
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -67,27 +68,27 @@ func (s *Server) CreateApplication(ctx context.Context, req *app.CreateApplicati
return nil, err return nil, err
} }
return &app.CreateApplicationResponse{ return connect.NewResponse(&app.CreateApplicationResponse{
AppId: samlApp.AppID, AppId: samlApp.AppID,
CreationDate: timestamppb.New(samlApp.ChangeDate), CreationDate: timestamppb.New(samlApp.ChangeDate),
CreationResponseType: &app.CreateApplicationResponse_SamlResponse{ CreationResponseType: &app.CreateApplicationResponse_SamlResponse{
SamlResponse: &app.CreateSAMLApplicationResponse{}, SamlResponse: &app.CreateSAMLApplicationResponse{},
}, },
}, nil }), nil
default: default:
return nil, zerrors.ThrowInvalidArgument(nil, "APP-0iiN46", "unknown app type") return nil, zerrors.ThrowInvalidArgument(nil, "APP-0iiN46", "unknown app type")
} }
} }
func (s *Server) UpdateApplication(ctx context.Context, req *app.UpdateApplicationRequest) (*app.UpdateApplicationResponse, error) { func (s *Server) UpdateApplication(ctx context.Context, req *connect.Request[app.UpdateApplicationRequest]) (*connect.Response[app.UpdateApplicationResponse], error) {
var changedTime time.Time var changedTime time.Time
if name := strings.TrimSpace(req.GetName()); name != "" { if name := strings.TrimSpace(req.Msg.GetName()); name != "" {
updatedDetails, err := s.command.UpdateApplicationName( updatedDetails, err := s.command.UpdateApplicationName(
ctx, ctx,
req.GetProjectId(), req.Msg.GetProjectId(),
&domain.ChangeApp{ &domain.ChangeApp{
AppID: req.GetId(), AppID: req.Msg.GetId(),
AppName: name, AppName: name,
}, },
"", "",
@@ -99,9 +100,9 @@ func (s *Server) UpdateApplication(ctx context.Context, req *app.UpdateApplicati
changedTime = updatedDetails.EventDate changedTime = updatedDetails.EventDate
} }
switch t := req.GetUpdateRequestType().(type) { switch t := req.Msg.GetUpdateRequestType().(type) {
case *app.UpdateApplicationRequest_ApiConfigurationRequest: case *app.UpdateApplicationRequest_ApiConfigurationRequest:
updatedAPIApp, err := s.command.UpdateAPIApplication(ctx, convert.UpdateAPIApplicationConfigurationRequestToDomain(req.GetId(), req.GetProjectId(), t.ApiConfigurationRequest), "") updatedAPIApp, err := s.command.UpdateAPIApplication(ctx, convert.UpdateAPIApplicationConfigurationRequestToDomain(req.Msg.GetId(), req.Msg.GetProjectId(), t.ApiConfigurationRequest), "")
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -109,7 +110,7 @@ func (s *Server) UpdateApplication(ctx context.Context, req *app.UpdateApplicati
changedTime = updatedAPIApp.ChangeDate changedTime = updatedAPIApp.ChangeDate
case *app.UpdateApplicationRequest_OidcConfigurationRequest: case *app.UpdateApplicationRequest_OidcConfigurationRequest:
oidcApp, err := convert.UpdateOIDCAppConfigRequestToDomain(req.GetId(), req.GetProjectId(), t.OidcConfigurationRequest) oidcApp, err := convert.UpdateOIDCAppConfigRequestToDomain(req.Msg.GetId(), req.Msg.GetProjectId(), t.OidcConfigurationRequest)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -122,7 +123,7 @@ func (s *Server) UpdateApplication(ctx context.Context, req *app.UpdateApplicati
changedTime = updatedOIDCApp.ChangeDate changedTime = updatedOIDCApp.ChangeDate
case *app.UpdateApplicationRequest_SamlConfigurationRequest: case *app.UpdateApplicationRequest_SamlConfigurationRequest:
samlApp, err := convert.UpdateSAMLAppConfigRequestToDomain(req.GetId(), req.GetProjectId(), t.SamlConfigurationRequest) samlApp, err := convert.UpdateSAMLAppConfigRequestToDomain(req.Msg.GetId(), req.Msg.GetProjectId(), t.SamlConfigurationRequest)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -135,53 +136,53 @@ func (s *Server) UpdateApplication(ctx context.Context, req *app.UpdateApplicati
changedTime = updatedSAMLApp.ChangeDate changedTime = updatedSAMLApp.ChangeDate
} }
return &app.UpdateApplicationResponse{ return connect.NewResponse(&app.UpdateApplicationResponse{
ChangeDate: timestamppb.New(changedTime), ChangeDate: timestamppb.New(changedTime),
}, nil }), nil
} }
func (s *Server) DeleteApplication(ctx context.Context, req *app.DeleteApplicationRequest) (*app.DeleteApplicationResponse, error) { func (s *Server) DeleteApplication(ctx context.Context, req *connect.Request[app.DeleteApplicationRequest]) (*connect.Response[app.DeleteApplicationResponse], error) {
details, err := s.command.RemoveApplication(ctx, req.GetProjectId(), req.GetId(), "") details, err := s.command.RemoveApplication(ctx, req.Msg.GetProjectId(), req.Msg.GetId(), "")
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &app.DeleteApplicationResponse{ return connect.NewResponse(&app.DeleteApplicationResponse{
DeletionDate: timestamppb.New(details.EventDate), DeletionDate: timestamppb.New(details.EventDate),
}, nil }), nil
} }
func (s *Server) DeactivateApplication(ctx context.Context, req *app.DeactivateApplicationRequest) (*app.DeactivateApplicationResponse, error) { func (s *Server) DeactivateApplication(ctx context.Context, req *connect.Request[app.DeactivateApplicationRequest]) (*connect.Response[app.DeactivateApplicationResponse], error) {
details, err := s.command.DeactivateApplication(ctx, req.GetProjectId(), req.GetId(), "") details, err := s.command.DeactivateApplication(ctx, req.Msg.GetProjectId(), req.Msg.GetId(), "")
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &app.DeactivateApplicationResponse{ return connect.NewResponse(&app.DeactivateApplicationResponse{
DeactivationDate: timestamppb.New(details.EventDate), DeactivationDate: timestamppb.New(details.EventDate),
}, nil }), nil
} }
func (s *Server) ReactivateApplication(ctx context.Context, req *app.ReactivateApplicationRequest) (*app.ReactivateApplicationResponse, error) { func (s *Server) ReactivateApplication(ctx context.Context, req *connect.Request[app.ReactivateApplicationRequest]) (*connect.Response[app.ReactivateApplicationResponse], error) {
details, err := s.command.ReactivateApplication(ctx, req.GetProjectId(), req.GetId(), "") details, err := s.command.ReactivateApplication(ctx, req.Msg.GetProjectId(), req.Msg.GetId(), "")
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &app.ReactivateApplicationResponse{ return connect.NewResponse(&app.ReactivateApplicationResponse{
ReactivationDate: timestamppb.New(details.EventDate), ReactivationDate: timestamppb.New(details.EventDate),
}, nil }), nil
} }
func (s *Server) RegenerateClientSecret(ctx context.Context, req *app.RegenerateClientSecretRequest) (*app.RegenerateClientSecretResponse, error) { func (s *Server) RegenerateClientSecret(ctx context.Context, req *connect.Request[app.RegenerateClientSecretRequest]) (*connect.Response[app.RegenerateClientSecretResponse], error) {
var secret string var secret string
var changeDate time.Time var changeDate time.Time
switch req.GetAppType().(type) { switch req.Msg.GetAppType().(type) {
case *app.RegenerateClientSecretRequest_IsApi: case *app.RegenerateClientSecretRequest_IsApi:
config, err := s.command.ChangeAPIApplicationSecret(ctx, req.GetProjectId(), req.GetApplicationId(), "") config, err := s.command.ChangeAPIApplicationSecret(ctx, req.Msg.GetProjectId(), req.Msg.GetApplicationId(), "")
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -189,7 +190,7 @@ func (s *Server) RegenerateClientSecret(ctx context.Context, req *app.Regenerate
changeDate = config.ChangeDate changeDate = config.ChangeDate
case *app.RegenerateClientSecretRequest_IsOidc: case *app.RegenerateClientSecretRequest_IsOidc:
config, err := s.command.ChangeOIDCApplicationSecret(ctx, req.GetProjectId(), req.GetApplicationId(), "") config, err := s.command.ChangeOIDCApplicationSecret(ctx, req.Msg.GetProjectId(), req.Msg.GetApplicationId(), "")
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -201,8 +202,8 @@ func (s *Server) RegenerateClientSecret(ctx context.Context, req *app.Regenerate
return nil, zerrors.ThrowInvalidArgument(nil, "APP-aLWIzw", "unknown app type") return nil, zerrors.ThrowInvalidArgument(nil, "APP-aLWIzw", "unknown app type")
} }
return &app.RegenerateClientSecretResponse{ return connect.NewResponse(&app.RegenerateClientSecretResponse{
ClientSecret: secret, ClientSecret: secret,
CreationDate: timestamppb.New(changeDate), CreationDate: timestamppb.New(changeDate),
}, nil }), nil
} }

View File

@@ -4,14 +4,15 @@ import (
"context" "context"
"strings" "strings"
"connectrpc.com/connect"
"google.golang.org/protobuf/types/known/timestamppb" "google.golang.org/protobuf/types/known/timestamppb"
"github.com/zitadel/zitadel/internal/api/grpc/app/v2beta/convert" "github.com/zitadel/zitadel/internal/api/grpc/app/v2beta/convert"
app "github.com/zitadel/zitadel/pkg/grpc/app/v2beta" app "github.com/zitadel/zitadel/pkg/grpc/app/v2beta"
) )
func (s *Server) CreateApplicationKey(ctx context.Context, req *app.CreateApplicationKeyRequest) (*app.CreateApplicationKeyResponse, error) { func (s *Server) CreateApplicationKey(ctx context.Context, req *connect.Request[app.CreateApplicationKeyRequest]) (*connect.Response[app.CreateApplicationKeyResponse], error) {
domainReq := convert.CreateAPIClientKeyRequestToDomain(req) domainReq := convert.CreateAPIClientKeyRequestToDomain(req.Msg)
appKey, err := s.command.AddApplicationKey(ctx, domainReq, "") appKey, err := s.command.AddApplicationKey(ctx, domainReq, "")
if err != nil { if err != nil {
@@ -23,25 +24,25 @@ func (s *Server) CreateApplicationKey(ctx context.Context, req *app.CreateApplic
return nil, err return nil, err
} }
return &app.CreateApplicationKeyResponse{ return connect.NewResponse(&app.CreateApplicationKeyResponse{
Id: appKey.KeyID, Id: appKey.KeyID,
CreationDate: timestamppb.New(appKey.ChangeDate), CreationDate: timestamppb.New(appKey.ChangeDate),
KeyDetails: keyDetails, KeyDetails: keyDetails,
}, nil }), nil
} }
func (s *Server) DeleteApplicationKey(ctx context.Context, req *app.DeleteApplicationKeyRequest) (*app.DeleteApplicationKeyResponse, error) { func (s *Server) DeleteApplicationKey(ctx context.Context, req *connect.Request[app.DeleteApplicationKeyRequest]) (*connect.Response[app.DeleteApplicationKeyResponse], error) {
deletionDetails, err := s.command.RemoveApplicationKey(ctx, deletionDetails, err := s.command.RemoveApplicationKey(ctx,
strings.TrimSpace(req.GetProjectId()), strings.TrimSpace(req.Msg.GetProjectId()),
strings.TrimSpace(req.GetApplicationId()), strings.TrimSpace(req.Msg.GetApplicationId()),
strings.TrimSpace(req.GetId()), strings.TrimSpace(req.Msg.GetId()),
strings.TrimSpace(req.GetOrganizationId()), strings.TrimSpace(req.Msg.GetOrganizationId()),
) )
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &app.DeleteApplicationKeyResponse{ return connect.NewResponse(&app.DeleteApplicationKeyResponse{
DeletionDate: timestamppb.New(deletionDetails.EventDate), DeletionDate: timestamppb.New(deletionDetails.EventDate),
}, nil }), nil
} }

View File

@@ -4,6 +4,7 @@ import (
"context" "context"
"strings" "strings"
"connectrpc.com/connect"
"google.golang.org/protobuf/types/known/timestamppb" "google.golang.org/protobuf/types/known/timestamppb"
"github.com/zitadel/zitadel/internal/api/grpc/app/v2beta/convert" "github.com/zitadel/zitadel/internal/api/grpc/app/v2beta/convert"
@@ -12,19 +13,19 @@ import (
app "github.com/zitadel/zitadel/pkg/grpc/app/v2beta" app "github.com/zitadel/zitadel/pkg/grpc/app/v2beta"
) )
func (s *Server) GetApplication(ctx context.Context, req *app.GetApplicationRequest) (*app.GetApplicationResponse, error) { func (s *Server) GetApplication(ctx context.Context, req *connect.Request[app.GetApplicationRequest]) (*connect.Response[app.GetApplicationResponse], error) {
res, err := s.query.AppByIDWithPermission(ctx, req.GetId(), false, s.checkPermission) res, err := s.query.AppByIDWithPermission(ctx, req.Msg.GetId(), false, s.checkPermission)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &app.GetApplicationResponse{ return connect.NewResponse(&app.GetApplicationResponse{
App: convert.AppToPb(res), App: convert.AppToPb(res),
}, nil }), nil
} }
func (s *Server) ListApplications(ctx context.Context, req *app.ListApplicationsRequest) (*app.ListApplicationsResponse, error) { func (s *Server) ListApplications(ctx context.Context, req *connect.Request[app.ListApplicationsRequest]) (*connect.Response[app.ListApplicationsResponse], error) {
queries, err := convert.ListApplicationsRequestToModel(s.systemDefaults, req) queries, err := convert.ListApplicationsRequestToModel(s.systemDefaults, req.Msg)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -34,32 +35,32 @@ func (s *Server) ListApplications(ctx context.Context, req *app.ListApplications
return nil, err return nil, err
} }
return &app.ListApplicationsResponse{ return connect.NewResponse(&app.ListApplicationsResponse{
Applications: convert.AppsToPb(res.Apps), Applications: convert.AppsToPb(res.Apps),
Pagination: filter.QueryToPaginationPb(queries.SearchRequest, res.SearchResponse), Pagination: filter.QueryToPaginationPb(queries.SearchRequest, res.SearchResponse),
}, nil }), nil
} }
func (s *Server) GetApplicationKey(ctx context.Context, req *app.GetApplicationKeyRequest) (*app.GetApplicationKeyResponse, error) { func (s *Server) GetApplicationKey(ctx context.Context, req *connect.Request[app.GetApplicationKeyRequest]) (*connect.Response[app.GetApplicationKeyResponse], error) {
queries, err := convert.GetApplicationKeyQueriesRequestToDomain(req.GetOrganizationId(), req.GetProjectId(), req.GetApplicationId()) queries, err := convert.GetApplicationKeyQueriesRequestToDomain(req.Msg.GetOrganizationId(), req.Msg.GetProjectId(), req.Msg.GetApplicationId())
if err != nil { if err != nil {
return nil, err return nil, err
} }
key, err := s.query.GetAuthNKeyByIDWithPermission(ctx, true, strings.TrimSpace(req.GetId()), s.checkPermission, queries...) key, err := s.query.GetAuthNKeyByIDWithPermission(ctx, true, strings.TrimSpace(req.Msg.GetId()), s.checkPermission, queries...)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &app.GetApplicationKeyResponse{ return connect.NewResponse(&app.GetApplicationKeyResponse{
Id: key.ID, Id: key.ID,
CreationDate: timestamppb.New(key.CreationDate), CreationDate: timestamppb.New(key.CreationDate),
ExpirationDate: timestamppb.New(key.Expiration), ExpirationDate: timestamppb.New(key.Expiration),
}, nil }), nil
} }
func (s *Server) ListApplicationKeys(ctx context.Context, req *app.ListApplicationKeysRequest) (*app.ListApplicationKeysResponse, error) { func (s *Server) ListApplicationKeys(ctx context.Context, req *connect.Request[app.ListApplicationKeysRequest]) (*connect.Response[app.ListApplicationKeysResponse], error) {
queries, err := convert.ListApplicationKeysRequestToDomain(s.systemDefaults, req) queries, err := convert.ListApplicationKeysRequestToDomain(s.systemDefaults, req.Msg)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -69,8 +70,8 @@ func (s *Server) ListApplicationKeys(ctx context.Context, req *app.ListApplicati
return nil, err return nil, err
} }
return &app.ListApplicationKeysResponse{ return connect.NewResponse(&app.ListApplicationKeysResponse{
Keys: convert.ApplicationKeysToPb(res.AuthNKeys), Keys: convert.ApplicationKeysToPb(res.AuthNKeys),
Pagination: filter.QueryToPaginationPb(queries.SearchRequest, res.SearchResponse), Pagination: filter.QueryToPaginationPb(queries.SearchRequest, res.SearchResponse),
}, nil }), nil
} }

View File

@@ -1,21 +1,23 @@
package app package app
import ( import (
"google.golang.org/grpc" "net/http"
"connectrpc.com/connect"
"google.golang.org/protobuf/reflect/protoreflect"
"github.com/zitadel/zitadel/internal/api/authz" "github.com/zitadel/zitadel/internal/api/authz"
"github.com/zitadel/zitadel/internal/api/grpc/server"
"github.com/zitadel/zitadel/internal/command" "github.com/zitadel/zitadel/internal/command"
"github.com/zitadel/zitadel/internal/config/systemdefaults" "github.com/zitadel/zitadel/internal/config/systemdefaults"
"github.com/zitadel/zitadel/internal/domain" "github.com/zitadel/zitadel/internal/domain"
"github.com/zitadel/zitadel/internal/query" "github.com/zitadel/zitadel/internal/query"
app "github.com/zitadel/zitadel/pkg/grpc/app/v2beta" app "github.com/zitadel/zitadel/pkg/grpc/app/v2beta"
"github.com/zitadel/zitadel/pkg/grpc/app/v2beta/appconnect"
) )
var _ app.AppServiceServer = (*Server)(nil) var _ appconnect.AppServiceHandler = (*Server)(nil)
type Server struct { type Server struct {
app.UnimplementedAppServiceServer
command *command.Commands command *command.Commands
query *query.Queries query *query.Queries
systemDefaults systemdefaults.SystemDefaults systemDefaults systemdefaults.SystemDefaults
@@ -36,8 +38,12 @@ func CreateServer(
} }
} }
func (s *Server) RegisterServer(grpcServer *grpc.Server) { func (s *Server) RegisterConnectServer(interceptors ...connect.Interceptor) (string, http.Handler) {
app.RegisterAppServiceServer(grpcServer, s) return appconnect.NewAppServiceHandler(s, connect.WithInterceptors(interceptors...))
}
func (s *Server) FileDescriptor() protoreflect.FileDescriptor {
return app.File_zitadel_app_v2beta_app_service_proto
} }
func (s *Server) AppName() string { func (s *Server) AppName() string {
@@ -51,7 +57,3 @@ func (s *Server) MethodPrefix() string {
func (s *Server) AuthMethods() authz.MethodMapping { func (s *Server) AuthMethods() authz.MethodMapping {
return app.AppService_AuthMethods return app.AppService_AuthMethods
} }
func (s *Server) RegisterGateway() server.RegisterGatewayFunc {
return app.RegisterAppServiceHandler
}

View File

@@ -3,6 +3,7 @@ package feature
import ( import (
"context" "context"
"connectrpc.com/connect"
"google.golang.org/grpc/codes" "google.golang.org/grpc/codes"
"google.golang.org/grpc/status" "google.golang.org/grpc/status"
@@ -10,8 +11,8 @@ import (
"github.com/zitadel/zitadel/pkg/grpc/feature/v2" "github.com/zitadel/zitadel/pkg/grpc/feature/v2"
) )
func (s *Server) SetSystemFeatures(ctx context.Context, req *feature.SetSystemFeaturesRequest) (_ *feature.SetSystemFeaturesResponse, err error) { func (s *Server) SetSystemFeatures(ctx context.Context, req *connect.Request[feature.SetSystemFeaturesRequest]) (_ *connect.Response[feature.SetSystemFeaturesResponse], err error) {
features, err := systemFeaturesToCommand(req) features, err := systemFeaturesToCommand(req.Msg)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -19,31 +20,31 @@ func (s *Server) SetSystemFeatures(ctx context.Context, req *feature.SetSystemFe
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &feature.SetSystemFeaturesResponse{ return connect.NewResponse(&feature.SetSystemFeaturesResponse{
Details: object.DomainToDetailsPb(details), Details: object.DomainToDetailsPb(details),
}, nil }), nil
} }
func (s *Server) ResetSystemFeatures(ctx context.Context, req *feature.ResetSystemFeaturesRequest) (_ *feature.ResetSystemFeaturesResponse, err error) { func (s *Server) ResetSystemFeatures(ctx context.Context, req *connect.Request[feature.ResetSystemFeaturesRequest]) (_ *connect.Response[feature.ResetSystemFeaturesResponse], err error) {
details, err := s.command.ResetSystemFeatures(ctx) details, err := s.command.ResetSystemFeatures(ctx)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &feature.ResetSystemFeaturesResponse{ return connect.NewResponse(&feature.ResetSystemFeaturesResponse{
Details: object.DomainToDetailsPb(details), Details: object.DomainToDetailsPb(details),
}, nil }), nil
} }
func (s *Server) GetSystemFeatures(ctx context.Context, req *feature.GetSystemFeaturesRequest) (_ *feature.GetSystemFeaturesResponse, err error) { func (s *Server) GetSystemFeatures(ctx context.Context, req *connect.Request[feature.GetSystemFeaturesRequest]) (_ *connect.Response[feature.GetSystemFeaturesResponse], err error) {
f, err := s.query.GetSystemFeatures(ctx) f, err := s.query.GetSystemFeatures(ctx)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return systemFeaturesToPb(f), nil return connect.NewResponse(systemFeaturesToPb(f)), nil
} }
func (s *Server) SetInstanceFeatures(ctx context.Context, req *feature.SetInstanceFeaturesRequest) (_ *feature.SetInstanceFeaturesResponse, err error) { func (s *Server) SetInstanceFeatures(ctx context.Context, req *connect.Request[feature.SetInstanceFeaturesRequest]) (_ *connect.Response[feature.SetInstanceFeaturesResponse], err error) {
features, err := instanceFeaturesToCommand(req) features, err := instanceFeaturesToCommand(req.Msg)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -51,44 +52,44 @@ func (s *Server) SetInstanceFeatures(ctx context.Context, req *feature.SetInstan
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &feature.SetInstanceFeaturesResponse{ return connect.NewResponse(&feature.SetInstanceFeaturesResponse{
Details: object.DomainToDetailsPb(details), Details: object.DomainToDetailsPb(details),
}, nil }), nil
} }
func (s *Server) ResetInstanceFeatures(ctx context.Context, req *feature.ResetInstanceFeaturesRequest) (_ *feature.ResetInstanceFeaturesResponse, err error) { func (s *Server) ResetInstanceFeatures(ctx context.Context, req *connect.Request[feature.ResetInstanceFeaturesRequest]) (_ *connect.Response[feature.ResetInstanceFeaturesResponse], err error) {
details, err := s.command.ResetInstanceFeatures(ctx) details, err := s.command.ResetInstanceFeatures(ctx)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &feature.ResetInstanceFeaturesResponse{ return connect.NewResponse(&feature.ResetInstanceFeaturesResponse{
Details: object.DomainToDetailsPb(details), Details: object.DomainToDetailsPb(details),
}, nil }), nil
} }
func (s *Server) GetInstanceFeatures(ctx context.Context, req *feature.GetInstanceFeaturesRequest) (_ *feature.GetInstanceFeaturesResponse, err error) { func (s *Server) GetInstanceFeatures(ctx context.Context, req *connect.Request[feature.GetInstanceFeaturesRequest]) (_ *connect.Response[feature.GetInstanceFeaturesResponse], err error) {
f, err := s.query.GetInstanceFeatures(ctx, req.GetInheritance()) f, err := s.query.GetInstanceFeatures(ctx, req.Msg.GetInheritance())
if err != nil { if err != nil {
return nil, err return nil, err
} }
return instanceFeaturesToPb(f), nil return connect.NewResponse(instanceFeaturesToPb(f)), nil
} }
func (s *Server) SetOrganizationFeatures(ctx context.Context, req *feature.SetOrganizationFeaturesRequest) (_ *feature.SetOrganizationFeaturesResponse, err error) { func (s *Server) SetOrganizationFeatures(ctx context.Context, req *connect.Request[feature.SetOrganizationFeaturesRequest]) (_ *connect.Response[feature.SetOrganizationFeaturesResponse], err error) {
return nil, status.Errorf(codes.Unimplemented, "method SetOrganizationFeatures not implemented") return nil, status.Errorf(codes.Unimplemented, "method SetOrganizationFeatures not implemented")
} }
func (s *Server) ResetOrganizationFeatures(ctx context.Context, req *feature.ResetOrganizationFeaturesRequest) (_ *feature.ResetOrganizationFeaturesResponse, err error) { func (s *Server) ResetOrganizationFeatures(ctx context.Context, req *connect.Request[feature.ResetOrganizationFeaturesRequest]) (_ *connect.Response[feature.ResetOrganizationFeaturesResponse], err error) {
return nil, status.Errorf(codes.Unimplemented, "method ResetOrganizationFeatures not implemented") return nil, status.Errorf(codes.Unimplemented, "method ResetOrganizationFeatures not implemented")
} }
func (s *Server) GetOrganizationFeatures(ctx context.Context, req *feature.GetOrganizationFeaturesRequest) (_ *feature.GetOrganizationFeaturesResponse, err error) { func (s *Server) GetOrganizationFeatures(ctx context.Context, req *connect.Request[feature.GetOrganizationFeaturesRequest]) (_ *connect.Response[feature.GetOrganizationFeaturesResponse], err error) {
return nil, status.Errorf(codes.Unimplemented, "method GetOrganizationFeatures not implemented") return nil, status.Errorf(codes.Unimplemented, "method GetOrganizationFeatures not implemented")
} }
func (s *Server) SetUserFeatures(ctx context.Context, req *feature.SetUserFeatureRequest) (_ *feature.SetUserFeaturesResponse, err error) { func (s *Server) SetUserFeatures(ctx context.Context, req *connect.Request[feature.SetUserFeatureRequest]) (_ *connect.Response[feature.SetUserFeaturesResponse], err error) {
return nil, status.Errorf(codes.Unimplemented, "method SetUserFeatures not implemented") return nil, status.Errorf(codes.Unimplemented, "method SetUserFeatures not implemented")
} }
func (s *Server) ResetUserFeatures(ctx context.Context, req *feature.ResetUserFeaturesRequest) (_ *feature.ResetUserFeaturesResponse, err error) { func (s *Server) ResetUserFeatures(ctx context.Context, req *connect.Request[feature.ResetUserFeaturesRequest]) (_ *connect.Response[feature.ResetUserFeaturesResponse], err error) {
return nil, status.Errorf(codes.Unimplemented, "method ResetUserFeatures not implemented") return nil, status.Errorf(codes.Unimplemented, "method ResetUserFeatures not implemented")
} }
func (s *Server) GetUserFeatures(ctx context.Context, req *feature.GetUserFeaturesRequest) (_ *feature.GetUserFeaturesResponse, err error) { func (s *Server) GetUserFeatures(ctx context.Context, req *connect.Request[feature.GetUserFeaturesRequest]) (_ *connect.Response[feature.GetUserFeaturesResponse], err error) {
return nil, status.Errorf(codes.Unimplemented, "method GetUserFeatures not implemented") return nil, status.Errorf(codes.Unimplemented, "method GetUserFeatures not implemented")
} }

View File

@@ -1,17 +1,22 @@
package feature package feature
import ( import (
"google.golang.org/grpc" "net/http"
"connectrpc.com/connect"
"google.golang.org/protobuf/reflect/protoreflect"
"github.com/zitadel/zitadel/internal/api/authz" "github.com/zitadel/zitadel/internal/api/authz"
"github.com/zitadel/zitadel/internal/api/grpc/server" "github.com/zitadel/zitadel/internal/api/grpc/server"
"github.com/zitadel/zitadel/internal/command" "github.com/zitadel/zitadel/internal/command"
"github.com/zitadel/zitadel/internal/query" "github.com/zitadel/zitadel/internal/query"
"github.com/zitadel/zitadel/pkg/grpc/feature/v2" "github.com/zitadel/zitadel/pkg/grpc/feature/v2"
"github.com/zitadel/zitadel/pkg/grpc/feature/v2/featureconnect"
) )
var _ featureconnect.FeatureServiceHandler = (*Server)(nil)
type Server struct { type Server struct {
feature.UnimplementedFeatureServiceServer
command *command.Commands command *command.Commands
query *query.Queries query *query.Queries
} }
@@ -26,8 +31,12 @@ func CreateServer(
} }
} }
func (s *Server) RegisterServer(grpcServer *grpc.Server) { func (s *Server) RegisterConnectServer(interceptors ...connect.Interceptor) (string, http.Handler) {
feature.RegisterFeatureServiceServer(grpcServer, s) return featureconnect.NewFeatureServiceHandler(s, connect.WithInterceptors(interceptors...))
}
func (s *Server) FileDescriptor() protoreflect.FileDescriptor {
return feature.File_zitadel_feature_v2_feature_service_proto
} }
func (s *Server) AppName() string { func (s *Server) AppName() string {

View File

@@ -3,6 +3,7 @@ package feature
import ( import (
"context" "context"
"connectrpc.com/connect"
"google.golang.org/grpc/codes" "google.golang.org/grpc/codes"
"google.golang.org/grpc/status" "google.golang.org/grpc/status"
@@ -10,77 +11,77 @@ import (
feature "github.com/zitadel/zitadel/pkg/grpc/feature/v2beta" feature "github.com/zitadel/zitadel/pkg/grpc/feature/v2beta"
) )
func (s *Server) SetSystemFeatures(ctx context.Context, req *feature.SetSystemFeaturesRequest) (_ *feature.SetSystemFeaturesResponse, err error) { func (s *Server) SetSystemFeatures(ctx context.Context, req *connect.Request[feature.SetSystemFeaturesRequest]) (_ *connect.Response[feature.SetSystemFeaturesResponse], err error) {
details, err := s.command.SetSystemFeatures(ctx, systemFeaturesToCommand(req)) details, err := s.command.SetSystemFeatures(ctx, systemFeaturesToCommand(req.Msg))
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &feature.SetSystemFeaturesResponse{ return connect.NewResponse(&feature.SetSystemFeaturesResponse{
Details: object.DomainToDetailsPb(details), Details: object.DomainToDetailsPb(details),
}, nil }), nil
} }
func (s *Server) ResetSystemFeatures(ctx context.Context, req *feature.ResetSystemFeaturesRequest) (_ *feature.ResetSystemFeaturesResponse, err error) { func (s *Server) ResetSystemFeatures(ctx context.Context, req *connect.Request[feature.ResetSystemFeaturesRequest]) (_ *connect.Response[feature.ResetSystemFeaturesResponse], err error) {
details, err := s.command.ResetSystemFeatures(ctx) details, err := s.command.ResetSystemFeatures(ctx)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &feature.ResetSystemFeaturesResponse{ return connect.NewResponse(&feature.ResetSystemFeaturesResponse{
Details: object.DomainToDetailsPb(details), Details: object.DomainToDetailsPb(details),
}, nil }), nil
} }
func (s *Server) GetSystemFeatures(ctx context.Context, req *feature.GetSystemFeaturesRequest) (_ *feature.GetSystemFeaturesResponse, err error) { func (s *Server) GetSystemFeatures(ctx context.Context, req *connect.Request[feature.GetSystemFeaturesRequest]) (_ *connect.Response[feature.GetSystemFeaturesResponse], err error) {
f, err := s.query.GetSystemFeatures(ctx) f, err := s.query.GetSystemFeatures(ctx)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return systemFeaturesToPb(f), nil return connect.NewResponse(systemFeaturesToPb(f)), nil
} }
func (s *Server) SetInstanceFeatures(ctx context.Context, req *feature.SetInstanceFeaturesRequest) (_ *feature.SetInstanceFeaturesResponse, err error) { func (s *Server) SetInstanceFeatures(ctx context.Context, req *connect.Request[feature.SetInstanceFeaturesRequest]) (_ *connect.Response[feature.SetInstanceFeaturesResponse], err error) {
details, err := s.command.SetInstanceFeatures(ctx, instanceFeaturesToCommand(req)) details, err := s.command.SetInstanceFeatures(ctx, instanceFeaturesToCommand(req.Msg))
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &feature.SetInstanceFeaturesResponse{ return connect.NewResponse(&feature.SetInstanceFeaturesResponse{
Details: object.DomainToDetailsPb(details), Details: object.DomainToDetailsPb(details),
}, nil }), nil
} }
func (s *Server) ResetInstanceFeatures(ctx context.Context, req *feature.ResetInstanceFeaturesRequest) (_ *feature.ResetInstanceFeaturesResponse, err error) { func (s *Server) ResetInstanceFeatures(ctx context.Context, req *connect.Request[feature.ResetInstanceFeaturesRequest]) (_ *connect.Response[feature.ResetInstanceFeaturesResponse], err error) {
details, err := s.command.ResetInstanceFeatures(ctx) details, err := s.command.ResetInstanceFeatures(ctx)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &feature.ResetInstanceFeaturesResponse{ return connect.NewResponse(&feature.ResetInstanceFeaturesResponse{
Details: object.DomainToDetailsPb(details), Details: object.DomainToDetailsPb(details),
}, nil }), nil
} }
func (s *Server) GetInstanceFeatures(ctx context.Context, req *feature.GetInstanceFeaturesRequest) (_ *feature.GetInstanceFeaturesResponse, err error) { func (s *Server) GetInstanceFeatures(ctx context.Context, req *connect.Request[feature.GetInstanceFeaturesRequest]) (_ *connect.Response[feature.GetInstanceFeaturesResponse], err error) {
f, err := s.query.GetInstanceFeatures(ctx, req.GetInheritance()) f, err := s.query.GetInstanceFeatures(ctx, req.Msg.GetInheritance())
if err != nil { if err != nil {
return nil, err return nil, err
} }
return instanceFeaturesToPb(f), nil return connect.NewResponse(instanceFeaturesToPb(f)), nil
} }
func (s *Server) SetOrganizationFeatures(ctx context.Context, req *feature.SetOrganizationFeaturesRequest) (_ *feature.SetOrganizationFeaturesResponse, err error) { func (s *Server) SetOrganizationFeatures(ctx context.Context, req *connect.Request[feature.SetOrganizationFeaturesRequest]) (_ *connect.Response[feature.SetOrganizationFeaturesResponse], err error) {
return nil, status.Errorf(codes.Unimplemented, "method SetOrganizationFeatures not implemented") return nil, status.Errorf(codes.Unimplemented, "method SetOrganizationFeatures not implemented")
} }
func (s *Server) ResetOrganizationFeatures(ctx context.Context, req *feature.ResetOrganizationFeaturesRequest) (_ *feature.ResetOrganizationFeaturesResponse, err error) { func (s *Server) ResetOrganizationFeatures(ctx context.Context, req *connect.Request[feature.ResetOrganizationFeaturesRequest]) (_ *connect.Response[feature.ResetOrganizationFeaturesResponse], err error) {
return nil, status.Errorf(codes.Unimplemented, "method ResetOrganizationFeatures not implemented") return nil, status.Errorf(codes.Unimplemented, "method ResetOrganizationFeatures not implemented")
} }
func (s *Server) GetOrganizationFeatures(ctx context.Context, req *feature.GetOrganizationFeaturesRequest) (_ *feature.GetOrganizationFeaturesResponse, err error) { func (s *Server) GetOrganizationFeatures(ctx context.Context, req *connect.Request[feature.GetOrganizationFeaturesRequest]) (_ *connect.Response[feature.GetOrganizationFeaturesResponse], err error) {
return nil, status.Errorf(codes.Unimplemented, "method GetOrganizationFeatures not implemented") return nil, status.Errorf(codes.Unimplemented, "method GetOrganizationFeatures not implemented")
} }
func (s *Server) SetUserFeatures(ctx context.Context, req *feature.SetUserFeatureRequest) (_ *feature.SetUserFeaturesResponse, err error) { func (s *Server) SetUserFeatures(ctx context.Context, req *connect.Request[feature.SetUserFeatureRequest]) (_ *connect.Response[feature.SetUserFeaturesResponse], err error) {
return nil, status.Errorf(codes.Unimplemented, "method SetUserFeatures not implemented") return nil, status.Errorf(codes.Unimplemented, "method SetUserFeatures not implemented")
} }
func (s *Server) ResetUserFeatures(ctx context.Context, req *feature.ResetUserFeaturesRequest) (_ *feature.ResetUserFeaturesResponse, err error) { func (s *Server) ResetUserFeatures(ctx context.Context, req *connect.Request[feature.ResetUserFeaturesRequest]) (_ *connect.Response[feature.ResetUserFeaturesResponse], err error) {
return nil, status.Errorf(codes.Unimplemented, "method ResetUserFeatures not implemented") return nil, status.Errorf(codes.Unimplemented, "method ResetUserFeatures not implemented")
} }
func (s *Server) GetUserFeatures(ctx context.Context, req *feature.GetUserFeaturesRequest) (_ *feature.GetUserFeaturesResponse, err error) { func (s *Server) GetUserFeatures(ctx context.Context, req *connect.Request[feature.GetUserFeaturesRequest]) (_ *connect.Response[feature.GetUserFeaturesResponse], err error) {
return nil, status.Errorf(codes.Unimplemented, "method GetUserFeatures not implemented") return nil, status.Errorf(codes.Unimplemented, "method GetUserFeatures not implemented")
} }

View File

@@ -1,17 +1,22 @@
package feature package feature
import ( import (
"google.golang.org/grpc" "net/http"
"connectrpc.com/connect"
"google.golang.org/protobuf/reflect/protoreflect"
"github.com/zitadel/zitadel/internal/api/authz" "github.com/zitadel/zitadel/internal/api/authz"
"github.com/zitadel/zitadel/internal/api/grpc/server" "github.com/zitadel/zitadel/internal/api/grpc/server"
"github.com/zitadel/zitadel/internal/command" "github.com/zitadel/zitadel/internal/command"
"github.com/zitadel/zitadel/internal/query" "github.com/zitadel/zitadel/internal/query"
feature "github.com/zitadel/zitadel/pkg/grpc/feature/v2beta" feature "github.com/zitadel/zitadel/pkg/grpc/feature/v2beta"
"github.com/zitadel/zitadel/pkg/grpc/feature/v2beta/featureconnect"
) )
var _ featureconnect.FeatureServiceHandler = (*Server)(nil)
type Server struct { type Server struct {
feature.UnimplementedFeatureServiceServer
command *command.Commands command *command.Commands
query *query.Queries query *query.Queries
} }
@@ -26,8 +31,12 @@ func CreateServer(
} }
} }
func (s *Server) RegisterServer(grpcServer *grpc.Server) { func (s *Server) RegisterConnectServer(interceptors ...connect.Interceptor) (string, http.Handler) {
feature.RegisterFeatureServiceServer(grpcServer, s) return featureconnect.NewFeatureServiceHandler(s, connect.WithInterceptors(interceptors...))
}
func (s *Server) FileDescriptor() protoreflect.FileDescriptor {
return feature.File_zitadel_feature_v2beta_feature_service_proto
} }
func (s *Server) AppName() string { func (s *Server) AppName() string {

View File

@@ -3,10 +3,12 @@ package gerrors
import ( import (
"errors" "errors"
"connectrpc.com/connect"
"github.com/jackc/pgx/v5/pgconn" "github.com/jackc/pgx/v5/pgconn"
"github.com/zitadel/logging" "github.com/zitadel/logging"
"google.golang.org/grpc/codes" "google.golang.org/grpc/codes"
"google.golang.org/grpc/status" "google.golang.org/grpc/status"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/protoadapt" "google.golang.org/protobuf/protoadapt"
commandErrors "github.com/zitadel/zitadel/internal/command/errors" commandErrors "github.com/zitadel/zitadel/internal/command/errors"
@@ -36,6 +38,30 @@ func ZITADELToGRPCError(err error) error {
return s.Err() return s.Err()
} }
func ZITADELToConnectError(err error) error {
if err == nil {
return nil
}
connectError := new(connect.Error)
if errors.As(err, &connectError) {
return err
}
code, key, id, ok := ExtractZITADELError(err)
if !ok {
return status.Convert(err).Err()
}
msg := key
msg += " (" + id + ")"
errorInfo := getErrorInfo(id, key, err)
cErr := connect.NewError(connect.Code(code), errors.New(msg))
if detail, detailErr := connect.NewErrorDetail(errorInfo.(proto.Message)); detailErr == nil {
cErr.AddDetail(detail)
}
return cErr
}
func ExtractZITADELError(err error) (c codes.Code, msg, id string, ok bool) { func ExtractZITADELError(err error) (c codes.Code, msg, id string, ok bool) {
if err == nil { if err == nil {
return codes.OK, "", "", false return codes.OK, "", "", false

View File

@@ -3,6 +3,7 @@ package idp
import ( import (
"context" "context"
"connectrpc.com/connect"
"github.com/crewjam/saml" "github.com/crewjam/saml"
"github.com/muhlemmer/gu" "github.com/muhlemmer/gu"
"google.golang.org/protobuf/types/known/durationpb" "google.golang.org/protobuf/types/known/durationpb"
@@ -15,12 +16,12 @@ import (
idp_pb "github.com/zitadel/zitadel/pkg/grpc/idp/v2" idp_pb "github.com/zitadel/zitadel/pkg/grpc/idp/v2"
) )
func (s *Server) GetIDPByID(ctx context.Context, req *idp_pb.GetIDPByIDRequest) (*idp_pb.GetIDPByIDResponse, error) { func (s *Server) GetIDPByID(ctx context.Context, req *connect.Request[idp_pb.GetIDPByIDRequest]) (*connect.Response[idp_pb.GetIDPByIDResponse], error) {
idp, err := s.query.IDPTemplateByID(ctx, true, req.Id, false, s.checkPermission) idp, err := s.query.IDPTemplateByID(ctx, true, req.Msg.GetId(), false, s.checkPermission)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &idp_pb.GetIDPByIDResponse{Idp: idpToPb(idp)}, nil return connect.NewResponse(&idp_pb.GetIDPByIDResponse{Idp: idpToPb(idp)}), nil
} }
func idpToPb(idp *query.IDPTemplate) *idp_pb.IDP { func idpToPb(idp *query.IDPTemplate) *idp_pb.IDP {

View File

@@ -1,7 +1,10 @@
package idp package idp
import ( import (
"google.golang.org/grpc" "net/http"
"connectrpc.com/connect"
"google.golang.org/protobuf/reflect/protoreflect"
"github.com/zitadel/zitadel/internal/api/authz" "github.com/zitadel/zitadel/internal/api/authz"
"github.com/zitadel/zitadel/internal/api/grpc/server" "github.com/zitadel/zitadel/internal/api/grpc/server"
@@ -9,12 +12,12 @@ import (
"github.com/zitadel/zitadel/internal/domain" "github.com/zitadel/zitadel/internal/domain"
"github.com/zitadel/zitadel/internal/query" "github.com/zitadel/zitadel/internal/query"
"github.com/zitadel/zitadel/pkg/grpc/idp/v2" "github.com/zitadel/zitadel/pkg/grpc/idp/v2"
"github.com/zitadel/zitadel/pkg/grpc/idp/v2/idpconnect"
) )
var _ idp.IdentityProviderServiceServer = (*Server)(nil) var _ idpconnect.IdentityProviderServiceHandler = (*Server)(nil)
type Server struct { type Server struct {
idp.UnimplementedIdentityProviderServiceServer
command *command.Commands command *command.Commands
query *query.Queries query *query.Queries
@@ -35,8 +38,12 @@ func CreateServer(
} }
} }
func (s *Server) RegisterServer(grpcServer *grpc.Server) { func (s *Server) RegisterConnectServer(interceptors ...connect.Interceptor) (string, http.Handler) {
idp.RegisterIdentityProviderServiceServer(grpcServer, s) return idpconnect.NewIdentityProviderServiceHandler(s, connect.WithInterceptors(interceptors...))
}
func (s *Server) FileDescriptor() protoreflect.FileDescriptor {
return idp.File_zitadel_idp_v2_idp_service_proto
} }
func (s *Server) AppName() string { func (s *Server) AppName() string {

View File

@@ -3,48 +3,49 @@ package instance
import ( import (
"context" "context"
"connectrpc.com/connect"
"google.golang.org/protobuf/types/known/timestamppb" "google.golang.org/protobuf/types/known/timestamppb"
instance "github.com/zitadel/zitadel/pkg/grpc/instance/v2beta" instance "github.com/zitadel/zitadel/pkg/grpc/instance/v2beta"
) )
func (s *Server) AddCustomDomain(ctx context.Context, req *instance.AddCustomDomainRequest) (*instance.AddCustomDomainResponse, error) { func (s *Server) AddCustomDomain(ctx context.Context, req *connect.Request[instance.AddCustomDomainRequest]) (*connect.Response[instance.AddCustomDomainResponse], error) {
details, err := s.command.AddInstanceDomain(ctx, req.GetDomain()) details, err := s.command.AddInstanceDomain(ctx, req.Msg.GetDomain())
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &instance.AddCustomDomainResponse{ return connect.NewResponse(&instance.AddCustomDomainResponse{
CreationDate: timestamppb.New(details.CreationDate), CreationDate: timestamppb.New(details.CreationDate),
}, nil }), nil
} }
func (s *Server) RemoveCustomDomain(ctx context.Context, req *instance.RemoveCustomDomainRequest) (*instance.RemoveCustomDomainResponse, error) { func (s *Server) RemoveCustomDomain(ctx context.Context, req *connect.Request[instance.RemoveCustomDomainRequest]) (*connect.Response[instance.RemoveCustomDomainResponse], error) {
details, err := s.command.RemoveInstanceDomain(ctx, req.GetDomain()) details, err := s.command.RemoveInstanceDomain(ctx, req.Msg.GetDomain())
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &instance.RemoveCustomDomainResponse{ return connect.NewResponse(&instance.RemoveCustomDomainResponse{
DeletionDate: timestamppb.New(details.EventDate), DeletionDate: timestamppb.New(details.EventDate),
}, nil }), nil
} }
func (s *Server) AddTrustedDomain(ctx context.Context, req *instance.AddTrustedDomainRequest) (*instance.AddTrustedDomainResponse, error) { func (s *Server) AddTrustedDomain(ctx context.Context, req *connect.Request[instance.AddTrustedDomainRequest]) (*connect.Response[instance.AddTrustedDomainResponse], error) {
details, err := s.command.AddTrustedDomain(ctx, req.GetDomain()) details, err := s.command.AddTrustedDomain(ctx, req.Msg.GetDomain())
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &instance.AddTrustedDomainResponse{ return connect.NewResponse(&instance.AddTrustedDomainResponse{
CreationDate: timestamppb.New(details.CreationDate), CreationDate: timestamppb.New(details.CreationDate),
}, nil }), nil
} }
func (s *Server) RemoveTrustedDomain(ctx context.Context, req *instance.RemoveTrustedDomainRequest) (*instance.RemoveTrustedDomainResponse, error) { func (s *Server) RemoveTrustedDomain(ctx context.Context, req *connect.Request[instance.RemoveTrustedDomainRequest]) (*connect.Response[instance.RemoveTrustedDomainResponse], error) {
details, err := s.command.RemoveTrustedDomain(ctx, req.GetDomain()) details, err := s.command.RemoveTrustedDomain(ctx, req.Msg.GetDomain())
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &instance.RemoveTrustedDomainResponse{ return connect.NewResponse(&instance.RemoveTrustedDomainResponse{
DeletionDate: timestamppb.New(details.EventDate), DeletionDate: timestamppb.New(details.EventDate),
}, nil }), nil
} }

View File

@@ -3,30 +3,31 @@ package instance
import ( import (
"context" "context"
"connectrpc.com/connect"
"google.golang.org/protobuf/types/known/timestamppb" "google.golang.org/protobuf/types/known/timestamppb"
instance "github.com/zitadel/zitadel/pkg/grpc/instance/v2beta" instance "github.com/zitadel/zitadel/pkg/grpc/instance/v2beta"
) )
func (s *Server) DeleteInstance(ctx context.Context, request *instance.DeleteInstanceRequest) (*instance.DeleteInstanceResponse, error) { func (s *Server) DeleteInstance(ctx context.Context, request *connect.Request[instance.DeleteInstanceRequest]) (*connect.Response[instance.DeleteInstanceResponse], error) {
obj, err := s.command.RemoveInstance(ctx, request.GetInstanceId()) obj, err := s.command.RemoveInstance(ctx, request.Msg.GetInstanceId())
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &instance.DeleteInstanceResponse{ return connect.NewResponse(&instance.DeleteInstanceResponse{
DeletionDate: timestamppb.New(obj.EventDate), DeletionDate: timestamppb.New(obj.EventDate),
}, nil }), nil
} }
func (s *Server) UpdateInstance(ctx context.Context, request *instance.UpdateInstanceRequest) (*instance.UpdateInstanceResponse, error) { func (s *Server) UpdateInstance(ctx context.Context, request *connect.Request[instance.UpdateInstanceRequest]) (*connect.Response[instance.UpdateInstanceResponse], error) {
obj, err := s.command.UpdateInstance(ctx, request.GetInstanceName()) obj, err := s.command.UpdateInstance(ctx, request.Msg.GetInstanceName())
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &instance.UpdateInstanceResponse{ return connect.NewResponse(&instance.UpdateInstanceResponse{
ChangeDate: timestamppb.New(obj.EventDate), ChangeDate: timestamppb.New(obj.EventDate),
}, nil }), nil
} }

View File

@@ -3,23 +3,25 @@ package instance
import ( import (
"context" "context"
"connectrpc.com/connect"
filter "github.com/zitadel/zitadel/internal/api/grpc/filter/v2beta" filter "github.com/zitadel/zitadel/internal/api/grpc/filter/v2beta"
instance "github.com/zitadel/zitadel/pkg/grpc/instance/v2beta" instance "github.com/zitadel/zitadel/pkg/grpc/instance/v2beta"
) )
func (s *Server) GetInstance(ctx context.Context, _ *instance.GetInstanceRequest) (*instance.GetInstanceResponse, error) { func (s *Server) GetInstance(ctx context.Context, _ *connect.Request[instance.GetInstanceRequest]) (*connect.Response[instance.GetInstanceResponse], error) {
inst, err := s.query.Instance(ctx, true) inst, err := s.query.Instance(ctx, true)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &instance.GetInstanceResponse{ return connect.NewResponse(&instance.GetInstanceResponse{
Instance: ToProtoObject(inst), Instance: ToProtoObject(inst),
}, nil }), nil
} }
func (s *Server) ListInstances(ctx context.Context, req *instance.ListInstancesRequest) (*instance.ListInstancesResponse, error) { func (s *Server) ListInstances(ctx context.Context, req *connect.Request[instance.ListInstancesRequest]) (*connect.Response[instance.ListInstancesResponse], error) {
queries, err := ListInstancesRequestToModel(req, s.systemDefaults) queries, err := ListInstancesRequestToModel(req.Msg, s.systemDefaults)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -29,14 +31,14 @@ func (s *Server) ListInstances(ctx context.Context, req *instance.ListInstancesR
return nil, err return nil, err
} }
return &instance.ListInstancesResponse{ return connect.NewResponse(&instance.ListInstancesResponse{
Instances: InstancesToPb(instances.Instances), Instances: InstancesToPb(instances.Instances),
Pagination: filter.QueryToPaginationPb(queries.SearchRequest, instances.SearchResponse), Pagination: filter.QueryToPaginationPb(queries.SearchRequest, instances.SearchResponse),
}, nil }), nil
} }
func (s *Server) ListCustomDomains(ctx context.Context, req *instance.ListCustomDomainsRequest) (*instance.ListCustomDomainsResponse, error) { func (s *Server) ListCustomDomains(ctx context.Context, req *connect.Request[instance.ListCustomDomainsRequest]) (*connect.Response[instance.ListCustomDomainsResponse], error) {
queries, err := ListCustomDomainsRequestToModel(req, s.systemDefaults) queries, err := ListCustomDomainsRequestToModel(req.Msg, s.systemDefaults)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -46,14 +48,14 @@ func (s *Server) ListCustomDomains(ctx context.Context, req *instance.ListCustom
return nil, err return nil, err
} }
return &instance.ListCustomDomainsResponse{ return connect.NewResponse(&instance.ListCustomDomainsResponse{
Domains: DomainsToPb(domains.Domains), Domains: DomainsToPb(domains.Domains),
Pagination: filter.QueryToPaginationPb(queries.SearchRequest, domains.SearchResponse), Pagination: filter.QueryToPaginationPb(queries.SearchRequest, domains.SearchResponse),
}, nil }), nil
} }
func (s *Server) ListTrustedDomains(ctx context.Context, req *instance.ListTrustedDomainsRequest) (*instance.ListTrustedDomainsResponse, error) { func (s *Server) ListTrustedDomains(ctx context.Context, req *connect.Request[instance.ListTrustedDomainsRequest]) (*connect.Response[instance.ListTrustedDomainsResponse], error) {
queries, err := ListTrustedDomainsRequestToModel(req, s.systemDefaults) queries, err := ListTrustedDomainsRequestToModel(req.Msg, s.systemDefaults)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -63,8 +65,8 @@ func (s *Server) ListTrustedDomains(ctx context.Context, req *instance.ListTrust
return nil, err return nil, err
} }
return &instance.ListTrustedDomainsResponse{ return connect.NewResponse(&instance.ListTrustedDomainsResponse{
TrustedDomain: trustedDomainsToPb(domains.Domains), TrustedDomain: trustedDomainsToPb(domains.Domains),
Pagination: filter.QueryToPaginationPb(queries.SearchRequest, domains.SearchResponse), Pagination: filter.QueryToPaginationPb(queries.SearchRequest, domains.SearchResponse),
}, nil }), nil
} }

View File

@@ -1,7 +1,10 @@
package instance package instance
import ( import (
"google.golang.org/grpc" "net/http"
"connectrpc.com/connect"
"google.golang.org/protobuf/reflect/protoreflect"
"github.com/zitadel/zitadel/internal/api/authz" "github.com/zitadel/zitadel/internal/api/authz"
"github.com/zitadel/zitadel/internal/api/grpc/server" "github.com/zitadel/zitadel/internal/api/grpc/server"
@@ -9,12 +12,12 @@ import (
"github.com/zitadel/zitadel/internal/config/systemdefaults" "github.com/zitadel/zitadel/internal/config/systemdefaults"
"github.com/zitadel/zitadel/internal/query" "github.com/zitadel/zitadel/internal/query"
instance "github.com/zitadel/zitadel/pkg/grpc/instance/v2beta" instance "github.com/zitadel/zitadel/pkg/grpc/instance/v2beta"
"github.com/zitadel/zitadel/pkg/grpc/instance/v2beta/instanceconnect"
) )
var _ instance.InstanceServiceServer = (*Server)(nil) var _ instanceconnect.InstanceServiceHandler = (*Server)(nil)
type Server struct { type Server struct {
instance.UnimplementedInstanceServiceServer
command *command.Commands command *command.Commands
query *query.Queries query *query.Queries
systemDefaults systemdefaults.SystemDefaults systemDefaults systemdefaults.SystemDefaults
@@ -39,8 +42,12 @@ func CreateServer(
} }
} }
func (s *Server) RegisterServer(grpcServer *grpc.Server) { func (s *Server) RegisterConnectServer(interceptors ...connect.Interceptor) (string, http.Handler) {
instance.RegisterInstanceServiceServer(grpcServer, s) return instanceconnect.NewInstanceServiceHandler(s, connect.WithInterceptors(interceptors...))
}
func (s *Server) FileDescriptor() protoreflect.FileDescriptor {
return instance.File_zitadel_instance_v2beta_instance_service_proto
} }
func (s *Server) AppName() string { func (s *Server) AppName() string {

View File

@@ -4,6 +4,7 @@ import (
"context" "context"
"encoding/base64" "encoding/base64"
"connectrpc.com/connect"
"github.com/zitadel/logging" "github.com/zitadel/logging"
"github.com/zitadel/oidc/v3/pkg/op" "github.com/zitadel/oidc/v3/pkg/op"
"google.golang.org/protobuf/types/known/durationpb" "google.golang.org/protobuf/types/known/durationpb"
@@ -18,30 +19,30 @@ import (
oidc_pb "github.com/zitadel/zitadel/pkg/grpc/oidc/v2" oidc_pb "github.com/zitadel/zitadel/pkg/grpc/oidc/v2"
) )
func (s *Server) GetAuthRequest(ctx context.Context, req *oidc_pb.GetAuthRequestRequest) (*oidc_pb.GetAuthRequestResponse, error) { func (s *Server) GetAuthRequest(ctx context.Context, req *connect.Request[oidc_pb.GetAuthRequestRequest]) (*connect.Response[oidc_pb.GetAuthRequestResponse], error) {
authRequest, err := s.query.AuthRequestByID(ctx, true, req.GetAuthRequestId(), true) authRequest, err := s.query.AuthRequestByID(ctx, true, req.Msg.GetAuthRequestId(), true)
if err != nil { if err != nil {
logging.WithError(err).Error("query authRequest by ID") logging.WithError(err).Error("query authRequest by ID")
return nil, err return nil, err
} }
return &oidc_pb.GetAuthRequestResponse{ return connect.NewResponse(&oidc_pb.GetAuthRequestResponse{
AuthRequest: authRequestToPb(authRequest), AuthRequest: authRequestToPb(authRequest),
}, nil }), nil
} }
func (s *Server) CreateCallback(ctx context.Context, req *oidc_pb.CreateCallbackRequest) (*oidc_pb.CreateCallbackResponse, error) { func (s *Server) CreateCallback(ctx context.Context, req *connect.Request[oidc_pb.CreateCallbackRequest]) (*connect.Response[oidc_pb.CreateCallbackResponse], error) {
switch v := req.GetCallbackKind().(type) { switch v := req.Msg.GetCallbackKind().(type) {
case *oidc_pb.CreateCallbackRequest_Error: case *oidc_pb.CreateCallbackRequest_Error:
return s.failAuthRequest(ctx, req.GetAuthRequestId(), v.Error) return s.failAuthRequest(ctx, req.Msg.GetAuthRequestId(), v.Error)
case *oidc_pb.CreateCallbackRequest_Session: case *oidc_pb.CreateCallbackRequest_Session:
return s.linkSessionToAuthRequest(ctx, req.GetAuthRequestId(), v.Session) return s.linkSessionToAuthRequest(ctx, req.Msg.GetAuthRequestId(), v.Session)
default: default:
return nil, zerrors.ThrowUnimplementedf(nil, "OIDCv2-zee7A", "verification oneOf %T in method CreateCallback not implemented", v) return nil, zerrors.ThrowUnimplementedf(nil, "OIDCv2-zee7A", "verification oneOf %T in method CreateCallback not implemented", v)
} }
} }
func (s *Server) GetDeviceAuthorizationRequest(ctx context.Context, req *oidc_pb.GetDeviceAuthorizationRequestRequest) (*oidc_pb.GetDeviceAuthorizationRequestResponse, error) { func (s *Server) GetDeviceAuthorizationRequest(ctx context.Context, req *connect.Request[oidc_pb.GetDeviceAuthorizationRequestRequest]) (*connect.Response[oidc_pb.GetDeviceAuthorizationRequestResponse], error) {
deviceRequest, err := s.query.DeviceAuthRequestByUserCode(ctx, req.GetUserCode()) deviceRequest, err := s.query.DeviceAuthRequestByUserCode(ctx, req.Msg.GetUserCode())
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -49,7 +50,7 @@ func (s *Server) GetDeviceAuthorizationRequest(ctx context.Context, req *oidc_pb
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &oidc_pb.GetDeviceAuthorizationRequestResponse{ return connect.NewResponse(&oidc_pb.GetDeviceAuthorizationRequestResponse{
DeviceAuthorizationRequest: &oidc_pb.DeviceAuthorizationRequest{ DeviceAuthorizationRequest: &oidc_pb.DeviceAuthorizationRequest{
Id: base64.RawURLEncoding.EncodeToString(encrypted), Id: base64.RawURLEncoding.EncodeToString(encrypted),
ClientId: deviceRequest.ClientID, ClientId: deviceRequest.ClientID,
@@ -57,24 +58,24 @@ func (s *Server) GetDeviceAuthorizationRequest(ctx context.Context, req *oidc_pb
AppName: deviceRequest.AppName, AppName: deviceRequest.AppName,
ProjectName: deviceRequest.ProjectName, ProjectName: deviceRequest.ProjectName,
}, },
}, nil }), nil
} }
func (s *Server) AuthorizeOrDenyDeviceAuthorization(ctx context.Context, req *oidc_pb.AuthorizeOrDenyDeviceAuthorizationRequest) (*oidc_pb.AuthorizeOrDenyDeviceAuthorizationResponse, error) { func (s *Server) AuthorizeOrDenyDeviceAuthorization(ctx context.Context, req *connect.Request[oidc_pb.AuthorizeOrDenyDeviceAuthorizationRequest]) (*connect.Response[oidc_pb.AuthorizeOrDenyDeviceAuthorizationResponse], error) {
deviceCode, err := s.deviceCodeFromID(req.GetDeviceAuthorizationId()) deviceCode, err := s.deviceCodeFromID(req.Msg.GetDeviceAuthorizationId())
if err != nil { if err != nil {
return nil, err return nil, err
} }
switch req.GetDecision().(type) { switch req.Msg.GetDecision().(type) {
case *oidc_pb.AuthorizeOrDenyDeviceAuthorizationRequest_Session: case *oidc_pb.AuthorizeOrDenyDeviceAuthorizationRequest_Session:
_, err = s.command.ApproveDeviceAuthWithSession(ctx, deviceCode, req.GetSession().GetSessionId(), req.GetSession().GetSessionToken()) _, err = s.command.ApproveDeviceAuthWithSession(ctx, deviceCode, req.Msg.GetSession().GetSessionId(), req.Msg.GetSession().GetSessionToken())
case *oidc_pb.AuthorizeOrDenyDeviceAuthorizationRequest_Deny: case *oidc_pb.AuthorizeOrDenyDeviceAuthorizationRequest_Deny:
_, err = s.command.CancelDeviceAuth(ctx, deviceCode, domain.DeviceAuthCanceledDenied) _, err = s.command.CancelDeviceAuth(ctx, deviceCode, domain.DeviceAuthCanceledDenied)
} }
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &oidc_pb.AuthorizeOrDenyDeviceAuthorizationResponse{}, nil return connect.NewResponse(&oidc_pb.AuthorizeOrDenyDeviceAuthorizationResponse{}), nil
} }
func authRequestToPb(a *query.AuthRequest) *oidc_pb.AuthRequest { func authRequestToPb(a *query.AuthRequest) *oidc_pb.AuthRequest {
@@ -136,7 +137,7 @@ func (s *Server) checkPermission(ctx context.Context, clientID string, userID st
return nil return nil
} }
func (s *Server) failAuthRequest(ctx context.Context, authRequestID string, ae *oidc_pb.AuthorizationError) (*oidc_pb.CreateCallbackResponse, error) { func (s *Server) failAuthRequest(ctx context.Context, authRequestID string, ae *oidc_pb.AuthorizationError) (*connect.Response[oidc_pb.CreateCallbackResponse], error) {
details, aar, err := s.command.FailAuthRequest(ctx, authRequestID, errorReasonToDomain(ae.GetError())) details, aar, err := s.command.FailAuthRequest(ctx, authRequestID, errorReasonToDomain(ae.GetError()))
if err != nil { if err != nil {
return nil, err return nil, err
@@ -146,13 +147,13 @@ func (s *Server) failAuthRequest(ctx context.Context, authRequestID string, ae *
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &oidc_pb.CreateCallbackResponse{ return connect.NewResponse(&oidc_pb.CreateCallbackResponse{
Details: object.DomainToDetailsPb(details), Details: object.DomainToDetailsPb(details),
CallbackUrl: callback, CallbackUrl: callback,
}, nil }), nil
} }
func (s *Server) linkSessionToAuthRequest(ctx context.Context, authRequestID string, session *oidc_pb.Session) (*oidc_pb.CreateCallbackResponse, error) { func (s *Server) linkSessionToAuthRequest(ctx context.Context, authRequestID string, session *oidc_pb.Session) (*connect.Response[oidc_pb.CreateCallbackResponse], error) {
details, aar, err := s.command.LinkSessionToAuthRequest(ctx, authRequestID, session.GetSessionId(), session.GetSessionToken(), true, s.checkPermission) details, aar, err := s.command.LinkSessionToAuthRequest(ctx, authRequestID, session.GetSessionId(), session.GetSessionToken(), true, s.checkPermission)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -172,10 +173,10 @@ func (s *Server) linkSessionToAuthRequest(ctx context.Context, authRequestID str
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &oidc_pb.CreateCallbackResponse{ return connect.NewResponse(&oidc_pb.CreateCallbackResponse{
Details: object.DomainToDetailsPb(details), Details: object.DomainToDetailsPb(details),
CallbackUrl: callback, CallbackUrl: callback,
}, nil }), nil
} }
func errorReasonToDomain(errorReason oidc_pb.ErrorReason) domain.OIDCErrorReason { func errorReasonToDomain(errorReason oidc_pb.ErrorReason) domain.OIDCErrorReason {

View File

@@ -1,7 +1,10 @@
package oidc package oidc
import ( import (
"google.golang.org/grpc" "net/http"
"connectrpc.com/connect"
"google.golang.org/protobuf/reflect/protoreflect"
"github.com/zitadel/zitadel/internal/api/authz" "github.com/zitadel/zitadel/internal/api/authz"
"github.com/zitadel/zitadel/internal/api/grpc/server" "github.com/zitadel/zitadel/internal/api/grpc/server"
@@ -10,12 +13,12 @@ import (
"github.com/zitadel/zitadel/internal/crypto" "github.com/zitadel/zitadel/internal/crypto"
"github.com/zitadel/zitadel/internal/query" "github.com/zitadel/zitadel/internal/query"
oidc_pb "github.com/zitadel/zitadel/pkg/grpc/oidc/v2" oidc_pb "github.com/zitadel/zitadel/pkg/grpc/oidc/v2"
"github.com/zitadel/zitadel/pkg/grpc/oidc/v2/oidcconnect"
) )
var _ oidc_pb.OIDCServiceServer = (*Server)(nil) var _ oidcconnect.OIDCServiceHandler = (*Server)(nil)
type Server struct { type Server struct {
oidc_pb.UnimplementedOIDCServiceServer
command *command.Commands command *command.Commands
query *query.Queries query *query.Queries
@@ -42,8 +45,12 @@ func CreateServer(
} }
} }
func (s *Server) RegisterServer(grpcServer *grpc.Server) { func (s *Server) RegisterConnectServer(interceptors ...connect.Interceptor) (string, http.Handler) {
oidc_pb.RegisterOIDCServiceServer(grpcServer, s) return oidcconnect.NewOIDCServiceHandler(s, connect.WithInterceptors(interceptors...))
}
func (s *Server) FileDescriptor() protoreflect.FileDescriptor {
return oidc_pb.File_zitadel_oidc_v2_oidc_service_proto
} }
func (s *Server) AppName() string { func (s *Server) AppName() string {

View File

@@ -3,6 +3,7 @@ package oidc
import ( import (
"context" "context"
"connectrpc.com/connect"
"github.com/zitadel/logging" "github.com/zitadel/logging"
"github.com/zitadel/oidc/v3/pkg/op" "github.com/zitadel/oidc/v3/pkg/op"
"google.golang.org/protobuf/types/known/durationpb" "google.golang.org/protobuf/types/known/durationpb"
@@ -17,15 +18,15 @@ import (
oidc_pb "github.com/zitadel/zitadel/pkg/grpc/oidc/v2beta" oidc_pb "github.com/zitadel/zitadel/pkg/grpc/oidc/v2beta"
) )
func (s *Server) GetAuthRequest(ctx context.Context, req *oidc_pb.GetAuthRequestRequest) (*oidc_pb.GetAuthRequestResponse, error) { func (s *Server) GetAuthRequest(ctx context.Context, req *connect.Request[oidc_pb.GetAuthRequestRequest]) (*connect.Response[oidc_pb.GetAuthRequestResponse], error) {
authRequest, err := s.query.AuthRequestByID(ctx, true, req.GetAuthRequestId(), true) authRequest, err := s.query.AuthRequestByID(ctx, true, req.Msg.GetAuthRequestId(), true)
if err != nil { if err != nil {
logging.WithError(err).Error("query authRequest by ID") logging.WithError(err).Error("query authRequest by ID")
return nil, err return nil, err
} }
return &oidc_pb.GetAuthRequestResponse{ return connect.NewResponse(&oidc_pb.GetAuthRequestResponse{
AuthRequest: authRequestToPb(authRequest), AuthRequest: authRequestToPb(authRequest),
}, nil }), nil
} }
func authRequestToPb(a *query.AuthRequest) *oidc_pb.AuthRequest { func authRequestToPb(a *query.AuthRequest) *oidc_pb.AuthRequest {
@@ -73,18 +74,18 @@ func promptToPb(p domain.Prompt) oidc_pb.Prompt {
} }
} }
func (s *Server) CreateCallback(ctx context.Context, req *oidc_pb.CreateCallbackRequest) (*oidc_pb.CreateCallbackResponse, error) { func (s *Server) CreateCallback(ctx context.Context, req *connect.Request[oidc_pb.CreateCallbackRequest]) (*connect.Response[oidc_pb.CreateCallbackResponse], error) {
switch v := req.GetCallbackKind().(type) { switch v := req.Msg.GetCallbackKind().(type) {
case *oidc_pb.CreateCallbackRequest_Error: case *oidc_pb.CreateCallbackRequest_Error:
return s.failAuthRequest(ctx, req.GetAuthRequestId(), v.Error) return s.failAuthRequest(ctx, req.Msg.GetAuthRequestId(), v.Error)
case *oidc_pb.CreateCallbackRequest_Session: case *oidc_pb.CreateCallbackRequest_Session:
return s.linkSessionToAuthRequest(ctx, req.GetAuthRequestId(), v.Session) return s.linkSessionToAuthRequest(ctx, req.Msg.GetAuthRequestId(), v.Session)
default: default:
return nil, zerrors.ThrowUnimplementedf(nil, "OIDCv2-zee7A", "verification oneOf %T in method CreateCallback not implemented", v) return nil, zerrors.ThrowUnimplementedf(nil, "OIDCv2-zee7A", "verification oneOf %T in method CreateCallback not implemented", v)
} }
} }
func (s *Server) failAuthRequest(ctx context.Context, authRequestID string, ae *oidc_pb.AuthorizationError) (*oidc_pb.CreateCallbackResponse, error) { func (s *Server) failAuthRequest(ctx context.Context, authRequestID string, ae *oidc_pb.AuthorizationError) (*connect.Response[oidc_pb.CreateCallbackResponse], error) {
details, aar, err := s.command.FailAuthRequest(ctx, authRequestID, errorReasonToDomain(ae.GetError())) details, aar, err := s.command.FailAuthRequest(ctx, authRequestID, errorReasonToDomain(ae.GetError()))
if err != nil { if err != nil {
return nil, err return nil, err
@@ -94,10 +95,10 @@ func (s *Server) failAuthRequest(ctx context.Context, authRequestID string, ae *
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &oidc_pb.CreateCallbackResponse{ return connect.NewResponse(&oidc_pb.CreateCallbackResponse{
Details: object.DomainToDetailsPb(details), Details: object.DomainToDetailsPb(details),
CallbackUrl: callback, CallbackUrl: callback,
}, nil }), nil
} }
func (s *Server) checkPermission(ctx context.Context, clientID string, userID string) error { func (s *Server) checkPermission(ctx context.Context, clientID string, userID string) error {
@@ -114,7 +115,7 @@ func (s *Server) checkPermission(ctx context.Context, clientID string, userID st
return nil return nil
} }
func (s *Server) linkSessionToAuthRequest(ctx context.Context, authRequestID string, session *oidc_pb.Session) (*oidc_pb.CreateCallbackResponse, error) { func (s *Server) linkSessionToAuthRequest(ctx context.Context, authRequestID string, session *oidc_pb.Session) (*connect.Response[oidc_pb.CreateCallbackResponse], error) {
details, aar, err := s.command.LinkSessionToAuthRequest(ctx, authRequestID, session.GetSessionId(), session.GetSessionToken(), true, s.checkPermission) details, aar, err := s.command.LinkSessionToAuthRequest(ctx, authRequestID, session.GetSessionId(), session.GetSessionToken(), true, s.checkPermission)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -130,10 +131,10 @@ func (s *Server) linkSessionToAuthRequest(ctx context.Context, authRequestID str
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &oidc_pb.CreateCallbackResponse{ return connect.NewResponse(&oidc_pb.CreateCallbackResponse{
Details: object.DomainToDetailsPb(details), Details: object.DomainToDetailsPb(details),
CallbackUrl: callback, CallbackUrl: callback,
}, nil }), nil
} }
func errorReasonToDomain(errorReason oidc_pb.ErrorReason) domain.OIDCErrorReason { func errorReasonToDomain(errorReason oidc_pb.ErrorReason) domain.OIDCErrorReason {

View File

@@ -1,7 +1,10 @@
package oidc package oidc
import ( import (
"google.golang.org/grpc" "net/http"
"connectrpc.com/connect"
"google.golang.org/protobuf/reflect/protoreflect"
"github.com/zitadel/zitadel/internal/api/authz" "github.com/zitadel/zitadel/internal/api/authz"
"github.com/zitadel/zitadel/internal/api/grpc/server" "github.com/zitadel/zitadel/internal/api/grpc/server"
@@ -9,12 +12,12 @@ import (
"github.com/zitadel/zitadel/internal/command" "github.com/zitadel/zitadel/internal/command"
"github.com/zitadel/zitadel/internal/query" "github.com/zitadel/zitadel/internal/query"
oidc_pb "github.com/zitadel/zitadel/pkg/grpc/oidc/v2beta" oidc_pb "github.com/zitadel/zitadel/pkg/grpc/oidc/v2beta"
"github.com/zitadel/zitadel/pkg/grpc/oidc/v2beta/oidcconnect"
) )
var _ oidc_pb.OIDCServiceServer = (*Server)(nil) var _ oidcconnect.OIDCServiceHandler = (*Server)(nil)
type Server struct { type Server struct {
oidc_pb.UnimplementedOIDCServiceServer
command *command.Commands command *command.Commands
query *query.Queries query *query.Queries
@@ -38,8 +41,12 @@ func CreateServer(
} }
} }
func (s *Server) RegisterServer(grpcServer *grpc.Server) { func (s *Server) RegisterConnectServer(interceptors ...connect.Interceptor) (string, http.Handler) {
oidc_pb.RegisterOIDCServiceServer(grpcServer, s) return oidcconnect.NewOIDCServiceHandler(s, connect.WithInterceptors(interceptors...))
}
func (s *Server) FileDescriptor() protoreflect.FileDescriptor {
return oidc_pb.File_zitadel_oidc_v2beta_oidc_service_proto
} }
func (s *Server) AppName() string { func (s *Server) AppName() string {

View File

@@ -3,6 +3,8 @@ package org
import ( import (
"context" "context"
"connectrpc.com/connect"
"github.com/zitadel/zitadel/internal/api/grpc/object/v2" "github.com/zitadel/zitadel/internal/api/grpc/object/v2"
"github.com/zitadel/zitadel/internal/api/grpc/user/v2" "github.com/zitadel/zitadel/internal/api/grpc/user/v2"
"github.com/zitadel/zitadel/internal/command" "github.com/zitadel/zitadel/internal/command"
@@ -10,8 +12,8 @@ import (
"github.com/zitadel/zitadel/pkg/grpc/org/v2" "github.com/zitadel/zitadel/pkg/grpc/org/v2"
) )
func (s *Server) AddOrganization(ctx context.Context, request *org.AddOrganizationRequest) (*org.AddOrganizationResponse, error) { func (s *Server) AddOrganization(ctx context.Context, request *connect.Request[org.AddOrganizationRequest]) (*connect.Response[org.AddOrganizationResponse], error) {
orgSetup, err := addOrganizationRequestToCommand(request) orgSetup, err := addOrganizationRequestToCommand(request.Msg)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -68,7 +70,7 @@ func addOrganizationRequestAdminToCommand(admin *org.AddOrganizationRequest_Admi
} }
} }
func createdOrganizationToPb(createdOrg *command.CreatedOrg) (_ *org.AddOrganizationResponse, err error) { func createdOrganizationToPb(createdOrg *command.CreatedOrg) (_ *connect.Response[org.AddOrganizationResponse], err error) {
admins := make([]*org.AddOrganizationResponse_CreatedAdmin, 0, len(createdOrg.OrgAdmins)) admins := make([]*org.AddOrganizationResponse_CreatedAdmin, 0, len(createdOrg.OrgAdmins))
for _, admin := range createdOrg.OrgAdmins { for _, admin := range createdOrg.OrgAdmins {
admin, ok := admin.(*command.CreatedOrgAdmin) admin, ok := admin.(*command.CreatedOrgAdmin)
@@ -80,9 +82,9 @@ func createdOrganizationToPb(createdOrg *command.CreatedOrg) (_ *org.AddOrganiza
}) })
} }
} }
return &org.AddOrganizationResponse{ return connect.NewResponse(&org.AddOrganizationResponse{
Details: object.DomainToDetailsPb(createdOrg.ObjectDetails), Details: object.DomainToDetailsPb(createdOrg.ObjectDetails),
OrganizationId: createdOrg.ObjectDetails.ResourceOwner, OrganizationId: createdOrg.ObjectDetails.ResourceOwner,
CreatedAdmins: admins, CreatedAdmins: admins,
}, nil }), nil
} }

View File

@@ -4,6 +4,7 @@ import (
"testing" "testing"
"time" "time"
"connectrpc.com/connect"
"github.com/muhlemmer/gu" "github.com/muhlemmer/gu"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"google.golang.org/protobuf/types/known/timestamppb" "google.golang.org/protobuf/types/known/timestamppb"
@@ -138,7 +139,7 @@ func Test_createdOrganizationToPb(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
args args args args
want *org.AddOrganizationResponse want *connect.Response[org.AddOrganizationResponse]
wantErr error wantErr error
}{ }{
{ {
@@ -159,7 +160,7 @@ func Test_createdOrganizationToPb(t *testing.T) {
}, },
}, },
}, },
want: &org.AddOrganizationResponse{ want: connect.NewResponse(&org.AddOrganizationResponse{
Details: &object.Details{ Details: &object.Details{
Sequence: 1, Sequence: 1,
ChangeDate: timestamppb.New(now), ChangeDate: timestamppb.New(now),
@@ -173,7 +174,7 @@ func Test_createdOrganizationToPb(t *testing.T) {
PhoneCode: gu.Ptr("phoneCode"), PhoneCode: gu.Ptr("phoneCode"),
}, },
}, },
}, }),
}, },
} }
for _, tt := range tests { for _, tt := range tests {

View File

@@ -3,6 +3,8 @@ package org
import ( import (
"context" "context"
"connectrpc.com/connect"
"github.com/zitadel/zitadel/internal/api/authz" "github.com/zitadel/zitadel/internal/api/authz"
"github.com/zitadel/zitadel/internal/api/grpc/object/v2" "github.com/zitadel/zitadel/internal/api/grpc/object/v2"
"github.com/zitadel/zitadel/internal/domain" "github.com/zitadel/zitadel/internal/domain"
@@ -11,36 +13,36 @@ import (
"github.com/zitadel/zitadel/pkg/grpc/org/v2" "github.com/zitadel/zitadel/pkg/grpc/org/v2"
) )
func (s *Server) ListOrganizations(ctx context.Context, req *org.ListOrganizationsRequest) (*org.ListOrganizationsResponse, error) { func (s *Server) ListOrganizations(ctx context.Context, req *connect.Request[org.ListOrganizationsRequest]) (*connect.Response[org.ListOrganizationsResponse], error) {
queries, err := listOrgRequestToModel(ctx, req) queries, err := listOrgRequestToModel(ctx, req)
if err != nil { if err != nil {
return nil, err return nil, err
} }
orgs, err := s.query.SearchOrgs(ctx, queries, s.checkPermission) orgs, err := s.query.SearchOrgs(ctx, queries.Msg, s.checkPermission)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &org.ListOrganizationsResponse{ return connect.NewResponse(&org.ListOrganizationsResponse{
Result: organizationsToPb(orgs.Orgs), Result: organizationsToPb(orgs.Orgs),
Details: object.ToListDetails(orgs.SearchResponse), Details: object.ToListDetails(orgs.SearchResponse),
}, nil }), nil
} }
func listOrgRequestToModel(ctx context.Context, req *org.ListOrganizationsRequest) (*query.OrgSearchQueries, error) { func listOrgRequestToModel(ctx context.Context, req *connect.Request[org.ListOrganizationsRequest]) (*connect.Response[query.OrgSearchQueries], error) {
offset, limit, asc := object.ListQueryToQuery(req.Query) offset, limit, asc := object.ListQueryToQuery(req.Msg.Query)
queries, err := orgQueriesToQuery(ctx, req.Queries) queries, err := orgQueriesToQuery(ctx, req.Msg.Queries)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &query.OrgSearchQueries{ return connect.NewResponse(&query.OrgSearchQueries{
SearchRequest: query.SearchRequest{ SearchRequest: query.SearchRequest{
Offset: offset, Offset: offset,
Limit: limit, Limit: limit,
SortingColumn: fieldNameToOrganizationColumn(req.SortingColumn), SortingColumn: fieldNameToOrganizationColumn(req.Msg.SortingColumn),
Asc: asc, Asc: asc,
}, },
Queries: queries, Queries: queries,
}, nil }), nil
} }
func orgQueriesToQuery(ctx context.Context, queries []*org.SearchQuery) (_ []query.SearchQuery, err error) { func orgQueriesToQuery(ctx context.Context, queries []*org.SearchQuery) (_ []query.SearchQuery, err error) {

View File

@@ -1,7 +1,10 @@
package org package org
import ( import (
"google.golang.org/grpc" "net/http"
"connectrpc.com/connect"
"google.golang.org/protobuf/reflect/protoreflect"
"github.com/zitadel/zitadel/internal/api/authz" "github.com/zitadel/zitadel/internal/api/authz"
"github.com/zitadel/zitadel/internal/api/grpc/server" "github.com/zitadel/zitadel/internal/api/grpc/server"
@@ -9,12 +12,12 @@ import (
"github.com/zitadel/zitadel/internal/domain" "github.com/zitadel/zitadel/internal/domain"
"github.com/zitadel/zitadel/internal/query" "github.com/zitadel/zitadel/internal/query"
"github.com/zitadel/zitadel/pkg/grpc/org/v2" "github.com/zitadel/zitadel/pkg/grpc/org/v2"
"github.com/zitadel/zitadel/pkg/grpc/org/v2/orgconnect"
) )
var _ org.OrganizationServiceServer = (*Server)(nil) var _ orgconnect.OrganizationServiceHandler = (*Server)(nil)
type Server struct { type Server struct {
org.UnimplementedOrganizationServiceServer
command *command.Commands command *command.Commands
query *query.Queries query *query.Queries
checkPermission domain.PermissionCheck checkPermission domain.PermissionCheck
@@ -34,8 +37,12 @@ func CreateServer(
} }
} }
func (s *Server) RegisterServer(grpcServer *grpc.Server) { func (s *Server) RegisterConnectServer(interceptors ...connect.Interceptor) (string, http.Handler) {
org.RegisterOrganizationServiceServer(grpcServer, s) return orgconnect.NewOrganizationServiceHandler(s, connect.WithInterceptors(interceptors...))
}
func (s *Server) FileDescriptor() protoreflect.FileDescriptor {
return org.File_zitadel_org_v2_org_service_proto
} }
func (s *Server) AppName() string { func (s *Server) AppName() string {

View File

@@ -3,6 +3,7 @@ package org
import ( import (
"context" "context"
"connectrpc.com/connect"
"google.golang.org/protobuf/types/known/timestamppb" "google.golang.org/protobuf/types/known/timestamppb"
// TODO fix below // TODO fix below
@@ -71,7 +72,7 @@ func OrgStateToPb(state domain.OrgState) v2beta_org.OrgState {
} }
} }
func createdOrganizationToPb(createdOrg *command.CreatedOrg) (_ *org.CreateOrganizationResponse, err error) { func createdOrganizationToPb(createdOrg *command.CreatedOrg) (_ *connect.Response[org.CreateOrganizationResponse], err error) {
admins := make([]*org.OrganizationAdmin, len(createdOrg.OrgAdmins)) admins := make([]*org.OrganizationAdmin, len(createdOrg.OrgAdmins))
for i, admin := range createdOrg.OrgAdmins { for i, admin := range createdOrg.OrgAdmins {
switch admin := admin.(type) { switch admin := admin.(type) {
@@ -95,11 +96,11 @@ func createdOrganizationToPb(createdOrg *command.CreatedOrg) (_ *org.CreateOrgan
} }
} }
} }
return &org.CreateOrganizationResponse{ return connect.NewResponse(&org.CreateOrganizationResponse{
CreationDate: timestamppb.New(createdOrg.ObjectDetails.EventDate), CreationDate: timestamppb.New(createdOrg.ObjectDetails.EventDate),
Id: createdOrg.ObjectDetails.ResourceOwner, Id: createdOrg.ObjectDetails.ResourceOwner,
OrganizationAdmins: admins, OrganizationAdmins: admins,
}, nil }), nil
} }
func OrgViewsToPb(orgs []*query.Org) []*v2beta_org.Organization { func OrgViewsToPb(orgs []*query.Org) []*v2beta_org.Organization {

View File

@@ -4,6 +4,7 @@ import (
"context" "context"
"errors" "errors"
"connectrpc.com/connect"
"google.golang.org/protobuf/types/known/timestamppb" "google.golang.org/protobuf/types/known/timestamppb"
metadata "github.com/zitadel/zitadel/internal/api/grpc/metadata/v2beta" metadata "github.com/zitadel/zitadel/internal/api/grpc/metadata/v2beta"
@@ -17,8 +18,8 @@ import (
v2beta_org "github.com/zitadel/zitadel/pkg/grpc/org/v2beta" v2beta_org "github.com/zitadel/zitadel/pkg/grpc/org/v2beta"
) )
func (s *Server) CreateOrganization(ctx context.Context, request *v2beta_org.CreateOrganizationRequest) (*v2beta_org.CreateOrganizationResponse, error) { func (s *Server) CreateOrganization(ctx context.Context, request *connect.Request[v2beta_org.CreateOrganizationRequest]) (*connect.Response[v2beta_org.CreateOrganizationResponse], error) {
orgSetup, err := createOrganizationRequestToCommand(request) orgSetup, err := createOrganizationRequestToCommand(request.Msg)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -29,19 +30,19 @@ func (s *Server) CreateOrganization(ctx context.Context, request *v2beta_org.Cre
return createdOrganizationToPb(createdOrg) return createdOrganizationToPb(createdOrg)
} }
func (s *Server) UpdateOrganization(ctx context.Context, request *v2beta_org.UpdateOrganizationRequest) (*v2beta_org.UpdateOrganizationResponse, error) { func (s *Server) UpdateOrganization(ctx context.Context, request *connect.Request[v2beta_org.UpdateOrganizationRequest]) (*connect.Response[v2beta_org.UpdateOrganizationResponse], error) {
org, err := s.command.ChangeOrg(ctx, request.Id, request.Name) org, err := s.command.ChangeOrg(ctx, request.Msg.GetId(), request.Msg.GetName())
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &v2beta_org.UpdateOrganizationResponse{ return connect.NewResponse(&v2beta_org.UpdateOrganizationResponse{
ChangeDate: timestamppb.New(org.EventDate), ChangeDate: timestamppb.New(org.EventDate),
}, nil }), nil
} }
func (s *Server) ListOrganizations(ctx context.Context, request *v2beta_org.ListOrganizationsRequest) (*v2beta_org.ListOrganizationsResponse, error) { func (s *Server) ListOrganizations(ctx context.Context, request *connect.Request[v2beta_org.ListOrganizationsRequest]) (*connect.Response[v2beta_org.ListOrganizationsResponse], error) {
queries, err := listOrgRequestToModel(s.systemDefaults, request) queries, err := listOrgRequestToModel(s.systemDefaults, request.Msg)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -49,107 +50,107 @@ func (s *Server) ListOrganizations(ctx context.Context, request *v2beta_org.List
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &v2beta_org.ListOrganizationsResponse{ return connect.NewResponse(&v2beta_org.ListOrganizationsResponse{
Organizations: OrgViewsToPb(orgs.Orgs), Organizations: OrgViewsToPb(orgs.Orgs),
Pagination: &filter.PaginationResponse{ Pagination: &filter.PaginationResponse{
TotalResult: orgs.Count, TotalResult: orgs.Count,
AppliedLimit: uint64(request.GetPagination().GetLimit()), AppliedLimit: uint64(request.Msg.GetPagination().GetLimit()),
}, },
}, nil }), nil
} }
func (s *Server) DeleteOrganization(ctx context.Context, request *v2beta_org.DeleteOrganizationRequest) (*v2beta_org.DeleteOrganizationResponse, error) { func (s *Server) DeleteOrganization(ctx context.Context, request *connect.Request[v2beta_org.DeleteOrganizationRequest]) (*connect.Response[v2beta_org.DeleteOrganizationResponse], error) {
details, err := s.command.RemoveOrg(ctx, request.Id) details, err := s.command.RemoveOrg(ctx, request.Msg.GetId())
if err != nil { if err != nil {
var notFoundError *zerrors.NotFoundError var notFoundError *zerrors.NotFoundError
if errors.As(err, &notFoundError) { if errors.As(err, &notFoundError) {
return &v2beta_org.DeleteOrganizationResponse{}, nil return connect.NewResponse(&v2beta_org.DeleteOrganizationResponse{}), nil
} }
return nil, err return nil, err
} }
return &v2beta_org.DeleteOrganizationResponse{ return connect.NewResponse(&v2beta_org.DeleteOrganizationResponse{
DeletionDate: timestamppb.New(details.EventDate), DeletionDate: timestamppb.New(details.EventDate),
}, nil }), nil
} }
func (s *Server) SetOrganizationMetadata(ctx context.Context, request *v2beta_org.SetOrganizationMetadataRequest) (*v2beta_org.SetOrganizationMetadataResponse, error) { func (s *Server) SetOrganizationMetadata(ctx context.Context, request *connect.Request[v2beta_org.SetOrganizationMetadataRequest]) (*connect.Response[v2beta_org.SetOrganizationMetadataResponse], error) {
result, err := s.command.BulkSetOrgMetadata(ctx, request.OrganizationId, BulkSetOrgMetadataToDomain(request)...) result, err := s.command.BulkSetOrgMetadata(ctx, request.Msg.GetOrganizationId(), BulkSetOrgMetadataToDomain(request.Msg)...)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &org.SetOrganizationMetadataResponse{ return connect.NewResponse(&org.SetOrganizationMetadataResponse{
SetDate: timestamppb.New(result.EventDate), SetDate: timestamppb.New(result.EventDate),
}, nil }), nil
} }
func (s *Server) ListOrganizationMetadata(ctx context.Context, request *v2beta_org.ListOrganizationMetadataRequest) (*v2beta_org.ListOrganizationMetadataResponse, error) { func (s *Server) ListOrganizationMetadata(ctx context.Context, request *connect.Request[v2beta_org.ListOrganizationMetadataRequest]) (*connect.Response[v2beta_org.ListOrganizationMetadataResponse], error) {
metadataQueries, err := ListOrgMetadataToDomain(s.systemDefaults, request) metadataQueries, err := ListOrgMetadataToDomain(s.systemDefaults, request.Msg)
if err != nil { if err != nil {
return nil, err return nil, err
} }
res, err := s.query.SearchOrgMetadata(ctx, true, request.OrganizationId, metadataQueries, false) res, err := s.query.SearchOrgMetadata(ctx, true, request.Msg.GetOrganizationId(), metadataQueries, false)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &v2beta_org.ListOrganizationMetadataResponse{ return connect.NewResponse(&v2beta_org.ListOrganizationMetadataResponse{
Metadata: metadata.OrgMetadataListToPb(res.Metadata), Metadata: metadata.OrgMetadataListToPb(res.Metadata),
Pagination: &filter.PaginationResponse{ Pagination: &filter.PaginationResponse{
TotalResult: res.Count, TotalResult: res.Count,
AppliedLimit: uint64(request.GetPagination().GetLimit()), AppliedLimit: uint64(request.Msg.GetPagination().GetLimit()),
}, },
}, nil }), nil
} }
func (s *Server) DeleteOrganizationMetadata(ctx context.Context, request *v2beta_org.DeleteOrganizationMetadataRequest) (*v2beta_org.DeleteOrganizationMetadataResponse, error) { func (s *Server) DeleteOrganizationMetadata(ctx context.Context, request *connect.Request[v2beta_org.DeleteOrganizationMetadataRequest]) (*connect.Response[v2beta_org.DeleteOrganizationMetadataResponse], error) {
result, err := s.command.BulkRemoveOrgMetadata(ctx, request.OrganizationId, request.Keys...) result, err := s.command.BulkRemoveOrgMetadata(ctx, request.Msg.GetOrganizationId(), request.Msg.Keys...)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &v2beta_org.DeleteOrganizationMetadataResponse{ return connect.NewResponse(&v2beta_org.DeleteOrganizationMetadataResponse{
DeletionDate: timestamppb.New(result.EventDate), DeletionDate: timestamppb.New(result.EventDate),
}, nil }), nil
} }
func (s *Server) DeactivateOrganization(ctx context.Context, request *org.DeactivateOrganizationRequest) (*org.DeactivateOrganizationResponse, error) { func (s *Server) DeactivateOrganization(ctx context.Context, request *connect.Request[org.DeactivateOrganizationRequest]) (*connect.Response[org.DeactivateOrganizationResponse], error) {
objectDetails, err := s.command.DeactivateOrg(ctx, request.Id) objectDetails, err := s.command.DeactivateOrg(ctx, request.Msg.GetId())
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &org.DeactivateOrganizationResponse{ return connect.NewResponse(&org.DeactivateOrganizationResponse{
ChangeDate: timestamppb.New(objectDetails.EventDate), ChangeDate: timestamppb.New(objectDetails.EventDate),
}, nil }), nil
} }
func (s *Server) ActivateOrganization(ctx context.Context, request *org.ActivateOrganizationRequest) (*org.ActivateOrganizationResponse, error) { func (s *Server) ActivateOrganization(ctx context.Context, request *connect.Request[org.ActivateOrganizationRequest]) (*connect.Response[org.ActivateOrganizationResponse], error) {
objectDetails, err := s.command.ReactivateOrg(ctx, request.Id) objectDetails, err := s.command.ReactivateOrg(ctx, request.Msg.GetId())
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &org.ActivateOrganizationResponse{ return connect.NewResponse(&org.ActivateOrganizationResponse{
ChangeDate: timestamppb.New(objectDetails.EventDate), ChangeDate: timestamppb.New(objectDetails.EventDate),
}, err }), err
} }
func (s *Server) AddOrganizationDomain(ctx context.Context, request *org.AddOrganizationDomainRequest) (*org.AddOrganizationDomainResponse, error) { func (s *Server) AddOrganizationDomain(ctx context.Context, request *connect.Request[org.AddOrganizationDomainRequest]) (*connect.Response[org.AddOrganizationDomainResponse], error) {
userIDs, err := s.getClaimedUserIDsOfOrgDomain(ctx, request.Domain, request.OrganizationId) userIDs, err := s.getClaimedUserIDsOfOrgDomain(ctx, request.Msg.GetDomain(), request.Msg.GetOrganizationId())
if err != nil { if err != nil {
return nil, err return nil, err
} }
details, err := s.command.AddOrgDomain(ctx, request.OrganizationId, request.Domain, userIDs) details, err := s.command.AddOrgDomain(ctx, request.Msg.GetOrganizationId(), request.Msg.GetDomain(), userIDs)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &org.AddOrganizationDomainResponse{ return connect.NewResponse(&org.AddOrganizationDomainResponse{
CreationDate: timestamppb.New(details.EventDate), CreationDate: timestamppb.New(details.EventDate),
}, nil }), nil
} }
func (s *Server) ListOrganizationDomains(ctx context.Context, req *org.ListOrganizationDomainsRequest) (*org.ListOrganizationDomainsResponse, error) { func (s *Server) ListOrganizationDomains(ctx context.Context, req *connect.Request[org.ListOrganizationDomainsRequest]) (*connect.Response[org.ListOrganizationDomainsResponse], error) {
queries, err := ListOrgDomainsRequestToModel(s.systemDefaults, req) queries, err := ListOrgDomainsRequestToModel(s.systemDefaults, req.Msg)
if err != nil { if err != nil {
return nil, err return nil, err
} }
orgIDQuery, err := query.NewOrgDomainOrgIDSearchQuery(req.OrganizationId) orgIDQuery, err := query.NewOrgDomainOrgIDSearchQuery(req.Msg.GetOrganizationId())
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -159,48 +160,48 @@ func (s *Server) ListOrganizationDomains(ctx context.Context, req *org.ListOrgan
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &org.ListOrganizationDomainsResponse{ return connect.NewResponse(&org.ListOrganizationDomainsResponse{
Domains: object.DomainsToPb(domains.Domains), Domains: object.DomainsToPb(domains.Domains),
Pagination: &filter.PaginationResponse{ Pagination: &filter.PaginationResponse{
TotalResult: domains.Count, TotalResult: domains.Count,
AppliedLimit: uint64(req.GetPagination().GetLimit()), AppliedLimit: uint64(req.Msg.GetPagination().GetLimit()),
}, },
}, nil }), nil
} }
func (s *Server) DeleteOrganizationDomain(ctx context.Context, req *org.DeleteOrganizationDomainRequest) (*org.DeleteOrganizationDomainResponse, error) { func (s *Server) DeleteOrganizationDomain(ctx context.Context, req *connect.Request[org.DeleteOrganizationDomainRequest]) (*connect.Response[org.DeleteOrganizationDomainResponse], error) {
details, err := s.command.RemoveOrgDomain(ctx, RemoveOrgDomainRequestToDomain(ctx, req)) details, err := s.command.RemoveOrgDomain(ctx, RemoveOrgDomainRequestToDomain(ctx, req.Msg))
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &org.DeleteOrganizationDomainResponse{ return connect.NewResponse(&org.DeleteOrganizationDomainResponse{
DeletionDate: timestamppb.New(details.EventDate), DeletionDate: timestamppb.New(details.EventDate),
}, err }), err
} }
func (s *Server) GenerateOrganizationDomainValidation(ctx context.Context, req *org.GenerateOrganizationDomainValidationRequest) (*org.GenerateOrganizationDomainValidationResponse, error) { func (s *Server) GenerateOrganizationDomainValidation(ctx context.Context, req *connect.Request[org.GenerateOrganizationDomainValidationRequest]) (*connect.Response[org.GenerateOrganizationDomainValidationResponse], error) {
token, url, err := s.command.GenerateOrgDomainValidation(ctx, GenerateOrgDomainValidationRequestToDomain(ctx, req)) token, url, err := s.command.GenerateOrgDomainValidation(ctx, GenerateOrgDomainValidationRequestToDomain(ctx, req.Msg))
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &org.GenerateOrganizationDomainValidationResponse{ return connect.NewResponse(&org.GenerateOrganizationDomainValidationResponse{
Token: token, Token: token,
Url: url, Url: url,
}, nil }), nil
} }
func (s *Server) VerifyOrganizationDomain(ctx context.Context, request *org.VerifyOrganizationDomainRequest) (*org.VerifyOrganizationDomainResponse, error) { func (s *Server) VerifyOrganizationDomain(ctx context.Context, request *connect.Request[org.VerifyOrganizationDomainRequest]) (*connect.Response[org.VerifyOrganizationDomainResponse], error) {
userIDs, err := s.getClaimedUserIDsOfOrgDomain(ctx, request.Domain, request.OrganizationId) userIDs, err := s.getClaimedUserIDsOfOrgDomain(ctx, request.Msg.GetDomain(), request.Msg.GetOrganizationId())
if err != nil { if err != nil {
return nil, err return nil, err
} }
details, err := s.command.ValidateOrgDomain(ctx, ValidateOrgDomainRequestToDomain(ctx, request), userIDs) details, err := s.command.ValidateOrgDomain(ctx, ValidateOrgDomainRequestToDomain(ctx, request.Msg), userIDs)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &org.VerifyOrganizationDomainResponse{ return connect.NewResponse(&org.VerifyOrganizationDomainResponse{
ChangeDate: timestamppb.New(details.EventDate), ChangeDate: timestamppb.New(details.EventDate),
}, nil }), nil
} }
func createOrganizationRequestToCommand(request *v2beta_org.CreateOrganizationRequest) (*command.OrgSetup, error) { func createOrganizationRequestToCommand(request *v2beta_org.CreateOrganizationRequest) (*command.OrgSetup, error) {

View File

@@ -4,6 +4,7 @@ import (
"testing" "testing"
"time" "time"
"connectrpc.com/connect"
"github.com/muhlemmer/gu" "github.com/muhlemmer/gu"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
@@ -138,7 +139,7 @@ func Test_createdOrganizationToPb(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
args args args args
want *org.CreateOrganizationResponse want *connect.Response[org.CreateOrganizationResponse]
wantErr error wantErr error
}{ }{
{ {
@@ -159,7 +160,7 @@ func Test_createdOrganizationToPb(t *testing.T) {
}, },
}, },
}, },
want: &org.CreateOrganizationResponse{ want: connect.NewResponse(&org.CreateOrganizationResponse{
CreationDate: timestamppb.New(now), CreationDate: timestamppb.New(now),
Id: "orgID", Id: "orgID",
OrganizationAdmins: []*org.OrganizationAdmin{ OrganizationAdmins: []*org.OrganizationAdmin{
@@ -173,7 +174,7 @@ func Test_createdOrganizationToPb(t *testing.T) {
}, },
}, },
}, },
}, }),
}, },
} }
for _, tt := range tests { for _, tt := range tests {

View File

@@ -1,7 +1,10 @@
package org package org
import ( import (
"google.golang.org/grpc" "net/http"
"connectrpc.com/connect"
"google.golang.org/protobuf/reflect/protoreflect"
"github.com/zitadel/zitadel/internal/api/authz" "github.com/zitadel/zitadel/internal/api/authz"
"github.com/zitadel/zitadel/internal/api/grpc/server" "github.com/zitadel/zitadel/internal/api/grpc/server"
@@ -10,12 +13,12 @@ import (
"github.com/zitadel/zitadel/internal/domain" "github.com/zitadel/zitadel/internal/domain"
"github.com/zitadel/zitadel/internal/query" "github.com/zitadel/zitadel/internal/query"
org "github.com/zitadel/zitadel/pkg/grpc/org/v2beta" org "github.com/zitadel/zitadel/pkg/grpc/org/v2beta"
"github.com/zitadel/zitadel/pkg/grpc/org/v2beta/orgconnect"
) )
var _ org.OrganizationServiceServer = (*Server)(nil) var _ orgconnect.OrganizationServiceHandler = (*Server)(nil)
type Server struct { type Server struct {
org.UnimplementedOrganizationServiceServer
systemDefaults systemdefaults.SystemDefaults systemDefaults systemdefaults.SystemDefaults
command *command.Commands command *command.Commands
query *query.Queries query *query.Queries
@@ -38,8 +41,12 @@ func CreateServer(
} }
} }
func (s *Server) RegisterServer(grpcServer *grpc.Server) { func (s *Server) RegisterConnectServer(interceptors ...connect.Interceptor) (string, http.Handler) {
org.RegisterOrganizationServiceServer(grpcServer, s) return orgconnect.NewOrganizationServiceHandler(s, connect.WithInterceptors(interceptors...))
}
func (s *Server) FileDescriptor() protoreflect.FileDescriptor {
return org.File_zitadel_org_v2beta_org_service_proto
} }
func (s *Server) AppName() string { func (s *Server) AppName() string {

View File

@@ -3,6 +3,7 @@ package project
import ( import (
"context" "context"
"connectrpc.com/connect"
"github.com/muhlemmer/gu" "github.com/muhlemmer/gu"
"google.golang.org/protobuf/types/known/timestamppb" "google.golang.org/protobuf/types/known/timestamppb"
@@ -13,8 +14,8 @@ import (
project_pb "github.com/zitadel/zitadel/pkg/grpc/project/v2beta" project_pb "github.com/zitadel/zitadel/pkg/grpc/project/v2beta"
) )
func (s *Server) CreateProject(ctx context.Context, req *project_pb.CreateProjectRequest) (*project_pb.CreateProjectResponse, error) { func (s *Server) CreateProject(ctx context.Context, req *connect.Request[project_pb.CreateProjectRequest]) (*connect.Response[project_pb.CreateProjectResponse], error) {
add := projectCreateToCommand(req) add := projectCreateToCommand(req.Msg)
project, err := s.command.AddProject(ctx, add) project, err := s.command.AddProject(ctx, add)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -23,10 +24,10 @@ func (s *Server) CreateProject(ctx context.Context, req *project_pb.CreateProjec
if !project.EventDate.IsZero() { if !project.EventDate.IsZero() {
creationDate = timestamppb.New(project.EventDate) creationDate = timestamppb.New(project.EventDate)
} }
return &project_pb.CreateProjectResponse{ return connect.NewResponse(&project_pb.CreateProjectResponse{
Id: add.AggregateID, Id: add.AggregateID,
CreationDate: creationDate, CreationDate: creationDate,
}, nil }), nil
} }
func projectCreateToCommand(req *project_pb.CreateProjectRequest) *command.AddProject { func projectCreateToCommand(req *project_pb.CreateProjectRequest) *command.AddProject {
@@ -60,8 +61,8 @@ func privateLabelingSettingToDomain(setting project_pb.PrivateLabelingSetting) d
} }
} }
func (s *Server) UpdateProject(ctx context.Context, req *project_pb.UpdateProjectRequest) (*project_pb.UpdateProjectResponse, error) { func (s *Server) UpdateProject(ctx context.Context, req *connect.Request[project_pb.UpdateProjectRequest]) (*connect.Response[project_pb.UpdateProjectResponse], error) {
project, err := s.command.ChangeProject(ctx, projectUpdateToCommand(req)) project, err := s.command.ChangeProject(ctx, projectUpdateToCommand(req.Msg))
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -69,9 +70,9 @@ func (s *Server) UpdateProject(ctx context.Context, req *project_pb.UpdateProjec
if !project.EventDate.IsZero() { if !project.EventDate.IsZero() {
changeDate = timestamppb.New(project.EventDate) changeDate = timestamppb.New(project.EventDate)
} }
return &project_pb.UpdateProjectResponse{ return connect.NewResponse(&project_pb.UpdateProjectResponse{
ChangeDate: changeDate, ChangeDate: changeDate,
}, nil }), nil
} }
func projectUpdateToCommand(req *project_pb.UpdateProjectRequest) *command.ChangeProject { func projectUpdateToCommand(req *project_pb.UpdateProjectRequest) *command.ChangeProject {
@@ -91,13 +92,13 @@ func projectUpdateToCommand(req *project_pb.UpdateProjectRequest) *command.Chang
} }
} }
func (s *Server) DeleteProject(ctx context.Context, req *project_pb.DeleteProjectRequest) (*project_pb.DeleteProjectResponse, error) { func (s *Server) DeleteProject(ctx context.Context, req *connect.Request[project_pb.DeleteProjectRequest]) (*connect.Response[project_pb.DeleteProjectResponse], error) {
userGrantIDs, err := s.userGrantsFromProject(ctx, req.Id) userGrantIDs, err := s.userGrantsFromProject(ctx, req.Msg.GetId())
if err != nil { if err != nil {
return nil, err return nil, err
} }
deletedAt, err := s.command.DeleteProject(ctx, req.Id, "", userGrantIDs...) deletedAt, err := s.command.DeleteProject(ctx, req.Msg.GetId(), "", userGrantIDs...)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -105,9 +106,9 @@ func (s *Server) DeleteProject(ctx context.Context, req *project_pb.DeleteProjec
if !deletedAt.IsZero() { if !deletedAt.IsZero() {
deletionDate = timestamppb.New(deletedAt) deletionDate = timestamppb.New(deletedAt)
} }
return &project_pb.DeleteProjectResponse{ return connect.NewResponse(&project_pb.DeleteProjectResponse{
DeletionDate: deletionDate, DeletionDate: deletionDate,
}, nil }), nil
} }
func (s *Server) userGrantsFromProject(ctx context.Context, projectID string) ([]string, error) { func (s *Server) userGrantsFromProject(ctx context.Context, projectID string) ([]string, error) {
@@ -124,8 +125,8 @@ func (s *Server) userGrantsFromProject(ctx context.Context, projectID string) ([
return userGrantsToIDs(userGrants.UserGrants), nil return userGrantsToIDs(userGrants.UserGrants), nil
} }
func (s *Server) DeactivateProject(ctx context.Context, req *project_pb.DeactivateProjectRequest) (*project_pb.DeactivateProjectResponse, error) { func (s *Server) DeactivateProject(ctx context.Context, req *connect.Request[project_pb.DeactivateProjectRequest]) (*connect.Response[project_pb.DeactivateProjectResponse], error) {
details, err := s.command.DeactivateProject(ctx, req.Id, "") details, err := s.command.DeactivateProject(ctx, req.Msg.GetId(), "")
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -133,13 +134,13 @@ func (s *Server) DeactivateProject(ctx context.Context, req *project_pb.Deactiva
if !details.EventDate.IsZero() { if !details.EventDate.IsZero() {
changeDate = timestamppb.New(details.EventDate) changeDate = timestamppb.New(details.EventDate)
} }
return &project_pb.DeactivateProjectResponse{ return connect.NewResponse(&project_pb.DeactivateProjectResponse{
ChangeDate: changeDate, ChangeDate: changeDate,
}, nil }), nil
} }
func (s *Server) ActivateProject(ctx context.Context, req *project_pb.ActivateProjectRequest) (*project_pb.ActivateProjectResponse, error) { func (s *Server) ActivateProject(ctx context.Context, req *connect.Request[project_pb.ActivateProjectRequest]) (*connect.Response[project_pb.ActivateProjectResponse], error) {
details, err := s.command.ReactivateProject(ctx, req.Id, "") details, err := s.command.ReactivateProject(ctx, req.Msg.GetId(), "")
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -147,9 +148,9 @@ func (s *Server) ActivateProject(ctx context.Context, req *project_pb.ActivatePr
if !details.EventDate.IsZero() { if !details.EventDate.IsZero() {
changeDate = timestamppb.New(details.EventDate) changeDate = timestamppb.New(details.EventDate)
} }
return &project_pb.ActivateProjectResponse{ return connect.NewResponse(&project_pb.ActivateProjectResponse{
ChangeDate: changeDate, ChangeDate: changeDate,
}, nil }), nil
} }
func userGrantsToIDs(userGrants []*query.UserGrant) []string { func userGrantsToIDs(userGrants []*query.UserGrant) []string {

View File

@@ -3,6 +3,7 @@ package project
import ( import (
"context" "context"
"connectrpc.com/connect"
"google.golang.org/protobuf/types/known/timestamppb" "google.golang.org/protobuf/types/known/timestamppb"
"github.com/zitadel/zitadel/internal/command" "github.com/zitadel/zitadel/internal/command"
@@ -11,8 +12,8 @@ import (
project_pb "github.com/zitadel/zitadel/pkg/grpc/project/v2beta" project_pb "github.com/zitadel/zitadel/pkg/grpc/project/v2beta"
) )
func (s *Server) CreateProjectGrant(ctx context.Context, req *project_pb.CreateProjectGrantRequest) (*project_pb.CreateProjectGrantResponse, error) { func (s *Server) CreateProjectGrant(ctx context.Context, req *connect.Request[project_pb.CreateProjectGrantRequest]) (*connect.Response[project_pb.CreateProjectGrantResponse], error) {
add := projectGrantCreateToCommand(req) add := projectGrantCreateToCommand(req.Msg)
project, err := s.command.AddProjectGrant(ctx, add) project, err := s.command.AddProjectGrant(ctx, add)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -21,9 +22,9 @@ func (s *Server) CreateProjectGrant(ctx context.Context, req *project_pb.CreateP
if !project.EventDate.IsZero() { if !project.EventDate.IsZero() {
creationDate = timestamppb.New(project.EventDate) creationDate = timestamppb.New(project.EventDate)
} }
return &project_pb.CreateProjectGrantResponse{ return connect.NewResponse(&project_pb.CreateProjectGrantResponse{
CreationDate: creationDate, CreationDate: creationDate,
}, nil }), nil
} }
func projectGrantCreateToCommand(req *project_pb.CreateProjectGrantRequest) *command.AddProjectGrant { func projectGrantCreateToCommand(req *project_pb.CreateProjectGrantRequest) *command.AddProjectGrant {
@@ -37,8 +38,8 @@ func projectGrantCreateToCommand(req *project_pb.CreateProjectGrantRequest) *com
} }
} }
func (s *Server) UpdateProjectGrant(ctx context.Context, req *project_pb.UpdateProjectGrantRequest) (*project_pb.UpdateProjectGrantResponse, error) { func (s *Server) UpdateProjectGrant(ctx context.Context, req *connect.Request[project_pb.UpdateProjectGrantRequest]) (*connect.Response[project_pb.UpdateProjectGrantResponse], error) {
project, err := s.command.ChangeProjectGrant(ctx, projectGrantUpdateToCommand(req)) project, err := s.command.ChangeProjectGrant(ctx, projectGrantUpdateToCommand(req.Msg))
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -46,9 +47,9 @@ func (s *Server) UpdateProjectGrant(ctx context.Context, req *project_pb.UpdateP
if !project.EventDate.IsZero() { if !project.EventDate.IsZero() {
changeDate = timestamppb.New(project.EventDate) changeDate = timestamppb.New(project.EventDate)
} }
return &project_pb.UpdateProjectGrantResponse{ return connect.NewResponse(&project_pb.UpdateProjectGrantResponse{
ChangeDate: changeDate, ChangeDate: changeDate,
}, nil }), nil
} }
func projectGrantUpdateToCommand(req *project_pb.UpdateProjectGrantRequest) *command.ChangeProjectGrant { func projectGrantUpdateToCommand(req *project_pb.UpdateProjectGrantRequest) *command.ChangeProjectGrant {
@@ -61,8 +62,8 @@ func projectGrantUpdateToCommand(req *project_pb.UpdateProjectGrantRequest) *com
} }
} }
func (s *Server) DeactivateProjectGrant(ctx context.Context, req *project_pb.DeactivateProjectGrantRequest) (*project_pb.DeactivateProjectGrantResponse, error) { func (s *Server) DeactivateProjectGrant(ctx context.Context, req *connect.Request[project_pb.DeactivateProjectGrantRequest]) (*connect.Response[project_pb.DeactivateProjectGrantResponse], error) {
details, err := s.command.DeactivateProjectGrant(ctx, req.ProjectId, "", req.GrantedOrganizationId, "") details, err := s.command.DeactivateProjectGrant(ctx, req.Msg.GetProjectId(), "", req.Msg.GetGrantedOrganizationId(), "")
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -70,13 +71,13 @@ func (s *Server) DeactivateProjectGrant(ctx context.Context, req *project_pb.Dea
if !details.EventDate.IsZero() { if !details.EventDate.IsZero() {
changeDate = timestamppb.New(details.EventDate) changeDate = timestamppb.New(details.EventDate)
} }
return &project_pb.DeactivateProjectGrantResponse{ return connect.NewResponse(&project_pb.DeactivateProjectGrantResponse{
ChangeDate: changeDate, ChangeDate: changeDate,
}, nil }), nil
} }
func (s *Server) ActivateProjectGrant(ctx context.Context, req *project_pb.ActivateProjectGrantRequest) (*project_pb.ActivateProjectGrantResponse, error) { func (s *Server) ActivateProjectGrant(ctx context.Context, req *connect.Request[project_pb.ActivateProjectGrantRequest]) (*connect.Response[project_pb.ActivateProjectGrantResponse], error) {
details, err := s.command.ReactivateProjectGrant(ctx, req.ProjectId, "", req.GrantedOrganizationId, "") details, err := s.command.ReactivateProjectGrant(ctx, req.Msg.GetProjectId(), "", req.Msg.GetGrantedOrganizationId(), "")
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -84,17 +85,17 @@ func (s *Server) ActivateProjectGrant(ctx context.Context, req *project_pb.Activ
if !details.EventDate.IsZero() { if !details.EventDate.IsZero() {
changeDate = timestamppb.New(details.EventDate) changeDate = timestamppb.New(details.EventDate)
} }
return &project_pb.ActivateProjectGrantResponse{ return connect.NewResponse(&project_pb.ActivateProjectGrantResponse{
ChangeDate: changeDate, ChangeDate: changeDate,
}, nil }), nil
} }
func (s *Server) DeleteProjectGrant(ctx context.Context, req *project_pb.DeleteProjectGrantRequest) (*project_pb.DeleteProjectGrantResponse, error) { func (s *Server) DeleteProjectGrant(ctx context.Context, req *connect.Request[project_pb.DeleteProjectGrantRequest]) (*connect.Response[project_pb.DeleteProjectGrantResponse], error) {
userGrantIDs, err := s.userGrantsFromProjectGrant(ctx, req.ProjectId, req.GrantedOrganizationId) userGrantIDs, err := s.userGrantsFromProjectGrant(ctx, req.Msg.GetProjectId(), req.Msg.GetGrantedOrganizationId())
if err != nil { if err != nil {
return nil, err return nil, err
} }
details, err := s.command.DeleteProjectGrant(ctx, req.ProjectId, "", req.GrantedOrganizationId, "", userGrantIDs...) details, err := s.command.DeleteProjectGrant(ctx, req.Msg.GetProjectId(), "", req.Msg.GetGrantedOrganizationId(), "", userGrantIDs...)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -102,9 +103,9 @@ func (s *Server) DeleteProjectGrant(ctx context.Context, req *project_pb.DeleteP
if !details.EventDate.IsZero() { if !details.EventDate.IsZero() {
deletionDate = timestamppb.New(details.EventDate) deletionDate = timestamppb.New(details.EventDate)
} }
return &project_pb.DeleteProjectGrantResponse{ return connect.NewResponse(&project_pb.DeleteProjectGrantResponse{
DeletionDate: deletionDate, DeletionDate: deletionDate,
}, nil }), nil
} }
func (s *Server) userGrantsFromProjectGrant(ctx context.Context, projectID, grantedOrganizationID string) ([]string, error) { func (s *Server) userGrantsFromProjectGrant(ctx context.Context, projectID, grantedOrganizationID string) ([]string, error) {

View File

@@ -3,6 +3,7 @@ package project
import ( import (
"context" "context"
"connectrpc.com/connect"
"google.golang.org/protobuf/types/known/timestamppb" "google.golang.org/protobuf/types/known/timestamppb"
"github.com/zitadel/zitadel/internal/command" "github.com/zitadel/zitadel/internal/command"
@@ -11,8 +12,8 @@ import (
project_pb "github.com/zitadel/zitadel/pkg/grpc/project/v2beta" project_pb "github.com/zitadel/zitadel/pkg/grpc/project/v2beta"
) )
func (s *Server) AddProjectRole(ctx context.Context, req *project_pb.AddProjectRoleRequest) (*project_pb.AddProjectRoleResponse, error) { func (s *Server) AddProjectRole(ctx context.Context, req *connect.Request[project_pb.AddProjectRoleRequest]) (*connect.Response[project_pb.AddProjectRoleResponse], error) {
role, err := s.command.AddProjectRole(ctx, addProjectRoleRequestToCommand(req)) role, err := s.command.AddProjectRole(ctx, addProjectRoleRequestToCommand(req.Msg))
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -20,9 +21,9 @@ func (s *Server) AddProjectRole(ctx context.Context, req *project_pb.AddProjectR
if !role.EventDate.IsZero() { if !role.EventDate.IsZero() {
creationDate = timestamppb.New(role.EventDate) creationDate = timestamppb.New(role.EventDate)
} }
return &project_pb.AddProjectRoleResponse{ return connect.NewResponse(&project_pb.AddProjectRoleResponse{
CreationDate: creationDate, CreationDate: creationDate,
}, nil }), nil
} }
func addProjectRoleRequestToCommand(req *project_pb.AddProjectRoleRequest) *command.AddProjectRole { func addProjectRoleRequestToCommand(req *project_pb.AddProjectRoleRequest) *command.AddProjectRole {
@@ -41,8 +42,8 @@ func addProjectRoleRequestToCommand(req *project_pb.AddProjectRoleRequest) *comm
} }
} }
func (s *Server) UpdateProjectRole(ctx context.Context, req *project_pb.UpdateProjectRoleRequest) (*project_pb.UpdateProjectRoleResponse, error) { func (s *Server) UpdateProjectRole(ctx context.Context, req *connect.Request[project_pb.UpdateProjectRoleRequest]) (*connect.Response[project_pb.UpdateProjectRoleResponse], error) {
role, err := s.command.ChangeProjectRole(ctx, updateProjectRoleRequestToCommand(req)) role, err := s.command.ChangeProjectRole(ctx, updateProjectRoleRequestToCommand(req.Msg))
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -50,9 +51,9 @@ func (s *Server) UpdateProjectRole(ctx context.Context, req *project_pb.UpdatePr
if !role.EventDate.IsZero() { if !role.EventDate.IsZero() {
changeDate = timestamppb.New(role.EventDate) changeDate = timestamppb.New(role.EventDate)
} }
return &project_pb.UpdateProjectRoleResponse{ return connect.NewResponse(&project_pb.UpdateProjectRoleResponse{
ChangeDate: changeDate, ChangeDate: changeDate,
}, nil }), nil
} }
func updateProjectRoleRequestToCommand(req *project_pb.UpdateProjectRoleRequest) *command.ChangeProjectRole { func updateProjectRoleRequestToCommand(req *project_pb.UpdateProjectRoleRequest) *command.ChangeProjectRole {
@@ -75,16 +76,16 @@ func updateProjectRoleRequestToCommand(req *project_pb.UpdateProjectRoleRequest)
} }
} }
func (s *Server) RemoveProjectRole(ctx context.Context, req *project_pb.RemoveProjectRoleRequest) (*project_pb.RemoveProjectRoleResponse, error) { func (s *Server) RemoveProjectRole(ctx context.Context, req *connect.Request[project_pb.RemoveProjectRoleRequest]) (*connect.Response[project_pb.RemoveProjectRoleResponse], error) {
userGrantIDs, err := s.userGrantsFromProjectAndRole(ctx, req.ProjectId, req.RoleKey) userGrantIDs, err := s.userGrantsFromProjectAndRole(ctx, req.Msg.GetProjectId(), req.Msg.GetRoleKey())
if err != nil { if err != nil {
return nil, err return nil, err
} }
projectGrantIDs, err := s.projectGrantsFromProjectAndRole(ctx, req.ProjectId, req.RoleKey) projectGrantIDs, err := s.projectGrantsFromProjectAndRole(ctx, req.Msg.GetProjectId(), req.Msg.GetRoleKey())
if err != nil { if err != nil {
return nil, err return nil, err
} }
details, err := s.command.RemoveProjectRole(ctx, req.ProjectId, req.RoleKey, "", projectGrantIDs, userGrantIDs...) details, err := s.command.RemoveProjectRole(ctx, req.Msg.GetProjectId(), req.Msg.GetRoleKey(), "", projectGrantIDs, userGrantIDs...)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -92,9 +93,9 @@ func (s *Server) RemoveProjectRole(ctx context.Context, req *project_pb.RemovePr
if !details.EventDate.IsZero() { if !details.EventDate.IsZero() {
deletionDate = timestamppb.New(details.EventDate) deletionDate = timestamppb.New(details.EventDate)
} }
return &project_pb.RemoveProjectRoleResponse{ return connect.NewResponse(&project_pb.RemoveProjectRoleResponse{
RemovalDate: deletionDate, RemovalDate: deletionDate,
}, nil }), nil
} }
func (s *Server) userGrantsFromProjectAndRole(ctx context.Context, projectID, roleKey string) ([]string, error) { func (s *Server) userGrantsFromProjectAndRole(ctx context.Context, projectID, roleKey string) ([]string, error) {

View File

@@ -3,6 +3,7 @@ package project
import ( import (
"context" "context"
"connectrpc.com/connect"
"google.golang.org/protobuf/types/known/timestamppb" "google.golang.org/protobuf/types/known/timestamppb"
filter "github.com/zitadel/zitadel/internal/api/grpc/filter/v2beta" filter "github.com/zitadel/zitadel/internal/api/grpc/filter/v2beta"
@@ -13,18 +14,18 @@ import (
project_pb "github.com/zitadel/zitadel/pkg/grpc/project/v2beta" project_pb "github.com/zitadel/zitadel/pkg/grpc/project/v2beta"
) )
func (s *Server) GetProject(ctx context.Context, req *project_pb.GetProjectRequest) (*project_pb.GetProjectResponse, error) { func (s *Server) GetProject(ctx context.Context, req *connect.Request[project_pb.GetProjectRequest]) (*connect.Response[project_pb.GetProjectResponse], error) {
project, err := s.query.GetProjectByIDWithPermission(ctx, true, req.Id, s.checkPermission) project, err := s.query.GetProjectByIDWithPermission(ctx, true, req.Msg.GetId(), s.checkPermission)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &project_pb.GetProjectResponse{ return connect.NewResponse(&project_pb.GetProjectResponse{
Project: projectToPb(project), Project: projectToPb(project),
}, nil }), nil
} }
func (s *Server) ListProjects(ctx context.Context, req *project_pb.ListProjectsRequest) (*project_pb.ListProjectsResponse, error) { func (s *Server) ListProjects(ctx context.Context, req *connect.Request[project_pb.ListProjectsRequest]) (*connect.Response[project_pb.ListProjectsResponse], error) {
queries, err := s.listProjectRequestToModel(req) queries, err := s.listProjectRequestToModel(req.Msg)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -32,10 +33,10 @@ func (s *Server) ListProjects(ctx context.Context, req *project_pb.ListProjectsR
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &project_pb.ListProjectsResponse{ return connect.NewResponse(&project_pb.ListProjectsResponse{
Projects: grantedProjectsToPb(resp.GrantedProjects), Projects: grantedProjectsToPb(resp.GrantedProjects),
Pagination: filter.QueryToPaginationPb(queries.SearchRequest, resp.SearchResponse), Pagination: filter.QueryToPaginationPb(queries.SearchRequest, resp.SearchResponse),
}, nil }), nil
} }
func (s *Server) listProjectRequestToModel(req *project_pb.ListProjectsRequest) (*query.ProjectAndGrantedProjectSearchQueries, error) { func (s *Server) listProjectRequestToModel(req *project_pb.ListProjectsRequest) (*query.ProjectAndGrantedProjectSearchQueries, error) {
@@ -213,8 +214,8 @@ func privateLabelingSettingToPb(setting domain.PrivateLabelingSetting) project_p
} }
} }
func (s *Server) ListProjectGrants(ctx context.Context, req *project_pb.ListProjectGrantsRequest) (*project_pb.ListProjectGrantsResponse, error) { func (s *Server) ListProjectGrants(ctx context.Context, req *connect.Request[project_pb.ListProjectGrantsRequest]) (*connect.Response[project_pb.ListProjectGrantsResponse], error) {
queries, err := s.listProjectGrantsRequestToModel(req) queries, err := s.listProjectGrantsRequestToModel(req.Msg)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -222,10 +223,10 @@ func (s *Server) ListProjectGrants(ctx context.Context, req *project_pb.ListProj
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &project_pb.ListProjectGrantsResponse{ return connect.NewResponse(&project_pb.ListProjectGrantsResponse{
ProjectGrants: projectGrantsToPb(resp.ProjectGrants), ProjectGrants: projectGrantsToPb(resp.ProjectGrants),
Pagination: filter.QueryToPaginationPb(queries.SearchRequest, resp.SearchResponse), Pagination: filter.QueryToPaginationPb(queries.SearchRequest, resp.SearchResponse),
}, nil }), nil
} }
func (s *Server) listProjectGrantsRequestToModel(req *project_pb.ListProjectGrantsRequest) (*query.ProjectGrantSearchQueries, error) { func (s *Server) listProjectGrantsRequestToModel(req *project_pb.ListProjectGrantsRequest) (*query.ProjectGrantSearchQueries, error) {
@@ -329,12 +330,12 @@ func projectGrantStateToPb(state domain.ProjectGrantState) project_pb.ProjectGra
} }
} }
func (s *Server) ListProjectRoles(ctx context.Context, req *project_pb.ListProjectRolesRequest) (*project_pb.ListProjectRolesResponse, error) { func (s *Server) ListProjectRoles(ctx context.Context, req *connect.Request[project_pb.ListProjectRolesRequest]) (*connect.Response[project_pb.ListProjectRolesResponse], error) {
queries, err := s.listProjectRolesRequestToModel(req) queries, err := s.listProjectRolesRequestToModel(req.Msg)
if err != nil { if err != nil {
return nil, err return nil, err
} }
err = queries.AppendProjectIDQuery(req.ProjectId) err = queries.AppendProjectIDQuery(req.Msg.GetProjectId())
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -342,10 +343,10 @@ func (s *Server) ListProjectRoles(ctx context.Context, req *project_pb.ListProje
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &project_pb.ListProjectRolesResponse{ return connect.NewResponse(&project_pb.ListProjectRolesResponse{
ProjectRoles: roleViewsToPb(roles.ProjectRoles), ProjectRoles: roleViewsToPb(roles.ProjectRoles),
Pagination: filter.QueryToPaginationPb(queries.SearchRequest, roles.SearchResponse), Pagination: filter.QueryToPaginationPb(queries.SearchRequest, roles.SearchResponse),
}, nil }), nil
} }
func (s *Server) listProjectRolesRequestToModel(req *project_pb.ListProjectRolesRequest) (*query.ProjectRoleSearchQueries, error) { func (s *Server) listProjectRolesRequestToModel(req *project_pb.ListProjectRolesRequest) (*query.ProjectRoleSearchQueries, error) {

View File

@@ -1,21 +1,23 @@
package project package project
import ( import (
"google.golang.org/grpc" "net/http"
"connectrpc.com/connect"
"google.golang.org/protobuf/reflect/protoreflect"
"github.com/zitadel/zitadel/internal/api/authz" "github.com/zitadel/zitadel/internal/api/authz"
"github.com/zitadel/zitadel/internal/api/grpc/server"
"github.com/zitadel/zitadel/internal/command" "github.com/zitadel/zitadel/internal/command"
"github.com/zitadel/zitadel/internal/config/systemdefaults" "github.com/zitadel/zitadel/internal/config/systemdefaults"
"github.com/zitadel/zitadel/internal/domain" "github.com/zitadel/zitadel/internal/domain"
"github.com/zitadel/zitadel/internal/query" "github.com/zitadel/zitadel/internal/query"
project "github.com/zitadel/zitadel/pkg/grpc/project/v2beta" project "github.com/zitadel/zitadel/pkg/grpc/project/v2beta"
"github.com/zitadel/zitadel/pkg/grpc/project/v2beta/projectconnect"
) )
var _ project.ProjectServiceServer = (*Server)(nil) var _ projectconnect.ProjectServiceHandler = (*Server)(nil)
type Server struct { type Server struct {
project.UnimplementedProjectServiceServer
systemDefaults systemdefaults.SystemDefaults systemDefaults systemdefaults.SystemDefaults
command *command.Commands command *command.Commands
query *query.Queries query *query.Queries
@@ -39,8 +41,12 @@ func CreateServer(
} }
} }
func (s *Server) RegisterServer(grpcServer *grpc.Server) { func (s *Server) RegisterConnectServer(interceptors ...connect.Interceptor) (string, http.Handler) {
project.RegisterProjectServiceServer(grpcServer, s) return projectconnect.NewProjectServiceHandler(s, connect.WithInterceptors(interceptors...))
}
func (s *Server) FileDescriptor() protoreflect.FileDescriptor {
return project.File_zitadel_project_v2beta_project_service_proto
} }
func (s *Server) AppName() string { func (s *Server) AppName() string {
@@ -54,7 +60,3 @@ func (s *Server) MethodPrefix() string {
func (s *Server) AuthMethods() authz.MethodMapping { func (s *Server) AuthMethods() authz.MethodMapping {
return project.ProjectService_AuthMethods return project.ProjectService_AuthMethods
} }
func (s *Server) RegisterGateway() server.RegisterGatewayFunc {
return project.RegisterProjectServiceHandler
}

View File

@@ -3,6 +3,7 @@ package saml
import ( import (
"context" "context"
"connectrpc.com/connect"
"github.com/zitadel/logging" "github.com/zitadel/logging"
"github.com/zitadel/saml/pkg/provider" "github.com/zitadel/saml/pkg/provider"
"google.golang.org/protobuf/types/known/timestamppb" "google.golang.org/protobuf/types/known/timestamppb"
@@ -16,15 +17,15 @@ import (
saml_pb "github.com/zitadel/zitadel/pkg/grpc/saml/v2" saml_pb "github.com/zitadel/zitadel/pkg/grpc/saml/v2"
) )
func (s *Server) GetSAMLRequest(ctx context.Context, req *saml_pb.GetSAMLRequestRequest) (*saml_pb.GetSAMLRequestResponse, error) { func (s *Server) GetSAMLRequest(ctx context.Context, req *connect.Request[saml_pb.GetSAMLRequestRequest]) (*connect.Response[saml_pb.GetSAMLRequestResponse], error) {
authRequest, err := s.query.SamlRequestByID(ctx, true, req.GetSamlRequestId(), true) authRequest, err := s.query.SamlRequestByID(ctx, true, req.Msg.GetSamlRequestId(), true)
if err != nil { if err != nil {
logging.WithError(err).Error("query samlRequest by ID") logging.WithError(err).Error("query samlRequest by ID")
return nil, err return nil, err
} }
return &saml_pb.GetSAMLRequestResponse{ return connect.NewResponse(&saml_pb.GetSAMLRequestResponse{
SamlRequest: samlRequestToPb(authRequest), SamlRequest: samlRequestToPb(authRequest),
}, nil }), nil
} }
func samlRequestToPb(a *query.SamlRequest) *saml_pb.SAMLRequest { func samlRequestToPb(a *query.SamlRequest) *saml_pb.SAMLRequest {
@@ -34,18 +35,18 @@ func samlRequestToPb(a *query.SamlRequest) *saml_pb.SAMLRequest {
} }
} }
func (s *Server) CreateResponse(ctx context.Context, req *saml_pb.CreateResponseRequest) (*saml_pb.CreateResponseResponse, error) { func (s *Server) CreateResponse(ctx context.Context, req *connect.Request[saml_pb.CreateResponseRequest]) (*connect.Response[saml_pb.CreateResponseResponse], error) {
switch v := req.GetResponseKind().(type) { switch v := req.Msg.GetResponseKind().(type) {
case *saml_pb.CreateResponseRequest_Error: case *saml_pb.CreateResponseRequest_Error:
return s.failSAMLRequest(ctx, req.GetSamlRequestId(), v.Error) return s.failSAMLRequest(ctx, req.Msg.GetSamlRequestId(), v.Error)
case *saml_pb.CreateResponseRequest_Session: case *saml_pb.CreateResponseRequest_Session:
return s.linkSessionToSAMLRequest(ctx, req.GetSamlRequestId(), v.Session) return s.linkSessionToSAMLRequest(ctx, req.Msg.GetSamlRequestId(), v.Session)
default: default:
return nil, zerrors.ThrowUnimplementedf(nil, "SAMLv2-0Tfak3fBS0", "verification oneOf %T in method CreateResponse not implemented", v) return nil, zerrors.ThrowUnimplementedf(nil, "SAMLv2-0Tfak3fBS0", "verification oneOf %T in method CreateResponse not implemented", v)
} }
} }
func (s *Server) failSAMLRequest(ctx context.Context, samlRequestID string, ae *saml_pb.AuthorizationError) (*saml_pb.CreateResponseResponse, error) { func (s *Server) failSAMLRequest(ctx context.Context, samlRequestID string, ae *saml_pb.AuthorizationError) (*connect.Response[saml_pb.CreateResponseResponse], error) {
details, aar, err := s.command.FailSAMLRequest(ctx, samlRequestID, errorReasonToDomain(ae.GetError())) details, aar, err := s.command.FailSAMLRequest(ctx, samlRequestID, errorReasonToDomain(ae.GetError()))
if err != nil { if err != nil {
return nil, err return nil, err
@@ -55,7 +56,7 @@ func (s *Server) failSAMLRequest(ctx context.Context, samlRequestID string, ae *
if err != nil { if err != nil {
return nil, err return nil, err
} }
return createCallbackResponseFromBinding(details, url, body, authReq.RelayState), nil return connect.NewResponse(createCallbackResponseFromBinding(details, url, body, authReq.RelayState)), nil
} }
func (s *Server) checkPermission(ctx context.Context, issuer string, userID string) error { func (s *Server) checkPermission(ctx context.Context, issuer string, userID string) error {
@@ -72,7 +73,7 @@ func (s *Server) checkPermission(ctx context.Context, issuer string, userID stri
return nil return nil
} }
func (s *Server) linkSessionToSAMLRequest(ctx context.Context, samlRequestID string, session *saml_pb.Session) (*saml_pb.CreateResponseResponse, error) { func (s *Server) linkSessionToSAMLRequest(ctx context.Context, samlRequestID string, session *saml_pb.Session) (*connect.Response[saml_pb.CreateResponseResponse], error) {
details, aar, err := s.command.LinkSessionToSAMLRequest(ctx, samlRequestID, session.GetSessionId(), session.GetSessionToken(), true, s.checkPermission) details, aar, err := s.command.LinkSessionToSAMLRequest(ctx, samlRequestID, session.GetSessionId(), session.GetSessionToken(), true, s.checkPermission)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -87,7 +88,7 @@ func (s *Server) linkSessionToSAMLRequest(ctx context.Context, samlRequestID str
if err != nil { if err != nil {
return nil, err return nil, err
} }
return createCallbackResponseFromBinding(details, url, body, authReq.RelayState), nil return connect.NewResponse(createCallbackResponseFromBinding(details, url, body, authReq.RelayState)), nil
} }
func createCallbackResponseFromBinding(details *domain.ObjectDetails, url string, body string, relayState string) *saml_pb.CreateResponseResponse { func createCallbackResponseFromBinding(details *domain.ObjectDetails, url string, body string, relayState string) *saml_pb.CreateResponseResponse {

View File

@@ -1,7 +1,10 @@
package saml package saml
import ( import (
"google.golang.org/grpc" "net/http"
"connectrpc.com/connect"
"google.golang.org/protobuf/reflect/protoreflect"
"github.com/zitadel/zitadel/internal/api/authz" "github.com/zitadel/zitadel/internal/api/authz"
"github.com/zitadel/zitadel/internal/api/grpc/server" "github.com/zitadel/zitadel/internal/api/grpc/server"
@@ -9,9 +12,10 @@ import (
"github.com/zitadel/zitadel/internal/command" "github.com/zitadel/zitadel/internal/command"
"github.com/zitadel/zitadel/internal/query" "github.com/zitadel/zitadel/internal/query"
saml_pb "github.com/zitadel/zitadel/pkg/grpc/saml/v2" saml_pb "github.com/zitadel/zitadel/pkg/grpc/saml/v2"
"github.com/zitadel/zitadel/pkg/grpc/saml/v2/samlconnect"
) )
var _ saml_pb.SAMLServiceServer = (*Server)(nil) var _ samlconnect.SAMLServiceHandler = (*Server)(nil)
type Server struct { type Server struct {
saml_pb.UnimplementedSAMLServiceServer saml_pb.UnimplementedSAMLServiceServer
@@ -38,8 +42,12 @@ func CreateServer(
} }
} }
func (s *Server) RegisterServer(grpcServer *grpc.Server) { func (s *Server) RegisterConnectServer(interceptors ...connect.Interceptor) (string, http.Handler) {
saml_pb.RegisterSAMLServiceServer(grpcServer, s) return samlconnect.NewSAMLServiceHandler(s, connect.WithInterceptors(interceptors...))
}
func (s *Server) FileDescriptor() protoreflect.FileDescriptor {
return saml_pb.File_zitadel_saml_v2_saml_service_proto
} }
func (s *Server) AppName() string { func (s *Server) AppName() string {

View File

@@ -0,0 +1,57 @@
package connect_middleware
import (
"context"
"net/http"
"time"
"connectrpc.com/connect"
"github.com/zitadel/zitadel/internal/api/authz"
http_util "github.com/zitadel/zitadel/internal/api/http"
"github.com/zitadel/zitadel/internal/logstore"
"github.com/zitadel/zitadel/internal/logstore/record"
"github.com/zitadel/zitadel/internal/telemetry/tracing"
)
func AccessStorageInterceptor(svc *logstore.Service[*record.AccessLog]) connect.UnaryInterceptorFunc {
return func(handler connect.UnaryFunc) connect.UnaryFunc {
return func(ctx context.Context, req connect.AnyRequest) (_ connect.AnyResponse, err error) {
if !svc.Enabled() {
return handler(ctx, req)
}
resp, handlerErr := handler(ctx, req)
interceptorCtx, span := tracing.NewServerInterceptorSpan(ctx)
defer func() { span.EndWithError(err) }()
var respStatus uint32
if code := connect.CodeOf(handlerErr); code != connect.CodeUnknown {
respStatus = uint32(code)
}
respHeader := http.Header{}
if resp != nil {
respHeader = resp.Header()
}
instance := authz.GetInstance(ctx)
domainCtx := http_util.DomainContext(ctx)
r := &record.AccessLog{
LogDate: time.Now(),
Protocol: record.GRPC,
RequestURL: req.Spec().Procedure,
ResponseStatus: respStatus,
RequestHeaders: req.Header(),
ResponseHeaders: respHeader,
InstanceID: instance.InstanceID(),
ProjectID: instance.ProjectID(),
RequestedDomain: domainCtx.RequestedDomain(),
RequestedHost: domainCtx.RequestedHost(),
}
svc.Handle(interceptorCtx, r)
return resp, handlerErr
}
}
}

View File

@@ -0,0 +1,52 @@
package connect_middleware
import (
"context"
"net/http"
"slices"
"strings"
"connectrpc.com/connect"
"github.com/zitadel/zitadel/internal/activity"
"github.com/zitadel/zitadel/internal/api/grpc/gerrors"
ainfo "github.com/zitadel/zitadel/internal/api/info"
)
func ActivityInterceptor() connect.UnaryInterceptorFunc {
return func(handler connect.UnaryFunc) connect.UnaryFunc {
return func(ctx context.Context, req connect.AnyRequest) (connect.AnyResponse, error) {
ctx = activityInfoFromGateway(ctx, req.Header()).SetMethod(req.Spec().Procedure).IntoContext(ctx)
resp, err := handler(ctx, req)
if isResourceAPI(req.Spec().Procedure) {
code, _, _, _ := gerrors.ExtractZITADELError(err)
ctx = ainfo.ActivityInfoFromContext(ctx).SetGRPCStatus(code).IntoContext(ctx)
activity.TriggerGRPCWithContext(ctx, activity.ResourceAPI)
}
return resp, err
}
}
}
var resourcePrefixes = []string{
"/zitadel.management.v1.ManagementService/",
"/zitadel.admin.v1.AdminService/",
"/zitadel.user.v2.UserService/",
"/zitadel.settings.v2.SettingsService/",
"/zitadel.user.v2beta.UserService/",
"/zitadel.settings.v2beta.SettingsService/",
"/zitadel.auth.v1.AuthService/",
}
func isResourceAPI(method string) bool {
return slices.ContainsFunc(resourcePrefixes, func(prefix string) bool {
return strings.HasPrefix(method, prefix)
})
}
func activityInfoFromGateway(ctx context.Context, headers http.Header) *ainfo.ActivityInfo {
info := ainfo.ActivityInfoFromContext(ctx)
path := headers.Get(activity.PathKey)
requestMethod := headers.Get(activity.RequestMethodKey)
return info.SetPath(path).SetRequestMethod(requestMethod)
}

View File

@@ -0,0 +1,65 @@
package connect_middleware
import (
"context"
"errors"
"connectrpc.com/connect"
"github.com/zitadel/zitadel/internal/api/authz"
"github.com/zitadel/zitadel/internal/api/http"
"github.com/zitadel/zitadel/internal/telemetry/tracing"
)
func AuthorizationInterceptor(verifier authz.APITokenVerifier, systemUserPermissions authz.Config, authConfig authz.Config) connect.UnaryInterceptorFunc {
return func(handler connect.UnaryFunc) connect.UnaryFunc {
return func(ctx context.Context, req connect.AnyRequest) (connect.AnyResponse, error) {
return authorize(ctx, req, handler, verifier, systemUserPermissions, authConfig)
}
}
}
func authorize(ctx context.Context, req connect.AnyRequest, handler connect.UnaryFunc, verifier authz.APITokenVerifier, systemUserPermissions authz.Config, authConfig authz.Config) (_ connect.AnyResponse, err error) {
authOpt, needsToken := verifier.CheckAuthMethod(req.Spec().Procedure)
if !needsToken {
return handler(ctx, req)
}
authCtx, span := tracing.NewServerInterceptorSpan(ctx)
defer func() { span.EndWithError(err) }()
authToken := req.Header().Get(http.Authorization)
if authToken == "" {
return nil, connect.NewError(connect.CodeUnauthenticated, errors.New("auth header missing"))
}
orgID, orgDomain := orgIDAndDomainFromRequest(req)
ctxSetter, err := authz.CheckUserAuthorization(authCtx, req, authToken, orgID, orgDomain, verifier, systemUserPermissions.RolePermissionMappings, authConfig.RolePermissionMappings, authOpt, req.Spec().Procedure)
if err != nil {
return nil, err
}
span.End()
return handler(ctxSetter(ctx), req)
}
func orgIDAndDomainFromRequest(req connect.AnyRequest) (id, domain string) {
orgID := req.Header().Get(http.ZitadelOrgID)
oz, ok := req.Any().(OrganizationFromRequest)
if ok {
id = oz.OrganizationFromRequestConnect().ID
domain = oz.OrganizationFromRequestConnect().Domain
if id != "" || domain != "" {
return id, domain
}
}
return orgID, domain
}
type Organization struct {
ID string
Domain string
}
type OrganizationFromRequest interface {
OrganizationFromRequestConnect() *Organization
}

View File

@@ -0,0 +1,318 @@
package connect_middleware
import (
"context"
"errors"
"net/http"
"reflect"
"testing"
"connectrpc.com/connect"
"github.com/zitadel/zitadel/internal/api/authz"
"github.com/zitadel/zitadel/internal/zerrors"
)
const anAPIRole = "AN_API_ROLE"
type authzRepoMock struct{}
func (v *authzRepoMock) VerifyAccessToken(ctx context.Context, token, clientID, projectID string) (string, string, string, string, string, error) {
return "", "", "", "", "", nil
}
func (v *authzRepoMock) SearchMyMemberships(ctx context.Context, orgID string, _ bool) ([]*authz.Membership, error) {
return authz.Memberships{{
MemberType: authz.MemberTypeOrganization,
AggregateID: orgID,
Roles: []string{anAPIRole},
}}, nil
}
func (v *authzRepoMock) ProjectIDAndOriginsByClientID(ctx context.Context, clientID string) (string, []string, error) {
return "", nil, nil
}
func (v *authzRepoMock) ExistsOrg(ctx context.Context, orgID, domain string) (string, error) {
return orgID, nil
}
func (v *authzRepoMock) VerifierClientID(ctx context.Context, appName string) (string, string, error) {
return "", "", nil
}
var (
accessTokenOK = authz.AccessTokenVerifierFunc(func(ctx context.Context, token string) (userID string, clientID string, agentID string, prefLan string, resourceOwner string, err error) {
return "user1", "", "", "", "org1", nil
})
accessTokenNOK = authz.AccessTokenVerifierFunc(func(ctx context.Context, token string) (userID string, clientID string, agentID string, prefLan string, resourceOwner string, err error) {
return "", "", "", "", "", zerrors.ThrowUnauthenticated(nil, "TEST-fQHDI", "unauthenticaded")
})
systemTokenNOK = authz.SystemTokenVerifierFunc(func(ctx context.Context, token string, orgID string) (memberships authz.Memberships, userID string, err error) {
return nil, "", errors.New("system token error")
})
)
type mockOrgFromRequest struct {
id string
}
func (m *mockOrgFromRequest) OrganizationFromRequestConnect() *Organization {
return &Organization{
ID: m.id,
Domain: "",
}
}
func Test_authorize(t *testing.T) {
type args struct {
ctx context.Context
req connect.AnyRequest
handler func(t *testing.T) connect.UnaryFunc
verifier func() authz.APITokenVerifier
authConfig authz.Config
}
type res struct {
want interface{}
wantErr bool
}
tests := []struct {
name string
args args
res res
}{
{
"no token needed ok",
args{
ctx: context.Background(),
req: &mockReq[struct{}]{procedure: "/no/token/needed"},
handler: emptyMockHandler(&connect.Response[struct{}]{}, authz.CtxData{}),
verifier: func() authz.APITokenVerifier {
verifier := authz.StartAPITokenVerifier(&authzRepoMock{}, accessTokenOK, systemTokenNOK)
verifier.RegisterServer("need", "need", authz.MethodMapping{})
return verifier
},
},
res{
&connect.Response[struct{}]{},
false,
},
},
{
"auth header missing error",
args{
ctx: context.Background(),
req: &mockReq[struct{}]{procedure: "/need/authentication"},
handler: emptyMockHandler(&connect.Response[struct{}]{}, authz.CtxData{}),
verifier: func() authz.APITokenVerifier {
verifier := authz.StartAPITokenVerifier(&authzRepoMock{}, accessTokenOK, systemTokenNOK)
verifier.RegisterServer("need", "need", authz.MethodMapping{"/need/authentication": authz.Option{Permission: "authenticated"}})
return verifier
},
authConfig: authz.Config{},
},
res{
nil,
true,
},
},
{
"unauthorized error",
args{
ctx: context.Background(),
req: &mockReq[struct{}]{procedure: "/need/authentication", header: http.Header{"Authorization": []string{"wrong"}}},
handler: emptyMockHandler(&connect.Response[struct{}]{}, authz.CtxData{}),
verifier: func() authz.APITokenVerifier {
verifier := authz.StartAPITokenVerifier(&authzRepoMock{}, accessTokenOK, systemTokenNOK)
verifier.RegisterServer("need", "need", authz.MethodMapping{"/need/authentication": authz.Option{Permission: "authenticated"}})
return verifier
},
authConfig: authz.Config{},
},
res{
nil,
true,
},
},
{
"authorized ok",
args{
ctx: context.Background(),
req: &mockReq[struct{}]{procedure: "/need/authentication", header: http.Header{"Authorization": []string{"Bearer token"}}},
handler: emptyMockHandler(&connect.Response[struct{}]{}, authz.CtxData{
UserID: "user1",
OrgID: "org1",
ResourceOwner: "org1",
}),
verifier: func() authz.APITokenVerifier {
verifier := authz.StartAPITokenVerifier(&authzRepoMock{}, accessTokenOK, systemTokenNOK)
verifier.RegisterServer("need", "need", authz.MethodMapping{"/need/authentication": authz.Option{Permission: "authenticated"}})
return verifier
},
authConfig: authz.Config{},
},
res{
&connect.Response[struct{}]{},
false,
},
},
{
"authorized ok, org by request",
args{
ctx: context.Background(),
req: &mockReq[mockOrgFromRequest]{
Request: connect.Request[mockOrgFromRequest]{Msg: &mockOrgFromRequest{"id"}},
procedure: "/need/authentication",
header: http.Header{"Authorization": []string{"Bearer token"}},
},
handler: emptyMockHandler(&connect.Response[mockOrgFromRequest]{Msg: &mockOrgFromRequest{"id"}}, authz.CtxData{
UserID: "user1",
OrgID: "id",
ResourceOwner: "org1",
}),
verifier: func() authz.APITokenVerifier {
verifier := authz.StartAPITokenVerifier(&authzRepoMock{}, accessTokenOK, systemTokenNOK)
verifier.RegisterServer("need", "need", authz.MethodMapping{"/need/authentication": authz.Option{Permission: "authenticated"}})
return verifier
},
authConfig: authz.Config{},
},
res{
&connect.Response[mockOrgFromRequest]{Msg: &mockOrgFromRequest{"id"}},
false,
},
},
{
"permission denied error",
args{
ctx: context.Background(),
req: &mockReq[struct{}]{procedure: "/need/authentication", header: http.Header{"Authorization": []string{"Bearer token"}}},
handler: emptyMockHandler(&connect.Response[struct{}]{}, authz.CtxData{
UserID: "user1",
OrgID: "org1",
ResourceOwner: "org1",
}),
verifier: func() authz.APITokenVerifier {
verifier := authz.StartAPITokenVerifier(&authzRepoMock{}, accessTokenOK, systemTokenNOK)
verifier.RegisterServer("need", "need", authz.MethodMapping{"/need/authentication": authz.Option{Permission: "to.do.something"}})
return verifier
},
authConfig: authz.Config{
RolePermissionMappings: []authz.RoleMapping{{
Role: anAPIRole,
Permissions: []string{"to.do.something.else"},
}},
},
},
res{
nil,
true,
},
},
{
"permission ok",
args{
ctx: context.Background(),
req: &mockReq[struct{}]{procedure: "/need/authentication", header: http.Header{"Authorization": []string{"Bearer token"}}},
handler: emptyMockHandler(&connect.Response[struct{}]{}, authz.CtxData{
UserID: "user1",
OrgID: "org1",
ResourceOwner: "org1",
}),
verifier: func() authz.APITokenVerifier {
verifier := authz.StartAPITokenVerifier(&authzRepoMock{}, accessTokenOK, systemTokenNOK)
verifier.RegisterServer("need", "need", authz.MethodMapping{"/need/authentication": authz.Option{Permission: "to.do.something"}})
return verifier
},
authConfig: authz.Config{
RolePermissionMappings: []authz.RoleMapping{{
Role: anAPIRole,
Permissions: []string{"to.do.something"},
}},
},
},
res{
&connect.Response[struct{}]{},
false,
},
},
{
"system token permission denied error",
args{
ctx: context.Background(),
req: &mockReq[struct{}]{procedure: "/need/authentication", header: http.Header{"Authorization": []string{"Bearer token"}}},
handler: emptyMockHandler(&connect.Response[struct{}]{}, authz.CtxData{}),
verifier: func() authz.APITokenVerifier {
verifier := authz.StartAPITokenVerifier(&authzRepoMock{}, accessTokenNOK, authz.SystemTokenVerifierFunc(func(ctx context.Context, token string, orgID string) (memberships authz.Memberships, userID string, err error) {
return authz.Memberships{{
MemberType: authz.MemberTypeSystem,
Roles: []string{"A_SYSTEM_ROLE"},
}}, "systemuser", nil
}))
verifier.RegisterServer("need", "need", authz.MethodMapping{"/need/authentication": authz.Option{Permission: "to.do.something"}})
return verifier
},
authConfig: authz.Config{
RolePermissionMappings: []authz.RoleMapping{{
Role: "A_SYSTEM_ROLE",
Permissions: []string{"to.do.something.else"},
}},
},
},
res{
nil,
true,
},
},
{
"system token permission denied error",
args{
ctx: context.Background(),
req: &mockReq[struct{}]{procedure: "/need/authentication", header: http.Header{"Authorization": []string{"Bearer token"}}},
handler: emptyMockHandler(&connect.Response[struct{}]{}, authz.CtxData{
UserID: "systemuser",
SystemMemberships: authz.Memberships{{
MemberType: authz.MemberTypeSystem,
Roles: []string{"A_SYSTEM_ROLE"},
}},
SystemUserPermissions: []authz.SystemUserPermissions{{
MemberType: authz.MemberTypeSystem,
Permissions: []string{"to.do.something"},
}},
}),
verifier: func() authz.APITokenVerifier {
verifier := authz.StartAPITokenVerifier(&authzRepoMock{}, accessTokenNOK, authz.SystemTokenVerifierFunc(func(ctx context.Context, token string, orgID string) (memberships authz.Memberships, userID string, err error) {
return authz.Memberships{{
MemberType: authz.MemberTypeSystem,
Roles: []string{"A_SYSTEM_ROLE"},
}}, "systemuser", nil
}))
verifier.RegisterServer("need", "need", authz.MethodMapping{"/need/authentication": authz.Option{Permission: "to.do.something"}})
return verifier
},
authConfig: authz.Config{
RolePermissionMappings: []authz.RoleMapping{{
Role: "A_SYSTEM_ROLE",
Permissions: []string{"to.do.something"},
}},
},
},
res{
&connect.Response[struct{}]{},
false,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := authorize(tt.args.ctx, tt.args.req, tt.args.handler(t), tt.args.verifier(), tt.args.authConfig, tt.args.authConfig)
if (err != nil) != tt.res.wantErr {
t.Errorf("authorize() error = %v, wantErr %v", err, tt.res.wantErr)
return
}
if !reflect.DeepEqual(got, tt.res.want) {
t.Errorf("authorize() got = %v, want %v", got, tt.res.want)
}
})
}
}

View File

@@ -0,0 +1,31 @@
package connect_middleware
import (
"context"
"net/http"
"time"
"connectrpc.com/connect"
_ "github.com/zitadel/zitadel/internal/statik"
)
func NoCacheInterceptor() connect.UnaryInterceptorFunc {
return func(handler connect.UnaryFunc) connect.UnaryFunc {
return func(ctx context.Context, req connect.AnyRequest) (connect.AnyResponse, error) {
headers := map[string]string{
"cache-control": "no-store",
"expires": time.Now().UTC().Format(http.TimeFormat),
"pragma": "no-cache",
}
resp, err := handler(ctx, req)
if err != nil {
return nil, err
}
for key, value := range headers {
resp.Header().Set(key, value)
}
return resp, err
}
}
}

View File

@@ -0,0 +1,18 @@
package connect_middleware
import (
"context"
"connectrpc.com/connect"
"github.com/zitadel/zitadel/internal/api/call"
)
func CallDurationHandler() connect.UnaryInterceptorFunc {
return func(handler connect.UnaryFunc) connect.UnaryFunc {
return func(ctx context.Context, req connect.AnyRequest) (connect.AnyResponse, error) {
ctx = call.WithTimestamp(ctx)
return handler(ctx, req)
}
}
}

View File

@@ -0,0 +1,23 @@
package connect_middleware
import (
"context"
"connectrpc.com/connect"
"github.com/zitadel/zitadel/internal/api/grpc/gerrors"
_ "github.com/zitadel/zitadel/internal/statik"
)
func ErrorHandler() connect.UnaryInterceptorFunc {
return func(handler connect.UnaryFunc) connect.UnaryFunc {
return func(ctx context.Context, req connect.AnyRequest) (connect.AnyResponse, error) {
return toConnectError(ctx, req, handler)
}
}
}
func toConnectError(ctx context.Context, req connect.AnyRequest, handler connect.UnaryFunc) (connect.AnyResponse, error) {
resp, err := handler(ctx, req)
return resp, gerrors.ZITADELToConnectError(err) // TODO !
}

View File

@@ -0,0 +1,65 @@
package connect_middleware
import (
"context"
"reflect"
"testing"
"connectrpc.com/connect"
"github.com/zitadel/zitadel/internal/api/authz"
)
func Test_toGRPCError(t *testing.T) {
type args struct {
ctx context.Context
req connect.AnyRequest
handler func(t *testing.T) connect.UnaryFunc
}
type res struct {
want interface{}
wantErr bool
}
tests := []struct {
name string
args args
res res
}{
{
"no error",
args{
ctx: context.Background(),
req: &mockReq[struct{}]{},
handler: emptyMockHandler(&connect.Response[struct{}]{}, authz.CtxData{}),
},
res{
&connect.Response[struct{}]{},
false,
},
},
{
"error",
args{
ctx: context.Background(),
req: &mockReq[struct{}]{},
handler: errorMockHandler(),
},
res{
nil,
true,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := toConnectError(tt.args.ctx, tt.args.req, tt.args.handler(t))
if (err != nil) != tt.res.wantErr {
t.Errorf("toGRPCError() error = %v, wantErr %v", err, tt.res.wantErr)
return
}
if !reflect.DeepEqual(got, tt.res.want) {
t.Errorf("toGRPCError() got = %v, want %v", got, tt.res.want)
}
})
}
}

View File

@@ -0,0 +1,160 @@
package connect_middleware
import (
"context"
"encoding/json"
"connectrpc.com/connect"
"google.golang.org/protobuf/encoding/protojson"
"google.golang.org/protobuf/proto"
"github.com/zitadel/zitadel/internal/api/authz"
"github.com/zitadel/zitadel/internal/execution"
"github.com/zitadel/zitadel/internal/query"
"github.com/zitadel/zitadel/internal/telemetry/tracing"
)
func ExecutionHandler(queries *query.Queries) connect.UnaryInterceptorFunc {
return func(handler connect.UnaryFunc) connect.UnaryFunc {
return func(ctx context.Context, req connect.AnyRequest) (_ connect.AnyResponse, err error) {
requestTargets, responseTargets := execution.QueryExecutionTargetsForRequestAndResponse(ctx, queries, req.Spec().Procedure)
// call targets otherwise return req
handledReq, err := executeTargetsForRequest(ctx, requestTargets, req.Spec().Procedure, req)
if err != nil {
return nil, err
}
response, err := handler(ctx, handledReq)
if err != nil {
return nil, err
}
return executeTargetsForResponse(ctx, responseTargets, req.Spec().Procedure, handledReq, response)
}
}
}
func executeTargetsForRequest(ctx context.Context, targets []execution.Target, fullMethod string, req connect.AnyRequest) (_ connect.AnyRequest, err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }()
// if no targets are found, return without any calls
if len(targets) == 0 {
return req, nil
}
ctxData := authz.GetCtxData(ctx)
info := &ContextInfoRequest{
FullMethod: fullMethod,
InstanceID: authz.GetInstance(ctx).InstanceID(),
ProjectID: ctxData.ProjectID,
OrgID: ctxData.OrgID,
UserID: ctxData.UserID,
Request: Message{req.Any().(proto.Message)},
}
_, err = execution.CallTargets(ctx, targets, info)
if err != nil {
return nil, err
}
return req, nil
}
func executeTargetsForResponse(ctx context.Context, targets []execution.Target, fullMethod string, req connect.AnyRequest, resp connect.AnyResponse) (_ connect.AnyResponse, err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }()
// if no targets are found, return without any calls
if len(targets) == 0 {
return resp, nil
}
ctxData := authz.GetCtxData(ctx)
info := &ContextInfoResponse{
FullMethod: fullMethod,
InstanceID: authz.GetInstance(ctx).InstanceID(),
ProjectID: ctxData.ProjectID,
OrgID: ctxData.OrgID,
UserID: ctxData.UserID,
Request: Message{req.Any().(proto.Message)},
Response: Message{resp.Any().(proto.Message)},
}
_, err = execution.CallTargets(ctx, targets, info)
if err != nil {
return nil, err
}
return resp, nil
}
var _ execution.ContextInfo = &ContextInfoRequest{}
type ContextInfoRequest struct {
FullMethod string `json:"fullMethod,omitempty"`
InstanceID string `json:"instanceID,omitempty"`
OrgID string `json:"orgID,omitempty"`
ProjectID string `json:"projectID,omitempty"`
UserID string `json:"userID,omitempty"`
Request Message `json:"request,omitempty"`
}
type Message struct {
proto.Message
}
func (r *Message) MarshalJSON() ([]byte, error) {
data, err := protojson.Marshal(r.Message)
if err != nil {
return nil, err
}
return data, nil
}
func (r *Message) UnmarshalJSON(data []byte) error {
return protojson.Unmarshal(data, r.Message)
}
func (c *ContextInfoRequest) GetHTTPRequestBody() []byte {
data, err := json.Marshal(c)
if err != nil {
return nil
}
return data
}
func (c *ContextInfoRequest) SetHTTPResponseBody(resp []byte) error {
return json.Unmarshal(resp, &c.Request)
}
func (c *ContextInfoRequest) GetContent() interface{} {
return c.Request.Message
}
var _ execution.ContextInfo = &ContextInfoResponse{}
type ContextInfoResponse struct {
FullMethod string `json:"fullMethod,omitempty"`
InstanceID string `json:"instanceID,omitempty"`
OrgID string `json:"orgID,omitempty"`
ProjectID string `json:"projectID,omitempty"`
UserID string `json:"userID,omitempty"`
Request Message `json:"request,omitempty"`
Response Message `json:"response,omitempty"`
}
func (c *ContextInfoResponse) GetHTTPRequestBody() []byte {
data, err := json.Marshal(c)
if err != nil {
return nil
}
return data
}
func (c *ContextInfoResponse) SetHTTPResponseBody(resp []byte) error {
return json.Unmarshal(resp, &c.Response)
}
func (c *ContextInfoResponse) GetContent() interface{} {
return c.Response.Message
}

View File

@@ -0,0 +1,815 @@
package connect_middleware
import (
"context"
"encoding/json"
"io"
"net/http"
"net/http/httptest"
"reflect"
"testing"
"time"
"connectrpc.com/connect"
"github.com/stretchr/testify/assert"
"google.golang.org/protobuf/encoding/protojson"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/types/known/structpb"
"github.com/zitadel/zitadel/internal/domain"
"github.com/zitadel/zitadel/internal/execution"
)
var _ execution.Target = &mockExecutionTarget{}
type mockExecutionTarget struct {
InstanceID string
ExecutionID string
TargetID string
TargetType domain.TargetType
Endpoint string
Timeout time.Duration
InterruptOnError bool
SigningKey string
}
func (e *mockExecutionTarget) SetEndpoint(endpoint string) {
e.Endpoint = endpoint
}
func (e *mockExecutionTarget) IsInterruptOnError() bool {
return e.InterruptOnError
}
func (e *mockExecutionTarget) GetEndpoint() string {
return e.Endpoint
}
func (e *mockExecutionTarget) GetTargetType() domain.TargetType {
return e.TargetType
}
func (e *mockExecutionTarget) GetTimeout() time.Duration {
return e.Timeout
}
func (e *mockExecutionTarget) GetTargetID() string {
return e.TargetID
}
func (e *mockExecutionTarget) GetExecutionID() string {
return e.ExecutionID
}
func (e *mockExecutionTarget) GetSigningKey() string {
return e.SigningKey
}
func newMockContentRequest(content string) *connect.Request[structpb.Struct] {
return connect.NewRequest(&structpb.Struct{
Fields: map[string]*structpb.Value{
"content": {
Kind: &structpb.Value_StringValue{StringValue: content},
},
},
})
}
func newMockContentResponse(content string) *connect.Response[structpb.Struct] {
return connect.NewResponse(&structpb.Struct{
Fields: map[string]*structpb.Value{
"content": {
Kind: &structpb.Value_StringValue{StringValue: content},
},
},
})
}
func newMockContextInfoRequest(fullMethod, request string) *ContextInfoRequest {
return &ContextInfoRequest{
FullMethod: fullMethod,
Request: Message{Message: newMockContentRequest(request).Msg},
}
}
func newMockContextInfoResponse(fullMethod, request, response string) *ContextInfoResponse {
return &ContextInfoResponse{
FullMethod: fullMethod,
Request: Message{Message: newMockContentRequest(request).Msg},
Response: Message{Message: newMockContentResponse(response).Msg},
}
}
func Test_executeTargetsForGRPCFullMethod_request(t *testing.T) {
type target struct {
reqBody execution.ContextInfo
sleep time.Duration
statusCode int
respBody connect.AnyResponse
}
type args struct {
ctx context.Context
executionTargets []execution.Target
targets []target
fullMethod string
req connect.AnyRequest
}
type res struct {
want interface{}
wantErr bool
}
tests := []struct {
name string
args args
res res
}{
{
"target, executionTargets nil",
args{
ctx: context.Background(),
fullMethod: "/service/method",
executionTargets: nil,
req: newMockContentRequest("request"),
},
res{
want: newMockContentRequest("request"),
},
},
{
"target, executionTargets empty",
args{
ctx: context.Background(),
fullMethod: "/service/method",
executionTargets: []execution.Target{},
req: newMockContentRequest("request"),
},
res{
want: newMockContentRequest("request"),
},
},
{
"target, not reachable",
args{
ctx: context.Background(),
fullMethod: "/service/method",
executionTargets: []execution.Target{
&mockExecutionTarget{
InstanceID: "instance",
ExecutionID: "request./zitadel.session.v2.SessionService/SetSession",
TargetID: "target",
TargetType: domain.TargetTypeCall,
Timeout: time.Minute,
InterruptOnError: true,
},
},
targets: []target{},
req: newMockContentRequest("content"),
},
res{
wantErr: true,
},
},
{
"target, error without interrupt",
args{
ctx: context.Background(),
fullMethod: "/service/method",
executionTargets: []execution.Target{
&mockExecutionTarget{
InstanceID: "instance",
ExecutionID: "request./zitadel.session.v2.SessionService/SetSession",
TargetID: "target",
TargetType: domain.TargetTypeCall,
Timeout: time.Minute,
SigningKey: "signingkey",
},
},
targets: []target{
{
reqBody: newMockContextInfoRequest("/service/method", "content"),
respBody: newMockContentResponse("content1"),
sleep: 0,
statusCode: http.StatusBadRequest,
},
},
req: newMockContentRequest("content"),
},
res{
want: newMockContentRequest("content"),
},
},
{
"target, interruptOnError",
args{
ctx: context.Background(),
fullMethod: "/service/method",
executionTargets: []execution.Target{
&mockExecutionTarget{
InstanceID: "instance",
ExecutionID: "request./zitadel.session.v2.SessionService/SetSession",
TargetID: "target",
TargetType: domain.TargetTypeCall,
Timeout: time.Minute,
InterruptOnError: true,
SigningKey: "signingkey",
},
},
targets: []target{
{
reqBody: newMockContextInfoRequest("/service/method", "content"),
respBody: newMockContentResponse("content1"),
sleep: 0,
statusCode: http.StatusBadRequest,
},
},
req: newMockContentRequest("content"),
},
res{
wantErr: true,
},
},
{
"target, timeout",
args{
ctx: context.Background(),
fullMethod: "/service/method",
executionTargets: []execution.Target{
&mockExecutionTarget{
InstanceID: "instance",
ExecutionID: "request./zitadel.session.v2.SessionService/SetSession",
TargetID: "target",
TargetType: domain.TargetTypeCall,
Timeout: time.Second,
InterruptOnError: true,
SigningKey: "signingkey",
},
},
targets: []target{
{
reqBody: newMockContextInfoRequest("/service/method", "content"),
respBody: newMockContentResponse("content1"),
sleep: 5 * time.Second,
statusCode: http.StatusOK,
},
},
req: newMockContentRequest("content"),
},
res{
wantErr: true,
},
},
{
"target, wrong request",
args{
ctx: context.Background(),
fullMethod: "/service/method",
executionTargets: []execution.Target{
&mockExecutionTarget{
InstanceID: "instance",
ExecutionID: "request./zitadel.session.v2.SessionService/SetSession",
TargetID: "target",
TargetType: domain.TargetTypeCall,
Timeout: time.Second,
InterruptOnError: true,
SigningKey: "signingkey",
},
},
targets: []target{
{reqBody: newMockContextInfoRequest("/service/method", "wrong")},
},
req: newMockContentRequest("content"),
},
res{
wantErr: true,
},
},
{
"target, ok",
args{
ctx: context.Background(),
fullMethod: "/service/method",
executionTargets: []execution.Target{
&mockExecutionTarget{
InstanceID: "instance",
ExecutionID: "request./zitadel.session.v2.SessionService/SetSession",
TargetID: "target",
TargetType: domain.TargetTypeCall,
Timeout: time.Minute,
InterruptOnError: true,
SigningKey: "signingkey",
},
},
targets: []target{
{
reqBody: newMockContextInfoRequest("/service/method", "content"),
respBody: newMockContentResponse("content1"),
sleep: 0,
statusCode: http.StatusOK,
},
},
req: newMockContentRequest("content"),
},
res{
want: newMockContentRequest("content1"),
},
},
{
"target async, timeout",
args{
ctx: context.Background(),
fullMethod: "/service/method",
executionTargets: []execution.Target{
&mockExecutionTarget{
InstanceID: "instance",
ExecutionID: "request./zitadel.session.v2.SessionService/SetSession",
TargetID: "target",
TargetType: domain.TargetTypeAsync,
Timeout: time.Second,
SigningKey: "signingkey",
},
},
targets: []target{
{
reqBody: newMockContextInfoRequest("/service/method", "content"),
respBody: newMockContentResponse("content1"),
sleep: 5 * time.Second,
statusCode: http.StatusOK,
},
},
req: newMockContentRequest("content"),
},
res{
want: newMockContentRequest("content"),
},
},
{
"target async, ok",
args{
ctx: context.Background(),
fullMethod: "/service/method",
executionTargets: []execution.Target{
&mockExecutionTarget{
InstanceID: "instance",
ExecutionID: "request./zitadel.session.v2.SessionService/SetSession",
TargetID: "target",
TargetType: domain.TargetTypeAsync,
Timeout: time.Minute,
SigningKey: "signingkey",
},
},
targets: []target{
{
reqBody: newMockContextInfoRequest("/service/method", "content"),
respBody: newMockContentResponse("content1"),
sleep: 0,
statusCode: http.StatusOK,
},
},
req: newMockContentRequest("content"),
},
res{
want: newMockContentRequest("content"),
},
},
{
"webhook, error",
args{
ctx: context.Background(),
fullMethod: "/service/method",
executionTargets: []execution.Target{
&mockExecutionTarget{
InstanceID: "instance",
ExecutionID: "request./zitadel.session.v2.SessionService/SetSession",
TargetID: "target",
TargetType: domain.TargetTypeWebhook,
Timeout: time.Minute,
InterruptOnError: true,
SigningKey: "signingkey",
},
},
targets: []target{
{
reqBody: newMockContextInfoRequest("/service/method", "content"),
sleep: 0,
statusCode: http.StatusInternalServerError,
},
},
req: newMockContentRequest("content"),
},
res{
wantErr: true,
},
},
{
"webhook, timeout",
args{
ctx: context.Background(),
fullMethod: "/service/method",
executionTargets: []execution.Target{
&mockExecutionTarget{
InstanceID: "instance",
ExecutionID: "request./zitadel.session.v2.SessionService/SetSession",
TargetID: "target",
TargetType: domain.TargetTypeWebhook,
Timeout: time.Second,
InterruptOnError: true,
SigningKey: "signingkey",
},
},
targets: []target{
{
reqBody: newMockContextInfoRequest("/service/method", "content"),
respBody: newMockContentResponse("content1"),
sleep: 5 * time.Second,
statusCode: http.StatusOK,
},
},
req: newMockContentRequest("content"),
},
res{
wantErr: true,
},
},
{
"webhook, ok",
args{
ctx: context.Background(),
fullMethod: "/service/method",
executionTargets: []execution.Target{
&mockExecutionTarget{
InstanceID: "instance",
ExecutionID: "request./zitadel.session.v2.SessionService/SetSession",
TargetID: "target",
TargetType: domain.TargetTypeWebhook,
Timeout: time.Minute,
InterruptOnError: true,
SigningKey: "signingkey",
},
},
targets: []target{
{
reqBody: newMockContextInfoRequest("/service/method", "content"),
respBody: newMockContentResponse("content1"),
sleep: 0,
statusCode: http.StatusOK,
},
},
req: newMockContentRequest("content"),
},
res{
want: newMockContentRequest("content"),
},
},
{
"with includes, interruptOnError",
args{
ctx: context.Background(),
fullMethod: "/service/method",
executionTargets: []execution.Target{
&mockExecutionTarget{
InstanceID: "instance",
ExecutionID: "request./zitadel.session.v2.SessionService/SetSession",
TargetID: "target1",
TargetType: domain.TargetTypeCall,
Timeout: time.Minute,
InterruptOnError: true,
SigningKey: "signingkey",
},
&mockExecutionTarget{
InstanceID: "instance",
ExecutionID: "request./zitadel.session.v2.SessionService/SetSession",
TargetID: "target2",
TargetType: domain.TargetTypeCall,
Timeout: time.Minute,
InterruptOnError: true,
SigningKey: "signingkey",
},
&mockExecutionTarget{
InstanceID: "instance",
ExecutionID: "request./zitadel.session.v2.SessionService/SetSession",
TargetID: "target3",
TargetType: domain.TargetTypeCall,
Timeout: time.Minute,
InterruptOnError: true,
SigningKey: "signingkey",
},
},
targets: []target{
{
reqBody: newMockContextInfoRequest("/service/method", "content"),
respBody: newMockContentResponse("content1"),
sleep: 0,
statusCode: http.StatusOK,
},
{
reqBody: newMockContextInfoRequest("/service/method", "content1"),
respBody: newMockContentResponse("content2"),
sleep: 0,
statusCode: http.StatusBadRequest,
},
{
reqBody: newMockContextInfoRequest("/service/method", "content2"),
respBody: newMockContentResponse("content3"),
sleep: 0,
statusCode: http.StatusOK,
},
},
req: newMockContentRequest("content"),
},
res{
wantErr: true,
},
},
{
"with includes, timeout",
args{
ctx: context.Background(),
fullMethod: "/service/method",
executionTargets: []execution.Target{
&mockExecutionTarget{
InstanceID: "instance",
ExecutionID: "request./zitadel.session.v2.SessionService/SetSession",
TargetID: "target1",
TargetType: domain.TargetTypeCall,
Timeout: time.Minute,
InterruptOnError: true,
SigningKey: "signingkey",
},
&mockExecutionTarget{
InstanceID: "instance",
ExecutionID: "request./zitadel.session.v2.SessionService/SetSession",
TargetID: "target2",
TargetType: domain.TargetTypeCall,
Timeout: time.Second,
InterruptOnError: true,
SigningKey: "signingkey",
},
&mockExecutionTarget{
InstanceID: "instance",
ExecutionID: "request./zitadel.session.v2.SessionService/SetSession",
TargetID: "target3",
TargetType: domain.TargetTypeCall,
Timeout: time.Second,
InterruptOnError: true,
SigningKey: "signingkey",
},
},
targets: []target{
{
reqBody: newMockContextInfoRequest("/service/method", "content"),
respBody: newMockContentResponse("content1"),
sleep: 0,
statusCode: http.StatusOK,
},
{
reqBody: newMockContextInfoRequest("/service/method", "content1"),
respBody: newMockContentResponse("content2"),
sleep: 5 * time.Second,
statusCode: http.StatusBadRequest,
},
{
reqBody: newMockContextInfoRequest("/service/method", "content2"),
respBody: newMockContentResponse("content3"),
sleep: 5 * time.Second,
statusCode: http.StatusOK,
},
},
req: newMockContentRequest("content"),
},
res{
wantErr: true,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
closeFuncs := make([]func(), len(tt.args.targets))
for i, target := range tt.args.targets {
url, closeF := testServerCall(
target.reqBody,
target.sleep,
target.statusCode,
target.respBody,
)
et := tt.args.executionTargets[i].(*mockExecutionTarget)
et.SetEndpoint(url)
closeFuncs[i] = closeF
}
resp, err := executeTargetsForRequest(
tt.args.ctx,
tt.args.executionTargets,
tt.args.fullMethod,
tt.args.req,
)
if tt.res.wantErr {
assert.Error(t, err)
} else {
assert.NoError(t, err)
}
assert.EqualExportedValues(t, tt.res.want, resp)
for _, closeF := range closeFuncs {
closeF()
}
})
}
}
func testServerCall(
reqBody interface{},
sleep time.Duration,
statusCode int,
respBody connect.AnyResponse,
) (string, func()) {
handler := func(w http.ResponseWriter, r *http.Request) {
data, err := json.Marshal(reqBody)
if err != nil {
http.Error(w, "error", http.StatusInternalServerError)
return
}
sentBody, err := io.ReadAll(r.Body)
if err != nil {
http.Error(w, "error", http.StatusInternalServerError)
return
}
if !reflect.DeepEqual(data, sentBody) {
http.Error(w, "error", http.StatusInternalServerError)
return
}
if statusCode != http.StatusOK {
http.Error(w, "error", statusCode)
return
}
time.Sleep(sleep)
w.Header().Set("Content-Type", "application/json")
resp, err := protojson.Marshal(respBody.Any().(proto.Message))
if err != nil {
http.Error(w, "error", http.StatusInternalServerError)
return
}
if _, err := w.Write(resp); err != nil {
http.Error(w, "error", http.StatusInternalServerError)
return
}
}
server := httptest.NewServer(http.HandlerFunc(handler))
return server.URL, server.Close
}
func Test_executeTargetsForGRPCFullMethod_response(t *testing.T) {
type target struct {
reqBody execution.ContextInfo
sleep time.Duration
statusCode int
respBody connect.AnyResponse
}
type args struct {
ctx context.Context
executionTargets []execution.Target
targets []target
fullMethod string
req connect.AnyRequest
resp connect.AnyResponse
}
type res struct {
want interface{}
wantErr bool
}
tests := []struct {
name string
args args
res res
}{
{
"target, executionTargets nil",
args{
ctx: context.Background(),
fullMethod: "/service/method",
executionTargets: nil,
req: newMockContentRequest("request"),
resp: newMockContentResponse("response"),
},
res{
want: newMockContentResponse("response"),
},
},
{
"target, executionTargets empty",
args{
ctx: context.Background(),
fullMethod: "/service/method",
executionTargets: []execution.Target{},
req: newMockContentRequest("request"),
resp: newMockContentResponse("response"),
},
res{
want: newMockContentResponse("response"),
},
},
{
"target, empty response",
args{
ctx: context.Background(),
fullMethod: "/service/method",
executionTargets: []execution.Target{
&mockExecutionTarget{
InstanceID: "instance",
ExecutionID: "request./zitadel.session.v2.SessionService/SetSession",
TargetID: "target",
TargetType: domain.TargetTypeCall,
Timeout: time.Minute,
InterruptOnError: true,
SigningKey: "signingkey",
},
},
targets: []target{
{
reqBody: newMockContextInfoRequest("/service/method", "content"),
respBody: newMockContentResponse(""),
sleep: 0,
statusCode: http.StatusOK,
},
},
req: newMockContentRequest(""),
resp: newMockContentResponse(""),
},
res{
wantErr: true,
},
},
{
"target, ok",
args{
ctx: context.Background(),
fullMethod: "/service/method",
executionTargets: []execution.Target{
&mockExecutionTarget{
InstanceID: "instance",
ExecutionID: "response./zitadel.session.v2.SessionService/SetSession",
TargetID: "target",
TargetType: domain.TargetTypeCall,
Timeout: time.Minute,
InterruptOnError: true,
SigningKey: "signingkey",
},
},
targets: []target{
{
reqBody: newMockContextInfoResponse("/service/method", "request", "response"),
respBody: newMockContentResponse("response1"),
sleep: 0,
statusCode: http.StatusOK,
},
},
req: newMockContentRequest("request"),
resp: newMockContentResponse("response"),
},
res{
want: newMockContentResponse("response1"),
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
closeFuncs := make([]func(), len(tt.args.targets))
for i, target := range tt.args.targets {
url, closeF := testServerCall(
target.reqBody,
target.sleep,
target.statusCode,
target.respBody,
)
et := tt.args.executionTargets[i].(*mockExecutionTarget)
et.SetEndpoint(url)
closeFuncs[i] = closeF
}
resp, err := executeTargetsForResponse(
tt.args.ctx,
tt.args.executionTargets,
tt.args.fullMethod,
tt.args.req,
tt.args.resp,
)
if tt.res.wantErr {
assert.Error(t, err)
} else {
assert.NoError(t, err)
}
assert.EqualExportedValues(t, tt.res.want, resp)
for _, closeF := range closeFuncs {
closeF()
}
})
}
}

View File

@@ -0,0 +1,107 @@
package connect_middleware
import (
"context"
"errors"
"fmt"
"strings"
"connectrpc.com/connect"
"github.com/zitadel/logging"
"golang.org/x/text/language"
"github.com/zitadel/zitadel/internal/api/authz"
zitadel_http "github.com/zitadel/zitadel/internal/api/http"
"github.com/zitadel/zitadel/internal/i18n"
"github.com/zitadel/zitadel/internal/telemetry/tracing"
"github.com/zitadel/zitadel/internal/zerrors"
object_v3 "github.com/zitadel/zitadel/pkg/grpc/object/v3alpha"
)
func InstanceInterceptor(verifier authz.InstanceVerifier, externalDomain string, explicitInstanceIdServices ...string) connect.UnaryInterceptorFunc {
translator, err := i18n.NewZitadelTranslator(language.English)
logging.OnError(err).Panic("unable to get translator")
return func(handler connect.UnaryFunc) connect.UnaryFunc {
return func(ctx context.Context, req connect.AnyRequest) (connect.AnyResponse, error) {
return setInstance(ctx, req, handler, verifier, externalDomain, translator, explicitInstanceIdServices...)
}
}
}
func setInstance(ctx context.Context, req connect.AnyRequest, handler connect.UnaryFunc, verifier authz.InstanceVerifier, externalDomain string, translator *i18n.Translator, idFromRequestsServices ...string) (_ connect.AnyResponse, err error) {
interceptorCtx, span := tracing.NewServerInterceptorSpan(ctx)
defer func() { span.EndWithError(err) }()
for _, service := range idFromRequestsServices {
if !strings.HasPrefix(service, "/") {
service = "/" + service
}
if strings.HasPrefix(req.Spec().Procedure, service) {
withInstanceIDProperty, ok := req.Any().(interface {
GetInstanceId() string
})
if !ok {
return handler(ctx, req)
}
return addInstanceByID(interceptorCtx, req, handler, verifier, translator, withInstanceIDProperty.GetInstanceId())
}
}
explicitInstanceRequest, ok := req.Any().(interface {
GetInstance() *object_v3.Instance
})
if ok {
instance := explicitInstanceRequest.GetInstance()
if id := instance.GetId(); id != "" {
return addInstanceByID(interceptorCtx, req, handler, verifier, translator, id)
}
if domain := instance.GetDomain(); domain != "" {
return addInstanceByDomain(interceptorCtx, req, handler, verifier, translator, domain)
}
}
return addInstanceByRequestedHost(interceptorCtx, req, handler, verifier, translator, externalDomain)
}
func addInstanceByID(ctx context.Context, req connect.AnyRequest, handler connect.UnaryFunc, verifier authz.InstanceVerifier, translator *i18n.Translator, id string) (connect.AnyResponse, error) {
instance, err := verifier.InstanceByID(ctx, id)
if err != nil {
notFoundErr := new(zerrors.ZitadelError)
if errors.As(err, &notFoundErr) {
notFoundErr.Message = translator.LocalizeFromCtx(ctx, notFoundErr.GetMessage(), nil)
}
return nil, connect.NewError(connect.CodeNotFound, fmt.Errorf("unable to set instance using id %s: %w", id, notFoundErr))
}
return handler(authz.WithInstance(ctx, instance), req)
}
func addInstanceByDomain(ctx context.Context, req connect.AnyRequest, handler connect.UnaryFunc, verifier authz.InstanceVerifier, translator *i18n.Translator, domain string) (connect.AnyResponse, error) {
instance, err := verifier.InstanceByHost(ctx, domain, "")
if err != nil {
notFoundErr := new(zerrors.NotFoundError)
if errors.As(err, &notFoundErr) {
notFoundErr.Message = translator.LocalizeFromCtx(ctx, notFoundErr.GetMessage(), nil)
}
return nil, connect.NewError(connect.CodeNotFound, fmt.Errorf("unable to set instance using domain %s: %w", domain, notFoundErr))
}
return handler(authz.WithInstance(ctx, instance), req)
}
func addInstanceByRequestedHost(ctx context.Context, req connect.AnyRequest, handler connect.UnaryFunc, verifier authz.InstanceVerifier, translator *i18n.Translator, externalDomain string) (connect.AnyResponse, error) {
requestContext := zitadel_http.DomainContext(ctx)
if requestContext.InstanceHost == "" {
logging.WithFields("origin", requestContext.Origin(), "externalDomain", externalDomain).Error("unable to set instance")
return nil, connect.NewError(connect.CodeNotFound, errors.New("no instanceHost specified"))
}
instance, err := verifier.InstanceByHost(ctx, requestContext.InstanceHost, requestContext.PublicHost)
if err != nil {
origin := zitadel_http.DomainContext(ctx)
logging.WithFields("origin", requestContext.Origin(), "externalDomain", externalDomain).WithError(err).Error("unable to set instance")
zErr := new(zerrors.ZitadelError)
if errors.As(err, &zErr) {
zErr.SetMessage(translator.LocalizeFromCtx(ctx, zErr.GetMessage(), nil))
zErr.Parent = err
return nil, connect.NewError(connect.CodeNotFound, fmt.Errorf("unable to set instance using origin %s (ExternalDomain is %s): %s", origin, externalDomain, zErr.Error()))
}
return nil, connect.NewError(connect.CodeNotFound, fmt.Errorf("unable to set instance using origin %s (ExternalDomain is %s)", origin, externalDomain))
}
return handler(authz.WithInstance(ctx, instance), req)
}

View File

@@ -0,0 +1,34 @@
package connect_middleware
import (
"context"
"strings"
"connectrpc.com/connect"
"github.com/zitadel/zitadel/internal/api/authz"
"github.com/zitadel/zitadel/internal/zerrors"
)
func LimitsInterceptor(ignoreService ...string) connect.UnaryInterceptorFunc {
for idx, service := range ignoreService {
if !strings.HasPrefix(service, "/") {
ignoreService[idx] = "/" + service
}
}
return func(handler connect.UnaryFunc) connect.UnaryFunc {
return func(ctx context.Context, req connect.AnyRequest) (_ connect.AnyResponse, err error) {
for _, service := range ignoreService {
if strings.HasPrefix(req.Spec().Procedure, service) {
return handler(ctx, req)
}
}
instance := authz.GetInstance(ctx)
if block := instance.Block(); block != nil && *block {
return nil, zerrors.ThrowResourceExhausted(nil, "LIMITS-molsj", "Errors.Limits.Instance.Blocked")
}
return handler(ctx, req)
}
}
}

View File

@@ -0,0 +1,96 @@
package connect_middleware
import (
"context"
"strings"
"connectrpc.com/connect"
"github.com/grpc-ecosystem/grpc-gateway/runtime"
"github.com/zitadel/logging"
"go.opentelemetry.io/otel/attribute"
"google.golang.org/grpc/codes"
_ "github.com/zitadel/zitadel/internal/statik"
"github.com/zitadel/zitadel/internal/telemetry/metrics"
)
const (
GrpcMethod = "grpc_method"
ReturnCode = "return_code"
GrpcRequestCounter = "grpc.server.request_counter"
GrpcRequestCounterDescription = "Grpc request counter"
TotalGrpcRequestCounter = "grpc.server.total_request_counter"
TotalGrpcRequestCounterDescription = "Total grpc request counter"
GrpcStatusCodeCounter = "grpc.server.grpc_status_code"
GrpcStatusCodeCounterDescription = "Grpc status code counter"
)
func MetricsHandler(metricTypes []metrics.MetricType, ignoredMethodSuffixes ...string) connect.UnaryInterceptorFunc {
return func(handler connect.UnaryFunc) connect.UnaryFunc {
return func(ctx context.Context, req connect.AnyRequest) (connect.AnyResponse, error) {
return RegisterMetrics(ctx, req, handler, metricTypes, ignoredMethodSuffixes...)
}
}
}
func RegisterMetrics(ctx context.Context, req connect.AnyRequest, handler connect.UnaryFunc, metricTypes []metrics.MetricType, ignoredMethodSuffixes ...string) (_ connect.AnyResponse, err error) {
if len(metricTypes) == 0 {
return handler(ctx, req)
}
for _, ignore := range ignoredMethodSuffixes {
if strings.HasSuffix(req.Spec().Procedure, ignore) {
return handler(ctx, req)
}
}
resp, err := handler(ctx, req)
if containsMetricsMethod(metrics.MetricTypeRequestCount, metricTypes) {
RegisterGrpcRequestCounter(ctx, req.Spec().Procedure)
}
if containsMetricsMethod(metrics.MetricTypeTotalCount, metricTypes) {
RegisterGrpcTotalRequestCounter(ctx)
}
if containsMetricsMethod(metrics.MetricTypeStatusCode, metricTypes) {
RegisterGrpcRequestCodeCounter(ctx, req.Spec().Procedure, err)
}
return resp, err
}
func RegisterGrpcRequestCounter(ctx context.Context, path string) {
var labels = map[string]attribute.Value{
GrpcMethod: attribute.StringValue(path),
}
err := metrics.RegisterCounter(GrpcRequestCounter, GrpcRequestCounterDescription)
logging.OnError(err).Warn("failed to register grpc request counter")
err = metrics.AddCount(ctx, GrpcRequestCounter, 1, labels)
logging.OnError(err).Warn("failed to add grpc request count")
}
func RegisterGrpcTotalRequestCounter(ctx context.Context) {
err := metrics.RegisterCounter(TotalGrpcRequestCounter, TotalGrpcRequestCounterDescription)
logging.OnError(err).Warn("failed to register total grpc request counter")
err = metrics.AddCount(ctx, TotalGrpcRequestCounter, 1, nil)
logging.OnError(err).Warn("failed to add total grpc request count")
}
func RegisterGrpcRequestCodeCounter(ctx context.Context, path string, err error) {
statusCode := connect.CodeOf(err)
var labels = map[string]attribute.Value{
GrpcMethod: attribute.StringValue(path),
ReturnCode: attribute.IntValue(runtime.HTTPStatusFromCode(codes.Code(statusCode))),
}
err = metrics.RegisterCounter(GrpcStatusCodeCounter, GrpcStatusCodeCounterDescription)
logging.OnError(err).Warn("failed to register grpc status code counter")
err = metrics.AddCount(ctx, GrpcStatusCodeCounter, 1, labels)
logging.OnError(err).Warn("failed to add grpc status code count")
}
func containsMetricsMethod(metricType metrics.MetricType, metricTypes []metrics.MetricType) bool {
for _, m := range metricTypes {
if m == metricType {
return true
}
}
return false
}

View File

@@ -0,0 +1,50 @@
package connect_middleware
import (
"context"
"net/http"
"testing"
"connectrpc.com/connect"
"github.com/stretchr/testify/assert"
"github.com/zitadel/zitadel/internal/api/authz"
"github.com/zitadel/zitadel/internal/zerrors"
)
func emptyMockHandler(resp connect.AnyResponse, expectedCtxData authz.CtxData) func(*testing.T) connect.UnaryFunc {
return func(t *testing.T) connect.UnaryFunc {
return func(ctx context.Context, _ connect.AnyRequest) (connect.AnyResponse, error) {
assert.Equal(t, expectedCtxData, authz.GetCtxData(ctx))
return resp, nil
}
}
}
func errorMockHandler() func(*testing.T) connect.UnaryFunc {
return func(t *testing.T) connect.UnaryFunc {
return func(ctx context.Context, req connect.AnyRequest) (connect.AnyResponse, error) {
return nil, zerrors.ThrowInternal(nil, "test", "error")
}
}
}
type mockReq[t any] struct {
connect.Request[t]
procedure string
header http.Header
}
func (m *mockReq[T]) Spec() connect.Spec {
return connect.Spec{
Procedure: m.procedure,
}
}
func (m *mockReq[T]) Header() http.Header {
if m.header == nil {
m.header = make(http.Header)
}
return m.header
}

View File

@@ -0,0 +1,53 @@
package connect_middleware
import (
"context"
"strings"
"connectrpc.com/connect"
"github.com/zitadel/zitadel/internal/api/authz"
"github.com/zitadel/zitadel/internal/logstore"
"github.com/zitadel/zitadel/internal/logstore/record"
"github.com/zitadel/zitadel/internal/telemetry/tracing"
"github.com/zitadel/zitadel/internal/zerrors"
)
func QuotaExhaustedInterceptor(svc *logstore.Service[*record.AccessLog], ignoreService ...string) connect.UnaryInterceptorFunc {
for idx, service := range ignoreService {
if !strings.HasPrefix(service, "/") {
ignoreService[idx] = "/" + service
}
}
return func(handler connect.UnaryFunc) connect.UnaryFunc {
return func(ctx context.Context, req connect.AnyRequest) (_ connect.AnyResponse, err error) {
if !svc.Enabled() {
return handler(ctx, req)
}
interceptorCtx, span := tracing.NewServerInterceptorSpan(ctx)
defer func() { span.EndWithError(err) }()
// The auth interceptor will ensure that only authorized or public requests are allowed.
// So if there's no authorization context, we don't need to check for limitation
// Also, we don't limit calls with system user tokens
ctxData := authz.GetCtxData(ctx)
if ctxData.IsZero() || ctxData.SystemMemberships != nil {
return handler(ctx, req)
}
for _, service := range ignoreService {
if strings.HasPrefix(req.Spec().Procedure, service) {
return handler(ctx, req)
}
}
instance := authz.GetInstance(ctx)
remaining := svc.Limit(interceptorCtx, instance.InstanceID())
if remaining != nil && *remaining == 0 {
return nil, zerrors.ThrowResourceExhausted(nil, "QUOTA-vjAy8", "Quota.Access.Exhausted")
}
span.End()
return handler(ctx, req)
}
}
}

View File

@@ -0,0 +1,45 @@
package connect_middleware
import (
"context"
"strings"
"connectrpc.com/connect"
"github.com/zitadel/zitadel/internal/api/service"
_ "github.com/zitadel/zitadel/internal/statik"
)
const (
unknown = "UNKNOWN"
)
func ServiceHandler() connect.UnaryInterceptorFunc {
return func(handler connect.UnaryFunc) connect.UnaryFunc {
return func(ctx context.Context, req connect.AnyRequest) (connect.AnyResponse, error) {
serviceName, _ := serviceAndMethod(req.Spec().Procedure)
if serviceName != unknown {
return handler(ctx, req)
}
ctx = service.WithService(ctx, serviceName)
return handler(ctx, req)
}
}
}
// serviceAndMethod returns the service and method from a procedure.
func serviceAndMethod(procedure string) (string, string) {
procedure = strings.TrimPrefix(procedure, "/")
serviceName, method := unknown, unknown
if strings.Contains(procedure, "/") {
long := strings.Split(procedure, "/")[0]
if strings.Contains(long, ".") {
split := strings.Split(long, ".")
serviceName = split[len(split)-1]
}
}
if strings.Contains(procedure, "/") {
method = strings.Split(procedure, "/")[1]
}
return serviceName, method
}

View File

@@ -0,0 +1,48 @@
package connect_middleware
import (
"context"
"connectrpc.com/connect"
"github.com/zitadel/logging"
"github.com/zitadel/zitadel/internal/api/authz"
"github.com/zitadel/zitadel/internal/i18n"
_ "github.com/zitadel/zitadel/internal/statik"
"github.com/zitadel/zitadel/internal/telemetry/tracing"
)
func TranslationHandler() connect.UnaryInterceptorFunc {
return func(handler connect.UnaryFunc) connect.UnaryFunc {
return func(ctx context.Context, req connect.AnyRequest) (connect.AnyResponse, error) {
resp, err := handler(ctx, req)
ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }()
if err != nil {
translator, translatorError := getTranslator(ctx)
if translatorError != nil {
return resp, err
}
return resp, translateError(ctx, err, translator)
}
if loc, ok := resp.Any().(localizers); ok {
translator, translatorError := getTranslator(ctx)
if translatorError != nil {
return resp, err
}
translateFields(ctx, loc, translator)
}
return resp, nil
}
}
}
func getTranslator(ctx context.Context) (*i18n.Translator, error) {
translator, err := i18n.NewZitadelTranslator(authz.GetInstance(ctx).DefaultLanguage())
if err != nil {
logging.New().WithError(err).Error("could not load translator")
}
return translator, err
}

View File

@@ -0,0 +1,37 @@
package connect_middleware
import (
"context"
"errors"
"github.com/zitadel/zitadel/internal/i18n"
"github.com/zitadel/zitadel/internal/zerrors"
)
type localizers interface {
Localizers() []Localizer
}
type Localizer interface {
LocalizationKey() string
SetLocalizedMessage(string)
}
func translateFields(ctx context.Context, object localizers, translator *i18n.Translator) {
if translator == nil || object == nil {
return
}
for _, field := range object.Localizers() {
field.SetLocalizedMessage(translator.LocalizeFromCtx(ctx, field.LocalizationKey(), nil))
}
}
func translateError(ctx context.Context, err error, translator *i18n.Translator) error {
if translator == nil || err == nil {
return err
}
caosErr := new(zerrors.ZitadelError)
if errors.As(err, &caosErr) {
caosErr.SetMessage(translator.LocalizeFromCtx(ctx, caosErr.GetMessage(), nil))
}
return err
}

View File

@@ -0,0 +1,36 @@
package connect_middleware
import (
"context"
"connectrpc.com/connect"
// import to make sure go.mod does not lose it
// because dependency is only needed for generated code
_ "github.com/envoyproxy/protoc-gen-validate/validate"
)
func ValidationHandler() connect.UnaryInterceptorFunc {
return func(handler connect.UnaryFunc) connect.UnaryFunc {
return func(ctx context.Context, req connect.AnyRequest) (connect.AnyResponse, error) {
return validate(ctx, req, handler)
}
}
}
// validator interface needed for github.com/envoyproxy/protoc-gen-validate
// (it does not expose an interface itself)
type validator interface {
Validate() error
}
func validate(ctx context.Context, req connect.AnyRequest, handler connect.UnaryFunc) (connect.AnyResponse, error) {
validate, ok := req.Any().(validator)
if !ok {
return handler(ctx, req)
}
err := validate.Validate()
if err != nil {
return nil, connect.NewError(connect.CodeInvalidArgument, err)
}
return handler(ctx, req)
}

View File

@@ -171,7 +171,7 @@ func CreateGateway(
}, nil }, nil
} }
func RegisterGateway(ctx context.Context, gateway *Gateway, server Server) error { func RegisterGateway(ctx context.Context, gateway *Gateway, server WithGateway) error {
err := server.RegisterGateway()(ctx, gateway.mux, gateway.connection) err := server.RegisterGateway()(ctx, gateway.mux, gateway.connection)
if err != nil { if err != nil {
return fmt.Errorf("failed to register grpc gateway: %w", err) return fmt.Errorf("failed to register grpc gateway: %w", err)

View File

@@ -2,11 +2,14 @@ package server
import ( import (
"crypto/tls" "crypto/tls"
"net/http"
"connectrpc.com/connect"
grpc_middleware "github.com/grpc-ecosystem/go-grpc-middleware" grpc_middleware "github.com/grpc-ecosystem/go-grpc-middleware"
"google.golang.org/grpc" "google.golang.org/grpc"
"google.golang.org/grpc/credentials" "google.golang.org/grpc/credentials"
healthpb "google.golang.org/grpc/health/grpc_health_v1" healthpb "google.golang.org/grpc/health/grpc_health_v1"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
"github.com/zitadel/zitadel/internal/api/authz" "github.com/zitadel/zitadel/internal/api/authz"
grpc_api "github.com/zitadel/zitadel/internal/api/grpc" grpc_api "github.com/zitadel/zitadel/internal/api/grpc"
@@ -19,21 +22,36 @@ import (
) )
type Server interface { type Server interface {
RegisterServer(*grpc.Server)
RegisterGateway() RegisterGatewayFunc
AppName() string AppName() string
MethodPrefix() string MethodPrefix() string
AuthMethods() authz.MethodMapping AuthMethods() authz.MethodMapping
} }
type GrpcServer interface {
Server
RegisterServer(*grpc.Server)
}
type WithGateway interface {
Server
RegisterGateway() RegisterGatewayFunc
}
// WithGatewayPrefix extends the server interface with a prefix for the grpc gateway // WithGatewayPrefix extends the server interface with a prefix for the grpc gateway
// //
// it's used for the System, Admin, Mgmt and Auth API // it's used for the System, Admin, Mgmt and Auth API
type WithGatewayPrefix interface { type WithGatewayPrefix interface {
Server GrpcServer
WithGateway
GatewayPathPrefix() string GatewayPathPrefix() string
} }
type ConnectServer interface {
Server
RegisterConnectServer(interceptors ...connect.Interceptor) (string, http.Handler)
FileDescriptor() protoreflect.FileDescriptor
}
func CreateServer( func CreateServer(
verifier authz.APITokenVerifier, verifier authz.APITokenVerifier,
systemAuthz authz.Config, systemAuthz authz.Config,

View File

@@ -4,6 +4,7 @@ import (
"context" "context"
"time" "time"
"connectrpc.com/connect"
"github.com/muhlemmer/gu" "github.com/muhlemmer/gu"
"google.golang.org/protobuf/types/known/timestamppb" "google.golang.org/protobuf/types/known/timestamppb"
@@ -26,18 +27,18 @@ var (
} }
) )
func (s *Server) GetSession(ctx context.Context, req *session.GetSessionRequest) (*session.GetSessionResponse, error) { func (s *Server) GetSession(ctx context.Context, req *connect.Request[session.GetSessionRequest]) (*connect.Response[session.GetSessionResponse], error) {
res, err := s.query.SessionByID(ctx, true, req.GetSessionId(), req.GetSessionToken(), s.checkPermission) res, err := s.query.SessionByID(ctx, true, req.Msg.GetSessionId(), req.Msg.GetSessionToken(), s.checkPermission)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &session.GetSessionResponse{ return connect.NewResponse(&session.GetSessionResponse{
Session: sessionToPb(res), Session: sessionToPb(res),
}, nil }), nil
} }
func (s *Server) ListSessions(ctx context.Context, req *session.ListSessionsRequest) (*session.ListSessionsResponse, error) { func (s *Server) ListSessions(ctx context.Context, req *connect.Request[session.ListSessionsRequest]) (*connect.Response[session.ListSessionsResponse], error) {
queries, err := listSessionsRequestToQuery(ctx, req) queries, err := listSessionsRequestToQuery(ctx, req.Msg)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -45,10 +46,10 @@ func (s *Server) ListSessions(ctx context.Context, req *session.ListSessionsRequ
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &session.ListSessionsResponse{ return connect.NewResponse(&session.ListSessionsResponse{
Details: object.ToListDetails(sessions.SearchResponse), Details: object.ToListDetails(sessions.SearchResponse),
Sessions: sessionsToPb(sessions.Sessions), Sessions: sessionsToPb(sessions.Sessions),
}, nil }), nil
} }
func listSessionsRequestToQuery(ctx context.Context, req *session.ListSessionsRequest) (*query.SessionsSearchQueries, error) { func listSessionsRequestToQuery(ctx context.Context, req *session.ListSessionsRequest) (*query.SessionsSearchQueries, error) {

View File

@@ -1,7 +1,10 @@
package session package session
import ( import (
"google.golang.org/grpc" "net/http"
"connectrpc.com/connect"
"google.golang.org/protobuf/reflect/protoreflect"
"github.com/zitadel/zitadel/internal/api/authz" "github.com/zitadel/zitadel/internal/api/authz"
"github.com/zitadel/zitadel/internal/api/grpc/server" "github.com/zitadel/zitadel/internal/api/grpc/server"
@@ -9,12 +12,12 @@ import (
"github.com/zitadel/zitadel/internal/domain" "github.com/zitadel/zitadel/internal/domain"
"github.com/zitadel/zitadel/internal/query" "github.com/zitadel/zitadel/internal/query"
"github.com/zitadel/zitadel/pkg/grpc/session/v2" "github.com/zitadel/zitadel/pkg/grpc/session/v2"
"github.com/zitadel/zitadel/pkg/grpc/session/v2/sessionconnect"
) )
var _ session.SessionServiceServer = (*Server)(nil) var _ sessionconnect.SessionServiceHandler = (*Server)(nil)
type Server struct { type Server struct {
session.UnimplementedSessionServiceServer
command *command.Commands command *command.Commands
query *query.Queries query *query.Queries
@@ -35,8 +38,12 @@ func CreateServer(
} }
} }
func (s *Server) RegisterServer(grpcServer *grpc.Server) { func (s *Server) RegisterConnectServer(interceptors ...connect.Interceptor) (string, http.Handler) {
session.RegisterSessionServiceServer(grpcServer, s) return sessionconnect.NewSessionServiceHandler(s, connect.WithInterceptors(interceptors...))
}
func (s *Server) FileDescriptor() protoreflect.FileDescriptor {
return session.File_zitadel_session_v2_session_service_proto
} }
func (s *Server) AppName() string { func (s *Server) AppName() string {

View File

@@ -6,6 +6,7 @@ import (
"net/http" "net/http"
"time" "time"
"connectrpc.com/connect"
"golang.org/x/text/language" "golang.org/x/text/language"
"google.golang.org/protobuf/types/known/structpb" "google.golang.org/protobuf/types/known/structpb"
@@ -17,12 +18,12 @@ import (
"github.com/zitadel/zitadel/pkg/grpc/session/v2" "github.com/zitadel/zitadel/pkg/grpc/session/v2"
) )
func (s *Server) CreateSession(ctx context.Context, req *session.CreateSessionRequest) (*session.CreateSessionResponse, error) { func (s *Server) CreateSession(ctx context.Context, req *connect.Request[session.CreateSessionRequest]) (*connect.Response[session.CreateSessionResponse], error) {
checks, metadata, userAgent, lifetime, err := s.createSessionRequestToCommand(ctx, req) checks, metadata, userAgent, lifetime, err := s.createSessionRequestToCommand(ctx, req.Msg)
if err != nil { if err != nil {
return nil, err return nil, err
} }
challengeResponse, cmds, err := s.challengesToCommand(req.GetChallenges(), checks) challengeResponse, cmds, err := s.challengesToCommand(req.Msg.GetChallenges(), checks)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -32,43 +33,43 @@ func (s *Server) CreateSession(ctx context.Context, req *session.CreateSessionRe
return nil, err return nil, err
} }
return &session.CreateSessionResponse{ return connect.NewResponse(&session.CreateSessionResponse{
Details: object.DomainToDetailsPb(set.ObjectDetails), Details: object.DomainToDetailsPb(set.ObjectDetails),
SessionId: set.ID, SessionId: set.ID,
SessionToken: set.NewToken, SessionToken: set.NewToken,
Challenges: challengeResponse, Challenges: challengeResponse,
}, nil }), nil
} }
func (s *Server) SetSession(ctx context.Context, req *session.SetSessionRequest) (*session.SetSessionResponse, error) { func (s *Server) SetSession(ctx context.Context, req *connect.Request[session.SetSessionRequest]) (*connect.Response[session.SetSessionResponse], error) {
checks, err := s.setSessionRequestToCommand(ctx, req) checks, err := s.setSessionRequestToCommand(ctx, req.Msg)
if err != nil { if err != nil {
return nil, err return nil, err
} }
challengeResponse, cmds, err := s.challengesToCommand(req.GetChallenges(), checks) challengeResponse, cmds, err := s.challengesToCommand(req.Msg.GetChallenges(), checks)
if err != nil { if err != nil {
return nil, err return nil, err
} }
set, err := s.command.UpdateSession(ctx, req.GetSessionId(), cmds, req.GetMetadata(), req.GetLifetime().AsDuration()) set, err := s.command.UpdateSession(ctx, req.Msg.GetSessionId(), cmds, req.Msg.GetMetadata(), req.Msg.GetLifetime().AsDuration())
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &session.SetSessionResponse{ return connect.NewResponse(&session.SetSessionResponse{
Details: object.DomainToDetailsPb(set.ObjectDetails), Details: object.DomainToDetailsPb(set.ObjectDetails),
SessionToken: set.NewToken, SessionToken: set.NewToken,
Challenges: challengeResponse, Challenges: challengeResponse,
}, nil }), nil
} }
func (s *Server) DeleteSession(ctx context.Context, req *session.DeleteSessionRequest) (*session.DeleteSessionResponse, error) { func (s *Server) DeleteSession(ctx context.Context, req *connect.Request[session.DeleteSessionRequest]) (*connect.Response[session.DeleteSessionResponse], error) {
details, err := s.command.TerminateSession(ctx, req.GetSessionId(), req.GetSessionToken()) details, err := s.command.TerminateSession(ctx, req.Msg.GetSessionId(), req.Msg.GetSessionToken())
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &session.DeleteSessionResponse{ return connect.NewResponse(&session.DeleteSessionResponse{
Details: object.DomainToDetailsPb(details), Details: object.DomainToDetailsPb(details),
}, nil }), nil
} }
func (s *Server) createSessionRequestToCommand(ctx context.Context, req *session.CreateSessionRequest) ([]command.SessionCommand, map[string][]byte, *domain.UserAgent, time.Duration, error) { func (s *Server) createSessionRequestToCommand(ctx context.Context, req *session.CreateSessionRequest) ([]command.SessionCommand, map[string][]byte, *domain.UserAgent, time.Duration, error) {

View File

@@ -1,7 +1,10 @@
package session package session
import ( import (
"google.golang.org/grpc" "net/http"
"connectrpc.com/connect"
"google.golang.org/protobuf/reflect/protoreflect"
"github.com/zitadel/zitadel/internal/api/authz" "github.com/zitadel/zitadel/internal/api/authz"
"github.com/zitadel/zitadel/internal/api/grpc/server" "github.com/zitadel/zitadel/internal/api/grpc/server"
@@ -9,12 +12,12 @@ import (
"github.com/zitadel/zitadel/internal/domain" "github.com/zitadel/zitadel/internal/domain"
"github.com/zitadel/zitadel/internal/query" "github.com/zitadel/zitadel/internal/query"
session "github.com/zitadel/zitadel/pkg/grpc/session/v2beta" session "github.com/zitadel/zitadel/pkg/grpc/session/v2beta"
"github.com/zitadel/zitadel/pkg/grpc/session/v2beta/sessionconnect"
) )
var _ session.SessionServiceServer = (*Server)(nil) var _ sessionconnect.SessionServiceHandler = (*Server)(nil)
type Server struct { type Server struct {
session.UnimplementedSessionServiceServer
command *command.Commands command *command.Commands
query *query.Queries query *query.Queries
@@ -35,8 +38,12 @@ func CreateServer(
} }
} }
func (s *Server) RegisterServer(grpcServer *grpc.Server) { func (s *Server) RegisterConnectServer(interceptors ...connect.Interceptor) (string, http.Handler) {
session.RegisterSessionServiceServer(grpcServer, s) return sessionconnect.NewSessionServiceHandler(s, connect.WithInterceptors(interceptors...))
}
func (s *Server) FileDescriptor() protoreflect.FileDescriptor {
return session.File_zitadel_session_v2beta_session_service_proto
} }
func (s *Server) AppName() string { func (s *Server) AppName() string {

View File

@@ -6,6 +6,7 @@ import (
"net/http" "net/http"
"time" "time"
"connectrpc.com/connect"
"github.com/muhlemmer/gu" "github.com/muhlemmer/gu"
"golang.org/x/text/language" "golang.org/x/text/language"
"google.golang.org/protobuf/types/known/structpb" "google.golang.org/protobuf/types/known/structpb"
@@ -31,18 +32,18 @@ var (
} }
) )
func (s *Server) GetSession(ctx context.Context, req *session.GetSessionRequest) (*session.GetSessionResponse, error) { func (s *Server) GetSession(ctx context.Context, req *connect.Request[session.GetSessionRequest]) (*connect.Response[session.GetSessionResponse], error) {
res, err := s.query.SessionByID(ctx, true, req.GetSessionId(), req.GetSessionToken(), s.checkPermission) res, err := s.query.SessionByID(ctx, true, req.Msg.GetSessionId(), req.Msg.GetSessionToken(), s.checkPermission)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &session.GetSessionResponse{ return connect.NewResponse(&session.GetSessionResponse{
Session: sessionToPb(res), Session: sessionToPb(res),
}, nil }), nil
} }
func (s *Server) ListSessions(ctx context.Context, req *session.ListSessionsRequest) (*session.ListSessionsResponse, error) { func (s *Server) ListSessions(ctx context.Context, req *connect.Request[session.ListSessionsRequest]) (*connect.Response[session.ListSessionsResponse], error) {
queries, err := listSessionsRequestToQuery(ctx, req) queries, err := listSessionsRequestToQuery(ctx, req.Msg)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -50,18 +51,18 @@ func (s *Server) ListSessions(ctx context.Context, req *session.ListSessionsRequ
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &session.ListSessionsResponse{ return connect.NewResponse(&session.ListSessionsResponse{
Details: object.ToListDetails(sessions.SearchResponse), Details: object.ToListDetails(sessions.SearchResponse),
Sessions: sessionsToPb(sessions.Sessions), Sessions: sessionsToPb(sessions.Sessions),
}, nil }), nil
} }
func (s *Server) CreateSession(ctx context.Context, req *session.CreateSessionRequest) (*session.CreateSessionResponse, error) { func (s *Server) CreateSession(ctx context.Context, req *connect.Request[session.CreateSessionRequest]) (*connect.Response[session.CreateSessionResponse], error) {
checks, metadata, userAgent, lifetime, err := s.createSessionRequestToCommand(ctx, req) checks, metadata, userAgent, lifetime, err := s.createSessionRequestToCommand(ctx, req.Msg)
if err != nil { if err != nil {
return nil, err return nil, err
} }
challengeResponse, cmds, err := s.challengesToCommand(req.GetChallenges(), checks) challengeResponse, cmds, err := s.challengesToCommand(req.Msg.GetChallenges(), checks)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -71,43 +72,43 @@ func (s *Server) CreateSession(ctx context.Context, req *session.CreateSessionRe
return nil, err return nil, err
} }
return &session.CreateSessionResponse{ return connect.NewResponse(&session.CreateSessionResponse{
Details: object.DomainToDetailsPb(set.ObjectDetails), Details: object.DomainToDetailsPb(set.ObjectDetails),
SessionId: set.ID, SessionId: set.ID,
SessionToken: set.NewToken, SessionToken: set.NewToken,
Challenges: challengeResponse, Challenges: challengeResponse,
}, nil }), nil
} }
func (s *Server) SetSession(ctx context.Context, req *session.SetSessionRequest) (*session.SetSessionResponse, error) { func (s *Server) SetSession(ctx context.Context, req *connect.Request[session.SetSessionRequest]) (*connect.Response[session.SetSessionResponse], error) {
checks, err := s.setSessionRequestToCommand(ctx, req) checks, err := s.setSessionRequestToCommand(ctx, req.Msg)
if err != nil { if err != nil {
return nil, err return nil, err
} }
challengeResponse, cmds, err := s.challengesToCommand(req.GetChallenges(), checks) challengeResponse, cmds, err := s.challengesToCommand(req.Msg.GetChallenges(), checks)
if err != nil { if err != nil {
return nil, err return nil, err
} }
set, err := s.command.UpdateSession(ctx, req.GetSessionId(), cmds, req.GetMetadata(), req.GetLifetime().AsDuration()) set, err := s.command.UpdateSession(ctx, req.Msg.GetSessionId(), cmds, req.Msg.GetMetadata(), req.Msg.GetLifetime().AsDuration())
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &session.SetSessionResponse{ return connect.NewResponse(&session.SetSessionResponse{
Details: object.DomainToDetailsPb(set.ObjectDetails), Details: object.DomainToDetailsPb(set.ObjectDetails),
SessionToken: set.NewToken, SessionToken: set.NewToken,
Challenges: challengeResponse, Challenges: challengeResponse,
}, nil }), nil
} }
func (s *Server) DeleteSession(ctx context.Context, req *session.DeleteSessionRequest) (*session.DeleteSessionResponse, error) { func (s *Server) DeleteSession(ctx context.Context, req *connect.Request[session.DeleteSessionRequest]) (*connect.Response[session.DeleteSessionResponse], error) {
details, err := s.command.TerminateSession(ctx, req.GetSessionId(), req.GetSessionToken()) details, err := s.command.TerminateSession(ctx, req.Msg.GetSessionId(), req.Msg.GetSessionToken())
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &session.DeleteSessionResponse{ return connect.NewResponse(&session.DeleteSessionResponse{
Details: object.DomainToDetailsPb(details), Details: object.DomainToDetailsPb(details),
}, nil }), nil
} }
func sessionsToPb(sessions []*query.Session) []*session.Session { func sessionsToPb(sessions []*query.Session) []*session.Session {

View File

@@ -3,6 +3,7 @@ package settings
import ( import (
"context" "context"
"connectrpc.com/connect"
"google.golang.org/protobuf/types/known/timestamppb" "google.golang.org/protobuf/types/known/timestamppb"
"github.com/zitadel/zitadel/internal/api/authz" "github.com/zitadel/zitadel/internal/api/authz"
@@ -14,12 +15,12 @@ import (
"github.com/zitadel/zitadel/pkg/grpc/settings/v2" "github.com/zitadel/zitadel/pkg/grpc/settings/v2"
) )
func (s *Server) GetLoginSettings(ctx context.Context, req *settings.GetLoginSettingsRequest) (*settings.GetLoginSettingsResponse, error) { func (s *Server) GetLoginSettings(ctx context.Context, req *connect.Request[settings.GetLoginSettingsRequest]) (*connect.Response[settings.GetLoginSettingsResponse], error) {
current, err := s.query.LoginPolicyByID(ctx, true, object.ResourceOwnerFromReq(ctx, req.GetCtx()), false) current, err := s.query.LoginPolicyByID(ctx, true, object.ResourceOwnerFromReq(ctx, req.Msg.GetCtx()), false)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &settings.GetLoginSettingsResponse{ return connect.NewResponse(&settings.GetLoginSettingsResponse{
Settings: loginSettingsToPb(current), Settings: loginSettingsToPb(current),
Details: &object_pb.Details{ Details: &object_pb.Details{
Sequence: current.Sequence, Sequence: current.Sequence,
@@ -27,15 +28,15 @@ func (s *Server) GetLoginSettings(ctx context.Context, req *settings.GetLoginSet
ChangeDate: timestamppb.New(current.ChangeDate), ChangeDate: timestamppb.New(current.ChangeDate),
ResourceOwner: current.OrgID, ResourceOwner: current.OrgID,
}, },
}, nil }), nil
} }
func (s *Server) GetPasswordComplexitySettings(ctx context.Context, req *settings.GetPasswordComplexitySettingsRequest) (*settings.GetPasswordComplexitySettingsResponse, error) { func (s *Server) GetPasswordComplexitySettings(ctx context.Context, req *connect.Request[settings.GetPasswordComplexitySettingsRequest]) (*connect.Response[settings.GetPasswordComplexitySettingsResponse], error) {
current, err := s.query.PasswordComplexityPolicyByOrg(ctx, true, object.ResourceOwnerFromReq(ctx, req.GetCtx()), false) current, err := s.query.PasswordComplexityPolicyByOrg(ctx, true, object.ResourceOwnerFromReq(ctx, req.Msg.GetCtx()), false)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &settings.GetPasswordComplexitySettingsResponse{ return connect.NewResponse(&settings.GetPasswordComplexitySettingsResponse{
Settings: passwordComplexitySettingsToPb(current), Settings: passwordComplexitySettingsToPb(current),
Details: &object_pb.Details{ Details: &object_pb.Details{
Sequence: current.Sequence, Sequence: current.Sequence,
@@ -43,15 +44,15 @@ func (s *Server) GetPasswordComplexitySettings(ctx context.Context, req *setting
ChangeDate: timestamppb.New(current.ChangeDate), ChangeDate: timestamppb.New(current.ChangeDate),
ResourceOwner: current.ResourceOwner, ResourceOwner: current.ResourceOwner,
}, },
}, nil }), nil
} }
func (s *Server) GetPasswordExpirySettings(ctx context.Context, req *settings.GetPasswordExpirySettingsRequest) (*settings.GetPasswordExpirySettingsResponse, error) { func (s *Server) GetPasswordExpirySettings(ctx context.Context, req *connect.Request[settings.GetPasswordExpirySettingsRequest]) (*connect.Response[settings.GetPasswordExpirySettingsResponse], error) {
current, err := s.query.PasswordAgePolicyByOrg(ctx, true, object.ResourceOwnerFromReq(ctx, req.GetCtx()), false) current, err := s.query.PasswordAgePolicyByOrg(ctx, true, object.ResourceOwnerFromReq(ctx, req.Msg.GetCtx()), false)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &settings.GetPasswordExpirySettingsResponse{ return connect.NewResponse(&settings.GetPasswordExpirySettingsResponse{
Settings: passwordExpirySettingsToPb(current), Settings: passwordExpirySettingsToPb(current),
Details: &object_pb.Details{ Details: &object_pb.Details{
Sequence: current.Sequence, Sequence: current.Sequence,
@@ -59,15 +60,15 @@ func (s *Server) GetPasswordExpirySettings(ctx context.Context, req *settings.Ge
ChangeDate: timestamppb.New(current.ChangeDate), ChangeDate: timestamppb.New(current.ChangeDate),
ResourceOwner: current.ResourceOwner, ResourceOwner: current.ResourceOwner,
}, },
}, nil }), nil
} }
func (s *Server) GetBrandingSettings(ctx context.Context, req *settings.GetBrandingSettingsRequest) (*settings.GetBrandingSettingsResponse, error) { func (s *Server) GetBrandingSettings(ctx context.Context, req *connect.Request[settings.GetBrandingSettingsRequest]) (*connect.Response[settings.GetBrandingSettingsResponse], error) {
current, err := s.query.ActiveLabelPolicyByOrg(ctx, object.ResourceOwnerFromReq(ctx, req.GetCtx()), false) current, err := s.query.ActiveLabelPolicyByOrg(ctx, object.ResourceOwnerFromReq(ctx, req.Msg.GetCtx()), false)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &settings.GetBrandingSettingsResponse{ return connect.NewResponse(&settings.GetBrandingSettingsResponse{
Settings: brandingSettingsToPb(current, s.assetsAPIDomain(ctx)), Settings: brandingSettingsToPb(current, s.assetsAPIDomain(ctx)),
Details: &object_pb.Details{ Details: &object_pb.Details{
Sequence: current.Sequence, Sequence: current.Sequence,
@@ -75,15 +76,15 @@ func (s *Server) GetBrandingSettings(ctx context.Context, req *settings.GetBrand
ChangeDate: timestamppb.New(current.ChangeDate), ChangeDate: timestamppb.New(current.ChangeDate),
ResourceOwner: current.ResourceOwner, ResourceOwner: current.ResourceOwner,
}, },
}, nil }), nil
} }
func (s *Server) GetDomainSettings(ctx context.Context, req *settings.GetDomainSettingsRequest) (*settings.GetDomainSettingsResponse, error) { func (s *Server) GetDomainSettings(ctx context.Context, req *connect.Request[settings.GetDomainSettingsRequest]) (*connect.Response[settings.GetDomainSettingsResponse], error) {
current, err := s.query.DomainPolicyByOrg(ctx, true, object.ResourceOwnerFromReq(ctx, req.GetCtx()), false) current, err := s.query.DomainPolicyByOrg(ctx, true, object.ResourceOwnerFromReq(ctx, req.Msg.GetCtx()), false)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &settings.GetDomainSettingsResponse{ return connect.NewResponse(&settings.GetDomainSettingsResponse{
Settings: domainSettingsToPb(current), Settings: domainSettingsToPb(current),
Details: &object_pb.Details{ Details: &object_pb.Details{
Sequence: current.Sequence, Sequence: current.Sequence,
@@ -91,15 +92,15 @@ func (s *Server) GetDomainSettings(ctx context.Context, req *settings.GetDomainS
ChangeDate: timestamppb.New(current.ChangeDate), ChangeDate: timestamppb.New(current.ChangeDate),
ResourceOwner: current.ResourceOwner, ResourceOwner: current.ResourceOwner,
}, },
}, nil }), nil
} }
func (s *Server) GetLegalAndSupportSettings(ctx context.Context, req *settings.GetLegalAndSupportSettingsRequest) (*settings.GetLegalAndSupportSettingsResponse, error) { func (s *Server) GetLegalAndSupportSettings(ctx context.Context, req *connect.Request[settings.GetLegalAndSupportSettingsRequest]) (*connect.Response[settings.GetLegalAndSupportSettingsResponse], error) {
current, err := s.query.PrivacyPolicyByOrg(ctx, true, object.ResourceOwnerFromReq(ctx, req.GetCtx()), false) current, err := s.query.PrivacyPolicyByOrg(ctx, true, object.ResourceOwnerFromReq(ctx, req.Msg.GetCtx()), false)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &settings.GetLegalAndSupportSettingsResponse{ return connect.NewResponse(&settings.GetLegalAndSupportSettingsResponse{
Settings: legalAndSupportSettingsToPb(current), Settings: legalAndSupportSettingsToPb(current),
Details: &object_pb.Details{ Details: &object_pb.Details{
Sequence: current.Sequence, Sequence: current.Sequence,
@@ -107,15 +108,15 @@ func (s *Server) GetLegalAndSupportSettings(ctx context.Context, req *settings.G
ChangeDate: timestamppb.New(current.ChangeDate), ChangeDate: timestamppb.New(current.ChangeDate),
ResourceOwner: current.ResourceOwner, ResourceOwner: current.ResourceOwner,
}, },
}, nil }), nil
} }
func (s *Server) GetLockoutSettings(ctx context.Context, req *settings.GetLockoutSettingsRequest) (*settings.GetLockoutSettingsResponse, error) { func (s *Server) GetLockoutSettings(ctx context.Context, req *connect.Request[settings.GetLockoutSettingsRequest]) (*connect.Response[settings.GetLockoutSettingsResponse], error) {
current, err := s.query.LockoutPolicyByOrg(ctx, true, object.ResourceOwnerFromReq(ctx, req.GetCtx())) current, err := s.query.LockoutPolicyByOrg(ctx, true, object.ResourceOwnerFromReq(ctx, req.Msg.GetCtx()))
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &settings.GetLockoutSettingsResponse{ return connect.NewResponse(&settings.GetLockoutSettingsResponse{
Settings: lockoutSettingsToPb(current), Settings: lockoutSettingsToPb(current),
Details: &object_pb.Details{ Details: &object_pb.Details{
Sequence: current.Sequence, Sequence: current.Sequence,
@@ -123,24 +124,24 @@ func (s *Server) GetLockoutSettings(ctx context.Context, req *settings.GetLockou
ChangeDate: timestamppb.New(current.ChangeDate), ChangeDate: timestamppb.New(current.ChangeDate),
ResourceOwner: current.ResourceOwner, ResourceOwner: current.ResourceOwner,
}, },
}, nil }), nil
} }
func (s *Server) GetActiveIdentityProviders(ctx context.Context, req *settings.GetActiveIdentityProvidersRequest) (*settings.GetActiveIdentityProvidersResponse, error) { func (s *Server) GetActiveIdentityProviders(ctx context.Context, req *connect.Request[settings.GetActiveIdentityProvidersRequest]) (*connect.Response[settings.GetActiveIdentityProvidersResponse], error) {
queries, err := activeIdentityProvidersToQuery(req) queries, err := activeIdentityProvidersToQuery(req.Msg)
if err != nil { if err != nil {
return nil, err return nil, err
} }
links, err := s.query.IDPLoginPolicyLinks(ctx, object.ResourceOwnerFromReq(ctx, req.GetCtx()), &query.IDPLoginPolicyLinksSearchQuery{Queries: queries}, false) links, err := s.query.IDPLoginPolicyLinks(ctx, object.ResourceOwnerFromReq(ctx, req.Msg.GetCtx()), &query.IDPLoginPolicyLinksSearchQuery{Queries: queries}, false)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &settings.GetActiveIdentityProvidersResponse{ return connect.NewResponse(&settings.GetActiveIdentityProvidersResponse{
Details: object.ToListDetails(links.SearchResponse), Details: object.ToListDetails(links.SearchResponse),
IdentityProviders: identityProvidersToPb(links.Links), IdentityProviders: identityProvidersToPb(links.Links),
}, nil }), nil
} }
func activeIdentityProvidersToQuery(req *settings.GetActiveIdentityProvidersRequest) (_ []query.SearchQuery, err error) { func activeIdentityProvidersToQuery(req *settings.GetActiveIdentityProvidersRequest) (_ []query.SearchQuery, err error) {
@@ -180,30 +181,30 @@ func activeIdentityProvidersToQuery(req *settings.GetActiveIdentityProvidersRequ
return q, nil return q, nil
} }
func (s *Server) GetGeneralSettings(ctx context.Context, _ *settings.GetGeneralSettingsRequest) (*settings.GetGeneralSettingsResponse, error) { func (s *Server) GetGeneralSettings(ctx context.Context, _ *connect.Request[settings.GetGeneralSettingsRequest]) (*connect.Response[settings.GetGeneralSettingsResponse], error) {
instance := authz.GetInstance(ctx) instance := authz.GetInstance(ctx)
return &settings.GetGeneralSettingsResponse{ return connect.NewResponse(&settings.GetGeneralSettingsResponse{
SupportedLanguages: domain.LanguagesToStrings(i18n.SupportedLanguages()), SupportedLanguages: domain.LanguagesToStrings(i18n.SupportedLanguages()),
DefaultOrgId: instance.DefaultOrganisationID(), DefaultOrgId: instance.DefaultOrganisationID(),
DefaultLanguage: instance.DefaultLanguage().String(), DefaultLanguage: instance.DefaultLanguage().String(),
}, nil }), nil
} }
func (s *Server) GetSecuritySettings(ctx context.Context, req *settings.GetSecuritySettingsRequest) (*settings.GetSecuritySettingsResponse, error) { func (s *Server) GetSecuritySettings(ctx context.Context, req *connect.Request[settings.GetSecuritySettingsRequest]) (*connect.Response[settings.GetSecuritySettingsResponse], error) {
policy, err := s.query.SecurityPolicy(ctx) policy, err := s.query.SecurityPolicy(ctx)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &settings.GetSecuritySettingsResponse{ return connect.NewResponse(&settings.GetSecuritySettingsResponse{
Settings: securityPolicyToSettingsPb(policy), Settings: securityPolicyToSettingsPb(policy),
}, nil }), nil
} }
func (s *Server) GetHostedLoginTranslation(ctx context.Context, req *settings.GetHostedLoginTranslationRequest) (*settings.GetHostedLoginTranslationResponse, error) { func (s *Server) GetHostedLoginTranslation(ctx context.Context, req *connect.Request[settings.GetHostedLoginTranslationRequest]) (*connect.Response[settings.GetHostedLoginTranslationResponse], error) {
translation, err := s.query.GetHostedLoginTranslation(ctx, req) translation, err := s.query.GetHostedLoginTranslation(ctx, req.Msg)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return translation, nil return connect.NewResponse(translation), nil
} }

View File

@@ -2,8 +2,10 @@ package settings
import ( import (
"context" "context"
"net/http"
"google.golang.org/grpc" "connectrpc.com/connect"
"google.golang.org/protobuf/reflect/protoreflect"
"github.com/zitadel/zitadel/internal/api/assets" "github.com/zitadel/zitadel/internal/api/assets"
"github.com/zitadel/zitadel/internal/api/authz" "github.com/zitadel/zitadel/internal/api/authz"
@@ -11,12 +13,12 @@ import (
"github.com/zitadel/zitadel/internal/command" "github.com/zitadel/zitadel/internal/command"
"github.com/zitadel/zitadel/internal/query" "github.com/zitadel/zitadel/internal/query"
"github.com/zitadel/zitadel/pkg/grpc/settings/v2" "github.com/zitadel/zitadel/pkg/grpc/settings/v2"
"github.com/zitadel/zitadel/pkg/grpc/settings/v2/settingsconnect"
) )
var _ settings.SettingsServiceServer = (*Server)(nil) var _ settingsconnect.SettingsServiceHandler = (*Server)(nil)
type Server struct { type Server struct {
settings.UnimplementedSettingsServiceServer
command *command.Commands command *command.Commands
query *query.Queries query *query.Queries
assetsAPIDomain func(context.Context) string assetsAPIDomain func(context.Context) string
@@ -35,8 +37,12 @@ func CreateServer(
} }
} }
func (s *Server) RegisterServer(grpcServer *grpc.Server) { func (s *Server) RegisterConnectServer(interceptors ...connect.Interceptor) (string, http.Handler) {
settings.RegisterSettingsServiceServer(grpcServer, s) return settingsconnect.NewSettingsServiceHandler(s, connect.WithInterceptors(interceptors...))
}
func (s *Server) FileDescriptor() protoreflect.FileDescriptor {
return settings.File_zitadel_settings_v2_settings_service_proto
} }
func (s *Server) AppName() string { func (s *Server) AppName() string {

View File

@@ -3,25 +3,27 @@ package settings
import ( import (
"context" "context"
"connectrpc.com/connect"
"github.com/zitadel/zitadel/internal/api/grpc/object/v2" "github.com/zitadel/zitadel/internal/api/grpc/object/v2"
"github.com/zitadel/zitadel/pkg/grpc/settings/v2" "github.com/zitadel/zitadel/pkg/grpc/settings/v2"
) )
func (s *Server) SetSecuritySettings(ctx context.Context, req *settings.SetSecuritySettingsRequest) (*settings.SetSecuritySettingsResponse, error) { func (s *Server) SetSecuritySettings(ctx context.Context, req *connect.Request[settings.SetSecuritySettingsRequest]) (*connect.Response[settings.SetSecuritySettingsResponse], error) {
details, err := s.command.SetSecurityPolicy(ctx, securitySettingsToCommand(req)) details, err := s.command.SetSecurityPolicy(ctx, securitySettingsToCommand(req.Msg))
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &settings.SetSecuritySettingsResponse{ return connect.NewResponse(&settings.SetSecuritySettingsResponse{
Details: object.DomainToDetailsPb(details), Details: object.DomainToDetailsPb(details),
}, nil }), nil
} }
func (s *Server) SetHostedLoginTranslation(ctx context.Context, req *settings.SetHostedLoginTranslationRequest) (*settings.SetHostedLoginTranslationResponse, error) { func (s *Server) SetHostedLoginTranslation(ctx context.Context, req *connect.Request[settings.SetHostedLoginTranslationRequest]) (*connect.Response[settings.SetHostedLoginTranslationResponse], error) {
res, err := s.command.SetHostedLoginTranslation(ctx, req) res, err := s.command.SetHostedLoginTranslation(ctx, req.Msg)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return res, nil return connect.NewResponse(res), nil
} }

View File

@@ -2,8 +2,10 @@ package settings
import ( import (
"context" "context"
"net/http"
"google.golang.org/grpc" "connectrpc.com/connect"
"google.golang.org/protobuf/reflect/protoreflect"
"github.com/zitadel/zitadel/internal/api/assets" "github.com/zitadel/zitadel/internal/api/assets"
"github.com/zitadel/zitadel/internal/api/authz" "github.com/zitadel/zitadel/internal/api/authz"
@@ -11,12 +13,12 @@ import (
"github.com/zitadel/zitadel/internal/command" "github.com/zitadel/zitadel/internal/command"
"github.com/zitadel/zitadel/internal/query" "github.com/zitadel/zitadel/internal/query"
settings "github.com/zitadel/zitadel/pkg/grpc/settings/v2beta" settings "github.com/zitadel/zitadel/pkg/grpc/settings/v2beta"
"github.com/zitadel/zitadel/pkg/grpc/settings/v2beta/settingsconnect"
) )
var _ settings.SettingsServiceServer = (*Server)(nil) var _ settingsconnect.SettingsServiceHandler = (*Server)(nil)
type Server struct { type Server struct {
settings.UnimplementedSettingsServiceServer
command *command.Commands command *command.Commands
query *query.Queries query *query.Queries
assetsAPIDomain func(context.Context) string assetsAPIDomain func(context.Context) string
@@ -35,8 +37,12 @@ func CreateServer(
} }
} }
func (s *Server) RegisterServer(grpcServer *grpc.Server) { func (s *Server) RegisterConnectServer(interceptors ...connect.Interceptor) (string, http.Handler) {
settings.RegisterSettingsServiceServer(grpcServer, s) return settingsconnect.NewSettingsServiceHandler(s, connect.WithInterceptors(interceptors...))
}
func (s *Server) FileDescriptor() protoreflect.FileDescriptor {
return settings.File_zitadel_settings_v2beta_settings_service_proto
} }
func (s *Server) AppName() string { func (s *Server) AppName() string {

View File

@@ -3,6 +3,7 @@ package settings
import ( import (
"context" "context"
"connectrpc.com/connect"
"google.golang.org/protobuf/types/known/timestamppb" "google.golang.org/protobuf/types/known/timestamppb"
"github.com/zitadel/zitadel/internal/api/authz" "github.com/zitadel/zitadel/internal/api/authz"
@@ -14,12 +15,12 @@ import (
settings "github.com/zitadel/zitadel/pkg/grpc/settings/v2beta" settings "github.com/zitadel/zitadel/pkg/grpc/settings/v2beta"
) )
func (s *Server) GetLoginSettings(ctx context.Context, req *settings.GetLoginSettingsRequest) (*settings.GetLoginSettingsResponse, error) { func (s *Server) GetLoginSettings(ctx context.Context, req *connect.Request[settings.GetLoginSettingsRequest]) (*connect.Response[settings.GetLoginSettingsResponse], error) {
current, err := s.query.LoginPolicyByID(ctx, true, object.ResourceOwnerFromReq(ctx, req.GetCtx()), false) current, err := s.query.LoginPolicyByID(ctx, true, object.ResourceOwnerFromReq(ctx, req.Msg.GetCtx()), false)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &settings.GetLoginSettingsResponse{ return connect.NewResponse(&settings.GetLoginSettingsResponse{
Settings: loginSettingsToPb(current), Settings: loginSettingsToPb(current),
Details: &object_pb.Details{ Details: &object_pb.Details{
Sequence: current.Sequence, Sequence: current.Sequence,
@@ -27,15 +28,15 @@ func (s *Server) GetLoginSettings(ctx context.Context, req *settings.GetLoginSet
ChangeDate: timestamppb.New(current.ChangeDate), ChangeDate: timestamppb.New(current.ChangeDate),
ResourceOwner: current.OrgID, ResourceOwner: current.OrgID,
}, },
}, nil }), nil
} }
func (s *Server) GetPasswordComplexitySettings(ctx context.Context, req *settings.GetPasswordComplexitySettingsRequest) (*settings.GetPasswordComplexitySettingsResponse, error) { func (s *Server) GetPasswordComplexitySettings(ctx context.Context, req *connect.Request[settings.GetPasswordComplexitySettingsRequest]) (*connect.Response[settings.GetPasswordComplexitySettingsResponse], error) {
current, err := s.query.PasswordComplexityPolicyByOrg(ctx, true, object.ResourceOwnerFromReq(ctx, req.GetCtx()), false) current, err := s.query.PasswordComplexityPolicyByOrg(ctx, true, object.ResourceOwnerFromReq(ctx, req.Msg.GetCtx()), false)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &settings.GetPasswordComplexitySettingsResponse{ return connect.NewResponse(&settings.GetPasswordComplexitySettingsResponse{
Settings: passwordComplexitySettingsToPb(current), Settings: passwordComplexitySettingsToPb(current),
Details: &object_pb.Details{ Details: &object_pb.Details{
Sequence: current.Sequence, Sequence: current.Sequence,
@@ -43,15 +44,15 @@ func (s *Server) GetPasswordComplexitySettings(ctx context.Context, req *setting
ChangeDate: timestamppb.New(current.ChangeDate), ChangeDate: timestamppb.New(current.ChangeDate),
ResourceOwner: current.ResourceOwner, ResourceOwner: current.ResourceOwner,
}, },
}, nil }), nil
} }
func (s *Server) GetPasswordExpirySettings(ctx context.Context, req *settings.GetPasswordExpirySettingsRequest) (*settings.GetPasswordExpirySettingsResponse, error) { func (s *Server) GetPasswordExpirySettings(ctx context.Context, req *connect.Request[settings.GetPasswordExpirySettingsRequest]) (*connect.Response[settings.GetPasswordExpirySettingsResponse], error) {
current, err := s.query.PasswordAgePolicyByOrg(ctx, true, object.ResourceOwnerFromReq(ctx, req.GetCtx()), false) current, err := s.query.PasswordAgePolicyByOrg(ctx, true, object.ResourceOwnerFromReq(ctx, req.Msg.GetCtx()), false)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &settings.GetPasswordExpirySettingsResponse{ return connect.NewResponse(&settings.GetPasswordExpirySettingsResponse{
Settings: passwordExpirySettingsToPb(current), Settings: passwordExpirySettingsToPb(current),
Details: &object_pb.Details{ Details: &object_pb.Details{
Sequence: current.Sequence, Sequence: current.Sequence,
@@ -59,15 +60,15 @@ func (s *Server) GetPasswordExpirySettings(ctx context.Context, req *settings.Ge
ChangeDate: timestamppb.New(current.ChangeDate), ChangeDate: timestamppb.New(current.ChangeDate),
ResourceOwner: current.ResourceOwner, ResourceOwner: current.ResourceOwner,
}, },
}, nil }), nil
} }
func (s *Server) GetBrandingSettings(ctx context.Context, req *settings.GetBrandingSettingsRequest) (*settings.GetBrandingSettingsResponse, error) { func (s *Server) GetBrandingSettings(ctx context.Context, req *connect.Request[settings.GetBrandingSettingsRequest]) (*connect.Response[settings.GetBrandingSettingsResponse], error) {
current, err := s.query.ActiveLabelPolicyByOrg(ctx, object.ResourceOwnerFromReq(ctx, req.GetCtx()), false) current, err := s.query.ActiveLabelPolicyByOrg(ctx, object.ResourceOwnerFromReq(ctx, req.Msg.GetCtx()), false)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &settings.GetBrandingSettingsResponse{ return connect.NewResponse(&settings.GetBrandingSettingsResponse{
Settings: brandingSettingsToPb(current, s.assetsAPIDomain(ctx)), Settings: brandingSettingsToPb(current, s.assetsAPIDomain(ctx)),
Details: &object_pb.Details{ Details: &object_pb.Details{
Sequence: current.Sequence, Sequence: current.Sequence,
@@ -75,15 +76,15 @@ func (s *Server) GetBrandingSettings(ctx context.Context, req *settings.GetBrand
ChangeDate: timestamppb.New(current.ChangeDate), ChangeDate: timestamppb.New(current.ChangeDate),
ResourceOwner: current.ResourceOwner, ResourceOwner: current.ResourceOwner,
}, },
}, nil }), nil
} }
func (s *Server) GetDomainSettings(ctx context.Context, req *settings.GetDomainSettingsRequest) (*settings.GetDomainSettingsResponse, error) { func (s *Server) GetDomainSettings(ctx context.Context, req *connect.Request[settings.GetDomainSettingsRequest]) (*connect.Response[settings.GetDomainSettingsResponse], error) {
current, err := s.query.DomainPolicyByOrg(ctx, true, object.ResourceOwnerFromReq(ctx, req.GetCtx()), false) current, err := s.query.DomainPolicyByOrg(ctx, true, object.ResourceOwnerFromReq(ctx, req.Msg.GetCtx()), false)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &settings.GetDomainSettingsResponse{ return connect.NewResponse(&settings.GetDomainSettingsResponse{
Settings: domainSettingsToPb(current), Settings: domainSettingsToPb(current),
Details: &object_pb.Details{ Details: &object_pb.Details{
Sequence: current.Sequence, Sequence: current.Sequence,
@@ -91,15 +92,15 @@ func (s *Server) GetDomainSettings(ctx context.Context, req *settings.GetDomainS
ChangeDate: timestamppb.New(current.ChangeDate), ChangeDate: timestamppb.New(current.ChangeDate),
ResourceOwner: current.ResourceOwner, ResourceOwner: current.ResourceOwner,
}, },
}, nil }), nil
} }
func (s *Server) GetLegalAndSupportSettings(ctx context.Context, req *settings.GetLegalAndSupportSettingsRequest) (*settings.GetLegalAndSupportSettingsResponse, error) { func (s *Server) GetLegalAndSupportSettings(ctx context.Context, req *connect.Request[settings.GetLegalAndSupportSettingsRequest]) (*connect.Response[settings.GetLegalAndSupportSettingsResponse], error) {
current, err := s.query.PrivacyPolicyByOrg(ctx, true, object.ResourceOwnerFromReq(ctx, req.GetCtx()), false) current, err := s.query.PrivacyPolicyByOrg(ctx, true, object.ResourceOwnerFromReq(ctx, req.Msg.GetCtx()), false)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &settings.GetLegalAndSupportSettingsResponse{ return connect.NewResponse(&settings.GetLegalAndSupportSettingsResponse{
Settings: legalAndSupportSettingsToPb(current), Settings: legalAndSupportSettingsToPb(current),
Details: &object_pb.Details{ Details: &object_pb.Details{
Sequence: current.Sequence, Sequence: current.Sequence,
@@ -107,15 +108,15 @@ func (s *Server) GetLegalAndSupportSettings(ctx context.Context, req *settings.G
ChangeDate: timestamppb.New(current.ChangeDate), ChangeDate: timestamppb.New(current.ChangeDate),
ResourceOwner: current.ResourceOwner, ResourceOwner: current.ResourceOwner,
}, },
}, nil }), nil
} }
func (s *Server) GetLockoutSettings(ctx context.Context, req *settings.GetLockoutSettingsRequest) (*settings.GetLockoutSettingsResponse, error) { func (s *Server) GetLockoutSettings(ctx context.Context, req *connect.Request[settings.GetLockoutSettingsRequest]) (*connect.Response[settings.GetLockoutSettingsResponse], error) {
current, err := s.query.LockoutPolicyByOrg(ctx, true, object.ResourceOwnerFromReq(ctx, req.GetCtx())) current, err := s.query.LockoutPolicyByOrg(ctx, true, object.ResourceOwnerFromReq(ctx, req.Msg.GetCtx()))
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &settings.GetLockoutSettingsResponse{ return connect.NewResponse(&settings.GetLockoutSettingsResponse{
Settings: lockoutSettingsToPb(current), Settings: lockoutSettingsToPb(current),
Details: &object_pb.Details{ Details: &object_pb.Details{
Sequence: current.Sequence, Sequence: current.Sequence,
@@ -123,46 +124,46 @@ func (s *Server) GetLockoutSettings(ctx context.Context, req *settings.GetLockou
ChangeDate: timestamppb.New(current.ChangeDate), ChangeDate: timestamppb.New(current.ChangeDate),
ResourceOwner: current.ResourceOwner, ResourceOwner: current.ResourceOwner,
}, },
}, nil }), nil
} }
func (s *Server) GetActiveIdentityProviders(ctx context.Context, req *settings.GetActiveIdentityProvidersRequest) (*settings.GetActiveIdentityProvidersResponse, error) { func (s *Server) GetActiveIdentityProviders(ctx context.Context, req *connect.Request[settings.GetActiveIdentityProvidersRequest]) (*connect.Response[settings.GetActiveIdentityProvidersResponse], error) {
links, err := s.query.IDPLoginPolicyLinks(ctx, object.ResourceOwnerFromReq(ctx, req.GetCtx()), &query.IDPLoginPolicyLinksSearchQuery{}, false) links, err := s.query.IDPLoginPolicyLinks(ctx, object.ResourceOwnerFromReq(ctx, req.Msg.GetCtx()), &query.IDPLoginPolicyLinksSearchQuery{}, false)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &settings.GetActiveIdentityProvidersResponse{ return connect.NewResponse(&settings.GetActiveIdentityProvidersResponse{
Details: object.ToListDetails(links.SearchResponse), Details: object.ToListDetails(links.SearchResponse),
IdentityProviders: identityProvidersToPb(links.Links), IdentityProviders: identityProvidersToPb(links.Links),
}, nil }), nil
} }
func (s *Server) GetGeneralSettings(ctx context.Context, _ *settings.GetGeneralSettingsRequest) (*settings.GetGeneralSettingsResponse, error) { func (s *Server) GetGeneralSettings(ctx context.Context, _ *connect.Request[settings.GetGeneralSettingsRequest]) (*connect.Response[settings.GetGeneralSettingsResponse], error) {
instance := authz.GetInstance(ctx) instance := authz.GetInstance(ctx)
return &settings.GetGeneralSettingsResponse{ return connect.NewResponse(&settings.GetGeneralSettingsResponse{
SupportedLanguages: domain.LanguagesToStrings(i18n.SupportedLanguages()), SupportedLanguages: domain.LanguagesToStrings(i18n.SupportedLanguages()),
DefaultOrgId: instance.DefaultOrganisationID(), DefaultOrgId: instance.DefaultOrganisationID(),
DefaultLanguage: instance.DefaultLanguage().String(), DefaultLanguage: instance.DefaultLanguage().String(),
}, nil }), nil
} }
func (s *Server) GetSecuritySettings(ctx context.Context, req *settings.GetSecuritySettingsRequest) (*settings.GetSecuritySettingsResponse, error) { func (s *Server) GetSecuritySettings(ctx context.Context, req *connect.Request[settings.GetSecuritySettingsRequest]) (*connect.Response[settings.GetSecuritySettingsResponse], error) {
policy, err := s.query.SecurityPolicy(ctx) policy, err := s.query.SecurityPolicy(ctx)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &settings.GetSecuritySettingsResponse{ return connect.NewResponse(&settings.GetSecuritySettingsResponse{
Settings: securityPolicyToSettingsPb(policy), Settings: securityPolicyToSettingsPb(policy),
}, nil }), nil
} }
func (s *Server) SetSecuritySettings(ctx context.Context, req *settings.SetSecuritySettingsRequest) (*settings.SetSecuritySettingsResponse, error) { func (s *Server) SetSecuritySettings(ctx context.Context, req *connect.Request[settings.SetSecuritySettingsRequest]) (*connect.Response[settings.SetSecuritySettingsResponse], error) {
details, err := s.command.SetSecurityPolicy(ctx, securitySettingsToCommand(req)) details, err := s.command.SetSecurityPolicy(ctx, securitySettingsToCommand(req.Msg))
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &settings.SetSecuritySettingsResponse{ return connect.NewResponse(&settings.SetSecuritySettingsResponse{
Details: object.DomainToDetailsPb(details), Details: object.DomainToDetailsPb(details),
}, nil }), nil
} }

View File

@@ -3,6 +3,7 @@ package user
import ( import (
"context" "context"
"connectrpc.com/connect"
"google.golang.org/protobuf/types/known/timestamppb" "google.golang.org/protobuf/types/known/timestamppb"
"github.com/zitadel/zitadel/internal/domain" "github.com/zitadel/zitadel/internal/domain"
@@ -11,18 +12,18 @@ import (
"github.com/zitadel/zitadel/pkg/grpc/user/v2" "github.com/zitadel/zitadel/pkg/grpc/user/v2"
) )
func (s *Server) SetEmail(ctx context.Context, req *user.SetEmailRequest) (resp *user.SetEmailResponse, err error) { func (s *Server) SetEmail(ctx context.Context, req *connect.Request[user.SetEmailRequest]) (resp *connect.Response[user.SetEmailResponse], err error) {
var email *domain.Email var email *domain.Email
switch v := req.GetVerification().(type) { switch v := req.Msg.GetVerification().(type) {
case *user.SetEmailRequest_SendCode: case *user.SetEmailRequest_SendCode:
email, err = s.command.ChangeUserEmailURLTemplate(ctx, req.GetUserId(), req.GetEmail(), s.userCodeAlg, v.SendCode.GetUrlTemplate()) email, err = s.command.ChangeUserEmailURLTemplate(ctx, req.Msg.GetUserId(), req.Msg.GetEmail(), s.userCodeAlg, v.SendCode.GetUrlTemplate())
case *user.SetEmailRequest_ReturnCode: case *user.SetEmailRequest_ReturnCode:
email, err = s.command.ChangeUserEmailReturnCode(ctx, req.GetUserId(), req.GetEmail(), s.userCodeAlg) email, err = s.command.ChangeUserEmailReturnCode(ctx, req.Msg.GetUserId(), req.Msg.GetEmail(), s.userCodeAlg)
case *user.SetEmailRequest_IsVerified: case *user.SetEmailRequest_IsVerified:
email, err = s.command.ChangeUserEmailVerified(ctx, req.GetUserId(), req.GetEmail()) email, err = s.command.ChangeUserEmailVerified(ctx, req.Msg.GetUserId(), req.Msg.GetEmail())
case nil: case nil:
email, err = s.command.ChangeUserEmail(ctx, req.GetUserId(), req.GetEmail(), s.userCodeAlg) email, err = s.command.ChangeUserEmail(ctx, req.Msg.GetUserId(), req.Msg.GetEmail(), s.userCodeAlg)
default: default:
err = zerrors.ThrowUnimplementedf(nil, "USERv2-Ahng0", "verification oneOf %T in method SetEmail not implemented", v) err = zerrors.ThrowUnimplementedf(nil, "USERv2-Ahng0", "verification oneOf %T in method SetEmail not implemented", v)
} }
@@ -30,26 +31,26 @@ func (s *Server) SetEmail(ctx context.Context, req *user.SetEmailRequest) (resp
return nil, err return nil, err
} }
return &user.SetEmailResponse{ return connect.NewResponse(&user.SetEmailResponse{
Details: &object.Details{ Details: &object.Details{
Sequence: email.Sequence, Sequence: email.Sequence,
ChangeDate: timestamppb.New(email.ChangeDate), ChangeDate: timestamppb.New(email.ChangeDate),
ResourceOwner: email.ResourceOwner, ResourceOwner: email.ResourceOwner,
}, },
VerificationCode: email.PlainCode, VerificationCode: email.PlainCode,
}, nil }), nil
} }
func (s *Server) ResendEmailCode(ctx context.Context, req *user.ResendEmailCodeRequest) (resp *user.ResendEmailCodeResponse, err error) { func (s *Server) ResendEmailCode(ctx context.Context, req *connect.Request[user.ResendEmailCodeRequest]) (resp *connect.Response[user.ResendEmailCodeResponse], err error) {
var email *domain.Email var email *domain.Email
switch v := req.GetVerification().(type) { switch v := req.Msg.GetVerification().(type) {
case *user.ResendEmailCodeRequest_SendCode: case *user.ResendEmailCodeRequest_SendCode:
email, err = s.command.ResendUserEmailCodeURLTemplate(ctx, req.GetUserId(), s.userCodeAlg, v.SendCode.GetUrlTemplate()) email, err = s.command.ResendUserEmailCodeURLTemplate(ctx, req.Msg.GetUserId(), s.userCodeAlg, v.SendCode.GetUrlTemplate())
case *user.ResendEmailCodeRequest_ReturnCode: case *user.ResendEmailCodeRequest_ReturnCode:
email, err = s.command.ResendUserEmailReturnCode(ctx, req.GetUserId(), s.userCodeAlg) email, err = s.command.ResendUserEmailReturnCode(ctx, req.Msg.GetUserId(), s.userCodeAlg)
case nil: case nil:
email, err = s.command.ResendUserEmailCode(ctx, req.GetUserId(), s.userCodeAlg) email, err = s.command.ResendUserEmailCode(ctx, req.Msg.GetUserId(), s.userCodeAlg)
default: default:
err = zerrors.ThrowUnimplementedf(nil, "USERv2-faj0l0nj5x", "verification oneOf %T in method ResendEmailCode not implemented", v) err = zerrors.ThrowUnimplementedf(nil, "USERv2-faj0l0nj5x", "verification oneOf %T in method ResendEmailCode not implemented", v)
} }
@@ -57,26 +58,26 @@ func (s *Server) ResendEmailCode(ctx context.Context, req *user.ResendEmailCodeR
return nil, err return nil, err
} }
return &user.ResendEmailCodeResponse{ return connect.NewResponse(&user.ResendEmailCodeResponse{
Details: &object.Details{ Details: &object.Details{
Sequence: email.Sequence, Sequence: email.Sequence,
ChangeDate: timestamppb.New(email.ChangeDate), ChangeDate: timestamppb.New(email.ChangeDate),
ResourceOwner: email.ResourceOwner, ResourceOwner: email.ResourceOwner,
}, },
VerificationCode: email.PlainCode, VerificationCode: email.PlainCode,
}, nil }), nil
} }
func (s *Server) SendEmailCode(ctx context.Context, req *user.SendEmailCodeRequest) (resp *user.SendEmailCodeResponse, err error) { func (s *Server) SendEmailCode(ctx context.Context, req *connect.Request[user.SendEmailCodeRequest]) (resp *connect.Response[user.SendEmailCodeResponse], err error) {
var email *domain.Email var email *domain.Email
switch v := req.GetVerification().(type) { switch v := req.Msg.GetVerification().(type) {
case *user.SendEmailCodeRequest_SendCode: case *user.SendEmailCodeRequest_SendCode:
email, err = s.command.SendUserEmailCodeURLTemplate(ctx, req.GetUserId(), s.userCodeAlg, v.SendCode.GetUrlTemplate()) email, err = s.command.SendUserEmailCodeURLTemplate(ctx, req.Msg.GetUserId(), s.userCodeAlg, v.SendCode.GetUrlTemplate())
case *user.SendEmailCodeRequest_ReturnCode: case *user.SendEmailCodeRequest_ReturnCode:
email, err = s.command.SendUserEmailReturnCode(ctx, req.GetUserId(), s.userCodeAlg) email, err = s.command.SendUserEmailReturnCode(ctx, req.Msg.GetUserId(), s.userCodeAlg)
case nil: case nil:
email, err = s.command.SendUserEmailCode(ctx, req.GetUserId(), s.userCodeAlg) email, err = s.command.SendUserEmailCode(ctx, req.Msg.GetUserId(), s.userCodeAlg)
default: default:
err = zerrors.ThrowUnimplementedf(nil, "USERv2-faj0l0nj5x", "verification oneOf %T in method SendEmailCode not implemented", v) err = zerrors.ThrowUnimplementedf(nil, "USERv2-faj0l0nj5x", "verification oneOf %T in method SendEmailCode not implemented", v)
} }
@@ -84,30 +85,30 @@ func (s *Server) SendEmailCode(ctx context.Context, req *user.SendEmailCodeReque
return nil, err return nil, err
} }
return &user.SendEmailCodeResponse{ return connect.NewResponse(&user.SendEmailCodeResponse{
Details: &object.Details{ Details: &object.Details{
Sequence: email.Sequence, Sequence: email.Sequence,
ChangeDate: timestamppb.New(email.ChangeDate), ChangeDate: timestamppb.New(email.ChangeDate),
ResourceOwner: email.ResourceOwner, ResourceOwner: email.ResourceOwner,
}, },
VerificationCode: email.PlainCode, VerificationCode: email.PlainCode,
}, nil }), nil
} }
func (s *Server) VerifyEmail(ctx context.Context, req *user.VerifyEmailRequest) (*user.VerifyEmailResponse, error) { func (s *Server) VerifyEmail(ctx context.Context, req *connect.Request[user.VerifyEmailRequest]) (*connect.Response[user.VerifyEmailResponse], error) {
details, err := s.command.VerifyUserEmail(ctx, details, err := s.command.VerifyUserEmail(ctx,
req.GetUserId(), req.Msg.GetUserId(),
req.GetVerificationCode(), req.Msg.GetVerificationCode(),
s.userCodeAlg, s.userCodeAlg,
) )
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &user.VerifyEmailResponse{ return connect.NewResponse(&user.VerifyEmailResponse{
Details: &object.Details{ Details: &object.Details{
Sequence: details.Sequence, Sequence: details.Sequence,
ChangeDate: timestamppb.New(details.EventDate), ChangeDate: timestamppb.New(details.EventDate),
ResourceOwner: details.ResourceOwner, ResourceOwner: details.ResourceOwner,
}, },
}, nil }), nil
} }

View File

@@ -4,6 +4,7 @@ import (
"context" "context"
"io" "io"
"connectrpc.com/connect"
"golang.org/x/text/language" "golang.org/x/text/language"
"google.golang.org/protobuf/types/known/timestamppb" "google.golang.org/protobuf/types/known/timestamppb"
@@ -14,7 +15,7 @@ import (
"github.com/zitadel/zitadel/pkg/grpc/user/v2" "github.com/zitadel/zitadel/pkg/grpc/user/v2"
) )
func (s *Server) createUserTypeHuman(ctx context.Context, humanPb *user.CreateUserRequest_Human, orgId string, userName, userId *string) (*user.CreateUserResponse, error) { func (s *Server) createUserTypeHuman(ctx context.Context, humanPb *user.CreateUserRequest_Human, orgId string, userName, userId *string) (*connect.Response[user.CreateUserResponse], error) {
addHumanPb := &user.AddHumanUserRequest{ addHumanPb := &user.AddHumanUserRequest{
Username: userName, Username: userName,
UserId: userId, UserId: userId,
@@ -52,15 +53,15 @@ func (s *Server) createUserTypeHuman(ctx context.Context, humanPb *user.CreateUs
); err != nil { ); err != nil {
return nil, err return nil, err
} }
return &user.CreateUserResponse{ return connect.NewResponse(&user.CreateUserResponse{
Id: newHuman.ID, Id: newHuman.ID,
CreationDate: timestamppb.New(newHuman.Details.EventDate), CreationDate: timestamppb.New(newHuman.Details.EventDate),
EmailCode: newHuman.EmailCode, EmailCode: newHuman.EmailCode,
PhoneCode: newHuman.PhoneCode, PhoneCode: newHuman.PhoneCode,
}, nil }), nil
} }
func (s *Server) updateUserTypeHuman(ctx context.Context, humanPb *user.UpdateUserRequest_Human, userId string, userName *string) (*user.UpdateUserResponse, error) { func (s *Server) updateUserTypeHuman(ctx context.Context, humanPb *user.UpdateUserRequest_Human, userId string, userName *string) (*connect.Response[user.UpdateUserResponse], error) {
cmd, err := updateHumanUserToCommand(userId, userName, humanPb) cmd, err := updateHumanUserToCommand(userId, userName, humanPb)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -68,11 +69,11 @@ func (s *Server) updateUserTypeHuman(ctx context.Context, humanPb *user.UpdateUs
if err = s.command.ChangeUserHuman(ctx, cmd, s.userCodeAlg); err != nil { if err = s.command.ChangeUserHuman(ctx, cmd, s.userCodeAlg); err != nil {
return nil, err return nil, err
} }
return &user.UpdateUserResponse{ return connect.NewResponse(&user.UpdateUserResponse{
ChangeDate: timestamppb.New(cmd.Details.EventDate), ChangeDate: timestamppb.New(cmd.Details.EventDate),
EmailCode: cmd.EmailCode, EmailCode: cmd.EmailCode,
PhoneCode: cmd.PhoneCode, PhoneCode: cmd.PhoneCode,
}, nil }), nil
} }
func updateHumanUserToCommand(userId string, userName *string, human *user.UpdateUserRequest_Human) (*command.ChangeHuman, error) { func updateHumanUserToCommand(userId string, userName *string, human *user.UpdateUserRequest_Human) (*command.ChangeHuman, error) {

View File

@@ -3,6 +3,8 @@ package user
import ( import (
"context" "context"
"connectrpc.com/connect"
"github.com/zitadel/zitadel/internal/api/grpc/object/v2" "github.com/zitadel/zitadel/internal/api/grpc/object/v2"
"github.com/zitadel/zitadel/internal/command" "github.com/zitadel/zitadel/internal/command"
"github.com/zitadel/zitadel/internal/domain" "github.com/zitadel/zitadel/internal/domain"
@@ -11,22 +13,22 @@ import (
"github.com/zitadel/zitadel/pkg/grpc/user/v2" "github.com/zitadel/zitadel/pkg/grpc/user/v2"
) )
func (s *Server) AddIDPLink(ctx context.Context, req *user.AddIDPLinkRequest) (_ *user.AddIDPLinkResponse, err error) { func (s *Server) AddIDPLink(ctx context.Context, req *connect.Request[user.AddIDPLinkRequest]) (_ *connect.Response[user.AddIDPLinkResponse], err error) {
details, err := s.command.AddUserIDPLink(ctx, req.UserId, "", &command.AddLink{ details, err := s.command.AddUserIDPLink(ctx, req.Msg.GetUserId(), "", &command.AddLink{
IDPID: req.GetIdpLink().GetIdpId(), IDPID: req.Msg.GetIdpLink().GetIdpId(),
DisplayName: req.GetIdpLink().GetUserName(), DisplayName: req.Msg.GetIdpLink().GetUserName(),
IDPExternalID: req.GetIdpLink().GetUserId(), IDPExternalID: req.Msg.GetIdpLink().GetUserId(),
}) })
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &user.AddIDPLinkResponse{ return connect.NewResponse(&user.AddIDPLinkResponse{
Details: object.DomainToDetailsPb(details), Details: object.DomainToDetailsPb(details),
}, nil }), nil
} }
func (s *Server) ListIDPLinks(ctx context.Context, req *user.ListIDPLinksRequest) (_ *user.ListIDPLinksResponse, err error) { func (s *Server) ListIDPLinks(ctx context.Context, req *connect.Request[user.ListIDPLinksRequest]) (_ *connect.Response[user.ListIDPLinksResponse], err error) {
queries, err := ListLinkedIDPsRequestToQuery(req) queries, err := ListLinkedIDPsRequestToQuery(req.Msg)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -34,10 +36,10 @@ func (s *Server) ListIDPLinks(ctx context.Context, req *user.ListIDPLinksRequest
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &user.ListIDPLinksResponse{ return connect.NewResponse(&user.ListIDPLinksResponse{
Result: IDPLinksToPb(res.Links), Result: IDPLinksToPb(res.Links),
Details: object.ToListDetails(res.SearchResponse), Details: object.ToListDetails(res.SearchResponse),
}, nil }), nil
} }
func ListLinkedIDPsRequestToQuery(req *user.ListIDPLinksRequest) (*query.IDPUserLinksSearchQuery, error) { func ListLinkedIDPsRequestToQuery(req *user.ListIDPLinksRequest) (*query.IDPUserLinksSearchQuery, error) {
@@ -72,14 +74,14 @@ func IDPLinkToPb(link *query.IDPUserLink) *user.IDPLink {
} }
} }
func (s *Server) RemoveIDPLink(ctx context.Context, req *user.RemoveIDPLinkRequest) (*user.RemoveIDPLinkResponse, error) { func (s *Server) RemoveIDPLink(ctx context.Context, req *connect.Request[user.RemoveIDPLinkRequest]) (*connect.Response[user.RemoveIDPLinkResponse], error) {
objectDetails, err := s.command.RemoveUserIDPLink(ctx, RemoveIDPLinkRequestToDomain(ctx, req)) objectDetails, err := s.command.RemoveUserIDPLink(ctx, RemoveIDPLinkRequestToDomain(ctx, req.Msg))
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &user.RemoveIDPLinkResponse{ return connect.NewResponse(&user.RemoveIDPLinkResponse{
Details: object.DomainToDetailsPb(objectDetails), Details: object.DomainToDetailsPb(objectDetails),
}, nil }), nil
} }
func RemoveIDPLinkRequestToDomain(ctx context.Context, req *user.RemoveIDPLinkRequest) *domain.UserIDPLink { func RemoveIDPLinkRequestToDomain(ctx context.Context, req *user.RemoveIDPLinkRequest) *domain.UserIDPLink {

View File

@@ -6,6 +6,7 @@ import (
"errors" "errors"
"time" "time"
"connectrpc.com/connect"
oidc_pkg "github.com/zitadel/oidc/v3/pkg/oidc" oidc_pkg "github.com/zitadel/oidc/v3/pkg/oidc"
"google.golang.org/protobuf/types/known/structpb" "google.golang.org/protobuf/types/known/structpb"
"google.golang.org/protobuf/types/known/timestamppb" "google.golang.org/protobuf/types/known/timestamppb"
@@ -32,18 +33,18 @@ import (
"github.com/zitadel/zitadel/pkg/grpc/user/v2" "github.com/zitadel/zitadel/pkg/grpc/user/v2"
) )
func (s *Server) StartIdentityProviderIntent(ctx context.Context, req *user.StartIdentityProviderIntentRequest) (_ *user.StartIdentityProviderIntentResponse, err error) { func (s *Server) StartIdentityProviderIntent(ctx context.Context, req *connect.Request[user.StartIdentityProviderIntentRequest]) (_ *connect.Response[user.StartIdentityProviderIntentResponse], err error) {
switch t := req.GetContent().(type) { switch t := req.Msg.GetContent().(type) {
case *user.StartIdentityProviderIntentRequest_Urls: case *user.StartIdentityProviderIntentRequest_Urls:
return s.startIDPIntent(ctx, req.GetIdpId(), t.Urls) return s.startIDPIntent(ctx, req.Msg.GetIdpId(), t.Urls)
case *user.StartIdentityProviderIntentRequest_Ldap: case *user.StartIdentityProviderIntentRequest_Ldap:
return s.startLDAPIntent(ctx, req.GetIdpId(), t.Ldap) return s.startLDAPIntent(ctx, req.Msg.GetIdpId(), t.Ldap)
default: default:
return nil, zerrors.ThrowUnimplementedf(nil, "USERv2-S2g21", "type oneOf %T in method StartIdentityProviderIntent not implemented", t) return nil, zerrors.ThrowUnimplementedf(nil, "USERv2-S2g21", "type oneOf %T in method StartIdentityProviderIntent not implemented", t)
} }
} }
func (s *Server) startIDPIntent(ctx context.Context, idpID string, urls *user.RedirectURLs) (*user.StartIdentityProviderIntentResponse, error) { func (s *Server) startIDPIntent(ctx context.Context, idpID string, urls *user.RedirectURLs) (*connect.Response[user.StartIdentityProviderIntentResponse], error) {
state, session, err := s.command.AuthFromProvider(ctx, idpID, s.idpCallback(ctx), s.samlRootURL(ctx, idpID)) state, session, err := s.command.AuthFromProvider(ctx, idpID, s.idpCallback(ctx), s.samlRootURL(ctx, idpID))
if err != nil { if err != nil {
return nil, err return nil, err
@@ -58,12 +59,12 @@ func (s *Server) startIDPIntent(ctx context.Context, idpID string, urls *user.Re
} }
switch a := auth.(type) { switch a := auth.(type) {
case *idp.RedirectAuth: case *idp.RedirectAuth:
return &user.StartIdentityProviderIntentResponse{ return connect.NewResponse(&user.StartIdentityProviderIntentResponse{
Details: object.DomainToDetailsPb(details), Details: object.DomainToDetailsPb(details),
NextStep: &user.StartIdentityProviderIntentResponse_AuthUrl{AuthUrl: a.RedirectURL}, NextStep: &user.StartIdentityProviderIntentResponse_AuthUrl{AuthUrl: a.RedirectURL},
}, nil }), nil
case *idp.FormAuth: case *idp.FormAuth:
return &user.StartIdentityProviderIntentResponse{ return connect.NewResponse(&user.StartIdentityProviderIntentResponse{
Details: object.DomainToDetailsPb(details), Details: object.DomainToDetailsPb(details),
NextStep: &user.StartIdentityProviderIntentResponse_FormData{ NextStep: &user.StartIdentityProviderIntentResponse_FormData{
FormData: &user.FormData{ FormData: &user.FormData{
@@ -71,12 +72,12 @@ func (s *Server) startIDPIntent(ctx context.Context, idpID string, urls *user.Re
Fields: a.Fields, Fields: a.Fields,
}, },
}, },
}, nil }), nil
} }
return nil, zerrors.ThrowInvalidArgumentf(nil, "USERv2-3g2j3", "type oneOf %T in method StartIdentityProviderIntent not implemented", auth) return nil, zerrors.ThrowInvalidArgumentf(nil, "USERv2-3g2j3", "type oneOf %T in method StartIdentityProviderIntent not implemented", auth)
} }
func (s *Server) startLDAPIntent(ctx context.Context, idpID string, ldapCredentials *user.LDAPCredentials) (*user.StartIdentityProviderIntentResponse, error) { func (s *Server) startLDAPIntent(ctx context.Context, idpID string, ldapCredentials *user.LDAPCredentials) (*connect.Response[user.StartIdentityProviderIntentResponse], error) {
intentWriteModel, details, err := s.command.CreateIntent(ctx, "", idpID, "", "", authz.GetInstance(ctx).InstanceID(), nil) intentWriteModel, details, err := s.command.CreateIntent(ctx, "", idpID, "", "", authz.GetInstance(ctx).InstanceID(), nil)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -92,7 +93,7 @@ func (s *Server) startLDAPIntent(ctx context.Context, idpID string, ldapCredenti
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &user.StartIdentityProviderIntentResponse{ return connect.NewResponse(&user.StartIdentityProviderIntentResponse{
Details: object.DomainToDetailsPb(details), Details: object.DomainToDetailsPb(details),
NextStep: &user.StartIdentityProviderIntentResponse_IdpIntent{ NextStep: &user.StartIdentityProviderIntentResponse_IdpIntent{
IdpIntent: &user.IDPIntent{ IdpIntent: &user.IDPIntent{
@@ -101,7 +102,7 @@ func (s *Server) startLDAPIntent(ctx context.Context, idpID string, ldapCredenti
UserId: userID, UserId: userID,
}, },
}, },
}, nil }), nil
} }
func (s *Server) checkLinkedExternalUser(ctx context.Context, idpID, externalUserID string) (string, error) { func (s *Server) checkLinkedExternalUser(ctx context.Context, idpID, externalUserID string) (string, error) {
@@ -150,12 +151,12 @@ func (s *Server) ldapLogin(ctx context.Context, idpID, username, password string
return externalUser, userID, session, nil return externalUser, userID, session, nil
} }
func (s *Server) RetrieveIdentityProviderIntent(ctx context.Context, req *user.RetrieveIdentityProviderIntentRequest) (_ *user.RetrieveIdentityProviderIntentResponse, err error) { func (s *Server) RetrieveIdentityProviderIntent(ctx context.Context, req *connect.Request[user.RetrieveIdentityProviderIntentRequest]) (_ *connect.Response[user.RetrieveIdentityProviderIntentResponse], err error) {
intent, err := s.command.GetIntentWriteModel(ctx, req.GetIdpIntentId(), "") intent, err := s.command.GetIntentWriteModel(ctx, req.Msg.GetIdpIntentId(), "")
if err != nil { if err != nil {
return nil, err return nil, err
} }
if err := s.checkIntentToken(req.GetIdpIntentToken(), intent.AggregateID); err != nil { if err := s.checkIntentToken(req.Msg.GetIdpIntentToken(), intent.AggregateID); err != nil {
return nil, err return nil, err
} }
if intent.State != domain.IDPIntentStateSucceeded { if intent.State != domain.IDPIntentStateSucceeded {
@@ -203,7 +204,7 @@ func (s *Server) RetrieveIdentityProviderIntent(ctx context.Context, req *user.R
} }
idpIntent.AddHumanUser = idpUserToAddHumanUser(idpUser, idpIntent.IdpInformation.IdpId) idpIntent.AddHumanUser = idpUserToAddHumanUser(idpUser, idpIntent.IdpInformation.IdpId)
} }
return idpIntent, nil return connect.NewResponse(idpIntent), nil
} }
type rawUserMapper struct { type rawUserMapper struct {

View File

@@ -3,6 +3,7 @@ package user
import ( import (
"context" "context"
"connectrpc.com/connect"
"google.golang.org/protobuf/types/known/timestamppb" "google.golang.org/protobuf/types/known/timestamppb"
"github.com/zitadel/zitadel/internal/command" "github.com/zitadel/zitadel/internal/command"
@@ -11,16 +12,16 @@ import (
"github.com/zitadel/zitadel/pkg/grpc/user/v2" "github.com/zitadel/zitadel/pkg/grpc/user/v2"
) )
func (s *Server) AddKey(ctx context.Context, req *user.AddKeyRequest) (*user.AddKeyResponse, error) { func (s *Server) AddKey(ctx context.Context, req *connect.Request[user.AddKeyRequest]) (*connect.Response[user.AddKeyResponse], error) {
newMachineKey := &command.MachineKey{ newMachineKey := &command.MachineKey{
ObjectRoot: models.ObjectRoot{ ObjectRoot: models.ObjectRoot{
AggregateID: req.UserId, AggregateID: req.Msg.GetUserId(),
}, },
ExpirationDate: req.GetExpirationDate().AsTime(), ExpirationDate: req.Msg.GetExpirationDate().AsTime(),
Type: domain.AuthNKeyTypeJSON, Type: domain.AuthNKeyTypeJSON,
PermissionCheck: s.command.NewPermissionCheckUserWrite(ctx), PermissionCheck: s.command.NewPermissionCheckUserWrite(ctx),
} }
newMachineKey.PublicKey = req.PublicKey newMachineKey.PublicKey = req.Msg.GetPublicKey()
pubkeySupplied := len(newMachineKey.PublicKey) > 0 pubkeySupplied := len(newMachineKey.PublicKey) > 0
details, err := s.command.AddUserMachineKey(ctx, newMachineKey) details, err := s.command.AddUserMachineKey(ctx, newMachineKey)
@@ -37,26 +38,26 @@ func (s *Server) AddKey(ctx context.Context, req *user.AddKeyRequest) (*user.Add
return nil, err return nil, err
} }
} }
return &user.AddKeyResponse{ return connect.NewResponse(&user.AddKeyResponse{
KeyId: newMachineKey.KeyID, KeyId: newMachineKey.KeyID,
KeyContent: keyDetails, KeyContent: keyDetails,
CreationDate: timestamppb.New(details.EventDate), CreationDate: timestamppb.New(details.EventDate),
}, nil }), nil
} }
func (s *Server) RemoveKey(ctx context.Context, req *user.RemoveKeyRequest) (*user.RemoveKeyResponse, error) { func (s *Server) RemoveKey(ctx context.Context, req *connect.Request[user.RemoveKeyRequest]) (*connect.Response[user.RemoveKeyResponse], error) {
machineKey := &command.MachineKey{ machineKey := &command.MachineKey{
ObjectRoot: models.ObjectRoot{ ObjectRoot: models.ObjectRoot{
AggregateID: req.UserId, AggregateID: req.Msg.GetUserId(),
}, },
PermissionCheck: s.command.NewPermissionCheckUserWrite(ctx), PermissionCheck: s.command.NewPermissionCheckUserWrite(ctx),
KeyID: req.KeyId, KeyID: req.Msg.GetKeyId(),
} }
objectDetails, err := s.command.RemoveUserMachineKey(ctx, machineKey) objectDetails, err := s.command.RemoveUserMachineKey(ctx, machineKey)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &user.RemoveKeyResponse{ return connect.NewResponse(&user.RemoveKeyResponse{
DeletionDate: timestamppb.New(objectDetails.EventDate), DeletionDate: timestamppb.New(objectDetails.EventDate),
}, nil }), nil
} }

View File

@@ -3,6 +3,7 @@ package user
import ( import (
"context" "context"
"connectrpc.com/connect"
"google.golang.org/protobuf/types/known/timestamppb" "google.golang.org/protobuf/types/known/timestamppb"
"github.com/zitadel/zitadel/internal/api/grpc/filter/v2" "github.com/zitadel/zitadel/internal/api/grpc/filter/v2"
@@ -12,13 +13,13 @@ import (
"github.com/zitadel/zitadel/pkg/grpc/user/v2" "github.com/zitadel/zitadel/pkg/grpc/user/v2"
) )
func (s *Server) ListKeys(ctx context.Context, req *user.ListKeysRequest) (*user.ListKeysResponse, error) { func (s *Server) ListKeys(ctx context.Context, req *connect.Request[user.ListKeysRequest]) (*connect.Response[user.ListKeysResponse], error) {
offset, limit, asc, err := filter.PaginationPbToQuery(s.systemDefaults, req.Pagination) offset, limit, asc, err := filter.PaginationPbToQuery(s.systemDefaults, req.Msg.GetPagination())
if err != nil { if err != nil {
return nil, err return nil, err
} }
filters, err := keyFiltersToQueries(req.Filters) filters, err := keyFiltersToQueries(req.Msg.GetFilters())
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -27,7 +28,7 @@ func (s *Server) ListKeys(ctx context.Context, req *user.ListKeysRequest) (*user
Offset: offset, Offset: offset,
Limit: limit, Limit: limit,
Asc: asc, Asc: asc,
SortingColumn: authnKeyFieldNameToSortingColumn(req.SortingColumn), SortingColumn: authnKeyFieldNameToSortingColumn(req.Msg.SortingColumn),
}, },
Queries: filters, Queries: filters,
} }
@@ -49,7 +50,7 @@ func (s *Server) ListKeys(ctx context.Context, req *user.ListKeysRequest) (*user
ExpirationDate: timestamppb.New(key.Expiration), ExpirationDate: timestamppb.New(key.Expiration),
} }
} }
return resp, nil return connect.NewResponse(resp), nil
} }
func keyFiltersToQueries(filters []*user.KeysSearchFilter) (_ []query.SearchQuery, err error) { func keyFiltersToQueries(filters []*user.KeysSearchFilter) (_ []query.SearchQuery, err error) {

View File

@@ -3,6 +3,7 @@ package user
import ( import (
"context" "context"
"connectrpc.com/connect"
"google.golang.org/protobuf/types/known/timestamppb" "google.golang.org/protobuf/types/known/timestamppb"
"github.com/zitadel/zitadel/internal/command" "github.com/zitadel/zitadel/internal/command"
@@ -11,7 +12,7 @@ import (
"github.com/zitadel/zitadel/pkg/grpc/user/v2" "github.com/zitadel/zitadel/pkg/grpc/user/v2"
) )
func (s *Server) createUserTypeMachine(ctx context.Context, machinePb *user.CreateUserRequest_Machine, orgId, userName, userId string) (*user.CreateUserResponse, error) { func (s *Server) createUserTypeMachine(ctx context.Context, machinePb *user.CreateUserRequest_Machine, orgId, userName, userId string) (*connect.Response[user.CreateUserResponse], error) {
cmd := &command.Machine{ cmd := &command.Machine{
Username: userName, Username: userName,
Name: machinePb.Name, Name: machinePb.Name,
@@ -32,21 +33,21 @@ func (s *Server) createUserTypeMachine(ctx context.Context, machinePb *user.Crea
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &user.CreateUserResponse{ return connect.NewResponse(&user.CreateUserResponse{
Id: cmd.AggregateID, Id: cmd.AggregateID,
CreationDate: timestamppb.New(details.EventDate), CreationDate: timestamppb.New(details.EventDate),
}, nil }), nil
} }
func (s *Server) updateUserTypeMachine(ctx context.Context, machinePb *user.UpdateUserRequest_Machine, userId string, userName *string) (*user.UpdateUserResponse, error) { func (s *Server) updateUserTypeMachine(ctx context.Context, machinePb *user.UpdateUserRequest_Machine, userId string, userName *string) (*connect.Response[user.UpdateUserResponse], error) {
cmd := updateMachineUserToCommand(userId, userName, machinePb) cmd := updateMachineUserToCommand(userId, userName, machinePb)
err := s.command.ChangeUserMachine(ctx, cmd) err := s.command.ChangeUserMachine(ctx, cmd)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &user.UpdateUserResponse{ return connect.NewResponse(&user.UpdateUserResponse{
ChangeDate: timestamppb.New(cmd.Details.EventDate), ChangeDate: timestamppb.New(cmd.Details.EventDate),
}, nil }), nil
} }
func updateMachineUserToCommand(userId string, userName *string, machine *user.UpdateUserRequest_Machine) *command.ChangeMachine { func updateMachineUserToCommand(userId string, userName *string, machine *user.UpdateUserRequest_Machine) *command.ChangeMachine {

View File

@@ -3,39 +3,41 @@ package user
import ( import (
"context" "context"
"connectrpc.com/connect"
"github.com/zitadel/zitadel/internal/api/grpc/object/v2" "github.com/zitadel/zitadel/internal/api/grpc/object/v2"
"github.com/zitadel/zitadel/pkg/grpc/user/v2" "github.com/zitadel/zitadel/pkg/grpc/user/v2"
) )
func (s *Server) AddOTPSMS(ctx context.Context, req *user.AddOTPSMSRequest) (*user.AddOTPSMSResponse, error) { func (s *Server) AddOTPSMS(ctx context.Context, req *connect.Request[user.AddOTPSMSRequest]) (*connect.Response[user.AddOTPSMSResponse], error) {
details, err := s.command.AddHumanOTPSMS(ctx, req.GetUserId(), "") details, err := s.command.AddHumanOTPSMS(ctx, req.Msg.GetUserId(), "")
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &user.AddOTPSMSResponse{Details: object.DomainToDetailsPb(details)}, nil return connect.NewResponse(&user.AddOTPSMSResponse{Details: object.DomainToDetailsPb(details)}), nil
} }
func (s *Server) RemoveOTPSMS(ctx context.Context, req *user.RemoveOTPSMSRequest) (*user.RemoveOTPSMSResponse, error) { func (s *Server) RemoveOTPSMS(ctx context.Context, req *connect.Request[user.RemoveOTPSMSRequest]) (*connect.Response[user.RemoveOTPSMSResponse], error) {
objectDetails, err := s.command.RemoveHumanOTPSMS(ctx, req.GetUserId(), "") objectDetails, err := s.command.RemoveHumanOTPSMS(ctx, req.Msg.GetUserId(), "")
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &user.RemoveOTPSMSResponse{Details: object.DomainToDetailsPb(objectDetails)}, nil return connect.NewResponse(&user.RemoveOTPSMSResponse{Details: object.DomainToDetailsPb(objectDetails)}), nil
} }
func (s *Server) AddOTPEmail(ctx context.Context, req *user.AddOTPEmailRequest) (*user.AddOTPEmailResponse, error) { func (s *Server) AddOTPEmail(ctx context.Context, req *connect.Request[user.AddOTPEmailRequest]) (*connect.Response[user.AddOTPEmailResponse], error) {
details, err := s.command.AddHumanOTPEmail(ctx, req.GetUserId(), "") details, err := s.command.AddHumanOTPEmail(ctx, req.Msg.GetUserId(), "")
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &user.AddOTPEmailResponse{Details: object.DomainToDetailsPb(details)}, nil return connect.NewResponse(&user.AddOTPEmailResponse{Details: object.DomainToDetailsPb(details)}), nil
} }
func (s *Server) RemoveOTPEmail(ctx context.Context, req *user.RemoveOTPEmailRequest) (*user.RemoveOTPEmailResponse, error) { func (s *Server) RemoveOTPEmail(ctx context.Context, req *connect.Request[user.RemoveOTPEmailRequest]) (*connect.Response[user.RemoveOTPEmailResponse], error) {
objectDetails, err := s.command.RemoveHumanOTPEmail(ctx, req.GetUserId(), "") objectDetails, err := s.command.RemoveHumanOTPEmail(ctx, req.Msg.GetUserId(), "")
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &user.RemoveOTPEmailResponse{Details: object.DomainToDetailsPb(objectDetails)}, nil return connect.NewResponse(&user.RemoveOTPEmailResponse{Details: object.DomainToDetailsPb(objectDetails)}), nil
} }

View File

@@ -3,6 +3,7 @@ package user
import ( import (
"context" "context"
"connectrpc.com/connect"
"google.golang.org/protobuf/types/known/structpb" "google.golang.org/protobuf/types/known/structpb"
"github.com/zitadel/zitadel/internal/api/grpc/object/v2" "github.com/zitadel/zitadel/internal/api/grpc/object/v2"
@@ -13,17 +14,17 @@ import (
"github.com/zitadel/zitadel/pkg/grpc/user/v2" "github.com/zitadel/zitadel/pkg/grpc/user/v2"
) )
func (s *Server) RegisterPasskey(ctx context.Context, req *user.RegisterPasskeyRequest) (resp *user.RegisterPasskeyResponse, err error) { func (s *Server) RegisterPasskey(ctx context.Context, req *connect.Request[user.RegisterPasskeyRequest]) (resp *connect.Response[user.RegisterPasskeyResponse], err error) {
var ( var (
authenticator = passkeyAuthenticatorToDomain(req.GetAuthenticator()) authenticator = passkeyAuthenticatorToDomain(req.Msg.GetAuthenticator())
) )
if code := req.GetCode(); code != nil { if code := req.Msg.GetCode(); code != nil {
return passkeyRegistrationDetailsToPb( return passkeyRegistrationDetailsToPb(
s.command.RegisterUserPasskeyWithCode(ctx, req.GetUserId(), "", authenticator, code.Id, code.Code, req.GetDomain(), s.userCodeAlg), s.command.RegisterUserPasskeyWithCode(ctx, req.Msg.GetUserId(), "", authenticator, code.Id, code.Code, req.Msg.GetDomain(), s.userCodeAlg),
) )
} }
return passkeyRegistrationDetailsToPb( return passkeyRegistrationDetailsToPb(
s.command.RegisterUserPasskey(ctx, req.GetUserId(), "", req.GetDomain(), authenticator), s.command.RegisterUserPasskey(ctx, req.Msg.GetUserId(), "", req.Msg.GetDomain(), authenticator),
) )
} }
@@ -51,86 +52,86 @@ func webAuthNRegistrationDetailsToPb(details *domain.WebAuthNRegistrationDetails
return object.DomainToDetailsPb(details.ObjectDetails), options, nil return object.DomainToDetailsPb(details.ObjectDetails), options, nil
} }
func passkeyRegistrationDetailsToPb(details *domain.WebAuthNRegistrationDetails, err error) (*user.RegisterPasskeyResponse, error) { func passkeyRegistrationDetailsToPb(details *domain.WebAuthNRegistrationDetails, err error) (*connect.Response[user.RegisterPasskeyResponse], error) {
objectDetails, options, err := webAuthNRegistrationDetailsToPb(details, err) objectDetails, options, err := webAuthNRegistrationDetailsToPb(details, err)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &user.RegisterPasskeyResponse{ return connect.NewResponse(&user.RegisterPasskeyResponse{
Details: objectDetails, Details: objectDetails,
PasskeyId: details.ID, PasskeyId: details.ID,
PublicKeyCredentialCreationOptions: options, PublicKeyCredentialCreationOptions: options,
}, nil }), nil
} }
func (s *Server) VerifyPasskeyRegistration(ctx context.Context, req *user.VerifyPasskeyRegistrationRequest) (*user.VerifyPasskeyRegistrationResponse, error) { func (s *Server) VerifyPasskeyRegistration(ctx context.Context, req *connect.Request[user.VerifyPasskeyRegistrationRequest]) (*connect.Response[user.VerifyPasskeyRegistrationResponse], error) {
pkc, err := req.GetPublicKeyCredential().MarshalJSON() pkc, err := req.Msg.GetPublicKeyCredential().MarshalJSON()
if err != nil { if err != nil {
return nil, zerrors.ThrowInternal(err, "USERv2-Pha2o", "Errors.Internal") return nil, zerrors.ThrowInternal(err, "USERv2-Pha2o", "Errors.Internal")
} }
objectDetails, err := s.command.HumanHumanPasswordlessSetup(ctx, req.GetUserId(), "", req.GetPasskeyName(), "", pkc) objectDetails, err := s.command.HumanHumanPasswordlessSetup(ctx, req.Msg.GetUserId(), "", req.Msg.GetPasskeyName(), "", pkc)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &user.VerifyPasskeyRegistrationResponse{ return connect.NewResponse(&user.VerifyPasskeyRegistrationResponse{
Details: object.DomainToDetailsPb(objectDetails), Details: object.DomainToDetailsPb(objectDetails),
}, nil }), nil
} }
func (s *Server) CreatePasskeyRegistrationLink(ctx context.Context, req *user.CreatePasskeyRegistrationLinkRequest) (resp *user.CreatePasskeyRegistrationLinkResponse, err error) { func (s *Server) CreatePasskeyRegistrationLink(ctx context.Context, req *connect.Request[user.CreatePasskeyRegistrationLinkRequest]) (resp *connect.Response[user.CreatePasskeyRegistrationLinkResponse], err error) {
switch medium := req.Medium.(type) { switch medium := req.Msg.Medium.(type) {
case nil: case nil:
return passkeyDetailsToPb( return passkeyDetailsToPb(
s.command.AddUserPasskeyCode(ctx, req.GetUserId(), "", s.userCodeAlg), s.command.AddUserPasskeyCode(ctx, req.Msg.GetUserId(), "", s.userCodeAlg),
) )
case *user.CreatePasskeyRegistrationLinkRequest_SendLink: case *user.CreatePasskeyRegistrationLinkRequest_SendLink:
return passkeyDetailsToPb( return passkeyDetailsToPb(
s.command.AddUserPasskeyCodeURLTemplate(ctx, req.GetUserId(), "", s.userCodeAlg, medium.SendLink.GetUrlTemplate()), s.command.AddUserPasskeyCodeURLTemplate(ctx, req.Msg.GetUserId(), "", s.userCodeAlg, medium.SendLink.GetUrlTemplate()),
) )
case *user.CreatePasskeyRegistrationLinkRequest_ReturnCode: case *user.CreatePasskeyRegistrationLinkRequest_ReturnCode:
return passkeyCodeDetailsToPb( return passkeyCodeDetailsToPb(
s.command.AddUserPasskeyCodeReturn(ctx, req.GetUserId(), "", s.userCodeAlg), s.command.AddUserPasskeyCodeReturn(ctx, req.Msg.GetUserId(), "", s.userCodeAlg),
) )
default: default:
return nil, zerrors.ThrowUnimplementedf(nil, "USERv2-gaD8y", "verification oneOf %T in method CreatePasskeyRegistrationLink not implemented", medium) return nil, zerrors.ThrowUnimplementedf(nil, "USERv2-gaD8y", "verification oneOf %T in method CreatePasskeyRegistrationLink not implemented", medium)
} }
} }
func passkeyDetailsToPb(details *domain.ObjectDetails, err error) (*user.CreatePasskeyRegistrationLinkResponse, error) { func passkeyDetailsToPb(details *domain.ObjectDetails, err error) (*connect.Response[user.CreatePasskeyRegistrationLinkResponse], error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &user.CreatePasskeyRegistrationLinkResponse{ return connect.NewResponse(&user.CreatePasskeyRegistrationLinkResponse{
Details: object.DomainToDetailsPb(details), Details: object.DomainToDetailsPb(details),
}, nil }), nil
} }
func passkeyCodeDetailsToPb(details *domain.PasskeyCodeDetails, err error) (*user.CreatePasskeyRegistrationLinkResponse, error) { func passkeyCodeDetailsToPb(details *domain.PasskeyCodeDetails, err error) (*connect.Response[user.CreatePasskeyRegistrationLinkResponse], error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &user.CreatePasskeyRegistrationLinkResponse{ return connect.NewResponse(&user.CreatePasskeyRegistrationLinkResponse{
Details: object.DomainToDetailsPb(details.ObjectDetails), Details: object.DomainToDetailsPb(details.ObjectDetails),
Code: &user.PasskeyRegistrationCode{ Code: &user.PasskeyRegistrationCode{
Id: details.CodeID, Id: details.CodeID,
Code: details.Code, Code: details.Code,
}, },
}, nil }), nil
} }
func (s *Server) RemovePasskey(ctx context.Context, req *user.RemovePasskeyRequest) (*user.RemovePasskeyResponse, error) { func (s *Server) RemovePasskey(ctx context.Context, req *connect.Request[user.RemovePasskeyRequest]) (*connect.Response[user.RemovePasskeyResponse], error) {
objectDetails, err := s.command.HumanRemovePasswordless(ctx, req.GetUserId(), req.GetPasskeyId(), "") objectDetails, err := s.command.HumanRemovePasswordless(ctx, req.Msg.GetUserId(), req.Msg.GetPasskeyId(), "")
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &user.RemovePasskeyResponse{ return connect.NewResponse(&user.RemovePasskeyResponse{
Details: object.DomainToDetailsPb(objectDetails), Details: object.DomainToDetailsPb(objectDetails),
}, nil }), nil
} }
func (s *Server) ListPasskeys(ctx context.Context, req *user.ListPasskeysRequest) (*user.ListPasskeysResponse, error) { func (s *Server) ListPasskeys(ctx context.Context, req *connect.Request[user.ListPasskeysRequest]) (*connect.Response[user.ListPasskeysResponse], error) {
query := new(query.UserAuthMethodSearchQueries) query := new(query.UserAuthMethodSearchQueries)
err := query.AppendUserIDQuery(req.UserId) err := query.AppendUserIDQuery(req.Msg.UserId)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -146,10 +147,10 @@ func (s *Server) ListPasskeys(ctx context.Context, req *user.ListPasskeysRequest
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &user.ListPasskeysResponse{ return connect.NewResponse(&user.ListPasskeysResponse{
Details: object.ToListDetails(authMethods.SearchResponse), Details: object.ToListDetails(authMethods.SearchResponse),
Result: authMethodsToPasskeyPb(authMethods), Result: authMethodsToPasskeyPb(authMethods),
}, nil }), nil
} }
func authMethodsToPasskeyPb(methods *query.AuthMethods) []*user.Passkey { func authMethodsToPasskeyPb(methods *query.AuthMethods) []*user.Passkey {

View File

@@ -123,11 +123,11 @@ func Test_passkeyRegistrationDetailsToPb(t *testing.T) {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
got, err := passkeyRegistrationDetailsToPb(tt.args.details, tt.args.err) got, err := passkeyRegistrationDetailsToPb(tt.args.details, tt.args.err)
require.ErrorIs(t, err, tt.wantErr) require.ErrorIs(t, err, tt.wantErr)
if !proto.Equal(tt.want, got) { if tt.want != nil && !proto.Equal(tt.want, got.Msg) {
t.Errorf("Not equal:\nExpected\n%s\nActual:%s", tt.want, got) t.Errorf("Not equal:\nExpected\n%s\nActual:%s", tt.want, got)
} }
if tt.want != nil { if tt.want != nil {
grpc.AllFieldsSet(t, got.ProtoReflect()) grpc.AllFieldsSet(t, got.Msg.ProtoReflect())
} }
}) })
} }
@@ -181,7 +181,9 @@ func Test_passkeyDetailsToPb(t *testing.T) {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
got, err := passkeyDetailsToPb(tt.args.details, tt.args.err) got, err := passkeyDetailsToPb(tt.args.details, tt.args.err)
require.ErrorIs(t, err, tt.args.err) require.ErrorIs(t, err, tt.args.err)
assert.Equal(t, tt.want, got) if tt.want != nil {
assert.Equal(t, tt.want, got.Msg)
}
}) })
} }
} }
@@ -242,9 +244,9 @@ func Test_passkeyCodeDetailsToPb(t *testing.T) {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
got, err := passkeyCodeDetailsToPb(tt.args.details, tt.args.err) got, err := passkeyCodeDetailsToPb(tt.args.details, tt.args.err)
require.ErrorIs(t, err, tt.args.err) require.ErrorIs(t, err, tt.args.err)
assert.Equal(t, tt.want, got)
if tt.want != nil { if tt.want != nil {
grpc.AllFieldsSet(t, got.ProtoReflect()) assert.Equal(t, tt.want, got.Msg)
grpc.AllFieldsSet(t, got.Msg.ProtoReflect())
} }
}) })
} }

View File

@@ -3,23 +3,25 @@ package user
import ( import (
"context" "context"
"connectrpc.com/connect"
"github.com/zitadel/zitadel/internal/api/grpc/object/v2" "github.com/zitadel/zitadel/internal/api/grpc/object/v2"
"github.com/zitadel/zitadel/internal/domain" "github.com/zitadel/zitadel/internal/domain"
"github.com/zitadel/zitadel/internal/zerrors" "github.com/zitadel/zitadel/internal/zerrors"
"github.com/zitadel/zitadel/pkg/grpc/user/v2" "github.com/zitadel/zitadel/pkg/grpc/user/v2"
) )
func (s *Server) PasswordReset(ctx context.Context, req *user.PasswordResetRequest) (_ *user.PasswordResetResponse, err error) { func (s *Server) PasswordReset(ctx context.Context, req *connect.Request[user.PasswordResetRequest]) (_ *connect.Response[user.PasswordResetResponse], err error) {
var details *domain.ObjectDetails var details *domain.ObjectDetails
var code *string var code *string
switch m := req.GetMedium().(type) { switch m := req.Msg.GetMedium().(type) {
case *user.PasswordResetRequest_SendLink: case *user.PasswordResetRequest_SendLink:
details, code, err = s.command.RequestPasswordResetURLTemplate(ctx, req.GetUserId(), m.SendLink.GetUrlTemplate(), notificationTypeToDomain(m.SendLink.GetNotificationType())) details, code, err = s.command.RequestPasswordResetURLTemplate(ctx, req.Msg.GetUserId(), m.SendLink.GetUrlTemplate(), notificationTypeToDomain(m.SendLink.GetNotificationType()))
case *user.PasswordResetRequest_ReturnCode: case *user.PasswordResetRequest_ReturnCode:
details, code, err = s.command.RequestPasswordResetReturnCode(ctx, req.GetUserId()) details, code, err = s.command.RequestPasswordResetReturnCode(ctx, req.Msg.GetUserId())
case nil: case nil:
details, code, err = s.command.RequestPasswordReset(ctx, req.GetUserId()) details, code, err = s.command.RequestPasswordReset(ctx, req.Msg.GetUserId())
default: default:
err = zerrors.ThrowUnimplementedf(nil, "USERv2-SDeeg", "verification oneOf %T in method RequestPasswordReset not implemented", m) err = zerrors.ThrowUnimplementedf(nil, "USERv2-SDeeg", "verification oneOf %T in method RequestPasswordReset not implemented", m)
} }
@@ -27,10 +29,10 @@ func (s *Server) PasswordReset(ctx context.Context, req *user.PasswordResetReque
return nil, err return nil, err
} }
return &user.PasswordResetResponse{ return connect.NewResponse(&user.PasswordResetResponse{
Details: object.DomainToDetailsPb(details), Details: object.DomainToDetailsPb(details),
VerificationCode: code, VerificationCode: code,
}, nil }), nil
} }
func notificationTypeToDomain(notificationType user.NotificationType) domain.NotificationType { func notificationTypeToDomain(notificationType user.NotificationType) domain.NotificationType {
@@ -46,16 +48,16 @@ func notificationTypeToDomain(notificationType user.NotificationType) domain.Not
} }
} }
func (s *Server) SetPassword(ctx context.Context, req *user.SetPasswordRequest) (_ *user.SetPasswordResponse, err error) { func (s *Server) SetPassword(ctx context.Context, req *connect.Request[user.SetPasswordRequest]) (_ *connect.Response[user.SetPasswordResponse], err error) {
var details *domain.ObjectDetails var details *domain.ObjectDetails
switch v := req.GetVerification().(type) { switch v := req.Msg.GetVerification().(type) {
case *user.SetPasswordRequest_CurrentPassword: case *user.SetPasswordRequest_CurrentPassword:
details, err = s.command.ChangePassword(ctx, "", req.GetUserId(), v.CurrentPassword, req.GetNewPassword().GetPassword(), "", req.GetNewPassword().GetChangeRequired()) details, err = s.command.ChangePassword(ctx, "", req.Msg.GetUserId(), v.CurrentPassword, req.Msg.GetNewPassword().GetPassword(), "", req.Msg.GetNewPassword().GetChangeRequired())
case *user.SetPasswordRequest_VerificationCode: case *user.SetPasswordRequest_VerificationCode:
details, err = s.command.SetPasswordWithVerifyCode(ctx, "", req.GetUserId(), v.VerificationCode, req.GetNewPassword().GetPassword(), "", req.GetNewPassword().GetChangeRequired()) details, err = s.command.SetPasswordWithVerifyCode(ctx, "", req.Msg.GetUserId(), v.VerificationCode, req.Msg.GetNewPassword().GetPassword(), "", req.Msg.GetNewPassword().GetChangeRequired())
case nil: case nil:
details, err = s.command.SetPassword(ctx, "", req.GetUserId(), req.GetNewPassword().GetPassword(), req.GetNewPassword().GetChangeRequired()) details, err = s.command.SetPassword(ctx, "", req.Msg.GetUserId(), req.Msg.GetNewPassword().GetPassword(), req.Msg.GetNewPassword().GetChangeRequired())
default: default:
err = zerrors.ThrowUnimplementedf(nil, "USERv2-SFdf2", "verification oneOf %T in method SetPasswordRequest not implemented", v) err = zerrors.ThrowUnimplementedf(nil, "USERv2-SFdf2", "verification oneOf %T in method SetPasswordRequest not implemented", v)
} }
@@ -63,7 +65,7 @@ func (s *Server) SetPassword(ctx context.Context, req *user.SetPasswordRequest)
return nil, err return nil, err
} }
return &user.SetPasswordResponse{ return connect.NewResponse(&user.SetPasswordResponse{
Details: object.DomainToDetailsPb(details), Details: object.DomainToDetailsPb(details),
}, nil }), nil
} }

View File

@@ -3,6 +3,7 @@ package user
import ( import (
"context" "context"
"connectrpc.com/connect"
"github.com/zitadel/oidc/v3/pkg/oidc" "github.com/zitadel/oidc/v3/pkg/oidc"
"google.golang.org/protobuf/types/known/timestamppb" "google.golang.org/protobuf/types/known/timestamppb"
@@ -13,13 +14,13 @@ import (
"github.com/zitadel/zitadel/pkg/grpc/user/v2" "github.com/zitadel/zitadel/pkg/grpc/user/v2"
) )
func (s *Server) AddPersonalAccessToken(ctx context.Context, req *user.AddPersonalAccessTokenRequest) (*user.AddPersonalAccessTokenResponse, error) { func (s *Server) AddPersonalAccessToken(ctx context.Context, req *connect.Request[user.AddPersonalAccessTokenRequest]) (*connect.Response[user.AddPersonalAccessTokenResponse], error) {
newPat := &command.PersonalAccessToken{ newPat := &command.PersonalAccessToken{
ObjectRoot: models.ObjectRoot{ ObjectRoot: models.ObjectRoot{
AggregateID: req.UserId, AggregateID: req.Msg.GetUserId(),
}, },
PermissionCheck: s.command.NewPermissionCheckUserWrite(ctx), PermissionCheck: s.command.NewPermissionCheckUserWrite(ctx),
ExpirationDate: req.ExpirationDate.AsTime(), ExpirationDate: req.Msg.GetExpirationDate().AsTime(),
Scopes: []string{ Scopes: []string{
oidc.ScopeOpenID, oidc.ScopeOpenID,
oidc.ScopeProfile, oidc.ScopeProfile,
@@ -32,25 +33,25 @@ func (s *Server) AddPersonalAccessToken(ctx context.Context, req *user.AddPerson
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &user.AddPersonalAccessTokenResponse{ return connect.NewResponse(&user.AddPersonalAccessTokenResponse{
CreationDate: timestamppb.New(details.EventDate), CreationDate: timestamppb.New(details.EventDate),
TokenId: newPat.TokenID, TokenId: newPat.TokenID,
Token: newPat.Token, Token: newPat.Token,
}, nil }), nil
} }
func (s *Server) RemovePersonalAccessToken(ctx context.Context, req *user.RemovePersonalAccessTokenRequest) (*user.RemovePersonalAccessTokenResponse, error) { func (s *Server) RemovePersonalAccessToken(ctx context.Context, req *connect.Request[user.RemovePersonalAccessTokenRequest]) (*connect.Response[user.RemovePersonalAccessTokenResponse], error) {
objectDetails, err := s.command.RemovePersonalAccessToken(ctx, &command.PersonalAccessToken{ objectDetails, err := s.command.RemovePersonalAccessToken(ctx, &command.PersonalAccessToken{
TokenID: req.TokenId, TokenID: req.Msg.GetTokenId(),
ObjectRoot: models.ObjectRoot{ ObjectRoot: models.ObjectRoot{
AggregateID: req.UserId, AggregateID: req.Msg.GetUserId(),
}, },
PermissionCheck: s.command.NewPermissionCheckUserWrite(ctx), PermissionCheck: s.command.NewPermissionCheckUserWrite(ctx),
}) })
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &user.RemovePersonalAccessTokenResponse{ return connect.NewResponse(&user.RemovePersonalAccessTokenResponse{
DeletionDate: timestamppb.New(objectDetails.EventDate), DeletionDate: timestamppb.New(objectDetails.EventDate),
}, nil }), nil
} }

View File

@@ -3,6 +3,7 @@ package user
import ( import (
"context" "context"
"connectrpc.com/connect"
"google.golang.org/protobuf/types/known/timestamppb" "google.golang.org/protobuf/types/known/timestamppb"
"github.com/zitadel/zitadel/internal/api/grpc/filter/v2" "github.com/zitadel/zitadel/internal/api/grpc/filter/v2"
@@ -12,12 +13,12 @@ import (
"github.com/zitadel/zitadel/pkg/grpc/user/v2" "github.com/zitadel/zitadel/pkg/grpc/user/v2"
) )
func (s *Server) ListPersonalAccessTokens(ctx context.Context, req *user.ListPersonalAccessTokensRequest) (*user.ListPersonalAccessTokensResponse, error) { func (s *Server) ListPersonalAccessTokens(ctx context.Context, req *connect.Request[user.ListPersonalAccessTokensRequest]) (*connect.Response[user.ListPersonalAccessTokensResponse], error) {
offset, limit, asc, err := filter.PaginationPbToQuery(s.systemDefaults, req.Pagination) offset, limit, asc, err := filter.PaginationPbToQuery(s.systemDefaults, req.Msg.GetPagination())
if err != nil { if err != nil {
return nil, err return nil, err
} }
filters, err := patFiltersToQueries(req.Filters) filters, err := patFiltersToQueries(req.Msg.GetFilters())
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -26,7 +27,7 @@ func (s *Server) ListPersonalAccessTokens(ctx context.Context, req *user.ListPer
Offset: offset, Offset: offset,
Limit: limit, Limit: limit,
Asc: asc, Asc: asc,
SortingColumn: authnPersonalAccessTokenFieldNameToSortingColumn(req.SortingColumn), SortingColumn: authnPersonalAccessTokenFieldNameToSortingColumn(req.Msg.SortingColumn),
}, },
Queries: filters, Queries: filters,
} }
@@ -48,7 +49,7 @@ func (s *Server) ListPersonalAccessTokens(ctx context.Context, req *user.ListPer
ExpirationDate: timestamppb.New(pat.Expiration), ExpirationDate: timestamppb.New(pat.Expiration),
} }
} }
return resp, nil return connect.NewResponse(resp), nil
} }
func patFiltersToQueries(filters []*user.PersonalAccessTokensSearchFilter) (_ []query.SearchQuery, err error) { func patFiltersToQueries(filters []*user.PersonalAccessTokensSearchFilter) (_ []query.SearchQuery, err error) {

View File

@@ -3,6 +3,7 @@ package user
import ( import (
"context" "context"
"connectrpc.com/connect"
"google.golang.org/protobuf/types/known/timestamppb" "google.golang.org/protobuf/types/known/timestamppb"
"github.com/zitadel/zitadel/internal/domain" "github.com/zitadel/zitadel/internal/domain"
@@ -11,18 +12,18 @@ import (
"github.com/zitadel/zitadel/pkg/grpc/user/v2" "github.com/zitadel/zitadel/pkg/grpc/user/v2"
) )
func (s *Server) SetPhone(ctx context.Context, req *user.SetPhoneRequest) (resp *user.SetPhoneResponse, err error) { func (s *Server) SetPhone(ctx context.Context, req *connect.Request[user.SetPhoneRequest]) (resp *connect.Response[user.SetPhoneResponse], err error) {
var phone *domain.Phone var phone *domain.Phone
switch v := req.GetVerification().(type) { switch v := req.Msg.GetVerification().(type) {
case *user.SetPhoneRequest_SendCode: case *user.SetPhoneRequest_SendCode:
phone, err = s.command.ChangeUserPhone(ctx, req.GetUserId(), req.GetPhone(), s.userCodeAlg) phone, err = s.command.ChangeUserPhone(ctx, req.Msg.GetUserId(), req.Msg.GetPhone(), s.userCodeAlg)
case *user.SetPhoneRequest_ReturnCode: case *user.SetPhoneRequest_ReturnCode:
phone, err = s.command.ChangeUserPhoneReturnCode(ctx, req.GetUserId(), req.GetPhone(), s.userCodeAlg) phone, err = s.command.ChangeUserPhoneReturnCode(ctx, req.Msg.GetUserId(), req.Msg.GetPhone(), s.userCodeAlg)
case *user.SetPhoneRequest_IsVerified: case *user.SetPhoneRequest_IsVerified:
phone, err = s.command.ChangeUserPhoneVerified(ctx, req.GetUserId(), req.GetPhone()) phone, err = s.command.ChangeUserPhoneVerified(ctx, req.Msg.GetUserId(), req.Msg.GetPhone())
case nil: case nil:
phone, err = s.command.ChangeUserPhone(ctx, req.GetUserId(), req.GetPhone(), s.userCodeAlg) phone, err = s.command.ChangeUserPhone(ctx, req.Msg.GetUserId(), req.Msg.GetPhone(), s.userCodeAlg)
default: default:
err = zerrors.ThrowUnimplementedf(nil, "USERv2-Ahng0", "verification oneOf %T in method SetPhone not implemented", v) err = zerrors.ThrowUnimplementedf(nil, "USERv2-Ahng0", "verification oneOf %T in method SetPhone not implemented", v)
} }
@@ -30,42 +31,42 @@ func (s *Server) SetPhone(ctx context.Context, req *user.SetPhoneRequest) (resp
return nil, err return nil, err
} }
return &user.SetPhoneResponse{ return connect.NewResponse(&user.SetPhoneResponse{
Details: &object.Details{ Details: &object.Details{
Sequence: phone.Sequence, Sequence: phone.Sequence,
ChangeDate: timestamppb.New(phone.ChangeDate), ChangeDate: timestamppb.New(phone.ChangeDate),
ResourceOwner: phone.ResourceOwner, ResourceOwner: phone.ResourceOwner,
}, },
VerificationCode: phone.PlainCode, VerificationCode: phone.PlainCode,
}, nil }), nil
} }
func (s *Server) RemovePhone(ctx context.Context, req *user.RemovePhoneRequest) (resp *user.RemovePhoneResponse, err error) { func (s *Server) RemovePhone(ctx context.Context, req *connect.Request[user.RemovePhoneRequest]) (resp *connect.Response[user.RemovePhoneResponse], err error) {
details, err := s.command.RemoveUserPhone(ctx, details, err := s.command.RemoveUserPhone(ctx,
req.GetUserId(), req.Msg.GetUserId(),
) )
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &user.RemovePhoneResponse{ return connect.NewResponse(&user.RemovePhoneResponse{
Details: &object.Details{ Details: &object.Details{
Sequence: details.Sequence, Sequence: details.Sequence,
ChangeDate: timestamppb.New(details.EventDate), ChangeDate: timestamppb.New(details.EventDate),
ResourceOwner: details.ResourceOwner, ResourceOwner: details.ResourceOwner,
}, },
}, nil }), nil
} }
func (s *Server) ResendPhoneCode(ctx context.Context, req *user.ResendPhoneCodeRequest) (resp *user.ResendPhoneCodeResponse, err error) { func (s *Server) ResendPhoneCode(ctx context.Context, req *connect.Request[user.ResendPhoneCodeRequest]) (resp *connect.Response[user.ResendPhoneCodeResponse], err error) {
var phone *domain.Phone var phone *domain.Phone
switch v := req.GetVerification().(type) { switch v := req.Msg.GetVerification().(type) {
case *user.ResendPhoneCodeRequest_SendCode: case *user.ResendPhoneCodeRequest_SendCode:
phone, err = s.command.ResendUserPhoneCode(ctx, req.GetUserId(), s.userCodeAlg) phone, err = s.command.ResendUserPhoneCode(ctx, req.Msg.GetUserId(), s.userCodeAlg)
case *user.ResendPhoneCodeRequest_ReturnCode: case *user.ResendPhoneCodeRequest_ReturnCode:
phone, err = s.command.ResendUserPhoneCodeReturnCode(ctx, req.GetUserId(), s.userCodeAlg) phone, err = s.command.ResendUserPhoneCodeReturnCode(ctx, req.Msg.GetUserId(), s.userCodeAlg)
case nil: case nil:
phone, err = s.command.ResendUserPhoneCode(ctx, req.GetUserId(), s.userCodeAlg) phone, err = s.command.ResendUserPhoneCode(ctx, req.Msg.GetUserId(), s.userCodeAlg)
default: default:
err = zerrors.ThrowUnimplementedf(nil, "USERv2-ResendUserPhoneCode", "verification oneOf %T in method SetPhone not implemented", v) err = zerrors.ThrowUnimplementedf(nil, "USERv2-ResendUserPhoneCode", "verification oneOf %T in method SetPhone not implemented", v)
} }
@@ -73,30 +74,30 @@ func (s *Server) ResendPhoneCode(ctx context.Context, req *user.ResendPhoneCodeR
return nil, err return nil, err
} }
return &user.ResendPhoneCodeResponse{ return connect.NewResponse(&user.ResendPhoneCodeResponse{
Details: &object.Details{ Details: &object.Details{
Sequence: phone.Sequence, Sequence: phone.Sequence,
ChangeDate: timestamppb.New(phone.ChangeDate), ChangeDate: timestamppb.New(phone.ChangeDate),
ResourceOwner: phone.ResourceOwner, ResourceOwner: phone.ResourceOwner,
}, },
VerificationCode: phone.PlainCode, VerificationCode: phone.PlainCode,
}, nil }), nil
} }
func (s *Server) VerifyPhone(ctx context.Context, req *user.VerifyPhoneRequest) (*user.VerifyPhoneResponse, error) { func (s *Server) VerifyPhone(ctx context.Context, req *connect.Request[user.VerifyPhoneRequest]) (*connect.Response[user.VerifyPhoneResponse], error) {
details, err := s.command.VerifyUserPhone(ctx, details, err := s.command.VerifyUserPhone(ctx,
req.GetUserId(), req.Msg.GetUserId(),
req.GetVerificationCode(), req.Msg.GetVerificationCode(),
s.userCodeAlg, s.userCodeAlg,
) )
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &user.VerifyPhoneResponse{ return connect.NewResponse(&user.VerifyPhoneResponse{
Details: &object.Details{ Details: &object.Details{
Sequence: details.Sequence, Sequence: details.Sequence,
ChangeDate: timestamppb.New(details.EventDate), ChangeDate: timestamppb.New(details.EventDate),
ResourceOwner: details.ResourceOwner, ResourceOwner: details.ResourceOwner,
}, },
}, nil }), nil
} }

View File

@@ -3,37 +3,38 @@ package user
import ( import (
"context" "context"
"connectrpc.com/connect"
"google.golang.org/protobuf/types/known/timestamppb" "google.golang.org/protobuf/types/known/timestamppb"
"github.com/zitadel/zitadel/internal/command" "github.com/zitadel/zitadel/internal/command"
"github.com/zitadel/zitadel/pkg/grpc/user/v2" "github.com/zitadel/zitadel/pkg/grpc/user/v2"
) )
func (s *Server) AddSecret(ctx context.Context, req *user.AddSecretRequest) (*user.AddSecretResponse, error) { func (s *Server) AddSecret(ctx context.Context, req *connect.Request[user.AddSecretRequest]) (*connect.Response[user.AddSecretResponse], error) {
newSecret := &command.GenerateMachineSecret{ newSecret := &command.GenerateMachineSecret{
PermissionCheck: s.command.NewPermissionCheckUserWrite(ctx), PermissionCheck: s.command.NewPermissionCheckUserWrite(ctx),
} }
details, err := s.command.GenerateMachineSecret(ctx, req.UserId, "", newSecret) details, err := s.command.GenerateMachineSecret(ctx, req.Msg.GetUserId(), "", newSecret)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &user.AddSecretResponse{ return connect.NewResponse(&user.AddSecretResponse{
CreationDate: timestamppb.New(details.EventDate), CreationDate: timestamppb.New(details.EventDate),
ClientSecret: newSecret.ClientSecret, ClientSecret: newSecret.ClientSecret,
}, nil }), nil
} }
func (s *Server) RemoveSecret(ctx context.Context, req *user.RemoveSecretRequest) (*user.RemoveSecretResponse, error) { func (s *Server) RemoveSecret(ctx context.Context, req *connect.Request[user.RemoveSecretRequest]) (*connect.Response[user.RemoveSecretResponse], error) {
details, err := s.command.RemoveMachineSecret( details, err := s.command.RemoveMachineSecret(
ctx, ctx,
req.UserId, req.Msg.GetUserId(),
"", "",
s.command.NewPermissionCheckUserWrite(ctx), s.command.NewPermissionCheckUserWrite(ctx),
) )
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &user.RemoveSecretResponse{ return connect.NewResponse(&user.RemoveSecretResponse{
DeletionDate: timestamppb.New(details.EventDate), DeletionDate: timestamppb.New(details.EventDate),
}, nil }), nil
} }

Some files were not shown because too many files have changed in this diff Show More