Skip to content

Commit 07609e6

Browse files
Technoboy-srinath-ctds
authored andcommitted
[improve][broker] Add fine-grain authorization to ns/topic management endpoints (apache#22305)
(cherry picked from commit fd34d4a) Conflicts: pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/PersistentTopicsBase.java
1 parent 0ca7265 commit 07609e6

File tree

6 files changed

+683
-171
lines changed

6 files changed

+683
-171
lines changed

pulsar-broker-common/src/main/java/org/apache/pulsar/broker/authorization/PulsarAuthorizationProvider.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -597,6 +597,7 @@ public CompletableFuture<Boolean> allowTopicOperationAsync(TopicName topicName,
597597
case COMPACT:
598598
case OFFLOAD:
599599
case UNLOAD:
600+
case TRIM_TOPIC:
600601
case DELETE_METADATA:
601602
case UPDATE_METADATA:
602603
case ADD_BUNDLE_RANGE:

pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/AdminResource.java

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,6 @@
6060
import org.apache.pulsar.common.policies.data.NamespaceOperation;
6161
import org.apache.pulsar.common.policies.data.PersistencePolicies;
6262
import org.apache.pulsar.common.policies.data.Policies;
63-
import org.apache.pulsar.common.policies.data.PolicyName;
64-
import org.apache.pulsar.common.policies.data.PolicyOperation;
6563
import org.apache.pulsar.common.policies.data.RetentionPolicies;
6664
import org.apache.pulsar.common.policies.data.SchemaCompatibilityStrategy;
6765
import org.apache.pulsar.common.policies.data.SubscribeRate;
@@ -711,10 +709,7 @@ private CompletableFuture<Void> provisionPartitionedTopicPath(int numPartitions,
711709
}
712710

713711
protected CompletableFuture<SchemaCompatibilityStrategy> getSchemaCompatibilityStrategyAsync() {
714-
return validateTopicPolicyOperationAsync(topicName,
715-
PolicyName.SCHEMA_COMPATIBILITY_STRATEGY,
716-
PolicyOperation.READ)
717-
.thenCompose((__) -> getSchemaCompatibilityStrategyAsyncWithoutAuth()).whenComplete((__, ex) -> {
712+
return getSchemaCompatibilityStrategyAsyncWithoutAuth().whenComplete((__, ex) -> {
718713
if (ex != null) {
719714
log.error("[{}] Failed to get schema compatibility strategy of topic {} {}",
720715
clientAppId(), topicName, ex);

pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/NamespacesBase.java

Lines changed: 87 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -2354,102 +2354,110 @@ protected void internalSetMaxTopicsPerNamespace(Integer maxTopicsPerNamespace) {
23542354
}
23552355

23562356
protected void internalSetProperty(String key, String value, AsyncResponse asyncResponse) {
2357-
validatePoliciesReadOnlyAccess();
2358-
updatePoliciesAsync(namespaceName, policies -> {
2359-
policies.properties.put(key, value);
2360-
return policies;
2361-
}).thenAccept(v -> {
2362-
log.info("[{}] Successfully set property for key {} on namespace {}", clientAppId(), key,
2363-
namespaceName);
2364-
asyncResponse.resume(Response.noContent().build());
2365-
}).exceptionally(ex -> {
2366-
Throwable cause = ex.getCause();
2367-
log.error("[{}] Failed to set property for key {} on namespace {}", clientAppId(), key,
2368-
namespaceName, cause);
2369-
asyncResponse.resume(cause);
2370-
return null;
2371-
});
2357+
validateAdminAccessForTenantAsync(namespaceName.getTenant())
2358+
.thenCompose(__ -> validatePoliciesReadOnlyAccessAsync())
2359+
.thenCompose(__ -> updatePoliciesAsync(namespaceName, policies -> {
2360+
policies.properties.put(key, value);
2361+
return policies;
2362+
}))
2363+
.thenAccept(v -> {
2364+
log.info("[{}] Successfully set property for key {} on namespace {}", clientAppId(), key,
2365+
namespaceName);
2366+
asyncResponse.resume(Response.noContent().build());
2367+
}).exceptionally(ex -> {
2368+
Throwable cause = ex.getCause();
2369+
log.error("[{}] Failed to set property for key {} on namespace {}", clientAppId(), key,
2370+
namespaceName, cause);
2371+
asyncResponse.resume(cause);
2372+
return null;
2373+
});
23722374
}
23732375

23742376
protected void internalSetProperties(Map<String, String> properties, AsyncResponse asyncResponse) {
2375-
validatePoliciesReadOnlyAccess();
2376-
updatePoliciesAsync(namespaceName, policies -> {
2377-
policies.properties.putAll(properties);
2378-
return policies;
2379-
}).thenAccept(v -> {
2380-
log.info("[{}] Successfully set {} properties on namespace {}", clientAppId(), properties.size(),
2381-
namespaceName);
2382-
asyncResponse.resume(Response.noContent().build());
2383-
}).exceptionally(ex -> {
2384-
Throwable cause = ex.getCause();
2385-
log.error("[{}] Failed to set {} properties on namespace {}", clientAppId(), properties.size(),
2386-
namespaceName, cause);
2387-
asyncResponse.resume(cause);
2388-
return null;
2389-
});
2377+
validateAdminAccessForTenantAsync(namespaceName.getTenant())
2378+
.thenCompose(__ -> validatePoliciesReadOnlyAccessAsync())
2379+
.thenCompose(__ -> updatePoliciesAsync(namespaceName, policies -> {
2380+
policies.properties.putAll(properties);
2381+
return policies;
2382+
}))
2383+
.thenAccept(v -> {
2384+
log.info("[{}] Successfully set {} properties on namespace {}", clientAppId(), properties.size(),
2385+
namespaceName);
2386+
asyncResponse.resume(Response.noContent().build());
2387+
}).exceptionally(ex -> {
2388+
Throwable cause = ex.getCause();
2389+
log.error("[{}] Failed to set {} properties on namespace {}", clientAppId(), properties.size(),
2390+
namespaceName, cause);
2391+
asyncResponse.resume(cause);
2392+
return null;
2393+
});
23902394
}
23912395

23922396
protected void internalGetProperty(String key, AsyncResponse asyncResponse) {
2393-
getNamespacePoliciesAsync(namespaceName).thenAccept(policies -> {
2394-
asyncResponse.resume(policies.properties.get(key));
2395-
}).exceptionally(ex -> {
2396-
Throwable cause = ex.getCause();
2397-
log.error("[{}] Failed to get property for key {} of namespace {}", clientAppId(), key,
2398-
namespaceName, cause);
2399-
asyncResponse.resume(cause);
2400-
return null;
2401-
});
2397+
validateAdminAccessForTenantAsync(namespaceName.getTenant())
2398+
.thenCompose(__ -> getNamespacePoliciesAsync(namespaceName))
2399+
.thenAccept(policies -> asyncResponse.resume(policies.properties.get(key)))
2400+
.exceptionally(ex -> {
2401+
Throwable cause = ex.getCause();
2402+
log.error("[{}] Failed to get property for key {} of namespace {}", clientAppId(), key,
2403+
namespaceName, cause);
2404+
asyncResponse.resume(cause);
2405+
return null;
2406+
});
24022407
}
24032408

24042409
protected void internalGetProperties(AsyncResponse asyncResponse) {
2405-
getNamespacePoliciesAsync(namespaceName).thenAccept(policies -> {
2406-
asyncResponse.resume(policies.properties);
2407-
}).exceptionally(ex -> {
2408-
Throwable cause = ex.getCause();
2409-
log.error("[{}] Failed to get properties of namespace {}", clientAppId(), namespaceName, cause);
2410-
asyncResponse.resume(cause);
2411-
return null;
2412-
});
2410+
validateAdminAccessForTenantAsync(namespaceName.getTenant())
2411+
.thenCompose(__ -> getNamespacePoliciesAsync(namespaceName))
2412+
.thenAccept(policies -> asyncResponse.resume(policies.properties))
2413+
.exceptionally(ex -> {
2414+
Throwable cause = ex.getCause();
2415+
log.error("[{}] Failed to get properties of namespace {}", clientAppId(), namespaceName, cause);
2416+
asyncResponse.resume(cause);
2417+
return null;
2418+
});
24132419
}
24142420

24152421
protected void internalRemoveProperty(String key, AsyncResponse asyncResponse) {
2416-
validatePoliciesReadOnlyAccess();
2417-
24182422
AtomicReference<String> oldVal = new AtomicReference<>(null);
2419-
updatePoliciesAsync(namespaceName, policies -> {
2420-
oldVal.set(policies.properties.remove(key));
2421-
return policies;
2422-
}).thenAccept(v -> {
2423-
asyncResponse.resume(oldVal.get());
2424-
log.info("[{}] Successfully remove property for key {} on namespace {}", clientAppId(), key,
2425-
namespaceName);
2426-
}).exceptionally(ex -> {
2427-
Throwable cause = ex.getCause();
2428-
log.error("[{}] Failed to remove property for key {} on namespace {}", clientAppId(), key,
2429-
namespaceName, cause);
2430-
asyncResponse.resume(cause);
2431-
return null;
2432-
});
2423+
validateAdminAccessForTenantAsync(namespaceName.getTenant())
2424+
.thenCompose(__ -> validatePoliciesReadOnlyAccessAsync())
2425+
.thenCompose(__ -> updatePoliciesAsync(namespaceName, policies -> {
2426+
oldVal.set(policies.properties.remove(key));
2427+
return policies;
2428+
})).thenAccept(v -> {
2429+
asyncResponse.resume(oldVal.get());
2430+
log.info("[{}] Successfully remove property for key {} on namespace {}", clientAppId(), key,
2431+
namespaceName);
2432+
}).exceptionally(ex -> {
2433+
Throwable cause = ex.getCause();
2434+
log.error("[{}] Failed to remove property for key {} on namespace {}", clientAppId(), key,
2435+
namespaceName, cause);
2436+
asyncResponse.resume(cause);
2437+
return null;
2438+
});
24332439
}
24342440

24352441
protected void internalClearProperties(AsyncResponse asyncResponse) {
2436-
validatePoliciesReadOnlyAccess();
24372442
AtomicReference<Integer> clearedCount = new AtomicReference<>(0);
2438-
updatePoliciesAsync(namespaceName, policies -> {
2439-
clearedCount.set(policies.properties.size());
2440-
policies.properties.clear();
2441-
return policies;
2442-
}).thenAccept(v -> {
2443-
asyncResponse.resume(Response.noContent().build());
2444-
log.info("[{}] Successfully clear {} properties on namespace {}", clientAppId(), clearedCount.get(),
2445-
namespaceName);
2446-
}).exceptionally(ex -> {
2447-
Throwable cause = ex.getCause();
2448-
log.error("[{}] Failed to clear {} properties on namespace {}", clientAppId(), clearedCount.get(),
2449-
namespaceName, cause);
2450-
asyncResponse.resume(cause);
2451-
return null;
2452-
});
2443+
validateAdminAccessForTenantAsync(namespaceName.getTenant())
2444+
.thenCompose(__ -> validatePoliciesReadOnlyAccessAsync())
2445+
.thenCompose(__ -> updatePoliciesAsync(namespaceName, policies -> {
2446+
clearedCount.set(policies.properties.size());
2447+
policies.properties.clear();
2448+
return policies;
2449+
}))
2450+
.thenAccept(v -> {
2451+
asyncResponse.resume(Response.noContent().build());
2452+
log.info("[{}] Successfully clear {} properties on namespace {}", clientAppId(), clearedCount.get(),
2453+
namespaceName);
2454+
}).exceptionally(ex -> {
2455+
Throwable cause = ex.getCause();
2456+
log.error("[{}] Failed to clear {} properties on namespace {}", clientAppId(), clearedCount.get(),
2457+
namespaceName, cause);
2458+
asyncResponse.resume(cause);
2459+
return null;
2460+
});
24532461
}
24542462

24552463
private CompletableFuture<Void> updatePoliciesAsync(NamespaceName ns, Function<Policies, Policies> updateFunction) {

0 commit comments

Comments
 (0)