From f6c262d67593ab10ace8513646e075331456bd2b Mon Sep 17 00:00:00 2001 From: Johan Siebens Date: Sat, 3 Feb 2024 12:07:54 +0100 Subject: [PATCH] feat: validate iam policy filters --- internal/service/iam.go | 4 ++++ internal/service/service.go | 13 +++++++++++++ internal/service/tailnet.go | 4 ++++ 3 files changed, 21 insertions(+) diff --git a/internal/service/iam.go b/internal/service/iam.go index edbbd33b..8d8258ab 100644 --- a/internal/service/iam.go +++ b/internal/service/iam.go @@ -46,6 +46,10 @@ func (s *Service) SetIAMPolicy(ctx context.Context, req *connect.Request[api.Set return nil, connect.NewError(connect.CodeNotFound, fmt.Errorf("tailnet does not exist")) } + if err := validateIamPolicy(req.Msg.Policy); err != nil { + return nil, connect.NewError(connect.CodeInvalidArgument, fmt.Errorf("invalid iam policy: %w", err)) + } + tailnet.IAMPolicy = domain.IAMPolicy{ Subs: req.Msg.Policy.Subs, Emails: req.Msg.Policy.Emails, diff --git a/internal/service/service.go b/internal/service/service.go index 26adb8b7..17d09099 100644 --- a/internal/service/service.go +++ b/internal/service/service.go @@ -2,7 +2,10 @@ package service import ( "context" + "fmt" "github.com/bufbuild/connect-go" + "github.com/hashicorp/go-bexpr/grammar" + "github.com/hashicorp/go-multierror" "github.com/jsiebens/ionscale/internal/auth" "github.com/jsiebens/ionscale/internal/config" "github.com/jsiebens/ionscale/internal/core" @@ -37,3 +40,13 @@ func (s *Service) GetVersion(_ context.Context, _ *connect.Request[api.GetVersio Revision: revision, }), nil } + +func validateIamPolicy(p *api.IAMPolicy) error { + var mErr *multierror.Error + for i, exp := range p.Filters { + if _, err := grammar.Parse(fmt.Sprintf("filter %d", i), []byte(exp)); err != nil { + mErr = multierror.Append(mErr, err) + } + } + return mErr.ErrorOrNil() +} diff --git a/internal/service/tailnet.go b/internal/service/tailnet.go index 7cefe29f..cc003651 100644 --- a/internal/service/tailnet.go +++ b/internal/service/tailnet.go @@ -42,6 +42,10 @@ func (s *Service) CreateTailnet(ctx context.Context, req *connect.Request[api.Cr return nil, connect.NewError(connect.CodePermissionDenied, fmt.Errorf("permission denied")) } + if err := validateIamPolicy(req.Msg.IamPolicy); err != nil { + return nil, connect.NewError(connect.CodeInvalidArgument, fmt.Errorf("invalid iam policy: %w", err)) + } + tailnet := &domain.Tailnet{ ID: util.NextID(), Name: req.Msg.Name,