Skip to content

Commit

Permalink
feat(graphql-auth-transformer): @auth allow more granular access righ…
Browse files Browse the repository at this point in the history
…ts for read (#23)
  • Loading branch information
lazpavel committed Jun 7, 2022
1 parent 892b618 commit 041fb80
Show file tree
Hide file tree
Showing 26 changed files with 1,245 additions and 298 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,217 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`read get list auth operations 1`] = `
"## [Start] Authorization Steps. **
$util.qr($ctx.stash.put(\\"hasAuth\\", true))
#set( $isAuthorized = false )
#set( $primaryFieldMap = {} )
#if( $util.authType() == \\"API Key Authorization\\" )
#end
#if( !$isAuthorized && $util.isNull($ctx.stash.authFilter) )
$util.unauthorized()
#end
$util.toJson({\\"version\\":\\"2018-05-29\\",\\"payload\\":{}})
## [End] Authorization Steps. **"
`;

exports[`read get list auth operations 2`] = `
"## [Start] Authorization Steps. **
$util.qr($ctx.stash.put(\\"hasAuth\\", true))
#set( $isAuthorized = false )
#set( $primaryFieldMap = {} )
#if( $util.authType() == \\"API Key Authorization\\" )
#set( $isAuthorized = true )
#end
#if( !$isAuthorized && $util.isNull($ctx.stash.authFilter) )
$util.unauthorized()
#end
$util.toJson({\\"version\\":\\"2018-05-29\\",\\"payload\\":{}})
## [End] Authorization Steps. **"
`;

exports[`read get list auth operations 3`] = `
"## [Start] Authorization Steps. **
$util.qr($ctx.stash.put(\\"hasAuth\\", true))
#set( $isAuthorized = false )
#if( $util.authType() == \\"API Key Authorization\\" )
#end
#if( !$isAuthorized )
$util.unauthorized()
#end
$util.toJson({\\"version\\":\\"2018-05-29\\",\\"payload\\":{}})
## [End] Authorization Steps. **"
`;

exports[`read get list auth operations 4`] = `
"## [Start] Authorization Steps. **
$util.qr($ctx.stash.put(\\"hasAuth\\", true))
#set( $isAuthorized = false )
#if( $util.authType() == \\"API Key Authorization\\" )
#end
#if( !$isAuthorized )
$util.unauthorized()
#end
$util.toJson({\\"version\\":\\"2018-05-29\\",\\"payload\\":{}})
## [End] Authorization Steps. **"
`;

exports[`read get list auth operations 5`] = `
"## [Start] Authorization Steps. **
$util.qr($ctx.stash.put(\\"hasAuth\\", true))
#set( $isAuthorized = false )
#if( $util.authType() == \\"API Key Authorization\\" )
#end
#if( !$isAuthorized )
$util.unauthorized()
#end
$util.toJson({\\"version\\":\\"2018-05-29\\",\\"payload\\":{}})
## [End] Authorization Steps. **"
`;

exports[`read get list auth operations 6`] = `
"## [Start] Authorization Steps. **
$util.qr($ctx.stash.put(\\"hasAuth\\", true))
#set( $isAuthorized = false )
#set( $primaryFieldMap = {} )
#if( $util.authType() == \\"API Key Authorization\\" )
#set( $isAuthorized = true )
#end
#if( !$isAuthorized && $util.isNull($ctx.stash.authFilter) )
$util.unauthorized()
#end
$util.toJson({\\"version\\":\\"2018-05-29\\",\\"payload\\":{}})
## [End] Authorization Steps. **"
`;

exports[`read get list auth operations 7`] = `
"## [Start] Authorization Steps. **
$util.qr($ctx.stash.put(\\"hasAuth\\", true))
#set( $isAuthorized = false )
#set( $primaryFieldMap = {} )
#if( $util.authType() == \\"API Key Authorization\\" )
#end
#if( !$isAuthorized && $util.isNull($ctx.stash.authFilter) )
$util.unauthorized()
#end
$util.toJson({\\"version\\":\\"2018-05-29\\",\\"payload\\":{}})
## [End] Authorization Steps. **"
`;

exports[`read get list auth operations 8`] = `
"## [Start] Authorization Steps. **
$util.qr($ctx.stash.put(\\"hasAuth\\", true))
#set( $isAuthorized = false )
#if( $util.authType() == \\"API Key Authorization\\" )
#end
#if( !$isAuthorized )
$util.unauthorized()
#end
$util.toJson({\\"version\\":\\"2018-05-29\\",\\"payload\\":{}})
## [End] Authorization Steps. **"
`;

exports[`read get list auth operations 9`] = `
"## [Start] Authorization Steps. **
$util.qr($ctx.stash.put(\\"hasAuth\\", true))
#set( $isAuthorized = false )
#if( $util.authType() == \\"API Key Authorization\\" )
#end
#if( !$isAuthorized )
$util.unauthorized()
#end
$util.toJson({\\"version\\":\\"2018-05-29\\",\\"payload\\":{}})
## [End] Authorization Steps. **"
`;

exports[`read get list auth operations 10`] = `
"## [Start] Authorization Steps. **
$util.qr($ctx.stash.put(\\"hasAuth\\", true))
#set( $isAuthorized = false )
#if( $util.authType() == \\"API Key Authorization\\" )
#end
#if( !$isAuthorized )
$util.unauthorized()
#end
$util.toJson({\\"version\\":\\"2018-05-29\\",\\"payload\\":{}})
## [End] Authorization Steps. **"
`;

exports[`read get list auth operations 11`] = `
"## [Start] Authorization Steps. **
$util.qr($ctx.stash.put(\\"hasAuth\\", true))
#set( $isAuthorized = false )
#set( $primaryFieldMap = {} )
#if( $util.authType() == \\"API Key Authorization\\" )
#set( $isAuthorized = true )
#end
#if( !$isAuthorized && $util.isNull($ctx.stash.authFilter) )
$util.unauthorized()
#end
$util.toJson({\\"version\\":\\"2018-05-29\\",\\"payload\\":{}})
## [End] Authorization Steps. **"
`;

exports[`read get list auth operations 12`] = `
"## [Start] Authorization Steps. **
$util.qr($ctx.stash.put(\\"hasAuth\\", true))
#set( $isAuthorized = false )
#set( $primaryFieldMap = {} )
#if( $util.authType() == \\"API Key Authorization\\" )
#set( $isAuthorized = true )
#end
#if( !$isAuthorized && $util.isNull($ctx.stash.authFilter) )
$util.unauthorized()
#end
$util.toJson({\\"version\\":\\"2018-05-29\\",\\"payload\\":{}})
## [End] Authorization Steps. **"
`;

exports[`read get list auth operations 13`] = `
"## [Start] Authorization Steps. **
$util.qr($ctx.stash.put(\\"hasAuth\\", true))
#set( $isAuthorized = false )
#if( $util.authType() == \\"API Key Authorization\\" )
#set( $isAuthorized = true )
#end
#if( !$isAuthorized )
$util.unauthorized()
#end
$util.toJson({\\"version\\":\\"2018-05-29\\",\\"payload\\":{}})
## [End] Authorization Steps. **"
`;

exports[`read get list auth operations 14`] = `
"## [Start] Authorization Steps. **
$util.qr($ctx.stash.put(\\"hasAuth\\", true))
#set( $isAuthorized = false )
#if( $util.authType() == \\"API Key Authorization\\" )
#set( $isAuthorized = true )
#end
#if( !$isAuthorized )
$util.unauthorized()
#end
$util.toJson({\\"version\\":\\"2018-05-29\\",\\"payload\\":{}})
## [End] Authorization Steps. **"
`;

exports[`read get list auth operations 15`] = `
"## [Start] Authorization Steps. **
$util.qr($ctx.stash.put(\\"hasAuth\\", true))
#set( $isAuthorized = false )
#if( $util.authType() == \\"API Key Authorization\\" )
#set( $isAuthorized = true )
#end
#if( !$isAuthorized )
$util.unauthorized()
#end
$util.toJson({\\"version\\":\\"2018-05-29\\",\\"payload\\":{}})
## [End] Authorization Steps. **"
`;
Original file line number Diff line number Diff line change
Expand Up @@ -247,8 +247,6 @@ exports[`with identity claim feature flag disabled does not generate field resol
## [End] Checking for allowed operations which can return this field. **"
`;

exports[`with identity claim feature flag disabled error on non null fields which need resolvers 1`] = `"Because \\"Post\\" has a field-level authorization rule and subscriptions are enabled, you need to either apply field-level authorization rules to all required fields where all rules have read access [\\"id\\",\\"name\\",\\"ssn\\"], make those fields nullable, or disable subscriptions for \\"Post\\" (setting level to off or public)."`;

exports[`with identity claim feature flag disabled generates field resolver for other provider rules even if private removes all provided-related rules 1`] = `
"## [Start] Field Authorization Steps. **
#set( $isAuthorized = false )
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,25 +43,37 @@ test('access control on object and field', () => {
// add the student static group rule which only has read access
acm.setRole({
role: studentGroupRole,
operations: ['read'],
operations: ['get', 'list', 'search', 'sync', 'listen'],
});

studentTypeFields.forEach(field => {
// check that admin has CRUD access on all fields
expect(acm.isAllowed(adminRole, field, 'create')).toBe(true);
expect(acm.isAllowed(adminRole, field, 'read')).toBe(true);
expect(acm.isAllowed(adminRole, field, 'search')).toBe(true);
expect(acm.isAllowed(adminRole, field, 'sync')).toBe(true);
expect(acm.isAllowed(adminRole, field, 'listen')).toBe(true);
expect(acm.isAllowed(adminRole, field, 'list')).toBe(true);
expect(acm.isAllowed(adminRole, field, 'get')).toBe(true);
expect(acm.isAllowed(adminRole, field, 'update')).toBe(true);
expect(acm.isAllowed(adminRole, field, 'delete')).toBe(true);
// check that studentGroupRole has access to read only
expect(acm.isAllowed(studentGroupRole, field, 'read')).toBe(true);
expect(acm.isAllowed(studentGroupRole, field, 'search')).toBe(true);
expect(acm.isAllowed(studentGroupRole, field, 'sync')).toBe(true);
expect(acm.isAllowed(studentGroupRole, field, 'listen')).toBe(true);
expect(acm.isAllowed(studentGroupRole, field, 'list')).toBe(true);
expect(acm.isAllowed(studentGroupRole, field, 'get')).toBe(true);
expect(acm.isAllowed(studentGroupRole, field, 'create')).toBe(false);
expect(acm.isAllowed(studentGroupRole, field, 'update')).toBe(false);
expect(acm.isAllowed(studentGroupRole, field, 'delete')).toBe(false);
});
// when adding a field rule on email we need to overwrite it
acm.resetAccessForResource('email');

expect(acm.isAllowed(studentGroupRole, 'email', 'read')).toBe(false);
expect(acm.isAllowed(studentGroupRole, 'email', 'list')).toBe(false);
expect(acm.isAllowed(studentGroupRole, 'email', 'get')).toBe(false);
expect(acm.isAllowed(studentGroupRole, 'email', 'sync')).toBe(false);
expect(acm.isAllowed(studentGroupRole, 'email', 'search')).toBe(false);
expect(acm.isAllowed(studentGroupRole, 'email', 'listen')).toBe(false);
acm.setRole({
role: studentOwnerRole,
operations: ['update'],
Expand Down Expand Up @@ -96,19 +108,27 @@ test('access control only on field', () => {
operations: MODEL_OPERATIONS,
});
// set role for email field
acm.setRole({ role: studentOwnerRole, operations: ['read', 'update'], resource: 'email' });
acm.setRole({ role: studentOwnerRole, operations: ['get', 'list', 'search', 'listen', 'sync', 'update'], resource: 'email' });
// set role for ssn field
acm.setRole({ role: studentOwnerRole, operations: ['read'], resource: 'ssn' });
acm.setRole({ role: studentOwnerRole, operations: ['get', 'list'], resource: 'ssn' });

// expect the correct permissions are assigned for email field
expect(acm.isAllowed(studentOwnerRole, 'email', 'update')).toBe(true);
expect(acm.isAllowed(studentOwnerRole, 'email', 'read')).toBe(true);
expect(acm.isAllowed(studentOwnerRole, 'email', 'search')).toBe(true);
expect(acm.isAllowed(studentOwnerRole, 'email', 'sync')).toBe(true);
expect(acm.isAllowed(studentOwnerRole, 'email', 'listen')).toBe(true);
expect(acm.isAllowed(studentOwnerRole, 'email', 'list')).toBe(true);
expect(acm.isAllowed(studentOwnerRole, 'email', 'get')).toBe(true);
expect(acm.isAllowed(studentOwnerRole, 'email', 'delete')).toBe(false);
expect(acm.isAllowed(studentOwnerRole, 'email', 'create')).toBe(false);

// expect the correct permissions are assigned for ssn field
expect(acm.isAllowed(studentOwnerRole, 'ssn', 'create')).toBe(false);
expect(acm.isAllowed(studentOwnerRole, 'ssn', 'read')).toBe(true);
expect(acm.isAllowed(studentOwnerRole, 'ssn', 'search')).toBe(false);
expect(acm.isAllowed(studentOwnerRole, 'ssn', 'sync')).toBe(false);
expect(acm.isAllowed(studentOwnerRole, 'ssn', 'listen')).toBe(false);
expect(acm.isAllowed(studentOwnerRole, 'ssn', 'list')).toBe(true);
expect(acm.isAllowed(studentOwnerRole, 'ssn', 'get')).toBe(true);
expect(acm.isAllowed(studentOwnerRole, 'ssn', 'update')).toBe(false);
expect(acm.isAllowed(studentOwnerRole, 'ssn', 'delete')).toBe(false);
});
Expand All @@ -122,17 +142,22 @@ test('that adding a role again without a resource is not allowed', () => {
operations: MODEL_OPERATIONS,
});
acm.setRole({ role: blogOwnerRole, operations: MODEL_OPERATIONS });
for (const field of blogFields) {
blogFields.forEach(field => {
expect(acm.isAllowed(blogOwnerRole, field, 'create')).toBe(true);
expect(acm.isAllowed(blogOwnerRole, field, 'read')).toBe(true);
expect(acm.isAllowed(blogOwnerRole, field, 'search')).toBe(true);
expect(acm.isAllowed(blogOwnerRole, field, 'sync')).toBe(true);
expect(acm.isAllowed(blogOwnerRole, field, 'listen')).toBe(true);
expect(acm.isAllowed(blogOwnerRole, field, 'list')).toBe(true);
expect(acm.isAllowed(blogOwnerRole, field, 'get')).toBe(true);
expect(acm.isAllowed(blogOwnerRole, field, 'update')).toBe(true);
expect(acm.isAllowed(blogOwnerRole, field, 'delete')).toBe(true);
}
expect(() => acm.setRole({ role: blogOwnerRole, operations: ['read'] })).toThrow(`@auth ${blogOwnerRole} already exists for Blog`);
});
expect(() => acm.setRole({ role: blogOwnerRole, operations: ['get', 'list'] })).toThrow(`@auth ${blogOwnerRole} already exists for Blog`);
// field overwrites should still be allowed
acm.setRole({ role: blogOwnerRole, operations: ['read'], resource: 'name' });
acm.setRole({ role: blogOwnerRole, operations: ['read'], resource: 'id' });
expect(acm.isAllowed(blogOwnerRole, 'id', 'read')).toBe(true);
acm.setRole({ role: blogOwnerRole, operations: ['list', 'get'], resource: 'name' });
acm.setRole({ role: blogOwnerRole, operations: ['list', 'get'], resource: 'id' });
expect(acm.isAllowed(blogOwnerRole, 'id', 'get')).toBe(true);
expect(acm.isAllowed(blogOwnerRole, 'id', 'list')).toBe(true);
});

test('that adding a role again without a resource is allowed with overwrite flag enabled', () => {
Expand All @@ -144,17 +169,25 @@ test('that adding a role again without a resource is allowed with overwrite flag
operations: MODEL_OPERATIONS,
});
acm.setRole({ role: blogOwnerRole, operations: MODEL_OPERATIONS });
for (const field of blogFields) {
blogFields.forEach(field => {
expect(acm.isAllowed(blogOwnerRole, field, 'create')).toBe(true);
expect(acm.isAllowed(blogOwnerRole, field, 'read')).toBe(true);
expect(acm.isAllowed(blogOwnerRole, field, 'search')).toBe(true);
expect(acm.isAllowed(blogOwnerRole, field, 'sync')).toBe(true);
expect(acm.isAllowed(blogOwnerRole, field, 'listen')).toBe(true);
expect(acm.isAllowed(blogOwnerRole, field, 'list')).toBe(true);
expect(acm.isAllowed(blogOwnerRole, field, 'get')).toBe(true);
expect(acm.isAllowed(blogOwnerRole, field, 'update')).toBe(true);
expect(acm.isAllowed(blogOwnerRole, field, 'delete')).toBe(true);
}
acm.setRole({ role: blogOwnerRole, operations: ['read'], allowRoleOverwrite: true });
for (const field of blogFields) {
});
acm.setRole({ role: blogOwnerRole, operations: ['list', 'get'], allowRoleOverwrite: true });
blogFields.forEach(field => {
expect(acm.isAllowed(blogOwnerRole, field, 'create')).toBe(false);
expect(acm.isAllowed(blogOwnerRole, field, 'read')).toBe(true);
expect(acm.isAllowed(blogOwnerRole, field, 'search')).toBe(false);
expect(acm.isAllowed(blogOwnerRole, field, 'sync')).toBe(false);
expect(acm.isAllowed(blogOwnerRole, field, 'listen')).toBe(false);
expect(acm.isAllowed(blogOwnerRole, field, 'list')).toBe(true);
expect(acm.isAllowed(blogOwnerRole, field, 'get')).toBe(true);
expect(acm.isAllowed(blogOwnerRole, field, 'update')).toBe(false);
expect(acm.isAllowed(blogOwnerRole, field, 'delete')).toBe(false);
}
});
});
Loading

0 comments on commit 041fb80

Please sign in to comment.