@@ -57,6 +57,10 @@ type mySubjectMappingClient struct {
5757 sm.SubjectMappingServiceClient
5858}
5959
60+ type paginatedMockSubjectMappingClient struct {
61+ sm.SubjectMappingServiceClient
62+ }
63+
6064func (* mySubjectMappingClient ) ListSubjectMappings (_ context.Context , _ * sm.ListSubjectMappingsRequest , _ ... grpc.CallOption ) (* sm.ListSubjectMappingsResponse , error ) {
6165 return & listSubjectMappings , nil
6266}
@@ -69,6 +73,52 @@ func (*myERSClient) ResolveEntities(_ context.Context, _ *entityresolution.Resol
6973 return & resolveEntitiesResp , nil
7074}
7175
76+ var (
77+ smPaginationOffset = 3
78+ smListCallCount = 0
79+ )
80+
81+ func (* paginatedMockSubjectMappingClient ) ListSubjectMappings (_ context.Context , _ * sm.ListSubjectMappingsRequest , _ ... grpc.CallOption ) (* sm.ListSubjectMappingsResponse , error ) {
82+ smListCallCount ++
83+ // simulate paginated list and policy LIST behavior
84+ if smPaginationOffset > 0 {
85+ rsp := & sm.ListSubjectMappingsResponse {
86+ SubjectMappings : nil ,
87+ Pagination : & policy.PageResponse {
88+ NextOffset : int32 (smPaginationOffset ),
89+ },
90+ }
91+ smPaginationOffset = 0
92+ return rsp , nil
93+ }
94+ return & listSubjectMappings , nil
95+ }
96+
97+ type paginatedMockAttributesClient struct {
98+ attr.AttributesServiceClient
99+ }
100+
101+ var (
102+ attrPaginationOffset = 3
103+ attrListCallCount = 0
104+ )
105+
106+ func (* paginatedMockAttributesClient ) ListAttributes (_ context.Context , _ * attr.ListAttributesRequest , _ ... grpc.CallOption ) (* attr.ListAttributesResponse , error ) {
107+ attrListCallCount ++
108+ // simulate paginated list and policy LIST behavior
109+ if attrPaginationOffset > 0 {
110+ rsp := & attr.ListAttributesResponse {
111+ Attributes : nil ,
112+ Pagination : & policy.PageResponse {
113+ NextOffset : int32 (attrPaginationOffset ),
114+ },
115+ }
116+ attrPaginationOffset = 0
117+ return rsp , nil
118+ }
119+ return & listAttributeResp , nil
120+ }
121+
72122func TestGetComprehensiveHierarchy (t * testing.T ) {
73123 as := & AuthorizationService {
74124 logger : logger .CreateTestLogger (),
@@ -763,6 +813,91 @@ func Test_GetEntitlementsFqnCasing(t *testing.T) {
763813 assert .Equal (t , []string {"https://www.example.org/attr/foo/value/value1" }, resp .Msg .GetEntitlements ()[0 ].GetAttributeValueFqns ())
764814}
765815
816+ func Test_GetEntitlements_HandlesPagination (t * testing.T ) {
817+ logger := logger .CreateTestLogger ()
818+
819+ listAttributeResp = attr.ListAttributesResponse {}
820+ attrDef := policy.Attribute {
821+ Name : mockAttrName ,
822+ Namespace : & policy.Namespace {
823+ Name : mockNamespace ,
824+ },
825+ Rule : policy .AttributeRuleTypeEnum_ATTRIBUTE_RULE_TYPE_ENUM_ALL_OF ,
826+ Values : []* policy.Value {
827+ {
828+ Value : mockAttrValue1 ,
829+ },
830+ {
831+ Value : mockAttrValue2 ,
832+ },
833+ },
834+ }
835+ listAttributeResp .Attributes = []* policy.Attribute {& attrDef }
836+ userRepresentation := map [string ]interface {}{
837+ "A" : "B" ,
838+ "C" : "D" ,
839+ }
840+ userStruct , _ := structpb .NewStruct (userRepresentation )
841+ resolveEntitiesResp = entityresolution.ResolveEntitiesResponse {
842+ EntityRepresentations : []* entityresolution.EntityRepresentation {
843+ {
844+ OriginalId : "e1" ,
845+ AdditionalProps : []* structpb.Struct {
846+ userStruct ,
847+ },
848+ },
849+ },
850+ }
851+
852+ ctxb := context .Background ()
853+
854+ rego := rego .New (
855+ rego .Query ("data.example.p" ),
856+ rego .Module ("example.rego" ,
857+ `package example
858+ p = {"e1":["https://www.example.org/attr/foo/value/value1"]} { true }` ,
859+ ))
860+
861+ // Run evaluation.
862+ prepared , err := rego .PrepareForEval (ctxb )
863+ require .NoError (t , err )
864+
865+ as := AuthorizationService {
866+ logger : logger , sdk : & otdf.SDK {
867+ SubjectMapping : & paginatedMockSubjectMappingClient {},
868+ Attributes : & paginatedMockAttributesClient {},
869+ EntityResoution : & myERSClient {},
870+ },
871+ eval : prepared ,
872+ }
873+
874+ req := connect.Request [authorization.GetEntitlementsRequest ]{
875+ Msg : & authorization.GetEntitlementsRequest {
876+ Entities : []* authorization.Entity {{Id : "e1" , EntityType : & authorization.Entity_ClientId {ClientId : "testclient" }, Category : authorization .Entity_CATEGORY_ENVIRONMENT }},
877+ // Using mixed case here
878+ Scope : & authorization.ResourceAttribute {AttributeValueFqns : []string {"https://www.example.org/attr/foo/value/VaLuE1" }},
879+ },
880+ }
881+
882+ for fqn := range makeScopeMap (req .Msg .GetScope ()) {
883+ assert .Equal (t , fqn , strings .ToLower (fqn ))
884+ }
885+
886+ resp , err := as .GetEntitlements (ctxb , & req )
887+
888+ require .NoError (t , err )
889+ assert .NotNil (t , resp )
890+ assert .Len (t , resp .Msg .GetEntitlements (), 1 )
891+ assert .Equal (t , "e1" , resp .Msg .GetEntitlements ()[0 ].GetEntityId ())
892+ assert .Equal (t , []string {"https://www.example.org/attr/foo/value/value1" }, resp .Msg .GetEntitlements ()[0 ].GetAttributeValueFqns ())
893+
894+ // paginated successfully
895+ assert .Equal (t , 2 , smListCallCount )
896+ assert .Zero (t , smPaginationOffset )
897+ assert .Equal (t , 2 , attrListCallCount )
898+ assert .Zero (t , attrPaginationOffset )
899+ }
900+
766901func Test_GetEntitlementsWithComprehensiveHierarchy (t * testing.T ) {
767902 logger := logger .CreateTestLogger ()
768903 attrDef := policy.Attribute {
0 commit comments