From 5ee54db8dcec57c34b9f4c5610fbcdead8dbaa58 Mon Sep 17 00:00:00 2001 From: Arijit Das Date: Thu, 9 Jul 2020 07:21:16 +0530 Subject: [PATCH] fix(GraphQL): Apply auth rules on type having @dgraph directive (#5702) (#5863) Auth rules were not applied on type having @dgraph directive because they were stored in authRules map corresponding to Graphql type name and was fetched with Dgraph type name when rewriting the query. (cherry picked from commit 8562311a6e70eb7278abcb5c9c0c004196f206dd) --- graphql/e2e/auth/auth_test.go | 86 ++++++++++++++++++++++++++++ graphql/e2e/auth/schema.graphql | 11 ++++ graphql/resolve/auth_query_test.yaml | 31 ++++++++++ graphql/schema/wrappers.go | 2 +- 4 files changed, 129 insertions(+), 1 deletion(-) diff --git a/graphql/e2e/auth/auth_test.go b/graphql/e2e/auth/auth_test.go index 235b336fcee..2fba943ff6e 100644 --- a/graphql/e2e/auth/auth_test.go +++ b/graphql/e2e/auth/auth_test.go @@ -113,6 +113,11 @@ type Project struct { Columns []*Column `json:"columns,omitempty"` } +type Student struct { + Id string `json:"id,omitempty"` + Email string `json:"email,omitempty"` +} + type TestCase struct { user string role string @@ -147,6 +152,87 @@ func getJWT(t *testing.T, user, role string) http.Header { return h } +func (s Student) deleteByEmail(t *testing.T) { + getParams := &common.GraphQLParams{ + Query: ` + mutation delStudent ($filter : StudentFilter!){ + deleteStudent (filter: $filter) { + numUids + } + } + `, + Variables: map[string]interface{}{"filter": map[string]interface{}{ + "email": map[string]interface{}{"eq": s.Email}, + }}, + } + gqlResponse := getParams.ExecuteAsPost(t, graphqlURL) + require.Nil(t, gqlResponse.Errors) +} + +func (s Student) add(t *testing.T) { + mutation := &common.GraphQLParams{ + Query: ` + mutation addStudent($student : AddStudentInput!) { + addStudent(input: [$student]) { + numUids + } + }`, + Variables: map[string]interface{}{"student": s}, + } + result := `{"addStudent":{"numUids": 1}}` + gqlResponse := mutation.ExecuteAsPost(t, graphqlURL) + common.RequireNoGQLErrors(t, gqlResponse) + require.JSONEq(t, result, string(gqlResponse.Data)) +} + +func TestAuthWithDgraphDirective(t *testing.T) { + students := []Student{ + { + Email: "user1@gmail.com", + }, + { + Email: "user2@gmail.com", + }, + } + for _, student := range students { + student.add(t) + } + + testCases := []TestCase{{ + user: students[0].Email, + role: "ADMIN", + result: `{"queryStudent":[{"email":"` + students[0].Email + `"}]}`, + }, { + user: students[0].Email, + role: "USER", + result: `{"queryStudent" : []}`, + }} + + queryStudent := ` + query { + queryStudent { + email + } + }` + + for _, tcase := range testCases { + t.Run(tcase.role+"_"+tcase.user, func(t *testing.T) { + queryParams := &common.GraphQLParams{ + Query: queryStudent, + Headers: getJWT(t, tcase.user, tcase.role), + } + gqlResponse := queryParams.ExecuteAsPost(t, graphqlURL) + common.RequireNoGQLErrors(t, gqlResponse) + require.JSONEq(t, tcase.result, string(gqlResponse.Data)) + }) + } + + // Clean up + for _, student := range students { + student.deleteByEmail(t) + } +} + func TestAuthRulesWithMissingJWT(t *testing.T) { testCases := []TestCase{ {name: "Query non auth field without JWT Token", diff --git a/graphql/e2e/auth/schema.graphql b/graphql/e2e/auth/schema.graphql index 5767ac5888e..0e6428aa8aa 100644 --- a/graphql/e2e/auth/schema.graphql +++ b/graphql/e2e/auth/schema.graphql @@ -511,3 +511,14 @@ type Review @auth() { comment: String! } +type Student @dgraph(type: "is7sowSm") +@auth(query: { and : [ {rule: """ +query($USER: String!) { + queryStudent(filter: {email: { eq: $USER}}) { + __typename + } +} +"""},{ rule: "{$ROLE: { eq: \"ADMIN\" }}"}]}) { + id: ID! + email: String! @dgraph(pred: "IOw80vnV") @search(by: [hash]) +} diff --git a/graphql/resolve/auth_query_test.yaml b/graphql/resolve/auth_query_test.yaml index d7f2a2eed68..9b796e237f0 100644 --- a/graphql/resolve/auth_query_test.yaml +++ b/graphql/resolve/auth_query_test.yaml @@ -1,3 +1,34 @@ +- name: "Auth query with @dgraph pred." + gqlquery: | + query { + queryStudent { + email + } + } + role: "ADMIN" + dgquery: |- + query { + queryStudent(func: uid(Student1)) @filter(uid(Student2)) { + email : IOw80vnV + dgraph.uid : uid + } + Student1 as var(func: type(is7sowSm)) + Student2 as var(func: uid(Student1)) @filter(eq(IOw80vnV, "user1")) @cascade + } + +- name: "Auth query with @dgraph pred (Test RBAC)." + gqlquery: | + query { + queryStudent { + email + } + } + role: "USER" + dgquery: |- + query { + queryStudent() + } + - name: "Auth with deep get query." gqlquery: | query { diff --git a/graphql/schema/wrappers.go b/graphql/schema/wrappers.go index b17fb9387ae..f224fe4a799 100644 --- a/graphql/schema/wrappers.go +++ b/graphql/schema/wrappers.go @@ -1284,7 +1284,7 @@ func (m *mutation) IsAuthQuery() bool { } func (t *astType) AuthRules() *TypeAuth { - return t.inSchema.authRules[t.Name()] + return t.inSchema.authRules[t.DgraphName()] } func (t *astType) Field(name string) FieldDefinition {