Files
ocdp-go/backend/internal/pkg/authz/authz.go
Ivan087 7f238a3168 refactor: full-stack restructure with multi-tenancy, workspace management, and K8s diagnostics
- Add Workspace domain (entity, repository, service, handler, DTO)
- Add multi-tenant K8s client with tenant binding and quota management
- Add K8s diagnostics client (instance diagnostics)
- Add authorization middleware (authz package)
- Restructure frontend to feature-based architecture (features/)
- Add User Management page in configuration
- Add AccessDenied page and route guards
- Refactor shared components (form inputs, layout, UI)
- Update Tailwind config for new design system
- Add comprehensive documentation (docs/, tasks/, plans)
- Improve cluster service with better kubeconfig handling
- Add tests for crypto, config, helm client, tenant binding
2026-05-12 16:15:14 +08:00

145 lines
3.1 KiB
Go

package authz
import (
"context"
"errors"
)
type contextKey string
const principalKey contextKey = "principal"
const (
RoleAdmin = "admin"
RoleUser = "user"
)
const (
VisibilityPrivate = "private"
VisibilityWorkspaceShared = "workspace_shared"
VisibilityGlobalShared = "global_shared"
)
var (
ErrUnauthenticated = errors.New("authentication required")
ErrForbidden = errors.New("permission denied")
)
type Principal struct {
UserID string
Username string
Role string
WorkspaceID string
WorkspaceName string
Namespace string
DefaultClusterID string
QuotaCPU string
QuotaMemory string
QuotaGPU string
QuotaGPUMem string
Permissions []string
PermissionVersion int
}
func WithPrincipal(ctx context.Context, principal *Principal) context.Context {
return context.WithValue(ctx, principalKey, principal)
}
func PrincipalFromContext(ctx context.Context) (*Principal, bool) {
principal, ok := ctx.Value(principalKey).(*Principal)
return principal, ok && principal != nil
}
func RequirePrincipal(ctx context.Context) (*Principal, error) {
principal, ok := PrincipalFromContext(ctx)
if !ok {
return nil, ErrUnauthenticated
}
return principal, nil
}
func (p *Principal) IsAdmin() bool {
return p != nil && p.Role == RoleAdmin
}
func CanReadResource(p *Principal, workspaceID, ownerID, visibility string) bool {
if p == nil {
return false
}
if p.IsAdmin() {
return true
}
switch visibility {
case VisibilityGlobalShared:
return true
case VisibilityWorkspaceShared:
return workspaceID != "" && workspaceID == p.WorkspaceID
default:
return ownerID != "" && ownerID == p.UserID
}
}
func CanWriteResource(p *Principal, workspaceID, ownerID, visibility string) bool {
if p == nil {
return false
}
if p.IsAdmin() {
return true
}
if visibility == VisibilityGlobalShared {
return false
}
return workspaceID != "" && workspaceID == p.WorkspaceID && ownerID != "" && ownerID == p.UserID
}
func NormalizeVisibility(role, requested string) string {
switch requested {
case VisibilityWorkspaceShared:
if role == RoleAdmin {
return requested
}
return VisibilityPrivate
case VisibilityGlobalShared:
if role == RoleAdmin {
return requested
}
return VisibilityPrivate
case VisibilityPrivate:
return requested
default:
return VisibilityPrivate
}
}
func PermissionsForRole(role string) []string {
if role == RoleAdmin {
return []string{
"*",
"home:view",
"workspaces:manage",
"users:manage",
"configuration:clusters:manage",
"configuration:registries:manage",
"artifact:registries:view",
"artifact:instances:manage",
"monitoring:clusters:view",
"clusters:manage:any",
"registries:manage:any",
"instances:manage:any",
"kubeconfig:issue:any",
}
}
return []string{
"home:view",
"configuration:clusters:manage_own",
"configuration:registries:manage_own",
"artifact:registries:view",
"artifact:instances:manage_own",
"monitoring:clusters:view",
"clusters:manage:own",
"registries:manage:own",
"instances:manage:own",
"kubeconfig:issue:own",
}
}