Skip to content

Commit

Permalink
[#5162] Add grant and revoke privileges to the Gravitino CLI. (#5783)
Browse files Browse the repository at this point in the history
### What changes were proposed in this pull request?

Add grant and revoke privileges to the Gravitino CLI.

### Why are the changes needed?

To complete the role commands.

Fix: #5162

### Does this PR introduce _any_ user-facing change?

No but it adds two more commands.

### How was this patch tested?

Tested locally.
  • Loading branch information
justinmclean authored Dec 19, 2024
1 parent 61c2d87 commit 7ad9377
Show file tree
Hide file tree
Showing 12 changed files with 601 additions and 5 deletions.
13 changes: 13 additions & 0 deletions clients/cli/src/main/java/org/apache/gravitino/cli/FullName.java
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,19 @@ public String getColumnName() {
return getNamePart(3);
}

/**
* Retrieves the name from the command line options.
*
* @return The name, or null if not found.
*/
public String getName() {
if (line.hasOption(GravitinoOptions.NAME)) {
return line.getOptionValue(GravitinoOptions.NAME);
}

return null;
}

/**
* Helper method to retrieve a specific part of the full name based on the position of the part.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -672,6 +672,7 @@ protected void handleRoleCommand() {
FullName name = new FullName(line);
String metalake = name.getMetalakeName();
String role = line.getOptionValue(GravitinoOptions.ROLE);
String[] privileges = line.getOptionValues(GravitinoOptions.PRIVILEGE);

Command.setAuthenticationMode(auth, userName);

Expand All @@ -697,6 +698,14 @@ protected void handleRoleCommand() {
newDeleteRole(url, ignore, forceDelete, metalake, role).handle();
break;

case CommandActions.GRANT:
newGrantPrivilegesToRole(url, ignore, metalake, role, name, privileges).handle();
break;

case CommandActions.REVOKE:
newRevokePrivilegesFromRole(url, ignore, metalake, role, name, privileges).handle();
break;

default:
System.err.println(ErrorMessages.UNSUPPORTED_ACTION);
break;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ public class GravitinoOptions {
public static final String OWNER = "owner";
public static final String PARTITION = "partition";
public static final String POSITION = "position";
public static final String PRIVILEGE = "privilege";
public static final String PROPERTIES = "properties";
public static final String PROPERTY = "property";
public static final String PROVIDER = "provider";
Expand Down Expand Up @@ -105,6 +106,7 @@ public Options options() {
// Options that support multiple values
options.addOption(createArgsOption("p", PROPERTIES, "property name/value pairs"));
options.addOption(createArgsOption("t", TAG, "tag name"));
options.addOption(createArgsOption(null, PRIVILEGE, "privilege(s)"));
options.addOption(createArgsOption("r", ROLE, "role name"));

// Force delete entities and rename metalake operations
Expand Down
119 changes: 119 additions & 0 deletions clients/cli/src/main/java/org/apache/gravitino/cli/Privileges.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
/*
* 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.cli;

import java.util.HashSet;
import org.apache.gravitino.authorization.Privilege;

public class Privileges {
public static final String CREATE_CATALOG = "create_catalog";
public static final String USE_CATALOG = "use_catalog";
public static final String CREATE_SCHEMA = "create_schema";
public static final String USE_SCHEMA = "use_schema";
public static final String CREATE_TABLE = "create_table";
public static final String MODIFY_TABLE = "modify_table";
public static final String SELECT_TABLE = "select_table";
public static final String CREATE_FILESET = "create_fileset";
public static final String WRITE_FILESET = "write_fileset";
public static final String READ_FILESET = "read_fileset";
public static final String CREATE_TOPIC = "create_topic";
public static final String PRODUCE_TOPIC = "produce_topic";
public static final String CONSUME_TOPIC = "consume_topic";
public static final String MANAGE_USERS = "manage_users";
public static final String CREATE_ROLE = "create_role";
public static final String MANAGE_GRANTS = "manage_grants";

private static final HashSet<String> VALID_PRIVILEGES = new HashSet<>();

static {
VALID_PRIVILEGES.add(CREATE_CATALOG);
VALID_PRIVILEGES.add(USE_CATALOG);
VALID_PRIVILEGES.add(CREATE_SCHEMA);
VALID_PRIVILEGES.add(USE_SCHEMA);
VALID_PRIVILEGES.add(CREATE_TABLE);
VALID_PRIVILEGES.add(MODIFY_TABLE);
VALID_PRIVILEGES.add(SELECT_TABLE);
VALID_PRIVILEGES.add(CREATE_FILESET);
VALID_PRIVILEGES.add(WRITE_FILESET);
VALID_PRIVILEGES.add(READ_FILESET);
VALID_PRIVILEGES.add(CREATE_TOPIC);
VALID_PRIVILEGES.add(PRODUCE_TOPIC);
VALID_PRIVILEGES.add(CONSUME_TOPIC);
VALID_PRIVILEGES.add(MANAGE_USERS);
VALID_PRIVILEGES.add(CREATE_ROLE);
VALID_PRIVILEGES.add(MANAGE_GRANTS);
}

/**
* Checks if a given privilege is a valid one.
*
* @param privilege The privilege to check.
* @return true if the privilege is valid, false otherwise.
*/
public static boolean isValid(String privilege) {
return VALID_PRIVILEGES.contains(privilege);
}

/**
* Converts a string representation of a privilege to the corresponding {@link Privilege.Name}.
*
* @param privilege the privilege to be converted.
* @return the corresponding {@link Privilege.Name} constant, or nullif the privilege is unknown.
*/
public static Privilege.Name toName(String privilege) {
switch (privilege) {
case CREATE_CATALOG:
return Privilege.Name.CREATE_CATALOG;
case USE_CATALOG:
return Privilege.Name.USE_CATALOG;
case CREATE_SCHEMA:
return Privilege.Name.CREATE_SCHEMA;
case USE_SCHEMA:
return Privilege.Name.USE_SCHEMA;
case CREATE_TABLE:
return Privilege.Name.CREATE_TABLE;
case MODIFY_TABLE:
return Privilege.Name.MODIFY_TABLE;
case SELECT_TABLE:
return Privilege.Name.SELECT_TABLE;
case CREATE_FILESET:
return Privilege.Name.CREATE_FILESET;
case WRITE_FILESET:
return Privilege.Name.WRITE_FILESET;
case READ_FILESET:
return Privilege.Name.READ_FILESET;
case CREATE_TOPIC:
return Privilege.Name.CREATE_TOPIC;
case PRODUCE_TOPIC:
return Privilege.Name.PRODUCE_TOPIC;
case CONSUME_TOPIC:
return Privilege.Name.CONSUME_TOPIC;
case MANAGE_USERS:
return Privilege.Name.MANAGE_USERS;
case CREATE_ROLE:
return Privilege.Name.CREATE_ROLE;
case MANAGE_GRANTS:
return Privilege.Name.MANAGE_GRANTS;
default:
System.err.println("Unknown privilege");
return null;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
import org.apache.gravitino.cli.commands.DeleteTopic;
import org.apache.gravitino.cli.commands.DeleteUser;
import org.apache.gravitino.cli.commands.FilesetDetails;
import org.apache.gravitino.cli.commands.GrantPrivilegesToRole;
import org.apache.gravitino.cli.commands.GroupAudit;
import org.apache.gravitino.cli.commands.GroupDetails;
import org.apache.gravitino.cli.commands.ListAllTags;
Expand Down Expand Up @@ -85,6 +86,7 @@
import org.apache.gravitino.cli.commands.RemoveTableProperty;
import org.apache.gravitino.cli.commands.RemoveTagProperty;
import org.apache.gravitino.cli.commands.RemoveTopicProperty;
import org.apache.gravitino.cli.commands.RevokePrivilegesFromRole;
import org.apache.gravitino.cli.commands.RoleAudit;
import org.apache.gravitino.cli.commands.RoleDetails;
import org.apache.gravitino.cli.commands.SchemaAudit;
Expand Down Expand Up @@ -862,4 +864,24 @@ protected CreateTable newCreateTable(
String comment) {
return new CreateTable(url, ignore, metalake, catalog, schema, table, columnFile, comment);
}

protected GrantPrivilegesToRole newGrantPrivilegesToRole(
String url,
boolean ignore,
String metalake,
String role,
FullName entity,
String[] privileges) {
return new GrantPrivilegesToRole(url, ignore, metalake, role, entity, privileges);
}

protected RevokePrivilegesFromRole newRevokePrivilegesFromRole(
String url,
boolean ignore,
String metalake,
String role,
FullName entity,
String[] privileges) {
return new RevokePrivilegesFromRole(url, ignore, metalake, role, entity, privileges);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
/*
* 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.cli.commands;

import java.util.ArrayList;
import java.util.List;
import org.apache.gravitino.MetadataObject;
import org.apache.gravitino.authorization.Privilege;
import org.apache.gravitino.cli.ErrorMessages;
import org.apache.gravitino.cli.FullName;
import org.apache.gravitino.cli.Privileges;
import org.apache.gravitino.client.GravitinoClient;
import org.apache.gravitino.dto.authorization.PrivilegeDTO;
import org.apache.gravitino.exceptions.NoSuchMetadataObjectException;
import org.apache.gravitino.exceptions.NoSuchMetalakeException;
import org.apache.gravitino.exceptions.NoSuchRoleException;

/** Grants one or more privileges. */
public class GrantPrivilegesToRole extends MetadataCommand {

protected final String metalake;
protected final String role;
protected final FullName entity;
protected final String[] privileges;

/**
* Grants one or more privileges.
*
* @param url The URL of the Gravitino server.
* @param ignoreVersions If true don't check the client/server versions match.
* @param metalake The name of the metalake.
* @param role The name of the role.
* @param entity The name of the entity.
* @param privileges The list of privileges.
*/
public GrantPrivilegesToRole(
String url,
boolean ignoreVersions,
String metalake,
String role,
FullName entity,
String[] privileges) {
super(url, ignoreVersions);
this.metalake = metalake;
this.entity = entity;
this.role = role;
this.privileges = privileges;
}

/** Grants one or more privileges. */
@Override
public void handle() {
try {
GravitinoClient client = buildClient(metalake);
List<Privilege> privilegesList = new ArrayList<>();

for (String privilege : privileges) {
if (!Privileges.isValid(privilege)) {
System.err.println("Unknown privilege " + privilege);
return;
}
PrivilegeDTO privilegeDTO =
PrivilegeDTO.builder()
.withName(Privileges.toName(privilege))
.withCondition(Privilege.Condition.ALLOW)
.build();
privilegesList.add(privilegeDTO);
}

MetadataObject metadataObject = constructMetadataObject(entity, client);
client.grantPrivilegesToRole(role, metadataObject, privilegesList);
} catch (NoSuchMetalakeException err) {
System.err.println(ErrorMessages.UNKNOWN_METALAKE);
return;
} catch (NoSuchRoleException err) {
System.err.println(ErrorMessages.UNKNOWN_ROLE);
return;
} catch (NoSuchMetadataObjectException err) {
System.err.println(ErrorMessages.UNKNOWN_USER);
return;
} catch (Exception exp) {
System.err.println(exp.getMessage());
return;
}

String all = String.join(",", privileges);
System.out.println(role + " granted " + all + " on " + entity.getName());
}
}
Loading

0 comments on commit 7ad9377

Please sign in to comment.