Skip to content

Commit f15fc92

Browse files
author
François
committed
Issues/300: Other extractors handle regex as values.
1 parent 33b4a54 commit f15fc92

File tree

7 files changed

+186
-81
lines changed

7 files changed

+186
-81
lines changed

api/src/main/java/io/kafbat/ui/service/rbac/extractor/CognitoAuthorityExtractor.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ private Set<String> extractUsernameRoles(AccessControlService acs, DefaultOAuth2
5050
.stream()
5151
.filter(s -> s.getProvider().equals(Provider.OAUTH_COGNITO))
5252
.filter(s -> s.getType().equals("user"))
53-
.anyMatch(s -> s.getValue().equalsIgnoreCase(principal.getName())))
53+
.anyMatch(s -> principal.getName() != null && principal.getName().matches(s.getValue())))
5454
.map(Role::getName)
5555
.collect(Collectors.toSet());
5656

@@ -76,7 +76,7 @@ private Set<String> extractGroupRoles(AccessControlService acs, DefaultOAuth2Use
7676
.filter(s -> s.getType().equals("group"))
7777
.anyMatch(subject -> groups
7878
.stream()
79-
.anyMatch(cognitoGroup -> cognitoGroup.equalsIgnoreCase(subject.getValue()))
79+
.anyMatch(cognitoGroup -> cognitoGroup.matches(subject.getValue()))
8080
))
8181
.map(Role::getName)
8282
.collect(Collectors.toSet());

api/src/main/java/io/kafbat/ui/service/rbac/extractor/GithubAuthorityExtractor.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ private Set<String> extractUsernameRoles(DefaultOAuth2User principal, AccessCont
9090
.stream()
9191
.filter(s -> s.getProvider().equals(Provider.OAUTH_GITHUB))
9292
.filter(s -> s.getType().equals("user"))
93-
.anyMatch(s -> s.getValue().equals(username)))
93+
.anyMatch(s -> username.matches(s.getValue())))
9494
.map(Role::getName)
9595
.collect(Collectors.toSet());
9696

@@ -131,7 +131,7 @@ private Mono<Set<String>> getOrganizationRoles(DefaultOAuth2User principal, Map<
131131
.filter(s -> s.getType().equals(ORGANIZATION))
132132
.anyMatch(subject -> orgsMap.stream()
133133
.map(org -> org.get(ORGANIZATION_NAME).toString())
134-
.anyMatch(orgName -> orgName.equalsIgnoreCase(subject.getValue()))
134+
.anyMatch(orgName -> orgName.matches(subject.getValue()))
135135
))
136136
.map(Role::getName)
137137
.collect(Collectors.toSet()));
@@ -189,7 +189,7 @@ private Mono<Set<String>> getTeamRoles(WebClient webClient, Map<String, Object>
189189
.filter(s -> s.getProvider().equals(Provider.OAUTH_GITHUB))
190190
.filter(s -> s.getType().equals("team"))
191191
.anyMatch(subject -> teams.stream()
192-
.anyMatch(teamName -> teamName.equalsIgnoreCase(subject.getValue()))
192+
.anyMatch(teamName -> teamName.matches(subject.getValue()))
193193
))
194194
.map(Role::getName)
195195
.collect(Collectors.toSet()));

api/src/main/java/io/kafbat/ui/service/rbac/extractor/GoogleAuthorityExtractor.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,10 @@ private Set<String> extractUsernameRoles(AccessControlService acs, DefaultOAuth2
5050
.stream()
5151
.filter(s -> s.getProvider().equals(Provider.OAUTH_GOOGLE))
5252
.filter(s -> s.getType().equals("user"))
53-
.anyMatch(s -> s.getValue().equalsIgnoreCase(principal.getAttribute(EMAIL_ATTRIBUTE_NAME))))
53+
.anyMatch(s -> {
54+
String email = principal.getAttribute(EMAIL_ATTRIBUTE_NAME);
55+
return email != null && email.matches(s.getValue());
56+
}))
5457
.map(Role::getName)
5558
.collect(Collectors.toSet());
5659
}
@@ -68,7 +71,7 @@ private Set<String> extractDomainRoles(AccessControlService acs, DefaultOAuth2Us
6871
.stream()
6972
.filter(s -> s.getProvider().equals(Provider.OAUTH_GOOGLE))
7073
.filter(s -> s.getType().equals("domain"))
71-
.anyMatch(s -> s.getValue().equals(domain)))
74+
.anyMatch(s -> domain.matches(s.getValue())))
7275
.map(Role::getName)
7376
.collect(Collectors.toSet());
7477
}

api/src/main/java/io/kafbat/ui/service/rbac/extractor/OauthAuthorityExtractor.java

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ private Set<String> extractUsernameRoles(AccessControlService acs, DefaultOAuth2
6060
.filter(s -> s.getType().equals("user"))
6161
.peek(s -> log.trace("[{}] matches [{}]? [{}]", s.getValue(), principalName,
6262
s.getValue().equalsIgnoreCase(principalName)))
63-
.anyMatch(s -> principalName.matches(s.getValue())))
63+
.anyMatch(s -> principalName != null && principalName.matches(s.getValue())))
6464
.map(Role::getName)
6565
.collect(Collectors.toSet());
6666

@@ -94,11 +94,7 @@ private Set<String> extractRoles(AccessControlService acs, DefaultOAuth2User pri
9494
.stream()
9595
.filter(s -> s.getProvider().equals(Provider.OAUTH))
9696
.filter(s -> s.getType().equals("role"))
97-
.anyMatch(subject -> {
98-
var roleName = subject.getValue();
99-
return principalRoles.stream().anyMatch(s -> s.matches(subject.getValue()));
100-
})
101-
)
97+
.anyMatch(subject -> principalRoles.stream().anyMatch(s -> s.matches(subject.getValue()))))
10298
.map(Role::getName)
10399
.collect(Collectors.toSet());
104100

api/src/test/java/io/kafbat/ui/config/ProviderAuthorityExtractorTest.java

Lines changed: 0 additions & 68 deletions
This file was deleted.
Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
package io.kafbat.ui.config;
2+
3+
import static org.junit.jupiter.api.Assertions.assertEquals;
4+
import static org.mockito.Mockito.when;
5+
import static org.springframework.security.oauth2.client.registration.ClientRegistration.withRegistrationId;
6+
7+
import io.kafbat.ui.config.auth.OAuthProperties;
8+
import io.kafbat.ui.model.rbac.Role;
9+
import io.kafbat.ui.service.rbac.AccessControlService;
10+
import io.kafbat.ui.service.rbac.extractor.CognitoAuthorityExtractor;
11+
import io.kafbat.ui.service.rbac.extractor.GithubAuthorityExtractor;
12+
import io.kafbat.ui.service.rbac.extractor.GoogleAuthorityExtractor;
13+
import io.kafbat.ui.service.rbac.extractor.OauthAuthorityExtractor;
14+
import io.kafbat.ui.service.rbac.extractor.ProviderAuthorityExtractor;
15+
import io.kafbat.ui.util.AccessControlServiceMock;
16+
import java.io.InputStream;
17+
import java.time.Instant;
18+
import java.time.temporal.ChronoUnit;
19+
import java.util.HashMap;
20+
import java.util.List;
21+
import java.util.Map;
22+
import java.util.Set;
23+
import lombok.SneakyThrows;
24+
import org.junit.jupiter.api.BeforeEach;
25+
import org.junit.jupiter.api.Test;
26+
import org.springframework.security.core.authority.AuthorityUtils;
27+
import org.springframework.security.oauth2.client.userinfo.OAuth2UserRequest;
28+
import org.springframework.security.oauth2.core.AuthorizationGrantType;
29+
import org.springframework.security.oauth2.core.OAuth2AccessToken;
30+
import org.springframework.security.oauth2.core.user.DefaultOAuth2User;
31+
import org.springframework.security.oauth2.core.user.OAuth2User;
32+
import org.yaml.snakeyaml.Yaml;
33+
import org.yaml.snakeyaml.introspector.BeanAccess;
34+
35+
public class RegexBasedProviderAuthorityExtractorTest {
36+
37+
38+
private final AccessControlService accessControlService = new AccessControlServiceMock().getMock();
39+
Yaml yaml;
40+
ProviderAuthorityExtractor extractor;
41+
42+
@BeforeEach
43+
void setUp() {
44+
yaml = new Yaml();
45+
yaml.setBeanAccess(BeanAccess.FIELD);
46+
47+
InputStream rolesFile = this.getClass()
48+
.getClassLoader()
49+
.getResourceAsStream("roles_definition.yaml");
50+
51+
Role[] roleArray = yaml.loadAs(rolesFile, Role[].class);
52+
when(accessControlService.getRoles()).thenReturn(List.of(roleArray));
53+
54+
}
55+
56+
@SneakyThrows
57+
@Test
58+
void extractOauth2Authorities() {
59+
60+
extractor = new OauthAuthorityExtractor();
61+
62+
OAuth2User oauth2User = new DefaultOAuth2User(
63+
AuthorityUtils.createAuthorityList("SCOPE_message:read"),
64+
Map.of("role_definition", Set.of("ROLE-ADMIN", "ANOTHER-ROLE"), "user_name", "[email protected]"),
65+
"user_name");
66+
67+
HashMap<String, Object> additionalParams = new HashMap<>();
68+
OAuthProperties.OAuth2Provider provider = new OAuthProperties.OAuth2Provider();
69+
provider.setCustomParams(Map.of("roles-field", "role_definition"));
70+
additionalParams.put("provider", provider);
71+
72+
Set<String> roles = extractor.extract(accessControlService, oauth2User, additionalParams).block();
73+
74+
assertEquals(Set.of("viewer", "admin"), roles);
75+
76+
}
77+
78+
@SneakyThrows
79+
@Test
80+
void extractCognitoAuthorities() {
81+
82+
extractor = new CognitoAuthorityExtractor();
83+
84+
OAuth2User oauth2User = new DefaultOAuth2User(
85+
AuthorityUtils.createAuthorityList("SCOPE_message:read"),
86+
Map.of("cognito:groups", List.of("ROLE-ADMIN", "ANOTHER-ROLE"), "user_name", "[email protected]"),
87+
"user_name");
88+
89+
HashMap<String, Object> additionalParams = new HashMap<>();
90+
91+
OAuthProperties.OAuth2Provider provider = new OAuthProperties.OAuth2Provider();
92+
provider.setCustomParams(Map.of("roles-field", "role_definition"));
93+
additionalParams.put("provider", provider);
94+
95+
Set<String> roles = extractor.extract(accessControlService, oauth2User, additionalParams).block();
96+
97+
assertEquals(Set.of("viewer", "admin"), roles);
98+
99+
}
100+
101+
@SneakyThrows
102+
@Test
103+
void extractGithubAuthorities() {
104+
105+
extractor = new GithubAuthorityExtractor();
106+
107+
OAuth2User oauth2User = new DefaultOAuth2User(
108+
AuthorityUtils.createAuthorityList("SCOPE_message:read"),
109+
Map.of("login", "[email protected]"),
110+
"login");
111+
112+
HashMap<String, Object> additionalParams = new HashMap<>();
113+
114+
OAuthProperties.OAuth2Provider provider = new OAuthProperties.OAuth2Provider();
115+
additionalParams.put("provider", provider);
116+
117+
additionalParams.put("request", new OAuth2UserRequest(
118+
withRegistrationId("registration-1")
119+
.clientId("client-1")
120+
.clientSecret("secret")
121+
.redirectUri("https://client.com")
122+
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
123+
.authorizationUri("https://provider.com/oauth2/authorization")
124+
.tokenUri("https://provider.com/oauth2/token")
125+
.clientName("Client 1")
126+
.build(),
127+
new OAuth2AccessToken(OAuth2AccessToken.TokenType.BEARER, "XXXX", Instant.now(),
128+
Instant.now().plus(10, ChronoUnit.HOURS))));
129+
130+
Set<String> roles = extractor.extract(accessControlService, oauth2User, additionalParams).block();
131+
132+
assertEquals(Set.of("viewer"), roles);
133+
134+
}
135+
136+
@SneakyThrows
137+
@Test
138+
void extractGoogleAuthorities() {
139+
140+
extractor = new GoogleAuthorityExtractor();
141+
142+
OAuth2User oauth2User = new DefaultOAuth2User(
143+
AuthorityUtils.createAuthorityList("SCOPE_message:read"),
144+
Map.of("hd", "test.domain.com", "email", "[email protected]"),
145+
"email");
146+
147+
HashMap<String, Object> additionalParams = new HashMap<>();
148+
149+
OAuthProperties.OAuth2Provider provider = new OAuthProperties.OAuth2Provider();
150+
provider.setCustomParams(Map.of("roles-field", "role_definition"));
151+
additionalParams.put("provider", provider);
152+
153+
Set<String> roles = extractor.extract(accessControlService, oauth2User, additionalParams).block();
154+
155+
assertEquals(Set.of("viewer", "admin"), roles);
156+
157+
}
158+
159+
}

api/src/test/resources/roles_definition.yaml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,12 @@
33
- provider: 'OAUTH'
44
value: 'ROLE-[A-Z]+'
55
type: 'role'
6+
- provider: 'OAUTH_COGNITO'
7+
value: 'ROLE-[A-Z]+'
8+
type: 'group'
9+
- provider: 'OAUTH_GOOGLE'
10+
value: '.*.domain.com'
11+
type: 'domain'
612
clusters:
713
- local
814
- remote
@@ -17,6 +23,15 @@
1723
- provider: 'OAUTH'
1824
value: '.*@kafka.com'
1925
type: 'user'
26+
- provider: 'OAUTH_COGNITO'
27+
value: '.*@kafka.com'
28+
type: 'user'
29+
- provider: 'OAUTH_GITHUB'
30+
value: '.*@kafka.com'
31+
type: 'user'
32+
- provider: 'OAUTH_GOOGLE'
33+
value: '.*@kafka.com'
34+
type: 'user'
2035
clusters:
2136
- remote
2237
permissions:

0 commit comments

Comments
 (0)