This is an automated email from the ASF dual-hosted git repository.
jerryshao pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/gravitino.git
The following commit(s) were added to refs/heads/main by this push:
new 3207d8f5f9 [#13685] fix(gvfs): Support Basic authentication in Java
client (#13688)
3207d8f5f9 is described below
commit 3207d8f5f92159ee3274b7df0ac1ea919dd40691
Author: mchades <[email protected]>
AuthorDate: Thu Oct 8 14:28:44 2026 +0800
[#13685] fix(gvfs): Support Basic authentication in Java client (#13688)
### What changes were proposed in this pull request?
- Add Basic authentication support to the Java GVFS client.
- Validate the configured Basic username and password.
- Exclude Basic credentials from generic client configuration.
- Add authentication tests and document the new configuration
properties.
### Why are the changes needed?
Java GVFS currently rejects `basic` authentication even though the Java
SDK supports it. This prevents GVFS from connecting to a Gravitino
server backed by the built-in local user store.
Fix: #13685
### Does this PR introduce _any_ user-facing change?
Yes. Java GVFS now supports:
- `fs.gravitino.client.authType=basic`
- `fs.gravitino.client.basic.username`
- `fs.gravitino.client.basic.password`
### How was this patch tested?
- `./gradlew :clients:filesystem-hadoop3:check :docs:spotlessCheck
-PskipITs`
- Verified Basic, Simple, OAuth2, and Kerberos authentication tests.
Docker and integration tests were not run.
---
.../GravitinoVirtualFileSystemConfiguration.java | 17 ++-
.../hadoop/GravitinoVirtualFileSystemUtils.java | 25 ++++
.../filesystem/hadoop/TestBasicClient.java | 152 +++++++++++++++++++++
docs/how-to-use-gvfs.md | 25 +++-
4 files changed, 216 insertions(+), 3 deletions(-)
diff --git
a/clients/filesystem-hadoop3/src/main/java/org/apache/gravitino/filesystem/hadoop/GravitinoVirtualFileSystemConfiguration.java
b/clients/filesystem-hadoop3/src/main/java/org/apache/gravitino/filesystem/hadoop/GravitinoVirtualFileSystemConfiguration.java
index 3334e17b6e..2cc8dd0e49 100644
---
a/clients/filesystem-hadoop3/src/main/java/org/apache/gravitino/filesystem/hadoop/GravitinoVirtualFileSystemConfiguration.java
+++
b/clients/filesystem-hadoop3/src/main/java/org/apache/gravitino/filesystem/hadoop/GravitinoVirtualFileSystemConfiguration.java
@@ -48,14 +48,29 @@ public class GravitinoVirtualFileSystemConfiguration {
/** The authentication type for simple authentication. */
public static final String SIMPLE_AUTH_TYPE = "simple";
+ /** The authentication type for basic authentication. */
+ public static final String BASIC_AUTH_TYPE = "basic";
+
/** The authentication type for oauth2 authentication. */
public static final String OAUTH2_AUTH_TYPE = "oauth2";
/** The authentication type for kerberos authentication. */
public static final String KERBEROS_AUTH_TYPE = "kerberos";
+ // basic
+ /** The configuration key prefix for basic authentication. */
+ public static final String FS_GRAVITINO_CLIENT_BASIC_PREFIX =
"fs.gravitino.client.basic.";
+
+ /** The configuration key for the basic authentication username. */
+ public static final String FS_GRAVITINO_CLIENT_BASIC_USERNAME_KEY =
+ "fs.gravitino.client.basic.username";
+
+ /** The configuration key for the basic authentication password. */
+ public static final String FS_GRAVITINO_CLIENT_BASIC_PASSWORD_KEY =
+ "fs.gravitino.client.basic.password";
+
// oauth2
- /** The configuration key prefix for oauth2 */
+ /** The configuration key prefix for oauth2. */
public static final String FS_GRAVITINO_CLIENT_OAUTH2_PREFIX =
"fs.gravitino.client.oauth2.";
/** The configuration key for the URI of the default OAuth server. */
diff --git
a/clients/filesystem-hadoop3/src/main/java/org/apache/gravitino/filesystem/hadoop/GravitinoVirtualFileSystemUtils.java
b/clients/filesystem-hadoop3/src/main/java/org/apache/gravitino/filesystem/hadoop/GravitinoVirtualFileSystemUtils.java
index c532757081..aca5b3ce9f 100644
---
a/clients/filesystem-hadoop3/src/main/java/org/apache/gravitino/filesystem/hadoop/GravitinoVirtualFileSystemUtils.java
+++
b/clients/filesystem-hadoop3/src/main/java/org/apache/gravitino/filesystem/hadoop/GravitinoVirtualFileSystemUtils.java
@@ -20,6 +20,7 @@
package org.apache.gravitino.filesystem.hadoop;
import static
org.apache.gravitino.client.GravitinoClientConfiguration.GRAVITINO_CLIENT_CONFIG_PREFIX;
+import static
org.apache.gravitino.filesystem.hadoop.GravitinoVirtualFileSystemConfiguration.FS_GRAVITINO_CLIENT_BASIC_PREFIX;
import static
org.apache.gravitino.filesystem.hadoop.GravitinoVirtualFileSystemConfiguration.FS_GRAVITINO_CLIENT_CONFIG_PREFIX;
import static
org.apache.gravitino.filesystem.hadoop.GravitinoVirtualFileSystemConfiguration.FS_GRAVITINO_CLIENT_KERBEROS_PREFIX;
import static
org.apache.gravitino.filesystem.hadoop.GravitinoVirtualFileSystemConfiguration.FS_GRAVITINO_CLIENT_OAUTH2_PREFIX;
@@ -138,6 +139,29 @@ public class GravitinoVirtualFileSystemUtils {
.withHeaders(requestHeaders)
.withClientConfig(clientConfig)
.build();
+ } else if
(authType.equalsIgnoreCase(GravitinoVirtualFileSystemConfiguration.BASIC_AUTH_TYPE))
{
+ String username =
+ configuration.get(
+
GravitinoVirtualFileSystemConfiguration.FS_GRAVITINO_CLIENT_BASIC_USERNAME_KEY);
+ checkAuthConfig(
+ GravitinoVirtualFileSystemConfiguration.BASIC_AUTH_TYPE,
+
GravitinoVirtualFileSystemConfiguration.FS_GRAVITINO_CLIENT_BASIC_USERNAME_KEY,
+ username);
+
+ String password =
+ configuration.get(
+
GravitinoVirtualFileSystemConfiguration.FS_GRAVITINO_CLIENT_BASIC_PASSWORD_KEY);
+ checkAuthConfig(
+ GravitinoVirtualFileSystemConfiguration.BASIC_AUTH_TYPE,
+
GravitinoVirtualFileSystemConfiguration.FS_GRAVITINO_CLIENT_BASIC_PASSWORD_KEY,
+ password);
+
+ return GravitinoClient.builder(serverUri)
+ .withMetalake(metalakeValue)
+ .withBasicAuth(username, password)
+ .withHeaders(requestHeaders)
+ .withClientConfig(clientConfig)
+ .build();
} else if (authType.equalsIgnoreCase(
GravitinoVirtualFileSystemConfiguration.OAUTH2_AUTH_TYPE)) {
String authServerUri =
@@ -241,6 +265,7 @@ public class GravitinoVirtualFileSystemUtils {
private static boolean isClientConfigKey(String key) {
return key.startsWith(FS_GRAVITINO_CLIENT_CONFIG_PREFIX)
+ && !key.startsWith(FS_GRAVITINO_CLIENT_BASIC_PREFIX)
&& !key.startsWith(FS_GRAVITINO_CLIENT_OAUTH2_PREFIX)
&& !key.startsWith(FS_GRAVITINO_CLIENT_KERBEROS_PREFIX)
&& !key.startsWith(FS_GRAVITINO_CLIENT_REQUEST_HEADER_PREFIX)
diff --git
a/clients/filesystem-hadoop3/src/test/java/org/apache/gravitino/filesystem/hadoop/TestBasicClient.java
b/clients/filesystem-hadoop3/src/test/java/org/apache/gravitino/filesystem/hadoop/TestBasicClient.java
new file mode 100644
index 0000000000..43eefcfd57
--- /dev/null
+++
b/clients/filesystem-hadoop3/src/test/java/org/apache/gravitino/filesystem/hadoop/TestBasicClient.java
@@ -0,0 +1,152 @@
+/*
+ * 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.filesystem.hadoop;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.time.Instant;
+import java.util.Base64;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicReference;
+import org.apache.gravitino.auth.AuthConstants;
+import org.apache.gravitino.client.GravitinoClient;
+import org.apache.gravitino.dto.AuditDTO;
+import org.apache.gravitino.dto.MetalakeDTO;
+import org.apache.gravitino.dto.responses.MetalakeResponse;
+import org.apache.gravitino.exceptions.RESTException;
+import org.apache.gravitino.json.JsonUtils;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.fs.FileSystem;
+import org.apache.hadoop.fs.Path;
+import org.apache.hc.core5.http.HttpStatus;
+import org.apache.hc.core5.http.Method;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.mockserver.matchers.Times;
+import org.mockserver.model.Header;
+import org.mockserver.model.HttpRequest;
+import org.mockserver.model.HttpResponse;
+
+/** Tests Basic authentication for the Java Gravitino Virtual File System
client. */
+public class TestBasicClient extends TestGvfsBase {
+ private static final String USERNAME = "admin";
+ private static final String PASSWORD = "YourSecurePassword12";
+
+ /** Sets up the mock server and Basic authentication configuration. */
+ @BeforeAll
+ public static void setup() {
+ TestGvfsBase.setup();
+ conf.set(
+
GravitinoVirtualFileSystemConfiguration.FS_GRAVITINO_CLIENT_AUTH_TYPE_KEY,
+ GravitinoVirtualFileSystemConfiguration.BASIC_AUTH_TYPE);
+ conf.set(
+
GravitinoVirtualFileSystemConfiguration.FS_GRAVITINO_CLIENT_BASIC_USERNAME_KEY,
USERNAME);
+ conf.set(
+
GravitinoVirtualFileSystemConfiguration.FS_GRAVITINO_CLIENT_BASIC_PASSWORD_KEY,
PASSWORD);
+ }
+
+ /** Verifies that GVFS sends the configured Basic authentication
credentials. */
+ @Test
+ public void testBasicAuthToken() throws IOException {
+ String testMetalake = "test_basic_token";
+ HttpRequest mockRequest =
+ HttpRequest.request("/api/metalakes/" + testMetalake)
+ .withMethod(Method.GET.name())
+ .withQueryStringParameters(Collections.emptyMap());
+
+ MetalakeDTO mockMetalake =
+ MetalakeDTO.builder()
+ .withName(testMetalake)
+ .withComment("comment")
+ .withAudit(
+
AuditDTO.builder().withCreator("creator").withCreateTime(Instant.now()).build())
+ .build();
+ MetalakeResponse response = new MetalakeResponse(mockMetalake);
+
+ AtomicReference<String> actualTokenValue = new AtomicReference<>();
+ mockServer()
+ .when(mockRequest, Times.unlimited())
+ .respond(
+ request -> {
+ List<Header> headers = request.getHeaders().getEntries();
+ for (Header header : headers) {
+ if (header.getName().equalsIgnoreCase("Authorization")) {
+ actualTokenValue.set(header.getValues().get(0).getValue());
+ }
+ }
+ return HttpResponse.response()
+ .withStatusCode(HttpStatus.SC_OK)
+
.withBody(JsonUtils.objectMapper().writeValueAsString(response));
+ });
+
+ Path managedFilesetPath =
+ FileSystemTestUtils.createFilesetPath(catalogName, schemaName,
"testBasicAuthToken", true);
+ Path path = new Path(managedFilesetPath.toString().replace(metalakeName,
testMetalake));
+
+ Configuration configuration = new Configuration(conf);
+ configuration.set(
+
GravitinoVirtualFileSystemConfiguration.FS_GRAVITINO_CLIENT_METALAKE_KEY,
testMetalake);
+ try (FileSystem fileSystem = path.getFileSystem(configuration)) {
+ assertThrows(RESTException.class, () -> fileSystem.exists(path));
+ }
+
+ String credentials = USERNAME + ":" + PASSWORD;
+ assertEquals(
+ AuthConstants.AUTHORIZATION_BASIC_HEADER
+ +
Base64.getEncoder().encodeToString(credentials.getBytes(StandardCharsets.UTF_8)),
+ actualTokenValue.get());
+ }
+
+ /** Verifies Basic authentication configuration validation and filtering. */
+ @Test
+ public void testBasicAuthConfigs() {
+ Configuration configuration = new Configuration(false);
+ configuration.set(
+ GravitinoVirtualFileSystemConfiguration.FS_GRAVITINO_SERVER_URI_KEY,
serverUri());
+ configuration.set(
+
GravitinoVirtualFileSystemConfiguration.FS_GRAVITINO_CLIENT_METALAKE_KEY,
metalakeName);
+ configuration.set(
+
GravitinoVirtualFileSystemConfiguration.FS_GRAVITINO_CLIENT_AUTH_TYPE_KEY,
+ GravitinoVirtualFileSystemConfiguration.BASIC_AUTH_TYPE);
+
+ assertThrows(
+ IllegalArgumentException.class,
+ () -> GravitinoVirtualFileSystemUtils.createClient(configuration));
+
+ configuration.set(
+
GravitinoVirtualFileSystemConfiguration.FS_GRAVITINO_CLIENT_BASIC_USERNAME_KEY,
USERNAME);
+ assertThrows(
+ IllegalArgumentException.class,
+ () -> GravitinoVirtualFileSystemUtils.createClient(configuration));
+
+ configuration.set(
+
GravitinoVirtualFileSystemConfiguration.FS_GRAVITINO_CLIENT_BASIC_PASSWORD_KEY,
PASSWORD);
+ try (GravitinoClient ignored =
GravitinoVirtualFileSystemUtils.createClient(configuration)) {
+ Map<String, String> clientConfig =
+ GravitinoVirtualFileSystemUtils.extractClientConfig(
+ GravitinoVirtualFileSystemUtils.getConfigMap(configuration));
+ assertEquals(Collections.emptyMap(), clientConfig);
+ }
+ }
+}
diff --git a/docs/how-to-use-gvfs.md b/docs/how-to-use-gvfs.md
index 257015c72c..17cb874591 100644
--- a/docs/how-to-use-gvfs.md
+++ b/docs/how-to-use-gvfs.md
@@ -53,7 +53,9 @@ the path mapping and convert automatically.
| `fs.gvfs.impl.disable.cache` | Disable the
Gravitino Virtual File System cache in the Hadoop environment. If you need to
proxy multi-user operations, set this value to `true` and create a separate
File System for each user.
| `false`
| No [...]
| `fs.gravitino.server.uri` | The Gravitino server
URI which GVFS needs to load the fileset metadata.
| (none)
| Yes [...]
| `fs.gravitino.client.metalake` | The metalake to
which the fileset belongs.
| (none)
| Yes [...]
-| `fs.gravitino.client.authType` | The auth type the
Gravitino client uses with the Gravitino Virtual File System. Supports
`simple`, `oauth2`, and `kerberos`.
| `simple`
| No [...]
+| `fs.gravitino.client.authType` | The auth type the
Gravitino client uses with the Gravitino Virtual File System. Supports
`simple`, `basic`, `oauth2`, and `kerberos`.
| `simple`
| No [...]
+| `fs.gravitino.client.basic.username` | The username for the
Gravitino client when using `basic` auth type with the local user store.
| (none)
| Yes if y [...]
+| `fs.gravitino.client.basic.password` | The password for the
Gravitino client when using `basic` auth type with the local user store.
| (none)
| Yes if y [...]
| `fs.gravitino.client.oauth2.serverUri` | The auth server URI
for the Gravitino client when using `oauth2` auth type with the Gravitino
Virtual File System.
| (none)
| Yes if y [...]
| `fs.gravitino.client.oauth2.credential` | The auth credential
for the Gravitino client when using `oauth2` auth type in the Gravitino Virtual
File System.
| (none)
| Yes if y [...]
| `fs.gravitino.client.oauth2.path` | The auth server path
for the Gravitino client when using `oauth2` auth type with the Gravitino
Virtual File System. Please remove the first slash `/` from the path, for
example `oauth/token`.
| (none)
| Yes if y [...]
@@ -321,7 +323,7 @@ For Tensorflow to support GVFS, you need to recompile the
[tensorflow-io](https:
### Authentication
-Gravitino Virtual File System supports two kinds of authentication types to
access Gravitino server: `simple` and `oauth2`.
+Gravitino Virtual File System supports `simple`, `basic`, `oauth2`, and
`kerberos` authentication to access the Gravitino server.
The type of `simple` is the default authentication type in Gravitino Virtual
File System.
@@ -349,6 +351,25 @@ Path filesetPath = new
Path("gvfs://fileset/test_catalog/test_schema/test_filese
FileSystem fs = filesetPath.getFileSystem(conf);
```
+#### `Basic` Authentication
+
+To use `basic` authentication, configure the Gravitino server with the
built-in local user store as described in [Local users and
groups](security/local-users-and-groups.md).
+
+Then, configure the Hadoop client with the local user's credentials:
+
+```java
+Configuration conf = new Configuration();
+conf.set("fs.AbstractFileSystem.gvfs.impl","org.apache.gravitino.filesystem.hadoop.Gvfs");
+conf.set("fs.gvfs.impl","org.apache.gravitino.filesystem.hadoop.GravitinoVirtualFileSystem");
+conf.set("fs.gravitino.server.uri","http://localhost:8090");
+conf.set("fs.gravitino.client.metalake","test_metalake");
+conf.set("fs.gravitino.client.authType", "basic");
+conf.set("fs.gravitino.client.basic.username", "${your_username}");
+conf.set("fs.gravitino.client.basic.password", "${your_password}");
+Path filesetPath = new
Path("gvfs://fileset/test_catalog/test_schema/test_fileset_1");
+FileSystem fs = filesetPath.getFileSystem(conf);
+```
+
#### `OAuth` Authentication
If you want to use `oauth2` authentication for the Gravitino client in the
Gravitino Virtual File System,