diff options
author | Luke Duncalfe <lduncalfe@eml.cc> | 2019-02-18 04:19:49 +0300 |
---|---|---|
committer | Luke Duncalfe <lduncalfe@eml.cc> | 2019-02-26 00:22:12 +0300 |
commit | ccb4edbca1aa7e94a76a5a8d361af02fd093e1b9 (patch) | |
tree | 833f8cd26fc162cc3b71e0a46ed4db69d4e69cde /spec | |
parent | 7ff0c8ae57e6a88c86afae4f8e08bfacfb34d761 (diff) |
Improve GraphQL Authorization DSL
Previously GraphQL field authorization happened like this:
class ProjectType
field :my_field, MyFieldType do
authorize :permission
end
end
This change allowed us to authorize like this instead:
class ProjectType
field :my_field, MyFieldType, authorize: :permission
end
A new initializer registers the `authorize` metadata keyword on GraphQL
Schema Objects and Fields, and we can collect this data within the
context of Instrumentation like this:
field.metadata[:authorize]
The previous functionality of authorize is still being used for
mutations, as the #authorize method here is called at during the code
that executes during the mutation, rather than when a field resolves.
https://gitlab.com/gitlab-org/gitlab-ce/issues/57828
Diffstat (limited to 'spec')
-rw-r--r-- | spec/graphql/features/authorization_spec.rb | 106 | ||||
-rw-r--r-- | spec/lib/gitlab/graphql/authorize/authorize_resource_spec.rb | 18 | ||||
-rw-r--r-- | spec/lib/gitlab/graphql/authorize_spec.rb | 20 | ||||
-rw-r--r-- | spec/support/matchers/graphql_matchers.rb | 4 |
4 files changed, 125 insertions, 23 deletions
diff --git a/spec/graphql/features/authorization_spec.rb b/spec/graphql/features/authorization_spec.rb new file mode 100644 index 00000000000..a229d29afa6 --- /dev/null +++ b/spec/graphql/features/authorization_spec.rb @@ -0,0 +1,106 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe 'Gitlab::Graphql::Authorization' do + set(:user) { create(:user) } + + let(:test_object) { double(name: 'My name') } + let(:object_type) { object_type_class } + let(:query_type) { query_type_class(object_type, test_object) } + let(:schema) { schema_class(query_type) } + + let(:execute) do + schema.execute( + query_string, + context: { current_user: user }, + variables: {} + ) + end + + let(:result) { execute['data'] } + + before do + # By default, disallow all permissions. + allow(Ability).to receive(:allowed?).and_return(false) + end + + describe 'authorizing with a single permission' do + let(:query_string) { '{ singlePermission() { name } }' } + + subject { result['singlePermission'] } + + it 'should return the protected field when user has permission' do + permit(:foo) + + expect(subject['name']).to eq(test_object.name) + end + + it 'should return nil when user is not authorized' do + expect(subject).to be_nil + end + end + + describe 'authorizing with an Array of permissions' do + let(:query_string) { '{ permissionCollection() { name } }' } + + subject { result['permissionCollection'] } + + it 'should return the protected field when user has all permissions' do + permit(:foo, :bar) + + expect(subject['name']).to eq(test_object.name) + end + + it 'should return nil when user only has one of the permissions' do + permit(:foo) + + expect(subject).to be_nil + end + + it 'should return nil when user only has none of the permissions' do + expect(subject).to be_nil + end + end + + private + + def permit(*permissions) + permissions.each do |permission| + allow(Ability).to receive(:allowed?).with(user, permission, test_object).and_return(true) + end + end + + def object_type_class + Class.new(Types::BaseObject) do + graphql_name 'TestObject' + + field :name, GraphQL::STRING_TYPE, null: true + end + end + + def query_type_class(type, object) + Class.new(Types::BaseObject) do + graphql_name 'TestQuery' + + field :single_permission, type, + null: true, + authorize: :foo, + resolve: ->(obj, args, ctx) { object } + + field :permission_collection, type, + null: true, + resolve: ->(obj, args, ctx) { object } do + authorize [:foo, :bar] + end + end + end + + def schema_class(query) + Class.new(GraphQL::Schema) do + use Gitlab::Graphql::Authorize + + query(query) + end + end +end diff --git a/spec/lib/gitlab/graphql/authorize/authorize_resource_spec.rb b/spec/lib/gitlab/graphql/authorize/authorize_resource_spec.rb index 95bf7685ade..13cf52fd795 100644 --- a/spec/lib/gitlab/graphql/authorize/authorize_resource_spec.rb +++ b/spec/lib/gitlab/graphql/authorize/authorize_resource_spec.rb @@ -100,4 +100,22 @@ describe Gitlab::Graphql::Authorize::AuthorizeResource do expect { fake_class.new.find_object }.to raise_error(/Implement #find_object in #{fake_class.name}/) end end + + describe '#authorize' do + it 'adds permissions from subclasses to those of superclasses when used on classes' do + base_class = Class.new do + include Gitlab::Graphql::Authorize::AuthorizeResource + + authorize :base_authorization + end + + sub_class = Class.new(base_class) do + authorize :sub_authorization + end + + expect(base_class.required_permissions).to contain_exactly(:base_authorization) + expect(sub_class.required_permissions) + .to contain_exactly(:base_authorization, :sub_authorization) + end + end end diff --git a/spec/lib/gitlab/graphql/authorize_spec.rb b/spec/lib/gitlab/graphql/authorize_spec.rb deleted file mode 100644 index 9c17a3b0e4b..00000000000 --- a/spec/lib/gitlab/graphql/authorize_spec.rb +++ /dev/null @@ -1,20 +0,0 @@ -require 'spec_helper' - -describe Gitlab::Graphql::Authorize do - describe '#authorize' do - it 'adds permissions from subclasses to those of superclasses when used on classes' do - base_class = Class.new do - extend Gitlab::Graphql::Authorize - - authorize :base_authorization - end - sub_class = Class.new(base_class) do - authorize :sub_authorization - end - - expect(base_class.required_permissions).to contain_exactly(:base_authorization) - expect(sub_class.required_permissions) - .to contain_exactly(:base_authorization, :sub_authorization) - end - end -end diff --git a/spec/support/matchers/graphql_matchers.rb b/spec/support/matchers/graphql_matchers.rb index 7be84838e00..7894484f590 100644 --- a/spec/support/matchers/graphql_matchers.rb +++ b/spec/support/matchers/graphql_matchers.rb @@ -1,8 +1,6 @@ RSpec::Matchers.define :require_graphql_authorizations do |*expected| match do |field| - field_definition = field.metadata[:type_class] - expect(field_definition).to respond_to(:required_permissions) - expect(field_definition.required_permissions).to contain_exactly(*expected) + expect(field.metadata[:authorize]).to eq(*expected) end end |