Commit 4366ef0
fix: authorize every connection-scoped endpoint (116 were unguarded) (#86)
12 controllers took a caller-supplied connectionId and never checked it.
SecurityConfig only asserts .anyRequest().authenticated() and no filter,
interceptor or aspect inspects a connection id, so authentication was
the only barrier. Verified against a running install, not inferred: a
DEVELOPER holding no grant on any connection could
- read literal-bearing slow-query SQL with real customer ids and names
(GET /slow-query-analytics/{id}/query/{fp}/samples returned 200 while
GET /slow-log-source/{id} returned 403 in the same session),
- enumerate another tenant's schema and table statistics, via two
endpoints that decrypt the target connection's credentials and open a
live JDBC session (/tenant-column-suggestions and /config),
- and permanently delete that tenant's analysis history (DELETE
/slow-queries/history/connection/{id} -> 200, row gone).
Affected: SlowQueryController (43), SlowQueryAnalyticsController (13),
SchemaChangeController (13), SentinelAnalyticsController (10),
PerformanceActionController (9), QueryPerformanceController (8),
QueryPlanController (8), IndexAdvisorController (7),
PerformanceInsightsController (5), AdvisorController (3),
ResourceLimitsController (3), BusinessRuleController (3).
This is the same class of defect BrainController carried (93 of 116
unguarded). The safety test added then hardcodes one Path.of(...), so it
could not see any of these.
What changed
* 127 guard calls: assertCanReadConnectionContent on reads,
assertCanManageConnectionContent on writes and deletes.
* An id is not a capability. For endpoints keyed on alertId, actionId,
regressionId, recommendationId, fingerprintId, planId, ruleId,
snapshotId or historyId, resolve the owning connection and assert on
that. 15 new findConnectionIdFor* accessors where no lookup existed.
These report 404, not 403, for an unknown id — a 403 confirms the row
exists, turning the endpoint into an id oracle, and regressionId is a
sequential Long.
* Ids arriving in the request body are not constrained by a
path-variable check. Four holes survived exactly that kind of fix:
- schema-changes/snapshots/compare took two snapshot ids and no
connectionId at all, so it would diff tenant A's schema against tenant
B's; compareSnapshots now refuses a mismatch outright.
- PUT /performance-actions/batch-status took an arbitrary actionIds list
with no scope; it now authorizes every id before mutating any, so a
mixed batch fails atomically.
- changes/acknowledge and regressions/acknowledge authorized the path
connection and then acted on whatever ids the body named;
allChangesBelongTo / allComparisonsBelongTo verify membership, and an id
that resolves to nothing fails too, so unknown ids cannot be mixed into
an otherwise valid batch.
* Never take the actor from the request. userId was a query parameter
and acknowledgedBy/resolvedBy/updatedBy defaulted to the literal string
"user", so the acknowledgement trail was unauthenticated free text that
could name any colleague. 10 sites now use requireCurrentUsername(). The
parameters are still accepted for wire compatibility and ignored.
* ConnectionScopedAuthorizationSafetyTest replaces the per-file
approach: it scans every *Controller.java, so a new controller is
covered the day it is written. Six cases — connection-scoped endpoints
authorized, body-supplied id collections scoped, 403 not swallowed into
500, controller advices not swallowing denials, exemptions still true,
delegated service checks still present. The exemption list is itself
guarded, so it cannot rot into a way of hiding a real gap.
Two things found by writing and running the fix, not by reading it
* The generalized test immediately found 9 more unguarded endpoints in
controllers nobody was looking at: StatsController, ProjectController,
DashboardController, and a destructive DELETE
/sentinel/demo/cleanup/{connectionId}. Three had been in my draft
exemption list on the assumption they were connection-free; they were
not.
* Testing the fix found a bug reading it never would. 24 endpoints
returned 403 and index-advisor returned 500:
IndexAdvisorExceptionHandler's @ExceptionHandler(Exception.class)
swallowed the denial and reported "Index operation failed" with the
403's text in the body. The guard held, but the response blamed the
index store. It now handles ResponseStatusException first, and the
safety test asserts no advice with a catch-all omits that.
Also drops @crossorigin(origins = "*") from SentinelAnalyticsController.
Tested and inert — an evil-origin preflight gets 403 with no
Access-Control-Allow-Origin because the SecurityConfig allowlist wins,
while an allowed origin gets 200 + ACAO — but it reads like an
intentional hole.
Verification
Real Maven compile of main and test sources, zero errors.
SlowQueryControllerS3Test needed the new constructor argument and was
updated rather than left red.
Live, against the rebuilt image with a DEVELOPER holding no grant on the
target connection:
- 40/40 previously-leaking reads -> 403
- 10/10 writes and destructive endpoints -> 403, and psql confirms
nothing was mutated
- 7/7 orphan-id and body-scoped paths -> 404, no existence oracle
- 30/30 same endpoint shapes on a granted connection -> 200, zero false
denials; confirmed again from a real browser session
- index-advisor now returns 403 "Read access denied for this connection"
Not covered: mvn test was not executed (the image build uses -DskipTests
and this host has no JDK/Maven). The six safety-test cases were
validated by re-implementing their scan logic against the tree and the
file compiles, but they have not been run by JUnit.
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: Venkat SF <venkatesh.sakamuri@stayflexi.com>1 parent b04683a commit 4366ef0
28 files changed
Lines changed: 1277 additions & 35 deletions
File tree
- backend/src
- main/java/com/dbaagent
- controller
- service
- security
- test/java/com/dbaagent/controller
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
709 | 709 | | |
710 | 710 | | |
711 | 711 | | |
| 712 | + | |
| 713 | + | |
| 714 | + | |
| 715 | + | |
| 716 | + | |
| 717 | + | |
| 718 | + | |
| 719 | + | |
| 720 | + | |
| 721 | + | |
| 722 | + | |
| 723 | + | |
| 724 | + | |
| 725 | + | |
| 726 | + | |
| 727 | + | |
| 728 | + | |
| 729 | + | |
| 730 | + | |
| 731 | + | |
| 732 | + | |
| 733 | + | |
| 734 | + | |
| 735 | + | |
| 736 | + | |
| 737 | + | |
| 738 | + | |
| 739 | + | |
| 740 | + | |
| 741 | + | |
| 742 | + | |
| 743 | + | |
| 744 | + | |
| 745 | + | |
| 746 | + | |
| 747 | + | |
| 748 | + | |
| 749 | + | |
| 750 | + | |
| 751 | + | |
| 752 | + | |
| 753 | + | |
| 754 | + | |
| 755 | + | |
| 756 | + | |
| 757 | + | |
| 758 | + | |
| 759 | + | |
| 760 | + | |
| 761 | + | |
| 762 | + | |
| 763 | + | |
| 764 | + | |
| 765 | + | |
| 766 | + | |
| 767 | + | |
| 768 | + | |
| 769 | + | |
| 770 | + | |
| 771 | + | |
| 772 | + | |
| 773 | + | |
| 774 | + | |
| 775 | + | |
| 776 | + | |
| 777 | + | |
| 778 | + | |
| 779 | + | |
| 780 | + | |
| 781 | + | |
| 782 | + | |
| 783 | + | |
| 784 | + | |
| 785 | + | |
| 786 | + | |
| 787 | + | |
| 788 | + | |
| 789 | + | |
| 790 | + | |
| 791 | + | |
| 792 | + | |
| 793 | + | |
| 794 | + | |
| 795 | + | |
| 796 | + | |
| 797 | + | |
| 798 | + | |
| 799 | + | |
| 800 | + | |
| 801 | + | |
| 802 | + | |
| 803 | + | |
| 804 | + | |
| 805 | + | |
| 806 | + | |
| 807 | + | |
| 808 | + | |
712 | 809 | | |
713 | 810 | | |
714 | 811 | | |
| |||
Lines changed: 14 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
3 | 3 | | |
4 | 4 | | |
5 | 5 | | |
| 6 | + | |
6 | 7 | | |
7 | 8 | | |
8 | 9 | | |
9 | 10 | | |
10 | 11 | | |
11 | 12 | | |
12 | 13 | | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
13 | 23 | | |
14 | 24 | | |
15 | 25 | | |
16 | 26 | | |
17 | 27 | | |
18 | 28 | | |
19 | 29 | | |
| 30 | + | |
20 | 31 | | |
21 | 32 | | |
22 | 33 | | |
| |||
25 | 36 | | |
26 | 37 | | |
27 | 38 | | |
| 39 | + | |
28 | 40 | | |
29 | 41 | | |
30 | 42 | | |
| |||
44 | 56 | | |
45 | 57 | | |
46 | 58 | | |
| 59 | + | |
47 | 60 | | |
48 | 61 | | |
49 | 62 | | |
| |||
63 | 76 | | |
64 | 77 | | |
65 | 78 | | |
| 79 | + | |
66 | 80 | | |
67 | 81 | | |
68 | 82 | | |
| |||
Lines changed: 14 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
2 | 2 | | |
3 | 3 | | |
4 | 4 | | |
| 5 | + | |
5 | 6 | | |
6 | 7 | | |
7 | 8 | | |
| |||
11 | 12 | | |
12 | 13 | | |
13 | 14 | | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
14 | 21 | | |
15 | 22 | | |
16 | 23 | | |
17 | 24 | | |
18 | 25 | | |
19 | 26 | | |
20 | 27 | | |
| 28 | + | |
21 | 29 | | |
22 | 30 | | |
23 | 31 | | |
| |||
26 | 34 | | |
27 | 35 | | |
28 | 36 | | |
| 37 | + | |
29 | 38 | | |
30 | 39 | | |
31 | 40 | | |
| |||
49 | 58 | | |
50 | 59 | | |
51 | 60 | | |
| 61 | + | |
52 | 62 | | |
53 | 63 | | |
54 | 64 | | |
| |||
70 | 80 | | |
71 | 81 | | |
72 | 82 | | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
73 | 87 | | |
74 | 88 | | |
75 | 89 | | |
| |||
Lines changed: 9 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | 2 | | |
3 | 3 | | |
| 4 | + | |
4 | 5 | | |
5 | 6 | | |
6 | 7 | | |
7 | 8 | | |
8 | 9 | | |
9 | 10 | | |
10 | 11 | | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
11 | 18 | | |
12 | 19 | | |
13 | 20 | | |
| |||
16 | 23 | | |
17 | 24 | | |
18 | 25 | | |
| 26 | + | |
19 | 27 | | |
20 | 28 | | |
21 | 29 | | |
| |||
26 | 34 | | |
27 | 35 | | |
28 | 36 | | |
| 37 | + | |
29 | 38 | | |
30 | 39 | | |
31 | 40 | | |
| |||
Lines changed: 15 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
2 | 2 | | |
3 | 3 | | |
4 | 4 | | |
| 5 | + | |
5 | 6 | | |
6 | 7 | | |
7 | 8 | | |
| |||
12 | 13 | | |
13 | 14 | | |
14 | 15 | | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
15 | 22 | | |
16 | 23 | | |
17 | 24 | | |
| |||
21 | 28 | | |
22 | 29 | | |
23 | 30 | | |
| 31 | + | |
24 | 32 | | |
25 | 33 | | |
26 | 34 | | |
27 | 35 | | |
28 | 36 | | |
29 | 37 | | |
| 38 | + | |
30 | 39 | | |
31 | 40 | | |
32 | 41 | | |
| |||
35 | 44 | | |
36 | 45 | | |
37 | 46 | | |
| 47 | + | |
38 | 48 | | |
39 | 49 | | |
40 | 50 | | |
| |||
43 | 53 | | |
44 | 54 | | |
45 | 55 | | |
| 56 | + | |
46 | 57 | | |
47 | 58 | | |
48 | 59 | | |
| |||
53 | 64 | | |
54 | 65 | | |
55 | 66 | | |
| 67 | + | |
56 | 68 | | |
57 | 69 | | |
58 | 70 | | |
| |||
75 | 87 | | |
76 | 88 | | |
77 | 89 | | |
| 90 | + | |
78 | 91 | | |
79 | 92 | | |
80 | 93 | | |
| |||
94 | 107 | | |
95 | 108 | | |
96 | 109 | | |
| 110 | + | |
97 | 111 | | |
98 | 112 | | |
99 | 113 | | |
| |||
102 | 116 | | |
103 | 117 | | |
104 | 118 | | |
| 119 | + | |
105 | 120 | | |
106 | 121 | | |
107 | 122 | | |
0 commit comments