Recebendo "A permissão SELECT foi negada no objeto", mesmo que tenha sido concedida

11

Eu sou um programador, não um dba ... Eu sei apenas o suficiente para ser perigoso.

Eu herdei um banco de dados com um usuário herdado que é um db_owner para o banco de dados. Não podemos ajustar a permissão deste usuário para tabelas, esquemas, etc. existentes, por motivos comerciais, mas algumas novas tabelas estão sendo criadas e eu quero que esse usuário tenha apenas acesso SELECT nelas.

As permissões foram definidas para esse usuário para essas tabelas, para que tudo seja NEGADO, exceto SELECT, que está definido como GRANT.

No entanto, quando esse usuário (dbadmin) tenta executar um SELECT em uma dessas tabelas (AccountingAudit), esse erro ocorre:

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

Eu executei este SQL para tentar ver quais permissões estão definidas para esta tabela / usuário:

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

E é isso que eu recebo de volta:

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

Parece que deveria estar funcionando certo?

A chamada SELECT que estou fazendo é um SELECT * FROM AccountingAudit muito básico, no SSMS. Eu não estou fazendo nenhum sp_executesql especial ou algo assim.

Eu tentei conceder permissão explicitamente:

GRANT SELECT ON [dbo].AccountingAudit TO dbadmin

Isso não tem efeito (por que, a consulta acima já mostra que é concedida! ;-)

Eu procurei no stackoverflow.com e em outros lugares, e não consigo encontrar nada que ainda não tenha tentado. Gostaria de saber se tem algo a ver com a forma como os esquemas são configurados. (Neste ponto, eu sei muito pouco sobre esquemas.)

Alguma ideia? Obrigado!

Mason G. Zhwiti
fonte

Respostas:

10

Não tenho certeza aqui, mas vou me expor. Acho que seu problema pode estar no seu DENY CONTROLregistro. Veja aqui cerca da metade da página:

Negar a permissão CONTROL em um banco de dados nega implicitamente a permissão CONNECT no banco de dados. Uma entidade à qual foi negada a permissão CONTROL em um banco de dados não poderá se conectar a esse banco de dados.

Sei que o exemplo é para um banco de dados, mas considere mais um nível granual. Um DENY CONTROLem uma mesa negará todos os privilégios, suponho. Faça um REVOKE CONTROLpara se livrar disso e veja se isso resolve o seu problema.

Nesse caso, você terá que colocar o usuário em uma função de banco de dados ou negar a ele os privilégios explícitos na tabela.

Thomas Stringer
fonte
11
Obrigado! Inicialmente, nas minhas experiências, descobri que, se CONTROL não fosse negado, eles poderiam SELECIONAR. Mas, ao ler o BOL, interpretei incorretamente que isso significava que estava dando ao usuário controle total sobre a tabela. Vejo agora que, desde que não os negue CONTROL, ainda posso manter as outras permissões (INSERT, DELETE etc.) no nível DENY e alcançar os níveis de permissão desejados. Obrigado!
Mason G. Zhwiti 25/10
Essa é uma sutileza que votei, apesar de não resolver meu problema, que sinto que a maioria ignoraria. Separadamente, descobri que, se estiver usando grupos do Active Directory, se você alterou a associação ao grupo, o repadmin / syncall não corrige necessariamente os problemas e descobri que a reinicialização do servidor corrigiu o problema. Ainda procurando menos de uma abordagem de marreta, no entanto.
John Zabroski
0
  1. Use o sp_DBPermissionsprocedimento armazenado de Ken Fisher para examinar as permissões.

    1. Certifique-se DENY CONTROLnão é aplicada para a mesa, além do comum DENY SELECT, DENY INSERT, DENY UPDATE, DENY DELETEe DENY REFERENCES.
    2. Se a SELECTinstrução contiver funções com valor de tabela, verifique se existe uma EXECUTE AS OWNERfunção com valor de tabela ou uma GRANT EXECUTE(e não DENY EXECUTE!). Se for esse o caso, leia a mensagem de erro com mais cuidado, pois provavelmente não dirá que a permissão SELECT foi negada na tabela, mas sim algo sobre EXECUTE sendo negado.
  2. Se o usuário for um usuário ou grupo do AD, use o seguinte script para determinar o login_token(s) usuário (s):

EXECUTE AS LOGIN = 'EXAMPLEDOMAIN\JOHN.DOE';
SELECT * FROM sys.login_token;
REVERT;
  1. Veja o plano de execução real. Se o erro estiver dentro de um procedimento armazenado SET NOCOUNT ON;, o plano de execução real fornecerá informações sobre as quais você talvez não preste atenção, apenas observando a guia Mensagens no SSMS, pois "Linhas afetadas" podem estar fora de seu controle.

    1. Procure gatilhos ou tabelas temporais.
  2. Você pode compilar a instrução como um procedimento armazenado e o SSMS "Exibir Dependências de Objetos", bem como os truques descritos por Svetlana Golovko em Diferentes Maneiras de Encontrar Dependências de Objetos do SQL Server

  3. Use o evento de segurança do SQL Server Profiler "Evento de acesso ao objeto de esquema de auditoria" e as colunas "TextData" e "Success" para rastrear em quais objetos o SQL Server está avaliando permissões. - Vi situações em que há duas linhas emitidas para este evento, e um valor diz Sucesso = 1 e o outro diz Sucesso = 0. Nesse cenário, a única solução que encontrei para trabalhar é reiniciar o servidor. Até a execução repadmin /syncallnão resolveu o problema, nem o início e a parada do aplicativo (e, portanto, o conjunto de conexões).

  4. Determine as permissões efetivas para o logon:

-- '<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. Se o usuário estiver vinculado a um usuário ou grupo do AD, considere executar repadmin /syncallpara forçar as alterações feitas no diretório ativo a serem sincronizadas nos controladores de domínio. - Se alguém souber uma boa maneira de comparar os valores atuais de dois controladores de domínio, informe-me.

  2. Antes de considerar uma reinicialização completa de todo o sistema, tente eliminar todas as conexões ativas desse usuário. O motivo é que o usuário obtém seu token do Windows no controlador de domínio, que inclui seus grupos. O token não será atualizado até que o usuário obtenha um novo token - geralmente efetuando logoff e logon novamente.

  3. Reinicialize o sistema com força. Ele tem trabalhado para mim. Ainda não está 100% certo por que ainda. SOMENTE FAÇA ISSO SE PODE SOBREVIVER AO TEMPO ABAIXO! TENHA CUIDADO EM FAZER ISSO QUANDO TIVER GRANDES OPERAÇÕES EXCEPCIONAIS!

John Zabroski
fonte