Copilot commented on code in PR #896: URL: https://github.com/apache/ranger/pull/896#discussion_r3005830482
########## pdp/src/main/java/org/apache/ranger/pdp/security/KerberosAuthNHandler.java: ########## @@ -0,0 +1,275 @@ +/* + * 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.ranger.pdp.security; + +import org.apache.commons.codec.binary.Base64; +import org.apache.commons.lang3.StringUtils; +import org.apache.hadoop.security.authentication.util.KerberosName; +import org.apache.ranger.pdp.config.RangerPdpConstants; +import org.ietf.jgss.GSSContext; +import org.ietf.jgss.GSSCredential; +import org.ietf.jgss.GSSException; +import org.ietf.jgss.GSSManager; +import org.ietf.jgss.GSSName; +import org.ietf.jgss.Oid; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.security.auth.Subject; +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.CallbackHandler; +import javax.security.auth.callback.UnsupportedCallbackException; +import javax.security.auth.login.AppConfigurationEntry; +import javax.security.auth.login.Configuration; +import javax.security.auth.login.LoginContext; +import javax.security.auth.login.LoginException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import java.security.PrivilegedExceptionAction; +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; + +/** + * Authenticates requests using Kerberos SPNEGO (HTTP Negotiate). + * + * <p>Uses the JDK's built-in GSSAPI/JGSS support – no external Kerberos library is required. + * The service principal and keytab must be configured via: + * <ul> + * <li>{@code ranger.pdp.authn.kerberos.spnego.principal} – e.g. {@code HTTP/host.example.com@REALM} + * <li>{@code ranger.pdp.authn.kerberos.spnego.keytab} – absolute path to the keytab file + * <li>{@code ranger.pdp.authn.kerberos.name.rules} – Hadoop-style name rules (default: {@code DEFAULT}) + * </ul> + * + * <p>Authentication flow: + * <ol> + * <li>If no {@code Authorization: Negotiate} header is present the handler returns {@code SKIP}. + * <li>The SPNEGO token is extracted, validated via GSSAPI, and – if a response token is + * produced (mutual authentication) – written to {@code WWW-Authenticate: Negotiate <token>}. + * <li>On success the short-form principal name (strip {@literal @REALM} and host components) + * is returned as the authenticated user. + * <li>On failure a {@code 401 Negotiate} challenge is sent and {@code CHALLENGE} is returned. + * </ol> + */ +public class KerberosAuthNHandler implements PdpAuthNHandler { + private static final Logger LOG = LoggerFactory.getLogger(KerberosAuthNHandler.class); + + public static final String AUTH_TYPE = "KERBEROS"; + + private static final String NEGOTIATE_PREFIX = "Negotiate "; + private static final String WWW_AUTHENTICATE = "WWW-Authenticate"; + private static final String AUTHORIZATION = "Authorization"; + private static final Oid SPNEGO_OID; + private static final Oid KRB5_OID; + + static { + try { + SPNEGO_OID = new Oid("1.3.6.1.5.5.2"); + KRB5_OID = new Oid("1.2.840.113554.1.2.2"); + } catch (GSSException e) { + throw new ExceptionInInitializerError(e); + } + } + + private Subject serviceSubject; + private GSSManager gssManager; + private GSSCredential serverCred; + + @Override + public void init(Properties config) throws Exception { + String principal = config.getProperty(RangerPdpConstants.PROP_AUTHN_KERBEROS_SPNEGO_PRINCIPAL); + String keytab = config.getProperty(RangerPdpConstants.PROP_AUTHN_KERBEROS_SPNEGO_KEYTAB); + String nameRules = config.getProperty(RangerPdpConstants.PROP_AUTHN_KERBEROS_NAME_RULES, "DEFAULT"); + String tokenValidity = config.getProperty(RangerPdpConstants.PROP_AUTHN_KERBEROS_KRB_TOKEN_VALIDITY); + + int tokenLifetime = StringUtils.isBlank(tokenValidity) ? GSSCredential.INDEFINITE_LIFETIME : Integer.parseInt(tokenValidity); + + if (StringUtils.isBlank(principal) || StringUtils.isBlank(keytab)) { + throw new IllegalArgumentException("Kerberos auth requires configurations " + RangerPdpConstants.PROP_AUTHN_KERBEROS_SPNEGO_PRINCIPAL + " and " + RangerPdpConstants.PROP_AUTHN_KERBEROS_SPNEGO_KEYTAB); + } + + serviceSubject = loginWithKeytab(principal, keytab); + + initializeKerberosNameRules(nameRules); + + gssManager = GSSManager.getInstance(); + + GSSName serverName = gssManager.createName(principal, GSSName.NT_USER_NAME); + + // Create acceptor credentials in the logged-in Subject to avoid fallback to JVM default keytab. + serverCred = Subject.doAs(serviceSubject, (PrivilegedExceptionAction<GSSCredential>) () -> + gssManager.createCredential(serverName, tokenLifetime, new Oid[] {SPNEGO_OID, KRB5_OID}, GSSCredential.ACCEPT_ONLY)); + + LOG.info("KerberosAuthHandler initialized; principal={} (bound acceptor credential to configured principal)", principal); + } Review Comment: Log message refers to "KerberosAuthHandler" but the class is `KerberosAuthNHandler` (and similarly in other handlers). Using the exact handler name in logs will make debugging/grep’ing configuration issues easier. ########## pdp/conf.dist/logback.xml: ########## @@ -0,0 +1,36 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + 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. +--> + +<configuration> + <appender name="stdout" class="ch.qos.logback.core.ConsoleAppender"> + <Target>System.out</Target> Review Comment: In Logback `ConsoleAppender`, the element is `<target>`, not `<Target>`. With the current casing the setting may be ignored (falling back to the default) and can be confusing for operators. Please change it to the correct lowercase element name for consistency with other logback configs in the repo. ```suggestion <target>System.out</target> ``` ########## pdp/src/main/java/org/apache/ranger/pdp/RangerPdpServer.java: ########## @@ -0,0 +1,293 @@ +/* + * 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.ranger.pdp; + +import org.apache.catalina.Context; +import org.apache.catalina.LifecycleException; +import org.apache.catalina.connector.Connector; +import org.apache.catalina.startup.Tomcat; +import org.apache.catalina.valves.AccessLogValve; +import org.apache.coyote.http2.Http2Protocol; +import org.apache.ranger.authz.api.RangerAuthorizer; +import org.apache.ranger.authz.api.RangerAuthzException; +import org.apache.ranger.authz.embedded.RangerEmbeddedAuthorizer; +import org.apache.ranger.pdp.config.RangerPdpConfig; +import org.apache.ranger.pdp.config.RangerPdpConstants; +import org.apache.ranger.pdp.rest.RangerPdpApplication; +import org.apache.ranger.pdp.security.RangerPdpAuthNFilter; +import org.apache.ranger.pdp.security.RangerPdpRequestContextFilter; +import org.apache.tomcat.util.descriptor.web.FilterDef; +import org.apache.tomcat.util.descriptor.web.FilterMap; +import org.glassfish.jersey.servlet.ServletContainer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.servlet.Servlet; +import javax.servlet.http.HttpServlet; + +import java.io.File; + +/** + * Main entry point for the Ranger Policy Decision Point (PDP) server. + * + * <p>Starts an embedded Apache Tomcat instance that: + * <ul> + * <li>Creates and initialises a {@link RangerEmbeddedAuthorizer} singleton + * <li>Exposes the three authorizer methods as REST endpoints under {@code /authz/v1/} + * <li>Enforces authentication via {@link RangerPdpAuthNFilter} (Kerberos/JWT/HTTP-Header) + * <li>Optionally enables HTTP/2 ({@code Http2Protocol} upgrade on the connector) + * </ul> + * + * <p><b>Startup:</b> {@code java -jar ranger-pdp.jar} + * <br>Override config with: {@code -Dranger.pdp.conf.dir=/etc/ranger/pdp} + */ +public class RangerPdpServer { + private static final Logger LOG = LoggerFactory.getLogger(RangerPdpServer.class); + + private final RangerPdpConfig config; + private final RangerPdpStats runtimeStats = new RangerPdpStats(); + private Tomcat tomcat; + private RangerAuthorizer authorizer; + + public RangerPdpServer() { + this.config = new RangerPdpConfig(); + } + + public static void main(String[] args) throws Exception { + new RangerPdpServer().start(); + } + + public void start() throws Exception { + LOG.info("Starting Ranger PDP server"); + + initAuthorizer(); + startTomcat(); + } + + public void stop() { + LOG.info("Stopping Ranger PDP server"); + + runtimeStats.setAcceptingRequests(false); + runtimeStats.setServerStarted(false); + + if (tomcat != null) { + try { + if (tomcat.getConnector() != null) { + tomcat.getConnector().pause(); + } + + tomcat.stop(); + tomcat.destroy(); + } catch (LifecycleException e) { + LOG.warn("Error stopping Tomcat", e); + } + } + + if (authorizer != null) { + try { + authorizer.close(); + } catch (RangerAuthzException e) { + LOG.warn("Error closing authorizer", e); + } + } + } + + private void initAuthorizer() throws RangerAuthzException { + authorizer = new RangerEmbeddedAuthorizer(config.getAuthzProperties()); + + authorizer.init(); + + runtimeStats.setAuthorizerInitialized(true); + + LOG.info("RangerEmbeddedAuthorizer initialised"); + } + + private void startTomcat() throws Exception { + tomcat = new Tomcat(); + + tomcat.setConnector(createConnector()); + + String docBase = new File(System.getProperty("java.io.tmpdir"), "ranger-pdp-webapps").getAbsolutePath(); + + new File(docBase).mkdirs(); + + Context ctx = tomcat.addContext("", docBase); + + ctx.getServletContext().setAttribute(RangerPdpConstants.SERVLET_CTX_ATTR_AUTHORIZER, authorizer); + ctx.getServletContext().setAttribute(RangerPdpConstants.SERVLET_CTX_ATTR_CONFIG, config); + ctx.getServletContext().setAttribute(RangerPdpConstants.SERVLET_CTX_ATTR_RUNTIME_STATE, runtimeStats); + + addAuthFilter(ctx); + addJerseyServlet(ctx); + addStatusEndpoints(ctx); + addAccessLogValve(); + + Runtime.getRuntime().addShutdownHook(new Thread(this::stop, "ranger-pdp-shutdown")); + + tomcat.start(); + + runtimeStats.setServerStarted(true); + runtimeStats.setAcceptingRequests(true); + + LOG.info("Ranger PDP server listening on port {} (SSL={}, HTTP/2={})", config.getPort(), config.isSslEnabled(), config.isHttp2Enabled()); + + tomcat.getServer().await(); + } + + /** + * Builds the Tomcat connector. + * + * <p>When SSL is enabled the connector is configured as an HTTPS endpoint. + * When HTTP/2 is enabled an {@link Http2Protocol} upgrade protocol is added, + * supporting both {@code h2} (over TLS) and {@code h2c} (cleartext upgrade) depending + * on whether SSL is enabled. + */ + private Connector createConnector() { + Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol"); + + connector.setPort(config.getPort()); + connector.setProperty("maxThreads", String.valueOf(config.getHttpConnectorMaxThreads())); + connector.setProperty("minSpareThreads", String.valueOf(config.getHttpConnectorMinSpareThreads())); + connector.setProperty("acceptCount", String.valueOf(config.getHttpConnectorAcceptCount())); + connector.setProperty("maxConnections", String.valueOf(config.getHttpConnectorMaxConnections())); + + LOG.info("Configured HTTP connector limits: maxThreads={}, minSpareThreads={}, acceptCount={}, maxConnections={}", + config.getHttpConnectorMaxThreads(), config.getHttpConnectorMinSpareThreads(), + config.getHttpConnectorAcceptCount(), config.getHttpConnectorMaxConnections()); + + if (config.isSslEnabled()) { + connector.setSecure(true); + connector.setScheme("https"); + connector.setProperty("SSLEnabled", "true"); + connector.setProperty("protocol", "org.apache.coyote.http11.Http11NioProtocol"); + connector.setProperty("keystoreFile", config.getKeystoreFile()); + connector.setProperty("keystorePass", config.getKeystorePassword()); + connector.setProperty("keystoreType", config.getKeystoreType()); + connector.setProperty("sslProtocol", "TLS"); + + if (config.isTruststoreEnabled()) { + connector.setProperty("truststoreFile", config.getTruststoreFile()); + connector.setProperty("truststorePass", config.getTruststorePassword()); + connector.setProperty("truststoreType", config.getTruststoreType()); + connector.setProperty("clientAuth", "want"); Review Comment: When truststore is enabled, the code sets Tomcat `clientAuth` to "want" (optional mTLS), but the config/docs describe this setting as requiring client certificate authentication. This mismatch can lead to deployments believing mTLS is enforced when it isn’t. Consider using the Tomcat setting that requires client certs (or update the property name/description to reflect optional client auth). ```suggestion connector.setProperty("clientAuth", "true"); ``` ########## pdp/src/main/java/org/apache/ranger/pdp/security/RangerPdpAuthNFilter.java: ########## @@ -0,0 +1,187 @@ +/* + * 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.ranger.pdp.security; + +import org.apache.commons.lang3.StringUtils; +import org.apache.ranger.pdp.config.RangerPdpConstants; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Properties; + +import static org.apache.ranger.pdp.config.RangerPdpConstants.PROP_AUTHN_TYPES; + +/** + * Servlet filter that enforces authentication for all PDP REST endpoints. + * + * <p>Handlers are configured via the {@code ranger.pdp.authn.types} filter init parameter + * (comma-separated list of {@code header}, {@code jwt}, {@code kerberos}). Handlers are + * tried in the listed order; the first successful match wins. + * + * <p>On success the authenticated username is stored in the request attribute + * {@link RangerPdpConstants#ATTR_AUTHENTICATED_USER} so that REST resources can read it. + * + * <p>If all handlers return {@code SKIP} (no recognisable credentials found), the filter + * sends a {@code 401} response with {@code WWW-Authenticate} headers for every + * configured handler that provides a challenge. + */ +public class RangerPdpAuthNFilter implements Filter { + private static final Logger LOG = LoggerFactory.getLogger(RangerPdpAuthNFilter.class); + + private final List<PdpAuthNHandler> handlers = new ArrayList<>(); + + @Override + public void init(FilterConfig filterConfig) throws ServletException { + Properties config = toProperties(filterConfig); + String authnTypes = filterConfig.getInitParameter(PROP_AUTHN_TYPES); + + if (StringUtils.isNotBlank(authnTypes)) { + for (String authnType : authnTypes.split(",")) { + PdpAuthNHandler handler = createHandler(authnType.trim().toLowerCase(), filterConfig); + + if (handler == null) { + continue; + } + + try { + handler.init(config); + + handlers.add(handler); + + LOG.info("{}: successfully registered authentication handler", authnType); + } catch (Exception excp) { + LOG.error("{}: failed to initialize authentication handler. Handler disabled", authnType, excp); + } + } + } + + if (handlers.isEmpty()) { + throw new ServletException("No valid authentication handlers configured"); + } + } + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { + HttpServletRequest httpReq = (HttpServletRequest) request; + HttpServletResponse httpResp = (HttpServletResponse) response; + + for (PdpAuthNHandler handler : handlers) { + PdpAuthNHandler.Result result = handler.authenticate(httpReq, httpResp); + + switch (result.getStatus()) { + case AUTHENTICATED: + httpReq.setAttribute(RangerPdpConstants.ATTR_AUTHENTICATED_USER, result.getUserName()); + httpReq.setAttribute(RangerPdpConstants.ATTR_AUTHN_TYPE, result.getAuthType()); + + LOG.debug("doFilter(): authenticated user={}, type={}", result.getUserName(), result.getAuthType()); + + chain.doFilter(request, response); + return; + + case CHALLENGE: + // handler has already written the 401; stop processing + return; + + case SKIP: + default: + // try the next handler + break; + } + } + + // No handler could authenticate the request; send a 401 with all challenge headers + LOG.debug("doFilter(): no handler authenticated request from {}", httpReq.getRemoteAddr()); + + sendUnauthenticated(httpResp); + } + + @Override + public void destroy() { + handlers.clear(); + } + + private void sendUnauthenticated(HttpServletResponse response) throws IOException { + for (PdpAuthNHandler handler : handlers) { + String challenge = handler.getChallengeHeader(); + + if (StringUtils.isNotBlank(challenge)) { + response.addHeader("WWW-Authenticate", challenge); + } + } + + response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); + response.setContentType("application/json"); + response.getWriter().write("{\"code\":\"UNAUTHENTICATED\",\"message\":\"Authentication required\"}"); + } Review Comment: The unauthenticated response body here uses a custom schema/value (`{"code":"UNAUTHENTICATED",...}`) that differs from the REST resource error schema (`ErrorResponse` uses `status.name()`, e.g., `UNAUTHORIZED`). This inconsistency makes client-side error handling harder. Consider reusing the same error response shape/codes for 401s (or omit the body and rely on status + `WWW-Authenticate`). ########## pdp/src/main/resources/ranger-pdp-default.xml: ########## @@ -0,0 +1,364 @@ +<?xml version="1.0" encoding="UTF-8"?> +<?xml-stylesheet type="text/xsl" href="configuration.xsl"?> +<!-- + 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. +--> +<configuration> + <property> + <name>ranger.pdp.port</name> + <value>6500</value> + <description>Port the PDP server listens on.</description> + </property> + + <property> + <name>ranger.pdp.log.dir</name> + <value>/var/log/ranger/pdp</value> + <description>Directory for PDP server log files.</description> + </property> + + <property> + <name>ranger.pdp.service.*.delegation.users</name> + <value/> + <description>Comma-separated users, allowed to call on behalf of other users in all services</description> + </property> + + <!-- SSL/TLS --> + <property> + <name>ranger.pdp.ssl.enabled</name> + <value>false</value> + <description>Set to true to enable HTTPS.</description> + </property> + + <property> + <name>ranger.pdp.ssl.keystore.file</name> + <value/> + <description>Path to the keystore file (required when SSL is enabled).</description> + </property> + + <property> + <name>ranger.pdp.ssl.keystore.password</name> + <value/> + <description>Keystore password.</description> + </property> + + <property> + <name>ranger.pdp.ssl.keystore.type</name> + <value>JKS</value> + <description>Keystore type (JKS, PKCS12).</description> + </property> + + <property> + <name>ranger.pdp.ssl.truststore.enabled</name> + <value>false</value> + <description>Set to true to require client certificate authentication.</description> + </property> + + <property> + <name>ranger.pdp.ssl.truststore.file</name> + <value/> + <description>Path to the truststore file.</description> + </property> + + <property> + <name>ranger.pdp.ssl.truststore.password</name> + <value/> + <description>Truststore password.</description> + </property> + + <property> + <name>ranger.pdp.ssl.truststore.type</name> + <value>JKS</value> + <description>Truststore type (JKS, PKCS12).</description> + </property> + + <!-- HTTP/2 --> + <property> + <name>ranger.pdp.http2.enabled</name> + <value>true</value> + <description> + Enable HTTP/2 via upgrade on the connector. + Supports both h2 (over TLS) and h2c (cleartext upgrade) alongside HTTP/1.1. + </description> + </property> + + <!-- Connector concurrency / queue limits --> + <property> + <name>ranger.pdp.http.connector.maxThreads</name> + <value>200</value> + <description>Maximum number of worker threads handling simultaneous requests.</description> + </property> + + <property> + <name>ranger.pdp.http.connector.minSpareThreads</name> + <value>20</value> + <description>Minimum number of spare worker threads kept ready.</description> + </property> + + <property> + <name>ranger.pdp.http.connector.acceptCount</name> + <value>100</value> + <description>Queued connection backlog when all worker threads are busy.</description> + </property> + + <property> + <name>ranger.pdp.http.connector.maxConnections</name> + <value>10000</value> + <description>Maximum concurrent TCP connections accepted by the connector.</description> + </property> + + <!-- Authentication for incoming REST requests --> + <property> + <name>ranger.pdp.authn.types</name> + <value>header,jwt,kerberos</value> + <description> + Comma-separated list of authentication methods for incoming REST requests, + tried in listed order. Supported values: header, jwt, kerberos. + </description> + </property> + + <!-- HTTP Header authentication for incoming REST requests --> + <property> + <name>ranger.pdp.authn.header.enabled</name> + <value>false</value> + <description> + Enable trusted HTTP header authentication. Use only behind a trusted proxy. + </description> + </property> Review Comment: With the default settings here, `ranger.pdp.authn.types` lists header/jwt/kerberos but all corresponding `*.enabled` flags are `false`, which will cause `RangerPdpAuthNFilter` to start with no handlers and fail server startup. Either enable at least one authn method by default, adjust the default `authn.types` to match enabled handlers, or explicitly document that users must enable at least one auth method before the PDP can start. -- 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]
