diff --git a/presto-cassandra/src/test/java/com/facebook/presto/cassandra/TestCassandraConnector.java b/presto-cassandra/src/test/java/com/facebook/presto/cassandra/TestCassandraConnector.java index dfbbc863851d9..64b92c3a21282 100644 --- a/presto-cassandra/src/test/java/com/facebook/presto/cassandra/TestCassandraConnector.java +++ b/presto-cassandra/src/test/java/com/facebook/presto/cassandra/TestCassandraConnector.java @@ -36,6 +36,7 @@ import com.facebook.presto.spi.connector.ConnectorSplitManager; import com.facebook.presto.spi.connector.ConnectorSplitManager.SplitSchedulingContext; import com.facebook.presto.spi.connector.ConnectorTransactionHandle; +import com.facebook.presto.spi.security.ConnectorIdentity; import com.facebook.presto.testing.TestingConnectorContext; import com.facebook.presto.testing.TestingConnectorSession; import com.google.common.collect.ImmutableList; @@ -80,6 +81,7 @@ public class TestCassandraConnector private static final Date DATE = new Date(); private static final ConnectorSession SESSION = new TestingConnectorSession( "user", + new ConnectorIdentity("user", Optional.empty(), Optional.empty()), Optional.of("test"), Optional.empty(), UTC_KEY, diff --git a/presto-docs/src/main/sphinx/connector/hive.rst b/presto-docs/src/main/sphinx/connector/hive.rst index bfb4dd9618961..869da01652b5f 100644 --- a/presto-docs/src/main/sphinx/connector/hive.rst +++ b/presto-docs/src/main/sphinx/connector/hive.rst @@ -383,6 +383,90 @@ or credentials for a specific use case (e.g., bucket/user specific credentials). This Hadoop configuration property must be set in the Hadoop configuration files referenced by the ``hive.config.resources`` Hive connector property. +AWS Security Mapping +^^^^^^^^^^^^^^^^^^^^ + +Presto supports flexible mapping for AWS Lake Formation and AWS S3 API calls, allowing for separate +credentials or IAM roles for specific users. + +The mappings can be of two types: ``S3`` or ``LAKEFORMATION``. + +The mapping entries are processed in the order listed in the configuration +file. More specific mappings should be specified before less specific mappings. +You can set default configuration by not including any match criteria for the last +entry in the list. + +Each mapping entry when mapping type is ``S3`` may specify one match criteria. Available match criteria: + +* ``user``: Regular expression to match against username. Example: ``alice|bob`` + +The mapping must provide one or more configuration settings: + +* ``accessKey`` and ``secretKey``: AWS access key and secret key. This overrides + any globally configured credentials, such as access key or instance credentials. + +* ``iamRole``: IAM role to use. This overrides any globally configured IAM role. + +Example JSON configuration file for s3: + +.. code-block:: json + + { + "mappings": [ + { + "user": "admin", + "accessKey": "AKIAxxxaccess", + "secretKey": "iXbXxxxsecret" + }, + { + "user": "analyst|scientist", + "iamRole": "arn:aws:iam::123456789101:role/analyst_and_scientist_role" + }, + { + "iamRole": "arn:aws:iam::123456789101:role/default" + } + ] + } + +Each mapping entry when mapping type is ``LAKEFORMATION`` may specify one match criteria. Available match criteria: + +* ``user``: Regular expression to match against username. Example: ``alice|bob`` + +The mapping must provide one configuration setting: + +* ``iamRole``: IAM role to use. This overrides any globally configured IAM role. + +Example JSON configuration file for lakeformation: + +.. code-block:: json + + { + "mappings": [ + { + "user": "admin", + "iamRole": "arn:aws:iam::123456789101:role/admin_role" + }, + { + "user": "analyst", + "iamRole": "arn:aws:iam::123456789101:role/analyst_role" + }, + { + "iamRole": "arn:aws:iam::123456789101:role/default_role" + } + ] + } + +======================================================= ================================================================= +Property Name Description +======================================================= ================================================================= +``hive.aws.security-mapping.type`` AWS Security Mapping Type. Possible values: S3 or LAKEFORMATION + +``hive.aws.security-mapping.config-file`` JSON configuration file containing AWS IAM Security mappings + +``hive.aws.security-mapping.refresh-period`` Time interval after which AWS IAM security mapping configuration + will be refreshed +======================================================= ================================================================= + Tuning Properties ^^^^^^^^^^^^^^^^^ diff --git a/presto-hive-common/pom.xml b/presto-hive-common/pom.xml index 4e28ffce9e903..27b647d9a5cce 100644 --- a/presto-hive-common/pom.xml +++ b/presto-hive-common/pom.xml @@ -29,6 +29,11 @@ configuration + + com.facebook.airlift + log + + com.google.code.findbugs jsr305 @@ -50,6 +55,11 @@ presto-orc + + com.facebook.presto + presto-plugin-toolkit + + com.facebook.presto.hadoop hadoop-apache2 diff --git a/presto-hive-common/src/main/java/com/facebook/presto/hive/aws/security/AWSSecurityMapping.java b/presto-hive-common/src/main/java/com/facebook/presto/hive/aws/security/AWSSecurityMapping.java new file mode 100644 index 0000000000000..98987fa8c2923 --- /dev/null +++ b/presto-hive-common/src/main/java/com/facebook/presto/hive/aws/security/AWSSecurityMapping.java @@ -0,0 +1,81 @@ +/* + * 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 com.facebook.presto.hive.aws.security; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.util.Optional; +import java.util.function.Predicate; +import java.util.regex.Pattern; + +import static com.google.common.base.MoreObjects.toStringHelper; +import static com.google.common.base.Preconditions.checkArgument; +import static java.util.Objects.requireNonNull; + +public class AWSSecurityMapping +{ + private final Predicate user; + private final Optional iamRole; + private final Optional credentials; + + @JsonCreator + public AWSSecurityMapping( + @JsonProperty("user") Optional user, + @JsonProperty("iamRole") Optional iamRole, + @JsonProperty("accessKey") Optional accessKey, + @JsonProperty("secretKey") Optional secretKey) + { + this.user = requireNonNull(user, "user is null") + .map(AWSSecurityMapping::toPredicate) + .orElse(x -> true); + + this.iamRole = requireNonNull(iamRole, "iamRole is null"); + + requireNonNull(accessKey, "accessKey is null"); + requireNonNull(secretKey, "secretKey is null"); + checkArgument(accessKey.isPresent() == secretKey.isPresent(), "accessKey and secretKey must be provided together"); + this.credentials = accessKey.map(access -> new BasicAWSCredentials(access, secretKey.get())); + } + + public boolean matches(String user) + { + return this.user.test(user); + } + + public Optional getIamRole() + { + return iamRole; + } + + public Optional getCredentials() + { + return credentials; + } + + @Override + public String toString() + { + return toStringHelper(this) + .add("user", user) + .add("iamRole", iamRole) + .add("credentials", credentials) + .toString(); + } + + private static Predicate toPredicate(Pattern pattern) + { + return value -> pattern.matcher(value).matches(); + } +} diff --git a/presto-hive-common/src/main/java/com/facebook/presto/hive/aws/security/AWSSecurityMappingConfig.java b/presto-hive-common/src/main/java/com/facebook/presto/hive/aws/security/AWSSecurityMappingConfig.java new file mode 100644 index 0000000000000..e66bc59b757b2 --- /dev/null +++ b/presto-hive-common/src/main/java/com/facebook/presto/hive/aws/security/AWSSecurityMappingConfig.java @@ -0,0 +1,85 @@ +/* + * 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 com.facebook.presto.hive.aws.security; + +import com.facebook.airlift.configuration.Config; +import com.facebook.airlift.configuration.ConfigDescription; +import io.airlift.units.Duration; +import io.airlift.units.MinDuration; + +import javax.annotation.Nullable; +import javax.validation.constraints.AssertTrue; + +import java.io.File; +import java.util.Optional; + +import static java.util.Objects.requireNonNull; +import static java.util.concurrent.TimeUnit.SECONDS; + +public class AWSSecurityMappingConfig +{ + private static final String MAPPING_TYPE = "hive.aws.security-mapping.type"; + private static final String CONFIG_FILE = "hive.aws.security-mapping.config-file"; + private static final String REFRESH_PERIOD = "hive.aws.security-mapping.refresh-period"; + private AWSSecurityMappingType mappingType; + private File configFile; + private Duration refreshPeriod = new Duration(30, SECONDS); + + public AWSSecurityMappingType getMappingType() + { + return mappingType; + } + + @Config(MAPPING_TYPE) + @ConfigDescription("AWS Security Mapping Type. Possible values: S3 or LAKEFORMATION") + public AWSSecurityMappingConfig setMappingType(AWSSecurityMappingType mappingType) + { + this.mappingType = mappingType; + return this; + } + + public Optional getConfigFile() + { + return Optional.ofNullable(configFile); + } + + @Nullable + @Config(CONFIG_FILE) + @ConfigDescription("JSON configuration file containing AWS IAM Security mappings") + public AWSSecurityMappingConfig setConfigFile(File configFile) + { + this.configFile = configFile; + return this; + } + + public Duration getRefreshPeriod() + { + return refreshPeriod; + } + + @MinDuration("0ms") + @Config(REFRESH_PERIOD) + @ConfigDescription("Time interval after which AWS IAM security mapping configuration will be refreshed") + public AWSSecurityMappingConfig setRefreshPeriod(Duration refreshPeriod) + { + this.refreshPeriod = requireNonNull(refreshPeriod, "refreshPeriod is null"); + return this; + } + + @AssertTrue(message = "MAPPING TYPE(" + MAPPING_TYPE + ") must be configured when AWS Security Mapping Config File(" + CONFIG_FILE + ") is set and vice versa") + public boolean isValidConfiguration() + { + return (getConfigFile().isPresent() && getMappingType() != null) || (!getConfigFile().isPresent() && getMappingType() == null); + } +} diff --git a/presto-hive-common/src/main/java/com/facebook/presto/hive/aws/security/AWSSecurityMappingType.java b/presto-hive-common/src/main/java/com/facebook/presto/hive/aws/security/AWSSecurityMappingType.java new file mode 100644 index 0000000000000..fdede13c3c375 --- /dev/null +++ b/presto-hive-common/src/main/java/com/facebook/presto/hive/aws/security/AWSSecurityMappingType.java @@ -0,0 +1,20 @@ +/* + * 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 com.facebook.presto.hive.aws.security; + +public enum AWSSecurityMappingType +{ + S3, + LAKEFORMATION, +} diff --git a/presto-hive-common/src/main/java/com/facebook/presto/hive/aws/security/AWSSecurityMappings.java b/presto-hive-common/src/main/java/com/facebook/presto/hive/aws/security/AWSSecurityMappings.java new file mode 100644 index 0000000000000..875d985a363fc --- /dev/null +++ b/presto-hive-common/src/main/java/com/facebook/presto/hive/aws/security/AWSSecurityMappings.java @@ -0,0 +1,66 @@ +/* + * 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 com.facebook.presto.hive.aws.security; + +import com.facebook.presto.spi.security.AccessDeniedException; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.google.common.collect.ImmutableList; + +import java.util.List; +import java.util.Optional; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Verify.verify; + +public class AWSSecurityMappings +{ + private final List awsSecurityMappings; + + @JsonCreator + public AWSSecurityMappings(@JsonProperty("mappings") List awsSecurityMappings) + { + checkArgument(awsSecurityMappings != null, "No AWS Security mappings configured"); + + this.awsSecurityMappings = ImmutableList.copyOf(awsSecurityMappings); + } + + public AWSSecurityMapping getAWSLakeFormationSecurityMapping(String user) + { + Optional awsSecurityMapping = awsSecurityMappings.stream() + .filter(mapping -> (mapping.matches(user))) + .findFirst(); + + if (!awsSecurityMapping.isPresent()) { + throw new AccessDeniedException("No matching AWS Lake Formation Security Mapping"); + } + + verify(!awsSecurityMapping.get().getCredentials().isPresent(), + "Basic AWS Credentials are not supported for AWS Lake Formation Security Mapping"); + + verify(awsSecurityMapping.get().getIamRole().isPresent(), + "iamRole is mandatory for AWS Lake Formation Security Mapping"); + + return awsSecurityMapping.get(); + } + + public AWSSecurityMapping getAWSS3SecurityMapping(String user) + { + Optional awsSecurityMapping = awsSecurityMappings.stream() + .filter(mapping -> mapping.matches(user)) + .findFirst(); + + return awsSecurityMapping.orElseThrow(() -> new AccessDeniedException("No matching AWS S3 Security Mapping")); + } +} diff --git a/presto-hive-common/src/main/java/com/facebook/presto/hive/aws/security/AWSSecurityMappingsSupplier.java b/presto-hive-common/src/main/java/com/facebook/presto/hive/aws/security/AWSSecurityMappingsSupplier.java new file mode 100644 index 0000000000000..73d6052d01586 --- /dev/null +++ b/presto-hive-common/src/main/java/com/facebook/presto/hive/aws/security/AWSSecurityMappingsSupplier.java @@ -0,0 +1,65 @@ +/* + * 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 com.facebook.presto.hive.aws.security; + +import com.facebook.airlift.log.Logger; +import com.google.common.base.Suppliers; +import io.airlift.units.Duration; + +import java.io.File; +import java.util.Optional; +import java.util.function.Supplier; + +import static com.facebook.presto.plugin.base.JsonUtils.parseJson; +import static com.google.common.base.Preconditions.checkArgument; +import static java.util.Objects.requireNonNull; +import static java.util.concurrent.TimeUnit.MILLISECONDS; + +public class AWSSecurityMappingsSupplier +{ + private static final Logger log = Logger.get(AWSSecurityMappingsSupplier.class); + private final Supplier mappingsSupplier; + + public AWSSecurityMappingsSupplier(Optional configFile, Duration refreshPeriod) + { + requireNonNull(configFile, "configFile is null"); + requireNonNull(refreshPeriod, "refreshPeriod is null"); + + this.mappingsSupplier = getMappings(configFile, refreshPeriod); + } + + private static Supplier getMappings(Optional configFile, Duration refreshPeriod) + { + if (!configFile.isPresent()) { + return null; + } + + checkArgument(configFile.get().exists() && configFile.get().isFile(), "AWS Security Mapping config file does not exist: %s", configFile.get()); + + Supplier supplier = () -> parseJson(configFile.get().toPath(), AWSSecurityMappings.class); + + return Suppliers.memoizeWithExpiration( + () -> { + log.debug("Refreshing AWS security mapping configuration from %s", configFile); + return supplier.get(); + }, + refreshPeriod.toMillis(), + MILLISECONDS); + } + + public Supplier getMappingsSupplier() + { + return mappingsSupplier; + } +} diff --git a/presto-hive-common/src/main/java/com/facebook/presto/hive/aws/security/BasicAWSCredentials.java b/presto-hive-common/src/main/java/com/facebook/presto/hive/aws/security/BasicAWSCredentials.java new file mode 100644 index 0000000000000..ecdca1b5c95e0 --- /dev/null +++ b/presto-hive-common/src/main/java/com/facebook/presto/hive/aws/security/BasicAWSCredentials.java @@ -0,0 +1,38 @@ +/* + * 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 com.facebook.presto.hive.aws.security; + +import static java.util.Objects.requireNonNull; + +public class BasicAWSCredentials +{ + private final String accessKey; + private final String secretKey; + + public BasicAWSCredentials(String accessKey, String secretKey) + { + this.accessKey = requireNonNull(accessKey, "Access key cannot be null"); + this.secretKey = requireNonNull(secretKey, "Secret key cannot be null"); + } + + public String getAWSAccessKeyId() + { + return this.accessKey; + } + + public String getAWSSecretKey() + { + return this.secretKey; + } +} diff --git a/presto-hive-common/src/test/java/com/facebook/presto/hive/aws/security/TestAWSSecurityMappingConfig.java b/presto-hive-common/src/test/java/com/facebook/presto/hive/aws/security/TestAWSSecurityMappingConfig.java new file mode 100644 index 0000000000000..c1d730d980ef4 --- /dev/null +++ b/presto-hive-common/src/test/java/com/facebook/presto/hive/aws/security/TestAWSSecurityMappingConfig.java @@ -0,0 +1,59 @@ +/* + * 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 com.facebook.presto.hive.aws.security; + +import com.google.common.collect.ImmutableMap; +import io.airlift.units.Duration; +import org.testng.annotations.Test; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Map; + +import static com.facebook.airlift.configuration.testing.ConfigAssertions.assertFullMapping; +import static com.facebook.airlift.configuration.testing.ConfigAssertions.assertRecordedDefaults; +import static com.facebook.airlift.configuration.testing.ConfigAssertions.recordDefaults; + +public class TestAWSSecurityMappingConfig +{ + @Test + public void testDefaults() + { + assertRecordedDefaults(recordDefaults(AWSSecurityMappingConfig.class) + .setMappingType(null) + .setConfigFile(null) + .setRefreshPeriod(Duration.valueOf("30s"))); + } + + @Test + public void testExplicitPropertyMappings() + throws IOException + { + Path securityMappingConfigFile = Files.createTempFile(null, null); + + Map properties = new ImmutableMap.Builder() + .put("hive.aws.security-mapping.type", "S3") + .put("hive.aws.security-mapping.config-file", securityMappingConfigFile.toString()) + .put("hive.aws.security-mapping.refresh-period", "60s") + .build(); + + AWSSecurityMappingConfig expected = new AWSSecurityMappingConfig() + .setMappingType(AWSSecurityMappingType.S3) + .setConfigFile(securityMappingConfigFile.toFile()) + .setRefreshPeriod(Duration.valueOf("60s")); + + assertFullMapping(properties, expected); + } +} diff --git a/presto-hive-common/src/test/java/com/facebook/presto/hive/aws/security/TestAWSSecurityMappings.java b/presto-hive-common/src/test/java/com/facebook/presto/hive/aws/security/TestAWSSecurityMappings.java new file mode 100644 index 0000000000000..f5e8f060ae1b3 --- /dev/null +++ b/presto-hive-common/src/test/java/com/facebook/presto/hive/aws/security/TestAWSSecurityMappings.java @@ -0,0 +1,107 @@ +/* + * 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 com.facebook.presto.hive.aws.security; + +import com.google.common.base.VerifyException; +import org.testng.annotations.Test; + +import java.io.File; + +import static com.facebook.presto.plugin.base.JsonUtils.parseJson; +import static java.util.Objects.requireNonNull; +import static org.testng.Assert.assertEquals; + +public class TestAWSSecurityMappings +{ + private static final String DEFAULT_USER = "defaultUser"; + + @Test + public void testValidAWSLakeFormationMapping() + { + String lakeFormationSecurityMappingConfigPath = + this.getClass().getClassLoader().getResource("com.facebook.presto.hive.aws.security/aws-security-mapping-lakeformation-valid.json").getPath(); + + AWSSecurityMappings mappings = parseJson(new File(lakeFormationSecurityMappingConfigPath).toPath(), AWSSecurityMappings.class); + + assertEquals(MappingResult.role("arn:aws:iam::123456789101:role/admin_role").getIamRole(), + mappings.getAWSLakeFormationSecurityMapping(MappingSelector.empty().withUser("admin").getUser()).getIamRole().get()); + assertEquals(MappingResult.role("arn:aws:iam::123456789101:role/analyst_role").getIamRole(), + mappings.getAWSLakeFormationSecurityMapping(MappingSelector.empty().withUser("analyst").getUser()).getIamRole().get()); + assertEquals(MappingResult.role("arn:aws:iam::123456789101:role/default_role").getIamRole(), + mappings.getAWSLakeFormationSecurityMapping(MappingSelector.empty().getUser()).getIamRole().get()); + } + + @Test( + expectedExceptions = VerifyException.class, + expectedExceptionsMessageRegExp = + "(iamRole is mandatory for AWS Lake Formation Security Mapping|Basic AWS Credentials are not supported for AWS Lake Formation Security Mapping)") + public void testInvalidAWSLakeFormationMapping() + { + String lakeFormationSecurityMappingConfigPath = + this.getClass().getClassLoader().getResource("com.facebook.presto.hive.aws.security/aws-security-mapping-lakeformation-invalid.json").getPath(); + + AWSSecurityMappings mappings = parseJson(new File(lakeFormationSecurityMappingConfigPath).toPath(), AWSSecurityMappings.class); + + // Fails with VerifyException: iamRole is mandatory for AWS Lake Formation Security Mapping + mappings.getAWSLakeFormationSecurityMapping(MappingSelector.empty().withUser("admin").getUser()); + + // Fails with VerifyException: Basic AWS Credentials are not supported for AWS Lake Formation Security Mapping + mappings.getAWSLakeFormationSecurityMapping(MappingSelector.empty().withUser("analyst").getUser()); + } + + private static class MappingSelector + { + private static MappingSelector empty() + { + return new MappingSelector(DEFAULT_USER); + } + + private final String user; + + private MappingSelector(String user) + { + this.user = requireNonNull(user, "user is null"); + } + + private MappingSelector withUser(String user) + { + return new MappingSelector(user); + } + + private String getUser() + { + return user; + } + } + + private static class MappingResult + { + private static MappingResult role(String role) + { + return new MappingResult(role); + } + + private final String iamRole; + + private MappingResult(String iamRole) + { + this.iamRole = requireNonNull(iamRole, "role is null"); + } + + private String getIamRole() + { + return iamRole; + } + } +} diff --git a/presto-hive-common/src/test/resources/com.facebook.presto.hive.aws.security/aws-security-mapping-lakeformation-invalid.json b/presto-hive-common/src/test/resources/com.facebook.presto.hive.aws.security/aws-security-mapping-lakeformation-invalid.json new file mode 100644 index 0000000000000..709c943f2e7c4 --- /dev/null +++ b/presto-hive-common/src/test/resources/com.facebook.presto.hive.aws.security/aws-security-mapping-lakeformation-invalid.json @@ -0,0 +1,12 @@ +{ + "mappings": [ + { + "user": "admin" + }, + { + "user": "analyst", + "accessKey": "AKIAxxxaccess", + "secretKey": "iXbXxxxsecret" + } + ] +} \ No newline at end of file diff --git a/presto-hive-common/src/test/resources/com.facebook.presto.hive.aws.security/aws-security-mapping-lakeformation-valid.json b/presto-hive-common/src/test/resources/com.facebook.presto.hive.aws.security/aws-security-mapping-lakeformation-valid.json new file mode 100644 index 0000000000000..8c2c87eff1adc --- /dev/null +++ b/presto-hive-common/src/test/resources/com.facebook.presto.hive.aws.security/aws-security-mapping-lakeformation-valid.json @@ -0,0 +1,15 @@ +{ + "mappings": [ + { + "user": "admin", + "iamRole": "arn:aws:iam::123456789101:role/admin_role" + }, + { + "user": "analyst", + "iamRole": "arn:aws:iam::123456789101:role/analyst_role" + }, + { + "iamRole": "arn:aws:iam::123456789101:role/default_role" + } + ] +} \ No newline at end of file diff --git a/presto-hive/src/main/java/com/facebook/presto/hive/s3/HiveS3Module.java b/presto-hive/src/main/java/com/facebook/presto/hive/s3/HiveS3Module.java index 0862713d4fe2c..7b671f8bc4989 100644 --- a/presto-hive/src/main/java/com/facebook/presto/hive/s3/HiveS3Module.java +++ b/presto-hive/src/main/java/com/facebook/presto/hive/s3/HiveS3Module.java @@ -14,13 +14,22 @@ package com.facebook.presto.hive.s3; import com.facebook.airlift.configuration.AbstractConfigurationAwareModule; +import com.facebook.presto.hive.DynamicConfigurationProvider; import com.facebook.presto.hive.HiveClientConfig; +import com.facebook.presto.hive.aws.security.AWSSecurityMappingConfig; +import com.facebook.presto.hive.aws.security.AWSSecurityMappingsSupplier; +import com.facebook.presto.hive.s3.security.AWSS3SecurityMappingConfigurationProvider; +import com.facebook.presto.hive.s3.security.ForAWSS3DynamicConfigurationProvider; import com.google.inject.Binder; +import com.google.inject.Provides; import com.google.inject.Scopes; +import com.google.inject.Singleton; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.hive.common.JavaUtils; import static com.facebook.airlift.configuration.ConfigBinder.configBinder; +import static com.facebook.presto.hive.aws.security.AWSSecurityMappingType.S3; +import static com.google.inject.multibindings.Multibinder.newSetBinder; import static java.util.Objects.requireNonNull; import static org.weakref.jmx.ObjectNames.generatedNameOf; import static org.weakref.jmx.guice.ExportBinder.newExporter; @@ -42,6 +51,8 @@ protected void setup(Binder binder) { S3FileSystemType type = buildConfigObject(HiveClientConfig.class).getS3FileSystemType(); if (type == S3FileSystemType.PRESTO) { + bindSecurityMapping(binder); + binder.bind(S3ConfigurationUpdater.class).to(PrestoS3ConfigurationUpdater.class).in(Scopes.SINGLETON); configBinder(binder).bindConfig(HiveS3Config.class); @@ -61,6 +72,23 @@ else if (type == S3FileSystemType.HADOOP_DEFAULT) { } } + @Provides + @Singleton + @ForAWSS3DynamicConfigurationProvider + public AWSSecurityMappingsSupplier provideAWSSecurityMappingsSupplier(AWSSecurityMappingConfig config) + { + return new AWSSecurityMappingsSupplier(config.getConfigFile(), config.getRefreshPeriod()); + } + + private void bindSecurityMapping(Binder binder) + { + if (buildConfigObject(AWSSecurityMappingConfig.class).getConfigFile().isPresent() && + buildConfigObject(AWSSecurityMappingConfig.class).getMappingType().equals(S3)) { + newSetBinder(binder, DynamicConfigurationProvider.class).addBinding() + .to(AWSS3SecurityMappingConfigurationProvider.class).in(Scopes.SINGLETON); + } + } + private static void validateEmrFsClass() { // verify that the class exists diff --git a/presto-hive/src/main/java/com/facebook/presto/hive/s3/security/AWSS3SecurityMappingConfigurationProvider.java b/presto-hive/src/main/java/com/facebook/presto/hive/s3/security/AWSS3SecurityMappingConfigurationProvider.java new file mode 100644 index 0000000000000..a09e391377376 --- /dev/null +++ b/presto-hive/src/main/java/com/facebook/presto/hive/s3/security/AWSS3SecurityMappingConfigurationProvider.java @@ -0,0 +1,77 @@ +/* + * 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 com.facebook.presto.hive.s3.security; + +import com.facebook.presto.hive.DynamicConfigurationProvider; +import com.facebook.presto.hive.HdfsContext; +import com.facebook.presto.hive.aws.security.AWSSecurityMapping; +import com.facebook.presto.hive.aws.security.AWSSecurityMappings; +import com.facebook.presto.hive.aws.security.AWSSecurityMappingsSupplier; +import com.google.common.collect.ImmutableSet; +import org.apache.hadoop.conf.Configuration; + +import javax.inject.Inject; + +import java.net.URI; +import java.util.Set; +import java.util.function.Supplier; + +import static com.facebook.presto.hive.s3.S3ConfigurationUpdater.S3_ACCESS_KEY; +import static com.facebook.presto.hive.s3.S3ConfigurationUpdater.S3_IAM_ROLE; +import static com.facebook.presto.hive.s3.S3ConfigurationUpdater.S3_SECRET_KEY; +import static com.google.common.base.Preconditions.checkArgument; +import static java.util.Objects.requireNonNull; + +public class AWSS3SecurityMappingConfigurationProvider + implements DynamicConfigurationProvider +{ + private static final Set SCHEMES = ImmutableSet.of("s3", "s3a", "s3n"); + + private final Supplier mappings; + + @Inject + public AWSS3SecurityMappingConfigurationProvider( + @ForAWSS3DynamicConfigurationProvider AWSSecurityMappingsSupplier awsSecurityMappingsSupplier) + { + this(requireNonNull(awsSecurityMappingsSupplier, "awsSecurityMappingsSupplier is null").getMappingsSupplier()); + } + + private AWSS3SecurityMappingConfigurationProvider(Supplier mappings) + { + this.mappings = requireNonNull(mappings, "mappings is null"); + } + + @Override + public void updateConfiguration(Configuration configuration, HdfsContext context, URI uri) + { + if (!SCHEMES.contains(uri.getScheme())) { + return; + } + + AWSSecurityMapping awsS3SecurityMapping = mappings.get().getAWSS3SecurityMapping(context.getIdentity().getUser()); + + checkArgument( + awsS3SecurityMapping.getIamRole().isPresent() || awsS3SecurityMapping.getCredentials().isPresent(), + "AWS S3 security mapping must have role or credentials"); + + awsS3SecurityMapping.getCredentials().ifPresent(credentials -> { + configuration.set(S3_ACCESS_KEY, credentials.getAWSAccessKeyId()); + configuration.set(S3_SECRET_KEY, credentials.getAWSSecretKey()); + }); + + awsS3SecurityMapping.getIamRole().ifPresent(role -> { + configuration.set(S3_IAM_ROLE, role); + }); + } +} diff --git a/presto-hive/src/main/java/com/facebook/presto/hive/s3/security/ForAWSS3DynamicConfigurationProvider.java b/presto-hive/src/main/java/com/facebook/presto/hive/s3/security/ForAWSS3DynamicConfigurationProvider.java new file mode 100644 index 0000000000000..446032ade96c0 --- /dev/null +++ b/presto-hive/src/main/java/com/facebook/presto/hive/s3/security/ForAWSS3DynamicConfigurationProvider.java @@ -0,0 +1,31 @@ +/* + * 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 com.facebook.presto.hive.s3.security; + +import javax.inject.Qualifier; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.ElementType.PARAMETER; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +@Retention(RUNTIME) +@Target({PARAMETER, METHOD, FIELD}) +@Qualifier +public @interface ForAWSS3DynamicConfigurationProvider +{ +} diff --git a/presto-hive/src/test/java/com/facebook/presto/hive/s3/security/TestAWSS3SecurityMapping.java b/presto-hive/src/test/java/com/facebook/presto/hive/s3/security/TestAWSS3SecurityMapping.java new file mode 100644 index 0000000000000..0041e89942b52 --- /dev/null +++ b/presto-hive/src/test/java/com/facebook/presto/hive/s3/security/TestAWSS3SecurityMapping.java @@ -0,0 +1,192 @@ +/* + * 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 com.facebook.presto.hive.s3.security; + +import com.facebook.presto.cache.CacheConfig; +import com.facebook.presto.hive.DynamicConfigurationProvider; +import com.facebook.presto.hive.HdfsContext; +import com.facebook.presto.hive.HiveClientConfig; +import com.facebook.presto.hive.HiveSessionProperties; +import com.facebook.presto.hive.OrcFileWriterConfig; +import com.facebook.presto.hive.ParquetFileWriterConfig; +import com.facebook.presto.hive.aws.security.AWSSecurityMappingConfig; +import com.facebook.presto.hive.aws.security.AWSSecurityMappingType; +import com.facebook.presto.hive.aws.security.AWSSecurityMappingsSupplier; +import com.facebook.presto.spi.ConnectorSession; +import com.facebook.presto.spi.security.AccessDeniedException; +import com.facebook.presto.spi.security.ConnectorIdentity; +import com.facebook.presto.testing.TestingConnectorSession; +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.fs.Path; +import org.testng.annotations.Test; + +import java.io.File; +import java.util.Optional; + +import static com.facebook.presto.hive.s3.S3ConfigurationUpdater.S3_ACCESS_KEY; +import static com.facebook.presto.hive.s3.S3ConfigurationUpdater.S3_IAM_ROLE; +import static com.facebook.presto.hive.s3.S3ConfigurationUpdater.S3_SECRET_KEY; +import static com.google.common.io.Resources.getResource; +import static java.util.Objects.requireNonNull; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNull; + +public class TestAWSS3SecurityMapping +{ + private static final String DEFAULT_USER = "defaultUser"; + + @Test + public void testAWSS3SecurityMapping() + { + AWSSecurityMappingConfig mappingConfig = new AWSSecurityMappingConfig() + .setMappingType(AWSSecurityMappingType.S3) + .setConfigFile(new File(getResource(getClass(), "aws-security-mapping-with-default-role.json").getPath())); + + AWSSecurityMappingsSupplier awsSecurityMappingsSupplier = + new AWSSecurityMappingsSupplier(mappingConfig.getConfigFile(), mappingConfig.getRefreshPeriod()); + + DynamicConfigurationProvider provider = new AWSS3SecurityMappingConfigurationProvider(awsSecurityMappingsSupplier); + + // matches user -- mapping provides credentials + assertMapping( + provider, + MappingSelector.empty().withUser("admin"), + MappingResult.credentials("AKIAxxxaccess", "iXbXxxxsecret")); + + // matches user regex -- mapping provides iam role + assertMapping( + provider, + MappingSelector.empty().withUser("analyst"), + MappingResult.role("arn:aws:iam::123456789101:role/analyst_and_scientist_role")); + + // matches empty rule at end -- default role used + assertMapping( + provider, + MappingSelector.empty().withUser("defaultUser"), + MappingResult.role("arn:aws:iam::123456789101:role/default")); + } + + @Test( + expectedExceptions = AccessDeniedException.class, + expectedExceptionsMessageRegExp = "Access Denied: No matching AWS S3 Security Mapping") + public void testFailAWSS3SecurityMapping() + { + AWSSecurityMappingConfig mappingConfig = new AWSSecurityMappingConfig() + .setMappingType(AWSSecurityMappingType.S3) + .setConfigFile(new File(getResource(getClass(), "aws-security-mapping-without-default-role.json").getPath())); + + AWSSecurityMappingsSupplier awsSecurityMappingsSupplier = + new AWSSecurityMappingsSupplier(mappingConfig.getConfigFile(), mappingConfig.getRefreshPeriod()); + + DynamicConfigurationProvider provider = new AWSS3SecurityMappingConfigurationProvider(awsSecurityMappingsSupplier); + + // matches no security mapping -- access denied + Configuration configuration = new Configuration(false); + applyMapping(provider, MappingSelector.empty().withUser("defaultUser"), configuration); + } + + private static void assertMapping(DynamicConfigurationProvider provider, MappingSelector selector, MappingResult mappingResult) + { + Configuration configuration = new Configuration(false); + + assertNull(configuration.get(S3_ACCESS_KEY)); + assertNull(configuration.get(S3_SECRET_KEY)); + assertNull(configuration.get(S3_IAM_ROLE)); + + applyMapping(provider, selector, configuration); + + if (mappingResult.getAccessKey().isPresent()) { + assertEquals(configuration.get(S3_ACCESS_KEY), mappingResult.getAccessKey().get()); + assertEquals(configuration.get(S3_SECRET_KEY), mappingResult.getSecretKey().get()); + } + else { + assertEquals(configuration.get(S3_IAM_ROLE), mappingResult.getRole().get()); + } + } + + private static void applyMapping(DynamicConfigurationProvider provider, MappingSelector selector, Configuration configuration) + { + provider.updateConfiguration(configuration, selector.getHdfsContext(), new Path("s3://defaultBucket/").toUri()); + } + + private static class MappingSelector + { + private final String user; + + private MappingSelector(String user) + { + this.user = requireNonNull(user, "user is null"); + } + + private static MappingSelector empty() + { + return new MappingSelector(DEFAULT_USER); + } + + private MappingSelector withUser(String user) + { + return new MappingSelector(user); + } + + private HdfsContext getHdfsContext() + { + ConnectorSession connectorSession = new TestingConnectorSession( + new ConnectorIdentity( + user, Optional.empty(), Optional.empty()), + new HiveSessionProperties( + new HiveClientConfig(), new OrcFileWriterConfig(), new ParquetFileWriterConfig(), new CacheConfig() + ).getSessionProperties()); + return new HdfsContext(connectorSession, "schema"); + } + } + + private static class MappingResult + { + private static MappingResult credentials(String accessKey, String secretKey) + { + return new MappingResult(Optional.of(accessKey), Optional.of(secretKey), Optional.empty()); + } + + private static MappingResult role(String role) + { + return new MappingResult(Optional.empty(), Optional.empty(), Optional.of(role)); + } + + private final Optional accessKey; + private final Optional secretKey; + private final Optional role; + + private MappingResult(Optional accessKey, Optional secretKey, Optional role) + { + this.accessKey = accessKey; + this.secretKey = secretKey; + this.role = role; + } + + private Optional getAccessKey() + { + return accessKey; + } + + private Optional getSecretKey() + { + return secretKey; + } + + private Optional getRole() + { + return role; + } + } +} diff --git a/presto-hive/src/test/resources/com/facebook/presto/hive/s3/security/aws-security-mapping-with-default-role.json b/presto-hive/src/test/resources/com/facebook/presto/hive/s3/security/aws-security-mapping-with-default-role.json new file mode 100644 index 0000000000000..504541348c4cf --- /dev/null +++ b/presto-hive/src/test/resources/com/facebook/presto/hive/s3/security/aws-security-mapping-with-default-role.json @@ -0,0 +1,16 @@ +{ + "mappings": [ + { + "user": "admin", + "accessKey": "AKIAxxxaccess", + "secretKey": "iXbXxxxsecret" + }, + { + "user": "analyst|scientist", + "iamRole": "arn:aws:iam::123456789101:role/analyst_and_scientist_role" + }, + { + "iamRole": "arn:aws:iam::123456789101:role/default" + } + ] +} diff --git a/presto-hive/src/test/resources/com/facebook/presto/hive/s3/security/aws-security-mapping-without-default-role.json b/presto-hive/src/test/resources/com/facebook/presto/hive/s3/security/aws-security-mapping-without-default-role.json new file mode 100644 index 0000000000000..86a3441a0dae4 --- /dev/null +++ b/presto-hive/src/test/resources/com/facebook/presto/hive/s3/security/aws-security-mapping-without-default-role.json @@ -0,0 +1,13 @@ +{ + "mappings": [ + { + "user": "admin", + "accessKey": "AKIAxxxaccess", + "secretKey": "iXbXxxxsecret" + }, + { + "user": "analyst|scientist", + "iamRole": "arn:aws:iam::123456789101:role/analyst_and_scientist_role" + } + ] +} diff --git a/presto-main/src/main/java/com/facebook/presto/testing/TestingConnectorSession.java b/presto-main/src/main/java/com/facebook/presto/testing/TestingConnectorSession.java index 3bb4c3e9089fc..ca2470f0ec2e7 100644 --- a/presto-main/src/main/java/com/facebook/presto/testing/TestingConnectorSession.java +++ b/presto-main/src/main/java/com/facebook/presto/testing/TestingConnectorSession.java @@ -65,26 +65,32 @@ public class TestingConnectorSession public TestingConnectorSession(List> properties) { - this("user", Optional.of("test"), Optional.empty(), UTC_KEY, ENGLISH, System.currentTimeMillis(), properties, ImmutableMap.of(), new FeaturesConfig().isLegacyTimestamp(), Optional.empty(), ImmutableSet.of(), Optional.empty(), ImmutableMap.of()); + this("user", new ConnectorIdentity("user", Optional.empty(), Optional.empty()), Optional.of("test"), Optional.empty(), UTC_KEY, ENGLISH, System.currentTimeMillis(), properties, ImmutableMap.of(), new FeaturesConfig().isLegacyTimestamp(), Optional.empty(), ImmutableSet.of(), Optional.empty(), ImmutableMap.of()); + } + + public TestingConnectorSession(ConnectorIdentity identity, List> properties) + { + this(identity.getUser(), identity, Optional.of("test"), Optional.empty(), UTC_KEY, ENGLISH, System.currentTimeMillis(), properties, ImmutableMap.of(), new FeaturesConfig().isLegacyTimestamp(), Optional.empty(), ImmutableSet.of(), Optional.empty(), ImmutableMap.of()); } public TestingConnectorSession(List> properties, Set clientTags) { - this("user", Optional.of("test"), Optional.empty(), UTC_KEY, ENGLISH, System.currentTimeMillis(), properties, ImmutableMap.of(), new FeaturesConfig().isLegacyTimestamp(), Optional.empty(), clientTags, Optional.empty(), ImmutableMap.of()); + this("user", new ConnectorIdentity("user", Optional.empty(), Optional.empty()), Optional.of("test"), Optional.empty(), UTC_KEY, ENGLISH, System.currentTimeMillis(), properties, ImmutableMap.of(), new FeaturesConfig().isLegacyTimestamp(), Optional.empty(), clientTags, Optional.empty(), ImmutableMap.of()); } public TestingConnectorSession(List> properties, Map propertyValues) { - this("user", Optional.of("test"), Optional.empty(), UTC_KEY, ENGLISH, System.currentTimeMillis(), properties, propertyValues, new FeaturesConfig().isLegacyTimestamp(), Optional.empty(), ImmutableSet.of(), Optional.empty(), ImmutableMap.of()); + this("user", new ConnectorIdentity("user", Optional.empty(), Optional.empty()), Optional.of("test"), Optional.empty(), UTC_KEY, ENGLISH, System.currentTimeMillis(), properties, propertyValues, new FeaturesConfig().isLegacyTimestamp(), Optional.empty(), ImmutableSet.of(), Optional.empty(), ImmutableMap.of()); } public TestingConnectorSession(List> properties, Optional schema) { - this("user", Optional.of("test"), Optional.empty(), UTC_KEY, ENGLISH, System.currentTimeMillis(), properties, ImmutableMap.of(), new FeaturesConfig().isLegacyTimestamp(), Optional.empty(), ImmutableSet.of(), schema, ImmutableMap.of()); + this("user", new ConnectorIdentity("user", Optional.empty(), Optional.empty()), Optional.of("test"), Optional.empty(), UTC_KEY, ENGLISH, System.currentTimeMillis(), properties, ImmutableMap.of(), new FeaturesConfig().isLegacyTimestamp(), Optional.empty(), ImmutableSet.of(), schema, ImmutableMap.of()); } public TestingConnectorSession( String user, + ConnectorIdentity identity, Optional source, Optional traceToken, TimeZoneKey timeZoneKey, @@ -99,7 +105,7 @@ public TestingConnectorSession( Map sessionFunctions) { this.queryId = queryIdGenerator.createNextQueryId().toString(); - this.identity = new ConnectorIdentity(requireNonNull(user, "user is null"), Optional.empty(), Optional.empty()); + this.identity = requireNonNull(identity, "identity is null"); this.source = requireNonNull(source, "source is null"); this.traceToken = requireNonNull(traceToken, "traceToken is null"); this.timeZoneKey = requireNonNull(timeZoneKey, "timeZoneKey is null"); diff --git a/presto-main/src/test/java/com/facebook/presto/operator/scalar/TestDateTimeFunctionsBase.java b/presto-main/src/test/java/com/facebook/presto/operator/scalar/TestDateTimeFunctionsBase.java index 2f3be9168f9af..7a782eb6a8018 100644 --- a/presto-main/src/test/java/com/facebook/presto/operator/scalar/TestDateTimeFunctionsBase.java +++ b/presto-main/src/test/java/com/facebook/presto/operator/scalar/TestDateTimeFunctionsBase.java @@ -26,6 +26,7 @@ import com.facebook.presto.common.type.TimestampType; import com.facebook.presto.common.type.Type; import com.facebook.presto.spi.StandardErrorCode; +import com.facebook.presto.spi.security.ConnectorIdentity; import com.facebook.presto.testing.TestingConnectorSession; import com.facebook.presto.testing.TestingSession; import com.facebook.presto.type.SqlIntervalDayTime; @@ -165,6 +166,7 @@ private void assertCurrentDateAtInstant(TimeZoneKey timeZoneKey, long instant) long dateTimeCalculation = currentDate( new TestingConnectorSession( "test", + new ConnectorIdentity("test", Optional.empty(), Optional.empty()), Optional.empty(), Optional.empty(), timeZoneKey, diff --git a/presto-pinot-toolkit/src/test/java/com/facebook/presto/pinot/TestPinotSplitManager.java b/presto-pinot-toolkit/src/test/java/com/facebook/presto/pinot/TestPinotSplitManager.java index daa98d7a87a4e..3ee64e600415f 100644 --- a/presto-pinot-toolkit/src/test/java/com/facebook/presto/pinot/TestPinotSplitManager.java +++ b/presto-pinot-toolkit/src/test/java/com/facebook/presto/pinot/TestPinotSplitManager.java @@ -18,6 +18,7 @@ import com.facebook.presto.spi.ConnectorSplitSource; import com.facebook.presto.spi.plan.AggregationNode; import com.facebook.presto.spi.plan.PlanNode; +import com.facebook.presto.spi.security.ConnectorIdentity; import com.facebook.presto.sql.analyzer.FeaturesConfig; import com.facebook.presto.sql.planner.iterative.rule.test.PlanBuilder; import com.facebook.presto.testing.TestingConnectorSession; @@ -224,6 +225,7 @@ public static ConnectorSession createSessionWithNumSplits(int numSegmentsPerSpli { return new TestingConnectorSession( "user", + new ConnectorIdentity("user", Optional.empty(), Optional.empty()), Optional.of("test"), Optional.empty(), UTC_KEY, @@ -246,6 +248,7 @@ public static ConnectorSession createSessionWithLimitLarge(int limitLarge, Pinot { return new TestingConnectorSession( "user", + new ConnectorIdentity("user", Optional.empty(), Optional.empty()), Optional.of("test"), Optional.empty(), UTC_KEY, @@ -266,6 +269,7 @@ public static ConnectorSession createSessionWithTopNLarge(int topNLarge, PinotCo { return new TestingConnectorSession( "user", + new ConnectorIdentity("user", Optional.empty(), Optional.empty()), Optional.of("test"), Optional.empty(), UTC_KEY,