This is an automated email from the ASF dual-hosted git repository.

jshao pushed a commit to branch branch-0.9
in repository https://gitbox.apache.org/repos/asf/gravitino.git


The following commit(s) were added to refs/heads/branch-0.9 by this push:
     new a736a93e76 [#7002] feat(client): Client supports custom token provider 
(#7005)
a736a93e76 is described below

commit a736a93e766f626c51de7ca022dfeb6a131dd111
Author: github-actions[bot] 
<41898282+github-actions[bot]@users.noreply.github.com>
AuthorDate: Fri Apr 18 17:36:16 2025 +0800

    [#7002] feat(client): Client supports custom token provider (#7005)
    
    ### What changes were proposed in this pull request?
    
    Client supports custom token provider.
    
    ### Why are the changes needed?
    
    Fix: #7002
    
    ### Does this PR introduce _any_ user-facing change?
    
    Document added.
    
    ### How was this patch tested?
    
    Add a new UT.
    
    Co-authored-by: roryqi <[email protected]>
---
 .../gravitino/client/CustomTokenProvider.java      | 123 +++++++++++++++++++++
 .../gravitino/client/GravitinoClientBase.java      |  12 ++
 .../gravitino/client/TestCustomTokenProvider.java  |  79 +++++++++++++
 docs/security/how-to-authenticate.md               |  13 +++
 4 files changed, 227 insertions(+)

diff --git 
a/clients/client-java/src/main/java/org/apache/gravitino/client/CustomTokenProvider.java
 
b/clients/client-java/src/main/java/org/apache/gravitino/client/CustomTokenProvider.java
new file mode 100644
index 0000000000..842ece577c
--- /dev/null
+++ 
b/clients/client-java/src/main/java/org/apache/gravitino/client/CustomTokenProvider.java
@@ -0,0 +1,123 @@
+/*
+ * 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.client;
+
+import com.google.common.base.Preconditions;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import org.apache.commons.lang3.StringUtils;
+
+/** CustomTokenProvider will provide a custom access token for every request. 
*/
+public abstract class CustomTokenProvider implements AuthDataProvider {
+  private static final String BLANK_SPACE = " ";
+
+  /** The name of authentication scheme. */
+  protected String schemeName;
+
+  @Override
+  public boolean hasTokenData() {
+    return true;
+  }
+
+  @Override
+  public byte[] getTokenData() {
+    return (schemeName + BLANK_SPACE + 
getCustomTokenInfo()).getBytes(StandardCharsets.UTF_8);
+  }
+
+  @Override
+  public void close() throws IOException {
+    // do nothing
+  }
+
+  /**
+   * Gets the custom token information.
+   *
+   * @return The custom token information.
+   */
+  protected abstract String getCustomTokenInfo();
+
+  /**
+   * Builder interface for configuring and creating instances of 
CustomTokenProvider.
+   *
+   * @param <SELF> The subclass type of the Builder.
+   * @param <T> The subclass type of the CustomTokenProvider.
+   */
+  protected interface Builder<SELF extends Builder<SELF, T>, T extends 
CustomTokenProvider> {
+    /**
+     * Sets the scheme name for the CustomTokenProvider.
+     *
+     * @param schemeName The scheme name for the CustomTokenProvider.
+     * @return This Builder instance for method chaining.
+     */
+    SELF withSchemeName(String schemeName);
+
+    /**
+     * Builds the instance of the CustomTokenProvider.
+     *
+     * @return The instance of the CustomTokenProvider.
+     */
+    T build();
+  }
+
+  /** Builder class for configuring and creating instances of 
CustomTokenProvider. */
+  public abstract static class CustomTokenProviderBuilder<
+          SELF extends Builder<SELF, T>, T extends CustomTokenProvider>
+      implements Builder<SELF, T> {
+
+    /** the name of authentication scheme */
+    protected String schemeName;
+
+    /**
+     * Sets the scheme name for the CustomTokenProvider.
+     *
+     * <p>Scheme name is the name of the authentication scheme. For example, 
"Bearer" or "Basic".
+     *
+     * @param schemeName The scheme name for the CustomTokenProvider.
+     * @return This Builder instance for method chaining.
+     */
+    public SELF withSchemeName(String schemeName) {
+      this.schemeName = schemeName;
+      return self();
+    }
+
+    /**
+     * Builds the instance of the CustomTokenProvider.
+     *
+     * @return The instance of the CustomTokenProvider.
+     */
+    public T build() {
+      Preconditions.checkArgument(
+          StringUtils.isNotBlank(schemeName), "CustomTokenProvider must set 
schemeName");
+
+      T t = internalBuild();
+      return t;
+    }
+
+    /**
+     * Builds the instance of the CustomTokenProvider.
+     *
+     * @return The built CustomTokenProvider instance.
+     */
+    protected abstract T internalBuild();
+
+    private SELF self() {
+      return (SELF) this;
+    }
+  }
+}
diff --git 
a/clients/client-java/src/main/java/org/apache/gravitino/client/GravitinoClientBase.java
 
b/clients/client-java/src/main/java/org/apache/gravitino/client/GravitinoClientBase.java
index 649f5cc6b8..1e39133e72 100644
--- 
a/clients/client-java/src/main/java/org/apache/gravitino/client/GravitinoClientBase.java
+++ 
b/clients/client-java/src/main/java/org/apache/gravitino/client/GravitinoClientBase.java
@@ -281,6 +281,18 @@ public abstract class GravitinoClientBase implements 
Closeable {
       return this;
     }
 
+    /**
+     * Sets CustomTokenProvider for the Gravitino.
+     *
+     * @param dataProvider The CustomTokenProvider used as the provider of 
authentication data for
+     *     Gravitino Client.
+     * @return This Builder instance for method chaining.
+     */
+    public Builder<T> withCustomTokenAuth(CustomTokenProvider dataProvider) {
+      this.authDataProvider = dataProvider;
+      return this;
+    }
+
     /**
      * Set base header for Gravitino Client.
      *
diff --git 
a/clients/client-java/src/test/java/org/apache/gravitino/client/TestCustomTokenProvider.java
 
b/clients/client-java/src/test/java/org/apache/gravitino/client/TestCustomTokenProvider.java
new file mode 100644
index 0000000000..12456ca956
--- /dev/null
+++ 
b/clients/client-java/src/test/java/org/apache/gravitino/client/TestCustomTokenProvider.java
@@ -0,0 +1,79 @@
+/*
+ * 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.client;
+
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+public class TestCustomTokenProvider {
+
+  @Test
+  public void testAuthentication() throws IOException {
+    try (AuthDataProvider provider =
+        
CustomTestTokenProvider.builder().withSchemeName("test").withTokenInfo("test").build())
 {
+      Assertions.assertTrue(provider.hasTokenData());
+      Assertions.assertArrayEquals(
+          provider.getTokenData(), "test 
test".getBytes(StandardCharsets.UTF_8));
+      // Token won't change
+      Assertions.assertArrayEquals(
+          provider.getTokenData(), "test 
test".getBytes(StandardCharsets.UTF_8));
+    }
+  }
+
+  private static class CustomTestTokenProvider extends CustomTokenProvider {
+    private String tokenInfo;
+
+    private CustomTestTokenProvider() {}
+
+    @Override
+    protected String getCustomTokenInfo() {
+      return tokenInfo;
+    }
+
+    public static Builder builder() {
+      return new Builder();
+    }
+
+    public static class Builder
+        extends CustomTokenProviderBuilder<Builder, CustomTestTokenProvider> {
+      private String tokenInfo;
+
+      public Builder withTokenInfo(String tokenInfo) {
+        this.tokenInfo = tokenInfo;
+        return this;
+      }
+
+      @Override
+      public Builder withSchemeName(String schemeName) {
+        this.schemeName = schemeName;
+        return this;
+      }
+
+      @Override
+      protected CustomTestTokenProvider internalBuild() {
+        CustomTestTokenProvider tokenProvider = new CustomTestTokenProvider();
+        tokenProvider.schemeName = schemeName;
+        tokenProvider.tokenInfo = tokenInfo;
+        return tokenProvider;
+      }
+    }
+  }
+}
diff --git a/docs/security/how-to-authenticate.md 
b/docs/security/how-to-authenticate.md
index 61c2295f09..e5a0c00e3b 100644
--- a/docs/security/how-to-authenticate.md
+++ b/docs/security/how-to-authenticate.md
@@ -86,6 +86,19 @@ Now Iceberg REST service doesn't support Kerberos 
authentication.
 The URI must use the hostname of server instead of IP.
 :::
 
+### Custom mode
+
+Gravitino also supports to implement custom authentication mode.
+For server side, you can implement the interface `Authenticator` and specify 
`grantviino.authenciators`.
+For client side, you extend the abstract class `CustomTokenProvider` and 
specify the token provider.
+
+```java
+GravitinoClient client = GravitinoClient.builder(uri)
+    .withMetalake("metalake")
+    .withCustomProvider(provider)
+    .build();
+```
+
 ### Server configuration
 
 | Configuration item                                | Description              
                                                                                
                                                                                
                                                                  | Default 
value     | Required                                   | Since version    |

Reply via email to