Skip to content
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

[#4698] feat(auth-ranger): Extended Ranger authorization by rules #4744

Merged
merged 11 commits into from
Sep 19, 2024

Conversation

xunliu
Copy link
Member

@xunliu xunliu commented Aug 28, 2024

What changes were proposed in this pull request?

  1. Added interface RangerPrivilegesMappingProvider, we can use it to map Gravitino privileges to the Ranger privileges.
  2. Added abstract class RangerAuthorizationPlugin, we can use it to extend another Ranger authorization plugin.

Why are the changes needed?

Fix: #4698

Does this PR introduce any user-facing change?

NA

How was this patch tested?

CI Passed.

@xunliu xunliu requested a review from yuqi1129 August 28, 2024 14:12
@xunliu xunliu self-assigned this Aug 28, 2024
@xunliu
Copy link
Member Author

xunliu commented Aug 28, 2024

@lw-yang Please help me review this PR, thanks.

@xunliu xunliu changed the title [#4698] feat(core): Extended Apache Ranger authorization by configuration [#4698] feat(auth-ranger): Extended Ranger authorization by configuration Aug 29, 2024
@lw-yang
Copy link
Contributor

lw-yang commented Aug 30, 2024

LGTM.

@xunliu
Copy link
Member Author

xunliu commented Aug 30, 2024

@yuqi1129 I fixed all comments. Please help me review again, Thanks!

* Initial Ranger policy search key defines. <br>
* Initial precise filter key defines. <br>
*/
private void initAuthorizationConfig(AuthorizationConfig authorizationConfig) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we provide default values as before, it's too complicated to set the mapping for most users and only those users that have special requirement will configure this value.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea, I improved it, Please help me review this PR, again.

@yuqi1129
Copy link
Contributor

yuqi1129 commented Sep 2, 2024

LGTM, @jerqi @jerryshao Would you like to take a look?

@jerryshao
Copy link
Contributor

Sorry for late response, I will take a look at this today.

@jerryshao
Copy link
Contributor

I'm a little confused about the changes here made, can you describe more clearly about the scenarios and how users will use this feature? It's really not easy to understand.

@xunliu
Copy link
Member Author

xunliu commented Sep 6, 2024

I'm a little confused about the changes here made, can you describe more clearly about the scenarios and how users will use this feature? It's really not easy to understand.

In Gravitino, we specify that each Gravitino Privilege maps multiple Privileges on the underlying system(Ranger), but there are some users whose environments have different privilege mappings than ours, so we allow users to configure their own to meet their own personalized needs, in addition to using our default Privilege mappings.

@lw-yang
Copy link
Contributor

lw-yang commented Sep 6, 2024

@jerryshao This feature allows for custom configuration of the mapping relationship between Gravitino Privileges and Ranger Privileges. If the default mapping relationship in Gravitino does not meet our scenario, we can customize it.

For example, by default, Gravitino's MODIFY_TABLE maps to Ranger's RangerHivePrivilege.UPDATE, RangerHivePrivilege.ALTER, RangerHivePrivilege.WRITE. In our scenario, we need to add RangerHivePrivilege.DROP, so we can customize this mapping relationship.

import org.apache.gravitino.config.ConfigEntry;

public class AuthorizationConfig extends Config {
public static final ConfigEntry<List<String>> AUTHORIZATION_OWNER_PRIVILEGES =
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are these generic authorization configs or ranger authorization only configs?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are generic authorization configs.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If these are generic configs, they should be put into the code module, not Ranger module. Also I'm curious how other plugins like JDBC, IAM can leverage these configurations later on. From my understanding, they're quite Ranger specific.

AuthorizationConfig authorizationConfig = new AuthorizationConfig();
boolean testEnv = System.getenv("GRAVITINO_TEST") != null;
String propertyFilePath =
String.format("authorization-defs/authorization-%s.properties", providerName);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we can directly put this file into the conf, not so necessary to add another "authorization-defs" folder, WDYT?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, I moved it to distribution/package/authorizations/ranger/conf/authorization-hive.properties.

# Format: authorization.privilege.mapping.<GRAVITINO-PRIVILEGE> = <RANGER-PRIVILEGE>,<RANGER-PRIVILEGE>,...
# gravitino.authorization.privilege.mapping.CREATE_SCHEMA = create
# gravitino.authorization.privilege.mapping.CREATE_TABLE = create
# gravitino.authorization.privilege.mapping.SELECT_TABLE = read,select
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we handle the scenarios like having prefix and trailing whitespace in between policies for the conf value? like:

gravitino.authorization.privilege.mapping.CREATE_TABLE = create, aaa, xxx,   aaa

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I have test case to cover these scenarios.
authorizations/authorization-ranger/src/test/resources/authorization-defs/authorization-hive-nonstandard.properties


Gravitino privileges defined in the `api/src/main/java/org/apache/gravitino/authorization/Privilege.java`
Format: authorization.privilege.mapping.<GRAVITINO-PRIVILEGE> = <RANGER-PRIVILEGE>,<RANGER-PRIVILEGE>,...
:::
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the document here is not enough. You should clearly describe how to configure, what is the meaning, and give an example here.

Also, do we only support 4 privileges for mapping, how do we support more privileges to map easily?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the document here is not enough. You should clearly describe how to configure, what is the meaning, and give an example here.

OK, I added example in the docs.

Also, do we only support 4 privileges for mapping, how do we support more privileges to map easily?

No, We can support all Gravitino privileges to configurations.
Because I use

Privilege.Name gravitinoPrivilege =
                    Privilege.Name.valueOf(key.trim().toUpperCase());

These codes can convert any String to a Gravitino Privilege enum value.

import org.apache.gravitino.config.ConfigEntry;

public class AuthorizationConfig extends Config {
public static final ConfigEntry<List<String>> AUTHORIZATION_OWNER_PRIVILEGES =
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are generic authorization configs.

# Format: authorization.privilege.mapping.<GRAVITINO-PRIVILEGE> = <RANGER-PRIVILEGE>,<RANGER-PRIVILEGE>,...
# gravitino.authorization.privilege.mapping.CREATE_SCHEMA = create
# gravitino.authorization.privilege.mapping.CREATE_TABLE = create
# gravitino.authorization.privilege.mapping.SELECT_TABLE = read,select
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I have test case to cover these scenarios.
authorizations/authorization-ranger/src/test/resources/authorization-defs/authorization-hive-nonstandard.properties

AuthorizationConfig authorizationConfig = new AuthorizationConfig();
boolean testEnv = System.getenv("GRAVITINO_TEST") != null;
String propertyFilePath =
String.format("authorization-defs/authorization-%s.properties", providerName);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, I moved it to distribution/package/authorizations/ranger/conf/authorization-hive.properties.

Comment on lines 129 to 130
Privilege.Name gravitinoPrivilege =
Privilege.Name.valueOf(key.trim().toUpperCase());
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hi @jerryshao
These codes can convert any String to a Gravitino Privilege enum value.


Gravitino privileges defined in the `api/src/main/java/org/apache/gravitino/authorization/Privilege.java`
Format: authorization.privilege.mapping.<GRAVITINO-PRIVILEGE> = <RANGER-PRIVILEGE>,<RANGER-PRIVILEGE>,...
:::
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the document here is not enough. You should clearly describe how to configure, what is the meaning, and give an example here.

OK, I added example in the docs.

Also, do we only support 4 privileges for mapping, how do we support more privileges to map easily?

No, We can support all Gravitino privileges to configurations.
Because I use

Privilege.Name gravitinoPrivilege =
                    Privilege.Name.valueOf(key.trim().toUpperCase());

These codes can convert any String to a Gravitino Privilege enum value.

@xunliu
Copy link
Member Author

xunliu commented Sep 10, 2024

@jerryshao I updated this PR, Please help me review it again, thanks.

@jerqi
Copy link
Collaborator

jerqi commented Sep 12, 2024

This is just a discussion instead of review suggestion.
In my opinion,

What's the difference between users and developers.
Users can only change the configurations. Developers can use the interface to custom their need.

This feature should be used by developers instead of users. So I prefer extracting an interface PrivilegeMappingProviderPlugin to let other developer extend other mapping relation.

Configuration has less restriction than the interface. The interface can help us define better behaviour.

This is just my cent, not a strong suggestion.

@xunliu
Copy link
Member Author

xunliu commented Sep 13, 2024

@jerryshao I removed the use properties file to overwrite the default authorization configuration.
Please help me review it again, thanks!

import org.apache.gravitino.authorization.Privilege;

/**
* Ranger authorization use this configuration to mapping Gravitino privilege to the Ranger
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I need to think a bit on this, my initial feeling is that This RangerAuthorizationConfig may not be easy for people to use.

Most of the interfaces like initializePrivilegesMappingConfig() is hard to people to understand from the definition. People doesn't know what should be implemented, what is the input, output and side-effect of this interface. Without knowing this, it is hard for the developers to extend or implement this interface.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's OK for internal use. But if we want to expose to the developers to extend, seems the definition is not self-explanatory. The concept of xxxConfig makes people hard to understand without context.

Copy link
Member Author

@xunliu xunliu Sep 14, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we can change class name fromRangerAuthorizationConfig to PrivilegeMappingRules?
and change the function name from

  1. initializePrivilegesMappingConfig() -> setPrivilegesMappingRule()
  2. initializeOwnerPrivilegesConfig() -> setOwnerPrivilegesRule()
  3. initializePolicyResourceDefinesConfig() -> setPolicyResourceDefinesRule()

What do you think?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typically, it is hard to design an interface for like "initializeXXX" or "setXXX", because it is hard for developers to know how to correctly implement a code about "initializeXXX" or "setXXX". Instead, I would suggest like:

interface RangerPrivilegesMappingProvider {

Map<GravitinoPrivilege, Set<RangerPrivileges>> privilegesMappingRule()
Map<GravitinoPrivilege, Set<RangerPrivileges>> ownerMappingRule()
...
}

Just for your reference, please take a look, thanks.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, I accept your suggestion.

public interface RangerPrivilege {
String toString();

boolean equals(String value);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the interface name equals is conflicted with Java's built-in equals method name, also for toString, it is better to have another name.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, change equals() to isEquals().

REPLADMIN("repladmin"),
SERVICEADMIN("serviceadmin");

private final String string; // Access a type in the Ranger policy item
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is better to have a different name for this class variable, not similar to the reserved word.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DONE.

@xunliu xunliu force-pushed the issue-4698 branch 3 times, most recently from 449d564 to be618e8 Compare September 18, 2024 05:54
@xunliu
Copy link
Member Author

xunliu commented Sep 18, 2024

@jerryshao I accept your suggestion and modify the code, please help me review again, thanks.

void ownerMappingRule();

/** Set the policy resource defines rule. */
void policyResourceDefinesRule();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still think that you should have the return value for the method you defined here. Otherwise, it is hard for others to implement a such interface.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea.

return ImmutableList.of(
PolicyResource.DATABASE.getName(),
PolicyResource.TABLE.getName(),
PolicyResource.COLUMN.getName());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like all these methods return immutable map or list, if so, I would suggest make them singletons, so that we don't have to create maps or lists for each call.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed to singleton.

Comment on lines 70 to 74
private Map<Privilege.Name, Set<RangerPrivilege>> privilegesMapping;
/** The owner privileges, the owner can do anything on the metadata object configuration */
private Set<RangerPrivilege> ownerPrivileges;
/** The Ranger policy resource defines configuration. */
private List<String> policyResourceDefines;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you please make these variables final?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also for other class variables.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DONE.

// Initialize privilegesMapping and ownerPrivileges
ownerPrivileges = ownerMappingRule();
privilegesMapping = privilegesMappingRule();
policyResourceDefines = policyResourceDefinesRule();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also please change the style to this.xxx = xxx for class variable assignment.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DONE.

}

public final List<String> getPolicyResourceDefines() {
return policyResourceDefines;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also do you still need these methods? I think you can directly call privilegesMappingRule, ownerMappingRule, etc.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DONE

public interface RangerPrivilege {
String getName();

boolean isEquals(String value);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"isEquals" is not correct for grammar, can you please change to equalsTo(xxxx)?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DONE

@@ -38,7 +38,7 @@ public class RangerContainer extends BaseContainer {
public static final String DEFAULT_IMAGE = System.getenv("GRAVITINO_CI_RANGER_DOCKER_IMAGE");
public static final String HOST_NAME = "gravitino-ci-ranger";
public static final int RANGER_SERVER_PORT = 6080;
public RangerClient rangerClient;
public RangerClientExtend rangerClient;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you please change this class name "RangerClientExtend" to "RangerExtendedClient" or "RangerClientExtension", the name "xxxExtend" is a verb not a noun.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed to RangerClientExtension.

@jerryshao
Copy link
Contributor

@xunliu , can you please also update the PR title and description to reflect what you did currently.

@xunliu xunliu changed the title [#4698] feat(auth-ranger): Extended Ranger authorization by configuration [#4698] feat(auth-ranger): Extended Ranger authorization by rules Sep 18, 2024
Copy link
Member Author

@xunliu xunliu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jerryshao I refactoring the code, Please help me review again.

Comment on lines 70 to 74
private Map<Privilege.Name, Set<RangerPrivilege>> privilegesMapping;
/** The owner privileges, the owner can do anything on the metadata object configuration */
private Set<RangerPrivilege> ownerPrivileges;
/** The Ranger policy resource defines configuration. */
private List<String> policyResourceDefines;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DONE.

// Initialize privilegesMapping and ownerPrivileges
ownerPrivileges = ownerMappingRule();
privilegesMapping = privilegesMappingRule();
policyResourceDefines = policyResourceDefinesRule();
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DONE.

}

public final List<String> getPolicyResourceDefines() {
return policyResourceDefines;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DONE

public interface RangerPrivilege {
String getName();

boolean isEquals(String value);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DONE

@@ -38,7 +38,7 @@ public class RangerContainer extends BaseContainer {
public static final String DEFAULT_IMAGE = System.getenv("GRAVITINO_CI_RANGER_DOCKER_IMAGE");
public static final String HOST_NAME = "gravitino-ci-ranger";
public static final int RANGER_SERVER_PORT = 6080;
public RangerClient rangerClient;
public RangerClientExtend rangerClient;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed to RangerClientExtension.

return ImmutableList.of(
PolicyResource.DATABASE.getName(),
PolicyResource.TABLE.getName(),
PolicyResource.COLUMN.getName());
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed to singleton.

@jerryshao jerryshao merged commit aa988e1 into apache:main Sep 19, 2024
26 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[Subtask] Extended Apache Ranger authorization by configuration
5 participants