From 2c9779b25fc235888c41325448848a21da540e18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Greffier?= Date: Tue, 23 Jul 2024 23:59:39 +0200 Subject: [PATCH] Finalize fix --- .../AkhqClaimProviderController.java | 14 +- .../controller/acl/AclController.java | 24 +- .../acl/AclNonNamespacedController.java | 6 +- ...ntrolEntryService.java => AclService.java} | 7 +- .../service/ConnectClusterService.java | 6 +- .../ns4kafka/service/ConnectorService.java | 6 +- .../service/ConsumerGroupService.java | 4 +- .../ns4kafka/service/NamespaceService.java | 4 +- .../ns4kafka/service/SchemaService.java | 6 +- .../ns4kafka/service/StreamService.java | 4 +- .../ns4kafka/service/TopicService.java | 12 +- .../AccessControlEntryAsyncExecutor.java | 39 +- .../controller/AclControllerTest.java | 857 +++++++++++------- .../AclNonNamespacedControllerTest.java | 35 +- .../AkhqClaimProviderControllerTest.java | 40 +- .../AkhqClaimProviderControllerV3Test.java | 30 +- ...lListTest.java => AclIntegrationTest.java} | 4 +- ....java => ApiResourcesIntegrationTest.java} | 14 +- ...tTest.java => ConnectIntegrationTest.java} | 4 +- ...a => ExceptionHandlerIntegrationTest.java} | 4 +- ...ginTest.java => LoginIntegrationTest.java} | 2 +- ...est.java => NamespaceIntegrationTest.java} | 10 +- ...maTest.java => SchemaIntegrationTest.java} | 4 +- ...amTest.java => StreamIntegrationTest.java} | 4 +- ...picTest.java => TopicIntegrationTest.java} | 2 +- ...UserTest.java => UserIntegrationTest.java} | 6 +- ...ryServiceTest.java => AclServiceTest.java} | 372 +++++--- .../service/ConnectClusterServiceTest.java | 32 +- .../service/ConnectorServiceTest.java | 42 +- .../service/NamespaceServiceTest.java | 16 +- .../ns4kafka/service/SchemaServiceTest.java | 6 +- .../ns4kafka/service/StreamServiceTest.java | 4 +- .../ns4kafka/service/TopicServiceTest.java | 154 ++-- 33 files changed, 1059 insertions(+), 715 deletions(-) rename src/main/java/com/michelin/ns4kafka/service/{AccessControlEntryService.java => AclService.java} (98%) rename src/test/java/com/michelin/ns4kafka/integration/{AccessControlListTest.java => AclIntegrationTest.java} (99%) rename src/test/java/com/michelin/ns4kafka/integration/{ApiResourcesTest.java => ApiResourcesIntegrationTest.java} (88%) rename src/test/java/com/michelin/ns4kafka/integration/{ConnectTest.java => ConnectIntegrationTest.java} (99%) rename src/test/java/com/michelin/ns4kafka/integration/{ExceptionHandlerTest.java => ExceptionHandlerIntegrationTest.java} (98%) rename src/test/java/com/michelin/ns4kafka/integration/{LoginTest.java => LoginIntegrationTest.java} (95%) rename src/test/java/com/michelin/ns4kafka/integration/{NamespaceTest.java => NamespaceIntegrationTest.java} (97%) rename src/test/java/com/michelin/ns4kafka/integration/{SchemaTest.java => SchemaIntegrationTest.java} (99%) rename src/test/java/com/michelin/ns4kafka/integration/{StreamTest.java => StreamIntegrationTest.java} (97%) rename src/test/java/com/michelin/ns4kafka/integration/{TopicTest.java => TopicIntegrationTest.java} (99%) rename src/test/java/com/michelin/ns4kafka/integration/{UserTest.java => UserIntegrationTest.java} (97%) rename src/test/java/com/michelin/ns4kafka/service/{AccessControlEntryServiceTest.java => AclServiceTest.java} (76%) diff --git a/src/main/java/com/michelin/ns4kafka/controller/AkhqClaimProviderController.java b/src/main/java/com/michelin/ns4kafka/controller/AkhqClaimProviderController.java index aeb9cd36..108108c5 100644 --- a/src/main/java/com/michelin/ns4kafka/controller/AkhqClaimProviderController.java +++ b/src/main/java/com/michelin/ns4kafka/controller/AkhqClaimProviderController.java @@ -3,7 +3,7 @@ import com.michelin.ns4kafka.model.AccessControlEntry; import com.michelin.ns4kafka.property.AkhqProperties; import com.michelin.ns4kafka.property.ManagedClusterProperties; -import com.michelin.ns4kafka.service.AccessControlEntryService; +import com.michelin.ns4kafka.service.AclService; import com.michelin.ns4kafka.service.NamespaceService; import io.micronaut.core.annotation.Introspected; import io.micronaut.http.annotation.Body; @@ -46,7 +46,7 @@ public class AkhqClaimProviderController { AkhqProperties config; @Inject - AccessControlEntryService accessControlEntryService; + AclService aclService; @Inject NamespaceService namespaceService; @@ -76,11 +76,11 @@ public AkhqClaimResponse generateClaim(@Valid @Body AkhqClaimRequest request) { .stream() .filter(namespace -> namespace.getMetadata().getLabels() != null && groups.contains(namespace.getMetadata().getLabels().getOrDefault(config.getGroupLabel(), "_"))) - .flatMap(namespace -> accessControlEntryService.findAllGrantedToNamespace(namespace).stream()) + .flatMap(namespace -> aclService.findAllGrantedToNamespace(namespace).stream()) .collect(Collectors.toList()); // Add all public ACLs. - relatedAcl.addAll(accessControlEntryService.findAllPublicGrantedTo()); + relatedAcl.addAll(aclService.findAllPublicGrantedTo()); return AkhqClaimResponse.builder() .roles(config.getFormerRoles()) @@ -117,7 +117,7 @@ public AkhqClaimResponseV2 generateClaimV2(@Valid @Body AkhqClaimRequest request List relatedAcl = getAclsByGroups(groups); // Add all public ACLs. - relatedAcl.addAll(accessControlEntryService.findAllPublicGrantedTo()); + relatedAcl.addAll(aclService.findAllPublicGrantedTo()); return AkhqClaimResponseV2.builder() .roles(config.getFormerRoles()) @@ -146,7 +146,7 @@ public AkhqClaimResponseV3 generateClaimV3(@Valid @Body AkhqClaimRequest request List acls = getAclsByGroups(groups); // Add all public ACLs - acls.addAll(accessControlEntryService.findAllPublicGrantedTo()); + acls.addAll(aclService.findAllPublicGrantedTo()); // Remove unnecessary ACLs // E.g., project.topic1 when project.* is granted on the same resource type and cluster @@ -297,7 +297,7 @@ private List getAclsByGroups(List groups) { && !Collections.disjoint(groups, List.of(namespace.getMetadata().getLabels() .getOrDefault(config.getGroupLabel(), "_") .split(",")))) - .flatMap(namespace -> accessControlEntryService.findAllGrantedToNamespace(namespace).stream()) + .flatMap(namespace -> aclService.findAllGrantedToNamespace(namespace).stream()) .collect(Collectors.toList()); } diff --git a/src/main/java/com/michelin/ns4kafka/controller/acl/AclController.java b/src/main/java/com/michelin/ns4kafka/controller/acl/AclController.java index 531192cb..a9c0bcc6 100644 --- a/src/main/java/com/michelin/ns4kafka/controller/acl/AclController.java +++ b/src/main/java/com/michelin/ns4kafka/controller/acl/AclController.java @@ -1,6 +1,6 @@ package com.michelin.ns4kafka.controller.acl; -import static com.michelin.ns4kafka.service.AccessControlEntryService.PUBLIC_GRANTED_TO; +import static com.michelin.ns4kafka.service.AclService.PUBLIC_GRANTED_TO; import static com.michelin.ns4kafka.util.FormatErrorUtils.invalidAclDeleteOnlyAdmin; import static com.michelin.ns4kafka.util.FormatErrorUtils.invalidImmutableField; import static com.michelin.ns4kafka.util.FormatErrorUtils.invalidNotFound; @@ -10,7 +10,7 @@ import com.michelin.ns4kafka.model.AccessControlEntry; import com.michelin.ns4kafka.model.Namespace; import com.michelin.ns4kafka.security.ResourceBasedSecurityRule; -import com.michelin.ns4kafka.service.AccessControlEntryService; +import com.michelin.ns4kafka.service.AclService; import com.michelin.ns4kafka.util.enumation.ApplyStatus; import com.michelin.ns4kafka.util.exception.ResourceValidationException; import io.micronaut.http.HttpResponse; @@ -39,7 +39,7 @@ @Controller("/api/namespaces/{namespace}/acls") public class AclController extends NamespacedResourceController { @Inject - AccessControlEntryService accessControlEntryService; + AclService aclService; /** * List ACLs by namespace. @@ -56,11 +56,11 @@ public List list(String namespace, Optional limit) Namespace ns = getNamespace(namespace); return switch (limit.get()) { - case GRANTEE -> accessControlEntryService.findAllGrantedToNamespace(ns) + case GRANTEE -> aclService.findAllGrantedToNamespace(ns) .stream() .sorted(Comparator.comparing(o -> o.getMetadata().getNamespace())) .toList(); - case GRANTOR -> accessControlEntryService.findAllForCluster(ns.getMetadata().getCluster()) + case GRANTOR -> aclService.findAllForCluster(ns.getMetadata().getCluster()) .stream() // granted by me .filter(accessControlEntry -> accessControlEntry.getMetadata().getNamespace().equals(namespace)) @@ -68,7 +68,7 @@ public List list(String namespace, Optional limit) .filter(accessControlEntry -> !accessControlEntry.getSpec().getGrantedTo().equals(namespace)) .sorted(Comparator.comparing(o -> o.getSpec().getGrantedTo())) .toList(); - default -> accessControlEntryService.findAllForCluster(ns.getMetadata().getCluster()) + default -> aclService.findAllForCluster(ns.getMetadata().getCluster()) .stream() .filter(accessControlEntry -> accessControlEntry.getMetadata().getNamespace().equals(namespace) @@ -115,9 +115,9 @@ public HttpResponse apply(Authentication authentication, Str List validationErrors; if (isAdmin && isSelfAssigned) { // Validate overlapping OWNER - validationErrors = accessControlEntryService.validateAsAdmin(accessControlEntry, ns); + validationErrors = aclService.validateAsAdmin(accessControlEntry, ns); } else { - validationErrors = accessControlEntryService.validate(accessControlEntry, ns); + validationErrors = aclService.validate(accessControlEntry, ns); } if (!validationErrors.isEmpty()) { @@ -127,7 +127,7 @@ public HttpResponse apply(Authentication authentication, Str // AccessControlEntry spec is immutable // This prevents accidental updates on ACL resources already declared with the same name (with different rules) Optional existingAcl = - accessControlEntryService.findByName(namespace, accessControlEntry.getMetadata().getName()); + aclService.findByName(namespace, accessControlEntry.getMetadata().getName()); if (existingAcl.isPresent() && !existingAcl.get().getSpec().equals(accessControlEntry.getSpec())) { throw new ResourceValidationException(accessControlEntry, invalidImmutableField("spec")); @@ -150,7 +150,7 @@ public HttpResponse apply(Authentication authentication, Str sendEventLog(accessControlEntry, status, existingAcl.map(AccessControlEntry::getSpec).orElse(null), accessControlEntry.getSpec()); - return formatHttpResponse(accessControlEntryService.create(accessControlEntry), status); + return formatHttpResponse(aclService.create(accessControlEntry), status); } /** @@ -166,7 +166,7 @@ public HttpResponse apply(Authentication authentication, Str @Status(HttpStatus.NO_CONTENT) public HttpResponse delete(Authentication authentication, String namespace, String name, @QueryValue(defaultValue = "false") boolean dryrun) { - AccessControlEntry accessControlEntry = accessControlEntryService + AccessControlEntry accessControlEntry = aclService .findByName(namespace, name) .orElseThrow(() -> new ResourceValidationException(ACCESS_CONTROL_ENTRY, name, invalidNotFound(name))); @@ -183,7 +183,7 @@ public HttpResponse delete(Authentication authentication, String namespace sendEventLog(accessControlEntry, ApplyStatus.deleted, accessControlEntry.getSpec(), null); - accessControlEntryService.delete(getNamespace(namespace), accessControlEntry); + aclService.delete(accessControlEntry); return HttpResponse.noContent(); } diff --git a/src/main/java/com/michelin/ns4kafka/controller/acl/AclNonNamespacedController.java b/src/main/java/com/michelin/ns4kafka/controller/acl/AclNonNamespacedController.java index 28e18a29..6b6d1bb4 100644 --- a/src/main/java/com/michelin/ns4kafka/controller/acl/AclNonNamespacedController.java +++ b/src/main/java/com/michelin/ns4kafka/controller/acl/AclNonNamespacedController.java @@ -3,7 +3,7 @@ import com.michelin.ns4kafka.controller.generic.NonNamespacedResourceController; import com.michelin.ns4kafka.model.AccessControlEntry; import com.michelin.ns4kafka.security.ResourceBasedSecurityRule; -import com.michelin.ns4kafka.service.AccessControlEntryService; +import com.michelin.ns4kafka.service.AclService; import io.micronaut.http.annotation.Controller; import io.micronaut.http.annotation.Get; import io.swagger.v3.oas.annotations.tags.Tag; @@ -19,7 +19,7 @@ @RolesAllowed(ResourceBasedSecurityRule.IS_ADMIN) public class AclNonNamespacedController extends NonNamespacedResourceController { @Inject - AccessControlEntryService accessControlEntryService; + AclService aclService; /** * List ACLs. @@ -28,6 +28,6 @@ public class AclNonNamespacedController extends NonNamespacedResourceController */ @Get public List listAll() { - return accessControlEntryService.findAll(); + return aclService.findAll(); } } diff --git a/src/main/java/com/michelin/ns4kafka/service/AccessControlEntryService.java b/src/main/java/com/michelin/ns4kafka/service/AclService.java similarity index 98% rename from src/main/java/com/michelin/ns4kafka/service/AccessControlEntryService.java rename to src/main/java/com/michelin/ns4kafka/service/AclService.java index 8aa8db11..37abd2e4 100644 --- a/src/main/java/com/michelin/ns4kafka/service/AccessControlEntryService.java +++ b/src/main/java/com/michelin/ns4kafka/service/AclService.java @@ -25,7 +25,7 @@ * Access control entry service. */ @Singleton -public class AccessControlEntryService { +public class AclService { public static final String PUBLIC_GRANTED_TO = "*"; @Inject @@ -235,14 +235,13 @@ public AccessControlEntry create(AccessControlEntry accessControlEntry) { /** * Delete an ACL from broker and from internal topic. * - * @param namespace The namespace * @param accessControlEntry The ACL */ - public void delete(Namespace namespace, AccessControlEntry accessControlEntry) { + public void delete(AccessControlEntry accessControlEntry) { AccessControlEntryAsyncExecutor accessControlEntryAsyncExecutor = applicationContext.getBean(AccessControlEntryAsyncExecutor.class, Qualifiers.byName(accessControlEntry.getMetadata().getCluster())); - accessControlEntryAsyncExecutor.deleteAcl(namespace, accessControlEntry); + accessControlEntryAsyncExecutor.deleteAcl(accessControlEntry); accessControlEntryRepository.delete(accessControlEntry); } diff --git a/src/main/java/com/michelin/ns4kafka/service/ConnectClusterService.java b/src/main/java/com/michelin/ns4kafka/service/ConnectClusterService.java index 3b3c9e01..51184020 100644 --- a/src/main/java/com/michelin/ns4kafka/service/ConnectClusterService.java +++ b/src/main/java/com/michelin/ns4kafka/service/ConnectClusterService.java @@ -54,7 +54,7 @@ public class ConnectClusterService { KafkaConnectClient kafkaConnectClient; @Inject - AccessControlEntryService accessControlEntryService; + AclService aclService; @Inject ConnectClusterRepository connectClusterRepository; @@ -124,7 +124,7 @@ public Flux findAll(boolean all) { */ public List findAllByNamespace(Namespace namespace, List permissions) { - List acls = accessControlEntryService.findAllGrantedToNamespace(namespace).stream() + List acls = aclService.findAllGrantedToNamespace(namespace).stream() .filter(acl -> permissions.contains(acl.getSpec().getPermission())) .filter(acl -> acl.getSpec().getResourceType() == AccessControlEntry.ResourceType.CONNECT_CLUSTER).toList(); @@ -346,7 +346,7 @@ public void delete(ConnectCluster connectCluster) { * @return true if it is, false otherwise */ public boolean isNamespaceOwnerOfConnectCluster(Namespace namespace, String connectCluster) { - return accessControlEntryService.isNamespaceOwnerOfResource(namespace.getMetadata().getName(), + return aclService.isNamespaceOwnerOfResource(namespace.getMetadata().getName(), AccessControlEntry.ResourceType.CONNECT_CLUSTER, connectCluster); } diff --git a/src/main/java/com/michelin/ns4kafka/service/ConnectorService.java b/src/main/java/com/michelin/ns4kafka/service/ConnectorService.java index 9e9819bc..ac9d03a7 100644 --- a/src/main/java/com/michelin/ns4kafka/service/ConnectorService.java +++ b/src/main/java/com/michelin/ns4kafka/service/ConnectorService.java @@ -36,7 +36,7 @@ @Singleton public class ConnectorService { @Inject - AccessControlEntryService accessControlEntryService; + AclService aclService; @Inject KafkaConnectClient kafkaConnectClient; @@ -57,7 +57,7 @@ public class ConnectorService { * @return A list of connectors */ public List findAllForNamespace(Namespace namespace) { - List acls = accessControlEntryService.findAllGrantedToNamespace(namespace); + List acls = aclService.findAllGrantedToNamespace(namespace); return connectorRepository.findAllForCluster(namespace.getMetadata().getCluster()) .stream() .filter(connector -> acls.stream().anyMatch(accessControlEntry -> { @@ -161,7 +161,7 @@ public Mono> validateLocally(Namespace namespace, Connector connect * @return true if it is, false otherwise */ public boolean isNamespaceOwnerOfConnect(Namespace namespace, String connect) { - return accessControlEntryService.isNamespaceOwnerOfResource(namespace.getMetadata().getName(), + return aclService.isNamespaceOwnerOfResource(namespace.getMetadata().getName(), AccessControlEntry.ResourceType.CONNECT, connect); } diff --git a/src/main/java/com/michelin/ns4kafka/service/ConsumerGroupService.java b/src/main/java/com/michelin/ns4kafka/service/ConsumerGroupService.java index 68e8a06c..257fc79e 100644 --- a/src/main/java/com/michelin/ns4kafka/service/ConsumerGroupService.java +++ b/src/main/java/com/michelin/ns4kafka/service/ConsumerGroupService.java @@ -37,7 +37,7 @@ public class ConsumerGroupService { ApplicationContext applicationContext; @Inject - AccessControlEntryService accessControlEntryService; + AclService aclService; /** * Check if a given namespace is owner of a given group. @@ -47,7 +47,7 @@ public class ConsumerGroupService { * @return true if it is, false otherwise */ public boolean isNamespaceOwnerOfConsumerGroup(String namespace, String groupId) { - return accessControlEntryService.isNamespaceOwnerOfResource(namespace, AccessControlEntry.ResourceType.GROUP, + return aclService.isNamespaceOwnerOfResource(namespace, AccessControlEntry.ResourceType.GROUP, groupId); } diff --git a/src/main/java/com/michelin/ns4kafka/service/NamespaceService.java b/src/main/java/com/michelin/ns4kafka/service/NamespaceService.java index c617c0cb..08abd446 100644 --- a/src/main/java/com/michelin/ns4kafka/service/NamespaceService.java +++ b/src/main/java/com/michelin/ns4kafka/service/NamespaceService.java @@ -41,7 +41,7 @@ public class NamespaceService { RoleBindingService roleBindingService; @Inject - AccessControlEntryService accessControlEntryService; + AclService aclService; @Inject ConnectorService connectorService; @@ -166,7 +166,7 @@ public List listAllNamespaceResources(Namespace namespace) { .map(connector -> CONNECTOR + "/" + connector.getMetadata().getName()), connectClusterService.findAllByNamespaceOwner(namespace).stream() .map(connectCluster -> CONNECT_CLUSTER + "/" + connectCluster.getMetadata().getName()), - accessControlEntryService.findAllForNamespace(namespace).stream() + aclService.findAllForNamespace(namespace).stream() .map(ace -> ACCESS_CONTROL_ENTRY + "/" + ace.getMetadata().getName()), resourceQuotaService.findByNamespace(namespace.getMetadata().getName()).stream() .map(resourceQuota -> RESOURCE_QUOTA + "/" + resourceQuota.getMetadata().getName()), diff --git a/src/main/java/com/michelin/ns4kafka/service/SchemaService.java b/src/main/java/com/michelin/ns4kafka/service/SchemaService.java index 6c556545..9ff41d3c 100644 --- a/src/main/java/com/michelin/ns4kafka/service/SchemaService.java +++ b/src/main/java/com/michelin/ns4kafka/service/SchemaService.java @@ -36,7 +36,7 @@ @Singleton public class SchemaService { @Inject - AccessControlEntryService accessControlEntryService; + AclService aclService; @Inject SchemaRegistryClient schemaRegistryClient; @@ -48,7 +48,7 @@ public class SchemaService { * @return A list of schemas */ public Flux findAllForNamespace(Namespace namespace) { - List acls = accessControlEntryService.findAllGrantedToNamespace(namespace).stream() + List acls = aclService.findAllGrantedToNamespace(namespace).stream() .filter(acl -> acl.getSpec().getPermission() == AccessControlEntry.Permission.OWNER) .filter(acl -> acl.getSpec().getResourceType() == AccessControlEntry.ResourceType.TOPIC).toList(); @@ -291,7 +291,7 @@ public Mono updateSubjectCompatibility(Namespace na */ public boolean isNamespaceOwnerOfSubject(Namespace namespace, String subjectName) { String underlyingTopicName = subjectName.replaceAll("(-key|-value)$", ""); - return accessControlEntryService.isNamespaceOwnerOfResource(namespace.getMetadata().getName(), + return aclService.isNamespaceOwnerOfResource(namespace.getMetadata().getName(), AccessControlEntry.ResourceType.TOPIC, underlyingTopicName); } diff --git a/src/main/java/com/michelin/ns4kafka/service/StreamService.java b/src/main/java/com/michelin/ns4kafka/service/StreamService.java index ffbf4e6d..4e9ceaed 100644 --- a/src/main/java/com/michelin/ns4kafka/service/StreamService.java +++ b/src/main/java/com/michelin/ns4kafka/service/StreamService.java @@ -22,7 +22,7 @@ public class StreamService { StreamRepository streamRepository; @Inject - AccessControlEntryService accessControlEntryService; + AclService aclService; @Inject ApplicationContext applicationContext; @@ -62,7 +62,7 @@ public Optional findByName(Namespace namespace, String stream) { * @return true if it is, false otherwise */ public boolean isNamespaceOwnerOfKafkaStream(Namespace namespace, String resource) { - return new HashSet<>(accessControlEntryService.findAllGrantedToNamespace(namespace) + return new HashSet<>(aclService.findAllGrantedToNamespace(namespace) .stream() .filter(accessControlEntry -> accessControlEntry.getSpec().getPermission() == AccessControlEntry.Permission.OWNER) diff --git a/src/main/java/com/michelin/ns4kafka/service/TopicService.java b/src/main/java/com/michelin/ns4kafka/service/TopicService.java index 4ebd350f..90a3bee9 100644 --- a/src/main/java/com/michelin/ns4kafka/service/TopicService.java +++ b/src/main/java/com/michelin/ns4kafka/service/TopicService.java @@ -39,7 +39,7 @@ public class TopicService { TopicRepository topicRepository; @Inject - AccessControlEntryService accessControlEntryService; + AclService aclService; @Inject ApplicationContext applicationContext; @@ -63,7 +63,7 @@ public List findAll() { * @return A list of topics */ public List findAllForNamespace(Namespace namespace) { - List acls = accessControlEntryService.findAllGrantedToNamespace(namespace); + List acls = aclService.findAllGrantedToNamespace(namespace); return topicRepository.findAllForCluster(namespace.getMetadata().getCluster()) .stream() .filter(topic -> acls.stream().anyMatch(accessControlEntry -> { @@ -106,7 +106,7 @@ public Optional findByName(Namespace namespace, String topic) { * @return true if it is, false otherwise */ public boolean isNamespaceOwnerOfTopic(String namespace, String topic) { - return accessControlEntryService.isNamespaceOwnerOfResource(namespace, AccessControlEntry.ResourceType.TOPIC, + return aclService.isNamespaceOwnerOfResource(namespace, AccessControlEntry.ResourceType.TOPIC, topic); } @@ -322,13 +322,13 @@ public Map deleteRecords(Topic topic, Map tag.matches("^[a-zA-Z]\\w*$")); + .stream() + .allMatch(tag -> tag.matches("^[a-zA-Z]\\w*$")); } /** diff --git a/src/main/java/com/michelin/ns4kafka/service/executor/AccessControlEntryAsyncExecutor.java b/src/main/java/com/michelin/ns4kafka/service/executor/AccessControlEntryAsyncExecutor.java index e1ce1a76..680df73d 100644 --- a/src/main/java/com/michelin/ns4kafka/service/executor/AccessControlEntryAsyncExecutor.java +++ b/src/main/java/com/michelin/ns4kafka/service/executor/AccessControlEntryAsyncExecutor.java @@ -3,7 +3,7 @@ import static com.michelin.ns4kafka.model.AccessControlEntry.ResourceType.GROUP; import static com.michelin.ns4kafka.model.AccessControlEntry.ResourceType.TOPIC; import static com.michelin.ns4kafka.model.AccessControlEntry.ResourceType.TRANSACTIONAL_ID; -import static com.michelin.ns4kafka.service.AccessControlEntryService.PUBLIC_GRANTED_TO; +import static com.michelin.ns4kafka.service.AclService.PUBLIC_GRANTED_TO; import com.michelin.ns4kafka.model.AccessControlEntry; import com.michelin.ns4kafka.model.KafkaStream; @@ -11,7 +11,7 @@ import com.michelin.ns4kafka.property.ManagedClusterProperties; import com.michelin.ns4kafka.repository.NamespaceRepository; import com.michelin.ns4kafka.repository.kafka.KafkaStoreException; -import com.michelin.ns4kafka.service.AccessControlEntryService; +import com.michelin.ns4kafka.service.AclService; import com.michelin.ns4kafka.service.StreamService; import io.micronaut.context.annotation.EachBean; import jakarta.inject.Singleton; @@ -47,7 +47,7 @@ public class AccessControlEntryAsyncExecutor { private final ManagedClusterProperties managedClusterProperties; - private AccessControlEntryService accessControlEntryService; + private AclService aclService; private StreamService streamService; @@ -125,7 +125,7 @@ private List collectNs4KafkaAcls() { // Converts topic, group and transaction Ns4Kafka ACLs to topic and group Kafka AclBindings Stream aclBindingsFromAcls = namespaces .stream() - .flatMap(namespace -> accessControlEntryService.findAllGrantedToNamespace(namespace) + .flatMap(namespace -> aclService.findAllGrantedToNamespace(namespace) .stream() .filter(accessControlEntry -> List.of(TOPIC, GROUP, TRANSACTIONAL_ID) .contains(accessControlEntry.getSpec().getResourceType())) @@ -143,16 +143,13 @@ private List collectNs4KafkaAcls() { // Converts connect ACLs to group AclBindings (connect-) Stream aclBindingFromConnect = namespaces .stream() - .flatMap(namespace -> accessControlEntryService.findAllGrantedToNamespace(namespace) + .flatMap(namespace -> aclService.findAllGrantedToNamespace(namespace) .stream() .filter(accessControlEntry -> accessControlEntry.getSpec().getResourceType() == AccessControlEntry.ResourceType.CONNECT) .filter(accessControlEntry -> accessControlEntry.getSpec().getPermission() == AccessControlEntry.Permission.OWNER) - .map(accessControlEntry -> convertConnectorAccessControlEntryToAclBinding( - accessControlEntry, - namespace.getSpec().getKafkaUser()) - )); + .map(this::convertConnectorAccessControlEntryToAclBinding)); List ns4kafkaAcls = Stream.of(aclBindingsFromAcls, aclBindingFromKstream, aclBindingFromConnect) .flatMap(Function.identity()) @@ -312,17 +309,25 @@ private List buildAclBindingsFromKafkaStream(KafkaStream stream, Str /** * Convert Ns4Kafka connect ACL into Kafka ACL. * - * @param acl The Ns4Kafka ACL - * @param kafkaUser The ACL owner + * @param accessControlEntry The Ns4Kafka ACL + * @param kafkaUser The ACL owner * @return A list of Kafka ACLs */ - private AclBinding convertConnectorAccessControlEntryToAclBinding(AccessControlEntry acl, String kafkaUser) { - PatternType patternType = PatternType.fromString(acl.getSpec().getResourcePatternType().toString()); + private AclBinding convertConnectorAccessControlEntryToAclBinding(AccessControlEntry accessControlEntry) { + PatternType patternType = PatternType.fromString( + accessControlEntry.getSpec().getResourcePatternType().toString() + ); + ResourcePattern resourcePattern = new ResourcePattern( org.apache.kafka.common.resource.ResourceType.GROUP, - "connect-" + acl.getSpec().getResource(), + "connect-" + accessControlEntry.getSpec().getResource(), patternType); + String kafkaUser = namespaceRepository.findByName(accessControlEntry.getSpec().getGrantedTo()) + .orElseThrow() + .getSpec() + .getKafkaUser(); + return new AclBinding( resourcePattern, new org.apache.kafka.common.acl.AccessControlEntry( @@ -377,10 +382,9 @@ private void deleteAcls(List toDelete) { * Delete a given Ns4Kafka ACL. * Convert Ns4Kafka ACL into Kafka ACLs before deletion. * - * @param namespace The namespace * @param accessControlEntry The ACL */ - public void deleteAcl(Namespace namespace, AccessControlEntry accessControlEntry) { + public void deleteAcl(AccessControlEntry accessControlEntry) { if (managedClusterProperties.isManageAcls()) { List results = new ArrayList<>(); @@ -390,8 +394,7 @@ public void deleteAcl(Namespace namespace, AccessControlEntry accessControlEntry if (accessControlEntry.getSpec().getResourceType() == AccessControlEntry.ResourceType.CONNECT && accessControlEntry.getSpec().getPermission() == AccessControlEntry.Permission.OWNER) { - results.add(convertConnectorAccessControlEntryToAclBinding(accessControlEntry, - namespace.getSpec().getKafkaUser())); + results.add(convertConnectorAccessControlEntryToAclBinding(accessControlEntry)); } deleteAcls(results); diff --git a/src/test/java/com/michelin/ns4kafka/controller/AclControllerTest.java b/src/test/java/com/michelin/ns4kafka/controller/AclControllerTest.java index 2cdec9ed..14fd5eff 100644 --- a/src/test/java/com/michelin/ns4kafka/controller/AclControllerTest.java +++ b/src/test/java/com/michelin/ns4kafka/controller/AclControllerTest.java @@ -2,6 +2,7 @@ import static com.michelin.ns4kafka.security.auth.JwtCustomClaimNames.ROLES; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentMatchers.any; @@ -16,7 +17,7 @@ import com.michelin.ns4kafka.model.Metadata; import com.michelin.ns4kafka.model.Namespace; import com.michelin.ns4kafka.security.ResourceBasedSecurityRule; -import com.michelin.ns4kafka.service.AccessControlEntryService; +import com.michelin.ns4kafka.service.AclService; import com.michelin.ns4kafka.service.NamespaceService; import com.michelin.ns4kafka.util.exception.ResourceValidationException; import io.micronaut.context.event.ApplicationEventPublisher; @@ -27,7 +28,6 @@ import java.util.List; import java.util.Map; import java.util.Optional; -import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.ArgumentMatchers; @@ -38,7 +38,7 @@ @ExtendWith(MockitoExtension.class) class AclControllerTest { @Mock - AccessControlEntryService accessControlEntryService; + AclService aclService; @Mock NamespaceService namespaceService; @@ -53,126 +53,218 @@ class AclControllerTest { AclController accessControlListController; @Test - void list() { - Namespace ns = - Namespace.builder().metadata(Metadata.builder().name("test").cluster("local").build()).build(); - // granted by admin to test - AccessControlEntry ace1 = - AccessControlEntry.builder().metadata(Metadata.builder().namespace("admin").cluster("local").build()) - .spec(AccessControlEntry.AccessControlEntrySpec.builder() - .resourceType(AccessControlEntry.ResourceType.TOPIC) - .resourcePatternType(AccessControlEntry.ResourcePatternType.PREFIXED) - .permission(AccessControlEntry.Permission.OWNER).resource("prefix").grantedTo("test").build()) - .build(); - // granted by admin to test - AccessControlEntry ace2 = - AccessControlEntry.builder().metadata(Metadata.builder().namespace("admin").cluster("local").build()) - .spec(AccessControlEntry.AccessControlEntrySpec.builder() - .resourceType(AccessControlEntry.ResourceType.CONNECT) - .resourcePatternType(AccessControlEntry.ResourcePatternType.PREFIXED) - .permission(AccessControlEntry.Permission.OWNER).resource("prefix").grantedTo("test").build()) - .build(); - // granted by test to namespace-other - AccessControlEntry ace3 = - AccessControlEntry.builder().metadata(Metadata.builder().namespace("test").cluster("local").build()) - .spec( - AccessControlEntry.AccessControlEntrySpec.builder() - .resourceType(AccessControlEntry.ResourceType.TOPIC) - .resourcePatternType(AccessControlEntry.ResourcePatternType.PREFIXED) - .permission(AccessControlEntry.Permission.READ).resource("prefix").grantedTo("namespace-other") - .build()).build(); - // granted by admin to namespace-other - AccessControlEntry ace4 = - AccessControlEntry.builder().metadata(Metadata.builder().namespace("admin").cluster("local").build()) - .spec(AccessControlEntry.AccessControlEntrySpec.builder() - .resourceType(AccessControlEntry.ResourceType.TOPIC) - .resourcePatternType(AccessControlEntry.ResourcePatternType.PREFIXED) - .permission(AccessControlEntry.Permission.OWNER).resource("other-prefix") - .grantedTo("namespace-other").build()).build(); - // granted by namespace-other to test - AccessControlEntry ace5 = AccessControlEntry.builder() - .metadata(Metadata.builder().namespace("namespace-other").cluster("local").build()).spec( - AccessControlEntry.AccessControlEntrySpec.builder().resourceType(AccessControlEntry.ResourceType.TOPIC) - .resourcePatternType(AccessControlEntry.ResourcePatternType.PREFIXED) - .permission(AccessControlEntry.Permission.READ).resource("other-prefix").grantedTo("test").build()) + void shouldListAcls() { + Namespace namespace = Namespace.builder() + .metadata(Metadata.builder() + .name("test") + .cluster("local") + .build()) + .build(); + + AccessControlEntry aceTopicPrefixedOwnerAdminToTest = AccessControlEntry.builder() + .metadata(Metadata.builder() + .namespace("admin") + .cluster("local") + .build()) + .spec(AccessControlEntry.AccessControlEntrySpec.builder() + .resourceType(AccessControlEntry.ResourceType.TOPIC) + .resourcePatternType(AccessControlEntry.ResourcePatternType.PREFIXED) + .permission(AccessControlEntry.Permission.OWNER) + .resource("prefix") + .grantedTo("test") + .build()) + .build(); + + AccessControlEntry aceConnectPrefixedOwnerAdminToTest = AccessControlEntry.builder() + .metadata(Metadata.builder() + .namespace("admin") + .cluster("local") + .build()) + .spec(AccessControlEntry.AccessControlEntrySpec.builder() + .resourceType(AccessControlEntry.ResourceType.CONNECT) + .resourcePatternType(AccessControlEntry.ResourcePatternType.PREFIXED) + .permission(AccessControlEntry.Permission.OWNER) + .resource("prefix") + .grantedTo("test") + .build()) + .build(); + + AccessControlEntry aceTopicPrefixedReadTestToNamespaceOther = AccessControlEntry.builder() + .metadata(Metadata.builder() + .namespace("test") + .cluster("local") + .build()) + .spec(AccessControlEntry.AccessControlEntrySpec.builder() + .resourceType(AccessControlEntry.ResourceType.TOPIC) + .resourcePatternType(AccessControlEntry.ResourcePatternType.PREFIXED) + .permission(AccessControlEntry.Permission.READ) + .resource("prefix") + .grantedTo("namespace-other") + .build()) .build(); - // granted by admin to all (public) - AccessControlEntry ace6 = - AccessControlEntry.builder().metadata(Metadata.builder().namespace("admin").cluster("local").build()) - .spec(AccessControlEntry.AccessControlEntrySpec.builder() - .resourceType(AccessControlEntry.ResourceType.TOPIC) - .resourcePatternType(AccessControlEntry.ResourcePatternType.PREFIXED) - .permission(AccessControlEntry.Permission.READ).resource("public-prefix").grantedTo("*").build()) - .build(); - when(namespaceService.findByName("test")).thenReturn(Optional.of(ns)); - when(accessControlEntryService.findAllGrantedToNamespace(ns)).thenReturn(List.of(ace1, ace2, ace5, ace6)); - when(accessControlEntryService.findAllForCluster("local")).thenReturn( - List.of(ace1, ace2, ace3, ace4, ace5, ace6)); - List actual = - accessControlListController.list("test", Optional.of(AclController.AclLimit.GRANTEE)); + AccessControlEntry aceTopicPrefixedOwnerAdminToNamespaceOther = AccessControlEntry.builder() + .metadata(Metadata.builder() + .namespace("admin") + .cluster("local") + .build()) + .spec(AccessControlEntry.AccessControlEntrySpec.builder() + .resourceType(AccessControlEntry.ResourceType.TOPIC) + .resourcePatternType(AccessControlEntry.ResourcePatternType.PREFIXED) + .permission(AccessControlEntry.Permission.OWNER) + .resource("other-prefix") + .grantedTo("namespace-other") + .build()) + .build(); + + AccessControlEntry aceTopicPrefixedReadNamespaceOtherToTest = AccessControlEntry.builder() + .metadata(Metadata.builder() + .namespace("namespace-other") + .cluster("local") + .build()) + .spec(AccessControlEntry.AccessControlEntrySpec.builder() + .resourceType(AccessControlEntry.ResourceType.TOPIC) + .resourcePatternType(AccessControlEntry.ResourcePatternType.PREFIXED) + .permission(AccessControlEntry.Permission.READ) + .resource("other-prefix") + .grantedTo("test") + .build()) + .build(); + + AccessControlEntry aceTopicPrefixedReadAdminToAll = AccessControlEntry.builder() + .metadata(Metadata.builder() + .namespace("admin") + .cluster("local") + .build()) + .spec(AccessControlEntry.AccessControlEntrySpec.builder() + .resourceType(AccessControlEntry.ResourceType.TOPIC) + .resourcePatternType(AccessControlEntry.ResourcePatternType.PREFIXED) + .permission(AccessControlEntry.Permission.READ) + .resource("public-prefix") + .grantedTo("*") + .build()) + .build(); + + when(namespaceService.findByName("test")).thenReturn(Optional.of(namespace)); + when(aclService.findAllGrantedToNamespace(namespace)).thenReturn( + List.of(aceTopicPrefixedOwnerAdminToTest, aceConnectPrefixedOwnerAdminToTest, + aceTopicPrefixedReadNamespaceOtherToTest, aceTopicPrefixedReadAdminToAll)); + when(aclService.findAllForCluster("local")).thenReturn( + List.of(aceTopicPrefixedOwnerAdminToTest, aceConnectPrefixedOwnerAdminToTest, + aceTopicPrefixedReadTestToNamespaceOther, aceTopicPrefixedOwnerAdminToNamespaceOther, + aceTopicPrefixedReadNamespaceOtherToTest, aceTopicPrefixedReadAdminToAll)); + + List actual = accessControlListController + .list("test", Optional.of(AclController.AclLimit.GRANTEE)); + assertEquals(4, actual.size()); - assertTrue(actual.contains(ace1)); - assertTrue(actual.contains(ace2)); - assertTrue(actual.contains(ace5)); - assertTrue(actual.contains(ace6)); + assertTrue(actual.contains(aceTopicPrefixedOwnerAdminToTest)); + assertTrue(actual.contains(aceConnectPrefixedOwnerAdminToTest)); + assertTrue(actual.contains(aceTopicPrefixedReadNamespaceOtherToTest)); + assertTrue(actual.contains(aceTopicPrefixedReadAdminToAll)); actual = accessControlListController.list("test", Optional.of(AclController.AclLimit.GRANTOR)); assertEquals(1, actual.size()); - assertTrue(actual.contains(ace3)); + assertTrue(actual.contains(aceTopicPrefixedReadTestToNamespaceOther)); actual = accessControlListController.list("test", Optional.of(AclController.AclLimit.ALL)); assertEquals(5, actual.size()); - assertTrue(actual.contains(ace1)); - assertTrue(actual.contains(ace2)); - assertTrue(actual.contains(ace3)); - assertTrue(actual.contains(ace5)); - assertTrue(actual.contains(ace6)); - + assertTrue(actual.contains(aceTopicPrefixedOwnerAdminToTest)); + assertTrue(actual.contains(aceConnectPrefixedOwnerAdminToTest)); + assertTrue(actual.contains(aceTopicPrefixedReadTestToNamespaceOther)); + assertTrue(actual.contains(aceTopicPrefixedReadNamespaceOtherToTest)); + assertTrue(actual.contains(aceTopicPrefixedReadAdminToAll)); } @Test - void getAcl() { - Namespace ns = - Namespace.builder().metadata(Metadata.builder().name("test").cluster("local").build()).build(); - // granted by tes to test - AccessControlEntry ace1 = AccessControlEntry.builder() - .metadata(Metadata.builder().name("ace1").namespace("test").cluster("local").build()).spec( - AccessControlEntry.AccessControlEntrySpec.builder().resourceType(AccessControlEntry.ResourceType.TOPIC) - .resourcePatternType(AccessControlEntry.ResourcePatternType.PREFIXED) - .permission(AccessControlEntry.Permission.OWNER).resource("prefix").grantedTo("test").build()) + void shouldGetAcl() { + Namespace namespace = Namespace.builder() + .metadata(Metadata.builder() + .name("test") + .cluster("local") + .build()) .build(); - // granted by test to test - AccessControlEntry ace2 = AccessControlEntry.builder() - .metadata(Metadata.builder().name("ace2").namespace("test").cluster("local").build()).spec( - AccessControlEntry.AccessControlEntrySpec.builder() - .resourceType(AccessControlEntry.ResourceType.CONNECT) - .resourcePatternType(AccessControlEntry.ResourcePatternType.PREFIXED) - .permission(AccessControlEntry.Permission.OWNER).resource("prefix").grantedTo("test").build()) + + AccessControlEntry aceTopicPrefixedOwnerTestToTest = AccessControlEntry.builder() + .metadata(Metadata.builder() + .name("ace1") + .namespace("test") + .cluster("local") + .build()) + .spec(AccessControlEntry.AccessControlEntrySpec.builder() + .resourceType(AccessControlEntry.ResourceType.TOPIC) + .resourcePatternType(AccessControlEntry.ResourcePatternType.PREFIXED) + .permission(AccessControlEntry.Permission.OWNER) + .resource("prefix") + .grantedTo("test") + .build()) .build(); - // granted by test to namespace-other - AccessControlEntry ace3 = AccessControlEntry.builder() - .metadata(Metadata.builder().name("ace3").namespace("test").cluster("local").build()).spec( - AccessControlEntry.AccessControlEntrySpec.builder().resourceType(AccessControlEntry.ResourceType.TOPIC) - .resourcePatternType(AccessControlEntry.ResourcePatternType.PREFIXED) - .permission(AccessControlEntry.Permission.READ).resource("prefix").grantedTo("namespace-other") - .build()).build(); - // granted by admin to namespace-other - AccessControlEntry ace4 = AccessControlEntry.builder() - .metadata(Metadata.builder().name("ace4").namespace("admin").cluster("local").build()).spec( - AccessControlEntry.AccessControlEntrySpec.builder().resourceType(AccessControlEntry.ResourceType.TOPIC) - .resourcePatternType(AccessControlEntry.ResourcePatternType.PREFIXED) - .permission(AccessControlEntry.Permission.OWNER).resource("other-prefix") - .grantedTo("namespace-other").build()).build(); - // granted by namespace-other to test - AccessControlEntry ace5 = AccessControlEntry.builder() - .metadata(Metadata.builder().name("ace5").namespace("namespace-other").cluster("local").build()).spec( - AccessControlEntry.AccessControlEntrySpec.builder().resourceType(AccessControlEntry.ResourceType.TOPIC) - .resourcePatternType(AccessControlEntry.ResourcePatternType.PREFIXED) - .permission(AccessControlEntry.Permission.READ).resource("other-prefix").grantedTo("test").build()) + + AccessControlEntry aceConnectPrefixedOwnerTestToTest = AccessControlEntry.builder() + .metadata(Metadata.builder() + .name("ace2") + .namespace("test") + .cluster("local") + .build()) + .spec(AccessControlEntry.AccessControlEntrySpec.builder() + .resourceType(AccessControlEntry.ResourceType.CONNECT) + .resourcePatternType(AccessControlEntry.ResourcePatternType.PREFIXED) + .permission(AccessControlEntry.Permission.OWNER) + .resource("prefix") + .grantedTo("test") + .build()) + .build(); + + AccessControlEntry aceTopicPrefixedReadTestToNamespaceOther = AccessControlEntry.builder() + .metadata(Metadata.builder() + .name("ace3") + .namespace("test") + .cluster("local") + .build()) + .spec(AccessControlEntry.AccessControlEntrySpec.builder() + .resourceType(AccessControlEntry.ResourceType.TOPIC) + .resourcePatternType(AccessControlEntry.ResourcePatternType.PREFIXED) + .permission(AccessControlEntry.Permission.READ) + .resource("prefix") + .grantedTo("namespace-other") + .build()) + .build(); + + AccessControlEntry aceTopicPrefixedOwnerAdminToNamespaceOther = AccessControlEntry.builder() + .metadata(Metadata.builder() + .name("ace4") + .namespace("admin") + .cluster("local") + .build()) + .spec(AccessControlEntry.AccessControlEntrySpec.builder() + .resourceType(AccessControlEntry.ResourceType.TOPIC) + .resourcePatternType(AccessControlEntry.ResourcePatternType.PREFIXED) + .permission(AccessControlEntry.Permission.OWNER) + .resource("other-prefix") + .grantedTo("namespace-other") + .build()) + .build(); + + AccessControlEntry aceTopicPrefixedReadNamespaceOtherToTest = AccessControlEntry.builder() + .metadata(Metadata.builder() + .name("ace5") + .namespace("namespace-other") + .cluster("local") + .build()) + .spec(AccessControlEntry.AccessControlEntrySpec.builder() + .resourceType(AccessControlEntry.ResourceType.TOPIC) + .resourcePatternType(AccessControlEntry.ResourcePatternType.PREFIXED) + .permission(AccessControlEntry.Permission.READ) + .resource("other-prefix") + .grantedTo("test") + .build()) .build(); - when(namespaceService.findByName("test")).thenReturn(Optional.of(ns)); - when(accessControlEntryService.findAllForCluster("local")).thenReturn(List.of(ace1, ace2, ace3, ace4, ace5)); + + when(namespaceService.findByName("test")).thenReturn(Optional.of(namespace)); + when(aclService.findAllForCluster("local")).thenReturn( + List.of(aceTopicPrefixedOwnerTestToTest, aceConnectPrefixedOwnerTestToTest, + aceTopicPrefixedReadTestToNamespaceOther, aceTopicPrefixedOwnerAdminToNamespaceOther, + aceTopicPrefixedReadNamespaceOtherToTest)); // Name not in list Optional result1 = accessControlListController.get("test", "ace6"); @@ -187,70 +279,80 @@ void getAcl() { Optional result3 = accessControlListController.get("test", "ace3"); assertTrue(result3.isPresent()); - assertEquals(ace3, result3.get()); + assertEquals(aceTopicPrefixedReadTestToNamespaceOther, result3.get()); // Granted to me Optional result4 = accessControlListController.get("test", "ace5"); assertTrue(result4.isPresent()); - assertEquals(ace5, result4.get()); + assertEquals(aceTopicPrefixedReadNamespaceOtherToTest, result4.get()); } @Test - void applyAsAdminFailure() { - Namespace ns = Namespace.builder() + void shouldApplyFailsAsAdmin() { + Namespace namespace = Namespace.builder() .metadata(Metadata.builder() .name("test") .cluster("local") .build()) .build(); - AccessControlEntry ace1 = - AccessControlEntry.builder().metadata(Metadata.builder().namespace("test").cluster("local").build()) - .spec( - AccessControlEntry.AccessControlEntrySpec.builder() - .resourceType(AccessControlEntry.ResourceType.TOPIC) - .resourcePatternType(AccessControlEntry.ResourcePatternType.PREFIXED) - .permission(AccessControlEntry.Permission.OWNER).resource("prefix").grantedTo("test").build()) - .build(); + AccessControlEntry accessControlEntry = AccessControlEntry.builder() + .metadata(Metadata.builder() + .namespace("test") + .cluster("local") + .build()) + .spec(AccessControlEntry.AccessControlEntrySpec.builder() + .resourceType(AccessControlEntry.ResourceType.TOPIC) + .resourcePatternType(AccessControlEntry.ResourcePatternType.PREFIXED) + .permission(AccessControlEntry.Permission.OWNER) + .resource("prefix") + .grantedTo("test") + .build()) + .build(); - Authentication auth = Authentication.build("admin", List.of("isAdmin()"), + Authentication authentication = Authentication.build("admin", List.of("isAdmin()"), Map.of(ROLES, List.of("isAdmin()"))); - when(namespaceService.findByName("test")).thenReturn(Optional.of(ns)); - when(accessControlEntryService.validateAsAdmin(ace1, ns)).thenReturn(List.of("ValidationError")); + when(namespaceService.findByName("test")).thenReturn(Optional.of(namespace)); + when(aclService.validateAsAdmin(accessControlEntry, namespace)) + .thenReturn(List.of("ValidationError")); ResourceValidationException actual = assertThrows(ResourceValidationException.class, - () -> accessControlListController.apply(auth, "test", ace1, false)); + () -> accessControlListController.apply(authentication, "test", accessControlEntry, false)); assertEquals(1, actual.getValidationErrors().size()); } @Test - void applyAsAdminSuccess() { - Namespace ns = Namespace.builder() + void shouldApplyWithSuccessAsAdmin() { + Namespace namespace = Namespace.builder() .metadata(Metadata.builder() .name("test") .cluster("local") .build()) .build(); - AccessControlEntry ace1 = - AccessControlEntry.builder().metadata(Metadata.builder().name("acl-test").build()) - .spec( - AccessControlEntry.AccessControlEntrySpec.builder() - .resourceType(AccessControlEntry.ResourceType.TOPIC) - .resourcePatternType(AccessControlEntry.ResourcePatternType.PREFIXED) - .permission(AccessControlEntry.Permission.OWNER).resource("prefix").grantedTo("test").build()) - .build(); + AccessControlEntry accessControlEntry = AccessControlEntry.builder() + .metadata(Metadata.builder() + .name("acl-test") + .build()) + .spec(AccessControlEntry.AccessControlEntrySpec.builder() + .resourceType(AccessControlEntry.ResourceType.TOPIC) + .resourcePatternType(AccessControlEntry.ResourcePatternType.PREFIXED) + .permission(AccessControlEntry.Permission.OWNER) + .resource("prefix") + .grantedTo("test") + .build()) + .build(); - Authentication auth = Authentication.build("admin", List.of("isAdmin()"), + Authentication authentication = Authentication.build("admin", List.of("isAdmin()"), Map.of(ROLES, List.of("isAdmin()"))); - when(namespaceService.findByName("test")).thenReturn(Optional.of(ns)); - when(accessControlEntryService.validateAsAdmin(ace1, ns)).thenReturn(List.of()); - when(accessControlEntryService.create(ace1)).thenReturn(ace1); + when(namespaceService.findByName("test")).thenReturn(Optional.of(namespace)); + when(aclService.validateAsAdmin(accessControlEntry, namespace)).thenReturn(List.of()); + when(aclService.create(accessControlEntry)).thenReturn(accessControlEntry); - var response = accessControlListController.apply(auth, "test", ace1, false); + var response = accessControlListController.apply(authentication, "test", accessControlEntry, false); AccessControlEntry actual = response.body(); assertEquals("created", response.header("X-Ns4kafka-Result")); assertEquals("test", actual.getMetadata().getNamespace()); @@ -258,45 +360,69 @@ void applyAsAdminSuccess() { } @Test - void applyValidationErrors() { - Namespace ns = - Namespace.builder().metadata(Metadata.builder().name("test").cluster("local").build()).build(); - AccessControlEntry ace1 = - AccessControlEntry.builder().metadata(Metadata.builder().namespace("test").cluster("local").build()) - .spec( - AccessControlEntry.AccessControlEntrySpec.builder() - .resourceType(AccessControlEntry.ResourceType.TOPIC) - .resourcePatternType(AccessControlEntry.ResourcePatternType.PREFIXED) - .permission(AccessControlEntry.Permission.OWNER).resource("prefix").grantedTo("test").build()) - .build(); - Authentication auth = Authentication.build("user", Map.of("roles", List.of())); + void shouldApplyFailWithValidationErrors() { + Namespace namespace = Namespace.builder() + .metadata(Metadata.builder() + .name("test") + .cluster("local") + .build()) + .build(); - when(namespaceService.findByName("test")).thenReturn(Optional.of(ns)); - when(accessControlEntryService.validate(ace1, ns)).thenReturn(List.of("ValidationError")); + AccessControlEntry accessControlEntry = AccessControlEntry.builder() + .metadata(Metadata.builder() + .namespace("test") + .cluster("local") + .build()) + .spec(AccessControlEntry.AccessControlEntrySpec.builder() + .resourceType(AccessControlEntry.ResourceType.TOPIC) + .resourcePatternType(AccessControlEntry.ResourcePatternType.PREFIXED) + .permission(AccessControlEntry.Permission.OWNER) + .resource("prefix") + .grantedTo("test") + .build()) + .build(); + + Authentication authentication = Authentication.build("user", Map.of("roles", List.of())); + + when(namespaceService.findByName("test")).thenReturn(Optional.of(namespace)); + when(aclService.validate(accessControlEntry, namespace)).thenReturn(List.of("ValidationError")); ResourceValidationException actual = assertThrows(ResourceValidationException.class, - () -> accessControlListController.apply(auth, "test", ace1, false)); + () -> accessControlListController.apply(authentication, "test", accessControlEntry, false)); assertEquals(1, actual.getValidationErrors().size()); } @Test - void applySuccess() { - Namespace ns = - Namespace.builder().metadata(Metadata.builder().name("test").cluster("local").build()).build(); - AccessControlEntry ace1 = AccessControlEntry.builder().metadata(Metadata.builder().build()).spec( - AccessControlEntry.AccessControlEntrySpec.builder().resourceType(AccessControlEntry.ResourceType.TOPIC) + void shouldApplyAclWithSuccess() { + Namespace namespace = Namespace.builder() + .metadata(Metadata.builder() + .name("test") + .cluster("local") + .build()) + .build(); + + AccessControlEntry accessControlEntry = AccessControlEntry.builder() + .metadata(Metadata.builder() + .build()) + .spec(AccessControlEntry.AccessControlEntrySpec.builder() + .resourceType(AccessControlEntry.ResourceType.TOPIC) .resourcePatternType(AccessControlEntry.ResourcePatternType.PREFIXED) - .permission(AccessControlEntry.Permission.OWNER).resource("prefix").grantedTo("test").build()).build(); - Authentication auth = Authentication.build("user", Map.of("roles", List.of())); + .permission(AccessControlEntry.Permission.OWNER) + .resource("prefix") + .grantedTo("test") + .build()) + .build(); - when(namespaceService.findByName("test")).thenReturn(Optional.of(ns)); - when(accessControlEntryService.validate(ace1, ns)).thenReturn(List.of()); + Authentication authentication = Authentication.build("user", Map.of("roles", List.of())); + + when(namespaceService.findByName("test")).thenReturn(Optional.of(namespace)); + when(aclService.validate(accessControlEntry, namespace)).thenReturn(List.of()); when(securityService.username()).thenReturn(Optional.of("test-user")); when(securityService.hasRole(ResourceBasedSecurityRule.IS_ADMIN)).thenReturn(false); doNothing().when(applicationEventPublisher).publishEvent(any()); - when(accessControlEntryService.create(ace1)).thenReturn(ace1); + when(aclService.create(accessControlEntry)).thenReturn(accessControlEntry); - var response = accessControlListController.apply(auth, "test", ace1, false); + var response = accessControlListController.apply(authentication, "test", accessControlEntry, false); AccessControlEntry actual = response.body(); assertEquals("created", response.header("X-Ns4kafka-Result")); assertEquals("test", actual.getMetadata().getNamespace()); @@ -304,10 +430,15 @@ void applySuccess() { } @Test - void applySuccessAlreadyExists() { - Namespace ns = - Namespace.builder().metadata(Metadata.builder().name("test").cluster("local").build()).build(); - AccessControlEntry ace1 = AccessControlEntry.builder() + void shouldEndApplyWithSuccessWhenAclAlreadyExists() { + Namespace namespace = Namespace.builder() + .metadata(Metadata.builder() + .name("test") + .cluster("local") + .build()) + .build(); + + AccessControlEntry accessControlEntry = AccessControlEntry.builder() .metadata(Metadata.builder() .name("ace1") .build()) @@ -319,25 +450,31 @@ void applySuccessAlreadyExists() { .grantedTo("test") .build()) .build(); - Authentication auth = Authentication.build("user", Map.of("roles", List.of())); - when(namespaceService.findByName("test")).thenReturn(Optional.of(ns)); - when(accessControlEntryService.validate(ace1, ns)).thenReturn(List.of()); - when(accessControlEntryService.findByName("test", "ace1")).thenReturn(Optional.of(ace1)); + Authentication authentication = Authentication.build("user", Map.of("roles", List.of())); + + when(namespaceService.findByName("test")).thenReturn(Optional.of(namespace)); + when(aclService.validate(accessControlEntry, namespace)).thenReturn(List.of()); + when(aclService.findByName("test", "ace1")).thenReturn(Optional.of(accessControlEntry)); - var response = accessControlListController.apply(auth, "test", ace1, false); + var response = accessControlListController.apply(authentication, "test", accessControlEntry, false); AccessControlEntry actual = response.body(); assertEquals("unchanged", response.header("X-Ns4kafka-Result")); assertEquals("test", actual.getMetadata().getNamespace()); assertEquals("local", actual.getMetadata().getCluster()); - verify(accessControlEntryService, never()).create(ArgumentMatchers.any()); + verify(aclService, never()).create(ArgumentMatchers.any()); } @Test - void applyFailedChangedSpec() { - Namespace ns = - Namespace.builder().metadata(Metadata.builder().name("test").cluster("local").build()).build(); - AccessControlEntry ace1 = AccessControlEntry.builder() + void shouldApplyFailWhenSpecChanges() { + Namespace namespace = Namespace.builder() + .metadata(Metadata.builder() + .name("test") + .cluster("local") + .build()) + .build(); + + AccessControlEntry accessControlEntry = AccessControlEntry.builder() .metadata(Metadata.builder() .name("ace1") .build()) @@ -349,251 +486,335 @@ void applyFailedChangedSpec() { .grantedTo("test") .build()) .build(); - AccessControlEntry ace1Old = - AccessControlEntry.builder().metadata(Metadata.builder().name("ace1").build()) - .spec(AccessControlEntry.AccessControlEntrySpec.builder() - .resourceType(AccessControlEntry.ResourceType.CONNECT) //This line was changed - .resourcePatternType(AccessControlEntry.ResourcePatternType.PREFIXED) - .permission(AccessControlEntry.Permission.OWNER).resource("prefix").grantedTo("test").build()) - .build(); - Authentication auth = Authentication.build("user", Map.of("roles", List.of())); - when(namespaceService.findByName("test")).thenReturn(Optional.of(ns)); - when(accessControlEntryService.validate(ace1, ns)).thenReturn(List.of()); - when(accessControlEntryService.findByName("test", "ace1")).thenReturn(Optional.of(ace1Old)); + AccessControlEntry oldAccessControlEntry = AccessControlEntry.builder() + .metadata(Metadata.builder() + .name("ace1") + .build()) + .spec(AccessControlEntry.AccessControlEntrySpec.builder() + .resourceType(AccessControlEntry.ResourceType.CONNECT) // This line was changed + .resourcePatternType(AccessControlEntry.ResourcePatternType.PREFIXED) + .permission(AccessControlEntry.Permission.OWNER) + .resource("prefix") + .grantedTo("test") + .build()) + .build(); + + Authentication authentication = Authentication.build("user", Map.of("roles", List.of())); + + when(namespaceService.findByName("test")).thenReturn(Optional.of(namespace)); + when(aclService.validate(accessControlEntry, namespace)).thenReturn(List.of()); + when(aclService.findByName("test", "ace1")).thenReturn(Optional.of(oldAccessControlEntry)); ResourceValidationException actual = assertThrows(ResourceValidationException.class, - () -> accessControlListController.apply(auth, "test", ace1, false)); + () -> accessControlListController.apply(authentication, "test", accessControlEntry, false)); assertEquals(1, actual.getValidationErrors().size()); assertEquals("Invalid \"apply\" operation: field \"spec\" is immutable.", actual.getValidationErrors().get(0)); - } @Test - void applySuccessChangedMetadata() { - Namespace ns = - Namespace.builder().metadata(Metadata.builder().name("test").cluster("local").build()).build(); - AccessControlEntry ace1 = AccessControlEntry.builder() - .metadata( - Metadata.builder().name("ace1").labels(Map.of("new-label", "label-value")) // This label is new - .build()).spec( - AccessControlEntry.AccessControlEntrySpec.builder().resourceType(AccessControlEntry.ResourceType.TOPIC) + void shouldApplyAclWithSuccessWhenMetadataChanges() { + Namespace namespace = Namespace.builder() + .metadata(Metadata.builder() + .name("test") + .cluster("local") + .build()) + .build(); + + AccessControlEntry accessControlEntry = AccessControlEntry.builder() + .metadata(Metadata.builder() + .name("ace1") + .labels(Map.of("new-label", "label-value")) // This label is new + .build()) + .spec(AccessControlEntry.AccessControlEntrySpec.builder() + .resourceType(AccessControlEntry.ResourceType.TOPIC) + .resourcePatternType(AccessControlEntry.ResourcePatternType.PREFIXED) + .permission(AccessControlEntry.Permission.OWNER) + .resource("prefix") + .grantedTo("test") + .build()) + .build(); + + AccessControlEntry oldAccessControlEntry = + AccessControlEntry.builder() + .metadata(Metadata.builder() + .name("ace1") + .build()) + .spec(AccessControlEntry.AccessControlEntrySpec.builder() + .resourceType(AccessControlEntry.ResourceType.TOPIC) .resourcePatternType(AccessControlEntry.ResourcePatternType.PREFIXED) - .permission(AccessControlEntry.Permission.OWNER).resource("prefix").grantedTo("test").build()) - .build(); - AccessControlEntry ace1Old = - AccessControlEntry.builder().metadata(Metadata.builder().name("ace1").build()) - .spec( - AccessControlEntry.AccessControlEntrySpec.builder() - .resourceType(AccessControlEntry.ResourceType.TOPIC) - .resourcePatternType(AccessControlEntry.ResourcePatternType.PREFIXED) - .permission(AccessControlEntry.Permission.OWNER).resource("prefix").grantedTo("test").build()) + .permission(AccessControlEntry.Permission.OWNER) + .resource("prefix") + .grantedTo("test") + .build()) .build(); - Authentication auth = Authentication.build("user", Map.of("roles", List.of())); - when(namespaceService.findByName("test")).thenReturn(Optional.of(ns)); - when(accessControlEntryService.validate(ace1, ns)).thenReturn(List.of()); - when(accessControlEntryService.findByName("test", "ace1")).thenReturn(Optional.of(ace1Old)); - when(accessControlEntryService.create(ace1)).thenReturn(ace1); + Authentication authentication = Authentication.build("user", Map.of("roles", List.of())); + + when(namespaceService.findByName("test")).thenReturn(Optional.of(namespace)); + when(aclService.validate(accessControlEntry, namespace)).thenReturn(List.of()); + when(aclService.findByName("test", "ace1")).thenReturn(Optional.of(oldAccessControlEntry)); + when(aclService.create(accessControlEntry)).thenReturn(accessControlEntry); - var response = accessControlListController.apply(auth, "test", ace1, false); + var response = accessControlListController.apply(authentication, "test", accessControlEntry, false); AccessControlEntry actual = response.body(); assertEquals("changed", response.header("X-Ns4kafka-Result")); assertEquals("test", actual.getMetadata().getNamespace()); assertEquals("local", actual.getMetadata().getCluster()); - Assertions.assertFalse(actual.getMetadata().getLabels().isEmpty()); - + assertFalse(actual.getMetadata().getLabels().isEmpty()); } @Test - void applySuccessChangedMetadataDryRun() { - Namespace ns = - Namespace.builder().metadata(Metadata.builder().name("test").cluster("local").build()).build(); - AccessControlEntry ace1 = AccessControlEntry.builder() - .metadata( - Metadata.builder().name("ace1").labels(Map.of("new-label", "label-value")) // This label is new - .build()).spec( - AccessControlEntry.AccessControlEntrySpec.builder().resourceType(AccessControlEntry.ResourceType.TOPIC) + void shouldApplyAclWithSuccessWhenMetadataChangesInDryRunMode() { + Namespace ns = Namespace.builder() + .metadata(Metadata.builder() + .name("test") + .cluster("local") + .build()) + .build(); + + AccessControlEntry accessControlEntry = AccessControlEntry.builder() + .metadata(Metadata.builder() + .name("ace1") + .labels(Map.of("new-label", "label-value")) // This label is new + .build()) + .spec(AccessControlEntry.AccessControlEntrySpec.builder() + .resourceType(AccessControlEntry.ResourceType.TOPIC) + .resourcePatternType(AccessControlEntry.ResourcePatternType.PREFIXED) + .permission(AccessControlEntry.Permission.OWNER) + .resource("prefix") + .grantedTo("test") + .build()) + .build(); + + AccessControlEntry oldAccessControlEntry = + AccessControlEntry.builder() + .metadata(Metadata.builder() + .name("ace1") + .build()) + .spec(AccessControlEntry.AccessControlEntrySpec.builder() + .resourceType(AccessControlEntry.ResourceType.TOPIC) .resourcePatternType(AccessControlEntry.ResourcePatternType.PREFIXED) - .permission(AccessControlEntry.Permission.OWNER).resource("prefix").grantedTo("test").build()) - .build(); - AccessControlEntry ace1Old = - AccessControlEntry.builder().metadata(Metadata.builder().name("ace1").build()) - .spec( - AccessControlEntry.AccessControlEntrySpec.builder() - .resourceType(AccessControlEntry.ResourceType.TOPIC) - .resourcePatternType(AccessControlEntry.ResourcePatternType.PREFIXED) - .permission(AccessControlEntry.Permission.OWNER).resource("prefix").grantedTo("test").build()) + .permission(AccessControlEntry.Permission.OWNER) + .resource("prefix") + .grantedTo("test") + .build()) .build(); - Authentication auth = Authentication.build("user", Map.of("roles", List.of())); + + Authentication authentication = Authentication.build("user", Map.of("roles", List.of())); when(namespaceService.findByName("test")).thenReturn(Optional.of(ns)); - when(accessControlEntryService.validate(ace1, ns)).thenReturn(List.of()); - when(accessControlEntryService.findByName("test", "ace1")).thenReturn(Optional.of(ace1Old)); + when(aclService.validate(accessControlEntry, ns)).thenReturn(List.of()); + when(aclService.findByName("test", "ace1")).thenReturn(Optional.of(oldAccessControlEntry)); - var response = accessControlListController.apply(auth, "test", ace1, true); + var response = accessControlListController.apply(authentication, "test", accessControlEntry, true); AccessControlEntry actual = response.body(); assertEquals("changed", response.header("X-Ns4kafka-Result")); assertEquals("test", actual.getMetadata().getNamespace()); assertEquals("local", actual.getMetadata().getCluster()); - Assertions.assertFalse(actual.getMetadata().getLabels().isEmpty()); - + assertFalse(actual.getMetadata().getLabels().isEmpty()); } @Test - void applyDryRunAdmin() { - Namespace ns = Namespace.builder() + void shouldApplyAclInDryRunModeAsAdmin() { + Namespace namespace = Namespace.builder() .metadata(Metadata.builder() .name("test") .cluster("local") .build()) .build(); - AccessControlEntry ace1 = - AccessControlEntry.builder().metadata(Metadata.builder().namespace("admin").cluster("local").build()) + AccessControlEntry accessControlEntry = + AccessControlEntry.builder() + .metadata(Metadata.builder() + .namespace("admin") + .cluster("local") + .build()) .spec(AccessControlEntry.AccessControlEntrySpec.builder() .resourceType(AccessControlEntry.ResourceType.TOPIC) .resourcePatternType(AccessControlEntry.ResourcePatternType.PREFIXED) - .permission(AccessControlEntry.Permission.OWNER).resource("prefix").grantedTo("test").build()) + .permission(AccessControlEntry.Permission.OWNER) + .resource("prefix") + .grantedTo("test") + .build()) .build(); - Authentication auth = Authentication.build("admin", List.of("isAdmin()"), + Authentication authentication = Authentication.build("admin", List.of("isAdmin()"), Map.of(ROLES, List.of("isAdmin()"))); - when(namespaceService.findByName("test")).thenReturn(Optional.of(ns)); - when(accessControlEntryService.validateAsAdmin(ace1, ns)).thenReturn(List.of()); + when(namespaceService.findByName("test")).thenReturn(Optional.of(namespace)); + when(aclService.validateAsAdmin(accessControlEntry, namespace)).thenReturn(List.of()); - var response = accessControlListController.apply(auth, "test", ace1, true); + var response = accessControlListController.apply(authentication, "test", accessControlEntry, true); assertEquals("created", response.header("X-Ns4kafka-Result")); - verify(accessControlEntryService, never()).create(ArgumentMatchers.any()); + verify(aclService, never()).create(ArgumentMatchers.any()); } @Test - void applyDryRun() { - Namespace ns = - Namespace.builder().metadata(Metadata.builder().name("test").cluster("local").build()).build(); + void shouldApplyAclInDryRunMode() { + Namespace namespace = Namespace.builder() + .metadata(Metadata.builder() + .name("test") + .cluster("local") + .build()) + .build(); - AccessControlEntry ace1 = AccessControlEntry.builder().metadata(Metadata.builder().build()).spec( - AccessControlEntry.AccessControlEntrySpec.builder().resourceType(AccessControlEntry.ResourceType.TOPIC) + AccessControlEntry accessControlEntry = AccessControlEntry.builder() + .metadata(Metadata.builder() + .build()) + .spec(AccessControlEntry.AccessControlEntrySpec.builder() + .resourceType(AccessControlEntry.ResourceType.TOPIC) .resourcePatternType(AccessControlEntry.ResourcePatternType.PREFIXED) - .permission(AccessControlEntry.Permission.OWNER).resource("prefix").grantedTo("test").build()).build(); + .permission(AccessControlEntry.Permission.OWNER) + .resource("prefix") + .grantedTo("test") + .build()) + .build(); - Authentication auth = Authentication.build("user", Map.of("roles", List.of())); + Authentication authentication = Authentication.build("user", Map.of("roles", List.of())); - when(namespaceService.findByName("test")).thenReturn(Optional.of(ns)); - when(accessControlEntryService.validate(ace1, ns)).thenReturn(List.of()); + when(namespaceService.findByName("test")).thenReturn(Optional.of(namespace)); + when(aclService.validate(accessControlEntry, namespace)).thenReturn(List.of()); - var response = accessControlListController.apply(auth, "test", ace1, true); + var response = accessControlListController.apply(authentication, "test", accessControlEntry, true); assertEquals("created", response.header("X-Ns4kafka-Result")); - verify(accessControlEntryService, never()).create(ace1); + verify(aclService, never()).create(accessControlEntry); } @Test - void deleteFailNotFound() { - Namespace ns = - Namespace.builder().metadata(Metadata.builder().name("test").cluster("local").build()).build(); - - Authentication auth = Authentication.build("user", Map.of("roles", List.of())); + void shouldDeleteAclFailWhenNotFound() { + Authentication authentication = Authentication.build("user", Map.of("roles", List.of())); - when(accessControlEntryService.findByName("test", "ace1")).thenReturn(Optional.empty()); + when(aclService.findByName("test", "ace1")).thenReturn(Optional.empty()); ResourceValidationException actual = assertThrows(ResourceValidationException.class, - () -> accessControlListController.delete(auth, "test", "ace1", false)); + () -> accessControlListController.delete(authentication, "test", "ace1", false)); assertEquals("Invalid value \"ace1\" for field \"name\": resource not found.", actual.getValidationErrors().get(0)); } @Test - void deleteFailSelfAssigned() { - Namespace ns = - Namespace.builder().metadata(Metadata.builder().name("test").cluster("local").build()).build(); - - AccessControlEntry ace1 = AccessControlEntry.builder() - .metadata(Metadata.builder().name("ace1").namespace("test").cluster("local").build()).spec( - AccessControlEntry.AccessControlEntrySpec.builder().resourceType(AccessControlEntry.ResourceType.TOPIC) - .resourcePatternType(AccessControlEntry.ResourcePatternType.PREFIXED) - .permission(AccessControlEntry.Permission.READ).resource("prefix").grantedTo("test").build()) + void shouldDeleteSelfAssignedAclFailWhenNotAdmin() { + AccessControlEntry accessControlEntry = AccessControlEntry.builder() + .metadata(Metadata.builder() + .name("ace1") + .namespace("test") + .cluster("local") + .build()) + .spec(AccessControlEntry.AccessControlEntrySpec.builder() + .resourceType(AccessControlEntry.ResourceType.TOPIC) + .resourcePatternType(AccessControlEntry.ResourcePatternType.PREFIXED) + .permission(AccessControlEntry.Permission.READ) + .resource("prefix") + .grantedTo("test").build()) .build(); - Authentication auth = Authentication.build("user", Map.of("roles", List.of())); + Authentication authentication = Authentication.build("user", Map.of("roles", List.of())); - when(accessControlEntryService.findByName("test", "ace1")).thenReturn(Optional.of(ace1)); + when(aclService.findByName("test", "ace1")).thenReturn(Optional.of(accessControlEntry)); ResourceValidationException actual = assertThrows(ResourceValidationException.class, - () -> accessControlListController.delete(auth, "test", "ace1", false)); + () -> accessControlListController.delete(authentication, "test", "ace1", false)); assertEquals("Invalid value \"ace1\" for field \"name\": only administrators can delete this ACL.", actual.getValidationErrors().get(0)); } @Test - void deleteSuccessSelfAssignedAsAdmin() { - Namespace ns = - Namespace.builder().metadata(Metadata.builder().name("test").cluster("local").build()).build(); + void shouldDeleteSelfAssignedAclWithSuccessAsAdmin() { + Namespace namespace = Namespace.builder() + .metadata(Metadata.builder() + .name("test") + .cluster("local") + .build()) + .build(); - AccessControlEntry ace1 = AccessControlEntry.builder() - .metadata(Metadata.builder().name("ace1").namespace("test").cluster("local").build()).spec( - AccessControlEntry.AccessControlEntrySpec.builder().resourceType(AccessControlEntry.ResourceType.TOPIC) - .resourcePatternType(AccessControlEntry.ResourcePatternType.PREFIXED) - .permission(AccessControlEntry.Permission.READ).resource("prefix").grantedTo("test").build()) + AccessControlEntry accessControlEntry = AccessControlEntry.builder() + .metadata(Metadata.builder() + .name("ace1") + .namespace("test") + .cluster("local") + .build()) + .spec(AccessControlEntry.AccessControlEntrySpec.builder() + .resourceType(AccessControlEntry.ResourceType.TOPIC) + .resourcePatternType(AccessControlEntry.ResourcePatternType.PREFIXED) + .permission(AccessControlEntry.Permission.READ) + .resource("prefix") + .grantedTo("test").build()) .build(); - Authentication auth = Authentication.build("user", List.of("isAdmin()"), + Authentication authentication = Authentication.build("user", List.of("isAdmin()"), Map.of("roles", List.of("isAdmin()"))); - when(namespaceService.findByName("test")).thenReturn(Optional.of(ns)); - when(accessControlEntryService.findByName("test", "ace1")).thenReturn(Optional.of(ace1)); + when(aclService.findByName("test", "ace1")).thenReturn(Optional.of(accessControlEntry)); - HttpResponse actual = accessControlListController.delete(auth, "test", "ace1", false); + HttpResponse actual = accessControlListController.delete(authentication, "test", "ace1", false); assertEquals(HttpStatus.NO_CONTENT, actual.status()); } @Test - void deleteSuccess() { - Namespace ns = - Namespace.builder().metadata(Metadata.builder().name("test").cluster("local").build()).build(); + void shouldDeleteAclWithSuccess() { + Namespace namespace = Namespace.builder() + .metadata(Metadata.builder() + .name("test") + .cluster("local") + .build()) + .build(); - AccessControlEntry ace1 = AccessControlEntry.builder() - .metadata(Metadata.builder().name("ace1").namespace("test").cluster("local").build()).spec( - AccessControlEntry.AccessControlEntrySpec.builder().resourceType(AccessControlEntry.ResourceType.TOPIC) - .resourcePatternType(AccessControlEntry.ResourcePatternType.PREFIXED) - .permission(AccessControlEntry.Permission.READ).resource("prefix").grantedTo("namespace-other") - .build()).build(); - Authentication auth = Authentication.build("user", Map.of("roles", List.of())); + AccessControlEntry accessControlEntry = AccessControlEntry.builder() + .metadata(Metadata.builder() + .name("ace1") + .namespace("test") + .cluster("local") + .build()) + .spec(AccessControlEntry.AccessControlEntrySpec.builder() + .resourceType(AccessControlEntry.ResourceType.TOPIC) + .resourcePatternType(AccessControlEntry.ResourcePatternType.PREFIXED) + .permission(AccessControlEntry.Permission.READ) + .resource("prefix") + .grantedTo("namespace-other") + .build()) + .build(); - when(namespaceService.findByName("test")).thenReturn(Optional.of(ns)); - when(accessControlEntryService.findByName("test", "ace1")).thenReturn(Optional.of(ace1)); + Authentication authentication = Authentication.build("user", Map.of("roles", List.of())); + + when(aclService.findByName("test", "ace1")).thenReturn(Optional.of(accessControlEntry)); when(securityService.username()).thenReturn(Optional.of("test-user")); when(securityService.hasRole(ResourceBasedSecurityRule.IS_ADMIN)).thenReturn(false); doNothing().when(applicationEventPublisher).publishEvent(any()); - HttpResponse actual = accessControlListController.delete(auth, "test", "ace1", false); + HttpResponse actual = accessControlListController.delete(authentication, "test", "ace1", false); assertEquals(HttpStatus.NO_CONTENT, actual.status()); } @Test - void deleteDryRun() { - Namespace ns = - Namespace.builder().metadata(Metadata.builder().name("test").cluster("local").build()).build(); + void shouldDeleteInDryRunMode() { + AccessControlEntry accessControlEntry = AccessControlEntry.builder() + .metadata(Metadata.builder() + .name("ace1") + .namespace("test") + .cluster("local") + .build()) + .spec(AccessControlEntry.AccessControlEntrySpec.builder() + .resourceType(AccessControlEntry.ResourceType.TOPIC) + .resourcePatternType(AccessControlEntry.ResourcePatternType.PREFIXED) + .permission(AccessControlEntry.Permission.READ) + .resource("prefix") + .grantedTo("namespace-other") + .build()).build(); - AccessControlEntry ace1 = AccessControlEntry.builder() - .metadata(Metadata.builder().name("ace1").namespace("test").cluster("local").build()).spec( - AccessControlEntry.AccessControlEntrySpec.builder().resourceType(AccessControlEntry.ResourceType.TOPIC) - .resourcePatternType(AccessControlEntry.ResourcePatternType.PREFIXED) - .permission(AccessControlEntry.Permission.READ).resource("prefix").grantedTo("namespace-other") - .build()).build(); - Authentication auth = Authentication.build("user", Map.of("roles", List.of())); + Authentication authentication = Authentication.build("user", Map.of("roles", List.of())); - when(accessControlEntryService.findByName("test", "ace1")).thenReturn(Optional.of(ace1)); - HttpResponse actual = accessControlListController.delete(auth, "test", "ace1", true); + when(aclService.findByName("test", "ace1")).thenReturn(Optional.of(accessControlEntry)); + HttpResponse actual = accessControlListController.delete(authentication, "test", "ace1", true); - verify(accessControlEntryService, never()).delete(any(), any()); + verify(aclService, never()).delete(any()); assertEquals(HttpStatus.NO_CONTENT, actual.status()); } } diff --git a/src/test/java/com/michelin/ns4kafka/controller/AclNonNamespacedControllerTest.java b/src/test/java/com/michelin/ns4kafka/controller/AclNonNamespacedControllerTest.java index 95f4be6a..ad723bf9 100644 --- a/src/test/java/com/michelin/ns4kafka/controller/AclNonNamespacedControllerTest.java +++ b/src/test/java/com/michelin/ns4kafka/controller/AclNonNamespacedControllerTest.java @@ -6,7 +6,7 @@ import com.michelin.ns4kafka.controller.acl.AclNonNamespacedController; import com.michelin.ns4kafka.model.AccessControlEntry; import com.michelin.ns4kafka.model.Metadata; -import com.michelin.ns4kafka.service.AccessControlEntryService; +import com.michelin.ns4kafka.service.AclService; import java.util.List; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -17,25 +17,36 @@ @ExtendWith(MockitoExtension.class) class AclNonNamespacedControllerTest { @Mock - AccessControlEntryService accessControlEntryService; + AclService aclService; @InjectMocks AclNonNamespacedController aclNonNamespacedController; @Test - void listAll() { - AccessControlEntry ace1 = AccessControlEntry.builder() - .metadata(Metadata.builder().namespace("namespace1").build()) - .spec(AccessControlEntry.AccessControlEntrySpec.builder().grantedTo("namespace1").build()).build(); - AccessControlEntry ace2 = AccessControlEntry.builder() - .metadata(Metadata.builder().namespace("namespace2").build()) - .spec(AccessControlEntry.AccessControlEntrySpec.builder().grantedTo("namespace2").build()).build(); - - when(accessControlEntryService.findAll()).thenReturn(List.of(ace1, ace2)); + void shouldListAcls() { + AccessControlEntry accessControlEntry = AccessControlEntry.builder() + .metadata(Metadata.builder() + .namespace("namespace1") + .build()) + .spec(AccessControlEntry.AccessControlEntrySpec.builder() + .grantedTo("namespace1") + .build()) + .build(); + + AccessControlEntry accessControlEntry2 = AccessControlEntry.builder() + .metadata(Metadata.builder() + .namespace("namespace2") + .build()) + .spec(AccessControlEntry.AccessControlEntrySpec.builder() + .grantedTo("namespace2") + .build()) + .build(); + + when(aclService.findAll()).thenReturn(List.of(accessControlEntry, accessControlEntry2)); List actual = aclNonNamespacedController.listAll(); assertEquals(2, actual.size()); - assertEquals(List.of(ace1, ace2), actual); + assertEquals(List.of(accessControlEntry, accessControlEntry2), actual); } } diff --git a/src/test/java/com/michelin/ns4kafka/controller/AkhqClaimProviderControllerTest.java b/src/test/java/com/michelin/ns4kafka/controller/AkhqClaimProviderControllerTest.java index 03bb05eb..19eaaa24 100644 --- a/src/test/java/com/michelin/ns4kafka/controller/AkhqClaimProviderControllerTest.java +++ b/src/test/java/com/michelin/ns4kafka/controller/AkhqClaimProviderControllerTest.java @@ -10,7 +10,7 @@ import com.michelin.ns4kafka.model.Metadata; import com.michelin.ns4kafka.model.Namespace; import com.michelin.ns4kafka.property.AkhqProperties; -import com.michelin.ns4kafka.service.AccessControlEntryService; +import com.michelin.ns4kafka.service.AclService; import com.michelin.ns4kafka.service.NamespaceService; import java.util.List; import java.util.Map; @@ -28,7 +28,7 @@ class AkhqClaimProviderControllerTest { NamespaceService namespaceService; @Mock - AccessControlEntryService accessControlEntryService; + AclService aclService; @InjectMocks AkhqClaimProviderController akhqClaimProviderController; @@ -276,11 +276,11 @@ void generateClaimTestSuccess() { when(namespaceService.listAll()) .thenReturn(List.of(ns1, ns2, ns3, ns4, ns5)); - when(accessControlEntryService.findAllGrantedToNamespace(ns1)) + when(aclService.findAllGrantedToNamespace(ns1)) .thenReturn(List.of(ns1Ace1, ns1Ace2, pubAce1)); - when(accessControlEntryService.findAllGrantedToNamespace(ns2)) + when(aclService.findAllGrantedToNamespace(ns2)) .thenReturn(List.of(ns2Ace1, ns2Ace2, pubAce1)); - when(accessControlEntryService.findAllGrantedToNamespace(ns3)) + when(aclService.findAllGrantedToNamespace(ns3)) .thenReturn(List.of(ns3Ace1, pubAce1)); AkhqClaimProviderController.AkhqClaimRequest request = AkhqClaimProviderController.AkhqClaimRequest.builder() @@ -310,12 +310,12 @@ void generateClaimTestSuccess() { actual.getAttributes().get("topicsFilterRegexp") ); - verify(accessControlEntryService).findAllGrantedToNamespace(ns1); - verify(accessControlEntryService).findAllGrantedToNamespace(ns2); - verify(accessControlEntryService).findAllGrantedToNamespace(ns3); - verify(accessControlEntryService, never()).findAllGrantedToNamespace(ns4); - verify(accessControlEntryService, never()).findAllGrantedToNamespace(ns5); - verify(accessControlEntryService).findAllPublicGrantedTo(); + verify(aclService).findAllGrantedToNamespace(ns1); + verify(aclService).findAllGrantedToNamespace(ns2); + verify(aclService).findAllGrantedToNamespace(ns3); + verify(aclService, never()).findAllGrantedToNamespace(ns4); + verify(aclService, never()).findAllGrantedToNamespace(ns5); + verify(aclService).findAllPublicGrantedTo(); } @Test @@ -418,11 +418,11 @@ void generateClaimV2TestSuccess() { .build(); when(namespaceService.listAll()) .thenReturn(List.of(ns1, ns2, ns3, ns4, ns5)); - when(accessControlEntryService.findAllGrantedToNamespace(ns1)) + when(aclService.findAllGrantedToNamespace(ns1)) .thenReturn(List.of(ns1Ace1, ns1Ace2, pubAce1)); - when(accessControlEntryService.findAllGrantedToNamespace(ns2)) + when(aclService.findAllGrantedToNamespace(ns2)) .thenReturn(List.of(ns2Ace1, ns2Ace2, pubAce1)); - when(accessControlEntryService.findAllGrantedToNamespace(ns3)) + when(aclService.findAllGrantedToNamespace(ns3)) .thenReturn(List.of(ns3Ace1, pubAce1)); AkhqClaimProviderController.AkhqClaimRequest request = AkhqClaimProviderController.AkhqClaimRequest.builder() @@ -451,12 +451,12 @@ void generateClaimV2TestSuccess() { actual.getTopicsFilterRegexp() ); - verify(accessControlEntryService).findAllGrantedToNamespace(ns1); - verify(accessControlEntryService).findAllGrantedToNamespace(ns2); - verify(accessControlEntryService).findAllGrantedToNamespace(ns3); - verify(accessControlEntryService, never()).findAllGrantedToNamespace(ns4); - verify(accessControlEntryService, never()).findAllGrantedToNamespace(ns5); - verify(accessControlEntryService).findAllPublicGrantedTo(); + verify(aclService).findAllGrantedToNamespace(ns1); + verify(aclService).findAllGrantedToNamespace(ns2); + verify(aclService).findAllGrantedToNamespace(ns3); + verify(aclService, never()).findAllGrantedToNamespace(ns4); + verify(aclService, never()).findAllGrantedToNamespace(ns5); + verify(aclService).findAllPublicGrantedTo(); } @Test diff --git a/src/test/java/com/michelin/ns4kafka/controller/AkhqClaimProviderControllerV3Test.java b/src/test/java/com/michelin/ns4kafka/controller/AkhqClaimProviderControllerV3Test.java index 88ec542e..1a3d0401 100644 --- a/src/test/java/com/michelin/ns4kafka/controller/AkhqClaimProviderControllerV3Test.java +++ b/src/test/java/com/michelin/ns4kafka/controller/AkhqClaimProviderControllerV3Test.java @@ -7,7 +7,7 @@ import com.michelin.ns4kafka.model.Namespace; import com.michelin.ns4kafka.property.AkhqProperties; import com.michelin.ns4kafka.property.ManagedClusterProperties; -import com.michelin.ns4kafka.service.AccessControlEntryService; +import com.michelin.ns4kafka.service.AclService; import com.michelin.ns4kafka.service.NamespaceService; import java.util.List; import java.util.Map; @@ -25,7 +25,7 @@ class AkhqClaimProviderControllerV3Test { NamespaceService namespaceService; @Mock - AccessControlEntryService accessControlEntryService; + AclService aclService; @InjectMocks AkhqClaimProviderController akhqClaimProviderController; @@ -69,7 +69,7 @@ void generateClaimHappyPath() { List.of(new ManagedClusterProperties("cluster1"), new ManagedClusterProperties("cluster2")); when(namespaceService.listAll()) .thenReturn(List.of(ns1Cluster1)); - when(accessControlEntryService.findAllGrantedToNamespace(ns1Cluster1)) + when(aclService.findAllGrantedToNamespace(ns1Cluster1)) .thenReturn(List.of(ace1Ns1Cluster1)); AkhqClaimProviderController.AkhqClaimRequest request = AkhqClaimProviderController.AkhqClaimRequest.builder() @@ -118,7 +118,7 @@ void shouldGrantAllAccessToGroup() { List.of(new ManagedClusterProperties("cluster1"), new ManagedClusterProperties("cluster2")); when(namespaceService.listAll()) .thenReturn(List.of(ns1Cluster1)); - when(accessControlEntryService.findAllGrantedToNamespace(ns1Cluster1)) + when(aclService.findAllGrantedToNamespace(ns1Cluster1)) .thenReturn(List.of(ace1Ns1Cluster1, ace2Ns1Cluster1)); AkhqClaimProviderController.AkhqClaimRequest request = AkhqClaimProviderController.AkhqClaimRequest.builder() @@ -159,7 +159,7 @@ void generateClaimMultipleSupportGroups() { List.of(new ManagedClusterProperties("cluster1"), new ManagedClusterProperties("cluster2")); when(namespaceService.listAll()) .thenReturn(List.of(ns1Cluster1)); - when(accessControlEntryService.findAllGrantedToNamespace(ns1Cluster1)) + when(aclService.findAllGrantedToNamespace(ns1Cluster1)) .thenReturn(List.of(ace1Ns1Cluster1)); AkhqClaimProviderController.AkhqClaimRequest request = AkhqClaimProviderController.AkhqClaimRequest.builder() @@ -223,7 +223,7 @@ void generateClaimWithOptimizedClusters() { akhqClaimProviderController.managedClusters = List.of(new ManagedClusterProperties("cluster1"), new ManagedClusterProperties("cluster2")); when(namespaceService.listAll()).thenReturn(List.of(ns1Cluster1, ns1Cluster2)); - when(accessControlEntryService.findAllGrantedToNamespace(ns1Cluster1)) + when(aclService.findAllGrantedToNamespace(ns1Cluster1)) .thenReturn(List.of(ace1Ns1Cluster1)); AccessControlEntry ace1Ns1Cluster2 = AccessControlEntry.builder() @@ -235,7 +235,7 @@ void generateClaimWithOptimizedClusters() { .build()) .build(); - when(accessControlEntryService.findAllGrantedToNamespace(ns1Cluster2)) + when(aclService.findAllGrantedToNamespace(ns1Cluster2)) .thenReturn(List.of(ace1Ns1Cluster2)); AkhqClaimProviderController.AkhqClaimRequest request = AkhqClaimProviderController.AkhqClaimRequest.builder() @@ -279,7 +279,7 @@ void generateClaimWithMultiplePatternsOnSameCluster() { akhqClaimProviderController.managedClusters = List.of(new ManagedClusterProperties("cluster1"), new ManagedClusterProperties("cluster2")); when(namespaceService.listAll()).thenReturn(List.of(ns1Cluster1, ns2Cluster1)); - when(accessControlEntryService.findAllGrantedToNamespace(ns1Cluster1)) + when(aclService.findAllGrantedToNamespace(ns1Cluster1)) .thenReturn(List.of(ace1Ns1Cluster1)); AccessControlEntry ace2Ns2Cluster1 = AccessControlEntry.builder() @@ -291,7 +291,7 @@ void generateClaimWithMultiplePatternsOnSameCluster() { .build()) .build(); - when(accessControlEntryService.findAllGrantedToNamespace(ns2Cluster1)) + when(aclService.findAllGrantedToNamespace(ns2Cluster1)) .thenReturn(List.of(ace2Ns2Cluster1)); AkhqClaimProviderController.AkhqClaimRequest request = AkhqClaimProviderController.AkhqClaimRequest.builder() @@ -335,7 +335,7 @@ void generateClaimWithMultipleGroups() { akhqClaimProviderController.managedClusters = List.of(new ManagedClusterProperties("cluster1"), new ManagedClusterProperties("cluster2")); when(namespaceService.listAll()).thenReturn(List.of(ns1Cluster1, ns1Cluster2)); - when(accessControlEntryService.findAllGrantedToNamespace(ns1Cluster1)) + when(aclService.findAllGrantedToNamespace(ns1Cluster1)) .thenReturn(List.of(ace1Cluster1)); AccessControlEntry ace1Cluster2 = AccessControlEntry.builder() @@ -347,7 +347,7 @@ void generateClaimWithMultipleGroups() { .build()) .build(); - when(accessControlEntryService.findAllGrantedToNamespace(ns1Cluster2)) + when(aclService.findAllGrantedToNamespace(ns1Cluster2)) .thenReturn(List.of(ace1Cluster2)); AkhqClaimProviderController.AkhqClaimRequest request = AkhqClaimProviderController.AkhqClaimRequest.builder() @@ -391,7 +391,7 @@ void generateClaimWithPatternOnMultipleClusters() { akhqClaimProviderController.managedClusters = List.of(new ManagedClusterProperties("cluster1"), new ManagedClusterProperties("cluster2")); when(namespaceService.listAll()).thenReturn(List.of(ns1Cluster1, ns2Cluster2)); - when(accessControlEntryService.findAllGrantedToNamespace(ns1Cluster1)) + when(aclService.findAllGrantedToNamespace(ns1Cluster1)) .thenReturn(List.of(ace1Ns1Cluster1)); AccessControlEntry ace1Ns2Cluster2 = AccessControlEntry.builder() @@ -403,7 +403,7 @@ void generateClaimWithPatternOnMultipleClusters() { .build()) .build(); - when(accessControlEntryService.findAllGrantedToNamespace(ns2Cluster2)) + when(aclService.findAllGrantedToNamespace(ns2Cluster2)) .thenReturn(List.of(ace1Ns2Cluster2)); AkhqClaimProviderController.AkhqClaimRequest request = AkhqClaimProviderController.AkhqClaimRequest.builder() @@ -523,7 +523,7 @@ void generateClaimAndOptimizePatterns() { akhqClaimProviderController.managedClusters = List.of(new ManagedClusterProperties("cluster1"), new ManagedClusterProperties("cluster2")); when(namespaceService.listAll()).thenReturn(List.of(ns1Cluster1)); - when(accessControlEntryService.findAllGrantedToNamespace(ns1Cluster1)).thenReturn(inputAcls); + when(aclService.findAllGrantedToNamespace(ns1Cluster1)).thenReturn(inputAcls); AkhqClaimProviderController.AkhqClaimRequest request = AkhqClaimProviderController.AkhqClaimRequest.builder() .groups(List.of("GP-PROJECT1&2-SUPPORT")) @@ -613,7 +613,7 @@ void generateClaimAndOptimizePatternsForDifferentClusters() { new ManagedClusterProperties("cluster2"), new ManagedClusterProperties("cluster3"), new ManagedClusterProperties("cluster4")); when(namespaceService.listAll()).thenReturn(List.of(ns1Cluster1)); - when(accessControlEntryService.findAllGrantedToNamespace(ns1Cluster1)).thenReturn(inputAcls); + when(aclService.findAllGrantedToNamespace(ns1Cluster1)).thenReturn(inputAcls); AkhqClaimProviderController.AkhqClaimRequest request = AkhqClaimProviderController.AkhqClaimRequest.builder() .groups(List.of("GP-PROJECT1&2-SUPPORT")) diff --git a/src/test/java/com/michelin/ns4kafka/integration/AccessControlListTest.java b/src/test/java/com/michelin/ns4kafka/integration/AclIntegrationTest.java similarity index 99% rename from src/test/java/com/michelin/ns4kafka/integration/AccessControlListTest.java rename to src/test/java/com/michelin/ns4kafka/integration/AclIntegrationTest.java index 06e1f991..13a7d286 100644 --- a/src/test/java/com/michelin/ns4kafka/integration/AccessControlListTest.java +++ b/src/test/java/com/michelin/ns4kafka/integration/AclIntegrationTest.java @@ -3,7 +3,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; -import com.michelin.ns4kafka.integration.TopicTest.BearerAccessRefreshToken; +import com.michelin.ns4kafka.integration.TopicIntegrationTest.BearerAccessRefreshToken; import com.michelin.ns4kafka.model.AccessControlEntry; import com.michelin.ns4kafka.model.AccessControlEntry.AccessControlEntrySpec; import com.michelin.ns4kafka.model.AccessControlEntry.Permission; @@ -48,7 +48,7 @@ @MicronautTest @Property(name = "micronaut.security.gitlab.enabled", value = "false") -class AccessControlListTest extends AbstractIntegrationTest { +class AclIntegrationTest extends AbstractIntegrationTest { @Inject @Client("/") HttpClient ns4KafkaClient; diff --git a/src/test/java/com/michelin/ns4kafka/integration/ApiResourcesTest.java b/src/test/java/com/michelin/ns4kafka/integration/ApiResourcesIntegrationTest.java similarity index 88% rename from src/test/java/com/michelin/ns4kafka/integration/ApiResourcesTest.java rename to src/test/java/com/michelin/ns4kafka/integration/ApiResourcesIntegrationTest.java index 98bec802..eb81f194 100644 --- a/src/test/java/com/michelin/ns4kafka/integration/ApiResourcesTest.java +++ b/src/test/java/com/michelin/ns4kafka/integration/ApiResourcesIntegrationTest.java @@ -25,7 +25,7 @@ */ @MicronautTest @Property(name = "micronaut.security.gitlab.enabled", value = "false") -class ApiResourcesTest extends AbstractIntegrationTest { +class ApiResourcesIntegrationTest extends AbstractIntegrationTest { @Inject @Client("/") HttpClient client; @@ -33,8 +33,8 @@ class ApiResourcesTest extends AbstractIntegrationTest { @Test void asAdmin() { UsernamePasswordCredentials credentials = new UsernamePasswordCredentials("admin", "admin"); - HttpResponse response = client.toBlocking() - .exchange(HttpRequest.POST("/login", credentials), TopicTest.BearerAccessRefreshToken.class); + HttpResponse response = client.toBlocking() + .exchange(HttpRequest.POST("/login", credentials), TopicIntegrationTest.BearerAccessRefreshToken.class); String token = response.getBody().get().getAccessToken(); List resources = client.toBlocking().retrieve( @@ -86,8 +86,8 @@ void asUser() { .build(); UsernamePasswordCredentials credentials = new UsernamePasswordCredentials("admin", "admin"); - HttpResponse response = client.toBlocking() - .exchange(HttpRequest.POST("/login", credentials), TopicTest.BearerAccessRefreshToken.class); + HttpResponse response = client.toBlocking() + .exchange(HttpRequest.POST("/login", credentials), TopicIntegrationTest.BearerAccessRefreshToken.class); String token = response.getBody().get().getAccessToken(); @@ -97,8 +97,8 @@ void asUser() { HttpRequest.create(HttpMethod.POST, "/api/namespaces/ns1/role-bindings").bearerAuth(token).body(rb1)); UsernamePasswordCredentials userCredentials = new UsernamePasswordCredentials("user", "admin"); - HttpResponse userResponse = client.toBlocking() - .exchange(HttpRequest.POST("/login", userCredentials), TopicTest.BearerAccessRefreshToken.class); + HttpResponse userResponse = client.toBlocking() + .exchange(HttpRequest.POST("/login", userCredentials), TopicIntegrationTest.BearerAccessRefreshToken.class); String userToken = userResponse.getBody().get().getAccessToken(); List resources = client.toBlocking().retrieve( diff --git a/src/test/java/com/michelin/ns4kafka/integration/ConnectTest.java b/src/test/java/com/michelin/ns4kafka/integration/ConnectIntegrationTest.java similarity index 99% rename from src/test/java/com/michelin/ns4kafka/integration/ConnectTest.java rename to src/test/java/com/michelin/ns4kafka/integration/ConnectIntegrationTest.java index 7b2df2a4..e1a4fdf1 100644 --- a/src/test/java/com/michelin/ns4kafka/integration/ConnectTest.java +++ b/src/test/java/com/michelin/ns4kafka/integration/ConnectIntegrationTest.java @@ -4,7 +4,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; -import com.michelin.ns4kafka.integration.TopicTest.BearerAccessRefreshToken; +import com.michelin.ns4kafka.integration.TopicIntegrationTest.BearerAccessRefreshToken; import com.michelin.ns4kafka.model.AccessControlEntry; import com.michelin.ns4kafka.model.AccessControlEntry.AccessControlEntrySpec; import com.michelin.ns4kafka.model.AccessControlEntry.Permission; @@ -52,7 +52,7 @@ @MicronautTest @Property(name = "micronaut.security.gitlab.enabled", value = "false") -class ConnectTest extends AbstractIntegrationConnectTest { +class ConnectIntegrationTest extends AbstractIntegrationConnectTest { @Inject private ApplicationContext applicationContext; diff --git a/src/test/java/com/michelin/ns4kafka/integration/ExceptionHandlerTest.java b/src/test/java/com/michelin/ns4kafka/integration/ExceptionHandlerIntegrationTest.java similarity index 98% rename from src/test/java/com/michelin/ns4kafka/integration/ExceptionHandlerTest.java rename to src/test/java/com/michelin/ns4kafka/integration/ExceptionHandlerIntegrationTest.java index f1186a3a..e61983b9 100644 --- a/src/test/java/com/michelin/ns4kafka/integration/ExceptionHandlerTest.java +++ b/src/test/java/com/michelin/ns4kafka/integration/ExceptionHandlerIntegrationTest.java @@ -4,7 +4,7 @@ import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; -import com.michelin.ns4kafka.integration.TopicTest.BearerAccessRefreshToken; +import com.michelin.ns4kafka.integration.TopicIntegrationTest.BearerAccessRefreshToken; import com.michelin.ns4kafka.model.AccessControlEntry; import com.michelin.ns4kafka.model.AccessControlEntry.AccessControlEntrySpec; import com.michelin.ns4kafka.model.AccessControlEntry.Permission; @@ -45,7 +45,7 @@ */ @MicronautTest @Property(name = "micronaut.security.gitlab.enabled", value = "false") -class ExceptionHandlerTest extends AbstractIntegrationTest { +class ExceptionHandlerIntegrationTest extends AbstractIntegrationTest { @Inject @Client("/") HttpClient client; diff --git a/src/test/java/com/michelin/ns4kafka/integration/LoginTest.java b/src/test/java/com/michelin/ns4kafka/integration/LoginIntegrationTest.java similarity index 95% rename from src/test/java/com/michelin/ns4kafka/integration/LoginTest.java rename to src/test/java/com/michelin/ns4kafka/integration/LoginIntegrationTest.java index ca21ee53..ec7c5f30 100644 --- a/src/test/java/com/michelin/ns4kafka/integration/LoginTest.java +++ b/src/test/java/com/michelin/ns4kafka/integration/LoginIntegrationTest.java @@ -15,7 +15,7 @@ @MicronautTest @Property(name = "micronaut.security.gitlab.enabled", value = "false") -class LoginTest extends AbstractIntegrationTest { +class LoginIntegrationTest extends AbstractIntegrationTest { @Inject @Client("/") HttpClient client; diff --git a/src/test/java/com/michelin/ns4kafka/integration/NamespaceTest.java b/src/test/java/com/michelin/ns4kafka/integration/NamespaceIntegrationTest.java similarity index 97% rename from src/test/java/com/michelin/ns4kafka/integration/NamespaceTest.java rename to src/test/java/com/michelin/ns4kafka/integration/NamespaceIntegrationTest.java index df9a33c2..ebcd229f 100644 --- a/src/test/java/com/michelin/ns4kafka/integration/NamespaceTest.java +++ b/src/test/java/com/michelin/ns4kafka/integration/NamespaceIntegrationTest.java @@ -33,7 +33,7 @@ */ @MicronautTest @Property(name = "micronaut.security.gitlab.enabled", value = "false") -class NamespaceTest extends AbstractIntegrationTest { +class NamespaceIntegrationTest extends AbstractIntegrationTest { @Inject @Client("/") HttpClient client; @@ -43,9 +43,9 @@ class NamespaceTest extends AbstractIntegrationTest { @BeforeAll void init() { UsernamePasswordCredentials credentials = new UsernamePasswordCredentials("admin", "admin"); - HttpResponse response = + HttpResponse response = client.toBlocking().exchange(HttpRequest.POST("/login", credentials), - TopicTest.BearerAccessRefreshToken.class); + TopicIntegrationTest.BearerAccessRefreshToken.class); token = response.getBody().get().getAccessToken(); } @@ -291,9 +291,9 @@ void shouldFailWhenRequestedNamespaceIsForbidden() { UsernamePasswordCredentials credentials = new UsernamePasswordCredentials("user", "admin"); - HttpResponse response = + HttpResponse response = client.toBlocking().exchange(HttpRequest.POST("/login", credentials), - TopicTest.BearerAccessRefreshToken.class); + TopicIntegrationTest.BearerAccessRefreshToken.class); String userToken = response.getBody().get().getAccessToken(); diff --git a/src/test/java/com/michelin/ns4kafka/integration/SchemaTest.java b/src/test/java/com/michelin/ns4kafka/integration/SchemaIntegrationTest.java similarity index 99% rename from src/test/java/com/michelin/ns4kafka/integration/SchemaTest.java rename to src/test/java/com/michelin/ns4kafka/integration/SchemaIntegrationTest.java index 0656a5a4..76574f15 100644 --- a/src/test/java/com/michelin/ns4kafka/integration/SchemaTest.java +++ b/src/test/java/com/michelin/ns4kafka/integration/SchemaIntegrationTest.java @@ -4,7 +4,7 @@ import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; -import com.michelin.ns4kafka.integration.TopicTest.BearerAccessRefreshToken; +import com.michelin.ns4kafka.integration.TopicIntegrationTest.BearerAccessRefreshToken; import com.michelin.ns4kafka.model.AccessControlEntry; import com.michelin.ns4kafka.model.Metadata; import com.michelin.ns4kafka.model.Namespace; @@ -37,7 +37,7 @@ @MicronautTest @Property(name = "micronaut.security.gitlab.enabled", value = "false") -class SchemaTest extends AbstractIntegrationSchemaRegistryTest { +class SchemaIntegrationTest extends AbstractIntegrationSchemaRegistryTest { @Inject private ApplicationContext applicationContext; diff --git a/src/test/java/com/michelin/ns4kafka/integration/StreamTest.java b/src/test/java/com/michelin/ns4kafka/integration/StreamIntegrationTest.java similarity index 97% rename from src/test/java/com/michelin/ns4kafka/integration/StreamTest.java rename to src/test/java/com/michelin/ns4kafka/integration/StreamIntegrationTest.java index 9094b718..690b3520 100644 --- a/src/test/java/com/michelin/ns4kafka/integration/StreamTest.java +++ b/src/test/java/com/michelin/ns4kafka/integration/StreamIntegrationTest.java @@ -3,7 +3,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; -import com.michelin.ns4kafka.integration.TopicTest.BearerAccessRefreshToken; +import com.michelin.ns4kafka.integration.TopicIntegrationTest.BearerAccessRefreshToken; import com.michelin.ns4kafka.model.AccessControlEntry; import com.michelin.ns4kafka.model.AccessControlEntry.AccessControlEntrySpec; import com.michelin.ns4kafka.model.AccessControlEntry.Permission; @@ -37,7 +37,7 @@ @MicronautTest @Property(name = "micronaut.security.gitlab.enabled", value = "false") -class StreamTest extends AbstractIntegrationTest { +class StreamIntegrationTest extends AbstractIntegrationTest { @Inject @Client("/") HttpClient client; diff --git a/src/test/java/com/michelin/ns4kafka/integration/TopicTest.java b/src/test/java/com/michelin/ns4kafka/integration/TopicIntegrationTest.java similarity index 99% rename from src/test/java/com/michelin/ns4kafka/integration/TopicTest.java rename to src/test/java/com/michelin/ns4kafka/integration/TopicIntegrationTest.java index cd44f77d..13b78d83 100644 --- a/src/test/java/com/michelin/ns4kafka/integration/TopicTest.java +++ b/src/test/java/com/michelin/ns4kafka/integration/TopicIntegrationTest.java @@ -57,7 +57,7 @@ @MicronautTest @Property(name = "micronaut.security.gitlab.enabled", value = "false") -class TopicTest extends AbstractIntegrationTest { +class TopicIntegrationTest extends AbstractIntegrationTest { @Inject @Client("/") HttpClient client; diff --git a/src/test/java/com/michelin/ns4kafka/integration/UserTest.java b/src/test/java/com/michelin/ns4kafka/integration/UserIntegrationTest.java similarity index 97% rename from src/test/java/com/michelin/ns4kafka/integration/UserTest.java rename to src/test/java/com/michelin/ns4kafka/integration/UserIntegrationTest.java index 4283a2ec..c868c3bd 100644 --- a/src/test/java/com/michelin/ns4kafka/integration/UserTest.java +++ b/src/test/java/com/michelin/ns4kafka/integration/UserIntegrationTest.java @@ -36,7 +36,7 @@ @MicronautTest @Property(name = "micronaut.security.gitlab.enabled", value = "false") -class UserTest extends AbstractIntegrationTest { +class UserIntegrationTest extends AbstractIntegrationTest { @Inject @Client("/") HttpClient client; @@ -75,8 +75,8 @@ void init() { .build(); UsernamePasswordCredentials credentials = new UsernamePasswordCredentials("admin", "admin"); - HttpResponse response = client.toBlocking() - .exchange(HttpRequest.POST("/login", credentials), TopicTest.BearerAccessRefreshToken.class); + HttpResponse response = client.toBlocking() + .exchange(HttpRequest.POST("/login", credentials), TopicIntegrationTest.BearerAccessRefreshToken.class); token = response.getBody().get().getAccessToken(); diff --git a/src/test/java/com/michelin/ns4kafka/service/AccessControlEntryServiceTest.java b/src/test/java/com/michelin/ns4kafka/service/AclServiceTest.java similarity index 76% rename from src/test/java/com/michelin/ns4kafka/service/AccessControlEntryServiceTest.java rename to src/test/java/com/michelin/ns4kafka/service/AclServiceTest.java index 90d50782..e64d38da 100644 --- a/src/test/java/com/michelin/ns4kafka/service/AccessControlEntryServiceTest.java +++ b/src/test/java/com/michelin/ns4kafka/service/AclServiceTest.java @@ -1,6 +1,7 @@ package com.michelin.ns4kafka.service; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertLinesMatch; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.Mockito.when; @@ -12,7 +13,6 @@ import io.micronaut.context.ApplicationContext; import java.util.List; import java.util.Optional; -import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.params.ParameterizedTest; @@ -25,7 +25,7 @@ * Access control entry service test. */ @ExtendWith(MockitoExtension.class) -class AccessControlEntryServiceTest { +class AclServiceTest { @Mock AccessControlEntryRepository accessControlEntryRepository; @@ -36,11 +36,11 @@ class AccessControlEntryServiceTest { NamespaceService namespaceService; @InjectMocks - AccessControlEntryService accessControlEntryService; + AclService aclService; @Test - void validateNotAllowedResources() { - Namespace ns = Namespace.builder() + void shouldNotValidateAcl() { + Namespace namespace = Namespace.builder() .metadata(Metadata.builder() .name("namespace") .cluster("local") @@ -67,7 +67,8 @@ void validateNotAllowedResources() { .thenReturn(Optional.empty()); when(accessControlEntryRepository.findAll()) .thenReturn(List.of()); - List actual = accessControlEntryService.validate(badAcl, ns); + + List actual = aclService.validate(badAcl, namespace); assertLinesMatch(List.of( "Invalid value \"CONNECT\" for field \"resourceType\": " + "value must be one of \"TOPIC, CONNECT_CLUSTER\".", @@ -80,8 +81,8 @@ void validateNotAllowedResources() { } @Test - void validateNotAllowedSelfGrant() { - Namespace ns = Namespace.builder() + void shouldNotValidateAclBecauseSelfGranted() { + Namespace namespace = Namespace.builder() .metadata(Metadata.builder() .name("namespace") .cluster("local") @@ -105,10 +106,11 @@ void validateNotAllowedSelfGrant() { when(applicationContext.getBean(NamespaceService.class)) .thenReturn(namespaceService); when(namespaceService.findByName("namespace")) - .thenReturn(Optional.of(ns)); + .thenReturn(Optional.of(namespace)); when(accessControlEntryRepository.findAll()) .thenReturn(List.of()); - List actual = accessControlEntryService.validate(badAcl, ns); + + List actual = aclService.validate(badAcl, namespace); assertLinesMatch(List.of( "Invalid value \"namespace\" for field \"grantedTo\": cannot grant ACL to yourself.", "Invalid value \"test/PREFIXED\" for fields \"resource/resourcePatternType\": " @@ -117,7 +119,7 @@ void validateNotAllowedSelfGrant() { } @Test - void validateNotAllowedOwnerOfBadPrefix() { + void shouldNotValidateAclBecauseNotOwnerOfTopLevelResourceHavingBadPrefix() { Namespace ns = Namespace.builder() .metadata(Metadata.builder() .name("namespace") @@ -155,14 +157,15 @@ void validateNotAllowedOwnerOfBadPrefix() { ) .build() )); - List actual = accessControlEntryService.validate(accessControlEntry, ns); + + List actual = aclService.validate(accessControlEntry, ns); assertLinesMatch(List.of("Invalid value \"main/PREFIXED\" for fields \"resource/resourcePatternType\": " + "cannot grant ACL because namespace is not owner of the top level resource."), actual); } @Test - void validateNotAllowedOwnerOfBadLiteral() { - Namespace ns = Namespace.builder() + void shouldNotValidateAclBecauseNotOwnerOfTopLevelResourceHavingBadLiteral() { + Namespace namespace = Namespace.builder() .metadata(Metadata.builder() .name("namespace") .cluster("local") @@ -199,19 +202,20 @@ void validateNotAllowedOwnerOfBadLiteral() { .build() )); - List actual = accessControlEntryService.validate(accessControlEntry, ns); + List actual = aclService.validate(accessControlEntry, namespace); assertLinesMatch(List.of("Invalid value \"resource2/LITERAL\" for fields \"resource/resourcePatternType\": " + "cannot grant ACL because namespace is not owner of the top level resource."), actual); } @Test - void validate_AllowedOwnerOfLiteral() { - Namespace ns = Namespace.builder() + void shouldValidateAclBecauseOwnerOfLiteral() { + Namespace namespace = Namespace.builder() .metadata(Metadata.builder() .name("namespace") .cluster("local") .build()) .build(); + AccessControlEntry accessControlEntry = AccessControlEntry.builder() .metadata(Metadata.builder() .name("acl-name") @@ -225,6 +229,7 @@ void validate_AllowedOwnerOfLiteral() { .grantedTo("target-ns") .build()) .build(); + when(applicationContext.getBean(NamespaceService.class)) .thenReturn(namespaceService); when(namespaceService.findByName("target-ns")) @@ -241,18 +246,20 @@ void validate_AllowedOwnerOfLiteral() { ) .build() )); - List actual = accessControlEntryService.validate(accessControlEntry, ns); + + List actual = aclService.validate(accessControlEntry, namespace); assertTrue(actual.isEmpty()); } @Test - void validate_AllowedOwnerOfPrefix() { - Namespace ns = Namespace.builder() + void shouldValidateAclBecauseOwnerOfPrefix() { + Namespace namespace = Namespace.builder() .metadata(Metadata.builder() .name("namespace") .cluster("local") .build()) .build(); + AccessControlEntry accessControlEntry = AccessControlEntry.builder() .metadata(Metadata.builder() .name("acl-name") @@ -266,6 +273,7 @@ void validate_AllowedOwnerOfPrefix() { .grantedTo("target-ns") .build()) .build(); + when(applicationContext.getBean(NamespaceService.class)) .thenReturn(namespaceService); when(namespaceService.findByName("target-ns")) @@ -283,18 +291,20 @@ void validate_AllowedOwnerOfPrefix() { ) .build() )); - List actual = accessControlEntryService.validate(accessControlEntry, ns); + + List actual = aclService.validate(accessControlEntry, namespace); assertTrue(actual.isEmpty()); } @Test - void validateAllowedPublicGrantedTo() { - Namespace ns = Namespace.builder() + void shouldValidateAclWhenGrantedToAll() { + Namespace namespace = Namespace.builder() .metadata(Metadata.builder() .name("namespace") .cluster("local") .build()) .build(); + AccessControlEntry accessControlEntry = AccessControlEntry.builder() .metadata(Metadata.builder() .name("acl-name") @@ -308,6 +318,7 @@ void validateAllowedPublicGrantedTo() { .grantedTo("*") .build()) .build(); + when(applicationContext.getBean(NamespaceService.class)) .thenReturn(namespaceService); when(namespaceService.findByName("*")) @@ -324,12 +335,13 @@ void validateAllowedPublicGrantedTo() { ) .build() )); - List actual = accessControlEntryService.validate(accessControlEntry, ns); + + List actual = aclService.validate(accessControlEntry, namespace); assertTrue(actual.isEmpty()); } @Test - void validateAsAdminSuccessUpdatingExistingAcl() { + void shouldValidateAsAdminUpdatingExistingAcl() { AccessControlEntry accessControlEntry = AccessControlEntry.builder() .metadata(Metadata.builder() .name("acl-name") @@ -344,6 +356,7 @@ void validateAsAdminSuccessUpdatingExistingAcl() { .grantedTo("target-ns") .build()) .build(); + Namespace namespace = Namespace.builder() .metadata(Metadata.builder() .name("target-ns") @@ -354,21 +367,26 @@ void validateAsAdminSuccessUpdatingExistingAcl() { when(accessControlEntryRepository.findAll()) .thenReturn(List.of(accessControlEntry)); - List actual = accessControlEntryService.validateAsAdmin(accessControlEntry, namespace); + List actual = aclService.validateAsAdmin(accessControlEntry, namespace); assertTrue(actual.isEmpty()); } @ParameterizedTest - @CsvSource({"project1,project2_t1,project1,project2_t1", - "project1.,project2_t1,project1_,project2.t1"}) - void validateAsAdminFailSameOverlap(String existingA, String existingB, String toCreateA, String toCreateB) { - // another namespace is already OWNER of PREFIXED or LITERAL resource - // example : - // if already exists: + @CsvSource({ + "project1,project2_t1,project1,project2_t1", + "project1.,project2_t1,project1_,project2.t1" + }) + void shouldValidateFailAsAdminWhenAclOverlap(String existingA, + String existingB, + String toCreateA, + String toCreateB) { + // Another namespace is already OWNER of PREFIXED or LITERAL resource. + // Example : + // If already exists: // namespace1 OWNER:PREFIXED:project1 // namespace1 OWNER:LITERAL:project2_t1 - // and we try to create: + // And we try to create: // namespace2 OWNER:PREFIXED:project1 KO 1 same <<<<<< // namespace2 OWNER:LITERAL:project1 KO 2 same <<<<<< // namespace2 OWNER:PREFIXED:project1_sub KO 3 child overlap @@ -379,7 +397,8 @@ void validateAsAdminFailSameOverlap(String existingA, String existingB, String t // namespace2 OWNER:PREFIXED:project3_topic1_sub OK 7 // namespace2 OWNER:LITERAL:project2 OK 8 // namespace2 OWNER:LITERAL:proj OK 9 - AccessControlEntry existing1 = AccessControlEntry.builder() + + AccessControlEntry aceTopicPrefixedOwnerOtherNsToOtherNs = AccessControlEntry.builder() .metadata(Metadata.builder() .name("acl-existing1") .namespace("other-ns") @@ -394,7 +413,7 @@ void validateAsAdminFailSameOverlap(String existingA, String existingB, String t .build()) .build(); - AccessControlEntry existing2 = AccessControlEntry.builder() + AccessControlEntry aceTopicLiteralOwnerOtherNsToOtherNs = AccessControlEntry.builder() .metadata(Metadata.builder() .name("acl-existing2") .namespace("other-ns") @@ -416,7 +435,7 @@ void validateAsAdminFailSameOverlap(String existingA, String existingB, String t .build()) .build(); - AccessControlEntry toCreate1 = AccessControlEntry.builder() + AccessControlEntry aceTopicPrefixedOwnerTargetNsToTargetNs = AccessControlEntry.builder() .metadata(Metadata.builder() .name("acl-tocreate") .namespace("target-ns") @@ -431,7 +450,7 @@ void validateAsAdminFailSameOverlap(String existingA, String existingB, String t .build()) .build(); - AccessControlEntry toCreate2 = AccessControlEntry.builder() + AccessControlEntry aceTopicLiteralOwnerTargetNsToTargetNs = AccessControlEntry.builder() .metadata(Metadata.builder() .name("acl-tocreate") .namespace("target-ns") @@ -447,21 +466,25 @@ void validateAsAdminFailSameOverlap(String existingA, String existingB, String t .build(); when(accessControlEntryRepository.findAll()) - .thenReturn(List.of(existing1, existing2)); + .thenReturn(List.of(aceTopicPrefixedOwnerOtherNsToOtherNs, aceTopicLiteralOwnerOtherNsToOtherNs)); - List actual = accessControlEntryService.validateAsAdmin(toCreate1, namespace); + List actual = aclService.validateAsAdmin(aceTopicPrefixedOwnerTargetNsToTargetNs, namespace); assertEquals(1, actual.size()); - actual = accessControlEntryService.validateAsAdmin(toCreate2, namespace); + actual = aclService.validateAsAdmin(aceTopicLiteralOwnerTargetNsToTargetNs, namespace); assertEquals(1, actual.size()); } @ParameterizedTest - @CsvSource({"project1,project2_t1,proj,project2", - "project1.abc,project1.def_ghi,project1_,project1_def"}) - void shouldValidateAsAdminFailParentOverlap(String existingA, String existingB, String toCreateA, - String toCreateB) { - AccessControlEntry existing1 = AccessControlEntry.builder() + @CsvSource({ + "project1,project2_t1,proj,project2", + "project1.abc,project1.def_ghi,project1_,project1_def" + }) + void shouldValidateFailAsAdminWhenParentAclOverlap(String existingA, + String existingB, + String toCreateA, + String toCreateB) { + AccessControlEntry aceTopicPrefixedOwnerOtherNsToOtherNs = AccessControlEntry.builder() .metadata(Metadata.builder() .name("acl-existing1") .namespace("other-ns") @@ -476,7 +499,7 @@ void shouldValidateAsAdminFailParentOverlap(String existingA, String existingB, .build()) .build(); - AccessControlEntry existing2 = AccessControlEntry.builder() + AccessControlEntry aceTopicLiteralOwnerOtherNsToOtherNs = AccessControlEntry.builder() .metadata(Metadata.builder() .name("acl-existing2") .namespace("other-ns") @@ -498,7 +521,7 @@ void shouldValidateAsAdminFailParentOverlap(String existingA, String existingB, .build()) .build(); - AccessControlEntry toCreate1 = AccessControlEntry.builder() + AccessControlEntry aceTopicPrefixedOwnerTargetNsToTargetNs = AccessControlEntry.builder() .metadata(Metadata.builder() .name("acl-tocreate") .namespace("target-ns") @@ -513,7 +536,7 @@ void shouldValidateAsAdminFailParentOverlap(String existingA, String existingB, .build()) .build(); - AccessControlEntry toCreate2 = AccessControlEntry.builder() + AccessControlEntry aceTopicPrefixedOwnerTargetNsToTargetNs2 = AccessControlEntry.builder() .metadata(Metadata.builder() .name("acl-tocreate") .namespace("target-ns") @@ -527,22 +550,27 @@ void shouldValidateAsAdminFailParentOverlap(String existingA, String existingB, .grantedTo("target-ns") .build()) .build(); + when(accessControlEntryRepository.findAll()) - .thenReturn(List.of(existing1, existing2)); + .thenReturn(List.of(aceTopicPrefixedOwnerOtherNsToOtherNs, aceTopicLiteralOwnerOtherNsToOtherNs)); - List actual = accessControlEntryService.validateAsAdmin(toCreate1, namespace); + List actual = aclService.validateAsAdmin(aceTopicPrefixedOwnerTargetNsToTargetNs, namespace); assertEquals(2, actual.size()); - actual = accessControlEntryService.validateAsAdmin(toCreate2, namespace); + actual = aclService.validateAsAdmin(aceTopicPrefixedOwnerTargetNsToTargetNs2, namespace); assertEquals(1, actual.size()); } @ParameterizedTest - @CsvSource({"project1,project2_t1,project1_sub,project1_t1", - "project1.,project2_t1,project1_sub,project1_t1"}) - void shouldValidateAsAdminFailChildOverlap(String existingA, String existingB, String toCreateA, - String toCreateB) { - AccessControlEntry existing1 = AccessControlEntry.builder() + @CsvSource({ + "project1,project2_t1,project1_sub,project1_t1", + "project1.,project2_t1,project1_sub,project1_t1" + }) + void shouldValidateFailAsAdminWhenChildAclOverlap(String existingA, + String existingB, + String toCreateA, + String toCreateB) { + AccessControlEntry aceTopicPrefixedOwnerOtherNsToOtherNs = AccessControlEntry.builder() .metadata(Metadata.builder() .name("acl-existing1") .namespace("other-ns") @@ -557,7 +585,7 @@ void shouldValidateAsAdminFailChildOverlap(String existingA, String existingB, S .build()) .build(); - AccessControlEntry existing2 = AccessControlEntry.builder() + AccessControlEntry aceTopicLiteralOwnerOtherNsToOtherNs = AccessControlEntry.builder() .metadata(Metadata.builder() .name("acl-existing2") .namespace("other-ns") @@ -579,7 +607,7 @@ void shouldValidateAsAdminFailChildOverlap(String existingA, String existingB, S .build()) .build(); - AccessControlEntry toCreate1 = AccessControlEntry.builder() + AccessControlEntry aceTopicPrefixedOwnerTargetNsToTargetNs = AccessControlEntry.builder() .metadata(Metadata.builder() .name("acl-tocreate") .namespace("target-ns") @@ -594,7 +622,7 @@ void shouldValidateAsAdminFailChildOverlap(String existingA, String existingB, S .build()) .build(); - AccessControlEntry toCreate2 = AccessControlEntry.builder() + AccessControlEntry aceTopicLiteralOwnerTargetNsToTargetNs = AccessControlEntry.builder() .metadata(Metadata.builder() .name("acl-tocreate") .namespace("target-ns") @@ -610,25 +638,25 @@ void shouldValidateAsAdminFailChildOverlap(String existingA, String existingB, S .build(); when(accessControlEntryRepository.findAll()) - .thenReturn(List.of(existing1, existing2)); + .thenReturn(List.of(aceTopicPrefixedOwnerOtherNsToOtherNs, aceTopicLiteralOwnerOtherNsToOtherNs)); - List actual = accessControlEntryService.validateAsAdmin(toCreate1, namespace); + List actual = aclService.validateAsAdmin(aceTopicPrefixedOwnerTargetNsToTargetNs, namespace); assertEquals(1, actual.size()); - actual = accessControlEntryService.validateAsAdmin(toCreate2, namespace); + actual = aclService.validateAsAdmin(aceTopicLiteralOwnerTargetNsToTargetNs, namespace); assertEquals(1, actual.size()); } @Test - void shouldValidateAsAdmin() { - // another namespace is already OWNER of PREFIXED or LITERAL resource - // example : - // if already exists: + void shouldValidateAclsAsAdmin() { + // Another namespace is already OWNER of PREFIXED or LITERAL resource + // Example : + // If already exists: // namespace1 OWNER:PREFIXED:project1 // namespace1 OWNER:LITERAL:project2_t1 // namespace1 OWNER:PREFIXED:p of CONNECT (should not interfere) // namespace1 READ:PREFIXED:p OF TOPIC (should not interfere) - // and we try to create: + // And we try to create: // namespace2 OWNER:PREFIXED:project1 KO 1 same // namespace2 OWNER:LITERAL:project1 KO 2 same // namespace2 OWNER:PREFIXED:project1_sub KO 3 child overlap @@ -639,7 +667,8 @@ void shouldValidateAsAdmin() { // namespace2 OWNER:PREFIXED:project3_topic1_sub OK 7 <<<<<<<< // namespace2 OWNER:LITERAL:project2 OK 8 <<<<<<<< // namespace2 OWNER:LITERAL:proj OK 9 <<<<<<<< - AccessControlEntry existing1 = AccessControlEntry.builder() + + AccessControlEntry aceTopicPrefixedOwnerOtherNsToOtherNs = AccessControlEntry.builder() .metadata(Metadata.builder() .name("acl-existing1") .namespace("other-ns") @@ -654,7 +683,7 @@ void shouldValidateAsAdmin() { .build()) .build(); - AccessControlEntry existing2 = AccessControlEntry.builder() + AccessControlEntry aceTopicLiteralOwnerOtherNsToOtherNs = AccessControlEntry.builder() .metadata(Metadata.builder() .name("acl-existing2") .namespace("other-ns") @@ -669,7 +698,7 @@ void shouldValidateAsAdmin() { .build()) .build(); - AccessControlEntry existing3 = AccessControlEntry.builder() + AccessControlEntry aceConnectPrefixedOwnerOtherNsToOtherNs = AccessControlEntry.builder() .metadata(Metadata.builder() .name("acl-existing2") .namespace("other-ns") @@ -691,7 +720,7 @@ void shouldValidateAsAdmin() { .build()) .build(); - AccessControlEntry toCreate1 = AccessControlEntry.builder() + AccessControlEntry aceTopicPrefixedOwnerTargetNsToTargetNs = AccessControlEntry.builder() .metadata(Metadata.builder() .name("acl-tocreate") .namespace("target-ns") @@ -707,9 +736,10 @@ void shouldValidateAsAdmin() { .build(); when(accessControlEntryRepository.findAll()) - .thenReturn(List.of(existing1, existing2, existing3)); + .thenReturn(List.of(aceTopicPrefixedOwnerOtherNsToOtherNs, aceTopicLiteralOwnerOtherNsToOtherNs, + aceConnectPrefixedOwnerOtherNsToOtherNs)); - List actual = accessControlEntryService.validateAsAdmin(toCreate1, namespace); + List actual = aclService.validateAsAdmin(aceTopicPrefixedOwnerTargetNsToTargetNs, namespace); assertTrue(actual.isEmpty()); AccessControlEntry toCreate2 = AccessControlEntry.builder() @@ -727,10 +757,10 @@ void shouldValidateAsAdmin() { .build()) .build(); - actual = accessControlEntryService.validateAsAdmin(toCreate2, namespace); + actual = aclService.validateAsAdmin(toCreate2, namespace); assertTrue(actual.isEmpty()); - AccessControlEntry toCreate3 = AccessControlEntry.builder() + AccessControlEntry aceTopicLiteralOwnerTargetNsToTargetNs = AccessControlEntry.builder() .metadata(Metadata.builder() .name("acl-tocreate") .namespace("target-ns") @@ -745,143 +775,223 @@ void shouldValidateAsAdmin() { .build()) .build(); - actual = accessControlEntryService.validateAsAdmin(toCreate3, namespace); + actual = aclService.validateAsAdmin(aceTopicLiteralOwnerTargetNsToTargetNs, namespace); assertTrue(actual.isEmpty()); } @Test - void findAllGrantedToNamespace() { - Namespace ns = Namespace.builder() - .metadata(Metadata.builder().name("namespace1").build()).build(); + void shouldFindAllAclsGrantedToNamespace() { + Namespace namespace = Namespace.builder() + .metadata(Metadata.builder() + .name("namespace1") + .build()) + .build(); + AccessControlEntry ace1 = AccessControlEntry.builder() - .spec(AccessControlEntry.AccessControlEntrySpec.builder().grantedTo("namespace1").build()).build(); + .spec(AccessControlEntry.AccessControlEntrySpec.builder() + .grantedTo("namespace1") + .build()) + .build(); + AccessControlEntry ace2 = AccessControlEntry.builder() - .spec(AccessControlEntry.AccessControlEntrySpec.builder().grantedTo("namespace1").build()).build(); + .spec(AccessControlEntry.AccessControlEntrySpec.builder() + .grantedTo("namespace1") + .build()) + .build(); + AccessControlEntry ace3 = AccessControlEntry.builder() - .spec(AccessControlEntry.AccessControlEntrySpec.builder().grantedTo("namespace2").build()).build(); + .spec(AccessControlEntry.AccessControlEntrySpec.builder() + .grantedTo("namespace2") + .build()) + .build(); + AccessControlEntry ace4 = AccessControlEntry.builder() - .spec(AccessControlEntry.AccessControlEntrySpec.builder().grantedTo("*").build()).build(); + .spec(AccessControlEntry.AccessControlEntrySpec.builder() + .grantedTo("*") + .build()) + .build(); when(accessControlEntryRepository.findAll()) .thenReturn(List.of(ace1, ace2, ace3, ace4)); - List actual = accessControlEntryService.findAllGrantedToNamespace(ns); + + List actual = aclService.findAllGrantedToNamespace(namespace); assertEquals(3, actual.size()); } @Test - void findAllPublicGrantedTo() { + void shouldFindAllAclsGrantedToAll() { AccessControlEntry ace1 = AccessControlEntry.builder() - .spec(AccessControlEntry.AccessControlEntrySpec.builder().grantedTo("namespace1").build()).build(); + .spec(AccessControlEntry.AccessControlEntrySpec.builder() + .grantedTo("namespace1") + .build()) + .build(); + AccessControlEntry ace2 = AccessControlEntry.builder() - .spec(AccessControlEntry.AccessControlEntrySpec.builder().grantedTo("namespace1").build()).build(); + .spec(AccessControlEntry.AccessControlEntrySpec.builder() + .grantedTo("namespace1") + .build()) + .build(); + AccessControlEntry ace3 = AccessControlEntry.builder() - .spec(AccessControlEntry.AccessControlEntrySpec.builder().grantedTo("namespace2").build()).build(); + .spec(AccessControlEntry.AccessControlEntrySpec.builder() + .grantedTo("namespace2") + .build()) + .build(); + AccessControlEntry ace4 = AccessControlEntry.builder() - .spec(AccessControlEntry.AccessControlEntrySpec.builder().grantedTo("*").build()).build(); + .spec(AccessControlEntry.AccessControlEntrySpec.builder() + .grantedTo("*") + .build()) + .build(); when(accessControlEntryRepository.findAll()) .thenReturn(List.of(ace1, ace2, ace3, ace4)); - List actual = accessControlEntryService.findAllPublicGrantedTo(); + + List actual = aclService.findAllPublicGrantedTo(); assertEquals(1, actual.size()); } @Test - void findAllForNamespace() { + void shouldFindAllAclForNamespace() { Namespace ns = Namespace.builder() - .metadata(Metadata.builder().name("namespace1").build()).build(); + .metadata(Metadata.builder() + .name("namespace1") + .build()) + .build(); + AccessControlEntry ace1 = AccessControlEntry.builder() - .metadata(Metadata.builder().namespace("namespace1").build()) - .spec(AccessControlEntry.AccessControlEntrySpec.builder().grantedTo("namespace1").build()).build(); + .metadata(Metadata.builder() + .namespace("namespace1") + .build()) + .spec(AccessControlEntry.AccessControlEntrySpec.builder() + .grantedTo("namespace1") + .build()) + .build(); + AccessControlEntry ace2 = AccessControlEntry.builder() - .metadata(Metadata.builder().namespace("namespace1").build()) - .spec(AccessControlEntry.AccessControlEntrySpec.builder().grantedTo("namespace2").build()).build(); + .metadata(Metadata.builder() + .namespace("namespace1") + .build()) + .spec(AccessControlEntry.AccessControlEntrySpec.builder() + .grantedTo("namespace2") + .build()) + .build(); + AccessControlEntry ace3 = AccessControlEntry.builder() - .metadata(Metadata.builder().namespace("namespace2").build()) - .spec(AccessControlEntry.AccessControlEntrySpec.builder().grantedTo("namespace2").build()).build(); + .metadata(Metadata.builder() + .namespace("namespace2") + .build()) + .spec(AccessControlEntry.AccessControlEntrySpec.builder() + .grantedTo("namespace2") + .build()) + .build(); when(accessControlEntryRepository.findAll()) .thenReturn(List.of(ace1, ace2, ace3)); - List actual = accessControlEntryService.findAllForNamespace(ns); + + List actual = aclService.findAllForNamespace(ns); assertEquals(2, actual.size()); } @Test - void findAll() { + void shouldFindAllAcls() { AccessControlEntry ace1 = AccessControlEntry.builder() - .metadata(Metadata.builder().namespace("namespace1").build()) - .spec(AccessControlEntry.AccessControlEntrySpec.builder().grantedTo("namespace1").build()).build(); + .metadata(Metadata.builder() + .namespace("namespace1") + .build()) + .spec(AccessControlEntry.AccessControlEntrySpec.builder() + .grantedTo("namespace1") + .build()) + .build(); + AccessControlEntry ace2 = AccessControlEntry.builder() - .metadata(Metadata.builder().namespace("namespace2").build()) - .spec(AccessControlEntry.AccessControlEntrySpec.builder().grantedTo("namespace2").build()).build(); + .metadata(Metadata.builder() + .namespace("namespace2") + .build()) + .spec(AccessControlEntry.AccessControlEntrySpec.builder() + .grantedTo("namespace2") + .build()) + .build(); + AccessControlEntry ace3 = AccessControlEntry.builder() - .metadata(Metadata.builder().namespace("namespace3").build()) - .spec(AccessControlEntry.AccessControlEntrySpec.builder().grantedTo("namespace3").build()).build(); + .metadata(Metadata.builder() + .namespace("namespace3") + .build()) + .spec(AccessControlEntry.AccessControlEntrySpec.builder() + .grantedTo("namespace3") + .build()).build(); when(accessControlEntryRepository.findAll()) .thenReturn(List.of(ace1, ace2, ace3)); - List actual = accessControlEntryService.findAll(); + + List actual = aclService.findAll(); assertEquals(3, actual.size()); } @Test - void isNamespaceOwnerOfResource() { - AccessControlEntry ace1 = AccessControlEntry.builder() + void shouldCheckIfNamespaceIsOwnerOfResource() { + AccessControlEntry aceTopicPrefixedOwner = AccessControlEntry.builder() .spec(AccessControlEntry.AccessControlEntrySpec.builder() .resourceType(AccessControlEntry.ResourceType.TOPIC) .resourcePatternType(AccessControlEntry.ResourcePatternType.PREFIXED) .permission(AccessControlEntry.Permission.OWNER) .resource("main") .grantedTo("namespace") - .build() - ) + .build()) .build(); - AccessControlEntry ace2 = AccessControlEntry.builder() + + AccessControlEntry aceConnectLiteralOwner = AccessControlEntry.builder() .spec(AccessControlEntry.AccessControlEntrySpec.builder() .resourceType(AccessControlEntry.ResourceType.CONNECT) .resourcePatternType(AccessControlEntry.ResourcePatternType.LITERAL) .permission(AccessControlEntry.Permission.OWNER) .resource("connect") .grantedTo("namespace") - .build() - ) + .build()) .build(); - AccessControlEntry ace3 = AccessControlEntry.builder() + + AccessControlEntry aceConnectLiteralWrite = AccessControlEntry.builder() .spec(AccessControlEntry.AccessControlEntrySpec.builder() .resourceType(AccessControlEntry.ResourceType.CONNECT) .resourcePatternType(AccessControlEntry.ResourcePatternType.LITERAL) .permission(AccessControlEntry.Permission.WRITE) .resource("connect") .grantedTo("namespace-other") - .build() - ) + .build()) .build(); + when(accessControlEntryRepository.findAll()) - .thenReturn(List.of(ace1, ace2, ace3)); + .thenReturn(List.of(aceTopicPrefixedOwner, aceConnectLiteralOwner, aceConnectLiteralWrite)); + assertTrue( - accessControlEntryService.isNamespaceOwnerOfResource("namespace", + aclService.isNamespaceOwnerOfResource("namespace", AccessControlEntry.ResourceType.CONNECT, "connect")); + assertTrue( - accessControlEntryService.isNamespaceOwnerOfResource("namespace", + aclService.isNamespaceOwnerOfResource("namespace", AccessControlEntry.ResourceType.TOPIC, "main")); + assertTrue( - accessControlEntryService.isNamespaceOwnerOfResource("namespace", + aclService.isNamespaceOwnerOfResource("namespace", AccessControlEntry.ResourceType.TOPIC, "main.sub"), "subresource"); - Assertions.assertFalse( - accessControlEntryService.isNamespaceOwnerOfResource("namespace-other", + + assertFalse( + aclService.isNamespaceOwnerOfResource("namespace-other", AccessControlEntry.ResourceType.TOPIC, "main")); - Assertions.assertFalse( - accessControlEntryService.isNamespaceOwnerOfResource("namespace-other", + + assertFalse( + aclService.isNamespaceOwnerOfResource("namespace-other", AccessControlEntry.ResourceType.CONNECT, "connect")); } @Test void shouldNotCollideIfDifferentResource() { - AccessControlEntry ace1 = AccessControlEntry.builder() + AccessControlEntry aceTopicPrefixedOwner = AccessControlEntry.builder() .spec(AccessControlEntry.AccessControlEntrySpec.builder() .resourceType(AccessControlEntry.ResourceType.TOPIC) .resourcePatternType(AccessControlEntry.ResourcePatternType.PREFIXED) @@ -891,7 +1001,7 @@ void shouldNotCollideIfDifferentResource() { .build()) .build(); - AccessControlEntry ace2 = AccessControlEntry.builder() + AccessControlEntry aceConnectLiteralOwner = AccessControlEntry.builder() .spec(AccessControlEntry.AccessControlEntrySpec.builder() .resourceType(AccessControlEntry.ResourceType.CONNECT) .resourcePatternType(AccessControlEntry.ResourcePatternType.LITERAL) @@ -901,9 +1011,9 @@ void shouldNotCollideIfDifferentResource() { .build()) .build(); - Assertions.assertFalse(accessControlEntryService.topicAclsCollideWithParentOrChild(ace1, ace2)); - Assertions.assertFalse(accessControlEntryService.topicAclsCollideWithParentOrChild(ace2, ace1)); - Assertions.assertFalse(accessControlEntryService.topicAclsCollide(ace1, ace2)); - Assertions.assertFalse(accessControlEntryService.topicAclsCollide(ace2, ace1)); + assertFalse(aclService.topicAclsCollideWithParentOrChild(aceTopicPrefixedOwner, aceConnectLiteralOwner)); + assertFalse(aclService.topicAclsCollideWithParentOrChild(aceConnectLiteralOwner, aceTopicPrefixedOwner)); + assertFalse(aclService.topicAclsCollide(aceTopicPrefixedOwner, aceConnectLiteralOwner)); + assertFalse(aclService.topicAclsCollide(aceConnectLiteralOwner, aceTopicPrefixedOwner)); } } diff --git a/src/test/java/com/michelin/ns4kafka/service/ConnectClusterServiceTest.java b/src/test/java/com/michelin/ns4kafka/service/ConnectClusterServiceTest.java index bc6c57cd..1b2f6195 100644 --- a/src/test/java/com/michelin/ns4kafka/service/ConnectClusterServiceTest.java +++ b/src/test/java/com/michelin/ns4kafka/service/ConnectClusterServiceTest.java @@ -50,7 +50,7 @@ class ConnectClusterServiceTest { ConnectClusterRepository connectClusterRepository; @Mock - AccessControlEntryService accessControlEntryService; + AclService aclService; @Mock List managedClusterPropertiesList; @@ -169,7 +169,7 @@ void findAllForNamespace() { when(connectClusterRepository.findAllForCluster("local")) .thenReturn(List.of(connectCluster, connectClusterTwo, connectClusterThree, connectClusterFour)); - when(accessControlEntryService.findAllGrantedToNamespace(namespace)) + when(aclService.findAllGrantedToNamespace(namespace)) .thenReturn(List.of( AccessControlEntry.builder() .spec(AccessControlEntry.AccessControlEntrySpec.builder() @@ -252,7 +252,7 @@ void findByNamespaceAndName() { when(connectClusterRepository.findAllForCluster("local")) .thenReturn(List.of(connectCluster)); - when(accessControlEntryService.findAllGrantedToNamespace(namespace)) + when(aclService.findAllGrantedToNamespace(namespace)) .thenReturn(List.of( AccessControlEntry.builder() .spec(AccessControlEntry.AccessControlEntrySpec.builder() @@ -300,7 +300,7 @@ void findByNamespaceAndNameUnhealthy() { when(connectClusterRepository.findAllForCluster("local")) .thenReturn(List.of(connectCluster)); - when(accessControlEntryService.findAllGrantedToNamespace(namespace)) + when(aclService.findAllGrantedToNamespace(namespace)) .thenReturn(List.of( AccessControlEntry.builder() .spec(AccessControlEntry.AccessControlEntrySpec.builder() @@ -349,7 +349,7 @@ void findByNamespaceAndNameEmpty() { when(connectClusterRepository.findAllForCluster("local")) .thenReturn(List.of(connectCluster)); - when(accessControlEntryService.findAllGrantedToNamespace(namespace)) + when(aclService.findAllGrantedToNamespace(namespace)) .thenReturn(List.of( AccessControlEntry.builder() .spec(AccessControlEntry.AccessControlEntrySpec.builder() @@ -589,7 +589,7 @@ void validateConnectClusterVaultNoClusterAvailable() { when(connectClusterRepository.findAllForCluster("local")) .thenReturn(List.of(connectCluster)); - when(accessControlEntryService.findAllGrantedToNamespace(namespace)) + when(aclService.findAllGrantedToNamespace(namespace)) .thenReturn(List.of( AccessControlEntry.builder() .spec(AccessControlEntry.AccessControlEntrySpec.builder() @@ -645,7 +645,7 @@ void validateConnectClusterVaultNoClusterAvailableWithAes256() { when(connectClusterRepository.findAllForCluster("local")) .thenReturn(List.of(connectCluster1, connectCluster2, connectCluster3)); - when(accessControlEntryService.findAllGrantedToNamespace(namespace)) + when(aclService.findAllGrantedToNamespace(namespace)) .thenReturn(List.of( AccessControlEntry.builder() .spec(AccessControlEntry.AccessControlEntrySpec.builder() @@ -725,7 +725,7 @@ void validateConnectClusterVaultClusterNotAvailable() { when(connectClusterRepository.findAllForCluster("local")) .thenReturn(List.of(connectCluster1, connectCluster2, connectCluster3)); - when(accessControlEntryService.findAllGrantedToNamespace(namespace)) + when(aclService.findAllGrantedToNamespace(namespace)) .thenReturn(List.of( AccessControlEntry.builder() .spec(AccessControlEntry.AccessControlEntrySpec.builder() @@ -787,7 +787,7 @@ void validateConnectClusterVault() { when(connectClusterRepository.findAllForCluster("local")) .thenReturn(List.of(connectCluster)); - when(accessControlEntryService.findAllGrantedToNamespace(namespace)) + when(aclService.findAllGrantedToNamespace(namespace)) .thenReturn(List.of( AccessControlEntry.builder() .spec(AccessControlEntry.AccessControlEntrySpec.builder() @@ -827,7 +827,7 @@ void vaultPasswordNoConnectClusterWithAes256Config() { when(connectClusterRepository.findAllForCluster("local")) .thenReturn(List.of(connectCluster)); - when(accessControlEntryService.findAllGrantedToNamespace(namespace)) + when(aclService.findAllGrantedToNamespace(namespace)) .thenReturn(List.of( AccessControlEntry.builder() .spec(AccessControlEntry.AccessControlEntrySpec.builder() @@ -891,7 +891,7 @@ void findAllByNamespaceWriteAsOwner() { when(connectClusterRepository.findAllForCluster("local")) .thenReturn(List.of(connectCluster, connectClusterOwner)); - when(accessControlEntryService.findAllGrantedToNamespace(namespace)) + when(aclService.findAllGrantedToNamespace(namespace)) .thenReturn(List.of( AccessControlEntry.builder() .spec(AccessControlEntry.AccessControlEntrySpec.builder() @@ -955,7 +955,7 @@ void shouldNamespaceOwnerOfConnectCluster() { .build()) .build(); - when(accessControlEntryService.isNamespaceOwnerOfResource(any(), any(), any())) + when(aclService.isNamespaceOwnerOfResource(any(), any(), any())) .thenReturn(true); boolean actual = connectClusterService.isNamespaceOwnerOfConnectCluster(namespace, "prefix.connect-cluster"); @@ -998,7 +998,7 @@ void shouldNamespaceAllowedForConnectCluster() { when(connectClusterRepository.findAllForCluster("local")) .thenReturn(List.of(connectCluster, connectClusterOwner)); - when(accessControlEntryService.findAllGrantedToNamespace(namespace)) + when(aclService.findAllGrantedToNamespace(namespace)) .thenReturn(List.of( AccessControlEntry.builder() .spec(AccessControlEntry.AccessControlEntrySpec.builder() @@ -1060,7 +1060,7 @@ void shouldNamespaceNotAllowedForConnectCluster() { when(connectClusterRepository.findAllForCluster("local")) .thenReturn(List.of(connectCluster, connectClusterOwner)); - when(accessControlEntryService.findAllGrantedToNamespace(namespace)) + when(aclService.findAllGrantedToNamespace(namespace)) .thenReturn(List.of( AccessControlEntry.builder() .spec(AccessControlEntry.AccessControlEntrySpec.builder() @@ -1116,7 +1116,7 @@ void vaultPasswordWithoutFormat() { when(connectClusterRepository.findAllForCluster("local")) .thenReturn(List.of(connectCluster)); - when(accessControlEntryService.findAllGrantedToNamespace(namespace)) + when(aclService.findAllGrantedToNamespace(namespace)) .thenReturn(List.of( AccessControlEntry.builder() .spec(AccessControlEntry.AccessControlEntrySpec.builder() @@ -1166,7 +1166,7 @@ void vaultPasswordWithFormat() { when(connectClusterRepository.findAllForCluster("local")) .thenReturn(List.of(connectCluster)); - when(accessControlEntryService.findAllGrantedToNamespace(namespace)) + when(aclService.findAllGrantedToNamespace(namespace)) .thenReturn(List.of( AccessControlEntry.builder() .spec(AccessControlEntry.AccessControlEntrySpec.builder() diff --git a/src/test/java/com/michelin/ns4kafka/service/ConnectorServiceTest.java b/src/test/java/com/michelin/ns4kafka/service/ConnectorServiceTest.java index 6cbc9060..c783016f 100644 --- a/src/test/java/com/michelin/ns4kafka/service/ConnectorServiceTest.java +++ b/src/test/java/com/michelin/ns4kafka/service/ConnectorServiceTest.java @@ -48,7 +48,7 @@ @ExtendWith(MockitoExtension.class) class ConnectorServiceTest { @Mock - AccessControlEntryService accessControlEntryService; + AclService aclService; @Mock KafkaConnectClient kafkaConnectClient; @@ -113,7 +113,7 @@ void findByNamespaceMultiple() { .metadata(Metadata.builder().name("ns2-connect1").build()) .build(); - when(accessControlEntryService.findAllGrantedToNamespace(ns)) + when(aclService.findAllGrantedToNamespace(ns)) .thenReturn(List.of( AccessControlEntry.builder() .spec(AccessControlEntry.AccessControlEntrySpec.builder() @@ -222,7 +222,7 @@ void findByNameFound() { .metadata(Metadata.builder().name("other-connect1").build()) .build(); - when(accessControlEntryService.findAllGrantedToNamespace(ns)) + when(aclService.findAllGrantedToNamespace(ns)) .thenReturn(List.of( AccessControlEntry.builder() .spec(AccessControlEntry.AccessControlEntrySpec.builder() @@ -253,7 +253,7 @@ void findByNameFound() { .build() )); - when(accessControlEntryService.findAllGrantedToNamespace(ns)) + when(aclService.findAllGrantedToNamespace(ns)) .thenReturn(List.of(AccessControlEntry.builder() .spec(AccessControlEntry.AccessControlEntrySpec.builder() .permission(AccessControlEntry.Permission.OWNER) @@ -760,23 +760,23 @@ void listUnsynchronizedNoExistingConnectors() { .thenReturn(Flux.fromIterable(List.of(c5))); // list of existing Ns4Kafka access control entries - when(accessControlEntryService.isNamespaceOwnerOfResource("namespace", AccessControlEntry.ResourceType.CONNECT, + when(aclService.isNamespaceOwnerOfResource("namespace", AccessControlEntry.ResourceType.CONNECT, "ns-connect1")) .thenReturn(true); - when(accessControlEntryService.isNamespaceOwnerOfResource("namespace", AccessControlEntry.ResourceType.CONNECT, + when(aclService.isNamespaceOwnerOfResource("namespace", AccessControlEntry.ResourceType.CONNECT, "ns-connect2")) .thenReturn(true); - when(accessControlEntryService.isNamespaceOwnerOfResource("namespace", AccessControlEntry.ResourceType.CONNECT, + when(aclService.isNamespaceOwnerOfResource("namespace", AccessControlEntry.ResourceType.CONNECT, "ns1-connect1")) .thenReturn(true); - when(accessControlEntryService.isNamespaceOwnerOfResource("namespace", AccessControlEntry.ResourceType.CONNECT, + when(aclService.isNamespaceOwnerOfResource("namespace", AccessControlEntry.ResourceType.CONNECT, "ns1-connect2")) .thenReturn(true); - when(accessControlEntryService.isNamespaceOwnerOfResource("namespace", AccessControlEntry.ResourceType.CONNECT, + when(aclService.isNamespaceOwnerOfResource("namespace", AccessControlEntry.ResourceType.CONNECT, "ns2-connect1")) .thenReturn(false); - when(accessControlEntryService.findAllGrantedToNamespace(ns)) + when(aclService.findAllGrantedToNamespace(ns)) .thenReturn(List.of( AccessControlEntry.builder() .spec(AccessControlEntry.AccessControlEntrySpec.builder() @@ -856,23 +856,23 @@ void listUnsynchronizedAllExistingConnectors() { .thenReturn(List.of(c1, c2, c3, c4, c5)); // list of existing Ns4Kafka access control entries - when(accessControlEntryService.isNamespaceOwnerOfResource("namespace", AccessControlEntry.ResourceType.CONNECT, + when(aclService.isNamespaceOwnerOfResource("namespace", AccessControlEntry.ResourceType.CONNECT, "ns-connect1")) .thenReturn(true); - when(accessControlEntryService.isNamespaceOwnerOfResource("namespace", AccessControlEntry.ResourceType.CONNECT, + when(aclService.isNamespaceOwnerOfResource("namespace", AccessControlEntry.ResourceType.CONNECT, "ns-connect2")) .thenReturn(true); - when(accessControlEntryService.isNamespaceOwnerOfResource("namespace", AccessControlEntry.ResourceType.CONNECT, + when(aclService.isNamespaceOwnerOfResource("namespace", AccessControlEntry.ResourceType.CONNECT, "ns1-connect1")) .thenReturn(true); - when(accessControlEntryService.isNamespaceOwnerOfResource("namespace", AccessControlEntry.ResourceType.CONNECT, + when(aclService.isNamespaceOwnerOfResource("namespace", AccessControlEntry.ResourceType.CONNECT, "ns1-connect2")) .thenReturn(true); - when(accessControlEntryService.isNamespaceOwnerOfResource("namespace", AccessControlEntry.ResourceType.CONNECT, + when(aclService.isNamespaceOwnerOfResource("namespace", AccessControlEntry.ResourceType.CONNECT, "ns2-connect1")) .thenReturn(false); - when(accessControlEntryService.findAllGrantedToNamespace(ns)) + when(aclService.findAllGrantedToNamespace(ns)) .thenReturn(List.of( AccessControlEntry.builder() .spec(AccessControlEntry.AccessControlEntrySpec.builder() @@ -947,20 +947,20 @@ void listUnsynchronizedPartialExistingConnectors() { // list of existing Ns4Kafka access control entries - when(accessControlEntryService.isNamespaceOwnerOfResource("namespace", AccessControlEntry.ResourceType.CONNECT, + when(aclService.isNamespaceOwnerOfResource("namespace", AccessControlEntry.ResourceType.CONNECT, "ns-connect1")) .thenReturn(true); - when(accessControlEntryService.isNamespaceOwnerOfResource("namespace", AccessControlEntry.ResourceType.CONNECT, + when(aclService.isNamespaceOwnerOfResource("namespace", AccessControlEntry.ResourceType.CONNECT, "ns-connect2")) .thenReturn(true); - when(accessControlEntryService.isNamespaceOwnerOfResource("namespace", AccessControlEntry.ResourceType.CONNECT, + when(aclService.isNamespaceOwnerOfResource("namespace", AccessControlEntry.ResourceType.CONNECT, "ns1-connect1")) .thenReturn(true); - when(accessControlEntryService.isNamespaceOwnerOfResource("namespace", AccessControlEntry.ResourceType.CONNECT, + when(aclService.isNamespaceOwnerOfResource("namespace", AccessControlEntry.ResourceType.CONNECT, "ns2-connect1")) .thenReturn(false); - when(accessControlEntryService.findAllGrantedToNamespace(ns)) + when(aclService.findAllGrantedToNamespace(ns)) .thenReturn(List.of( AccessControlEntry.builder() .spec(AccessControlEntry.AccessControlEntrySpec.builder() diff --git a/src/test/java/com/michelin/ns4kafka/service/NamespaceServiceTest.java b/src/test/java/com/michelin/ns4kafka/service/NamespaceServiceTest.java index a7d69968..de663e05 100644 --- a/src/test/java/com/michelin/ns4kafka/service/NamespaceServiceTest.java +++ b/src/test/java/com/michelin/ns4kafka/service/NamespaceServiceTest.java @@ -44,7 +44,7 @@ class NamespaceServiceTest { RoleBindingService roleBindingService; @Mock - AccessControlEntryService accessControlEntryService; + AclService aclService; @Mock ConnectorService connectorService; @@ -374,7 +374,7 @@ void listAllNamespaceResourcesEmpty() { .thenReturn(List.of()); when(roleBindingService.list("namespace")) .thenReturn(List.of()); - when(accessControlEntryService.findAllForNamespace(ns)) + when(aclService.findAllForNamespace(ns)) .thenReturn(List.of()); when(connectClusterService.findAllByNamespaceOwner(ns)) .thenReturn(List.of()); @@ -411,7 +411,7 @@ void listAllNamespaceResourcesTopic() { .thenReturn(List.of()); when(roleBindingService.list("namespace")) .thenReturn(List.of()); - when(accessControlEntryService.findAllForNamespace(ns)) + when(aclService.findAllForNamespace(ns)) .thenReturn(List.of()); when(connectClusterService.findAllByNamespaceOwner(ns)) .thenReturn(List.of()); @@ -449,7 +449,7 @@ void listAllNamespaceResourcesConnect() { .thenReturn(List.of(connector)); when(roleBindingService.list("namespace")) .thenReturn(List.of()); - when(accessControlEntryService.findAllForNamespace(ns)) + when(aclService.findAllForNamespace(ns)) .thenReturn(List.of()); when(connectClusterService.findAllByNamespaceOwner(ns)) .thenReturn(List.of()); @@ -487,7 +487,7 @@ void listAllNamespaceResourcesRoleBinding() { .thenReturn(List.of()); when(roleBindingService.list("namespace")) .thenReturn(List.of(rb)); - when(accessControlEntryService.findAllForNamespace(ns)) + when(aclService.findAllForNamespace(ns)) .thenReturn(List.of()); when(connectClusterService.findAllByNamespaceOwner(ns)) .thenReturn(List.of()); @@ -525,7 +525,7 @@ void listAllNamespaceResourcesAccessControlEntry() { .thenReturn(List.of()); when(roleBindingService.list("namespace")) .thenReturn(List.of()); - when(accessControlEntryService.findAllForNamespace(ns)) + when(aclService.findAllForNamespace(ns)) .thenReturn(List.of(ace)); when(connectClusterService.findAllByNamespaceOwner(ns)) .thenReturn(List.of()); @@ -563,7 +563,7 @@ void listAllNamespaceResourcesConnectCluster() { .thenReturn(List.of()); when(roleBindingService.list("namespace")) .thenReturn(List.of()); - when(accessControlEntryService.findAllForNamespace(ns)) + when(aclService.findAllForNamespace(ns)) .thenReturn(List.of()); when(connectClusterService.findAllByNamespaceOwner(ns)) .thenReturn(List.of(connectCluster)); @@ -601,7 +601,7 @@ void listAllNamespaceResourcesQuota() { .thenReturn(List.of()); when(roleBindingService.list("namespace")) .thenReturn(List.of()); - when(accessControlEntryService.findAllForNamespace(ns)) + when(aclService.findAllForNamespace(ns)) .thenReturn(List.of()); when(connectClusterService.findAllByNamespaceOwner(ns)) .thenReturn(List.of()); diff --git a/src/test/java/com/michelin/ns4kafka/service/SchemaServiceTest.java b/src/test/java/com/michelin/ns4kafka/service/SchemaServiceTest.java index 5ecec9b8..39d5fa16 100644 --- a/src/test/java/com/michelin/ns4kafka/service/SchemaServiceTest.java +++ b/src/test/java/com/michelin/ns4kafka/service/SchemaServiceTest.java @@ -34,7 +34,7 @@ class SchemaServiceTest { SchemaService schemaService; @Mock - AccessControlEntryService accessControlEntryService; + AclService aclService; @Mock SchemaRegistryClient schemaRegistryClient; @@ -47,7 +47,7 @@ void getAllByNamespace() { when(schemaRegistryClient.getSubjects(namespace.getMetadata().getCluster())).thenReturn( Flux.fromIterable(subjectsResponse)); - when(accessControlEntryService.findAllGrantedToNamespace(namespace)) + when(aclService.findAllGrantedToNamespace(namespace)) .thenReturn(List.of( AccessControlEntry.builder() .spec(AccessControlEntry.AccessControlEntrySpec.builder() @@ -276,7 +276,7 @@ void updateSubjectCompatibility() { @Test void isNamespaceOwnerOfSubjectTest() { Namespace ns = buildNamespace(); - when(accessControlEntryService.isNamespaceOwnerOfResource("myNamespace", AccessControlEntry.ResourceType.TOPIC, + when(aclService.isNamespaceOwnerOfResource("myNamespace", AccessControlEntry.ResourceType.TOPIC, "prefix.schema-one")) .thenReturn(true); diff --git a/src/test/java/com/michelin/ns4kafka/service/StreamServiceTest.java b/src/test/java/com/michelin/ns4kafka/service/StreamServiceTest.java index 3ef7dd3f..a4f3c20e 100644 --- a/src/test/java/com/michelin/ns4kafka/service/StreamServiceTest.java +++ b/src/test/java/com/michelin/ns4kafka/service/StreamServiceTest.java @@ -23,7 +23,7 @@ class StreamServiceTest { StreamService streamService; @Mock - AccessControlEntryService accessControlEntryService; + AclService aclService; @Mock StreamRepository streamRepository; @@ -217,7 +217,7 @@ void isNamespaceOwnerOfKafkaStream() { ) .build(); - when(accessControlEntryService.findAllGrantedToNamespace(ns)) + when(aclService.findAllGrantedToNamespace(ns)) .thenReturn(List.of(ace1, ace2, ace3, ace4, ace5, ace6, ace7)); assertTrue( diff --git a/src/test/java/com/michelin/ns4kafka/service/TopicServiceTest.java b/src/test/java/com/michelin/ns4kafka/service/TopicServiceTest.java index b2d34ddb..260c26aa 100644 --- a/src/test/java/com/michelin/ns4kafka/service/TopicServiceTest.java +++ b/src/test/java/com/michelin/ns4kafka/service/TopicServiceTest.java @@ -42,7 +42,7 @@ class TopicServiceTest { TopicService topicService; @Mock - AccessControlEntryService accessControlEntryService; + AclService aclService; @Mock TopicRepository topicRepository; @@ -90,7 +90,7 @@ void findByName() { when(topicRepository.findAllForCluster("local")) .thenReturn(List.of(t1, t2, t3, t4)); - when(accessControlEntryService.findAllGrantedToNamespace(ns)) + when(aclService.findAllGrantedToNamespace(ns)) .thenReturn(List.of( AccessControlEntry.builder() .spec(AccessControlEntry.AccessControlEntrySpec.builder() @@ -136,7 +136,7 @@ void findAllForNamespaceNoTopics() { .build(); // no ns4kfk access control entries - when(accessControlEntryService.findAllGrantedToNamespace(ns)) + when(aclService.findAllGrantedToNamespace(ns)) .thenReturn(List.of()); // no ns4kfk topics @@ -179,7 +179,7 @@ void findAllForNamespaceNoAcls() { .thenReturn(List.of(t1, t2, t3, t4)); // no ns4kfk access control entries - when(accessControlEntryService.findAllGrantedToNamespace(ns)) + when(aclService.findAllGrantedToNamespace(ns)) .thenReturn(List.of()); // list of topics is empty @@ -217,7 +217,7 @@ void findAllForNamespace() { when(topicRepository.findAllForCluster("local")) .thenReturn(List.of(t0, t1, t2, t3, t4)); - when(accessControlEntryService.findAllGrantedToNamespace(ns)) + when(aclService.findAllGrantedToNamespace(ns)) .thenReturn(List.of( AccessControlEntry.builder() .spec(AccessControlEntry.AccessControlEntrySpec.builder() @@ -293,20 +293,20 @@ void listUnsynchronizedNoExistingTopics() throws InterruptedException, Execution "ns1-topic1", "ns2-topic1")); // list of existing ns4kfk access control entries - when(accessControlEntryService.isNamespaceOwnerOfResource("namespace", AccessControlEntry.ResourceType.TOPIC, + when(aclService.isNamespaceOwnerOfResource("namespace", AccessControlEntry.ResourceType.TOPIC, "ns-topic1")) .thenReturn(true); - when(accessControlEntryService.isNamespaceOwnerOfResource("namespace", AccessControlEntry.ResourceType.TOPIC, + when(aclService.isNamespaceOwnerOfResource("namespace", AccessControlEntry.ResourceType.TOPIC, "ns-topic2")) .thenReturn(true); - when(accessControlEntryService.isNamespaceOwnerOfResource("namespace", AccessControlEntry.ResourceType.TOPIC, + when(aclService.isNamespaceOwnerOfResource("namespace", AccessControlEntry.ResourceType.TOPIC, "ns1-topic1")) .thenReturn(true); - when(accessControlEntryService.isNamespaceOwnerOfResource("namespace", AccessControlEntry.ResourceType.TOPIC, + when(aclService.isNamespaceOwnerOfResource("namespace", AccessControlEntry.ResourceType.TOPIC, "ns2-topic1")) .thenReturn(false); - when(accessControlEntryService.findAllGrantedToNamespace(ns)) + when(aclService.findAllGrantedToNamespace(ns)) .thenReturn(List.of( AccessControlEntry.builder() .spec(AccessControlEntry.AccessControlEntrySpec.builder() @@ -380,20 +380,20 @@ void listUnsynchronizedAllExistingTopics() throws InterruptedException, Executio t3.getMetadata().getName(), t4.getMetadata().getName())); // list of existing ns4kfk access control entries - when(accessControlEntryService.isNamespaceOwnerOfResource("namespace", AccessControlEntry.ResourceType.TOPIC, + when(aclService.isNamespaceOwnerOfResource("namespace", AccessControlEntry.ResourceType.TOPIC, t1.getMetadata().getName())) .thenReturn(true); - when(accessControlEntryService.isNamespaceOwnerOfResource("namespace", AccessControlEntry.ResourceType.TOPIC, + when(aclService.isNamespaceOwnerOfResource("namespace", AccessControlEntry.ResourceType.TOPIC, t2.getMetadata().getName())) .thenReturn(true); - when(accessControlEntryService.isNamespaceOwnerOfResource("namespace", AccessControlEntry.ResourceType.TOPIC, + when(aclService.isNamespaceOwnerOfResource("namespace", AccessControlEntry.ResourceType.TOPIC, t3.getMetadata().getName())) .thenReturn(true); - when(accessControlEntryService.isNamespaceOwnerOfResource("namespace", AccessControlEntry.ResourceType.TOPIC, + when(aclService.isNamespaceOwnerOfResource("namespace", AccessControlEntry.ResourceType.TOPIC, t4.getMetadata().getName())) .thenReturn(false); - when(accessControlEntryService.findAllGrantedToNamespace(ns)) + when(aclService.findAllGrantedToNamespace(ns)) .thenReturn(List.of( AccessControlEntry.builder() .spec(AccessControlEntry.AccessControlEntrySpec.builder() @@ -452,20 +452,20 @@ void listUnsynchronizedPartialExistingTopics() throws InterruptedException, Exec "ns1-topic1", "ns2-topic1")); // list of existing ns4kfk access control entries - when(accessControlEntryService.isNamespaceOwnerOfResource("namespace", AccessControlEntry.ResourceType.TOPIC, + when(aclService.isNamespaceOwnerOfResource("namespace", AccessControlEntry.ResourceType.TOPIC, "ns-topic1")) .thenReturn(true); - when(accessControlEntryService.isNamespaceOwnerOfResource("namespace", AccessControlEntry.ResourceType.TOPIC, + when(aclService.isNamespaceOwnerOfResource("namespace", AccessControlEntry.ResourceType.TOPIC, "ns-topic2")) .thenReturn(true); - when(accessControlEntryService.isNamespaceOwnerOfResource("namespace", AccessControlEntry.ResourceType.TOPIC, + when(aclService.isNamespaceOwnerOfResource("namespace", AccessControlEntry.ResourceType.TOPIC, "ns1-topic1")) .thenReturn(true); - when(accessControlEntryService.isNamespaceOwnerOfResource("namespace", AccessControlEntry.ResourceType.TOPIC, + when(aclService.isNamespaceOwnerOfResource("namespace", AccessControlEntry.ResourceType.TOPIC, "ns2-topic1")) .thenReturn(false); - when(accessControlEntryService.findAllGrantedToNamespace(ns)) + when(aclService.findAllGrantedToNamespace(ns)) .thenReturn(List.of( AccessControlEntry.builder() .spec(AccessControlEntry.AccessControlEntrySpec.builder() @@ -926,7 +926,7 @@ void shouldListUnsynchronizedTopicNames() throws ExecutionException, Interrupted when(applicationContext.getBean(eq(TopicAsyncExecutor.class), any())).thenReturn(topicAsyncExecutor); when(topicAsyncExecutor.listBrokerTopicNames()).thenReturn(List.of("ns-topic1", "ns-topic2", "ns2-topic1")); - when(accessControlEntryService.isNamespaceOwnerOfResource(any(), any(), any())) + when(aclService.isNamespaceOwnerOfResource(any(), any(), any())) .thenReturn(true) .thenReturn(true) .thenReturn(false); @@ -980,48 +980,48 @@ void shouldTagsBeInvalidWhenNotConfluentCloud() { List validationErrors = topicService.validateTags(ns, topic); assertEquals(1, validationErrors.size()); assertEquals("Invalid value \"TAG_TEST\" for field \"tags\": tags are not currently supported.", - validationErrors.getFirst()); + validationErrors.getFirst()); } @Test void shouldReturnTrueWhenTagFormatIsValid() { Topic topicWithTag = Topic.builder() - .metadata(Metadata.builder().name("ns-topic1").build()) - .spec(Topic.TopicSpec.builder() - .tags(List.of("test")).build()) - .build(); + .metadata(Metadata.builder().name("ns-topic1").build()) + .spec(Topic.TopicSpec.builder() + .tags(List.of("test")).build()) + .build(); assertEquals(true, topicService.isTagsFormatValid(topicWithTag)); Topic topicWithSimpliestTag = Topic.builder() - .metadata(Metadata.builder().name("ns-topic2").build()) - .spec(Topic.TopicSpec.builder() - .tags(List.of("A")).build()) - .build(); + .metadata(Metadata.builder().name("ns-topic2").build()) + .spec(Topic.TopicSpec.builder() + .tags(List.of("A")).build()) + .build(); assertEquals(true, topicService.isTagsFormatValid(topicWithSimpliestTag)); Topic topicWithUnderscoreAndNumberTag = Topic.builder() - .metadata(Metadata.builder().name("ns-topic3").build()) - .spec(Topic.TopicSpec.builder() - .tags(List.of("TEST1_TAG")).build()) - .build(); + .metadata(Metadata.builder().name("ns-topic3").build()) + .spec(Topic.TopicSpec.builder() + .tags(List.of("TEST1_TAG")).build()) + .build(); assertEquals(true, topicService.isTagsFormatValid(topicWithUnderscoreAndNumberTag)); Topic topicWithUnderscoreAndUpperLowerCase = Topic.builder() - .metadata(Metadata.builder().name("ns-topic4").build()) - .spec(Topic.TopicSpec.builder() - .tags(List.of("t1_T_a_g2")).build()) - .build(); + .metadata(Metadata.builder().name("ns-topic4").build()) + .spec(Topic.TopicSpec.builder() + .tags(List.of("t1_T_a_g2")).build()) + .build(); assertEquals(true, topicService.isTagsFormatValid(topicWithUnderscoreAndUpperLowerCase)); Topic topicWithMultipleCorrectTags = Topic.builder() - .metadata(Metadata.builder().name("ns-topic5").build()) - .spec(Topic.TopicSpec.builder() - .tags(List.of("TEST1", "test2", "tEST_3", "T_a_g")).build()) - .build(); + .metadata(Metadata.builder().name("ns-topic5").build()) + .spec(Topic.TopicSpec.builder() + .tags(List.of("TEST1", "test2", "tEST_3", "T_a_g")).build()) + .build(); assertEquals(true, topicService.isTagsFormatValid(topicWithMultipleCorrectTags)); } @@ -1029,50 +1029,50 @@ void shouldReturnTrueWhenTagFormatIsValid() { @Test void shouldReturnFalseWhenTagFormatIsInvalid() { Topic topicWithBeginningDigitTag = Topic.builder() - .metadata(Metadata.builder().name("ns-topic1").build()) - .spec(Topic.TopicSpec.builder() - .tags(List.of("0test")).build()) - .build(); + .metadata(Metadata.builder().name("ns-topic1").build()) + .spec(Topic.TopicSpec.builder() + .tags(List.of("0test")).build()) + .build(); assertEquals(false, topicService.isTagsFormatValid(topicWithBeginningDigitTag)); Topic topicWithBeginningUnderscoreTag = Topic.builder() - .metadata(Metadata.builder().name("ns-topic2").build()) - .spec(Topic.TopicSpec.builder() - .tags(List.of("_TEST")).build()) - .build(); + .metadata(Metadata.builder().name("ns-topic2").build()) + .spec(Topic.TopicSpec.builder() + .tags(List.of("_TEST")).build()) + .build(); assertEquals(false, topicService.isTagsFormatValid(topicWithBeginningUnderscoreTag)); Topic topicWithForbiddenCharacterTag = Topic.builder() - .metadata(Metadata.builder().name("ns-topic3").build()) - .spec(Topic.TopicSpec.builder() - .tags(List.of("test-tag")).build()) - .build(); + .metadata(Metadata.builder().name("ns-topic3").build()) + .spec(Topic.TopicSpec.builder() + .tags(List.of("test-tag")).build()) + .build(); assertEquals(false, topicService.isTagsFormatValid(topicWithForbiddenCharacterTag)); Topic topicWithManyForbiddenCharactersTag = Topic.builder() - .metadata(Metadata.builder().name("ns-topic4").build()) - .spec(Topic.TopicSpec.builder() - .tags(List.of("&~#()[]{}-+=*%:.,;!?^°çé")).build()) - .build(); + .metadata(Metadata.builder().name("ns-topic4").build()) + .spec(Topic.TopicSpec.builder() + .tags(List.of("&~#()[]{}-+=*%:.,;!?^°çé")).build()) + .build(); assertEquals(false, topicService.isTagsFormatValid(topicWithManyForbiddenCharactersTag)); Topic topicWithMultipleIncorrectTags = Topic.builder() - .metadata(Metadata.builder().name("ns-topic5").build()) - .spec(Topic.TopicSpec.builder() - .tags(List.of("test-tag", "TEST.tag", "0TEST")).build()) - .build(); + .metadata(Metadata.builder().name("ns-topic5").build()) + .spec(Topic.TopicSpec.builder() + .tags(List.of("test-tag", "TEST.tag", "0TEST")).build()) + .build(); assertEquals(false, topicService.isTagsFormatValid(topicWithMultipleIncorrectTags)); Topic topicWithOneIncorrectAndMultipleCorrectTags = Topic.builder() - .metadata(Metadata.builder().name("ns-topic5").build()) - .spec(Topic.TopicSpec.builder() - .tags(List.of("testTag", "0TEST-tag", "TEST")).build()) - .build(); + .metadata(Metadata.builder().name("ns-topic5").build()) + .spec(Topic.TopicSpec.builder() + .tags(List.of("testTag", "0TEST-tag", "TEST")).build()) + .build(); assertEquals(false, topicService.isTagsFormatValid(topicWithOneIncorrectAndMultipleCorrectTags)); } @@ -1080,26 +1080,26 @@ void shouldReturnFalseWhenTagFormatIsInvalid() { @Test void shouldTagsBeInvalidWhenFormatIsWrong() { Namespace ns = Namespace.builder() - .metadata(Metadata.builder() - .name("namespace") - .cluster("local") - .build()) - .build(); + .metadata(Metadata.builder() + .name("namespace") + .cluster("local") + .build()) + .build(); Topic topic = Topic.builder() - .metadata(Metadata.builder().name("ns-topic1").build()) - .spec(Topic.TopicSpec.builder() - .tags(List.of("0TAG-TEST")).build()) - .build(); + .metadata(Metadata.builder().name("ns-topic1").build()) + .spec(Topic.TopicSpec.builder() + .tags(List.of("0TAG-TEST")).build()) + .build(); when(managedClusterProperties.stream()).thenReturn(Stream.of( - new ManagedClusterProperties("local", ManagedClusterProperties.KafkaProvider.CONFLUENT_CLOUD))); + new ManagedClusterProperties("local", ManagedClusterProperties.KafkaProvider.CONFLUENT_CLOUD))); List validationErrors = topicService.validateTags(ns, topic); assertEquals(1, validationErrors.size()); assertEquals("Invalid value \"0TAG-TEST\" for field \"tags\": " + "tags should start with letter and be followed by alphanumeric or _ characters.", - validationErrors.getFirst()); + validationErrors.getFirst()); } }