Skip to content

Commit

Permalink
Fix edge cases for parsing
Browse files Browse the repository at this point in the history
  • Loading branch information
giuseppelillo committed Mar 6, 2023
1 parent 985e3a1 commit cbbdbfa
Show file tree
Hide file tree
Showing 6 changed files with 48 additions and 24 deletions.
22 changes: 12 additions & 10 deletions src/main/java/io/aiven/kafka/auth/VerdictCache.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.function.Predicate;

import org.apache.kafka.common.security.auth.KafkaPrincipal;
Expand All @@ -31,20 +30,23 @@ public class VerdictCache {
private final Map<String, Boolean> cache = new ConcurrentHashMap<>();

private VerdictCache(final List<AivenAcl> aclEntries) {
this.aclEntries = new CopyOnWriteArrayList<>(aclEntries);
this.aclEntries = aclEntries;
}

public boolean get(final KafkaPrincipal principal,
final String operation,
final String resource) {
final String cacheKey = resource
+ "|" + operation
+ "|" + principal.getName()
+ "|" + principal.getPrincipalType();

final Predicate<AivenAcl> matcher = aclEntry ->
aclEntry.check(principal.getPrincipalType(), principal.getName(), operation, resource);
return cache.computeIfAbsent(cacheKey, key -> aclEntries.stream().anyMatch(matcher));
if (aclEntries != null) {
final String cacheKey = resource
+ "|" + operation
+ "|" + principal.getName()
+ "|" + principal.getPrincipalType();
final Predicate<AivenAcl> matcher = aclEntry ->
aclEntry.check(principal.getPrincipalType(), principal.getName(), operation, resource);
return cache.computeIfAbsent(cacheKey, key -> aclEntries.stream().anyMatch(matcher));
} else {
return false;
}
}

public List<AivenAcl> aclEntries() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ public static List<AclBinding> convert(final AivenAcl aivenAcl) {
}

for (final var operation : AclOperationsParser.parse(aivenAcl.operationRe.pattern())) {
final List<String> principals = AclPrincipalParser.parse(
final List<String> principals = AclPrincipalFormatter.parse(
aivenAcl.principalType, aivenAcl.principalRe.pattern()
);
for (final var principal : principals) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,19 +19,19 @@
import java.util.List;
import java.util.stream.Collectors;

class AclPrincipalParser {
class AclPrincipalFormatter {
// Visible for test
static List<String> parse(final String principalType, final String principalPattern) {
if (principalType == null || principalPattern == null) {
return List.of();
}
if (principalPattern.contains(".*")) {
return List.of(principalType + ":*");
}
List<String> principals = RegexParser.parse(principalPattern);
if (principals == null) {
principals = List.of(principalPattern);
}
if (principals.contains("(.*)") || principals.contains(".*")) {
return List.of(principalType + ":*");
}
return principals.stream()
.map(p -> principalType + ":" + p)
.collect(Collectors.toList());
Expand Down
8 changes: 6 additions & 2 deletions src/main/java/io/aiven/kafka/auth/nativeacls/RegexParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@

class RegexParser {

private static final Pattern PARSER_PATTERN = Pattern.compile("\\^\\(?(.*?)\\)?\\$");
private static final Pattern PARSER_PATTERN = Pattern.compile("(?<=^\\^)(.*?)(?=\\$$)");

// Visible for test
/**
Expand All @@ -44,7 +44,11 @@ static List<String> parse(final String pattern) {
return null;
}

final String group = matcher.group(1);
String group = matcher.group(0);
final int lastChar = group.length() - 1;
if (group.charAt(0) == '(' && group.charAt(lastChar) == ')') {
group = group.substring(1, lastChar);
}
return Arrays.stream(group.split("\\|"))
.filter(Predicate.not(String::isBlank))
.collect(Collectors.toList());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,36 +22,42 @@

import static org.assertj.core.api.Assertions.assertThat;

public class AclPrincipalParserTest {
public class AclPrincipalFormatterTest {

@Test
public final void parseSinglePrincipal() {
assertThat(AclPrincipalParser.parse("User", "^username$"))
assertThat(AclPrincipalFormatter.parse("User", "^username$"))
.containsExactly("User:username");
}

@ParameterizedTest
@ValueSource(strings = {"(.*)", "^(username|(.*))$"})
@ValueSource(strings = {"(.*)", ".*", "^(username|(.*))$", "^(username|.*)$"})
public final void parseWildcardPrincipal(final String value) {
assertThat(AclPrincipalParser.parse("User", value))
assertThat(AclPrincipalFormatter.parse("User", value))
.containsExactly("User:*");
}

@Test
public final void parseNotWildcard() {
assertThat(AclPrincipalFormatter.parse("User", "username.*"))
.containsExactly("User:username.*");
}

@Test
public final void parseMultipleUsers() {
assertThat(AclPrincipalParser.parse("User", "^(user1|user2)$"))
assertThat(AclPrincipalFormatter.parse("User", "^(user1|user2)$"))
.containsExactly("User:user1", "User:user2");
}

@Test
public final void parseNullPrincipal() {
assertThat(AclPrincipalParser.parse("User", null))
assertThat(AclPrincipalFormatter.parse("User", null))
.isEmpty();
}

@Test
public final void parseNullPrincipalType() {
assertThat(AclPrincipalParser.parse(null, "^username$"))
assertThat(AclPrincipalFormatter.parse(null, "^username$"))
.isEmpty();
}

Expand Down
12 changes: 12 additions & 0 deletions src/test/java/io/aiven/kafka/auth/nativeacls/RegexParserTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,18 @@ public final void parseRegexListSingleWithParens() {
.containsExactly("AAA");
}

@Test
public final void parseParenthesis() {
assertThat(RegexParser.parse("^qwe)$"))
.containsExactly("qwe)");
}

@Test
public final void parseNestedRegex() {
assertThat(RegexParser.parse("^(AAA|^(BB)$)$"))
.containsExactly("AAA", "^(BB)$");
}

@Test
public final void parseRegexListMultiple() {
assertThat(RegexParser.parse("^(AAA|BBB|CCC|DDD)$"))
Expand Down

0 comments on commit cbbdbfa

Please sign in to comment.