Skip to content

Commit

Permalink
BE: RBAC: Add integration test for Active Directory auth
Browse files Browse the repository at this point in the history
  • Loading branch information
wernerdv committed Dec 26, 2024
1 parent bacf1b4 commit 1c358bd
Show file tree
Hide file tree
Showing 3 changed files with 208 additions and 0 deletions.
118 changes: 118 additions & 0 deletions api/src/test/java/io/kafbat/ui/ActiveDirectoryIntegrationTest.java
Original file line number Diff line number Diff line change
@@ -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<UserPermissionDTO> 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<ConfigurableApplicationContext> {
@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);
}
}
}
Original file line number Diff line number Diff line change
@@ -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<ActiveDirectoryContainer> {
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());
}
}
}
15 changes: 15 additions & 0 deletions api/src/test/resources/application-rbac-ad.yml
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit 1c358bd

Please sign in to comment.