374 lines
26 KiB
Markdown
374 lines
26 KiB
Markdown
# LIAM NTFS Provider Findings
|
|
|
|
## Umfang der Prüfung
|
|
|
|
Die Prüfung umfasst den kompletten NTFS-Provider-Code im Projekt `LiamNtfs`, also nicht nur den aktuellen Provider-Einstieg, sondern auch die darunterliegenden Engine- und Hilfsklassen.
|
|
|
|
Geprüft wurden insbesondere:
|
|
|
|
- `LiamNtfs/C4IT.LIAM.Ntfs.cs`
|
|
- `LiamNtfs/cNtfsBase.cs`
|
|
- `LiamNtfs/cActiveDirectoryBase.cs`
|
|
- `LiamNtfs/C4IT_IAM_SET/DataArea_FileSystem.cs`
|
|
- `LiamNtfs/C4IT_IAM_SET/SecurityGroup.cs`
|
|
- `LiamNtfs/C4IT_IAM_SET/DataArea.cs`
|
|
- `LiamNtfs/C4IT_IAM_SET/DataArea_FileSystem_GET.cs`
|
|
- `LiamNtfs/C4IT_IAM_SET/cNetworkConnection.cs`
|
|
- `LiamNtfs/C4IT_IAM_SET/Helper.cs`
|
|
- `LiamNtfs/C4IT_IAM_SET/ResultToken.cs`
|
|
|
|
Nicht im Detail geprüft wurden andere Provider wie Exchange, AD oder Teams in diesem Dokument. Verweise dorthin wurden nur dann berücksichtigt, wenn sie für das Verhalten des NTFS-Providers direkt relevant waren.
|
|
|
|
## Priorisierte Findings
|
|
|
|
### 1. Kritisch: Traverse-Fehler können als Erfolg zurückgegeben werden
|
|
|
|
Der gefährlichste Punkt liegt im Schreibpfad für die Ordneranlage und das Ensure von Berechtigungen.
|
|
|
|
Im Create-Pfad wird zunächst die AD-Gruppenanlage ausgeführt, danach der Ordner erstellt und danach `SetTraversePermissions()` aufgerufen. Das Problem ist, dass das Ergebnis der Ordnererstellung anschließend vollständig durch das Ergebnis des Traverse-Schritts überschrieben wird. Wenn `SetTraversePermissions()` intern in einen Fehlerzustand läuft, aber trotzdem ein `ResultToken` mit `resultErrorId = 0` zurückgibt, sieht der Aufrufer am Ende formal einen Erfolg.
|
|
|
|
Genau das passiert in `SetTraversePermissions()` an mehreren Stellen. Dort werden Fehler zwar geloggt, aber häufig nur mit `return resultToken;` beendet, ohne einen fachlichen Fehlercode zu setzen. Damit ist die Methode in vielen Fällen „logisch fehlgeschlagen“, aber technisch weiterhin erfolgreich.
|
|
|
|
Die Folge ist gefährlich:
|
|
|
|
- Ordner kann erstellt worden sein, aber Traverse-Gruppen fehlen teilweise oder vollständig.
|
|
- AD-Gruppen können erzeugt worden sein, aber Traverse-Nesting ist unvollständig.
|
|
- Aufrufende Schichten wie Workflow, Diagnostics oder API können einen Erfolg anzeigen, obwohl das Ergebnis fachlich inkonsistent ist.
|
|
|
|
Betroffene Stellen:
|
|
|
|
- [DataArea_FileSystem.cs#L170](/mnt/c/Workspace/C4IT%20DEV%20LIAM%20WEB%20Service_git/LiamNtfs/C4IT_IAM_SET/DataArea_FileSystem.cs#L170)
|
|
- [DataArea_FileSystem.cs#L173](/mnt/c/Workspace/C4IT%20DEV%20LIAM%20WEB%20Service_git/LiamNtfs/C4IT_IAM_SET/DataArea_FileSystem.cs#L173)
|
|
- [DataArea_FileSystem.cs#L368](/mnt/c/Workspace/C4IT%20DEV%20LIAM%20WEB%20Service_git/LiamNtfs/C4IT_IAM_SET/DataArea_FileSystem.cs#L368)
|
|
|
|
### 2. Hoch: Die Security-Group-Templates werden mutiert und danach wiederverwendet
|
|
|
|
`SecurityGroups.GenerateNewSecurityGroups()` verändert die übergebenen Templates direkt. Dabei werden `NamingTemplate`, `DescriptionTemplate` und `WildcardTemplate` in-place mit konkreten Pfaden, Tags und Platzhaltern überschrieben.
|
|
|
|
Das ist problematisch, weil dieselbe Template-Liste innerhalb derselben Engine-Instanz mehrfach verwendet wird:
|
|
|
|
- im Retry-Loop bei Namenskollisionen während der Gruppenerzeugung
|
|
- später erneut beim Traverse-Handling
|
|
- potenziell auch zwischen Ensure- und Create-Pfaden innerhalb derselben Session
|
|
|
|
Sobald das Template einmal materialisiert wurde, ist es kein Template mehr. Ein zweiter Lauf arbeitet nicht mehr mit der ursprünglichen Konfiguration, sondern mit bereits ersetzten Strings. Dadurch entstehen mehrere Risiken:
|
|
|
|
- der Loop-Counter arbeitet nicht mehr auf dem Originalmuster
|
|
- spätere Durchläufe können bereits ersetzte Namen nochmals verarbeiten
|
|
- Wildcards passen nicht mehr sauber zum ursprünglichen Naming-Schema
|
|
- Traverse-Gruppen können auf anderen Namensmustern basieren als Owner/Write/Read
|
|
|
|
Das ist kein kosmetisches Problem, sondern ein echter Zustandsfehler. Konfiguration wird in Laufzeitstatus verwandelt und danach weiterbenutzt.
|
|
|
|
Betroffene Stellen:
|
|
|
|
- [SecurityGroup.cs#L146](/mnt/c/Workspace/C4IT%20DEV%20LIAM%20WEB%20Service_git/LiamNtfs/C4IT_IAM_SET/SecurityGroup.cs#L146)
|
|
- [SecurityGroup.cs#L184](/mnt/c/Workspace/C4IT%20DEV%20LIAM%20WEB%20Service_git/LiamNtfs/C4IT_IAM_SET/SecurityGroup.cs#L184)
|
|
- [DataArea_FileSystem.cs#L1016](/mnt/c/Workspace/C4IT%20DEV%20LIAM%20WEB%20Service_git/LiamNtfs/C4IT_IAM_SET/DataArea_FileSystem.cs#L1016)
|
|
- [DataArea_FileSystem.cs#L411](/mnt/c/Workspace/C4IT%20DEV%20LIAM%20WEB%20Service_git/LiamNtfs/C4IT_IAM_SET/DataArea_FileSystem.cs#L411)
|
|
|
|
Status:
|
|
|
|
- Am 2026-03-10 umgesetzt.
|
|
- `GenerateNewSecurityGroups()` arbeitet jetzt auf einer pro Aufruf geklonten Template-Liste statt auf der übergebenen Originalsammlung.
|
|
- Die Konfigurationstemplates im Engine-Kontext bleiben dadurch unverändert und können in Retry-Loops und später im Traverse-Pfad erneut korrekt materialisiert werden.
|
|
- Der Fix adressiert bewusst nur die Zustandsmutation. Die fachliche Gruppenerzeugung und das Naming-Verhalten selbst wurden dabei nicht geändert.
|
|
|
|
### 3. Hoch: Drei Minuten harter Blocker im Traverse-Pfad
|
|
|
|
Im Traverse-Pfad steckt ein explizites `Thread.Sleep(180000)`. Das blockiert den ausführenden Thread für drei Minuten.
|
|
|
|
Das ist in einer Bibliothek dieser Art ein massiver Risikofaktor:
|
|
|
|
- Workflows können in Timeouts laufen
|
|
- GUI-Aktionen wirken eingefroren
|
|
- Web-/Service-Threads werden unnötig belegt
|
|
- parallele Verarbeitung skaliert sehr schlecht
|
|
|
|
Der Code dokumentiert das zusätzlich falsch mit „60 Sekunden warten“, obwohl tatsächlich 180 Sekunden geschlafen wird. Das erschwert Diagnose und Betrieb zusätzlich.
|
|
|
|
Wenn dieses Sleep als AD-Replikations-Workaround gedacht war, ist es trotzdem der falsche technische Schnitt. Dann müsste stattdessen gezielt auf die Verfügbarkeit der erzeugten Gruppen geprüft werden, idealerweise mit Polling und Timeout statt blindem Warten.
|
|
|
|
Betroffene Stelle:
|
|
|
|
- [DataArea_FileSystem.cs#L676](/mnt/c/Workspace/C4IT%20DEV%20LIAM%20WEB%20Service_git/LiamNtfs/C4IT_IAM_SET/DataArea_FileSystem.cs#L676)
|
|
- [DataArea_FileSystem.cs#L678](/mnt/c/Workspace/C4IT%20DEV%20LIAM%20WEB%20Service_git/LiamNtfs/C4IT_IAM_SET/DataArea_FileSystem.cs#L678)
|
|
|
|
Status:
|
|
|
|
- Am 2026-03-18 umgesetzt.
|
|
- Das harte `Thread.Sleep(180000)` wurde entfernt.
|
|
- Zunächst wurde der Wait auf die bloße Auflösbarkeit neu erzeugter Gruppen umgestellt. Nach fachlicher Rückmeldung wurde der Fix auf den tatsächlich kritischen Folgeschritt verschoben: die Membership-Änderung an der Traverse-Gruppe.
|
|
- Die Traverse-Logik retryt jetzt direkt `Members.Contains(...)`, `Members.Add(...)` und `Save()` mit sofortigem Erstversuch und kurzem Backoff.
|
|
- Die maximale Obergrenze bleibt bewusst bei 3 Minuten, damit das bisherige Sicherheitsfenster für langsame AD-Konsistenz erhalten bleibt.
|
|
- Im Normalfall endet die Wartezeit jetzt deutlich früher, sobald die Membership-Änderung erfolgreich durchläuft.
|
|
|
|
### 4. Hoch: Unterschiedliches SMB-Verhalten zwischen Lesen und Schreiben
|
|
|
|
Der Provider verwendet für das Lesen des NTFS-Baums `cNtfsBase.LogonAsync()`. Dort wird der bekannte SMB-Fehler `1219` abgefangen, die bestehende Verbindung getrennt und anschließend ein neuer Versuch gestartet.
|
|
|
|
Die Create- und Ensure-Pfade verwenden dagegen `cNetworkConnection`, und diese Klasse wirft bei jedem Fehler direkt eine Exception. Ein Retry für `1219` findet dort nicht statt.
|
|
|
|
Das führt zu einem inkonsistenten Betriebsverhalten:
|
|
|
|
- Ein und dieselbe Konfiguration kann beim Lesen funktionieren.
|
|
- Dieselbe Konfiguration kann beim Schreiben scheitern, obwohl die Ursache nur eine bestehende Session auf den Share ist.
|
|
|
|
Das ist besonders tückisch, weil es im Betrieb wie ein „sporadischer“ Fehler aussieht, tatsächlich aber ein systematischer Unterschied zwischen Read- und Write-Pfad ist.
|
|
|
|
Betroffene Stellen:
|
|
|
|
- [DataArea_FileSystem.cs#L161](/mnt/c/Workspace/C4IT%20DEV%20LIAM%20WEB%20Service_git/LiamNtfs/C4IT_IAM_SET/DataArea_FileSystem.cs#L161)
|
|
- [DataArea_FileSystem.cs#L300](/mnt/c/Workspace/C4IT%20DEV%20LIAM%20WEB%20Service_git/LiamNtfs/C4IT_IAM_SET/DataArea_FileSystem.cs#L300)
|
|
- [cNetworkConnection.cs#L41](/mnt/c/Workspace/C4IT%20DEV%20LIAM%20WEB%20Service_git/LiamNtfs/C4IT_IAM_SET/cNetworkConnection.cs#L41)
|
|
- [cNtfsBase.cs#L61](/mnt/c/Workspace/C4IT%20DEV%20LIAM%20WEB%20Service_git/LiamNtfs/cNtfsBase.cs#L61)
|
|
|
|
### 5. Hoch: Geerbte ACLs werden im Ensure-Pfad als „vorhanden“ behandelt
|
|
|
|
Fachlich war bereits geklärt, dass geerbte Rechte hier keine Rolle spielen sollen. Genau das macht der neue Ensure-Pfad aktuell aber nicht konsequent.
|
|
|
|
Bei der Prüfung, ob eine ACL bereits vorhanden ist, werden Regeln mit `GetAccessRules(true, true, ...)` geladen. Das zweite `true` bedeutet, dass auch geerbte Regeln berücksichtigt werden. Damit kann eine Berechtigung, die nur von oben geerbt wurde, dazu führen, dass der Provider glaubt, die explizite ACL sei bereits gesetzt.
|
|
|
|
Im Ergebnis kann das Ensure-Feature damit stillschweigend zu wenig tun:
|
|
|
|
- fehlende explizite ACLs werden nicht gesetzt
|
|
- das Ergebnis sieht erfolgreich aus
|
|
- späteres Mapping oder Downstream-Logik kann trotzdem unerwartetes Verhalten zeigen
|
|
|
|
Das betrifft nicht nur Traverse, sondern auch die allgemeine ACL-Sicherstellung im neuen Ensure-Pfad.
|
|
|
|
Betroffene Stellen:
|
|
|
|
- [DataArea_FileSystem.cs#L808](/mnt/c/Workspace/C4IT%20DEV%20LIAM%20WEB%20Service_git/LiamNtfs/C4IT_IAM_SET/DataArea_FileSystem.cs#L808)
|
|
- [DataArea_FileSystem.cs#L646](/mnt/c/Workspace/C4IT%20DEV%20LIAM%20WEB%20Service_git/LiamNtfs/C4IT_IAM_SET/DataArea_FileSystem.cs#L646)
|
|
|
|
### 6. Hoch: Per Call übergebene CustomTags erfüllen die Pflichtanforderungen nicht wirklich
|
|
|
|
Im Provider wird in `CreateFilesystemEngine()` zwar eine gemergte Tag-Sammlung aufgebaut, in der Provider-Tags und per Aufruf übergebene Tags zusammengeführt werden. Das klingt zunächst korrekt.
|
|
|
|
Die Pflichtwerte für `groupPrefix`, `groupOwnerTag`, `groupWriteTag`, `groupReadTag`, `groupTraverseTag`, `groupDLTag` und `groupGTag` werden aber nicht aus dieser gemergten Sammlung gelesen, sondern weiterhin direkt aus `Provider.CustomTags`.
|
|
|
|
Die Folge ist eine verdeckte Inkonsistenz:
|
|
|
|
- im Debug-/GUI-Output sehen die Tags vorhanden aus
|
|
- im Engine-Aufbau schlagen Pflichtprüfungen trotzdem fehl
|
|
- Call-spezifische Overrides wirken nur teilweise
|
|
|
|
Das ist besonders ungünstig für Workflow- oder Diagnostics-Szenarien, in denen Tags bewusst pro Aufruf ergänzt oder überschrieben werden sollen.
|
|
|
|
Betroffene Stellen:
|
|
|
|
- [C4IT.LIAM.Ntfs.cs#L366](/mnt/c/Workspace/C4IT%20DEV%20LIAM%20WEB%20Service_git/LiamNtfs/C4IT.LIAM.Ntfs.cs#L366)
|
|
- [C4IT.LIAM.Ntfs.cs#L384](/mnt/c/Workspace/C4IT%20DEV%20LIAM%20WEB%20Service_git/LiamNtfs/C4IT.LIAM.Ntfs.cs#L384)
|
|
- [C4IT.LIAM.Ntfs.cs#L472](/mnt/c/Workspace/C4IT%20DEV%20LIAM%20WEB%20Service_git/LiamNtfs/C4IT.LIAM.Ntfs.cs#L472)
|
|
|
|
### 7. Hoch: `ReplaceNtfsCustomTags()` ist zu früh, zu strikt und verändert Konfiguration dauerhaft
|
|
|
|
Bereits im Provider-Konstruktor wird `ReplaceNtfsCustomTags()` ausgeführt. Die Methode greift direkt per `CustomTags[...]` auf Dictionary-Einträge zu und ersetzt Platzhalter in den Naming-Conventions.
|
|
|
|
Das erzeugt drei Probleme gleichzeitig:
|
|
|
|
1. Fehlende Tags schlagen schon beim Provider-Aufbau fehl, bevor eine gezielte Validierung mit verständlicher Fehlermeldung greifen kann.
|
|
2. Die Naming-Conventions werden direkt verändert. Danach ist nicht mehr klar, was Originalkonfiguration und was bereits materialisierter Laufzeitzustand ist.
|
|
3. Alias-Verhalten wie `ADGroupPrefix` wird hier noch nicht sauber berücksichtigt, obwohl es später teilweise unterstützt wird.
|
|
|
|
Damit wird Konfiguration zu früh und zu aggressiv „kompiliert“.
|
|
|
|
Betroffene Stellen:
|
|
|
|
- [C4IT.LIAM.Ntfs.cs#L39](/mnt/c/Workspace/C4IT%20DEV%20LIAM%20WEB%20Service_git/LiamNtfs/C4IT.LIAM.Ntfs.cs#L39)
|
|
- [C4IT.LIAM.Ntfs.cs#L54](/mnt/c/Workspace/C4IT%20DEV%20LIAM%20WEB%20Service_git/LiamNtfs/C4IT.LIAM.Ntfs.cs#L54)
|
|
- [C4IT.LIAM.Ntfs.cs#L63](/mnt/c/Workspace/C4IT%20DEV%20LIAM%20WEB%20Service_git/LiamNtfs/C4IT.LIAM.Ntfs.cs#L63)
|
|
- [C4IT.LIAM.Ntfs.cs#L88](/mnt/c/Workspace/C4IT%20DEV%20LIAM%20WEB%20Service_git/LiamNtfs/C4IT.LIAM.Ntfs.cs#L88)
|
|
|
|
### 8. Hoch: AD-Gruppennamen werden nicht gegen Längenlimits abgesichert
|
|
|
|
Die Namensbildung für AD-Gruppen materialisiert Templates, Platzhalter und CustomTags direkt zu einem finalen Gruppennamen. Dieser Wert wird anschließend unverändert sowohl als `CN` als auch als `sAMAccountName` verwendet.
|
|
|
|
Aktuell gibt es davor keine echte Längenprüfung und keine Kürzungslogik. Der Code prüft nur, ob der Name bereits existiert, und erhöht bei Bedarf über den `LOOP`-Mechanismus die Eindeutigkeit. Gegen zu lange Namen schützt das aber nicht.
|
|
|
|
Dadurch entsteht ein reales Betriebsrisiko:
|
|
|
|
- tiefe Ordnerpfade oder lange Ordnernamen können AD-seitig unzulässige Gruppennamen erzeugen
|
|
- der Fehler tritt erst spät beim eigentlichen AD-Create auf
|
|
- das Verhalten ist nicht deterministisch vorbereitet, sondern von der AD-Rückmeldung abhängig
|
|
- auch eine spätere manuelle Korrektur ist unsauber, weil Naming und ACL-Zuordnung bereits auf dem ursprünglichen Namen basieren können
|
|
|
|
Betroffene Stellen:
|
|
|
|
- [SecurityGroup.cs#L192](/mnt/c/Workspace/C4IT%20DEV%20LIAM%20WEB%20Service_git/LiamNtfs/C4IT_IAM_SET/SecurityGroup.cs#L192)
|
|
- [SecurityGroup.cs#L680](/mnt/c/Workspace/C4IT%20DEV%20LIAM%20WEB%20Service_git/LiamNtfs/C4IT_IAM_SET/SecurityGroup.cs#L680)
|
|
- [DataArea_FileSystem.cs#L1186](/mnt/c/Workspace/C4IT%20DEV%20LIAM%20WEB%20Service_git/LiamNtfs/C4IT_IAM_SET/DataArea_FileSystem.cs#L1186)
|
|
|
|
Status:
|
|
|
|
- Am 2026-03-18 umgesetzt.
|
|
- Vor der AD-Gruppenerzeugung wird jetzt zentral eine konservative Namensgrenze von 64 Zeichen angewendet.
|
|
- Die Begrenzung reserviert zusätzlich Platz für einen möglichen `LOOP`-Suffix, damit spätere Kollisionsauflösung nicht wieder über das sichere Limit hinausschießt.
|
|
- Die Kürzung greift nur auf dem dynamischen Pfadanteil, nicht auf stabilen fachlichen Tags wie Prefix, Scope oder Gruppentyp.
|
|
- Die gemeinsame Logik wird sowohl im normalen Security-Group-Pfad als auch im Traverse-Pfad verwendet.
|
|
- Wenn gekürzt werden muss, wird das nur im Log protokolliert. Es wird kein fachlicher Fehler geworfen.
|
|
- Die Implementierung arbeitet bewusst ohne Hash-Fallback, damit die resultierenden Namen vollständig human-readable bleiben.
|
|
- Verifiziert mit `msbuild LiamNtfs/LiamNtfs.csproj /p:Configuration=Debug`. Das bestehende Warning `CS0162` in `SecurityGroup.cs` blieb unverändert.
|
|
|
|
Vorschlag zum Fixen:
|
|
|
|
- Vor dem AD-Write jeden final generierten Gruppennamen gegen eine zentrale, konservative Maximalgrenze prüfen, die für die tatsächlich beschriebenen AD-Attribute sicher eingehalten wird.
|
|
- Wenn ein Name innerhalb der Grenze liegt, unverändert weiterarbeiten.
|
|
- Wenn ein Name zu lang ist, keinen fachlichen Fehler werfen, sondern den Umstand nur im Log dokumentieren und anschließend automatisch auf einen kontrolliert verkürzten Namen umschalten.
|
|
- Die Verkürzung sollte deterministisch sein und die stabilen fachlichen Tags erhalten. Kürzen sollte möglichst nur der dynamische Pfadanteil (`NAME` bzw. `RELATIVEPATH`).
|
|
- Der bestehende `LOOP`-Mechanismus zur Kollisionsbehandlung sollte danach unverändert weiterlaufen, damit Längenbegrenzung und Eindeutigkeitslogik sauber getrennt bleiben.
|
|
|
|
Konkreter Vorschlag für die Verkürzungslogik:
|
|
|
|
- Den finalen AD-Gruppennamen nicht als Ganzes kürzen, sondern vor dem Zusammenbau logisch in `prefixPart`, `dynamicPart` und `suffixPart` aufteilen.
|
|
- `prefixPart` umfasst die stabilen fachlichen Tags wie Prefix, Scope-Tag und feste Typbestandteile. `suffixPart` umfasst Typ-/Scope-Enden und einen eventuell benötigten `LOOP`-Puffer. Beide Bereiche bleiben unverändert.
|
|
- Nur `dynamicPart` darf verkürzt werden. Dieser Teil stammt fachlich aus `NAME` oder `RELATIVEPATH`.
|
|
- Wenn `dynamicPart` aus `NAME` stammt, wird zuerst nur dieser Name gekürzt.
|
|
- Wenn `dynamicPart` aus `RELATIVEPATH` stammt, sollte segmentbasiert gekürzt werden. Das letzte Segment bleibt möglichst am längsten erhalten, weil es fachlich meist den eigentlichen Zielordner beschreibt.
|
|
- Erste Kürzungsstufe: frühe oder mittlere Segmente verkürzen, bevor das letzte Segment gekappt wird. Beispiel: `Abteilung_Standort_Projekt_Unterordner` wird eher zu `Abt_Sta_Proj_Unterordner` als zu `Abteilung_Standort_Projekt_Unter`.
|
|
- Zweite Kürzungsstufe: wenn die segmentbasierte Verkürzung noch nicht reicht, werden zuerst die frühen Segmente weiter reduziert und danach bei Bedarf ganze frühe Segmente entfernt, bevor das letzte Segment angetastet wird.
|
|
- Nur wenn kein frühes Segment mehr sinnvoll gekürzt oder entfernt werden kann, wird das letzte verbleibende Segment weiter reduziert.
|
|
- Vor der Kürzung muss bereits Reserve für einen möglichen `LOOP`-Suffix eingeplant werden, damit die spätere Kollisionsauflösung nicht erneut über die Maximalgrenze hinausschießt.
|
|
- Logging nur dann, wenn tatsächlich gekürzt wurde. Im Log sollten Originalname, Zielname, alte Länge, neue Länge und die verwendete Strategie (`truncate-name`, `truncate-relativepath`) stehen.
|
|
- Die gesamte Logik sollte in einer zentralen Hilfsmethode gekapselt werden, damit Create, Ensure, Traverse und Preview denselben Namensalgorithmus verwenden.
|
|
|
|
### 9. Mittel-Hoch: `LoadDataArea()` behandelt UNC-Pfade fachlich falsch
|
|
|
|
Die Einzel-Ladefunktion `LoadDataArea()` ist sichtbar unfertig. Das ist nicht nur ein Stilproblem, sondern erzeugt reales Fehlverhalten.
|
|
|
|
Der Code splittet den Pfad mit `UID.Split(Path.DirectorySeparatorChar)` ohne `RemoveEmptyEntries`. Bei UNC-Pfaden wie `\\server\share` entstehen dadurch führende leere Segmente. Das führt dazu, dass ein Share-Pfad nicht sauber als Share erkannt wird, sondern in den Default-Branch läuft.
|
|
|
|
Zusätzlich wird `DisplayName` aus `Path.GetDirectoryName(UID)` ermittelt. Das ist für den Anwendungsfall falsch, weil damit der Elternpfad statt des Blattnamens verwendet wird.
|
|
|
|
Konkrete Folgen:
|
|
|
|
- Share-Roots können beim Einzel-Laden als Folder erscheinen
|
|
- Anzeigenamen stimmen nicht
|
|
- Root-Level und Child-Level verhalten sich inkonsistent
|
|
|
|
Betroffene Stellen:
|
|
|
|
- [C4IT.LIAM.Ntfs.cs#L225](/mnt/c/Workspace/C4IT%20DEV%20LIAM%20WEB%20Service_git/LiamNtfs/C4IT.LIAM.Ntfs.cs#L225)
|
|
- [C4IT.LIAM.Ntfs.cs#L227](/mnt/c/Workspace/C4IT%20DEV%20LIAM%20WEB%20Service_git/LiamNtfs/C4IT.LIAM.Ntfs.cs#L227)
|
|
- [C4IT.LIAM.Ntfs.cs#L236](/mnt/c/Workspace/C4IT%20DEV%20LIAM%20WEB%20Service_git/LiamNtfs/C4IT.LIAM.Ntfs.cs#L236)
|
|
|
|
### 10. Mittel-Hoch: `Depth = 0` verliert die Root-DataArea
|
|
|
|
Der Provider baut in `getDataAreasAsync()` zunächst korrekt das Root-Objekt auf. Danach wird die Unterordnerliste über `ntfsBase.RequestFoldersListAsync()` geladen. Wenn `Depth == 0` ist, liefert `RequestFoldersListAsync()` aber `null` statt einer leeren Liste zurück.
|
|
|
|
Im Provider wird `null` dann als harter Fehler interpretiert und es wird insgesamt `null` zurückgegeben. Das bereits erzeugte Root-Objekt geht damit verloren.
|
|
|
|
Für einen Aufrufer, der bewusst nur Ebene 0 sehen möchte, ist das klar fehlerhaft.
|
|
|
|
Betroffene Stellen:
|
|
|
|
- [C4IT.LIAM.Ntfs.cs#L147](/mnt/c/Workspace/C4IT%20DEV%20LIAM%20WEB%20Service_git/LiamNtfs/C4IT.LIAM.Ntfs.cs#L147)
|
|
- [C4IT.LIAM.Ntfs.cs#L183](/mnt/c/Workspace/C4IT%20DEV%20LIAM%20WEB%20Service_git/LiamNtfs/C4IT.LIAM.Ntfs.cs#L183)
|
|
- [cNtfsBase.cs#L108](/mnt/c/Workspace/C4IT%20DEV%20LIAM%20WEB%20Service_git/LiamNtfs/cNtfsBase.cs#L108)
|
|
- [cNtfsBase.cs#L114](/mnt/c/Workspace/C4IT%20DEV%20LIAM%20WEB%20Service_git/LiamNtfs/cNtfsBase.cs#L114)
|
|
|
|
### 11. Mittel: AD-Gruppenabfragen können still unvollständig sein
|
|
|
|
`cActiveDirectoryBase.privRequestSecurityGroupsListAsync()` baut die Gruppenliste aus LDAP-Ergebnissen auf. Dort wird jedoch `GroupPrincipal.FindByIdentity(...).GroupScope` ohne Null-Check verwendet.
|
|
|
|
Wenn eine Gruppe aus dem LDAP-Result zwar gefunden wird, aber nicht sauber als `GroupPrincipal` auflösbar ist, entsteht ein Fehler. Dieser wird anschließend durch einen allgemeinen `catch` verschluckt, und es wird einfach die bis dahin gesammelte Teilliste zurückgegeben.
|
|
|
|
Das ist problematisch, weil der Aufrufer nicht klar zwischen „Liste vollständig“ und „Liste vorzeitig abgebrochen“ unterscheiden kann.
|
|
|
|
Betroffene Stellen:
|
|
|
|
- [cActiveDirectoryBase.cs#L167](/mnt/c/Workspace/C4IT%20DEV%20LIAM%20WEB%20Service_git/LiamNtfs/cActiveDirectoryBase.cs#L167)
|
|
- [cActiveDirectoryBase.cs#L186](/mnt/c/Workspace/C4IT%20DEV%20LIAM%20WEB%20Service_git/LiamNtfs/cActiveDirectoryBase.cs#L186)
|
|
- [cActiveDirectoryBase.cs#L192](/mnt/c/Workspace/C4IT%20DEV%20LIAM%20WEB%20Service_git/LiamNtfs/cActiveDirectoryBase.cs#L192)
|
|
|
|
### 12. Mittel: Zentrale Fehlerschnittstelle des Providers deckt Schreibfehler nicht ab
|
|
|
|
`GetLastErrorMessage()` sammelt nur Fehler aus `ntfsBase` und `activeDirectoryBase`. Die eigentlichen Fehler aus `DataArea_FileSystem` laufen aber über `ResultToken` und landen nicht in dieser zentralen Fehlerschnittstelle.
|
|
|
|
Das bedeutet:
|
|
|
|
- `Logon`- und Read-Fehler sind über `GetLastErrorMessage()` erkennbar
|
|
- Create-/Ensure-Fehler dagegen oft nicht
|
|
|
|
Für aufrufende Schichten, die nur diese zentrale Schnittstelle kennen, entsteht damit ein unvollständiges Fehlerbild.
|
|
|
|
Betroffene Stellen:
|
|
|
|
- [C4IT.LIAM.Ntfs.cs#L506](/mnt/c/Workspace/C4IT%20DEV%20LIAM%20WEB%20Service_git/LiamNtfs/C4IT.LIAM.Ntfs.cs#L506)
|
|
- [DataArea_FileSystem.cs#L137](/mnt/c/Workspace/C4IT%20DEV%20LIAM%20WEB%20Service_git/LiamNtfs/C4IT_IAM_SET/DataArea_FileSystem.cs#L137)
|
|
|
|
### 13. Mittel: ACL-Mapping ist stark von vollständigen Naming-Conventions abhängig und fällt auf Sentinel-Werte zurück
|
|
|
|
Die Permission-Auflösung in `ResolvePermissionGroupsAsync()` verwendet `.First(...)` für die Conventions von Owner, Write und Read. Fehlt eine passende Konvention, wirft der Code sofort eine Exception.
|
|
|
|
Parallel dazu sind die Zielwerte mit `S-1-0-0` vorbelegt. Das führt zu zwei unterschiedlichen Fehlermustern:
|
|
|
|
- bei fehlender Konfiguration: harter Laufzeitfehler
|
|
- bei nicht gefundenem Match: scheinbar gültige SID, fachlich aber nur ein Platzhalter
|
|
|
|
Das macht Ergebnisse schwer interpretierbar und erhöht das Risiko, dass Fehler spät erkannt werden.
|
|
|
|
Betroffene Stellen:
|
|
|
|
- [C4IT.LIAM.Ntfs.cs#L522](/mnt/c/Workspace/C4IT%20DEV%20LIAM%20WEB%20Service_git/LiamNtfs/C4IT.LIAM.Ntfs.cs#L522)
|
|
- [C4IT.LIAM.Ntfs.cs#L611](/mnt/c/Workspace/C4IT%20DEV%20LIAM%20WEB%20Service_git/LiamNtfs/C4IT.LIAM.Ntfs.cs#L611)
|
|
|
|
### 14. Mittel: Mitgliederauflösung bricht intern mit NullReference ab und wird dann nur noch als `null` sichtbar
|
|
|
|
`GetMembersAsync()` ruft `privGetMembersAsync(sid).ToList()` auf, bevor geprüft wird, ob überhaupt ein Result vorliegt. Wenn die Gruppe nicht gefunden wird, kommt `null` zurück und `.ToList()` wirft intern.
|
|
|
|
Die Exception wird zwar gefangen, aber nach außen sieht der Aufrufer nur noch `null`. Damit verschwimmt der Unterschied zwischen:
|
|
|
|
- Gruppe nicht vorhanden
|
|
- AD-Auflösung fehlgeschlagen
|
|
- echte Kommunikationsstörung
|
|
|
|
Betroffene Stellen:
|
|
|
|
- [cActiveDirectoryBase.cs#L269](/mnt/c/Workspace/C4IT%20DEV%20LIAM%20WEB%20Service_git/LiamNtfs/cActiveDirectoryBase.cs#L269)
|
|
- [cActiveDirectoryBase.cs#L274](/mnt/c/Workspace/C4IT%20DEV%20LIAM%20WEB%20Service_git/LiamNtfs/cActiveDirectoryBase.cs#L274)
|
|
- [cActiveDirectoryBase.cs#L299](/mnt/c/Workspace/C4IT%20DEV%20LIAM%20WEB%20Service_git/LiamNtfs/cActiveDirectoryBase.cs#L299)
|
|
|
|
### 15. Mittel/Niedrig: Share-Objekte können keine Kinder nachladen
|
|
|
|
`cLiamNtfsShare.getFolders()` und `getChildrenAsync()` liefern aktuell immer nur leere Listen zurück. Das bedeutet, dass Share-Objekte zwar initial erzeugt werden können, ein späteres Nachladen über die Objektmethoden aber praktisch nicht funktioniert.
|
|
|
|
Wenn diese Methoden nicht mehr verwendet werden, ist das nur Altlast. Wenn doch, ist das ein funktionaler Bruch.
|
|
|
|
Betroffene Stellen:
|
|
|
|
- [C4IT.LIAM.Ntfs.cs#L706](/mnt/c/Workspace/C4IT%20DEV%20LIAM%20WEB%20Service_git/LiamNtfs/C4IT.LIAM.Ntfs.cs#L706)
|
|
- [C4IT.LIAM.Ntfs.cs#L727](/mnt/c/Workspace/C4IT%20DEV%20LIAM%20WEB%20Service_git/LiamNtfs/C4IT.LIAM.Ntfs.cs#L727)
|
|
|
|
### 16. Niedrig, aber inkonsistent: Der alte GET-Pfad verhält sich anders als der aktuelle Providerpfad
|
|
|
|
Im älteren `DataArea_FileSystem_GET`-Pfad wird die Root-Struktur anders aufgebaut als im aktuellen Providerpfad. Ebene 0 bekommt dort kein Root-ACL-Mapping, und das Verhalten unterscheidet sich insgesamt von der neueren Logik im eigentlichen Provider.
|
|
|
|
Wenn dieser Altpfad noch produktiv verwendet wird, gibt es damit zwei unterschiedliche Wahrheiten für denselben fachlichen Bereich.
|
|
|
|
Betroffene Stellen:
|
|
|
|
- [DataArea_FileSystem_GET.cs#L228](/mnt/c/Workspace/C4IT%20DEV%20LIAM%20WEB%20Service_git/LiamNtfs/C4IT_IAM_SET/DataArea_FileSystem_GET.cs#L228)
|
|
- [DataArea_FileSystem_GET.cs#L264](/mnt/c/Workspace/C4IT%20DEV%20LIAM%20WEB%20Service_git/LiamNtfs/C4IT_IAM_SET/DataArea_FileSystem_GET.cs#L264)
|
|
|
|
## Fazit
|
|
|
|
Der NTFS-Provider ist an mehreren Stellen funktionsfähig, aber der Schreibpfad ist deutlich fragiler als der Lesepfad.
|
|
|
|
Die wichtigsten Risiken sind:
|
|
|
|
- stille Erfolgsrückgaben trotz unvollständiger Traverse-Verarbeitung
|
|
- mutierende Templates mit Folgeschäden für Naming und Wiederholungslogik
|
|
- blockierende Wartezeiten und inkonsistentes SMB-Verbindungsverhalten
|
|
- Berücksichtigung geerbter ACLs im neuen Ensure-Pfad trotz fachlicher Gegenanforderung
|
|
- unvollständige oder irreführende Fehlerkommunikation nach außen
|
|
|
|
Für eine technische Bereinigung würde ich die Themen in dieser Reihenfolge angehen:
|
|
|
|
1. harte Erfolgs-/Fehlersemantik im Create-/Ensure-/Traverse-Pfad
|
|
2. Entfernen des `Thread.Sleep` und Ersatz durch kontrolliertes Polling
|
|
3. Templates unveränderlich behandeln und pro Lauf kopieren
|
|
4. ACL-Prüfungen im Ensure-Pfad auf explizite Regeln einschränken
|
|
5. Tag- und Konfigurationsauflösung sauber zentralisieren
|