Permalink
Browse files

CDH-23206: Impala support for column-level authorization (part 1)

This commit adds partial support for column-level authorization in
Impala using the Sentry Service. The following changes are included:
* Added support for parsing and analyzing GRANT/REVOKE statements with column-level
  privileges. The supporting syntax is:
  - GRANT SELECT (<col_names>) ON TABLE <table_name>
    TO [ROLE] <role_name> [WITH GRANT OPTION]
  - REVOKE [GRANT OPTION FROM] SELECT (<col_names>) ON
    TABLE <table_name> FROM [ROLE] <role_name>
* Added support for storing column-level privileges in the Catalog Service and updating
  the Sentry Service when GRANT/REVOKE statements are executed.
* Modified the SHOW GRANT ROLE statement to include information about
  column-level privileges.

Subsequent patches will add support for enforcing column-level
privileges in SQL queries and other statements.

Change-Id: I0fd9daa92cc5147cb6f4b25eb9651aab8bf3049f
Reviewed-on: http://gerrit.cloudera.org:8080/607
Reviewed-by: Dimitris Tsirogiannis <dtsirogiannis@cloudera.com>
Tested-by: Internal Jenkins
  • Loading branch information...
dtsirogiannis authored and Internal Jenkins committed Aug 4, 2015
1 parent 8fcdff0 commit 2b594561435a60126c66bc2c5a607fa16f5f8d2f
@@ -388,6 +388,7 @@ enum TPrivilegeScope {
URI,
DATABASE,
TABLE,
COLUMN,
}
// The privilege level allowed.
@@ -405,13 +406,13 @@ enum TPrivilegeLevel {
struct TPrivilege {
// A human readable name for this privilege. The combination of role_id +
// privilege_name is guaranteed to be unique. Stored in a form that can be passed
// to Sentry: [ServerName]->[DbName]->[TableName]->[Action Granted].
// to Sentry: [ServerName]->[DbName]->[TableName]->[ColumnName]->[Action Granted].
1: required string privilege_name
// The level of access this privilege provides.
2: required TPrivilegeLevel privilege_level
// The scope of the privilege: SERVER, DATABASE, URI, or TABLE
// The scope of the privilege: SERVER, DATABASE, URI, TABLE or COLUMN
3: required TPrivilegeScope scope
// If true, GRANT OPTION was specified. For a GRANT privilege statement, everyone
@@ -438,6 +439,9 @@ struct TPrivilege {
// Time this privilege was created (in milliseconds since epoch).
10: optional i64 create_time_ms
// Set if scope is COLUMN
11: optional string column_name
}
// Thrift representation of an HdfsCachePool.
@@ -470,14 +470,18 @@ struct TGrantRevokeRoleParams {
// Parameters for GRANT/REVOKE privilege TO/FROM role.
struct TGrantRevokePrivParams {
// List of privileges being granted or revoked.
// List of privileges being granted or revoked. The 'has_grant_opt' for each
// TPrivilege is inherited from the 'has_grant_opt' of this object.
1: required list<CatalogObjects.TPrivilege> privileges
// The role name this change should apply to.
2: required string role_name
// True if this is a GRANT statement false if this is a REVOKE statement.
3: required bool is_grant
// True if WITH GRANT OPTION is set.
4: required bool has_grant_opt
}
// Parameters of DROP DATABASE commands
@@ -725,6 +725,8 @@ privilege_spec ::=
{: RESULT = PrivilegeSpec.createDbScopedPriv(priv, db_name); :}
| privilege:priv KW_ON KW_TABLE table_name:tbl_name
{: RESULT = PrivilegeSpec.createTableScopedPriv(priv, tbl_name); :}
| privilege:priv LPAREN opt_ident_list:cols RPAREN KW_ON KW_TABLE table_name:tbl_name
{: RESULT = PrivilegeSpec.createColumnScopedPriv(priv, tbl_name, cols); :}
| privilege:priv KW_ON uri_ident:uri_kw STRING_LITERAL:uri
{: RESULT = PrivilegeSpec.createUriScopedPriv(priv, new HdfsUri(uri)); :}
;
@@ -2236,12 +2236,21 @@ public Db getDb(String dbName, Privilege privilege, boolean throwIfDoesNotExist)
registerPrivReq(pb.allOf(privilege).onDb(dbName).toRequest());
}
Db db = getDb(dbName, throwIfDoesNotExist);
globalState_.accessEvents.add(new TAccessEvent(
dbName, TCatalogObjectType.DATABASE, privilege.toString()));
return db;
}
/**
* Returns a Catalog Db object without checking for privileges.
*/
public Db getDb(String dbName, boolean throwIfDoesNotExist)
throws AnalysisException {
Db db = getCatalog().getDb(dbName);
if (db == null && throwIfDoesNotExist) {
throw new AnalysisException(DB_DOES_NOT_EXIST_ERROR_MSG + dbName);
}
globalState_.accessEvents.add(new TAccessEvent(
dbName, TCatalogObjectType.DATABASE, privilege.toString()));
return db;
}
@@ -14,13 +14,14 @@
package com.cloudera.impala.analysis;
import java.util.List;
import com.cloudera.impala.catalog.Role;
import com.cloudera.impala.common.AnalysisException;
import com.cloudera.impala.thrift.TGrantRevokePrivParams;
import com.cloudera.impala.thrift.TPrivilege;
import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
/**
* Represents a "GRANT/REVOKE PRIVILEGE" statement.
@@ -53,10 +54,13 @@ public TGrantRevokePrivParams toThrift() {
TGrantRevokePrivParams params = new TGrantRevokePrivParams();
params.setRole_name(roleName_);
params.setIs_grant(isGrantPrivStmt_);
TPrivilege privilege = privilegeSpec_.toThrift();
privilege.setRole_id(role_.getId());
privilege.setHas_grant_opt(hasGrantOpt_);
params.setPrivileges(Lists.newArrayList(privilege));
List<TPrivilege> privileges = privilegeSpec_.toThrift();
for (TPrivilege privilege: privileges) {
privilege.setRole_id(role_.getId());
privilege.setHas_grant_opt(hasGrantOpt_);
}
params.setHas_grant_opt(hasGrantOpt_);
params.setPrivileges(privileges);
return params;
}
@@ -84,4 +88,4 @@ public void analyze(Analyzer analyzer) throws AnalysisException {
}
privilegeSpec_.analyze(analyzer);
}
}
}
Oops, something went wrong.

0 comments on commit 2b59456

Please sign in to comment.