This is an automated email from the ASF dual-hosted git repository.
jshao 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 ac691c77f1 [#7002] feat(client): Client supports custom token provider
(#7003)
ac691c77f1 is described below
commit ac691c77f1cd66d91c175ef14f4951f7968a157e
Author: roryqi <[email protected]>
AuthorDate: Fri Apr 18 16:13:28 2025 +0800
[#7002] feat(client): Client supports custom token provider (#7003)
### 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.
---
.../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 |