dimas-b commented on code in PR #623:
URL: https://github.com/apache/polaris/pull/623#discussion_r1907564807
##########
polaris-core/src/main/java/org/apache/polaris/core/persistence/resolver/Resolver.java:
##########
@@ -703,61 +693,73 @@ private ResolverStatus resolvePaths(
*
* @param toValidate all entities we have resolved from the cache, hence we
will have to verify
* that these entities have not changed in the backend
- * @param callerPrincipalId the id of the principal which made the call
- * @param callerPrincipalRoleNamesScope if not null, subset of roles
activated by this call
* @return the status of resolution
*/
private ResolverStatus resolveCallerPrincipalAndPrincipalRoles(
- List<EntityCacheEntry> toValidate,
- long callerPrincipalId,
- String callerPrincipalName,
- Set<String> callerPrincipalRoleNamesScope) {
+ List<EntityCacheEntry> toValidate) {
// resolve the principal, by name or id
this.resolvedCallerPrincipal =
- (callerPrincipalId != PolarisEntityConstants.getNullId())
- ? this.resolveById(
- toValidate,
- PolarisEntityType.PRINCIPAL,
- PolarisEntityConstants.getNullId(),
- callerPrincipalId)
- : this.resolveByName(toValidate, PolarisEntityType.PRINCIPAL,
callerPrincipalName);
+ this.resolveById(
+ toValidate,
+ PolarisEntityType.PRINCIPAL,
+ PolarisEntityConstants.getNullId(),
+ polarisPrincipal.getPrincipalEntity().getId());
// if the principal was not found, we can end right there
if (this.resolvedCallerPrincipal == null
|| this.resolvedCallerPrincipal.getEntity().isDropped()) {
return new
ResolverStatus(ResolverStatus.StatusEnum.CALLER_PRINCIPAL_DOES_NOT_EXIST);
}
- // activate all principal roles which still exist
- for (PolarisGrantRecord grantRecord :
this.resolvedCallerPrincipal.getGrantRecordsAsGrantee()) {
- if (grantRecord.getPrivilegeCode() ==
PolarisPrivilege.PRINCIPAL_ROLE_USAGE.getCode()) {
-
- // resolve principal role granted to that principal
- EntityCacheEntry principalRole =
- this.resolveById(
- toValidate,
- PolarisEntityType.PRINCIPAL_ROLE,
- PolarisEntityConstants.getNullId(),
- grantRecord.getSecurableId());
-
- // skip if purged or has been dropped
- if (principalRole != null && !principalRole.getEntity().isDropped()) {
- // add it to the activated list if no scoped principal role or this
principal role is
- // activated
- if (callerPrincipalRoleNamesScope == null
- ||
callerPrincipalRoleNamesScope.contains(principalRole.getEntity().getName())) {
- // this principal role is activated
- this.resolvedCallerPrincipalRoles.add(principalRole);
- }
- }
- }
- }
+ // activate all principal roles specified in the authenticated principal
+ resolvedCallerPrincipalRoles =
+ this.polarisPrincipal.getActivatedPrincipalRoleNames().isEmpty()
+ ? resolveAllPrincipalRoles(toValidate, resolvedCallerPrincipal)
+ : resolvePrincipalRolesByName(
+ toValidate,
this.polarisPrincipal.getActivatedPrincipalRoleNames());
// total success
return new ResolverStatus(ResolverStatus.StatusEnum.SUCCESS);
}
+ /**
+ * Resolve all principal roles that the principal has grants for
+ *
+ * @param toValidate
+ * @param resolvedCallerPrincipal1
+ * @return the list of resolved principal roles the principal has grants for
+ */
+ private List<EntityCacheEntry> resolveAllPrincipalRoles(
+ List<EntityCacheEntry> toValidate, EntityCacheEntry
resolvedCallerPrincipal1) {
+ return resolvedCallerPrincipal1.getGrantRecordsAsGrantee().stream()
+ .filter(gr -> gr.getPrivilegeCode() ==
PolarisPrivilege.PRINCIPAL_ROLE_USAGE.getCode())
+ .map(
+ gr ->
+ resolveById(
+ toValidate,
+ PolarisEntityType.PRINCIPAL_ROLE,
+ PolarisEntityConstants.getRootEntityId(),
+ gr.getSecurableId()))
+ .collect(Collectors.toList());
+ }
+
+ /**
+ * Resolve the specified list of principal roles. The SecurityContext is
used to determine whether
+ * the principal actually has the roles specified.
+ *
+ * @param toValidate
+ * @param roleNames
+ * @return the filtered list of resolved principal roles
+ */
+ private List<EntityCacheEntry> resolvePrincipalRolesByName(
+ List<EntityCacheEntry> toValidate, Set<String> roleNames) {
+ return roleNames.stream()
+ .filter(securityContext::isUserInRole)
Review Comment:
Why not use `AuthenticatedPolarisPrincipal` as the source of active role
membership info? It looks like the Web App filters create both the principal
and the security context, so the role information is available in the same
logical scope as the principal.
##########
dropwizard/service/src/main/java/org/apache/polaris/service/dropwizard/auth/PolarisPrincipalRoleSecurityContextProvider.java:
##########
@@ -0,0 +1,144 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.polaris.service.dropwizard.auth;
+
+import jakarta.annotation.Priority;
+import jakarta.inject.Inject;
+import jakarta.inject.Provider;
+import jakarta.ws.rs.Priorities;
+import jakarta.ws.rs.container.ContainerRequestContext;
+import jakarta.ws.rs.container.ContainerRequestFilter;
+import jakarta.ws.rs.core.SecurityContext;
+import java.io.IOException;
+import java.security.Principal;
+import java.util.List;
+import java.util.Set;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
+import org.apache.iceberg.exceptions.NotAuthorizedException;
+import org.apache.polaris.core.PolarisCallContext;
+import org.apache.polaris.core.auth.AuthenticatedPolarisPrincipal;
+import org.apache.polaris.core.auth.PolarisGrantManager;
+import org.apache.polaris.core.context.CallContext;
+import org.apache.polaris.core.context.RealmContext;
+import org.apache.polaris.core.entity.PolarisEntity;
+import org.apache.polaris.core.entity.PrincipalRoleEntity;
+import org.apache.polaris.core.persistence.MetaStoreManagerFactory;
+import org.apache.polaris.core.persistence.PolarisMetaStoreManager;
+import org.apache.polaris.service.auth.BasePolarisAuthenticator;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@Priority(Priorities.AUTHENTICATION + 1)
+public class PolarisPrincipalRoleSecurityContextProvider implements
ContainerRequestFilter {
+ private static final Logger LOGGER =
+
LoggerFactory.getLogger(PolarisPrincipalRoleSecurityContextProvider.class);
+ @Inject Provider<SecurityContext> securityContextProvider;
+ @Inject MetaStoreManagerFactory metaStoreManager;
+ @Inject Provider<PolarisGrantManager> polarisGrantManagerProvider;
+
+ @Override
+ public void filter(ContainerRequestContext requestContext) throws
IOException {
+ AuthenticatedPolarisPrincipal polarisPrincipal =
+ (AuthenticatedPolarisPrincipal)
securityContextProvider.get().getUserPrincipal();
+ if (polarisPrincipal == null) {
+ return;
+ }
+ SecurityContext securityContext =
+ createSecurityContext(requestContext.getSecurityContext(),
polarisPrincipal);
+ requestContext.setSecurityContext(securityContext);
Review Comment:
Replacing the security context looks a bit too intrusive to me. I wonder if
we could avoid that by using `AuthenticatedPolarisPrincipal` to convey active
role membership?
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]