From 1874d4badd940b663d0b2fc17605ccf880d19e28 Mon Sep 17 00:00:00 2001 From: Tolga Ozen Date: Wed, 1 Nov 2023 23:47:26 +0300 Subject: [PATCH 1/3] *: version v0.5.6 info update --- docs/apidocs.swagger.json | 2 +- internal/info.go | 2 +- pkg/pb/base/v1/openapi.pb.go | 2 +- proto/base/v1/openapi.proto | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/apidocs.swagger.json b/docs/apidocs.swagger.json index 39ae84b97..dc6e8e4ee 100644 --- a/docs/apidocs.swagger.json +++ b/docs/apidocs.swagger.json @@ -3,7 +3,7 @@ "info": { "title": "Permify API", "description": "Permify is an open-source authorization service for creating and maintaining fine-grained authorizations across your individual applications and services. Permify converts authorization data as relational tuples into a database you point at. We called that database a Write Database (WriteDB) and it behaves as a centralized data source for your authorization system. You can model of your authorization with Permify's DSL - Permify Schema - and perform access checks with a single API call anywhere on your stack. Access decisions made according to stored relational tuples.", - "version": "v0.5.5", + "version": "v0.5.6", "contact": { "name": "API Support", "url": "https://github.com/Permify/permify/issues", diff --git a/internal/info.go b/internal/info.go index ddf24be4f..906eb3023 100644 --- a/internal/info.go +++ b/internal/info.go @@ -20,7 +20,7 @@ var Identifier = xid.New().String() */ const ( // Version is the last release of the Permify (e.g. v0.1.0) - Version = "v0.5.5" + Version = "v0.5.6" // Banner is the view for terminal. Banner = ` diff --git a/pkg/pb/base/v1/openapi.pb.go b/pkg/pb/base/v1/openapi.pb.go index afec48876..e008b739b 100644 --- a/pkg/pb/base/v1/openapi.pb.go +++ b/pkg/pb/base/v1/openapi.pb.go @@ -75,7 +75,7 @@ var file_base_v1_openapi_proto_rawDesc = []byte{ 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x66, 0x79, 0x2f, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x66, 0x79, 0x2f, 0x62, 0x6c, 0x6f, 0x62, 0x2f, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x2f, 0x4c, 0x49, 0x43, 0x45, - 0x4e, 0x53, 0x45, 0x32, 0x06, 0x76, 0x30, 0x2e, 0x35, 0x2e, 0x35, 0x2a, 0x01, 0x02, 0x32, 0x10, + 0x4e, 0x53, 0x45, 0x32, 0x06, 0x76, 0x30, 0x2e, 0x35, 0x2e, 0x36, 0x2a, 0x01, 0x02, 0x32, 0x10, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6a, 0x73, 0x6f, 0x6e, 0x3a, 0x10, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6a, 0x73, 0x6f, 0x6e, 0x5a, 0x23, 0x0a, 0x21, 0x0a, 0x0a, 0x41, 0x70, 0x69, 0x4b, 0x65, 0x79, 0x41, 0x75, diff --git a/proto/base/v1/openapi.proto b/proto/base/v1/openapi.proto index 6632a94f1..050844e50 100644 --- a/proto/base/v1/openapi.proto +++ b/proto/base/v1/openapi.proto @@ -9,7 +9,7 @@ option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = { info: { title: "Permify API"; description: "Permify is an open-source authorization service for creating and maintaining fine-grained authorizations across your individual applications and services. Permify converts authorization data as relational tuples into a database you point at. We called that database a Write Database (WriteDB) and it behaves as a centralized data source for your authorization system. You can model of your authorization with Permify's DSL - Permify Schema - and perform access checks with a single API call anywhere on your stack. Access decisions made according to stored relational tuples."; - version: "v0.5.5"; + version: "v0.5.6"; contact: { name: "API Support"; url: "https://github.com/Permify/permify/issues"; From 5baf6f4fe9d2bc79e57dece285ed348012977791 Mon Sep 17 00:00:00 2001 From: Tolga Ozen Date: Wed, 1 Nov 2023 23:49:04 +0300 Subject: [PATCH 2/3] fix: update query to include tenant_id in WHERE clauses --- internal/storage/postgres/dataWriter.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/storage/postgres/dataWriter.go b/internal/storage/postgres/dataWriter.go index 199e70199..7f05723a7 100644 --- a/internal/storage/postgres/dataWriter.go +++ b/internal/storage/postgres/dataWriter.go @@ -289,7 +289,7 @@ func (w *DataWriter) Delete(ctx context.Context, tenantID string, tupleFilter *b } if !validation.IsTupleFilterEmpty(tupleFilter) { - tbuilder := w.database.Builder.Update(RelationTuplesTable).Set("expired_tx_id", xid).Where(squirrel.Eq{"expired_tx_id": "0"}) + tbuilder := w.database.Builder.Update(RelationTuplesTable).Set("expired_tx_id", xid).Where(squirrel.Eq{"expired_tx_id": "0", "tenant_id": tenantID}) tbuilder = utils.TuplesFilterQueryForUpdateBuilder(tbuilder, tupleFilter) var tquery string @@ -316,7 +316,7 @@ func (w *DataWriter) Delete(ctx context.Context, tenantID string, tupleFilter *b } if !validation.IsAttributeFilterEmpty(attributeFilter) { - abuilder := w.database.Builder.Update(AttributesTable).Set("expired_tx_id", xid).Where(squirrel.Eq{"expired_tx_id": "0"}) + abuilder := w.database.Builder.Update(AttributesTable).Set("expired_tx_id", xid).Where(squirrel.Eq{"expired_tx_id": "0", "tenant_id": tenantID}) abuilder = utils.AttributesFilterQueryForUpdateBuilder(abuilder, attributeFilter) var aquery string From 64cba8ef6708486c20cd7f51ca76e678f24a84c0 Mon Sep 17 00:00:00 2001 From: Tolga Ozen Date: Wed, 1 Nov 2023 23:49:18 +0300 Subject: [PATCH 3/3] test: tenants should be isolated test case added --- internal/storage/postgres/dataWriter_test.go | 143 +++++++++++++++++++ 1 file changed, 143 insertions(+) diff --git a/internal/storage/postgres/dataWriter_test.go b/internal/storage/postgres/dataWriter_test.go index 6b5f5cbbb..a6fc9fb4f 100644 --- a/internal/storage/postgres/dataWriter_test.go +++ b/internal/storage/postgres/dataWriter_test.go @@ -272,5 +272,148 @@ var _ = Describe("DataWriter", func() { Expect(ct5.String()).Should(Equal("")) Expect(len(col4.GetAttributes())).Should(Equal(1)) }) + + It("tenants should be isolated", func() { + ctx := context.Background() + + attr1, err := attribute.Attribute("organization:organization-1$public|boolean:true") + Expect(err).ShouldNot(HaveOccurred()) + + attr2, err := attribute.Attribute("organization:organization-1$ip_addresses|string[]:127.0.0.1,127.0.0.2") + Expect(err).ShouldNot(HaveOccurred()) + + attr3, err := attribute.Attribute("organization:organization-3$balance|double:234.344") + Expect(err).ShouldNot(HaveOccurred()) + + tup1, err := tuple.Tuple("organization:organization-1#admin@user:user-1") + Expect(err).ShouldNot(HaveOccurred()) + + tup2, err := tuple.Tuple("organization:organization-1#admin@user:user-4") + Expect(err).ShouldNot(HaveOccurred()) + + tup3, err := tuple.Tuple("organization:organization-1#admin@user:user-2") + Expect(err).ShouldNot(HaveOccurred()) + + attributes1 := database.NewAttributeCollection([]*base.Attribute{ + attr1, + attr2, + attr3, + }...) + + tuples1 := database.NewTupleCollection([]*base.Tuple{ + tup1, + tup2, + tup3, + }...) + + token1, err := dataWriter.Write(ctx, "t1", tuples1, attributes1) + Expect(err).ShouldNot(HaveOccurred()) + Expect(token1.String()).ShouldNot(Equal("")) + + tokenT21, err := dataWriter.Write(ctx, "t2", tuples1, attributes1) + Expect(err).ShouldNot(HaveOccurred()) + Expect(tokenT21.String()).ShouldNot(Equal("")) + + col1, ct1, err := dataReader.ReadRelationships(ctx, "t1", &base.TupleFilter{ + Entity: &base.EntityFilter{ + Type: "organization", + Ids: []string{"organization-1"}, + }, + }, token1.String(), database.NewPagination(database.Size(10), database.Token(""))) + Expect(err).ShouldNot(HaveOccurred()) + Expect(ct1.String()).Should(Equal("")) + Expect(len(col1.GetTuples())).Should(Equal(3)) + + col2, ct2, err := dataReader.ReadAttributes(ctx, "t1", &base.AttributeFilter{ + Entity: &base.EntityFilter{ + Type: "organization", + Ids: []string{"organization-1"}, + }, + }, token1.String(), database.NewPagination(database.Size(10), database.Token(""))) + Expect(err).ShouldNot(HaveOccurred()) + Expect(ct2.String()).Should(Equal("")) + Expect(len(col2.GetAttributes())).Should(Equal(2)) + + colT21, ctT21, err := dataReader.ReadRelationships(ctx, "t2", &base.TupleFilter{ + Entity: &base.EntityFilter{ + Type: "organization", + Ids: []string{"organization-1"}, + }, + }, tokenT21.String(), database.NewPagination(database.Size(10), database.Token(""))) + Expect(err).ShouldNot(HaveOccurred()) + Expect(ctT21.String()).Should(Equal("")) + Expect(len(colT21.GetTuples())).Should(Equal(3)) + + colT22, ctT22, err := dataReader.ReadAttributes(ctx, "t2", &base.AttributeFilter{ + Entity: &base.EntityFilter{ + Type: "organization", + Ids: []string{"organization-1"}, + }, + }, tokenT21.String(), database.NewPagination(database.Size(10), database.Token(""))) + Expect(err).ShouldNot(HaveOccurred()) + Expect(ctT22.String()).Should(Equal("")) + Expect(len(colT22.GetAttributes())).Should(Equal(2)) + + token2, err := dataWriter.Delete(ctx, "t1", + &base.TupleFilter{ + Entity: &base.EntityFilter{ + Type: "organization", + Ids: []string{"organization-1"}, + }, + Relation: "admin", + Subject: &base.SubjectFilter{ + Type: "user", + Ids: []string{"user-1"}, + }, + }, + &base.AttributeFilter{ + Entity: &base.EntityFilter{ + Type: "organization", + Ids: []string{"organization-1"}, + }, + Attributes: []string{"public"}, + }) + Expect(err).ShouldNot(HaveOccurred()) + + col3, ct3, err := dataReader.ReadRelationships(ctx, "t1", &base.TupleFilter{ + Entity: &base.EntityFilter{ + Type: "organization", + Ids: []string{"organization-1"}, + }, + }, token2.String(), database.NewPagination(database.Size(10), database.Token(""))) + Expect(err).ShouldNot(HaveOccurred()) + Expect(ct3.String()).Should(Equal("")) + Expect(len(col3.GetTuples())).Should(Equal(2)) + + col4, ct5, err := dataReader.ReadAttributes(ctx, "t1", &base.AttributeFilter{ + Entity: &base.EntityFilter{ + Type: "organization", + Ids: []string{"organization-1"}, + }, + }, token2.String(), database.NewPagination(database.Size(10), database.Token(""))) + Expect(err).ShouldNot(HaveOccurred()) + Expect(ct5.String()).Should(Equal("")) + Expect(len(col4.GetAttributes())).Should(Equal(1)) + + colT23, ctT23, err := dataReader.ReadRelationships(ctx, "t2", &base.TupleFilter{ + Entity: &base.EntityFilter{ + Type: "organization", + Ids: []string{"organization-1"}, + }, + }, token2.String(), database.NewPagination(database.Size(10), database.Token(""))) + Expect(err).ShouldNot(HaveOccurred()) + Expect(ctT23.String()).Should(Equal("")) + Expect(len(colT23.GetTuples())).Should(Equal(3)) + + colT24, ctT25, err := dataReader.ReadAttributes(ctx, "t2", &base.AttributeFilter{ + Entity: &base.EntityFilter{ + Type: "organization", + Ids: []string{"organization-1"}, + }, + }, token2.String(), database.NewPagination(database.Size(10), database.Token(""))) + Expect(err).ShouldNot(HaveOccurred()) + Expect(ctT25.String()).Should(Equal("")) + Expect(len(colT24.GetAttributes())).Should(Equal(2)) + }) }) })