sqlinsight-pro/db/permissions/revoke-dynamics-ax-read.sql
Søren Eggert Lundsteen Olsen 31fa89b385 Review 1.4: AX detection survives passing errors; revoke only what the grant gave; smaller fixes
- A lock timeout or deadlock while detecting (e.g. during an AX table
  synchronisation) dropped the database from AX monitoring for an hour, so
  its findings resolved and reopened. The earlier detection is kept and
  retried within 5 minutes. A cancelled collection is no longer reported as
  "læsningen fejlede".
- A lock timeout kept the earlier batch picture forever; now at most 15
  minutes (MeasuredAt), so a job that has started is not reported late from
  an old picture.
- revoke-dynamics-ax-read.sql revoked SELECT on same-named tables in every
  schema, also a DENY set by a DBA. It now finds the AX schema like the grant
  script and revokes only granted SELECT there.
- SQLI-AX-006 skips blocked sequences (as -005/-008 do); forecasts under a
  day say "inden for et døgn" instead of "om ca. 0 dage".
- Integration tests: the SQL Scripts run as-is in main's format, and the
  shared connection has the agent's session settings after the AX reads.
- docs/dynamics-ax.md: history bounds, lock-timeout window, session settings,
  /detection-problems, API redaction.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-02 14:45:31 +02:00

66 lines
3.1 KiB
Transact-SQL

/*
SQLInsight Pro: fjern den valgfri læseadgang til Dynamics AX' systemtabeller
==============================================================================
Fjerner det, grant-dynamics-ax-read.sql gav, i én AX-database: SELECT på AX' batch-, nummerserie-, RecId- og
firmatabeller. Agentens database-bruger slettes ikke (den kan være oprettet af grant-least-privilege.sql). Bagefter
viser SQLInsight AX-datatjekkene som "ikke målbar" med den GRANT, der skal til for at slå dem til igen.
Understøtter SQL Server 2005 og nyere. Kør som sysadmin eller som db_owner/db_securityadmin i AX-databasen.
*/
SET NOCOUNT ON;
DECLARE @DatabaseName sysname;
DECLARE @LoginName sysname;
SET @DatabaseName = N'AXDB'; -- <== ret til AX-databasen
SET @LoginName = N'DOMÆNE\svc-sqlinsight$'; -- <== ret til agentens login
IF DB_ID(@DatabaseName) IS NULL
BEGIN
RAISERROR(N'Databasen %s findes ikke.', 16, 1, @DatabaseName);
RETURN;
END;
DECLARE @Procedure nvarchar(300);
DECLARE @Sql nvarchar(max);
SET @Procedure = QUOTENAME(@DatabaseName) + N'.sys.sp_executesql';
SET @Sql = N'
SET NOCOUNT ON;
DECLARE @user sysname;
DECLARE @revoke nvarchar(max);
DECLARE @count int;
SELECT @user = name FROM sys.database_principals WHERE sid = SUSER_SID(@login);
IF @user IS NULL
BEGIN
PRINT N''Login''''et har ingen bruger i '' + DB_NAME() + N''. Intet at fjerne.'';
RETURN;
END;
/* Only the AX schema (where SQLDICTIONARY and DATAAREA are, as grant-dynamics-ax-read.sql finds it), and only a SELECT
that was granted: a DENY, or a grant on a same-named table in another schema set up for another reason, is left alone. */
DECLARE @schema sysname;
SELECT TOP 1 @schema = s.name
FROM sys.tables t
JOIN sys.schemas s ON s.schema_id = t.schema_id
WHERE UPPER(t.name) = N''SQLDICTIONARY'' AND OBJECT_ID(QUOTENAME(s.name) + N''.DATAAREA'', N''U'') IS NOT NULL
ORDER BY CASE WHEN s.name = N''dbo'' THEN 0 ELSE 1 END;
IF @schema IS NULL
BEGIN
PRINT DB_NAME() + N'' er ikke en Dynamics AX-database (SQLDICTIONARY og DATAAREA findes ikke i samme skema). Intet er ændret.'';
RETURN;
END;
SET @revoke = N'''';
SET @count = 0;
SELECT @revoke = @revoke + N''REVOKE SELECT ON '' + QUOTENAME(s.name) + N''.'' + QUOTENAME(t.name) + N'' FROM '' + QUOTENAME(@user) + N''; '', @count = @count + 1
FROM sys.tables t
JOIN sys.schemas s ON s.schema_id = t.schema_id
WHERE s.name = @schema
AND UPPER(t.name) IN (N''BATCH'', N''BATCHJOB'', N''BATCHJOBHISTORY'', N''NUMBERSEQUENCETABLE'', N''NUMBERSEQUENCESCOPE'',
N''NUMBERSEQUENCEREFERENCE'', N''SYSTEMSEQUENCES'', N''SQLDICTIONARY'', N''DATAAREA'')
AND EXISTS (SELECT 1 FROM sys.database_permissions p
WHERE p.class = 1 AND p.major_id = t.object_id AND p.minor_id = 0 AND p.grantee_principal_id = USER_ID(@user)
AND p.permission_name = N''SELECT'' AND p.state IN (''G'', ''W''));
IF @count > 0 EXEC (@revoke);
PRINT N''SELECT fjernet på '' + CAST(@count AS nvarchar(10)) + N'' AX-tabeller i '' + DB_NAME() + N'' for '' + @user + N''.'';';
EXEC @Procedure @Sql, N'@login sysname', @login = @LoginName;