@@ -16,6 +16,8 @@ type AuthzCache interface {
1616 CreateFGARelations (ctx context.Context , relations []* descope.FGARelation ) error
1717 DeleteFGARelations (ctx context.Context , relations []* descope.FGARelation ) error
1818 Check (ctx context.Context , relations []* descope.FGARelation ) ([]* descope.FGACheck , error )
19+ WhoCanAccess (ctx context.Context , resource , relationDefinition , namespace string ) ([]string , error )
20+ WhatCanTargetAccess (ctx context.Context , target string ) ([]* descope.AuthzRelation , error )
1921}
2022
2123type RemoteClientCreator func (projectID string , logger logger.LoggerInterface ) (sdk.Management , error )
@@ -140,26 +142,119 @@ func (a *authzCache) Check(ctx context.Context, relations []*descope.FGARelation
140142 return result , nil
141143}
142144
145+ func (a * authzCache ) WhoCanAccess (ctx context.Context , resource , relationDefinition , namespace string ) ([]string , error ) {
146+ projectCache , mgmtSDK , err := a .getOrCreateProjectCache (ctx )
147+ if err != nil {
148+ return nil , err // notest
149+ }
150+ candidates , cacheHit := projectCache .GetWhoCanAccessCached (ctx , resource , relationDefinition , namespace )
151+ if cacheHit && len (candidates ) > 0 {
152+ verified , err := a .filterWhoCanAccessCandidates (ctx , resource , relationDefinition , namespace , candidates )
153+ if err != nil {
154+ return nil , err // notest
155+ }
156+ cctx .Logger (ctx ).Debug ().
157+ Str ("resource" , resource ).
158+ Int ("candidates" , len (candidates )).
159+ Int ("verified" , len (verified )).
160+ Msg ("WhoCanAccess cache hit with candidate filtering" )
161+ return verified , nil
162+ }
163+ targets , err := mgmtSDK .Authz ().WhoCanAccess (ctx , resource , relationDefinition , namespace )
164+ if err != nil {
165+ return nil , err // notest
166+ }
167+ projectCache .SetWhoCanAccessCached (ctx , resource , relationDefinition , namespace , targets )
168+ return targets , nil
169+ }
170+
171+ func (a * authzCache ) filterWhoCanAccessCandidates (ctx context.Context , resource , relationDefinition , namespace string , candidates []string ) ([]string , error ) {
172+ relations := make ([]* descope.FGARelation , len (candidates ))
173+ for i , target := range candidates {
174+ relations [i ] = & descope.FGARelation {
175+ Resource : resource ,
176+ ResourceType : namespace ,
177+ Relation : relationDefinition ,
178+ Target : target ,
179+ }
180+ }
181+ checks , err := a .Check (ctx , relations )
182+ if err != nil {
183+ return nil , err
184+ }
185+ var verified []string
186+ for i , check := range checks {
187+ if check .Allowed {
188+ verified = append (verified , candidates [i ])
189+ }
190+ }
191+ return verified , nil
192+ }
193+
194+ func (a * authzCache ) WhatCanTargetAccess (ctx context.Context , target string ) ([]* descope.AuthzRelation , error ) {
195+ projectCache , mgmtSDK , err := a .getOrCreateProjectCache (ctx )
196+ if err != nil {
197+ return nil , err // notest
198+ }
199+ candidates , cacheHit := projectCache .GetWhatCanTargetAccessCached (ctx , target )
200+ if cacheHit && len (candidates ) > 0 {
201+ verified , err := a .filterWhatCanTargetAccessCandidates (ctx , target , candidates )
202+ if err != nil {
203+ return nil , err // notest
204+ }
205+ cctx .Logger (ctx ).Debug ().
206+ Str ("target" , target ).
207+ Int ("candidates" , len (candidates )).
208+ Int ("verified" , len (verified )).
209+ Msg ("WhatCanTargetAccess cache hit with candidate filtering" )
210+ return verified , nil
211+ }
212+ relations , err := mgmtSDK .Authz ().WhatCanTargetAccess (ctx , target )
213+ if err != nil {
214+ return nil , err // notest
215+ }
216+ projectCache .SetWhatCanTargetAccessCached (ctx , target , relations )
217+ return relations , nil
218+ }
219+
220+ func (a * authzCache ) filterWhatCanTargetAccessCandidates (ctx context.Context , target string , candidates []* descope.AuthzRelation ) ([]* descope.AuthzRelation , error ) {
221+ relations := make ([]* descope.FGARelation , len (candidates ))
222+ for i , r := range candidates {
223+ relations [i ] = & descope.FGARelation {
224+ Resource : r .Resource ,
225+ ResourceType : r .Namespace ,
226+ Relation : r .RelationDefinition ,
227+ Target : target ,
228+ }
229+ }
230+ checks , err := a .Check (ctx , relations )
231+ if err != nil {
232+ return nil , err
233+ }
234+ var verified []* descope.AuthzRelation
235+ for i , check := range checks {
236+ if check .Allowed {
237+ verified = append (verified , candidates [i ])
238+ }
239+ }
240+ return verified , nil
241+ }
242+
143243func (a * authzCache ) getOrCreateProjectCache (ctx context.Context ) (caches.ProjectAuthzCache , sdk.Management , error ) {
144244 projectID := cctx .ProjectID (ctx )
145245 if p , ok := a .projects .Load (projectID ); ok {
146246 return p .(project ).cache , p .(project ).mgmtSDK , nil
147247 }
148248 cctx .Logger (ctx ).Info ().Msg ("Creating new project cache" )
149- // create project mgmt sdk
150249 projectMgmtSDK , err := a .remoteClientCreator (projectID , cctx .Logger (ctx ))
151250 if err != nil {
152251 return nil , nil , err // notest
153252 }
154- // create project cache
155253 projectCache , err := a .projectCacheCreator (ctx , projectMgmtSDK .Authz ())
156254 if err != nil {
157255 return nil , nil , err // notest
158256 }
159- // start remote changes polling
160257 projectCache .StartRemoteChangesPolling (ctx )
161- // save cache and sdk
162258 a .projects .Store (projectID , project {cache : projectCache , mgmtSDK : projectMgmtSDK })
163- // return cache and sdk
164259 return projectCache , projectMgmtSDK , nil
165260}
0 commit comments