Skip to content

Commit 869ef3a

Browse files
committed
Merge branch 'main' into add-zen-qa
2 parents 2c1e80a + a3d7546 commit 869ef3a

13 files changed

Lines changed: 253 additions & 74 deletions

File tree

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,18 +36,18 @@ Zen operates autonomously on the same server as your Java app to:
3636
### Web frameworks
3737
#### Java
3838
*[`Spring MVC`](docs/spring.md) 3.x
39-
*[`Spring Webflux`](docs/spring_webflux.md) 3.x
4039
*[`Javalin`](docs/javalin.md) 6.x
40+
* 🚧 [`Spring Webflux`](docs/spring_webflux.md) 3.x
4141

4242
#### Kotlin
4343
*[`Spring MVC`](docs/spring.md) 3.x
44-
*[`Spring Webflux`](docs/spring_webflux.md) 3.x
4544
*[`Javalin`](docs/javalin.md) 6.x
45+
* 🚧 [`Spring Webflux`](docs/spring_webflux.md) 3.x
4646
* 🚧 `Ktor`
4747

4848
#### Groovy
4949
*[`Spring MVC`](docs/spring.md) 3.x
50-
* [`Spring Webflux`](docs/spring_webflux.md) 3.x
50+
* 🚧 [`Spring Webflux`](docs/spring_webflux.md) 3.x
5151

5252
#### 🚧 Scala
5353
* 🚧 `Akka`
Lines changed: 21 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,14 @@
11
package dev.aikido.agent_api.background.cloud;
22

33
import dev.aikido.agent_api.Config;
4+
import dev.aikido.agent_api.helpers.net.Hostname;
5+
import dev.aikido.agent_api.helpers.net.IPAddress;
46
import dev.aikido.agent_api.storage.ServiceConfigStore;
57
import dev.aikido.agent_api.storage.ServiceConfiguration;
68

79
import java.util.List;
810
import java.util.Map;
911

10-
import static dev.aikido.agent_api.helpers.net.Hostname.getHostname;
11-
import static dev.aikido.agent_api.helpers.net.IPAddress.getIpAddress;
12-
1312
/**
1413
* Class to give you the "agent" info, which is the CloudConnectionManager in Java.
1514
*/
@@ -29,37 +28,40 @@ public record ManagerInfo(
2928
String nodeEnv,
3029
Platform platform
3130
) {}
31+
32+
3233
public record OS(String name, String version) {}
34+
private static final OS OS_INFO;
35+
static {
36+
String osName = System.getProperty("os.name");
37+
String osVersion = System.getProperty("os.version");
38+
OS_INFO = new OS(osName, osVersion);
39+
}
3340

3441
public record Platform(String name, String version) {}
42+
private static final Platform PLATFORM_INFO;
43+
static {
44+
String jvmName = System.getProperty("java.vm.name");
45+
String jvmVersion = System.getProperty("java.version");
46+
PLATFORM_INFO = new Platform(jvmName, jvmVersion);
47+
}
48+
3549

3650
public static ManagerInfo getManagerInfo() {
3751
ServiceConfiguration serviceConfig = ServiceConfigStore.getConfig();
3852
return new ManagerInfo(
3953
!serviceConfig.isBlockingEnabled(), // dryMode
40-
getHostname(), // hostname
54+
Hostname.get(), // hostname
4155
Config.pkgVersion, // version
4256
"firewall-java", // library
43-
getIpAddress(), // ipAddress
57+
IPAddress.get(), // ipAddress
4458
Map.of(), // packages (FIX LATER)
4559
null, // serverless is not supported for Java
4660
List.of(), // stack
47-
getOSInfo(), // os
61+
OS_INFO, // os
4862
false, // preventedPrototypePollution, should be removed from API
4963
"", // nodeEnv
50-
getPlatformInfo() // platform info
64+
PLATFORM_INFO // platform info
5165
);
5266
}
53-
54-
private static OS getOSInfo() {
55-
String name = System.getProperty("os.name");
56-
String version = System.getProperty("os.version");
57-
return new OS(name, version);
58-
}
59-
60-
private static Platform getPlatformInfo() {
61-
String name = System.getProperty("java.vm.name");
62-
String version = System.getProperty("java.version");
63-
return new Platform(name, version);
64-
}
6567
}

agent_api/src/main/java/dev/aikido/agent_api/background/cloud/api/events/DetectedAttack.java

Lines changed: 32 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
import dev.aikido.agent_api.context.User;
66
import dev.aikido.agent_api.vulnerabilities.Attack;
77

8-
import java.util.List;
98
import java.util.Map;
109

1110
import static dev.aikido.agent_api.background.cloud.GetManagerInfo.getManagerInfo;
@@ -23,11 +22,9 @@ public record DetectedAttackEvent (
2322
) implements APIEvent {}
2423
public record RequestData (
2524
String method,
26-
Map<String, List<String>> headers,
2725
String ipAddress,
2826
String userAgent,
2927
String url,
30-
String body,
3128
String source,
3229
String route
3330
) {};
@@ -48,26 +45,41 @@ public record AttackData (
4845

4946
public static DetectedAttackEvent createAPIEvent(Attack attack, ContextObject context) {
5047
boolean blocking = getConfig().isBlockingEnabled();
51-
RequestData requestData = new RequestData(
52-
context.getMethod(), // Method
53-
context.getHeaders(), // headers
54-
context.getRemoteAddress(), // ipAddress
55-
context.getHeader("user-agent"), // userAgent
56-
context.getUrl(), // url
57-
context.getJSONBody(), // body
58-
context.getSource(), // source
59-
context.getRoute() // route
60-
);
61-
AttackData attackData = new AttackData(
62-
attack.kind, attack.operation, attack.source, attack.pathToPayload, attack.payload, attack.metadata,
63-
"module", blocking, attack.stack, attack.user
64-
);
6548
return new DetectedAttackEvent(
66-
"detected_attack", // type
67-
requestData, // request
68-
attackData, // attack
49+
"detected_attack", // type
50+
buildRequestData(context), // request
51+
buildAttackData(attack, blocking), // attack
6952
getManagerInfo(), // agent
7053
getUnixTimeMS() // time
7154
);
7255
}
56+
57+
private static RequestData buildRequestData(ContextObject context) {
58+
if (context == null) {
59+
return null;
60+
}
61+
return new RequestData(
62+
context.getMethod(),
63+
context.getRemoteAddress(),
64+
context.getHeader("user-agent"),
65+
context.getUrl(),
66+
context.getSource(),
67+
context.getRoute()
68+
);
69+
}
70+
71+
private static AttackData buildAttackData(Attack attack, boolean blocking) {
72+
return new AttackData(
73+
attack.kind,
74+
attack.operation,
75+
attack.source,
76+
attack.pathToPayload,
77+
attack.payload,
78+
attack.metadata,
79+
"module",
80+
blocking,
81+
attack.stack,
82+
attack.user
83+
);
84+
}
7385
}

agent_api/src/main/java/dev/aikido/agent_api/context/ContextObject.java

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -99,16 +99,6 @@ public HashMap<String, List<String>> getCookies() {
9999
public Map<String, Map<String, String>> getCache() { return cache; }
100100
public Hostnames getHostnames() { return hostnames; }
101101

102-
public String toJson() {
103-
Gson gson = new GsonBuilder().setPrettyPrinting().create();
104-
return gson.toJson(this);
105-
}
106-
107-
public String getJSONBody() {
108-
Gson gson = new Gson();
109-
return gson.toJson(this.body);
110-
}
111-
112102
public void setForcedProtectionOff(boolean forcedProtectionOff) {
113103
this.forcedProtectionOff = Optional.of(forcedProtectionOff);
114104
}

agent_api/src/main/java/dev/aikido/agent_api/helpers/net/Hostname.java

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,25 +2,30 @@
22

33
import dev.aikido.agent_api.helpers.logging.LogManager;
44
import dev.aikido.agent_api.helpers.logging.Logger;
5-
65
import java.io.IOException;
76
import java.util.Scanner;
87

9-
108
public final class Hostname {
119
private Hostname() {}
10+
1211
private static final Logger logger = LogManager.getLogger(Hostname.class);
12+
private static final String HOSTNAME;
1313

14-
public static String getHostname() {
15-
// getHostName function seem unreliable, so using "hostname" command which works for both UNIX(-like) systems and Windows
16-
// See https://stackoverflow.com/a/7800008 for more info.
14+
// getHostName function seem unreliable, so using "hostname" command which works for both UNIX(-like) systems and Windows
15+
// See https://stackoverflow.com/a/7800008 for more info.
16+
static {
17+
String hostname = "unknown";
1718
try (Scanner s = new Scanner(Runtime.getRuntime().exec("hostname").getInputStream()).useDelimiter("\\A")) {
1819
if (s.hasNext()) {
19-
return s.next().trim();
20+
hostname = s.next().trim();
2021
}
2122
} catch (IOException e) {
2223
logger.debug(e);
2324
}
24-
return "unknown";
25+
HOSTNAME = hostname;
26+
}
27+
28+
public static String get() {
29+
return HOSTNAME;
2530
}
2631
}

agent_api/src/main/java/dev/aikido/agent_api/helpers/net/IPAddress.java

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,19 +7,23 @@ public final class IPAddress {
77
private IPAddress() {
88
}
99

10-
public static String getIpAddress() {
11-
try {
12-
String hostAddress = InetAddress.getLocalHost().getHostAddress();
10+
private static final String IP_ADDRESS;
1311

12+
static {
13+
String hostAddress = "0.0.0.0";
14+
try {
15+
hostAddress = InetAddress.getLocalHost().getHostAddress();
1416
// Remove the zone index if present
1517
if (hostAddress.contains("%")) {
1618
hostAddress = hostAddress.substring(0, hostAddress.indexOf('%'));
1719
}
18-
19-
return hostAddress;
2020
} catch (UnknownHostException ignored) {
2121
// pass-through
2222
}
23-
return "0.0.0.0";
23+
IP_ADDRESS = hostAddress;
24+
}
25+
26+
public static String get() {
27+
return IP_ADDRESS;
2428
}
2529
}
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
package background.cloud.api;
2+
3+
import dev.aikido.agent_api.background.cloud.api.events.DetectedAttack;
4+
import dev.aikido.agent_api.context.ContextObject;
5+
import dev.aikido.agent_api.vulnerabilities.Attack;
6+
import dev.aikido.agent_api.vulnerabilities.Vulnerabilities;
7+
import org.junit.jupiter.api.Test;
8+
import utils.EmptySampleContextObject;
9+
10+
import java.util.HashMap;
11+
import java.util.Map;
12+
13+
import static org.junit.jupiter.api.Assertions.*;
14+
15+
class DetectedAttackTest {
16+
17+
@Test
18+
void createAPIEvent_WithValidContextAndAttack_ReturnsDetectedAttackEvent() {
19+
// Arrange
20+
ContextObject context = new EmptySampleContextObject("test", "/api/resource", "POST");
21+
22+
Map<String, String> metadata = new HashMap<>();
23+
metadata.put("key", "value");
24+
25+
Attack attack = new Attack(
26+
"read",
27+
new Vulnerabilities.SQLInjectionVulnerability(),
28+
"web",
29+
"/api/resource",
30+
metadata,
31+
"test_payload",
32+
"stack_trace",
33+
null
34+
);
35+
36+
// Act
37+
DetectedAttack.DetectedAttackEvent event = DetectedAttack.createAPIEvent(attack, context);
38+
39+
// Assert
40+
assertNotNull(event);
41+
assertEquals("detected_attack", event.type());
42+
assertNotNull(event.request());
43+
assertEquals("POST", event.request().method());
44+
assertEquals("web", event.request().source());
45+
assertEquals("/api/resource", event.request().route());
46+
assertNotNull(event.attack());
47+
assertEquals("sql_injection", event.attack().kind());
48+
assertEquals("read", event.attack().operation());
49+
assertEquals("web", event.attack().source());
50+
assertEquals("/api/resource", event.attack().path());
51+
assertEquals("test_payload", event.attack().payload());
52+
assertEquals(metadata, event.attack().metadata());
53+
assertEquals("module", event.attack().module());
54+
assertEquals("stack_trace", event.attack().stack());
55+
assertNull(event.attack().user());
56+
assertNotNull(event.agent());
57+
assertTrue(event.time() > 0);
58+
}
59+
60+
@Test
61+
void createAPIEvent_WithNullContext_ReturnsDetectedAttackEventWithNullRequest() {
62+
// Arrange
63+
Attack attack = new Attack(
64+
"read",
65+
new Vulnerabilities.SQLInjectionVulnerability(),
66+
"web",
67+
"/api/resource",
68+
Map.of("key", "value"),
69+
"test_payload",
70+
"stack_trace",
71+
null
72+
);
73+
74+
// Act
75+
DetectedAttack.DetectedAttackEvent event = DetectedAttack.createAPIEvent(attack, null);
76+
77+
// Assert
78+
assertNotNull(event);
79+
assertEquals("detected_attack", event.type());
80+
assertNull(event.request());
81+
assertNotNull(event.attack());
82+
assertEquals("sql_injection", event.attack().kind());
83+
assertEquals("read", event.attack().operation());
84+
assertEquals("web", event.attack().source());
85+
assertEquals("/api/resource", event.attack().path());
86+
assertEquals("test_payload", event.attack().payload());
87+
assertEquals(Map.of("key", "value"), event.attack().metadata());
88+
assertEquals("module", event.attack().module());
89+
assertEquals("stack_trace", event.attack().stack());
90+
assertNull(event.attack().user());
91+
assertNotNull(event.agent());
92+
assertTrue(event.time() > 0);
93+
}
94+
}

0 commit comments

Comments
 (0)