Commit 60526a52 authored by Yorick Peterse's avatar Yorick Peterse

Fix TRIGGER checks for MySQL

This ensures we can check if the user has TRIGGER permissions without
querying restricted tables. Thanks to Steve Norman
(https://gitlab.com/stevenorman) for helping out with this merge
request.

Fixes https://gitlab.com/gitlab-org/gitlab-ce/issues/38372
parent c71cf908
---
title: Fix TRIGGER checks for MySQL
merge_request:
author:
type: fixed
...@@ -6,28 +6,36 @@ module Gitlab ...@@ -6,28 +6,36 @@ module Gitlab
if Database.postgresql? if Database.postgresql?
'information_schema.role_table_grants' 'information_schema.role_table_grants'
else else
'mysql.user' 'information_schema.schema_privileges'
end end
def self.scope_to_current_user
if Database.postgresql?
where('grantee = user')
else
where("CONCAT(User, '@', Host) = current_user()")
end
end
# Returns true if the current user can create and execute triggers on the # Returns true if the current user can create and execute triggers on the
# given table. # given table.
def self.create_and_execute_trigger?(table) def self.create_and_execute_trigger?(table)
priv = priv =
if Database.postgresql? if Database.postgresql?
where(privilege_type: 'TRIGGER', table_name: table) where(privilege_type: 'TRIGGER', table_name: table)
.where('grantee = user')
else else
where(Trigger_priv: 'Y') queries = [
Grant.select(1)
.from('information_schema.user_privileges')
.where("PRIVILEGE_TYPE = 'SUPER'")
.where("GRANTEE = CONCAT('\\'', REPLACE(CURRENT_USER(), '@', '\\'@\\''), '\\'')"),
Grant.select(1)
.from('information_schema.schema_privileges')
.where("PRIVILEGE_TYPE = 'TRIGGER'")
.where('TABLE_SCHEMA = ?', Gitlab::Database.database_name)
.where("GRANTEE = CONCAT('\\'', REPLACE(CURRENT_USER(), '@', '\\'@\\''), '\\'')")
]
union = SQL::Union.new(queries).to_sql
Grant.from("(#{union}) privs")
end end
priv.scope_to_current_user.any? priv.any?
end end
end end
end end
......
require 'spec_helper' require 'spec_helper'
describe Gitlab::Database::Grant do describe Gitlab::Database::Grant do
describe '.scope_to_current_user' do
it 'scopes the relation to the current user' do
user = Gitlab::Database.username
column = Gitlab::Database.postgresql? ? :grantee : :User
names = described_class.scope_to_current_user.pluck(column).uniq
expect(names).to eq([user])
end
end
describe '.create_and_execute_trigger' do describe '.create_and_execute_trigger' do
it 'returns true when the user can create and execute a trigger' do it 'returns true when the user can create and execute a trigger' do
# We assume the DB/user is set up correctly so that triggers can be # We assume the DB/user is set up correctly so that triggers can be
...@@ -18,13 +8,11 @@ describe Gitlab::Database::Grant do ...@@ -18,13 +8,11 @@ describe Gitlab::Database::Grant do
expect(described_class.create_and_execute_trigger?('users')).to eq(true) expect(described_class.create_and_execute_trigger?('users')).to eq(true)
end end
it 'returns false when the user can not create and/or execute a trigger' do it 'returns false when the user can not create and/or execute a trigger', :postgresql do
allow(described_class).to receive(:scope_to_current_user) # In case of MySQL the user may have SUPER permissions, making it
.and_return(described_class.none) # impossible to have `false` returned when running tests; hence we only
# run these tests on PostgreSQL.
result = described_class.create_and_execute_trigger?('kittens') expect(described_class.create_and_execute_trigger?('foo')).to eq(false)
expect(result).to eq(false)
end end
end end
end end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment