This is an automated email from the ASF dual-hosted git repository.
adutra pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/polaris.git
The following commit(s) were added to refs/heads/main by this push:
new bcc97eca Make JWT brokers injectable (#570)
bcc97eca is described below
commit bcc97ecaa0e3e0ddf0c5f4229fd1f878e3996b14
Author: Dmitri Bourlatchkov <[email protected]>
AuthorDate: Tue Jan 7 08:06:15 2025 -0500
Make JWT brokers injectable (#570)
---
.../config/PolarisApplicationConfig.java | 57 ++++------------
.../dropwizard/config/TokenBrokerConfig.java | 75 ++++++++++++++++++++++
.../main/resources/META-INF/hk2-locator/default | 5 ++
.../polaris/service/auth/JWTRSAKeyPairFactory.java | 13 ++--
.../service/auth/JWTSymmetricKeyFactory.java | 51 +++++++--------
...airFactory.java => NoneTokenBrokerFactory.java} | 45 +++++++++----
...rFactory.java => TokenBrokerFactoryConfig.java} | 30 ++++-----
7 files changed, 165 insertions(+), 111 deletions(-)
diff --git
a/dropwizard/service/src/main/java/org/apache/polaris/service/dropwizard/config/PolarisApplicationConfig.java
b/dropwizard/service/src/main/java/org/apache/polaris/service/dropwizard/config/PolarisApplicationConfig.java
index d2afa150..2c351d0f 100644
---
a/dropwizard/service/src/main/java/org/apache/polaris/service/dropwizard/config/PolarisApplicationConfig.java
+++
b/dropwizard/service/src/main/java/org/apache/polaris/service/dropwizard/config/PolarisApplicationConfig.java
@@ -32,7 +32,6 @@ import java.io.IOException;
import java.util.Date;
import java.util.List;
import java.util.Map;
-import java.util.Objects;
import java.util.Optional;
import java.util.function.Supplier;
import org.apache.commons.lang3.StringUtils;
@@ -41,10 +40,8 @@ import
org.apache.polaris.core.auth.AuthenticatedPolarisPrincipal;
import org.apache.polaris.core.persistence.MetaStoreManagerFactory;
import org.apache.polaris.core.storage.PolarisStorageIntegrationProvider;
import org.apache.polaris.service.auth.Authenticator;
-import org.apache.polaris.service.auth.DecodedToken;
-import org.apache.polaris.service.auth.TokenBroker;
import org.apache.polaris.service.auth.TokenBrokerFactory;
-import org.apache.polaris.service.auth.TokenResponse;
+import org.apache.polaris.service.auth.TokenBrokerFactoryConfig;
import org.apache.polaris.service.catalog.api.IcebergRestOAuth2ApiService;
import org.apache.polaris.service.catalog.io.FileIOFactory;
import org.apache.polaris.service.config.DefaultConfigurationStore;
@@ -54,7 +51,6 @@ import
org.apache.polaris.service.context.RealmContextResolver;
import org.apache.polaris.service.ratelimiter.RateLimiter;
import org.apache.polaris.service.ratelimiter.TokenBucketFactory;
import
org.apache.polaris.service.storage.PolarisStorageIntegrationProviderImpl;
-import org.apache.polaris.service.types.TokenType;
import org.glassfish.hk2.api.Factory;
import org.glassfish.hk2.api.ServiceLocator;
import org.glassfish.hk2.api.TypeLiteral;
@@ -92,7 +88,7 @@ public class PolarisApplicationConfig extends Configuration {
private FileIOFactory fileIOFactory;
private RateLimiter rateLimiter;
private TokenBucketFactory tokenBucketFactory;
- private TokenBrokerFactory tokenBrokerFactory;
+ private TokenBrokerConfig tokenBroker = new TokenBrokerConfig();
private AccessToken gcpAccessToken;
@@ -131,7 +127,13 @@ public class PolarisApplicationConfig extends
Configuration {
bindFactory(SupplierFactory.create(serviceLocator,
config::getPolarisAuthenticator))
.to(Authenticator.class)
.ranked(OVERRIDE_BINDING_RANK);
- bindFactory(SupplierFactory.create(serviceLocator,
config::getTokenBrokerFactory))
+ bindFactory(SupplierFactory.create(serviceLocator, () -> tokenBroker))
+ .to(TokenBrokerFactoryConfig.class);
+ bindFactory(
+ SupplierFactory.create(
+ serviceLocator,
+ () ->
+ serviceLocator.getService(TokenBrokerFactory.class,
tokenBroker.getType())))
.to(TokenBrokerFactory.class)
.ranked(OVERRIDE_BINDING_RANK);
bindFactory(SupplierFactory.create(serviceLocator,
config::getOauth2Service))
@@ -228,45 +230,8 @@ public class PolarisApplicationConfig extends
Configuration {
}
@JsonProperty("tokenBroker")
- @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include =
JsonTypeInfo.As.PROPERTY, property = "type")
- public void setTokenBrokerFactory(TokenBrokerFactory tokenBrokerFactory) {
- this.tokenBrokerFactory = tokenBrokerFactory;
- }
-
- private TokenBrokerFactory getTokenBrokerFactory() {
- // return a no-op implementation if none is specified
- return Objects.requireNonNullElseGet(
- tokenBrokerFactory,
- () ->
- (rc) ->
- new TokenBroker() {
- @Override
- public boolean supportsGrantType(String grantType) {
- return false;
- }
-
- @Override
- public boolean supportsRequestedTokenType(TokenType
tokenType) {
- return false;
- }
-
- @Override
- public TokenResponse generateFromClientSecrets(
- String clientId, String clientSecret, String grantType,
String scope) {
- return null;
- }
-
- @Override
- public TokenResponse generateFromToken(
- TokenType tokenType, String subjectToken, String
grantType, String scope) {
- return null;
- }
-
- @Override
- public DecodedToken verify(String token) {
- return null;
- }
- });
+ public void setTokenBroker(TokenBrokerConfig tokenBroker) {
+ this.tokenBroker = tokenBroker;
}
private RealmContextResolver getRealmContextResolver() {
diff --git
a/dropwizard/service/src/main/java/org/apache/polaris/service/dropwizard/config/TokenBrokerConfig.java
b/dropwizard/service/src/main/java/org/apache/polaris/service/dropwizard/config/TokenBrokerConfig.java
new file mode 100644
index 00000000..3e349fcf
--- /dev/null
+++
b/dropwizard/service/src/main/java/org/apache/polaris/service/dropwizard/config/TokenBrokerConfig.java
@@ -0,0 +1,75 @@
+/*
+ * 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.polaris.service.dropwizard.config;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import jakarta.annotation.Nullable;
+import org.apache.polaris.service.auth.TokenBrokerFactoryConfig;
+
+/**
+ * This object receives the subsection of the server config YAML
(`polaris-server.yml`) that is
+ * related to JWT brokers.
+ */
+public class TokenBrokerConfig implements TokenBrokerFactoryConfig {
+ private String type = "none";
+ private int maxTokenGenerationInSeconds = 3600;
+ private String file;
+ private String secret;
+
+ @JsonProperty("type")
+ public void setType(String type) {
+ this.type = type;
+ }
+
+ @JsonProperty("file")
+ public void setFile(String file) {
+ this.file = file;
+ }
+
+ @JsonProperty("secret")
+ public void setSecret(String secret) {
+ this.secret = secret;
+ }
+
+ @JsonProperty("maxTokenGenerationInSeconds")
+ public void setMaxTokenGenerationInSeconds(int maxTokenGenerationInSeconds) {
+ this.maxTokenGenerationInSeconds = maxTokenGenerationInSeconds;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ @Override
+ public int maxTokenGenerationInSeconds() {
+ return maxTokenGenerationInSeconds;
+ }
+
+ @Nullable
+ @Override
+ public String file() {
+ return file;
+ }
+
+ @Nullable
+ @Override
+ public String secret() {
+ return secret;
+ }
+}
diff --git a/dropwizard/service/src/main/resources/META-INF/hk2-locator/default
b/dropwizard/service/src/main/resources/META-INF/hk2-locator/default
index 1771a6ad..b5eacf9c 100644
--- a/dropwizard/service/src/main/resources/META-INF/hk2-locator/default
+++ b/dropwizard/service/src/main/resources/META-INF/hk2-locator/default
@@ -51,6 +51,11 @@ contract={org.apache.polaris.service.auth.TokenBrokerFactory}
name=rsa-key-pair
qualifier={io.smallrye.common.annotation.Identifier}
+[org.apache.polaris.service.auth.NoneTokenBrokerFactory]S
+contract={org.apache.polaris.service.auth.TokenBrokerFactory}
+name=none
+qualifier={io.smallrye.common.annotation.Identifier}
+
[org.apache.polaris.service.context.DefaultRealmContextResolver]S
contract={org.apache.polaris.service.context.RealmContextResolver}
name=default
diff --git
a/service/common/src/main/java/org/apache/polaris/service/auth/JWTRSAKeyPairFactory.java
b/service/common/src/main/java/org/apache/polaris/service/auth/JWTRSAKeyPairFactory.java
index 4b11a466..cb49ea2b 100644
---
a/service/common/src/main/java/org/apache/polaris/service/auth/JWTRSAKeyPairFactory.java
+++
b/service/common/src/main/java/org/apache/polaris/service/auth/JWTRSAKeyPairFactory.java
@@ -25,18 +25,21 @@ import
org.apache.polaris.core.persistence.MetaStoreManagerFactory;
@Identifier("rsa-key-pair")
public class JWTRSAKeyPairFactory implements TokenBrokerFactory {
- private int maxTokenGenerationInSeconds = 3600;
- @Inject private MetaStoreManagerFactory metaStoreManagerFactory;
+ private final TokenBrokerFactoryConfig config;
+ private final MetaStoreManagerFactory metaStoreManagerFactory;
- public void setMaxTokenGenerationInSeconds(int maxTokenGenerationInSeconds) {
- this.maxTokenGenerationInSeconds = maxTokenGenerationInSeconds;
+ @Inject
+ public JWTRSAKeyPairFactory(
+ TokenBrokerFactoryConfig config, MetaStoreManagerFactory
metaStoreManagerFactory) {
+ this.config = config;
+ this.metaStoreManagerFactory = metaStoreManagerFactory;
}
@Override
public TokenBroker apply(RealmContext realmContext) {
return new JWTRSAKeyPair(
metaStoreManagerFactory.getOrCreateMetaStoreManager(realmContext),
- maxTokenGenerationInSeconds);
+ config.maxTokenGenerationInSeconds());
}
}
diff --git
a/service/common/src/main/java/org/apache/polaris/service/auth/JWTSymmetricKeyFactory.java
b/service/common/src/main/java/org/apache/polaris/service/auth/JWTSymmetricKeyFactory.java
index bb04b048..061a8a18 100644
---
a/service/common/src/main/java/org/apache/polaris/service/auth/JWTSymmetricKeyFactory.java
+++
b/service/common/src/main/java/org/apache/polaris/service/auth/JWTSymmetricKeyFactory.java
@@ -18,10 +18,13 @@
*/
package org.apache.polaris.service.auth;
+import static com.google.common.base.Preconditions.checkState;
+
import io.smallrye.common.annotation.Identifier;
import jakarta.inject.Inject;
import java.io.IOException;
import java.nio.file.Files;
+import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.function.Supplier;
import org.apache.polaris.core.context.RealmContext;
@@ -29,46 +32,38 @@ import
org.apache.polaris.core.persistence.MetaStoreManagerFactory;
@Identifier("symmetric-key")
public class JWTSymmetricKeyFactory implements TokenBrokerFactory {
- @Inject private MetaStoreManagerFactory metaStoreManagerFactory;
- private int maxTokenGenerationInSeconds = 3600;
- private String file;
- private String secret;
+
+ private final MetaStoreManagerFactory metaStoreManagerFactory;
+ private final TokenBrokerFactoryConfig config;
+ private final Supplier<String> secretSupplier;
+
+ @Inject
+ public JWTSymmetricKeyFactory(
+ MetaStoreManagerFactory metaStoreManagerFactory,
TokenBrokerFactoryConfig config) {
+ this.metaStoreManagerFactory = metaStoreManagerFactory;
+ this.config = config;
+
+ String secret = config.secret();
+ String file = config.file();
+ checkState(secret != null || file != null, "Either file or secret must be
set");
+ this.secretSupplier = secret != null ? () -> secret :
readSecretFromDisk(Paths.get(file));
+ }
@Override
public TokenBroker apply(RealmContext realmContext) {
- if (file == null && secret == null) {
- throw new IllegalStateException("Either file or secret must be set");
- }
- Supplier<String> secretSupplier = secret != null ? () -> secret :
readSecretFromDisk();
return new JWTSymmetricKeyBroker(
metaStoreManagerFactory.getOrCreateMetaStoreManager(realmContext),
- maxTokenGenerationInSeconds,
+ config.maxTokenGenerationInSeconds(),
secretSupplier);
}
- private Supplier<String> readSecretFromDisk() {
+ private Supplier<String> readSecretFromDisk(Path path) {
return () -> {
try {
- return Files.readString(Paths.get(file));
+ return Files.readString(path);
} catch (IOException e) {
- throw new RuntimeException("Failed to read secret from file: " + file,
e);
+ throw new RuntimeException("Failed to read secret from file: " +
config.file(), e);
}
};
}
-
- public void setMaxTokenGenerationInSeconds(int maxTokenGenerationInSeconds) {
- this.maxTokenGenerationInSeconds = maxTokenGenerationInSeconds;
- }
-
- public void setFile(String file) {
- this.file = file;
- }
-
- public void setSecret(String secret) {
- this.secret = secret;
- }
-
- public void setMetaStoreManagerFactory(MetaStoreManagerFactory
metaStoreManagerFactory) {
- this.metaStoreManagerFactory = metaStoreManagerFactory;
- }
}
diff --git
a/service/common/src/main/java/org/apache/polaris/service/auth/JWTRSAKeyPairFactory.java
b/service/common/src/main/java/org/apache/polaris/service/auth/NoneTokenBrokerFactory.java
similarity index 52%
copy from
service/common/src/main/java/org/apache/polaris/service/auth/JWTRSAKeyPairFactory.java
copy to
service/common/src/main/java/org/apache/polaris/service/auth/NoneTokenBrokerFactory.java
index 4b11a466..c39124fe 100644
---
a/service/common/src/main/java/org/apache/polaris/service/auth/JWTRSAKeyPairFactory.java
+++
b/service/common/src/main/java/org/apache/polaris/service/auth/NoneTokenBrokerFactory.java
@@ -19,24 +19,41 @@
package org.apache.polaris.service.auth;
import io.smallrye.common.annotation.Identifier;
-import jakarta.inject.Inject;
import org.apache.polaris.core.context.RealmContext;
-import org.apache.polaris.core.persistence.MetaStoreManagerFactory;
+import org.apache.polaris.service.types.TokenType;
-@Identifier("rsa-key-pair")
-public class JWTRSAKeyPairFactory implements TokenBrokerFactory {
- private int maxTokenGenerationInSeconds = 3600;
+/** Default {@link TokenBrokerFactory} that produces token brokers that do not
do anything. */
+@Identifier("none")
+public class NoneTokenBrokerFactory implements TokenBrokerFactory {
+ @Override
+ public TokenBroker apply(RealmContext realmContext) {
+ return new TokenBroker() {
+ @Override
+ public boolean supportsGrantType(String grantType) {
+ return false;
+ }
- @Inject private MetaStoreManagerFactory metaStoreManagerFactory;
+ @Override
+ public boolean supportsRequestedTokenType(TokenType tokenType) {
+ return false;
+ }
- public void setMaxTokenGenerationInSeconds(int maxTokenGenerationInSeconds) {
- this.maxTokenGenerationInSeconds = maxTokenGenerationInSeconds;
- }
+ @Override
+ public TokenResponse generateFromClientSecrets(
+ String clientId, String clientSecret, String grantType, String
scope) {
+ return null;
+ }
- @Override
- public TokenBroker apply(RealmContext realmContext) {
- return new JWTRSAKeyPair(
- metaStoreManagerFactory.getOrCreateMetaStoreManager(realmContext),
- maxTokenGenerationInSeconds);
+ @Override
+ public TokenResponse generateFromToken(
+ TokenType tokenType, String subjectToken, String grantType, String
scope) {
+ return null;
+ }
+
+ @Override
+ public DecodedToken verify(String token) {
+ return null;
+ }
+ };
}
}
diff --git
a/service/common/src/main/java/org/apache/polaris/service/auth/JWTRSAKeyPairFactory.java
b/service/common/src/main/java/org/apache/polaris/service/auth/TokenBrokerFactoryConfig.java
similarity index 52%
copy from
service/common/src/main/java/org/apache/polaris/service/auth/JWTRSAKeyPairFactory.java
copy to
service/common/src/main/java/org/apache/polaris/service/auth/TokenBrokerFactoryConfig.java
index 4b11a466..20811e14 100644
---
a/service/common/src/main/java/org/apache/polaris/service/auth/JWTRSAKeyPairFactory.java
+++
b/service/common/src/main/java/org/apache/polaris/service/auth/TokenBrokerFactoryConfig.java
@@ -18,25 +18,19 @@
*/
package org.apache.polaris.service.auth;
-import io.smallrye.common.annotation.Identifier;
-import jakarta.inject.Inject;
-import org.apache.polaris.core.context.RealmContext;
-import org.apache.polaris.core.persistence.MetaStoreManagerFactory;
+import jakarta.annotation.Nullable;
-@Identifier("rsa-key-pair")
-public class JWTRSAKeyPairFactory implements TokenBrokerFactory {
- private int maxTokenGenerationInSeconds = 3600;
-
- @Inject private MetaStoreManagerFactory metaStoreManagerFactory;
+/**
+ * This is a union of configuration settings of all token brokers.
+ *
+ * @see TokenBrokerFactory
+ */
+public interface TokenBrokerFactoryConfig {
+ @Nullable
+ String file();
- public void setMaxTokenGenerationInSeconds(int maxTokenGenerationInSeconds) {
- this.maxTokenGenerationInSeconds = maxTokenGenerationInSeconds;
- }
+ @Nullable
+ String secret();
- @Override
- public TokenBroker apply(RealmContext realmContext) {
- return new JWTRSAKeyPair(
- metaStoreManagerFactory.getOrCreateMetaStoreManager(realmContext),
- maxTokenGenerationInSeconds);
- }
+ int maxTokenGenerationInSeconds();
}