Steps to reproduce
- Create schema with Auth and Add Authorization with claims: {“email”: "harshad@harshad.com, “isAuthenticated”: “True”, “role”: “USER”}
interface Node {
id: ID!
}
type User implements Node
@auth(
add: { and: [
{ rule: "{ $isAuthenticated: { eq: \"True\" } }" },
{ rule: "{ $role: { eq: \"USER\" } }"},
{ rule: """query($email: String!) {
queryUser(filter: { username: { eq: $email}}) {
id
}
}
"""
},
]},
query: { and: [
{ rule: "{ $isAuthenticated: { eq: \"True\" } }" },
{ rule: "{ $role: { eq: \"USER\" } }"},
{ rule: """
query($email: String!) {
queryUser(filter: { username: { eq: $email}}) {
username
}
}
"""},
]},
)
{
username: String! @id @search(by: [hash])
displayName: String @search(by: [exact])
phoneNumber: String @search(by: [exact])
photoUrl: String @search(by: [exact])
}
- Now create a user with queryVariables without JWT header.
mutation AU($users: AddUserInput!) {
addUser(input: [$users]) {
numUids
user {
id
displayName
username
}
}
}
Expected: "message": "mutation failed because authorization failed"
Got: "message": "mutation failed because authorization failed"
THIS IS GOOD!
- Now using a valid JWT create a user.
mutation AU($users: AddUserInput!) {
addUser(input: [$users]) {
numUids
user {
id
displayName
username
}
}
}
queryVariables
{
"users": {
"displayName": "harshad",
"username": "harshad@harshad.com",
"photoUrl": "https://someurl23.com"
}
}
-
You should see successful return of the user. Another Good News !
-
Try and run the same mutation this time
Without any JWT header
value.
Expected: “mutation failed because authorization failed”
Got:
"errors": [
{
"message": "couldn't rewrite query for mutation addUser because id harshad@harshad.com already exists for type User"
}
],
"data": {
"addUser": {
"numUids": 0,
"user": []
}
},
"extensions": {
"touched_uids": 4,
"tracing": {
"version": 1,
"startTime": "2020-08-15T12:24:53.4089533Z",
"endTime": "2020-08-15T12:24:53.4196013Z",
"duration": 10647600,
"execution": {
"resolvers": [
{
"path": [
"addUser"
],
"parentType": "Mutation",
"fieldName": "addUser",
"returnType": "AddUserPayload",
"startOffset": 141200,
"duration": 10453100,
"dgraph": [
{
"label": "mutation",
"startOffset": 257600,
"duration": 5287200
},
{
"label": "query",
"startOffset": 8644300,
"duration": 1887600
}
]
}
]
}
}
}
}
You see an issue here?!
Notes:
- If the mutation is executed for the first time then we do not get any errors given valid JWT.
- Run the same mutation without JWT token. When a record already exist the error actually reveals there is an existing record. Now if you look closely at the query I am passing username field as part of
Query Variables
. It appears that validation somehow is done using query variable as opposed to the JWT variable which should be injected via dgraph.
The way I see this is potential security risk as any personal accessing the endpoint can constantly try and retrieve information from endpoint pretending to be other user without being the real user. This same could be applied to other model objects as well.
Please let me know if I am doing something wrong here. Just incase !
Regards
Harshad