RBAC integration added
This commit is contained in:
parent
0db0af0567
commit
cb17449407
5 changed files with 77 additions and 11 deletions
|
@ -3,7 +3,10 @@ package com.provectus.kafka.ui.controller;
|
||||||
import com.provectus.kafka.ui.api.AclsApi;
|
import com.provectus.kafka.ui.api.AclsApi;
|
||||||
import com.provectus.kafka.ui.mapper.ClusterMapper;
|
import com.provectus.kafka.ui.mapper.ClusterMapper;
|
||||||
import com.provectus.kafka.ui.model.KafkaAclDTO;
|
import com.provectus.kafka.ui.model.KafkaAclDTO;
|
||||||
|
import com.provectus.kafka.ui.model.rbac.AccessContext;
|
||||||
|
import com.provectus.kafka.ui.model.rbac.permission.AclAction;
|
||||||
import com.provectus.kafka.ui.service.acl.AclsService;
|
import com.provectus.kafka.ui.service.acl.AclsService;
|
||||||
|
import com.provectus.kafka.ui.service.rbac.AccessControlService;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
@ -16,11 +19,19 @@ import reactor.core.publisher.Mono;
|
||||||
public class AclsController extends AbstractController implements AclsApi {
|
public class AclsController extends AbstractController implements AclsApi {
|
||||||
|
|
||||||
private final AclsService aclsService;
|
private final AclsService aclsService;
|
||||||
|
private final AccessControlService accessControlService;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Mono<ResponseEntity<Void>> createAcl(String clusterName, Mono<KafkaAclDTO> kafkaAclDto,
|
public Mono<ResponseEntity<Void>> createAcl(String clusterName, Mono<KafkaAclDTO> kafkaAclDto,
|
||||||
ServerWebExchange exchange) {
|
ServerWebExchange exchange) {
|
||||||
return kafkaAclDto.map(ClusterMapper::toAclBinding)
|
AccessContext context = AccessContext.builder()
|
||||||
|
.cluster(clusterName)
|
||||||
|
.aclActions(AclAction.EDIT)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
return accessControlService.validateAccess(context)
|
||||||
|
.then(kafkaAclDto)
|
||||||
|
.map(ClusterMapper::toAclBinding)
|
||||||
.flatMap(binding -> aclsService.createAcl(getCluster(clusterName), binding))
|
.flatMap(binding -> aclsService.createAcl(getCluster(clusterName), binding))
|
||||||
.thenReturn(ResponseEntity.ok().build());
|
.thenReturn(ResponseEntity.ok().build());
|
||||||
}
|
}
|
||||||
|
@ -28,28 +39,56 @@ public class AclsController extends AbstractController implements AclsApi {
|
||||||
@Override
|
@Override
|
||||||
public Mono<ResponseEntity<Void>> deleteAcl(String clusterName, Mono<KafkaAclDTO> kafkaAclDto,
|
public Mono<ResponseEntity<Void>> deleteAcl(String clusterName, Mono<KafkaAclDTO> kafkaAclDto,
|
||||||
ServerWebExchange exchange) {
|
ServerWebExchange exchange) {
|
||||||
return kafkaAclDto.map(ClusterMapper::toAclBinding)
|
AccessContext context = AccessContext.builder()
|
||||||
|
.cluster(clusterName)
|
||||||
|
.aclActions(AclAction.EDIT)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
return accessControlService.validateAccess(context)
|
||||||
|
.then(kafkaAclDto)
|
||||||
|
.map(ClusterMapper::toAclBinding)
|
||||||
.flatMap(binding -> aclsService.deleteAcl(getCluster(clusterName), binding))
|
.flatMap(binding -> aclsService.deleteAcl(getCluster(clusterName), binding))
|
||||||
.thenReturn(ResponseEntity.ok().build());
|
.thenReturn(ResponseEntity.ok().build());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Mono<ResponseEntity<Flux<KafkaAclDTO>>> listAcls(String clusterName, ServerWebExchange exchange) {
|
public Mono<ResponseEntity<Flux<KafkaAclDTO>>> listAcls(String clusterName, ServerWebExchange exchange) {
|
||||||
return Mono.just(
|
AccessContext context = AccessContext.builder()
|
||||||
ResponseEntity.ok(
|
.cluster(clusterName)
|
||||||
aclsService.listAcls(getCluster(clusterName)).map(ClusterMapper::toKafkaAclDto)));
|
.aclActions(AclAction.VIEW)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
return accessControlService.validateAccess(context).then(
|
||||||
|
Mono.just(
|
||||||
|
ResponseEntity.ok(
|
||||||
|
aclsService.listAcls(getCluster(clusterName)).map(ClusterMapper::toKafkaAclDto)))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Mono<ResponseEntity<String>> getAclAsCsv(String clusterName, ServerWebExchange exchange) {
|
public Mono<ResponseEntity<String>> getAclAsCsv(String clusterName, ServerWebExchange exchange) {
|
||||||
return aclsService.getAclAsCsvString(getCluster(clusterName))
|
AccessContext context = AccessContext.builder()
|
||||||
.map(ResponseEntity::ok)
|
.cluster(clusterName)
|
||||||
.flatMap(Mono::just);
|
.aclActions(AclAction.VIEW)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
return accessControlService.validateAccess(context).then(
|
||||||
|
aclsService.getAclAsCsvString(getCluster(clusterName))
|
||||||
|
.map(ResponseEntity::ok)
|
||||||
|
.flatMap(Mono::just)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Mono<ResponseEntity<Void>> syncAclsCsv(String clusterName, Mono<String> csvMono, ServerWebExchange exchange) {
|
public Mono<ResponseEntity<Void>> syncAclsCsv(String clusterName, Mono<String> csvMono, ServerWebExchange exchange) {
|
||||||
return csvMono.flatMap(csv -> aclsService.syncAclWithAclCsv(getCluster(clusterName), csv))
|
AccessContext context = AccessContext.builder()
|
||||||
|
.cluster(clusterName)
|
||||||
|
.aclActions(AclAction.EDIT)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
return accessControlService.validateAccess(context)
|
||||||
|
.then(csvMono)
|
||||||
|
.flatMap(csv -> aclsService.syncAclWithAclCsv(getCluster(clusterName), csv))
|
||||||
.thenReturn(ResponseEntity.ok().build());
|
.thenReturn(ResponseEntity.ok().build());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package com.provectus.kafka.ui.model.rbac;
|
package com.provectus.kafka.ui.model.rbac;
|
||||||
|
|
||||||
|
import com.provectus.kafka.ui.model.rbac.permission.AclAction;
|
||||||
import com.provectus.kafka.ui.model.rbac.permission.ClusterConfigAction;
|
import com.provectus.kafka.ui.model.rbac.permission.ClusterConfigAction;
|
||||||
import com.provectus.kafka.ui.model.rbac.permission.ConnectAction;
|
import com.provectus.kafka.ui.model.rbac.permission.ConnectAction;
|
||||||
import com.provectus.kafka.ui.model.rbac.permission.ConsumerGroupAction;
|
import com.provectus.kafka.ui.model.rbac.permission.ConsumerGroupAction;
|
||||||
|
@ -34,6 +35,8 @@ public class AccessContext {
|
||||||
|
|
||||||
Collection<KsqlAction> ksqlActions;
|
Collection<KsqlAction> ksqlActions;
|
||||||
|
|
||||||
|
Collection<AclAction> aclActions;
|
||||||
|
|
||||||
public static AccessContextBuilder builder() {
|
public static AccessContextBuilder builder() {
|
||||||
return new AccessContextBuilder();
|
return new AccessContextBuilder();
|
||||||
}
|
}
|
||||||
|
@ -51,6 +54,7 @@ public class AccessContext {
|
||||||
private String schema;
|
private String schema;
|
||||||
private Collection<SchemaAction> schemaActions = Collections.emptySet();
|
private Collection<SchemaAction> schemaActions = Collections.emptySet();
|
||||||
private Collection<KsqlAction> ksqlActions = Collections.emptySet();
|
private Collection<KsqlAction> ksqlActions = Collections.emptySet();
|
||||||
|
private Collection<AclAction> aclActions = Collections.emptySet();
|
||||||
|
|
||||||
private AccessContextBuilder() {
|
private AccessContextBuilder() {
|
||||||
}
|
}
|
||||||
|
@ -121,6 +125,12 @@ public class AccessContext {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public AccessContextBuilder aclActions(AclAction... actions) {
|
||||||
|
Assert.isTrue(actions.length > 0, "actions not present");
|
||||||
|
this.aclActions = List.of(actions);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public AccessContext build() {
|
public AccessContext build() {
|
||||||
return new AccessContext(cluster, clusterConfigActions,
|
return new AccessContext(cluster, clusterConfigActions,
|
||||||
topic, topicActions,
|
topic, topicActions,
|
||||||
|
@ -128,7 +138,7 @@ public class AccessContext {
|
||||||
connect, connectActions,
|
connect, connectActions,
|
||||||
connector,
|
connector,
|
||||||
schema, schemaActions,
|
schema, schemaActions,
|
||||||
ksqlActions);
|
ksqlActions, aclActions);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,8 @@ public enum Resource {
|
||||||
CONSUMER,
|
CONSUMER,
|
||||||
SCHEMA,
|
SCHEMA,
|
||||||
CONNECT,
|
CONNECT,
|
||||||
KSQL;
|
KSQL,
|
||||||
|
ACL;
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public static Resource fromString(String name) {
|
public static Resource fromString(String name) {
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
package com.provectus.kafka.ui.model.rbac.permission;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.EnumUtils;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
public enum AclAction implements PermissibleAction {
|
||||||
|
|
||||||
|
VIEW,
|
||||||
|
EDIT;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public static AclAction fromString(String name) {
|
||||||
|
return EnumUtils.getEnum(AclAction.class, name);
|
||||||
|
}
|
||||||
|
}
|
|
@ -3316,6 +3316,7 @@ components:
|
||||||
- SCHEMA
|
- SCHEMA
|
||||||
- CONNECT
|
- CONNECT
|
||||||
- KSQL
|
- KSQL
|
||||||
|
- ACL
|
||||||
|
|
||||||
KafkaAcl:
|
KafkaAcl:
|
||||||
type: object
|
type: object
|
||||||
|
|
Loading…
Add table
Reference in a new issue