feat(relational): command permission check (#10771)

# Which Problems Are Solved

There is no implementation of the permission framework in the new
command pattern. We risk forgetting permission options as we are already
migrating the service layer to the new pattern.

# How the Problems Are Solved

Use an permission checker interface, which will be a sub-interface of
the Permission Repository. The permission checker is passed in the
command executor and invoker as part of the command options. From here
the implementation can call the correct permission method.

This PR proposes a check method for each
[level](https://github.com/zitadel/zitadel/wiki/Internal-AuthZ#levels).

# Additional Changes

- none 

# Additional Context

- Draft design:
https://github.com/zitadel/zitadel/wiki/Internal-AuthZ#enforcement
- Related for queries: https://github.com/zitadel/zitadel/pull/10756
This commit is contained in:
Tim Möhlmann
2025-10-13 17:04:39 +02:00
committed by GitHub
parent 013620baab
commit fcb05fd561
2 changed files with 54 additions and 4 deletions
+6 -4
View File
@@ -28,8 +28,9 @@ type Invoker interface {
// CommandOpts are passed to each command
// it provides common fields used by commands like the database client.
type CommandOpts struct {
DB database.QueryExecutor
Invoker Invoker
DB database.QueryExecutor
Invoker Invoker
Permissions PermissionChecker
}
type ensureTxOpts struct {
@@ -101,8 +102,9 @@ func DefaultOpts(invoker Invoker) *CommandOpts {
invoker = &noopInvoker{}
}
return &CommandOpts{
DB: pool,
Invoker: invoker,
DB: pool,
Invoker: invoker,
Permissions: &noopPermissionChecker{}, // prevent panics for now
}
}
+48
View File
@@ -0,0 +1,48 @@
package domain
import "context"
// PermissionRepository is the interface that manages and checks Zitadel permissions.
//
// TODO(muhlemmer): This just defines the checker methods, rest to be done later.
type PermissionRepository interface {
PermissionChecker
}
// PermissionChecker defines the methods needed to check permissions.
type PermissionChecker interface {
// Check if the authenticated user has the given permission on instance level.
CheckInstancePermission(ctx context.Context, permission string) error
// Check if the authenticated user has the given permission on the given organization.
// A permission may be inherited from the instance level.
CheckOrganizationPermission(ctx context.Context, permission, orgID string) error
// Check if the authenticated user has the given permission on the given project.
// A permission may be inherited from the instance or organization level.
CheckProjectPermission(ctx context.Context, permission, projectID string) error
// Check if the authenticated user has the given permission on the given project grant.
// A permission may be inherited from the instance or granted organization level.
CheckProjectGrantPermission(ctx context.Context, permission, projectGrantID string) error
}
type noopPermissionChecker struct{}
var _ PermissionChecker = (*noopPermissionChecker)(nil)
func (*noopPermissionChecker) CheckInstancePermission(context.Context, string) error {
return nil
}
func (*noopPermissionChecker) CheckOrganizationPermission(context.Context, string, string) error {
return nil
}
func (*noopPermissionChecker) CheckProjectPermission(context.Context, string, string) error {
return nil
}
func (*noopPermissionChecker) CheckProjectGrantPermission(context.Context, string, string) error {
return nil
}