@@ -53,11 +53,12 @@ type Service struct {
5353 sf * singleflight.Group
5454
5555 // Cache for user permissions, user team memberships and user basic roles
56- idCache * cacheWrap [store.UserIdentifiers ]
57- permCache * cacheWrap [map [string ]bool ]
58- teamCache * cacheWrap [[]int64 ]
59- basicRoleCache * cacheWrap [store.BasicRole ]
60- folderCache * cacheWrap [folderTree ]
56+ idCache * cacheWrap [store.UserIdentifiers ]
57+ permCache * cacheWrap [map [string ]bool ]
58+ permDenialCache * cacheWrap [bool ]
59+ teamCache * cacheWrap [[]int64 ]
60+ basicRoleCache * cacheWrap [store.BasicRole ]
61+ folderCache * cacheWrap [folderTree ]
6162}
6263
6364func NewService (
@@ -81,6 +82,7 @@ func NewService(
8182 mapper : newMapper (),
8283 idCache : newCacheWrap [store.UserIdentifiers ](cache , logger , longCacheTTL ),
8384 permCache : newCacheWrap [map [string ]bool ](cache , logger , shortCacheTTL ),
85+ permDenialCache : newCacheWrap [bool ](cache , logger , shortCacheTTL ),
8486 teamCache : newCacheWrap [[]int64 ](cache , logger , shortCacheTTL ),
8587 basicRoleCache : newCacheWrap [store.BasicRole ](cache , logger , shortCacheTTL ),
8688 folderCache : newCacheWrap [folderTree ](cache , logger , shortCacheTTL ),
@@ -111,6 +113,29 @@ func (s *Service) Check(ctx context.Context, req *authzv1.CheckRequest) (*authzv
111113 attribute .String ("folder" , checkReq .ParentFolder ),
112114 )
113115
116+ permDenialKey := userPermDenialCacheKey (checkReq .Namespace .Value , checkReq .UserUID , checkReq .Action , checkReq .Name , checkReq .ParentFolder )
117+ if _ , ok := s .permDenialCache .Get (ctx , permDenialKey ); ok {
118+ s .metrics .permissionCacheUsage .WithLabelValues ("true" , checkReq .Action ).Inc ()
119+ s .metrics .requestCount .WithLabelValues ("false" , "true" , req .GetVerb (), req .GetGroup (), req .GetResource ()).Inc ()
120+ return & authzv1.CheckResponse {Allowed : false }, nil
121+ }
122+
123+ cachedPerms , err := s .getCachedIdentityPermissions (ctx , checkReq .Namespace , checkReq .IdentityType , checkReq .UserUID , checkReq .Action )
124+ if err == nil {
125+ allowed , err := s .checkPermission (ctx , cachedPerms , checkReq )
126+ if err != nil {
127+ ctxLogger .Error ("could not check permission" , "error" , err )
128+ s .metrics .requestCount .WithLabelValues ("true" , "true" , req .GetVerb (), req .GetGroup (), req .GetResource ()).Inc ()
129+ return deny , err
130+ }
131+ if allowed {
132+ s .metrics .permissionCacheUsage .WithLabelValues ("true" , checkReq .Action ).Inc ()
133+ s .metrics .requestCount .WithLabelValues ("false" , "true" , req .GetVerb (), req .GetGroup (), req .GetResource ()).Inc ()
134+ return & authzv1.CheckResponse {Allowed : allowed }, nil
135+ }
136+ }
137+ s .metrics .permissionCacheUsage .WithLabelValues ("false" , checkReq .Action ).Inc ()
138+
114139 permissions , err := s .getIdentityPermissions (ctx , checkReq .Namespace , checkReq .IdentityType , checkReq .UserUID , checkReq .Action )
115140 if err != nil {
116141 ctxLogger .Error ("could not get user permissions" , "subject" , req .GetSubject (), "error" , err )
@@ -125,6 +150,10 @@ func (s *Service) Check(ctx context.Context, req *authzv1.CheckRequest) (*authzv
125150 return deny , err
126151 }
127152
153+ if ! allowed {
154+ s .permDenialCache .Set (ctx , permDenialKey , true )
155+ }
156+
128157 s .metrics .requestCount .WithLabelValues ("false" , "true" , req .GetVerb (), req .GetGroup (), req .GetResource ()).Inc ()
129158 return & authzv1.CheckResponse {Allowed : allowed }, nil
130159}
@@ -148,11 +177,18 @@ func (s *Service) List(ctx context.Context, req *authzv1.ListRequest) (*authzv1.
148177 attribute .String ("action" , listReq .Action ),
149178 )
150179
151- permissions , err := s .getIdentityPermissions (ctx , listReq .Namespace , listReq .IdentityType , listReq .UserUID , listReq .Action )
152- if err != nil {
153- ctxLogger .Error ("could not get user permissions" , "subject" , req .GetSubject (), "error" , err )
154- s .metrics .requestCount .WithLabelValues ("true" , "true" , req .GetVerb (), req .GetGroup (), req .GetResource ()).Inc ()
155- return nil , err
180+ permissions , err := s .getCachedIdentityPermissions (ctx , listReq .Namespace , listReq .IdentityType , listReq .UserUID , listReq .Action )
181+ if err == nil {
182+ s .metrics .permissionCacheUsage .WithLabelValues ("true" , listReq .Action ).Inc ()
183+ } else {
184+ s .metrics .permissionCacheUsage .WithLabelValues ("false" , listReq .Action ).Inc ()
185+
186+ permissions , err = s .getIdentityPermissions (ctx , listReq .Namespace , listReq .IdentityType , listReq .UserUID , listReq .Action )
187+ if err != nil {
188+ ctxLogger .Error ("could not get user permissions" , "subject" , req .GetSubject (), "error" , err )
189+ s .metrics .requestCount .WithLabelValues ("true" , "true" , req .GetVerb (), req .GetGroup (), req .GetResource ()).Inc ()
190+ return nil , err
191+ }
156192 }
157193
158194 resp , err := s .listPermission (ctx , permissions , listReq )
@@ -303,6 +339,34 @@ func (s *Service) getIdentityPermissions(ctx context.Context, ns types.Namespace
303339 }
304340}
305341
342+ func (s * Service ) getCachedIdentityPermissions (ctx context.Context , ns types.NamespaceInfo , idType types.IdentityType , userID , action string ) (map [string ]bool , error ) {
343+ ctx , span := s .tracer .Start (ctx , "authz_direct_db.service.getCachedIdentityPermissions" )
344+ defer span .End ()
345+
346+ switch idType {
347+ case types .TypeAnonymous :
348+ anonPermKey := anonymousPermCacheKey (ns .Value , action )
349+ if cached , ok := s .permCache .Get (ctx , anonPermKey ); ok {
350+ return cached , nil
351+ }
352+ return nil , cache .ErrNotFound
353+ case types .TypeRenderService :
354+ return nil , cache .ErrNotFound
355+ case types .TypeUser , types .TypeServiceAccount :
356+ userIdentifiers , err := s .GetUserIdentifiers (ctx , ns , userID )
357+ if err != nil {
358+ return nil , err
359+ }
360+ userPermKey := userPermCacheKey (ns .Value , userIdentifiers .UID , action )
361+ if cached , ok := s .permCache .Get (ctx , userPermKey ); ok {
362+ return cached , nil
363+ }
364+ return nil , cache .ErrNotFound
365+ default :
366+ return nil , fmt .Errorf ("unsupported identity type: %s" , idType )
367+ }
368+ }
369+
306370func (s * Service ) getUserPermissions (ctx context.Context , ns types.NamespaceInfo , userID , action string , actionSets []string ) (map [string ]bool , error ) {
307371 ctx , span := s .tracer .Start (ctx , "authz_direct_db.service.getUserPermissions" )
308372 defer span .End ()
@@ -313,12 +377,6 @@ func (s *Service) getUserPermissions(ctx context.Context, ns types.NamespaceInfo
313377 }
314378
315379 userPermKey := userPermCacheKey (ns .Value , userIdentifiers .UID , action )
316- if cached , ok := s .permCache .Get (ctx , userPermKey ); ok {
317- s .metrics .permissionCacheUsage .WithLabelValues ("true" , action ).Inc ()
318- return cached , nil
319- }
320- s .metrics .permissionCacheUsage .WithLabelValues ("false" , action ).Inc ()
321-
322380 res , err , _ := s .sf .Do (userPermKey + "_getUserPermissions" , func () (interface {}, error ) {
323381 basicRoles , err := s .getUserBasicRole (ctx , ns , userIdentifiers )
324382 if err != nil {
@@ -363,9 +421,6 @@ func (s *Service) getAnonymousPermissions(ctx context.Context, ns types.Namespac
363421 defer span .End ()
364422
365423 anonPermKey := anonymousPermCacheKey (ns .Value , action )
366- if cached , ok := s .permCache .Get (ctx , anonPermKey ); ok {
367- return cached , nil
368- }
369424 res , err , _ := s .sf .Do (anonPermKey + "_getAnonymousPermissions" , func () (interface {}, error ) {
370425 permissions , err := s .permissionStore .GetUserPermissions (ctx , ns , store.PermissionsQuery {Action : action , ActionSets : actionSets , Role : "Viewer" })
371426 if err != nil {
0 commit comments