Unterschiede
Hier werden die Unterschiede zwischen zwei Versionen angezeigt.
| Nächste Überarbeitung | Vorhergehende Überarbeitung | ||
| de:int:wvdsshell:notes:01-auth-architecture:auth-migration [2026/03/05 14:27] – angelegt - Externe Bearbeitung 127.0.0.1 | de:int:wvdsshell:notes:01-auth-architecture:auth-migration [Unbekanntes Datum] (aktuell) – gelöscht - Externe Bearbeitung (Unbekanntes Datum) 127.0.0.1 | ||
|---|---|---|---|
| Zeile 1: | Zeile 1: | ||
| - | ====== Auth-Migration — Legacy-Systeme ====== | ||
| - | |||
| - | //Stand: 2026-03-05// | ||
| - | |||
| - | Übergeordnet: | ||
| - | Verwandt: [[de: | ||
| - | |||
| - | ===== Migrations-Übersicht ===== | ||
| - | |||
| - | ^ Phase ^ Inhalt | ||
| - | | 1 | '' | ||
| - | | 2 | LD-System: ENIVERS '' | ||
| - | | 3 | AMED Bestandsdaten (Branches, Devices, Facilities) → ENIVERSCAFM | Ausstehend | ||
| - | | 4 | ENIVERSPIMS aufbauen; WIS/ | ||
| - | | 5 | ENIVERSASYS aufbauen; Feature-Flags aus ENIVERSCAFM auslagern | ||
| - | |||
| - | ===== Phase 1 — ENIVERSCAFM auth.* → ENIVERSSCCM ===== | ||
| - | |||
| - | ==== Ausgangslage ==== | ||
| - | |||
| - | Die Auth-Tabellen ('' | ||
| - | **ENIVERSCAFM**. Ziel war die Konsolidierung: | ||
| - | Identity-Datenbank **ENIVERSSCCM**. ENIVERSCAFM erhält danach Synonyme — bestehender | ||
| - | Code funktioniert transparent weiter ohne Änderungen. | ||
| - | |||
| - | ==== Mapping: auth.* (13 Tabellen + core.person) ==== | ||
| - | |||
| - | ^ ENIVERSCAFM (Quelle) | ||
| - | | '' | ||
| - | | '' | ||
| - | | '' | ||
| - | | '' | ||
| - | | '' | ||
| - | | '' | ||
| - | | '' | ||
| - | | '' | ||
| - | | '' | ||
| - | | '' | ||
| - | | '' | ||
| - | | '' | ||
| - | | '' | ||
| - | | '' | ||
| - | |||
| - | > **Hinweis: | ||
| - | > Referenzielle Integrität zwischen ENIVERSCAFM und ENIVERSSCCM wird app-seitig | ||
| - | > (Gateway.Service) sichergestellt. | ||
| - | |||
| - | ==== Skripte Phase 1 ==== | ||
| - | |||
| - | **Ausführungsreihenfolge: | ||
| - | |||
| - | - '' | ||
| - | - '' | ||
| - | - '' | ||
| - | - '' | ||
| - | |||
| - | === sccm_create_tables.sql — ENIVERSSCCM Schema + Tabellen === | ||
| - | |||
| - | <code sql> | ||
| - | /* ================================================================ | ||
| - | | ||
| - | | ||
| - | | ||
| - | | ||
| - | | ||
| - | USE ENIVERSSCCM; | ||
| - | GO | ||
| - | |||
| - | -- Schema ' | ||
| - | IF NOT EXISTS (SELECT 1 FROM sys.schemas WHERE name = ' | ||
| - | EXEC(' | ||
| - | PRINT ' | ||
| - | GO | ||
| - | |||
| - | -- ------------------------------------------------------------------ | ||
| - | -- 1. auth.permission — Berechtigungs-Objekte (Resource / Action / Scope) | ||
| - | -- ------------------------------------------------------------------ | ||
| - | IF NOT EXISTS ( | ||
| - | SELECT 1 FROM sys.tables t | ||
| - | JOIN sys.schemas s ON s.schema_id = t.schema_id | ||
| - | WHERE s.name = ' | ||
| - | ) | ||
| - | BEGIN | ||
| - | CREATE TABLE auth.permission ( | ||
| - | id INT NOT NULL IDENTITY(1, | ||
| - | resource | ||
| - | action | ||
| - | scope | ||
| - | description NVARCHAR(256) | ||
| - | CONSTRAINT pk_permission PRIMARY KEY (id), | ||
| - | CONSTRAINT uq_permission UNIQUE (resource, action, scope) | ||
| - | ); | ||
| - | PRINT ' | ||
| - | END | ||
| - | GO | ||
| - | |||
| - | -- ------------------------------------------------------------------ | ||
| - | -- 2. auth.role — Rollen-Definitionen | ||
| - | -- ------------------------------------------------------------------ | ||
| - | IF NOT EXISTS ( | ||
| - | SELECT 1 FROM sys.tables t | ||
| - | JOIN sys.schemas s ON s.schema_id = t.schema_id | ||
| - | WHERE s.name = ' | ||
| - | ) | ||
| - | BEGIN | ||
| - | CREATE TABLE auth.role ( | ||
| - | id | ||
| - | code | ||
| - | name | ||
| - | description | ||
| - | is_system_role BIT NOT NULL CONSTRAINT df_role_system | ||
| - | is_active | ||
| - | created_at | ||
| - | updated_at | ||
| - | CONSTRAINT pk_role | ||
| - | CONSTRAINT uq_role_code UNIQUE (code) | ||
| - | ); | ||
| - | PRINT ' | ||
| - | END | ||
| - | GO | ||
| - | |||
| - | -- ------------------------------------------------------------------ | ||
| - | -- 3. auth.[user] — Anmeldedaten, | ||
| - | -- Hinweis: person_id referenziert core.person (Intra-DB-FK, | ||
| - | -- wird nach Daten-Migration in sccm_person.sql gesetzt) | ||
| - | -- ------------------------------------------------------------------ | ||
| - | IF NOT EXISTS ( | ||
| - | SELECT 1 FROM sys.tables t | ||
| - | JOIN sys.schemas s ON s.schema_id = t.schema_id | ||
| - | WHERE s.name = ' | ||
| - | ) | ||
| - | BEGIN | ||
| - | CREATE TABLE auth.[user] ( | ||
| - | id INT NOT NULL IDENTITY(1, | ||
| - | person_id | ||
| - | username | ||
| - | email | ||
| - | -- Passwort-Felder: | ||
| - | password_hash | ||
| - | password_salt | ||
| - | password_changed_at | ||
| - | password_failed_attempts INT NOT NULL CONSTRAINT df_user_pw_fails | ||
| - | password_locked_until | ||
| - | -- TOTP-Felder: | ||
| - | totp_secret | ||
| - | totp_enabled | ||
| - | totp_verified_at | ||
| - | totp_failed_attempts | ||
| - | totp_locked_until | ||
| - | totp_pending_secret | ||
| - | totp_pending_expires_at DATETIME2 | ||
| - | last_mfa_at | ||
| - | last_mfa_method | ||
| - | is_active | ||
| - | last_login_at | ||
| - | created_at | ||
| - | updated_at | ||
| - | CONSTRAINT pk_user | ||
| - | CONSTRAINT uq_user_person | ||
| - | CONSTRAINT uq_user_username UNIQUE (username) | ||
| - | ); | ||
| - | CREATE INDEX ix_user_person | ||
| - | CREATE INDEX ix_user_username | ||
| - | CREATE INDEX ix_user_active | ||
| - | CREATE INDEX ix_user_totp_enabled ON auth.[user] (totp_enabled); | ||
| - | PRINT ' | ||
| - | END | ||
| - | GO | ||
| - | |||
| - | -- ------------------------------------------------------------------ | ||
| - | -- 4. auth.device — Geräte-Sessions, | ||
| - | -- ------------------------------------------------------------------ | ||
| - | IF NOT EXISTS ( | ||
| - | SELECT 1 FROM sys.tables t | ||
| - | JOIN sys.schemas s ON s.schema_id = t.schema_id | ||
| - | WHERE s.name = ' | ||
| - | ) | ||
| - | BEGIN | ||
| - | CREATE TABLE auth.device ( | ||
| - | id | ||
| - | device_id | ||
| - | user_id | ||
| - | name | ||
| - | passkey_credential_id | ||
| - | passkey_public_key | ||
| - | pq_dsa_public_key | ||
| - | pq_dsa_key_id | ||
| - | pq_kem_public_key | ||
| - | pq_kem_key_id | ||
| - | pq_key_created_at | ||
| - | pq_dsa_public_key_prev | ||
| - | pq_dsa_key_id_prev | ||
| - | pq_kem_public_key_prev | ||
| - | pq_kem_key_id_prev | ||
| - | pq_key_prev_expires_at | ||
| - | refresh_token_hash | ||
| - | refresh_token_expires_at DATETIME2 | ||
| - | refresh_family_id | ||
| - | refresh_generation | ||
| - | last_ip | ||
| - | last_geo_country | ||
| - | last_geo_region | ||
| - | last_asn | ||
| - | last_asn_type | ||
| - | last_user_agent | ||
| - | session_state | ||
| - | session_hold_until | ||
| - | session_hold_reason | ||
| - | session_revoked_at | ||
| - | session_revoked_reason | ||
| - | is_active | ||
| - | last_used_at | ||
| - | created_at | ||
| - | CONSTRAINT pk_device | ||
| - | CONSTRAINT uq_device_id | ||
| - | CONSTRAINT fk_device_user FOREIGN KEY (user_id) REFERENCES auth.[user](id) | ||
| - | ); | ||
| - | CREATE INDEX ix_device_user | ||
| - | CREATE INDEX ix_device_user_active | ||
| - | CREATE INDEX ix_device_session_state ON auth.device (session_state, | ||
| - | CREATE INDEX ix_device_refresh_family ON auth.device (refresh_family_id); | ||
| - | PRINT ' | ||
| - | END | ||
| - | GO | ||
| - | |||
| - | -- ------------------------------------------------------------------ | ||
| - | -- 5. auth.backup_code — MFA Backup-Codes (gehashed, CWE-256) | ||
| - | -- ------------------------------------------------------------------ | ||
| - | IF NOT EXISTS ( | ||
| - | SELECT 1 FROM sys.tables t | ||
| - | JOIN sys.schemas s ON s.schema_id = t.schema_id | ||
| - | WHERE s.name = ' | ||
| - | ) | ||
| - | BEGIN | ||
| - | CREATE TABLE auth.backup_code ( | ||
| - | id | ||
| - | user_id | ||
| - | code_hash | ||
| - | code_prefix | ||
| - | is_used | ||
| - | used_at | ||
| - | used_from_ip VARCHAR(45) | ||
| - | created_at | ||
| - | CONSTRAINT pk_backup_code PRIMARY KEY (id), | ||
| - | CONSTRAINT fk_bc_user | ||
| - | ); | ||
| - | CREATE INDEX ix_backup_code_user ON auth.backup_code (user_id, is_used); | ||
| - | PRINT ' | ||
| - | END | ||
| - | GO | ||
| - | |||
| - | -- ------------------------------------------------------------------ | ||
| - | -- 6. auth.known_location — Bekannte Standorte (Geo-IP, MFA-verifiziert) | ||
| - | -- ------------------------------------------------------------------ | ||
| - | IF NOT EXISTS ( | ||
| - | SELECT 1 FROM sys.tables t | ||
| - | JOIN sys.schemas s ON s.schema_id = t.schema_id | ||
| - | WHERE s.name = ' | ||
| - | ) | ||
| - | BEGIN | ||
| - | CREATE TABLE auth.known_location ( | ||
| - | id | ||
| - | user_id | ||
| - | geo_country | ||
| - | geo_region | ||
| - | asn INT NULL, | ||
| - | first_seen_at | ||
| - | last_seen_at | ||
| - | expires_at | ||
| - | verified_via_mfa BIT NOT NULL CONSTRAINT df_kl_mfa | ||
| - | CONSTRAINT pk_known_location PRIMARY KEY (id), | ||
| - | CONSTRAINT uq_known_location UNIQUE (user_id, geo_country, | ||
| - | CONSTRAINT fk_kl_user | ||
| - | ); | ||
| - | CREATE INDEX ix_known_location_user ON auth.known_location (user_id, expires_at); | ||
| - | PRINT ' | ||
| - | END | ||
| - | GO | ||
| - | |||
| - | -- ------------------------------------------------------------------ | ||
| - | -- 7. auth.mfa_session — TOTP Challenge-Sessions (In-Memory-Äquivalent in DB) | ||
| - | -- ------------------------------------------------------------------ | ||
| - | IF NOT EXISTS ( | ||
| - | SELECT 1 FROM sys.tables t | ||
| - | JOIN sys.schemas s ON s.schema_id = t.schema_id | ||
| - | WHERE s.name = ' | ||
| - | ) | ||
| - | BEGIN | ||
| - | CREATE TABLE auth.mfa_session ( | ||
| - | id | ||
| - | mfa_session_id VARCHAR(64) NOT NULL, | ||
| - | user_id | ||
| - | device_id | ||
| - | reason | ||
| - | original_action VARCHAR(50) | ||
| - | is_verified | ||
| - | verified_method VARCHAR(20) | ||
| - | attempts | ||
| - | created_at | ||
| - | expires_at | ||
| - | verified_at | ||
| - | CONSTRAINT pk_mfa_session | ||
| - | CONSTRAINT uq_mfa_session_id UNIQUE (mfa_session_id), | ||
| - | CONSTRAINT fk_mfas_user | ||
| - | CONSTRAINT fk_mfas_device | ||
| - | ); | ||
| - | CREATE INDEX ix_mfa_session_user ON auth.mfa_session (user_id, created_at); | ||
| - | PRINT ' | ||
| - | END | ||
| - | GO | ||
| - | |||
| - | -- ------------------------------------------------------------------ | ||
| - | -- 8. auth.nonce_cache — Replay-Protection (jti-Blacklist) | ||
| - | -- ------------------------------------------------------------------ | ||
| - | IF NOT EXISTS ( | ||
| - | SELECT 1 FROM sys.tables t | ||
| - | JOIN sys.schemas s ON s.schema_id = t.schema_id | ||
| - | WHERE s.name = ' | ||
| - | ) | ||
| - | BEGIN | ||
| - | CREATE TABLE auth.nonce_cache ( | ||
| - | nonce | ||
| - | device_id | ||
| - | received_at DATETIME2 | ||
| - | expires_at | ||
| - | CONSTRAINT pk_nonce_cache PRIMARY KEY (nonce) | ||
| - | ); | ||
| - | CREATE INDEX ix_nonce_expires ON auth.nonce_cache (expires_at); | ||
| - | PRINT ' | ||
| - | END | ||
| - | GO | ||
| - | |||
| - | -- ------------------------------------------------------------------ | ||
| - | -- 9. auth.rate_limit_event — Rate-Limit Protokoll | ||
| - | -- ------------------------------------------------------------------ | ||
| - | IF NOT EXISTS ( | ||
| - | SELECT 1 FROM sys.tables t | ||
| - | JOIN sys.schemas s ON s.schema_id = t.schema_id | ||
| - | WHERE s.name = ' | ||
| - | ) | ||
| - | BEGIN | ||
| - | CREATE TABLE auth.rate_limit_event ( | ||
| - | id | ||
| - | user_id | ||
| - | device_id | ||
| - | ip_address VARCHAR(45) NOT NULL, | ||
| - | event_type VARCHAR(30) NOT NULL, | ||
| - | created_at DATETIME2 | ||
| - | CONSTRAINT pk_rate_limit_event PRIMARY KEY (id), | ||
| - | CONSTRAINT fk_rle_user | ||
| - | CONSTRAINT fk_rle_device | ||
| - | ); | ||
| - | CREATE INDEX ix_rate_limit_user_time ON auth.rate_limit_event (user_id, created_at); | ||
| - | CREATE INDEX ix_rate_limit_ip_time | ||
| - | CREATE INDEX ix_rate_limit_cleanup | ||
| - | PRINT ' | ||
| - | END | ||
| - | GO | ||
| - | |||
| - | -- ------------------------------------------------------------------ | ||
| - | -- 10. auth.refresh_token_family — Refresh Token Rotation Tracking | ||
| - | -- ------------------------------------------------------------------ | ||
| - | IF NOT EXISTS ( | ||
| - | SELECT 1 FROM sys.tables t | ||
| - | JOIN sys.schemas s ON s.schema_id = t.schema_id | ||
| - | WHERE s.name = ' | ||
| - | ) | ||
| - | BEGIN | ||
| - | CREATE TABLE auth.refresh_token_family ( | ||
| - | id | ||
| - | family_id | ||
| - | user_id | ||
| - | device_id | ||
| - | current_generation INT NOT NULL CONSTRAINT df_rtf_gen | ||
| - | is_revoked | ||
| - | revoked_reason | ||
| - | created_at | ||
| - | last_used_at | ||
| - | revoked_at | ||
| - | CONSTRAINT pk_refresh_token_family PRIMARY KEY (id), | ||
| - | CONSTRAINT uq_rtf_family_id | ||
| - | CONSTRAINT fk_rtf_user | ||
| - | CONSTRAINT fk_rtf_device | ||
| - | ); | ||
| - | CREATE INDEX ix_refresh_family_user ON auth.refresh_token_family (user_id, is_revoked); | ||
| - | PRINT ' | ||
| - | END | ||
| - | GO | ||
| - | |||
| - | -- ------------------------------------------------------------------ | ||
| - | -- 11. auth.role_permission — Rollen-Berechtigungs-Zuordnung (Junction) | ||
| - | -- ------------------------------------------------------------------ | ||
| - | IF NOT EXISTS ( | ||
| - | SELECT 1 FROM sys.tables t | ||
| - | JOIN sys.schemas s ON s.schema_id = t.schema_id | ||
| - | WHERE s.name = ' | ||
| - | ) | ||
| - | BEGIN | ||
| - | CREATE TABLE auth.role_permission ( | ||
| - | role_id | ||
| - | permission_id INT NOT NULL, | ||
| - | CONSTRAINT pk_role_permission PRIMARY KEY (role_id, permission_id), | ||
| - | CONSTRAINT fk_rp_role | ||
| - | CONSTRAINT fk_rp_permission | ||
| - | ); | ||
| - | PRINT ' | ||
| - | END | ||
| - | GO | ||
| - | |||
| - | -- ------------------------------------------------------------------ | ||
| - | -- 12. auth.server_key — Server-seitige ML-DSA/ | ||
| - | -- ------------------------------------------------------------------ | ||
| - | IF NOT EXISTS ( | ||
| - | SELECT 1 FROM sys.tables t | ||
| - | JOIN sys.schemas s ON s.schema_id = t.schema_id | ||
| - | WHERE s.name = ' | ||
| - | ) | ||
| - | BEGIN | ||
| - | CREATE TABLE auth.server_key ( | ||
| - | id INT NOT NULL IDENTITY(1, | ||
| - | key_id | ||
| - | key_type | ||
| - | algorithm | ||
| - | public_key | ||
| - | -- Private Key verschlüsselt gespeichert (CWE-256) | ||
| - | private_key_encrypted VARBINARY(MAX) NOT NULL, | ||
| - | is_active | ||
| - | not_before | ||
| - | not_after | ||
| - | created_at | ||
| - | CONSTRAINT pk_server_key | ||
| - | CONSTRAINT uq_server_key_id UNIQUE (key_id) | ||
| - | ); | ||
| - | CREATE INDEX ix_server_key_type_active ON auth.server_key (key_type, is_active, not_after); | ||
| - | PRINT ' | ||
| - | END | ||
| - | GO | ||
| - | |||
| - | -- ------------------------------------------------------------------ | ||
| - | -- 13. auth.user_role — User-Rollen-Zuordnung (mit optionalem Site-Scope) | ||
| - | -- | ||
| - | -- Integrität app-seitig sichergestellt) | ||
| - | -- ------------------------------------------------------------------ | ||
| - | IF NOT EXISTS ( | ||
| - | SELECT 1 FROM sys.tables t | ||
| - | JOIN sys.schemas s ON s.schema_id = t.schema_id | ||
| - | WHERE s.name = ' | ||
| - | ) | ||
| - | BEGIN | ||
| - | CREATE TABLE auth.user_role ( | ||
| - | id | ||
| - | user_id | ||
| - | role_id | ||
| - | site_id | ||
| - | granted_at DATETIME2 NOT NULL CONSTRAINT df_ur_granted DEFAULT (SYSUTCDATETIME()), | ||
| - | granted_by INT NULL, | ||
| - | CONSTRAINT pk_user_role | ||
| - | CONSTRAINT uq_user_role_site UNIQUE (user_id, role_id, site_id), | ||
| - | CONSTRAINT fk_ur_user | ||
| - | CONSTRAINT fk_ur_role | ||
| - | CONSTRAINT fk_ur_granted_by | ||
| - | ); | ||
| - | PRINT ' | ||
| - | END | ||
| - | GO | ||
| - | |||
| - | PRINT '=== sccm_create_tables: | ||
| - | </ | ||
| - | |||
| - | === sccm_copy_data.sql — Daten ENIVERSCAFM → ENIVERSSCCM === | ||
| - | |||
| - | <code sql> | ||
| - | /* ================================================================ | ||
| - | | ||
| - | | ||
| - | | ||
| - | | ||
| - | | ||
| - | | ||
| - | |||
| - | -- ------------------------------------------------------------------ | ||
| - | -- 1. auth.permission — 15 Zeilen, keine Abhängigkeiten | ||
| - | -- ------------------------------------------------------------------ | ||
| - | SET IDENTITY_INSERT ENIVERSSCCM.auth.permission ON; | ||
| - | |||
| - | INSERT INTO ENIVERSSCCM.auth.permission (id, resource, action, scope, description) | ||
| - | SELECT id, resource, action, scope, description | ||
| - | FROM | ||
| - | |||
| - | SET IDENTITY_INSERT ENIVERSSCCM.auth.permission OFF; | ||
| - | PRINT ' | ||
| - | |||
| - | -- ------------------------------------------------------------------ | ||
| - | -- 2. auth.role — 26 Zeilen, keine Abhängigkeiten | ||
| - | -- ------------------------------------------------------------------ | ||
| - | SET IDENTITY_INSERT ENIVERSSCCM.auth.role ON; | ||
| - | |||
| - | INSERT INTO ENIVERSSCCM.auth.role | ||
| - | (id, code, name, description, | ||
| - | SELECT id, code, name, description, | ||
| - | FROM | ||
| - | |||
| - | SET IDENTITY_INSERT ENIVERSSCCM.auth.role OFF; | ||
| - | PRINT ' | ||
| - | |||
| - | -- ------------------------------------------------------------------ | ||
| - | -- 3. auth.[user] — 241 Zeilen, hängt von core.person ab (person_id) | ||
| - | -- FK auth.[user] → core.person wird nach sccm_person.sql gesetzt | ||
| - | -- ------------------------------------------------------------------ | ||
| - | SET IDENTITY_INSERT ENIVERSSCCM.auth.[user] ON; | ||
| - | |||
| - | INSERT INTO ENIVERSSCCM.auth.[user] ( | ||
| - | id, person_id, username, email, | ||
| - | password_hash, | ||
| - | password_failed_attempts, | ||
| - | totp_secret, | ||
| - | totp_failed_attempts, | ||
| - | totp_pending_secret, | ||
| - | last_mfa_at, | ||
| - | is_active, last_login_at, | ||
| - | ) | ||
| - | SELECT | ||
| - | id, person_id, username, email, | ||
| - | password_hash, | ||
| - | password_failed_attempts, | ||
| - | totp_secret, | ||
| - | totp_failed_attempts, | ||
| - | totp_pending_secret, | ||
| - | last_mfa_at, | ||
| - | is_active, last_login_at, | ||
| - | FROM ENIVERSCAFM.auth.[user]; | ||
| - | |||
| - | SET IDENTITY_INSERT ENIVERSSCCM.auth.[user] OFF; | ||
| - | PRINT ' | ||
| - | |||
| - | -- ------------------------------------------------------------------ | ||
| - | -- 4–8. Tabellen ohne Daten (0 Zeilen) — Synonyme genügen | ||
| - | -- ------------------------------------------------------------------ | ||
| - | SET IDENTITY_INSERT ENIVERSSCCM.auth.device ON; | ||
| - | INSERT INTO ENIVERSSCCM.auth.device ( | ||
| - | id, device_id, user_id, name, | ||
| - | passkey_credential_id, | ||
| - | pq_dsa_public_key, | ||
| - | pq_dsa_public_key_prev, | ||
| - | refresh_token_hash, | ||
| - | last_ip, last_geo_country, | ||
| - | session_state, | ||
| - | session_revoked_at, | ||
| - | is_active, last_used_at, | ||
| - | ) | ||
| - | SELECT | ||
| - | id, device_id, user_id, name, | ||
| - | passkey_credential_id, | ||
| - | pq_dsa_public_key, | ||
| - | pq_dsa_public_key_prev, | ||
| - | refresh_token_hash, | ||
| - | last_ip, last_geo_country, | ||
| - | session_state, | ||
| - | session_revoked_at, | ||
| - | is_active, last_used_at, | ||
| - | FROM ENIVERSCAFM.auth.device; | ||
| - | SET IDENTITY_INSERT ENIVERSSCCM.auth.device OFF; | ||
| - | PRINT ' | ||
| - | |||
| - | SET IDENTITY_INSERT ENIVERSSCCM.auth.backup_code ON; | ||
| - | INSERT INTO ENIVERSSCCM.auth.backup_code | ||
| - | (id, user_id, code_hash, code_prefix, | ||
| - | SELECT id, user_id, code_hash, code_prefix, | ||
| - | FROM | ||
| - | SET IDENTITY_INSERT ENIVERSSCCM.auth.backup_code OFF; | ||
| - | PRINT ' | ||
| - | |||
| - | SET IDENTITY_INSERT ENIVERSSCCM.auth.known_location ON; | ||
| - | INSERT INTO ENIVERSSCCM.auth.known_location | ||
| - | (id, user_id, geo_country, | ||
| - | SELECT id, user_id, geo_country, | ||
| - | FROM | ||
| - | SET IDENTITY_INSERT ENIVERSSCCM.auth.known_location OFF; | ||
| - | PRINT ' | ||
| - | |||
| - | SET IDENTITY_INSERT ENIVERSSCCM.auth.mfa_session ON; | ||
| - | INSERT INTO ENIVERSSCCM.auth.mfa_session | ||
| - | (id, mfa_session_id, | ||
| - | SELECT id, mfa_session_id, | ||
| - | FROM | ||
| - | SET IDENTITY_INSERT ENIVERSSCCM.auth.mfa_session OFF; | ||
| - | PRINT ' | ||
| - | |||
| - | INSERT INTO ENIVERSSCCM.auth.nonce_cache (nonce, device_id, received_at, | ||
| - | SELECT nonce, device_id, received_at, | ||
| - | FROM | ||
| - | PRINT ' | ||
| - | |||
| - | SET IDENTITY_INSERT ENIVERSSCCM.auth.rate_limit_event ON; | ||
| - | INSERT INTO ENIVERSSCCM.auth.rate_limit_event (id, user_id, device_id, ip_address, event_type, created_at) | ||
| - | SELECT id, user_id, device_id, ip_address, event_type, created_at | ||
| - | FROM | ||
| - | SET IDENTITY_INSERT ENIVERSSCCM.auth.rate_limit_event OFF; | ||
| - | PRINT ' | ||
| - | |||
| - | SET IDENTITY_INSERT ENIVERSSCCM.auth.refresh_token_family ON; | ||
| - | INSERT INTO ENIVERSSCCM.auth.refresh_token_family | ||
| - | (id, family_id, user_id, device_id, current_generation, | ||
| - | SELECT id, family_id, user_id, device_id, current_generation, | ||
| - | FROM | ||
| - | SET IDENTITY_INSERT ENIVERSSCCM.auth.refresh_token_family OFF; | ||
| - | PRINT ' | ||
| - | |||
| - | -- ------------------------------------------------------------------ | ||
| - | -- 9. auth.role_permission — 33 Zeilen, hängt von role + permission ab | ||
| - | -- ------------------------------------------------------------------ | ||
| - | INSERT INTO ENIVERSSCCM.auth.role_permission (role_id, permission_id) | ||
| - | SELECT role_id, permission_id | ||
| - | FROM | ||
| - | PRINT ' | ||
| - | |||
| - | SET IDENTITY_INSERT ENIVERSSCCM.auth.server_key ON; | ||
| - | INSERT INTO ENIVERSSCCM.auth.server_key | ||
| - | (id, key_id, key_type, algorithm, public_key, private_key_encrypted, | ||
| - | SELECT id, key_id, key_type, algorithm, public_key, private_key_encrypted, | ||
| - | FROM | ||
| - | SET IDENTITY_INSERT ENIVERSSCCM.auth.server_key OFF; | ||
| - | PRINT ' | ||
| - | |||
| - | -- ------------------------------------------------------------------ | ||
| - | -- 10. auth.user_role — 9.445 Zeilen, zuletzt (FK auf user + role) | ||
| - | -- ------------------------------------------------------------------ | ||
| - | SET IDENTITY_INSERT ENIVERSSCCM.auth.user_role ON; | ||
| - | |||
| - | INSERT INTO ENIVERSSCCM.auth.user_role (id, user_id, role_id, site_id, granted_at, granted_by) | ||
| - | SELECT id, user_id, role_id, site_id, granted_at, granted_by | ||
| - | FROM | ||
| - | |||
| - | SET IDENTITY_INSERT ENIVERSSCCM.auth.user_role OFF; | ||
| - | PRINT ' | ||
| - | |||
| - | PRINT '=== sccm_copy_data: | ||
| - | </ | ||
| - | |||
| - | === sccm_person.sql — core.person anlegen, befüllen, FK + Synonym === | ||
| - | |||
| - | <code sql> | ||
| - | /* ================================================================ | ||
| - | | ||
| - | | ||
| - | | ||
| - | | ||
| - | | ||
| - | |||
| - | -- ------------------------------------------------------------------ | ||
| - | -- Schritt 1: Schema ' | ||
| - | -- ------------------------------------------------------------------ | ||
| - | USE ENIVERSSCCM; | ||
| - | GO | ||
| - | |||
| - | IF NOT EXISTS (SELECT 1 FROM sys.schemas WHERE name = ' | ||
| - | EXEC(' | ||
| - | GO | ||
| - | |||
| - | CREATE TABLE core.person ( | ||
| - | id | ||
| - | first_name | ||
| - | last_name | ||
| - | position | ||
| - | notes NVARCHAR(MAX) | ||
| - | is_active | ||
| - | is_system_user BIT NOT NULL CONSTRAINT df_person_sysuser DEFAULT (0), | ||
| - | created_at | ||
| - | updated_at | ||
| - | CONSTRAINT pk_person PRIMARY KEY (id) | ||
| - | ); | ||
| - | PRINT ' | ||
| - | GO | ||
| - | |||
| - | -- ------------------------------------------------------------------ | ||
| - | -- Schritt 2: Daten aus ENIVERSCAFM.hr.person übertragen (241 Zeilen) | ||
| - | -- IDENTITY_INSERT ON, damit Original-IDs erhalten bleiben | ||
| - | -- ------------------------------------------------------------------ | ||
| - | SET IDENTITY_INSERT ENIVERSSCCM.core.person ON; | ||
| - | |||
| - | INSERT INTO ENIVERSSCCM.core.person | ||
| - | (id, first_name, last_name, position, notes, is_active, is_system_user, | ||
| - | SELECT id, first_name, last_name, position, notes, is_active, is_system_user, | ||
| - | FROM | ||
| - | |||
| - | SET IDENTITY_INSERT ENIVERSSCCM.core.person OFF; | ||
| - | PRINT ' | ||
| - | GO | ||
| - | |||
| - | -- ------------------------------------------------------------------ | ||
| - | -- Schritt 3: FK auth.[user].person_id → core.person(id) wiederherstellen | ||
| - | -- (jetzt echter Intra-DB-FK innerhalb ENIVERSSCCM) | ||
| - | -- ------------------------------------------------------------------ | ||
| - | ALTER TABLE auth.[user] | ||
| - | ADD CONSTRAINT fk_user_person | ||
| - | FOREIGN KEY (person_id) REFERENCES core.person(id); | ||
| - | PRINT 'FK auth.[user].person_id → core.person(id): | ||
| - | GO | ||
| - | |||
| - | -- ------------------------------------------------------------------ | ||
| - | -- Schritt 4: hr.person in ENIVERSCAFM droppen und Synonym anlegen | ||
| - | -- ------------------------------------------------------------------ | ||
| - | USE ENIVERSCAFM; | ||
| - | GO | ||
| - | |||
| - | DROP TABLE hr.person; | ||
| - | PRINT ' | ||
| - | GO | ||
| - | |||
| - | CREATE SYNONYM hr.person FOR ENIVERSSCCM.core.person; | ||
| - | PRINT ' | ||
| - | GO | ||
| - | |||
| - | PRINT '=== sccm_person: | ||
| - | </ | ||
| - | |||
| - | === sccm_drop_and_synonyms.sql — FKs droppen, Tabellen droppen, Synonyme erstellen === | ||
| - | |||
| - | <code sql> | ||
| - | /* ================================================================ | ||
| - | | ||
| - | | ||
| - | | ||
| - | 13 Synonyme auf ENIVERSSCCM erstellen | ||
| - | | ||
| - | | ||
| - | USE ENIVERSCAFM; | ||
| - | GO | ||
| - | |||
| - | -- ------------------------------------------------------------------ | ||
| - | -- Schritt 1: Cross-Schema FKs droppen | ||
| - | -- (audit→auth, | ||
| - | -- Diese können nach DB-Move nicht als echte FKs wieder- | ||
| - | -- hergestellt werden — Integrität wird app-seitig gewährleistet | ||
| - | -- ------------------------------------------------------------------ | ||
| - | IF OBJECT_ID(' | ||
| - | AND EXISTS (SELECT 1 FROM sys.foreign_keys | ||
| - | WHERE name = ' | ||
| - | AND parent_object_id = OBJECT_ID(' | ||
| - | ALTER TABLE audit.event_log DROP CONSTRAINT fk_el_user; | ||
| - | |||
| - | IF OBJECT_ID(' | ||
| - | AND EXISTS (SELECT 1 FROM sys.foreign_keys | ||
| - | WHERE name = ' | ||
| - | AND parent_object_id = OBJECT_ID(' | ||
| - | ALTER TABLE audit.event_log DROP CONSTRAINT fk_el_device; | ||
| - | |||
| - | IF OBJECT_ID(' | ||
| - | AND EXISTS (SELECT 1 FROM sys.foreign_keys | ||
| - | WHERE name = ' | ||
| - | AND parent_object_id = OBJECT_ID(' | ||
| - | ALTER TABLE audit.pq_signature DROP CONSTRAINT fk_pqs_user; | ||
| - | |||
| - | IF OBJECT_ID(' | ||
| - | AND EXISTS (SELECT 1 FROM sys.foreign_keys | ||
| - | WHERE name = ' | ||
| - | AND parent_object_id = OBJECT_ID(' | ||
| - | ALTER TABLE audit.pq_signature DROP CONSTRAINT fk_pqs_device; | ||
| - | |||
| - | IF OBJECT_ID(' | ||
| - | AND EXISTS (SELECT 1 FROM sys.foreign_keys | ||
| - | WHERE name = ' | ||
| - | AND parent_object_id = OBJECT_ID(' | ||
| - | ALTER TABLE settings.user_preference DROP CONSTRAINT fk_user_preference_user; | ||
| - | |||
| - | IF EXISTS (SELECT 1 FROM sys.foreign_keys | ||
| - | WHERE name = ' | ||
| - | AND parent_object_id = OBJECT_ID(' | ||
| - | ALTER TABLE auth.[user] DROP CONSTRAINT fk_user_person; | ||
| - | |||
| - | IF EXISTS (SELECT 1 FROM sys.foreign_keys | ||
| - | WHERE name = ' | ||
| - | AND parent_object_id = OBJECT_ID(' | ||
| - | ALTER TABLE auth.user_role DROP CONSTRAINT fk_ur_site; | ||
| - | |||
| - | PRINT ' | ||
| - | GO | ||
| - | |||
| - | -- ------------------------------------------------------------------ | ||
| - | -- Schritt 2: Interne auth-FKs droppen (Children zuerst) | ||
| - | -- ------------------------------------------------------------------ | ||
| - | |||
| - | -- auth.user_role hängt von auth.[user] + auth.role ab | ||
| - | ALTER TABLE auth.user_role DROP CONSTRAINT fk_ur_granted_by; | ||
| - | ALTER TABLE auth.user_role DROP CONSTRAINT fk_ur_user; | ||
| - | ALTER TABLE auth.user_role DROP CONSTRAINT fk_ur_role; | ||
| - | |||
| - | -- auth.role_permission | ||
| - | ALTER TABLE auth.role_permission DROP CONSTRAINT fk_rp_permission; | ||
| - | ALTER TABLE auth.role_permission DROP CONSTRAINT fk_rp_role; | ||
| - | |||
| - | -- auth.refresh_token_family | ||
| - | ALTER TABLE auth.refresh_token_family DROP CONSTRAINT fk_rtf_device; | ||
| - | ALTER TABLE auth.refresh_token_family DROP CONSTRAINT fk_rtf_user; | ||
| - | |||
| - | -- auth.rate_limit_event | ||
| - | ALTER TABLE auth.rate_limit_event DROP CONSTRAINT fk_rle_device; | ||
| - | ALTER TABLE auth.rate_limit_event DROP CONSTRAINT fk_rle_user; | ||
| - | |||
| - | -- auth.mfa_session | ||
| - | ALTER TABLE auth.mfa_session DROP CONSTRAINT fk_mfas_device; | ||
| - | ALTER TABLE auth.mfa_session DROP CONSTRAINT fk_mfas_user; | ||
| - | |||
| - | -- auth.known_location | ||
| - | ALTER TABLE auth.known_location DROP CONSTRAINT fk_kl_user; | ||
| - | |||
| - | -- auth.backup_code | ||
| - | ALTER TABLE auth.backup_code DROP CONSTRAINT fk_bc_user; | ||
| - | |||
| - | -- auth.device (letzte Child-Tabelle von auth.[user]) | ||
| - | ALTER TABLE auth.device DROP CONSTRAINT fk_device_user; | ||
| - | |||
| - | PRINT ' | ||
| - | GO | ||
| - | |||
| - | -- ------------------------------------------------------------------ | ||
| - | -- Schritt 3: auth-Tabellen droppen (Children vor Parents) | ||
| - | -- ------------------------------------------------------------------ | ||
| - | DROP TABLE auth.nonce_cache; | ||
| - | DROP TABLE auth.mfa_session; | ||
| - | DROP TABLE auth.rate_limit_event; | ||
| - | DROP TABLE auth.refresh_token_family; | ||
| - | DROP TABLE auth.backup_code; | ||
| - | DROP TABLE auth.known_location; | ||
| - | DROP TABLE auth.role_permission; | ||
| - | DROP TABLE auth.user_role; | ||
| - | DROP TABLE auth.device; | ||
| - | DROP TABLE auth.[user]; | ||
| - | DROP TABLE auth.role; | ||
| - | DROP TABLE auth.permission; | ||
| - | DROP TABLE auth.server_key; | ||
| - | PRINT ' | ||
| - | GO | ||
| - | |||
| - | -- ------------------------------------------------------------------ | ||
| - | -- Schritt 4: 13 Synonyme auf ENIVERSSCCM.auth.* erstellen | ||
| - | -- Bestehender Code kann weiterhin ENIVERSCAFM.auth.* | ||
| - | -- ansprechen — transparent umgeleitet | ||
| - | -- ------------------------------------------------------------------ | ||
| - | CREATE SYNONYM auth.backup_code | ||
| - | CREATE SYNONYM auth.device | ||
| - | CREATE SYNONYM auth.known_location | ||
| - | CREATE SYNONYM auth.mfa_session | ||
| - | CREATE SYNONYM auth.nonce_cache | ||
| - | CREATE SYNONYM auth.permission | ||
| - | CREATE SYNONYM auth.rate_limit_event | ||
| - | CREATE SYNONYM auth.refresh_token_family FOR ENIVERSSCCM.auth.refresh_token_family; | ||
| - | CREATE SYNONYM auth.role | ||
| - | CREATE SYNONYM auth.role_permission | ||
| - | CREATE SYNONYM auth.server_key | ||
| - | CREATE SYNONYM auth.[user] | ||
| - | CREATE SYNONYM auth.user_role | ||
| - | PRINT '13 Synonyme in ENIVERSCAFM.auth: | ||
| - | GO | ||
| - | |||
| - | PRINT '=== sccm_drop_and_synonyms: | ||
| - | </ | ||
| - | |||
| - | ===== Phase 2 — LD-System: ENIVERS → ENIVERSSCCM ===== | ||
| - | |||
| - | ==== Quellsysteme ==== | ||
| - | |||
| - | === Quelle 1: ENIVERS-Datenbank (SQL Server) === | ||
| - | |||
| - | **Verbindung: | ||
| - | |||
| - | ^ ENIVERS-Tabelle | ||
| - | | '' | ||
| - | | '' | ||
| - | | '' | ||
| - | | '' | ||
| - | | '' | ||
| - | | '' | ||
| - | |||
| - | === Quelle 2: LdUsr.accdb (MS Access, Datei-Datenbank) === | ||
| - | |||
| - | **Pfad:** '' | ||
| - | **Export-Stand: | ||
| - | |||
| - | Die Access-Datei enthält primär die **Benutzeroberfläche** (Formulare, Berichte, VBA) | ||
| - | und nutzt **verknüpfte Tabellen** (Linked Tables) aus der ENIVERS SQL-Server-Datenbank. | ||
| - | Es gibt keine eigenständigen Access-nativen Tabellen — alle Daten kommen aus Quelle 1. | ||
| - | |||
| - | Relevant als Referenz für Geschäftsregeln: | ||
| - | * Formular-Logik: | ||
| - | * Rollen-/ | ||
| - | * Scheduling-Logik: | ||
| - | |||
| - | ==== Feldmapping: | ||
| - | |||
| - | ^ tblPerson-Feld | ||
| - | | '' | ||
| - | | '' | ||
| - | | '' | ||
| - | | '' | ||
| - | | '' | ||
| - | | '' | ||
| - | | '' | ||
| - | | '' | ||
| - | | '' | ||
| - | | '' | ||
| - | | '' | ||
| - | | '' | ||
| - | | '' | ||
| - | | '' | ||
| - | | '' | ||
| - | | '' | ||
| - | |||
| - | > **Sicherheitshinweis: | ||
| - | > Access-System. Diese Spalte darf **niemals** übernommen werden (CWE-256). | ||
| - | > Benutzer erhalten beim ersten Login einen Passwort-Reset-Link. | ||
| - | |||
| - | ==== Feldmapping: | ||
| - | |||
| - | ^ tblRolle-Feld | ||
| - | | '' | ||
| - | | '' | ||
| - | | '' | ||
| - | | '' | ||
| - | | '' | ||
| - | | '' | ||
| - | | '' | ||
| - | | '' | ||
| - | |||
| - | ==== Feldmapping: | ||
| - | |||
| - | ^ Quell-Tabelle | ||
| - | | '' | ||
| - | | '' | ||
| - | | '' | ||
| - | | '' | ||
| - | | '' | ||
| - | | '' | ||
| - | | '' | ||
| - | | '' | ||
| - | |||
| - | ==== Besonderheiten ==== | ||
| - | |||
| - | === Rollen-ID-Konflikt === | ||
| - | |||
| - | '' | ||
| - | bereits durch eine System-Rolle belegt. Kein IDENTITY_INSERT für '' | ||
| - | |||
| - | **Lösung: | ||
| - | * Matching via '' | ||
| - | * Für bestehende Rollen (z. B. '' | ||
| - | * Für neue LD-Rollen → auto-generierte IDs aus IDENTITY | ||
| - | |||
| - | === Username-Duplikate === | ||
| - | |||
| - | 3 Duplikat-Paare in '' | ||
| - | |||
| - | ^ strPeWinUser | ||
| - | | '' | ||
| - | | '' | ||
| - | | '' | ||
| - | |||
| - | **Lösung: | ||
| - | Ergebnis: 73 neue '' | ||
| - | |||
| - | ==== Skripte Phase 2 ==== | ||
| - | |||
| - | === ld_migration.sql — Hauptmigration === | ||
| - | |||
| - | <code sql> | ||
| - | /* ================================================================ | ||
| - | | ||
| - | | ||
| - | tblPersonRolleBetrieb) | ||
| - | | ||
| - | auth.user_role) | ||
| - | | ||
| - | | ||
| - | mit bestehenden 591–2896) | ||
| - | | ||
| - | | ||
| - | | ||
| - | | ||
| - | | ||
| - | |||
| - | USE ENIVERSSCCM; | ||
| - | GO | ||
| - | |||
| - | -- ------------------------------------------------------------------ | ||
| - | -- Schritt 1: Neue Personen einfügen (76 Zeilen, IDENTITY_INSERT) | ||
| - | -- Nur Personen, die noch keinen übereinstimmenden | ||
| - | -- auth.[user]-Eintrag haben (Collation-sicherer Vergleich) | ||
| - | -- ------------------------------------------------------------------ | ||
| - | SET IDENTITY_INSERT core.person ON; | ||
| - | |||
| - | INSERT INTO core.person | ||
| - | (id, first_name, last_name, position, notes, | ||
| - | | ||
| - | SELECT | ||
| - | p.idPerson, | ||
| - | ISNULL(p.strPeVorname, | ||
| - | ISNULL(p.strPeNachname, | ||
| - | p.strPePosition, | ||
| - | p.memPeNotiz, | ||
| - | ISNULL(p.bitPeAktiv, | ||
| - | ISNULL(p.bitPeSysUser, | ||
| - | p.dtCreated, | ||
| - | ISNULL(p.dtUpdated, | ||
| - | FROM ENIVERS.dbo.tblPerson p | ||
| - | WHERE NOT EXISTS ( | ||
| - | SELECT 1 | ||
| - | FROM | ||
| - | WHERE LOWER(u.username | ||
| - | = LOWER(p.strPeWinUser COLLATE Latin1_General_CI_AS) | ||
| - | ); | ||
| - | |||
| - | SET IDENTITY_INSERT core.person OFF; | ||
| - | PRINT ' | ||
| - | GO | ||
| - | |||
| - | -- ------------------------------------------------------------------ | ||
| - | -- Schritt 2: Neue auth.[user] einfügen (auto-ID) | ||
| - | -- person_id = idPerson aus tblPerson (soeben eingefügt) | ||
| - | -- username | ||
| - | -- Kein Passwort — Legacy-Passwörter nicht übernehmen (CWE-256) | ||
| - | -- ------------------------------------------------------------------ | ||
| - | INSERT INTO auth.[user] | ||
| - | (person_id, username, is_active, created_at, updated_at) | ||
| - | SELECT | ||
| - | p.idPerson, | ||
| - | p.strPeWinUser, | ||
| - | ISNULL(p.bitPeAktiv, | ||
| - | p.dtCreated, | ||
| - | ISNULL(p.dtUpdated, | ||
| - | FROM ENIVERS.dbo.tblPerson p | ||
| - | WHERE NOT EXISTS ( | ||
| - | SELECT 1 | ||
| - | FROM | ||
| - | WHERE LOWER(u.username | ||
| - | = LOWER(p.strPeWinUser COLLATE Latin1_General_CI_AS) | ||
| - | ); | ||
| - | PRINT ' | ||
| - | GO | ||
| - | |||
| - | -- ------------------------------------------------------------------ | ||
| - | -- Schritt 3: Neue Rollen einfügen (auto-ID) | ||
| - | -- Kein IDENTITY_INSERT — idRolle=4 kollidiert mit | ||
| - | -- bestehendem System-Role (viewer). Code-basiertes Matching. | ||
| - | -- 12 neue LD-spezifische Rollen werden eingefügt. | ||
| - | -- ------------------------------------------------------------------ | ||
| - | INSERT INTO auth.role | ||
| - | (code, name, description, | ||
| - | SELECT | ||
| - | r.strRolAbk, | ||
| - | r.strRolName, | ||
| - | r.memRolNotiz, | ||
| - | ISNULL(r.bitRolSysRole, | ||
| - | ISNULL(r.bitRolAktiv, | ||
| - | r.dtCreated, | ||
| - | ISNULL(r.dtEdited, | ||
| - | FROM ENIVERS.dbo.tblRolle r | ||
| - | WHERE NOT EXISTS ( | ||
| - | SELECT 1 | ||
| - | FROM | ||
| - | WHERE LOWER(ar.code COLLATE Latin1_General_CI_AS) | ||
| - | = LOWER(r.strRolAbk COLLATE Latin1_General_CI_AS) | ||
| - | ); | ||
| - | PRINT ' | ||
| - | GO | ||
| - | |||
| - | -- ------------------------------------------------------------------ | ||
| - | -- Schritt 4: Rollen-ID-Mapping aufbauen (#role_map, temporär) | ||
| - | -- Verbindet ENIVERS idRolle mit dem tatsächlichen | ||
| - | -- ENIVERSSCCM auth.role.id (via Code-Matching) | ||
| - | -- ------------------------------------------------------------------ | ||
| - | IF OBJECT_ID(' | ||
| - | DROP TABLE #role_map; | ||
| - | |||
| - | CREATE TABLE #role_map ( | ||
| - | enivers_id INT NOT NULL, | ||
| - | sccm_id | ||
| - | ); | ||
| - | |||
| - | INSERT INTO #role_map (enivers_id, | ||
| - | SELECT | ||
| - | r.idRolle, | ||
| - | ar.id | ||
| - | FROM ENIVERS.dbo.tblRolle r | ||
| - | JOIN auth.role ar | ||
| - | ON LOWER(ar.code COLLATE Latin1_General_CI_AS) | ||
| - | = LOWER(r.strRolAbk COLLATE Latin1_General_CI_AS); | ||
| - | |||
| - | PRINT '# | ||
| - | |||
| - | -- ------------------------------------------------------------------ | ||
| - | -- Schritt 5: Personen-ID-Mapping aufbauen (# | ||
| - | -- Verbindet ENIVERS idPerson mit ENIVERSSCCM auth.[user].id | ||
| - | -- ------------------------------------------------------------------ | ||
| - | IF OBJECT_ID(' | ||
| - | DROP TABLE # | ||
| - | |||
| - | CREATE TABLE #person_map ( | ||
| - | enivers_id | ||
| - | sccm_user_id INT NOT NULL | ||
| - | ); | ||
| - | |||
| - | INSERT INTO #person_map (enivers_id, | ||
| - | SELECT | ||
| - | p.idPerson, | ||
| - | u.id | ||
| - | FROM ENIVERS.dbo.tblPerson p | ||
| - | JOIN auth.[user] u | ||
| - | ON LOWER(u.username | ||
| - | = LOWER(p.strPeWinUser COLLATE Latin1_General_CI_AS); | ||
| - | |||
| - | PRINT '# | ||
| - | |||
| - | -- ------------------------------------------------------------------ | ||
| - | -- Schritt 6a: auth.user_role aus tblPersonRolle (kein Site-Scope) | ||
| - | -- Nur einfügen wenn Kombination noch nicht vorhanden | ||
| - | -- ------------------------------------------------------------------ | ||
| - | INSERT INTO auth.user_role (user_id, role_id, granted_at, granted_by) | ||
| - | SELECT | ||
| - | pm.sccm_user_id, | ||
| - | rm.sccm_id, | ||
| - | pr.dtCreated, | ||
| - | NULL | ||
| - | FROM ENIVERS.dbo.tblPersonRolle pr | ||
| - | JOIN #person_map pm ON pm.enivers_id = pr.fiPrPerson | ||
| - | JOIN # | ||
| - | WHERE NOT EXISTS ( | ||
| - | SELECT 1 | ||
| - | FROM | ||
| - | WHERE ur.user_id = pm.sccm_user_id | ||
| - | AND ur.role_id = rm.sccm_id | ||
| - | AND ur.site_id IS NULL | ||
| - | ); | ||
| - | PRINT ' | ||
| - | |||
| - | -- ------------------------------------------------------------------ | ||
| - | -- Schritt 6b: auth.user_role aus tblPersonRolleBetrieb (mit Site-Scope) | ||
| - | -- | ||
| - | -- | ||
| - | -- ------------------------------------------------------------------ | ||
| - | INSERT INTO auth.user_role (user_id, role_id, site_id, granted_at, granted_by) | ||
| - | SELECT | ||
| - | pm.sccm_user_id, | ||
| - | rm.sccm_id, | ||
| - | prb.fiPrbBetrieb, | ||
| - | prb.dtCreated, | ||
| - | NULL | ||
| - | FROM ENIVERS.dbo.tblPersonRolleBetrieb prb | ||
| - | JOIN #person_map pm ON pm.enivers_id = prb.fiPrbPerson | ||
| - | JOIN # | ||
| - | WHERE NOT EXISTS ( | ||
| - | SELECT 1 | ||
| - | FROM | ||
| - | WHERE ur.user_id = pm.sccm_user_id | ||
| - | AND ur.role_id = rm.sccm_id | ||
| - | AND ur.site_id = prb.fiPrbBetrieb | ||
| - | ); | ||
| - | PRINT ' | ||
| - | GO | ||
| - | |||
| - | -- ------------------------------------------------------------------ | ||
| - | -- Schritt 7: Ergebnis-Übersicht | ||
| - | -- ------------------------------------------------------------------ | ||
| - | SELECT ' | ||
| - | UNION ALL | ||
| - | SELECT ' | ||
| - | UNION ALL | ||
| - | SELECT ' | ||
| - | UNION ALL | ||
| - | SELECT ' | ||
| - | |||
| - | PRINT '=== ld_migration: | ||
| - | GO | ||
| - | </ | ||
| - | |||
| - | === ld_migration_users_fix.sql — Username-Duplikat-Fix === | ||
| - | |||
| - | <code sql> | ||
| - | /* ================================================================ | ||
| - | | ||
| - | | ||
| - | (Schritt 2 aus ld_migration.sql schlug fehl wegen | ||
| - | 3 Username-Duplikaten in tblPerson) | ||
| - | | ||
| - | | ||
| - | | ||
| - | | ||
| - | | ||
| - | | ||
| - | |||
| - | USE ENIVERSSCCM; | ||
| - | GO | ||
| - | |||
| - | -- Deduplizierung: | ||
| - | WITH dedup AS ( | ||
| - | SELECT MIN(idPerson) AS idPerson | ||
| - | FROM | ||
| - | GROUP BY strPeWinUser | ||
| - | ) | ||
| - | INSERT INTO auth.[user] | ||
| - | (person_id, username, is_active, created_at, updated_at) | ||
| - | SELECT | ||
| - | p.idPerson, | ||
| - | p.strPeWinUser, | ||
| - | ISNULL(p.bitPeAktiv, | ||
| - | p.dtCreated, | ||
| - | ISNULL(p.dtUpdated, | ||
| - | FROM ENIVERS.dbo.tblPerson p | ||
| - | JOIN dedup d ON d.idPerson = p.idPerson | ||
| - | WHERE NOT EXISTS ( | ||
| - | SELECT 1 | ||
| - | FROM | ||
| - | WHERE LOWER(u.username | ||
| - | = LOWER(p.strPeWinUser COLLATE Latin1_General_CI_AS) | ||
| - | ); | ||
| - | PRINT ' | ||
| - | |||
| - | -- Ergebnis-Übersicht | ||
| - | SELECT ' | ||
| - | UNION ALL | ||
| - | SELECT ' | ||
| - | UNION ALL | ||
| - | SELECT ' | ||
| - | UNION ALL | ||
| - | SELECT ' | ||
| - | GO | ||
| - | </ | ||
| - | |||
| - | ==== Ergebnis Phase 2 ==== | ||
| - | |||
| - | ^ Tabelle | ||
| - | | '' | ||
| - | | '' | ||
| - | | '' | ||
| - | | '' | ||
| - | |||
| - | > **Hinweis: | ||
| - | > Personen ohne gültigen '' | ||
| - | |||
| - | ===== Quellsysteme und Migrationspfade ===== | ||
| - | |||
| - | ==== Stack-Übersicht (AMED / WIS / TecDB) ==== | ||
| - | |||
| - | ^ Stack ^ Pfad ^ Technologie | ||
| - | | AMED .NET Framework | ||
| - | | AMED .NET 8 (SETY) | ||
| - | | Delphi (alle Module) | '' | ||
| - | |||
| - | ==== Delphi-Anwendungen (alle Module) ==== | ||
| - | |||
| - | ^ Modul ^ Pfad (relativ zu src\) ^ Zweck ^ Migrationsziel | ||
| - | | '' | ||
| - | | '' | ||
| - | | '' | ||
| - | | '' | ||
| - | | '' | ||
| - | | '' | ||
| - | | '' | ||
| - | | '' | ||
| - | | '' | ||
| - | | '' | ||
| - | | '' | ||
| - | | '' | ||
| - | | '' | ||
| - | | '' | ||
| - | | '' | ||
| - | |||
| - | ===== Phase 3 — AMED Bestandsdaten (geplant) ===== | ||
| - | |||
| - | Migrationsziel: | ||
| - | |||
| - | Geplante Quellen: | ||
| - | * AMED-Datenbank (SQL Server): Branches, BETRIEB, tblGebaeude, | ||
| - | * AMED .NET Framework DAL (Referenz für Schema-Struktur) | ||
| - | * Delphi ATEA / ETCM / MOT (ergänzende Bestandsdaten) | ||
| - | |||
| - | Schema-Reorganisation: | ||
| - | |||
| - | ===== Phase 4 — ENIVERSPIMS aufbauen (geplant) ===== | ||
| - | |||
| - | Neues Schema, Quellen: | ||
| - | * WIS-Delphi: DAL-Units '' | ||
| - | * TecDB (SQL Server): Rohrleitungs- und Messtechnik-Daten (Struktur noch zu analysieren) | ||
| - | * Delphi REP: Schadensmeldungen, | ||
| - | |||
| - | ===== Phase 5 — ENIVERSASYS aufbauen (geplant) ===== | ||
| - | |||
| - | Feature-Flags-System aus ENIVERSCAFM auslagern: | ||
| - | * Aktuell: Feature-Flags im '' | ||
| - | * Ziel: Dediziertes ENIVERSASYS mit eigenem Feature-Flags-Schema | ||
| - | * Shell und Gateway sprechen bereits gegen den ''/ | ||
| - | das Backend-Target (ENIVERSCAFM vs. ENIVERSASYS) ist intern transparent | ||
Zuletzt geändert: den 05.03.2026 um 14:27