Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,13 @@
import java.time.Clock;
import java.time.Duration;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import org.apache.polaris.core.auth.PolarisAuthorizableOperation;
import org.apache.polaris.core.auth.PolarisPrincipal;
import org.apache.polaris.core.collection.AttributeMap;
import org.apache.polaris.core.collection.AttributeMap.AttributeKey;
import org.apache.polaris.core.collection.ImmutableAttributeMap;
import org.apache.polaris.core.config.RealmConfig;
import org.apache.polaris.core.context.RealmContext;
import org.apache.polaris.core.entity.PolarisBaseEntity;
Expand Down Expand Up @@ -221,7 +223,8 @@ public void testFactoryPassesRealmToAuthorizerContext() throws Exception {
OpaPolarisAuthorizer authorizer =
(OpaPolarisAuthorizer) factory.create(mock(RealmConfig.class));

PolarisPrincipal principal = PolarisPrincipal.of("alice", Map.of(), Set.of("admin"));
PolarisPrincipal principal =
PolarisPrincipal.of("alice", AttributeMap.EMPTY, Set.of("admin"));
assertThatNoException()
.isThrownBy(
() ->
Expand Down Expand Up @@ -277,7 +280,8 @@ public void testFactoryUsesDistinctRealmValues() throws Exception {
OpaPolarisAuthorizer authorizer =
(OpaPolarisAuthorizer) factory.create(mock(RealmConfig.class));

PolarisPrincipal principal = PolarisPrincipal.of("alice", Map.of(), Set.of("admin"));
PolarisPrincipal principal =
PolarisPrincipal.of("alice", AttributeMap.EMPTY, Set.of("admin"));
assertThatNoException()
.isThrownBy(
() ->
Expand Down Expand Up @@ -337,7 +341,12 @@ public void testFactoryPassesResolvedRequestIdToAuthorizerContext() throws Excep
OpaPolarisAuthorizer authorizer = (OpaPolarisAuthorizer) factory.create(realmConfig);

PolarisPrincipal principal =
PolarisPrincipal.of("eve", Map.of("department", "finance"), Set.of("auditor"));
PolarisPrincipal.of(
"eve",
ImmutableAttributeMap.builder()
.put(new AttributeKey<>("department"), "finance")
.build(),
Set.of("auditor"));
PolarisResolvedPathWrapper target = new PolarisResolvedPathWrapper(List.of());
PolarisResolvedPathWrapper secondary = new PolarisResolvedPathWrapper(List.of());

Expand Down Expand Up @@ -401,7 +410,12 @@ public void testFactoryResolvesFreshRequestIdPerCreateCall() throws Exception {

RealmConfig realmConfig = mock(RealmConfig.class);
PolarisPrincipal principal =
PolarisPrincipal.of("eve", Map.of("department", "finance"), Set.of("auditor"));
PolarisPrincipal.of(
"eve",
ImmutableAttributeMap.builder()
.put(new AttributeKey<>("department"), "finance")
.build(),
Set.of("auditor"));
PolarisResolvedPathWrapper target = new PolarisResolvedPathWrapper(List.of());
PolarisResolvedPathWrapper secondary = new PolarisResolvedPathWrapper(List.of());

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import org.apache.hc.client5.http.classic.methods.HttpPost;
Expand All @@ -59,6 +58,9 @@
import org.apache.polaris.core.auth.PolarisSecurable;
import org.apache.polaris.core.auth.RenameAuthorizationIntent;
import org.apache.polaris.core.auth.SingleTargetAuthorizationIntent;
import org.apache.polaris.core.collection.AttributeMap;
import org.apache.polaris.core.collection.AttributeMap.AttributeKey;
import org.apache.polaris.core.collection.ImmutableAttributeMap;
import org.apache.polaris.core.entity.PolarisBaseEntity;
import org.apache.polaris.core.entity.PolarisEntity;
import org.apache.polaris.core.entity.PolarisEntityConstants;
Expand Down Expand Up @@ -96,7 +98,12 @@ void serializesBasicOpaInput() throws Exception {
"test-realm");

PolarisPrincipal principal =
PolarisPrincipal.of("eve", Map.of("department", "finance"), Set.of("auditor"));
PolarisPrincipal.of(
"eve",
ImmutableAttributeMap.builder()
.put(new AttributeKey<>("department"), "finance")
.build(),
Set.of("auditor"));

Set<PolarisBaseEntity> entities = Set.of();
PolarisResolvedPathWrapper target = new PolarisResolvedPathWrapper(List.of());
Expand Down Expand Up @@ -153,7 +160,10 @@ void serializesHierarchicalTarget() throws Exception {
PolarisPrincipal principal =
PolarisPrincipal.of(
"alice",
Map.of("department", "analytics", "level", "senior"),
ImmutableAttributeMap.builder()
.put(new AttributeKey<>("department"), "analytics")
.put(new AttributeKey<>("level"), "senior")
.build(),
Set.of("data_engineer", "analyst"));

// Create a hierarchical resource structure: catalog.namespace.table
Expand Down Expand Up @@ -293,7 +303,10 @@ void serializesMultiLevelNamespaceTarget() throws Exception {
PolarisPrincipal principal =
PolarisPrincipal.of(
"bob",
Map.of("team", "ml", "project", "forecasting"),
ImmutableAttributeMap.builder()
.put(new AttributeKey<>("team"), "ml")
.put(new AttributeKey<>("project"), "forecasting")
.build(),
Set.of("data_scientist", "analyst"));

// Create a multi-level namespace structure: catalog.department.team.table
Expand Down Expand Up @@ -462,7 +475,8 @@ void authorizeOrThrowHandlesEmptyTargetsAndSecondaries() throws Exception {
null,
"test-realm");

PolarisPrincipal principal = PolarisPrincipal.of("alice", Map.of(), Set.of("admin"));
PolarisPrincipal principal =
PolarisPrincipal.of("alice", AttributeMap.EMPTY, Set.of("admin"));

Set<PolarisBaseEntity> entities = Set.of();

Expand Down Expand Up @@ -545,7 +559,7 @@ <T> T httpClientExecute(
};

PolarisPrincipal mockPrincipal =
PolarisPrincipal.of("test-user", Map.of(), Collections.emptySet());
PolarisPrincipal.of("test-user", AttributeMap.EMPTY, Collections.emptySet());

PolarisAuthorizableOperation mockOperation = PolarisAuthorizableOperation.LOAD_TABLE;
PolarisResolvedPathWrapper target = null;
Expand Down Expand Up @@ -591,7 +605,7 @@ <T> T httpClientExecute(

// Create mock principal and entities
PolarisPrincipal mockPrincipal =
PolarisPrincipal.of("test-user", Map.of(), Collections.emptySet());
PolarisPrincipal.of("test-user", AttributeMap.EMPTY, Collections.emptySet());

PolarisAuthorizableOperation mockOperation = PolarisAuthorizableOperation.LOAD_TABLE;
PolarisResolvedPathWrapper target = null;
Expand Down Expand Up @@ -620,7 +634,7 @@ void resolveAuthorizationInputsResolvesAll() {
"test-realm");
PolarisResolutionManifest resolutionManifest = mock(PolarisResolutionManifest.class);
AuthorizationState authzState = new AuthorizationState(resolutionManifest);
PolarisPrincipal principal = PolarisPrincipal.of("alice", Map.of(), Set.of("role-1"));
PolarisPrincipal principal = PolarisPrincipal.of("alice", AttributeMap.EMPTY, Set.of("role-1"));

authorizer.resolveAuthorizationInputs(authzState, requestWithCatalogTarget(principal));

Expand All @@ -630,7 +644,7 @@ void resolveAuthorizationInputsResolvesAll() {
@Test
void authorizeUsesIntentInputsAndAllows() throws Exception {
final String[] capturedRequestBody = new String[1];
PolarisPrincipal principal = PolarisPrincipal.of("alice", Map.of(), Set.of("role-1"));
PolarisPrincipal principal = PolarisPrincipal.of("alice", AttributeMap.EMPTY, Set.of("role-1"));
AuthorizationRequest request = requestWithCatalogTarget(principal);
HttpEntity mockEntity = HttpEntities.create("{\"result\":{\"allow\":true}}");
@SuppressWarnings("resource")
Expand Down Expand Up @@ -680,7 +694,7 @@ <T> T httpClientExecute(

@Test
void authorizeDeniesWhenOpaDenies() {
PolarisPrincipal principal = PolarisPrincipal.of("alice", Map.of(), Set.of("role-1"));
PolarisPrincipal principal = PolarisPrincipal.of("alice", AttributeMap.EMPTY, Set.of("role-1"));
AuthorizationRequest request = requestWithCatalogTarget(principal);
HttpEntity mockEntity = HttpEntities.create("{\"result\":{\"allow\":false}}");
@SuppressWarnings("resource")
Expand Down Expand Up @@ -722,7 +736,7 @@ void authorizeIncludesStructuredParentsFromSecurable() throws Exception {
final String[] capturedRequestBody = new String[1];
AuthorizationRequest request =
new AuthorizationRequest(
PolarisPrincipal.of("alice", Map.of(), Set.of("role-1")),
PolarisPrincipal.of("alice", AttributeMap.EMPTY, Set.of("role-1")),
List.of(
new SingleTargetAuthorizationIntent(
PolarisAuthorizableOperation.LOAD_TABLE,
Expand Down Expand Up @@ -820,7 +834,7 @@ void authorizeResolvedCatalogTargetPreservesRootParent() throws Exception {
.isThrownBy(
() ->
authorizer.authorizeOrThrow(
PolarisPrincipal.of("root", Map.of(), Set.of("service_admin")),
PolarisPrincipal.of("root", AttributeMap.EMPTY, Set.of("service_admin")),
Set.of(),
PolarisAuthorizableOperation.GET_CATALOG,
new PolarisResolvedPathWrapper(
Expand Down Expand Up @@ -885,7 +899,7 @@ void authorizeRootScopedOperationSerializesRootTarget() throws Exception {
.isThrownBy(
() ->
authorizer.authorizeOrThrow(
PolarisPrincipal.of("root", Map.of(), Set.of("service_admin")),
PolarisPrincipal.of("root", AttributeMap.EMPTY, Set.of("service_admin")),
Set.of(),
PolarisAuthorizableOperation.LIST_CATALOGS,
new PolarisResolvedPathWrapper(List.of(createResolvedEntity(rootEntity))),
Expand Down Expand Up @@ -922,7 +936,7 @@ void authorizeRenameIncludesTargetAndSecondaryPaths() throws Exception {

AuthorizationRequest request =
new AuthorizationRequest(
PolarisPrincipal.of("alice", Map.of(), Set.of("role-1")),
PolarisPrincipal.of("alice", AttributeMap.EMPTY, Set.of("role-1")),
List.of(
new RenameAuthorizationIntent(
PolarisAuthorizableOperation.RENAME_TABLE,
Expand Down Expand Up @@ -1000,7 +1014,7 @@ void authorizeSingleOperationMultiIntentRequestEvaluatesSequentially() throws Ex

PolarisResolutionManifest resolutionManifest = mock(PolarisResolutionManifest.class);
AuthorizationState authzState = new AuthorizationState(resolutionManifest);
PolarisPrincipal principal = PolarisPrincipal.of("alice", Map.of(), Set.of("role-1"));
PolarisPrincipal principal = PolarisPrincipal.of("alice", AttributeMap.EMPTY, Set.of("role-1"));

OpaPolarisAuthorizer authorizer =
new OpaPolarisAuthorizer(
Expand Down Expand Up @@ -1083,7 +1097,7 @@ void authorizeUpdateTableMultiIntentRequestEvaluatesSequentially() {

PolarisResolutionManifest resolutionManifest = mock(PolarisResolutionManifest.class);
AuthorizationState authzState = new AuthorizationState(resolutionManifest);
PolarisPrincipal principal = PolarisPrincipal.of("alice", Map.of(), Set.of("role-1"));
PolarisPrincipal principal = PolarisPrincipal.of("alice", AttributeMap.EMPTY, Set.of("role-1"));
PolarisSecurable tableTarget =
PolarisSecurable.of(
new PathSegment(PolarisEntityType.CATALOG, "catalog-1"),
Expand Down Expand Up @@ -1140,7 +1154,8 @@ void serializesInputWithRealm() throws Exception {
null,
"explicit-realm");

PolarisPrincipal principal = PolarisPrincipal.of("eve", Map.of(), Set.of("auditor"));
PolarisPrincipal principal =
PolarisPrincipal.of("eve", AttributeMap.EMPTY, Set.of("auditor"));

assertThatNoException()
.isThrownBy(
Expand Down Expand Up @@ -1183,7 +1198,8 @@ void serializesRealmInAuthorizePath() throws Exception {
PolarisResolutionManifest resolutionManifest = mock(PolarisResolutionManifest.class);
AuthorizationState authzState = new AuthorizationState(resolutionManifest);

PolarisPrincipal principal = PolarisPrincipal.of("alice", Map.of(), Set.of("admin"));
PolarisPrincipal principal =
PolarisPrincipal.of("alice", AttributeMap.EMPTY, Set.of("admin"));
AuthorizationRequest request = requestWithCatalogTarget(principal);

assertThatNoException().isThrownBy(() -> authorizer.authorize(authzState, request));
Expand Down Expand Up @@ -1215,7 +1231,12 @@ void requestIdIsIncludedInContextWhenProvided() throws Exception {
"test-realm");

PolarisPrincipal principal =
PolarisPrincipal.of("eve", Map.of("department", "finance"), Set.of("auditor"));
PolarisPrincipal.of(
"eve",
ImmutableAttributeMap.builder()
.put(new AttributeKey<>("department"), "finance")
.build(),
Set.of("auditor"));
PolarisResolvedPathWrapper target = new PolarisResolvedPathWrapper(List.of());
PolarisResolvedPathWrapper secondary = new PolarisResolvedPathWrapper(List.of());

Expand Down Expand Up @@ -1256,7 +1277,12 @@ void requestIdFallsBackToRandomUuidWhenNull() throws Exception {
"test-realm");

PolarisPrincipal principal =
PolarisPrincipal.of("eve", Map.of("department", "finance"), Set.of("auditor"));
PolarisPrincipal.of(
"eve",
ImmutableAttributeMap.builder()
.put(new AttributeKey<>("department"), "finance")
.build(),
Set.of("auditor"));
PolarisResolvedPathWrapper target = new PolarisResolvedPathWrapper(List.of());
PolarisResolvedPathWrapper secondary = new PolarisResolvedPathWrapper(List.of());

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import org.apache.commons.lang3.StringUtils;
import org.apache.polaris.core.auth.PolarisAuthorizableOperation;
import org.apache.polaris.core.auth.PolarisPrincipal;
import org.apache.polaris.core.auth.PolarisPrincipalAttributes;
import org.apache.polaris.core.entity.PolarisEntity;
import org.apache.polaris.core.entity.PolarisEntityType;
import org.apache.polaris.core.entity.PrincipalEntity;
Expand Down Expand Up @@ -130,7 +131,8 @@ private static Map<String, Object> getResourceAttributes(
private static Map<String, Object> getUserAttributes(PolarisPrincipal principal) {
Map<String, String> properties =
principal
.getAttribute(PolarisPrincipal.PRINCIPAL_ENTITY_ATTRIBUTE_KEY, PrincipalEntity.class)
.getAttributes()
.getOptional(PolarisPrincipalAttributes.PRINCIPAL_ENTITY_ATTRIBUTE_KEY)
.map(PrincipalEntity::getInternalPropertiesAsMap)
.orElse(Collections.emptyMap());

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
import org.apache.polaris.core.auth.PolarisAuthorizableOperation;
import org.apache.polaris.core.auth.PolarisAuthorizer;
import org.apache.polaris.core.auth.PolarisPrincipal;
import org.apache.polaris.core.collection.AttributeMap;
import org.apache.polaris.core.entity.PolarisEntity;
import org.apache.polaris.core.entity.PolarisEntityType;
import org.apache.polaris.core.persistence.PolarisResolvedPathWrapper;
Expand Down Expand Up @@ -199,7 +200,7 @@ public PolarisPrincipal deserialize(JsonParser parser, DeserializationContext co

String name = nameNode != null ? nameNode.asString() : null;

return PolarisPrincipal.of(name, Collections.emptyMap(), Collections.emptySet());
return PolarisPrincipal.of(name, AttributeMap.EMPTY, Collections.emptySet());
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
import org.apache.kafka.common.serialization.StringDeserializer;
import org.apache.kafka.common.serialization.UUIDDeserializer;
import org.apache.polaris.core.auth.PolarisPrincipal;
import org.apache.polaris.core.collection.AttributeMap;
import org.apache.polaris.service.events.EventAttributeMap;
import org.apache.polaris.service.events.EventAttributes;
import org.apache.polaris.service.events.ImmutablePolarisEventMetadata;
Expand Down Expand Up @@ -77,7 +78,7 @@ class KafkaEventListenerTest {
private static final String KAFKA_GROUP_ID = "polaris-group-id";
private static final String TEST_CATALOG = "test_catalog";
private static final PolarisPrincipal PRINCIPAL =
PolarisPrincipal.of(TEST_USER, Map.of(), Set.of("role1", "role2"));
PolarisPrincipal.of(TEST_USER, AttributeMap.EMPTY, Set.of("role1", "role2"));
private static final TableIdentifier TEST_TABLE_IDENTIFIER =
TableIdentifier.of("test_namespace", "test_table");
private static final JsonMapper OBJECT_MAPPER = JsonMapper.shared();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
*/
package org.apache.polaris.core.auth;

import java.util.Optional;
import org.apache.iceberg.exceptions.ForbiddenException;
import org.apache.polaris.core.config.FeatureConfiguration;
import org.apache.polaris.core.config.RealmConfig;
Expand Down Expand Up @@ -57,8 +58,10 @@ && mustRotateCredentials(polarisPrincipal)) {
}

private static boolean mustRotateCredentials(PolarisPrincipal principal) {
return principal
.getAttribute(PolarisPrincipal.PRINCIPAL_ENTITY_ATTRIBUTE_KEY, PrincipalEntity.class)
return Optional.ofNullable(
principal
.getAttributes()
.get(PolarisPrincipalAttributes.PRINCIPAL_ENTITY_ATTRIBUTE_KEY))
.map(PrincipalEntity::getInternalPropertiesAsMap)
.map(
map ->
Expand Down
Loading
Loading