Skip to content

Conversation

jerqi
Copy link
Contributor

@jerqi jerqi commented Sep 25, 2024

What changes were proposed in this pull request?

Supports to grant or revoke privileges for a role

Why are the changes needed?

Fix: #4903

Does this PR introduce any user-facing change?

I will add the document later.

How was this patch tested?

Add the UT.

@jerqi jerqi force-pushed the ISSUE-4903 branch 2 times, most recently from 6b06613 to 32bb163 Compare September 25, 2024 12:04
@jerqi jerqi self-assigned this Sep 25, 2024
@jerqi
Copy link
Contributor Author

jerqi commented Sep 25, 2024

@lw-yang Could you help me review this pull request?

@jerqi jerqi force-pushed the ISSUE-4903 branch 3 times, most recently from fc4ee73 to 9e62ca7 Compare September 26, 2024 02:23
NoSuchRoleException.class,
() ->
metalake.revokePrivilegesFromRole(
"not-exist", metadataObject, Lists.newArrayList(Privileges.CreateCatalog.allow())));
Copy link
Contributor

Choose a reason for hiding this comment

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

Should you add the tests about binding wrong privileges to the metadata object?

Copy link
Contributor

Choose a reason for hiding this comment

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

You'd better add more bad cases to test the robustness of your logic.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added.

@@ -93,6 +94,10 @@ public Map<String, String> properties() {
*/
@Override
public List<SecurableObject> securableObjects() {
if (securableObjects == null) {
return Collections.emptyList();
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Will we return a null securableObjects here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Legacy code. Removed.

String.format("Doesn't support the type %s", object.type()));
}
}

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 we can create a helper method like this to simplify the code.

public static void check(final boolean expression, Supplier<? extends RuntimeException> exceptionToThrowSupplier) {
    if (!expression) {
        throw checkNotNull(exceptionToThrowSupplier).get();
    }
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

OK.


List<SecurableObject> updateSecurableObjects = Lists.newArrayList();
// Only update the first matched securable object privilege
for (SecurableObject securableObject : securableObjects) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Is it possible that there are many securable objects that equals to the object in the List?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, but it's enough that we add the first matched securable object like the comment.

Copy link
Contributor

Choose a reason for hiding this comment

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

Why not remove duplicated items in the roleEntity?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

OK, I can add the limitation for them.

Comment on lines 391 to 432
List<SecurableObject> updateSecurableObjects = Lists.newArrayList();
// Only update the first matched securable object privilege
for (SecurableObject securableObject : securableObjects) {
if (!objectExist
&& securableObject.type() == object.type()
&& securableObject.fullName().equals(object.fullName())) {
objectExist = true;
Set<Privilege> updatePrivileges = Sets.newHashSet();
updatePrivileges.addAll(securableObject.privileges());
// If privileges has granted, we won't generate the new securable object.
if (updatePrivileges.containsAll(privileges)) {
updateSecurableObjects.add(securableObject);
} else {
updatePrivileges.addAll(privileges);
SecurableObject newSecurableObject =
SecurableObjects.parse(
securableObject.fullName(),
securableObject.type(),
Lists.newArrayList(updatePrivileges));

updateSecurableObjects.add(newSecurableObject);
AuthorizationUtils.callAuthorizationPluginForMetadataObject(
metalake,
object,
authorizationPlugin -> {
authorizationPlugin.onRoleUpdated(
roleEntity,
RoleChange.updateSecurableObject(
role, securableObject, newSecurableObject));
});
}

} else {
updateSecurableObjects.add(securableObject);
}
}

// If the role doesn't contain the securable object, the role appends a new securable
// object.
if (!objectExist) {
SecurableObject securableObject =
SecurableObjects.parse(
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
List<SecurableObject> updateSecurableObjects = Lists.newArrayList();
// Only update the first matched securable object privilege
for (SecurableObject securableObject : securableObjects) {
if (!objectExist
&& securableObject.type() == object.type()
&& securableObject.fullName().equals(object.fullName())) {
objectExist = true;
Set<Privilege> updatePrivileges = Sets.newHashSet();
updatePrivileges.addAll(securableObject.privileges());
// If privileges has granted, we won't generate the new securable object.
if (updatePrivileges.containsAll(privileges)) {
updateSecurableObjects.add(securableObject);
} else {
updatePrivileges.addAll(privileges);
SecurableObject newSecurableObject =
SecurableObjects.parse(
securableObject.fullName(),
securableObject.type(),
Lists.newArrayList(updatePrivileges));
updateSecurableObjects.add(newSecurableObject);
AuthorizationUtils.callAuthorizationPluginForMetadataObject(
metalake,
object,
authorizationPlugin -> {
authorizationPlugin.onRoleUpdated(
roleEntity,
RoleChange.updateSecurableObject(
role, securableObject, newSecurableObject));
});
}
} else {
updateSecurableObjects.add(securableObject);
}
}
// If the role doesn't contain the securable object, the role appends a new securable
// object.
if (!objectExist) {
SecurableObject securableObject =
SecurableObjects.parse(
List<SecurableObject> updateSecurableObjects = Lists.newArrayList(securableObjects);
SecurableObject se =
securableObjects.stream().filter(securableObject -> securableObject.type() == object.type()
&& securableObject.fullName().equals(object.fullName()))
.findFirst().orElse(null);
if (se == null) {
SecurableObject securableObject =
SecurableObjects.parse(
object.fullName(), object.type(), Lists.newArrayList(privileges));
AuthorizationUtils.callAuthorizationPluginForMetadataObject(
metalake,
object,
authorizationPlugin -> {
authorizationPlugin.onRoleUpdated(
roleEntity, RoleChange.addSecurableObject(role, securableObject));
});
updateSecurableObjects.add(securableObject);
} else {
Set<Privilege> updatePrivileges = Sets.newHashSet();
updatePrivileges.addAll(se.privileges());
if (!updatePrivileges.containsAll(privileges)) {
updatePrivileges.addAll(privileges);
SecurableObject newSecurableObject =
SecurableObjects.parse(
se.fullName(),
se.type(),
Lists.newArrayList(updatePrivileges));
// Remove the old one and add the new one
updateSecurableObjects.remove(se);
updateSecurableObjects.add(newSecurableObject);
// Update the new newSecurableObject in the authorization plugin
AuthorizationUtils.callAuthorizationPluginForMetadataObject(
metalake,
object,
authorizationPlugin -> {
authorizationPlugin.onRoleUpdated(
roleEntity,
RoleChange.updateSecurableObject(
role, se, newSecurableObject));
});
}
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I rewrite here.

private List<String> toRoleNames(List<RoleEntity> roleEntities) {
return roleEntities.stream().map(RoleEntity::name).collect(Collectors.toList());
Role grantPrivilegeToRole(
String metalake, String role, MetadataObject object, List<Privilege> privileges) {
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 you need to check if these privileges can be bound to this metadata object before you update the role.

Copy link
Contributor

@jerryshao jerryshao Sep 27, 2024

Choose a reason for hiding this comment

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

Also I think you need to deduplicate the privileges if the user inputs the same privileges.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I deduplicate privileges in the PermissonManager.

Copy link
Contributor

Choose a reason for hiding this comment

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

What if two same privileges with one allow and one deny are both set, what will be happened and do you handle such scenario?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I add new check logic to avoid this case.

boolean objectExist = false;

List<SecurableObject> updateSecurableObjects = Lists.newArrayList();
// Only update the first matched securable object privilege
Copy link
Contributor

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 this comment?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

After discussing with Yuqi, I add more limitations. We won't have duplicated securable objects. So I remove this comment.

Lists.newArrayList(updatePrivileges));

updateSecurableObjects.add(newSecurableObject);
AuthorizationUtils.callAuthorizationPluginForMetadataObject(
Copy link
Contributor

Choose a reason for hiding this comment

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

Should you do this in the SQL transaction, or after the update is done?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

* @throws NoSuchMetadataObjectException If the metadata object with the given name does not
* exist.
* @throws NoSuchMetalakeException If the Metalake with the given name does not exist.
* @throws RuntimeException If revoking roles from a group encounters storage issues.
Copy link
Contributor

Choose a reason for hiding this comment

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

“grant”, not "revoke".

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed.

* @throws RuntimeException If revoking roles from a group encounters storage issues.
*/
public Role grantPrivilegeToRole(String role, MetadataObject object, List<Privilege> privileges)
throws NoSuchRoleException, NoSuchMetadataObjectException, NoSuchMetalakeException {
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 we should also add an exception about failed to grant/revoke privileges to role, because some privileges cannot be bound to some metadata objects.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I used IllegalArgumentException. WDYT?

Copy link
Contributor

Choose a reason for hiding this comment

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

OK.

Copy link
Contributor

Choose a reason for hiding this comment

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

On a second thought, maybe we should explicitly define an exception for illegal grant/revoke action, so that users will know better what issue it is, not implicitly thrown an exception here. Even for IllegalArgumentException I would suggest clearly define it.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

OK, I will do it.

* @throws NoSuchMetadataObjectException If the metadata object with the given name does not
* exist.
* @throws NoSuchMetalakeException If the Metalake with the given name does not exist.
* @throws RuntimeException If revoking roles from a group encounters storage issues.
Copy link
Contributor

Choose a reason for hiding this comment

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

Check all the codes to make sure no such error for "grant" or "revoke".

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed.


Preconditions.checkArgument(
securableObjects != null && securableObjects.length != 0,
"\"securableObjects\" can't null or empty");
Copy link
Contributor

@jerryshao jerryshao Sep 29, 2024

Choose a reason for hiding this comment

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

Can you add a UT and IT about the changes here, to check to create a role with empty/null privilege?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added.

* @return The role after granted.
* @throws NoSuchRoleException If the role with the given name does not exist.
* @throws NoSuchMetalakeException If the Metalake with the given name does not exist.
* @throws RuntimeException If revoking roles from a group encounters storage issues.
Copy link
Contributor

Choose a reason for hiding this comment

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

Also here...

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed.

.withAuditInfo(auditInfo)
.withSecurableObjects(updateSecurableObjects)
.build();
});
Copy link
Contributor

Choose a reason for hiding this comment

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

The update logic here is too long, you'd better split into several helper methods.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

List<SecurableObject> securableObjects = roleEntity.securableObjects();

List<SecurableObject> updateSecurableObjects = Lists.newArrayList();
// Remove all the matching securable object privileges
Copy link
Contributor

Choose a reason for hiding this comment

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

What if all the securable object are not matched, or the privileges are not/partially matched, should you at least add some logs?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added.

.build();
});
} catch (NoSuchEntityException nse) {
LOG.warn("Failed to revoke, role {} does not exist in the metalake {}", role, metalake, nse);
Copy link
Contributor

Choose a reason for hiding this comment

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

error

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed.


List<SecurableObject> updateSecurableObjects = Lists.newArrayList();
// Only update the first matched securable object privilege
for (SecurableObject securableObject : securableObjects) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Why not remove duplicated items in the roleEntity?

* @throws RuntimeException If revoking roles from a group encounters storage issues.
*/
public Role grantPrivilegeToRole(String role, MetadataObject object, List<Privilege> privileges)
throws NoSuchRoleException, NoSuchMetadataObjectException, NoSuchMetalakeException {
Copy link
Contributor

Choose a reason for hiding this comment

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

On a second thought, maybe we should explicitly define an exception for illegal grant/revoke action, so that users will know better what issue it is, not implicitly thrown an exception here. Even for IllegalArgumentException I would suggest clearly define it.

private List<String> toRoleNames(List<RoleEntity> roleEntities) {
return roleEntities.stream().map(RoleEntity::name).collect(Collectors.toList());
Role grantPrivilegeToRole(
String metalake, String role, MetadataObject object, List<Privilege> privileges) {
Copy link
Contributor

Choose a reason for hiding this comment

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

What if two same privileges with one allow and one deny are both set, what will be happened and do you handle such scenario?

object.type(),
Lists.newArrayList(privileges));

authorizationPluginCallbackWrapper.setCallBack(
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we do this out of SQL transaction, this will hurt the performance and lead to unexpected behavior if we put it here.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This place we only set the callback. After we execute SQL transaction, we execute the callbak.

if (updatePrivileges.containsAll(privileges)) {
return oldObject;
} else {
updatePrivileges.addAll(privileges);
Copy link
Contributor

Choose a reason for hiding this comment

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

Should you check the allow and deny of the privileges here?

Also, do you need to check if the privileges are inclusive or exclusive, so you don't have store some particular privileges to the storage?

Copy link
Contributor Author

@jerqi jerqi Oct 8, 2024

Choose a reason for hiding this comment

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

  1. If the privilege have the same Name , but it have different conditions. They are different privileges.
  2. I don't know the meaning about inclusive or exclusive.
    If you mean the case about use schema and select table, we don't check it in the granting or revoking operations.
    If you mean the case about schema's select table and table's select table, we don't check it, too. grant/revoke operation is effect on a specific object, schema and table are different objects.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

OK, I will check the privileges. We don't allow the same name privilege is allowed and denied at the same time.

.withAuditInfo(auditInfo)
.withSecurableObjects(updateSecurableObjects)
.build();
});
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 method is still too big, you need to split it into some methods.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Already splitted.

object.fullName(),
object.type(),
role);
return null;
Copy link
Contributor

Choose a reason for hiding this comment

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

What will be happened in the client side when we return a null object?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is updater. If this return null, we don't include the the new object.

// securable object. Remove duplicated privileges
Set<Privilege> updatePrivileges = Sets.newHashSet();
updatePrivileges.addAll(oldObject.privileges());
privileges.forEach(updatePrivileges::remove);
Copy link
Contributor

Choose a reason for hiding this comment

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

The same question here, some privileges are not exactly the same, but they're inclusive, should you handle this problem?

RoleChange.removeSecurableObject(role, oldObject));
}));

return null;
Copy link
Contributor

Choose a reason for hiding this comment

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

Also here, it would be better to 1) simplify the current method to split into several small methods; 2) move the callback out of transaction to avoid transaction block.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I will split it.


// We set authorization callback here, we won't execute this callback in this place.
// We will execute the callback after we execute the SQL transaction.
authorizationPluginCallbackWrapper.setCallBack(
Copy link
Contributor

Choose a reason for hiding this comment

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

Callback is a word, please change to Callback.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

OK.


return newSecurableObject;
} else {
// If the object doesn't contain any privilege, we remove this object.
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 need to remove this in the database?

Copy link
Contributor Author

@jerqi jerqi Oct 8, 2024

Choose a reason for hiding this comment

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

We have removed the object in the database in the current logic.

Function<SecurableObject, SecurableObject> objectUpdater) {
boolean isExist = false;
List<SecurableObject> updateSecurableObjects = Lists.newArrayList();
for (SecurableObject securableObject : securableObjects) {
Copy link
Contributor

@jerryshao jerryshao Oct 8, 2024

Choose a reason for hiding this comment

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

Do we support updating multiple securable objects in one time? I don't quite understand the code here, can you please explain more?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We don't support to update multiple securable objects. We find one target securable object and update the privileges of the obejct.

Copy link
Contributor

@jerryshao jerryshao Oct 8, 2024

Choose a reason for hiding this comment

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

If we don't support, why don't we just search the matched securable object and update it, no need to do this in a loop add a flag?

For example:

securableObject = get matched securableObject
updater.apply(securableOject)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The method name isn't good. I should generate all the securable objects for the role. I changed to

generateNewSecurableObjects

And I tune the logic of this method and I make it clear.

Copy link
Contributor

Choose a reason for hiding this comment

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

   List<SecurableObject> updateSecurableObjects = Lists.newArrayList(securableObjects);
    SecurableObject matchedSecurableObject = securableObjects.stream().filter(targetObject::equals).findFirst().orElse(null);
    if (matchedSecurableObject != null) {
      updateSecurableObjects.remove(matchedSecurableObject);
    }

This may be more efficient that the above.

Entity.EntityType.ROLE,
roleEntity -> {
List<SecurableObject> updateSecurableObjects =
updateSecurableObjects(
Copy link
Contributor

Choose a reason for hiding this comment

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

The variable here is the same as method name, can you change to a different name?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

changed to grantedSecurableObjects.

MetadataObject targetObject,
Function<SecurableObject, SecurableObject> objectUpdater) {
boolean isExist = false;
List<SecurableObject> updateSecurableObjects = Lists.newArrayList();
Copy link
Contributor

Choose a reason for hiding this comment

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

Also here, can you use a different name?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Changed to RevokedSecurableObjects.


// If there not exists a securable object matching the target object.
if (!isExist) {
SecurableObject newSecurableObject = objectUpdater.apply(null);
Copy link
Contributor

Choose a reason for hiding this comment

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

From the code I saw that if the input is null, then the output of this function is always null, can you please confirm this?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

In grant method, if apply null, we will return a new created object.

Comment on lines 218 to 227
for (SecurableObjectPO objectPO : deleteSecurableObjectPOS) {
SessionUtils.doWithoutCommit(
SecurableObjectMapper.class,
mapper ->
mapper.softDeleteSecurableObjectsByObjectIdAndPrivileges(
objectPO.getRoleId(),
objectPO.getMetadataObjectId(),
objectPO.getPrivilegeConditions(),
objectPO.getPrivilegeNames()));
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we do this in a batch?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I tried. It's ok to use batch.

Function<SecurableObject, SecurableObject> objectUpdater) {
boolean isExist = false;
List<SecurableObject> updateSecurableObjects = Lists.newArrayList();
for (SecurableObject securableObject : securableObjects) {
Copy link
Contributor

Choose a reason for hiding this comment

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

   List<SecurableObject> updateSecurableObjects = Lists.newArrayList(securableObjects);
    SecurableObject matchedSecurableObject = securableObjects.stream().filter(targetObject::equals).findFirst().orElse(null);
    if (matchedSecurableObject != null) {
      updateSecurableObjects.remove(matchedSecurableObject);
    }

This may be more efficient that the above.

List<Privilege> privileges,
RoleEntity roleEntity,
AuthorizationPluginCallbackWrapper authorizationPluginCallbackWrapper) {
// Add a new securable object if there not exists the object in the role
Copy link
Contributor

Choose a reason for hiding this comment

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

if there doesn't exist the...

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed.

return newRoleEntity;
}

List<SecurableObjectPO> deleteSecurableObjectPOS =
Copy link
Contributor

Choose a reason for hiding this comment

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

"POs", not "POS"

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed.

}
}

private List<SecurableObjectPO> toSecurablePOs(
Copy link
Contributor

Choose a reason for hiding this comment

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

toSecurableObjectPOs

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed.

@jerryshao
Copy link
Contributor

Generally LGTM, @yuqi1129 can you please take another look at this PR?

Copy link
Contributor

@yuqi1129 yuqi1129 left a comment

Choose a reason for hiding this comment

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

Some minor ones, others LGTM.

LOG.error("Failed to revoke, role {} does not exist in the metalake {}", role, metalake, nse);
throw new NoSuchRoleException(ROLE_DOES_NOT_EXIST_MSG, role, metalake);
} catch (IOException ioe) {
throw new RuntimeException(ioe);
Copy link
Contributor

Choose a reason for hiding this comment

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

I noticed that you have logged NoSuchEntityException. Why don't you also add logs here? Do you have any other considerations?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added the log.

updatePrivileges.addAll(targetObject.privileges());
privileges.forEach(updatePrivileges::remove);

// If the object still contain privilege, we should update the object
Copy link
Contributor

Choose a reason for hiding this comment

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

contain -> contains

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed.

for (Privilege privilege : privileges) {
if (privilegeNameSet.contains(privilege.name())) {
throw new IllegalPrivilegeException(
"Doesn't support duplicated privilege name %s with different condition",
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 output all the duplicated privilege names , not just one of them?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This should be unnecessary. It will be allow and deny the privilege name.

Copy link
Contributor

@yuqi1129 yuqi1129 left a comment

Choose a reason for hiding this comment

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

Some minor ones, others LGTM.

"Catalog %s type %s don't support privilege %s",
catalogIdent, catalog.type(), privilege));
throw new IllegalPrivilegeException(
"Catalog %s type %s don't support privilege %s", catalogIdent, catalog.type(), privilege);
Copy link
Contributor

Choose a reason for hiding this comment

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

"doesn't support..."

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed.

Copy link
Contributor

@yuqi1129 yuqi1129 left a comment

Choose a reason for hiding this comment

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

LGTM

@jerryshao jerryshao merged commit 75ec8ae into apache:main Oct 9, 2024
26 checks passed
@jerryshao
Copy link
Contributor

@jerqi the cherry-pick is failed, please do it manually against branch-0.6.

jerqi added a commit to qqqttt123/gravitino that referenced this pull request Oct 9, 2024
…s for a role (apache#5021)

Supports to grant or revoke privileges for  a role

Fix: apache#4903

I will add the document later.

Add the UT.
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.

[Improvement] Supports to grant and revoke privilege for a role
3 participants