@@ -200,20 +200,21 @@ func (as *AuthorizationService) GetDecisions(ctx context.Context, req *connect.R
200200}
201201
202202func (as * AuthorizationService ) getDecisions (ctx context.Context , dr * authorization.DecisionRequest ) ([]* authorization.DecisionResponse , error ) {
203- var attrDefsReqs [][]* policy.Attribute
204- var attrValsReqs [][]* policy.Value
205- var fqnsReqs [][]string
206203 allPertinentFQNS := & authorization.ResourceAttribute {AttributeValueFqns : make ([]string , 0 )}
207204 response := make ([]* authorization.DecisionResponse , len (dr .GetResourceAttributes ())* len (dr .GetEntityChains ()))
208- for raIdx , ra := range dr .GetResourceAttributes () {
209- as .logger .DebugContext (ctx , "getting resource attributes" , slog .String ("FQNs" , strings .Join (ra .GetAttributeValueFqns (), ", " )))
210205
211- // get attribute definition/value combinations
212- dataAttrDefsAndVals , err := retrieveAttributeDefinitions (ctx , ra , as .sdk )
213- if err != nil {
214- // if attribute an FQN does not exist
215- // return deny for all entity chains aginst this RA set and continue to next
216- if errors .Is (err , status .Error (codes .NotFound , db .ErrTextNotFound )) || errors .Is (err , ErrEmptyStringAttribute ) {
206+ // TODO: fetching missing FQNs should not lead into a complete failure, rather a list of unknown FQNs would be preferred
207+ var err error
208+ var dataAttrDefsAndVals map [string ]* attr.GetAttributeValuesByFqnsResponse_AttributeAndValue
209+ allPertinentFQNS .AttributeValueFqns , err = getAttributesFromRas (dr .GetResourceAttributes ())
210+ if err == nil {
211+ dataAttrDefsAndVals , err = retrieveAttributeDefinitions (ctx , allPertinentFQNS .GetAttributeValueFqns (), as .sdk )
212+ }
213+ if err != nil {
214+ // if attribute an FQN does not exist
215+ // return deny for all entity chains aginst this RAs
216+ if errors .Is (err , status .Error (codes .NotFound , db .ErrTextNotFound )) || errors .Is (err , ErrEmptyStringAttribute ) {
217+ for raIdx , ra := range dr .GetResourceAttributes () {
217218 for ecIdx , ec := range dr .GetEntityChains () {
218219 decisionResp := & authorization.DecisionResponse {
219220 Decision : authorization .DecisionResponse_DECISION_DENY ,
@@ -231,45 +232,28 @@ func (as *AuthorizationService) getDecisions(ctx context.Context, dr *authorizat
231232 }
232233 responseIdx := (raIdx * len (dr .GetEntityChains ())) + ecIdx
233234 response [responseIdx ] = decisionResp
234- // append empty values to keep the order of the requests
235- attrDefsReqs = append (attrDefsReqs , []* policy.Attribute {})
236- attrValsReqs = append (attrValsReqs , []* policy.Value {})
237- fqnsReqs = append (fqnsReqs , []string {})
238235 }
239- continue
240236 }
241- return nil , db . StatusifyError ( err , db . ErrTextGetRetrievalFailed , slog . String ( "fqns" , strings . Join ( ra . GetAttributeValueFqns (), ", " )))
237+ return response , nil
242238 }
239+ return nil , db .StatusifyError (err , db .ErrTextGetRetrievalFailed , slog .String ("fqns" , strings .Join (allPertinentFQNS .GetAttributeValueFqns (), ", " )))
240+ }
243241
244- var attrDefs []* policy.Attribute
245- var attrVals []* policy.Value
246- var fqns []string
247-
248- for fqn , v := range dataAttrDefsAndVals {
249- attrDefs = append (attrDefs , v .GetAttribute ())
250- attrVal := v .GetValue ()
251- fqns = append (fqns , fqn )
252- attrVal .Fqn = fqn
253- attrVals = append (attrVals , attrVal )
254- }
255-
256- attrDefs , err = populateAttrDefValueFqns (attrDefs )
257- if err != nil {
258- return nil , connect .NewError (connect .CodeInternal , err )
259- }
260- allPertinentFQNS .AttributeValueFqns = append (allPertinentFQNS .GetAttributeValueFqns (), ra .GetAttributeValueFqns ()... )
261-
262- // get the relevant resource attribute fqns
263- for _ , attrDef := range attrDefs {
264- if attrDef .GetRule () == policy .AttributeRuleTypeEnum_ATTRIBUTE_RULE_TYPE_ENUM_HIERARCHY {
265- for _ , value := range attrDef .GetValues () {
266- allPertinentFQNS .AttributeValueFqns = append (allPertinentFQNS .AttributeValueFqns , value .GetFqn ())
267- }
242+ var allAttrDefs []* policy.Attribute
243+ for _ , v := range dataAttrDefsAndVals {
244+ allAttrDefs = append (allAttrDefs , v .GetAttribute ())
245+ }
246+ allAttrDefs , err = populateAttrDefValueFqns (allAttrDefs )
247+ if err != nil {
248+ return nil , connect .NewError (connect .CodeInternal , err )
249+ }
250+ // get the relevant resource attribute fqns
251+ for _ , attrDef := range allAttrDefs {
252+ if attrDef .GetRule () == policy .AttributeRuleTypeEnum_ATTRIBUTE_RULE_TYPE_ENUM_HIERARCHY {
253+ for _ , value := range attrDef .GetValues () {
254+ allPertinentFQNS .AttributeValueFqns = append (allPertinentFQNS .AttributeValueFqns , value .GetFqn ())
268255 }
269256 }
270- attrDefsReqs = append (attrDefsReqs , attrDefs )
271- attrValsReqs = append (attrValsReqs , attrVals )
272- fqnsReqs = append (fqnsReqs , fqns )
273257 }
274258
275259 var ecChainEntitlementsResponse []* connect.Response [authorization.GetEntitlementsResponse ]
@@ -294,15 +278,31 @@ func (as *AuthorizationService) getDecisions(ctx context.Context, dr *authorizat
294278 }
295279
296280 for raIdx , ra := range dr .GetResourceAttributes () {
281+ var attrDefs []* policy.Attribute
282+ var attrVals []* policy.Value
283+ var fqns []string
284+
285+ for _ , fqn := range ra .GetAttributeValueFqns () {
286+ fqn = strings .ToLower (fqn )
287+ fqns = append (fqns , fqn )
288+ v := dataAttrDefsAndVals [fqn ]
289+ attrDefs = append (attrDefs , v .GetAttribute ())
290+ attrVal := v .GetValue ()
291+ attrVal .Fqn = fqn
292+ attrVals = append (attrVals , attrVal )
293+ }
294+
295+ attrDefs , err = populateAttrDefValueFqns (attrDefs )
296+ if err != nil {
297+ return nil , connect .NewError (connect .CodeInternal , err )
298+ }
299+
297300 for ecIdx , ec := range dr .GetEntityChains () {
298301 // check if we already have a decision for this entity chain
299302 responseIdx := (raIdx * len (dr .GetEntityChains ())) + ecIdx
300303 if response [responseIdx ] != nil {
301304 continue
302305 }
303- attrVals := attrValsReqs [raIdx ]
304- attrDefs := attrDefsReqs [raIdx ]
305- fqns := fqnsReqs [raIdx ]
306306
307307 //
308308 // TODO: we should already have the subject mappings here and be able to just use OPA to trim down the known data attr values to the ones matched up with the entities
@@ -651,27 +651,36 @@ func (as *AuthorizationService) GetEntitlements(ctx context.Context, req *connec
651651 return resp , nil
652652}
653653
654- func retrieveAttributeDefinitions (ctx context.Context , ra * authorization.ResourceAttribute , sdk * otdf.SDK ) (map [string ]* attr.GetAttributeValuesByFqnsResponse_AttributeAndValue , error ) {
655- attrFqns := ra .GetAttributeValueFqns ()
656- if len (attrFqns ) == 0 {
657- return make (map [string ]* attr.GetAttributeValuesByFqnsResponse_AttributeAndValue ), nil
658- }
659- // remove empty strings
660- attrFqnsNoEmpty := attrFqns [:0 ] // Use the same backing array to avoid allocation
661- for _ , str := range attrFqns {
662- if str != "" {
663- attrFqnsNoEmpty = append (attrFqnsNoEmpty , str )
654+ func getAttributesFromRas (ras []* authorization.ResourceAttribute ) ([]string , error ) {
655+ var attrFqns []string
656+ repeats := make (map [string ]bool )
657+ moreThanOneAttr := false
658+ for _ , ra := range ras {
659+ for _ , str := range ra .GetAttributeValueFqns () {
660+ moreThanOneAttr = true
661+ if str != "" && ! repeats [str ] {
662+ attrFqns = append (attrFqns , str )
663+ repeats [str ] = true
664+ }
664665 }
665666 }
666- // if no attribute value FQNs after removal, return error
667- if len (attrFqnsNoEmpty ) == 0 {
667+
668+ if moreThanOneAttr && len (attrFqns ) == 0 {
668669 return nil , ErrEmptyStringAttribute
669670 }
671+ return attrFqns , nil
672+ }
673+
674+ func retrieveAttributeDefinitions (ctx context.Context , attrFqns []string , sdk * otdf.SDK ) (map [string ]* attr.GetAttributeValuesByFqnsResponse_AttributeAndValue , error ) {
675+ if len (attrFqns ) == 0 {
676+ return make (map [string ]* attr.GetAttributeValuesByFqnsResponse_AttributeAndValue ), nil
677+ }
678+
670679 resp , err := sdk .Attributes .GetAttributeValuesByFqns (ctx , & attr.GetAttributeValuesByFqnsRequest {
671680 WithValue : & policy.AttributeValueSelector {
672681 WithSubjectMaps : false ,
673682 },
674- Fqns : attrFqnsNoEmpty ,
683+ Fqns : attrFqns ,
675684 })
676685 if err != nil {
677686 return nil , err
0 commit comments