Developpez.com - SQL-Server
X

Choisissez d'abord la catégorieensuite la rubrique :


Déclencheurs de type LOGON

Date de publication : 14 août 2010

Par Etienne ZINZINDOHOUE () (Blog)
 


       Version PDF (Miroir)   Version hors-ligne (Miroir)
Viadeo Twitter Facebook Share on Google+        



I. Introduction
II. Audit du compte sa
II-A. Création de la table de collecte
II-B. Création du trigger de connexion
II-C. Comment visualiser le trigger créé ?
II-D. Test de connexion du compte "sa"
II-E. Audit des connexions
III. Limiter le nombre de sessions ouvertes à l'aide du trigger LOGON
III-A. Création du trigger
III-B. Test du trigger


I. Introduction

Depuis la version 2005 de SQL SERVER, Microsoft a introduit le trigger (déclencheur) de connexion (LOGON). Chaque fois qu'un utilisateur ou une application se connecte à une instance SQL SERVER, l'évènement LOGON est levé et provoque ainsi l'activation du déclencheur de connexion.
Ce couple "évènement-déclencheur" de connexion peut être utilisé pour diverses raisons. En voici quelques unes :

Dans cet article, nous allons voir différentes manières d'utiliser le trigger LOGON :


II. Audit du compte sa

Nous envisageons ici d'avoir l'historique de connexion du compte "sa" à une instance SQL SERVER. Pour ce faire, nous allons créer dans la base master une table audit_loginsa qui va collecter l'historique des connexions du compte concerné.


II-A. Création de la table de collecte

La DDL de la table de collecte est la suivante :

USE master
GO
CREATE TABLE [dbo].[audit_loginsa](
	[loginName] [varchar](50) NULL,
	[loginType] [varchar](50) NULL,
	[loginTime] [datetime] NULL,
	[hostUser] [varchar](50) NULL
) ON [PRIMARY]

GO
					

Le descriptif des colonnes de la table audit_loginsa est la suivante :

Colonne Description Commentaire
loginName Nom du login Dans notre exemple ce champ a pour valeur "sa"
loginType Type d'authentification 2 types d'authentification : SQL ou Windows
loginTime Date et heure de connexion  
hostUser Nom ou adresse IP du poste utilisateur Nom ou l'IP de la machine à partir duquel la connexion est établie

II-B. Création du trigger de connexion

 

-- Creation du trigger : l'idée ici c'est de tracer le compte 'sa'
CREATE TRIGGER TR_audit_loginsa
ON ALL SERVER 
FOR LOGON
AS
BEGIN
       DECLARE @DataTrigger XML          
       SET @DataTrigger = EVENTDATA() ;
       
       IF ORIGINAL_LOGIN()= 'sa'        
       INSERT INTO master..audit_loginsa 
       SELECT @DataTrigger.value('(/EVENT_INSTANCE/LoginName)[1]', 'varchar(50)'),
		      @DataTrigger.value('(/EVENT_INSTANCE/LoginType)[1]', 'varchar(50)'),
              @DataTrigger.value('(/EVENT_INSTANCE/PostTime)[1]', 'datetime'),         
              @DataTrigger.value('(/EVENT_INSTANCE/ClientHost)[1]', 'varchar(50)')          
END
					
 



II-C. Comment visualiser le trigger créé ?

Comment peut-on visualiser ce trigger qui a une portée (étendue) SERVER (ON ALL SERVER) ? Le premier réflexe consiste à aller voir dans la base master, dans le dossier Déclencheur : non ce n'est pas là qu'il faut le chercher !

Ce trigger est visible dans le dossier Déclencheurs sous Objets serveur :



La requête suivante permet d'afficher les caractéristiques du trigger créé :

SELECT name,
parent_class_desc 'Class',
tr.Type,
tr_ev.Type_desc + '_' + tr.Type_desc 'Trigger_Type_Desc',
is_ms_shipped,is_disabled
FROM master.sys.server_triggers tr
Inner Join master.sys.server_trigger_events tr_ev
on tr.object_id = tr_ev.object_id
					
Le résultat est le suivant :




II-D. Test de connexion du compte "sa"

Essayons de nous connecter avec le compte "sa" avec SQL Server Management Studio :



La connexion s'est correctement effectuée. Déconnectons-nous et essayons de se connecter à nouveau à la même instance SQL SERVER, mais cette fois si avec un autre compte (authentification Windows ou un autre autre compte SQL). Dans mon cas j'utilise un autre compte SQL :




II-E. Audit des connexions

Les connexions avec le compte "sa" peuvent être auditées dès à présent à l'aide de la requête suivante :

-- Audit du login 'sa'
SELECT * FROM master.dbo.audit_loginsa
ORDER BY loginTime DESC
					
Le résultat est le suivant :



On observe ici l'historique de connexion du compte "sa". On constate bien que seul ce compte est audité.


III. Limiter le nombre de sessions ouvertes à l'aide du trigger LOGON

Le trigger LOGON permet également de limiter le nombre de sessions ouvertes avec un compte déterminé. Pour mettre ceci en évidence, créons d'abord un compte qu'on va nommer "logon3Max" :

-- Créer le compte 'logon3Max'
USE master;
GO
CREATE LOGIN logon3Max WITH PASSWORD = 'pwdlogon3Max' 
GRANT VIEW SERVER STATE TO logon3Max;
GO
				

III-A. Création du trigger


-- Limiter le nombre de connexion au server à 3 pour le compte 'logon3Max'
CREATE TRIGGER TR_logon3Max
ON ALL SERVER 
FOR LOGON
AS
BEGIN           
    IF ORIGINAL_LOGIN()= 'logon3Max' AND
    (SELECT COUNT(*) 
     FROM sys.dm_exec_sessions
     WHERE is_user_process = 1 AND original_login_name = 'logon3Max') > 3
     ROLLBACK;
END
					

III-B. Test du trigger

Première session avec le compte "logon3Max" :



La requête suivante indique qu'il n'existe qu'une seule session associée au compte "logon3max" pour le moment :

SELECT COUNT(*) Nbconnexion
FROM sys.dm_exec_sessions
WHERE is_user_process = 1 AND original_login_name = 'logon3Max'
					
Deuxième session avec le compte "logon3Max". La requête précédente indique qu'il existe 2 sessions pour le compte "logon3Max" :



Répétons les mêmes étapes jusqu'à la 4ème session. Pour cette dernière un message d'erreur apparaît :




Comment peut-on débloquer cette situation ?

Cette question nous amène à examiner quelques problèmes que l'on peut rencontrer lorsqu'on utilise ce type de déclencheur.

Je me souviens de la première fois où j'ai eu un problème avec le trigger LOGON, c'était sur PC portable et j'avais créé un déclencheur LOGIN avec une erreur de frappe. J'ai passé des heures à m'arracher les cheveux ;-) . Le principal problème avec le trigger LOGON (ON ALL SERVER) est le blocage de la session SQL SERVER. Ceci peut arriver dans les cas suivants :

Prenons un cas concret :

CREATE TRIGGER TR_logon3Max
ON ALL SERVER 
FOR LOGON
AS
BEGIN           
    IF ORIGINAL_LOGIN()= 'logon3Max' AND
    (SELECT COUNT(*) 
     FROM sys.dm_exec_sessions
     WHERE is_user_process = 1 AND original_login_name = 'logon3Max') > 3
     ROLLBACK;
END
					
Supposons maintenant qu'il existe une erreur de frappe sur de la vue sys.dm_exec_sessions comme ci-dessous :

ALTER TRIGGER TR_logon3Max
ON ALL SERVER 
FOR LOGON
AS
BEGIN           
    IF ORIGINAL_LOGIN()= 'logon3Max' AND
    (SELECT COUNT(*) 
     FROM sys.dm_exec_session
     WHERE is_user_process = 1 AND original_login_name = 'logon3Max') > 3
     ROLLBACK;
END
					
A l'exécution de cette commande SQL Server Management Studio affiche "commande réussie " ! et c'est à partir de là que tous les problèmes commencent !

Essayons maintenant de nous connecter à l'instance avec les différents types de compte en notre possession (sa, logon3Max et l'authentification Windows par défaut). Un message d'erreur apparaît pour les 3 connexions :



Impossible donc de se connecter à l'instance ! Si vous avez ce problème sur une base en production, les conséquences seront désastreuses : aucune application, aucun utilisateur ne pourront accéder à la base !!! Vous devez donc savoir très rapidement comment remédier à ce problème d'accès à SQL SERVER.


Comment régler ce problème ?

Il faut d'abord se connecter à l'instance SQL Server avec une connexion administrateur dédiée (DAC). Pour cela on peut lancer une commande DOS comme-ci dessous :



Il faut ensuite afficher la liste des triggers LOGON de l'instance à l'aide les vues systèmes sys.server_triggers et sys.server_events.

SELECT name,
parent_class_desc 'class',
tr.Type,tr_ev.Type_desc + '_' + tr.Type_desc 'Trigger_Type_Desc',
is_ms_shipped,is_disabled
FROM master.sys.server_triggers tr
Inner Join master.sys.server_trigger_events tr_ev
on tr.object_id = tr_ev.object_id
					
Le résultat est le suivant :



On visualise bien les deux triggers que l'on avait créés : TR_audit_loginsa et TR_logon3Max. Une solution rapide consiste à désactiver l'ensemble des triggers de type LOGON si on ne connaît pas le trigger à l'origine du problème. La commande suivante permet de désactiver tous les triggers de type LOGON de l'instance SQL Server :

Disable Trigger All ON ALL Server;
					
Cependant dans notre cas, on sait que c'est le trigger TR_logon3Max qui est la source du problème. On va donc juste le désactiver à l'aide de la commande suivante :

Disable Trigger TR_logon3Max ON ALL Server;
					


Une fois le trigger désactivé on peut éditer afin de voir où se situe exactement l'erreur et le modifier en conséquence

SELECT definition
FROM master.sys.server_sql_modules sq
Inner Join master.sys.server_triggers tr on sq.object_id = tr.object_id
					
Une méthode violente existe également et consiste à supprimer le trigger à l'origine du problème. Attention cette méthode n'est à utiliser qu'en dernier recours !!

DROP TRIGGER TR_logon3Max ON ALL SERVER;
					
 



               Version PDF (Miroir)   Version hors-ligne (Miroir)

Valid XHTML 1.0 TransitionalValid CSS!

Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2010 Etienne ZINZINDOHOUE. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.

Contacter le responsable de la rubrique SQL-Server