mirror of
https://github.com/zitadel/zitadel.git
synced 2025-08-11 14:47:33 +00:00
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:
1
.github/workflows/core.yml
vendored
1
.github/workflows/core.yml
vendored
@@ -25,6 +25,7 @@ env:
|
||||
internal/api/assets/router.go
|
||||
openapi/v2
|
||||
pkg/grpc/**/*.pb.*
|
||||
pkg/grpc/**/*.connect.go
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@@ -52,6 +52,7 @@ console/src/app/proto/generated/
|
||||
!pkg/grpc/protoc/v2/options.pb.go
|
||||
**.proto.mock.go
|
||||
**.pb.*.go
|
||||
pkg/**/**.connect.go
|
||||
**.gen.go
|
||||
openapi/**/*.json
|
||||
/internal/api/assets/authz.go
|
||||
|
3
Makefile
3
Makefile
@@ -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/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 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
|
||||
core_api: core_api_generator core_grpc_dependencies
|
||||
buf generate
|
||||
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
|
||||
cp -r .artifacts/grpc/zitadel/ openapi/v2/zitadel
|
||||
|
||||
|
@@ -19,3 +19,5 @@ plugins:
|
||||
out: .artifacts/grpc
|
||||
- plugin: zitadel
|
||||
out: .artifacts/grpc
|
||||
- plugin: connect-go
|
||||
out: .artifacts/grpc
|
||||
|
@@ -59,7 +59,8 @@ import (
|
||||
"github.com/zitadel/zitadel/internal/api/grpc/system"
|
||||
user_v2 "github.com/zitadel/zitadel/internal/api/grpc/user/v2"
|
||||
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"
|
||||
"github.com/zitadel/zitadel/internal/api/http/middleware"
|
||||
"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 {
|
||||
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
|
||||
}
|
||||
if err := apis.RegisterService(ctx, debug_events.CreateServer(commands, queries)); err != nil {
|
||||
|
1
docs/.gitignore
vendored
1
docs/.gitignore
vendored
@@ -27,3 +27,4 @@ npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
.vercel
|
||||
/protoc-gen-connect-openapi*
|
||||
|
3
docs/base.yaml
Normal file
3
docs/base.yaml
Normal file
@@ -0,0 +1,3 @@
|
||||
openapi: 3.1.0
|
||||
info:
|
||||
version: v2
|
@@ -1,11 +1,18 @@
|
||||
# buf.gen.yaml
|
||||
version: v1
|
||||
version: v2
|
||||
managed:
|
||||
enabled: true
|
||||
plugins:
|
||||
- plugin: buf.build/grpc-ecosystem/openapiv2
|
||||
- remote: buf.build/grpc-ecosystem/openapiv2
|
||||
out: .artifacts/openapi
|
||||
opt:
|
||||
- allow_delete_body
|
||||
- remove_internal_comments=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
|
||||
|
@@ -337,7 +337,7 @@ module.exports = {
|
||||
},
|
||||
webkey_v2: {
|
||||
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",
|
||||
sidebarOptions: {
|
||||
groupPathsBy: "tag",
|
||||
@@ -373,7 +373,7 @@ module.exports = {
|
||||
},
|
||||
org_v2beta: {
|
||||
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",
|
||||
sidebarOptions: {
|
||||
groupPathsBy: "tag",
|
||||
@@ -382,16 +382,24 @@ module.exports = {
|
||||
},
|
||||
project_v2beta: {
|
||||
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",
|
||||
sidebarOptions: {
|
||||
groupPathsBy: "tag",
|
||||
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: {
|
||||
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",
|
||||
sidebarOptions: {
|
||||
groupPathsBy: "tag",
|
||||
|
@@ -18,7 +18,8 @@
|
||||
"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: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": {
|
||||
"@bufbuild/buf": "^1.14.0",
|
||||
|
21
docs/plugin-download.sh
Normal file
21
docs/plugin-download.sh
Normal 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
|
@@ -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_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_app_v2 = require("./docs/apis/resources/application_service_v2/sidebar.ts").default
|
||||
|
||||
module.exports = {
|
||||
guides: [
|
||||
@@ -806,6 +807,18 @@ module.exports = {
|
||||
},
|
||||
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",
|
||||
label: "Identity Provider",
|
||||
@@ -820,19 +833,15 @@ module.exports = {
|
||||
},
|
||||
{
|
||||
type: "category",
|
||||
label: "Web key (Beta)",
|
||||
label: "Web Key",
|
||||
link: {
|
||||
type: "generated-index",
|
||||
title: "Web Key Service API (Beta)",
|
||||
title: "Web Key Service API",
|
||||
slug: "/apis/resources/webkey_service_v2",
|
||||
description:
|
||||
"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"+
|
||||
"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.",
|
||||
"The public key endpoint (outside of this service) is used to retrieve the public keys of the active and inactive keys.\n",
|
||||
},
|
||||
items: sidebar_api_webkey_service_v2
|
||||
},
|
||||
@@ -857,6 +866,54 @@ module.exports = {
|
||||
},
|
||||
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,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
|
@@ -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"
|
||||
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:
|
||||
version "2.0.1"
|
||||
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"
|
||||
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:
|
||||
version "1.5.172"
|
||||
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.172.tgz#fe1d99028d8d6321668d0f1fed61d99ac896259c"
|
||||
|
2
go.mod
2
go.mod
@@ -7,6 +7,8 @@ toolchain go1.24.1
|
||||
require (
|
||||
cloud.google.com/go/profiler v0.4.2
|
||||
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
|
||||
github.com/BurntSushi/toml v1.5.0
|
||||
github.com/DATA-DOG/go-sqlmock v1.5.2
|
||||
|
4
go.sum
4
go.sum
@@ -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/trace v1.11.3 h1:c+I4YFjxRQjvAhRmSsmjpASUKq88chOX854ied0K/pE=
|
||||
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/go.mod h1:E/hbnu0NxMFBjpMIE34DRGLWqDy0g5FuKDhCb31ngxA=
|
||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||
|
@@ -7,16 +7,18 @@ import (
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"connectrpc.com/grpcreflect"
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/improbable-eng/grpc-web/go/grpcweb"
|
||||
"github.com/zitadel/logging"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/health"
|
||||
healthpb "google.golang.org/grpc/health/grpc_health_v1"
|
||||
"google.golang.org/grpc/reflection"
|
||||
|
||||
"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/connect_middleware"
|
||||
http_util "github.com/zitadel/zitadel/internal/api/http"
|
||||
http_mw "github.com/zitadel/zitadel/internal/api/http/middleware"
|
||||
"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/tracing"
|
||||
"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 {
|
||||
port uint16
|
||||
externalDomain string
|
||||
grpcServer *grpc.Server
|
||||
verifier authz.APITokenVerifier
|
||||
health healthCheck
|
||||
@@ -37,16 +45,23 @@ type API struct {
|
||||
healthServer *health.Server
|
||||
accessInterceptor *http_mw.AccessInterceptor
|
||||
queries *query.Queries
|
||||
authConfig authz.Config
|
||||
systemAuthZ authz.Config
|
||||
connectServices map[string][]string
|
||||
}
|
||||
|
||||
func (a *API) ListGrpcServices() []string {
|
||||
serviceInfo := a.grpcServer.GetServiceInfo()
|
||||
services := make([]string, len(serviceInfo))
|
||||
services := make([]string, len(serviceInfo)+len(a.connectServices))
|
||||
i := 0
|
||||
for servicename := range serviceInfo {
|
||||
services[i] = servicename
|
||||
i++
|
||||
}
|
||||
for prefix := range a.connectServices {
|
||||
services[i] = strings.Trim(prefix, "/")
|
||||
i++
|
||||
}
|
||||
sort.Strings(services)
|
||||
return services
|
||||
}
|
||||
@@ -59,6 +74,11 @@ func (a *API) ListGrpcMethods() []string {
|
||||
methods = append(methods, "/"+servicename+"/"+method.Name)
|
||||
}
|
||||
}
|
||||
for service, methodList := range a.connectServices {
|
||||
for _, method := range methodList {
|
||||
methods = append(methods, service+method)
|
||||
}
|
||||
}
|
||||
sort.Strings(methods)
|
||||
return methods
|
||||
}
|
||||
@@ -82,12 +102,16 @@ func New(
|
||||
) (_ *API, err error) {
|
||||
api := &API{
|
||||
port: port,
|
||||
externalDomain: externalDomain,
|
||||
verifier: verifier,
|
||||
health: queries,
|
||||
router: router,
|
||||
queries: queries,
|
||||
accessInterceptor: accessInterceptor,
|
||||
hostHeaders: hostHeaders,
|
||||
authConfig: authZ,
|
||||
systemAuthZ: systemAuthz,
|
||||
connectServices: make(map[string][]string),
|
||||
}
|
||||
|
||||
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.router.Handle("/", http.RedirectHandler(login.HandlerPrefix, http.StatusFound))
|
||||
|
||||
reflection.Register(api.grpcServer)
|
||||
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,
|
||||
// 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
|
||||
//
|
||||
// used for >= v2 api (e.g. user, session, ...)
|
||||
func (a *API) RegisterService(ctx context.Context, grpcServer server.Server) error {
|
||||
grpcServer.RegisterServer(a.grpcServer)
|
||||
err := server.RegisterGateway(ctx, a.grpcGateway, grpcServer)
|
||||
func (a *API) RegisterService(ctx context.Context, srv server.Server) error {
|
||||
switch service := srv.(type) {
|
||||
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 {
|
||||
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
|
||||
}
|
||||
|
||||
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
|
||||
// path, instead of prefix like RegisterHandlerOnPrefix.
|
||||
func (a *API) HandleFunc(path string, f http.HandlerFunc) {
|
||||
@@ -173,6 +235,9 @@ func (a *API) registerHealthServer() {
|
||||
}
|
||||
|
||||
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.
|
||||
MatcherFunc(func(r *http.Request, _ *mux.RouteMatch) bool {
|
||||
return r.ProtoMajor == 2
|
||||
|
@@ -3,6 +3,7 @@ package action
|
||||
import (
|
||||
"context"
|
||||
|
||||
"connectrpc.com/connect"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/authz"
|
||||
@@ -13,8 +14,8 @@ import (
|
||||
action "github.com/zitadel/zitadel/pkg/grpc/action/v2beta"
|
||||
)
|
||||
|
||||
func (s *Server) SetExecution(ctx context.Context, req *action.SetExecutionRequest) (*action.SetExecutionResponse, error) {
|
||||
reqTargets := req.GetTargets()
|
||||
func (s *Server) SetExecution(ctx context.Context, req *connect.Request[action.SetExecutionRequest]) (*connect.Response[action.SetExecutionResponse], error) {
|
||||
reqTargets := req.Msg.GetTargets()
|
||||
targets := make([]*execution.Target, len(reqTargets))
|
||||
for i, target := range reqTargets {
|
||||
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 details *domain.ObjectDetails
|
||||
instanceID := authz.GetInstance(ctx).InstanceID()
|
||||
switch t := req.GetCondition().GetConditionType().(type) {
|
||||
switch t := req.Msg.GetCondition().GetConditionType().(type) {
|
||||
case *action.Condition_Request:
|
||||
cond := executionConditionFromRequest(t.Request)
|
||||
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 {
|
||||
return nil, err
|
||||
}
|
||||
return &action.SetExecutionResponse{
|
||||
return connect.NewResponse(&action.SetExecutionResponse{
|
||||
SetDate: timestamppb.New(details.EventDate),
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (s *Server) ListExecutionFunctions(ctx context.Context, _ *action.ListExecutionFunctionsRequest) (*action.ListExecutionFunctionsResponse, error) {
|
||||
return &action.ListExecutionFunctionsResponse{
|
||||
func (s *Server) ListExecutionFunctions(ctx context.Context, _ *connect.Request[action.ListExecutionFunctionsRequest]) (*connect.Response[action.ListExecutionFunctionsResponse], error) {
|
||||
return connect.NewResponse(&action.ListExecutionFunctionsResponse{
|
||||
Functions: s.ListActionFunctions(),
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (s *Server) ListExecutionMethods(ctx context.Context, _ *action.ListExecutionMethodsRequest) (*action.ListExecutionMethodsResponse, error) {
|
||||
return &action.ListExecutionMethodsResponse{
|
||||
func (s *Server) ListExecutionMethods(ctx context.Context, _ *connect.Request[action.ListExecutionMethodsRequest]) (*connect.Response[action.ListExecutionMethodsResponse], error) {
|
||||
return connect.NewResponse(&action.ListExecutionMethodsResponse{
|
||||
Methods: s.ListGRPCMethods(),
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (s *Server) ListExecutionServices(ctx context.Context, _ *action.ListExecutionServicesRequest) (*action.ListExecutionServicesResponse, error) {
|
||||
return &action.ListExecutionServicesResponse{
|
||||
func (s *Server) ListExecutionServices(ctx context.Context, _ *connect.Request[action.ListExecutionServicesRequest]) (*connect.Response[action.ListExecutionServicesResponse], error) {
|
||||
return connect.NewResponse(&action.ListExecutionServicesResponse{
|
||||
Services: s.ListGRPCServices(),
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func executionConditionFromRequest(request *action.RequestExecution) *command.ExecutionAPICondition {
|
||||
|
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"strings"
|
||||
|
||||
"connectrpc.com/connect"
|
||||
"google.golang.org/protobuf/types/known/durationpb"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
|
||||
@@ -22,14 +23,14 @@ const (
|
||||
conditionIDEventGroupSegmentCount = 1
|
||||
)
|
||||
|
||||
func (s *Server) GetTarget(ctx context.Context, req *action.GetTargetRequest) (*action.GetTargetResponse, error) {
|
||||
resp, err := s.query.GetTargetByID(ctx, req.GetId())
|
||||
func (s *Server) GetTarget(ctx context.Context, req *connect.Request[action.GetTargetRequest]) (*connect.Response[action.GetTargetResponse], error) {
|
||||
resp, err := s.query.GetTargetByID(ctx, req.Msg.GetId())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &action.GetTargetResponse{
|
||||
return connect.NewResponse(&action.GetTargetResponse{
|
||||
Target: targetToPb(resp),
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
type InstanceContext interface {
|
||||
@@ -41,8 +42,8 @@ type Context interface {
|
||||
GetOwner() InstanceContext
|
||||
}
|
||||
|
||||
func (s *Server) ListTargets(ctx context.Context, req *action.ListTargetsRequest) (*action.ListTargetsResponse, error) {
|
||||
queries, err := s.ListTargetsRequestToModel(req)
|
||||
func (s *Server) ListTargets(ctx context.Context, req *connect.Request[action.ListTargetsRequest]) (*connect.Response[action.ListTargetsResponse], error) {
|
||||
queries, err := s.ListTargetsRequestToModel(req.Msg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -50,14 +51,14 @@ func (s *Server) ListTargets(ctx context.Context, req *action.ListTargetsRequest
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &action.ListTargetsResponse{
|
||||
return connect.NewResponse(&action.ListTargetsResponse{
|
||||
Result: targetsToPb(resp.Targets),
|
||||
Pagination: filter.QueryToPaginationPb(queries.SearchRequest, resp.SearchResponse),
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (s *Server) ListExecutions(ctx context.Context, req *action.ListExecutionsRequest) (*action.ListExecutionsResponse, error) {
|
||||
queries, err := s.ListExecutionsRequestToModel(req)
|
||||
func (s *Server) ListExecutions(ctx context.Context, req *connect.Request[action.ListExecutionsRequest]) (*connect.Response[action.ListExecutionsResponse], error) {
|
||||
queries, err := s.ListExecutionsRequestToModel(req.Msg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -65,10 +66,10 @@ func (s *Server) ListExecutions(ctx context.Context, req *action.ListExecutionsR
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &action.ListExecutionsResponse{
|
||||
return connect.NewResponse(&action.ListExecutionsResponse{
|
||||
Result: executionsToPb(resp.Executions),
|
||||
Pagination: filter.QueryToPaginationPb(queries.SearchRequest, resp.SearchResponse),
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func targetsToPb(targets []*query.Target) []*action.Target {
|
||||
|
@@ -1,7 +1,10 @@
|
||||
package action
|
||||
|
||||
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/grpc/server"
|
||||
@@ -9,12 +12,12 @@ import (
|
||||
"github.com/zitadel/zitadel/internal/config/systemdefaults"
|
||||
"github.com/zitadel/zitadel/internal/query"
|
||||
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 {
|
||||
action.UnimplementedActionServiceServer
|
||||
systemDefaults systemdefaults.SystemDefaults
|
||||
command *command.Commands
|
||||
query *query.Queries
|
||||
@@ -43,8 +46,12 @@ func CreateServer(
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) RegisterServer(grpcServer *grpc.Server) {
|
||||
action.RegisterActionServiceServer(grpcServer, s)
|
||||
func (s *Server) RegisterConnectServer(interceptors ...connect.Interceptor) (string, http.Handler) {
|
||||
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 {
|
||||
|
@@ -3,6 +3,7 @@ package action
|
||||
import (
|
||||
"context"
|
||||
|
||||
"connectrpc.com/connect"
|
||||
"github.com/muhlemmer/gu"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
|
||||
@@ -13,8 +14,8 @@ import (
|
||||
action "github.com/zitadel/zitadel/pkg/grpc/action/v2beta"
|
||||
)
|
||||
|
||||
func (s *Server) CreateTarget(ctx context.Context, req *action.CreateTargetRequest) (*action.CreateTargetResponse, error) {
|
||||
add := createTargetToCommand(req)
|
||||
func (s *Server) CreateTarget(ctx context.Context, req *connect.Request[action.CreateTargetRequest]) (*connect.Response[action.CreateTargetResponse], error) {
|
||||
add := createTargetToCommand(req.Msg)
|
||||
instanceID := authz.GetInstance(ctx).InstanceID()
|
||||
createdAt, err := s.command.AddTarget(ctx, add, instanceID)
|
||||
if err != nil {
|
||||
@@ -24,16 +25,16 @@ func (s *Server) CreateTarget(ctx context.Context, req *action.CreateTargetReque
|
||||
if !createdAt.IsZero() {
|
||||
creationDate = timestamppb.New(createdAt)
|
||||
}
|
||||
return &action.CreateTargetResponse{
|
||||
return connect.NewResponse(&action.CreateTargetResponse{
|
||||
Id: add.AggregateID,
|
||||
CreationDate: creationDate,
|
||||
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()
|
||||
update := updateTargetToCommand(req)
|
||||
update := updateTargetToCommand(req.Msg)
|
||||
changedAt, err := s.command.ChangeTarget(ctx, update, instanceID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -42,15 +43,15 @@ func (s *Server) UpdateTarget(ctx context.Context, req *action.UpdateTargetReque
|
||||
if !changedAt.IsZero() {
|
||||
changeDate = timestamppb.New(changedAt)
|
||||
}
|
||||
return &action.UpdateTargetResponse{
|
||||
return connect.NewResponse(&action.UpdateTargetResponse{
|
||||
ChangeDate: changeDate,
|
||||
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()
|
||||
deletedAt, err := s.command.DeleteTarget(ctx, req.GetId(), instanceID)
|
||||
deletedAt, err := s.command.DeleteTarget(ctx, req.Msg.GetId(), instanceID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -58,9 +59,9 @@ func (s *Server) DeleteTarget(ctx context.Context, req *action.DeleteTargetReque
|
||||
if !deletedAt.IsZero() {
|
||||
deletionDate = timestamppb.New(deletedAt)
|
||||
}
|
||||
return &action.DeleteTargetResponse{
|
||||
return connect.NewResponse(&action.DeleteTargetResponse{
|
||||
DeletionDate: deletionDate,
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func createTargetToCommand(req *action.CreateTargetRequest) *command.AddTarget {
|
||||
|
@@ -5,6 +5,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"connectrpc.com/connect"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/grpc/app/v2beta/convert"
|
||||
@@ -13,15 +14,15 @@ import (
|
||||
app "github.com/zitadel/zitadel/pkg/grpc/app/v2beta"
|
||||
)
|
||||
|
||||
func (s *Server) CreateApplication(ctx context.Context, req *app.CreateApplicationRequest) (*app.CreateApplicationResponse, error) {
|
||||
switch t := req.GetCreationRequestType().(type) {
|
||||
func (s *Server) CreateApplication(ctx context.Context, req *connect.Request[app.CreateApplicationRequest]) (*connect.Response[app.CreateApplicationResponse], error) {
|
||||
switch t := req.Msg.GetCreationRequestType().(type) {
|
||||
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 {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &app.CreateApplicationResponse{
|
||||
return connect.NewResponse(&app.CreateApplicationResponse{
|
||||
AppId: apiApp.AppID,
|
||||
CreationDate: timestamppb.New(apiApp.ChangeDate),
|
||||
CreationResponseType: &app.CreateApplicationResponse_ApiResponse{
|
||||
@@ -30,10 +31,10 @@ func (s *Server) CreateApplication(ctx context.Context, req *app.CreateApplicati
|
||||
ClientSecret: apiApp.ClientSecretString,
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
}), nil
|
||||
|
||||
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 {
|
||||
return nil, err
|
||||
}
|
||||
@@ -43,7 +44,7 @@ func (s *Server) CreateApplication(ctx context.Context, req *app.CreateApplicati
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &app.CreateApplicationResponse{
|
||||
return connect.NewResponse(&app.CreateApplicationResponse{
|
||||
AppId: oidcApp.AppID,
|
||||
CreationDate: timestamppb.New(oidcApp.ChangeDate),
|
||||
CreationResponseType: &app.CreateApplicationResponse_OidcResponse{
|
||||
@@ -54,10 +55,10 @@ func (s *Server) CreateApplication(ctx context.Context, req *app.CreateApplicati
|
||||
ComplianceProblems: convert.ComplianceProblemsToLocalizedMessages(oidcApp.Compliance.Problems),
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
}), nil
|
||||
|
||||
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 {
|
||||
return nil, err
|
||||
}
|
||||
@@ -67,27 +68,27 @@ func (s *Server) CreateApplication(ctx context.Context, req *app.CreateApplicati
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &app.CreateApplicationResponse{
|
||||
return connect.NewResponse(&app.CreateApplicationResponse{
|
||||
AppId: samlApp.AppID,
|
||||
CreationDate: timestamppb.New(samlApp.ChangeDate),
|
||||
CreationResponseType: &app.CreateApplicationResponse_SamlResponse{
|
||||
SamlResponse: &app.CreateSAMLApplicationResponse{},
|
||||
},
|
||||
}, nil
|
||||
}), nil
|
||||
default:
|
||||
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
|
||||
|
||||
if name := strings.TrimSpace(req.GetName()); name != "" {
|
||||
if name := strings.TrimSpace(req.Msg.GetName()); name != "" {
|
||||
updatedDetails, err := s.command.UpdateApplicationName(
|
||||
ctx,
|
||||
req.GetProjectId(),
|
||||
req.Msg.GetProjectId(),
|
||||
&domain.ChangeApp{
|
||||
AppID: req.GetId(),
|
||||
AppID: req.Msg.GetId(),
|
||||
AppName: name,
|
||||
},
|
||||
"",
|
||||
@@ -99,9 +100,9 @@ func (s *Server) UpdateApplication(ctx context.Context, req *app.UpdateApplicati
|
||||
changedTime = updatedDetails.EventDate
|
||||
}
|
||||
|
||||
switch t := req.GetUpdateRequestType().(type) {
|
||||
switch t := req.Msg.GetUpdateRequestType().(type) {
|
||||
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 {
|
||||
return nil, err
|
||||
}
|
||||
@@ -109,7 +110,7 @@ func (s *Server) UpdateApplication(ctx context.Context, req *app.UpdateApplicati
|
||||
changedTime = updatedAPIApp.ChangeDate
|
||||
|
||||
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 {
|
||||
return nil, err
|
||||
}
|
||||
@@ -122,7 +123,7 @@ func (s *Server) UpdateApplication(ctx context.Context, req *app.UpdateApplicati
|
||||
changedTime = updatedOIDCApp.ChangeDate
|
||||
|
||||
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 {
|
||||
return nil, err
|
||||
}
|
||||
@@ -135,53 +136,53 @@ func (s *Server) UpdateApplication(ctx context.Context, req *app.UpdateApplicati
|
||||
changedTime = updatedSAMLApp.ChangeDate
|
||||
}
|
||||
|
||||
return &app.UpdateApplicationResponse{
|
||||
return connect.NewResponse(&app.UpdateApplicationResponse{
|
||||
ChangeDate: timestamppb.New(changedTime),
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (s *Server) DeleteApplication(ctx context.Context, req *app.DeleteApplicationRequest) (*app.DeleteApplicationResponse, error) {
|
||||
details, err := s.command.RemoveApplication(ctx, req.GetProjectId(), req.GetId(), "")
|
||||
func (s *Server) DeleteApplication(ctx context.Context, req *connect.Request[app.DeleteApplicationRequest]) (*connect.Response[app.DeleteApplicationResponse], error) {
|
||||
details, err := s.command.RemoveApplication(ctx, req.Msg.GetProjectId(), req.Msg.GetId(), "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &app.DeleteApplicationResponse{
|
||||
return connect.NewResponse(&app.DeleteApplicationResponse{
|
||||
DeletionDate: timestamppb.New(details.EventDate),
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (s *Server) DeactivateApplication(ctx context.Context, req *app.DeactivateApplicationRequest) (*app.DeactivateApplicationResponse, error) {
|
||||
details, err := s.command.DeactivateApplication(ctx, req.GetProjectId(), req.GetId(), "")
|
||||
func (s *Server) DeactivateApplication(ctx context.Context, req *connect.Request[app.DeactivateApplicationRequest]) (*connect.Response[app.DeactivateApplicationResponse], error) {
|
||||
details, err := s.command.DeactivateApplication(ctx, req.Msg.GetProjectId(), req.Msg.GetId(), "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &app.DeactivateApplicationResponse{
|
||||
return connect.NewResponse(&app.DeactivateApplicationResponse{
|
||||
DeactivationDate: timestamppb.New(details.EventDate),
|
||||
}, nil
|
||||
}), nil
|
||||
|
||||
}
|
||||
|
||||
func (s *Server) ReactivateApplication(ctx context.Context, req *app.ReactivateApplicationRequest) (*app.ReactivateApplicationResponse, error) {
|
||||
details, err := s.command.ReactivateApplication(ctx, req.GetProjectId(), req.GetId(), "")
|
||||
func (s *Server) ReactivateApplication(ctx context.Context, req *connect.Request[app.ReactivateApplicationRequest]) (*connect.Response[app.ReactivateApplicationResponse], error) {
|
||||
details, err := s.command.ReactivateApplication(ctx, req.Msg.GetProjectId(), req.Msg.GetId(), "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &app.ReactivateApplicationResponse{
|
||||
return connect.NewResponse(&app.ReactivateApplicationResponse{
|
||||
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 changeDate time.Time
|
||||
|
||||
switch req.GetAppType().(type) {
|
||||
switch req.Msg.GetAppType().(type) {
|
||||
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 {
|
||||
return nil, err
|
||||
}
|
||||
@@ -189,7 +190,7 @@ func (s *Server) RegenerateClientSecret(ctx context.Context, req *app.Regenerate
|
||||
changeDate = config.ChangeDate
|
||||
|
||||
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 {
|
||||
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 &app.RegenerateClientSecretResponse{
|
||||
return connect.NewResponse(&app.RegenerateClientSecretResponse{
|
||||
ClientSecret: secret,
|
||||
CreationDate: timestamppb.New(changeDate),
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
@@ -4,14 +4,15 @@ import (
|
||||
"context"
|
||||
"strings"
|
||||
|
||||
"connectrpc.com/connect"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/grpc/app/v2beta/convert"
|
||||
app "github.com/zitadel/zitadel/pkg/grpc/app/v2beta"
|
||||
)
|
||||
|
||||
func (s *Server) CreateApplicationKey(ctx context.Context, req *app.CreateApplicationKeyRequest) (*app.CreateApplicationKeyResponse, error) {
|
||||
domainReq := convert.CreateAPIClientKeyRequestToDomain(req)
|
||||
func (s *Server) CreateApplicationKey(ctx context.Context, req *connect.Request[app.CreateApplicationKeyRequest]) (*connect.Response[app.CreateApplicationKeyResponse], error) {
|
||||
domainReq := convert.CreateAPIClientKeyRequestToDomain(req.Msg)
|
||||
|
||||
appKey, err := s.command.AddApplicationKey(ctx, domainReq, "")
|
||||
if err != nil {
|
||||
@@ -23,25 +24,25 @@ func (s *Server) CreateApplicationKey(ctx context.Context, req *app.CreateApplic
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &app.CreateApplicationKeyResponse{
|
||||
return connect.NewResponse(&app.CreateApplicationKeyResponse{
|
||||
Id: appKey.KeyID,
|
||||
CreationDate: timestamppb.New(appKey.ChangeDate),
|
||||
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,
|
||||
strings.TrimSpace(req.GetProjectId()),
|
||||
strings.TrimSpace(req.GetApplicationId()),
|
||||
strings.TrimSpace(req.GetId()),
|
||||
strings.TrimSpace(req.GetOrganizationId()),
|
||||
strings.TrimSpace(req.Msg.GetProjectId()),
|
||||
strings.TrimSpace(req.Msg.GetApplicationId()),
|
||||
strings.TrimSpace(req.Msg.GetId()),
|
||||
strings.TrimSpace(req.Msg.GetOrganizationId()),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &app.DeleteApplicationKeyResponse{
|
||||
return connect.NewResponse(&app.DeleteApplicationKeyResponse{
|
||||
DeletionDate: timestamppb.New(deletionDetails.EventDate),
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"strings"
|
||||
|
||||
"connectrpc.com/connect"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/grpc/app/v2beta/convert"
|
||||
@@ -12,19 +13,19 @@ import (
|
||||
app "github.com/zitadel/zitadel/pkg/grpc/app/v2beta"
|
||||
)
|
||||
|
||||
func (s *Server) GetApplication(ctx context.Context, req *app.GetApplicationRequest) (*app.GetApplicationResponse, error) {
|
||||
res, err := s.query.AppByIDWithPermission(ctx, req.GetId(), false, s.checkPermission)
|
||||
func (s *Server) GetApplication(ctx context.Context, req *connect.Request[app.GetApplicationRequest]) (*connect.Response[app.GetApplicationResponse], error) {
|
||||
res, err := s.query.AppByIDWithPermission(ctx, req.Msg.GetId(), false, s.checkPermission)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &app.GetApplicationResponse{
|
||||
return connect.NewResponse(&app.GetApplicationResponse{
|
||||
App: convert.AppToPb(res),
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (s *Server) ListApplications(ctx context.Context, req *app.ListApplicationsRequest) (*app.ListApplicationsResponse, error) {
|
||||
queries, err := convert.ListApplicationsRequestToModel(s.systemDefaults, req)
|
||||
func (s *Server) ListApplications(ctx context.Context, req *connect.Request[app.ListApplicationsRequest]) (*connect.Response[app.ListApplicationsResponse], error) {
|
||||
queries, err := convert.ListApplicationsRequestToModel(s.systemDefaults, req.Msg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -34,32 +35,32 @@ func (s *Server) ListApplications(ctx context.Context, req *app.ListApplications
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &app.ListApplicationsResponse{
|
||||
return connect.NewResponse(&app.ListApplicationsResponse{
|
||||
Applications: convert.AppsToPb(res.Apps),
|
||||
Pagination: filter.QueryToPaginationPb(queries.SearchRequest, res.SearchResponse),
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (s *Server) GetApplicationKey(ctx context.Context, req *app.GetApplicationKeyRequest) (*app.GetApplicationKeyResponse, error) {
|
||||
queries, err := convert.GetApplicationKeyQueriesRequestToDomain(req.GetOrganizationId(), req.GetProjectId(), req.GetApplicationId())
|
||||
func (s *Server) GetApplicationKey(ctx context.Context, req *connect.Request[app.GetApplicationKeyRequest]) (*connect.Response[app.GetApplicationKeyResponse], error) {
|
||||
queries, err := convert.GetApplicationKeyQueriesRequestToDomain(req.Msg.GetOrganizationId(), req.Msg.GetProjectId(), req.Msg.GetApplicationId())
|
||||
if err != nil {
|
||||
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 {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &app.GetApplicationKeyResponse{
|
||||
return connect.NewResponse(&app.GetApplicationKeyResponse{
|
||||
Id: key.ID,
|
||||
CreationDate: timestamppb.New(key.CreationDate),
|
||||
ExpirationDate: timestamppb.New(key.Expiration),
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (s *Server) ListApplicationKeys(ctx context.Context, req *app.ListApplicationKeysRequest) (*app.ListApplicationKeysResponse, error) {
|
||||
queries, err := convert.ListApplicationKeysRequestToDomain(s.systemDefaults, req)
|
||||
func (s *Server) ListApplicationKeys(ctx context.Context, req *connect.Request[app.ListApplicationKeysRequest]) (*connect.Response[app.ListApplicationKeysResponse], error) {
|
||||
queries, err := convert.ListApplicationKeysRequestToDomain(s.systemDefaults, req.Msg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -69,8 +70,8 @@ func (s *Server) ListApplicationKeys(ctx context.Context, req *app.ListApplicati
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &app.ListApplicationKeysResponse{
|
||||
return connect.NewResponse(&app.ListApplicationKeysResponse{
|
||||
Keys: convert.ApplicationKeysToPb(res.AuthNKeys),
|
||||
Pagination: filter.QueryToPaginationPb(queries.SearchRequest, res.SearchResponse),
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
@@ -1,21 +1,23 @@
|
||||
package app
|
||||
|
||||
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/grpc/server"
|
||||
"github.com/zitadel/zitadel/internal/command"
|
||||
"github.com/zitadel/zitadel/internal/config/systemdefaults"
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
"github.com/zitadel/zitadel/internal/query"
|
||||
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 {
|
||||
app.UnimplementedAppServiceServer
|
||||
command *command.Commands
|
||||
query *query.Queries
|
||||
systemDefaults systemdefaults.SystemDefaults
|
||||
@@ -36,8 +38,12 @@ func CreateServer(
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) RegisterServer(grpcServer *grpc.Server) {
|
||||
app.RegisterAppServiceServer(grpcServer, s)
|
||||
func (s *Server) RegisterConnectServer(interceptors ...connect.Interceptor) (string, http.Handler) {
|
||||
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 {
|
||||
@@ -51,7 +57,3 @@ func (s *Server) MethodPrefix() string {
|
||||
func (s *Server) AuthMethods() authz.MethodMapping {
|
||||
return app.AppService_AuthMethods
|
||||
}
|
||||
|
||||
func (s *Server) RegisterGateway() server.RegisterGatewayFunc {
|
||||
return app.RegisterAppServiceHandler
|
||||
}
|
||||
|
@@ -3,6 +3,7 @@ package feature
|
||||
import (
|
||||
"context"
|
||||
|
||||
"connectrpc.com/connect"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
|
||||
@@ -10,8 +11,8 @@ import (
|
||||
"github.com/zitadel/zitadel/pkg/grpc/feature/v2"
|
||||
)
|
||||
|
||||
func (s *Server) SetSystemFeatures(ctx context.Context, req *feature.SetSystemFeaturesRequest) (_ *feature.SetSystemFeaturesResponse, err error) {
|
||||
features, err := systemFeaturesToCommand(req)
|
||||
func (s *Server) SetSystemFeatures(ctx context.Context, req *connect.Request[feature.SetSystemFeaturesRequest]) (_ *connect.Response[feature.SetSystemFeaturesResponse], err error) {
|
||||
features, err := systemFeaturesToCommand(req.Msg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -19,31 +20,31 @@ func (s *Server) SetSystemFeatures(ctx context.Context, req *feature.SetSystemFe
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &feature.SetSystemFeaturesResponse{
|
||||
return connect.NewResponse(&feature.SetSystemFeaturesResponse{
|
||||
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)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &feature.ResetSystemFeaturesResponse{
|
||||
return connect.NewResponse(&feature.ResetSystemFeaturesResponse{
|
||||
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)
|
||||
if err != nil {
|
||||
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) {
|
||||
features, err := instanceFeaturesToCommand(req)
|
||||
func (s *Server) SetInstanceFeatures(ctx context.Context, req *connect.Request[feature.SetInstanceFeaturesRequest]) (_ *connect.Response[feature.SetInstanceFeaturesResponse], err error) {
|
||||
features, err := instanceFeaturesToCommand(req.Msg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -51,44 +52,44 @@ func (s *Server) SetInstanceFeatures(ctx context.Context, req *feature.SetInstan
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &feature.SetInstanceFeaturesResponse{
|
||||
return connect.NewResponse(&feature.SetInstanceFeaturesResponse{
|
||||
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)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &feature.ResetInstanceFeaturesResponse{
|
||||
return connect.NewResponse(&feature.ResetInstanceFeaturesResponse{
|
||||
Details: object.DomainToDetailsPb(details),
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (s *Server) GetInstanceFeatures(ctx context.Context, req *feature.GetInstanceFeaturesRequest) (_ *feature.GetInstanceFeaturesResponse, err error) {
|
||||
f, err := s.query.GetInstanceFeatures(ctx, req.GetInheritance())
|
||||
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.Msg.GetInheritance())
|
||||
if err != nil {
|
||||
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")
|
||||
}
|
||||
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")
|
||||
}
|
||||
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")
|
||||
}
|
||||
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")
|
||||
}
|
||||
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")
|
||||
}
|
||||
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")
|
||||
}
|
||||
|
@@ -1,17 +1,22 @@
|
||||
package feature
|
||||
|
||||
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/grpc/server"
|
||||
"github.com/zitadel/zitadel/internal/command"
|
||||
"github.com/zitadel/zitadel/internal/query"
|
||||
"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 {
|
||||
feature.UnimplementedFeatureServiceServer
|
||||
command *command.Commands
|
||||
query *query.Queries
|
||||
}
|
||||
@@ -26,8 +31,12 @@ func CreateServer(
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) RegisterServer(grpcServer *grpc.Server) {
|
||||
feature.RegisterFeatureServiceServer(grpcServer, s)
|
||||
func (s *Server) RegisterConnectServer(interceptors ...connect.Interceptor) (string, http.Handler) {
|
||||
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 {
|
||||
|
@@ -3,6 +3,7 @@ package feature
|
||||
import (
|
||||
"context"
|
||||
|
||||
"connectrpc.com/connect"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
|
||||
@@ -10,77 +11,77 @@ import (
|
||||
feature "github.com/zitadel/zitadel/pkg/grpc/feature/v2beta"
|
||||
)
|
||||
|
||||
func (s *Server) SetSystemFeatures(ctx context.Context, req *feature.SetSystemFeaturesRequest) (_ *feature.SetSystemFeaturesResponse, err error) {
|
||||
details, err := s.command.SetSystemFeatures(ctx, systemFeaturesToCommand(req))
|
||||
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.Msg))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &feature.SetSystemFeaturesResponse{
|
||||
return connect.NewResponse(&feature.SetSystemFeaturesResponse{
|
||||
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)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &feature.ResetSystemFeaturesResponse{
|
||||
return connect.NewResponse(&feature.ResetSystemFeaturesResponse{
|
||||
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)
|
||||
if err != nil {
|
||||
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) {
|
||||
details, err := s.command.SetInstanceFeatures(ctx, instanceFeaturesToCommand(req))
|
||||
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.Msg))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &feature.SetInstanceFeaturesResponse{
|
||||
return connect.NewResponse(&feature.SetInstanceFeaturesResponse{
|
||||
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)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &feature.ResetInstanceFeaturesResponse{
|
||||
return connect.NewResponse(&feature.ResetInstanceFeaturesResponse{
|
||||
Details: object.DomainToDetailsPb(details),
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (s *Server) GetInstanceFeatures(ctx context.Context, req *feature.GetInstanceFeaturesRequest) (_ *feature.GetInstanceFeaturesResponse, err error) {
|
||||
f, err := s.query.GetInstanceFeatures(ctx, req.GetInheritance())
|
||||
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.Msg.GetInheritance())
|
||||
if err != nil {
|
||||
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")
|
||||
}
|
||||
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")
|
||||
}
|
||||
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")
|
||||
}
|
||||
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")
|
||||
}
|
||||
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")
|
||||
}
|
||||
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")
|
||||
}
|
||||
|
@@ -1,17 +1,22 @@
|
||||
package feature
|
||||
|
||||
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/grpc/server"
|
||||
"github.com/zitadel/zitadel/internal/command"
|
||||
"github.com/zitadel/zitadel/internal/query"
|
||||
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 {
|
||||
feature.UnimplementedFeatureServiceServer
|
||||
command *command.Commands
|
||||
query *query.Queries
|
||||
}
|
||||
@@ -26,8 +31,12 @@ func CreateServer(
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) RegisterServer(grpcServer *grpc.Server) {
|
||||
feature.RegisterFeatureServiceServer(grpcServer, s)
|
||||
func (s *Server) RegisterConnectServer(interceptors ...connect.Interceptor) (string, http.Handler) {
|
||||
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 {
|
||||
|
@@ -3,10 +3,12 @@ package gerrors
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"connectrpc.com/connect"
|
||||
"github.com/jackc/pgx/v5/pgconn"
|
||||
"github.com/zitadel/logging"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
"google.golang.org/protobuf/proto"
|
||||
"google.golang.org/protobuf/protoadapt"
|
||||
|
||||
commandErrors "github.com/zitadel/zitadel/internal/command/errors"
|
||||
@@ -36,6 +38,30 @@ func ZITADELToGRPCError(err error) error {
|
||||
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) {
|
||||
if err == nil {
|
||||
return codes.OK, "", "", false
|
||||
|
@@ -3,6 +3,7 @@ package idp
|
||||
import (
|
||||
"context"
|
||||
|
||||
"connectrpc.com/connect"
|
||||
"github.com/crewjam/saml"
|
||||
"github.com/muhlemmer/gu"
|
||||
"google.golang.org/protobuf/types/known/durationpb"
|
||||
@@ -15,12 +16,12 @@ import (
|
||||
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) {
|
||||
idp, err := s.query.IDPTemplateByID(ctx, true, req.Id, false, s.checkPermission)
|
||||
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.Msg.GetId(), false, s.checkPermission)
|
||||
if err != nil {
|
||||
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 {
|
||||
|
@@ -1,7 +1,10 @@
|
||||
package idp
|
||||
|
||||
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/grpc/server"
|
||||
@@ -9,12 +12,12 @@ import (
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
"github.com/zitadel/zitadel/internal/query"
|
||||
"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 {
|
||||
idp.UnimplementedIdentityProviderServiceServer
|
||||
command *command.Commands
|
||||
query *query.Queries
|
||||
|
||||
@@ -35,8 +38,12 @@ func CreateServer(
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) RegisterServer(grpcServer *grpc.Server) {
|
||||
idp.RegisterIdentityProviderServiceServer(grpcServer, s)
|
||||
func (s *Server) RegisterConnectServer(interceptors ...connect.Interceptor) (string, http.Handler) {
|
||||
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 {
|
||||
|
@@ -3,48 +3,49 @@ package instance
|
||||
import (
|
||||
"context"
|
||||
|
||||
"connectrpc.com/connect"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
|
||||
instance "github.com/zitadel/zitadel/pkg/grpc/instance/v2beta"
|
||||
)
|
||||
|
||||
func (s *Server) AddCustomDomain(ctx context.Context, req *instance.AddCustomDomainRequest) (*instance.AddCustomDomainResponse, error) {
|
||||
details, err := s.command.AddInstanceDomain(ctx, req.GetDomain())
|
||||
func (s *Server) AddCustomDomain(ctx context.Context, req *connect.Request[instance.AddCustomDomainRequest]) (*connect.Response[instance.AddCustomDomainResponse], error) {
|
||||
details, err := s.command.AddInstanceDomain(ctx, req.Msg.GetDomain())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &instance.AddCustomDomainResponse{
|
||||
return connect.NewResponse(&instance.AddCustomDomainResponse{
|
||||
CreationDate: timestamppb.New(details.CreationDate),
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (s *Server) RemoveCustomDomain(ctx context.Context, req *instance.RemoveCustomDomainRequest) (*instance.RemoveCustomDomainResponse, error) {
|
||||
details, err := s.command.RemoveInstanceDomain(ctx, req.GetDomain())
|
||||
func (s *Server) RemoveCustomDomain(ctx context.Context, req *connect.Request[instance.RemoveCustomDomainRequest]) (*connect.Response[instance.RemoveCustomDomainResponse], error) {
|
||||
details, err := s.command.RemoveInstanceDomain(ctx, req.Msg.GetDomain())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &instance.RemoveCustomDomainResponse{
|
||||
return connect.NewResponse(&instance.RemoveCustomDomainResponse{
|
||||
DeletionDate: timestamppb.New(details.EventDate),
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (s *Server) AddTrustedDomain(ctx context.Context, req *instance.AddTrustedDomainRequest) (*instance.AddTrustedDomainResponse, error) {
|
||||
details, err := s.command.AddTrustedDomain(ctx, req.GetDomain())
|
||||
func (s *Server) AddTrustedDomain(ctx context.Context, req *connect.Request[instance.AddTrustedDomainRequest]) (*connect.Response[instance.AddTrustedDomainResponse], error) {
|
||||
details, err := s.command.AddTrustedDomain(ctx, req.Msg.GetDomain())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &instance.AddTrustedDomainResponse{
|
||||
return connect.NewResponse(&instance.AddTrustedDomainResponse{
|
||||
CreationDate: timestamppb.New(details.CreationDate),
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (s *Server) RemoveTrustedDomain(ctx context.Context, req *instance.RemoveTrustedDomainRequest) (*instance.RemoveTrustedDomainResponse, error) {
|
||||
details, err := s.command.RemoveTrustedDomain(ctx, req.GetDomain())
|
||||
func (s *Server) RemoveTrustedDomain(ctx context.Context, req *connect.Request[instance.RemoveTrustedDomainRequest]) (*connect.Response[instance.RemoveTrustedDomainResponse], error) {
|
||||
details, err := s.command.RemoveTrustedDomain(ctx, req.Msg.GetDomain())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &instance.RemoveTrustedDomainResponse{
|
||||
return connect.NewResponse(&instance.RemoveTrustedDomainResponse{
|
||||
DeletionDate: timestamppb.New(details.EventDate),
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
@@ -3,30 +3,31 @@ package instance
|
||||
import (
|
||||
"context"
|
||||
|
||||
"connectrpc.com/connect"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
|
||||
instance "github.com/zitadel/zitadel/pkg/grpc/instance/v2beta"
|
||||
)
|
||||
|
||||
func (s *Server) DeleteInstance(ctx context.Context, request *instance.DeleteInstanceRequest) (*instance.DeleteInstanceResponse, error) {
|
||||
obj, err := s.command.RemoveInstance(ctx, request.GetInstanceId())
|
||||
func (s *Server) DeleteInstance(ctx context.Context, request *connect.Request[instance.DeleteInstanceRequest]) (*connect.Response[instance.DeleteInstanceResponse], error) {
|
||||
obj, err := s.command.RemoveInstance(ctx, request.Msg.GetInstanceId())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &instance.DeleteInstanceResponse{
|
||||
return connect.NewResponse(&instance.DeleteInstanceResponse{
|
||||
DeletionDate: timestamppb.New(obj.EventDate),
|
||||
}, nil
|
||||
}), nil
|
||||
|
||||
}
|
||||
|
||||
func (s *Server) UpdateInstance(ctx context.Context, request *instance.UpdateInstanceRequest) (*instance.UpdateInstanceResponse, error) {
|
||||
obj, err := s.command.UpdateInstance(ctx, request.GetInstanceName())
|
||||
func (s *Server) UpdateInstance(ctx context.Context, request *connect.Request[instance.UpdateInstanceRequest]) (*connect.Response[instance.UpdateInstanceResponse], error) {
|
||||
obj, err := s.command.UpdateInstance(ctx, request.Msg.GetInstanceName())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &instance.UpdateInstanceResponse{
|
||||
return connect.NewResponse(&instance.UpdateInstanceResponse{
|
||||
ChangeDate: timestamppb.New(obj.EventDate),
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
@@ -3,23 +3,25 @@ package instance
|
||||
import (
|
||||
"context"
|
||||
|
||||
"connectrpc.com/connect"
|
||||
|
||||
filter "github.com/zitadel/zitadel/internal/api/grpc/filter/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)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &instance.GetInstanceResponse{
|
||||
return connect.NewResponse(&instance.GetInstanceResponse{
|
||||
Instance: ToProtoObject(inst),
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (s *Server) ListInstances(ctx context.Context, req *instance.ListInstancesRequest) (*instance.ListInstancesResponse, error) {
|
||||
queries, err := ListInstancesRequestToModel(req, s.systemDefaults)
|
||||
func (s *Server) ListInstances(ctx context.Context, req *connect.Request[instance.ListInstancesRequest]) (*connect.Response[instance.ListInstancesResponse], error) {
|
||||
queries, err := ListInstancesRequestToModel(req.Msg, s.systemDefaults)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -29,14 +31,14 @@ func (s *Server) ListInstances(ctx context.Context, req *instance.ListInstancesR
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &instance.ListInstancesResponse{
|
||||
return connect.NewResponse(&instance.ListInstancesResponse{
|
||||
Instances: InstancesToPb(instances.Instances),
|
||||
Pagination: filter.QueryToPaginationPb(queries.SearchRequest, instances.SearchResponse),
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (s *Server) ListCustomDomains(ctx context.Context, req *instance.ListCustomDomainsRequest) (*instance.ListCustomDomainsResponse, error) {
|
||||
queries, err := ListCustomDomainsRequestToModel(req, s.systemDefaults)
|
||||
func (s *Server) ListCustomDomains(ctx context.Context, req *connect.Request[instance.ListCustomDomainsRequest]) (*connect.Response[instance.ListCustomDomainsResponse], error) {
|
||||
queries, err := ListCustomDomainsRequestToModel(req.Msg, s.systemDefaults)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -46,14 +48,14 @@ func (s *Server) ListCustomDomains(ctx context.Context, req *instance.ListCustom
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &instance.ListCustomDomainsResponse{
|
||||
return connect.NewResponse(&instance.ListCustomDomainsResponse{
|
||||
Domains: DomainsToPb(domains.Domains),
|
||||
Pagination: filter.QueryToPaginationPb(queries.SearchRequest, domains.SearchResponse),
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (s *Server) ListTrustedDomains(ctx context.Context, req *instance.ListTrustedDomainsRequest) (*instance.ListTrustedDomainsResponse, error) {
|
||||
queries, err := ListTrustedDomainsRequestToModel(req, s.systemDefaults)
|
||||
func (s *Server) ListTrustedDomains(ctx context.Context, req *connect.Request[instance.ListTrustedDomainsRequest]) (*connect.Response[instance.ListTrustedDomainsResponse], error) {
|
||||
queries, err := ListTrustedDomainsRequestToModel(req.Msg, s.systemDefaults)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -63,8 +65,8 @@ func (s *Server) ListTrustedDomains(ctx context.Context, req *instance.ListTrust
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &instance.ListTrustedDomainsResponse{
|
||||
return connect.NewResponse(&instance.ListTrustedDomainsResponse{
|
||||
TrustedDomain: trustedDomainsToPb(domains.Domains),
|
||||
Pagination: filter.QueryToPaginationPb(queries.SearchRequest, domains.SearchResponse),
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
@@ -1,7 +1,10 @@
|
||||
package instance
|
||||
|
||||
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/grpc/server"
|
||||
@@ -9,12 +12,12 @@ import (
|
||||
"github.com/zitadel/zitadel/internal/config/systemdefaults"
|
||||
"github.com/zitadel/zitadel/internal/query"
|
||||
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 {
|
||||
instance.UnimplementedInstanceServiceServer
|
||||
command *command.Commands
|
||||
query *query.Queries
|
||||
systemDefaults systemdefaults.SystemDefaults
|
||||
@@ -39,8 +42,12 @@ func CreateServer(
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) RegisterServer(grpcServer *grpc.Server) {
|
||||
instance.RegisterInstanceServiceServer(grpcServer, s)
|
||||
func (s *Server) RegisterConnectServer(interceptors ...connect.Interceptor) (string, http.Handler) {
|
||||
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 {
|
||||
|
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"encoding/base64"
|
||||
|
||||
"connectrpc.com/connect"
|
||||
"github.com/zitadel/logging"
|
||||
"github.com/zitadel/oidc/v3/pkg/op"
|
||||
"google.golang.org/protobuf/types/known/durationpb"
|
||||
@@ -18,30 +19,30 @@ import (
|
||||
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) {
|
||||
authRequest, err := s.query.AuthRequestByID(ctx, true, req.GetAuthRequestId(), true)
|
||||
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.Msg.GetAuthRequestId(), true)
|
||||
if err != nil {
|
||||
logging.WithError(err).Error("query authRequest by ID")
|
||||
return nil, err
|
||||
}
|
||||
return &oidc_pb.GetAuthRequestResponse{
|
||||
return connect.NewResponse(&oidc_pb.GetAuthRequestResponse{
|
||||
AuthRequest: authRequestToPb(authRequest),
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (s *Server) CreateCallback(ctx context.Context, req *oidc_pb.CreateCallbackRequest) (*oidc_pb.CreateCallbackResponse, error) {
|
||||
switch v := req.GetCallbackKind().(type) {
|
||||
func (s *Server) CreateCallback(ctx context.Context, req *connect.Request[oidc_pb.CreateCallbackRequest]) (*connect.Response[oidc_pb.CreateCallbackResponse], error) {
|
||||
switch v := req.Msg.GetCallbackKind().(type) {
|
||||
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:
|
||||
return s.linkSessionToAuthRequest(ctx, req.GetAuthRequestId(), v.Session)
|
||||
return s.linkSessionToAuthRequest(ctx, req.Msg.GetAuthRequestId(), v.Session)
|
||||
default:
|
||||
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) {
|
||||
deviceRequest, err := s.query.DeviceAuthRequestByUserCode(ctx, req.GetUserCode())
|
||||
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.Msg.GetUserCode())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -49,7 +50,7 @@ func (s *Server) GetDeviceAuthorizationRequest(ctx context.Context, req *oidc_pb
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &oidc_pb.GetDeviceAuthorizationRequestResponse{
|
||||
return connect.NewResponse(&oidc_pb.GetDeviceAuthorizationRequestResponse{
|
||||
DeviceAuthorizationRequest: &oidc_pb.DeviceAuthorizationRequest{
|
||||
Id: base64.RawURLEncoding.EncodeToString(encrypted),
|
||||
ClientId: deviceRequest.ClientID,
|
||||
@@ -57,24 +58,24 @@ func (s *Server) GetDeviceAuthorizationRequest(ctx context.Context, req *oidc_pb
|
||||
AppName: deviceRequest.AppName,
|
||||
ProjectName: deviceRequest.ProjectName,
|
||||
},
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (s *Server) AuthorizeOrDenyDeviceAuthorization(ctx context.Context, req *oidc_pb.AuthorizeOrDenyDeviceAuthorizationRequest) (*oidc_pb.AuthorizeOrDenyDeviceAuthorizationResponse, error) {
|
||||
deviceCode, err := s.deviceCodeFromID(req.GetDeviceAuthorizationId())
|
||||
func (s *Server) AuthorizeOrDenyDeviceAuthorization(ctx context.Context, req *connect.Request[oidc_pb.AuthorizeOrDenyDeviceAuthorizationRequest]) (*connect.Response[oidc_pb.AuthorizeOrDenyDeviceAuthorizationResponse], error) {
|
||||
deviceCode, err := s.deviceCodeFromID(req.Msg.GetDeviceAuthorizationId())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
switch req.GetDecision().(type) {
|
||||
switch req.Msg.GetDecision().(type) {
|
||||
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:
|
||||
_, err = s.command.CancelDeviceAuth(ctx, deviceCode, domain.DeviceAuthCanceledDenied)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &oidc_pb.AuthorizeOrDenyDeviceAuthorizationResponse{}, nil
|
||||
return connect.NewResponse(&oidc_pb.AuthorizeOrDenyDeviceAuthorizationResponse{}), nil
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
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()))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -146,13 +147,13 @@ func (s *Server) failAuthRequest(ctx context.Context, authRequestID string, ae *
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &oidc_pb.CreateCallbackResponse{
|
||||
return connect.NewResponse(&oidc_pb.CreateCallbackResponse{
|
||||
Details: object.DomainToDetailsPb(details),
|
||||
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)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -172,10 +173,10 @@ func (s *Server) linkSessionToAuthRequest(ctx context.Context, authRequestID str
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &oidc_pb.CreateCallbackResponse{
|
||||
return connect.NewResponse(&oidc_pb.CreateCallbackResponse{
|
||||
Details: object.DomainToDetailsPb(details),
|
||||
CallbackUrl: callback,
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func errorReasonToDomain(errorReason oidc_pb.ErrorReason) domain.OIDCErrorReason {
|
||||
|
@@ -1,7 +1,10 @@
|
||||
package oidc
|
||||
|
||||
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/grpc/server"
|
||||
@@ -10,12 +13,12 @@ import (
|
||||
"github.com/zitadel/zitadel/internal/crypto"
|
||||
"github.com/zitadel/zitadel/internal/query"
|
||||
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 {
|
||||
oidc_pb.UnimplementedOIDCServiceServer
|
||||
command *command.Commands
|
||||
query *query.Queries
|
||||
|
||||
@@ -42,8 +45,12 @@ func CreateServer(
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) RegisterServer(grpcServer *grpc.Server) {
|
||||
oidc_pb.RegisterOIDCServiceServer(grpcServer, s)
|
||||
func (s *Server) RegisterConnectServer(interceptors ...connect.Interceptor) (string, http.Handler) {
|
||||
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 {
|
||||
|
@@ -3,6 +3,7 @@ package oidc
|
||||
import (
|
||||
"context"
|
||||
|
||||
"connectrpc.com/connect"
|
||||
"github.com/zitadel/logging"
|
||||
"github.com/zitadel/oidc/v3/pkg/op"
|
||||
"google.golang.org/protobuf/types/known/durationpb"
|
||||
@@ -17,15 +18,15 @@ import (
|
||||
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) {
|
||||
authRequest, err := s.query.AuthRequestByID(ctx, true, req.GetAuthRequestId(), true)
|
||||
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.Msg.GetAuthRequestId(), true)
|
||||
if err != nil {
|
||||
logging.WithError(err).Error("query authRequest by ID")
|
||||
return nil, err
|
||||
}
|
||||
return &oidc_pb.GetAuthRequestResponse{
|
||||
return connect.NewResponse(&oidc_pb.GetAuthRequestResponse{
|
||||
AuthRequest: authRequestToPb(authRequest),
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
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) {
|
||||
switch v := req.GetCallbackKind().(type) {
|
||||
func (s *Server) CreateCallback(ctx context.Context, req *connect.Request[oidc_pb.CreateCallbackRequest]) (*connect.Response[oidc_pb.CreateCallbackResponse], error) {
|
||||
switch v := req.Msg.GetCallbackKind().(type) {
|
||||
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:
|
||||
return s.linkSessionToAuthRequest(ctx, req.GetAuthRequestId(), v.Session)
|
||||
return s.linkSessionToAuthRequest(ctx, req.Msg.GetAuthRequestId(), v.Session)
|
||||
default:
|
||||
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()))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -94,10 +95,10 @@ func (s *Server) failAuthRequest(ctx context.Context, authRequestID string, ae *
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &oidc_pb.CreateCallbackResponse{
|
||||
return connect.NewResponse(&oidc_pb.CreateCallbackResponse{
|
||||
Details: object.DomainToDetailsPb(details),
|
||||
CallbackUrl: callback,
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
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)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -130,10 +131,10 @@ func (s *Server) linkSessionToAuthRequest(ctx context.Context, authRequestID str
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &oidc_pb.CreateCallbackResponse{
|
||||
return connect.NewResponse(&oidc_pb.CreateCallbackResponse{
|
||||
Details: object.DomainToDetailsPb(details),
|
||||
CallbackUrl: callback,
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func errorReasonToDomain(errorReason oidc_pb.ErrorReason) domain.OIDCErrorReason {
|
||||
|
@@ -1,7 +1,10 @@
|
||||
package oidc
|
||||
|
||||
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/grpc/server"
|
||||
@@ -9,12 +12,12 @@ import (
|
||||
"github.com/zitadel/zitadel/internal/command"
|
||||
"github.com/zitadel/zitadel/internal/query"
|
||||
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 {
|
||||
oidc_pb.UnimplementedOIDCServiceServer
|
||||
command *command.Commands
|
||||
query *query.Queries
|
||||
|
||||
@@ -38,8 +41,12 @@ func CreateServer(
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) RegisterServer(grpcServer *grpc.Server) {
|
||||
oidc_pb.RegisterOIDCServiceServer(grpcServer, s)
|
||||
func (s *Server) RegisterConnectServer(interceptors ...connect.Interceptor) (string, http.Handler) {
|
||||
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 {
|
||||
|
@@ -3,6 +3,8 @@ package org
|
||||
import (
|
||||
"context"
|
||||
|
||||
"connectrpc.com/connect"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/grpc/object/v2"
|
||||
"github.com/zitadel/zitadel/internal/api/grpc/user/v2"
|
||||
"github.com/zitadel/zitadel/internal/command"
|
||||
@@ -10,8 +12,8 @@ import (
|
||||
"github.com/zitadel/zitadel/pkg/grpc/org/v2"
|
||||
)
|
||||
|
||||
func (s *Server) AddOrganization(ctx context.Context, request *org.AddOrganizationRequest) (*org.AddOrganizationResponse, error) {
|
||||
orgSetup, err := addOrganizationRequestToCommand(request)
|
||||
func (s *Server) AddOrganization(ctx context.Context, request *connect.Request[org.AddOrganizationRequest]) (*connect.Response[org.AddOrganizationResponse], error) {
|
||||
orgSetup, err := addOrganizationRequestToCommand(request.Msg)
|
||||
if err != nil {
|
||||
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))
|
||||
for _, admin := range createdOrg.OrgAdmins {
|
||||
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),
|
||||
OrganizationId: createdOrg.ObjectDetails.ResourceOwner,
|
||||
CreatedAdmins: admins,
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
@@ -4,6 +4,7 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"connectrpc.com/connect"
|
||||
"github.com/muhlemmer/gu"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
@@ -138,7 +139,7 @@ func Test_createdOrganizationToPb(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want *org.AddOrganizationResponse
|
||||
want *connect.Response[org.AddOrganizationResponse]
|
||||
wantErr error
|
||||
}{
|
||||
{
|
||||
@@ -159,7 +160,7 @@ func Test_createdOrganizationToPb(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
want: &org.AddOrganizationResponse{
|
||||
want: connect.NewResponse(&org.AddOrganizationResponse{
|
||||
Details: &object.Details{
|
||||
Sequence: 1,
|
||||
ChangeDate: timestamppb.New(now),
|
||||
@@ -173,7 +174,7 @@ func Test_createdOrganizationToPb(t *testing.T) {
|
||||
PhoneCode: gu.Ptr("phoneCode"),
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
|
@@ -3,6 +3,8 @@ package org
|
||||
import (
|
||||
"context"
|
||||
|
||||
"connectrpc.com/connect"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/authz"
|
||||
"github.com/zitadel/zitadel/internal/api/grpc/object/v2"
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
@@ -11,36 +13,36 @@ import (
|
||||
"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)
|
||||
if err != nil {
|
||||
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 {
|
||||
return nil, err
|
||||
}
|
||||
return &org.ListOrganizationsResponse{
|
||||
return connect.NewResponse(&org.ListOrganizationsResponse{
|
||||
Result: organizationsToPb(orgs.Orgs),
|
||||
Details: object.ToListDetails(orgs.SearchResponse),
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func listOrgRequestToModel(ctx context.Context, req *org.ListOrganizationsRequest) (*query.OrgSearchQueries, error) {
|
||||
offset, limit, asc := object.ListQueryToQuery(req.Query)
|
||||
queries, err := orgQueriesToQuery(ctx, req.Queries)
|
||||
func listOrgRequestToModel(ctx context.Context, req *connect.Request[org.ListOrganizationsRequest]) (*connect.Response[query.OrgSearchQueries], error) {
|
||||
offset, limit, asc := object.ListQueryToQuery(req.Msg.Query)
|
||||
queries, err := orgQueriesToQuery(ctx, req.Msg.Queries)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &query.OrgSearchQueries{
|
||||
return connect.NewResponse(&query.OrgSearchQueries{
|
||||
SearchRequest: query.SearchRequest{
|
||||
Offset: offset,
|
||||
Limit: limit,
|
||||
SortingColumn: fieldNameToOrganizationColumn(req.SortingColumn),
|
||||
SortingColumn: fieldNameToOrganizationColumn(req.Msg.SortingColumn),
|
||||
Asc: asc,
|
||||
},
|
||||
Queries: queries,
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func orgQueriesToQuery(ctx context.Context, queries []*org.SearchQuery) (_ []query.SearchQuery, err error) {
|
||||
|
@@ -1,7 +1,10 @@
|
||||
package org
|
||||
|
||||
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/grpc/server"
|
||||
@@ -9,12 +12,12 @@ import (
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
"github.com/zitadel/zitadel/internal/query"
|
||||
"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 {
|
||||
org.UnimplementedOrganizationServiceServer
|
||||
command *command.Commands
|
||||
query *query.Queries
|
||||
checkPermission domain.PermissionCheck
|
||||
@@ -34,8 +37,12 @@ func CreateServer(
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) RegisterServer(grpcServer *grpc.Server) {
|
||||
org.RegisterOrganizationServiceServer(grpcServer, s)
|
||||
func (s *Server) RegisterConnectServer(interceptors ...connect.Interceptor) (string, http.Handler) {
|
||||
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 {
|
||||
|
@@ -3,6 +3,7 @@ package org
|
||||
import (
|
||||
"context"
|
||||
|
||||
"connectrpc.com/connect"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
|
||||
// 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))
|
||||
for i, admin := range createdOrg.OrgAdmins {
|
||||
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),
|
||||
Id: createdOrg.ObjectDetails.ResourceOwner,
|
||||
OrganizationAdmins: admins,
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func OrgViewsToPb(orgs []*query.Org) []*v2beta_org.Organization {
|
||||
|
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
"connectrpc.com/connect"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
|
||||
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"
|
||||
)
|
||||
|
||||
func (s *Server) CreateOrganization(ctx context.Context, request *v2beta_org.CreateOrganizationRequest) (*v2beta_org.CreateOrganizationResponse, error) {
|
||||
orgSetup, err := createOrganizationRequestToCommand(request)
|
||||
func (s *Server) CreateOrganization(ctx context.Context, request *connect.Request[v2beta_org.CreateOrganizationRequest]) (*connect.Response[v2beta_org.CreateOrganizationResponse], error) {
|
||||
orgSetup, err := createOrganizationRequestToCommand(request.Msg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -29,19 +30,19 @@ func (s *Server) CreateOrganization(ctx context.Context, request *v2beta_org.Cre
|
||||
return createdOrganizationToPb(createdOrg)
|
||||
}
|
||||
|
||||
func (s *Server) UpdateOrganization(ctx context.Context, request *v2beta_org.UpdateOrganizationRequest) (*v2beta_org.UpdateOrganizationResponse, error) {
|
||||
org, err := s.command.ChangeOrg(ctx, request.Id, request.Name)
|
||||
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.Msg.GetId(), request.Msg.GetName())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &v2beta_org.UpdateOrganizationResponse{
|
||||
return connect.NewResponse(&v2beta_org.UpdateOrganizationResponse{
|
||||
ChangeDate: timestamppb.New(org.EventDate),
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (s *Server) ListOrganizations(ctx context.Context, request *v2beta_org.ListOrganizationsRequest) (*v2beta_org.ListOrganizationsResponse, error) {
|
||||
queries, err := listOrgRequestToModel(s.systemDefaults, request)
|
||||
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.Msg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -49,107 +50,107 @@ func (s *Server) ListOrganizations(ctx context.Context, request *v2beta_org.List
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &v2beta_org.ListOrganizationsResponse{
|
||||
return connect.NewResponse(&v2beta_org.ListOrganizationsResponse{
|
||||
Organizations: OrgViewsToPb(orgs.Orgs),
|
||||
Pagination: &filter.PaginationResponse{
|
||||
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) {
|
||||
details, err := s.command.RemoveOrg(ctx, request.Id)
|
||||
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.Msg.GetId())
|
||||
if err != nil {
|
||||
var notFoundError *zerrors.NotFoundError
|
||||
if errors.As(err, ¬FoundError) {
|
||||
return &v2beta_org.DeleteOrganizationResponse{}, nil
|
||||
return connect.NewResponse(&v2beta_org.DeleteOrganizationResponse{}), nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return &v2beta_org.DeleteOrganizationResponse{
|
||||
return connect.NewResponse(&v2beta_org.DeleteOrganizationResponse{
|
||||
DeletionDate: timestamppb.New(details.EventDate),
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (s *Server) SetOrganizationMetadata(ctx context.Context, request *v2beta_org.SetOrganizationMetadataRequest) (*v2beta_org.SetOrganizationMetadataResponse, error) {
|
||||
result, err := s.command.BulkSetOrgMetadata(ctx, request.OrganizationId, BulkSetOrgMetadataToDomain(request)...)
|
||||
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.Msg.GetOrganizationId(), BulkSetOrgMetadataToDomain(request.Msg)...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &org.SetOrganizationMetadataResponse{
|
||||
return connect.NewResponse(&org.SetOrganizationMetadataResponse{
|
||||
SetDate: timestamppb.New(result.EventDate),
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (s *Server) ListOrganizationMetadata(ctx context.Context, request *v2beta_org.ListOrganizationMetadataRequest) (*v2beta_org.ListOrganizationMetadataResponse, error) {
|
||||
metadataQueries, err := ListOrgMetadataToDomain(s.systemDefaults, request)
|
||||
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.Msg)
|
||||
if err != nil {
|
||||
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 {
|
||||
return nil, err
|
||||
}
|
||||
return &v2beta_org.ListOrganizationMetadataResponse{
|
||||
return connect.NewResponse(&v2beta_org.ListOrganizationMetadataResponse{
|
||||
Metadata: metadata.OrgMetadataListToPb(res.Metadata),
|
||||
Pagination: &filter.PaginationResponse{
|
||||
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) {
|
||||
result, err := s.command.BulkRemoveOrgMetadata(ctx, request.OrganizationId, request.Keys...)
|
||||
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.Msg.GetOrganizationId(), request.Msg.Keys...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &v2beta_org.DeleteOrganizationMetadataResponse{
|
||||
return connect.NewResponse(&v2beta_org.DeleteOrganizationMetadataResponse{
|
||||
DeletionDate: timestamppb.New(result.EventDate),
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (s *Server) DeactivateOrganization(ctx context.Context, request *org.DeactivateOrganizationRequest) (*org.DeactivateOrganizationResponse, error) {
|
||||
objectDetails, err := s.command.DeactivateOrg(ctx, request.Id)
|
||||
func (s *Server) DeactivateOrganization(ctx context.Context, request *connect.Request[org.DeactivateOrganizationRequest]) (*connect.Response[org.DeactivateOrganizationResponse], error) {
|
||||
objectDetails, err := s.command.DeactivateOrg(ctx, request.Msg.GetId())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &org.DeactivateOrganizationResponse{
|
||||
return connect.NewResponse(&org.DeactivateOrganizationResponse{
|
||||
ChangeDate: timestamppb.New(objectDetails.EventDate),
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (s *Server) ActivateOrganization(ctx context.Context, request *org.ActivateOrganizationRequest) (*org.ActivateOrganizationResponse, error) {
|
||||
objectDetails, err := s.command.ReactivateOrg(ctx, request.Id)
|
||||
func (s *Server) ActivateOrganization(ctx context.Context, request *connect.Request[org.ActivateOrganizationRequest]) (*connect.Response[org.ActivateOrganizationResponse], error) {
|
||||
objectDetails, err := s.command.ReactivateOrg(ctx, request.Msg.GetId())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &org.ActivateOrganizationResponse{
|
||||
return connect.NewResponse(&org.ActivateOrganizationResponse{
|
||||
ChangeDate: timestamppb.New(objectDetails.EventDate),
|
||||
}, err
|
||||
}), err
|
||||
}
|
||||
|
||||
func (s *Server) AddOrganizationDomain(ctx context.Context, request *org.AddOrganizationDomainRequest) (*org.AddOrganizationDomainResponse, error) {
|
||||
userIDs, err := s.getClaimedUserIDsOfOrgDomain(ctx, request.Domain, request.OrganizationId)
|
||||
func (s *Server) AddOrganizationDomain(ctx context.Context, request *connect.Request[org.AddOrganizationDomainRequest]) (*connect.Response[org.AddOrganizationDomainResponse], error) {
|
||||
userIDs, err := s.getClaimedUserIDsOfOrgDomain(ctx, request.Msg.GetDomain(), request.Msg.GetOrganizationId())
|
||||
if err != nil {
|
||||
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 {
|
||||
return nil, err
|
||||
}
|
||||
return &org.AddOrganizationDomainResponse{
|
||||
return connect.NewResponse(&org.AddOrganizationDomainResponse{
|
||||
CreationDate: timestamppb.New(details.EventDate),
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (s *Server) ListOrganizationDomains(ctx context.Context, req *org.ListOrganizationDomainsRequest) (*org.ListOrganizationDomainsResponse, error) {
|
||||
queries, err := ListOrgDomainsRequestToModel(s.systemDefaults, req)
|
||||
func (s *Server) ListOrganizationDomains(ctx context.Context, req *connect.Request[org.ListOrganizationDomainsRequest]) (*connect.Response[org.ListOrganizationDomainsResponse], error) {
|
||||
queries, err := ListOrgDomainsRequestToModel(s.systemDefaults, req.Msg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
orgIDQuery, err := query.NewOrgDomainOrgIDSearchQuery(req.OrganizationId)
|
||||
orgIDQuery, err := query.NewOrgDomainOrgIDSearchQuery(req.Msg.GetOrganizationId())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -159,48 +160,48 @@ func (s *Server) ListOrganizationDomains(ctx context.Context, req *org.ListOrgan
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &org.ListOrganizationDomainsResponse{
|
||||
return connect.NewResponse(&org.ListOrganizationDomainsResponse{
|
||||
Domains: object.DomainsToPb(domains.Domains),
|
||||
Pagination: &filter.PaginationResponse{
|
||||
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) {
|
||||
details, err := s.command.RemoveOrgDomain(ctx, RemoveOrgDomainRequestToDomain(ctx, req))
|
||||
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.Msg))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &org.DeleteOrganizationDomainResponse{
|
||||
return connect.NewResponse(&org.DeleteOrganizationDomainResponse{
|
||||
DeletionDate: timestamppb.New(details.EventDate),
|
||||
}, err
|
||||
}), err
|
||||
}
|
||||
|
||||
func (s *Server) GenerateOrganizationDomainValidation(ctx context.Context, req *org.GenerateOrganizationDomainValidationRequest) (*org.GenerateOrganizationDomainValidationResponse, error) {
|
||||
token, url, err := s.command.GenerateOrgDomainValidation(ctx, GenerateOrgDomainValidationRequestToDomain(ctx, req))
|
||||
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.Msg))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &org.GenerateOrganizationDomainValidationResponse{
|
||||
return connect.NewResponse(&org.GenerateOrganizationDomainValidationResponse{
|
||||
Token: token,
|
||||
Url: url,
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (s *Server) VerifyOrganizationDomain(ctx context.Context, request *org.VerifyOrganizationDomainRequest) (*org.VerifyOrganizationDomainResponse, error) {
|
||||
userIDs, err := s.getClaimedUserIDsOfOrgDomain(ctx, request.Domain, request.OrganizationId)
|
||||
func (s *Server) VerifyOrganizationDomain(ctx context.Context, request *connect.Request[org.VerifyOrganizationDomainRequest]) (*connect.Response[org.VerifyOrganizationDomainResponse], error) {
|
||||
userIDs, err := s.getClaimedUserIDsOfOrgDomain(ctx, request.Msg.GetDomain(), request.Msg.GetOrganizationId())
|
||||
if err != nil {
|
||||
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 {
|
||||
return nil, err
|
||||
}
|
||||
return &org.VerifyOrganizationDomainResponse{
|
||||
return connect.NewResponse(&org.VerifyOrganizationDomainResponse{
|
||||
ChangeDate: timestamppb.New(details.EventDate),
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func createOrganizationRequestToCommand(request *v2beta_org.CreateOrganizationRequest) (*command.OrgSetup, error) {
|
||||
|
@@ -4,6 +4,7 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"connectrpc.com/connect"
|
||||
"github.com/muhlemmer/gu"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
@@ -138,7 +139,7 @@ func Test_createdOrganizationToPb(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want *org.CreateOrganizationResponse
|
||||
want *connect.Response[org.CreateOrganizationResponse]
|
||||
wantErr error
|
||||
}{
|
||||
{
|
||||
@@ -159,7 +160,7 @@ func Test_createdOrganizationToPb(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
want: &org.CreateOrganizationResponse{
|
||||
want: connect.NewResponse(&org.CreateOrganizationResponse{
|
||||
CreationDate: timestamppb.New(now),
|
||||
Id: "orgID",
|
||||
OrganizationAdmins: []*org.OrganizationAdmin{
|
||||
@@ -173,7 +174,7 @@ func Test_createdOrganizationToPb(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
|
@@ -1,7 +1,10 @@
|
||||
package org
|
||||
|
||||
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/grpc/server"
|
||||
@@ -10,12 +13,12 @@ import (
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
"github.com/zitadel/zitadel/internal/query"
|
||||
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 {
|
||||
org.UnimplementedOrganizationServiceServer
|
||||
systemDefaults systemdefaults.SystemDefaults
|
||||
command *command.Commands
|
||||
query *query.Queries
|
||||
@@ -38,8 +41,12 @@ func CreateServer(
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) RegisterServer(grpcServer *grpc.Server) {
|
||||
org.RegisterOrganizationServiceServer(grpcServer, s)
|
||||
func (s *Server) RegisterConnectServer(interceptors ...connect.Interceptor) (string, http.Handler) {
|
||||
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 {
|
||||
|
@@ -3,6 +3,7 @@ package project
|
||||
import (
|
||||
"context"
|
||||
|
||||
"connectrpc.com/connect"
|
||||
"github.com/muhlemmer/gu"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
|
||||
@@ -13,8 +14,8 @@ import (
|
||||
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) {
|
||||
add := projectCreateToCommand(req)
|
||||
func (s *Server) CreateProject(ctx context.Context, req *connect.Request[project_pb.CreateProjectRequest]) (*connect.Response[project_pb.CreateProjectResponse], error) {
|
||||
add := projectCreateToCommand(req.Msg)
|
||||
project, err := s.command.AddProject(ctx, add)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -23,10 +24,10 @@ func (s *Server) CreateProject(ctx context.Context, req *project_pb.CreateProjec
|
||||
if !project.EventDate.IsZero() {
|
||||
creationDate = timestamppb.New(project.EventDate)
|
||||
}
|
||||
return &project_pb.CreateProjectResponse{
|
||||
return connect.NewResponse(&project_pb.CreateProjectResponse{
|
||||
Id: add.AggregateID,
|
||||
CreationDate: creationDate,
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
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) {
|
||||
project, err := s.command.ChangeProject(ctx, projectUpdateToCommand(req))
|
||||
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.Msg))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -69,9 +70,9 @@ func (s *Server) UpdateProject(ctx context.Context, req *project_pb.UpdateProjec
|
||||
if !project.EventDate.IsZero() {
|
||||
changeDate = timestamppb.New(project.EventDate)
|
||||
}
|
||||
return &project_pb.UpdateProjectResponse{
|
||||
return connect.NewResponse(&project_pb.UpdateProjectResponse{
|
||||
ChangeDate: changeDate,
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
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) {
|
||||
userGrantIDs, err := s.userGrantsFromProject(ctx, req.Id)
|
||||
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.Msg.GetId())
|
||||
if err != nil {
|
||||
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 {
|
||||
return nil, err
|
||||
}
|
||||
@@ -105,9 +106,9 @@ func (s *Server) DeleteProject(ctx context.Context, req *project_pb.DeleteProjec
|
||||
if !deletedAt.IsZero() {
|
||||
deletionDate = timestamppb.New(deletedAt)
|
||||
}
|
||||
return &project_pb.DeleteProjectResponse{
|
||||
return connect.NewResponse(&project_pb.DeleteProjectResponse{
|
||||
DeletionDate: deletionDate,
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
func (s *Server) DeactivateProject(ctx context.Context, req *project_pb.DeactivateProjectRequest) (*project_pb.DeactivateProjectResponse, error) {
|
||||
details, err := s.command.DeactivateProject(ctx, req.Id, "")
|
||||
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.Msg.GetId(), "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -133,13 +134,13 @@ func (s *Server) DeactivateProject(ctx context.Context, req *project_pb.Deactiva
|
||||
if !details.EventDate.IsZero() {
|
||||
changeDate = timestamppb.New(details.EventDate)
|
||||
}
|
||||
return &project_pb.DeactivateProjectResponse{
|
||||
return connect.NewResponse(&project_pb.DeactivateProjectResponse{
|
||||
ChangeDate: changeDate,
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (s *Server) ActivateProject(ctx context.Context, req *project_pb.ActivateProjectRequest) (*project_pb.ActivateProjectResponse, error) {
|
||||
details, err := s.command.ReactivateProject(ctx, req.Id, "")
|
||||
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.Msg.GetId(), "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -147,9 +148,9 @@ func (s *Server) ActivateProject(ctx context.Context, req *project_pb.ActivatePr
|
||||
if !details.EventDate.IsZero() {
|
||||
changeDate = timestamppb.New(details.EventDate)
|
||||
}
|
||||
return &project_pb.ActivateProjectResponse{
|
||||
return connect.NewResponse(&project_pb.ActivateProjectResponse{
|
||||
ChangeDate: changeDate,
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func userGrantsToIDs(userGrants []*query.UserGrant) []string {
|
||||
|
@@ -3,6 +3,7 @@ package project
|
||||
import (
|
||||
"context"
|
||||
|
||||
"connectrpc.com/connect"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/command"
|
||||
@@ -11,8 +12,8 @@ import (
|
||||
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) {
|
||||
add := projectGrantCreateToCommand(req)
|
||||
func (s *Server) CreateProjectGrant(ctx context.Context, req *connect.Request[project_pb.CreateProjectGrantRequest]) (*connect.Response[project_pb.CreateProjectGrantResponse], error) {
|
||||
add := projectGrantCreateToCommand(req.Msg)
|
||||
project, err := s.command.AddProjectGrant(ctx, add)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -21,9 +22,9 @@ func (s *Server) CreateProjectGrant(ctx context.Context, req *project_pb.CreateP
|
||||
if !project.EventDate.IsZero() {
|
||||
creationDate = timestamppb.New(project.EventDate)
|
||||
}
|
||||
return &project_pb.CreateProjectGrantResponse{
|
||||
return connect.NewResponse(&project_pb.CreateProjectGrantResponse{
|
||||
CreationDate: creationDate,
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
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) {
|
||||
project, err := s.command.ChangeProjectGrant(ctx, projectGrantUpdateToCommand(req))
|
||||
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.Msg))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -46,9 +47,9 @@ func (s *Server) UpdateProjectGrant(ctx context.Context, req *project_pb.UpdateP
|
||||
if !project.EventDate.IsZero() {
|
||||
changeDate = timestamppb.New(project.EventDate)
|
||||
}
|
||||
return &project_pb.UpdateProjectGrantResponse{
|
||||
return connect.NewResponse(&project_pb.UpdateProjectGrantResponse{
|
||||
ChangeDate: changeDate,
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
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) {
|
||||
details, err := s.command.DeactivateProjectGrant(ctx, req.ProjectId, "", req.GrantedOrganizationId, "")
|
||||
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.Msg.GetProjectId(), "", req.Msg.GetGrantedOrganizationId(), "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -70,13 +71,13 @@ func (s *Server) DeactivateProjectGrant(ctx context.Context, req *project_pb.Dea
|
||||
if !details.EventDate.IsZero() {
|
||||
changeDate = timestamppb.New(details.EventDate)
|
||||
}
|
||||
return &project_pb.DeactivateProjectGrantResponse{
|
||||
return connect.NewResponse(&project_pb.DeactivateProjectGrantResponse{
|
||||
ChangeDate: changeDate,
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (s *Server) ActivateProjectGrant(ctx context.Context, req *project_pb.ActivateProjectGrantRequest) (*project_pb.ActivateProjectGrantResponse, error) {
|
||||
details, err := s.command.ReactivateProjectGrant(ctx, req.ProjectId, "", req.GrantedOrganizationId, "")
|
||||
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.Msg.GetProjectId(), "", req.Msg.GetGrantedOrganizationId(), "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -84,17 +85,17 @@ func (s *Server) ActivateProjectGrant(ctx context.Context, req *project_pb.Activ
|
||||
if !details.EventDate.IsZero() {
|
||||
changeDate = timestamppb.New(details.EventDate)
|
||||
}
|
||||
return &project_pb.ActivateProjectGrantResponse{
|
||||
return connect.NewResponse(&project_pb.ActivateProjectGrantResponse{
|
||||
ChangeDate: changeDate,
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (s *Server) DeleteProjectGrant(ctx context.Context, req *project_pb.DeleteProjectGrantRequest) (*project_pb.DeleteProjectGrantResponse, error) {
|
||||
userGrantIDs, err := s.userGrantsFromProjectGrant(ctx, req.ProjectId, req.GrantedOrganizationId)
|
||||
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.Msg.GetProjectId(), req.Msg.GetGrantedOrganizationId())
|
||||
if err != nil {
|
||||
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 {
|
||||
return nil, err
|
||||
}
|
||||
@@ -102,9 +103,9 @@ func (s *Server) DeleteProjectGrant(ctx context.Context, req *project_pb.DeleteP
|
||||
if !details.EventDate.IsZero() {
|
||||
deletionDate = timestamppb.New(details.EventDate)
|
||||
}
|
||||
return &project_pb.DeleteProjectGrantResponse{
|
||||
return connect.NewResponse(&project_pb.DeleteProjectGrantResponse{
|
||||
DeletionDate: deletionDate,
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (s *Server) userGrantsFromProjectGrant(ctx context.Context, projectID, grantedOrganizationID string) ([]string, error) {
|
||||
|
@@ -3,6 +3,7 @@ package project
|
||||
import (
|
||||
"context"
|
||||
|
||||
"connectrpc.com/connect"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/command"
|
||||
@@ -11,8 +12,8 @@ import (
|
||||
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) {
|
||||
role, err := s.command.AddProjectRole(ctx, addProjectRoleRequestToCommand(req))
|
||||
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.Msg))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -20,9 +21,9 @@ func (s *Server) AddProjectRole(ctx context.Context, req *project_pb.AddProjectR
|
||||
if !role.EventDate.IsZero() {
|
||||
creationDate = timestamppb.New(role.EventDate)
|
||||
}
|
||||
return &project_pb.AddProjectRoleResponse{
|
||||
return connect.NewResponse(&project_pb.AddProjectRoleResponse{
|
||||
CreationDate: creationDate,
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
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) {
|
||||
role, err := s.command.ChangeProjectRole(ctx, updateProjectRoleRequestToCommand(req))
|
||||
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.Msg))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -50,9 +51,9 @@ func (s *Server) UpdateProjectRole(ctx context.Context, req *project_pb.UpdatePr
|
||||
if !role.EventDate.IsZero() {
|
||||
changeDate = timestamppb.New(role.EventDate)
|
||||
}
|
||||
return &project_pb.UpdateProjectRoleResponse{
|
||||
return connect.NewResponse(&project_pb.UpdateProjectRoleResponse{
|
||||
ChangeDate: changeDate,
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
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) {
|
||||
userGrantIDs, err := s.userGrantsFromProjectAndRole(ctx, req.ProjectId, req.RoleKey)
|
||||
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.Msg.GetProjectId(), req.Msg.GetRoleKey())
|
||||
if err != nil {
|
||||
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 {
|
||||
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 {
|
||||
return nil, err
|
||||
}
|
||||
@@ -92,9 +93,9 @@ func (s *Server) RemoveProjectRole(ctx context.Context, req *project_pb.RemovePr
|
||||
if !details.EventDate.IsZero() {
|
||||
deletionDate = timestamppb.New(details.EventDate)
|
||||
}
|
||||
return &project_pb.RemoveProjectRoleResponse{
|
||||
return connect.NewResponse(&project_pb.RemoveProjectRoleResponse{
|
||||
RemovalDate: deletionDate,
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (s *Server) userGrantsFromProjectAndRole(ctx context.Context, projectID, roleKey string) ([]string, error) {
|
||||
|
@@ -3,6 +3,7 @@ package project
|
||||
import (
|
||||
"context"
|
||||
|
||||
"connectrpc.com/connect"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
|
||||
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"
|
||||
)
|
||||
|
||||
func (s *Server) GetProject(ctx context.Context, req *project_pb.GetProjectRequest) (*project_pb.GetProjectResponse, error) {
|
||||
project, err := s.query.GetProjectByIDWithPermission(ctx, true, req.Id, s.checkPermission)
|
||||
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.Msg.GetId(), s.checkPermission)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &project_pb.GetProjectResponse{
|
||||
return connect.NewResponse(&project_pb.GetProjectResponse{
|
||||
Project: projectToPb(project),
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (s *Server) ListProjects(ctx context.Context, req *project_pb.ListProjectsRequest) (*project_pb.ListProjectsResponse, error) {
|
||||
queries, err := s.listProjectRequestToModel(req)
|
||||
func (s *Server) ListProjects(ctx context.Context, req *connect.Request[project_pb.ListProjectsRequest]) (*connect.Response[project_pb.ListProjectsResponse], error) {
|
||||
queries, err := s.listProjectRequestToModel(req.Msg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -32,10 +33,10 @@ func (s *Server) ListProjects(ctx context.Context, req *project_pb.ListProjectsR
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &project_pb.ListProjectsResponse{
|
||||
return connect.NewResponse(&project_pb.ListProjectsResponse{
|
||||
Projects: grantedProjectsToPb(resp.GrantedProjects),
|
||||
Pagination: filter.QueryToPaginationPb(queries.SearchRequest, resp.SearchResponse),
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
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) {
|
||||
queries, err := s.listProjectGrantsRequestToModel(req)
|
||||
func (s *Server) ListProjectGrants(ctx context.Context, req *connect.Request[project_pb.ListProjectGrantsRequest]) (*connect.Response[project_pb.ListProjectGrantsResponse], error) {
|
||||
queries, err := s.listProjectGrantsRequestToModel(req.Msg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -222,10 +223,10 @@ func (s *Server) ListProjectGrants(ctx context.Context, req *project_pb.ListProj
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &project_pb.ListProjectGrantsResponse{
|
||||
return connect.NewResponse(&project_pb.ListProjectGrantsResponse{
|
||||
ProjectGrants: projectGrantsToPb(resp.ProjectGrants),
|
||||
Pagination: filter.QueryToPaginationPb(queries.SearchRequest, resp.SearchResponse),
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
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) {
|
||||
queries, err := s.listProjectRolesRequestToModel(req)
|
||||
func (s *Server) ListProjectRoles(ctx context.Context, req *connect.Request[project_pb.ListProjectRolesRequest]) (*connect.Response[project_pb.ListProjectRolesResponse], error) {
|
||||
queries, err := s.listProjectRolesRequestToModel(req.Msg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = queries.AppendProjectIDQuery(req.ProjectId)
|
||||
err = queries.AppendProjectIDQuery(req.Msg.GetProjectId())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -342,10 +343,10 @@ func (s *Server) ListProjectRoles(ctx context.Context, req *project_pb.ListProje
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &project_pb.ListProjectRolesResponse{
|
||||
return connect.NewResponse(&project_pb.ListProjectRolesResponse{
|
||||
ProjectRoles: roleViewsToPb(roles.ProjectRoles),
|
||||
Pagination: filter.QueryToPaginationPb(queries.SearchRequest, roles.SearchResponse),
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (s *Server) listProjectRolesRequestToModel(req *project_pb.ListProjectRolesRequest) (*query.ProjectRoleSearchQueries, error) {
|
||||
|
@@ -1,21 +1,23 @@
|
||||
package project
|
||||
|
||||
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/grpc/server"
|
||||
"github.com/zitadel/zitadel/internal/command"
|
||||
"github.com/zitadel/zitadel/internal/config/systemdefaults"
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
"github.com/zitadel/zitadel/internal/query"
|
||||
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 {
|
||||
project.UnimplementedProjectServiceServer
|
||||
systemDefaults systemdefaults.SystemDefaults
|
||||
command *command.Commands
|
||||
query *query.Queries
|
||||
@@ -39,8 +41,12 @@ func CreateServer(
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) RegisterServer(grpcServer *grpc.Server) {
|
||||
project.RegisterProjectServiceServer(grpcServer, s)
|
||||
func (s *Server) RegisterConnectServer(interceptors ...connect.Interceptor) (string, http.Handler) {
|
||||
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 {
|
||||
@@ -54,7 +60,3 @@ func (s *Server) MethodPrefix() string {
|
||||
func (s *Server) AuthMethods() authz.MethodMapping {
|
||||
return project.ProjectService_AuthMethods
|
||||
}
|
||||
|
||||
func (s *Server) RegisterGateway() server.RegisterGatewayFunc {
|
||||
return project.RegisterProjectServiceHandler
|
||||
}
|
||||
|
@@ -3,6 +3,7 @@ package saml
|
||||
import (
|
||||
"context"
|
||||
|
||||
"connectrpc.com/connect"
|
||||
"github.com/zitadel/logging"
|
||||
"github.com/zitadel/saml/pkg/provider"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
@@ -16,15 +17,15 @@ import (
|
||||
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) {
|
||||
authRequest, err := s.query.SamlRequestByID(ctx, true, req.GetSamlRequestId(), true)
|
||||
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.Msg.GetSamlRequestId(), true)
|
||||
if err != nil {
|
||||
logging.WithError(err).Error("query samlRequest by ID")
|
||||
return nil, err
|
||||
}
|
||||
return &saml_pb.GetSAMLRequestResponse{
|
||||
return connect.NewResponse(&saml_pb.GetSAMLRequestResponse{
|
||||
SamlRequest: samlRequestToPb(authRequest),
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
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) {
|
||||
switch v := req.GetResponseKind().(type) {
|
||||
func (s *Server) CreateResponse(ctx context.Context, req *connect.Request[saml_pb.CreateResponseRequest]) (*connect.Response[saml_pb.CreateResponseResponse], error) {
|
||||
switch v := req.Msg.GetResponseKind().(type) {
|
||||
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:
|
||||
return s.linkSessionToSAMLRequest(ctx, req.GetSamlRequestId(), v.Session)
|
||||
return s.linkSessionToSAMLRequest(ctx, req.Msg.GetSamlRequestId(), v.Session)
|
||||
default:
|
||||
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()))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -55,7 +56,7 @@ func (s *Server) failSAMLRequest(ctx context.Context, samlRequestID string, ae *
|
||||
if err != nil {
|
||||
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 {
|
||||
@@ -72,7 +73,7 @@ func (s *Server) checkPermission(ctx context.Context, issuer string, userID stri
|
||||
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)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -87,7 +88,7 @@ func (s *Server) linkSessionToSAMLRequest(ctx context.Context, samlRequestID str
|
||||
if err != nil {
|
||||
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 {
|
||||
|
@@ -1,7 +1,10 @@
|
||||
package saml
|
||||
|
||||
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/grpc/server"
|
||||
@@ -9,9 +12,10 @@ import (
|
||||
"github.com/zitadel/zitadel/internal/command"
|
||||
"github.com/zitadel/zitadel/internal/query"
|
||||
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 {
|
||||
saml_pb.UnimplementedSAMLServiceServer
|
||||
@@ -38,8 +42,12 @@ func CreateServer(
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) RegisterServer(grpcServer *grpc.Server) {
|
||||
saml_pb.RegisterSAMLServiceServer(grpcServer, s)
|
||||
func (s *Server) RegisterConnectServer(interceptors ...connect.Interceptor) (string, http.Handler) {
|
||||
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 {
|
||||
|
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
@@ -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)
|
||||
}
|
@@ -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
|
||||
}
|
@@ -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)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
@@ -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 !
|
||||
}
|
@@ -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)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
@@ -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
|
||||
}
|
@@ -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()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
@@ -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, ¬FoundErr) {
|
||||
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, ¬FoundErr) {
|
||||
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)
|
||||
}
|
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
@@ -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
|
||||
}
|
50
internal/api/grpc/server/connect_middleware/mock_test.go
Normal file
50
internal/api/grpc/server/connect_middleware/mock_test.go
Normal 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
|
||||
}
|
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
@@ -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
|
||||
}
|
@@ -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
|
||||
}
|
37
internal/api/grpc/server/connect_middleware/translator.go
Normal file
37
internal/api/grpc/server/connect_middleware/translator.go
Normal 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
|
||||
}
|
@@ -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)
|
||||
}
|
@@ -171,7 +171,7 @@ func CreateGateway(
|
||||
}, 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)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to register grpc gateway: %w", err)
|
||||
|
@@ -2,11 +2,14 @@ package server
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"net/http"
|
||||
|
||||
"connectrpc.com/connect"
|
||||
grpc_middleware "github.com/grpc-ecosystem/go-grpc-middleware"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/credentials"
|
||||
healthpb "google.golang.org/grpc/health/grpc_health_v1"
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/authz"
|
||||
grpc_api "github.com/zitadel/zitadel/internal/api/grpc"
|
||||
@@ -19,21 +22,36 @@ import (
|
||||
)
|
||||
|
||||
type Server interface {
|
||||
RegisterServer(*grpc.Server)
|
||||
RegisterGateway() RegisterGatewayFunc
|
||||
AppName() string
|
||||
MethodPrefix() string
|
||||
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
|
||||
//
|
||||
// it's used for the System, Admin, Mgmt and Auth API
|
||||
type WithGatewayPrefix interface {
|
||||
Server
|
||||
GrpcServer
|
||||
WithGateway
|
||||
GatewayPathPrefix() string
|
||||
}
|
||||
|
||||
type ConnectServer interface {
|
||||
Server
|
||||
RegisterConnectServer(interceptors ...connect.Interceptor) (string, http.Handler)
|
||||
FileDescriptor() protoreflect.FileDescriptor
|
||||
}
|
||||
|
||||
func CreateServer(
|
||||
verifier authz.APITokenVerifier,
|
||||
systemAuthz authz.Config,
|
||||
|
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"connectrpc.com/connect"
|
||||
"github.com/muhlemmer/gu"
|
||||
"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) {
|
||||
res, err := s.query.SessionByID(ctx, true, req.GetSessionId(), req.GetSessionToken(), s.checkPermission)
|
||||
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.Msg.GetSessionId(), req.Msg.GetSessionToken(), s.checkPermission)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &session.GetSessionResponse{
|
||||
return connect.NewResponse(&session.GetSessionResponse{
|
||||
Session: sessionToPb(res),
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (s *Server) ListSessions(ctx context.Context, req *session.ListSessionsRequest) (*session.ListSessionsResponse, error) {
|
||||
queries, err := listSessionsRequestToQuery(ctx, req)
|
||||
func (s *Server) ListSessions(ctx context.Context, req *connect.Request[session.ListSessionsRequest]) (*connect.Response[session.ListSessionsResponse], error) {
|
||||
queries, err := listSessionsRequestToQuery(ctx, req.Msg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -45,10 +46,10 @@ func (s *Server) ListSessions(ctx context.Context, req *session.ListSessionsRequ
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &session.ListSessionsResponse{
|
||||
return connect.NewResponse(&session.ListSessionsResponse{
|
||||
Details: object.ToListDetails(sessions.SearchResponse),
|
||||
Sessions: sessionsToPb(sessions.Sessions),
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func listSessionsRequestToQuery(ctx context.Context, req *session.ListSessionsRequest) (*query.SessionsSearchQueries, error) {
|
||||
|
@@ -1,7 +1,10 @@
|
||||
package session
|
||||
|
||||
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/grpc/server"
|
||||
@@ -9,12 +12,12 @@ import (
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
"github.com/zitadel/zitadel/internal/query"
|
||||
"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 {
|
||||
session.UnimplementedSessionServiceServer
|
||||
command *command.Commands
|
||||
query *query.Queries
|
||||
|
||||
@@ -35,8 +38,12 @@ func CreateServer(
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) RegisterServer(grpcServer *grpc.Server) {
|
||||
session.RegisterSessionServiceServer(grpcServer, s)
|
||||
func (s *Server) RegisterConnectServer(interceptors ...connect.Interceptor) (string, http.Handler) {
|
||||
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 {
|
||||
|
@@ -6,6 +6,7 @@ import (
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"connectrpc.com/connect"
|
||||
"golang.org/x/text/language"
|
||||
"google.golang.org/protobuf/types/known/structpb"
|
||||
|
||||
@@ -17,12 +18,12 @@ import (
|
||||
"github.com/zitadel/zitadel/pkg/grpc/session/v2"
|
||||
)
|
||||
|
||||
func (s *Server) CreateSession(ctx context.Context, req *session.CreateSessionRequest) (*session.CreateSessionResponse, error) {
|
||||
checks, metadata, userAgent, lifetime, err := s.createSessionRequestToCommand(ctx, req)
|
||||
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.Msg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
challengeResponse, cmds, err := s.challengesToCommand(req.GetChallenges(), checks)
|
||||
challengeResponse, cmds, err := s.challengesToCommand(req.Msg.GetChallenges(), checks)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -32,43 +33,43 @@ func (s *Server) CreateSession(ctx context.Context, req *session.CreateSessionRe
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &session.CreateSessionResponse{
|
||||
return connect.NewResponse(&session.CreateSessionResponse{
|
||||
Details: object.DomainToDetailsPb(set.ObjectDetails),
|
||||
SessionId: set.ID,
|
||||
SessionToken: set.NewToken,
|
||||
Challenges: challengeResponse,
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (s *Server) SetSession(ctx context.Context, req *session.SetSessionRequest) (*session.SetSessionResponse, error) {
|
||||
checks, err := s.setSessionRequestToCommand(ctx, req)
|
||||
func (s *Server) SetSession(ctx context.Context, req *connect.Request[session.SetSessionRequest]) (*connect.Response[session.SetSessionResponse], error) {
|
||||
checks, err := s.setSessionRequestToCommand(ctx, req.Msg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
challengeResponse, cmds, err := s.challengesToCommand(req.GetChallenges(), checks)
|
||||
challengeResponse, cmds, err := s.challengesToCommand(req.Msg.GetChallenges(), checks)
|
||||
if err != nil {
|
||||
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 {
|
||||
return nil, err
|
||||
}
|
||||
return &session.SetSessionResponse{
|
||||
return connect.NewResponse(&session.SetSessionResponse{
|
||||
Details: object.DomainToDetailsPb(set.ObjectDetails),
|
||||
SessionToken: set.NewToken,
|
||||
Challenges: challengeResponse,
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (s *Server) DeleteSession(ctx context.Context, req *session.DeleteSessionRequest) (*session.DeleteSessionResponse, error) {
|
||||
details, err := s.command.TerminateSession(ctx, req.GetSessionId(), req.GetSessionToken())
|
||||
func (s *Server) DeleteSession(ctx context.Context, req *connect.Request[session.DeleteSessionRequest]) (*connect.Response[session.DeleteSessionResponse], error) {
|
||||
details, err := s.command.TerminateSession(ctx, req.Msg.GetSessionId(), req.Msg.GetSessionToken())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &session.DeleteSessionResponse{
|
||||
return connect.NewResponse(&session.DeleteSessionResponse{
|
||||
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) {
|
||||
|
@@ -1,7 +1,10 @@
|
||||
package session
|
||||
|
||||
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/grpc/server"
|
||||
@@ -9,12 +12,12 @@ import (
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
"github.com/zitadel/zitadel/internal/query"
|
||||
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 {
|
||||
session.UnimplementedSessionServiceServer
|
||||
command *command.Commands
|
||||
query *query.Queries
|
||||
|
||||
@@ -35,8 +38,12 @@ func CreateServer(
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) RegisterServer(grpcServer *grpc.Server) {
|
||||
session.RegisterSessionServiceServer(grpcServer, s)
|
||||
func (s *Server) RegisterConnectServer(interceptors ...connect.Interceptor) (string, http.Handler) {
|
||||
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 {
|
||||
|
@@ -6,6 +6,7 @@ import (
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"connectrpc.com/connect"
|
||||
"github.com/muhlemmer/gu"
|
||||
"golang.org/x/text/language"
|
||||
"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) {
|
||||
res, err := s.query.SessionByID(ctx, true, req.GetSessionId(), req.GetSessionToken(), s.checkPermission)
|
||||
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.Msg.GetSessionId(), req.Msg.GetSessionToken(), s.checkPermission)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &session.GetSessionResponse{
|
||||
return connect.NewResponse(&session.GetSessionResponse{
|
||||
Session: sessionToPb(res),
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (s *Server) ListSessions(ctx context.Context, req *session.ListSessionsRequest) (*session.ListSessionsResponse, error) {
|
||||
queries, err := listSessionsRequestToQuery(ctx, req)
|
||||
func (s *Server) ListSessions(ctx context.Context, req *connect.Request[session.ListSessionsRequest]) (*connect.Response[session.ListSessionsResponse], error) {
|
||||
queries, err := listSessionsRequestToQuery(ctx, req.Msg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -50,18 +51,18 @@ func (s *Server) ListSessions(ctx context.Context, req *session.ListSessionsRequ
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &session.ListSessionsResponse{
|
||||
return connect.NewResponse(&session.ListSessionsResponse{
|
||||
Details: object.ToListDetails(sessions.SearchResponse),
|
||||
Sessions: sessionsToPb(sessions.Sessions),
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (s *Server) CreateSession(ctx context.Context, req *session.CreateSessionRequest) (*session.CreateSessionResponse, error) {
|
||||
checks, metadata, userAgent, lifetime, err := s.createSessionRequestToCommand(ctx, req)
|
||||
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.Msg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
challengeResponse, cmds, err := s.challengesToCommand(req.GetChallenges(), checks)
|
||||
challengeResponse, cmds, err := s.challengesToCommand(req.Msg.GetChallenges(), checks)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -71,43 +72,43 @@ func (s *Server) CreateSession(ctx context.Context, req *session.CreateSessionRe
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &session.CreateSessionResponse{
|
||||
return connect.NewResponse(&session.CreateSessionResponse{
|
||||
Details: object.DomainToDetailsPb(set.ObjectDetails),
|
||||
SessionId: set.ID,
|
||||
SessionToken: set.NewToken,
|
||||
Challenges: challengeResponse,
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (s *Server) SetSession(ctx context.Context, req *session.SetSessionRequest) (*session.SetSessionResponse, error) {
|
||||
checks, err := s.setSessionRequestToCommand(ctx, req)
|
||||
func (s *Server) SetSession(ctx context.Context, req *connect.Request[session.SetSessionRequest]) (*connect.Response[session.SetSessionResponse], error) {
|
||||
checks, err := s.setSessionRequestToCommand(ctx, req.Msg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
challengeResponse, cmds, err := s.challengesToCommand(req.GetChallenges(), checks)
|
||||
challengeResponse, cmds, err := s.challengesToCommand(req.Msg.GetChallenges(), checks)
|
||||
if err != nil {
|
||||
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 {
|
||||
return nil, err
|
||||
}
|
||||
return &session.SetSessionResponse{
|
||||
return connect.NewResponse(&session.SetSessionResponse{
|
||||
Details: object.DomainToDetailsPb(set.ObjectDetails),
|
||||
SessionToken: set.NewToken,
|
||||
Challenges: challengeResponse,
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (s *Server) DeleteSession(ctx context.Context, req *session.DeleteSessionRequest) (*session.DeleteSessionResponse, error) {
|
||||
details, err := s.command.TerminateSession(ctx, req.GetSessionId(), req.GetSessionToken())
|
||||
func (s *Server) DeleteSession(ctx context.Context, req *connect.Request[session.DeleteSessionRequest]) (*connect.Response[session.DeleteSessionResponse], error) {
|
||||
details, err := s.command.TerminateSession(ctx, req.Msg.GetSessionId(), req.Msg.GetSessionToken())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &session.DeleteSessionResponse{
|
||||
return connect.NewResponse(&session.DeleteSessionResponse{
|
||||
Details: object.DomainToDetailsPb(details),
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func sessionsToPb(sessions []*query.Session) []*session.Session {
|
||||
|
@@ -3,6 +3,7 @@ package settings
|
||||
import (
|
||||
"context"
|
||||
|
||||
"connectrpc.com/connect"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/authz"
|
||||
@@ -14,12 +15,12 @@ import (
|
||||
"github.com/zitadel/zitadel/pkg/grpc/settings/v2"
|
||||
)
|
||||
|
||||
func (s *Server) GetLoginSettings(ctx context.Context, req *settings.GetLoginSettingsRequest) (*settings.GetLoginSettingsResponse, error) {
|
||||
current, err := s.query.LoginPolicyByID(ctx, true, object.ResourceOwnerFromReq(ctx, req.GetCtx()), false)
|
||||
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.Msg.GetCtx()), false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &settings.GetLoginSettingsResponse{
|
||||
return connect.NewResponse(&settings.GetLoginSettingsResponse{
|
||||
Settings: loginSettingsToPb(current),
|
||||
Details: &object_pb.Details{
|
||||
Sequence: current.Sequence,
|
||||
@@ -27,15 +28,15 @@ func (s *Server) GetLoginSettings(ctx context.Context, req *settings.GetLoginSet
|
||||
ChangeDate: timestamppb.New(current.ChangeDate),
|
||||
ResourceOwner: current.OrgID,
|
||||
},
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (s *Server) GetPasswordComplexitySettings(ctx context.Context, req *settings.GetPasswordComplexitySettingsRequest) (*settings.GetPasswordComplexitySettingsResponse, error) {
|
||||
current, err := s.query.PasswordComplexityPolicyByOrg(ctx, true, object.ResourceOwnerFromReq(ctx, req.GetCtx()), false)
|
||||
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.Msg.GetCtx()), false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &settings.GetPasswordComplexitySettingsResponse{
|
||||
return connect.NewResponse(&settings.GetPasswordComplexitySettingsResponse{
|
||||
Settings: passwordComplexitySettingsToPb(current),
|
||||
Details: &object_pb.Details{
|
||||
Sequence: current.Sequence,
|
||||
@@ -43,15 +44,15 @@ func (s *Server) GetPasswordComplexitySettings(ctx context.Context, req *setting
|
||||
ChangeDate: timestamppb.New(current.ChangeDate),
|
||||
ResourceOwner: current.ResourceOwner,
|
||||
},
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (s *Server) GetPasswordExpirySettings(ctx context.Context, req *settings.GetPasswordExpirySettingsRequest) (*settings.GetPasswordExpirySettingsResponse, error) {
|
||||
current, err := s.query.PasswordAgePolicyByOrg(ctx, true, object.ResourceOwnerFromReq(ctx, req.GetCtx()), false)
|
||||
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.Msg.GetCtx()), false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &settings.GetPasswordExpirySettingsResponse{
|
||||
return connect.NewResponse(&settings.GetPasswordExpirySettingsResponse{
|
||||
Settings: passwordExpirySettingsToPb(current),
|
||||
Details: &object_pb.Details{
|
||||
Sequence: current.Sequence,
|
||||
@@ -59,15 +60,15 @@ func (s *Server) GetPasswordExpirySettings(ctx context.Context, req *settings.Ge
|
||||
ChangeDate: timestamppb.New(current.ChangeDate),
|
||||
ResourceOwner: current.ResourceOwner,
|
||||
},
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (s *Server) GetBrandingSettings(ctx context.Context, req *settings.GetBrandingSettingsRequest) (*settings.GetBrandingSettingsResponse, error) {
|
||||
current, err := s.query.ActiveLabelPolicyByOrg(ctx, object.ResourceOwnerFromReq(ctx, req.GetCtx()), false)
|
||||
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.Msg.GetCtx()), false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &settings.GetBrandingSettingsResponse{
|
||||
return connect.NewResponse(&settings.GetBrandingSettingsResponse{
|
||||
Settings: brandingSettingsToPb(current, s.assetsAPIDomain(ctx)),
|
||||
Details: &object_pb.Details{
|
||||
Sequence: current.Sequence,
|
||||
@@ -75,15 +76,15 @@ func (s *Server) GetBrandingSettings(ctx context.Context, req *settings.GetBrand
|
||||
ChangeDate: timestamppb.New(current.ChangeDate),
|
||||
ResourceOwner: current.ResourceOwner,
|
||||
},
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (s *Server) GetDomainSettings(ctx context.Context, req *settings.GetDomainSettingsRequest) (*settings.GetDomainSettingsResponse, error) {
|
||||
current, err := s.query.DomainPolicyByOrg(ctx, true, object.ResourceOwnerFromReq(ctx, req.GetCtx()), false)
|
||||
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.Msg.GetCtx()), false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &settings.GetDomainSettingsResponse{
|
||||
return connect.NewResponse(&settings.GetDomainSettingsResponse{
|
||||
Settings: domainSettingsToPb(current),
|
||||
Details: &object_pb.Details{
|
||||
Sequence: current.Sequence,
|
||||
@@ -91,15 +92,15 @@ func (s *Server) GetDomainSettings(ctx context.Context, req *settings.GetDomainS
|
||||
ChangeDate: timestamppb.New(current.ChangeDate),
|
||||
ResourceOwner: current.ResourceOwner,
|
||||
},
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (s *Server) GetLegalAndSupportSettings(ctx context.Context, req *settings.GetLegalAndSupportSettingsRequest) (*settings.GetLegalAndSupportSettingsResponse, error) {
|
||||
current, err := s.query.PrivacyPolicyByOrg(ctx, true, object.ResourceOwnerFromReq(ctx, req.GetCtx()), false)
|
||||
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.Msg.GetCtx()), false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &settings.GetLegalAndSupportSettingsResponse{
|
||||
return connect.NewResponse(&settings.GetLegalAndSupportSettingsResponse{
|
||||
Settings: legalAndSupportSettingsToPb(current),
|
||||
Details: &object_pb.Details{
|
||||
Sequence: current.Sequence,
|
||||
@@ -107,15 +108,15 @@ func (s *Server) GetLegalAndSupportSettings(ctx context.Context, req *settings.G
|
||||
ChangeDate: timestamppb.New(current.ChangeDate),
|
||||
ResourceOwner: current.ResourceOwner,
|
||||
},
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (s *Server) GetLockoutSettings(ctx context.Context, req *settings.GetLockoutSettingsRequest) (*settings.GetLockoutSettingsResponse, error) {
|
||||
current, err := s.query.LockoutPolicyByOrg(ctx, true, object.ResourceOwnerFromReq(ctx, req.GetCtx()))
|
||||
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.Msg.GetCtx()))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &settings.GetLockoutSettingsResponse{
|
||||
return connect.NewResponse(&settings.GetLockoutSettingsResponse{
|
||||
Settings: lockoutSettingsToPb(current),
|
||||
Details: &object_pb.Details{
|
||||
Sequence: current.Sequence,
|
||||
@@ -123,24 +124,24 @@ func (s *Server) GetLockoutSettings(ctx context.Context, req *settings.GetLockou
|
||||
ChangeDate: timestamppb.New(current.ChangeDate),
|
||||
ResourceOwner: current.ResourceOwner,
|
||||
},
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (s *Server) GetActiveIdentityProviders(ctx context.Context, req *settings.GetActiveIdentityProvidersRequest) (*settings.GetActiveIdentityProvidersResponse, error) {
|
||||
queries, err := activeIdentityProvidersToQuery(req)
|
||||
func (s *Server) GetActiveIdentityProviders(ctx context.Context, req *connect.Request[settings.GetActiveIdentityProvidersRequest]) (*connect.Response[settings.GetActiveIdentityProvidersResponse], error) {
|
||||
queries, err := activeIdentityProvidersToQuery(req.Msg)
|
||||
if err != nil {
|
||||
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 {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &settings.GetActiveIdentityProvidersResponse{
|
||||
return connect.NewResponse(&settings.GetActiveIdentityProvidersResponse{
|
||||
Details: object.ToListDetails(links.SearchResponse),
|
||||
IdentityProviders: identityProvidersToPb(links.Links),
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func activeIdentityProvidersToQuery(req *settings.GetActiveIdentityProvidersRequest) (_ []query.SearchQuery, err error) {
|
||||
@@ -180,30 +181,30 @@ func activeIdentityProvidersToQuery(req *settings.GetActiveIdentityProvidersRequ
|
||||
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)
|
||||
return &settings.GetGeneralSettingsResponse{
|
||||
return connect.NewResponse(&settings.GetGeneralSettingsResponse{
|
||||
SupportedLanguages: domain.LanguagesToStrings(i18n.SupportedLanguages()),
|
||||
DefaultOrgId: instance.DefaultOrganisationID(),
|
||||
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)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &settings.GetSecuritySettingsResponse{
|
||||
return connect.NewResponse(&settings.GetSecuritySettingsResponse{
|
||||
Settings: securityPolicyToSettingsPb(policy),
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (s *Server) GetHostedLoginTranslation(ctx context.Context, req *settings.GetHostedLoginTranslationRequest) (*settings.GetHostedLoginTranslationResponse, error) {
|
||||
translation, err := s.query.GetHostedLoginTranslation(ctx, req)
|
||||
func (s *Server) GetHostedLoginTranslation(ctx context.Context, req *connect.Request[settings.GetHostedLoginTranslationRequest]) (*connect.Response[settings.GetHostedLoginTranslationResponse], error) {
|
||||
translation, err := s.query.GetHostedLoginTranslation(ctx, req.Msg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return translation, nil
|
||||
return connect.NewResponse(translation), nil
|
||||
}
|
||||
|
@@ -2,8 +2,10 @@ package settings
|
||||
|
||||
import (
|
||||
"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/authz"
|
||||
@@ -11,12 +13,12 @@ import (
|
||||
"github.com/zitadel/zitadel/internal/command"
|
||||
"github.com/zitadel/zitadel/internal/query"
|
||||
"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 {
|
||||
settings.UnimplementedSettingsServiceServer
|
||||
command *command.Commands
|
||||
query *query.Queries
|
||||
assetsAPIDomain func(context.Context) string
|
||||
@@ -35,8 +37,12 @@ func CreateServer(
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) RegisterServer(grpcServer *grpc.Server) {
|
||||
settings.RegisterSettingsServiceServer(grpcServer, s)
|
||||
func (s *Server) RegisterConnectServer(interceptors ...connect.Interceptor) (string, http.Handler) {
|
||||
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 {
|
||||
|
@@ -3,25 +3,27 @@ package settings
|
||||
import (
|
||||
"context"
|
||||
|
||||
"connectrpc.com/connect"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/grpc/object/v2"
|
||||
"github.com/zitadel/zitadel/pkg/grpc/settings/v2"
|
||||
)
|
||||
|
||||
func (s *Server) SetSecuritySettings(ctx context.Context, req *settings.SetSecuritySettingsRequest) (*settings.SetSecuritySettingsResponse, error) {
|
||||
details, err := s.command.SetSecurityPolicy(ctx, securitySettingsToCommand(req))
|
||||
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.Msg))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &settings.SetSecuritySettingsResponse{
|
||||
return connect.NewResponse(&settings.SetSecuritySettingsResponse{
|
||||
Details: object.DomainToDetailsPb(details),
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (s *Server) SetHostedLoginTranslation(ctx context.Context, req *settings.SetHostedLoginTranslationRequest) (*settings.SetHostedLoginTranslationResponse, error) {
|
||||
res, err := s.command.SetHostedLoginTranslation(ctx, req)
|
||||
func (s *Server) SetHostedLoginTranslation(ctx context.Context, req *connect.Request[settings.SetHostedLoginTranslationRequest]) (*connect.Response[settings.SetHostedLoginTranslationResponse], error) {
|
||||
res, err := s.command.SetHostedLoginTranslation(ctx, req.Msg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return res, nil
|
||||
return connect.NewResponse(res), nil
|
||||
}
|
||||
|
@@ -2,8 +2,10 @@ package settings
|
||||
|
||||
import (
|
||||
"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/authz"
|
||||
@@ -11,12 +13,12 @@ import (
|
||||
"github.com/zitadel/zitadel/internal/command"
|
||||
"github.com/zitadel/zitadel/internal/query"
|
||||
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 {
|
||||
settings.UnimplementedSettingsServiceServer
|
||||
command *command.Commands
|
||||
query *query.Queries
|
||||
assetsAPIDomain func(context.Context) string
|
||||
@@ -35,8 +37,12 @@ func CreateServer(
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) RegisterServer(grpcServer *grpc.Server) {
|
||||
settings.RegisterSettingsServiceServer(grpcServer, s)
|
||||
func (s *Server) RegisterConnectServer(interceptors ...connect.Interceptor) (string, http.Handler) {
|
||||
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 {
|
||||
|
@@ -3,6 +3,7 @@ package settings
|
||||
import (
|
||||
"context"
|
||||
|
||||
"connectrpc.com/connect"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/authz"
|
||||
@@ -14,12 +15,12 @@ import (
|
||||
settings "github.com/zitadel/zitadel/pkg/grpc/settings/v2beta"
|
||||
)
|
||||
|
||||
func (s *Server) GetLoginSettings(ctx context.Context, req *settings.GetLoginSettingsRequest) (*settings.GetLoginSettingsResponse, error) {
|
||||
current, err := s.query.LoginPolicyByID(ctx, true, object.ResourceOwnerFromReq(ctx, req.GetCtx()), false)
|
||||
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.Msg.GetCtx()), false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &settings.GetLoginSettingsResponse{
|
||||
return connect.NewResponse(&settings.GetLoginSettingsResponse{
|
||||
Settings: loginSettingsToPb(current),
|
||||
Details: &object_pb.Details{
|
||||
Sequence: current.Sequence,
|
||||
@@ -27,15 +28,15 @@ func (s *Server) GetLoginSettings(ctx context.Context, req *settings.GetLoginSet
|
||||
ChangeDate: timestamppb.New(current.ChangeDate),
|
||||
ResourceOwner: current.OrgID,
|
||||
},
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (s *Server) GetPasswordComplexitySettings(ctx context.Context, req *settings.GetPasswordComplexitySettingsRequest) (*settings.GetPasswordComplexitySettingsResponse, error) {
|
||||
current, err := s.query.PasswordComplexityPolicyByOrg(ctx, true, object.ResourceOwnerFromReq(ctx, req.GetCtx()), false)
|
||||
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.Msg.GetCtx()), false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &settings.GetPasswordComplexitySettingsResponse{
|
||||
return connect.NewResponse(&settings.GetPasswordComplexitySettingsResponse{
|
||||
Settings: passwordComplexitySettingsToPb(current),
|
||||
Details: &object_pb.Details{
|
||||
Sequence: current.Sequence,
|
||||
@@ -43,15 +44,15 @@ func (s *Server) GetPasswordComplexitySettings(ctx context.Context, req *setting
|
||||
ChangeDate: timestamppb.New(current.ChangeDate),
|
||||
ResourceOwner: current.ResourceOwner,
|
||||
},
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (s *Server) GetPasswordExpirySettings(ctx context.Context, req *settings.GetPasswordExpirySettingsRequest) (*settings.GetPasswordExpirySettingsResponse, error) {
|
||||
current, err := s.query.PasswordAgePolicyByOrg(ctx, true, object.ResourceOwnerFromReq(ctx, req.GetCtx()), false)
|
||||
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.Msg.GetCtx()), false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &settings.GetPasswordExpirySettingsResponse{
|
||||
return connect.NewResponse(&settings.GetPasswordExpirySettingsResponse{
|
||||
Settings: passwordExpirySettingsToPb(current),
|
||||
Details: &object_pb.Details{
|
||||
Sequence: current.Sequence,
|
||||
@@ -59,15 +60,15 @@ func (s *Server) GetPasswordExpirySettings(ctx context.Context, req *settings.Ge
|
||||
ChangeDate: timestamppb.New(current.ChangeDate),
|
||||
ResourceOwner: current.ResourceOwner,
|
||||
},
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (s *Server) GetBrandingSettings(ctx context.Context, req *settings.GetBrandingSettingsRequest) (*settings.GetBrandingSettingsResponse, error) {
|
||||
current, err := s.query.ActiveLabelPolicyByOrg(ctx, object.ResourceOwnerFromReq(ctx, req.GetCtx()), false)
|
||||
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.Msg.GetCtx()), false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &settings.GetBrandingSettingsResponse{
|
||||
return connect.NewResponse(&settings.GetBrandingSettingsResponse{
|
||||
Settings: brandingSettingsToPb(current, s.assetsAPIDomain(ctx)),
|
||||
Details: &object_pb.Details{
|
||||
Sequence: current.Sequence,
|
||||
@@ -75,15 +76,15 @@ func (s *Server) GetBrandingSettings(ctx context.Context, req *settings.GetBrand
|
||||
ChangeDate: timestamppb.New(current.ChangeDate),
|
||||
ResourceOwner: current.ResourceOwner,
|
||||
},
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (s *Server) GetDomainSettings(ctx context.Context, req *settings.GetDomainSettingsRequest) (*settings.GetDomainSettingsResponse, error) {
|
||||
current, err := s.query.DomainPolicyByOrg(ctx, true, object.ResourceOwnerFromReq(ctx, req.GetCtx()), false)
|
||||
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.Msg.GetCtx()), false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &settings.GetDomainSettingsResponse{
|
||||
return connect.NewResponse(&settings.GetDomainSettingsResponse{
|
||||
Settings: domainSettingsToPb(current),
|
||||
Details: &object_pb.Details{
|
||||
Sequence: current.Sequence,
|
||||
@@ -91,15 +92,15 @@ func (s *Server) GetDomainSettings(ctx context.Context, req *settings.GetDomainS
|
||||
ChangeDate: timestamppb.New(current.ChangeDate),
|
||||
ResourceOwner: current.ResourceOwner,
|
||||
},
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (s *Server) GetLegalAndSupportSettings(ctx context.Context, req *settings.GetLegalAndSupportSettingsRequest) (*settings.GetLegalAndSupportSettingsResponse, error) {
|
||||
current, err := s.query.PrivacyPolicyByOrg(ctx, true, object.ResourceOwnerFromReq(ctx, req.GetCtx()), false)
|
||||
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.Msg.GetCtx()), false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &settings.GetLegalAndSupportSettingsResponse{
|
||||
return connect.NewResponse(&settings.GetLegalAndSupportSettingsResponse{
|
||||
Settings: legalAndSupportSettingsToPb(current),
|
||||
Details: &object_pb.Details{
|
||||
Sequence: current.Sequence,
|
||||
@@ -107,15 +108,15 @@ func (s *Server) GetLegalAndSupportSettings(ctx context.Context, req *settings.G
|
||||
ChangeDate: timestamppb.New(current.ChangeDate),
|
||||
ResourceOwner: current.ResourceOwner,
|
||||
},
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (s *Server) GetLockoutSettings(ctx context.Context, req *settings.GetLockoutSettingsRequest) (*settings.GetLockoutSettingsResponse, error) {
|
||||
current, err := s.query.LockoutPolicyByOrg(ctx, true, object.ResourceOwnerFromReq(ctx, req.GetCtx()))
|
||||
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.Msg.GetCtx()))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &settings.GetLockoutSettingsResponse{
|
||||
return connect.NewResponse(&settings.GetLockoutSettingsResponse{
|
||||
Settings: lockoutSettingsToPb(current),
|
||||
Details: &object_pb.Details{
|
||||
Sequence: current.Sequence,
|
||||
@@ -123,46 +124,46 @@ func (s *Server) GetLockoutSettings(ctx context.Context, req *settings.GetLockou
|
||||
ChangeDate: timestamppb.New(current.ChangeDate),
|
||||
ResourceOwner: current.ResourceOwner,
|
||||
},
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (s *Server) GetActiveIdentityProviders(ctx context.Context, req *settings.GetActiveIdentityProvidersRequest) (*settings.GetActiveIdentityProvidersResponse, error) {
|
||||
links, err := s.query.IDPLoginPolicyLinks(ctx, object.ResourceOwnerFromReq(ctx, req.GetCtx()), &query.IDPLoginPolicyLinksSearchQuery{}, false)
|
||||
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.Msg.GetCtx()), &query.IDPLoginPolicyLinksSearchQuery{}, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &settings.GetActiveIdentityProvidersResponse{
|
||||
return connect.NewResponse(&settings.GetActiveIdentityProvidersResponse{
|
||||
Details: object.ToListDetails(links.SearchResponse),
|
||||
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)
|
||||
return &settings.GetGeneralSettingsResponse{
|
||||
return connect.NewResponse(&settings.GetGeneralSettingsResponse{
|
||||
SupportedLanguages: domain.LanguagesToStrings(i18n.SupportedLanguages()),
|
||||
DefaultOrgId: instance.DefaultOrganisationID(),
|
||||
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)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &settings.GetSecuritySettingsResponse{
|
||||
return connect.NewResponse(&settings.GetSecuritySettingsResponse{
|
||||
Settings: securityPolicyToSettingsPb(policy),
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (s *Server) SetSecuritySettings(ctx context.Context, req *settings.SetSecuritySettingsRequest) (*settings.SetSecuritySettingsResponse, error) {
|
||||
details, err := s.command.SetSecurityPolicy(ctx, securitySettingsToCommand(req))
|
||||
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.Msg))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &settings.SetSecuritySettingsResponse{
|
||||
return connect.NewResponse(&settings.SetSecuritySettingsResponse{
|
||||
Details: object.DomainToDetailsPb(details),
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
@@ -3,6 +3,7 @@ package user
|
||||
import (
|
||||
"context"
|
||||
|
||||
"connectrpc.com/connect"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
@@ -11,18 +12,18 @@ import (
|
||||
"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
|
||||
|
||||
switch v := req.GetVerification().(type) {
|
||||
switch v := req.Msg.GetVerification().(type) {
|
||||
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:
|
||||
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:
|
||||
email, err = s.command.ChangeUserEmailVerified(ctx, req.GetUserId(), req.GetEmail())
|
||||
email, err = s.command.ChangeUserEmailVerified(ctx, req.Msg.GetUserId(), req.Msg.GetEmail())
|
||||
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:
|
||||
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 &user.SetEmailResponse{
|
||||
return connect.NewResponse(&user.SetEmailResponse{
|
||||
Details: &object.Details{
|
||||
Sequence: email.Sequence,
|
||||
ChangeDate: timestamppb.New(email.ChangeDate),
|
||||
ResourceOwner: email.ResourceOwner,
|
||||
},
|
||||
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
|
||||
|
||||
switch v := req.GetVerification().(type) {
|
||||
switch v := req.Msg.GetVerification().(type) {
|
||||
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:
|
||||
email, err = s.command.ResendUserEmailReturnCode(ctx, req.GetUserId(), s.userCodeAlg)
|
||||
email, err = s.command.ResendUserEmailReturnCode(ctx, req.Msg.GetUserId(), s.userCodeAlg)
|
||||
case nil:
|
||||
email, err = s.command.ResendUserEmailCode(ctx, req.GetUserId(), s.userCodeAlg)
|
||||
email, err = s.command.ResendUserEmailCode(ctx, req.Msg.GetUserId(), s.userCodeAlg)
|
||||
default:
|
||||
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 &user.ResendEmailCodeResponse{
|
||||
return connect.NewResponse(&user.ResendEmailCodeResponse{
|
||||
Details: &object.Details{
|
||||
Sequence: email.Sequence,
|
||||
ChangeDate: timestamppb.New(email.ChangeDate),
|
||||
ResourceOwner: email.ResourceOwner,
|
||||
},
|
||||
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
|
||||
|
||||
switch v := req.GetVerification().(type) {
|
||||
switch v := req.Msg.GetVerification().(type) {
|
||||
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:
|
||||
email, err = s.command.SendUserEmailReturnCode(ctx, req.GetUserId(), s.userCodeAlg)
|
||||
email, err = s.command.SendUserEmailReturnCode(ctx, req.Msg.GetUserId(), s.userCodeAlg)
|
||||
case nil:
|
||||
email, err = s.command.SendUserEmailCode(ctx, req.GetUserId(), s.userCodeAlg)
|
||||
email, err = s.command.SendUserEmailCode(ctx, req.Msg.GetUserId(), s.userCodeAlg)
|
||||
default:
|
||||
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 &user.SendEmailCodeResponse{
|
||||
return connect.NewResponse(&user.SendEmailCodeResponse{
|
||||
Details: &object.Details{
|
||||
Sequence: email.Sequence,
|
||||
ChangeDate: timestamppb.New(email.ChangeDate),
|
||||
ResourceOwner: email.ResourceOwner,
|
||||
},
|
||||
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,
|
||||
req.GetUserId(),
|
||||
req.GetVerificationCode(),
|
||||
req.Msg.GetUserId(),
|
||||
req.Msg.GetVerificationCode(),
|
||||
s.userCodeAlg,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &user.VerifyEmailResponse{
|
||||
return connect.NewResponse(&user.VerifyEmailResponse{
|
||||
Details: &object.Details{
|
||||
Sequence: details.Sequence,
|
||||
ChangeDate: timestamppb.New(details.EventDate),
|
||||
ResourceOwner: details.ResourceOwner,
|
||||
},
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"io"
|
||||
|
||||
"connectrpc.com/connect"
|
||||
"golang.org/x/text/language"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
|
||||
@@ -14,7 +15,7 @@ import (
|
||||
"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{
|
||||
Username: userName,
|
||||
UserId: userId,
|
||||
@@ -52,15 +53,15 @@ func (s *Server) createUserTypeHuman(ctx context.Context, humanPb *user.CreateUs
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &user.CreateUserResponse{
|
||||
return connect.NewResponse(&user.CreateUserResponse{
|
||||
Id: newHuman.ID,
|
||||
CreationDate: timestamppb.New(newHuman.Details.EventDate),
|
||||
EmailCode: newHuman.EmailCode,
|
||||
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)
|
||||
if err != nil {
|
||||
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 {
|
||||
return nil, err
|
||||
}
|
||||
return &user.UpdateUserResponse{
|
||||
return connect.NewResponse(&user.UpdateUserResponse{
|
||||
ChangeDate: timestamppb.New(cmd.Details.EventDate),
|
||||
EmailCode: cmd.EmailCode,
|
||||
PhoneCode: cmd.PhoneCode,
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func updateHumanUserToCommand(userId string, userName *string, human *user.UpdateUserRequest_Human) (*command.ChangeHuman, error) {
|
||||
|
@@ -3,6 +3,8 @@ package user
|
||||
import (
|
||||
"context"
|
||||
|
||||
"connectrpc.com/connect"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/grpc/object/v2"
|
||||
"github.com/zitadel/zitadel/internal/command"
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
@@ -11,22 +13,22 @@ import (
|
||||
"github.com/zitadel/zitadel/pkg/grpc/user/v2"
|
||||
)
|
||||
|
||||
func (s *Server) AddIDPLink(ctx context.Context, req *user.AddIDPLinkRequest) (_ *user.AddIDPLinkResponse, err error) {
|
||||
details, err := s.command.AddUserIDPLink(ctx, req.UserId, "", &command.AddLink{
|
||||
IDPID: req.GetIdpLink().GetIdpId(),
|
||||
DisplayName: req.GetIdpLink().GetUserName(),
|
||||
IDPExternalID: req.GetIdpLink().GetUserId(),
|
||||
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.Msg.GetUserId(), "", &command.AddLink{
|
||||
IDPID: req.Msg.GetIdpLink().GetIdpId(),
|
||||
DisplayName: req.Msg.GetIdpLink().GetUserName(),
|
||||
IDPExternalID: req.Msg.GetIdpLink().GetUserId(),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &user.AddIDPLinkResponse{
|
||||
return connect.NewResponse(&user.AddIDPLinkResponse{
|
||||
Details: object.DomainToDetailsPb(details),
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (s *Server) ListIDPLinks(ctx context.Context, req *user.ListIDPLinksRequest) (_ *user.ListIDPLinksResponse, err error) {
|
||||
queries, err := ListLinkedIDPsRequestToQuery(req)
|
||||
func (s *Server) ListIDPLinks(ctx context.Context, req *connect.Request[user.ListIDPLinksRequest]) (_ *connect.Response[user.ListIDPLinksResponse], err error) {
|
||||
queries, err := ListLinkedIDPsRequestToQuery(req.Msg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -34,10 +36,10 @@ func (s *Server) ListIDPLinks(ctx context.Context, req *user.ListIDPLinksRequest
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &user.ListIDPLinksResponse{
|
||||
return connect.NewResponse(&user.ListIDPLinksResponse{
|
||||
Result: IDPLinksToPb(res.Links),
|
||||
Details: object.ToListDetails(res.SearchResponse),
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
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) {
|
||||
objectDetails, err := s.command.RemoveUserIDPLink(ctx, RemoveIDPLinkRequestToDomain(ctx, req))
|
||||
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.Msg))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &user.RemoveIDPLinkResponse{
|
||||
return connect.NewResponse(&user.RemoveIDPLinkResponse{
|
||||
Details: object.DomainToDetailsPb(objectDetails),
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func RemoveIDPLinkRequestToDomain(ctx context.Context, req *user.RemoveIDPLinkRequest) *domain.UserIDPLink {
|
||||
|
@@ -6,6 +6,7 @@ import (
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"connectrpc.com/connect"
|
||||
oidc_pkg "github.com/zitadel/oidc/v3/pkg/oidc"
|
||||
"google.golang.org/protobuf/types/known/structpb"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
@@ -32,18 +33,18 @@ import (
|
||||
"github.com/zitadel/zitadel/pkg/grpc/user/v2"
|
||||
)
|
||||
|
||||
func (s *Server) StartIdentityProviderIntent(ctx context.Context, req *user.StartIdentityProviderIntentRequest) (_ *user.StartIdentityProviderIntentResponse, err error) {
|
||||
switch t := req.GetContent().(type) {
|
||||
func (s *Server) StartIdentityProviderIntent(ctx context.Context, req *connect.Request[user.StartIdentityProviderIntentRequest]) (_ *connect.Response[user.StartIdentityProviderIntentResponse], err error) {
|
||||
switch t := req.Msg.GetContent().(type) {
|
||||
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:
|
||||
return s.startLDAPIntent(ctx, req.GetIdpId(), t.Ldap)
|
||||
return s.startLDAPIntent(ctx, req.Msg.GetIdpId(), t.Ldap)
|
||||
default:
|
||||
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))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -58,12 +59,12 @@ func (s *Server) startIDPIntent(ctx context.Context, idpID string, urls *user.Re
|
||||
}
|
||||
switch a := auth.(type) {
|
||||
case *idp.RedirectAuth:
|
||||
return &user.StartIdentityProviderIntentResponse{
|
||||
return connect.NewResponse(&user.StartIdentityProviderIntentResponse{
|
||||
Details: object.DomainToDetailsPb(details),
|
||||
NextStep: &user.StartIdentityProviderIntentResponse_AuthUrl{AuthUrl: a.RedirectURL},
|
||||
}, nil
|
||||
}), nil
|
||||
case *idp.FormAuth:
|
||||
return &user.StartIdentityProviderIntentResponse{
|
||||
return connect.NewResponse(&user.StartIdentityProviderIntentResponse{
|
||||
Details: object.DomainToDetailsPb(details),
|
||||
NextStep: &user.StartIdentityProviderIntentResponse_FormData{
|
||||
FormData: &user.FormData{
|
||||
@@ -71,12 +72,12 @@ func (s *Server) startIDPIntent(ctx context.Context, idpID string, urls *user.Re
|
||||
Fields: a.Fields,
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
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)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -92,7 +93,7 @@ func (s *Server) startLDAPIntent(ctx context.Context, idpID string, ldapCredenti
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &user.StartIdentityProviderIntentResponse{
|
||||
return connect.NewResponse(&user.StartIdentityProviderIntentResponse{
|
||||
Details: object.DomainToDetailsPb(details),
|
||||
NextStep: &user.StartIdentityProviderIntentResponse_IdpIntent{
|
||||
IdpIntent: &user.IDPIntent{
|
||||
@@ -101,7 +102,7 @@ func (s *Server) startLDAPIntent(ctx context.Context, idpID string, ldapCredenti
|
||||
UserId: userID,
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
func (s *Server) RetrieveIdentityProviderIntent(ctx context.Context, req *user.RetrieveIdentityProviderIntentRequest) (_ *user.RetrieveIdentityProviderIntentResponse, err error) {
|
||||
intent, err := s.command.GetIntentWriteModel(ctx, req.GetIdpIntentId(), "")
|
||||
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.Msg.GetIdpIntentId(), "")
|
||||
if err != nil {
|
||||
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
|
||||
}
|
||||
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)
|
||||
}
|
||||
return idpIntent, nil
|
||||
return connect.NewResponse(idpIntent), nil
|
||||
}
|
||||
|
||||
type rawUserMapper struct {
|
||||
|
@@ -3,6 +3,7 @@ package user
|
||||
import (
|
||||
"context"
|
||||
|
||||
"connectrpc.com/connect"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/command"
|
||||
@@ -11,16 +12,16 @@ import (
|
||||
"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{
|
||||
ObjectRoot: models.ObjectRoot{
|
||||
AggregateID: req.UserId,
|
||||
AggregateID: req.Msg.GetUserId(),
|
||||
},
|
||||
ExpirationDate: req.GetExpirationDate().AsTime(),
|
||||
ExpirationDate: req.Msg.GetExpirationDate().AsTime(),
|
||||
Type: domain.AuthNKeyTypeJSON,
|
||||
PermissionCheck: s.command.NewPermissionCheckUserWrite(ctx),
|
||||
}
|
||||
newMachineKey.PublicKey = req.PublicKey
|
||||
newMachineKey.PublicKey = req.Msg.GetPublicKey()
|
||||
|
||||
pubkeySupplied := len(newMachineKey.PublicKey) > 0
|
||||
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 &user.AddKeyResponse{
|
||||
return connect.NewResponse(&user.AddKeyResponse{
|
||||
KeyId: newMachineKey.KeyID,
|
||||
KeyContent: keyDetails,
|
||||
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{
|
||||
ObjectRoot: models.ObjectRoot{
|
||||
AggregateID: req.UserId,
|
||||
AggregateID: req.Msg.GetUserId(),
|
||||
},
|
||||
PermissionCheck: s.command.NewPermissionCheckUserWrite(ctx),
|
||||
KeyID: req.KeyId,
|
||||
KeyID: req.Msg.GetKeyId(),
|
||||
}
|
||||
objectDetails, err := s.command.RemoveUserMachineKey(ctx, machineKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &user.RemoveKeyResponse{
|
||||
return connect.NewResponse(&user.RemoveKeyResponse{
|
||||
DeletionDate: timestamppb.New(objectDetails.EventDate),
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
@@ -3,6 +3,7 @@ package user
|
||||
import (
|
||||
"context"
|
||||
|
||||
"connectrpc.com/connect"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/grpc/filter/v2"
|
||||
@@ -12,13 +13,13 @@ import (
|
||||
"github.com/zitadel/zitadel/pkg/grpc/user/v2"
|
||||
)
|
||||
|
||||
func (s *Server) ListKeys(ctx context.Context, req *user.ListKeysRequest) (*user.ListKeysResponse, error) {
|
||||
offset, limit, asc, err := filter.PaginationPbToQuery(s.systemDefaults, req.Pagination)
|
||||
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.Msg.GetPagination())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
filters, err := keyFiltersToQueries(req.Filters)
|
||||
filters, err := keyFiltersToQueries(req.Msg.GetFilters())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -27,7 +28,7 @@ func (s *Server) ListKeys(ctx context.Context, req *user.ListKeysRequest) (*user
|
||||
Offset: offset,
|
||||
Limit: limit,
|
||||
Asc: asc,
|
||||
SortingColumn: authnKeyFieldNameToSortingColumn(req.SortingColumn),
|
||||
SortingColumn: authnKeyFieldNameToSortingColumn(req.Msg.SortingColumn),
|
||||
},
|
||||
Queries: filters,
|
||||
}
|
||||
@@ -49,7 +50,7 @@ func (s *Server) ListKeys(ctx context.Context, req *user.ListKeysRequest) (*user
|
||||
ExpirationDate: timestamppb.New(key.Expiration),
|
||||
}
|
||||
}
|
||||
return resp, nil
|
||||
return connect.NewResponse(resp), nil
|
||||
}
|
||||
|
||||
func keyFiltersToQueries(filters []*user.KeysSearchFilter) (_ []query.SearchQuery, err error) {
|
||||
|
@@ -3,6 +3,7 @@ package user
|
||||
import (
|
||||
"context"
|
||||
|
||||
"connectrpc.com/connect"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/command"
|
||||
@@ -11,7 +12,7 @@ import (
|
||||
"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{
|
||||
Username: userName,
|
||||
Name: machinePb.Name,
|
||||
@@ -32,21 +33,21 @@ func (s *Server) createUserTypeMachine(ctx context.Context, machinePb *user.Crea
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &user.CreateUserResponse{
|
||||
return connect.NewResponse(&user.CreateUserResponse{
|
||||
Id: cmd.AggregateID,
|
||||
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)
|
||||
err := s.command.ChangeUserMachine(ctx, cmd)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &user.UpdateUserResponse{
|
||||
return connect.NewResponse(&user.UpdateUserResponse{
|
||||
ChangeDate: timestamppb.New(cmd.Details.EventDate),
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func updateMachineUserToCommand(userId string, userName *string, machine *user.UpdateUserRequest_Machine) *command.ChangeMachine {
|
||||
|
@@ -3,39 +3,41 @@ package user
|
||||
import (
|
||||
"context"
|
||||
|
||||
"connectrpc.com/connect"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/grpc/object/v2"
|
||||
"github.com/zitadel/zitadel/pkg/grpc/user/v2"
|
||||
)
|
||||
|
||||
func (s *Server) AddOTPSMS(ctx context.Context, req *user.AddOTPSMSRequest) (*user.AddOTPSMSResponse, error) {
|
||||
details, err := s.command.AddHumanOTPSMS(ctx, req.GetUserId(), "")
|
||||
func (s *Server) AddOTPSMS(ctx context.Context, req *connect.Request[user.AddOTPSMSRequest]) (*connect.Response[user.AddOTPSMSResponse], error) {
|
||||
details, err := s.command.AddHumanOTPSMS(ctx, req.Msg.GetUserId(), "")
|
||||
if err != nil {
|
||||
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) {
|
||||
objectDetails, err := s.command.RemoveHumanOTPSMS(ctx, req.GetUserId(), "")
|
||||
func (s *Server) RemoveOTPSMS(ctx context.Context, req *connect.Request[user.RemoveOTPSMSRequest]) (*connect.Response[user.RemoveOTPSMSResponse], error) {
|
||||
objectDetails, err := s.command.RemoveHumanOTPSMS(ctx, req.Msg.GetUserId(), "")
|
||||
if err != nil {
|
||||
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) {
|
||||
details, err := s.command.AddHumanOTPEmail(ctx, req.GetUserId(), "")
|
||||
func (s *Server) AddOTPEmail(ctx context.Context, req *connect.Request[user.AddOTPEmailRequest]) (*connect.Response[user.AddOTPEmailResponse], error) {
|
||||
details, err := s.command.AddHumanOTPEmail(ctx, req.Msg.GetUserId(), "")
|
||||
if err != nil {
|
||||
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) {
|
||||
objectDetails, err := s.command.RemoveHumanOTPEmail(ctx, req.GetUserId(), "")
|
||||
func (s *Server) RemoveOTPEmail(ctx context.Context, req *connect.Request[user.RemoveOTPEmailRequest]) (*connect.Response[user.RemoveOTPEmailResponse], error) {
|
||||
objectDetails, err := s.command.RemoveHumanOTPEmail(ctx, req.Msg.GetUserId(), "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &user.RemoveOTPEmailResponse{Details: object.DomainToDetailsPb(objectDetails)}, nil
|
||||
return connect.NewResponse(&user.RemoveOTPEmailResponse{Details: object.DomainToDetailsPb(objectDetails)}), nil
|
||||
}
|
||||
|
@@ -3,6 +3,7 @@ package user
|
||||
import (
|
||||
"context"
|
||||
|
||||
"connectrpc.com/connect"
|
||||
"google.golang.org/protobuf/types/known/structpb"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/grpc/object/v2"
|
||||
@@ -13,17 +14,17 @@ import (
|
||||
"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 (
|
||||
authenticator = passkeyAuthenticatorToDomain(req.GetAuthenticator())
|
||||
authenticator = passkeyAuthenticatorToDomain(req.Msg.GetAuthenticator())
|
||||
)
|
||||
if code := req.GetCode(); code != nil {
|
||||
if code := req.Msg.GetCode(); code != nil {
|
||||
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(
|
||||
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
|
||||
}
|
||||
|
||||
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)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &user.RegisterPasskeyResponse{
|
||||
return connect.NewResponse(&user.RegisterPasskeyResponse{
|
||||
Details: objectDetails,
|
||||
PasskeyId: details.ID,
|
||||
PublicKeyCredentialCreationOptions: options,
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (s *Server) VerifyPasskeyRegistration(ctx context.Context, req *user.VerifyPasskeyRegistrationRequest) (*user.VerifyPasskeyRegistrationResponse, error) {
|
||||
pkc, err := req.GetPublicKeyCredential().MarshalJSON()
|
||||
func (s *Server) VerifyPasskeyRegistration(ctx context.Context, req *connect.Request[user.VerifyPasskeyRegistrationRequest]) (*connect.Response[user.VerifyPasskeyRegistrationResponse], error) {
|
||||
pkc, err := req.Msg.GetPublicKeyCredential().MarshalJSON()
|
||||
if err != nil {
|
||||
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 {
|
||||
return nil, err
|
||||
}
|
||||
return &user.VerifyPasskeyRegistrationResponse{
|
||||
return connect.NewResponse(&user.VerifyPasskeyRegistrationResponse{
|
||||
Details: object.DomainToDetailsPb(objectDetails),
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (s *Server) CreatePasskeyRegistrationLink(ctx context.Context, req *user.CreatePasskeyRegistrationLinkRequest) (resp *user.CreatePasskeyRegistrationLinkResponse, err error) {
|
||||
switch medium := req.Medium.(type) {
|
||||
func (s *Server) CreatePasskeyRegistrationLink(ctx context.Context, req *connect.Request[user.CreatePasskeyRegistrationLinkRequest]) (resp *connect.Response[user.CreatePasskeyRegistrationLinkResponse], err error) {
|
||||
switch medium := req.Msg.Medium.(type) {
|
||||
case nil:
|
||||
return passkeyDetailsToPb(
|
||||
s.command.AddUserPasskeyCode(ctx, req.GetUserId(), "", s.userCodeAlg),
|
||||
s.command.AddUserPasskeyCode(ctx, req.Msg.GetUserId(), "", s.userCodeAlg),
|
||||
)
|
||||
case *user.CreatePasskeyRegistrationLinkRequest_SendLink:
|
||||
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:
|
||||
return passkeyCodeDetailsToPb(
|
||||
s.command.AddUserPasskeyCodeReturn(ctx, req.GetUserId(), "", s.userCodeAlg),
|
||||
s.command.AddUserPasskeyCodeReturn(ctx, req.Msg.GetUserId(), "", s.userCodeAlg),
|
||||
)
|
||||
default:
|
||||
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 {
|
||||
return nil, err
|
||||
}
|
||||
return &user.CreatePasskeyRegistrationLinkResponse{
|
||||
return connect.NewResponse(&user.CreatePasskeyRegistrationLinkResponse{
|
||||
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 {
|
||||
return nil, err
|
||||
}
|
||||
return &user.CreatePasskeyRegistrationLinkResponse{
|
||||
return connect.NewResponse(&user.CreatePasskeyRegistrationLinkResponse{
|
||||
Details: object.DomainToDetailsPb(details.ObjectDetails),
|
||||
Code: &user.PasskeyRegistrationCode{
|
||||
Id: details.CodeID,
|
||||
Code: details.Code,
|
||||
},
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (s *Server) RemovePasskey(ctx context.Context, req *user.RemovePasskeyRequest) (*user.RemovePasskeyResponse, error) {
|
||||
objectDetails, err := s.command.HumanRemovePasswordless(ctx, req.GetUserId(), req.GetPasskeyId(), "")
|
||||
func (s *Server) RemovePasskey(ctx context.Context, req *connect.Request[user.RemovePasskeyRequest]) (*connect.Response[user.RemovePasskeyResponse], error) {
|
||||
objectDetails, err := s.command.HumanRemovePasswordless(ctx, req.Msg.GetUserId(), req.Msg.GetPasskeyId(), "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &user.RemovePasskeyResponse{
|
||||
return connect.NewResponse(&user.RemovePasskeyResponse{
|
||||
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)
|
||||
err := query.AppendUserIDQuery(req.UserId)
|
||||
err := query.AppendUserIDQuery(req.Msg.UserId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -146,10 +147,10 @@ func (s *Server) ListPasskeys(ctx context.Context, req *user.ListPasskeysRequest
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &user.ListPasskeysResponse{
|
||||
return connect.NewResponse(&user.ListPasskeysResponse{
|
||||
Details: object.ToListDetails(authMethods.SearchResponse),
|
||||
Result: authMethodsToPasskeyPb(authMethods),
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func authMethodsToPasskeyPb(methods *query.AuthMethods) []*user.Passkey {
|
||||
|
@@ -123,11 +123,11 @@ func Test_passkeyRegistrationDetailsToPb(t *testing.T) {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := passkeyRegistrationDetailsToPb(tt.args.details, tt.args.err)
|
||||
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)
|
||||
}
|
||||
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) {
|
||||
got, err := passkeyDetailsToPb(tt.args.details, 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) {
|
||||
got, err := passkeyCodeDetailsToPb(tt.args.details, tt.args.err)
|
||||
require.ErrorIs(t, err, tt.args.err)
|
||||
assert.Equal(t, tt.want, got)
|
||||
if tt.want != nil {
|
||||
grpc.AllFieldsSet(t, got.ProtoReflect())
|
||||
assert.Equal(t, tt.want, got.Msg)
|
||||
grpc.AllFieldsSet(t, got.Msg.ProtoReflect())
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@@ -3,23 +3,25 @@ package user
|
||||
import (
|
||||
"context"
|
||||
|
||||
"connectrpc.com/connect"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/grpc/object/v2"
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
"github.com/zitadel/zitadel/internal/zerrors"
|
||||
"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 code *string
|
||||
|
||||
switch m := req.GetMedium().(type) {
|
||||
switch m := req.Msg.GetMedium().(type) {
|
||||
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:
|
||||
details, code, err = s.command.RequestPasswordResetReturnCode(ctx, req.GetUserId())
|
||||
details, code, err = s.command.RequestPasswordResetReturnCode(ctx, req.Msg.GetUserId())
|
||||
case nil:
|
||||
details, code, err = s.command.RequestPasswordReset(ctx, req.GetUserId())
|
||||
details, code, err = s.command.RequestPasswordReset(ctx, req.Msg.GetUserId())
|
||||
default:
|
||||
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 &user.PasswordResetResponse{
|
||||
return connect.NewResponse(&user.PasswordResetResponse{
|
||||
Details: object.DomainToDetailsPb(details),
|
||||
VerificationCode: code,
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
switch v := req.GetVerification().(type) {
|
||||
switch v := req.Msg.GetVerification().(type) {
|
||||
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:
|
||||
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:
|
||||
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:
|
||||
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 &user.SetPasswordResponse{
|
||||
return connect.NewResponse(&user.SetPasswordResponse{
|
||||
Details: object.DomainToDetailsPb(details),
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
@@ -3,6 +3,7 @@ package user
|
||||
import (
|
||||
"context"
|
||||
|
||||
"connectrpc.com/connect"
|
||||
"github.com/zitadel/oidc/v3/pkg/oidc"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
|
||||
@@ -13,13 +14,13 @@ import (
|
||||
"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{
|
||||
ObjectRoot: models.ObjectRoot{
|
||||
AggregateID: req.UserId,
|
||||
AggregateID: req.Msg.GetUserId(),
|
||||
},
|
||||
PermissionCheck: s.command.NewPermissionCheckUserWrite(ctx),
|
||||
ExpirationDate: req.ExpirationDate.AsTime(),
|
||||
ExpirationDate: req.Msg.GetExpirationDate().AsTime(),
|
||||
Scopes: []string{
|
||||
oidc.ScopeOpenID,
|
||||
oidc.ScopeProfile,
|
||||
@@ -32,25 +33,25 @@ func (s *Server) AddPersonalAccessToken(ctx context.Context, req *user.AddPerson
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &user.AddPersonalAccessTokenResponse{
|
||||
return connect.NewResponse(&user.AddPersonalAccessTokenResponse{
|
||||
CreationDate: timestamppb.New(details.EventDate),
|
||||
TokenId: newPat.TokenID,
|
||||
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{
|
||||
TokenID: req.TokenId,
|
||||
TokenID: req.Msg.GetTokenId(),
|
||||
ObjectRoot: models.ObjectRoot{
|
||||
AggregateID: req.UserId,
|
||||
AggregateID: req.Msg.GetUserId(),
|
||||
},
|
||||
PermissionCheck: s.command.NewPermissionCheckUserWrite(ctx),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &user.RemovePersonalAccessTokenResponse{
|
||||
return connect.NewResponse(&user.RemovePersonalAccessTokenResponse{
|
||||
DeletionDate: timestamppb.New(objectDetails.EventDate),
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
@@ -3,6 +3,7 @@ package user
|
||||
import (
|
||||
"context"
|
||||
|
||||
"connectrpc.com/connect"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/grpc/filter/v2"
|
||||
@@ -12,12 +13,12 @@ import (
|
||||
"github.com/zitadel/zitadel/pkg/grpc/user/v2"
|
||||
)
|
||||
|
||||
func (s *Server) ListPersonalAccessTokens(ctx context.Context, req *user.ListPersonalAccessTokensRequest) (*user.ListPersonalAccessTokensResponse, error) {
|
||||
offset, limit, asc, err := filter.PaginationPbToQuery(s.systemDefaults, req.Pagination)
|
||||
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.Msg.GetPagination())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
filters, err := patFiltersToQueries(req.Filters)
|
||||
filters, err := patFiltersToQueries(req.Msg.GetFilters())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -26,7 +27,7 @@ func (s *Server) ListPersonalAccessTokens(ctx context.Context, req *user.ListPer
|
||||
Offset: offset,
|
||||
Limit: limit,
|
||||
Asc: asc,
|
||||
SortingColumn: authnPersonalAccessTokenFieldNameToSortingColumn(req.SortingColumn),
|
||||
SortingColumn: authnPersonalAccessTokenFieldNameToSortingColumn(req.Msg.SortingColumn),
|
||||
},
|
||||
Queries: filters,
|
||||
}
|
||||
@@ -48,7 +49,7 @@ func (s *Server) ListPersonalAccessTokens(ctx context.Context, req *user.ListPer
|
||||
ExpirationDate: timestamppb.New(pat.Expiration),
|
||||
}
|
||||
}
|
||||
return resp, nil
|
||||
return connect.NewResponse(resp), nil
|
||||
}
|
||||
|
||||
func patFiltersToQueries(filters []*user.PersonalAccessTokensSearchFilter) (_ []query.SearchQuery, err error) {
|
||||
|
@@ -3,6 +3,7 @@ package user
|
||||
import (
|
||||
"context"
|
||||
|
||||
"connectrpc.com/connect"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
@@ -11,18 +12,18 @@ import (
|
||||
"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
|
||||
|
||||
switch v := req.GetVerification().(type) {
|
||||
switch v := req.Msg.GetVerification().(type) {
|
||||
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:
|
||||
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:
|
||||
phone, err = s.command.ChangeUserPhoneVerified(ctx, req.GetUserId(), req.GetPhone())
|
||||
phone, err = s.command.ChangeUserPhoneVerified(ctx, req.Msg.GetUserId(), req.Msg.GetPhone())
|
||||
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:
|
||||
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 &user.SetPhoneResponse{
|
||||
return connect.NewResponse(&user.SetPhoneResponse{
|
||||
Details: &object.Details{
|
||||
Sequence: phone.Sequence,
|
||||
ChangeDate: timestamppb.New(phone.ChangeDate),
|
||||
ResourceOwner: phone.ResourceOwner,
|
||||
},
|
||||
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,
|
||||
req.GetUserId(),
|
||||
req.Msg.GetUserId(),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &user.RemovePhoneResponse{
|
||||
return connect.NewResponse(&user.RemovePhoneResponse{
|
||||
Details: &object.Details{
|
||||
Sequence: details.Sequence,
|
||||
ChangeDate: timestamppb.New(details.EventDate),
|
||||
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
|
||||
switch v := req.GetVerification().(type) {
|
||||
switch v := req.Msg.GetVerification().(type) {
|
||||
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:
|
||||
phone, err = s.command.ResendUserPhoneCodeReturnCode(ctx, req.GetUserId(), s.userCodeAlg)
|
||||
phone, err = s.command.ResendUserPhoneCodeReturnCode(ctx, req.Msg.GetUserId(), s.userCodeAlg)
|
||||
case nil:
|
||||
phone, err = s.command.ResendUserPhoneCode(ctx, req.GetUserId(), s.userCodeAlg)
|
||||
phone, err = s.command.ResendUserPhoneCode(ctx, req.Msg.GetUserId(), s.userCodeAlg)
|
||||
default:
|
||||
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 &user.ResendPhoneCodeResponse{
|
||||
return connect.NewResponse(&user.ResendPhoneCodeResponse{
|
||||
Details: &object.Details{
|
||||
Sequence: phone.Sequence,
|
||||
ChangeDate: timestamppb.New(phone.ChangeDate),
|
||||
ResourceOwner: phone.ResourceOwner,
|
||||
},
|
||||
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,
|
||||
req.GetUserId(),
|
||||
req.GetVerificationCode(),
|
||||
req.Msg.GetUserId(),
|
||||
req.Msg.GetVerificationCode(),
|
||||
s.userCodeAlg,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &user.VerifyPhoneResponse{
|
||||
return connect.NewResponse(&user.VerifyPhoneResponse{
|
||||
Details: &object.Details{
|
||||
Sequence: details.Sequence,
|
||||
ChangeDate: timestamppb.New(details.EventDate),
|
||||
ResourceOwner: details.ResourceOwner,
|
||||
},
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
@@ -3,37 +3,38 @@ package user
|
||||
import (
|
||||
"context"
|
||||
|
||||
"connectrpc.com/connect"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/command"
|
||||
"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{
|
||||
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 {
|
||||
return nil, err
|
||||
}
|
||||
return &user.AddSecretResponse{
|
||||
return connect.NewResponse(&user.AddSecretResponse{
|
||||
CreationDate: timestamppb.New(details.EventDate),
|
||||
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(
|
||||
ctx,
|
||||
req.UserId,
|
||||
req.Msg.GetUserId(),
|
||||
"",
|
||||
s.command.NewPermissionCheckUserWrite(ctx),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &user.RemoveSecretResponse{
|
||||
return connect.NewResponse(&user.RemoveSecretResponse{
|
||||
DeletionDate: timestamppb.New(details.EventDate),
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user