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

# Which Problems Are Solved

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

# How the Problems Are Solved

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

# Additional Changes

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

# Additional Context

closes #9483

---------

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

View File

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

3
.gitignore vendored
View File

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

View File

@@ -78,12 +78,13 @@ core_grpc_dependencies:
go install github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2@v2.22.0 # https://pkg.go.dev/github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2?tab=versions
go install github.com/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

View File

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

View File

@@ -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
View File

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

3
docs/base.yaml Normal file
View File

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

View File

@@ -1,11 +1,18 @@
# buf.gen.yaml
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

View File

@@ -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",

View File

@@ -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
View File

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

View File

@@ -16,6 +16,7 @@ const sidebar_api_actions_v2 = require("./docs/apis/resources/action_service_v2/
const sidebar_api_project_service_v2 = require("./docs/apis/resources/project_service_v2/sidebar.ts").default
const sidebar_api_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,
},
],
},
{

View File

@@ -6121,6 +6121,11 @@ caniuse-lite@^1.0.30001702, caniuse-lite@^1.0.30001718:
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001724.tgz#312e163553dd70d2c0fb603d74810c85d8ed94a0"
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
View File

@@ -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
View File

@@ -24,6 +24,10 @@ cloud.google.com/go/storage v1.54.0 h1:Du3XEyliAiftfyW0bwfdppm2MMLdpVAfiIg4T2nAI
cloud.google.com/go/storage v1.54.0/go.mod h1:hIi9Boe8cHxTyaeqh7KMMwKg088VblFK46C2x/BWaZE=
cloud.google.com/go/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=

View File

@@ -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)
if err != nil {
return err
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)
}
a.verifier.RegisterServer(grpcServer.AppName(), grpcServer.MethodPrefix(), grpcServer.AuthMethods())
a.healthServer.SetServingStatus(grpcServer.MethodPrefix(), healthpb.HealthCheckResponse_SERVING)
if withGateway, ok := srv.(server.WithGateway); ok {
err := server.RegisterGateway(ctx, a.grpcGateway, withGateway)
if err != nil {
return err
}
}
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

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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")
}

View File

@@ -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 {

View File

@@ -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")
}

View File

@@ -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 {

View File

@@ -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

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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
}

View File

@@ -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 {

View File

@@ -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) {

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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, &notFoundError) {
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) {

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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) {

View File

@@ -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) {

View File

@@ -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) {

View File

@@ -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
}

View File

@@ -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 {

View File

@@ -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 {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -171,7 +171,7 @@ func CreateGateway(
}, nil
}
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)

View File

@@ -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,

View File

@@ -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) {

View File

@@ -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 {

View File

@@ -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) {

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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
}

View File

@@ -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 {

View File

@@ -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
}

View File

@@ -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 {

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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) {

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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
}

View File

@@ -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) {

View File

@@ -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 {

View File

@@ -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
}

View File

@@ -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 {

View File

@@ -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())
}
})
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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) {

View File

@@ -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
}

View File

@@ -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