Copilot commented on code in PR #11901:
URL: https://github.com/apache/gravitino/pull/11901#discussion_r3527777234
##########
iceberg/iceberg-common/src/main/java/org/apache/gravitino/iceberg/common/utils/IcebergCatalogUtil.java:
##########
@@ -123,9 +124,22 @@ private static JdbcCatalog loadJdbcCatalog(IcebergConfig
icebergConfig) {
HdfsConfiguration hdfsConfiguration = new HdfsConfiguration();
properties.forEach(hdfsConfiguration::set);
- jdbcCatalog.setConf(hdfsConfiguration);
+ AuthenticationConfig authenticationConfig = new
AuthenticationConfig(properties);
Review Comment:
Populating `HdfsConfiguration` with *all* catalog properties risks copying
non-Hadoop keys (including secrets like JDBC passwords and possibly
auth-related values) into Hadoop configuration, which may get logged/serialized
or leak via debug tooling. Consider only applying an allowlist (e.g.,
`hadoop.*`, `dfs.*`) or a known prefix, and avoid injecting JDBC/password/auth
properties into `HdfsConfiguration`.
##########
iceberg/iceberg-common/src/main/java/org/apache/gravitino/iceberg/common/ClosableJdbcCatalog.java:
##########
@@ -0,0 +1,168 @@
+/*
+ * 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.gravitino.iceberg.common;
+
+import com.google.common.base.Preconditions;
+import java.io.Closeable;
+import java.io.File;
+import java.io.IOException;
+import java.security.PrivilegedExceptionAction;
+import java.util.Map;
+import java.util.function.Function;
+import org.apache.gravitino.catalog.hadoop.auth.KerberosAuthUtils;
+import org.apache.gravitino.catalog.hadoop.auth.KerberosClient;
+import org.apache.gravitino.iceberg.common.authentication.AuthenticationConfig;
+import org.apache.gravitino.iceberg.common.authentication.SupportsKerberos;
+import
org.apache.gravitino.iceberg.common.authentication.kerberos.KerberosConfig;
+import org.apache.gravitino.utils.PrincipalUtils;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.security.UserGroupInformation;
+import org.apache.iceberg.io.FileIO;
+import org.apache.iceberg.jdbc.JdbcCatalog;
+import org.apache.iceberg.jdbc.JdbcClientPool;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * ClosableJdbcCatalog is a wrapper class to wrap Iceberg JdbcCatalog to do
some clean-up work like
+ * closing resources and supporting Kerberos authentication for HDFS access.
+ */
+public class ClosableJdbcCatalog extends JdbcCatalog implements Closeable,
SupportsKerberos {
+
+ private static final Logger LOGGER =
LoggerFactory.getLogger(ClosableJdbcCatalog.class);
+
+ private KerberosClient kerberosClient;
+
+ private Configuration hadoopConf;
+
+ public ClosableJdbcCatalog() {
+ super();
+ }
+
+ public ClosableJdbcCatalog(
+ Function<Map<String, String>, FileIO> ioBuilder,
+ Function<Map<String, String>, JdbcClientPool> clientPoolBuilder,
+ boolean initializeCatalogTables) {
+ super(ioBuilder, clientPoolBuilder, initializeCatalogTables);
+ }
+
+ /**
+ * Initialize the ClosableJdbcCatalog with the given input name and
properties.
+ *
+ * <p>Note: This method can only be called once as it will create new client
pools.
+ *
+ * @param inputName name of the catalog
+ * @param properties properties for the catalog
+ */
+ @Override
+ public void initialize(String inputName, Map<String, String> properties) {
+ super.initialize(inputName, properties);
+
+ AuthenticationConfig authenticationConfig = new
AuthenticationConfig(properties);
+ if (authenticationConfig.isKerberosAuth()) {
+ this.kerberosClient = initKerberosClient();
+ }
+ }
+
+ /** Returns the Hadoop configuration used for Kerberos login and HDFS
access. */
+ public Configuration getHadoopConf() {
+ return hadoopConf;
+ }
+
+ /** Sets the Hadoop configuration used for Kerberos login and HDFS access. */
+ public void setHadoopConf(Configuration hadoopConf) {
+ this.hadoopConf = hadoopConf;
+ }
+
+ @Override
+ public void close() {
+ if (kerberosClient != null) {
+ try {
+ kerberosClient.close();
+ } catch (Exception e) {
+ LOGGER.warn("Failed to close KerberosClient", e);
+ }
+ }
+ try {
+ super.close();
+ } catch (Exception e) {
+ LOGGER.warn("Failed to close JdbcCatalog", e);
+ }
+ }
+
+ @Override
+ public <R> R doKerberosOperations(Executable<R> executable) throws Throwable
{
+ Map<String, String> properties = this.properties();
+ AuthenticationConfig authenticationConfig = new
AuthenticationConfig(properties);
+
+ final String finalPrincipalName;
+ String proxyKerberosPrincipalName =
PrincipalUtils.getCurrentPrincipal().getName();
+
+ if (!proxyKerberosPrincipalName.contains("@")) {
+ finalPrincipalName =
+ String.format("%s@%s", proxyKerberosPrincipalName,
kerberosClient.getRealm());
+ } else {
+ finalPrincipalName = proxyKerberosPrincipalName;
+ }
+
+ UserGroupInformation realUser =
+ authenticationConfig.isImpersonationEnabled()
+ ? UserGroupInformation.createProxyUser(
+ finalPrincipalName, kerberosClient.getLoginUser())
+ : kerberosClient.getLoginUser();
+
+ return realUser.doAs(
+ (PrivilegedExceptionAction<R>)
+ () -> {
+ try {
+ return executable.execute();
+ } catch (Throwable e) {
+ if (RuntimeException.class.isAssignableFrom(e.getClass())) {
+ throw (RuntimeException) e;
+ }
+ throw new RuntimeException("Failed to invoke method", e);
+ }
+ });
+ }
+
+ private KerberosClient initKerberosClient() {
+ try {
+ Configuration conf =
+ Preconditions.checkNotNull(
+ hadoopConf, "Hadoop configuration must be set before Kerberos
initialization");
+ KerberosConfig kerberosConfig = new KerberosConfig(this.properties());
+ KerberosClient client =
+ KerberosClient.builder(kerberosConfig.getPrincipalName(), conf)
+ .loginMode(KerberosAuthUtils.LoginMode.CURRENT_USER)
+ .checkIntervalSec(kerberosConfig.getCheckIntervalSec())
+ .build();
+ // catalog_uuid always exists for Gravitino managed catalogs, `0` is
just a fallback value.
+ String catalogUUID = properties().getOrDefault("catalog_uuid", "0");
+ File keytabFile =
+ new File(String.format(KerberosConfig.GRAVITINO_KEYTAB_FORMAT,
catalogUUID));
+ KerberosAuthUtils.saveKeytabFromUri(
+ kerberosConfig.getKeytab(), keytabFile,
kerberosConfig.getFetchTimeoutSec(), false, conf);
+ client.login(keytabFile.getAbsolutePath());
+ return client;
Review Comment:
A keytab is written to a local file path but there’s no cleanup of that on
`close()` (or after login). This can leave sensitive credentials on disk
indefinitely. Consider tracking the created keytab file and deleting it during
`close()` (or using a secure temp file with restricted permissions and
best-effort deletion), consistent with how other Kerberos-enabled components
manage local keytab material.
##########
iceberg/iceberg-common/src/main/java/org/apache/gravitino/iceberg/common/ClosableJdbcCatalog.java:
##########
@@ -0,0 +1,168 @@
+/*
+ * 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.gravitino.iceberg.common;
+
+import com.google.common.base.Preconditions;
+import java.io.Closeable;
+import java.io.File;
+import java.io.IOException;
+import java.security.PrivilegedExceptionAction;
+import java.util.Map;
+import java.util.function.Function;
+import org.apache.gravitino.catalog.hadoop.auth.KerberosAuthUtils;
+import org.apache.gravitino.catalog.hadoop.auth.KerberosClient;
+import org.apache.gravitino.iceberg.common.authentication.AuthenticationConfig;
+import org.apache.gravitino.iceberg.common.authentication.SupportsKerberos;
+import
org.apache.gravitino.iceberg.common.authentication.kerberos.KerberosConfig;
+import org.apache.gravitino.utils.PrincipalUtils;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.security.UserGroupInformation;
+import org.apache.iceberg.io.FileIO;
+import org.apache.iceberg.jdbc.JdbcCatalog;
+import org.apache.iceberg.jdbc.JdbcClientPool;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * ClosableJdbcCatalog is a wrapper class to wrap Iceberg JdbcCatalog to do
some clean-up work like
+ * closing resources and supporting Kerberos authentication for HDFS access.
+ */
+public class ClosableJdbcCatalog extends JdbcCatalog implements Closeable,
SupportsKerberos {
+
+ private static final Logger LOGGER =
LoggerFactory.getLogger(ClosableJdbcCatalog.class);
+
+ private KerberosClient kerberosClient;
+
+ private Configuration hadoopConf;
+
+ public ClosableJdbcCatalog() {
+ super();
+ }
+
+ public ClosableJdbcCatalog(
+ Function<Map<String, String>, FileIO> ioBuilder,
+ Function<Map<String, String>, JdbcClientPool> clientPoolBuilder,
+ boolean initializeCatalogTables) {
+ super(ioBuilder, clientPoolBuilder, initializeCatalogTables);
+ }
+
+ /**
+ * Initialize the ClosableJdbcCatalog with the given input name and
properties.
+ *
+ * <p>Note: This method can only be called once as it will create new client
pools.
+ *
+ * @param inputName name of the catalog
+ * @param properties properties for the catalog
+ */
+ @Override
+ public void initialize(String inputName, Map<String, String> properties) {
+ super.initialize(inputName, properties);
+
+ AuthenticationConfig authenticationConfig = new
AuthenticationConfig(properties);
+ if (authenticationConfig.isKerberosAuth()) {
+ this.kerberosClient = initKerberosClient();
+ }
+ }
+
+ /** Returns the Hadoop configuration used for Kerberos login and HDFS
access. */
+ public Configuration getHadoopConf() {
+ return hadoopConf;
+ }
+
+ /** Sets the Hadoop configuration used for Kerberos login and HDFS access. */
+ public void setHadoopConf(Configuration hadoopConf) {
+ this.hadoopConf = hadoopConf;
+ }
+
+ @Override
+ public void close() {
+ if (kerberosClient != null) {
+ try {
+ kerberosClient.close();
+ } catch (Exception e) {
+ LOGGER.warn("Failed to close KerberosClient", e);
+ }
+ }
+ try {
+ super.close();
+ } catch (Exception e) {
+ LOGGER.warn("Failed to close JdbcCatalog", e);
+ }
+ }
+
+ @Override
+ public <R> R doKerberosOperations(Executable<R> executable) throws Throwable
{
+ Map<String, String> properties = this.properties();
+ AuthenticationConfig authenticationConfig = new
AuthenticationConfig(properties);
+
+ final String finalPrincipalName;
+ String proxyKerberosPrincipalName =
PrincipalUtils.getCurrentPrincipal().getName();
+
+ if (!proxyKerberosPrincipalName.contains("@")) {
+ finalPrincipalName =
+ String.format("%s@%s", proxyKerberosPrincipalName,
kerberosClient.getRealm());
+ } else {
+ finalPrincipalName = proxyKerberosPrincipalName;
+ }
+
+ UserGroupInformation realUser =
+ authenticationConfig.isImpersonationEnabled()
+ ? UserGroupInformation.createProxyUser(
+ finalPrincipalName, kerberosClient.getLoginUser())
+ : kerberosClient.getLoginUser();
Review Comment:
`doKerberosOperations` unconditionally dereferences `kerberosClient` but
`kerberosClient` is only initialized when `authentication.type` is Kerberos and
after `initialize()` runs. If callers invoke this method for simple-auth
catalogs (or before initialization), it will throw an NPE. Consider either (a)
short-circuiting to `executable.execute()` when Kerberos is not enabled, or (b)
throwing a clear `IllegalStateException` when Kerberos is configured but the
client has not been initialized.
##########
docs/iceberg-rest-service.md:
##########
@@ -428,18 +432,62 @@ Refer to [HTTPS
Configuration](./security/how-to-use-https.md#apache-iceberg-res
#### Backend Authentication
-For JDBC backend, you can use the `gravitino.iceberg-rest.jdbc-user` and
`gravitino.iceberg-rest.jdbc-password` to authenticate the JDBC connection. For
Hive backend, you can use the `gravitino.iceberg-rest.authentication.type` to
specify the authentication type, and use the
`gravitino.iceberg-rest.authentication.kerberos.principal` and
`gravitino.iceberg-rest.authentication.kerberos.keytab-uri` to authenticate the
Kerberos connection.
+For the JDBC catalog backend, use `gravitino.iceberg-rest.jdbc-user` and
`gravitino.iceberg-rest.jdbc-password` to authenticate the JDBC metadata store
connection. Use `gravitino.iceberg-rest.authentication.type` to specify how the
catalog backend accesses the warehouse storage. When the warehouse is on HDFS,
set it to `kerberos` or `simple`, and configure
`gravitino.iceberg-rest.authentication.kerberos.principal` and
`gravitino.iceberg-rest.authentication.kerberos.keytab-uri` for Kerberos
authentication.
+
+For the Hive catalog backend, `gravitino.iceberg-rest.authentication.type`
controls both Hive Metastore and HDFS access. When using Kerberos, also
configure `gravitino.iceberg-rest.hive.metastore.sasl.enabled` and related Hive
Metastore Kerberos properties.
+
The detailed configuration items are as follows:
-| Configuration item |
Description
| Default value | Required
| Since Version |
-|---------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------|
-| `gravitino.iceberg-rest.authentication.type` |
The type of authentication for Iceberg rest catalog backend. This configuration
only applicable for Hive backend, and only supports `Kerberos`, `simple`
currently. As for JDBC backend, only username/password authentication was
supported now. | `simple` | No
| 0.7.0-incubating |
-| `gravitino.iceberg-rest.authentication.impersonation-enable` |
Whether to enable impersonation for the Iceberg catalog
| `false` | No
| 0.7.0-incubating |
-| `gravitino.iceberg-rest.hive.metastore.sasl.enabled` |
Whether to enable SASL authentication protocol when connect to Kerberos Hive
metastore.
| `false` | No, This value should be true in most case(Some will
use SSL protocol, but it rather rare) if the value of
`gravitino.iceberg-rest.authentication.type` is Kerberos. | 0.7.0-incubating |
-| `gravitino.iceberg-rest.authentication.kerberos.principal` |
The principal of the Kerberos authentication
| (none) | required if the value of
`gravitino.iceberg-rest.authentication.type` is Kerberos.
| 0.7.0-incubating |
-| `gravitino.iceberg-rest.authentication.kerberos.keytab-uri` |
The URI of The keytab for the Kerberos authentication.
| (none) | required if the value of
`gravitino.iceberg-rest.authentication.type` is Kerberos.
| 0.7.0-incubating |
-| `gravitino.iceberg-rest.authentication.kerberos.check-interval-sec` |
The check interval of Kerberos credential for Iceberg catalog.
| 60 | No
| 0.7.0-incubating |
-| `gravitino.iceberg-rest.authentication.kerberos.keytab-fetch-timeout-sec` |
The fetch timeout of retrieving Kerberos keytab from
`authentication.kerberos.keytab-uri`.
| 60 | No
| 0.7.0-incubating |
+| Configuration item
| Description
| Default value | Required
| Since Version |
+|
----------------------------------------------------------------------------- |
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| ----------------- |
------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| -------------------- |
+| `gravitino.iceberg-rest.authentication.type`
| The authentication type for HDFS warehouse access. Supports `kerberos` and
`simple` for Hive and JDBC catalog backends.
| `simple` | No
| 0.7.0-incubating |
+| `gravitino.iceberg-rest.authentication.impersonation-enable`
| Whether to enable impersonation for the Iceberg catalog
| `false` | No
| 0.7.0-incubating |
+| `gravitino.iceberg-rest.hive.metastore.sasl.enabled`
| Whether to enable SASL authentication protocol when connect to Kerberos Hive
metastore.
| `false` | No, This value should be true in most
case(Some will use SSL protocol, but it rather rare) if the value of
`gravitino.iceberg-rest.authentication.type` is kerberos. |
0.7.0-incubating |
Review Comment:
The requirement text in the table has grammar issues that make it harder to
read (e.g., `in most case(Some will use SSL protocol, but it rather rare)`).
Please rephrase for clarity (e.g., `in most cases (some deployments use SSL
instead, but it's rare)`), keeping capitalization of `kerberos` consistent with
the rest of the doc.
##########
iceberg/iceberg-common/src/main/java/org/apache/gravitino/iceberg/common/utils/IcebergCatalogUtil.java:
##########
@@ -123,9 +124,22 @@ private static JdbcCatalog loadJdbcCatalog(IcebergConfig
icebergConfig) {
HdfsConfiguration hdfsConfiguration = new HdfsConfiguration();
properties.forEach(hdfsConfiguration::set);
- jdbcCatalog.setConf(hdfsConfiguration);
+ AuthenticationConfig authenticationConfig = new
AuthenticationConfig(properties);
try {
- jdbcCatalog.initialize(icebergCatalogName, properties);
+ if (authenticationConfig.isSimpleAuth()) {
+ jdbcCatalog.setConf(hdfsConfiguration);
+ jdbcCatalog.setHadoopConf(hdfsConfiguration);
+ jdbcCatalog.initialize(icebergCatalogName, properties);
+ } else if (authenticationConfig.isKerberosAuth()) {
+ hdfsConfiguration.set(HADOOP_SECURITY_AUTHORIZATION, "true");
+ hdfsConfiguration.set(HADOOP_SECURITY_AUTHENTICATION, "kerberos");
+ jdbcCatalog.setConf(hdfsConfiguration);
+ jdbcCatalog.setHadoopConf(hdfsConfiguration);
+ jdbcCatalog.initialize(icebergCatalogName, properties);
+ } else {
+ throw new UnsupportedOperationException(
+ "Unsupported authentication method: " +
authenticationConfig.getAuthType());
+ }
Review Comment:
This adds a new behavior branch (`UnsupportedOperationException` for unknown
`authentication.type`) but the updated tests shown only assert the JDBC backend
loads as `ClosableJdbcCatalog`. Add a unit test that sets an unsupported auth
type and asserts the exception/message, to prevent regressions in auth
configuration handling.
##########
iceberg/iceberg-rest-server/src/test/java/org/apache/gravitino/iceberg/integration/test/IcebergRestKerberosJdbcCatalogIT.java:
##########
@@ -0,0 +1,174 @@
+/*
+ * 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.gravitino.iceberg.integration.test;
+
+import java.io.File;
+import java.lang.reflect.Method;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+import org.apache.commons.io.FileUtils;
+import org.apache.gravitino.catalog.lakehouse.iceberg.IcebergCatalogBackend;
+import org.apache.gravitino.catalog.lakehouse.iceberg.IcebergConstants;
+import org.apache.gravitino.iceberg.common.IcebergConfig;
+import org.apache.gravitino.integration.test.container.ContainerSuite;
+import org.apache.gravitino.integration.test.container.HiveContainer;
+import org.apache.gravitino.integration.test.util.GravitinoITUtils;
+import org.apache.gravitino.integration.test.util.ITUtils;
+import org.junit.jupiter.api.Tag;
+import org.junit.jupiter.api.TestInstance;
+import org.junit.jupiter.api.TestInstance.Lifecycle;
+import org.junit.jupiter.api.condition.EnabledIf;
+
+@Tag("gravitino-docker-test")
+@TestInstance(Lifecycle.PER_CLASS)
+@EnabledIf("isEmbedded")
+public class IcebergRestKerberosJdbcCatalogIT extends IcebergRESTServiceIT {
+
+ private static final ContainerSuite containerSuite =
ContainerSuite.getInstance();
+
+ private static final String HDFS_CLIENT_PRINCIPAL = "cli@HADOOPKRB";
+ private static final String HDFS_CLIENT_KEYTAB = "/client.keytab";
+
+ private static String tempDir;
+
+ public IcebergRestKerberosJdbcCatalogIT() {
+ catalogType = IcebergCatalogBackend.JDBC;
+ }
+
+ @Override
+ void initEnv() {
+ containerSuite.startKerberosHiveContainer();
+ try {
+ File baseDir = new File(System.getProperty("java.io.tmpdir"));
+ File file = Files.createTempDirectory(baseDir.toPath(), "test").toFile();
+ file.deleteOnExit();
+ tempDir = file.getAbsolutePath();
+
+ HiveContainer kerberosHiveContainer =
containerSuite.getKerberosHiveContainer();
+ kerberosHiveContainer
+ .getContainer()
+ .copyFileFromContainer("/etc/admin.keytab", tempDir +
HDFS_CLIENT_KEYTAB);
+
+ String tmpKrb5Path = tempDir + "/krb5.conf_tmp";
+ String krb5Path = tempDir + "/krb5.conf";
+
kerberosHiveContainer.getContainer().copyFileFromContainer("/etc/krb5.conf",
tmpKrb5Path);
+
+ String ip =
containerSuite.getKerberosHiveContainer().getContainerIpAddress();
+ String content = FileUtils.readFileToString(new File(tmpKrb5Path),
StandardCharsets.UTF_8);
+ content = content.replace("kdc = localhost:88", "kdc = " + ip + ":88");
+ content = content.replace("admin_server = localhost", "admin_server = "
+ ip + ":749");
+ FileUtils.write(new File(krb5Path), content, StandardCharsets.UTF_8);
+
+ LOG.info("Kerberos kdc config:\n{}, path: {}", content, krb5Path);
+ System.setProperty("java.security.krb5.conf", krb5Path);
+ System.setProperty("sun.security.krb5.debug", "true");
+ System.setProperty("java.security.krb5.realm", "HADOOPKRB");
+ System.setProperty("java.security.krb5.kdc", ip);
Review Comment:
This test sets JVM-global Kerberos system properties (including enabling
`sun.security.krb5.debug=true`) but doesn’t restore previous values afterward.
That can make other tests flaky/noisy when run in the same JVM. Capture
original property values and restore them in an `@AfterAll` (or similar)
cleanup step, and consider guarding the debug flag behind an opt-in system
property.
--
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]