Skip to content

Commit 0208d64

Browse files
authored
Add support for SQLSecurityAuditEvents (#78)
* Implement class for SQLSecurityAuditEventsType * Add SQLSecurityAuditEventsType support to NLFPlugin.syslogMessage * Check "category" valueType in NLFPlugin.syslogMessage - Category should always be a String
1 parent 0be48a8 commit 0208d64

6 files changed

Lines changed: 563 additions & 0 deletions

File tree

src/main/java/com/teragrep/nlf_01/NLFPlugin.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,15 @@ else if (
182182
eventTypes.add(new PostgreSQLType(parsedEvent, realHostname, componentNameForPartitions));
183183
}
184184
}
185+
else if (
186+
jsonObject.containsKey("category")
187+
&& jsonObject.get("category").getValueType().equals(JsonValue.ValueType.STRING)
188+
) {
189+
final String category = jsonObject.getString("category");
190+
if (category.equals("SQLSecurityAuditEvents")) {
191+
eventTypes.add(new SQLSecurityAuditEventsType(parsedEvent, realHostname, componentNameForPartitions));
192+
}
193+
}
185194

186195
if (eventTypes.isEmpty()) {
187196
throw new PluginException(
Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
/*
2+
* Teragrep Neon log format plugin for AKV_01
3+
* Copyright (C) 2025 Suomen Kanuuna Oy
4+
*
5+
* This program is free software: you can redistribute it and/or modify
6+
* it under the terms of the GNU Affero General Public License as published by
7+
* the Free Software Foundation, either version 3 of the License, or
8+
* (at your option) any later version.
9+
*
10+
* This program is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
* GNU Affero General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU Affero General Public License
16+
* along with this program. If not, see <https://www.gnu.org/licenses/>.
17+
*
18+
*
19+
* Additional permission under GNU Affero General Public License version 3
20+
* section 7
21+
*
22+
* If you modify this Program, or any covered work, by linking or combining it
23+
* with other code, such other code is not for that reason alone subject to any
24+
* of the requirements of the GNU Affero GPL version 3 as long as this Program
25+
* is the same Program as licensed from Suomen Kanuuna Oy without any additional
26+
* modifications.
27+
*
28+
* Supplemented terms under GNU Affero General Public License version 3
29+
* section 7
30+
*
31+
* Origin of the software must be attributed to Suomen Kanuuna Oy. Any modified
32+
* versions must be marked as "Modified version of" The Program.
33+
*
34+
* Names of the licensors and authors may not be used for publicity purposes.
35+
*
36+
* No rights are granted for use of trade names, trademarks, or service marks
37+
* which are in The Program if any.
38+
*
39+
* Licensee must indemnify licensors and authors for any liability that these
40+
* contractual assumptions impose on licensors and authors.
41+
*
42+
* To the extent this program is licensed as part of the Commercial versions of
43+
* Teragrep, the applicable Commercial License may apply to this file if you as
44+
* a licensee so wish it.
45+
*/
46+
package com.teragrep.nlf_01.types;
47+
48+
import com.teragrep.akv_01.event.ParsedEvent;
49+
import com.teragrep.akv_01.plugin.PluginException;
50+
import com.teragrep.nlf_01.util.ASCIIString;
51+
import com.teragrep.nlf_01.util.DefaultSDElements;
52+
import com.teragrep.nlf_01.util.MD5Hash;
53+
import com.teragrep.nlf_01.util.ResourceId;
54+
import com.teragrep.nlf_01.util.SDElements;
55+
import com.teragrep.nlf_01.util.ValidKey;
56+
import com.teragrep.nlf_01.util.ValidRFC5424AppName;
57+
import com.teragrep.nlf_01.util.ValidRFC5424Hostname;
58+
import com.teragrep.nlf_01.util.ValidRFC5424Timestamp;
59+
import com.teragrep.nlf_01.util.ValidStringKey;
60+
import com.teragrep.rlo_14.Facility;
61+
import com.teragrep.rlo_14.SDElement;
62+
import com.teragrep.rlo_14.Severity;
63+
import jakarta.json.JsonObject;
64+
import java.util.Objects;
65+
import java.util.Set;
66+
67+
public final class SQLSecurityAuditEventsType implements EventType {
68+
69+
private final ParsedEvent parsedEvent;
70+
private final String realHostname;
71+
private final String componentNameForPartitions;
72+
73+
public SQLSecurityAuditEventsType(
74+
final ParsedEvent parsedEvent,
75+
final String realHostname,
76+
final String componentNameForPartitions
77+
) {
78+
this.parsedEvent = parsedEvent;
79+
this.realHostname = realHostname;
80+
this.componentNameForPartitions = componentNameForPartitions;
81+
}
82+
83+
@Override
84+
public Severity severity() {
85+
return Severity.NOTICE;
86+
}
87+
88+
@Override
89+
public Facility facility() {
90+
return Facility.AUDIT;
91+
}
92+
93+
@Override
94+
public String hostname() throws PluginException {
95+
final JsonObject record = parsedEvent.asJsonStructure().asJsonObject();
96+
97+
final ValidKey<String> validKey = new ValidStringKey(record, "resourceId");
98+
99+
return new ValidRFC5424Hostname(
100+
"md5-".concat(new MD5Hash(validKey.value()).md5().concat("-").concat(new ASCIIString(new ResourceId(validKey.value()).resourceName()).withNonAsciiCharsRemoved()))
101+
).hostnameWithInvalidCharsRemoved();
102+
}
103+
104+
@Override
105+
public String appName() throws PluginException {
106+
final JsonObject record = parsedEvent.asJsonStructure().asJsonObject();
107+
108+
return new ValidRFC5424AppName(new ValidStringKey(record, "operationName").value()).appName();
109+
}
110+
111+
@Override
112+
public long timestamp() throws PluginException {
113+
final JsonObject record = parsedEvent.asJsonStructure().asJsonObject();
114+
115+
return new ValidRFC5424Timestamp(new ValidStringKey(record, "originalEventTimestamp").value()).validTimestamp();
116+
}
117+
118+
@Override
119+
public Set<SDElement> sdElements() throws PluginException {
120+
final SDElements defaultSDElements = new DefaultSDElements(
121+
parsedEvent,
122+
realHostname,
123+
this.getClass(),
124+
componentNameForPartitions
125+
);
126+
127+
return defaultSDElements.sdElements();
128+
}
129+
130+
@Override
131+
public String msgId() throws PluginException {
132+
final String sequenceNumber;
133+
if (!parsedEvent.systemProperties().isStub()) {
134+
sequenceNumber = String.valueOf(parsedEvent.systemProperties().asMap().getOrDefault("SequenceNumber", ""));
135+
}
136+
else {
137+
sequenceNumber = "";
138+
}
139+
return sequenceNumber;
140+
}
141+
142+
@Override
143+
public String msg() throws PluginException {
144+
return parsedEvent.asString();
145+
}
146+
147+
@Override
148+
public boolean equals(final Object o) {
149+
if (o == null || getClass() != o.getClass()) {
150+
return false;
151+
}
152+
final SQLSecurityAuditEventsType that = (SQLSecurityAuditEventsType) o;
153+
return Objects.equals(parsedEvent, that.parsedEvent) && Objects.equals(realHostname, that.realHostname)
154+
&& Objects.equals(componentNameForPartitions, that.componentNameForPartitions);
155+
}
156+
157+
@Override
158+
public int hashCode() {
159+
return Objects.hash(parsedEvent, realHostname, componentNameForPartitions);
160+
}
161+
}

src/test/java/com/teragrep/nlf_01/NLFPluginTest.java

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@
7777
import com.teragrep.nlf_01.types.PostgreSQLType;
7878
import com.teragrep.nlf_01.types.PowerAutomateActivityType;
7979
import com.teragrep.nlf_01.types.PowerPlatformAdminActivityType;
80+
import com.teragrep.nlf_01.types.SQLSecurityAuditEventsType;
8081
import com.teragrep.nlf_01.types.SyslogType;
8182
import com.teragrep.nlf_01.util.Sourceable;
8283
import com.teragrep.rlo_14.SDElement;
@@ -1017,6 +1018,45 @@ void testPowerPlatformAdminActivityType() {
10171018
Assertions.assertTrue(sdElementMap.get("aer_event@48577").containsKey("properties"));
10181019
}
10191020

1021+
@Test
1022+
void sqlSecurityAuditEventsTypeTest() {
1023+
final String json = Assertions
1024+
.assertDoesNotThrow(() -> Files.readString(Paths.get("src/test/resources/sqlsecurityauditevents.json")));
1025+
final ParsedEvent parsedEvent = new ParsedEventFactory(
1026+
new UnparsedEventImpl(json, new EventPartitionContextImpl(new HashMap<>()), new EventPropertiesImpl(new HashMap<>()), new EventSystemPropertiesImpl(new HashMap<>()), new EnqueuedTimeImpl("2020-01-01T00:00:00"), new EventOffsetImpl("0"))
1027+
).parsedEvent();
1028+
1029+
final NLFPlugin plugin = new NLFPlugin(new FakeSourceable());
1030+
final List<SyslogMessage> syslogMessages = Assertions
1031+
.assertDoesNotThrow(() -> plugin.syslogMessage(parsedEvent));
1032+
Assertions.assertEquals(1, syslogMessages.size());
1033+
1034+
final SyslogMessage syslogMessage = syslogMessages.get(0);
1035+
Assertions
1036+
.assertEquals(
1037+
"{\n" + " \"category\": \"SQLSecurityAuditEvents\",\n"
1038+
+ " \"operationName\": \"Operation-1\",\n"
1039+
+ " \"originalEventTimestamp\": \"2025-10-06T00:00:00.0000000Z\",\n"
1040+
+ " \"resourceId\": \"/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{resourceProviderNamespace}/{resourceType}/{resourceName}\"\n"
1041+
+ "}",
1042+
syslogMessage.getMsg()
1043+
);
1044+
Assertions.assertEquals("md5-0ded52ef915af563e25778bf26b0f129-resourceName", syslogMessage.getHostname());
1045+
Assertions.assertEquals("Operation-1", syslogMessage.getAppName());
1046+
Assertions.assertEquals("2025-10-06T00:00:00Z", syslogMessage.getTimestamp());
1047+
1048+
final Map<String, Map<String, String>> sdElementMap = syslogMessage
1049+
.getSDElements()
1050+
.stream()
1051+
.collect(Collectors.toMap((SDElement::getSdID), (sdElem) -> sdElem.getSdParams().stream().collect(Collectors.toMap(SDParam::getParamName, SDParam::getParamValue))));
1052+
1053+
Assertions.assertEquals(1, sdElementMap.get("nlf_01@48577").size());
1054+
Assertions
1055+
.assertEquals(SQLSecurityAuditEventsType.class.getSimpleName(), sdElementMap.get("nlf_01@48577").get("eventType"));
1056+
1057+
Assertions.assertTrue(sdElementMap.get("aer_event@48577").containsKey("properties"));
1058+
}
1059+
10201060
@Test
10211061
void unexpectedType() {
10221062
final String json = Assertions

0 commit comments

Comments
 (0)