Simplify DB to six tables and load credentials via Always Encrypted SonicCredential.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-07-29 08:23:55 +02:00
co-authored by Cursor
parent 4d19873776
commit dcfcb5289d
15 changed files with 1356 additions and 461 deletions
@@ -0,0 +1,36 @@
/*
DATABASE: [master]
OBJECTNAME: DropExisting
ACTION: DROP
IDX: 001
DATE: 2026-07-29
USER: CUR
COMMENT: Loescht die befuellte Alt-DB (Tippfehler-Name) und die Ziel-DB
vollstaendig inkl. aller Tabellen und Always-Encrypted-Keys
(CMK/CEK). Danach: 01_CreateDatabase -> 02_CreateSchema -> 03_Seed.
Voraussetzung Client: Always-Encrypted-Zertifikat mit Thumbprint
aus appsettings (CurrentUser\My) muss vorhanden bleiben.
ACHTUNG: destruktiv, keine Datenmigration.
*/
USE [master];
GO
/* Alte DB mit Tippfehler im Namen */
IF DB_ID(N'EsbZertifkatManager') IS NOT NULL
BEGIN
ALTER DATABASE [EsbZertifkatManager]
SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
DROP DATABASE [EsbZertifkatManager];
END;
GO
/* Ziel-DB (falls bereits angelegt / befuellt) */
IF DB_ID(N'EsbZertifikatManager') IS NOT NULL
BEGIN
ALTER DATABASE [EsbZertifikatManager]
SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
DROP DATABASE [EsbZertifikatManager];
END;
GO
@@ -0,0 +1,31 @@
/*
DATABASE: [EsbZertifikatManager]
OBJECTNAME: Database
ACTION: CREATE
IDX: 002
DATE: 2026-07-29
USER: CUR
COMMENT: Legt die leere Ziel-DB an. Vorher 00_DropExisting.sql ausfuehren
(loescht Alt- und Ziel-DB inkl. Always Encrypted).
Reihenfolge: 00_DropExisting -> 01_CreateDatabase ->
02_CreateSchema -> 03_Seed.
*/
USE [master];
GO
IF DB_ID(N'EsbZertifikatManager') IS NOT NULL
BEGIN
THROW 50001,
N'Datenbank [EsbZertifikatManager] existiert noch. Zuerst 00_DropExisting.sql ausfuehren.',
1;
END;
GO
CREATE DATABASE [EsbZertifikatManager];
GO
ALTER DATABASE [EsbZertifikatManager] SET RECOVERY SIMPLE;
GO
ALTER DATABASE [EsbZertifikatManager] SET READ_WRITE;
GO
@@ -0,0 +1,606 @@
/*
DATABASE: [EsbZertifikatManager]
OBJECTNAME: Schema
ACTION: CREATE
IDX: 002
DATE: 2026-07-29
USER: CUR
COMMENT: 6 Kern-Tabellen + Always Encrypted (CMK/CEK).
Vorher 00_DropExisting + 01_CreateDatabase ausfuehren.
CMK-KEY_PATH = CurrentUser/My/<Thumbprint aus appsettings>.
CEK-ENCRYPTED_VALUE ist an dieses Zertifikat gebunden.
Bei neuem Cert: CEK in SSMS neu erzeugen und ENCRYPTED_VALUE ersetzen.
Connection String muss Column Encryption Setting=Enabled enthalten.
*/
USE [EsbZertifikatManager];
GO
SET ANSI_NULLS ON;
GO
SET QUOTED_IDENTIFIER ON;
GO
/* -------------------------------------------------------------------------- */
/* Reste bereinigen: Kind-Tabellen -> AE-Tabellen -> CEK -> CMK */
/* -------------------------------------------------------------------------- */
IF OBJECT_ID(N'[dbo].[CertificateBackup]', N'U') IS NOT NULL
BEGIN
DROP TABLE [dbo].[CertificateBackup];
END;
GO
IF OBJECT_ID(N'[dbo].[DeploymentRunStep]', N'U') IS NOT NULL
BEGIN
DROP TABLE [dbo].[DeploymentRunStep];
END;
GO
IF OBJECT_ID(N'[dbo].[DeploymentRunContainer]', N'U') IS NOT NULL
BEGIN
DROP TABLE [dbo].[DeploymentRunContainer];
END;
GO
IF OBJECT_ID(N'[dbo].[DeploymentRun]', N'U') IS NOT NULL
BEGIN
DROP TABLE [dbo].[DeploymentRun];
END;
GO
IF OBJECT_ID(N'[dbo].[DeploymentAction]', N'U') IS NOT NULL
BEGIN
DROP TABLE [dbo].[DeploymentAction];
END;
GO
IF OBJECT_ID(N'[dbo].[TlsEndpoint]', N'U') IS NOT NULL
BEGIN
DROP TABLE [dbo].[TlsEndpoint];
END;
GO
IF OBJECT_ID(N'[dbo].[CertificateTarget]', N'U') IS NOT NULL
BEGIN
DROP TABLE [dbo].[CertificateTarget];
END;
GO
IF OBJECT_ID(N'[dbo].[CertificateArtifact]', N'U') IS NOT NULL
BEGIN
DROP TABLE [dbo].[CertificateArtifact];
END;
GO
IF OBJECT_ID(N'[dbo].[AppUser]', N'U') IS NOT NULL
BEGIN
DROP TABLE [dbo].[AppUser];
END;
GO
IF OBJECT_ID(N'[dbo].[SonicCredential]', N'U') IS NOT NULL
BEGIN
DROP TABLE [dbo].[SonicCredential];
END;
GO
IF OBJECT_ID(N'[dbo].[SonicContainer]', N'U') IS NOT NULL
BEGIN
DROP TABLE [dbo].[SonicContainer];
END;
GO
/* SonicConnection kann AE-Spalten haben — vor CEK-Drop entfernen */
IF OBJECT_ID(N'[dbo].[SonicConnection]', N'U') IS NOT NULL
BEGIN
DROP TABLE [dbo].[SonicConnection];
END;
GO
IF OBJECT_ID(N'[dbo].[EsbService]', N'U') IS NOT NULL
BEGIN
DROP TABLE [dbo].[EsbService];
END;
GO
IF OBJECT_ID(N'[dbo].[Country]', N'U') IS NOT NULL
BEGIN
DROP TABLE [dbo].[Country];
END;
GO
IF OBJECT_ID(N'[dbo].[Environment]', N'U') IS NOT NULL
BEGIN
DROP TABLE [dbo].[Environment];
END;
GO
IF OBJECT_ID(N'[dbo].[Company]', N'U') IS NOT NULL
BEGIN
DROP TABLE [dbo].[Company];
END;
GO
IF EXISTS
(
SELECT 1
FROM [sys].[column_encryption_keys] AS cek
WHERE cek.[name] = N'CEK_ESB_ZertifikatManager'
)
BEGIN
DROP COLUMN ENCRYPTION KEY [CEK_ESB_ZertifikatManager];
END;
GO
IF EXISTS
(
SELECT 1
FROM [sys].[column_master_keys] AS cmk
WHERE cmk.[name] = N'CMK_ESB_ZertifikatManager'
)
BEGIN
DROP COLUMN MASTER KEY [CMK_ESB_ZertifikatManager];
END;
GO
/* -------------------------------------------------------------------------- */
/* Always Encrypted neu anlegen */
/* -------------------------------------------------------------------------- */
CREATE COLUMN MASTER KEY [CMK_ESB_ZertifikatManager]
WITH
(
KEY_STORE_PROVIDER_NAME = N'MSSQL_CERTIFICATE_STORE',
KEY_PATH = N'CurrentUser/My/238AC7A32074D5B293C7EFB60E256907CB82C9C6'
);
GO
CREATE COLUMN ENCRYPTION KEY [CEK_ESB_ZertifikatManager]
WITH VALUES
(
COLUMN_MASTER_KEY = [CMK_ESB_ZertifikatManager],
ALGORITHM = 'RSA_OAEP',
ENCRYPTED_VALUE = 0x016E000001630075007200720065006E00740075007300650072002F006D0079002F003200330038006100630037006100330032003000370034006400350062003200390033006300370065006600620036003000650032003500360039003000370063006200380032006300390063003600B8FEA92C9873A6A27B4EB33481926ABF719FB0C2EE7DF959AE38D48185CC7286E7779016745253EDB10C769773D03B614995E2373AE9F02428370727C5DF69B902A01EC0B93E8B8D114460455BAC0C1868DAE1A49AAF04480E8A3D05867395CA455CA9FADEF046437B8C25BA7DE945FCB45A50590DA555B1EB860F23B556B72A142992C085E3D4A97E92D2882D6849C6DABCF37653926A8FBC532A115CB9748179BF34DADDE268FD0DC8FF1CFBCB7192D3220238794D6D2FC7C4BDE501BABE5F6BB989853C6B5C510396069F41338CF64236A6D7A4C26F0DF7BBD2A1A5BD3BA2F7D75FECF7BE0AB0C69DDEEAAD72E2849D0A4F9C9A0C25E021A432EE399AA075AB3F0FB9929392D825E1EC991D017022982C17E72CFA9EEDB17DED9FCECF2B8651B72CA87EEAED5473B3806BD4C0A56539703B4EFF38D2889D255B95C9A6F1AD7D22A1FF2F71621B286FCAD8B708810E7BF50D027BF6A0A829422EE599D00CF2D8E6ADB7DE802971A5805073EC2E6F9793E9AEDE30E7B8EC865D50183EB64B9B8286E4A9BFFB98ACDAA9C9D8D149834DE1CA7FEF9C6A54AF4B30BDDF4AC41C36FB0EFD4EE783CEE1546D25A7CA75C549A2FB978907AFBD209197A9D60239F14F4CFAC202F435AA80DBF6A6494AB3E934F86C640DBFBB77879F2FFA8B1C9DD1BF3B14299C12943F57F1948CC5833986918EB7ACABBC1C4D642E1944BB07AB8446
);
GO
/* -------------------------------------------------------------------------- */
/* Company */
/* -------------------------------------------------------------------------- */
IF OBJECT_ID(N'[dbo].[Company]', N'U') IS NULL
BEGIN
CREATE TABLE [dbo].[Company]
(
[CompanyId] [int] IDENTITY(1, 1) NOT NULL,
[CompanyCode] [nvarchar](30) NOT NULL,
[CompanyName] [nvarchar](200) NOT NULL,
[IsActive] [bit] NOT NULL,
[CreationDateTime] [datetime2](3) NOT NULL,
[CreatedBy] [nvarchar](128) NOT NULL,
[ModifiedDateTime] [datetime2](3) NULL,
[ModifiedBy] [nvarchar](128) NULL,
CONSTRAINT [pk_Company] PRIMARY KEY CLUSTERED ([CompanyId] ASC),
CONSTRAINT [uc_Company_CompanyCode] UNIQUE NONCLUSTERED ([CompanyCode] ASC)
);
END;
GO
IF OBJECT_ID(N'[dbo].[dc_Company_IsActive]', N'D') IS NULL
BEGIN
ALTER TABLE [dbo].[Company]
ADD CONSTRAINT [dc_Company_IsActive]
DEFAULT ((1)) FOR [IsActive];
END;
GO
IF OBJECT_ID(N'[dbo].[dc_Company_CreationDateTime]', N'D') IS NULL
BEGIN
ALTER TABLE [dbo].[Company]
ADD CONSTRAINT [dc_Company_CreationDateTime]
DEFAULT (SYSUTCDATETIME()) FOR [CreationDateTime];
END;
GO
IF OBJECT_ID(N'[dbo].[dc_Company_CreatedBy]', N'D') IS NULL
BEGIN
ALTER TABLE [dbo].[Company]
ADD CONSTRAINT [dc_Company_CreatedBy]
DEFAULT (SUSER_SNAME()) FOR [CreatedBy];
END;
GO
/* -------------------------------------------------------------------------- */
/* Environment */
/* -------------------------------------------------------------------------- */
IF OBJECT_ID(N'[dbo].[Environment]', N'U') IS NULL
BEGIN
CREATE TABLE [dbo].[Environment]
(
[EnvironmentId] [int] IDENTITY(1, 1) NOT NULL,
[EnvironmentCode] [nvarchar](30) NOT NULL,
[EnvironmentName] [nvarchar](100) NOT NULL,
[SortOrder] [int] NOT NULL,
[IsActive] [bit] NOT NULL,
[CreationDateTime] [datetime2](3) NOT NULL,
[CreatedBy] [nvarchar](128) NOT NULL,
[ModifiedDateTime] [datetime2](3) NULL,
[ModifiedBy] [nvarchar](128) NULL,
CONSTRAINT [pk_Environment] PRIMARY KEY CLUSTERED ([EnvironmentId] ASC),
CONSTRAINT [uc_Environment_EnvironmentCode] UNIQUE NONCLUSTERED ([EnvironmentCode] ASC),
CONSTRAINT [uc_Environment_SortOrder] UNIQUE NONCLUSTERED ([SortOrder] ASC)
);
END;
GO
IF OBJECT_ID(N'[dbo].[dc_Environment_IsActive]', N'D') IS NULL
BEGIN
ALTER TABLE [dbo].[Environment]
ADD CONSTRAINT [dc_Environment_IsActive]
DEFAULT ((1)) FOR [IsActive];
END;
GO
IF OBJECT_ID(N'[dbo].[dc_Environment_CreationDateTime]', N'D') IS NULL
BEGIN
ALTER TABLE [dbo].[Environment]
ADD CONSTRAINT [dc_Environment_CreationDateTime]
DEFAULT (SYSUTCDATETIME()) FOR [CreationDateTime];
END;
GO
IF OBJECT_ID(N'[dbo].[dc_Environment_CreatedBy]', N'D') IS NULL
BEGIN
ALTER TABLE [dbo].[Environment]
ADD CONSTRAINT [dc_Environment_CreatedBy]
DEFAULT (SUSER_SNAME()) FOR [CreatedBy];
END;
GO
/* -------------------------------------------------------------------------- */
/* SonicConnection */
/* -------------------------------------------------------------------------- */
IF OBJECT_ID(N'[dbo].[SonicConnection]', N'U') IS NULL
BEGIN
CREATE TABLE [dbo].[SonicConnection]
(
[SonicConnectionId] [int] IDENTITY(1, 1) NOT NULL,
[EnvironmentId] [int] NOT NULL,
[ConnectionName] [nvarchar](150) NOT NULL,
[ManagementHost] [nvarchar](255) NOT NULL,
[ManagementPort] [int] NOT NULL,
[DomainName] [nvarchar](150) NOT NULL,
[ConnectionProtocol] [nvarchar](20) NOT NULL,
[IsActive] [bit] NOT NULL,
[CreationDateTime] [datetime2](3) NOT NULL,
[CreatedBy] [nvarchar](128) NOT NULL,
[ModifiedDateTime] [datetime2](3) NULL,
[ModifiedBy] [nvarchar](128) NULL,
CONSTRAINT [pk_SonicConnection] PRIMARY KEY CLUSTERED ([SonicConnectionId] ASC),
CONSTRAINT [uc_SonicConnection_ConnectionName] UNIQUE NONCLUSTERED ([ConnectionName] ASC),
CONSTRAINT [fk_SonicConnection_EnvironmentId]
FOREIGN KEY ([EnvironmentId])
REFERENCES [dbo].[Environment] ([EnvironmentId]),
CONSTRAINT [cc_SonicConnection_ManagementPort]
CHECK ([ManagementPort] >= (1) AND [ManagementPort] <= (65535))
);
END;
GO
IF OBJECT_ID(N'[dbo].[dc_SonicConnection_ConnectionProtocol]', N'D') IS NULL
BEGIN
ALTER TABLE [dbo].[SonicConnection]
ADD CONSTRAINT [dc_SonicConnection_ConnectionProtocol]
DEFAULT (N'tcp') FOR [ConnectionProtocol];
END;
GO
IF OBJECT_ID(N'[dbo].[dc_SonicConnection_IsActive]', N'D') IS NULL
BEGIN
ALTER TABLE [dbo].[SonicConnection]
ADD CONSTRAINT [dc_SonicConnection_IsActive]
DEFAULT ((1)) FOR [IsActive];
END;
GO
IF OBJECT_ID(N'[dbo].[dc_SonicConnection_CreationDateTime]', N'D') IS NULL
BEGIN
ALTER TABLE [dbo].[SonicConnection]
ADD CONSTRAINT [dc_SonicConnection_CreationDateTime]
DEFAULT (SYSUTCDATETIME()) FOR [CreationDateTime];
END;
GO
IF OBJECT_ID(N'[dbo].[dc_SonicConnection_CreatedBy]', N'D') IS NULL
BEGIN
ALTER TABLE [dbo].[SonicConnection]
ADD CONSTRAINT [dc_SonicConnection_CreatedBy]
DEFAULT (SUSER_SNAME()) FOR [CreatedBy];
END;
GO
IF NOT EXISTS
(
SELECT 1
FROM [sys].[indexes] AS i
WHERE i.[object_id] = OBJECT_ID(N'[dbo].[SonicConnection]')
AND i.[name] = N'idx_SonicConnection_EnvironmentActive'
)
BEGIN
CREATE NONCLUSTERED INDEX [idx_SonicConnection_EnvironmentActive]
ON [dbo].[SonicConnection]
(
[EnvironmentId] ASC,
[IsActive] ASC
);
END;
GO
/* -------------------------------------------------------------------------- */
/* SonicCredential (Always Encrypted) */
/* -------------------------------------------------------------------------- */
IF OBJECT_ID(N'[dbo].[SonicCredential]', N'U') IS NULL
BEGIN
CREATE TABLE [dbo].[SonicCredential]
(
[SonicCredentialId] [int] IDENTITY(1, 1) NOT NULL,
[SonicConnectionId] [int] NOT NULL,
[CredentialName] [nvarchar](150) NOT NULL,
[CredentialUserName] [nvarchar](256)
COLLATE Latin1_General_BIN2
ENCRYPTED WITH
(
COLUMN_ENCRYPTION_KEY = [CEK_ESB_ZertifikatManager],
ENCRYPTION_TYPE = Randomized,
ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256'
) NULL,
[CredentialSecret] [nvarchar](512)
COLLATE Latin1_General_BIN2
ENCRYPTED WITH
(
COLUMN_ENCRYPTION_KEY = [CEK_ESB_ZertifikatManager],
ENCRYPTION_TYPE = Randomized,
ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256'
) NULL,
[IsDefault] [bit] NOT NULL,
[IsActive] [bit] NOT NULL,
[CreationDateTime] [datetime2](3) NOT NULL,
[CreatedBy] [nvarchar](128) NOT NULL,
[ModifiedDateTime] [datetime2](3) NULL,
[ModifiedBy] [nvarchar](128) NULL,
CONSTRAINT [pk_SonicCredential] PRIMARY KEY CLUSTERED ([SonicCredentialId] ASC),
CONSTRAINT [uc_SonicCredential_CredentialName]
UNIQUE NONCLUSTERED ([SonicConnectionId] ASC, [CredentialName] ASC),
CONSTRAINT [fk_SonicCredential_SonicConnectionId]
FOREIGN KEY ([SonicConnectionId])
REFERENCES [dbo].[SonicConnection] ([SonicConnectionId])
);
END;
GO
IF OBJECT_ID(N'[dbo].[dc_SonicCredential_IsDefault]', N'D') IS NULL
BEGIN
ALTER TABLE [dbo].[SonicCredential]
ADD CONSTRAINT [dc_SonicCredential_IsDefault]
DEFAULT ((0)) FOR [IsDefault];
END;
GO
IF OBJECT_ID(N'[dbo].[dc_SonicCredential_IsActive]', N'D') IS NULL
BEGIN
ALTER TABLE [dbo].[SonicCredential]
ADD CONSTRAINT [dc_SonicCredential_IsActive]
DEFAULT ((1)) FOR [IsActive];
END;
GO
IF OBJECT_ID(N'[dbo].[dc_SonicCredential_CreationDateTime]', N'D') IS NULL
BEGIN
ALTER TABLE [dbo].[SonicCredential]
ADD CONSTRAINT [dc_SonicCredential_CreationDateTime]
DEFAULT (SYSUTCDATETIME()) FOR [CreationDateTime];
END;
GO
IF OBJECT_ID(N'[dbo].[dc_SonicCredential_CreatedBy]', N'D') IS NULL
BEGIN
ALTER TABLE [dbo].[SonicCredential]
ADD CONSTRAINT [dc_SonicCredential_CreatedBy]
DEFAULT (SUSER_SNAME()) FOR [CreatedBy];
END;
GO
/* -------------------------------------------------------------------------- */
/* SonicContainer */
/* -------------------------------------------------------------------------- */
IF OBJECT_ID(N'[dbo].[SonicContainer]', N'U') IS NULL
BEGIN
CREATE TABLE [dbo].[SonicContainer]
(
[SonicContainerId] [int] IDENTITY(1, 1) NOT NULL,
[CompanyId] [int] NOT NULL,
[SonicConnectionId] [int] NOT NULL,
[ContainerName] [nvarchar](250) NOT NULL,
[ContainerDisplayName] [nvarchar](250) NULL,
[RestartTimeoutSeconds] [int] NOT NULL,
[IsActive] [bit] NOT NULL,
[CreationDateTime] [datetime2](3) NOT NULL,
[CreatedBy] [nvarchar](128) NOT NULL,
[ModifiedDateTime] [datetime2](3) NULL,
[ModifiedBy] [nvarchar](128) NULL,
CONSTRAINT [pk_SonicContainer] PRIMARY KEY CLUSTERED ([SonicContainerId] ASC),
CONSTRAINT [uc_SonicContainer_CompanyContainer]
UNIQUE NONCLUSTERED ([CompanyId] ASC, [ContainerName] ASC),
CONSTRAINT [fk_SonicContainer_CompanyId]
FOREIGN KEY ([CompanyId])
REFERENCES [dbo].[Company] ([CompanyId]),
CONSTRAINT [fk_SonicContainer_SonicConnectionId]
FOREIGN KEY ([SonicConnectionId])
REFERENCES [dbo].[SonicConnection] ([SonicConnectionId]),
CONSTRAINT [cc_SonicContainer_RestartTimeoutSeconds]
CHECK ([RestartTimeoutSeconds] >= (10) AND [RestartTimeoutSeconds] <= (3600))
);
END;
GO
IF OBJECT_ID(N'[dbo].[dc_SonicContainer_RestartTimeoutSeconds]', N'D') IS NULL
BEGIN
ALTER TABLE [dbo].[SonicContainer]
ADD CONSTRAINT [dc_SonicContainer_RestartTimeoutSeconds]
DEFAULT ((180)) FOR [RestartTimeoutSeconds];
END;
GO
IF OBJECT_ID(N'[dbo].[dc_SonicContainer_IsActive]', N'D') IS NULL
BEGIN
ALTER TABLE [dbo].[SonicContainer]
ADD CONSTRAINT [dc_SonicContainer_IsActive]
DEFAULT ((1)) FOR [IsActive];
END;
GO
IF OBJECT_ID(N'[dbo].[dc_SonicContainer_CreationDateTime]', N'D') IS NULL
BEGIN
ALTER TABLE [dbo].[SonicContainer]
ADD CONSTRAINT [dc_SonicContainer_CreationDateTime]
DEFAULT (SYSUTCDATETIME()) FOR [CreationDateTime];
END;
GO
IF OBJECT_ID(N'[dbo].[dc_SonicContainer_CreatedBy]', N'D') IS NULL
BEGIN
ALTER TABLE [dbo].[SonicContainer]
ADD CONSTRAINT [dc_SonicContainer_CreatedBy]
DEFAULT (SUSER_SNAME()) FOR [CreatedBy];
END;
GO
IF NOT EXISTS
(
SELECT 1
FROM [sys].[indexes] AS i
WHERE i.[object_id] = OBJECT_ID(N'[dbo].[SonicContainer]')
AND i.[name] = N'idx_SonicContainer_ConnectionActive'
)
BEGIN
CREATE NONCLUSTERED INDEX [idx_SonicContainer_ConnectionActive]
ON [dbo].[SonicContainer]
(
[SonicConnectionId] ASC,
[IsActive] ASC
);
END;
GO
IF NOT EXISTS
(
SELECT 1
FROM [sys].[indexes] AS i
WHERE i.[object_id] = OBJECT_ID(N'[dbo].[SonicContainer]')
AND i.[name] = N'idx_SonicContainer_CompanyActive'
)
BEGIN
CREATE NONCLUSTERED INDEX [idx_SonicContainer_CompanyActive]
ON [dbo].[SonicContainer]
(
[CompanyId] ASC,
[IsActive] ASC
);
END;
GO
/* -------------------------------------------------------------------------- */
/* CertificateTarget */
/* -------------------------------------------------------------------------- */
IF OBJECT_ID(N'[dbo].[CertificateTarget]', N'U') IS NULL
BEGIN
CREATE TABLE [dbo].[CertificateTarget]
(
[CertificateTargetId] [int] IDENTITY(1, 1) NOT NULL,
[SonicContainerId] [int] NOT NULL,
[TargetDirectory] [nvarchar](500) NOT NULL,
[TargetFileName] [nvarchar](260) NOT NULL,
[BackupEnabled] [bit] NOT NULL,
[BackupDirectoryName] [nvarchar](100) NOT NULL,
[IsActive] [bit] NOT NULL,
[CreationDateTime] [datetime2](3) NOT NULL,
[CreatedBy] [nvarchar](128) NOT NULL,
[ModifiedDateTime] [datetime2](3) NULL,
[ModifiedBy] [nvarchar](128) NULL,
CONSTRAINT [pk_CertificateTarget] PRIMARY KEY CLUSTERED ([CertificateTargetId] ASC),
CONSTRAINT [uc_CertificateTarget_Destination]
UNIQUE NONCLUSTERED
(
[SonicContainerId] ASC,
[TargetDirectory] ASC,
[TargetFileName] ASC
),
CONSTRAINT [fk_CertificateTarget_SonicContainerId]
FOREIGN KEY ([SonicContainerId])
REFERENCES [dbo].[SonicContainer] ([SonicContainerId])
);
END;
GO
IF OBJECT_ID(N'[dbo].[dc_CertificateTarget_BackupEnabled]', N'D') IS NULL
BEGIN
ALTER TABLE [dbo].[CertificateTarget]
ADD CONSTRAINT [dc_CertificateTarget_BackupEnabled]
DEFAULT ((1)) FOR [BackupEnabled];
END;
GO
IF OBJECT_ID(N'[dbo].[dc_CertificateTarget_BackupDirectoryName]', N'D') IS NULL
BEGIN
ALTER TABLE [dbo].[CertificateTarget]
ADD CONSTRAINT [dc_CertificateTarget_BackupDirectoryName]
DEFAULT (N'Backup') FOR [BackupDirectoryName];
END;
GO
IF OBJECT_ID(N'[dbo].[dc_CertificateTarget_IsActive]', N'D') IS NULL
BEGIN
ALTER TABLE [dbo].[CertificateTarget]
ADD CONSTRAINT [dc_CertificateTarget_IsActive]
DEFAULT ((1)) FOR [IsActive];
END;
GO
IF OBJECT_ID(N'[dbo].[dc_CertificateTarget_CreationDateTime]', N'D') IS NULL
BEGIN
ALTER TABLE [dbo].[CertificateTarget]
ADD CONSTRAINT [dc_CertificateTarget_CreationDateTime]
DEFAULT (SYSUTCDATETIME()) FOR [CreationDateTime];
END;
GO
IF OBJECT_ID(N'[dbo].[dc_CertificateTarget_CreatedBy]', N'D') IS NULL
BEGIN
ALTER TABLE [dbo].[CertificateTarget]
ADD CONSTRAINT [dc_CertificateTarget_CreatedBy]
DEFAULT (SUSER_SNAME()) FOR [CreatedBy];
END;
GO
IF NOT EXISTS
(
SELECT 1
FROM [sys].[indexes] AS i
WHERE i.[object_id] = OBJECT_ID(N'[dbo].[CertificateTarget]')
AND i.[name] = N'idx_CertificateTarget_ContainerActive'
)
BEGIN
CREATE NONCLUSTERED INDEX [idx_CertificateTarget_ContainerActive]
ON [dbo].[CertificateTarget]
(
[SonicContainerId] ASC,
[IsActive] ASC
);
END;
GO
@@ -0,0 +1,143 @@
/*
DATABASE: [EsbZertifikatManager]
OBJECTNAME: Seed
ACTION: INSERT
IDX: 001
DATE: 2026-07-29
USER: CUR
COMMENT: Stammdaten Company (DE/PL/AT) und Environment (TEST2/TEST/PROD).
Nach 00_DropExisting / 01_CreateDatabase / 02_CreateSchema.
SonicConnection / SonicContainer / CertificateTarget / SonicCredential
manuell pflegen — keine Secrets; Credentials nur via AE/Setup.
*/
USE [EsbZertifikatManager];
GO
SET ANSI_NULLS ON;
GO
SET QUOTED_IDENTIFIER ON;
GO
IF NOT EXISTS
(
SELECT 1
FROM [dbo].[Company] AS company
WHERE company.[CompanyCode] = N'DE'
)
BEGIN
INSERT INTO [dbo].[Company]
(
[CompanyCode],
[CompanyName],
[IsActive],
[CreationDateTime],
[CreatedBy]
)
VALUES
(N'DE', N'ZIEHL-ABEGG Deutschland', 1, SYSUTCDATETIME(), SUSER_SNAME());
END;
GO
IF NOT EXISTS
(
SELECT 1
FROM [dbo].[Company] AS company
WHERE company.[CompanyCode] = N'PL'
)
BEGIN
INSERT INTO [dbo].[Company]
(
[CompanyCode],
[CompanyName],
[IsActive],
[CreationDateTime],
[CreatedBy]
)
VALUES
(N'PL', N'ZIEHL-ABEGG Polen', 1, SYSUTCDATETIME(), SUSER_SNAME());
END;
GO
IF NOT EXISTS
(
SELECT 1
FROM [dbo].[Company] AS company
WHERE company.[CompanyCode] = N'AT'
)
BEGIN
INSERT INTO [dbo].[Company]
(
[CompanyCode],
[CompanyName],
[IsActive],
[CreationDateTime],
[CreatedBy]
)
VALUES
(N'AT', N'ZIEHL-ABEGG Oesterreich', 1, SYSUTCDATETIME(), SUSER_SNAME());
END;
GO
IF NOT EXISTS
(
SELECT 1
FROM [dbo].[Environment] AS environment
WHERE environment.[EnvironmentCode] = N'TEST2'
)
BEGIN
INSERT INTO [dbo].[Environment]
(
[EnvironmentCode],
[EnvironmentName],
[SortOrder],
[IsActive],
[CreationDateTime],
[CreatedBy]
)
VALUES
(N'TEST2', N'Test 2', 1, 1, SYSUTCDATETIME(), SUSER_SNAME());
END;
GO
IF NOT EXISTS
(
SELECT 1
FROM [dbo].[Environment] AS environment
WHERE environment.[EnvironmentCode] = N'TEST'
)
BEGIN
INSERT INTO [dbo].[Environment]
(
[EnvironmentCode],
[EnvironmentName],
[SortOrder],
[IsActive],
[CreationDateTime],
[CreatedBy]
)
VALUES
(N'TEST', N'Test', 2, 1, SYSUTCDATETIME(), SUSER_SNAME());
END;
GO
IF NOT EXISTS
(
SELECT 1
FROM [dbo].[Environment] AS environment
WHERE environment.[EnvironmentCode] = N'PROD'
)
BEGIN
INSERT INTO [dbo].[Environment]
(
[EnvironmentCode],
[EnvironmentName],
[SortOrder],
[IsActive],
[CreationDateTime],
[CreatedBy]
)
VALUES
(N'PROD', N'Production', 3, 1, SYSUTCDATETIME(), SUSER_SNAME());
END;
GO
@@ -0,0 +1,36 @@
# Datenbank EsbZertifikatManager
Schlankes Schema (6 Tabellen) für den ESB Certificate Manager.
## Hierarchie
- **Company** — DE / PL / AT
- **Environment** — TEST2 / TEST / PROD (an `SonicConnection`)
- **SonicConnection** — Management-Host/Port/Domain
- **SonicCredential** — Always-Encrypted-Zugangsdaten (einziger Credential-Speicher)
- **SonicContainer** — Container je Company + Connection
- **CertificateTarget** — Deploy-Pfad/Dateiname (+ lokales File-Backup)
## Deployment (bestehende befüllte DB ersetzen)
Alles wird gelöscht — keine Migration.
1. **Always-Encrypted-Zertifikat** prüfen (Thumbprint aus `appsettings.json``AlwaysEncrypted:CertificateThumbprint`) unter `CurrentUser\My` inkl. privatem Schlüssel.
2. Skripte **in dieser Reihenfolge** in SSMS ausführen:
1. `00_DropExisting.sql` — droppt `EsbZertifkatManager` (Alt) und `EsbZertifikatManager` inkl. CMK/CEK
2. `01_CreateDatabase.sql` — leere Ziel-DB
3. `02_CreateSchema.sql` — Always Encrypted (CMK/CEK) + 6 Tabellen
4. `03_Seed.sql` — Company + Environment
3. Connection String: `Database=EsbZertifikatManager` und `Column Encryption Setting=Enabled`.
4. Connections / Container / Targets manuell anlegen; Credentials **nur** über Setup-Wizard (`SonicCredential`, Always Encrypted).
5. App neu starten.
## Always Encrypted
| Objekt | Name |
|---|---|
| Column Master Key | `CMK_ESB_ZertifikatManager` |
| Column Encryption Key | `CEK_ESB_ZertifikatManager` |
| Verschlüsselte Spalten | `SonicCredential.CredentialUserName`, `SonicCredential.CredentialSecret` |
CMK zeigt auf `CurrentUser/My/<Thumbprint>`. Der `ENCRYPTED_VALUE` der CEK gilt nur für dieses Zertifikat — bei neuem Cert CEK in SSMS neu erzeugen und in `02_CreateSchema.sql` ersetzen.
+186 -23
View File
@@ -4,6 +4,7 @@ using System.Security.Cryptography.X509Certificates;
using ZA.CoreService.ESBCertificateManager.Configuration;
using ZA.CoreService.ESBCertificateManager.Models;
using ZA.CoreService.ESBCertificateManager.Services;
using ZA.CoreService.ESBCertificateManager.Setup;
using Microsoft.Data.SqlClient;
namespace ZA.CoreService.ESBCertificateManager
@@ -34,10 +35,17 @@ namespace ZA.CoreService.ESBCertificateManager
private DeploymentOrchestrator? _orchestrator;
private readonly SonicConnectionRepository _sonicConnectionRepository;
private readonly DeploymentTargetRepository _deploymentTargetRepository;
private readonly SonicSetupRepository _sonicSetupRepository;
private readonly LocalSetupSelectionStore _localSetupSelectionStore;
private IReadOnlyList<DatabaseSonicConnection>
_databaseSonicConnections = [];
private readonly Dictionary<int, SonicCredentialProfile>
_credentialsByConnectionId = new();
private LocalSetupSelection? _localSetupSelection;
private CertificateInfo? _loadedCertificateInfo;
private IReadOnlyList<DeploymentTarget> _loadedTargets = [];
private bool _isOperationRunning;
@@ -89,6 +97,11 @@ namespace ZA.CoreService.ESBCertificateManager
_deploymentTargetRepository = new DeploymentTargetRepository(
_settings.Database.ConnectionString);
_sonicSetupRepository = new SonicSetupRepository(
_settings.Database.ConnectionString);
_localSetupSelectionStore = new LocalSetupSelectionStore();
BuildDesign();
Shown += async (_, _) => await InitializeApplicationAsync();
@@ -135,6 +148,52 @@ namespace ZA.CoreService.ESBCertificateManager
dragStartPoint = e.Location;
}
}
private async Task OpenSettingsAsync()
{
if (_isOperationRunning)
{
MessageBox.Show(
this,
"Während einer laufenden Aktion können die Einstellungen nicht geöffnet werden.",
"Einstellungen",
MessageBoxButtons.OK,
MessageBoxIcon.Information);
return;
}
try
{
SetupCoordinator coordinator = new(
_settings,
new SonicSetupRepository(
_settings.Database.ConnectionString));
using SetupWizardForm settingsForm = new(
coordinator,
isSettingsMode: true);
if (settingsForm.ShowDialog(this) != DialogResult.OK)
{
return;
}
SetStatus(
"Einstellungen übernommen. Anwendung wird aktualisiert ...",
isError: false);
await InitializeApplicationAsync();
}
catch (Exception ex)
{
MessageBox.Show(
this,
ex.Message,
"Einstellungen",
MessageBoxButtons.OK,
MessageBoxIcon.Error);
}
}
private async Task InitializeApplicationAsync()
{
@@ -163,16 +222,32 @@ namespace ZA.CoreService.ESBCertificateManager
}
try
{
_databaseSonicConnections =
await _sonicConnectionRepository.GetActiveAsync();
_localSetupSelection =
_localSetupSelectionStore.Load();
List<SonicConnection> runtimeConnections =
_databaseSonicConnections
.Where(connection => connection.HasCredentials)
.Select(connection =>
_databaseSonicConnections =
await _sonicConnectionRepository.GetActiveAsync(
_settings.EnvironmentCode);
await LoadCredentialsForConnectionsAsync();
List<SonicConnection> runtimeConnections = [];
foreach (DatabaseSonicConnection connection
in _databaseSonicConnections)
{
if (!_credentialsByConnectionId.TryGetValue(
connection.Id,
out SonicCredentialProfile? credential))
{
continue;
}
runtimeConnections.Add(
connection.ToRuntimeConnection(
_settings.Runtime))
.ToList();
_settings.Runtime,
credential));
}
_orchestrator = new DeploymentOrchestrator(
_settings,
@@ -195,12 +270,13 @@ namespace ZA.CoreService.ESBCertificateManager
SetStatus(
$"{_databaseSonicConnections.Count} aktive Sonic-Verbindung(en) " +
$"aus SQL und {_loadedTargets.Count} lokale Testziele geladen.",
$"aus SQL und {_loadedTargets.Count} Bereitstellungsziel(e) geladen.",
isError: false);
}
catch (SqlException ex)
{
_databaseSonicConnections = [];
_credentialsByConnectionId.Clear();
SetStatus(
$"SQL-Zugriff fehlgeschlagen: {ex.Message}",
@@ -485,12 +561,12 @@ namespace ZA.CoreService.ESBCertificateManager
progressPanel.Controls.Add(progressTitle);
// -----------------------------
// 3. Footer unten: Version
// 3. Footer unten: Einstellungen + Version
// -----------------------------
Panel footerPanel = new Panel
{
Dock = DockStyle.Bottom,
Height = 70,
Height = 118,
Padding = new Padding(18, 8, 12, 8)
};
@@ -501,13 +577,36 @@ namespace ZA.CoreService.ESBCertificateManager
BackColor = BorderColor
};
Button btnSettings = new Button
{
Text = " Einstellungen",
Location = new Point(14, 14),
Size = new Size(176, 36),
FlatStyle = FlatStyle.Flat,
FlatAppearance =
{
BorderSize = 1,
BorderColor = BorderColor,
MouseOverBackColor = Color.FromArgb(37, 52, 74)
},
BackColor = SidebarColor,
ForeColor = TextColor,
Font = new Font("Segoe UI", 9, FontStyle.Bold),
TextAlign = ContentAlignment.MiddleLeft,
Cursor = Cursors.Hand,
Enabled = !_isOperationRunning
};
btnSettings.Click += async (_, _) =>
await OpenSettingsAsync();
Label versionLabel = new Label
{
Text = "INTERNAL TOOL",
ForeColor = MutedTextColor,
Font = new Font("Segoe UI", 7.5f, FontStyle.Bold),
AutoSize = true,
Location = new Point(18, 17)
Location = new Point(18, 62)
};
Label versionNumber = new Label
@@ -516,10 +615,11 @@ namespace ZA.CoreService.ESBCertificateManager
ForeColor = BlueColor,
Font = new Font("Segoe UI", 8),
AutoSize = true,
Location = new Point(18, 37)
Location = new Point(18, 82)
};
footerPanel.Controls.Add(footerSeparator);
footerPanel.Controls.Add(btnSettings);
footerPanel.Controls.Add(versionLabel);
footerPanel.Controls.Add(versionNumber);
@@ -1428,7 +1528,8 @@ namespace ZA.CoreService.ESBCertificateManager
isError: false);
_loadedTargets =
await _deploymentTargetRepository.GetActiveAsync();
await _deploymentTargetRepository.GetActiveAsync(
_settings.EnvironmentCode);
BindTargetsToGrid(_loadedTargets);
@@ -1943,6 +2044,42 @@ namespace ZA.CoreService.ESBCertificateManager
// ---------------------------------------------------------------
// Sonic Status (KnownContainers aus appsettings)
// ---------------------------------------------------------------
private async Task LoadCredentialsForConnectionsAsync()
{
_credentialsByConnectionId.Clear();
foreach (DatabaseSonicConnection connection
in _databaseSonicConnections)
{
IReadOnlyList<SonicCredentialProfile> profiles =
await _sonicSetupRepository.GetCredentialsAsync(
connection.Id);
SonicCredentialProfile? selected = null;
if (_localSetupSelection is not null
&& _localSetupSelection.SonicConnectionId
== connection.Id
&& _localSetupSelection.SonicCredentialId > 0)
{
selected = profiles.FirstOrDefault(
profile =>
profile.SonicCredentialId
== _localSetupSelection.SonicCredentialId);
}
selected ??=
profiles.FirstOrDefault(profile => profile.IsDefault)
?? profiles.FirstOrDefault();
if (selected is not null && selected.IsComplete)
{
_credentialsByConnectionId[connection.Id] =
selected;
}
}
}
private void BindDatabaseSonicConnections()
{
cmbSonicConnection.Items.Clear();
@@ -1953,13 +2090,34 @@ namespace ZA.CoreService.ESBCertificateManager
cmbSonicConnection.Items.Add(connection.Name);
}
if (cmbSonicConnection.Items.Count > 0)
if (cmbSonicConnection.Items.Count == 0)
{
cmbSonicConnection.SelectedIndex = 0;
RefreshSonicStatusLine();
return;
}
RefreshSonicStatusLine();
int preferredIndex = 0;
if (_localSetupSelection is not null
&& !string.IsNullOrWhiteSpace(
_localSetupSelection.ConnectionName))
{
for (int index = 0;
index < cmbSonicConnection.Items.Count;
index++)
{
if (string.Equals(
cmbSonicConnection.Items[index]?.ToString(),
_localSetupSelection.ConnectionName,
StringComparison.OrdinalIgnoreCase))
{
preferredIndex = index;
break;
}
}
}
cmbSonicConnection.SelectedIndex = preferredIndex;
}
private void BuildSonicDiscoveryRow(Panel card)
{
@@ -2036,14 +2194,19 @@ namespace ZA.CoreService.ESBCertificateManager
{
string connectionUrl = connection.BuildConnectionUrl();
bool hasCredentialReference =
!string.IsNullOrWhiteSpace(connection.CredentialReference);
bool hasCredential =
_credentialsByConnectionId.TryGetValue(
connection.Id,
out SonicCredentialProfile? credential);
lblSonicStatus.Text = hasCredentialReference
? $"{connection.Name}: {connectionUrl}, Credential-Referenz vorhanden"
: $"{connection.Name}: {connectionUrl}, sichere Zugangsdaten noch nicht konfiguriert";
string credentialInfo = hasCredential
? $"Profil '{credential!.CredentialName}'"
: "sichere Zugangsdaten noch nicht konfiguriert";
lblSonicStatus.ForeColor = hasCredentialReference
lblSonicStatus.Text =
$"{connection.Name}: {connectionUrl}, {credentialInfo}";
lblSonicStatus.ForeColor = hasCredential
? GreenColor
: GoldColor;
}
@@ -4,8 +4,7 @@ namespace ZA.CoreService.ESBCertificateManager.Models;
/// <summary>
/// Aus dbo.SonicConnection geladene Verbindungsdaten.
/// CredentialSecret wird durch Microsoft.Data.SqlClient
/// clientseitig entschlüsselt.
/// Zugangsdaten liegen ausschließlich in dbo.SonicCredential.
/// </summary>
public sealed class DatabaseSonicConnection
{
@@ -15,34 +14,16 @@ public sealed class DatabaseSonicConnection
public required string ManagementHost { get; init; }
public int? ManagementPort { get; init; }
public int ManagementPort { get; init; }
public string? ConnectionProtocol { get; init; }
public string? DomainName { get; init; }
public string? CredentialUserName { get; init; }
public string? CredentialReference { get; init; }
/// <summary>
/// Nur zur Laufzeit verfügbar.
/// Darf niemals protokolliert oder angezeigt werden.
/// </summary>
public string? CredentialSecret { get; init; }
public string? JavaHomePath { get; init; }
public string? SonicHomePath { get; init; }
public string? Notes { get; init; }
public string? EnvironmentCode { get; init; }
public bool IsActive { get; init; }
public bool HasCredentials =>
!string.IsNullOrWhiteSpace(CredentialUserName)
&& !string.IsNullOrEmpty(CredentialSecret);
public string BuildConnectionUrl()
{
if (string.IsNullOrWhiteSpace(ConnectionProtocol))
@@ -57,7 +38,7 @@ public sealed class DatabaseSonicConnection
$"Bei der Sonic-Verbindung '{Name}' fehlt ManagementHost.");
}
if (ManagementPort is null or < 1 or > 65535)
if (ManagementPort is < 1 or > 65535)
{
throw new InvalidOperationException(
$"Bei der Sonic-Verbindung '{Name}' fehlt ein gültiger ManagementPort.");
@@ -69,29 +50,26 @@ public sealed class DatabaseSonicConnection
string host = ManagementHost.Trim();
return $"{protocol}://{host}:{ManagementPort.Value}";
return $"{protocol}://{host}:{ManagementPort}";
}
public SonicConnection ToRuntimeConnection(
RuntimeSettings runtimeSettings)
RuntimeSettings runtimeSettings,
SonicCredentialProfile credential)
{
ArgumentNullException.ThrowIfNull(credential);
if (string.IsNullOrWhiteSpace(DomainName))
{
throw new InvalidOperationException(
$"Bei der Sonic-Verbindung '{Name}' fehlt DomainName.");
}
if (string.IsNullOrWhiteSpace(CredentialUserName))
{
throw new InvalidOperationException(
$"Bei der Sonic-Verbindung '{Name}' fehlt der Benutzername.");
}
if (string.IsNullOrEmpty(CredentialSecret))
if (!credential.IsComplete)
{
throw new InvalidOperationException(
$"Bei der Sonic-Verbindung '{Name}' fehlen die Zugangsdaten. " +
"Bitte das Setup ausführen.");
"Bitte die Einstellungen öffnen und ein Benutzerprofil hinterlegen.");
}
string javaExecutablePath =
@@ -119,10 +97,10 @@ public sealed class DatabaseSonicConnection
Name = Name,
DomainName = DomainName,
ConnectionUrl = BuildConnectionUrl(),
Username = CredentialUserName,
Username = credential.UserName,
// Nur Laufzeitwert, bereits clientseitig entschlüsselt.
Password = CredentialSecret,
Password = credential.Secret,
JavaPath = javaExecutablePath,
JavaHome = javaHome,
@@ -34,10 +34,12 @@ internal static class Program
.GetAwaiter()
.GetResult();
if (setupResult.IsReady)
if (!setupResult.IsReady)
{
using SetupWizardForm setupForm =
new(coordinator);
new(
coordinator,
isSettingsMode: false);
DialogResult setupDialogResult =
setupForm.ShowDialog();
@@ -57,7 +59,7 @@ internal static class Program
{
MessageBox.Show(
"Die Einrichtung ist noch nicht vollständig.",
"Setup unvollständig",
"Einstellungen unvollständig",
MessageBoxButtons.OK,
MessageBoxIcon.Warning);
@@ -1,4 +1,5 @@
using Microsoft.Data.SqlClient;
using System.Data;
using Microsoft.Data.SqlClient;
using ZA.CoreService.ESBCertificateManager.Models;
namespace ZA.CoreService.ESBCertificateManager.Services;
@@ -20,65 +21,57 @@ public sealed class DeploymentTargetRepository
}
public async Task<IReadOnlyList<DeploymentTarget>> GetActiveAsync(
string environmentCode,
CancellationToken cancellationToken = default)
{
if (string.IsNullOrWhiteSpace(environmentCode))
{
throw new ArgumentException(
"Der EnvironmentCode fehlt.",
nameof(environmentCode));
}
const string sql = """
SELECT
target.CertificateTargetId,
target.TargetDirectory,
target.TargetFileName,
target.BackupEnabled,
target.BackupDirectoryName,
target.BackupRetentionDays,
target.IsActive AS TargetIsActive,
target.[CertificateTargetId],
target.[TargetDirectory],
target.[TargetFileName],
target.[BackupEnabled],
target.[BackupDirectoryName],
target.[IsActive] AS [TargetIsActive],
container.SonicContainerId,
container.ContainerName,
container.ContainerDisplayName,
container.RestartTimeoutSeconds,
container.[SonicContainerId],
container.[ContainerName],
container.[ContainerDisplayName],
container.[RestartTimeoutSeconds],
connection.ConnectionName,
connection.[ConnectionName],
service.ServiceCode,
service.ServiceName,
environment.[EnvironmentCode],
environment.[SortOrder] AS [EnvironmentSortOrder],
environment.EnvironmentCode,
environment.SortOrder AS EnvironmentSortOrder,
company.CompanyCode,
country.CountryCode
FROM dbo.CertificateTarget AS target
INNER JOIN dbo.SonicContainer AS container
ON container.SonicContainerId = target.SonicContainerId
INNER JOIN dbo.SonicConnection AS connection
ON connection.SonicConnectionId = container.SonicConnectionId
INNER JOIN dbo.EsbService AS service
ON service.EsbServiceId = container.EsbServiceId
INNER JOIN dbo.Company AS company
ON company.CompanyId = service.CompanyId
LEFT JOIN dbo.Country AS country
ON country.CountryId = service.CountryId
INNER JOIN dbo.Environment AS environment
ON environment.EnvironmentId = service.EnvironmentId
WHERE target.IsActive = 1
AND container.IsActive = 1
AND connection.IsActive = 1
AND service.IsActive = 1
AND company.IsActive = 1
AND environment.IsActive = 1
AND
(
country.CountryId IS NULL
OR country.IsActive = 1
)
company.[CompanyCode]
FROM [dbo].[CertificateTarget] AS target
INNER JOIN [dbo].[SonicContainer] AS container
ON container.[SonicContainerId] = target.[SonicContainerId]
INNER JOIN [dbo].[SonicConnection] AS connection
ON connection.[SonicConnectionId] = container.[SonicConnectionId]
INNER JOIN [dbo].[Environment] AS environment
ON environment.[EnvironmentId] = connection.[EnvironmentId]
INNER JOIN [dbo].[Company] AS company
ON company.[CompanyId] = container.[CompanyId]
WHERE target.[IsActive] = 1
AND container.[IsActive] = 1
AND connection.[IsActive] = 1
AND company.[IsActive] = 1
AND environment.[IsActive] = 1
AND environment.[EnvironmentCode] = @EnvironmentCode
ORDER BY
company.CompanyCode,
country.CountryCode,
environment.SortOrder,
service.ServiceCode,
container.ContainerName,
target.TargetDirectory,
target.TargetFileName;
company.[CompanyCode],
environment.[SortOrder],
container.[ContainerName],
target.[TargetDirectory],
target.[TargetFileName];
""";
List<DeploymentTarget> targets = [];
@@ -88,6 +81,17 @@ public sealed class DeploymentTargetRepository
await using SqlCommand command = new(sql, connection);
command.Parameters.Add(
new SqlParameter(
"@EnvironmentCode",
SqlDbType.NVarChar,
30)
{
Value = environmentCode
.Trim()
.ToUpperInvariant()
});
await using SqlDataReader reader =
await command.ExecuteReaderAsync(cancellationToken);
@@ -106,9 +110,6 @@ public sealed class DeploymentTargetRepository
int backupDirectoryNameOrdinal =
reader.GetOrdinal("BackupDirectoryName");
int backupRetentionDaysOrdinal =
reader.GetOrdinal("BackupRetentionDays");
int targetIsActiveOrdinal =
reader.GetOrdinal("TargetIsActive");
@@ -124,12 +125,6 @@ public sealed class DeploymentTargetRepository
int connectionNameOrdinal =
reader.GetOrdinal("ConnectionName");
int serviceCodeOrdinal =
reader.GetOrdinal("ServiceCode");
int serviceNameOrdinal =
reader.GetOrdinal("ServiceName");
int environmentCodeOrdinal =
reader.GetOrdinal("EnvironmentCode");
@@ -139,9 +134,6 @@ public sealed class DeploymentTargetRepository
int companyCodeOrdinal =
reader.GetOrdinal("CompanyCode");
int countryCodeOrdinal =
reader.GetOrdinal("CountryCode");
while (await reader.ReadAsync(cancellationToken))
{
string containerName =
@@ -152,34 +144,19 @@ public sealed class DeploymentTargetRepository
reader,
containerDisplayNameOrdinal);
string serviceCode =
reader.GetString(serviceCodeOrdinal);
string serviceName =
reader.GetString(serviceNameOrdinal);
string companyCode =
reader.GetString(companyCodeOrdinal);
string? countryCode =
ReadNullableString(reader, countryCodeOrdinal);
string displayName =
string.IsNullOrWhiteSpace(containerDisplayName)
? containerName
: containerDisplayName;
string locationCode =
string.IsNullOrWhiteSpace(countryCode)
? companyCode
: $"{companyCode}/{countryCode}";
targets.Add(new DeploymentTarget
{
Id = reader.GetInt32(targetIdOrdinal),
Name =
$"{locationCode} / {serviceName} / {displayName}",
Name = $"{companyCode} / {displayName}",
Environment =
reader.GetString(environmentCodeOrdinal),
@@ -199,10 +176,7 @@ public sealed class DeploymentTargetRepository
BackupDirectoryName =
reader.GetString(backupDirectoryNameOrdinal),
BackupRetentionDays =
ReadNullableInt32(
reader,
backupRetentionDaysOrdinal),
BackupRetentionDays = null,
ContainerName = containerName,
@@ -238,13 +212,4 @@ public sealed class DeploymentTargetRepository
? null
: reader.GetString(ordinal);
}
private static int? ReadNullableInt32(
SqlDataReader reader,
int ordinal)
{
return reader.IsDBNull(ordinal)
? null
: reader.GetInt32(ordinal);
}
}
@@ -44,7 +44,7 @@ public sealed class LocalSetupSelectionStore
catch
{
// Eine beschädigte lokale Auswahl darf den Start
// nicht verhindern. Das Setup wird erneut angezeigt.
// nicht verhindern. Die Einstellungen werden erneut angezeigt.
return null;
}
}
@@ -60,7 +60,7 @@ public sealed class LocalSetupSelectionStore
if (string.IsNullOrWhiteSpace(directory))
{
throw new InvalidOperationException(
"Der lokale Setup-Ordner konnte nicht bestimmt werden.");
"Der lokale Einstellungen-Ordner konnte nicht bestimmt werden.");
}
Directory.CreateDirectory(directory);
@@ -23,26 +23,31 @@ public sealed class SonicConnectionRepository
public async Task<IReadOnlyList<DatabaseSonicConnection>>
GetActiveAsync(
string? environmentCode = null,
CancellationToken cancellationToken = default)
{
const string sql = """
SELECT
SonicConnectionId,
ConnectionName,
ManagementHost,
ManagementPort,
ConnectionProtocol,
DomainName,
CredentialUserName,
CredentialReference,
CredentialSecret,
JavaHomePath,
SonicHomePath,
Notes,
IsActive
FROM dbo.SonicConnection
WHERE IsActive = 1
ORDER BY ConnectionName;
connection.[SonicConnectionId],
connection.[ConnectionName],
connection.[ManagementHost],
connection.[ManagementPort],
connection.[ConnectionProtocol],
connection.[DomainName],
environment.[EnvironmentCode],
connection.[IsActive]
FROM [dbo].[SonicConnection] AS connection
INNER JOIN [dbo].[Environment] AS environment
ON environment.[EnvironmentId] =
connection.[EnvironmentId]
WHERE connection.[IsActive] = 1
AND environment.[IsActive] = 1
AND
(
@EnvironmentCode IS NULL
OR environment.[EnvironmentCode] = @EnvironmentCode
)
ORDER BY connection.[ConnectionName];
""";
List<DatabaseSonicConnection> connections = [];
@@ -55,6 +60,22 @@ public sealed class SonicConnectionRepository
await using SqlCommand command =
new(sql, connection);
string? normalizedEnvironmentCode =
string.IsNullOrWhiteSpace(environmentCode)
? null
: environmentCode.Trim().ToUpperInvariant();
command.Parameters.Add(
new SqlParameter(
"@EnvironmentCode",
SqlDbType.NVarChar,
30)
{
Value = normalizedEnvironmentCode is null
? DBNull.Value
: normalizedEnvironmentCode
});
await using SqlDataReader reader =
await command.ExecuteReaderAsync(
cancellationToken);
@@ -77,23 +98,8 @@ public sealed class SonicConnectionRepository
int domainOrdinal =
reader.GetOrdinal("DomainName");
int userNameOrdinal =
reader.GetOrdinal("CredentialUserName");
int credentialReferenceOrdinal =
reader.GetOrdinal("CredentialReference");
int credentialSecretOrdinal =
reader.GetOrdinal("CredentialSecret");
int javaHomeOrdinal =
reader.GetOrdinal("JavaHomePath");
int sonicHomeOrdinal =
reader.GetOrdinal("SonicHomePath");
int notesOrdinal =
reader.GetOrdinal("Notes");
int environmentCodeOrdinal =
reader.GetOrdinal("EnvironmentCode");
int isActiveOrdinal =
reader.GetOrdinal("IsActive");
@@ -112,9 +118,7 @@ public sealed class SonicConnectionRepository
reader.GetString(hostOrdinal),
ManagementPort =
ReadNullableInt32(
reader,
portOrdinal),
reader.GetInt32(portOrdinal),
ConnectionProtocol =
ReadNullableString(
@@ -126,35 +130,10 @@ public sealed class SonicConnectionRepository
reader,
domainOrdinal),
CredentialUserName =
EnvironmentCode =
ReadNullableString(
reader,
userNameOrdinal),
CredentialReference =
ReadNullableString(
reader,
credentialReferenceOrdinal),
CredentialSecret =
ReadNullableString(
reader,
credentialSecretOrdinal),
JavaHomePath =
ReadNullableString(
reader,
javaHomeOrdinal),
SonicHomePath =
ReadNullableString(
reader,
sonicHomeOrdinal),
Notes =
ReadNullableString(
reader,
notesOrdinal),
environmentCodeOrdinal),
IsActive =
reader.GetBoolean(
@@ -165,154 +144,6 @@ public sealed class SonicConnectionRepository
return connections;
}
public async Task SaveCredentialsAsync(
int sonicConnectionId,
string credentialUserName,
string credentialSecret,
CancellationToken cancellationToken = default)
{
if (sonicConnectionId <= 0)
{
throw new ArgumentOutOfRangeException(
nameof(sonicConnectionId),
"Die SonicConnectionId ist ungültig.");
}
if (string.IsNullOrWhiteSpace(
credentialUserName))
{
throw new ArgumentException(
"Der Sonic-Benutzername fehlt.",
nameof(credentialUserName));
}
if (string.IsNullOrEmpty(
credentialSecret))
{
throw new ArgumentException(
"Das Sonic-Kennwort fehlt.",
nameof(credentialSecret));
}
string normalizedUserName =
credentialUserName.Trim();
if (normalizedUserName.Length > 256)
{
throw new ArgumentException(
"Der Sonic-Benutzername darf maximal 256 Zeichen enthalten.",
nameof(credentialUserName));
}
if (credentialSecret.Length > 512)
{
throw new ArgumentException(
"Das Sonic-Kennwort darf maximal 512 Zeichen enthalten.",
nameof(credentialSecret));
}
const string sql = """
UPDATE dbo.SonicConnection
SET
CredentialUserName = @CredentialUserName,
CredentialSecret = @CredentialSecret,
UpdatedAtUtc = SYSUTCDATETIME()
WHERE SonicConnectionId = @SonicConnectionId
AND IsActive = 1;
""";
await using SqlConnection connection =
new(_connectionString);
await connection.OpenAsync(cancellationToken);
await using SqlCommand command =
new(sql, connection);
command.Parameters.Add(
new SqlParameter(
"@CredentialUserName",
SqlDbType.NVarChar,
256)
{
Value = normalizedUserName
});
command.Parameters.Add(
new SqlParameter(
"@CredentialSecret",
SqlDbType.NVarChar,
512)
{
Value = credentialSecret
});
command.Parameters.Add(
new SqlParameter(
"@SonicConnectionId",
SqlDbType.Int)
{
Value = sonicConnectionId
});
int affectedRows =
await command.ExecuteNonQueryAsync(
cancellationToken);
if (affectedRows != 1)
{
throw new InvalidOperationException(
"Die aktive Sonic-Verbindung wurde nicht eindeutig gefunden.");
}
}
public async Task ClearCredentialsAsync(
int sonicConnectionId,
CancellationToken cancellationToken = default)
{
if (sonicConnectionId <= 0)
{
throw new ArgumentOutOfRangeException(
nameof(sonicConnectionId),
"Die SonicConnectionId ist ungültig.");
}
const string sql = """
UPDATE dbo.SonicConnection
SET
CredentialUserName = NULL,
CredentialSecret = NULL,
UpdatedAtUtc = SYSUTCDATETIME()
WHERE SonicConnectionId = @SonicConnectionId;
""";
await using SqlConnection connection =
new(_connectionString);
await connection.OpenAsync(cancellationToken);
await using SqlCommand command =
new(sql, connection);
command.Parameters.Add(
new SqlParameter(
"@SonicConnectionId",
SqlDbType.Int)
{
Value = sonicConnectionId
});
int affectedRows =
await command.ExecuteNonQueryAsync(
cancellationToken);
if (affectedRows != 1)
{
throw new InvalidOperationException(
"Die Sonic-Verbindung wurde nicht eindeutig gefunden.");
}
}
private static string? ReadNullableString(
SqlDataReader reader,
int ordinal)
@@ -321,13 +152,4 @@ public sealed class SonicConnectionRepository
? null
: reader.GetString(ordinal);
}
private static int? ReadNullableInt32(
SqlDataReader reader,
int ordinal)
{
return reader.IsDBNull(ordinal)
? null
: reader.GetInt32(ordinal);
}
}
@@ -60,7 +60,7 @@ public sealed class SonicMfApiExecutor
null,
"Für die Sonic-Verbindung sind keine " +
"vollständigen Zugangsdaten eingerichtet. " +
"Bitte das Setup ausführen.");
"Bitte die Einstellungen öffnen und Zugangsdaten hinterlegen.");
}
if (string.IsNullOrWhiteSpace(
@@ -145,8 +145,8 @@ public sealed class SonicMfApiExecutor
* übergeben. Dadurch erscheint das Kennwort nicht in
* der Prozessargumentliste.
*
* CredentialSecret wurde zuvor durch Microsoft.Data.SqlClient
* clientseitig entschlüsselt und als Laufzeitwert in
* Das Kennwort stammt aus dbo.SonicCredential (Always Encrypted),
* wurde clientseitig entschlüsselt und als Laufzeitwert in
* SonicConnection.Password übernommen.
*/
startInfo.Environment[
@@ -33,40 +33,36 @@ public sealed class SonicSetupRepository
const string sql = """
SELECT
connection.SonicConnectionId,
connection.ConnectionName,
environment.EnvironmentCode,
connection.DomainName,
connection.ManagementHost,
connection.ManagementPort,
connection.ConnectionProtocol,
MIN(container.ContainerName)
AS ValidationContainerName
FROM dbo.SonicConnection AS connection
INNER JOIN dbo.SonicContainer AS container
ON container.SonicConnectionId =
connection.SonicConnectionId
INNER JOIN dbo.EsbService AS service
ON service.EsbServiceId =
container.EsbServiceId
INNER JOIN dbo.Environment AS environment
ON environment.EnvironmentId =
service.EnvironmentId
WHERE connection.IsActive = 1
AND container.IsActive = 1
AND service.IsActive = 1
AND environment.IsActive = 1
AND environment.EnvironmentCode =
connection.[SonicConnectionId],
connection.[ConnectionName],
environment.[EnvironmentCode],
connection.[DomainName],
connection.[ManagementHost],
connection.[ManagementPort],
connection.[ConnectionProtocol],
MIN(container.[ContainerName])
AS [ValidationContainerName]
FROM [dbo].[SonicConnection] AS connection
INNER JOIN [dbo].[Environment] AS environment
ON environment.[EnvironmentId] =
connection.[EnvironmentId]
INNER JOIN [dbo].[SonicContainer] AS container
ON container.[SonicConnectionId] =
connection.[SonicConnectionId]
WHERE connection.[IsActive] = 1
AND container.[IsActive] = 1
AND environment.[IsActive] = 1
AND environment.[EnvironmentCode] =
@EnvironmentCode
GROUP BY
connection.SonicConnectionId,
connection.ConnectionName,
environment.EnvironmentCode,
connection.DomainName,
connection.ManagementHost,
connection.ManagementPort,
connection.ConnectionProtocol
ORDER BY connection.ConnectionName;
connection.[SonicConnectionId],
connection.[ConnectionName],
environment.[EnvironmentCode],
connection.[DomainName],
connection.[ManagementHost],
connection.[ManagementPort],
connection.[ConnectionProtocol]
ORDER BY connection.[ConnectionName];
""";
List<SonicSystemOption> systems = [];
@@ -119,11 +115,6 @@ public sealed class SonicSetupRepository
while (await reader.ReadAsync(cancellationToken))
{
if (reader.IsDBNull(managementPortOrdinal))
{
continue;
}
systems.Add(
new SonicSystemOption
{
@@ -248,13 +239,14 @@ public sealed class SonicSetupRepository
if (isDefault)
{
const string clearDefaultSql = """
UPDATE dbo.SonicCredential
UPDATE [dbo].[SonicCredential]
SET
IsDefault = 0,
UpdatedAtUtc = SYSUTCDATETIME()
WHERE SonicConnectionId =
[IsDefault] = 0,
[ModifiedDateTime] = SYSUTCDATETIME(),
[ModifiedBy] = SUSER_SNAME()
WHERE [SonicConnectionId] =
@SonicConnectionId
AND IsDefault = 1;
AND [IsDefault] = 1;
""";
await using SqlCommand clearDefaultCommand =
@@ -276,18 +268,20 @@ public sealed class SonicSetupRepository
}
const string insertSql = """
INSERT INTO dbo.SonicCredential
INSERT INTO [dbo].[SonicCredential]
(
SonicConnectionId,
CredentialName,
CredentialUserName,
CredentialSecret,
IsDefault,
IsActive,
CreatedAtUtc,
UpdatedAtUtc
[SonicConnectionId],
[CredentialName],
[CredentialUserName],
[CredentialSecret],
[IsDefault],
[IsActive],
[CreationDateTime],
[CreatedBy],
[ModifiedDateTime],
[ModifiedBy]
)
OUTPUT INSERTED.SonicCredentialId
OUTPUT INSERTED.[SonicCredentialId]
VALUES
(
@SonicConnectionId,
@@ -297,6 +291,8 @@ public sealed class SonicSetupRepository
@IsDefault,
1,
SYSUTCDATETIME(),
SUSER_SNAME(),
NULL,
NULL
);
""";
@@ -397,19 +393,19 @@ public sealed class SonicSetupRepository
const string sql = """
SELECT
SonicCredentialId,
SonicConnectionId,
CredentialName,
CredentialUserName,
CredentialSecret,
IsDefault,
IsActive
FROM dbo.SonicCredential
WHERE SonicConnectionId = @SonicConnectionId
AND IsActive = 1
[SonicCredentialId],
[SonicConnectionId],
[CredentialName],
[CredentialUserName],
[CredentialSecret],
[IsDefault],
[IsActive]
FROM [dbo].[SonicCredential]
WHERE [SonicConnectionId] = @SonicConnectionId
AND [IsActive] = 1
ORDER BY
IsDefault DESC,
CredentialName;
[IsDefault] DESC,
[CredentialName];
""";
List<SonicCredentialProfile> profiles = [];
@@ -502,4 +498,101 @@ public sealed class SonicSetupRepository
return profiles;
}
public async Task<SonicCredentialProfile?> GetCredentialByIdAsync(
int sonicCredentialId,
CancellationToken cancellationToken = default)
{
if (sonicCredentialId <= 0)
{
throw new ArgumentOutOfRangeException(
nameof(sonicCredentialId));
}
const string sql = """
SELECT
[SonicCredentialId],
[SonicConnectionId],
[CredentialName],
[CredentialUserName],
[CredentialSecret],
[IsDefault],
[IsActive]
FROM [dbo].[SonicCredential]
WHERE [SonicCredentialId] = @SonicCredentialId
AND [IsActive] = 1;
""";
await using SqlConnection connection =
new(_connectionString);
await connection.OpenAsync(cancellationToken);
await using SqlCommand command =
new(sql, connection);
command.Parameters.Add(
new SqlParameter(
"@SonicCredentialId",
SqlDbType.Int)
{
Value = sonicCredentialId
});
await using SqlDataReader reader =
await command.ExecuteReaderAsync(cancellationToken);
if (!await reader.ReadAsync(cancellationToken))
{
return null;
}
int userNameOrdinal =
reader.GetOrdinal("CredentialUserName");
int secretOrdinal =
reader.GetOrdinal("CredentialSecret");
string? userName =
reader.IsDBNull(userNameOrdinal)
? null
: reader.GetString(userNameOrdinal);
string? secret =
reader.IsDBNull(secretOrdinal)
? null
: reader.GetString(secretOrdinal);
if (string.IsNullOrWhiteSpace(userName)
|| string.IsNullOrEmpty(secret))
{
return null;
}
return new SonicCredentialProfile
{
SonicCredentialId =
reader.GetInt32(
reader.GetOrdinal("SonicCredentialId")),
SonicConnectionId =
reader.GetInt32(
reader.GetOrdinal("SonicConnectionId")),
CredentialName =
reader.GetString(
reader.GetOrdinal("CredentialName")),
UserName = userName,
Secret = secret,
IsDefault =
reader.GetBoolean(
reader.GetOrdinal("IsDefault")),
IsActive =
reader.GetBoolean(
reader.GetOrdinal("IsActive"))
};
}
}
@@ -5,6 +5,7 @@ namespace ZA.CoreService.ESBCertificateManager.Setup;
public sealed class SetupWizardForm : Form
{
private readonly SetupCoordinator _coordinator;
private readonly bool _isSettingsMode;
private readonly Color _backgroundColor =
Color.FromArgb(10, 18, 34);
@@ -49,9 +50,11 @@ public sealed class SetupWizardForm : Form
private bool _running;
public SetupWizardForm(
SetupCoordinator coordinator)
SetupCoordinator coordinator,
bool isSettingsMode = false)
{
_coordinator = coordinator;
_isSettingsMode = isSettingsMode;
BuildInterface();
@@ -61,7 +64,7 @@ public sealed class SetupWizardForm : Form
private void BuildInterface()
{
Text = "ESB Certificate Manager einrichten";
Text = "Einstellungen";
StartPosition = FormStartPosition.CenterScreen;
Size = new Size(950, 690);
MinimumSize = new Size(900, 650);
@@ -73,7 +76,7 @@ public sealed class SetupWizardForm : Form
Label title = new()
{
Text = "Ersteinrichtung",
Text = "Einstellungen",
AutoSize = true,
Location = new Point(38, 25),
ForeColor = _textColor,
@@ -85,8 +88,9 @@ public sealed class SetupWizardForm : Form
Label subtitle = new()
{
Text =
"Runtime, Datenbank, Zertifikat und Systemauswahl prüfen.",
Text = _isSettingsMode
? "Runtime, Zertifikat, System und Benutzerprofil anpassen."
: "Runtime, Datenbank, Zertifikat und Systemauswahl prüfen.",
AutoSize = true,
Location = new Point(42, 70),
ForeColor = _mutedTextColor
@@ -244,7 +248,7 @@ public sealed class SetupWizardForm : Form
await InitializeAsync();
Button cancelButton = CreateButton(
"Abbrechen");
_isSettingsMode ? "Schließen" : "Abbrechen");
cancelButton.Location =
new Point(675, 580);
@@ -252,14 +256,30 @@ public sealed class SetupWizardForm : Form
cancelButton.Size =
new Size(110, 42);
cancelButton.Click += (_, _) =>
cancelButton.Click += async (_, _) =>
{
if (_isSettingsMode)
{
// Nach gespeicherter Auswahl die Hauptansicht aktualisieren.
SetupCheckResult check =
await _coordinator.CheckAsync();
DialogResult = check.IsReady
? DialogResult.OK
: DialogResult.Cancel;
}
else
{
DialogResult = DialogResult.Cancel;
}
Close();
};
_btnFinish = CreateButton(
"Setup abschließen");
_isSettingsMode
? "Übernehmen"
: "Fertig");
_btnFinish.Location =
new Point(795, 580);
@@ -338,7 +358,7 @@ public sealed class SetupWizardForm : Form
MessageBox.Show(
this,
ex.Message,
"Setup fehlgeschlagen",
"Einstellungen fehlgeschlagen",
MessageBoxButtons.OK,
MessageBoxIcon.Error);
}
@@ -590,7 +610,7 @@ public sealed class SetupWizardForm : Form
MessageBox.Show(
this,
"System und Benutzerprofil wurden ausgewählt.",
"Setup",
"Einstellungen",
MessageBoxButtons.OK,
MessageBoxIcon.Information);
@@ -707,7 +727,7 @@ public sealed class SetupWizardForm : Form
MessageBox.Show(
this,
message,
"Setup",
"Einstellungen",
MessageBoxButtons.OK,
MessageBoxIcon.Warning);
}
@@ -1,9 +1,9 @@
{
//TEST, PROD
// TEST2, TEST, PROD
"EnvironmentCode": "TEST",
"LogDirectory": "Logs",
"Database": {
"ConnectionString": "Server=VWEBDEV01;Database=EsbZertifkatManager;Integrated Security=True;Encrypt=True;Column Encryption Setting=Enabled;Application Name=ZA.CoreService.ESBCertificateManager;TrustServerCertificate=True;"
"ConnectionString": "Server=VWEBDEV01;Database=EsbZertifikatManager;Integrated Security=True;Encrypt=True;Column Encryption Setting=Enabled;Application Name=ZA.CoreService.ESBCertificateManager;TrustServerCertificate=True;"
},
"Runtime": {
"JavaExecutablePath": "Runtime\\bin\\java.exe",