Skip to content

Commit 250de4f

Browse files
committed
Implement ACL APIs
This change implements createAcls, describeAcls, and deleteAcls on the admin client.
1 parent a738f5c commit 250de4f

File tree

18 files changed

+1388
-503
lines changed

18 files changed

+1388
-503
lines changed

docker-compose.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,9 @@ services:
9595
# Consumer group options
9696
KAFKA_CFG_GROUP_COORDINATOR_REBALANCE_PROTOCOLS: "classic,consumer"
9797
KAFKA_CFG_GROUP_INITIAL_REBALANCE_DELAY_MS: "0"
98+
# ACL options
99+
KAFKA_AUTHORIZER_CLASS_NAME: "org.apache.kafka.metadata.authorizer.StandardAuthorizer"
100+
KAFKA_SUPER_USERS: "User:ANONYMOUS"
98101

99102
broker-cluster-2:
100103
image: *image

docs/admin.md

Lines changed: 46 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -98,10 +98,10 @@ The return value is an object specifying quotas for the requested user/client co
9898

9999
Options:
100100

101-
| Property | Type | Description |
102-
| ---------- | --------------------------------------------- | -------------------------------------------------------------------------------------------------------- |
103-
| components | `DescribeClientQuotasRequestComponent[]` | Array of components specifying the entity types and match criteria for which to describe client quotas. |
104-
| strict | `boolean` | Whether to use strict matching for components. Defaults to `false`. |
101+
| Property | Type | Description |
102+
| ---------- | ---------------------------------------- | ------------------------------------------------------------------------------------------------------- |
103+
| components | `DescribeClientQuotasRequestComponent[]` | Array of components specifying the entity types and match criteria for which to describe client quotas. |
104+
| strict | `boolean` | Whether to use strict matching for components. Defaults to `false`. |
105105

106106
### `alterClientQuotas(options[, callback])`
107107

@@ -111,10 +111,48 @@ The return value is a list of entities for which quotas have been changed.
111111

112112
Options:
113113

114-
| Property | Type | Description |
115-
| ------------ | --------------------------------- | ----------------------------------------------------------------------------------------- |
116-
| entries | `AlterClientQuotasRequestEntry[]` | Array of entries specifying the entities and quotas to change. |
117-
| validateOnly | `boolean` | Whether to only validate the request without applying changes. Defaults to `false`. |
114+
| Property | Type | Description |
115+
| ------------ | --------------------------------- | ----------------------------------------------------------------------------------- |
116+
| entries | `AlterClientQuotasRequestEntry[]` | Array of entries specifying the entities and quotas to change. |
117+
| validateOnly | `boolean` | Whether to only validate the request without applying changes. Defaults to `false`. |
118+
119+
### `createAcls(options[, callback])`
120+
121+
Creates Access Control List (ACL) entries to define permissions for Kafka resources.
122+
123+
The return value is `void`.
124+
125+
Options:
126+
127+
| Property | Type | Description |
128+
| ---------- | ------- | ------------------------------- |
129+
| creations | `Acl[]` | Array of ACL entries to create. |
130+
131+
### `describeAcls(options[, callback])`
132+
133+
Describes existing Access Control List (ACL) entries that match the specified filter criteria.
134+
135+
The return value is an array of resources with their associated ACL entries.
136+
137+
Options:
138+
139+
| Property | Type | Description |
140+
| -------- | ----------- | ----------------------------------------- |
141+
| filter | `AclFilter` | Filter criteria for matching ACL entries. |
142+
143+
The filter contains the same properties as ACL entries, but `resourceName`, `principal`, and `host` can be `null` to match any value.
144+
145+
### `deleteAcls(options[, callback])`
146+
147+
Deletes Access Control List (ACL) entries that match the specified filter criteria.
148+
149+
The return value is an array of deleted ACL entries.
150+
151+
Options:
152+
153+
| Property | Type | Description |
154+
| -------- | ------------- | --------------------------------------------------- |
155+
| filters | `AclFilter[]` | Array of filter criteria for ACL entries to delete. |
118156

119157
### `describeLogDirs(options[, callback])`
120158

docs/diagnostic.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ Each tracing channel publishes events with the following common properties:
7373
| `plt:kafka:admin:groups` | `Admin` | Traces a `Admin.listGroups`, `Admin.describeGroups` or `Admin.deleteGroups` request. |
7474
| `plt:kafka:admin:clientQuotas` | `Admin` | Traces a `Admin.describeClientQuotas` or `Admin.alterClientQuotas` request. |
7575
| `plt:kafka:admin:logDirs` | `Admin` | Traces a `Admin.describeLogDirs` request. |
76+
| `plt:kafka:admin:acls` | `Admin` | Traces a `Admin.createAcls`, `Admin.describeAcls` or `Admin.deleteAcls` request. |
7677
| `plt:kafka:producer:initIdempotent` | `Producer` | Traces a `Producer.initIdempotentProducer` request. |
7778
| `plt:kafka:producer:sends` | `Producer` | Traces a `Producer.send` request. |
7879
| `plt:kafka:consumer:group` | `Consumer` | Traces a `Consumer.findGroupCoordinator`, `Consumer.joinGroup` or `Consumer.leaveGroup` requests. |

playground/apis/admin/acl.ts

Lines changed: 25 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,7 @@
11
import { api as createAclsV3 } from '../../../src/apis/admin/create-acls-v3.ts'
22
import { api as deleteAclsV3 } from '../../../src/apis/admin/delete-acls-v3.ts'
33
import { api as describeAclsV3 } from '../../../src/apis/admin/describe-acls-v3.ts'
4-
import {
5-
AclOperations,
6-
AclPermissionTypes,
7-
ResourcePatternTypes,
8-
ResourceTypes
9-
} from '../../../src/apis/enumerations.ts'
4+
import { AclOperations, AclPermissionTypes, PatternTypes, ResourceTypes } from '../../../src/apis/enumerations.ts'
105
import { Connection } from '../../../src/network/connection.ts'
116
import { performAPICallWithRetry } from '../../utils.ts'
127

@@ -18,7 +13,7 @@ await performAPICallWithRetry('CreateAcls', () =>
1813
{
1914
resourceType: ResourceTypes.TOPIC,
2015
resourceName: 'temp',
21-
resourcePatternType: ResourcePatternTypes.LITERAL,
16+
patternType: PatternTypes.LITERAL,
2217
principal: 'abc:cde',
2318
host: '*',
2419
operation: AclOperations.READ,
@@ -27,37 +22,35 @@ await performAPICallWithRetry('CreateAcls', () =>
2722
]))
2823

2924
await performAPICallWithRetry('DescribeAcls', () =>
30-
describeAclsV3.async(
31-
connection,
32-
ResourceTypes.TOPIC,
33-
'temp',
34-
ResourcePatternTypes.LITERAL,
35-
null,
36-
null,
37-
AclOperations.READ,
38-
AclPermissionTypes.DENY
39-
))
25+
describeAclsV3.async(connection, {
26+
resourceType: ResourceTypes.TOPIC,
27+
resourceName: 'temp',
28+
patternType: PatternTypes.LITERAL,
29+
principal: null,
30+
host: null,
31+
operation: AclOperations.READ,
32+
permissionType: AclPermissionTypes.DENY
33+
}))
4034

4135
await performAPICallWithRetry('DescribeAcls', () =>
42-
describeAclsV3.async(
43-
connection,
44-
ResourceTypes.TOPIC,
45-
'temp',
46-
ResourcePatternTypes.LITERAL,
47-
null,
48-
null,
49-
AclOperations.READ,
50-
AclPermissionTypes.ALLOW
51-
))
36+
describeAclsV3.async(connection, {
37+
resourceType: ResourceTypes.TOPIC,
38+
resourceName: 'temp',
39+
patternType: PatternTypes.LITERAL,
40+
principal: null,
41+
host: null,
42+
operation: AclOperations.READ,
43+
permissionType: AclPermissionTypes.ALLOW
44+
}))
5245

5346
await performAPICallWithRetry('DeleteAcls', () =>
5447
deleteAclsV3.async(connection, [
5548
{
56-
resourceTypeFilter: ResourceTypes.TOPIC,
57-
resourceNameFilter: 'temp',
58-
patternTypeFilter: ResourcePatternTypes.LITERAL,
59-
principalFilter: null,
60-
hostFilter: null,
49+
resourceType: ResourceTypes.TOPIC,
50+
resourceName: 'temp',
51+
patternType: PatternTypes.LITERAL,
52+
principal: null,
53+
host: null,
6154
operation: AclOperations.READ,
6255
permissionType: AclPermissionTypes.DENY
6356
}

src/apis/admin/create-acls-v3.ts

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,7 @@ import { type NullableString } from '../../protocol/definitions.ts'
33
import { type Reader } from '../../protocol/reader.ts'
44
import { Writer } from '../../protocol/writer.ts'
55
import { createAPI, type ResponseErrorWithLocation } from '../definitions.ts'
6-
7-
export interface CreateAclsRequestCreation {
8-
resourceType: number
9-
resourceName: string
10-
resourcePatternType: number
11-
principal: string
12-
host: string
13-
operation: number
14-
permissionType: number
15-
}
6+
import { type Acl } from '../types.ts'
167

178
export type CreateAclsRequest = Parameters<typeof createRequest>
189

@@ -37,12 +28,12 @@ CreateAcls Request (Version: 3) => [creations] TAG_BUFFER
3728
operation => INT8
3829
permission_type => INT8
3930
*/
40-
export function createRequest (creations: CreateAclsRequestCreation[]): Writer {
31+
export function createRequest (creations: Acl[]): Writer {
4132
return Writer.create()
4233
.appendArray(creations, (w, c) => {
4334
w.appendInt8(c.resourceType)
4435
.appendString(c.resourceName)
45-
.appendInt8(c.resourcePatternType)
36+
.appendInt8(c.patternType)
4637
.appendString(c.principal)
4738
.appendString(c.host)
4839
.appendInt8(c.operation)

src/apis/admin/delete-acls-v3.ts

Lines changed: 13 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -3,28 +3,14 @@ import { type NullableString } from '../../protocol/definitions.ts'
33
import { type Reader } from '../../protocol/reader.ts'
44
import { Writer } from '../../protocol/writer.ts'
55
import { createAPI, type ResponseErrorWithLocation } from '../definitions.ts'
6+
import { type AclOperation, type AclPermissionType, type PatternType, type ResourceType } from '../enumerations.ts'
7+
import { type Acl, type AclFilter } from '../types.ts'
68

7-
export interface DeleteAclsRequestFilter {
8-
resourceTypeFilter: number
9-
resourceNameFilter?: NullableString
10-
patternTypeFilter: number
11-
principalFilter?: NullableString
12-
hostFilter?: NullableString
13-
operation: number
14-
permissionType: number
15-
}
169
export type DeleteAclsRequest = Parameters<typeof createRequest>
1710

18-
export interface DeleteAclsResponseMatchingAcl {
11+
export interface DeleteAclsResponseMatchingAcl extends Acl {
1912
errorCode: number
2013
errorMessage: NullableString
21-
resourceType: number
22-
resourceName: string
23-
patternType: number
24-
principal: string
25-
host: string
26-
operation: number
27-
permissionType: number
2814
}
2915

3016
export interface DeleteAclsResponseFilterResults {
@@ -48,14 +34,14 @@ export interface DeleteAclsResponse {
4834
operation => INT8
4935
permission_type => INT8
5036
*/
51-
export function createRequest (filters: DeleteAclsRequestFilter[]): Writer {
37+
export function createRequest (filters: AclFilter[]): Writer {
5238
return Writer.create()
5339
.appendArray(filters, (w, f) => {
54-
w.appendInt8(f.resourceTypeFilter)
55-
.appendString(f.resourceNameFilter)
56-
.appendInt8(f.patternTypeFilter)
57-
.appendString(f.principalFilter)
58-
.appendString(f.hostFilter)
40+
w.appendInt8(f.resourceType)
41+
.appendString(f.resourceName)
42+
.appendInt8(f.patternType)
43+
.appendString(f.principal)
44+
.appendString(f.host)
5945
.appendInt8(f.operation)
6046
.appendInt8(f.permissionType)
6147
})
@@ -109,13 +95,13 @@ export function parseResponse (
10995
return {
11096
errorCode,
11197
errorMessage: r.readNullableString(),
112-
resourceType: r.readInt8(),
98+
resourceType: r.readInt8() as ResourceType,
11399
resourceName: r.readString(),
114-
patternType: r.readInt8(),
100+
patternType: r.readInt8() as PatternType,
115101
principal: r.readString(),
116102
host: r.readString(),
117-
operation: r.readInt8(),
118-
permissionType: r.readInt8()
103+
operation: r.readInt8() as AclOperation,
104+
permissionType: r.readInt8() as AclPermissionType
119105
}
120106
})
121107
}

src/apis/admin/describe-acls-v3.ts

Lines changed: 16 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,13 @@ import { type NullableString } from '../../protocol/definitions.ts'
33
import { type Reader } from '../../protocol/reader.ts'
44
import { Writer } from '../../protocol/writer.ts'
55
import { createAPI } from '../definitions.ts'
6+
import { type AclOperation, type AclPermissionType, type PatternType, type ResourceType } from '../enumerations.ts'
7+
import { type AclPermission, type AclTarget, type AclFilter } from '../types.ts'
68

79
export type DescribeAclsRequest = Parameters<typeof createRequest>
810

9-
export interface DescribeAclsResponseAcl {
10-
principal: string
11-
host: string
12-
operation: number
13-
permissionType: number
14-
}
15-
16-
export interface DescribeAclsResponseResource {
17-
resourceType: number
18-
resourceName: string
19-
patternType: number
20-
acls: DescribeAclsResponseAcl[]
11+
export interface DescribeAclsResponseResource extends AclTarget {
12+
acls: AclPermission[]
2113
}
2214
export interface DescribeAclsResponse {
2315
throttleTimeMs: number
@@ -36,23 +28,15 @@ export interface DescribeAclsResponse {
3628
operation => INT8
3729
permission_type => INT8
3830
*/
39-
export function createRequest (
40-
resourceTypeFilter: number,
41-
resourceNameFilter: NullableString,
42-
patternTypeFilter: number,
43-
principalFilter: NullableString,
44-
hostFilter: NullableString,
45-
operation: number,
46-
permissionType: number
47-
): Writer {
31+
export function createRequest (filter: AclFilter): Writer {
4832
return Writer.create()
49-
.appendInt8(resourceTypeFilter)
50-
.appendString(resourceNameFilter)
51-
.appendInt8(patternTypeFilter)
52-
.appendString(principalFilter)
53-
.appendString(hostFilter)
54-
.appendInt8(operation)
55-
.appendInt8(permissionType)
33+
.appendInt8(filter.resourceType)
34+
.appendString(filter.resourceName)
35+
.appendInt8(filter.patternType)
36+
.appendString(filter.principal)
37+
.appendString(filter.host)
38+
.appendInt8(filter.operation)
39+
.appendInt8(filter.permissionType)
5640
.appendTaggedFields()
5741
}
5842

@@ -83,15 +67,15 @@ export function parseResponse (
8367
errorMessage: reader.readNullableString(),
8468
resources: reader.readArray(r => {
8569
return {
86-
resourceType: r.readInt8(),
70+
resourceType: r.readInt8() as ResourceType,
8771
resourceName: r.readString(),
88-
patternType: r.readInt8(),
72+
patternType: r.readInt8() as PatternType,
8973
acls: r.readArray(r => {
9074
return {
9175
principal: r.readString(),
9276
host: r.readString(),
93-
operation: r.readInt8(),
94-
permissionType: r.readInt8()
77+
operation: r.readInt8() as AclOperation,
78+
permissionType: r.readInt8() as AclPermissionType
9579
}
9680
})
9781
}

src/apis/enumerations.ts

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -48,12 +48,13 @@ export const ResourceTypes = {
4848
GROUP: 3,
4949
CLUSTER: 4,
5050
TRANSACTIONAL_ID: 5,
51-
DELEGATION_TOKEN: 6
51+
DELEGATION_TOKEN: 6,
52+
USER: 7
5253
} as const
53-
export type ResourceType = keyof typeof ResourceTypes
54+
export type ResourceType = (typeof ResourceTypes)[keyof typeof ResourceTypes]
5455

55-
export const ResourcePatternTypes = { UNKNOWN: 0, ANY: 1, MATCH: 2, LITERAL: 3, PREFIXED: 4 } as const
56-
export type ResourcePatternType = keyof typeof ResourcePatternTypes
56+
export const PatternTypes = { UNKNOWN: 0, ANY: 1, MATCH: 2, LITERAL: 3, PREFIXED: 4 } as const
57+
export type PatternType = (typeof PatternTypes)[keyof typeof PatternTypes]
5758

5859
export const AclOperations = {
5960
UNKNOWN: 0,
@@ -68,12 +69,15 @@ export const AclOperations = {
6869
CLUSTER_ACTION: 9,
6970
DESCRIBE_CONFIGS: 10,
7071
ALTER_CONFIGS: 11,
71-
IDEMPOTENT_WRITE: 12
72+
IDEMPOTENT_WRITE: 12,
73+
CREATE_TOKENS: 13,
74+
DESCRIBE_TOKENS: 14,
75+
TWO_PHASE_COMMIT: 15
7276
} as const
73-
export type AclOperation = keyof typeof AclOperations
77+
export type AclOperation = (typeof AclOperations)[keyof typeof AclOperations]
7478

7579
export const AclPermissionTypes = { UNKNOWN: 0, ANY: 1, DENY: 2, ALLOW: 3 } as const
76-
export type AclPermissionType = keyof typeof AclPermissionTypes
80+
export type AclPermissionType = (typeof AclPermissionTypes)[keyof typeof AclPermissionTypes]
7781

7882
// ./admin/*-configs.ts
7983
export const ConfigSources = {

src/apis/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
export * from './callbacks.ts'
33
export * from './definitions.ts'
44
export * from './enumerations.ts'
5+
export * from './types.ts'
56

67
// Low-level APIs
78
export * from './admin/index.ts'

0 commit comments

Comments
 (0)