-
Notifications
You must be signed in to change notification settings - Fork 392
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
[#3342] feat(core): Refactor the role and privilege model #3389
Conversation
612ee96
to
8828bf6
Compare
@jerqi is this ready for review? |
* means that you are denied to use the privilege. If you have `ALLOW` and `DENY` for the same | ||
* privilege name of the same securable object, the `DENY` will take effect. | ||
*/ | ||
enum Effect { |
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.
What do other systems like Ranger describe this behavior, do they use Effect
or other better word?
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.
Gravitiy use the word Effect
in their api.
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.
Ranger use Allow conditions
and Deny conditions
.
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 prefer to use "Condition" than "Effect".
* | ||
* @param privilege The string representation of the privilege. | ||
* @return The Privilege. | ||
*/ | ||
public static Privilege fromString(String privilege) { | ||
public static Privilege allowPrivilegeFromString(String 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 think the method name is a little verbose, maybe we can change to like:
public Privilege allow(String name);
public Privilege allow(Privilege.Name name);
public Privilege deny(String name);
public Privilege deny(Privilege.Name name);
* | ||
* @return The privileges of the role. | ||
*/ | ||
List<Privilege> privileges(); |
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.
Are these privileges inheritable in your current design?
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.
They are not inheritable.
api/src/main/java/com/datastrato/gravitino/authorization/SecurableObject.java
Outdated
Show resolved
Hide resolved
api/src/main/java/com/datastrato/gravitino/authorization/SecurableObjects.java
Outdated
Show resolved
Hide resolved
@Override | ||
public void bindPrivileges(List<Privilege> privileges) { | ||
this.privileges = privileges.stream().map(DTOConverters::toDTO).toArray(PrivilegeDTO[]::new); | ||
} |
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 interface (securable object) you designed and achieved here in DTO is a bit weird, who and when will call this method?
It is because your SecurableObject
has both getter and setter interfaces, it is mutable as the interface design. But DTO is immutable, so the interface design will make the DTO implementation a bit weird. I would suggest you rethink about how to design this SecurableObject
based on our UI requirement as well as code itself.
@@ -250,21 +250,16 @@ public boolean isMetalakeAdmin(String user) { | |||
* @param role The name of the Role. | |||
* @param properties The properties of the Role. | |||
* @param securableObject The securable object of the Role. | |||
* @param privileges The privileges of the Role. | |||
* @return The created Role instance. | |||
* @throws RoleAlreadyExistsException If a Role with the same name already exists. | |||
* @throws NoSuchMetalakeException If the Metalake with the given name does not exist. | |||
* @throws RuntimeException If creating the Role encounters storage issues. | |||
*/ | |||
public Role createRole( |
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 support add new securable object to the existing role?
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.
Now, we don't support it. We can support it in the future.
AuditInfo audit_info = 7; | ||
repeated string privilege_effects = 4; | ||
string securable_object_full_name = 5; | ||
string securable_object_type = 6; |
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 would suggest you support multiple securable objects here, otherwise you need to update the storage structure later on, which is hard to do so.
In the meantime, since you changed the definition of securable object, should you also update the layout 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.
Will you leave this storage part to 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.
Yes, I will leave the storage to the next PR.
After last review,
Could you give me further review? @jerryshao |
/** | ||
* The privileges of the securable object. For example: If the securable object is a table, the | ||
* privileges could be `READ TABLE`, `WRITE TABLE`, etc. If a schema has the privilege of `LOAD | ||
* TABLE`. It means the role can all tables of the schema. |
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.
“It means the role can 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.
public static SecurableObject ofSchema(SecurableObject catalog, String schema) { | ||
checkCatalog(catalog); | ||
public static SecurableObject ofSchema( | ||
String catalogFullName, String schema, List<Privilege> privileges) { |
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.
What's the meaning of catalogFullName?
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 do we represent the full name of the catalog, schema, etc, "a.b.c"? I think it will be better to use a class to restrict the format of the full name, otherwise, it is hard for users to formalize the input string.
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 replace this by securable object.
.map( | ||
privilege -> { | ||
return PrivilegeDTO.builder() | ||
.withEffect(privilege.condition()) |
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.
It should be changed to withCondition
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.
@JsonProperty("name") | ||
private Name name; | ||
|
||
@JsonProperty("effect") |
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 should also be updated.
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.
AuditInfo audit_info = 7; | ||
repeated string privilege_effects = 4; | ||
string securable_object_full_name = 5; | ||
string securable_object_type = 6; |
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 you leave this storage part to the next PR?
|
||
SecurableObjectImpl(SecurableObject parent, String name, Type type) { | ||
this.parent = parent; | ||
SecurableObjectImpl(String parentFullName, String name, Type type, List<Privilege> privileges) { |
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.
What is the purpose of using parentFullName
instead of SecurableObject parent
? How about using NameIdentifier for unification?
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.
NameIdentifier will include the information of the metalake.
|
||
return new SecurableObjectImpl(null, metalake, SecurableObject.Type.METALAKE); | ||
return new SecurableObjectImpl(null, metalake, SecurableObject.Type.METALAKE, privileges); |
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 use SecurableObject.of(xxx)
, that has some checks before creating a securable object.
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.
@@ -138,6 +138,7 @@ CREATE TABLE IF NOT EXISTS `role_meta` ( | |||
`securable_object_full_name` VARCHAR(256) NOT NULL COMMENT 'securable object full name', | |||
`securable_object_type` VARCHAR(32) NOT NULL COMMENT 'securable object type', | |||
`privileges` VARCHAR(64) NOT NULL COMMENT 'securable privileges', | |||
`privilege_conditions` VARCHAR(64) NOT NULL COMMENT 'securable privilege conditions', |
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 you leave the multiple securable object support 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.
Yes, I will
@jerryshao Could you review again? |
return GetRole.deny(); | ||
|
||
default: | ||
throw new IllegalArgumentException("Don't support the privilege: " + 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.
“Doesn't...”
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.
case GET_ROLE: | ||
return GetRole.get(); | ||
return GetRole.allow(); | ||
|
||
default: | ||
throw new IllegalArgumentException("Don't support the privilege: " + 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.
“Doesn't support...”
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.
*/ | ||
@Nullable | ||
SecurableObject parent(); | ||
String parentFullName(); |
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 use String parent()
, which seems simpler, WDYT?
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, maybe it's enough for us to tell user this is a full name string.
@jerryshao Comments are addressed. |
### What changes were proposed in this pull request? Add support for ALLOW/DENY effect for privileges. Move privileges from the role to the securable object. ### Why are the changes needed? Fix: #3342 ### Does this PR introduce _any_ user-facing change? Yes. ### How was this patch tested? UT passed. --------- Co-authored-by: Heng Qin <[email protected]>
…he#3389) ### What changes were proposed in this pull request? Add support for ALLOW/DENY effect for privileges. Move privileges from the role to the securable object. ### Why are the changes needed? Fix: apache#3342 ### Does this PR introduce _any_ user-facing change? Yes. ### How was this patch tested? UT passed. --------- Co-authored-by: Heng Qin <[email protected]>
What changes were proposed in this pull request?
Add support for ALLOW/DENY effect for privileges.
Move privileges from the role to the securable object.
Why are the changes needed?
Fix: #3342
Does this PR introduce any user-facing change?
Yes.
How was this patch tested?
UT passed.