Skip to content

Commit

Permalink
fix(auth): Mutation should always throw error (#40)
Browse files Browse the repository at this point in the history
  • Loading branch information
ktutnik committed Apr 9, 2023
1 parent 9d52b52 commit 0869a38
Show file tree
Hide file tree
Showing 5 changed files with 67 additions and 5 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ const typeDefs = `
role: String @authorize(policy: "Admin")
}

input User {
type User {
id: String!
name: String!
email: String! @authorize(policy: "Authenticated")
Expand Down
2 changes: 1 addition & 1 deletion packages/auth/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ const typeDefs = `
role: String @authorize(policy: "Admin")
}

input User {
type User {
id: String!
name: String!
# email only visible by authenticated user
Expand Down
6 changes: 5 additions & 1 deletion packages/auth/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { InvocationContext, InvokerHook, createDirectiveInvoker, createDirectiveInvokerPipeline } from "@graphql-directive/core"
import { MapperKind, getDirective, mapSchema } from "@graphql-tools/utils"
import { GraphQLError, GraphQLSchema, defaultFieldResolver, isNonNullType } from "graphql"
import { GraphQLError, GraphQLSchema, OperationTypeNode, defaultFieldResolver, isNonNullType } from "graphql"
import { Path } from "graphql/jsutils/Path"

const errorCode = "GRAPHQL_AUTHORIZATION_FAILED"
Expand Down Expand Up @@ -48,6 +48,7 @@ const transform = (schema: GraphQLSchema, options: AuthorizeOptions): GraphQLSch
return {
...config,
resolve: async (parent, args, context, info) => {
const operation = info.operation.operation
const path = getPath(info.path)
const [inputError, fieldError] = await Promise.all([
pipeline.invoke(args, path, config.args!, [parent, args, context, info]),
Expand All @@ -60,6 +61,9 @@ const transform = (schema: GraphQLSchema, options: AuthorizeOptions): GraphQLSch
if (fieldError.length === 0) {
return resolve(parent, args, context, info)
}
if (operation === OperationTypeNode.MUTATION) {
throw getError(fieldError)
}
if (options.queryResolution === "ThrowError") {
throw getError(fieldError)
}
Expand Down
34 changes: 34 additions & 0 deletions packages/auth/test/__snapshots__/authorize.spec.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,31 @@ exports[`Mutation authorization On complex return type (Filter mode) Should auth
}
`;

exports[`Mutation authorization On complex return type (Filter mode) Should authorize return type with proper role 3`] = `
{
"code": "GRAPHQL_AUTHORIZATION_FAILED",
"paths": [
"test.role",
],
}
`;

exports[`Mutation authorization On complex return type (Filter mode) Should throw error when authorize applied on mutation field 1`] = `
{
"name": "Wayan Koster",
"role": "admin",
}
`;

exports[`Mutation authorization On complex return type (Filter mode) Should throw error when authorize applied on mutation field 2`] = `
{
"code": "GRAPHQL_AUTHORIZATION_FAILED",
"paths": [
"test",
],
}
`;

exports[`Mutation authorization On complex return type (ThrowError mode) Should authorize return type with proper role 1`] = `
{
"name": "Wayan Koster",
Expand Down Expand Up @@ -117,6 +142,15 @@ exports[`Mutation authorization On mutation field Should authorize with proper r
}
`;

exports[`Mutation authorization On mutation field Should keep throwing error on Filter mode 1`] = `
{
"code": "GRAPHQL_AUTHORIZATION_FAILED",
"paths": [
"test",
],
}
`;

exports[`Mutation authorization On mutation field Should throw error when specify invalid policy name 1`] = `[GraphQLError: Unknown policy "superadmin" on test]`;

exports[`Query authorization Applied on query field argument Should able to apply multiple directives 1`] = `
Expand Down
28 changes: 26 additions & 2 deletions packages/auth/test/authorize.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,15 @@ describe("Mutation authorization", () => {
expect((await test(schema, "user")).errors![0].extensions).toMatchSnapshot()
})

it("Should keep throwing error on Filter mode", async () => {
const schema = createSchema(`
type Mutation {
test(name:String!, role: String): Boolean! @authorize(policy: "admin")
}`, { Mutation: { test: () => true } }, "Filter")
expect((await test(schema, "admin")).data!.test).toBe(true)
expect((await test(schema, "user")).errors![0].extensions).toMatchSnapshot()
})

it("Should able to apply multiple directives", async () => {
const schema = createSchema(`
type Mutation {
Expand Down Expand Up @@ -237,12 +246,27 @@ describe("Mutation authorization", () => {
role:String @authorize(policy: "admin")
}
type Mutation {
test(data:String!): User!
test(data:String!): User!
}`, resolver, "Filter")
expect((await test(schema, "admin")).data!.test).toMatchSnapshot()
const result = await test(schema, "user")
expect(result.data!.test).toMatchSnapshot()
expect(result.errors).toBeUndefined()
expect(result.errors![0].extensions).toMatchSnapshot()
})

it("Should throw error when authorize applied on mutation field", async () => {
const schema = createSchema(`
type User {
name:String!
role:String @authorize(policy: "admin")
}
type Mutation {
test(data:String!): User! @authorize(policy: "admin")
}`, resolver, "Filter")
expect((await test(schema, "admin")).data!.test).toMatchSnapshot()
const result = await test(schema, "user")
expect(result.data).toBeNull()
expect(result.errors![0].extensions).toMatchSnapshot()
})
})
})
Expand Down

0 comments on commit 0869a38

Please sign in to comment.