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,

Reply via email to