This is an automated email from the ASF dual-hosted git repository. collado pushed a commit to branch mcollado-authn-resolve-roles in repository https://gitbox.apache.org/repos/asf/polaris.git
commit bbdcc492bffc4392f7474a2746985fe9a309a6e1 Author: Michael Collado <[email protected]> AuthorDate: Fri Jan 10 17:02:53 2025 -0800 Addressed PR comments --- .../service/dropwizard/PolarisApplication.java | 57 +--------------- .../auth/PolarisPrincipalAuthenticator.java | 78 ++++++++++++++++++++++ .../service/auth/DefaultActiveRolesProvider.java | 4 +- 3 files changed, 81 insertions(+), 58 deletions(-) diff --git a/dropwizard/service/src/main/java/org/apache/polaris/service/dropwizard/PolarisApplication.java b/dropwizard/service/src/main/java/org/apache/polaris/service/dropwizard/PolarisApplication.java index 6e0bb298..1815dccf 100644 --- a/dropwizard/service/src/main/java/org/apache/polaris/service/dropwizard/PolarisApplication.java +++ b/dropwizard/service/src/main/java/org/apache/polaris/service/dropwizard/PolarisApplication.java @@ -57,7 +57,6 @@ import io.opentelemetry.sdk.trace.SdkTracerProvider; import io.opentelemetry.sdk.trace.export.SimpleSpanProcessor; import io.opentelemetry.semconv.ServiceAttributes; import io.prometheus.metrics.exporter.servlet.jakarta.PrometheusMetricsServlet; -import jakarta.annotation.Priority; import jakarta.inject.Inject; import jakarta.inject.Provider; import jakarta.inject.Singleton; @@ -69,27 +68,19 @@ import jakarta.servlet.ServletException; import jakarta.servlet.ServletRequest; import jakarta.servlet.ServletResponse; import jakarta.servlet.http.HttpServletRequest; -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.io.InputStream; import java.net.URL; -import java.security.Principal; import java.util.Collections; import java.util.EnumSet; import java.util.Map; import java.util.Objects; -import java.util.Optional; import java.util.concurrent.Executors; import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.Stream; -import org.apache.iceberg.exceptions.NotAuthorizedException; import org.apache.iceberg.rest.RESTSerializers; import org.apache.polaris.core.PolarisConfigurationStore; -import org.apache.polaris.core.auth.AuthenticatedPolarisPrincipal; import org.apache.polaris.core.auth.PolarisAuthorizer; import org.apache.polaris.core.auth.PolarisAuthorizerImpl; import org.apache.polaris.core.auth.PolarisGrantManager; @@ -108,7 +99,6 @@ import org.apache.polaris.service.admin.api.PolarisPrincipalRolesApiService; import org.apache.polaris.service.admin.api.PolarisPrincipalsApi; import org.apache.polaris.service.admin.api.PolarisPrincipalsApiService; import org.apache.polaris.service.auth.ActiveRolesProvider; -import org.apache.polaris.service.auth.Authenticator; import org.apache.polaris.service.auth.DefaultActiveRolesProvider; import org.apache.polaris.service.catalog.IcebergCatalogAdapter; import org.apache.polaris.service.catalog.api.IcebergRestCatalogApi; @@ -124,6 +114,7 @@ import org.apache.polaris.service.context.CallContextCatalogFactory; import org.apache.polaris.service.context.CallContextResolver; import org.apache.polaris.service.context.PolarisCallContextCatalogFactory; import org.apache.polaris.service.context.RealmContextResolver; +import org.apache.polaris.service.dropwizard.auth.PolarisPrincipalAuthenticator; import org.apache.polaris.service.dropwizard.auth.PolarisPrincipalRoleSecurityContextProvider; import org.apache.polaris.service.dropwizard.config.PolarisApplicationConfig; import org.apache.polaris.service.dropwizard.context.RealmScopeContext; @@ -479,52 +470,6 @@ public class PolarisApplication extends Application<PolarisApplicationConfig> { .build(); } - @jakarta.ws.rs.ext.Provider - @Priority(Priorities.AUTHENTICATION) - private static class PolarisPrincipalAuthenticator implements ContainerRequestFilter { - @Inject private Authenticator<String, AuthenticatedPolarisPrincipal> authenticator; - - @Override - public void filter(ContainerRequestContext requestContext) throws IOException { - String authHeader = requestContext.getHeaderString("Authorization"); - if (authHeader == null) { - throw new IOException("Authorization header is missing"); - } - int spaceIdx = authHeader.indexOf(' '); - if (spaceIdx <= 0 || !authHeader.substring(0, spaceIdx).equalsIgnoreCase("Bearer")) { - throw new IOException("Authorization header is not a Bearer token"); - } - String credential = authHeader.substring(spaceIdx + 1); - Optional<AuthenticatedPolarisPrincipal> principal = authenticator.authenticate(credential); - if (principal.isEmpty()) { - throw new NotAuthorizedException("Unable to authenticate"); - } - SecurityContext securityContext = requestContext.getSecurityContext(); - requestContext.setSecurityContext( - new SecurityContext() { - @Override - public Principal getUserPrincipal() { - return principal.get(); - } - - @Override - public boolean isUserInRole(String role) { - return securityContext.isUserInRole(role); - } - - @Override - public boolean isSecure() { - return securityContext.isSecure(); - } - - @Override - public String getAuthenticationScheme() { - return securityContext.getAuthenticationScheme(); - } - }); - } - } - /** Resolves and sets ThreadLocal CallContext/RealmContext based on the request contents. */ private static class ContextResolverFilter implements Filter { private final RealmContextResolver realmContextResolver; diff --git a/dropwizard/service/src/main/java/org/apache/polaris/service/dropwizard/auth/PolarisPrincipalAuthenticator.java b/dropwizard/service/src/main/java/org/apache/polaris/service/dropwizard/auth/PolarisPrincipalAuthenticator.java new file mode 100644 index 00000000..b8010cbe --- /dev/null +++ b/dropwizard/service/src/main/java/org/apache/polaris/service/dropwizard/auth/PolarisPrincipalAuthenticator.java @@ -0,0 +1,78 @@ +/* + * 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.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.Optional; +import org.apache.iceberg.exceptions.NotAuthorizedException; +import org.apache.polaris.core.auth.AuthenticatedPolarisPrincipal; +import org.apache.polaris.service.auth.Authenticator; + [email protected] +@Priority(Priorities.AUTHENTICATION) +public class PolarisPrincipalAuthenticator implements ContainerRequestFilter { + @Inject private Authenticator<String, AuthenticatedPolarisPrincipal> authenticator; + + @Override + public void filter(ContainerRequestContext requestContext) throws IOException { + String authHeader = requestContext.getHeaderString("Authorization"); + if (authHeader == null) { + throw new IOException("Authorization header is missing"); + } + int spaceIdx = authHeader.indexOf(' '); + if (spaceIdx <= 0 || !authHeader.substring(0, spaceIdx).equalsIgnoreCase("Bearer")) { + throw new IOException("Authorization header is not a Bearer token"); + } + String credential = authHeader.substring(spaceIdx + 1); + Optional<AuthenticatedPolarisPrincipal> principal = authenticator.authenticate(credential); + if (principal.isEmpty()) { + throw new NotAuthorizedException("Unable to authenticate"); + } + SecurityContext securityContext = requestContext.getSecurityContext(); + requestContext.setSecurityContext( + new SecurityContext() { + @Override + public Principal getUserPrincipal() { + return principal.get(); + } + + @Override + public boolean isUserInRole(String role) { + return securityContext.isUserInRole(role); + } + + @Override + public boolean isSecure() { + return securityContext.isSecure(); + } + + @Override + public String getAuthenticationScheme() { + return securityContext.getAuthenticationScheme(); + } + }); + } +} diff --git a/service/common/src/main/java/org/apache/polaris/service/auth/DefaultActiveRolesProvider.java b/service/common/src/main/java/org/apache/polaris/service/auth/DefaultActiveRolesProvider.java index 8706a7fd..186641da 100644 --- a/service/common/src/main/java/org/apache/polaris/service/auth/DefaultActiveRolesProvider.java +++ b/service/common/src/main/java/org/apache/polaris/service/auth/DefaultActiveRolesProvider.java @@ -46,7 +46,7 @@ import org.slf4j.LoggerFactory; public class DefaultActiveRolesProvider implements ActiveRolesProvider { private static final Logger LOGGER = LoggerFactory.getLogger(DefaultActiveRolesProvider.class); @Inject Provider<RealmContext> realmContextProvider; - @Inject MetaStoreManagerFactory metaStoreManager; + @Inject MetaStoreManagerFactory metaStoreManagerFactory; @Inject Provider<PolarisGrantManager> polarisGrantManagerProvider; @Override @@ -55,7 +55,7 @@ public class DefaultActiveRolesProvider implements ActiveRolesProvider { loadActivePrincipalRoles( principal.getActivatedPrincipalRoleNames(), principal.getPrincipalEntity(), - metaStoreManager.getOrCreateMetaStoreManager(realmContextProvider.get())); + metaStoreManagerFactory.getOrCreateMetaStoreManager(realmContextProvider.get())); return activeRoles.stream().map(PrincipalRoleEntity::getName).collect(Collectors.toSet()); }
