Получение «Отказано в разрешении SELECT для объекта», даже если оно было предоставлено

11

Я программист, а не дба ... Я знаю достаточно, чтобы быть опасным.

Я унаследовал базу данных от старого пользователя, который является db_owner для базы данных. Мы не можем настроить разрешение этого пользователя для существующих таблиц, схем и т. Д. По деловым причинам, но создаются некоторые новые таблицы, и я только хочу, чтобы этот пользователь имел к ним доступ SELECT.

Для этих пользователей были установлены разрешения для этих таблиц, так что все ОТКАЗАНО, кроме SELECT, для которого установлено значение GRANT.

Тем не менее, когда этот пользователь (dbadmin) пытается выполнить SELECT для одной из этих таблиц (AccountingAudit), возникает эта ошибка:

The SELECT permission was denied on the object 'AccountingAudit', database 'billing', schema 'dbo'.

Я запустил этот SQL, чтобы попытаться увидеть, какие разрешения установлены для этой таблицы / пользователя:

select object_name(major_id) as object,
 user_name(grantee_principal_id) as grantee,
 user_name(grantor_principal_id) as grantor,
 permission_name,
 state_desc
from sys.database_permissions

И вот что я получаю обратно:

AccountingAudit dbadmin dbo ALTER   DENY
AccountingAudit dbadmin dbo CONTROL DENY
AccountingAudit dbadmin dbo DELETE  DENY
AccountingAudit dbadmin dbo INSERT  DENY
AccountingAudit dbadmin dbo REFERENCES  DENY
AccountingAudit dbadmin dbo SELECT  GRANT
AccountingAudit dbadmin dbo TAKE OWNERSHIP  DENY
AccountingAudit dbadmin dbo UPDATE  DENY
AccountingAudit dbadmin dbo VIEW DEFINITION DENY
AccountingAudit dbadmin dbo VIEW CHANGE TRACKING    DENY

Похоже, это должно работать правильно?

Вызов SELECT, который я делаю, является очень простым SELECT * FROM AccountingAudit изнутри SSMS. Я не делаю никаких специальных sp_executesql или что-то в этом роде.

Я пытался явно предоставить разрешение:

GRANT SELECT ON [dbo].AccountingAudit TO dbadmin

Это не имеет никакого эффекта (почему бы, запрос выше уже показывает, что это предоставлено! ;-)

Я искал на stackoverflow.com и в других местах, и не могу найти ничего, что я еще не пробовал. Мне интересно, связано ли это с тем, как настроены схемы. (На данный момент я очень мало знаю о схемах.)

Есть идеи? Спасибо!

Мейсон Дж. Жвити
источник

Ответы:

10

Я не уверен здесь, но я собираюсь выйти на конечности. Я думаю, что ваша проблема может быть связана с вашей DENY CONTROLзаписью. Смотрите здесь примерно на полпути вниз по странице:

Отказ в разрешении CONTROL для базы данных неявно запрещает разрешение CONNECT для базы данных. Участник, которому отказано в разрешении CONTROL для базы данных, не сможет подключиться к этой базе данных.

Я понимаю, что этот пример для базы данных, но возьмем еще один гранулярный уровень. DENY CONTROLНа столе будет отрицать все привилегии на нем, я предполагаю , что . Сделайте, REVOKE CONTROLчтобы избавиться от этого и посмотреть, решит ли это вашу проблему.

Если это так, вам придется поместить пользователя в роль базы данных или запретить ему явные привилегии для таблицы.

Томас Стрингер
источник
1
Спасибо! Первоначально в ходе моих экспериментов я обнаружил, что если в CONTROL не было отказано, то они могли выбрать. Но при чтении BOL я неверно истолковал это как означающее, что я предоставляю пользователю полный контроль над таблицей. Теперь я вижу, что до тех пор, пока я не отказываю им в КОНТРОЛЕ, я могу сохранять другие разрешения (INSERT, DELETE и т. Д.) На уровне DENY и достигать желаемых уровней разрешений. Спасибо!
Мейсон Дж. Жвити,
Это та тонкость, за которую я проголосовал, несмотря на то, что не решил мою проблему, которую, как мне кажется, большинство бы не заметили Отдельно я обнаружил, что при использовании групп Active Directory, если вы изменили членство в группах, repadmin / syncall не обязательно исправляет проблемы, и я обнаружил, что перезагрузка сервера устранила проблему. Тем не менее, все еще ищем меньше подхода кувалдой.
Джон Заброски
0
  1. Используйте sp_DBPermissionsхранимую процедуру Кена Фишера для просмотра разрешений.

    1. Убедитесь , что DENY CONTROLне применяется к таблице, в дополнение к общему DENY SELECT, DENY INSERT, DENY UPDATE, DENY DELETEи DENY REFERENCES.
    2. Если в SELECTоператоре содержатся табличные функции, убедитесь, что EXECUTE AS OWNERв табличной функции есть или функция GRANT EXECUTEon (и нет DENY EXECUTE!). Если дело обстоит именно так, прочитайте сообщение об ошибке более внимательно, так как оно, скорее всего, не скажет, что разрешение SELECT было отклонено для таблицы, а вместо этого что-то об отказе EXECUTE.
  2. Если пользователь является пользователем или группой AD, используйте следующий сценарий для определения пользователя login_token(ей):

EXECUTE AS LOGIN = 'EXAMPLEDOMAIN\JOHN.DOE';
SELECT * FROM sys.login_token;
REVERT;
  1. Посмотрите на фактический план выполнения. Если ошибка находится внутри хранимой процедуры с SET NOCOUNT ON;, то фактический план выполнения даст вам понимание, на которое вы можете не обращать внимания, просто взглянув на вкладку «Сообщения» в SSMS, поскольку «Затрагиваемые строки» могут находиться вне вашего контроля.

    1. Ищите триггеры или временные таблицы.
  2. Вы можете скомпилировать оператор как хранимую процедуру и SSMS «Просмотр зависимостей объекта», а также приемы, описанные Светланой Головко в « Разных путях» для поиска зависимостей объекта SQL Server.

  3. Используйте событие безопасности SQL Server Profiler «Событие доступа к объекту схемы аудита» и столбцы «TextData» и «Success», чтобы отслеживать, для каких объектов SQL Server оценивает разрешения. - Я видел ситуации, когда для этого события выбрасывались две строки, и одно значение указывает «Успех = 1», а другое - «Успех = 0». В этом сценарии единственное решение, которое я нашел для работы, это перезагрузить сервер. Даже выполнение repadmin /syncallне решило проблему, не запустило и не остановило приложение (и, следовательно, пул соединений).

  4. Определите действующие разрешения для входа в систему:

-- '<domain>\<username>' is a domain user in the group you wish to test
EXECUTE AS LOGIN = '<domain>\<username>';
SELECT * FROM fn_my_permissions('Database.Schema.Table', 'OBJECT');
REVERT;
  1. Если пользователь привязан к пользователю или группе AD, рассмотрите возможность запуска, repadmin /syncallчтобы принудительно синхронизировать любые изменения, сделанные в активном каталоге, между контроллерами домена. - Если кто-то знает, как можно сравнить текущие значения двух контроллеров домена, сообщите мне.

  2. Прежде чем приступить к полной перезагрузке всей системы, попробуйте убить все активные подключения для этого пользователя. Причина в том, что пользователь получает свой токен Windows от DC, который включает их группы. Токен не будет обновляться до тех пор, пока пользователь не получит новый токен - обычно после выхода из системы и повторного входа.

  3. Тяжело перезагрузить систему. Это сработало для меня. Все еще не уверен на 100%, почему еще. ТОЛЬКО СДЕЛАЙТЕ ЭТО, ЕСЛИ ВЫ МОЖЕТЕ ВЫЖИТЬ ВНИЗ! БУДЬТЕ ОСТОРОЖНЫ, ЧТОБЫ ДЕЛАТЬ ЭТО, КОГДА У ВАС БОЛЬШИЕ ВЫДАЮЩИЕСЯ СДЕЛКИ!

Джон Заброски
источник