From 1c358bde18b7bb5920693af91ddd61e57225e106 Mon Sep 17 00:00:00 2001 From: Dmitry Werner Date: Thu, 26 Dec 2024 23:11:58 +0500 Subject: [PATCH] BE: RBAC: Add integration test for Active Directory auth --- .../ui/ActiveDirectoryIntegrationTest.java | 118 ++++++++++++++++++ .../container/ActiveDirectoryContainer.java | 75 +++++++++++ .../test/resources/application-rbac-ad.yml | 15 +++ 3 files changed, 208 insertions(+) create mode 100644 api/src/test/java/io/kafbat/ui/ActiveDirectoryIntegrationTest.java create mode 100644 api/src/test/java/io/kafbat/ui/container/ActiveDirectoryContainer.java create mode 100644 api/src/test/resources/application-rbac-ad.yml diff --git a/api/src/test/java/io/kafbat/ui/ActiveDirectoryIntegrationTest.java b/api/src/test/java/io/kafbat/ui/ActiveDirectoryIntegrationTest.java new file mode 100644 index 000000000..f95c554ea --- /dev/null +++ b/api/src/test/java/io/kafbat/ui/ActiveDirectoryIntegrationTest.java @@ -0,0 +1,118 @@ +package io.kafbat.ui; + +import static io.kafbat.ui.AbstractIntegrationTest.LOCAL; +import static io.kafbat.ui.container.ActiveDirectoryContainer.DOMAIN; +import static io.kafbat.ui.container.ActiveDirectoryContainer.FIRST_USER_WITH_GROUP; +import static io.kafbat.ui.container.ActiveDirectoryContainer.PASSWORD; +import static io.kafbat.ui.container.ActiveDirectoryContainer.SECOND_USER_WITH_GROUP; +import static io.kafbat.ui.container.ActiveDirectoryContainer.USER_WITHOUT_GROUP; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import io.kafbat.ui.container.ActiveDirectoryContainer; +import io.kafbat.ui.model.AuthenticationInfoDTO; +import io.kafbat.ui.model.ResourceTypeDTO; +import io.kafbat.ui.model.UserPermissionDTO; +import java.util.List; +import java.util.Objects; +import org.jetbrains.annotations.NotNull; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.ApplicationContextInitializer; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.http.MediaType; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.web.reactive.server.WebTestClient; +import org.springframework.web.reactive.function.BodyInserters; + +@SpringBootTest +@ActiveProfiles("rbac-ad") +@AutoConfigureWebTestClient(timeout = "60000") +@ContextConfiguration(initializers = {ActiveDirectoryIntegrationTest.Initializer.class}) +public class ActiveDirectoryIntegrationTest { + private static final String SESSION = "SESSION"; + + private static final ActiveDirectoryContainer ACTIVE_DIRECTORY = new ActiveDirectoryContainer(); + + @Autowired + private WebTestClient webTestClient; + + @BeforeAll + public static void setup() { + ACTIVE_DIRECTORY.start(); + } + + @AfterAll + public static void shutdown() { + ACTIVE_DIRECTORY.stop(); + } + + @Test + public void testUserPermissions() { + AuthenticationInfoDTO info = authenticationInfo(FIRST_USER_WITH_GROUP); + + assertNotNull(info); + assertTrue(info.getRbacEnabled()); + + List permissions = info.getUserInfo().getPermissions(); + + assertFalse(permissions.isEmpty()); + assertTrue(permissions.stream().anyMatch(permission -> + permission.getClusters().contains(LOCAL) && permission.getResource() == ResourceTypeDTO.TOPIC)); + assertEquals(permissions, authenticationInfo(SECOND_USER_WITH_GROUP).getUserInfo().getPermissions()); + } + + @Test + public void testEmptyPermissions() { + assertTrue(Objects.requireNonNull(authenticationInfo(USER_WITHOUT_GROUP)) + .getUserInfo() + .getPermissions() + .isEmpty() + ); + } + + private String session(String name) { + return Objects.requireNonNull( + webTestClient + .post() + .uri("/login") + .contentType(MediaType.APPLICATION_FORM_URLENCODED) + .body(BodyInserters.fromFormData("username", name).with("password", PASSWORD)) + .exchange() + .expectStatus() + .isFound() + .returnResult(String.class) + .getResponseCookies() + .getFirst(SESSION)) + .getValue(); + } + + private AuthenticationInfoDTO authenticationInfo(String name) { + return webTestClient + .get() + .uri("/api/authorization") + .cookie(SESSION, session(name)) + .exchange() + .expectStatus() + .isOk() + .returnResult(AuthenticationInfoDTO.class) + .getResponseBody() + .blockFirst(); + } + + public static class Initializer implements ApplicationContextInitializer { + @Override + public void initialize(@NotNull ConfigurableApplicationContext context) { + System.setProperty("spring.ldap.urls", ACTIVE_DIRECTORY.getLdapUrl()); + System.setProperty("oauth2.ldap.activeDirectory", "true"); + System.setProperty("oauth2.ldap.activeDirectory.domain", DOMAIN); + } + } +} diff --git a/api/src/test/java/io/kafbat/ui/container/ActiveDirectoryContainer.java b/api/src/test/java/io/kafbat/ui/container/ActiveDirectoryContainer.java new file mode 100644 index 000000000..8181229e2 --- /dev/null +++ b/api/src/test/java/io/kafbat/ui/container/ActiveDirectoryContainer.java @@ -0,0 +1,75 @@ +package io.kafbat.ui.container; + +import com.github.dockerjava.api.command.InspectContainerResponse; +import java.io.IOException; +import lombok.extern.slf4j.Slf4j; +import org.testcontainers.containers.GenericContainer; +import org.testcontainers.utility.DockerImageName; + +@Slf4j +public class ActiveDirectoryContainer extends GenericContainer { + public static final String DOMAIN = "corp.kafbat.io"; + public static final String PASSWORD = "StrongPassword123"; + public static final String FIRST_USER_WITH_GROUP = "JohnDoe"; + public static final String SECOND_USER_WITH_GROUP = "JohnWick"; + public static final String USER_WITHOUT_GROUP = "JackSmith"; + + private static final String DOMAIN_DC = "dc=corp,dc=kafbat,dc=io"; + private static final String GROUP = "group"; + private static final String TEST_GROUP = "test-AD-Group"; + private static final String DOMAIN_EMAIL = "kafbat.io"; + private static final String SAMBA_TOOL = "samba-tool"; + private static final int LDAP_PORT = 389; + private static final DockerImageName IMAGE_NAME = DockerImageName.parse("nowsci/samba-domain:latest"); + + public ActiveDirectoryContainer() { + super(IMAGE_NAME); + + withExposedPorts(LDAP_PORT); + + withEnv("DOMAIN", DOMAIN); + withEnv("DOMAIN_DC", DOMAIN_DC); + withEnv("DOMAIN_EMAIL", DOMAIN_EMAIL); + withEnv("DOMAINPASS", PASSWORD); + withEnv("NOCOMPLEXITY", "true"); + withEnv("INSECURELDAP", "true"); + + withPrivilegedMode(true); + } + + protected void containerIsStarted(InspectContainerResponse containerInfo) { + createUser(USER_WITHOUT_GROUP); + createUser(FIRST_USER_WITH_GROUP); + createUser(SECOND_USER_WITH_GROUP); + + exec(SAMBA_TOOL, GROUP, "add", TEST_GROUP); + exec(SAMBA_TOOL, GROUP, "addmembers", TEST_GROUP, FIRST_USER_WITH_GROUP); + exec(SAMBA_TOOL, GROUP, "addmembers", TEST_GROUP, SECOND_USER_WITH_GROUP); + } + + public String getLdapUrl() { + return String.format("ldap://%s:%s", getHost(), getMappedPort(LDAP_PORT)); + } + + private void createUser(String name) { + exec(SAMBA_TOOL, "user", "create", name, PASSWORD, "--mail-address", name + '@' + DOMAIN_EMAIL); + exec(SAMBA_TOOL, "user", "setexpiry", name, "--noexpiry"); + } + + private void exec(String... cmd) { + ExecResult result; + try { + result = execInContainer(cmd); + } catch (IOException | InterruptedException e) { + throw new RuntimeException(e); + } + + if (result.getStdout() != null && !result.getStdout().isEmpty()) { + log.info("Output: {}", result.getStdout()); + } + + if (result.getExitCode() != 0) { + throw new IllegalStateException(result.toString()); + } + } +} diff --git a/api/src/test/resources/application-rbac-ad.yml b/api/src/test/resources/application-rbac-ad.yml new file mode 100644 index 000000000..920de3a16 --- /dev/null +++ b/api/src/test/resources/application-rbac-ad.yml @@ -0,0 +1,15 @@ +auth: + type: LDAP +rbac: + roles: + - name: "test-AD-Group" + clusters: + - local + subjects: + - provider: ldap_ad + permissions: + - resource: applicationconfig + actions: all + - resource: topic + value: ".*" + actions: all