@@ -7,9 +7,13 @@ import (
77 apierrors "k8s.io/apimachinery/pkg/api/errors"
88 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
99
10+ "github.com/google/uuid"
11+
12+ authlib "github.com/grafana/authlib/types"
1013 "github.com/grafana/grafana-app-sdk/logging"
1114 "github.com/grafana/grafana/pkg/apimachinery/apis/common/v0alpha1"
1215 "github.com/grafana/grafana/pkg/apimachinery/identity"
16+ "github.com/grafana/grafana/pkg/apimachinery/utils"
1317 provisioning "github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1"
1418 "github.com/grafana/grafana/pkg/registry/apis/provisioning/repository"
1519 "github.com/grafana/grafana/pkg/registry/apis/provisioning/safepath"
@@ -21,10 +25,11 @@ type DualReadWriter struct {
2125 repo repository.ReaderWriter
2226 parser Parser
2327 folders * FolderManager
28+ access authlib.AccessChecker
2429}
2530
26- func NewDualReadWriter (repo repository.ReaderWriter , parser Parser , folders * FolderManager ) * DualReadWriter {
27- return & DualReadWriter {repo : repo , parser : parser , folders : folders }
31+ func NewDualReadWriter (repo repository.ReaderWriter , parser Parser , folders * FolderManager , access authlib. AccessChecker ) * DualReadWriter {
32+ return & DualReadWriter {repo : repo , parser : parser , folders : folders , access : access }
2833}
2934
3035func (r * DualReadWriter ) Read (ctx context.Context , path string , ref string ) (* ParsedResource , error ) {
@@ -43,6 +48,11 @@ func (r *DualReadWriter) Read(ctx context.Context, path string, ref string) (*Pa
4348 return nil , fmt .Errorf ("parse file: %w" , err )
4449 }
4550
51+ // Authorize the parsed resource
52+ if err = r .authorize (ctx , parsed , utils .VerbGet ); err != nil {
53+ return nil , err
54+ }
55+
4656 // Fail as we use the dry run for this response and it's not about updating the resource
4757 if err := parsed .DryRun (ctx ); err != nil {
4858 return nil , fmt .Errorf ("run dry run: %w" , err )
@@ -73,6 +83,10 @@ func (r *DualReadWriter) Delete(ctx context.Context, path string, ref string, me
7383 return nil , fmt .Errorf ("parse file: %w" , err )
7484 }
7585
86+ if err = r .authorize (ctx , parsed , utils .VerbDelete ); err != nil {
87+ return nil , err
88+ }
89+
7690 parsed .Action = provisioning .ResourceActionDelete
7791 err = r .repo .Delete (ctx , path , ref , message )
7892 if err != nil {
@@ -112,6 +126,10 @@ func (r *DualReadWriter) CreateFolder(ctx context.Context, path string, ref stri
112126 return nil , fmt .Errorf ("not a folder path" )
113127 }
114128
129+ if err := r .authorizeCreateFolder (ctx , path ); err != nil {
130+ return nil , err
131+ }
132+
115133 // Now actually create the folder
116134 if err := r .repo .Create (ctx , path , ref , nil , message ); err != nil {
117135 return nil , fmt .Errorf ("failed to create folder: %w" , err )
@@ -167,6 +185,10 @@ func (r *DualReadWriter) CreateResource(ctx context.Context, path string, ref st
167185 return nil , fmt .Errorf ("parse file: %w" , err )
168186 }
169187
188+ if err = r .authorize (ctx , parsed , utils .VerbCreate ); err != nil {
189+ return nil , err
190+ }
191+
170192 data , err = parsed .ToSaveBytes ()
171193 if err != nil {
172194 return nil , err
@@ -218,6 +240,10 @@ func (r *DualReadWriter) UpdateResource(ctx context.Context, path string, ref st
218240 return nil , fmt .Errorf ("parse file: %w" , err )
219241 }
220242
243+ if err = r .authorize (ctx , parsed , utils .VerbUpdate ); err != nil {
244+ return nil , err
245+ }
246+
221247 data , err = parsed .ToSaveBytes ()
222248 if err != nil {
223249 return nil , err
@@ -250,3 +276,51 @@ func (r *DualReadWriter) UpdateResource(ctx context.Context, path string, ref st
250276
251277 return parsed , nil
252278}
279+
280+ func (r * DualReadWriter ) authorize (ctx context.Context , parsed * ParsedResource , verb string ) error {
281+ auth , ok := authlib .AuthInfoFrom (ctx )
282+ if ! ok {
283+ return fmt .Errorf ("missing auth info in context" )
284+ }
285+ rsp , err := r .access .Check (ctx , auth , authlib.CheckRequest {
286+ Group : parsed .GVR .Group ,
287+ Resource : parsed .GVR .Resource ,
288+ Namespace : parsed .Obj .GetNamespace (),
289+ Name : parsed .Obj .GetName (),
290+ Folder : parsed .Meta .GetFolder (),
291+ Verb : verb ,
292+ })
293+ if err != nil {
294+ return err
295+ }
296+ if ! rsp .Allowed {
297+ return apierrors .NewForbidden (parsed .GVR .GroupResource (), parsed .Obj .GetName (),
298+ fmt .Errorf ("no access to see embedded file" ))
299+ }
300+ return nil
301+ }
302+
303+ func (r * DualReadWriter ) authorizeCreateFolder (ctx context.Context , _ string ) error {
304+ auth , ok := authlib .AuthInfoFrom (ctx )
305+ if ! ok {
306+ return fmt .Errorf ("missing auth info in context" )
307+ }
308+ rsp , err := r .access .Check (ctx , auth , authlib.CheckRequest {
309+ Group : FolderResource .Group ,
310+ Resource : FolderResource .Resource ,
311+ Namespace : r .repo .Config ().GetNamespace (),
312+ Verb : utils .VerbCreate ,
313+
314+ // TODO: Currently this checks if you can create a new folder in root
315+ // Ideally we should check the path and use the explicit parent and new id
316+ Name : "f" + uuid .NewString (),
317+ })
318+ if err != nil {
319+ return err
320+ }
321+ if ! rsp .Allowed {
322+ return apierrors .NewForbidden (FolderResource .GroupResource (), "" ,
323+ fmt .Errorf ("unable to create folder resource" ))
324+ }
325+ return nil
326+ }
0 commit comments