In AuthorizationProvider, the authorization interface grantPermissionAsync(TopicName topicName, Set<AuthAction> actions, String role, String authDataJson)
currently only supports granting permissions to a single topic at a time. When multiple topics need to be authorized under a namespace, the client makes the calls to the authorization interface concurrently. Since the permissions information is stored in the namespace-level policies, and multiple topics may be on different brokers, concurrent authorization modification will cause concurrent modification exceptions. Therefore, supporting granting permissions for multiple topics is very beneficial.
Supporting granting/revoking permissions for multiple topics, add grantPermissionAsync(List<GrantTopicPermissionOptions> options)
and revokePermissionAsync(List<RevokeTopicPermissionOptions> options)
in AuthorizationProvider.
grantPermissionAsync(List<GrantTopicPermissionOptions> options)
in AuthorizationProvider.revokePermissionAsync(List<GrantTopicPermissionOptions> options)
in AuthorizationProvider.Add default method implementation in AuthorizationProvider
public interface AuthorizationProvider extends Closeable { default CompletableFuture<Void> grantPermissionAsync(List<GrantTopicPermissionOptions> options) { return FutureUtil.failedFuture(new IllegalStateException( String.format("grantPermissionAsync is not supported by the Authorization"))); } default CompletableFuture<Void> revokePermissionAsync(List<RevokeTopicPermissionOptions> options) { return FutureUtil.failedFuture(new IllegalStateException( String.format("revokePermissionAsync is not supported by the Authorization"))); } }
@Data @Builder public class GrantTopicPermissionOptions { private final String topic; private final String role; private final Set<AuthAction> actions; } @Data @Builder public class RevokeTopicPermissionOptions { private final String topic; private final String role; }
Add namespace admin API.
public interface Namespaces { CompletableFuture<Void> grantPermissionOnTopicsAsync(List<GrantTopicPermissionOptions> options); void grantPermissionOnTopics(List<GrantTopicPermissionOptions> options) throws PulsarAdminException; CompletableFuture<Void> revokePermissionOnTopicsAsync(List<RevokeTopicPermissionOptions> options); void revokePermissionOnTopics(List<RevokeTopicPermissionOptions> options) throws PulsarAdminException; }
Add namespace rest implementation in broker side.
@POST @Path("/grantPermissions") public void grantPermissionOnTopics(@Suspended final AsyncResponse asyncResponse, List<GrantTopicPermissionOptions> options) { internalGrantPermissionsAsync(options) .thenAccept(__ -> asyncResponse.resume(Response.noContent().build())) .exceptionally(ex -> { log.error("[{}] Failed to grant permissions {}", clientAppId(), options, ex); resumeAsyncResponseExceptionally(asyncResponse, ex); return null; }); } @POST @Path("/revokePermissions") public void revokePermissionOnTopics(@Suspended final AsyncResponse asyncResponse, List<RevokeTopicPermissionOptions> options) { internalRevokePermissionsAsync(options) .thenAccept(__ -> asyncResponse.resume(Response.noContent().build())) .exceptionally(ex -> { log.error("[{}] Failed to revoke permissions {}", clientAppId(), options, ex); resumeAsyncResponseExceptionally(asyncResponse, ex); return null; }); }
so user can grant/revoke permissions to multi-topics like :
public class TestAuthorization { @Test public void testGrantPermission() { // grant permission for multi-topics List<GrantPermissionOptions> grantPermissions = new ArrayList<>(); grantPermissions.add(GrantPermissionOptions.builder().topic("topic1").role("role1").actions(Set.of(AuthAction.produce)).build()); grantPermissions.add(GrantPermissionOptions.builder().topic("topic2").role("role2").actions(Set.of(AuthAction.consume)).build()); admin.namespaces().grantPermissionOnTopics(grantPermissions); // revoke permission topics List<RevokePermissionOptions> revokePermissions = new ArrayList<>(); revokePermissions.add(RevokePermissionOptions.builder().topic("topic1").role("role1").build()); revokePermissions.add(RevokePermissionOptions.builder().topic("topic2").role("role2").build()); admin.namespaces().revokePermissionOnTopics(revokePermissions); } }