|
1 | 1 | package collectors; |
2 | 2 |
|
| 3 | +import dev.aikido.agent_api.background.cloud.api.events.DetectedAttackWave; |
| 4 | +import dev.aikido.agent_api.collectors.WebRequestCollector; |
3 | 5 | import dev.aikido.agent_api.collectors.WebResponseCollector; |
4 | 6 | import dev.aikido.agent_api.context.Context; |
5 | 7 | import dev.aikido.agent_api.context.ContextObject; |
6 | 8 | import dev.aikido.agent_api.context.RouteMetadata; |
| 9 | +import dev.aikido.agent_api.context.User; |
| 10 | +import dev.aikido.agent_api.storage.AttackQueue; |
| 11 | +import dev.aikido.agent_api.storage.ServiceConfigStore; |
7 | 12 | import dev.aikido.agent_api.storage.routes.RoutesStore; |
| 13 | +import dev.aikido.agent_api.storage.statistics.StatisticsStore; |
8 | 14 | import org.junit.jupiter.api.*; |
9 | 15 | import org.junit.jupiter.api.Test; |
| 16 | +import utils.EmptySampleContextObject; |
10 | 17 |
|
11 | 18 | import java.sql.SQLException; |
12 | 19 | import java.util.HashMap; |
| 20 | +import java.util.Map; |
13 | 21 |
|
14 | 22 | import static org.junit.jupiter.api.Assertions.*; |
| 23 | +import static utils.EmptyAPIResponses.emptyAPIListsResponse; |
| 24 | +import static utils.EmptyAPIResponses.emptyAPIResponse; |
15 | 25 |
|
16 | 26 |
|
17 | 27 | public class WebResponseCollectorTest { |
@@ -43,6 +53,8 @@ public static void clean() { |
43 | 53 | public void tearDown() throws SQLException { |
44 | 54 | Context.set(null); |
45 | 55 | RoutesStore.clear(); |
| 56 | + AttackQueue.clear(); |
| 57 | + StatisticsStore.clear(); |
46 | 58 | } |
47 | 59 |
|
48 | 60 | @Test |
@@ -92,5 +104,81 @@ public void testResponseCollectorWithInvalidMethodOrStatusCode() throws SQLExcep |
92 | 104 | WebResponseCollector.report(-200); |
93 | 105 | assertEquals(0, RoutesStore.getRoutesAsList().length); |
94 | 106 | } |
| 107 | + |
| 108 | + @Test |
| 109 | + public void testAttackWaveDetectionWithUserSet() throws SQLException, InterruptedException { |
| 110 | + // Setup |
| 111 | + ServiceConfigStore.updateFromAPIResponse(emptyAPIResponse); |
| 112 | + ServiceConfigStore.updateFromAPIListsResponse(emptyAPIListsResponse); |
| 113 | + |
| 114 | + // Create attack wave context (unusual route/method that triggers attack wave detection) |
| 115 | + ContextObject attackWaveCtx = new EmptySampleContextObject("/wp-config.php", "BADMETHOD", Map.of()); |
| 116 | + |
| 117 | + // Set a user in the context (simulating SetUser.setUser being called during request) |
| 118 | + User testUser = new User("user123", "John Doe", "192.168.1.1", System.currentTimeMillis()); |
| 119 | + attackWaveCtx.setUser(testUser); |
| 120 | + |
| 121 | + // Simulate the request flow: first WebRequestCollector, then trigger attack wave detection |
| 122 | + // We need to trigger attack waves by making multiple requests |
| 123 | + for (int i = 0; i < 15; i++) { |
| 124 | + Context.set(attackWaveCtx); |
| 125 | + WebRequestCollector.report(attackWaveCtx); |
| 126 | + } |
| 127 | + |
| 128 | + // Now call WebResponseCollector which should detect the attack wave WITH user info |
| 129 | + Context.set(attackWaveCtx); |
| 130 | + WebResponseCollector.report(200); |
| 131 | + |
| 132 | + // Verify attack wave was detected |
| 133 | + assertTrue(AttackQueue.getSize() > 0, "Attack wave should be detected"); |
| 134 | + assertEquals(1, StatisticsStore.getStatsRecord().requests().attackWaves().total()); |
| 135 | + |
| 136 | + // Get the attack wave event and verify user information is captured |
| 137 | + DetectedAttackWave.DetectedAttackWaveEvent event = |
| 138 | + (DetectedAttackWave.DetectedAttackWaveEvent) AttackQueue.get(); |
| 139 | + |
| 140 | + assertNotNull(event); |
| 141 | + assertEquals("detected_attack_wave", event.type()); |
| 142 | + assertEquals("192.168.1.1", event.request().ipAddress()); |
| 143 | + assertEquals("web", event.request().source()); |
| 144 | + |
| 145 | + // The key assertion: user information should be present |
| 146 | + assertNotNull(event.attack().user(), "User should be captured in attack wave event"); |
| 147 | + assertEquals("user123", event.attack().user().id()); |
| 148 | + assertEquals("John Doe", event.attack().user().name()); |
| 149 | + } |
| 150 | + |
| 151 | + @Test |
| 152 | + public void testAttackWaveDetectionWithoutUser() throws SQLException, InterruptedException { |
| 153 | + // Setup |
| 154 | + ServiceConfigStore.updateFromAPIResponse(emptyAPIResponse); |
| 155 | + ServiceConfigStore.updateFromAPIListsResponse(emptyAPIListsResponse); |
| 156 | + |
| 157 | + // Create attack wave context without user |
| 158 | + ContextObject attackWaveCtx = new EmptySampleContextObject("/wp-config.php", "BADMETHOD", Map.of()); |
| 159 | + |
| 160 | + // Trigger attack waves by making multiple requests |
| 161 | + for (int i = 0; i < 15; i++) { |
| 162 | + Context.set(attackWaveCtx); |
| 163 | + WebRequestCollector.report(attackWaveCtx); |
| 164 | + } |
| 165 | + |
| 166 | + // Call WebResponseCollector which should detect the attack wave without user info |
| 167 | + Context.set(attackWaveCtx); |
| 168 | + WebResponseCollector.report(200); |
| 169 | + |
| 170 | + // Verify attack wave was detected |
| 171 | + assertTrue(AttackQueue.getSize() > 0, "Attack wave should be detected"); |
| 172 | + |
| 173 | + // Get the attack wave event |
| 174 | + DetectedAttackWave.DetectedAttackWaveEvent event = |
| 175 | + (DetectedAttackWave.DetectedAttackWaveEvent) AttackQueue.get(); |
| 176 | + |
| 177 | + assertNotNull(event); |
| 178 | + assertEquals("detected_attack_wave", event.type()); |
| 179 | + |
| 180 | + // User should be null when not set |
| 181 | + assertNull(event.attack().user(), "User should be null when not set during request"); |
| 182 | + } |
95 | 183 | } |
96 | 184 |
|
0 commit comments