diff --git a/api/src/main/java/org/apache/gravitino/CatalogProvider.java b/api/src/main/java/org/apache/gravitino/CatalogProvider.java index 429f2f9add3..98b448a0b89 100644 --- a/api/src/main/java/org/apache/gravitino/CatalogProvider.java +++ b/api/src/main/java/org/apache/gravitino/CatalogProvider.java @@ -26,7 +26,27 @@ */ @Evolving public interface CatalogProvider { + enum CatalogName { + HIVE("hive"), + HADOOP("hadoop"), + KAFKA("kafka"), + JDBC_DORIS("jdbc-doris"), + JDBC_MYSQL("jdbc-mysql"), + JDBC_OCEANBASE("jdbc-oceanbase"), + JDBC_POSTGRESQL("jdbc-postgresql"), + LAKEHOUSE_ICEBERG("lakehouse-iceberg"), + LAKEHOUSE_HUDI("lakehouse-hudi"), + LAKEHOUSE_PAIMON("lakehouse-paimon"); + private final String name; + CatalogName(String name) { + this.name = name; + } + + public String getName() { + return this.name; + } + } /** * The string that represents the catalog that this provider uses. This is overridden by children * to provide a nice alias for the catalog. diff --git a/authorizations/authorization-chain/build.gradle.kts b/authorizations/authorization-chain/build.gradle.kts new file mode 100644 index 00000000000..f70c45bf3cd --- /dev/null +++ b/authorizations/authorization-chain/build.gradle.kts @@ -0,0 +1,141 @@ +/* + * 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. + */ +description = "authorization-chain" + +plugins { + `maven-publish` + id("java") + id("idea") +} + +val scalaVersion: String = project.properties["scalaVersion"] as? String ?: extra["defaultScalaVersion"].toString() +val sparkVersion: String = libs.versions.spark35.get() +val kyuubiVersion: String = libs.versions.kyuubi4paimon.get() +val sparkMajorVersion: String = sparkVersion.substringBeforeLast(".") + +dependencies { + implementation(project(":api")) { + exclude(group = "*") + } + implementation(project(":core")) { + exclude(group = "*") + } + implementation(project(":common")) { + exclude(group = "*") + } + + implementation(libs.bundles.log4j) + implementation(libs.commons.lang3) + implementation(libs.guava) + implementation(libs.javax.jaxb.api) { + exclude("*") + } + implementation(libs.javax.ws.rs.api) + implementation(libs.jettison) + compileOnly(libs.lombok) + implementation(libs.rome) + + testImplementation(project(":core", "testArtifacts")) + testImplementation(project(":clients:client-java")) + testImplementation(project(":server")) + testImplementation(project(":catalogs:catalog-common")) + testImplementation(project(":integration-test-common", "testArtifacts")) + testImplementation(project(":authorizations:authorization-ranger")) + testImplementation(project(":authorizations:authorization-ranger", "testArtifacts")) + testImplementation(libs.junit.jupiter.api) + testImplementation(libs.mockito.core) + testImplementation(libs.testcontainers) + testRuntimeOnly(libs.junit.jupiter.engine) + testImplementation(libs.mysql.driver) + testImplementation(libs.postgresql.driver) + testImplementation(libs.ranger.intg) { + exclude("org.apache.hadoop", "hadoop-common") + exclude("org.apache.hive", "hive-storage-api") + exclude("org.apache.lucene") + exclude("org.apache.solr") + exclude("org.apache.kafka") + exclude("org.elasticsearch") + exclude("org.elasticsearch.client") + exclude("org.elasticsearch.plugin") + exclude("org.apache.ranger", "ranger-plugins-audit") + exclude("org.apache.ranger", "ranger-plugins-cred") + exclude("org.apache.ranger", "ranger-plugin-classloader") + exclude("net.java.dev.jna") + exclude("javax.ws.rs") + exclude("org.eclipse.jetty") + } + testImplementation("org.apache.spark:spark-hive_$scalaVersion:$sparkVersion") + testImplementation("org.apache.spark:spark-sql_$scalaVersion:$sparkVersion") { + exclude("org.apache.avro") + exclude("org.apache.hadoop") + exclude("org.apache.zookeeper") + exclude("io.dropwizard.metrics") + exclude("org.rocksdb") + } + testImplementation("org.apache.kyuubi:kyuubi-spark-authz-shaded_$scalaVersion:$kyuubiVersion") { + exclude("com.sun.jersey") + } + testImplementation(libs.hadoop3.client) + testImplementation(libs.hadoop3.common) { + exclude("com.sun.jersey") + exclude("javax.servlet", "servlet-api") + } + testImplementation(libs.hadoop3.hdfs) { + exclude("com.sun.jersey") + exclude("javax.servlet", "servlet-api") + exclude("io.netty") + } +} + +tasks { + val runtimeJars by registering(Copy::class) { + from(configurations.runtimeClasspath) + into("build/libs") + } + + val copyAuthorizationLibs by registering(Copy::class) { + dependsOn("jar", runtimeJars) + from("build/libs") { + exclude("guava-*.jar") + exclude("log4j-*.jar") + exclude("slf4j-*.jar") + } + into("$rootDir/distribution/package/authorizations/chain/libs") + } + + register("copyLibAndConfig", Copy::class) { + dependsOn(copyAuthorizationLibs) + } + + jar { + dependsOn(runtimeJars) + } +} + +tasks.test { + dependsOn(":catalogs:catalog-hive:jar", ":catalogs:catalog-hive:runtimeJars", ":authorizations:authorization-ranger:jar", ":authorizations:authorization-ranger:runtimeJars") + + val skipITs = project.hasProperty("skipITs") + if (skipITs) { + // Exclude integration tests + exclude("**/integration/test/**") + } else { + dependsOn(tasks.jar) + } +} diff --git a/authorizations/authorization-chain/src/main/java/org/apache/gravitino/authorization/chain/ChainAuthorization.java b/authorizations/authorization-chain/src/main/java/org/apache/gravitino/authorization/chain/ChainAuthorization.java new file mode 100644 index 00000000000..d44174a327f --- /dev/null +++ b/authorizations/authorization-chain/src/main/java/org/apache/gravitino/authorization/chain/ChainAuthorization.java @@ -0,0 +1,43 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.gravitino.authorization.chain; + +import java.util.Map; +import org.apache.gravitino.connector.authorization.AuthorizationPlugin; +import org.apache.gravitino.connector.authorization.AuthorizationPluginProvider; +import org.apache.gravitino.connector.authorization.BaseAuthorization; + +/** Implementation of a Chain authorization in Gravitino. */ +public class ChainAuthorization extends BaseAuthorization { + @Override + public String shortName() { + return AuthorizationPluginProvider.Type.Chain.getName(); + } + + @Override + protected AuthorizationPlugin newPlugin(String catalogProvider, Map config) { + switch (catalogProvider) { + case "hive": + case "test": // For testing purposes + return ChainAuthorizationPlugin.getInstance(catalogProvider, config); + default: + throw new IllegalArgumentException("Unknown catalog provider: " + catalogProvider); + } + } +} diff --git a/authorizations/authorization-chain/src/main/java/org/apache/gravitino/authorization/chain/ChainAuthorizationBase.java b/authorizations/authorization-chain/src/main/java/org/apache/gravitino/authorization/chain/ChainAuthorizationBase.java new file mode 100644 index 00000000000..175fb887061 --- /dev/null +++ b/authorizations/authorization-chain/src/main/java/org/apache/gravitino/authorization/chain/ChainAuthorizationBase.java @@ -0,0 +1,303 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.gravitino.authorization.chain; + +import com.google.common.annotations.VisibleForTesting; +import com.google.common.base.Preconditions; +import com.google.common.collect.Lists; +import java.io.IOException; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import org.apache.gravitino.MetadataObject; +import org.apache.gravitino.authorization.Group; +import org.apache.gravitino.authorization.MetadataObjectChange; +import org.apache.gravitino.authorization.Owner; +import org.apache.gravitino.authorization.Role; +import org.apache.gravitino.authorization.RoleChange; +import org.apache.gravitino.authorization.User; +import org.apache.gravitino.connector.AuthorizationPropertiesMeta; +import org.apache.gravitino.connector.authorization.AuthorizationPlugin; +import org.apache.gravitino.connector.authorization.AuthorizationPluginProvider; +import org.apache.gravitino.connector.authorization.BaseAuthorization; +import org.apache.gravitino.exceptions.AuthorizationPluginException; +import org.apache.gravitino.utils.MapUtils; + +/** Chain call authorization plugin. */ +public abstract class ChainAuthorizationBase implements AuthorizationPlugin { + private List plugins = Lists.newArrayList(); + private final String catalogProviderName; + + ChainAuthorizationBase(String catalogProvider, Map config) { + this.catalogProviderName = catalogProvider; + initPlugins(config); + } + + private void initPlugins(Map config) { + String chainPlugins = config.get(AuthorizationPropertiesMeta.CHAIN_PLUGINS); + Map chainConfig = + MapUtils.getFilteredMap( + config, key -> key.toString().startsWith(AuthorizationPropertiesMeta.getChainPrefix())); + Arrays.stream(chainPlugins.split(AuthorizationPropertiesMeta.getChainPluginsSplitter())) + .forEach( + pluginName -> { + String providerKey = + AuthorizationPropertiesMeta.generateChainPluginsKey( + pluginName, AuthorizationPropertiesMeta.getChainProviderKey()); + Preconditions.checkArgument( + config.containsKey(providerKey), "Missing provider for plugin: " + pluginName); + String authProvider = config.get(providerKey); + Preconditions.checkArgument( + !authProvider.isEmpty(), "Provider for plugin: " + pluginName + " is empty"); + // Convert chain config to plugin config + Map pluginConfig = + chainConfig.entrySet().stream() + .filter( + entry -> + entry + .getKey() + .startsWith( + String.format( + "%s.%s", + AuthorizationPropertiesMeta.getChainPrefix(), + pluginName))) + .collect( + Collectors.toMap( + entry -> + AuthorizationPropertiesMeta.chainKeyToPluginKey( + entry.getKey(), pluginName), + Map.Entry::getValue)); + AuthorizationPlugin authorizationPlugin = + BaseAuthorization.createAuthorization( + this.getClass().getClassLoader(), authProvider) + .plugin(catalogProviderName, pluginConfig); + plugins.add(authorizationPlugin); + }); + } + + @VisibleForTesting + public final List getPlugins() { + return plugins; + } + + @Override + public String catalogProviderName() { + return catalogProviderName; + } + + @Override + public String pluginProviderName() { + return AuthorizationPluginProvider.Type.Chain.getName(); + } + + abstract Role translateRole(Role role, String toCatalogName, String toPluginName); + + @Override + public void close() throws IOException { + for (AuthorizationPlugin plugin : plugins) { + plugin.close(); + } + } + + @Override + public Boolean onMetadataUpdated(MetadataObjectChange... changes) + throws AuthorizationPluginException { + for (AuthorizationPlugin plugin : plugins) { + Boolean result = plugin.onMetadataUpdated(changes); + if (Boolean.FALSE.equals(result)) { + return Boolean.FALSE; + } + } + return Boolean.TRUE; + } + + @Override + public Boolean onRoleCreated(Role role) throws AuthorizationPluginException { + for (AuthorizationPlugin plugin : plugins) { + Role pluginRole = + translateRole(role, plugin.catalogProviderName(), plugin.pluginProviderName()); + Boolean result = plugin.onRoleCreated(pluginRole); + if (Boolean.FALSE.equals(result)) { + return Boolean.FALSE; + } + } + return Boolean.TRUE; + } + + @Override + public Boolean onRoleAcquired(Role role) throws AuthorizationPluginException { + for (AuthorizationPlugin plugin : plugins) { + Boolean result = plugin.onRoleAcquired(role); + if (Boolean.FALSE.equals(result)) { + return Boolean.FALSE; + } + } + return Boolean.TRUE; + } + + @Override + public Boolean onRoleDeleted(Role role) throws AuthorizationPluginException { + for (AuthorizationPlugin plugin : plugins) { + Boolean result = plugin.onRoleDeleted(role); + if (Boolean.FALSE.equals(result)) { + return Boolean.FALSE; + } + } + return Boolean.TRUE; + } + + @Override + public Boolean onRoleUpdated(Role role, RoleChange... changes) + throws AuthorizationPluginException { + for (AuthorizationPlugin plugin : plugins) { + Boolean result = plugin.onRoleUpdated(role, changes); + if (Boolean.FALSE.equals(result)) { + return Boolean.FALSE; + } + } + return Boolean.TRUE; + } + + @Override + public Boolean onGrantedRolesToUser(List roles, User user) + throws AuthorizationPluginException { + for (AuthorizationPlugin plugin : plugins) { + Boolean result = plugin.onGrantedRolesToUser(roles, user); + if (Boolean.FALSE.equals(result)) { + return Boolean.FALSE; + } + } + return Boolean.TRUE; + } + + @Override + public Boolean onRevokedRolesFromUser(List roles, User user) + throws AuthorizationPluginException { + for (AuthorizationPlugin plugin : plugins) { + Boolean result = plugin.onRevokedRolesFromUser(roles, user); + if (Boolean.FALSE.equals(result)) { + return Boolean.FALSE; + } + } + return Boolean.TRUE; + } + + @Override + public Boolean onGrantedRolesToGroup(List roles, Group group) + throws AuthorizationPluginException { + for (AuthorizationPlugin plugin : plugins) { + Boolean result = plugin.onGrantedRolesToGroup(roles, group); + if (Boolean.FALSE.equals(result)) { + return Boolean.FALSE; + } + } + return Boolean.TRUE; + } + + @Override + public Boolean onRevokedRolesFromGroup(List roles, Group group) + throws AuthorizationPluginException { + for (AuthorizationPlugin plugin : plugins) { + Boolean result = plugin.onRevokedRolesFromGroup(roles, group); + if (Boolean.FALSE.equals(result)) { + return Boolean.FALSE; + } + } + return Boolean.TRUE; + } + + @Override + public Boolean onUserAdded(User user) throws AuthorizationPluginException { + for (AuthorizationPlugin plugin : plugins) { + Boolean result = plugin.onUserAdded(user); + if (Boolean.FALSE.equals(result)) { + return Boolean.FALSE; + } + } + return Boolean.TRUE; + } + + @Override + public Boolean onUserRemoved(User user) throws AuthorizationPluginException { + for (AuthorizationPlugin plugin : plugins) { + Boolean result = plugin.onUserRemoved(user); + if (Boolean.FALSE.equals(result)) { + return Boolean.FALSE; + } + } + return Boolean.TRUE; + } + + @Override + public Boolean onUserAcquired(User user) throws AuthorizationPluginException { + for (AuthorizationPlugin plugin : plugins) { + Boolean result = plugin.onUserAcquired(user); + if (Boolean.FALSE.equals(result)) { + return Boolean.FALSE; + } + } + return Boolean.TRUE; + } + + @Override + public Boolean onGroupAdded(Group group) throws AuthorizationPluginException { + for (AuthorizationPlugin plugin : plugins) { + Boolean result = plugin.onGroupAdded(group); + if (Boolean.FALSE.equals(result)) { + return Boolean.FALSE; + } + } + return Boolean.TRUE; + } + + @Override + public Boolean onGroupRemoved(Group group) throws AuthorizationPluginException { + for (AuthorizationPlugin plugin : plugins) { + Boolean result = plugin.onGroupRemoved(group); + if (Boolean.FALSE.equals(result)) { + return Boolean.FALSE; + } + } + return Boolean.TRUE; + } + + @Override + public Boolean onGroupAcquired(Group group) throws AuthorizationPluginException { + for (AuthorizationPlugin plugin : plugins) { + Boolean result = plugin.onGroupAcquired(group); + if (Boolean.FALSE.equals(result)) { + return Boolean.FALSE; + } + } + return Boolean.TRUE; + } + + @Override + public Boolean onOwnerSet(MetadataObject metadataObject, Owner preOwner, Owner newOwner) + throws AuthorizationPluginException { + for (AuthorizationPlugin plugin : plugins) { + Boolean result = plugin.onOwnerSet(metadataObject, preOwner, newOwner); + if (Boolean.FALSE.equals(result)) { + return Boolean.FALSE; + } + } + return Boolean.TRUE; + } +} diff --git a/authorizations/authorization-chain/src/main/java/org/apache/gravitino/authorization/chain/ChainAuthorizationPlugin.java b/authorizations/authorization-chain/src/main/java/org/apache/gravitino/authorization/chain/ChainAuthorizationPlugin.java new file mode 100644 index 00000000000..fceb9b1a675 --- /dev/null +++ b/authorizations/authorization-chain/src/main/java/org/apache/gravitino/authorization/chain/ChainAuthorizationPlugin.java @@ -0,0 +1,70 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.gravitino.authorization.chain; + +import java.util.List; +import java.util.Map; +import org.apache.gravitino.authorization.Role; +import org.apache.gravitino.authorization.SecurableObject; +import org.apache.gravitino.authorization.chain.translates.ChainTranslateEntity; +import org.apache.gravitino.authorization.chain.translates.ChainTranslateMappingProvider; +import org.apache.gravitino.meta.RoleEntity; + +/** Chain authorization operations plugin class.
*/ +public class ChainAuthorizationPlugin extends ChainAuthorizationBase { + private static volatile ChainAuthorizationPlugin instance = null; + + public static synchronized ChainAuthorizationPlugin getInstance( + String catalogProvider, Map config) { + if (instance == null) { + synchronized (ChainAuthorizationPlugin.class) { + if (instance == null) { + instance = new ChainAuthorizationPlugin(catalogProvider, config); + } + } + } + return instance; + } + + private ChainAuthorizationPlugin(String catalogProvider, Map config) { + super(catalogProvider, config); + } + + @Override + Role translateRole(Role role, String toCatalogName, String toPluginName) { + ChainTranslateEntity chainMappingProvider = + new ChainTranslateEntity(catalogProviderName(), toCatalogName); + ChainTranslateMappingProvider.ChainTranslate translator = + ChainTranslateMappingProvider.getChainTranslator(chainMappingProvider); + if (translator == null) { + throw new UnsupportedOperationException( + "Translation not supported for " + chainMappingProvider); + } + List translateSecrableObjects = translator.translate(role.securableObjects()); + + RoleEntity roleEntity = (RoleEntity) role; + return RoleEntity.builder() + .withId(roleEntity.id()) + .withName(roleEntity.name()) + .withProperties(roleEntity.properties()) + .withAuditInfo(roleEntity.auditInfo()) + .withSecurableObjects(translateSecrableObjects) + .build(); + } +} diff --git a/authorizations/authorization-chain/src/main/java/org/apache/gravitino/authorization/chain/translates/ChainTranslateEntity.java b/authorizations/authorization-chain/src/main/java/org/apache/gravitino/authorization/chain/translates/ChainTranslateEntity.java new file mode 100644 index 00000000000..34c7891e1ad --- /dev/null +++ b/authorizations/authorization-chain/src/main/java/org/apache/gravitino/authorization/chain/translates/ChainTranslateEntity.java @@ -0,0 +1,60 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.gravitino.authorization.chain.translates; + +import java.util.Objects; +import org.apache.gravitino.CatalogProvider; +import org.apache.gravitino.connector.authorization.AuthorizationPluginProvider; + +/** + * The ChainTranslateEntity class presents a chain translation entity that contains the from and to + * catalog and plugin provider. + */ +public class ChainTranslateEntity { + CatalogProvider.CatalogName from; + CatalogProvider.CatalogName to; + + public ChainTranslateEntity( + CatalogProvider.CatalogName fromCatalogName, + CatalogProvider.CatalogName toCatalogName) { + this.from = fromCatalogName; + this.to = toCatalogName; + } + + public ChainTranslateEntity( + String fromCatalogName, + String toCatalogName) { + CatalogProvider.CatalogName fromCatalog = CatalogProvider.CatalogName.valueOf(fromCatalogName); + CatalogProvider.CatalogName toCatalog = CatalogProvider.CatalogName.valueOf(toCatalogName); + new ChainTranslateEntity(fromCatalog, toCatalog); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof ChainTranslateEntity)) return false; + ChainTranslateEntity that = (ChainTranslateEntity) o; + return Objects.equals(from, that.from) && Objects.equals(to, that.to); + } + + @Override + public int hashCode() { + return Objects.hash(from, to); + } +} diff --git a/authorizations/authorization-chain/src/main/java/org/apache/gravitino/authorization/chain/translates/ChainTranslateMappingProvider.java b/authorizations/authorization-chain/src/main/java/org/apache/gravitino/authorization/chain/translates/ChainTranslateMappingProvider.java new file mode 100644 index 00000000000..db462d462e6 --- /dev/null +++ b/authorizations/authorization-chain/src/main/java/org/apache/gravitino/authorization/chain/translates/ChainTranslateMappingProvider.java @@ -0,0 +1,44 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.gravitino.authorization.chain.translates; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.apache.gravitino.authorization.SecurableObject; + +/** + * The ChainTranslateMappingProvider class provides a mapping of chain translation entities to their + * respective chain translators. + */ +public class ChainTranslateMappingProvider { + public interface ChainTranslate { + List translate(List securableObjects); + } + + private static final Map translators = new HashMap<>(); + + public static ChainTranslate getChainTranslator(ChainTranslateEntity provider) { + return translators.get(provider); + } + + public static void put(ChainTranslateEntity provider, ChainTranslate translator) { + translators.put(provider, translator); + } +} diff --git a/authorizations/authorization-chain/src/main/java/org/apache/gravitino/authorization/chain/translates/TranslateHiveToHadoop.java b/authorizations/authorization-chain/src/main/java/org/apache/gravitino/authorization/chain/translates/TranslateHiveToHadoop.java new file mode 100644 index 00000000000..75f3ca90e66 --- /dev/null +++ b/authorizations/authorization-chain/src/main/java/org/apache/gravitino/authorization/chain/translates/TranslateHiveToHadoop.java @@ -0,0 +1,40 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.gravitino.authorization.chain.translates; + +import java.util.List; +import org.apache.gravitino.CatalogProvider; +import org.apache.gravitino.authorization.SecurableObject; + +/** + * The TranslateHiveToHadoop class provides translation from Hive to Hadoop. + * */ +public class TranslateHiveToHadoop + implements ChainTranslateMappingProvider.ChainTranslate { + static { + ChainTranslateEntity chainTranslateEntity = + new ChainTranslateEntity(CatalogProvider.CatalogName.HIVE, CatalogProvider.CatalogName.HADOOP); + ChainTranslateMappingProvider.put(chainTranslateEntity, new TranslateHiveToHadoop()); + } + + @Override + public List translate(List securableObjects) { + return null; + } +} diff --git a/authorizations/authorization-chain/src/main/resources/META-INF/services/org.apache.gravitino.connector.authorization.AuthorizationProvider b/authorizations/authorization-chain/src/main/resources/META-INF/services/org.apache.gravitino.connector.authorization.AuthorizationProvider new file mode 100644 index 00000000000..c4b35cb24df --- /dev/null +++ b/authorizations/authorization-chain/src/main/resources/META-INF/services/org.apache.gravitino.connector.authorization.AuthorizationProvider @@ -0,0 +1,19 @@ +# +# 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. +# +org.apache.gravitino.authorization.chain.ChainAuthorization \ No newline at end of file diff --git a/authorizations/authorization-chain/src/test/java/org/apache/gravitino/authorization/chain/TestAuthorizationPropertiesMeta.java b/authorizations/authorization-chain/src/test/java/org/apache/gravitino/authorization/chain/TestAuthorizationPropertiesMeta.java new file mode 100644 index 00000000000..f92fac494e6 --- /dev/null +++ b/authorizations/authorization-chain/src/test/java/org/apache/gravitino/authorization/chain/TestAuthorizationPropertiesMeta.java @@ -0,0 +1,82 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.gravitino.authorization.chain; + +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.apache.gravitino.connector.AuthorizationPropertiesMeta; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class TestAuthorizationPropertiesMeta { + private static final Logger LOG = LoggerFactory.getLogger(TestAuthorizationPropertiesMeta.class); + + @Test + public void checkChainPropertyDefines() throws IllegalAccessException { + Map mapVariable = + getPublicStaticVariableFromClass(AuthorizationPropertiesMeta.class); + List ignoreChecks = + Arrays.asList( + AuthorizationPropertiesMeta.CHAIN_PROVIDER, AuthorizationPropertiesMeta.CHAIN_PLUGINS); + mapVariable.values().stream() + .forEach( + value -> { + if (!ignoreChecks.stream().anyMatch(ignore -> value.equals(ignore)) + && value.contains(AuthorizationPropertiesMeta.getChainPrefix())) { + String pluginPropValue = + value.replace( + AuthorizationPropertiesMeta.generateChainPluginsKey( + AuthorizationPropertiesMeta.getChainPlugsWildcard(), ""), + AuthorizationPropertiesMeta.generatePluginKey("")); + LOG.info("Checking variable: {}, pluginPropValue: {}", value, pluginPropValue); + Assertions.assertTrue( + mapVariable.values().contains(pluginPropValue), + String.format("Variable %s is not defined in the class", value)); + } + }); + } + + /** + * Get all public static member variables from a class + * + * @param clazz The class to get public member variables from + * @return A map of the Map + */ + private Map getPublicStaticVariableFromClass(Class clazz) + throws IllegalAccessException { + Field[] fields = clazz.getFields(); + Map publicStaticFields = new HashMap<>(); + + for (Field field : fields) { + if (Modifier.isPublic(field.getModifiers()) + && Modifier.isStatic(field.getModifiers()) + && field.getDeclaringClass().equals(clazz) + && field.getType().equals(String.class)) { + publicStaticFields.put(field.getName(), field.get(null).toString()); + } + } + return publicStaticFields; + } +} diff --git a/authorizations/authorization-chain/src/test/java/org/apache/gravitino/authorization/chain/TestChainAuthorization.java b/authorizations/authorization-chain/src/test/java/org/apache/gravitino/authorization/chain/TestChainAuthorization.java new file mode 100644 index 00000000000..1b3f5c12d44 --- /dev/null +++ b/authorizations/authorization-chain/src/test/java/org/apache/gravitino/authorization/chain/TestChainAuthorization.java @@ -0,0 +1,110 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.gravitino.authorization.chain; + +import java.time.Instant; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import org.apache.gravitino.Catalog; +import org.apache.gravitino.Namespace; +import org.apache.gravitino.TestCatalog; +import org.apache.gravitino.connector.AuthorizationPropertiesMeta; +import org.apache.gravitino.connector.authorization.AuthorizationPlugin; +import org.apache.gravitino.connector.authorization.ranger.TestRangerAuthorizationHDFSPlugin; +import org.apache.gravitino.connector.authorization.ranger.TestRangerAuthorizationHadoopSQLPlugin; +import org.apache.gravitino.meta.AuditInfo; +import org.apache.gravitino.meta.CatalogEntity; +import org.apache.gravitino.utils.IsolatedClassLoader; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +public class TestChainAuthorization { + private static TestCatalog hiveCatalog; + + @BeforeAll + public static void setUp() { + AuditInfo auditInfo = + AuditInfo.builder().withCreator("test").withCreateTime(Instant.now()).build(); + + CatalogEntity hiveCatalogEntity = + CatalogEntity.builder() + .withId(1L) + .withName("catalog-test1") + .withNamespace(Namespace.of("default")) + .withType(Catalog.Type.RELATIONAL) + .withProvider("test") + .withAuditInfo(auditInfo) + .build(); + + Map catalogConf = new HashMap<>(); + catalogConf.put(Catalog.AUTHORIZATION_PROVIDER, "chain"); + catalogConf.put(AuthorizationPropertiesMeta.CHAIN_PLUGINS, "ranger1,mysql1"); + catalogConf.put("authorization.chain.ranger1.provider", "test_ranger"); + catalogConf.put("authorization.chain.ranger1.ranger.auth.types", "simple"); + catalogConf.put("authorization.chain.ranger1.ranger.admin.url", "http://localhost:6080"); + catalogConf.put("authorization.chain.ranger1.ranger.username", "admin"); + catalogConf.put("authorization.chain.ranger1.ranger.password", "admin"); + catalogConf.put("authorization.chain.ranger1.ranger.service.name", "hiveDev1"); + catalogConf.put("authorization.chain.mysql1.provider", "test_mysql"); + + hiveCatalog = + new TestCatalog().withCatalogConf(catalogConf).withCatalogEntity(hiveCatalogEntity); + IsolatedClassLoader isolatedClassLoader = + new IsolatedClassLoader( + Collections.emptyList(), Collections.emptyList(), Collections.emptyList()); + hiveCatalog.initAuthorizationPluginInstance(isolatedClassLoader); + } + + @Test + public void testChainAuthorization() { + AuthorizationPlugin chainAuthPlugin = hiveCatalog.getAuthorizationPlugin(); + Assertions.assertInstanceOf(ChainAuthorizationPlugin.class, chainAuthPlugin); + ChainAuthorizationPlugin chainAuthorizationPlugin = (ChainAuthorizationPlugin) chainAuthPlugin; + + chainAuthorizationPlugin + .getPlugins() + .forEach( + plugin -> { + if (plugin instanceof TestRangerAuthorizationHadoopSQLPlugin) { + Assertions.assertFalse( + ((TestRangerAuthorizationHadoopSQLPlugin) plugin).callOnCreateRole1); + } else if (plugin instanceof TestRangerAuthorizationHDFSPlugin) { + Assertions.assertFalse( + ((TestRangerAuthorizationHDFSPlugin) plugin).callOnCreateRole2); + } + }); + + chainAuthPlugin.onRoleCreated(null); + + chainAuthorizationPlugin + .getPlugins() + .forEach( + plugin -> { + if (plugin instanceof TestRangerAuthorizationHadoopSQLPlugin) { + Assertions.assertTrue( + ((TestRangerAuthorizationHadoopSQLPlugin) plugin).callOnCreateRole1); + } else if (plugin instanceof TestRangerAuthorizationHDFSPlugin) { + Assertions.assertTrue( + ((TestRangerAuthorizationHDFSPlugin) plugin).callOnCreateRole2); + } + }); + } +} diff --git a/authorizations/authorization-chain/src/test/java/org/apache/gravitino/authorization/chain/TestChainAuthorizationPropertiesMeta.java b/authorizations/authorization-chain/src/test/java/org/apache/gravitino/authorization/chain/TestChainAuthorizationPropertiesMeta.java new file mode 100644 index 00000000000..4014ee67ffa --- /dev/null +++ b/authorizations/authorization-chain/src/test/java/org/apache/gravitino/authorization/chain/TestChainAuthorizationPropertiesMeta.java @@ -0,0 +1,250 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.gravitino.authorization.chain; + +import static org.apache.gravitino.Catalog.AUTHORIZATION_PROVIDER; +import static org.apache.gravitino.catalog.hive.HiveConstants.IMPERSONATION_ENABLE; + +import com.google.common.collect.Maps; +import java.util.HashMap; +import java.util.Map; +import org.apache.gravitino.authorization.ranger.integration.test.RangerITEnv; +import org.apache.gravitino.catalog.PropertiesMetadataHelpers; +import org.apache.gravitino.catalog.hive.HiveConstants; +import org.apache.gravitino.connector.AuthorizationPropertiesMeta; +import org.apache.gravitino.connector.PropertiesMetadata; +import org.apache.gravitino.connector.authorization.AuthorizationPluginProvider; +import org.apache.gravitino.integration.test.container.RangerContainer; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class TestChainAuthorizationPropertiesMeta { + @Test + void testChainHiveCatalog() { + String pluginName = "hive1"; + Map properties = new HashMap<>(); + properties.put(HiveConstants.METASTORE_URIS, "thrift://localhost:9083"); + properties.put("gravitino.bypass.hive.metastore.client.capability.check", "true"); + properties.put(IMPERSONATION_ENABLE, "true"); + properties.put(AUTHORIZATION_PROVIDER, AuthorizationPluginProvider.Type.Chain.getName()); + properties.put(AuthorizationPropertiesMeta.CHAIN_PLUGINS, pluginName); + properties.put( + AuthorizationPropertiesMeta.generateChainPluginsKey( + pluginName, AuthorizationPropertiesMeta.getChainProviderKey()), + AuthorizationPluginProvider.Type.Chain.getName()); + properties.put( + AuthorizationPropertiesMeta.generateChainPluginsKey( + pluginName, AuthorizationPropertiesMeta.getRangerAuthTypeKey()), + RangerContainer.authType); + properties.put( + AuthorizationPropertiesMeta.generateChainPluginsKey( + pluginName, AuthorizationPropertiesMeta.getRangerAdminUrlKey()), + "http://localhost:" + RangerContainer.RANGER_SERVER_PORT); + properties.put( + AuthorizationPropertiesMeta.generateChainPluginsKey( + pluginName, AuthorizationPropertiesMeta.getRangerUsernameKey()), + RangerContainer.rangerUserName); + properties.put( + AuthorizationPropertiesMeta.generateChainPluginsKey( + pluginName, AuthorizationPropertiesMeta.getRangerPasswordKey()), + RangerContainer.rangerPassword); + properties.put( + AuthorizationPropertiesMeta.generateChainPluginsKey( + pluginName, AuthorizationPropertiesMeta.getRangerServiceNameKey()), + RangerITEnv.RANGER_HIVE_REPO_NAME); + PropertiesMetadata authorizationPropertiesMeta = new AuthorizationPropertiesMeta(); + Assertions.assertDoesNotThrow( + () -> + PropertiesMetadataHelpers.validatePropertyForCreate( + authorizationPropertiesMeta, properties)); + } + + @Test + void testWildcardPropertyChainPluginsOne() { + Map properties = Maps.newHashMap(); + properties.put(AuthorizationPropertiesMeta.CHAIN_PLUGINS, "hive1"); + properties.put("authorization.chain.hive1.provider", "ranger"); + properties.put("authorization.chain.hive1.ranger.auth.types", "simple"); + properties.put("authorization.chain.hive1.ranger.admin.url", "http://localhost:6080"); + properties.put("authorization.chain.hive1.ranger.username", "admin"); + properties.put("authorization.chain.hive1.ranger.password", "admin"); + properties.put("authorization.chain.hive1.ranger.service.name", "hiveDev"); + PropertiesMetadata authorizationPropertiesMeta = new AuthorizationPropertiesMeta(); + Assertions.assertDoesNotThrow( + () -> + PropertiesMetadataHelpers.validatePropertyForCreate( + authorizationPropertiesMeta, properties)); + } + + @Test + void testWildcardPropertyChainPluginsTwo() { + Map properties = Maps.newHashMap(); + properties.put(AuthorizationPropertiesMeta.CHAIN_PLUGINS, "hive1,hdfs1"); + properties.put("authorization.chain.hive1.provider", "ranger"); + properties.put("authorization.chain.hive1.ranger.auth.types", "simple"); + properties.put("authorization.chain.hive1.ranger.admin.url", "http://localhost:6080"); + properties.put("authorization.chain.hive1.ranger.username", "admin"); + properties.put("authorization.chain.hive1.ranger.password", "admin"); + properties.put("authorization.chain.hive1.ranger.service.name", "hiveDev"); + properties.put("authorization.chain.hdfs1.provider", "ranger"); + properties.put("authorization.chain.hdfs1.ranger.auth.types", "simple"); + properties.put("authorization.chain.hdfs1.ranger.admin.url", "http://localhost:6080"); + properties.put("authorization.chain.hdfs1.ranger.username", "admin"); + properties.put("authorization.chain.hdfs1.ranger.password", "admin"); + properties.put("authorization.chain.hdfs1.ranger.service.name", "hdfsDev"); + PropertiesMetadata authorizationPropertiesMeta = new AuthorizationPropertiesMeta(); + Assertions.assertDoesNotThrow( + () -> + PropertiesMetadataHelpers.validatePropertyForCreate( + authorizationPropertiesMeta, properties)); + } + + @Test + void testWildcardPropertyChainPluginsHasSpace() { + Map properties = Maps.newHashMap(); + properties.put(AuthorizationPropertiesMeta.CHAIN_PLUGINS, "hive1, hdfs1"); + properties.put("authorization.chain.hive1.provider", "ranger"); + properties.put("authorization.chain.hive1.ranger.auth.types", "simple"); + properties.put("authorization.chain.hive1.ranger.admin.url", "http://localhost:6080"); + properties.put("authorization.chain.hive1.ranger.username", "admin"); + properties.put("authorization.chain.hive1.ranger.password", "admin"); + properties.put("authorization.chain.hive1.ranger.service.name", "hiveDev"); + properties.put("authorization.chain.hdfs1.provider", "ranger"); + properties.put("authorization.chain.hdfs1.ranger.auth.types", "simple"); + properties.put("authorization.chain.hdfs1.ranger.admin.url", "http://localhost:6080"); + properties.put("authorization.chain.hdfs1.ranger.username", "admin"); + properties.put("authorization.chain.hdfs1.ranger.password", "admin"); + properties.put("authorization.chain.hdfs1.ranger.service.name", "hdfsDev"); + PropertiesMetadata authorizationPropertiesMeta = new AuthorizationPropertiesMeta(); + Assertions.assertDoesNotThrow( + () -> + PropertiesMetadataHelpers.validatePropertyForCreate( + authorizationPropertiesMeta, properties)); + } + + @Test + void testWildcardPropertyChainPluginsOneButHasTowPluginConfig() { + Map properties = Maps.newHashMap(); + properties.put(AuthorizationPropertiesMeta.CHAIN_PLUGINS, "hive1"); + properties.put("authorization.chain.hive1.provider", "ranger"); + properties.put("authorization.chain.hive1.ranger.auth.types", "simple"); + properties.put("authorization.chain.hive1.ranger.admin.url", "http://localhost:6080"); + properties.put("authorization.chain.hive1.ranger.username", "admin"); + properties.put("authorization.chain.hive1.ranger.password", "admin"); + properties.put("authorization.chain.hive1.ranger.service.name", "hiveDev"); + properties.put("authorization.chain.hdfs1.provider", "ranger"); + properties.put("authorization.chain.hdfs1.ranger.auth.types", "simple"); + properties.put("authorization.chain.hdfs1.ranger.admin.url", "http://localhost:6080"); + properties.put("authorization.chain.hdfs1.ranger.username", "admin"); + properties.put("authorization.chain.hdfs1.ranger.password", "admin"); + properties.put("authorization.chain.hdfs1.ranger.service.name", "hdfsDev"); + PropertiesMetadata authorizationPropertiesMeta = new AuthorizationPropertiesMeta(); + Assertions.assertThrows( + IllegalArgumentException.class, + () -> + PropertiesMetadataHelpers.validatePropertyForCreate( + authorizationPropertiesMeta, properties)); + } + + @Test + void testWildcardPropertyChainPluginsHasPoint() { + Map properties = Maps.newHashMap(); + properties.put(AuthorizationPropertiesMeta.CHAIN_PLUGINS, "plug.1, hdfs1"); + properties.put("authorization.chain.hive1.provider", "ranger"); + properties.put("authorization.chain.plug.1.ranger.auth.types", "simple"); + properties.put("authorization.chain.plug.1.ranger.admin.url", "http://localhost:6080"); + properties.put("authorization.chain.plug.1.ranger.username", "admin"); + properties.put("authorization.chain.plug.1.ranger.password", "admin"); + properties.put("authorization.chain.plug.1.ranger.service.name", "hiveDev"); + properties.put("authorization.chain.hdfs1.provider", "ranger"); + properties.put("authorization.chain.hdfs1.ranger.auth.types", "simple"); + properties.put("authorization.chain.hdfs1.ranger.admin.url", "http://localhost:6080"); + properties.put("authorization.chain.hdfs1.ranger.username", "admin"); + properties.put("authorization.chain.hdfs1.ranger.password", "admin"); + properties.put("authorization.chain.hdfs1.ranger.service.name", "hdfsDev"); + PropertiesMetadata authorizationPropertiesMeta = new AuthorizationPropertiesMeta(); + Assertions.assertThrows( + IllegalArgumentException.class, + () -> + PropertiesMetadataHelpers.validatePropertyForCreate( + authorizationPropertiesMeta, properties)); + } + + @Test + void testWildcardPropertyChainPluginErrorPluginName() { + Map properties = Maps.newHashMap(); + properties.put(AuthorizationPropertiesMeta.CHAIN_PLUGINS, "hive1,hdfs1"); + properties.put("authorization.chain.hive1.provider", "ranger"); + properties.put("authorization.chain.hive1.ranger.auth.types", "simple"); + properties.put("authorization.chain.hive1.ranger.admin.url", "http://localhost:6080"); + properties.put("authorization.chain.hive1.ranger.username", "admin"); + properties.put("authorization.chain.hive1.ranger.password", "admin"); + properties.put("authorization.chain.hive1.ranger.service.name", "hiveDev"); + properties.put("authorization.chain.hdfs1.provider", "ranger"); + properties.put("authorization.chain.hdfs1.ranger.auth.types", "simple"); + properties.put("authorization.chain.hdfs1.ranger.admin.url", "http://localhost:6080"); + properties.put("authorization.chain.hdfs1.ranger.username", "admin"); + properties.put("authorization.chain.hdfs1.ranger.password", "admin"); + properties.put("authorization.chain.plug3.ranger.service.name", "hdfsDev"); + PropertiesMetadata authorizationPropertiesMeta = new AuthorizationPropertiesMeta(); + Assertions.assertThrows( + IllegalArgumentException.class, + () -> + PropertiesMetadataHelpers.validatePropertyForCreate( + authorizationPropertiesMeta, properties)); + } + + @Test + void testWildcardPropertyChainPluginDuplicationPluginName() { + Map properties = Maps.newHashMap(); + properties.put(AuthorizationPropertiesMeta.CHAIN_PLUGINS, "hive1,hive1,hdfs1"); + properties.put("authorization.chain.hive1.provider", "ranger"); + properties.put("authorization.chain.hive1.ranger.auth.types", "simple"); + properties.put("authorization.chain.hive1.ranger.admin.url", "http://localhost:6080"); + properties.put("authorization.chain.hive1.ranger.username", "admin"); + properties.put("authorization.chain.hive1.ranger.password", "admin"); + properties.put("authorization.chain.hive1.ranger.service.name", "hiveDev"); + properties.put("authorization.chain.hdfs1.provider", "ranger"); + properties.put("authorization.chain.hdfs1.ranger.auth.types", "simple"); + properties.put("authorization.chain.hdfs1.ranger.admin.url", "http://localhost:6080"); + properties.put("authorization.chain.hdfs1.ranger.username", "admin"); + properties.put("authorization.chain.hdfs1.ranger.password", "admin"); + properties.put("authorization.chain.hdfs1.ranger.service.name", "hdfsDev"); + PropertiesMetadata authorizationPropertiesMeta = new AuthorizationPropertiesMeta(); + Assertions.assertThrows( + IllegalArgumentException.class, + () -> + PropertiesMetadataHelpers.validatePropertyForCreate( + authorizationPropertiesMeta, properties)); + } + + @Test + void testWildcardPropertyChainPluginErrorPropertyKey() { + Map properties = Maps.newHashMap(); + properties.put(AuthorizationPropertiesMeta.CHAIN_PLUGINS, "hive1"); + properties.put("authorization.chain.hive1.provider", "ranger"); + properties.put("authorization.chain.hive1.ranger-error.auth.types", "simple"); + PropertiesMetadata authorizationPropertiesMeta = new AuthorizationPropertiesMeta(); + Assertions.assertThrows( + IllegalArgumentException.class, + () -> + PropertiesMetadataHelpers.validatePropertyForCreate( + authorizationPropertiesMeta, properties)); + } +} diff --git a/authorizations/authorization-chain/src/test/java/org/apache/gravitino/authorization/chain/integration/test/TestChainAuthorizationIT.java b/authorizations/authorization-chain/src/test/java/org/apache/gravitino/authorization/chain/integration/test/TestChainAuthorizationIT.java new file mode 100644 index 00000000000..8c31086bea7 --- /dev/null +++ b/authorizations/authorization-chain/src/test/java/org/apache/gravitino/authorization/chain/integration/test/TestChainAuthorizationIT.java @@ -0,0 +1,124 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.gravitino.authorization.chain.integration.test; + +import static org.apache.gravitino.Catalog.AUTHORIZATION_PROVIDER; +import static org.apache.gravitino.catalog.hive.HiveConstants.IMPERSONATION_ENABLE; +import static org.apache.gravitino.connector.AuthorizationPropertiesMeta.getRangerAdminUrlKey; +import static org.apache.gravitino.connector.AuthorizationPropertiesMeta.getRangerAuthTypeKey; +import static org.apache.gravitino.connector.AuthorizationPropertiesMeta.getRangerPasswordKey; +import static org.apache.gravitino.connector.AuthorizationPropertiesMeta.getRangerServiceNameKey; +import static org.apache.gravitino.connector.AuthorizationPropertiesMeta.getRangerUsernameKey; + +import java.util.HashMap; +import java.util.Map; +import org.apache.gravitino.Catalog; +import org.apache.gravitino.CatalogProvider; +import org.apache.gravitino.authorization.ranger.integration.test.RangerHiveE2EIT; +import org.apache.gravitino.authorization.ranger.integration.test.RangerITEnv; +import org.apache.gravitino.catalog.hive.HiveConstants; +import org.apache.gravitino.connector.AuthorizationPropertiesMeta; +import org.apache.gravitino.connector.authorization.AuthorizationPluginProvider; +import org.apache.gravitino.integration.test.container.RangerContainer; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class TestChainAuthorizationIT extends RangerHiveE2EIT { + private static final Logger LOG = LoggerFactory.getLogger(TestChainAuthorizationIT.class); + + @BeforeAll + public void startIntegrationTest() throws Exception { + super.startIntegrationTest(); + } + + @Override + public void createCatalog() { + String pluginName = "hive1"; + Map catalogConf = new HashMap<>(); + catalogConf.put(HiveConstants.METASTORE_URIS, HIVE_METASTORE_URIS); + catalogConf.put(IMPERSONATION_ENABLE, "true"); + catalogConf.put(AUTHORIZATION_PROVIDER, AuthorizationPluginProvider.Type.Chain.getName()); + catalogConf.put(AuthorizationPropertiesMeta.CHAIN_PLUGINS, pluginName); + catalogConf.put( + AuthorizationPropertiesMeta.generateChainPluginsKey( + pluginName, AuthorizationPropertiesMeta.getChainProviderKey()), + AuthorizationPluginProvider.Type.Ranger.getName()); + catalogConf.put( + AuthorizationPropertiesMeta.generateChainPluginsKey(pluginName, getRangerAuthTypeKey()), + RangerContainer.authType); + catalogConf.put( + AuthorizationPropertiesMeta.generateChainPluginsKey(pluginName, getRangerAdminUrlKey()), + RANGER_ADMIN_URL); + catalogConf.put( + AuthorizationPropertiesMeta.generateChainPluginsKey(pluginName, getRangerUsernameKey()), + RangerContainer.rangerUserName); + catalogConf.put( + AuthorizationPropertiesMeta.generateChainPluginsKey(pluginName, getRangerPasswordKey()), + RangerContainer.rangerPassword); + catalogConf.put( + AuthorizationPropertiesMeta.generateChainPluginsKey(pluginName, getRangerServiceNameKey()), + RangerITEnv.RANGER_HIVE_REPO_NAME); + + metalake.createCatalog( + catalogName, + Catalog.Type.RELATIONAL, + CatalogProvider.CatalogName.HIVE.getName(), + "comment", + catalogConf); + catalog = metalake.loadCatalog(catalogName); + LOG.info("Catalog created: {}", catalog); + } + + @Test + public void testChainAuthorization() { + LOG.info(""); + } + + @Override + protected void checkTableAllPrivilegesExceptForCreating() {} + + @Override + protected void checkUpdateSQLWithReadWritePrivileges() {} + + @Override + protected void checkUpdateSQLWithReadPrivileges() {} + + @Override + protected void checkUpdateSQLWithWritePrivileges() {} + + @Override + protected void checkDeleteSQLWithReadWritePrivileges() {} + + @Override + protected void checkDeleteSQLWithReadPrivileges() {} + + @Override + protected void checkDeleteSQLWithWritePrivileges() {} + + @Override + protected void useCatalog() throws InterruptedException {} + + @Override + protected void checkWithoutPrivileges() {} + + @Override + protected void testAlterTable() {} +} diff --git a/authorizations/authorization-chain/src/test/resources/log4j2.properties b/authorizations/authorization-chain/src/test/resources/log4j2.properties new file mode 100644 index 00000000000..2a46c57ec2f --- /dev/null +++ b/authorizations/authorization-chain/src/test/resources/log4j2.properties @@ -0,0 +1,73 @@ +# +# 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. +# + +# Set to debug or trace if log4j initialization is failing +status = info + +# Name of the configuration +name = ConsoleLogConfig + +# Console appender configuration +appender.console.type = Console +appender.console.name = consoleLogger +appender.console.layout.type = PatternLayout +appender.console.layout.pattern = %d{yyyy-MM-dd HH:mm:ss} %-5p [%t] %c{1}:%L - %m%n + +# Log files location +property.logPath = ${sys:gravitino.log.path:-build/authorization-chain-integration-test.log} + +# File appender configuration +appender.file.type = File +appender.file.name = fileLogger +appender.file.fileName = ${logPath} +appender.file.layout.type = PatternLayout +appender.file.layout.pattern = %d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5p %c - %m%n + +# Root logger level +rootLogger.level = info + +# Root logger referring to console and file appenders +rootLogger.appenderRef.stdout.ref = consoleLogger +rootLogger.appenderRef.file.ref = fileLogger + +# File appender configuration for testcontainers +appender.testcontainersFile.type = File +appender.testcontainersFile.name = testcontainersLogger +appender.testcontainersFile.fileName = build/testcontainers.log +appender.testcontainersFile.layout.type = PatternLayout +appender.testcontainersFile.layout.pattern = %d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5p %c - %m%n + +# Logger for testcontainers +logger.testcontainers.name = org.testcontainers +logger.testcontainers.level = debug +logger.testcontainers.additivity = false +logger.testcontainers.appenderRef.file.ref = testcontainersLogger + +logger.tc.name = tc +logger.tc.level = debug +logger.tc.additivity = false +logger.tc.appenderRef.file.ref = testcontainersLogger + +logger.docker.name = com.github.dockerjava +logger.docker.level = warn +logger.docker.additivity = false +logger.docker.appenderRef.file.ref = testcontainersLogger + +logger.http.name = com.github.dockerjava.zerodep.shaded.org.apache.hc.client5.http.wire +logger.http.level = off diff --git a/authorizations/authorization-chain/src/test/resources/ranger-spark-security.xml.template b/authorizations/authorization-chain/src/test/resources/ranger-spark-security.xml.template new file mode 100644 index 00000000000..eb7f2b5e811 --- /dev/null +++ b/authorizations/authorization-chain/src/test/resources/ranger-spark-security.xml.template @@ -0,0 +1,45 @@ + + + + ranger.plugin.spark.policy.rest.url + __REPLACE__RANGER_ADMIN_URL + + + + ranger.plugin.spark.service.name + __REPLACE__RANGER_HIVE_REPO_NAME + + + + ranger.plugin.spark.policy.cache.dir + /tmp/policycache + + + + ranger.plugin.spark.policy.pollIntervalMs + 500 + + + + ranger.plugin.spark.policy.source.impl + org.apache.ranger.admin.client.RangerAdminRESTClient + + + \ No newline at end of file diff --git a/authorizations/authorization-ranger/build.gradle.kts b/authorizations/authorization-ranger/build.gradle.kts index f83aee72c54..7939db7eb4d 100644 --- a/authorizations/authorization-ranger/build.gradle.kts +++ b/authorizations/authorization-ranger/build.gradle.kts @@ -143,3 +143,16 @@ tasks.test { dependsOn(tasks.jar) } } + +val testJar by tasks.registering(Jar::class) { + archiveClassifier.set("tests") + from(sourceSets["test"].output) +} + +configurations { + create("testArtifacts") +} + +artifacts { + add("testArtifacts", testJar) +} diff --git a/authorizations/authorization-ranger/src/main/java/org/apache/gravitino/authorization/ranger/RangerAuthorization.java b/authorizations/authorization-ranger/src/main/java/org/apache/gravitino/authorization/ranger/RangerAuthorization.java index 459b6b04720..2e68e3e2d08 100644 --- a/authorizations/authorization-ranger/src/main/java/org/apache/gravitino/authorization/ranger/RangerAuthorization.java +++ b/authorizations/authorization-ranger/src/main/java/org/apache/gravitino/authorization/ranger/RangerAuthorization.java @@ -20,13 +20,14 @@ import java.util.Map; import org.apache.gravitino.connector.authorization.AuthorizationPlugin; +import org.apache.gravitino.connector.authorization.AuthorizationPluginProvider; import org.apache.gravitino.connector.authorization.BaseAuthorization; /** Implementation of a Ranger authorization in Gravitino. */ public class RangerAuthorization extends BaseAuthorization { @Override public String shortName() { - return "ranger"; + return AuthorizationPluginProvider.Type.Ranger.getName(); } @Override @@ -35,7 +36,7 @@ protected AuthorizationPlugin newPlugin(String catalogProvider, Map config) { - super(config); + private RangerAuthorizationHadoopSQLPlugin(String catalogProvider, Map config) { + super(catalogProvider, config); } public static synchronized RangerAuthorizationHadoopSQLPlugin getInstance( - Map config) { + String catalogProvider, Map config) { if (instance == null) { synchronized (RangerAuthorizationHadoopSQLPlugin.class) { if (instance == null) { - instance = new RangerAuthorizationHadoopSQLPlugin(config); + instance = new RangerAuthorizationHadoopSQLPlugin(catalogProvider, config); } } } @@ -229,7 +229,7 @@ public List translatePrivilege(SecurableObject sec .forEach( rangerPrivilege -> rangerPrivileges.add( - new RangerPrivileges.RangerHivePrivilegeImpl( + new RangerPrivileges.RangerHadoopSQLPrivilegeImpl( rangerPrivilege, gravitinoPrivilege.condition()))); switch (gravitinoPrivilege.name()) { diff --git a/authorizations/authorization-ranger/src/main/java/org/apache/gravitino/authorization/ranger/RangerAuthorizationPlugin.java b/authorizations/authorization-ranger/src/main/java/org/apache/gravitino/authorization/ranger/RangerAuthorizationPlugin.java index b522691cbaa..293dfc47a22 100644 --- a/authorizations/authorization-ranger/src/main/java/org/apache/gravitino/authorization/ranger/RangerAuthorizationPlugin.java +++ b/authorizations/authorization-ranger/src/main/java/org/apache/gravitino/authorization/ranger/RangerAuthorizationPlugin.java @@ -36,10 +36,6 @@ import java.util.stream.Collectors; import java.util.stream.Stream; import org.apache.gravitino.MetadataObject; -import org.apache.gravitino.authorization.AuthorizationMetadataObject; -import org.apache.gravitino.authorization.AuthorizationPrivilege; -import org.apache.gravitino.authorization.AuthorizationPrivilegesMappingProvider; -import org.apache.gravitino.authorization.AuthorizationSecurableObject; import org.apache.gravitino.authorization.Group; import org.apache.gravitino.authorization.MetadataObjectChange; import org.apache.gravitino.authorization.Owner; @@ -53,7 +49,12 @@ import org.apache.gravitino.authorization.ranger.reference.VXUser; import org.apache.gravitino.authorization.ranger.reference.VXUserList; import org.apache.gravitino.connector.AuthorizationPropertiesMeta; +import org.apache.gravitino.connector.authorization.AuthorizationMetadataObject; import org.apache.gravitino.connector.authorization.AuthorizationPlugin; +import org.apache.gravitino.connector.authorization.AuthorizationPluginProvider; +import org.apache.gravitino.connector.authorization.AuthorizationPrivilege; +import org.apache.gravitino.connector.authorization.AuthorizationPrivilegesMappingProvider; +import org.apache.gravitino.connector.authorization.AuthorizationSecurableObject; import org.apache.gravitino.exceptions.AuthorizationPluginException; import org.apache.gravitino.meta.AuditInfo; import org.apache.gravitino.meta.GroupEntity; @@ -84,8 +85,10 @@ public abstract class RangerAuthorizationPlugin protected final RangerClientExtension rangerClient; private final RangerHelper rangerHelper; @VisibleForTesting public final String rangerAdminName; + private final String catalogProviderName; - protected RangerAuthorizationPlugin(Map config) { + protected RangerAuthorizationPlugin(String catalogProvider, Map config) { + this.catalogProviderName = catalogProvider; String rangerUrl = config.get(AuthorizationPropertiesMeta.RANGER_ADMIN_URL); String authType = config.get(AuthorizationPropertiesMeta.RANGER_AUTH_TYPE); rangerAdminName = config.get(AuthorizationPropertiesMeta.RANGER_USERNAME); @@ -108,6 +111,16 @@ protected RangerAuthorizationPlugin(Map config) { policyResourceDefinesRule()); } + @Override + public String catalogProviderName() { + return catalogProviderName; + } + + @Override + public String pluginProviderName() { + return AuthorizationPluginProvider.Type.Ranger.getName(); + } + /** * Set the Ranger policy resource defines rule. * @@ -244,7 +257,8 @@ public Boolean onRoleUpdated(Role role, RoleChange... changes) } @Override - public Boolean onMetadataUpdated(MetadataObjectChange... changes) throws RuntimeException { + public Boolean onMetadataUpdated(MetadataObjectChange... changes) + throws AuthorizationPluginException { for (MetadataObjectChange change : changes) { if (change instanceof MetadataObjectChange.RenameMetadataObject) { MetadataObject metadataObject = diff --git a/authorizations/authorization-ranger/src/main/java/org/apache/gravitino/authorization/ranger/RangerHelper.java b/authorizations/authorization-ranger/src/main/java/org/apache/gravitino/authorization/ranger/RangerHelper.java index d955f765637..0a37a1c2b10 100644 --- a/authorizations/authorization-ranger/src/main/java/org/apache/gravitino/authorization/ranger/RangerHelper.java +++ b/authorizations/authorization-ranger/src/main/java/org/apache/gravitino/authorization/ranger/RangerHelper.java @@ -26,11 +26,11 @@ import java.util.Set; import java.util.stream.Collectors; import org.apache.commons.lang.StringUtils; -import org.apache.gravitino.authorization.AuthorizationMetadataObject; -import org.apache.gravitino.authorization.AuthorizationPrivilege; -import org.apache.gravitino.authorization.AuthorizationSecurableObject; import org.apache.gravitino.authorization.Owner; import org.apache.gravitino.authorization.Privilege; +import org.apache.gravitino.connector.authorization.AuthorizationMetadataObject; +import org.apache.gravitino.connector.authorization.AuthorizationPrivilege; +import org.apache.gravitino.connector.authorization.AuthorizationSecurableObject; import org.apache.gravitino.exceptions.AuthorizationPluginException; import org.apache.ranger.RangerClient; import org.apache.ranger.RangerServiceException; diff --git a/authorizations/authorization-ranger/src/main/java/org/apache/gravitino/authorization/ranger/RangerMetadataObject.java b/authorizations/authorization-ranger/src/main/java/org/apache/gravitino/authorization/ranger/RangerMetadataObject.java index b9354ee46f4..8785003028b 100644 --- a/authorizations/authorization-ranger/src/main/java/org/apache/gravitino/authorization/ranger/RangerMetadataObject.java +++ b/authorizations/authorization-ranger/src/main/java/org/apache/gravitino/authorization/ranger/RangerMetadataObject.java @@ -21,7 +21,7 @@ import com.google.common.base.Preconditions; import java.util.List; import org.apache.gravitino.MetadataObject; -import org.apache.gravitino.authorization.AuthorizationMetadataObject; +import org.apache.gravitino.connector.authorization.AuthorizationMetadataObject; /** The helper class for {@link AuthorizationMetadataObject}. */ public class RangerMetadataObject implements AuthorizationMetadataObject { diff --git a/authorizations/authorization-ranger/src/main/java/org/apache/gravitino/authorization/ranger/RangerPrivileges.java b/authorizations/authorization-ranger/src/main/java/org/apache/gravitino/authorization/ranger/RangerPrivileges.java index bbae16a6ba2..abe29298187 100644 --- a/authorizations/authorization-ranger/src/main/java/org/apache/gravitino/authorization/ranger/RangerPrivileges.java +++ b/authorizations/authorization-ranger/src/main/java/org/apache/gravitino/authorization/ranger/RangerPrivileges.java @@ -21,8 +21,8 @@ import com.google.common.base.Preconditions; import com.google.common.collect.Lists; import java.util.List; -import org.apache.gravitino.authorization.AuthorizationPrivilege; import org.apache.gravitino.authorization.Privilege; +import org.apache.gravitino.connector.authorization.AuthorizationPrivilege; public class RangerPrivileges { /** Ranger Hive privileges enumeration. */ @@ -62,11 +62,11 @@ public boolean equalsTo(String value) { } } - public static class RangerHivePrivilegeImpl implements AuthorizationPrivilege { + public static class RangerHadoopSQLPrivilegeImpl implements AuthorizationPrivilege { private AuthorizationPrivilege rangerHivePrivilege; private Privilege.Condition condition; - public RangerHivePrivilegeImpl( + public RangerHadoopSQLPrivilegeImpl( AuthorizationPrivilege rangerHivePrivilege, Privilege.Condition condition) { this.rangerHivePrivilege = rangerHivePrivilege; this.condition = condition; @@ -117,8 +117,7 @@ public boolean equalsTo(String value) { } static List>> allRangerPrivileges = - Lists.newArrayList( - RangerHadoopSQLPrivilege.class, RangerPrivileges.RangerHdfsPrivilege.class); + Lists.newArrayList(RangerHadoopSQLPrivilege.class, RangerHdfsPrivilege.class); public static AuthorizationPrivilege valueOf(String name) { Preconditions.checkArgument(name != null, "Privilege name string cannot be null!"); diff --git a/authorizations/authorization-ranger/src/main/java/org/apache/gravitino/authorization/ranger/RangerSecurableObject.java b/authorizations/authorization-ranger/src/main/java/org/apache/gravitino/authorization/ranger/RangerSecurableObject.java index 3a6294f822c..e026f53ee5e 100644 --- a/authorizations/authorization-ranger/src/main/java/org/apache/gravitino/authorization/ranger/RangerSecurableObject.java +++ b/authorizations/authorization-ranger/src/main/java/org/apache/gravitino/authorization/ranger/RangerSecurableObject.java @@ -22,9 +22,9 @@ import com.google.common.collect.Sets; import java.util.List; import java.util.Set; -import org.apache.gravitino.authorization.AuthorizationMetadataObject; -import org.apache.gravitino.authorization.AuthorizationPrivilege; -import org.apache.gravitino.authorization.AuthorizationSecurableObject; +import org.apache.gravitino.connector.authorization.AuthorizationMetadataObject; +import org.apache.gravitino.connector.authorization.AuthorizationPrivilege; +import org.apache.gravitino.connector.authorization.AuthorizationSecurableObject; /** The helper class for {@link RangerSecurableObject}. */ public class RangerSecurableObject extends RangerMetadataObject diff --git a/authorizations/authorization-ranger/src/test/java/org/apache/gravitino/authorization/ranger/integration/test/RangerAuthorizationPluginIT.java b/authorizations/authorization-ranger/src/test/java/org/apache/gravitino/authorization/ranger/integration/test/RangerAuthorizationPluginIT.java index 50ca331d221..1b90877ea59 100644 --- a/authorizations/authorization-ranger/src/test/java/org/apache/gravitino/authorization/ranger/integration/test/RangerAuthorizationPluginIT.java +++ b/authorizations/authorization-ranger/src/test/java/org/apache/gravitino/authorization/ranger/integration/test/RangerAuthorizationPluginIT.java @@ -24,8 +24,6 @@ import java.util.List; import org.apache.gravitino.MetadataObject; import org.apache.gravitino.MetadataObjects; -import org.apache.gravitino.authorization.AuthorizationMetadataObject; -import org.apache.gravitino.authorization.AuthorizationSecurableObject; import org.apache.gravitino.authorization.Privilege; import org.apache.gravitino.authorization.Privileges; import org.apache.gravitino.authorization.SecurableObject; @@ -33,6 +31,8 @@ import org.apache.gravitino.authorization.ranger.RangerAuthorizationPlugin; import org.apache.gravitino.authorization.ranger.RangerHelper; import org.apache.gravitino.authorization.ranger.RangerMetadataObject; +import org.apache.gravitino.connector.authorization.AuthorizationMetadataObject; +import org.apache.gravitino.connector.authorization.AuthorizationSecurableObject; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Tag; diff --git a/authorizations/authorization-ranger/src/test/java/org/apache/gravitino/authorization/ranger/integration/test/RangerBaseE2EIT.java b/authorizations/authorization-ranger/src/test/java/org/apache/gravitino/authorization/ranger/integration/test/RangerBaseE2EIT.java index 95dc4f93636..dbd2df49e15 100644 --- a/authorizations/authorization-ranger/src/test/java/org/apache/gravitino/authorization/ranger/integration/test/RangerBaseE2EIT.java +++ b/authorizations/authorization-ranger/src/test/java/org/apache/gravitino/authorization/ranger/integration/test/RangerBaseE2EIT.java @@ -169,6 +169,8 @@ protected void createMetalake() { metalake = loadMetalake; } + public abstract void createCatalog(); + protected static void waitForUpdatingPolicies() throws InterruptedException { // After Ranger authorization, Must wait a period of time for the Ranger Spark plugin to update // the policy Sleep time must be greater than the policy update interval diff --git a/authorizations/authorization-ranger/src/test/java/org/apache/gravitino/authorization/ranger/integration/test/RangerHiveE2EIT.java b/authorizations/authorization-ranger/src/test/java/org/apache/gravitino/authorization/ranger/integration/test/RangerHiveE2EIT.java index cb41e79216c..fb1949ddb21 100644 --- a/authorizations/authorization-ranger/src/test/java/org/apache/gravitino/authorization/ranger/integration/test/RangerHiveE2EIT.java +++ b/authorizations/authorization-ranger/src/test/java/org/apache/gravitino/authorization/ranger/integration/test/RangerHiveE2EIT.java @@ -170,7 +170,8 @@ protected void testAlterTable() { sparkSession.sql(SQL_ALTER_TABLE); } - private static void createCatalog() { + @Override + public void createCatalog() { Map properties = ImmutableMap.of( HiveConstants.METASTORE_URIS, diff --git a/authorizations/authorization-ranger/src/test/java/org/apache/gravitino/authorization/ranger/integration/test/RangerHiveIT.java b/authorizations/authorization-ranger/src/test/java/org/apache/gravitino/authorization/ranger/integration/test/RangerHiveIT.java index 243491867b8..c103e9a2dbb 100644 --- a/authorizations/authorization-ranger/src/test/java/org/apache/gravitino/authorization/ranger/integration/test/RangerHiveIT.java +++ b/authorizations/authorization-ranger/src/test/java/org/apache/gravitino/authorization/ranger/integration/test/RangerHiveIT.java @@ -38,7 +38,6 @@ import java.util.stream.Collectors; import org.apache.gravitino.MetadataObject; import org.apache.gravitino.MetadataObjects; -import org.apache.gravitino.authorization.AuthorizationSecurableObject; import org.apache.gravitino.authorization.MetadataObjectChange; import org.apache.gravitino.authorization.Owner; import org.apache.gravitino.authorization.Privilege; @@ -53,6 +52,7 @@ import org.apache.gravitino.authorization.ranger.RangerPrivileges; import org.apache.gravitino.authorization.ranger.RangerSecurableObject; import org.apache.gravitino.authorization.ranger.reference.RangerDefines; +import org.apache.gravitino.connector.authorization.AuthorizationSecurableObject; import org.apache.gravitino.integration.test.util.GravitinoITUtils; import org.apache.gravitino.meta.AuditInfo; import org.apache.gravitino.meta.GroupEntity; @@ -345,7 +345,7 @@ public void testFindManagedPolicy() { ImmutableList.of(String.format("%s3", dbName), "tab1"), RangerMetadataObject.Type.TABLE, ImmutableSet.of( - new RangerPrivileges.RangerHivePrivilegeImpl( + new RangerPrivileges.RangerHadoopSQLPrivilegeImpl( RangerPrivileges.RangerHadoopSQLPrivilege.ALL, Privilege.Condition.ALLOW))); Assertions.assertNull(rangerHelper.findManagedPolicy(rangerSecurableObject)); diff --git a/authorizations/authorization-ranger/src/test/java/org/apache/gravitino/authorization/ranger/integration/test/RangerITEnv.java b/authorizations/authorization-ranger/src/test/java/org/apache/gravitino/authorization/ranger/integration/test/RangerITEnv.java index 4f4a5ff911c..a8a8e4e5d69 100644 --- a/authorizations/authorization-ranger/src/test/java/org/apache/gravitino/authorization/ranger/integration/test/RangerITEnv.java +++ b/authorizations/authorization-ranger/src/test/java/org/apache/gravitino/authorization/ranger/integration/test/RangerITEnv.java @@ -27,7 +27,6 @@ import java.util.Map; import java.util.concurrent.atomic.AtomicReference; import java.util.stream.Collectors; -import org.apache.gravitino.authorization.AuthorizationSecurableObject; import org.apache.gravitino.authorization.Privilege; import org.apache.gravitino.authorization.Role; import org.apache.gravitino.authorization.ranger.RangerAuthorizationHadoopSQLPlugin; @@ -36,6 +35,7 @@ import org.apache.gravitino.authorization.ranger.RangerPrivileges; import org.apache.gravitino.authorization.ranger.reference.RangerDefines; import org.apache.gravitino.connector.AuthorizationPropertiesMeta; +import org.apache.gravitino.connector.authorization.AuthorizationSecurableObject; import org.apache.gravitino.integration.test.container.ContainerSuite; import org.apache.gravitino.integration.test.container.HiveContainer; import org.apache.gravitino.integration.test.container.RangerContainer; @@ -55,12 +55,12 @@ public class RangerITEnv { private static final Logger LOG = LoggerFactory.getLogger(RangerITEnv.class); protected static final String RANGER_TRINO_REPO_NAME = "trinoDev"; private static final String RANGER_TRINO_TYPE = "trino"; - protected static final String RANGER_HIVE_REPO_NAME = "hiveDev"; + public static final String RANGER_HIVE_REPO_NAME = "hiveDev"; private static final String RANGER_HIVE_TYPE = "hive"; protected static final String RANGER_HDFS_REPO_NAME = "hdfsDev"; private static final String RANGER_HDFS_TYPE = "hdfs"; protected static RangerClient rangerClient; - protected static final String HADOOP_USER_NAME = "gravitino"; + public static final String HADOOP_USER_NAME = "gravitino"; private static volatile boolean initRangerService = false; private static final ContainerSuite containerSuite = ContainerSuite.getInstance(); @@ -89,6 +89,7 @@ public static void init() { rangerAuthHivePlugin = RangerAuthorizationHadoopSQLPlugin.getInstance( + "hive", ImmutableMap.of( AuthorizationPropertiesMeta.RANGER_ADMIN_URL, String.format( @@ -131,7 +132,7 @@ public static void cleanup() { } } - static void startHiveRangerContainer() { + public static void startHiveRangerContainer() { containerSuite.startHiveRangerContainer( new HashMap<>( ImmutableMap.of( diff --git a/authorizations/authorization-ranger/src/test/java/org/apache/gravitino/authorization/ranger/integration/test/RangerIcebergE2EIT.java b/authorizations/authorization-ranger/src/test/java/org/apache/gravitino/authorization/ranger/integration/test/RangerIcebergE2EIT.java index 7b45eda7a6e..54241fead3a 100644 --- a/authorizations/authorization-ranger/src/test/java/org/apache/gravitino/authorization/ranger/integration/test/RangerIcebergE2EIT.java +++ b/authorizations/authorization-ranger/src/test/java/org/apache/gravitino/authorization/ranger/integration/test/RangerIcebergE2EIT.java @@ -167,7 +167,8 @@ protected void testAlterTable() { sparkSession.sql(SQL_ALTER_TABLE_BACK); } - private static void createCatalog() { + @Override + public void createCatalog() { Map properties = ImmutableMap.of( IcebergConstants.URI, diff --git a/authorizations/authorization-ranger/src/test/java/org/apache/gravitino/authorization/ranger/integration/test/RangerPaimonE2EIT.java b/authorizations/authorization-ranger/src/test/java/org/apache/gravitino/authorization/ranger/integration/test/RangerPaimonE2EIT.java index 7cb600b9d8c..6cb91f4205a 100644 --- a/authorizations/authorization-ranger/src/test/java/org/apache/gravitino/authorization/ranger/integration/test/RangerPaimonE2EIT.java +++ b/authorizations/authorization-ranger/src/test/java/org/apache/gravitino/authorization/ranger/integration/test/RangerPaimonE2EIT.java @@ -183,7 +183,8 @@ protected void testAlterTable() { sparkSession.sql(SQL_ALTER_TABLE_BACK); } - private static void createCatalog() { + @Override + public void createCatalog() { Map properties = ImmutableMap.of( "uri", diff --git a/catalogs/catalog-hadoop/src/main/java/org/apache/gravitino/catalog/hadoop/HadoopCatalog.java b/catalogs/catalog-hadoop/src/main/java/org/apache/gravitino/catalog/hadoop/HadoopCatalog.java index 193219ab8d2..32c505459d0 100644 --- a/catalogs/catalog-hadoop/src/main/java/org/apache/gravitino/catalog/hadoop/HadoopCatalog.java +++ b/catalogs/catalog-hadoop/src/main/java/org/apache/gravitino/catalog/hadoop/HadoopCatalog.java @@ -42,7 +42,7 @@ public class HadoopCatalog extends BaseCatalog { @Override public String shortName() { - return "hadoop"; + return CatalogName.HADOOP.getName(); } @Override diff --git a/catalogs/catalog-hive/src/main/java/org/apache/gravitino/catalog/hive/HiveCatalog.java b/catalogs/catalog-hive/src/main/java/org/apache/gravitino/catalog/hive/HiveCatalog.java index 717694e1850..5d96018e13b 100644 --- a/catalogs/catalog-hive/src/main/java/org/apache/gravitino/catalog/hive/HiveCatalog.java +++ b/catalogs/catalog-hive/src/main/java/org/apache/gravitino/catalog/hive/HiveCatalog.java @@ -45,7 +45,7 @@ public class HiveCatalog extends BaseCatalog { */ @Override public String shortName() { - return "hive"; + return CatalogName.HIVE.getName(); } /** diff --git a/catalogs/catalog-hive/src/main/java/org/apache/gravitino/catalog/hive/HiveCatalogPropertiesMeta.java b/catalogs/catalog-hive/src/main/java/org/apache/gravitino/catalog/hive/HiveCatalogPropertiesMeta.java index dc532e6014d..4af036f9b4a 100644 --- a/catalogs/catalog-hive/src/main/java/org/apache/gravitino/catalog/hive/HiveCatalogPropertiesMeta.java +++ b/catalogs/catalog-hive/src/main/java/org/apache/gravitino/catalog/hive/HiveCatalogPropertiesMeta.java @@ -110,7 +110,7 @@ public class HiveCatalogPropertiesMeta extends BaseCatalogPropertiesMetadata { DEFAULT_LIST_ALL_TABLES, false /* hidden */, false /* reserved */)) - .putAll(AuthorizationPropertiesMeta.RANGER_AUTHORIZATION_PROPERTY_ENTRIES) + .putAll(AuthorizationPropertiesMeta.AUTHORIZATION_PROPERTY_ENTRIES) .putAll(CLIENT_PROPERTIES_METADATA.propertyEntries()) .build(); diff --git a/catalogs/catalog-jdbc-doris/src/main/java/org/apache/gravitino/catalog/doris/DorisCatalog.java b/catalogs/catalog-jdbc-doris/src/main/java/org/apache/gravitino/catalog/doris/DorisCatalog.java index 0a24908d538..1a6bf5059e4 100644 --- a/catalogs/catalog-jdbc-doris/src/main/java/org/apache/gravitino/catalog/doris/DorisCatalog.java +++ b/catalogs/catalog-jdbc-doris/src/main/java/org/apache/gravitino/catalog/doris/DorisCatalog.java @@ -43,7 +43,7 @@ public class DorisCatalog extends JdbcCatalog { @Override public String shortName() { - return "jdbc-doris"; + return CatalogName.JDBC_DORIS.name(); } @Override diff --git a/catalogs/catalog-jdbc-mysql/src/main/java/org/apache/gravitino/catalog/mysql/MysqlCatalog.java b/catalogs/catalog-jdbc-mysql/src/main/java/org/apache/gravitino/catalog/mysql/MysqlCatalog.java index 1cd0667adf7..041de0a5ba0 100644 --- a/catalogs/catalog-jdbc-mysql/src/main/java/org/apache/gravitino/catalog/mysql/MysqlCatalog.java +++ b/catalogs/catalog-jdbc-mysql/src/main/java/org/apache/gravitino/catalog/mysql/MysqlCatalog.java @@ -41,7 +41,7 @@ public class MysqlCatalog extends JdbcCatalog { @Override public String shortName() { - return "jdbc-mysql"; + return CatalogName.JDBC_MYSQL.name(); } @Override diff --git a/catalogs/catalog-jdbc-oceanbase/src/main/java/org/apache/gravitino/catalog/oceanbase/OceanBaseCatalog.java b/catalogs/catalog-jdbc-oceanbase/src/main/java/org/apache/gravitino/catalog/oceanbase/OceanBaseCatalog.java index 12319264416..dbe874746cd 100644 --- a/catalogs/catalog-jdbc-oceanbase/src/main/java/org/apache/gravitino/catalog/oceanbase/OceanBaseCatalog.java +++ b/catalogs/catalog-jdbc-oceanbase/src/main/java/org/apache/gravitino/catalog/oceanbase/OceanBaseCatalog.java @@ -37,7 +37,7 @@ public class OceanBaseCatalog extends JdbcCatalog { @Override public String shortName() { - return "jdbc-oceanbase"; + return CatalogName.JDBC_OCEANBASE.name(); } @Override diff --git a/catalogs/catalog-jdbc-postgresql/src/main/java/org/apache/gravitino/catalog/postgresql/PostgreSqlCatalog.java b/catalogs/catalog-jdbc-postgresql/src/main/java/org/apache/gravitino/catalog/postgresql/PostgreSqlCatalog.java index e7d9b12140e..4e459cb38d7 100644 --- a/catalogs/catalog-jdbc-postgresql/src/main/java/org/apache/gravitino/catalog/postgresql/PostgreSqlCatalog.java +++ b/catalogs/catalog-jdbc-postgresql/src/main/java/org/apache/gravitino/catalog/postgresql/PostgreSqlCatalog.java @@ -37,7 +37,7 @@ public class PostgreSqlCatalog extends JdbcCatalog { @Override public String shortName() { - return "jdbc-postgresql"; + return CatalogName.JDBC_POSTGRESQL.name(); } @Override diff --git a/catalogs/catalog-kafka/src/main/java/org/apache/gravitino/catalog/kafka/KafkaCatalog.java b/catalogs/catalog-kafka/src/main/java/org/apache/gravitino/catalog/kafka/KafkaCatalog.java index a0de7228d62..d7a2264a35d 100644 --- a/catalogs/catalog-kafka/src/main/java/org/apache/gravitino/catalog/kafka/KafkaCatalog.java +++ b/catalogs/catalog-kafka/src/main/java/org/apache/gravitino/catalog/kafka/KafkaCatalog.java @@ -39,7 +39,7 @@ public class KafkaCatalog extends BaseCatalog { @Override public String shortName() { - return "kafka"; + return CatalogName.KAFKA.getName(); } @Override diff --git a/catalogs/catalog-lakehouse-hudi/src/main/java/org/apache/gravitino/catalog/lakehouse/hudi/HudiCatalog.java b/catalogs/catalog-lakehouse-hudi/src/main/java/org/apache/gravitino/catalog/lakehouse/hudi/HudiCatalog.java index f2146f36d88..180dd8ccb07 100644 --- a/catalogs/catalog-lakehouse-hudi/src/main/java/org/apache/gravitino/catalog/lakehouse/hudi/HudiCatalog.java +++ b/catalogs/catalog-lakehouse-hudi/src/main/java/org/apache/gravitino/catalog/lakehouse/hudi/HudiCatalog.java @@ -38,7 +38,7 @@ public class HudiCatalog extends BaseCatalog { /** @return The short name of the catalog. */ @Override public String shortName() { - return "lakehouse-hudi"; + return CatalogName.LAKEHOUSE_HUDI.getName(); } /** diff --git a/catalogs/catalog-lakehouse-iceberg/src/main/java/org/apache/gravitino/catalog/lakehouse/iceberg/IcebergCatalog.java b/catalogs/catalog-lakehouse-iceberg/src/main/java/org/apache/gravitino/catalog/lakehouse/iceberg/IcebergCatalog.java index 1010d7dde5c..fe09490ceb5 100644 --- a/catalogs/catalog-lakehouse-iceberg/src/main/java/org/apache/gravitino/catalog/lakehouse/iceberg/IcebergCatalog.java +++ b/catalogs/catalog-lakehouse-iceberg/src/main/java/org/apache/gravitino/catalog/lakehouse/iceberg/IcebergCatalog.java @@ -39,7 +39,7 @@ public class IcebergCatalog extends BaseCatalog { /** @return The short name of the catalog. */ @Override public String shortName() { - return "lakehouse-iceberg"; + return CatalogName.LAKEHOUSE_ICEBERG.getName(); } /** diff --git a/catalogs/catalog-lakehouse-paimon/src/main/java/org/apache/gravitino/catalog/lakehouse/paimon/PaimonCatalog.java b/catalogs/catalog-lakehouse-paimon/src/main/java/org/apache/gravitino/catalog/lakehouse/paimon/PaimonCatalog.java index e6438a44565..eeb09364c27 100644 --- a/catalogs/catalog-lakehouse-paimon/src/main/java/org/apache/gravitino/catalog/lakehouse/paimon/PaimonCatalog.java +++ b/catalogs/catalog-lakehouse-paimon/src/main/java/org/apache/gravitino/catalog/lakehouse/paimon/PaimonCatalog.java @@ -42,7 +42,7 @@ public class PaimonCatalog extends BaseCatalog { /** @return The short name of the catalog. */ @Override public String shortName() { - return "lakehouse-paimon"; + return CatalogName.LAKEHOUSE_PAIMON.getName(); } /** diff --git a/core/build.gradle.kts b/core/build.gradle.kts index b09c0e35889..4579ef3a02c 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -73,3 +73,16 @@ tasks.test { environment("GRAVITINO_HOME", project.rootDir.path + "/distribution/package") } } + +val testJar by tasks.registering(Jar::class) { + archiveClassifier.set("tests") + from(sourceSets["test"].output) +} + +configurations { + create("testArtifacts") +} + +artifacts { + add("testArtifacts", testJar) +} diff --git a/core/src/main/java/org/apache/gravitino/catalog/PropertiesMetadataHelpers.java b/core/src/main/java/org/apache/gravitino/catalog/PropertiesMetadataHelpers.java index 54320c325c7..fd8692fadd5 100644 --- a/core/src/main/java/org/apache/gravitino/catalog/PropertiesMetadataHelpers.java +++ b/core/src/main/java/org/apache/gravitino/catalog/PropertiesMetadataHelpers.java @@ -19,11 +19,15 @@ package org.apache.gravitino.catalog; import com.google.common.base.Preconditions; +import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.function.Function; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import java.util.stream.Collectors; +import org.apache.gravitino.connector.AuthorizationPropertiesMeta; import org.apache.gravitino.connector.PropertiesMetadata; import org.apache.gravitino.connector.PropertyEntry; @@ -67,6 +71,8 @@ public static void validatePropertyForCreate( "Properties are required and must be set: %s", absentProperties); + wildcardPropertyChecker(propertiesMetadata, properties); + // use decode function to validate the property values for (Map.Entry entry : properties.entrySet()) { String key = entry.getKey(); @@ -77,6 +83,96 @@ public static void validatePropertyForCreate( } } + private static void wildcardPropertyChecker( + PropertiesMetadata propertiesMetadata, Map properties) + throws IllegalArgumentException { + List wildcardProperties = + propertiesMetadata.propertyEntries().keySet().stream() + .filter(propertiesMetadata::isWildcardProperty) + .collect(Collectors.toList()); + if (wildcardProperties.size() > 0) { + List wildcardConfigKeys = + wildcardProperties.stream() + .filter(key -> !key.contains(AuthorizationPropertiesMeta.getChainPlugsWildcard())) + .collect(Collectors.toList()); + Preconditions.checkArgument( + wildcardConfigKeys.size() == 1, + "Wildcard properties `%s` not a valid wildcard config with values: %s", + wildcardConfigKeys); + String wildcardConfigKey = wildcardConfigKeys.get(0); + List wildcardConfigValues = + Arrays.stream( + properties + .get(wildcardConfigKey) + .split(AuthorizationPropertiesMeta.getChainPluginsSplitter())) + .map(String::trim) + .collect(Collectors.toList()); + + wildcardConfigValues.stream() + .filter(v -> v.contains(".")) + .forEach( + v -> { + throw new IllegalArgumentException( + String.format( + "Wildcard property values cannot be set with `.` character in the `%s = %s`.", + wildcardConfigKey, properties.get(wildcardConfigKey))); + }); + Preconditions.checkArgument( + wildcardConfigValues.size() == wildcardConfigValues.stream().distinct().count(), + "Duplicate values in wildcard config: %s", + wildcardConfigValues); + + List patterns = + wildcardProperties.stream() + .filter(k -> k.contains(AuthorizationPropertiesMeta.getChainPlugsWildcard())) + .collect(Collectors.toList()) + .stream() + .map( + wildcard -> + wildcard + .replace(".", "\\.") + .replace(AuthorizationPropertiesMeta.getChainPlugsWildcard(), "([^.]+)")) + .map(Pattern::compile) + .collect(Collectors.toList()); + + List wildcardPrefix = + wildcardProperties.stream() + .filter(s -> s.contains(AuthorizationPropertiesMeta.getChainPlugsWildcard())) + .map( + s -> + s.substring( + 0, s.indexOf(AuthorizationPropertiesMeta.getChainPlugsWildcard()))) + .distinct() + .collect(Collectors.toList()); + + for (String key : + properties.keySet().stream() + .filter( + k -> + !k.equals(wildcardConfigKey) + && wildcardPrefix.stream().anyMatch(k::startsWith)) + .collect(Collectors.toList())) { + boolean matches = + patterns.stream() + .anyMatch( + pattern -> { + Matcher matcher = pattern.matcher(key); + if (matcher.find()) { + String group = matcher.group(1); + return wildcardConfigValues.contains(group); + } else { + return false; + } + }); + Preconditions.checkArgument( + matches, + "Wildcard properties `%s` not a valid wildcard config with values: %s", + key, + wildcardConfigValues); + } + } + } + public static void validatePropertyForAlter( PropertiesMetadata propertiesMetadata, Map upserts, diff --git a/core/src/main/java/org/apache/gravitino/connector/AuthorizationPropertiesMeta.java b/core/src/main/java/org/apache/gravitino/connector/AuthorizationPropertiesMeta.java index e1b389f7ca3..b2d724aa4e6 100644 --- a/core/src/main/java/org/apache/gravitino/connector/AuthorizationPropertiesMeta.java +++ b/core/src/main/java/org/apache/gravitino/connector/AuthorizationPropertiesMeta.java @@ -21,25 +21,148 @@ import com.google.common.collect.ImmutableMap; import java.util.Map; -public class AuthorizationPropertiesMeta { +public class AuthorizationPropertiesMeta extends BasePropertiesMetadata { + private static final String AUTHORIZATION_PREFIX = "authorization"; + + public static final String getAuthorizationPrefix() { + return AUTHORIZATION_PREFIX; + } /** Ranger admin web URIs */ - public static final String RANGER_ADMIN_URL = "authorization.ranger.admin.url"; + private static final String RANGER_ADMIN_URL_KEY = "ranger.admin.url"; + + public static final String getRangerAdminUrlKey() { + return RANGER_ADMIN_URL_KEY; + } + + public static final String RANGER_ADMIN_URL = generatePluginKey(RANGER_ADMIN_URL_KEY); /** Ranger authentication type kerberos or simple */ - public static final String RANGER_AUTH_TYPE = "authorization.ranger.auth.type"; + private static final String RANGER_AUTH_TYPE_KEY = "ranger.auth.type"; + + public static final String getRangerAuthTypeKey() { + return RANGER_AUTH_TYPE_KEY; + } + + public static final String RANGER_AUTH_TYPE = generatePluginKey(RANGER_AUTH_TYPE_KEY); /** * Ranger admin web login username(auth_type=simple), or kerberos principal(auth_type=kerberos) */ - public static final String RANGER_USERNAME = "authorization.ranger.username"; + private static final String RANGER_USERNAME_KEY = "ranger.username"; + + public static final String getRangerUsernameKey() { + return RANGER_USERNAME_KEY; + } + + public static final String RANGER_USERNAME = generatePluginKey(RANGER_USERNAME_KEY); /** * Ranger admin web login user password(auth_type=simple), or path of the keytab * file(auth_type=kerberos) */ - public static final String RANGER_PASSWORD = "authorization.ranger.password"; + private static final String RANGER_PASSWORD_KEY = "ranger.password"; + + public static final String getRangerPasswordKey() { + return RANGER_PASSWORD_KEY; + } + + public static final String RANGER_PASSWORD = generatePluginKey(RANGER_PASSWORD_KEY); + /** Ranger service name */ - public static final String RANGER_SERVICE_NAME = "authorization.ranger.service.name"; + private static final String RANGER_SERVICE_NAME_KEY = "ranger.service.name"; + + public static final String getRangerServiceNameKey() { + return RANGER_SERVICE_NAME_KEY; + } + + public static final String RANGER_SERVICE_NAME = generatePluginKey(RANGER_SERVICE_NAME_KEY); + + private static final String CHAIN_PLUGINS_WILDCARD = "*"; + + public static final String getChainPlugsWildcard() { + return CHAIN_PLUGINS_WILDCARD; + } + + private static final String CHAIN_PLUGINS_SPLITTER = ","; + + public static final String getChainPluginsSplitter() { + return CHAIN_PLUGINS_SPLITTER; + } + + private static final String CHAIN_PREFIX = String.format("%s.chain", AUTHORIZATION_PREFIX); - public static final Map> RANGER_AUTHORIZATION_PROPERTY_ENTRIES = + public static final String getChainPrefix() { + return CHAIN_PREFIX; + } + /** Chain authorization plugins */ + public static final String CHAIN_PLUGINS = String.format("%s.plugins", CHAIN_PREFIX); + /** Chain authorization plugin provider */ + private static final String CHAIN_PROVIDER_KEY = "provider"; + + public static final String getChainProviderKey() { + return CHAIN_PROVIDER_KEY; + } + + public static final String CHAIN_PROVIDER = + generateChainPluginsKey(CHAIN_PLUGINS_WILDCARD, CHAIN_PROVIDER_KEY); + /** Chain authorization Ranger admin web URIs */ + public static final String CHAIN_RANGER_ADMIN_URL = + generateChainPluginsKey(CHAIN_PLUGINS_WILDCARD, RANGER_ADMIN_URL_KEY); + /** Chain authorization Ranger authentication type kerberos or simple */ + public static final String CHAIN_RANGER_AUTH_TYPES = + generateChainPluginsKey(CHAIN_PLUGINS_WILDCARD, RANGER_AUTH_TYPE_KEY); + /** Chain authorization Ranger username */ + public static final String CHAIN_RANGER_USERNAME = + generateChainPluginsKey(CHAIN_PLUGINS_WILDCARD, RANGER_USERNAME_KEY); + /** + * Chain authorization Ranger admin web login user password(auth_type=simple), or path of the + * keytab file(auth_type=kerberos) + */ + public static final String CHAIN_RANGER_PASSWORD = + generateChainPluginsKey(CHAIN_PLUGINS_WILDCARD, RANGER_PASSWORD_KEY); + /** Chain authorization Ranger service name */ + public static final String CHAIN_RANGER_SERVICE_NAME = + generateChainPluginsKey(CHAIN_PLUGINS_WILDCARD, RANGER_SERVICE_NAME_KEY); + + public static String generateChainPluginsKey(String pluginName, String key) { + return String.format("%s.%s.%s", CHAIN_PREFIX, pluginName, key); + } + + public static String generatePluginKey(String key) { + return String.format("%s.%s", AUTHORIZATION_PREFIX, key); + } + + public static String chainKeyToPluginKey(String chainKey, String plugin) { + return chainKey.replace(String.format("%s.%s", CHAIN_PREFIX, plugin), AUTHORIZATION_PREFIX); + } + + public static final Map> AUTHORIZATION_PROPERTY_ENTRIES = ImmutableMap.>builder() + .put( + CHAIN_PLUGINS, + PropertyEntry.wildcardPropertyEntry(CHAIN_PLUGINS, "The Chain authorization plugins")) + .put( + CHAIN_PROVIDER, + PropertyEntry.wildcardPropertyEntry( + CHAIN_PROVIDER, "The Chain authorization plugin provider")) + .put( + CHAIN_RANGER_SERVICE_NAME, + PropertyEntry.wildcardPropertyEntry( + CHAIN_RANGER_SERVICE_NAME, "The Chain authorization Ranger service name")) + .put( + CHAIN_RANGER_ADMIN_URL, + PropertyEntry.wildcardPropertyEntry( + CHAIN_RANGER_ADMIN_URL, "The Chain authorization Ranger admin web URIs")) + .put( + CHAIN_RANGER_AUTH_TYPES, + PropertyEntry.wildcardPropertyEntry( + CHAIN_RANGER_AUTH_TYPES, + "The Chain authorization Ranger admin web auth type (kerberos/simple)")) + .put( + CHAIN_RANGER_USERNAME, + PropertyEntry.wildcardPropertyEntry( + CHAIN_RANGER_USERNAME, "The Chain authorization Ranger admin web login username")) + .put( + CHAIN_RANGER_PASSWORD, + PropertyEntry.wildcardPropertyEntry( + CHAIN_RANGER_PASSWORD, "The Chain authorization Ranger admin web login password")) .put( RANGER_SERVICE_NAME, PropertyEntry.stringOptionalPropertyEntry( @@ -65,4 +188,9 @@ public class AuthorizationPropertiesMeta { PropertyEntry.stringOptionalPropertyEntry( RANGER_PASSWORD, "The Ranger admin web login password", true, null, false)) .build(); + + @Override + protected Map> specificPropertyEntries() { + return AUTHORIZATION_PROPERTY_ENTRIES; + } } diff --git a/core/src/main/java/org/apache/gravitino/connector/BaseCatalog.java b/core/src/main/java/org/apache/gravitino/connector/BaseCatalog.java index 213afd4fafc..02605a0529e 100644 --- a/core/src/main/java/org/apache/gravitino/connector/BaseCatalog.java +++ b/core/src/main/java/org/apache/gravitino/connector/BaseCatalog.java @@ -19,22 +19,16 @@ package org.apache.gravitino.connector; import com.google.common.base.Preconditions; -import com.google.common.collect.Iterables; import com.google.common.collect.Maps; -import com.google.common.collect.Streams; import java.io.Closeable; import java.io.IOException; -import java.util.List; import java.util.Map; import java.util.Optional; -import java.util.ServiceLoader; -import java.util.stream.Collectors; import org.apache.gravitino.Audit; import org.apache.gravitino.Catalog; import org.apache.gravitino.CatalogProvider; import org.apache.gravitino.annotation.Evolving; import org.apache.gravitino.connector.authorization.AuthorizationPlugin; -import org.apache.gravitino.connector.authorization.AuthorizationProvider; import org.apache.gravitino.connector.authorization.BaseAuthorization; import org.apache.gravitino.connector.capability.Capability; import org.apache.gravitino.meta.CatalogEntity; @@ -203,28 +197,7 @@ public void initAuthorizationPluginInstance(IsolatedClassLoader classLoader) { authorization = classLoader.withClassLoader( cl -> { - try { - ServiceLoader loader = - ServiceLoader.load(AuthorizationProvider.class, cl); - - List> providers = - Streams.stream(loader.iterator()) - .filter(p -> p.shortName().equalsIgnoreCase(authorizationProvider)) - .map(AuthorizationProvider::getClass) - .collect(Collectors.toList()); - if (providers.isEmpty()) { - throw new IllegalArgumentException( - "No authorization provider found for: " + authorizationProvider); - } else if (providers.size() > 1) { - throw new IllegalArgumentException( - "Multiple authorization providers found for: " + authorizationProvider); - } - return (BaseAuthorization) - Iterables.getOnlyElement(providers).getDeclaredConstructor().newInstance(); - } catch (Exception e) { - LOG.error("Failed to create authorization instance", e); - throw new RuntimeException(e); - } + return BaseAuthorization.createAuthorization(cl, authorizationProvider); }); } catch (Exception e) { LOG.error("Failed to load authorization with class loader", e); diff --git a/core/src/main/java/org/apache/gravitino/connector/PropertiesMetadata.java b/core/src/main/java/org/apache/gravitino/connector/PropertiesMetadata.java index d4778b2ff90..c1d7a7d7d01 100644 --- a/core/src/main/java/org/apache/gravitino/connector/PropertiesMetadata.java +++ b/core/src/main/java/org/apache/gravitino/connector/PropertiesMetadata.java @@ -50,6 +50,17 @@ default boolean isRequiredProperty(String propertyName) { && propertyEntries().get(propertyName).isRequired(); } + /** + * Check if the property is wildcard. + * + * @param propertyName The name of the property. + * @return true if the property is existed and wildcard, false otherwise. + */ + default boolean isWildcardProperty(String propertyName) { + return propertyEntries().containsKey(propertyName) + && propertyEntries().get(propertyName).isWildcard(); + } + /** * Check if the property is immutable. * diff --git a/core/src/main/java/org/apache/gravitino/connector/PropertyEntry.java b/core/src/main/java/org/apache/gravitino/connector/PropertyEntry.java index b4c788a60d8..4c606c27be9 100644 --- a/core/src/main/java/org/apache/gravitino/connector/PropertyEntry.java +++ b/core/src/main/java/org/apache/gravitino/connector/PropertyEntry.java @@ -39,6 +39,7 @@ public final class PropertyEntry { private final Function encoder; private final boolean hidden; private final boolean reserved; + private final boolean wildcard; /** * @param name The name of the property @@ -64,7 +65,8 @@ private PropertyEntry( Function decoder, Function encoder, boolean hidden, - boolean reserved) { + boolean reserved, + boolean wildcard) { Preconditions.checkArgument(StringUtils.isNotBlank(name), "name cannot be null or empty"); Preconditions.checkArgument( StringUtils.isNotBlank(description), "description cannot be null or empty"); @@ -87,6 +89,7 @@ private PropertyEntry( this.encoder = encoder; this.hidden = hidden; this.reserved = reserved; + this.wildcard = wildcard; } public static class Builder { @@ -100,6 +103,7 @@ public static class Builder { private Function encoder; private boolean hidden; private boolean reserved; + private boolean wildcard; public Builder withName(String name) { this.name = name; @@ -151,6 +155,11 @@ public Builder withReserved(boolean reserved) { return this; } + public Builder withWildcard(boolean wildcard) { + this.wildcard = wildcard; + return this; + } + public PropertyEntry build() { return new PropertyEntry( name, @@ -162,7 +171,8 @@ public PropertyEntry build() { decoder, encoder, hidden, - reserved); + reserved, + wildcard); } } @@ -268,6 +278,22 @@ public static PropertyEntry booleanReservedPropertyEntry( return booleanPropertyEntry(name, description, false, true, defaultValue, hidden, true); } + public static PropertyEntry wildcardPropertyEntry(String name, String description) { + return new Builder() + .withName(name) + .withDescription(description) + .withRequired(false) + .withImmutable(false) + .withJavaType(String.class) + .withDefaultValue(null) + .withDecoder(Function.identity()) + .withEncoder(Function.identity()) + .withHidden(false) + .withReserved(false) + .withWildcard(true) + .build(); + } + public static PropertyEntry booleanPropertyEntry( String name, String description, diff --git a/core/src/main/java/org/apache/gravitino/authorization/AuthorizationMetadataObject.java b/core/src/main/java/org/apache/gravitino/connector/authorization/AuthorizationMetadataObject.java similarity index 98% rename from core/src/main/java/org/apache/gravitino/authorization/AuthorizationMetadataObject.java rename to core/src/main/java/org/apache/gravitino/connector/authorization/AuthorizationMetadataObject.java index 07b72da8211..97c94d7e3b3 100644 --- a/core/src/main/java/org/apache/gravitino/authorization/AuthorizationMetadataObject.java +++ b/core/src/main/java/org/apache/gravitino/connector/authorization/AuthorizationMetadataObject.java @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -package org.apache.gravitino.authorization; +package org.apache.gravitino.connector.authorization; import com.google.common.base.Joiner; import com.google.common.base.Preconditions; diff --git a/core/src/main/java/org/apache/gravitino/connector/authorization/AuthorizationPlugin.java b/core/src/main/java/org/apache/gravitino/connector/authorization/AuthorizationPlugin.java index 8ac75a649a5..cc2fb281059 100644 --- a/core/src/main/java/org/apache/gravitino/connector/authorization/AuthorizationPlugin.java +++ b/core/src/main/java/org/apache/gravitino/connector/authorization/AuthorizationPlugin.java @@ -29,4 +29,5 @@ public interface AuthorizationPlugin extends UserGroupAuthorizationPlugin, RoleAuthorizationPlugin, MetadataAuthorizationPlugin, + AuthorizationPluginProvider, Closeable {} diff --git a/core/src/main/java/org/apache/gravitino/connector/authorization/AuthorizationPluginProvider.java b/core/src/main/java/org/apache/gravitino/connector/authorization/AuthorizationPluginProvider.java new file mode 100644 index 00000000000..be2a1b7f103 --- /dev/null +++ b/core/src/main/java/org/apache/gravitino/connector/authorization/AuthorizationPluginProvider.java @@ -0,0 +1,55 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.gravitino.connector.authorization; + +/** + * An Authorization plugin provider is a class that provides a catalog name and plugin name for an + * authorization plugin.
+ */ +public interface AuthorizationPluginProvider { + enum Type { + Ranger("ranger"), + Chain("chain"); + private final String name; + + Type(String name) { + this.name = name; + } + + public String getName() { + return this.name; + } + } + + /** + * The string that represents the authorization that this provider uses.
+ * This is overridden by children to provide a nice alias for the authorization. + * + * @return The string that represents the authorization that this provider uses. + */ + String catalogProviderName(); + + /** + * The string that represents the authorization plugin that this provider uses.
+ * This is overridden by children to provide a nice alias for the authorization. + * + * @return The string that represents the authorization plugin that this provider uses. + */ + String pluginProviderName(); +} diff --git a/core/src/main/java/org/apache/gravitino/authorization/AuthorizationPrivilege.java b/core/src/main/java/org/apache/gravitino/connector/authorization/AuthorizationPrivilege.java similarity index 90% rename from core/src/main/java/org/apache/gravitino/authorization/AuthorizationPrivilege.java rename to core/src/main/java/org/apache/gravitino/connector/authorization/AuthorizationPrivilege.java index 4c58b9ffcac..b3155cb706c 100644 --- a/core/src/main/java/org/apache/gravitino/authorization/AuthorizationPrivilege.java +++ b/core/src/main/java/org/apache/gravitino/connector/authorization/AuthorizationPrivilege.java @@ -16,7 +16,9 @@ * specific language governing permissions and limitations * under the License. */ -package org.apache.gravitino.authorization; +package org.apache.gravitino.connector.authorization; + +import org.apache.gravitino.authorization.Privilege; /** AuthorizationPrivilege interface is used to define the underlying data source privileges. */ public interface AuthorizationPrivilege { diff --git a/core/src/main/java/org/apache/gravitino/authorization/AuthorizationPrivilegesMappingProvider.java b/core/src/main/java/org/apache/gravitino/connector/authorization/AuthorizationPrivilegesMappingProvider.java similarity index 94% rename from core/src/main/java/org/apache/gravitino/authorization/AuthorizationPrivilegesMappingProvider.java rename to core/src/main/java/org/apache/gravitino/connector/authorization/AuthorizationPrivilegesMappingProvider.java index 218de26046e..be2e69021bb 100644 --- a/core/src/main/java/org/apache/gravitino/authorization/AuthorizationPrivilegesMappingProvider.java +++ b/core/src/main/java/org/apache/gravitino/connector/authorization/AuthorizationPrivilegesMappingProvider.java @@ -16,12 +16,14 @@ * specific language governing permissions and limitations * under the License. */ -package org.apache.gravitino.authorization; +package org.apache.gravitino.connector.authorization; import java.util.List; import java.util.Map; import java.util.Set; import org.apache.gravitino.MetadataObject; +import org.apache.gravitino.authorization.Privilege; +import org.apache.gravitino.authorization.SecurableObject; /** * Authorization use this provider to mapping Gravitino privilege to the underlying data source diff --git a/core/src/main/java/org/apache/gravitino/authorization/AuthorizationSecurableObject.java b/core/src/main/java/org/apache/gravitino/connector/authorization/AuthorizationSecurableObject.java similarity index 96% rename from core/src/main/java/org/apache/gravitino/authorization/AuthorizationSecurableObject.java rename to core/src/main/java/org/apache/gravitino/connector/authorization/AuthorizationSecurableObject.java index 5c0e1b67957..028145eed7d 100644 --- a/core/src/main/java/org/apache/gravitino/authorization/AuthorizationSecurableObject.java +++ b/core/src/main/java/org/apache/gravitino/connector/authorization/AuthorizationSecurableObject.java @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -package org.apache.gravitino.authorization; +package org.apache.gravitino.connector.authorization; import java.util.List; diff --git a/core/src/main/java/org/apache/gravitino/connector/authorization/BaseAuthorization.java b/core/src/main/java/org/apache/gravitino/connector/authorization/BaseAuthorization.java index 21a4ff85bfd..ba4399bb10d 100644 --- a/core/src/main/java/org/apache/gravitino/connector/authorization/BaseAuthorization.java +++ b/core/src/main/java/org/apache/gravitino/connector/authorization/BaseAuthorization.java @@ -18,9 +18,14 @@ */ package org.apache.gravitino.connector.authorization; +import com.google.common.collect.Iterables; +import com.google.common.collect.Streams; import java.io.Closeable; import java.io.IOException; +import java.util.List; import java.util.Map; +import java.util.ServiceLoader; +import java.util.stream.Collectors; /** * The abstract base class for Authorization implementations.
@@ -57,6 +62,31 @@ public AuthorizationPlugin plugin(String catalogProvider, Map co return plugin; } + public static BaseAuthorization createAuthorization( + ClassLoader classLoader, String authorizationProvider) { + try { + ServiceLoader loader = + ServiceLoader.load(AuthorizationProvider.class, classLoader); + + List> providers = + Streams.stream(loader.iterator()) + .filter(p -> p.shortName().equalsIgnoreCase(authorizationProvider)) + .map(AuthorizationProvider::getClass) + .collect(Collectors.toList()); + if (providers.isEmpty()) { + throw new IllegalArgumentException( + "No authorization provider found for: " + authorizationProvider); + } else if (providers.size() > 1) { + throw new IllegalArgumentException( + "Multiple authorization providers found for: " + authorizationProvider); + } + return (BaseAuthorization) + Iterables.getOnlyElement(providers).getDeclaredConstructor().newInstance(); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + @Override public void close() throws IOException { if (plugin != null) { diff --git a/core/src/main/java/org/apache/gravitino/connector/authorization/MetadataAuthorizationPlugin.java b/core/src/main/java/org/apache/gravitino/connector/authorization/MetadataAuthorizationPlugin.java index f228d98c74f..bca09859f2b 100644 --- a/core/src/main/java/org/apache/gravitino/connector/authorization/MetadataAuthorizationPlugin.java +++ b/core/src/main/java/org/apache/gravitino/connector/authorization/MetadataAuthorizationPlugin.java @@ -19,6 +19,7 @@ package org.apache.gravitino.connector.authorization; import org.apache.gravitino.authorization.MetadataObjectChange; +import org.apache.gravitino.exceptions.AuthorizationPluginException; /** * Interface for authorization User and Group plugin operation of the underlying access control @@ -33,5 +34,5 @@ interface MetadataAuthorizationPlugin { * @return True if the update operation is successful; False if the update operation fails. * @throws RuntimeException If update role encounters storage issues. */ - Boolean onMetadataUpdated(MetadataObjectChange... changes) throws RuntimeException; + Boolean onMetadataUpdated(MetadataObjectChange... changes) throws AuthorizationPluginException; } diff --git a/core/src/test/java/org/apache/gravitino/connector/authorization/TestAuthorization.java b/core/src/test/java/org/apache/gravitino/connector/authorization/TestAuthorization.java index 554ef0cec8b..0e159e46cb9 100644 --- a/core/src/test/java/org/apache/gravitino/connector/authorization/TestAuthorization.java +++ b/core/src/test/java/org/apache/gravitino/connector/authorization/TestAuthorization.java @@ -24,8 +24,8 @@ import org.apache.gravitino.Catalog; import org.apache.gravitino.Namespace; import org.apache.gravitino.TestCatalog; -import org.apache.gravitino.connector.authorization.mysql.TestMySQLAuthorizationPlugin; -import org.apache.gravitino.connector.authorization.ranger.TestRangerAuthorizationPlugin; +import org.apache.gravitino.connector.authorization.ranger.TestRangerAuthorizationHDFSPlugin; +import org.apache.gravitino.connector.authorization.ranger.TestRangerAuthorizationHadoopSQLPlugin; import org.apache.gravitino.meta.AuditInfo; import org.apache.gravitino.meta.CatalogEntity; import org.apache.gravitino.utils.IsolatedClassLoader; @@ -35,7 +35,7 @@ public class TestAuthorization { private static TestCatalog hiveCatalog; - private static TestCatalog mySQLCatalog; + private static TestCatalog filesetCatalog; @BeforeAll public static void setUp() throws Exception { @@ -54,47 +54,48 @@ public static void setUp() throws Exception { hiveCatalog = new TestCatalog() - .withCatalogConf(ImmutableMap.of(Catalog.AUTHORIZATION_PROVIDER, "ranger")) + .withCatalogConf( + ImmutableMap.of(Catalog.AUTHORIZATION_PROVIDER, "test_ranger_hadoop_sql")) .withCatalogEntity(hiveCatalogEntity); IsolatedClassLoader isolatedClassLoader = new IsolatedClassLoader( Collections.emptyList(), Collections.emptyList(), Collections.emptyList()); hiveCatalog.initAuthorizationPluginInstance(isolatedClassLoader); - CatalogEntity mySQLEntity = + CatalogEntity filesetEntity = CatalogEntity.builder() .withId(2L) .withName("catalog-test2") .withNamespace(Namespace.of("default")) - .withType(Catalog.Type.RELATIONAL) + .withType(Catalog.Type.FILESET) .withProvider("test") .withAuditInfo(auditInfo) .build(); - mySQLCatalog = + filesetCatalog = new TestCatalog() - .withCatalogConf(ImmutableMap.of(Catalog.AUTHORIZATION_PROVIDER, "mysql")) - .withCatalogEntity(mySQLEntity); - mySQLCatalog.initAuthorizationPluginInstance(isolatedClassLoader); + .withCatalogConf(ImmutableMap.of(Catalog.AUTHORIZATION_PROVIDER, "test_ranger_hdfs")) + .withCatalogEntity(filesetEntity); + filesetCatalog.initAuthorizationPluginInstance(isolatedClassLoader); } @Test - public void testRangerAuthorization() { + public void testRangerHadoopSQLAuthorization() { AuthorizationPlugin rangerAuthPlugin = hiveCatalog.getAuthorizationPlugin(); - Assertions.assertInstanceOf(TestRangerAuthorizationPlugin.class, rangerAuthPlugin); - TestRangerAuthorizationPlugin testRangerAuthPlugin = - (TestRangerAuthorizationPlugin) rangerAuthPlugin; + Assertions.assertInstanceOf(TestRangerAuthorizationHadoopSQLPlugin.class, rangerAuthPlugin); + TestRangerAuthorizationHadoopSQLPlugin testRangerAuthPlugin = + (TestRangerAuthorizationHadoopSQLPlugin) rangerAuthPlugin; Assertions.assertFalse(testRangerAuthPlugin.callOnCreateRole1); rangerAuthPlugin.onRoleCreated(null); Assertions.assertTrue(testRangerAuthPlugin.callOnCreateRole1); } @Test - public void testMySQLAuthorization() { - AuthorizationPlugin mySQLAuthPlugin = mySQLCatalog.getAuthorizationPlugin(); - Assertions.assertInstanceOf(TestMySQLAuthorizationPlugin.class, mySQLAuthPlugin); - TestMySQLAuthorizationPlugin testMySQLAuthPlugin = - (TestMySQLAuthorizationPlugin) mySQLAuthPlugin; + public void testRangerHDFSAuthorization() { + AuthorizationPlugin mySQLAuthPlugin = filesetCatalog.getAuthorizationPlugin(); + Assertions.assertInstanceOf(TestRangerAuthorizationHDFSPlugin.class, mySQLAuthPlugin); + TestRangerAuthorizationHDFSPlugin testMySQLAuthPlugin = + (TestRangerAuthorizationHDFSPlugin) mySQLAuthPlugin; Assertions.assertFalse(testMySQLAuthPlugin.callOnCreateRole2); mySQLAuthPlugin.onRoleCreated(null); Assertions.assertTrue(testMySQLAuthPlugin.callOnCreateRole2); diff --git a/core/src/test/java/org/apache/gravitino/connector/authorization/ranger/TestRangerAuthorization.java b/core/src/test/java/org/apache/gravitino/connector/authorization/ranger/TestRangerAuthorizationHDFS.java similarity index 84% rename from core/src/test/java/org/apache/gravitino/connector/authorization/ranger/TestRangerAuthorization.java rename to core/src/test/java/org/apache/gravitino/connector/authorization/ranger/TestRangerAuthorizationHDFS.java index c792c407bd3..ab904420df3 100644 --- a/core/src/test/java/org/apache/gravitino/connector/authorization/ranger/TestRangerAuthorization.java +++ b/core/src/test/java/org/apache/gravitino/connector/authorization/ranger/TestRangerAuthorizationHDFS.java @@ -22,17 +22,17 @@ import org.apache.gravitino.connector.authorization.AuthorizationPlugin; import org.apache.gravitino.connector.authorization.BaseAuthorization; -public class TestRangerAuthorization extends BaseAuthorization { +public class TestRangerAuthorizationHDFS extends BaseAuthorization { - public TestRangerAuthorization() {} + public TestRangerAuthorizationHDFS() {} @Override public String shortName() { - return "ranger"; + return "test_ranger_hdfs"; } @Override protected AuthorizationPlugin newPlugin(String catalogProvider, Map config) { - return new TestRangerAuthorizationPlugin(); + return new TestRangerAuthorizationHDFSPlugin(); } } diff --git a/core/src/test/java/org/apache/gravitino/connector/authorization/mysql/TestMySQLAuthorizationPlugin.java b/core/src/test/java/org/apache/gravitino/connector/authorization/ranger/TestRangerAuthorizationHDFSPlugin.java similarity index 91% rename from core/src/test/java/org/apache/gravitino/connector/authorization/mysql/TestMySQLAuthorizationPlugin.java rename to core/src/test/java/org/apache/gravitino/connector/authorization/ranger/TestRangerAuthorizationHDFSPlugin.java index e078eda410e..81bc84adb0d 100644 --- a/core/src/test/java/org/apache/gravitino/connector/authorization/mysql/TestMySQLAuthorizationPlugin.java +++ b/core/src/test/java/org/apache/gravitino/connector/authorization/ranger/TestRangerAuthorizationHDFSPlugin.java @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -package org.apache.gravitino.connector.authorization.mysql; +package org.apache.gravitino.connector.authorization.ranger; import java.io.IOException; import java.util.List; @@ -29,7 +29,7 @@ import org.apache.gravitino.authorization.User; import org.apache.gravitino.connector.authorization.AuthorizationPlugin; -public class TestMySQLAuthorizationPlugin implements AuthorizationPlugin { +public class TestRangerAuthorizationHDFSPlugin implements AuthorizationPlugin { public boolean callOnCreateRole2 = false; @Override @@ -116,4 +116,14 @@ public void close() throws IOException {} public Boolean onMetadataUpdated(MetadataObjectChange... changes) throws RuntimeException { return null; } + + @Override + public String catalogProviderName() { + return null; + } + + @Override + public String pluginProviderName() { + return null; + } } diff --git a/core/src/test/java/org/apache/gravitino/connector/authorization/mysql/TestMySQLAuthorization.java b/core/src/test/java/org/apache/gravitino/connector/authorization/ranger/TestRangerAuthorizationHadoopSQL.java similarity index 78% rename from core/src/test/java/org/apache/gravitino/connector/authorization/mysql/TestMySQLAuthorization.java rename to core/src/test/java/org/apache/gravitino/connector/authorization/ranger/TestRangerAuthorizationHadoopSQL.java index 06d7a9275ec..5ad598a877b 100644 --- a/core/src/test/java/org/apache/gravitino/connector/authorization/mysql/TestMySQLAuthorization.java +++ b/core/src/test/java/org/apache/gravitino/connector/authorization/ranger/TestRangerAuthorizationHadoopSQL.java @@ -16,23 +16,24 @@ * specific language governing permissions and limitations * under the License. */ -package org.apache.gravitino.connector.authorization.mysql; +package org.apache.gravitino.connector.authorization.ranger; import java.util.Map; import org.apache.gravitino.connector.authorization.AuthorizationPlugin; import org.apache.gravitino.connector.authorization.BaseAuthorization; -public class TestMySQLAuthorization extends BaseAuthorization { +public class TestRangerAuthorizationHadoopSQL + extends BaseAuthorization { - public TestMySQLAuthorization() {} + public TestRangerAuthorizationHadoopSQL() {} @Override public String shortName() { - return "mysql"; + return "test_ranger_hadoop_sql"; } @Override protected AuthorizationPlugin newPlugin(String catalogProvider, Map config) { - return new TestMySQLAuthorizationPlugin(); + return new TestRangerAuthorizationHadoopSQLPlugin(); } } diff --git a/core/src/test/java/org/apache/gravitino/connector/authorization/ranger/TestRangerAuthorizationPlugin.java b/core/src/test/java/org/apache/gravitino/connector/authorization/ranger/TestRangerAuthorizationHadoopSQLPlugin.java similarity index 93% rename from core/src/test/java/org/apache/gravitino/connector/authorization/ranger/TestRangerAuthorizationPlugin.java rename to core/src/test/java/org/apache/gravitino/connector/authorization/ranger/TestRangerAuthorizationHadoopSQLPlugin.java index 8a68f825d0e..4eb2bd2c236 100644 --- a/core/src/test/java/org/apache/gravitino/connector/authorization/ranger/TestRangerAuthorizationPlugin.java +++ b/core/src/test/java/org/apache/gravitino/connector/authorization/ranger/TestRangerAuthorizationHadoopSQLPlugin.java @@ -29,7 +29,7 @@ import org.apache.gravitino.authorization.User; import org.apache.gravitino.connector.authorization.AuthorizationPlugin; -public class TestRangerAuthorizationPlugin implements AuthorizationPlugin { +public class TestRangerAuthorizationHadoopSQLPlugin implements AuthorizationPlugin { public boolean callOnCreateRole1 = false; @Override @@ -116,4 +116,14 @@ public void close() throws IOException {} public Boolean onMetadataUpdated(MetadataObjectChange... changes) throws RuntimeException { return null; } + + @Override + public String catalogProviderName() { + return null; + } + + @Override + public String pluginProviderName() { + return null; + } } diff --git a/core/src/test/resources/META-INF/services/org.apache.gravitino.connector.authorization.AuthorizationProvider b/core/src/test/resources/META-INF/services/org.apache.gravitino.connector.authorization.AuthorizationProvider index e49cb8937e0..fc878c208ad 100644 --- a/core/src/test/resources/META-INF/services/org.apache.gravitino.connector.authorization.AuthorizationProvider +++ b/core/src/test/resources/META-INF/services/org.apache.gravitino.connector.authorization.AuthorizationProvider @@ -16,5 +16,5 @@ # specific language governing permissions and limitations # under the License. # -org.apache.gravitino.connector.authorization.ranger.TestRangerAuthorization -org.apache.gravitino.connector.authorization.mysql.TestMySQLAuthorization \ No newline at end of file +org.apache.gravitino.connector.authorization.ranger.TestRangerAuthorizationHadoopSQL +org.apache.gravitino.connector.authorization.ranger.TestRangerAuthorizationHDFS \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts index a36fde93cd3..8b561cff043 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -56,7 +56,7 @@ if (gradle.startParameter.projectProperties["enableFuse"]?.toBoolean() ?: false) } include("iceberg:iceberg-common") include("iceberg:iceberg-rest-server") -include("authorizations:authorization-ranger") +include("authorizations:authorization-ranger", "authorizations:authorization-chain") include("trino-connector:trino-connector", "trino-connector:integration-test") include("spark-connector:spark-common") // kyuubi hive connector doesn't support 2.13 for Spark3.3