Skip to content

Commit e192b8c

Browse files
Add webhook domain exclusion config for notification channels (#172)
* Add webhook domain exclusion config for notification channels
1 parent 93f14a5 commit e192b8c

17 files changed

Lines changed: 240 additions & 9 deletions

File tree

alerting-config-service-api/build.gradle.kts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,11 @@ protobuf {
3131

3232
dependencies {
3333
api(libs.bundles.grpc.api)
34+
constraints {
35+
implementation("com.google.guava:guava:32.0.1-jre") {
36+
because("https://nvd.nist.gov/vuln/detail/CVE-2023-2976")
37+
}
38+
}
3439
}
3540

3641
sourceSets {

config-proto-converter/build.gradle.kts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,9 @@ dependencies {
1111
because("https://snyk.io/vuln/SNYK-JAVA-COMGOOGLECODEGSON-1730327")
1212
}
1313
}
14+
constraints {
15+
implementation("com.google.guava:guava:32.0.1-jre") {
16+
because("https://nvd.nist.gov/vuln/detail/CVE-2023-2976")
17+
}
18+
}
1419
}

config-service-api/build.gradle.kts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,4 +73,9 @@ dependencies {
7373
testFixturesImplementation(libs.guava)
7474
testFixturesAnnotationProcessor(libs.lombok)
7575
testFixturesCompileOnly(libs.lombok)
76+
constraints {
77+
implementation("com.google.guava:guava:32.0.1-jre") {
78+
because("https://nvd.nist.gov/vuln/detail/CVE-2023-2976")
79+
}
80+
}
7681
}

config-service-factory/src/main/java/org/hypertrace/config/service/ConfigServiceFactory.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,8 @@ public List<GrpcPlatformService> buildServices(
6565
localChannel, config, configChangeEventGenerator),
6666
new EventConditionConfigServiceImpl(localChannel, configChangeEventGenerator),
6767
new NotificationRuleConfigServiceImpl(localChannel, configChangeEventGenerator),
68-
new NotificationChannelConfigServiceImpl(localChannel, configChangeEventGenerator),
68+
new NotificationChannelConfigServiceImpl(
69+
localChannel, config, configChangeEventGenerator),
6970
SpanProcessingConfigServiceFactory.build(localChannel, config))
7071
.map(GrpcPlatformService::new)
7172
.collect(Collectors.toUnmodifiableList());

gradle/libs.versions.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[versions]
2-
protoc = "3.21.12"
3-
grpc = "1.56.0"
2+
protoc = "3.23.2"
3+
grpc = "1.56.1"
44
gson = "2.9.0"
55
hypertrace-grpcutils = "0.12.1"
66
hypertrace-framework = "0.1.52"

label-application-rule-config-service-api/build.gradle.kts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,11 @@ protobuf {
3131

3232
dependencies {
3333
api(libs.bundles.grpc.api)
34+
constraints {
35+
implementation("com.google.guava:guava:32.0.1-jre") {
36+
because("https://nvd.nist.gov/vuln/detail/CVE-2023-2976")
37+
}
38+
}
3439
}
3540

3641
sourceSets {

labels-config-service-api/build.gradle.kts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,11 @@ protobuf {
3131

3232
dependencies {
3333
api(libs.bundles.grpc.api)
34+
constraints {
35+
implementation("com.google.guava:guava:32.0.1-jre") {
36+
because("https://nvd.nist.gov/vuln/detail/CVE-2023-2976")
37+
}
38+
}
3439
}
3540

3641
sourceSets {

notification-channel-config-service-api/build.gradle.kts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,11 @@ protobuf {
3131

3232
dependencies {
3333
api(libs.bundles.grpc.api)
34+
constraints {
35+
implementation("com.google.guava:guava:32.0.1-jre") {
36+
because("https://nvd.nist.gov/vuln/detail/CVE-2023-2976")
37+
}
38+
}
3439
}
3540

3641
sourceSets {

notification-channel-config-service-impl/src/main/java/org/hypertrace/notification/config/service/NotificationChannelConfigServiceImpl.java

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package org.hypertrace.notification.config.service;
22

3+
import com.typesafe.config.Config;
34
import io.grpc.Channel;
45
import io.grpc.Status;
56
import io.grpc.stub.StreamObserver;
@@ -27,11 +28,18 @@
2728
public class NotificationChannelConfigServiceImpl
2829
extends NotificationChannelConfigServiceGrpc.NotificationChannelConfigServiceImplBase {
2930

31+
static final String NOTIFICATION_CHANNEL_CONFIG_SERVICE_CONFIG =
32+
"notification.channel.config.service";
33+
3034
private final NotificationChannelStore notificationChannelStore;
3135
private final NotificationChannelConfigServiceRequestValidator validator;
36+
private Config notificationChannelConfig = null;
3237

3338
public NotificationChannelConfigServiceImpl(
34-
Channel channel, ConfigChangeEventGenerator configChangeEventGenerator) {
39+
Channel channel, Config config, ConfigChangeEventGenerator configChangeEventGenerator) {
40+
if (config.hasPath(NOTIFICATION_CHANNEL_CONFIG_SERVICE_CONFIG)) {
41+
this.notificationChannelConfig = config.getConfig(NOTIFICATION_CHANNEL_CONFIG_SERVICE_CONFIG);
42+
}
3543
this.notificationChannelStore =
3644
new NotificationChannelStore(channel, configChangeEventGenerator);
3745
this.validator = new NotificationChannelConfigServiceRequestValidator();
@@ -43,7 +51,8 @@ public void createNotificationChannel(
4351
StreamObserver<CreateNotificationChannelResponse> responseObserver) {
4452
try {
4553
RequestContext requestContext = RequestContext.CURRENT.get();
46-
validator.validateCreateNotificationChannelRequest(requestContext, request);
54+
validator.validateCreateNotificationChannelRequest(
55+
requestContext, request, notificationChannelConfig);
4756
NotificationChannel.Builder builder =
4857
NotificationChannel.newBuilder()
4958
.setId(UUID.randomUUID().toString())
@@ -66,7 +75,8 @@ public void updateNotificationChannel(
6675
StreamObserver<UpdateNotificationChannelResponse> responseObserver) {
6776
try {
6877
RequestContext requestContext = RequestContext.CURRENT.get();
69-
validator.validateUpdateNotificationChannelRequest(requestContext, request);
78+
validator.validateUpdateNotificationChannelRequest(
79+
requestContext, request, notificationChannelConfig);
7080
responseObserver.onNext(
7181
UpdateNotificationChannelResponse.newBuilder()
7282
.setNotificationChannel(

notification-channel-config-service-impl/src/main/java/org/hypertrace/notification/config/service/NotificationChannelConfigServiceRequestValidator.java

Lines changed: 75 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,11 @@
33
import static org.hypertrace.config.validation.GrpcValidatorUtils.validateNonDefaultPresenceOrThrow;
44
import static org.hypertrace.config.validation.GrpcValidatorUtils.validateRequestContextOrThrow;
55

6+
import com.typesafe.config.Config;
67
import io.grpc.Status;
8+
import java.net.MalformedURLException;
9+
import java.net.URL;
10+
import java.util.List;
711
import org.hypertrace.core.grpcutils.context.RequestContext;
812
import org.hypertrace.notification.config.service.v1.AwsS3BucketChannelConfig;
913
import org.hypertrace.notification.config.service.v1.AwsS3BucketChannelConfig.WebIdentityAuthenticationCredential;
@@ -20,17 +24,86 @@
2024

2125
public class NotificationChannelConfigServiceRequestValidator {
2226

27+
public static final String WEBHOOK_EXCLUSION_DOMAINS = "webhook.exclusion.domains";
28+
public static final String WEBHOOK_HTTP_SUPPORT_ENABLED = "webhook.http.support.enabled";
29+
2330
public void validateCreateNotificationChannelRequest(
24-
RequestContext requestContext, CreateNotificationChannelRequest request) {
31+
RequestContext requestContext,
32+
CreateNotificationChannelRequest request,
33+
Config notificationChannelConfig) {
2534
validateRequestContextOrThrow(requestContext);
2635
validateNotificationChannelMutableData(request.getNotificationChannelMutableData());
36+
validateWebhookConfigExclusionDomains(
37+
request.getNotificationChannelMutableData(), notificationChannelConfig);
38+
validateWebhookHttpSupport(
39+
request.getNotificationChannelMutableData(), notificationChannelConfig);
40+
}
41+
42+
void validateWebhookHttpSupport(
43+
NotificationChannelMutableData notificationChannelMutableData,
44+
Config notificationChannelConfig) {
45+
if (notificationChannelConfig == null
46+
|| notificationChannelMutableData.getWebhookChannelConfigList().isEmpty()) {
47+
return;
48+
}
49+
for (WebhookChannelConfig webhookChannelConfig :
50+
notificationChannelMutableData.getWebhookChannelConfigList()) {
51+
if (notificationChannelConfig.hasPath(WEBHOOK_HTTP_SUPPORT_ENABLED)
52+
&& notificationChannelConfig.getBoolean(WEBHOOK_HTTP_SUPPORT_ENABLED)) {
53+
continue;
54+
}
55+
validateHttpsUrl(webhookChannelConfig.getUrl());
56+
}
57+
}
58+
59+
private void validateHttpsUrl(String urlString) {
60+
try {
61+
URL url = new URL(urlString);
62+
String protocol = url.getProtocol();
63+
if (!protocol.equals("https")) {
64+
throw Status.INVALID_ARGUMENT
65+
.withDescription("URL configured in webhook is not https ")
66+
.asRuntimeException();
67+
}
68+
} catch (MalformedURLException e) {
69+
throw Status.INVALID_ARGUMENT
70+
.withDescription("URL configured in webhook is malformed ")
71+
.asRuntimeException();
72+
}
73+
}
74+
75+
void validateWebhookConfigExclusionDomains(
76+
NotificationChannelMutableData notificationChannelMutableData,
77+
Config notificationChannelConfig) {
78+
if (notificationChannelConfig == null
79+
|| notificationChannelMutableData.getWebhookChannelConfigList().isEmpty()) {
80+
return;
81+
}
82+
if (notificationChannelConfig.hasPath(WEBHOOK_EXCLUSION_DOMAINS)) {
83+
List<String> exclusionDomains =
84+
notificationChannelConfig.getStringList(WEBHOOK_EXCLUSION_DOMAINS);
85+
for (WebhookChannelConfig webhookChannelConfig :
86+
notificationChannelMutableData.getWebhookChannelConfigList()) {
87+
for (String exclusionDomain : exclusionDomains) {
88+
if (webhookChannelConfig.getUrl().contains(exclusionDomain)) {
89+
throw Status.INVALID_ARGUMENT
90+
.withDescription("URL configured in webhook contains excluded domain")
91+
.asRuntimeException();
92+
}
93+
}
94+
}
95+
}
2796
}
2897

2998
public void validateUpdateNotificationChannelRequest(
30-
RequestContext requestContext, UpdateNotificationChannelRequest request) {
99+
RequestContext requestContext,
100+
UpdateNotificationChannelRequest request,
101+
Config notificationChannelConfig) {
31102
validateRequestContextOrThrow(requestContext);
32103
validateNonDefaultPresenceOrThrow(request, UpdateNotificationChannelRequest.ID_FIELD_NUMBER);
33104
validateNotificationChannelMutableData(request.getNotificationChannelMutableData());
105+
validateWebhookConfigExclusionDomains(
106+
request.getNotificationChannelMutableData(), notificationChannelConfig);
34107
}
35108

36109
private void validateNotificationChannelMutableData(NotificationChannelMutableData data) {

0 commit comments

Comments
 (0)