- Add 07-02-SUMMARY.md with implementation details - Update STATE.md: progress 62%, decisions, session - Update ROADMAP.md: phase 7 now 3/8 plans complete
4.4 KiB
phase, plan, subsystem, tags, dependency_graph, tech_stack, key_files, decisions, metrics
| phase | plan | subsystem | tags | dependency_graph | tech_stack | key_files | decisions | metrics | |||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 07-user-access-audit | 02 | audit-engine |
|
|
|
|
|
|
Phase 7 Plan 02: UserAccessAuditService Implementation Summary
One-liner: UserAccessAuditService scans PermissionsService results across multiple sites, filters by target user logins via bidirectional contains matching, and emits fully-denormalized UserAccessEntry rows with access type classification, high-privilege detection, and external user flagging.
What Was Built
UserAccessAuditService.cs — Core business logic service implementing IUserAccessAuditService:
-
Multi-site loop — Iterates sites list, builds a
TenantProfileper site (TenantUrl = site URL), obtains aClientContextvia the injectedISessionManager, then delegates toIPermissionsService.ScanSiteAsyncfor raw permission data. Progress is reported per site. -
TransformEntries — Static iterator method that splits semicolon-delimited
UserLogins,Users, andPermissionLevelsfields from eachPermissionEntry. For each user/level combination that matches a target login, yields aUserAccessEntryrecord. Usesyield returnfor lazy evaluation. -
User matching — Case-insensitive bidirectional contains:
loginLower.Contains(target) || target.Contains(loginLower). Handles both plain email addresses and full SharePoint claim format (i:0#.f|membership|alice@contoso.com). -
ClassifyAccessType — Maps
HasUniquePermissions+GrantedThroughtoAccessTypeenum:!HasUniquePermissions→ Inherited;GrantedThroughstarts with "SharePoint Group:" → Group; else Direct. -
HighPrivilegeLevels — Static
HashSet<string>(case-insensitive) containing "Full Control" and "Site Collection Administrator". O(1) lookup per entry.
Tasks
| # | Task | Status | Commit |
|---|---|---|---|
| 1 | Implement UserAccessAuditService | Done | 44b238e |
Decisions Made
-
ClientId empty in service —
TenantProfile.ClientIdis set tostring.Emptywhen constructing per-site profiles.SessionManagervalidates ClientId only when creating a new context. Since the user authenticates at the ViewModel layer before invoking the service, the session is already cached and returned by URL key without re-checking ClientId. -
Bidirectional contains matching — The target login could be a short email ("alice@contoso.com") while the PermissionEntry stores the full claim ("i:0#.f|membership|alice@contoso.com"), or vice versa. Bidirectional contains handles both cases without requiring callers to normalize their input format.
-
Fully denormalized output — Consistent with the 07-01 decision: one row per user + object + permission level. A single PermissionEntry with 2 users and 3 permission levels emits up to 6 UserAccessEntry rows.
Deviations from Plan
None — plan executed exactly as written.
Verification
dotnet build SharepointToolbox/SharepointToolbox.csproj— 0 errors, 0 warnings- UserAccessAuditService implements IUserAccessAuditService interface
- TransformEntries splits semicolon-delimited logins/names/levels correctly
- ClassifyAccessType maps HasUniquePermissions + GrantedThrough to AccessType enum
- HighPrivilegeLevels HashSet contains "Full Control" and "Site Collection Administrator"
Self-Check: PASSED
Files confirmed present:
- FOUND: SharepointToolbox/Services/UserAccessAuditService.cs
Commits confirmed:
- FOUND:
44b238e