Skip to content

Commit 1b6d400

Browse files
authored
Merge branch 'main' into mike-pt/patch-jaasConfig-for-gcp
2 parents 5222498 + 5079b00 commit 1b6d400

File tree

112 files changed

+2490
-255
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

112 files changed

+2490
-255
lines changed

.github/CODEOWNERS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33

44
# BACKEND
5+
gradle/libs.versions.toml @kafbat/backend
56
/build.gradle @kafbat/backend
67
/gradle.properties @kafbat/backend
78
/settings.gradle @kafbat/backend

.github/dependabot.yml

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,20 @@ updates:
77
interval: weekly
88
time: "10:00"
99
timezone: Europe/London
10-
reviewers:
11-
- "kafbat/backend"
1210
open-pull-requests-limit: 10
1311
labels:
1412
- "type/dependencies"
1513
- "scope/backend"
1614
groups:
17-
gradle-dependencies:
15+
spring-boot-dependencies:
16+
patterns:
17+
- "org.springframework.boot:*"
18+
- "io.spring.dependency-management"
19+
# We will handle major upgrades manually
20+
update-types:
21+
- "patch"
22+
- "minor"
23+
other-dependencies:
1824
patterns:
1925
- "*"
2026
update-types:
@@ -27,8 +33,6 @@ updates:
2733
interval: weekly
2834
time: "10:00"
2935
timezone: Europe/London
30-
reviewers:
31-
- "kafbat/backend"
3236
open-pull-requests-limit: 10
3337
ignore:
3438
- dependency-name: "azul/zulu-openjdk-alpine"
@@ -43,8 +47,6 @@ updates:
4347
interval: weekly
4448
time: "10:00"
4549
timezone: Europe/London
46-
reviewers:
47-
- "kafbat/frontend"
4850
open-pull-requests-limit: 10
4951
versioning-strategy: increase-if-necessary
5052
labels:
@@ -64,8 +66,6 @@ updates:
6466
interval: weekly
6567
time: "10:00"
6668
timezone: Europe/London
67-
reviewers:
68-
- "kafbat/devops"
6969
open-pull-requests-limit: 10
7070
labels:
7171
- "type/dependencies"

api/build.gradle

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,12 @@ dependencies {
1414
implementation project(":contract")
1515
implementation project(":serde-api")
1616
implementation libs.spring.starter.webflux
17-
implementation libs.spring.starter.security
17+
implementation(libs.spring.starter.security){
18+
exclude group: 'com.nimbusds', module: 'nimbus-jose-jwt' because("Temporary overwrite to fix CVE-2025-53864. See https://avd.aquasec.com/nvd/2025/cve-2025-53864/")
19+
}
20+
implementation(libs.nimbus.jose.jwt){
21+
because("Fixes CVE-2025-5386. See https://avd.aquasec.com/nvd/2025/cve-2025-53864/")
22+
}
1823
implementation libs.spring.starter.actuator
1924
implementation libs.spring.starter.logging
2025
implementation libs.spring.starter.oauth2.client
@@ -53,15 +58,15 @@ dependencies {
5358
exclude group: 'io.projectreactor.ipc', module: 'reactor-netty'
5459
}
5560

56-
runtimeOnly libs.micrometer.registry.prometheus
61+
runtimeOnly(libs.micrometer.registry.prometheus) {
62+
exclude group: 'com.google.protobuf', module: 'protobuf-java' because("Micrometer uses protobuf-java 4.x, which is incompatible with protobuf-java 3.x used by various dependencies of this project. See https://github.com/prometheus/client_java/issues/1431")
63+
}
5764

5865
// CVE Fixes
5966
implementation libs.apache.commons.compress
6067
implementation libs.okhttp3.logging.intercepter
61-
implementation libs.json.smart
62-
implementation libs.netty.common
63-
implementation libs.netty.handler
64-
implementation libs.spring.context
68+
implementation libs.reactor.netty.http
69+
// CVE Fixes End
6570

6671
implementation libs.modelcontextprotocol.spring.webflux
6772
implementation libs.victools.jsonschema.generator

api/src/main/java/io/kafbat/ui/config/auth/RoleBasedAccessControlProperties.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package io.kafbat.ui.config.auth;
22

3+
import io.kafbat.ui.model.rbac.DefaultRole;
34
import io.kafbat.ui.model.rbac.Role;
5+
import jakarta.annotation.Nullable;
46
import jakarta.annotation.PostConstruct;
57
import java.util.ArrayList;
68
import java.util.List;
@@ -11,13 +13,26 @@ public class RoleBasedAccessControlProperties {
1113

1214
private final List<Role> roles = new ArrayList<>();
1315

16+
private DefaultRole defaultRole;
17+
1418
@PostConstruct
1519
public void init() {
1620
roles.forEach(Role::validate);
21+
if (defaultRole != null) {
22+
defaultRole.validate();
23+
}
1724
}
1825

1926
public List<Role> getRoles() {
2027
return roles;
2128
}
2229

30+
public void setDefaultRole(DefaultRole defaultRole) {
31+
this.defaultRole = defaultRole;
32+
}
33+
34+
@Nullable
35+
public DefaultRole getDefaultRole() {
36+
return defaultRole;
37+
}
2338
}

api/src/main/java/io/kafbat/ui/controller/AclsController.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ public Mono<ResponseEntity<Flux<KafkaAclDTO>>> listAcls(String clusterName,
6868
KafkaAclResourceTypeDTO resourceTypeDto,
6969
String resourceName,
7070
KafkaAclNamePatternTypeDTO namePatternTypeDto,
71+
String search,
7172
ServerWebExchange exchange) {
7273
AccessContext context = AccessContext.builder()
7374
.cluster(clusterName)
@@ -88,7 +89,7 @@ public Mono<ResponseEntity<Flux<KafkaAclDTO>>> listAcls(String clusterName,
8889
return validateAccess(context).then(
8990
Mono.just(
9091
ResponseEntity.ok(
91-
aclsService.listAcls(getCluster(clusterName), filter)
92+
aclsService.listAcls(getCluster(clusterName), filter, search)
9293
.map(ClusterMapper::toKafkaAclDto)))
9394
).doOnEach(sig -> audit(context, sig));
9495
}

api/src/main/java/io/kafbat/ui/controller/AuthorizationController.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,12 @@
33
import io.kafbat.ui.api.AuthorizationApi;
44
import io.kafbat.ui.model.ActionDTO;
55
import io.kafbat.ui.model.AuthenticationInfoDTO;
6+
import io.kafbat.ui.model.KafkaCluster;
67
import io.kafbat.ui.model.ResourceTypeDTO;
78
import io.kafbat.ui.model.UserInfoDTO;
89
import io.kafbat.ui.model.UserPermissionDTO;
910
import io.kafbat.ui.model.rbac.Permission;
11+
import io.kafbat.ui.service.ClustersStorage;
1012
import io.kafbat.ui.service.rbac.AccessControlService;
1113
import java.security.Principal;
1214
import java.util.Collection;
@@ -29,8 +31,15 @@
2931
public class AuthorizationController implements AuthorizationApi {
3032

3133
private final AccessControlService accessControlService;
34+
private final ClustersStorage clustersStorage;
3235

3336
public Mono<ResponseEntity<AuthenticationInfoDTO>> getUserAuthInfo(ServerWebExchange exchange) {
37+
List<UserPermissionDTO> defaultRolePermissions = accessControlService.getDefaultRole() != null
38+
? mapPermissions(
39+
accessControlService.getDefaultRole().getPermissions(),
40+
clustersStorage.getKafkaClusters().stream().map(KafkaCluster::getName).toList())
41+
: Collections.emptyList();
42+
3443
Mono<List<UserPermissionDTO>> permissions = AccessControlService.getUser()
3544
.map(user -> accessControlService.getRoles()
3645
.stream()
@@ -39,6 +48,8 @@ public Mono<ResponseEntity<AuthenticationInfoDTO>> getUserAuthInfo(ServerWebExch
3948
.flatMap(Collection::stream)
4049
.toList()
4150
)
51+
// if no roles are found, return default role permissions
52+
.map(userPermissions -> userPermissions.isEmpty() ? defaultRolePermissions : userPermissions)
4253
.switchIfEmpty(Mono.just(Collections.emptyList()));
4354

4455
Mono<String> userName = ReactiveSecurityContextHolder.getContext()
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package io.kafbat.ui.model.rbac;
2+
3+
import static com.google.common.base.Preconditions.checkArgument;
4+
5+
import java.util.ArrayList;
6+
import java.util.List;
7+
import lombok.Data;
8+
9+
@Data
10+
public class DefaultRole {
11+
12+
private List<Permission> permissions = new ArrayList<>();
13+
14+
public void validate() {
15+
permissions.forEach(Permission::validate);
16+
permissions.forEach(Permission::transform);
17+
}
18+
}

api/src/main/java/io/kafbat/ui/model/rbac/Role.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,5 +21,4 @@ public void validate() {
2121
permissions.forEach(Permission::transform);
2222
subjects.forEach(Subject::validate);
2323
}
24-
2524
}

api/src/main/java/io/kafbat/ui/serdes/ProducerRecordCreator.java

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import javax.annotation.Nullable;
66
import lombok.RequiredArgsConstructor;
77
import org.apache.kafka.clients.producer.ProducerRecord;
8-
import org.apache.kafka.common.header.Header;
8+
import org.apache.kafka.common.header.Headers;
99
import org.apache.kafka.common.header.internals.RecordHeader;
1010
import org.apache.kafka.common.header.internals.RecordHeaders;
1111

@@ -20,18 +20,23 @@ public ProducerRecord<byte[], byte[]> create(String topic,
2020
@Nullable String key,
2121
@Nullable String value,
2222
@Nullable Map<String, String> headers) {
23+
24+
Headers kafkaHeaders = createHeaders(headers);
25+
2326
return new ProducerRecord<>(
2427
topic,
2528
partition,
26-
key == null ? null : keySerializer.serialize(key),
27-
value == null ? null : valuesSerializer.serialize(value),
28-
headers == null ? null : createHeaders(headers)
29+
key == null ? null : keySerializer.serialize(key, kafkaHeaders),
30+
value == null ? null : valuesSerializer.serialize(value, kafkaHeaders),
31+
kafkaHeaders
2932
);
3033
}
3134

32-
private Iterable<Header> createHeaders(Map<String, String> clientHeaders) {
35+
private Headers createHeaders(Map<String, String> clientHeaders) {
3336
RecordHeaders headers = new RecordHeaders();
34-
clientHeaders.forEach((k, v) -> headers.add(new RecordHeader(k, v == null ? null : v.getBytes())));
37+
if (clientHeaders != null) {
38+
clientHeaders.forEach((k, v) -> headers.add(new RecordHeader(k, v == null ? null : v.getBytes())));
39+
}
3540
return headers;
3641
}
3742

api/src/main/java/io/kafbat/ui/serdes/SerdeInstance.java

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import lombok.Getter;
1111
import lombok.RequiredArgsConstructor;
1212
import lombok.extern.slf4j.Slf4j;
13+
import org.apache.kafka.common.header.Headers;
1314

1415
@Slf4j
1516
@RequiredArgsConstructor
@@ -80,7 +81,17 @@ public boolean canDeserialize(String topic, Serde.Target type) {
8081
public Serde.Serializer serializer(String topic, Serde.Target type) {
8182
return wrapWithClassloader(() -> {
8283
var serializer = serde.serializer(topic, type);
83-
return input -> wrapWithClassloader(() -> serializer.serialize(input));
84+
return new Serde.Serializer() {
85+
@Override
86+
public byte[] serialize(String input) {
87+
return wrapWithClassloader(() -> serializer.serialize(input));
88+
}
89+
90+
@Override
91+
public byte[] serialize(String input, Headers headers) {
92+
return wrapWithClassloader(() -> serializer.serialize(input, headers));
93+
}
94+
};
8495
});
8596
}
8697

0 commit comments

Comments
 (0)