Skip to content

Commit

Permalink
Merge pull request #478 from angrykoala/fix-roles-int-test
Browse files Browse the repository at this point in the history
Fix roles int test
  • Loading branch information
angrykoala authored Sep 13, 2021
2 parents b637570 + a59a7e0 commit b2f639c
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 0 deletions.
1 change: 1 addition & 0 deletions docs/modules/ROOT/content-nav.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -63,3 +63,4 @@
**** xref:guides/v2-migration/miscellaneous.adoc[]
** xref:troubleshooting/index.adoc[]
*** xref:troubleshooting/faqs.adoc[]
*** xref:troubleshooting/security.adoc[]
10 changes: 10 additions & 0 deletions docs/modules/ROOT/pages/troubleshooting/security.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[[security]]
= Security

This chapter describes security considerations and known issues.

== Authorization not triggered for empty match

If a query yields no results, the xref::auth/auth-directive.adoc[Authorization] process will not be triggered.
This means that the result will be empty, instead of throwing an authentication error. Unauthorized users may
then discern whether or not a certain type exists in the database, even if data itself cannot be accessed.
59 changes: 59 additions & 0 deletions packages/graphql/tests/integration/auth/roles.int.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,23 @@ describe("auth/roles", () => {
await driver.close();
});

beforeAll(async () => {
const session = driver.session();

try {
await session.run(`
CREATE (:Product { name: 'p1', id:123 })
CREATE (:User { id: 1234, password:'dontpanic' })
`);
await session.run(`
MATCH(N:NotANode)
DETACH DELETE(N)
`);
} finally {
await session.close();
}
});

describe("read", () => {
test("should throw if missing role on type definition", async () => {
const session = driver.session();
Expand Down Expand Up @@ -118,6 +135,48 @@ describe("auth/roles", () => {
await session.close();
}
});

// This tests reproduces the security issue related to authorization without match #195
test.skip("should throw if missing role on type definition and no nodes are matched", async () => {
const session = driver.session();

const typeDefs = `
type NotANode @auth(rules: [{
operations: [READ],
roles: ["admin"]
}]) {
name: String
}
`;

const query = `
{
notANodes {
name
}
}
`;

const secret = "secret";
const token = jsonwebtoken.sign({ roles: [] }, secret);
const neoSchema = new Neo4jGraphQL({ typeDefs, config: { jwt: { secret } } });

try {
const socket = new Socket({ readable: true });
const req = new IncomingMessage(socket);
req.headers.authorization = `Bearer ${token}`;

const gqlResult = await graphql({
schema: neoSchema.schema,
source: query,
contextValue: { driver, req, driverConfig: { bookmarks: session.lastBookmark() } },
});

expect((gqlResult.errors as any[])[0].message).toEqual("Forbidden");
} finally {
await session.close();
}
});
});

describe("create", () => {
Expand Down

0 comments on commit b2f639c

Please sign in to comment.