From 279e8512e2ae4fcd0fe3b30bb1b4f10753bda718 Mon Sep 17 00:00:00 2001 From: German Osin Date: Wed, 28 May 2025 16:27:41 +0200 Subject: [PATCH] Fix regex tests --- .../java/io/kafbat/ui/model/rbac/Role.java | 3 +- ...exBasedProviderAuthorityExtractorTest.java | 51 ++++++------- .../ui/config/YamlPropertySourceFactory.java | 24 +++++++ .../ui/util/AccessControlServiceMock.java | 13 ++++ .../application-roles-definition.yml | 72 +++++++++++++++++++ api/src/test/resources/roles_definition.yaml | 67 ----------------- 6 files changed, 134 insertions(+), 96 deletions(-) create mode 100644 api/src/test/java/io/kafbat/ui/config/YamlPropertySourceFactory.java create mode 100644 api/src/test/resources/application-roles-definition.yml delete mode 100644 api/src/test/resources/roles_definition.yaml diff --git a/api/src/main/java/io/kafbat/ui/model/rbac/Role.java b/api/src/main/java/io/kafbat/ui/model/rbac/Role.java index 20eec030d..068b46625 100644 --- a/api/src/main/java/io/kafbat/ui/model/rbac/Role.java +++ b/api/src/main/java/io/kafbat/ui/model/rbac/Role.java @@ -2,6 +2,7 @@ import static com.google.common.base.Preconditions.checkArgument; +import java.util.ArrayList; import java.util.List; import lombok.Data; @@ -11,7 +12,7 @@ public class Role { String name; List clusters; List subjects; - List permissions; + List permissions = new ArrayList<>(); public void validate() { checkArgument(clusters != null && !clusters.isEmpty(), "Role clusters cannot be empty"); diff --git a/api/src/test/java/io/kafbat/ui/config/RegexBasedProviderAuthorityExtractorTest.java b/api/src/test/java/io/kafbat/ui/config/RegexBasedProviderAuthorityExtractorTest.java index 11eec0ea4..13b9fe03b 100644 --- a/api/src/test/java/io/kafbat/ui/config/RegexBasedProviderAuthorityExtractorTest.java +++ b/api/src/test/java/io/kafbat/ui/config/RegexBasedProviderAuthorityExtractorTest.java @@ -4,14 +4,10 @@ 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 static org.mockito.Mockito.when; import static org.springframework.security.oauth2.client.registration.ClientRegistration.withRegistrationId; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; -import com.fasterxml.jackson.dataformat.yaml.YAMLMapper; import io.kafbat.ui.config.auth.OAuthProperties; -import io.kafbat.ui.model.rbac.Role; +import io.kafbat.ui.config.auth.RoleBasedAccessControlProperties; import io.kafbat.ui.service.rbac.AccessControlService; import io.kafbat.ui.service.rbac.extractor.CognitoAuthorityExtractor; import io.kafbat.ui.service.rbac.extractor.GithubAuthorityExtractor; @@ -19,8 +15,6 @@ import io.kafbat.ui.service.rbac.extractor.OauthAuthorityExtractor; import io.kafbat.ui.service.rbac.extractor.ProviderAuthorityExtractor; import io.kafbat.ui.util.AccessControlServiceMock; -import java.io.IOException; -import java.io.InputStream; import java.time.Instant; import java.time.temporal.ChronoUnit; import java.util.HashMap; @@ -30,39 +24,40 @@ import lombok.SneakyThrows; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.security.core.authority.AuthorityUtils; import org.springframework.security.oauth2.client.userinfo.OAuth2UserRequest; import org.springframework.security.oauth2.core.AuthorizationGrantType; import org.springframework.security.oauth2.core.OAuth2AccessToken; import org.springframework.security.oauth2.core.user.DefaultOAuth2User; import org.springframework.security.oauth2.core.user.OAuth2User; - +import org.springframework.test.context.TestPropertySource; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +@ExtendWith(SpringExtension.class) +@EnableConfigurationProperties(RoleBasedAccessControlProperties.class) +@TestPropertySource( + locations = "classpath:application-roles-definition.yml", + factory = YamlPropertySourceFactory.class +) public class RegexBasedProviderAuthorityExtractorTest { - - private final AccessControlService accessControlService = new AccessControlServiceMock().getMock(); - ProviderAuthorityExtractor extractor; + @Autowired + private RoleBasedAccessControlProperties properties; + private AccessControlService accessControlService; @BeforeEach - void setUp() throws IOException { - - YAMLMapper mapper = new YAMLMapper(); - - InputStream rolesFile = this.getClass() - .getClassLoader() - .getResourceAsStream("roles_definition.yaml"); - - Role[] roles = mapper.readValue(rolesFile, Role[].class); - - when(accessControlService.getRoles()).thenReturn(List.of(roles)); - + public void configure() { + this.accessControlService = new AccessControlServiceMock(properties.getRoles()).getMock(); } @SneakyThrows @Test void extractOauth2Authorities() { - extractor = new OauthAuthorityExtractor(); + ProviderAuthorityExtractor extractor = new OauthAuthorityExtractor(); OAuth2User oauth2User = new DefaultOAuth2User( AuthorityUtils.createAuthorityList("SCOPE_message:read"), @@ -86,7 +81,7 @@ void extractOauth2Authorities() { @Test() void extractOauth2Authorities_blankEmail() { - extractor = new OauthAuthorityExtractor(); + ProviderAuthorityExtractor extractor = new OauthAuthorityExtractor(); OAuth2User oauth2User = new DefaultOAuth2User( AuthorityUtils.createAuthorityList("SCOPE_message:read"), @@ -110,7 +105,7 @@ void extractOauth2Authorities_blankEmail() { @Test void extractCognitoAuthorities() { - extractor = new CognitoAuthorityExtractor(); + ProviderAuthorityExtractor extractor = new CognitoAuthorityExtractor(); OAuth2User oauth2User = new DefaultOAuth2User( AuthorityUtils.createAuthorityList("SCOPE_message:read"), @@ -135,7 +130,7 @@ void extractCognitoAuthorities() { @Test void extractGithubAuthorities() { - extractor = new GithubAuthorityExtractor(); + ProviderAuthorityExtractor extractor = new GithubAuthorityExtractor(); OAuth2User oauth2User = new DefaultOAuth2User( AuthorityUtils.createAuthorityList("SCOPE_message:read"), @@ -172,7 +167,7 @@ void extractGithubAuthorities() { @Test void extractGoogleAuthorities() { - extractor = new GoogleAuthorityExtractor(); + ProviderAuthorityExtractor extractor = new GoogleAuthorityExtractor(); OAuth2User oauth2User = new DefaultOAuth2User( AuthorityUtils.createAuthorityList("SCOPE_message:read"), diff --git a/api/src/test/java/io/kafbat/ui/config/YamlPropertySourceFactory.java b/api/src/test/java/io/kafbat/ui/config/YamlPropertySourceFactory.java new file mode 100644 index 000000000..d9f84433a --- /dev/null +++ b/api/src/test/java/io/kafbat/ui/config/YamlPropertySourceFactory.java @@ -0,0 +1,24 @@ +package io.kafbat.ui.config; + +import java.io.IOException; +import java.util.List; +import org.jetbrains.annotations.NotNull; +import org.springframework.boot.env.YamlPropertySourceLoader; +import org.springframework.core.env.PropertySource; +import org.springframework.core.io.support.EncodedResource; +import org.springframework.core.io.support.PropertySourceFactory; + +public class YamlPropertySourceFactory implements PropertySourceFactory { + private final YamlPropertySourceLoader loader = new YamlPropertySourceLoader(); + + @Override + public @NotNull PropertySource createPropertySource(String name, EncodedResource resource) + throws IOException { + List> loaded = loader.load(name, resource.getResource()); + if (loaded.size() == 1) { + return loaded.getFirst(); + } else { + throw new IOException(resource.getResource().getFilename()); + } + } +} diff --git a/api/src/test/java/io/kafbat/ui/util/AccessControlServiceMock.java b/api/src/test/java/io/kafbat/ui/util/AccessControlServiceMock.java index f1a6417d0..1059cc6af 100644 --- a/api/src/test/java/io/kafbat/ui/util/AccessControlServiceMock.java +++ b/api/src/test/java/io/kafbat/ui/util/AccessControlServiceMock.java @@ -4,11 +4,23 @@ import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.when; +import io.kafbat.ui.model.rbac.Role; import io.kafbat.ui.service.rbac.AccessControlService; +import java.util.List; import org.mockito.Mockito; import reactor.core.publisher.Mono; public class AccessControlServiceMock { + private final List roles; + + public AccessControlServiceMock(List roles) { + this.roles = roles; + } + + public AccessControlServiceMock() { + this(List.of()); + } + public AccessControlService getMock() { AccessControlService mock = Mockito.mock(AccessControlService.class); @@ -17,6 +29,7 @@ public AccessControlService getMock() { when(mock.isSchemaAccessible(anyString(), anyString())).thenReturn(Mono.just(true)); when(mock.filterViewableTopics(any(), any())).then(invocation -> Mono.just(invocation.getArgument(0))); + when(mock.getRoles()).thenReturn(roles); return mock; } diff --git a/api/src/test/resources/application-roles-definition.yml b/api/src/test/resources/application-roles-definition.yml new file mode 100644 index 000000000..8c641de00 --- /dev/null +++ b/api/src/test/resources/application-roles-definition.yml @@ -0,0 +1,72 @@ +rbac: + roles: + - name: 'admin' + subjects: + - provider: 'OAUTH' + value: 'ROLE-[A-Z]+' + type: 'role' + regex: 'true' + - provider: 'OAUTH_COGNITO' + value: 'ROLE-ADMIN' + type: 'group' + - provider: 'OAUTH_GOOGLE' + type: 'domain' + value: 'memelord.lol' + clusters: + - local + - remote + permissions: + - resource: APPLICATIONCONFIG + actions: [ all ] + - name: 'viewer' + subjects: + - provider: 'LDAP' + value: 'CS-XXX' + type: 'kafka-viewer' + - provider: 'OAUTH' + value: '.*@kafka.com' + type: 'user' + regex: 'true' + - provider: 'OAUTH_COGNITO' + value: '.*@kafka.com' + type: 'user' + regex: 'true' + - provider: 'OAUTH_GITHUB' + value: '.*@kafka.com' + type: 'user' + regex: 'true' + - provider: 'OAUTH_GOOGLE' + value: 'john@kafka.com' + type: 'user' + clusters: + - remote + permissions: + - resource: APPLICATIONCONFIG + actions: [ all ] + - name: 'editor' + subjects: + - provider: 'OAUTH' + value: 'ROLE_EDITOR' + type: 'role' + clusters: + - local + permissions: + - resource: APPLICATIONCONFIG + actions: [ all ] + - name: "no one's role" + clusters: + - local + - remote + subjects: + - provider: 'OAUTH' + value: '.*XXX' + type: 'role' + - provider: 'OAUTH_GITHUB' + value: '.*XXX' + type: 'user' + - provider: 'OAUTH_COGNITO' + value: '.*XXX' + type: 'user' + - provider: 'OAUTH_GOOGLE' + value: '.*XXX' + type: 'domain' diff --git a/api/src/test/resources/roles_definition.yaml b/api/src/test/resources/roles_definition.yaml deleted file mode 100644 index f9af4f507..000000000 --- a/api/src/test/resources/roles_definition.yaml +++ /dev/null @@ -1,67 +0,0 @@ -- name: 'admin' - subjects: - - provider: 'OAUTH' - value: 'ROLE-[A-Z]+' - type: 'role' - isRegex: 'true' - - provider: 'OAUTH_COGNITO' - value: 'ROLE-ADMIN' - type: 'group' - - provider: 'OAUTH_GOOGLE' - type: 'domain' - value: 'memelord.lol' - clusters: - - local - - remote - permissions: - - resource: APPLICATIONCONFIG - actions: [ all ] -- name: 'viewer' - subjects: - - provider: 'LDAP' - value: 'CS-XXX' - type: 'kafka-viewer' - - provider: 'OAUTH' - value: '.*@kafka.com' - type: 'user' - isRegex: 'true' - - provider: 'OAUTH_COGNITO' - value: '.*@kafka.com' - type: 'user' - isRegex: 'true' - - provider: 'OAUTH_GITHUB' - value: '.*@kafka.com' - type: 'user' - isRegex: 'true' - - provider: 'OAUTH_GOOGLE' - value: 'john@kafka.com' - type: 'user' - clusters: - - remote - permissions: - - resource: APPLICATIONCONFIG - actions: [ all ] -- name: 'editor' - subjects: - - provider: 'OAUTH' - value: 'ROLE_EDITOR' - type: 'role' - clusters: - - local - permissions: - - resource: APPLICATIONCONFIG - actions: [ all ] -- name: "no one's role" - subjects: - - provider: 'OAUTH' - value: '.*XXX' - type: 'role' - - provider: 'OAUTH_GITHUB' - value: '.*XXX' - type: 'user' - - provider: 'OAUTH_COGNITO' - value: '.*XXX' - type: 'user' - - provider: 'OAUTH_GOOGLE' - value: '.*XXX' - type: 'domain'