Réception «L'autorisation SELECT a été refusée sur l'objet» même si elle a été accordée

11

Je suis programmeur, pas dba ... J'en sais juste assez pour être dangereux.

J'ai hérité d'une base de données avec un utilisateur hérité qui est un db_owner pour la base de données. Nous ne pouvons pas ajuster l'autorisation de cet utilisateur pour les tables, schémas, etc. existants, pour des raisons commerciales, mais de nouvelles tables sont en cours de création, et je souhaite uniquement que cet utilisateur dispose d'un accès SELECT sur celles-ci.

Des autorisations ont été définies pour cet utilisateur pour ces tables afin que tout soit REFUSÉ, à l'exception de SELECT, qui est défini sur GRANT.

Pourtant, lorsque cet utilisateur (dbadmin) tente d'effectuer un SELECT sur l'une de ces tables (AccountingAudit), cette erreur se produit:

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

J'ai exécuté ce SQL pour essayer de voir quelles autorisations sont définies pour cette table / cet utilisateur:

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

Et voici ce que je récupère:

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

Il semble que cela devrait fonctionner correctement?

L'appel SELECT que je fais est un SELECT * FROM AccountingAudit très basique, depuis SSMS. Je ne fais pas de sp_executesql spécial ou quelque chose comme ça.

J'ai essayé d'accorder explicitement l'autorisation:

GRANT SELECT ON [dbo].AccountingAudit TO dbadmin

Cela n'a aucun effet (pourquoi, la requête ci-dessus montre déjà que c'est accordé! ;-)

J'ai cherché sur stackoverflow.com et ailleurs, et je ne trouve rien que je n'ai pas encore essayé. Je me demande si cela a quelque chose à voir avec la configuration des schémas. (À ce stade, je connais très peu de schémas.)

Des idées? Merci!

Mason G. Zhwiti
la source

Réponses:

10

Je ne suis pas sûr ici, mais je vais sortir sur un membre. Je pense que votre problème pourrait être avec votre DENY CONTROLdossier. Voir ici à mi-chemin de la page:

Refuser l'autorisation CONTROL sur une base de données refuse implicitement l'autorisation CONNECT sur la base de données. Un principal auquel l'autorisation CONTROL est refusée sur une base de données ne pourra pas se connecter à cette base de données.

Je me rends compte que cet exemple est pour une base de données, mais prenez-le un niveau plus granulaire. Un DENY CONTROLsur une table lui refusera tous les privilèges, je suppose. Faites un REVOKE CONTROLpour vous en débarrasser et voyez si cela résout votre problème.

Si c'est le cas, vous devrez placer l'utilisateur dans un rôle de base de données ou leur refuser les privilèges explicites sur la table.

Thomas Stringer
la source
1
Je vous remercie! Au début de mon expérimentation, j'ai découvert que si CONTROL n'était pas refusé, ils pouvaient alors sélectionner. Mais en lisant BOL, j'avais mal interprété cela comme signifiant que je donnais à l'utilisateur un contrôle total sur la table. Je vois maintenant que tant que je ne leur refuse pas CONTROL, je peux toujours garder les autres autorisations (INSERT, DELETE, etc.) au niveau DENY et atteindre les niveaux d'autorisation que je veux. Merci!
Mason G. Zhwiti,
C'est une subtilité que j'ai surévaluée, même si je n'ai pas résolu mon problème, que je pense que la plupart négligeraient. Séparément, j'ai trouvé que si vous utilisez des groupes Active Directory, si vous avez changé d'appartenance à un groupe, repadmin / syncall ne résout pas nécessairement les problèmes et j'ai trouvé que le redémarrage du serveur corrigeait le problème. Toujours à la recherche d'une approche moins puissante, cependant.
John Zabroski
0
  1. Utilisez la sp_DBPermissionsprocédure stockée de Ken Fisher pour consulter les autorisations.

    1. Assurez - vous que DENY CONTROLn'est pas appliquée à la table, en plus de la commune DENY SELECT, DENY INSERT, DENY UPDATE, DENY DELETEet DENY REFERENCES.
    2. Si l' SELECTinstruction contient des fonctions table, assurez-vous qu'il y a un EXECUTE AS OWNERsur la fonction table ou un GRANT EXECUTEdessus (et non DENY EXECUTE!). Si tel est le cas, lisez le message d'erreur plus attentivement car il ne dira probablement pas que l'autorisation SELECT a été refusée sur la table, mais à la place quelque chose sur EXECUTE étant refusé.
  2. Si l'utilisateur est un utilisateur ou un groupe AD, utilisez le script suivant pour déterminer le ou les utilisateurs login_token:

EXECUTE AS LOGIN = 'EXAMPLEDOMAIN\JOHN.DOE';
SELECT * FROM sys.login_token;
REVERT;
  1. Regardez le plan d'exécution réel. Si l'erreur se trouve dans une procédure stockée avec SET NOCOUNT ON;, le plan d'exécution réel vous donnera un aperçu auquel vous pourriez ne pas faire attention en regardant simplement l'onglet Messages dans SSMS, car les "lignes affectées" peuvent être hors de votre contrôle.

    1. Recherchez des déclencheurs ou des tables temporelles.
  2. Vous pouvez compiler l'instruction en tant que procédure stockée et SSMS "View Object Dependencies", ainsi que les astuces décrites par Svetlana Golovko de différentes manières pour trouver les dépendances d'objets SQL Server

  3. Utilisez l'événement SQL Server Profiler Security «Audit Schema Object Access Event» et les colonnes «TextData» et «Success» pour suivre les objets sur lesquels SQL Server évalue les autorisations. - J'ai vu des situations où deux lignes sont émises pour cet événement, et une valeur indique Success = 1 et l'autre indique Success = 0. Dans ce scénario, la seule solution que j'ai trouvée fonctionne est de redémarrer le serveur. Même l'exécution repadmin /syncalln'a pas résolu le problème, ni le démarrage et l'arrêt de l'application (et donc du pool de connexions).

  4. Déterminez les autorisations effectives pour la connexion:

-- '<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. Si l'utilisateur est lié à un utilisateur ou un groupe AD, pensez à exécuter repadmin /syncallpour forcer la synchronisation de toutes les modifications apportées à Active Directory sur vos contrôleurs de domaine. - Si quelqu'un connaît un bon moyen de comparer les valeurs actuelles de deux contrôleurs de domaine, faites-le moi savoir.

  2. Avant d'envisager un redémarrage dur de l'ensemble du système, essayez de supprimer toutes les connexions actives pour cet utilisateur. La raison en est que l'utilisateur obtient son jeton Windows du contrôleur de domaine qui inclut ses groupes. Le jeton ne sera pas mis à jour tant que l'utilisateur n'aura pas un nouveau jeton - généralement en se déconnectant puis en se reconnectant.

  3. Redémarrez durement le système. ça a marché pour moi. Toujours pas sûr à 100% pourquoi encore. FAITES-LE UNIQUEMENT SI VOUS POUVEZ SURVIVRE AU TEMPS! SOYEZ PRUDENT DE LE FAIRE PENDANT QUE VOUS AVEZ DE GRANDES TRANSACTIONS EN COURS!

John Zabroski
la source