From 319cf6b81a3fb0f863f3e0be7d13d6ac0f7f432d Mon Sep 17 00:00:00 2001 From: Thomas CAI <92149044+ThomasCAI-mlv@users.noreply.github.com> Date: Tue, 14 Jan 2025 11:59:28 +0100 Subject: [PATCH] Improve JWT format with namespaces grouping (#500) --- .../resources/admin/another-namespace2.yml | 147 ++++++++++++++++++ README.md | 10 +- .../security/ResourceBasedSecurityRule.java | 10 +- .../auth/AuthenticationRoleBinding.java | 2 +- .../security/auth/AuthenticationService.java | 25 ++- .../ResourceBasedSecurityRuleTest.java | 55 ++++++- .../security/auth/AuthenticationInfoTest.java | 12 +- .../auth/AuthenticationServiceTest.java | 109 +++++++++++-- .../GitlabAuthenticationProviderTest.java | 4 +- .../ldap/LdapAuthenticationMapperTest.java | 2 +- .../LocalUserAuthenticationProviderTest.java | 2 +- 11 files changed, 328 insertions(+), 50 deletions(-) create mode 100644 .docker/resources/admin/another-namespace2.yml diff --git a/.docker/resources/admin/another-namespace2.yml b/.docker/resources/admin/another-namespace2.yml new file mode 100644 index 00000000..a26c9d36 --- /dev/null +++ b/.docker/resources/admin/another-namespace2.yml @@ -0,0 +1,147 @@ +--- +apiVersion: v1 +kind: Namespace +metadata: + name: anotherNamespace + cluster: local + labels: + contacts: namespace.owner@example.com +spec: + kafkaUser: user2 + connectClusters: + - local + topicValidator: + validationConstraints: + partitions: + validation-type: Range + min: 1 + max: 6 + replication.factor: + validation-type: Range + min: 1 + max: 1 + min.insync.replicas: + validation-type: Range + min: 1 + max: 1 + retention.ms: + optional: true + validation-type: Range + min: 60000 + max: 604800000 + cleanup.policy: + validation-type: ValidList + validStrings: + - delete + - compact + connectValidator: + validationConstraints: + key.converter: + validation-type: NonEmptyString + value.converter: + validation-type: NonEmptyString + connector.class: + validation-type: ValidString + validStrings: + - io.confluent.connect.jdbc.JdbcSinkConnector + - io.confluent.connect.jdbc.JdbcSourceConnector + - io.confluent.kafka.connect.datagen.DatagenConnector + classValidationConstraints: + io.confluent.kafka.connect.datagen.DatagenConnector: + schema.string: + validation-type: NonEmptyString + schema.keyfield: + validation-type: NonEmptyString +--- +apiVersion: v1 +kind: RoleBinding +metadata: + name: anotherRoleBinding1 + namespace: anotherNamespace +spec: + role: + resourceTypes: + - schemas + - schemas/config + - topics + - topics/import + - topics/delete-records + - connectors + - connectors/import + - connectors/change-state + - connect-clusters + - connect-clusters/vaults + - acls + - consumer-groups/reset + - streams + verbs: + - GET + - POST + - PUT + - DELETE + subject: + subjectType: GROUP + subjectName: DEV +--- +apiVersion: v1 +kind: RoleBinding +metadata: + name: anotherRoleBinding2 + namespace: anotherNamespace +spec: + role: + resourceTypes: + - quota + verbs: + - GET + subject: + subjectType: GROUP + subjectName: DEV +--- +apiVersion: v1 +kind: AccessControlEntry +metadata: + name: anotherTopicAcl + namespace: anotherNamespace +spec: + resourceType: TOPIC + resource: def. + resourcePatternType: PREFIXED + permission: OWNER + grantedTo: anotherNamespace +--- +apiVersion: v1 +kind: AccessControlEntry +metadata: + name: anotherGroupAcl + namespace: anotherNamespace +spec: + resourceType: GROUP + resource: def. + resourcePatternType: PREFIXED + permission: OWNER + grantedTo: anotherNamespace +--- +apiVersion: v1 +kind: AccessControlEntry +metadata: + name: anotherConnectAcl + namespace: anotherNamespace +spec: + resourceType: CONNECT + resource: def. + resourcePatternType: PREFIXED + permission: OWNER + grantedTo: anotherNamespace +--- +apiVersion: v1 +kind: AccessControlEntry +metadata: + name: anotherConnectClusterAcl + namespace: anotherNamespace +spec: + resourceType: CONNECT_CLUSTER + resource: def. + resourcePatternType: PREFIXED + permission: OWNER + grantedTo: anotherNamespace \ No newline at end of file diff --git a/README.md b/README.md index beaa875f..91ad9257 100644 --- a/README.md +++ b/README.md @@ -154,7 +154,7 @@ The delivered JWT token will have the following format: { "roleBindings": [ { - "namespace": "myNamespace", + "namespaces": ["myNamespace"], "verbs": [ "GET", "POST", @@ -165,16 +165,14 @@ The delivered JWT token will have the following format: "schemas", "schemas/config", "topics", - "topics/import", "topics/delete-records", "connectors", - "connectors/import", "connectors/change-state", - "connect-clusters", - "connect-clusters/vaults", "acls", "consumer-groups/reset", - "streams" + "streams", + "connect-clusters", + "connect-clusters/vaults" ] } ], diff --git a/src/main/java/com/michelin/ns4kafka/security/ResourceBasedSecurityRule.java b/src/main/java/com/michelin/ns4kafka/security/ResourceBasedSecurityRule.java index 110884cf..9cf14810 100644 --- a/src/main/java/com/michelin/ns4kafka/security/ResourceBasedSecurityRule.java +++ b/src/main/java/com/michelin/ns4kafka/security/ResourceBasedSecurityRule.java @@ -5,7 +5,6 @@ import com.michelin.ns4kafka.model.RoleBinding; import com.michelin.ns4kafka.property.SecurityProperties; import com.michelin.ns4kafka.repository.NamespaceRepository; -import com.michelin.ns4kafka.repository.RoleBindingRepository; import com.michelin.ns4kafka.security.auth.AuthenticationInfo; import com.michelin.ns4kafka.security.auth.AuthenticationRoleBinding; import com.michelin.ns4kafka.util.exception.ForbiddenNamespaceException; @@ -44,9 +43,6 @@ public class ResourceBasedSecurityRule implements SecurityRule> { @Inject SecurityProperties securityProperties; - @Inject - RoleBindingRepository roleBindingRepository; - @Inject NamespaceRepository namespaceRepository; @@ -107,10 +103,12 @@ public SecurityRuleResult checkSecurity(HttpRequest request, @Nullable Authen AuthenticationInfo authenticationInfo = AuthenticationInfo.of(authentication); - // No role binding for the target namespace. User is targeting a namespace that he is not allowed to access + // No role binding for the target namespace: the user is not allowed to access the target namespace List namespaceRoleBindings = authenticationInfo.getRoleBindings() .stream() - .filter(roleBinding -> roleBinding.getNamespace().equals(namespace)) + .filter(roleBinding -> roleBinding.getNamespaces() + .stream() + .anyMatch(ns -> ns.equals(namespace))) .toList(); if (namespaceRoleBindings.isEmpty()) { diff --git a/src/main/java/com/michelin/ns4kafka/security/auth/AuthenticationRoleBinding.java b/src/main/java/com/michelin/ns4kafka/security/auth/AuthenticationRoleBinding.java index d5b853af..7fc19b93 100644 --- a/src/main/java/com/michelin/ns4kafka/security/auth/AuthenticationRoleBinding.java +++ b/src/main/java/com/michelin/ns4kafka/security/auth/AuthenticationRoleBinding.java @@ -15,7 +15,7 @@ @NoArgsConstructor @AllArgsConstructor public class AuthenticationRoleBinding { - private String namespace; + private List namespaces; private List verbs; private List resourceTypes; } diff --git a/src/main/java/com/michelin/ns4kafka/security/auth/AuthenticationService.java b/src/main/java/com/michelin/ns4kafka/security/auth/AuthenticationService.java index 4417d6e6..9da7968c 100644 --- a/src/main/java/com/michelin/ns4kafka/security/auth/AuthenticationService.java +++ b/src/main/java/com/michelin/ns4kafka/security/auth/AuthenticationService.java @@ -14,6 +14,7 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.stream.Collectors; import lombok.extern.slf4j.Slf4j; /** @@ -23,7 +24,6 @@ @Singleton public class AuthenticationService { - @Inject ResourceBasedSecurityRule resourceBasedSecurityRule; @@ -47,14 +47,25 @@ public AuthenticationResponse buildAuthJwtGroups(String username, List g throw new AuthenticationException(new AuthenticationFailed("No namespace matches your groups")); } - return AuthenticationResponse.success(username, resourceBasedSecurityRule.computeRolesFromGroups(groups), + return AuthenticationResponse.success( + username, + resourceBasedSecurityRule.computeRolesFromGroups(groups), Map.of(ROLE_BINDINGS, roleBindings .stream() - .map(roleBinding -> AuthenticationRoleBinding.builder() - .namespace(roleBinding.getMetadata().getNamespace()) - .verbs(new ArrayList<>(roleBinding.getSpec().getRole().getVerbs())) - .resourceTypes(new ArrayList<>(roleBinding.getSpec().getRole().getResourceTypes())) + // group the namespaces by roles in a mapping + .collect(Collectors.groupingBy( + roleBinding -> roleBinding.getSpec().getRole(), + Collectors.mapping(roleBinding -> roleBinding.getMetadata().getNamespace(), Collectors.toList()) + )) + // build JWT with a list of namespaces for each different role + .entrySet() + .stream() + .map(entry -> AuthenticationRoleBinding.builder() + .namespaces(entry.getValue()) + .verbs(new ArrayList<>(entry.getKey().getVerbs())) + .resourceTypes(new ArrayList<>(entry.getKey().getResourceTypes())) .build()) - .toList())); + .toList()) + ); } } diff --git a/src/test/java/com/michelin/ns4kafka/security/ResourceBasedSecurityRuleTest.java b/src/test/java/com/michelin/ns4kafka/security/ResourceBasedSecurityRuleTest.java index 8404920f..67ac11a9 100644 --- a/src/test/java/com/michelin/ns4kafka/security/ResourceBasedSecurityRuleTest.java +++ b/src/test/java/com/michelin/ns4kafka/security/ResourceBasedSecurityRuleTest.java @@ -31,7 +31,7 @@ @ExtendWith(MockitoExtension.class) class ResourceBasedSecurityRuleTest { - private static final String NAMESPACE = "namespace"; + private static final String NAMESPACES = "namespaces"; private static final String VERBS = "verbs"; private static final String RESOURCE_TYPES = "resourceTypes"; @@ -133,7 +133,7 @@ void checkReturnsAllowedNamespaceAsAdmin() { "topics,/api/namespaces/test/topics/topic.with.dots"}) void shouldReturnAllowedWhenHyphenAndDotResourcesAndHandleRoleBindingsType(String resourceType, String path) { List> jwtRoleBindings = List.of( - Map.of(NAMESPACE, "test", + Map.of(NAMESPACES, List.of("test"), VERBS, List.of(GET), RESOURCE_TYPES, List.of(resourceType))); @@ -148,7 +148,7 @@ void shouldReturnAllowedWhenHyphenAndDotResourcesAndHandleRoleBindingsType(Strin List basicAuthRoleBindings = List.of( AuthenticationRoleBinding.builder() - .namespace("test") + .namespaces(List.of("test")) .verbs(List.of(GET)) .resourceTypes(List.of(resourceType)) .build()); @@ -167,7 +167,7 @@ void shouldReturnAllowedWhenHyphenAndDotResourcesAndHandleRoleBindingsType(Strin @Test void shouldReturnAllowedWhenSubResource() { List> jwtRoleBindings = List.of( - Map.of(NAMESPACE, "test", + Map.of(NAMESPACES, List.of("test"), VERBS, List.of(GET), RESOURCE_TYPES, List.of("connectors/restart", "topics/delete-records"))); @@ -192,7 +192,7 @@ void shouldReturnAllowedWhenSubResource() { @CsvSource({"namespace", "name-space", "name.space", "_name_space_", "namespace123"}) void shouldReturnAllowedWhenSpecialNamespaceName(String namespace) { List> roleBindings = List.of( - Map.of(NAMESPACE, namespace, + Map.of(NAMESPACES, List.of(namespace), VERBS, List.of(GET), RESOURCE_TYPES, List.of("topics"))); @@ -207,6 +207,45 @@ void shouldReturnAllowedWhenSpecialNamespaceName(String namespace) { assertEquals(SecurityRuleResult.ALLOWED, actual); } + @Test + void shouldReturnAllowedWhenMultipleNamespaces() { + List> roleBindings = List.of( + Map.of(NAMESPACES, List.of("ns1", "ns2", "ns3"), + VERBS, List.of(GET), + RESOURCE_TYPES, List.of("topics"))); + + Map claims = Map.of(SUBJECT, "user", ROLES, List.of(), ROLE_BINDINGS, roleBindings); + Authentication auth = Authentication.build("user", claims); + + when(namespaceRepository.findByName("ns3")) + .thenReturn(Optional.of(Namespace.builder().build())); + + SecurityRuleResult actual = + resourceBasedSecurityRule.checkSecurity(HttpRequest.GET("/api/namespaces/ns3/topics"), auth); + assertEquals(SecurityRuleResult.ALLOWED, actual); + } + + @Test + void shouldReturnAllowedWhenMultipleVerbsResourceTypesCombinations() { + List> roleBindings = List.of( + Map.of(NAMESPACES, List.of("ns1"), + VERBS, List.of(GET), + RESOURCE_TYPES, List.of("topics")), + Map.of(NAMESPACES, List.of("ns2"), + VERBS, List.of(GET), + RESOURCE_TYPES, List.of("connectors"))); + + Map claims = Map.of(SUBJECT, "user", ROLES, List.of(), ROLE_BINDINGS, roleBindings); + Authentication auth = Authentication.build("user", claims); + + when(namespaceRepository.findByName("ns2")) + .thenReturn(Optional.of(Namespace.builder().build())); + + SecurityRuleResult actual = + resourceBasedSecurityRule.checkSecurity(HttpRequest.GET("/api/namespaces/ns2/connectors"), auth); + assertEquals(SecurityRuleResult.ALLOWED, actual); + } + @Test void shouldReturnForbiddenNamespaceWhenNoRoleBinding() { Map claims = Map.of(SUBJECT, "user", ROLES, List.of(), ROLE_BINDINGS, List.of()); @@ -226,7 +265,7 @@ void shouldReturnForbiddenNamespaceWhenNoRoleBinding() { @Test void shouldReturnForbiddenNamespaceWhenNoRoleBindingMatchingRequestedNamespace() { List> roleBindings = List.of( - Map.of(NAMESPACE, "namespace", + Map.of(NAMESPACES, List.of("namespace"), VERBS, List.of(GET), RESOURCE_TYPES, List.of("connectors"))); @@ -247,7 +286,7 @@ void shouldReturnForbiddenNamespaceWhenNoRoleBindingMatchingRequestedNamespace() @Test void checkReturnsUnknownSubResource() { List> roleBindings = List.of( - Map.of(NAMESPACE, "test", + Map.of(NAMESPACES, List.of("test"), VERBS, List.of(GET), RESOURCE_TYPES, List.of("connectors"))); @@ -266,7 +305,7 @@ void checkReturnsUnknownSubResource() { @Test void checkReturnsUnknownSubResourceWithDot() { List> roleBindings = List.of( - Map.of(NAMESPACE, "test", + Map.of(NAMESPACES, List.of("test"), VERBS, List.of(GET), RESOURCE_TYPES, List.of("connectors"))); diff --git a/src/test/java/com/michelin/ns4kafka/security/auth/AuthenticationInfoTest.java b/src/test/java/com/michelin/ns4kafka/security/auth/AuthenticationInfoTest.java index 4c0208a8..880a7419 100644 --- a/src/test/java/com/michelin/ns4kafka/security/auth/AuthenticationInfoTest.java +++ b/src/test/java/com/michelin/ns4kafka/security/auth/AuthenticationInfoTest.java @@ -19,7 +19,7 @@ class AuthenticationInfoTest { @Test void shouldConvertFromMapRoleBindingsType() { Map attributes = new HashMap<>(); - attributes.put(ROLE_BINDINGS, List.of(Map.of("namespace", "namespace", + attributes.put(ROLE_BINDINGS, List.of(Map.of("namespaces", List.of("namespace"), "verbs", List.of("GET"), "resourceTypes", List.of("topics")))); Authentication authentication = Authentication.build("name", List.of("role"), attributes); @@ -28,14 +28,14 @@ void shouldConvertFromMapRoleBindingsType() { assertEquals("name", authenticationInfo.getName()); assertEquals(List.of("role"), authenticationInfo.getRoles().stream().toList()); - assertIterableEquals(List.of(new AuthenticationRoleBinding("namespace", List.of(GET), List.of("topics"))), - authenticationInfo.getRoleBindings().stream().toList()); + assertIterableEquals(List.of(new AuthenticationRoleBinding(List.of("namespace"), List.of(GET), + List.of("topics"))), authenticationInfo.getRoleBindings().stream().toList()); } @Test void shouldConvertFromAuthenticationRoleBindingsType() { Map attributes = new HashMap<>(); - attributes.put(ROLE_BINDINGS, List.of(new AuthenticationRoleBinding("namespace", List.of(GET), + attributes.put(ROLE_BINDINGS, List.of(new AuthenticationRoleBinding(List.of("namespace"), List.of(GET), List.of("topics")))); Authentication authentication = Authentication.build("name", List.of("role"), attributes); @@ -43,7 +43,7 @@ void shouldConvertFromAuthenticationRoleBindingsType() { assertEquals("name", authenticationInfo.getName()); assertEquals(List.of("role"), authenticationInfo.getRoles().stream().toList()); - assertIterableEquals(List.of(new AuthenticationRoleBinding("namespace", List.of(GET), List.of("topics"))), - authenticationInfo.getRoleBindings().stream().toList()); + assertIterableEquals(List.of(new AuthenticationRoleBinding(List.of("namespace"), List.of(GET), + List.of("topics"))), authenticationInfo.getRoleBindings().stream().toList()); } } diff --git a/src/test/java/com/michelin/ns4kafka/security/auth/AuthenticationServiceTest.java b/src/test/java/com/michelin/ns4kafka/security/auth/AuthenticationServiceTest.java index a629a561..7eeacb13 100644 --- a/src/test/java/com/michelin/ns4kafka/security/auth/AuthenticationServiceTest.java +++ b/src/test/java/com/michelin/ns4kafka/security/auth/AuthenticationServiceTest.java @@ -106,19 +106,19 @@ void shouldReturnAuthenticationSuccessWhenAdminWithGroups() { assertEquals("admin", response.getAuthentication().get().getName()); assertTrue(response.getAuthentication().get().getRoles().contains(ResourceBasedSecurityRule.IS_ADMIN)); assertTrue(response.getAuthentication().get().getAttributes() - .containsKey("roleBindings")); - assertEquals("ns1", + .containsKey(ROLE_BINDINGS)); + assertEquals(List.of("ns1"), ((List) response.getAuthentication().get().getAttributes() - .get("roleBindings")).getFirst() - .getNamespace()); + .get(ROLE_BINDINGS)).getFirst() + .getNamespaces()); assertTrue( ((List) response.getAuthentication().get().getAttributes() - .get("roleBindings")).getFirst() + .get(ROLE_BINDINGS)).getFirst() .getVerbs() .containsAll(List.of(RoleBinding.Verb.POST, RoleBinding.Verb.GET))); assertTrue( ((List) response.getAuthentication().get().getAttributes() - .get("roleBindings")).getFirst() + .get(ROLE_BINDINGS)).getFirst() .getResourceTypes() .containsAll(List.of("topics", "acls"))); } @@ -155,20 +155,105 @@ void shouldReturnAuthenticationSuccessWhenUserWithGroups() { assertEquals("user", response.getAuthentication().get().getName()); assertTrue(response.getAuthentication().get().getRoles().isEmpty()); assertTrue(response.getAuthentication().get().getAttributes() - .containsKey("roleBindings")); - assertEquals("ns1", + .containsKey(ROLE_BINDINGS)); + assertEquals(List.of("ns1"), ((List) response.getAuthentication().get().getAttributes() - .get("roleBindings")).getFirst() - .getNamespace()); + .get(ROLE_BINDINGS)).getFirst() + .getNamespaces()); assertTrue( ((List) response.getAuthentication().get().getAttributes() - .get("roleBindings")).getFirst() + .get(ROLE_BINDINGS)).getFirst() .getVerbs() .containsAll(List.of(RoleBinding.Verb.POST, RoleBinding.Verb.GET))); assertTrue( ((List) response.getAuthentication().get().getAttributes() - .get("roleBindings")).getFirst() + .get(ROLE_BINDINGS)).getFirst() .getResourceTypes() .containsAll(List.of("topics", "acls"))); } + + @Test + @SuppressWarnings("unchecked") + void shouldReturnAuthenticationSuccessWhenMultipleGroupsWithSameVerbsAndResourceTypes() { + RoleBinding roleBinding1 = RoleBinding.builder() + .metadata(Metadata.builder() + .name("ns1-rb") + .namespace("ns1") + .build()) + .spec(RoleBinding.RoleBindingSpec.builder() + .role(RoleBinding.Role.builder() + .resourceTypes(List.of("topics", "acls")) + .verbs(List.of(RoleBinding.Verb.POST, RoleBinding.Verb.GET)) + .build()) + .subject(RoleBinding.Subject.builder() + .subjectName("group1") + .subjectType(RoleBinding.SubjectType.GROUP) + .build()) + .build()) + .build(); + + RoleBinding roleBinding2 = RoleBinding.builder() + .metadata(Metadata.builder() + .name("ns2-rb") + .namespace("ns2") + .build()) + .spec(RoleBinding.RoleBindingSpec.builder() + .role(RoleBinding.Role.builder() + .resourceTypes(List.of("topics")) + .verbs(List.of(RoleBinding.Verb.GET)) + .build()) + .subject(RoleBinding.Subject.builder() + .subjectName("group2") + .subjectType(RoleBinding.SubjectType.GROUP) + .build()) + .build()) + .build(); + + RoleBinding roleBinding3 = RoleBinding.builder() + .metadata(Metadata.builder() + .name("ns3-rb") + .namespace("ns3") + .build()) + .spec(RoleBinding.RoleBindingSpec.builder() + .role(RoleBinding.Role.builder() + .resourceTypes(List.of("topics", "acls")) + .verbs(List.of(RoleBinding.Verb.POST, RoleBinding.Verb.GET)) + .build()) + .subject(RoleBinding.Subject.builder() + .subjectName("group3") + .subjectType(RoleBinding.SubjectType.GROUP) + .build()) + .build()) + .build(); + + when(roleBindingService.findAllByGroups(any())) + .thenReturn(List.of(roleBinding1, roleBinding2, roleBinding3)); + + when(resourceBasedSecurityRule.computeRolesFromGroups(any())) + .thenReturn(List.of()); + + AuthenticationResponse response = authenticationService.buildAuthJwtGroups("user", List.of("group1")); + + assertTrue(response.getAuthentication().isPresent()); + assertEquals("user", response.getAuthentication().get().getName()); + assertTrue(response.getAuthentication().get().getRoles().isEmpty()); + assertTrue(response.getAuthentication().get().getAttributes().containsKey(ROLE_BINDINGS)); + assertTrue( + ((List) response.getAuthentication().get().getAttributes().get(ROLE_BINDINGS)) + .containsAll( + List.of( + AuthenticationRoleBinding.builder() + .namespaces(List.of("ns1", "ns3")) + .verbs(List.of(RoleBinding.Verb.POST, RoleBinding.Verb.GET)) + .resourceTypes(List.of("topics", "acls")) + .build(), + AuthenticationRoleBinding.builder() + .namespaces(List.of("ns2")) + .verbs(List.of(RoleBinding.Verb.GET)) + .resourceTypes(List.of("topics")) + .build() + ) + ) + ); + } } diff --git a/src/test/java/com/michelin/ns4kafka/security/auth/gitlab/GitlabAuthenticationProviderTest.java b/src/test/java/com/michelin/ns4kafka/security/auth/gitlab/GitlabAuthenticationProviderTest.java index f5473e2c..d4af8f02 100644 --- a/src/test/java/com/michelin/ns4kafka/security/auth/gitlab/GitlabAuthenticationProviderTest.java +++ b/src/test/java/com/michelin/ns4kafka/security/auth/gitlab/GitlabAuthenticationProviderTest.java @@ -52,7 +52,7 @@ void authenticationSuccess() { .thenReturn(Flux.fromIterable(groups)); AuthenticationRoleBinding authenticationRoleBinding = AuthenticationRoleBinding.builder() - .namespace("namespace") + .namespaces(List.of("namespace")) .verbs(List.of(RoleBinding.Verb.GET)) .resourceTypes(List.of("topics")) .build(); @@ -94,7 +94,7 @@ void authenticationSuccessAdmin() { .thenReturn(Flux.fromIterable(groups)); AuthenticationRoleBinding authenticationRoleBinding = AuthenticationRoleBinding.builder() - .namespace("namespace") + .namespaces(List.of("namespace")) .verbs(List.of(RoleBinding.Verb.GET)) .resourceTypes(List.of("topics")) .build(); diff --git a/src/test/java/com/michelin/ns4kafka/security/auth/ldap/LdapAuthenticationMapperTest.java b/src/test/java/com/michelin/ns4kafka/security/auth/ldap/LdapAuthenticationMapperTest.java index bb6f9112..8232fba2 100644 --- a/src/test/java/com/michelin/ns4kafka/security/auth/ldap/LdapAuthenticationMapperTest.java +++ b/src/test/java/com/michelin/ns4kafka/security/auth/ldap/LdapAuthenticationMapperTest.java @@ -30,7 +30,7 @@ class LdapAuthenticationMapperTest { @SuppressWarnings("unchecked") void shouldMapAttributesToAuthenticationResponse() { AuthenticationRoleBinding authenticationRoleBinding = AuthenticationRoleBinding.builder() - .namespace("namespace") + .namespaces(List.of("namespace")) .verbs(List.of(RoleBinding.Verb.GET)) .resourceTypes(List.of("topics")) .build(); diff --git a/src/test/java/com/michelin/ns4kafka/security/auth/local/LocalUserAuthenticationProviderTest.java b/src/test/java/com/michelin/ns4kafka/security/auth/local/LocalUserAuthenticationProviderTest.java index f75503e5..36f11357 100644 --- a/src/test/java/com/michelin/ns4kafka/security/auth/local/LocalUserAuthenticationProviderTest.java +++ b/src/test/java/com/michelin/ns4kafka/security/auth/local/LocalUserAuthenticationProviderTest.java @@ -80,7 +80,7 @@ void authenticateMatchUserMatchPassword() { .build())); AuthenticationRoleBinding authenticationRoleBinding = AuthenticationRoleBinding.builder() - .namespace("namespace") + .namespaces(List.of("namespace")) .verbs(List.of(RoleBinding.Verb.GET)) .resourceTypes(List.of("topics")) .build();