diff options
author | Luke Duncalfe <lduncalfe@eml.cc> | 2019-02-18 14:19:49 +1300 |
---|---|---|
committer | Luke Duncalfe <lduncalfe@eml.cc> | 2019-02-26 10:22:12 +1300 |
commit | ccb4edbca1aa7e94a76a5a8d361af02fd093e1b9 (patch) | |
tree | 833f8cd26fc162cc3b71e0a46ed4db69d4e69cde /spec/graphql | |
parent | 7ff0c8ae57e6a88c86afae4f8e08bfacfb34d761 (diff) | |
download | gitlab-ce-ccb4edbca1aa7e94a76a5a8d361af02fd093e1b9.tar.gz |
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/graphql')
-rw-r--r-- | spec/graphql/features/authorization_spec.rb | 106 |
1 files changed, 106 insertions, 0 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 |