web-dev-qa-db-fra.com

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

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 ait un accès SELECT sur elles.

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, à partir de 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!

11
Mason G. Zhwiti

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 CONTROL record. 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. UNE DENY CONTROL sur une table refusera tout privilèges dessus, je suppose. Fait une REVOKE CONTROL pour vous en débarrasser et voir 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.

10
Thomas Stringer
  1. Utilisez la procédure stockée sp_DBPermissions De Ken Fisher pour consulter les autorisations.

    1. Assurez-vous que DENY CONTROL N'est pas appliqué à la table, en plus des DENY SELECT, DENY INSERT, DENY UPDATE, DENY DELETE Et DENY REFERENCES.
    2. Si l'instruction SELECT contient des fonctions table, assurez-vous qu'il y a soit un EXECUTE AS OWNER Sur la fonction table, soit un GRANT EXECUTE Dessus (et aucun 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 plutôt 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 login_token (S) de l'utilisateur:

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 des informations auxquelles vous pourriez ne pas prêter attention en regardant simplement l'onglet Messages dans SSMS, car les "lignes affectées" peuvent être en dehors 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 dans Différentes façons de 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 de repadmin /syncall N'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, envisagez d'exécuter repadmin /syncall Pour forcer toutes les modifications apportées dans Active Directory à se synchroniser 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 à partir du DC qui inclut ses groupes. Le jeton ne sera pas mis à jour jusqu'à ce que l'utilisateur obtienne 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 FAIRE CECI PENDANT QUE VOUS AVEZ DE GRANDES TRANSACTIONS EN COURS!

0
John Zabroski