Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/main' into iceberg-load-properties
Browse files Browse the repository at this point in the history
  • Loading branch information
caican00 committed Apr 16, 2024
2 parents 330b36e + 1db59d7 commit bc96f6b
Show file tree
Hide file tree
Showing 77 changed files with 2,521 additions and 420 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/*
* Copyright 2024 Datastrato Pvt Ltd.
* This software is licensed under the Apache License version 2.
*/
package com.datastrato.gravitino.authorization;

import com.datastrato.gravitino.annotation.Evolving;

/**
* The interface of a privilege. The privilege represents the ability to execute kinds of operations
* for kinds of entities
*/
@Evolving
public interface Privilege {

/** @return The generic name of the privilege. */
Name name();

/** @return A readable string representation for the privilege. */
String simpleString();

/** The name of this privilege. */
enum Name {
/** The privilege of load a catalog. */
LOAD_CATALOG
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/*
* Copyright 2024 Datastrato Pvt Ltd.
* This software is licensed under the Apache License version 2.
*/
package com.datastrato.gravitino.authorization;

/** The helper class for {@link Privilege}. */
public class Privileges {

/**
* Returns the Privilege from the string representation.
*
* @param privilege The string representation of the privilege.
* @return The Privilege.
*/
public static Privilege fromString(String privilege) {
Privilege.Name name = Privilege.Name.valueOf(privilege);
return fromName(name);
}

/**
* Returns the Privilege from the `Privilege.Name`.
*
* @param name The `Privilege.Name` of the privilege.
* @return The Privilege.
*/
public static Privilege fromName(Privilege.Name name) {
switch (name) {
case LOAD_CATALOG:
return LoadCatalog.get();
default:
throw new IllegalArgumentException("Don't support the privilege: " + name);
}
}

/** The privilege of load a catalog. */
public static class LoadCatalog implements Privilege {
private static final LoadCatalog INSTANCE = new LoadCatalog();

/** @return The instance of the privilege. */
public static LoadCatalog get() {
return INSTANCE;
}

private LoadCatalog() {}

/** @return The generic name of the privilege. */
@Override
public Name name() {
return Name.LOAD_CATALOG;
}

/** @return A readable string representation for the privilege. */
@Override
public String simpleString() {
return "load catalog";
}
}
}
51 changes: 51 additions & 0 deletions api/src/main/java/com/datastrato/gravitino/authorization/Role.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* Copyright 2024 Datastrato Pvt Ltd.
* This software is licensed under the Apache License version 2.
*/
package com.datastrato.gravitino.authorization;

import com.datastrato.gravitino.Auditable;
import com.datastrato.gravitino.annotation.Evolving;
import java.util.List;
import java.util.Map;

/**
* The interface of a role. The role is the entity which has kinds of privileges. One role can have
* multiple privileges of one securable object. Gravitino chooses to bind one securable object to
* one role to avoid granting too many privileges to one role.
*/
@Evolving
public interface Role extends Auditable {

/**
* The name of the role.
*
* @return The name of the role.
*/
String name();

/**
* The properties of the role. Note, this method will return null if the properties are not set.
*
* @return The properties of the role.
*/
Map<String, String> properties();

/**
* The privileges of the role. All privileges belong to one 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.
*
* @return The privileges of the role.
*/
List<Privilege> privileges();

/**
* The securable object represents a special kind of entity with a unique identifier. All
* securable objects are organized by tree structure. For example: If the securable object is a
* table, the identifier may be `catalog1.schema1.table1`.
*
* @return The securable object of the role.
*/
SecurableObject securableObject();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
* Copyright 2024 Datastrato Pvt Ltd.
* This software is licensed under the Apache License version 2.
*/
package com.datastrato.gravitino.authorization;

import com.datastrato.gravitino.annotation.Evolving;
import javax.annotation.Nullable;

/**
* The securable object is the entity which access can be granted. Unless allowed by a grant, access
* is denied. Gravitino organizes the securable objects using tree structure. The securable object
* may be a catalog, a table or a schema, etc. For example, `catalog1.schema1.table1` represents a
* table named `table1`. It's in the schema named `schema1`. The schema is in the catalog named
* `catalog1`. Similarly, `catalog1.schema1.topic1` can represent a topic.
* `catalog1.schema1.fileset1` can represent a fileset. `*` represents all the catalogs. If you want
* to use other securable objects which represents all entities," you can use their parent entity,
* For example if you want to have read table privileges of all tables of `catalog1.schema1`, " you
* can use add `read table` privilege for `catalog1.schema1` directly
*/
@Evolving
public interface SecurableObject {

/**
* The parent securable object. If the securable object doesn't have parent, this method will
* return null.
*
* @return The parent securable object.
*/
@Nullable
SecurableObject parent();

/**
* The name of th securable object.
*
* @return The name of the securable object.
*/
String name();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
/*
* Copyright 2024 Datastrato Pvt Ltd.
* This software is licensed under the Apache License version 2.
*/
package com.datastrato.gravitino.authorization;

import java.util.Objects;

/** The helper class for {@link SecurableObject}. */
public class SecurableObjects {

/**
* Create the {@link SecurableObject} with the given names.
*
* @param names The names of the securable object.
* @return The created {@link SecurableObject}
*/
public static SecurableObject of(String... names) {
if (names == null) {
throw new IllegalArgumentException("Cannot create a securable object with null names");
}

if (names.length == 0) {
throw new IllegalArgumentException("Cannot create a securable object with no names");
}

SecurableObject parent = null;
for (String name : names) {
if (name == null) {
throw new IllegalArgumentException("Cannot create a securable object with null name");
}

if (name.equals("*")) {
throw new IllegalArgumentException(
"Cannot create a securable object with `*` name. If you want to use a securable object which represents all catalogs,"
+ " you use the method `ofAllCatalogs`."
+ " If you want to create an another securable object which represents all entities,"
+ " you can use its parent entity, For example,"
+ " if you want to have read table privileges of all tables of `catalog1.schema1`,"
+ " you can use add `read table` privilege for `catalog1.schema1` directly");
}

parent = new SecurableObjectImpl(parent, name);
}

return parent;
}

/**
* Create the catalog {@link SecurableObject} with the given catalog name.
*
* @param catalog The catalog name
* @return The created catalog {@link SecurableObject}
*/
public static SecurableObject ofCatalog(String catalog) {
return of(catalog);
}

/**
* Create the schema {@link SecurableObject} with the given securable catalog object and schema
* name.
*
* @param catalog The securable catalog object
* @param schema The schema name
* @return The created schema {@link SecurableObject}
*/
public static SecurableObject ofSchema(SecurableObject catalog, String schema) {
checkCatalog(catalog);

return of(catalog.name(), schema);
}

/**
* Create the table {@link SecurableObject} with the given securable schema object and table name.
*
* @param schema The securable schema object
* @param table The table name
* @return The created table {@link SecurableObject}
*/
public static SecurableObject ofTable(SecurableObject schema, String table) {
checkSchema(schema);

return of(schema.parent().name(), schema.name(), table);
}

/**
* Create the topic {@link SecurableObject} with the given securable schema object and topic name.
*
* @param schema The securable schema object
* @param topic The topic name
* @return The created topic {@link SecurableObject}
*/
public static SecurableObject ofTopic(SecurableObject schema, String topic) {
checkSchema(schema);

return of(schema.parent().name(), schema.name(), topic);
}

/**
* Create the table {@link SecurableObject} with the given securable schema object and fileset
* name.
*
* @param schema The securable schema object
* @param fileset The fileset name
* @return The created fileset {@link SecurableObject}
*/
public static SecurableObject ofFileset(SecurableObject schema, String fileset) {
checkSchema(schema);

return of(schema.parent().name(), schema.name(), fileset);
}

/**
* All catalogs is a special securable object .You can give the securable object the privileges
* `LOAD CATALOG`, `CREATE CATALOG`, etc. It means that you can load any catalog and create any
* which doesn't exist.
*
* @return The created {@link SecurableObject}
*/
public static SecurableObject ofAllCatalogs() {
return ALL_CATALOGS;
}

private static void checkSchema(SecurableObject schema) {
if (schema == null) {
throw new IllegalArgumentException("Securable schema object can't be null");
}
checkCatalog(schema.parent());
}

private static void checkCatalog(SecurableObject catalog) {
if (catalog == null) {
throw new IllegalArgumentException("Securable catalog object can't be null");
}

if (catalog.parent() != null) {
throw new IllegalArgumentException(
String.format("The parent of securable catalog object %s must be null", catalog.name()));
}
}

private static final SecurableObject ALL_CATALOGS = new SecurableObjectImpl(null, "*");

private static class SecurableObjectImpl implements SecurableObject {

private final SecurableObject parent;
private final String name;

SecurableObjectImpl(SecurableObject parent, String name) {
this.parent = parent;
this.name = name;
}

@Override
public SecurableObject parent() {
return parent;
}

@Override
public String name() {
return name;
}

@Override
public int hashCode() {
return Objects.hash(parent, name);
}

@Override
public String toString() {
if (parent != null) {
return parent.toString() + "." + name;
} else {
return name;
}
}

@Override
public boolean equals(Object other) {
if (!(other instanceof SecurableObject)) {
return false;
}

SecurableObject otherSecurableObject = (SecurableObject) other;
return Objects.equals(parent, otherSecurableObject.parent())
&& Objects.equals(name, otherSecurableObject.name());
}
}
}
Loading

0 comments on commit bc96f6b

Please sign in to comment.