Skip to content

Commit 7f31505

Browse files
authored
Implement PolicyCatalogHandler and Add Policy Privileges Stage 2: AttachPolicy + DetachPolicy (#1416)
* add auth test for attach/detach * apply formatter * refactor authorizePolicyAttachmentOperation * address comment * better naming
1 parent 4d4a71e commit 7f31505

File tree

7 files changed

+689
-16
lines changed

7 files changed

+689
-16
lines changed

polaris-core/src/main/java/org/apache/polaris/core/auth/PolarisAuthorizableOperation.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@
1818
*/
1919
package org.apache.polaris.core.auth;
2020

21+
import static org.apache.polaris.core.entity.PolarisPrivilege.CATALOG_ATTACH_POLICY;
2122
import static org.apache.polaris.core.entity.PolarisPrivilege.CATALOG_CREATE;
23+
import static org.apache.polaris.core.entity.PolarisPrivilege.CATALOG_DETACH_POLICY;
2224
import static org.apache.polaris.core.entity.PolarisPrivilege.CATALOG_DROP;
2325
import static org.apache.polaris.core.entity.PolarisPrivilege.CATALOG_LIST;
2426
import static org.apache.polaris.core.entity.PolarisPrivilege.CATALOG_LIST_GRANTS;
@@ -33,14 +35,18 @@
3335
import static org.apache.polaris.core.entity.PolarisPrivilege.CATALOG_ROLE_READ_PROPERTIES;
3436
import static org.apache.polaris.core.entity.PolarisPrivilege.CATALOG_ROLE_WRITE_PROPERTIES;
3537
import static org.apache.polaris.core.entity.PolarisPrivilege.CATALOG_WRITE_PROPERTIES;
38+
import static org.apache.polaris.core.entity.PolarisPrivilege.NAMESPACE_ATTACH_POLICY;
3639
import static org.apache.polaris.core.entity.PolarisPrivilege.NAMESPACE_CREATE;
40+
import static org.apache.polaris.core.entity.PolarisPrivilege.NAMESPACE_DETACH_POLICY;
3741
import static org.apache.polaris.core.entity.PolarisPrivilege.NAMESPACE_DROP;
3842
import static org.apache.polaris.core.entity.PolarisPrivilege.NAMESPACE_LIST;
3943
import static org.apache.polaris.core.entity.PolarisPrivilege.NAMESPACE_LIST_GRANTS;
4044
import static org.apache.polaris.core.entity.PolarisPrivilege.NAMESPACE_MANAGE_GRANTS_ON_SECURABLE;
4145
import static org.apache.polaris.core.entity.PolarisPrivilege.NAMESPACE_READ_PROPERTIES;
4246
import static org.apache.polaris.core.entity.PolarisPrivilege.NAMESPACE_WRITE_PROPERTIES;
47+
import static org.apache.polaris.core.entity.PolarisPrivilege.POLICY_ATTACH;
4348
import static org.apache.polaris.core.entity.PolarisPrivilege.POLICY_CREATE;
49+
import static org.apache.polaris.core.entity.PolarisPrivilege.POLICY_DETACH;
4450
import static org.apache.polaris.core.entity.PolarisPrivilege.POLICY_DROP;
4551
import static org.apache.polaris.core.entity.PolarisPrivilege.POLICY_LIST;
4652
import static org.apache.polaris.core.entity.PolarisPrivilege.POLICY_READ;
@@ -64,7 +70,9 @@
6470
import static org.apache.polaris.core.entity.PolarisPrivilege.PRINCIPAL_ROTATE_CREDENTIALS;
6571
import static org.apache.polaris.core.entity.PolarisPrivilege.PRINCIPAL_WRITE_PROPERTIES;
6672
import static org.apache.polaris.core.entity.PolarisPrivilege.SERVICE_MANAGE_ACCESS;
73+
import static org.apache.polaris.core.entity.PolarisPrivilege.TABLE_ATTACH_POLICY;
6774
import static org.apache.polaris.core.entity.PolarisPrivilege.TABLE_CREATE;
75+
import static org.apache.polaris.core.entity.PolarisPrivilege.TABLE_DETACH_POLICY;
6876
import static org.apache.polaris.core.entity.PolarisPrivilege.TABLE_DROP;
6977
import static org.apache.polaris.core.entity.PolarisPrivilege.TABLE_LIST;
7078
import static org.apache.polaris.core.entity.PolarisPrivilege.TABLE_LIST_GRANTS;
@@ -192,6 +200,16 @@ public enum PolarisAuthorizableOperation {
192200
DROP_POLICY(POLICY_DROP),
193201
UPDATE_POLICY(POLICY_WRITE),
194202
LIST_POLICY(POLICY_LIST),
203+
ATTACH_POLICY_TO_CATALOG(POLICY_ATTACH, CATALOG_ATTACH_POLICY),
204+
ATTACH_POLICY_TO_NAMESPACE(POLICY_ATTACH, NAMESPACE_ATTACH_POLICY),
205+
ATTACH_POLICY_TO_TABLE(POLICY_ATTACH, TABLE_ATTACH_POLICY),
206+
DETACH_POLICY_FROM_CATALOG(POLICY_DETACH, CATALOG_DETACH_POLICY),
207+
DETACH_POLICY_FROM_NAMESPACE(POLICY_DETACH, NAMESPACE_DETACH_POLICY),
208+
DETACH_POLICY_FROM_TABLE(POLICY_DETACH, TABLE_DETACH_POLICY),
209+
GET_APPLICABLE_POLICIES_ON_CATALOG(CATALOG_READ_PROPERTIES),
210+
GET_APPLICABLE_POLICIES_ON_NAMESPACE(NAMESPACE_READ_PROPERTIES),
211+
GET_APPLICABLE_POLICIES_ON_TABLE(TABLE_READ_PROPERTIES),
212+
GET_APPLICABLE_POLICIES_ON_VIEW(VIEW_READ_PROPERTIES),
195213
;
196214

197215
private final EnumSet<PolarisPrivilege> privilegesOnTarget;

polaris-core/src/main/java/org/apache/polaris/core/auth/PolarisAuthorizerImpl.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@
1818
*/
1919
package org.apache.polaris.core.auth;
2020

21+
import static org.apache.polaris.core.entity.PolarisPrivilege.CATALOG_ATTACH_POLICY;
2122
import static org.apache.polaris.core.entity.PolarisPrivilege.CATALOG_CREATE;
23+
import static org.apache.polaris.core.entity.PolarisPrivilege.CATALOG_DETACH_POLICY;
2224
import static org.apache.polaris.core.entity.PolarisPrivilege.CATALOG_DROP;
2325
import static org.apache.polaris.core.entity.PolarisPrivilege.CATALOG_FULL_METADATA;
2426
import static org.apache.polaris.core.entity.PolarisPrivilege.CATALOG_LIST;
@@ -39,15 +41,19 @@
3941
import static org.apache.polaris.core.entity.PolarisPrivilege.CATALOG_ROLE_USAGE;
4042
import static org.apache.polaris.core.entity.PolarisPrivilege.CATALOG_ROLE_WRITE_PROPERTIES;
4143
import static org.apache.polaris.core.entity.PolarisPrivilege.CATALOG_WRITE_PROPERTIES;
44+
import static org.apache.polaris.core.entity.PolarisPrivilege.NAMESPACE_ATTACH_POLICY;
4245
import static org.apache.polaris.core.entity.PolarisPrivilege.NAMESPACE_CREATE;
46+
import static org.apache.polaris.core.entity.PolarisPrivilege.NAMESPACE_DETACH_POLICY;
4347
import static org.apache.polaris.core.entity.PolarisPrivilege.NAMESPACE_DROP;
4448
import static org.apache.polaris.core.entity.PolarisPrivilege.NAMESPACE_FULL_METADATA;
4549
import static org.apache.polaris.core.entity.PolarisPrivilege.NAMESPACE_LIST;
4650
import static org.apache.polaris.core.entity.PolarisPrivilege.NAMESPACE_LIST_GRANTS;
4751
import static org.apache.polaris.core.entity.PolarisPrivilege.NAMESPACE_MANAGE_GRANTS_ON_SECURABLE;
4852
import static org.apache.polaris.core.entity.PolarisPrivilege.NAMESPACE_READ_PROPERTIES;
4953
import static org.apache.polaris.core.entity.PolarisPrivilege.NAMESPACE_WRITE_PROPERTIES;
54+
import static org.apache.polaris.core.entity.PolarisPrivilege.POLICY_ATTACH;
5055
import static org.apache.polaris.core.entity.PolarisPrivilege.POLICY_CREATE;
56+
import static org.apache.polaris.core.entity.PolarisPrivilege.POLICY_DETACH;
5157
import static org.apache.polaris.core.entity.PolarisPrivilege.POLICY_DROP;
5258
import static org.apache.polaris.core.entity.PolarisPrivilege.POLICY_FULL_METADATA;
5359
import static org.apache.polaris.core.entity.PolarisPrivilege.POLICY_LIST;
@@ -75,7 +81,9 @@
7581
import static org.apache.polaris.core.entity.PolarisPrivilege.PRINCIPAL_ROTATE_CREDENTIALS;
7682
import static org.apache.polaris.core.entity.PolarisPrivilege.PRINCIPAL_WRITE_PROPERTIES;
7783
import static org.apache.polaris.core.entity.PolarisPrivilege.SERVICE_MANAGE_ACCESS;
84+
import static org.apache.polaris.core.entity.PolarisPrivilege.TABLE_ATTACH_POLICY;
7885
import static org.apache.polaris.core.entity.PolarisPrivilege.TABLE_CREATE;
86+
import static org.apache.polaris.core.entity.PolarisPrivilege.TABLE_DETACH_POLICY;
7987
import static org.apache.polaris.core.entity.PolarisPrivilege.TABLE_DROP;
8088
import static org.apache.polaris.core.entity.PolarisPrivilege.TABLE_FULL_METADATA;
8189
import static org.apache.polaris.core.entity.PolarisPrivilege.TABLE_LIST;
@@ -495,6 +503,20 @@ public class PolarisAuthorizerImpl implements PolarisAuthorizer {
495503
POLICY_FULL_METADATA,
496504
CATALOG_MANAGE_METADATA,
497505
CATALOG_MANAGE_CONTENT));
506+
SUPER_PRIVILEGES.putAll(POLICY_ATTACH, List.of(POLICY_ATTACH, CATALOG_MANAGE_CONTENT));
507+
SUPER_PRIVILEGES.putAll(POLICY_DETACH, List.of(POLICY_DETACH, CATALOG_MANAGE_CONTENT));
508+
SUPER_PRIVILEGES.putAll(
509+
CATALOG_ATTACH_POLICY, List.of(CATALOG_ATTACH_POLICY, CATALOG_MANAGE_CONTENT));
510+
SUPER_PRIVILEGES.putAll(
511+
NAMESPACE_ATTACH_POLICY, List.of(NAMESPACE_ATTACH_POLICY, CATALOG_MANAGE_CONTENT));
512+
SUPER_PRIVILEGES.putAll(
513+
TABLE_ATTACH_POLICY, List.of(TABLE_ATTACH_POLICY, CATALOG_MANAGE_CONTENT));
514+
SUPER_PRIVILEGES.putAll(
515+
CATALOG_DETACH_POLICY, List.of(CATALOG_DETACH_POLICY, CATALOG_MANAGE_CONTENT));
516+
SUPER_PRIVILEGES.putAll(
517+
NAMESPACE_DETACH_POLICY, List.of(NAMESPACE_DETACH_POLICY, CATALOG_MANAGE_CONTENT));
518+
SUPER_PRIVILEGES.putAll(
519+
TABLE_DETACH_POLICY, List.of(TABLE_DETACH_POLICY, CATALOG_MANAGE_CONTENT));
498520
}
499521

500522
private final PolarisConfigurationStore featureConfig;

polaris-core/src/main/java/org/apache/polaris/core/entity/PolarisPrivilege.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,14 @@ public enum PolarisPrivilege {
142142
POLICY_WRITE(73, PolarisEntityType.POLICY),
143143
POLICY_LIST(74, PolarisEntityType.NAMESPACE),
144144
POLICY_FULL_METADATA(75, PolarisEntityType.POLICY),
145+
POLICY_ATTACH(76, PolarisEntityType.POLICY),
146+
POLICY_DETACH(77, PolarisEntityType.POLICY),
147+
CATALOG_ATTACH_POLICY(78, PolarisEntityType.CATALOG),
148+
NAMESPACE_ATTACH_POLICY(79, PolarisEntityType.NAMESPACE),
149+
TABLE_ATTACH_POLICY(80, PolarisEntityType.TABLE_LIKE, PolarisEntitySubType.ICEBERG_TABLE),
150+
CATALOG_DETACH_POLICY(81, PolarisEntityType.CATALOG),
151+
NAMESPACE_DETACH_POLICY(82, PolarisEntityType.NAMESPACE),
152+
TABLE_DETACH_POLICY(83, PolarisEntityType.TABLE_LIKE, PolarisEntitySubType.ICEBERG_TABLE),
145153
;
146154

147155
/**

quarkus/service/src/test/java/org/apache/polaris/service/quarkus/admin/PolarisAuthzTestBase.java

Lines changed: 36 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -627,24 +627,44 @@ protected void doTestInsufficientPrivileges(
627627
Runnable action,
628628
Function<PolarisPrivilege, Boolean> grantAction,
629629
Function<PolarisPrivilege, Boolean> revokeAction) {
630-
for (PolarisPrivilege privilege : insufficientPrivileges) {
631-
// Grant the single privilege at a catalog level to cascade to all objects.
632-
Assertions.assertThat(grantAction.apply(privilege)).isTrue();
630+
doTestInsufficientPrivilegeSets(
631+
insufficientPrivileges.stream().map(priv -> Set.of(priv)).toList(),
632+
principalName,
633+
action,
634+
grantAction,
635+
revokeAction);
636+
}
633637

634-
// Should be insufficient
635-
try {
636-
Assertions.assertThatThrownBy(() -> action.run())
637-
.isInstanceOf(ForbiddenException.class)
638-
.hasMessageContaining(principalName)
639-
.hasMessageContaining("is not authorized");
640-
} catch (Throwable t) {
641-
Assertions.fail(
642-
String.format("Expected failure with insufficientPrivilege '%s'", privilege), t);
643-
}
638+
/**
639+
* Tests each "insufficient" privilege individually using CATALOG_ROLE1 by granting at the
640+
* CATALOG_NAME level, ensuring the action fails, then revoking after each test case.
641+
*/
642+
protected void doTestInsufficientPrivilegeSets(
643+
List<Set<PolarisPrivilege>> insufficientPrivilegeSets,
644+
String principalName,
645+
Runnable action,
646+
Function<PolarisPrivilege, Boolean> grantAction,
647+
Function<PolarisPrivilege, Boolean> revokeAction) {
648+
for (Set<PolarisPrivilege> privilegeSet : insufficientPrivilegeSets) {
649+
for (PolarisPrivilege privilege : privilegeSet) {
650+
// Grant the single privilege at a catalog level to cascade to all objects.
651+
Assertions.assertThat(grantAction.apply(privilege)).isTrue();
644652

645-
// Revoking only matters in case there are some multi-privilege actions being tested with
646-
// only granting individual privileges in isolation.
647-
Assertions.assertThat(revokeAction.apply(privilege)).isTrue();
653+
// Should be insufficient
654+
try {
655+
Assertions.assertThatThrownBy(() -> action.run())
656+
.isInstanceOf(ForbiddenException.class)
657+
.hasMessageContaining(principalName)
658+
.hasMessageContaining("is not authorized");
659+
} catch (Throwable t) {
660+
Assertions.fail(
661+
String.format("Expected failure with insufficientPrivilege '%s'", privilege), t);
662+
}
663+
664+
// Revoking only matters in case there are some multi-privilege actions being tested with
665+
// only granting individual privileges in isolation.
666+
Assertions.assertThat(revokeAction.apply(privilege)).isTrue();
667+
}
648668
}
649669
}
650670
}

0 commit comments

Comments
 (0)