Skip to content
Snippets Groups Projects
Commit b3ce5321 authored by Bob Van Landuyt's avatar Bob Van Landuyt
Browse files

Fix failing auhtorizations in GraphQL

0. Add authorize to LabelType and NamespaceType.

1. Make sure that authorizations on non-nullable fields are also
executed.
parent 3c240b7a
No related branches found
No related tags found
No related merge requests found
Loading
Loading
@@ -4,6 +4,8 @@ module Types
class LabelType < BaseObject
graphql_name 'Label'
 
authorize :read_label
field :description, GraphQL::STRING_TYPE, null: true
field :title, GraphQL::STRING_TYPE, null: false
field :color, GraphQL::STRING_TYPE, null: false
Loading
Loading
Loading
Loading
@@ -4,6 +4,8 @@ module Types
class MetadataType < ::Types::BaseObject
graphql_name 'Metadata'
 
authorize :read_instance_metadata
field :version, GraphQL::STRING_TYPE, null: false
field :revision, GraphQL::STRING_TYPE, null: false
end
Loading
Loading
Loading
Loading
@@ -12,10 +12,7 @@ module Types
field :metadata, Types::MetadataType,
null: true,
resolver: Resolvers::MetadataResolver,
description: 'Metadata about GitLab' do |*args|
authorize :read_instance_metadata
end
description: 'Metadata about GitLab'
 
field :echo, GraphQL::STRING_TYPE, null: false, function: Functions::Echo.new
end
Loading
Loading
# frozen_string_literal: true
class RepositoryPolicy < BasePolicy
delegate { @subject.project }
end
---
title: Add missing authorizations in GraphQL
merge_request:
author:
type: security
Loading
Loading
@@ -39,6 +39,8 @@ module Gitlab
type = node_type_for_basic_connection(type)
end
 
type = type.unwrap if type.kind.non_null?
Array.wrap(type.metadata[:authorize])
end
 
Loading
Loading
# frozen_string_literal: true
require 'spec_helper'
describe GitlabSchema.types['Label'] do
it { is_expected.to require_graphql_authorizations(:read_label) }
end
Loading
Loading
@@ -2,4 +2,5 @@ require 'spec_helper'
 
describe GitlabSchema.types['Metadata'] do
it { expect(described_class.graphql_name).to eq('Metadata') }
it { is_expected.to require_graphql_authorizations(:read_instance_metadata) }
end
Loading
Loading
@@ -24,9 +24,5 @@ describe GitlabSchema.types['Query'] do
is_expected.to have_graphql_type(Types::MetadataType)
is_expected.to have_graphql_resolver(Resolvers::MetadataResolver)
end
it 'authorizes with read_instance_metadata' do
is_expected.to require_graphql_authorizations(:read_instance_metadata)
end
end
end
Loading
Loading
@@ -7,35 +7,39 @@ require 'spec_helper'
describe Gitlab::Graphql::Authorize::AuthorizeFieldService do
def type(type_authorizations = [])
Class.new(Types::BaseObject) do
graphql_name "TestType"
graphql_name 'TestType'
 
authorize type_authorizations
end
end
 
def type_with_field(field_type, field_authorizations = [], resolved_value = "Resolved value")
def type_with_field(field_type, field_authorizations = [], resolved_value = 'Resolved value', **options)
Class.new(Types::BaseObject) do
graphql_name "TestTypeWithField"
field :test_field, field_type, null: true, authorize: field_authorizations, resolve: -> (_, _, _) { resolved_value}
graphql_name 'TestTypeWithField'
options.reverse_merge!(null: true)
field :test_field, field_type,
authorize: field_authorizations,
resolve: -> (_, _, _) { resolved_value },
**options
end
end
 
let(:current_user) { double(:current_user) }
subject(:service) { described_class.new(field) }
 
describe "#authorized_resolve" do
let(:presented_object) { double("presented object") }
let(:presented_type) { double("parent type", object: presented_object) }
describe '#authorized_resolve' do
let(:presented_object) { double('presented object') }
let(:presented_type) { double('parent type', object: presented_object) }
subject(:resolved) { service.authorized_resolve.call(presented_type, {}, { current_user: current_user }) }
 
context "scalar types" do
shared_examples "checking permissions on the presented object" do
it "checks the abilities on the object being presented and returns the value" do
context 'scalar types' do
shared_examples 'checking permissions on the presented object' do
it 'checks the abilities on the object being presented and returns the value' do
expected_permissions.each do |permission|
spy_ability_check_for(permission, presented_object, passed: true)
end
 
expect(resolved).to eq("Resolved value")
expect(resolved).to eq('Resolved value')
end
 
it "returns nil if the value wasn't authorized" do
Loading
Loading
@@ -45,47 +49,57 @@ describe Gitlab::Graphql::Authorize::AuthorizeFieldService do
end
end
 
context "when the field is a scalar type" do
let(:field) { type_with_field(GraphQL::STRING_TYPE, :read_field).fields["testField"].to_graphql }
context 'when the field is a built-in scalar type' do
let(:field) { type_with_field(GraphQL::STRING_TYPE, :read_field).fields['testField'].to_graphql }
let(:expected_permissions) { [:read_field] }
 
it_behaves_like "checking permissions on the presented object"
it_behaves_like 'checking permissions on the presented object'
end
 
context "when the field is a list of scalar types" do
let(:field) { type_with_field([GraphQL::STRING_TYPE], :read_field).fields["testField"].to_graphql }
context 'when the field is a list of scalar types' do
let(:field) { type_with_field([GraphQL::STRING_TYPE], :read_field).fields['testField'].to_graphql }
let(:expected_permissions) { [:read_field] }
 
it_behaves_like "checking permissions on the presented object"
it_behaves_like 'checking permissions on the presented object'
end
end
 
context "when the field is a specific type" do
context 'when the field is a specific type' do
let(:custom_type) { type(:read_type) }
let(:object_in_field) { double("presented in field") }
let(:field) { type_with_field(custom_type, :read_field, object_in_field).fields["testField"].to_graphql }
let(:object_in_field) { double('presented in field') }
let(:field) { type_with_field(custom_type, :read_field, object_in_field).fields['testField'].to_graphql }
 
it "checks both field & type permissions" do
it 'checks both field & type permissions' do
spy_ability_check_for(:read_field, object_in_field, passed: true)
spy_ability_check_for(:read_type, object_in_field, passed: true)
 
expect(resolved).to eq(object_in_field)
end
 
it "returns nil if viewing was not allowed" do
it 'returns nil if viewing was not allowed' do
spy_ability_check_for(:read_field, object_in_field, passed: false)
spy_ability_check_for(:read_type, object_in_field, passed: true)
 
expect(resolved).to be_nil
end
 
context "when the field is a list" do
let(:object_1) { double("presented in field 1") }
let(:object_2) { double("presented in field 2") }
context 'when the field is not nullable' do
let(:field) { type_with_field(custom_type, [], object_in_field, null: false).fields['testField'].to_graphql }
it 'returns nil when viewing is not allowed' do
spy_ability_check_for(:read_type, object_in_field, passed: false)
expect(resolved).to be_nil
end
end
context 'when the field is a list' do
let(:object_1) { double('presented in field 1') }
let(:object_2) { double('presented in field 2') }
let(:presented_types) { [double(object: object_1), double(object: object_2)] }
let(:field) { type_with_field([custom_type], :read_field, presented_types).fields["testField"].to_graphql }
let(:field) { type_with_field([custom_type], :read_field, presented_types).fields['testField'].to_graphql }
 
it "checks all permissions" do
it 'checks all permissions' do
allow(Ability).to receive(:allowed?) { true }
 
spy_ability_check_for(:read_field, object_1, passed: true)
Loading
Loading
@@ -96,7 +110,7 @@ describe Gitlab::Graphql::Authorize::AuthorizeFieldService do
expect(resolved).to eq(presented_types)
end
 
it "filters out objects that the user cannot see" do
it 'filters out objects that the user cannot see' do
allow(Ability).to receive(:allowed?) { true }
 
spy_ability_check_for(:read_type, object_1, passed: false)
Loading
Loading
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment