You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@kafka.apache.org by mi...@apache.org on 2026/08/07 09:46:04 UTC
(kafka) branch trunk updated: KAFKA-20816: Add support for CIDR into Authorizer.authorizeByResourceType (#22883)
This is an automated email from the ASF dual-hosted git repository.
mimaison pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/kafka.git
The following commit(s) were added to refs/heads/trunk by this push:
new 9c943129ebb KAFKA-20816: Add support for CIDR into Authorizer.authorizeByResourceType (#22883)
9c943129ebb is described below
commit 9c943129ebb07a3a6b5d19f02a1c286c1fe8061b
Author: Maros Orsak <ma...@gmail.com>
AuthorDate: Fri Aug 7 11:45:57 2026 +0200
KAFKA-20816: Add support for CIDR into Authorizer.authorizeByResourceType (#22883)
This PR fixes a problem if someone sets up CIDR-based ACLs and an
idempotent producer connects from an IP within the CIDR range, the
`authorizeByResourceType` check would fail to match the CIDR ACL, and
the producer would get `CLUSTER_AUTHORIZATION_FAILED`. It is a narrow
edge case but its bug.
Reviewers: Mickael Maison <mi...@gmail.com>, Manikumar Reddy
<ma...@gmail.com>
---------
Signed-off-by: see-quick <ma...@gmail.com>
---
build.gradle | 9 +++----
checkstyle/import-control-metadata.xml | 1 -
checkstyle/import-control.xml | 7 ++++++
.../apache/kafka/server/authorizer/Authorizer.java | 4 +++-
.../server/authorizer/internals}/CidrUtils.java | 2 +-
.../authorizer/internals}/CidrUtilsTest.java | 6 ++---
.../apache/kafka/controller/AclControlManager.java | 2 +-
.../authorizer/StandardAuthorizerData.java | 1 +
.../authorizer/StandardAuthorizerTest.java | 28 ++++++++++++++++++++++
9 files changed, 49 insertions(+), 11 deletions(-)
diff --git a/build.gradle b/build.gradle
index 64831c79b0b..10183c8a955 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1498,10 +1498,6 @@ project(':metadata') {
implementation project(':server-common')
implementation project(':clients')
implementation project(':raft')
- // commons-io is a transitive dependency not needed by SubnetUtils/SubnetUtils6
- implementation(libs.commonsNet) {
- exclude group: 'commons-io', module: 'commons-io'
- }
implementation libs.jacksonDatabind
implementation libs.metrics
implementation libs.slf4jApi
@@ -2024,6 +2020,10 @@ project(':clients') {
implementation libs.opentelemetryProto
implementation libs.protobuf
implementation libs.slf4jApi
+ // commons-io is a transitive dependency not needed by SubnetUtils/SubnetUtils6
+ implementation(libs.commonsNet) {
+ exclude group: 'commons-io', module: 'commons-io'
+ }
// libraries which should be added as runtime dependencies in generated pom.xml should be defined here:
shadowed libs.zstd
@@ -2090,6 +2090,7 @@ project(':clients') {
// KIP-714: move shaded dependencies to a shaded location
relocate('io.opentelemetry.proto', 'org.apache.kafka.shaded.io.opentelemetry.proto')
relocate('com.google.protobuf', 'org.apache.kafka.shaded.com.google.protobuf')
+ relocate('org.apache.commons.net', 'org.apache.kafka.shaded.org.apache.commons.net')
// dependencies excluded from the final jar, since they are declared as runtime dependencies
dependencies {
diff --git a/checkstyle/import-control-metadata.xml b/checkstyle/import-control-metadata.xml
index 1ee3207de44..cdc73dcf65d 100644
--- a/checkstyle/import-control-metadata.xml
+++ b/checkstyle/import-control-metadata.xml
@@ -168,7 +168,6 @@
<allow pkg="org.apache.kafka.common.metrics" />
<allow pkg="org.apache.kafka.common.metrics.internals" />
<allow pkg="org.apache.kafka.common.metrics.stats" />
- <allow pkg="org.apache.commons.net.util" />
</subpackage>
<subpackage name="bootstrap">
<allow pkg="org.apache.kafka.snapshot" />
diff --git a/checkstyle/import-control.xml b/checkstyle/import-control.xml
index 36dde497ff7..d0d85a607f9 100644
--- a/checkstyle/import-control.xml
+++ b/checkstyle/import-control.xml
@@ -257,6 +257,13 @@
<!-- This is required to make AlterConfigPolicyTest work. -->
<allow pkg="org.apache.kafka.server.policy" />
+ <subpackage name="authorizer">
+ <allow pkg="org.apache.kafka.server.authorizer" />
+ <subpackage name="internals">
+ <allow pkg="org.apache.commons.net.util" />
+ </subpackage>
+ </subpackage>
+
<subpackage name="telemetry">
<allow class="org.apache.kafka.server.authorizer.AuthorizableRequestContext" />
</subpackage>
diff --git a/clients/src/main/java/org/apache/kafka/server/authorizer/Authorizer.java b/clients/src/main/java/org/apache/kafka/server/authorizer/Authorizer.java
index db61421de94..34a6a44d0b5 100644
--- a/clients/src/main/java/org/apache/kafka/server/authorizer/Authorizer.java
+++ b/clients/src/main/java/org/apache/kafka/server/authorizer/Authorizer.java
@@ -31,6 +31,7 @@ import org.apache.kafka.common.resource.ResourcePatternFilter;
import org.apache.kafka.common.resource.ResourceType;
import org.apache.kafka.common.security.auth.KafkaPrincipal;
import org.apache.kafka.common.utils.internals.SecurityUtils;
+import org.apache.kafka.server.authorizer.internals.CidrUtils;
import java.io.Closeable;
import java.util.Collections;
@@ -221,7 +222,8 @@ public interface Authorizer extends Configurable, Closeable {
String hostAddr = requestContext.clientAddress().getHostAddress();
for (AclBinding binding : acls(aclFilter)) {
- if (!binding.entry().host().equals(hostAddr) && !binding.entry().host().equals("*"))
+ String aclHost = binding.entry().host();
+ if (!aclHost.equals(hostAddr) && !aclHost.equals("*") && !CidrUtils.isInRange(hostAddr, aclHost))
continue;
if (!SecurityUtils.parseKafkaPrincipal(binding.entry().principal()).equals(principal)
diff --git a/metadata/src/main/java/org/apache/kafka/metadata/authorizer/CidrUtils.java b/clients/src/main/java/org/apache/kafka/server/authorizer/internals/CidrUtils.java
similarity index 97%
rename from metadata/src/main/java/org/apache/kafka/metadata/authorizer/CidrUtils.java
rename to clients/src/main/java/org/apache/kafka/server/authorizer/internals/CidrUtils.java
index 318b2c9bff0..e909a777742 100644
--- a/metadata/src/main/java/org/apache/kafka/metadata/authorizer/CidrUtils.java
+++ b/clients/src/main/java/org/apache/kafka/server/authorizer/internals/CidrUtils.java
@@ -15,7 +15,7 @@
* limitations under the License.
*/
-package org.apache.kafka.metadata.authorizer;
+package org.apache.kafka.server.authorizer.internals;
import org.apache.commons.net.util.SubnetUtils;
import org.apache.commons.net.util.SubnetUtils6;
diff --git a/metadata/src/test/java/org/apache/kafka/metadata/authorizer/CidrUtilsTest.java b/clients/src/test/java/org/apache/kafka/server/authorizer/internals/CidrUtilsTest.java
similarity index 95%
rename from metadata/src/test/java/org/apache/kafka/metadata/authorizer/CidrUtilsTest.java
rename to clients/src/test/java/org/apache/kafka/server/authorizer/internals/CidrUtilsTest.java
index f648944f0ba..46af4304c82 100644
--- a/metadata/src/test/java/org/apache/kafka/metadata/authorizer/CidrUtilsTest.java
+++ b/clients/src/test/java/org/apache/kafka/server/authorizer/internals/CidrUtilsTest.java
@@ -15,15 +15,15 @@
* limitations under the License.
*/
-package org.apache.kafka.metadata.authorizer;
+package org.apache.kafka.server.authorizer.internals;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.Timeout;
import java.net.InetAddress;
-import static org.apache.kafka.metadata.authorizer.CidrUtils.isInRange;
-import static org.apache.kafka.metadata.authorizer.CidrUtils.validate;
+import static org.apache.kafka.server.authorizer.internals.CidrUtils.isInRange;
+import static org.apache.kafka.server.authorizer.internals.CidrUtils.validate;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
diff --git a/metadata/src/main/java/org/apache/kafka/controller/AclControlManager.java b/metadata/src/main/java/org/apache/kafka/controller/AclControlManager.java
index 22808ced18d..3553ba6f7a3 100644
--- a/metadata/src/main/java/org/apache/kafka/controller/AclControlManager.java
+++ b/metadata/src/main/java/org/apache/kafka/controller/AclControlManager.java
@@ -28,12 +28,12 @@ import org.apache.kafka.common.metadata.AccessControlEntryRecord;
import org.apache.kafka.common.metadata.RemoveAccessControlEntryRecord;
import org.apache.kafka.common.requests.ApiError;
import org.apache.kafka.common.utils.internals.LogContext;
-import org.apache.kafka.metadata.authorizer.CidrUtils;
import org.apache.kafka.metadata.authorizer.StandardAcl;
import org.apache.kafka.metadata.authorizer.StandardAclWithId;
import org.apache.kafka.server.authorizer.AclCreateResult;
import org.apache.kafka.server.authorizer.AclDeleteResult;
import org.apache.kafka.server.authorizer.AclDeleteResult.AclBindingDeleteResult;
+import org.apache.kafka.server.authorizer.internals.CidrUtils;
import org.apache.kafka.server.common.ApiMessageAndVersion;
import org.apache.kafka.server.common.MetadataVersion;
import org.apache.kafka.server.mutable.BoundedList;
diff --git a/metadata/src/main/java/org/apache/kafka/metadata/authorizer/StandardAuthorizerData.java b/metadata/src/main/java/org/apache/kafka/metadata/authorizer/StandardAuthorizerData.java
index f56c39dc379..bb17549de83 100644
--- a/metadata/src/main/java/org/apache/kafka/metadata/authorizer/StandardAuthorizerData.java
+++ b/metadata/src/main/java/org/apache/kafka/metadata/authorizer/StandardAuthorizerData.java
@@ -32,6 +32,7 @@ import org.apache.kafka.common.utils.internals.SecurityUtils;
import org.apache.kafka.server.authorizer.Action;
import org.apache.kafka.server.authorizer.AuthorizableRequestContext;
import org.apache.kafka.server.authorizer.AuthorizationResult;
+import org.apache.kafka.server.authorizer.internals.CidrUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
diff --git a/metadata/src/test/java/org/apache/kafka/metadata/authorizer/StandardAuthorizerTest.java b/metadata/src/test/java/org/apache/kafka/metadata/authorizer/StandardAuthorizerTest.java
index 35e49bb85f5..c49f08f627b 100644
--- a/metadata/src/test/java/org/apache/kafka/metadata/authorizer/StandardAuthorizerTest.java
+++ b/metadata/src/test/java/org/apache/kafka/metadata/authorizer/StandardAuthorizerTest.java
@@ -875,4 +875,32 @@ public class StandardAuthorizerTest {
authorizer.authorize(aliceInBroadOnly, List.of(newAction(READ, TOPIC, "foo"))),
"Client in only the broad ALLOW /8 should be allowed");
}
+
+ @Test
+ public void testAuthorizeByResourceTypeWithCidrHost() throws Exception {
+ StandardAuthorizer authorizer = createAndInitializeStandardAuthorizer();
+
+ StandardAclWithId cidrAcl = withId(new StandardAcl(
+ TOPIC, "test-topic", LITERAL, "User:bob",
+ "192.168.1.0/24", WRITE, ALLOW));
+ authorizer.addAcl(cidrAcl.id(), cidrAcl.acl());
+
+ // Client within the CIDR range should be allowed
+ AuthorizableRequestContext bobInRange = new MockAuthorizableRequestContext.Builder()
+ .setPrincipal(new KafkaPrincipal(USER_TYPE, "bob"))
+ .setClientAddress(InetAddress.getByName("192.168.1.50"))
+ .build();
+ assertEquals(ALLOWED,
+ authorizer.authorizeByResourceType(bobInRange, WRITE, TOPIC),
+ "Client within CIDR range should be allowed by authorizeByResourceType");
+
+ // Client outside the CIDR range should be denied
+ AuthorizableRequestContext bobOutOfRange = new MockAuthorizableRequestContext.Builder()
+ .setPrincipal(new KafkaPrincipal(USER_TYPE, "bob"))
+ .setClientAddress(InetAddress.getByName("10.0.0.1"))
+ .build();
+ assertEquals(DENIED,
+ authorizer.authorizeByResourceType(bobOutOfRange, WRITE, TOPIC),
+ "Client outside CIDR range should be denied by authorizeByResourceType");
+ }
}