-
Notifications
You must be signed in to change notification settings - Fork 378
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[#5775] feat(auth): Chain authorization plugin framework #5786
Conversation
4b5dc53
to
4755a53
Compare
5a29c05
to
a19a314
Compare
ChainAuthorizationProperties.fetchAuthPluginProperties(pluginName, properties); | ||
String authProvider = | ||
ChainAuthorizationProperties.getPluginProvider(pluginName, properties); | ||
if ("ranger".equals(authProvider)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we only support Ranger plugin?
} | ||
|
||
@Override | ||
public AuthorizationPlugin newPlugin( | ||
String metalake, String catalogProvider, Map<String, String> config) { | ||
return new TestMySQLAuthorizationPlugin(); | ||
switch (catalogProvider) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we only support hive?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Currently, we only support the Hive catalog in this PR, But we can support more types in the future.
We need rigorous testing to enable this limit.
ChainAuthorizationProperties.fetchAuthPluginProperties(pluginName, properties); | ||
String authProvider = | ||
ChainAuthorizationProperties.getPluginProvider(pluginName, properties); | ||
if ("ranger".equals(authProvider)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe we can have a common module to define the constant variable like Ranger
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The community discussed it before, just like Catalog shortName uses string variables (Hive
, Hadoop
), not uses constant variable, So I kept consistent.
switch (metadataObject.type()) { | ||
case METALAKE: | ||
case SCHEMA: | ||
case TABLE: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this right? Table can have a location, too.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This PR only supports Create_schema
in the Catalog
in the chain Ranger Hive
and Ranger HDFS
. I split other operations in the next PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe you add TODO
comment at least.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I already add todo integration test in the TestChainedAuthorizationIT
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need add TODO
in the code. Otherwise I will think this is an error.
public static final String RESOURCE_ALL = "*"; | ||
/** The `/` gives access to all path resources */ | ||
public static final String RESOURCE_ROOT_PATH = "/test/"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why dow we need this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
rollback this change.
} catch (Exception e) { | ||
throw new IllegalStateException("Failed to set environment variable", e); | ||
} finally { | ||
setEnv(key, originalValue); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need recover the property user.name
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, I improved this code.
gravitinoPrivilege.name(), securableObject.type()); | ||
} | ||
break; | ||
case SELECT_TABLE: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If HDFS Ranger plugin is used for Hive, we should have the SELECT_TABLE privilege.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I split SELECT_TABLE
operations in the next PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe you add TODO
comment at least.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I already add todo integration test in the TestChainedAuthorizationIT
.
implementation(libs.javax.ws.rs.api) | ||
implementation(libs.jettison) | ||
compileOnly(libs.lombok) | ||
implementation(libs.rome) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you make this alphabetically ordering?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
DONE
public Boolean onMetadataUpdated(MetadataObjectChange... changes) | ||
throws AuthorizationPluginException { | ||
for (AuthorizationPlugin plugin : plugins) { | ||
Boolean result = plugin.onMetadataUpdated(changes); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will we throw exceptions here, what happens if the exception throws in the for loop?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In such a for loop, if the plugin calls the onMetadataUpdated
function and throws an exception, the exception will propagate to the outer method ChainAuthorizaiton::onMetadataUpdated
and will not be caught or handled. This means that the outer method also sell AuthorizationPluginException abnormalities, and the cycle will be interrupted, will not continue to deal with the rest of the plugin.
ImmutableMap.of(Catalog.AUTHORIZATION_PROVIDER, authProvider)) | ||
.ifPresent(libAndResourcesPaths::add); | ||
IsolatedClassLoader classLoader = | ||
IsolatedClassLoader.buildClassLoader(libAndResourcesPaths); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we need to build different classloaders for different plugins, can we just use catalog's classloader?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When we load ChainAuthorizationPlugin
, We need add authorizaitons/chain/libs
in the BaseCatalog
IsolatedClassLoader class paths.
We cann't add authorizaitons/ranger/libs
at same time. So we need an IsolatedClassLoader to separate load RangerAuthorizationPlugin
here.
} | ||
return Boolean.TRUE; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you can extract the common part and simplify the code like:
private Boolean chainedAction(Function<AuthorizationPlugin, Boolean> action) {
for (AuthorizationPlugin plugin : plugins) {
if (!action.apply(plugin)) {
return false;
}
}
return true;
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
DONE
@@ -25,12 +25,12 @@ | |||
import org.apache.gravitino.authorization.AuthorizationPrivilege; | |||
import org.apache.gravitino.authorization.AuthorizationSecurableObject; | |||
|
|||
public class RangerPathBaseSecurableObject extends RangerPathBaseMetadataObject | |||
public class RangerHDFSSecurableObject extends RangerHDFSMetadataObject |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we change the class name here? I assume Ranger doesn't care whether it is the HDFS or not, it cares more about the path, am I right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So if users have a Hadoop compatible file system, it can also be controlled by Ranger, but it is not a HDFS actually.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, I rollback this change.
* specific language governing permissions and limitations | ||
* under the License. | ||
*/ | ||
package org.apache.gravitino.authorization; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about renaming the package to org.apache.gravitino.authorization.common
for better understanding?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
DONE
@jerryshao I fixed all the problems, Please help me review it again. Thanks. |
testImplementation(project(":core")) | ||
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) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like we still have some alphabetical ordering issues, can you fix them all?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
DONE
import org.apache.gravitino.exceptions.AuthorizationPluginException; | ||
import org.apache.gravitino.utils.IsolatedClassLoader; | ||
|
||
/** Chain authorization operations plugin class. <br> */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Chained authorization operations...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
DONE
} | ||
|
||
private void initPlugins(String catalogProvider, Map<String, String> properties) { | ||
ChainedAuthorizationProperties chainedAuthProperties = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"Authz" is short for "Authorization", it would be better change to "Authz".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just minor suggestion, I'm OK with either.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
DONE
{ | ||
String locationPath = getLocationPath(securableObject); | ||
if (locationPath != null && !locationPath.isEmpty()) { | ||
RangerPathBaseMetadataObject rangerHDFSMetadataObject = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you also rename the variable to "rangerPathXXX", not "rangerHDFSXXX"?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
DONE
return rangerHDFSMetadataObject; | ||
} else { | ||
return new RangerPathBaseMetadataObject("", RangerPathBaseMetadataObject.Type.PATH); | ||
RangerPathBaseMetadataObject rangerHDFSMetadataObject; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
DONE
@jerryshao I fixed all the problems, Please help me review it again. Thanks. |
tasks { | ||
val runtimeJars by registering(Copy::class) { | ||
from(configurations.runtimeClasspath) | ||
into("build/libs") | ||
} | ||
|
||
jar { | ||
dependsOn(runtimeJars) | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess this is not needed, am I right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, I removed it.
test { | ||
subprojects.forEach { | ||
dependsOn(":${project.name}:${it.name}:test") | ||
} | ||
} | ||
|
||
register("copyLibAndConfig", Copy::class) { | ||
subprojects.forEach { | ||
if (!it.name.startsWith("authorization-common")) { | ||
dependsOn(":${project.name}:${it.name}:copyLibAndConfig") | ||
} | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need these codes? I found that each module already has these tasks.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can use it to optimize compileDistribution
in the root build.gradle.kts
.
} | ||
throw new IllegalArgumentException( | ||
"No matching RangerMetadataObject.Type for " + metadataType); | ||
} | ||
} | ||
|
||
private final String path; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we rename this class from RangerPathBaseMetadataObject
to RangerPathBasedMetadataObject
or RangerPathMetadataObject
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, I rename RangerPathBaseMetadataObject
to PathBasedMetadataObject
and moved it to authorization-common
modul.
What changes were proposed in this pull request?
Why are the changes needed?
Fix: #5775
Does this PR introduce any user-facing change?
N/A
How was this patch tested?
Add ITs