diff --git a/trino-aws-proxy-spi/src/main/java/io/trino/aws/proxy/spi/credentials/Identity.java b/trino-aws-proxy-spi/src/main/java/io/trino/aws/proxy/spi/credentials/Identity.java index 57969fbd..9524eedb 100644 --- a/trino-aws-proxy-spi/src/main/java/io/trino/aws/proxy/spi/credentials/Identity.java +++ b/trino-aws-proxy-spi/src/main/java/io/trino/aws/proxy/spi/credentials/Identity.java @@ -13,7 +13,11 @@ */ package io.trino.aws.proxy.spi.credentials; +import java.util.List; + public interface Identity { String user(); + + List groups(); } diff --git a/trino-aws-proxy-spi/src/main/java/io/trino/aws/proxy/spi/credentials/StandardIdentity.java b/trino-aws-proxy-spi/src/main/java/io/trino/aws/proxy/spi/credentials/StandardIdentity.java new file mode 100644 index 00000000..f82c9217 --- /dev/null +++ b/trino-aws-proxy-spi/src/main/java/io/trino/aws/proxy/spi/credentials/StandardIdentity.java @@ -0,0 +1,28 @@ +/* + * Licensed 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 io.trino.aws.proxy.spi.credentials; + +import java.util.List; + +import static java.util.Objects.requireNonNull; + +public record StandardIdentity(String user, List groups) + implements Identity +{ + public StandardIdentity + { + requireNonNull(user, "user is null"); + requireNonNull(groups, "groups is null"); + } +} diff --git a/trino-aws-proxy-spi/src/main/java/io/trino/aws/proxy/spi/plugin/TrinoAwsProxyServerBinding.java b/trino-aws-proxy-spi/src/main/java/io/trino/aws/proxy/spi/plugin/TrinoAwsProxyServerBinding.java index c2129c5e..f8f8bf1b 100644 --- a/trino-aws-proxy-spi/src/main/java/io/trino/aws/proxy/spi/plugin/TrinoAwsProxyServerBinding.java +++ b/trino-aws-proxy-spi/src/main/java/io/trino/aws/proxy/spi/plugin/TrinoAwsProxyServerBinding.java @@ -13,11 +13,14 @@ */ package io.trino.aws.proxy.spi.plugin; +import com.google.inject.Binder; import com.google.inject.Module; import com.google.inject.Scopes; +import com.google.inject.TypeLiteral; import io.airlift.log.Logger; import io.trino.aws.proxy.spi.credentials.AssumedRoleProvider; import io.trino.aws.proxy.spi.credentials.CredentialsProvider; +import io.trino.aws.proxy.spi.credentials.Identity; import io.trino.aws.proxy.spi.plugin.config.AssumedRoleProviderConfig; import io.trino.aws.proxy.spi.plugin.config.CredentialsProviderConfig; import io.trino.aws.proxy.spi.plugin.config.PluginIdentifierConfig; @@ -47,6 +50,14 @@ static Module s3SecurityFacadeProviderModule(String identifier, Class void bindIdentityType(Binder binder, Class type) + { + newOptionalBinder(binder, new TypeLiteral>() {}).setBinding().toProvider(() -> { + log.info("Using %s identity type", type.getSimpleName()); + return type; + }); + } + static Module optionalPluginModule( Class configClass, String identifier, diff --git a/trino-aws-proxy/pom.xml b/trino-aws-proxy/pom.xml index 15ead640..a9f9046b 100644 --- a/trino-aws-proxy/pom.xml +++ b/trino-aws-proxy/pom.xml @@ -24,6 +24,11 @@ trino-aws-proxy-spi + + com.fasterxml.jackson.core + jackson-annotations + + com.fasterxml.jackson.core jackson-core diff --git a/trino-aws-proxy/src/main/java/io/trino/aws/proxy/server/TrinoAwsProxyServerModule.java b/trino-aws-proxy/src/main/java/io/trino/aws/proxy/server/TrinoAwsProxyServerModule.java index 4e0ccfaf..ca6807c8 100644 --- a/trino-aws-proxy/src/main/java/io/trino/aws/proxy/server/TrinoAwsProxyServerModule.java +++ b/trino-aws-proxy/src/main/java/io/trino/aws/proxy/server/TrinoAwsProxyServerModule.java @@ -13,7 +13,11 @@ */ package io.trino.aws.proxy.server; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.databind.Module; import com.fasterxml.jackson.databind.PropertyNamingStrategies; +import com.fasterxml.jackson.databind.module.SimpleModule; import com.fasterxml.jackson.dataformat.xml.XmlMapper; import com.google.common.annotations.VisibleForTesting; import com.google.inject.Binder; @@ -40,6 +44,8 @@ import io.trino.aws.proxy.server.signing.SigningModule; import io.trino.aws.proxy.spi.credentials.AssumedRoleProvider; import io.trino.aws.proxy.spi.credentials.CredentialsProvider; +import io.trino.aws.proxy.spi.credentials.Identity; +import io.trino.aws.proxy.spi.credentials.StandardIdentity; import io.trino.aws.proxy.spi.plugin.TrinoAwsProxyServerPlugin; import io.trino.aws.proxy.spi.plugin.config.AssumedRoleProviderConfig; import io.trino.aws.proxy.spi.plugin.config.CredentialsProviderConfig; @@ -48,9 +54,13 @@ import io.trino.aws.proxy.spi.signing.SigningServiceType; import org.glassfish.jersey.server.model.Resource; +import java.util.List; +import java.util.Map; import java.util.ServiceLoader; +import java.util.Set; import static com.google.inject.multibindings.MapBinder.newMapBinder; +import static com.google.inject.multibindings.Multibinder.newSetBinder; import static com.google.inject.multibindings.OptionalBinder.newOptionalBinder; import static io.airlift.configuration.ConfigBinder.configBinder; import static io.airlift.http.client.HttpClientBinder.httpClientBinder; @@ -100,6 +110,10 @@ protected void setup(Binder binder) log.info("Using default %s NOOP implementation", CredentialsProvider.class.getSimpleName()); return CredentialsProvider.NOOP; }); + newOptionalBinder(binder, new TypeLiteral>() {}).setDefault().toProvider(() -> { + log.info("Using %s identity type", StandardIdentity.class.getSimpleName()); + return StandardIdentity.class; + }); // CredentialsProvider provided implementations install(new FileBasedCredentialsModule()); @@ -117,6 +131,8 @@ protected void setup(Binder binder) installPlugins(); install(new TrinoAwsProxyPluginValidatorModule()); + + addNullCollectionModule(binder); } @Provides @@ -147,6 +163,21 @@ protected void installSigningController(Binder binder) install(new SigningModule()); } + private void addNullCollectionModule(Binder binder) + { + Module module = new SimpleModule() + { + @Override + public void setupModule(SetupContext context) + { + context.configOverride(List.class).setSetterInfo(JsonSetter.Value.forValueNulls(Nulls.AS_EMPTY)); + context.configOverride(Set.class).setSetterInfo(JsonSetter.Value.forValueNulls(Nulls.AS_EMPTY)); + context.configOverride(Map.class).setSetterInfo(JsonSetter.Value.forValueNulls(Nulls.AS_EMPTY)); + } + }; + newSetBinder(binder, Module.class).addBinding().toInstance(module); + } + private void installPlugins() { ServiceLoader.load(TrinoAwsProxyServerPlugin.class) diff --git a/trino-aws-proxy/src/test/java/io/trino/aws/proxy/server/credentials/file/TestFileBasedCredentialsProvider.java b/trino-aws-proxy/src/test/java/io/trino/aws/proxy/server/credentials/file/TestFileBasedCredentialsProvider.java index 7ac95e68..a3ce8845 100644 --- a/trino-aws-proxy/src/test/java/io/trino/aws/proxy/server/credentials/file/TestFileBasedCredentialsProvider.java +++ b/trino-aws-proxy/src/test/java/io/trino/aws/proxy/server/credentials/file/TestFileBasedCredentialsProvider.java @@ -15,6 +15,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.module.SimpleModule; +import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import com.google.common.io.Resources; import io.airlift.json.ObjectMapperProvider; @@ -49,7 +50,7 @@ public void testValidCredentials() { Credential emulated = new Credential("test-emulated-access-key", "test-emulated-secret"); Credential remote = new Credential("test-remote-access-key", "test-remote-secret"); - Credentials expected = new Credentials(emulated, Optional.of(remote), Optional.empty(), Optional.of(new TestingIdentity("test-username"))); + Credentials expected = new Credentials(emulated, Optional.of(remote), Optional.empty(), Optional.of(new TestingIdentity("test-username", ImmutableList.of()))); Optional actual = credentialsProvider.credentials("test-emulated-access-key", Optional.empty()); assertThat(actual).contains(expected); } diff --git a/trino-aws-proxy/src/test/java/io/trino/aws/proxy/server/testing/TestingIdentity.java b/trino-aws-proxy/src/test/java/io/trino/aws/proxy/server/testing/TestingIdentity.java index 6e900ec5..1ae2e422 100644 --- a/trino-aws-proxy/src/test/java/io/trino/aws/proxy/server/testing/TestingIdentity.java +++ b/trino-aws-proxy/src/test/java/io/trino/aws/proxy/server/testing/TestingIdentity.java @@ -15,14 +15,17 @@ import io.trino.aws.proxy.spi.credentials.Identity; +import java.util.List; + import static java.util.Objects.requireNonNull; -public record TestingIdentity(String user) +public record TestingIdentity(String user, List groups) implements Identity { public TestingIdentity { requireNonNull(user, "username is null"); + requireNonNull(groups, "groups is null"); } @Override