diff --git a/paimon-core/src/main/java/org/apache/paimon/rest/RESTCatalog.java b/paimon-core/src/main/java/org/apache/paimon/rest/RESTCatalog.java index d45cf8b8a38c..ab1799a56367 100644 --- a/paimon-core/src/main/java/org/apache/paimon/rest/RESTCatalog.java +++ b/paimon-core/src/main/java/org/apache/paimon/rest/RESTCatalog.java @@ -26,7 +26,6 @@ import org.apache.paimon.manifest.PartitionEntry; import org.apache.paimon.options.CatalogOptions; import org.apache.paimon.options.Options; -import org.apache.paimon.rest.auth.AuthOptions; import org.apache.paimon.rest.auth.AuthSession; import org.apache.paimon.rest.auth.CredentialsProvider; import org.apache.paimon.rest.auth.CredentialsProviderFactory; @@ -81,7 +80,7 @@ public RESTCatalog(Options options) { CredentialsProvider credentialsProvider = CredentialsProviderFactory.createCredentialsProvider( options, RESTCatalog.class.getClassLoader()); - this.keepTokenRefreshed = options.get(AuthOptions.TOKEN_REFRESH_ENABLED); + this.keepTokenRefreshed = options.get(RESTCatalogOptions.TOKEN_REFRESH_ENABLED); if (keepTokenRefreshed) { this.catalogAuth = AuthSession.fromRefreshCredentialsProvider( diff --git a/paimon-core/src/main/java/org/apache/paimon/rest/RESTCatalogOptions.java b/paimon-core/src/main/java/org/apache/paimon/rest/RESTCatalogOptions.java index d49fa38ab85e..bc405b996a94 100644 --- a/paimon-core/src/main/java/org/apache/paimon/rest/RESTCatalogOptions.java +++ b/paimon-core/src/main/java/org/apache/paimon/rest/RESTCatalogOptions.java @@ -45,4 +45,29 @@ public class RESTCatalogOptions { .intType() .defaultValue(1) .withDescription("REST Catalog http client thread num."); + public static final ConfigOption TOKEN = + ConfigOptions.key("token") + .stringType() + .noDefaultValue() + .withDescription("REST Catalog auth token."); + public static final ConfigOption TOKEN_EXPIRATION_TIME = + ConfigOptions.key("token.expiration-time") + .durationType() + .defaultValue(Duration.ofHours(1)) + .withDescription("REST Catalog auth token expires in."); + public static final ConfigOption TOKEN_REFRESH_ENABLED = + ConfigOptions.key("token-refresh-enabled") + .booleanType() + .defaultValue(false) + .withDescription("REST Catalog auth token refresh enable."); + public static final ConfigOption TOKEN_PROVIDER_PATH = + ConfigOptions.key("token.provider.path") + .stringType() + .noDefaultValue() + .withDescription("REST Catalog auth token file path."); + public static final ConfigOption CREDENTIALS_PROVIDER = + ConfigOptions.key("credentials-provider") + .stringType() + .noDefaultValue() + .withDescription("REST Catalog auth credentials provider."); } diff --git a/paimon-core/src/main/java/org/apache/paimon/rest/auth/AuthOptions.java b/paimon-core/src/main/java/org/apache/paimon/rest/auth/AuthOptions.java deleted file mode 100644 index c68bb29d12e9..000000000000 --- a/paimon-core/src/main/java/org/apache/paimon/rest/auth/AuthOptions.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * 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.paimon.rest.auth; - -import org.apache.paimon.options.ConfigOption; -import org.apache.paimon.options.ConfigOptions; - -import java.time.Duration; - -/** Options for REST Catalog Auth. */ -public class AuthOptions { - public static final ConfigOption TOKEN = - ConfigOptions.key("token") - .stringType() - .noDefaultValue() - .withDescription("REST Catalog auth token."); - public static final ConfigOption TOKEN_EXPIRES_IN = - ConfigOptions.key("token-expires-in") - .durationType() - .defaultValue(Duration.ofHours(1)) - .withDescription("REST Catalog auth token expires in."); - public static final ConfigOption TOKEN_REFRESH_ENABLED = - ConfigOptions.key("token-refresh-enabled") - .booleanType() - .defaultValue(false) - .withDescription("REST Catalog auth token refresh enable."); - public static final ConfigOption TOKEN_FILE_PATH = - ConfigOptions.key("token-file-path") - .stringType() - .noDefaultValue() - .withDescription("REST Catalog auth token file path."); - public static final ConfigOption CREDENTIALS_PROVIDER = - ConfigOptions.key("credentials-provider") - .stringType() - .noDefaultValue() - .withDescription("REST Catalog auth credentials provider."); -} diff --git a/paimon-core/src/main/java/org/apache/paimon/rest/auth/BearTokenCredentialsProviderFactory.java b/paimon-core/src/main/java/org/apache/paimon/rest/auth/BearTokenCredentialsProviderFactory.java index f009ad8442cf..cf3864025107 100644 --- a/paimon-core/src/main/java/org/apache/paimon/rest/auth/BearTokenCredentialsProviderFactory.java +++ b/paimon-core/src/main/java/org/apache/paimon/rest/auth/BearTokenCredentialsProviderFactory.java @@ -19,6 +19,7 @@ package org.apache.paimon.rest.auth; import org.apache.paimon.options.Options; +import org.apache.paimon.rest.RESTCatalogOptions; import org.apache.paimon.utils.StringUtils; /** factory for create {@link BearTokenCredentialsProvider}. */ @@ -30,12 +31,12 @@ public String identifier() { @Override public CredentialsProvider create(Options options) { - if (options.getOptional(AuthOptions.TOKEN) + if (options.getOptional(RESTCatalogOptions.TOKEN) .map(StringUtils::isNullOrWhitespaceOnly) .orElse(true)) { throw new IllegalArgumentException( - AuthOptions.TOKEN.key() + " is required and not empty"); + RESTCatalogOptions.TOKEN.key() + " is required and not empty"); } - return new BearTokenCredentialsProvider(options.get(AuthOptions.TOKEN)); + return new BearTokenCredentialsProvider(options.get(RESTCatalogOptions.TOKEN)); } } diff --git a/paimon-core/src/main/java/org/apache/paimon/rest/auth/BearTokenFileCredentialsProvider.java b/paimon-core/src/main/java/org/apache/paimon/rest/auth/BearTokenFileCredentialsProvider.java index 4e8246498fb2..d479caa67fd0 100644 --- a/paimon-core/src/main/java/org/apache/paimon/rest/auth/BearTokenFileCredentialsProvider.java +++ b/paimon-core/src/main/java/org/apache/paimon/rest/auth/BearTokenFileCredentialsProvider.java @@ -18,12 +18,12 @@ package org.apache.paimon.rest.auth; +import org.apache.paimon.utils.FileIOUtils; import org.apache.paimon.utils.StringUtils; +import java.io.File; import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Paths; +import java.io.UncheckedIOException; import java.util.Optional; /** credentials provider for get bear token from file. */ @@ -57,11 +57,12 @@ String token() { @Override public boolean refresh() { long start = System.currentTimeMillis(); - this.token = getTokenFromFile(); - this.expiresAtMillis = start + this.expiresInMills; - if (StringUtils.isNullOrWhitespaceOnly(this.token)) { + String newToken = getTokenFromFile(); + if (StringUtils.isNullOrWhitespaceOnly(newToken)) { return false; } + this.expiresAtMillis = start + this.expiresInMills; + this.token = newToken; return true; } @@ -97,10 +98,9 @@ public Optional expiresInMills() { private String getTokenFromFile() { try { - // todo: handle exception - return new String(Files.readAllBytes(Paths.get(tokenFilePath)), StandardCharsets.UTF_8); + return FileIOUtils.readFileUtf8(new File(tokenFilePath)); } catch (IOException e) { - throw new RuntimeException(e); + throw new UncheckedIOException(e); } } } diff --git a/paimon-core/src/main/java/org/apache/paimon/rest/auth/BearTokenFileCredentialsProviderFactory.java b/paimon-core/src/main/java/org/apache/paimon/rest/auth/BearTokenFileCredentialsProviderFactory.java index 448d279cd887..b7a99639289e 100644 --- a/paimon-core/src/main/java/org/apache/paimon/rest/auth/BearTokenFileCredentialsProviderFactory.java +++ b/paimon-core/src/main/java/org/apache/paimon/rest/auth/BearTokenFileCredentialsProviderFactory.java @@ -19,9 +19,10 @@ package org.apache.paimon.rest.auth; import org.apache.paimon.options.Options; +import org.apache.paimon.rest.RESTCatalogOptions; -import static org.apache.paimon.rest.auth.AuthOptions.TOKEN_EXPIRES_IN; -import static org.apache.paimon.rest.auth.AuthOptions.TOKEN_FILE_PATH; +import static org.apache.paimon.rest.RESTCatalogOptions.TOKEN_EXPIRATION_TIME; +import static org.apache.paimon.rest.RESTCatalogOptions.TOKEN_PROVIDER_PATH; /** factory for create {@link BearTokenCredentialsProvider}. */ public class BearTokenFileCredentialsProviderFactory implements CredentialsProviderFactory { @@ -33,17 +34,17 @@ public String identifier() { @Override public CredentialsProvider create(Options options) { - if (!options.getOptional(TOKEN_FILE_PATH).isPresent()) { - throw new IllegalArgumentException(TOKEN_FILE_PATH.key() + " is required"); + if (!options.getOptional(TOKEN_PROVIDER_PATH).isPresent()) { + throw new IllegalArgumentException(TOKEN_PROVIDER_PATH.key() + " is required"); } - String tokenFilePath = options.get(TOKEN_FILE_PATH); - boolean keepTokenRefreshed = options.get(AuthOptions.TOKEN_REFRESH_ENABLED); + String tokenFilePath = options.get(TOKEN_PROVIDER_PATH); + boolean keepTokenRefreshed = options.get(RESTCatalogOptions.TOKEN_REFRESH_ENABLED); if (keepTokenRefreshed) { - if (!options.getOptional(TOKEN_EXPIRES_IN).isPresent()) { + if (!options.getOptional(TOKEN_EXPIRATION_TIME).isPresent()) { throw new IllegalArgumentException( - TOKEN_EXPIRES_IN.key() + " is required when token refresh enabled"); + TOKEN_EXPIRATION_TIME.key() + " is required when token refresh enabled"); } - long tokenExpireInMills = options.get(TOKEN_EXPIRES_IN).toMillis(); + long tokenExpireInMills = options.get(TOKEN_EXPIRATION_TIME).toMillis(); return new BearTokenFileCredentialsProvider(tokenFilePath, tokenExpireInMills); } else { diff --git a/paimon-core/src/main/java/org/apache/paimon/rest/auth/CredentialsProviderFactory.java b/paimon-core/src/main/java/org/apache/paimon/rest/auth/CredentialsProviderFactory.java index a20607c679ed..cf918805cbae 100644 --- a/paimon-core/src/main/java/org/apache/paimon/rest/auth/CredentialsProviderFactory.java +++ b/paimon-core/src/main/java/org/apache/paimon/rest/auth/CredentialsProviderFactory.java @@ -21,8 +21,9 @@ import org.apache.paimon.factories.Factory; import org.apache.paimon.factories.FactoryUtil; import org.apache.paimon.options.Options; +import org.apache.paimon.rest.RESTCatalogOptions; -import static org.apache.paimon.rest.auth.AuthOptions.CREDENTIALS_PROVIDER; +import static org.apache.paimon.rest.RESTCatalogOptions.CREDENTIALS_PROVIDER; /** Factory for creating {@link CredentialsProvider}. */ public interface CredentialsProviderFactory extends Factory { @@ -44,6 +45,6 @@ static CredentialsProvider createCredentialsProvider(Options options, ClassLoade return credentialsProviderFactory.create(options); } catch (UnsupportedOperationException ignore) { } - return new BearTokenCredentialsProvider(options.get(AuthOptions.TOKEN)); + return new BearTokenCredentialsProvider(options.get(RESTCatalogOptions.TOKEN)); } } diff --git a/paimon-core/src/test/java/org/apache/paimon/rest/RESTCatalogTest.java b/paimon-core/src/test/java/org/apache/paimon/rest/RESTCatalogTest.java index 5c40f435fbff..40983d82d6dd 100644 --- a/paimon-core/src/test/java/org/apache/paimon/rest/RESTCatalogTest.java +++ b/paimon-core/src/test/java/org/apache/paimon/rest/RESTCatalogTest.java @@ -20,7 +20,6 @@ import org.apache.paimon.options.CatalogOptions; import org.apache.paimon.options.Options; -import org.apache.paimon.rest.auth.AuthOptions; import org.apache.paimon.rest.auth.CredentialsProviderType; import okhttp3.mockwebserver.MockResponse; @@ -49,10 +48,11 @@ public void setUp() throws IOException { String baseUrl = mockWebServer.url("").toString(); Options options = new Options(); options.set(RESTCatalogOptions.URI, baseUrl); - options.set(AuthOptions.TOKEN, initToken); + options.set(RESTCatalogOptions.TOKEN, initToken); options.set(RESTCatalogOptions.THREAD_POOL_SIZE, 1); mockOptions(RESTCatalogInternalOptions.PREFIX.key(), "prefix"); - options.set(AuthOptions.CREDENTIALS_PROVIDER, CredentialsProviderType.BEAR_TOKEN.name()); + options.set( + RESTCatalogOptions.CREDENTIALS_PROVIDER, CredentialsProviderType.BEAR_TOKEN.name()); restCatalog = new RESTCatalog(options); } @@ -65,7 +65,8 @@ public void tearDown() throws IOException { public void testInitFailWhenDefineWarehouse() { Options options = new Options(); options.set(CatalogOptions.WAREHOUSE, "/a/b/c"); - options.set(AuthOptions.CREDENTIALS_PROVIDER, CredentialsProviderType.BEAR_TOKEN.name()); + options.set( + RESTCatalogOptions.CREDENTIALS_PROVIDER, CredentialsProviderType.BEAR_TOKEN.name()); assertThrows(IllegalArgumentException.class, () -> new RESTCatalog(options)); } diff --git a/paimon-core/src/test/java/org/apache/paimon/rest/auth/CredentialsProviderFactoryTest.java b/paimon-core/src/test/java/org/apache/paimon/rest/auth/CredentialsProviderFactoryTest.java index 1816c59212a7..c2ef4923175e 100644 --- a/paimon-core/src/test/java/org/apache/paimon/rest/auth/CredentialsProviderFactoryTest.java +++ b/paimon-core/src/test/java/org/apache/paimon/rest/auth/CredentialsProviderFactoryTest.java @@ -19,6 +19,7 @@ package org.apache.paimon.rest.auth; import org.apache.paimon.options.Options; +import org.apache.paimon.rest.RESTCatalogOptions; import org.apache.commons.io.FileUtils; import org.junit.Rule; @@ -41,8 +42,9 @@ public class CredentialsProviderFactoryTest { public void testCreateBearTokenCredentialsProviderSuccess() { Options options = new Options(); String token = UUID.randomUUID().toString(); - options.set(AuthOptions.TOKEN, token); - options.set(AuthOptions.CREDENTIALS_PROVIDER, CredentialsProviderType.BEAR_TOKEN.name()); + options.set(RESTCatalogOptions.TOKEN, token); + options.set( + RESTCatalogOptions.CREDENTIALS_PROVIDER, CredentialsProviderType.BEAR_TOKEN.name()); BearTokenCredentialsProvider credentialsProvider = (BearTokenCredentialsProvider) CredentialsProviderFactory.createCredentialsProvider( @@ -53,7 +55,8 @@ public void testCreateBearTokenCredentialsProviderSuccess() { @Test public void testCreateBearTokenCredentialsProviderFail() { Options options = new Options(); - options.set(AuthOptions.CREDENTIALS_PROVIDER, CredentialsProviderType.BEAR_TOKEN.name()); + options.set( + RESTCatalogOptions.CREDENTIALS_PROVIDER, CredentialsProviderType.BEAR_TOKEN.name()); assertThrows( IllegalArgumentException.class, () -> @@ -68,9 +71,10 @@ public void testCreateBearTokenFileCredentialsProviderSuccess() throws Exception File tokenFile = folder.newFile(fileName); String token = UUID.randomUUID().toString(); FileUtils.writeStringToFile(tokenFile, token); - options.set(AuthOptions.TOKEN_FILE_PATH, tokenFile.getPath()); + options.set(RESTCatalogOptions.TOKEN_PROVIDER_PATH, tokenFile.getPath()); options.set( - AuthOptions.CREDENTIALS_PROVIDER, CredentialsProviderType.BEAR_TOKEN_FILE.name()); + RESTCatalogOptions.CREDENTIALS_PROVIDER, + CredentialsProviderType.BEAR_TOKEN_FILE.name()); BearTokenFileCredentialsProvider credentialsProvider = (BearTokenFileCredentialsProvider) CredentialsProviderFactory.createCredentialsProvider( @@ -82,7 +86,8 @@ public void testCreateBearTokenFileCredentialsProviderSuccess() throws Exception public void testCreateBearTokenFileCredentialsProviderFail() throws Exception { Options options = new Options(); options.set( - AuthOptions.CREDENTIALS_PROVIDER, CredentialsProviderType.BEAR_TOKEN_FILE.name()); + RESTCatalogOptions.CREDENTIALS_PROVIDER, + CredentialsProviderType.BEAR_TOKEN_FILE.name()); assertThrows( IllegalArgumentException.class, () -> @@ -98,10 +103,11 @@ public void testCreateRefreshBearTokenFileCredentialsProviderSuccess() throws Ex String token = UUID.randomUUID().toString(); FileUtils.writeStringToFile(tokenFile, token); options.set( - AuthOptions.CREDENTIALS_PROVIDER, CredentialsProviderType.BEAR_TOKEN_FILE.name()); - options.set(AuthOptions.TOKEN_FILE_PATH, tokenFile.getPath()); - options.set(AuthOptions.TOKEN_REFRESH_ENABLED, true); - options.set(AuthOptions.TOKEN_EXPIRES_IN, Duration.ofSeconds(10L)); + RESTCatalogOptions.CREDENTIALS_PROVIDER, + CredentialsProviderType.BEAR_TOKEN_FILE.name()); + options.set(RESTCatalogOptions.TOKEN_PROVIDER_PATH, tokenFile.getPath()); + options.set(RESTCatalogOptions.TOKEN_REFRESH_ENABLED, true); + options.set(RESTCatalogOptions.TOKEN_EXPIRATION_TIME, Duration.ofSeconds(10L)); BearTokenFileCredentialsProvider credentialsProvider = (BearTokenFileCredentialsProvider) CredentialsProviderFactory.createCredentialsProvider( @@ -117,11 +123,13 @@ public void testCreateRefreshBearTokenFileCredentialsProviderFail() throws Excep String token = UUID.randomUUID().toString(); FileUtils.writeStringToFile(tokenFile, token); options.set( - AuthOptions.CREDENTIALS_PROVIDER, CredentialsProviderType.BEAR_TOKEN_FILE.name()); - options.set(AuthOptions.TOKEN_FILE_PATH, tokenFile.getPath()); - options.set(AuthOptions.TOKEN_REFRESH_ENABLED, true); + RESTCatalogOptions.CREDENTIALS_PROVIDER, + CredentialsProviderType.BEAR_TOKEN_FILE.name()); + options.set(RESTCatalogOptions.TOKEN_PROVIDER_PATH, tokenFile.getPath()); + options.set(RESTCatalogOptions.TOKEN_REFRESH_ENABLED, true); options.set( - AuthOptions.CREDENTIALS_PROVIDER, CredentialsProviderType.BEAR_TOKEN_FILE.name()); + RESTCatalogOptions.CREDENTIALS_PROVIDER, + CredentialsProviderType.BEAR_TOKEN_FILE.name()); assertThrows( IllegalArgumentException.class, () ->