You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@impala.apache.org by ta...@apache.org on 2018/08/16 00:29:48 UTC
[4/6] impala git commit: IMPALA-7342: Add initial support for
user-level permissions
IMPALA-7342: Add initial support for user-level permissions
This patch refactors the authorization code in preparation to add initial
support for for user-level permissions (IMPALA-6794) and object ownership
(IMPALA-7075). It introduces the notion of Principal that can be either
Role or User. The authorization tests are updated to run the tests with
user and role permissions.
Testing:
- Update authorization tests
- Ran core tests
Change-Id: I07e0d46d2e50d35bd64ee573b5aa4b779eb9e62f
Reviewed-on: http://gerrit.cloudera.org:8080/11039
Reviewed-by: Impala Public Jenkins <im...@cloudera.com>
Tested-by: Impala Public Jenkins <im...@cloudera.com>
Project: http://git-wip-us.apache.org/repos/asf/impala/repo
Commit: http://git-wip-us.apache.org/repos/asf/impala/commit/a23e6f29
Tree: http://git-wip-us.apache.org/repos/asf/impala/tree/a23e6f29
Diff: http://git-wip-us.apache.org/repos/asf/impala/diff/a23e6f29
Branch: refs/heads/master
Commit: a23e6f296369854b7fade98bf476242c1201dacc
Parents: e4ea231
Author: Fredy Wijaya <fw...@cloudera.com>
Authored: Tue Jul 24 14:56:28 2018 -0700
Committer: Impala Public Jenkins <im...@cloudera.com>
Committed: Wed Aug 15 22:02:46 2018 +0000
----------------------------------------------------------------------
be/src/catalog/catalog-util.cc | 13 +-
common/thrift/CatalogObjects.thrift | 61 ++--
.../impala/analysis/GrantRevokePrivStmt.java | 3 +-
.../apache/impala/analysis/PrivilegeSpec.java | 4 +-
.../impala/analysis/ShowGrantRoleStmt.java | 3 +-
.../impala/catalog/AuthorizationPolicy.java | 311 +++++++++++++------
.../java/org/apache/impala/catalog/Catalog.java | 44 +--
.../impala/catalog/CatalogServiceCatalog.java | 200 ++++++++----
.../apache/impala/catalog/ImpaladCatalog.java | 44 +--
.../org/apache/impala/catalog/Principal.java | 181 +++++++++++
.../impala/catalog/PrincipalPrivilege.java | 154 +++++++++
.../java/org/apache/impala/catalog/Role.java | 128 +-------
.../apache/impala/catalog/RolePrivilege.java | 151 ---------
.../java/org/apache/impala/catalog/User.java | 39 +++
.../impala/service/CatalogOpExecutor.java | 11 +-
.../org/apache/impala/service/JniFrontend.java | 1 -
.../apache/impala/util/SentryPolicyService.java | 8 +-
.../org/apache/impala/util/SentryProxy.java | 47 +--
.../impala/analysis/AnalyzeAuthStmtsTest.java | 4 +-
.../impala/analysis/AuthorizationStmtTest.java | 247 ++++++++++-----
.../org/apache/impala/catalog/CatalogTest.java | 87 ++++++
.../impala/testutil/ImpaladTestCatalog.java | 20 +-
22 files changed, 1146 insertions(+), 615 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/impala/blob/a23e6f29/be/src/catalog/catalog-util.cc
----------------------------------------------------------------------
diff --git a/be/src/catalog/catalog-util.cc b/be/src/catalog/catalog-util.cc
index 5d1c0fa..ad2024b 100644
--- a/be/src/catalog/catalog-util.cc
+++ b/be/src/catalog/catalog-util.cc
@@ -135,8 +135,8 @@ TCatalogObjectType::type TCatalogObjectTypeFromName(const string& name) {
return TCatalogObjectType::DATA_SOURCE;
} else if (upper == "HDFS_CACHE_POOL") {
return TCatalogObjectType::HDFS_CACHE_POOL;
- } else if (upper == "ROLE") {
- return TCatalogObjectType::ROLE;
+ } else if (upper == "PRINCIPAL") {
+ return TCatalogObjectType::PRINCIPAL;
} else if (upper == "PRIVILEGE") {
return TCatalogObjectType::PRIVILEGE;
}
@@ -196,10 +196,10 @@ Status TCatalogObjectFromObjectName(const TCatalogObjectType::type& object_type,
catalog_object->__set_cache_pool(THdfsCachePool());
catalog_object->cache_pool.__set_pool_name(object_name);
break;
- case TCatalogObjectType::ROLE:
+ case TCatalogObjectType::PRINCIPAL:
catalog_object->__set_type(object_type);
- catalog_object->__set_role(TRole());
- catalog_object->role.__set_role_name(object_name);
+ catalog_object->__set_principal(TPrincipal());
+ catalog_object->principal.__set_principal_name(object_name);
break;
case TCatalogObjectType::PRIVILEGE: {
int pos = object_name.find(".");
@@ -210,7 +210,8 @@ Status TCatalogObjectFromObjectName(const TCatalogObjectType::type& object_type,
}
catalog_object->__set_type(object_type);
catalog_object->__set_privilege(TPrivilege());
- catalog_object->privilege.__set_role_id(atoi(object_name.substr(0, pos).c_str()));
+ catalog_object->privilege.__set_principal_id(
+ atoi(object_name.substr(0, pos).c_str()));
catalog_object->privilege.__set_privilege_name(object_name.substr(pos + 1));
break;
}
http://git-wip-us.apache.org/repos/asf/impala/blob/a23e6f29/common/thrift/CatalogObjects.thrift
----------------------------------------------------------------------
diff --git a/common/thrift/CatalogObjects.thrift b/common/thrift/CatalogObjects.thrift
index b73c5e6..29f54e4 100644
--- a/common/thrift/CatalogObjects.thrift
+++ b/common/thrift/CatalogObjects.thrift
@@ -36,7 +36,7 @@ enum TCatalogObjectType {
VIEW,
FUNCTION,
DATA_SOURCE,
- ROLE,
+ PRINCIPAL,
PRIVILEGE,
HDFS_CACHE_POOL,
}
@@ -477,18 +477,28 @@ struct TDatabase {
2: optional hive_metastore.Database metastore_db
}
-// Represents a role in an authorization policy.
-struct TRole {
- // Case-insensitive role name
- 1: required string role_name
+// Represents a principal type that maps to Sentry principal type.
+// https://github.com/apache/sentry/blob/3d062f39ce6a047138660a7b3d0024bde916c5b4/sentry-service/sentry-service-api/src/gen/thrift/gen-javabean/org/apache/sentry/api/service/thrift/TSentryPrincipalType.java
+enum TPrincipalType {
+ ROLE,
+ USER
+}
+
+// Represents a principal in an authorization policy.
+struct TPrincipal {
+ // Case-insensitive principal name
+ 1: required string principal_name
+
+ // Unique ID of this principal, generated by the Catalog Server.
+ 2: required i32 principal_id
- // Unique ID of this role, generated by the Catalog Server.
- 2: required i32 role_id
+ // Type of this principal.
+ 3: required TPrincipalType principal_type
- // List of groups this role has been granted to (group names are case sensitive).
+ // List of groups this principal has been granted to (group names are case sensitive).
// TODO: Keep a list of grant groups globally (in TCatalog?) and reference by ID since
- // the same groups will likely be shared across multiple roles.
- 3: required list<string> grant_groups
+ // the same groups will likely be shared across multiple principals.
+ 4: required list<string> grant_groups
}
// The scope a TPrivilege applies to.
@@ -512,12 +522,12 @@ enum TPrivilegeLevel {
}
// Represents a privilege in an authorization policy. Privileges contain the level
-// of access, the scope and role the privilege applies to, and details on what
+// of access, the scope and principal the privilege applies to, and details on what
// catalog object the privilege is securing. Objects are hierarchical, so a privilege
// corresponding to a table must also specify all the parent objects (database name
// and server name).
struct TPrivilege {
- // A human readable name for this privilege. The combination of role_id +
+ // A human readable name for this privilege. The combination of principal_id +
// privilege_name is guaranteed to be unique. Stored in a form that can be passed
// to Sentry: [ServerName]->[DbName]->[TableName]->[ColumnName]->[Action Granted].
1: required string privilege_name
@@ -529,32 +539,35 @@ struct TPrivilege {
3: required TPrivilegeScope scope
// If true, GRANT OPTION was specified. For a GRANT privilege statement, everyone
- // granted this role should be able to issue GRANT/REVOKE privilege statements even if
- // they are not an admin. For REVOKE privilege statements, the privilege should be
+ // granted this principal should be able to issue GRANT/REVOKE privilege statements even
+ // if they are not an admin. For REVOKE privilege statements, the privilege should be
// retainined and the existing GRANT OPTION (if it was set) on the privilege should be
// removed.
4: required bool has_grant_opt
- // The ID of the role this privilege belongs to.
- 5: optional i32 role_id
+ // The ID of the principal this privilege belongs to.
+ 5: optional i32 principal_id
+
+ // The type of the principal this privilege belongs to.
+ 6: optional TPrincipalType principal_type
// Set if scope is SERVER, URI, DATABASE, or TABLE
- 6: optional string server_name
+ 7: optional string server_name
// Set if scope is DATABASE or TABLE
- 7: optional string db_name
+ 8: optional string db_name
// Unqualified table name. Set if scope is TABLE.
- 8: optional string table_name
+ 9: optional string table_name
// Set if scope is URI
- 9: optional string uri
+ 10: optional string uri
// Time this privilege was created (in milliseconds since epoch).
- 10: optional i64 create_time_ms
+ 11: optional i64 create_time_ms
// Set if scope is COLUMN
- 11: optional string column_name
+ 12: optional string column_name
}
// Thrift representation of an HdfsCachePool.
@@ -595,8 +608,8 @@ struct TCatalogObject {
// Set iff object type is DATA SOURCE
7: optional TDataSource data_source
- // Set iff object type is ROLE
- 8: optional TRole role
+ // Set iff object type is PRINCIPAL
+ 8: optional TPrincipal principal
// Set iff object type is PRIVILEGE
9: optional TPrivilege privilege
http://git-wip-us.apache.org/repos/asf/impala/blob/a23e6f29/fe/src/main/java/org/apache/impala/analysis/GrantRevokePrivStmt.java
----------------------------------------------------------------------
diff --git a/fe/src/main/java/org/apache/impala/analysis/GrantRevokePrivStmt.java b/fe/src/main/java/org/apache/impala/analysis/GrantRevokePrivStmt.java
index 9ded066..348383c 100644
--- a/fe/src/main/java/org/apache/impala/analysis/GrantRevokePrivStmt.java
+++ b/fe/src/main/java/org/apache/impala/analysis/GrantRevokePrivStmt.java
@@ -60,7 +60,8 @@ public class GrantRevokePrivStmt extends AuthorizationStmt {
params.setIs_grant(isGrantPrivStmt_);
List<TPrivilege> privileges = privilegeSpec_.toThrift();
for (TPrivilege privilege: privileges) {
- privilege.setRole_id(role_.getId());
+ privilege.setPrincipal_id(role_.getId());
+ privilege.setPrincipal_type(role_.getPrincipalType());
privilege.setHas_grant_opt(hasGrantOpt_);
}
params.setHas_grant_opt(hasGrantOpt_);
http://git-wip-us.apache.org/repos/asf/impala/blob/a23e6f29/fe/src/main/java/org/apache/impala/analysis/PrivilegeSpec.java
----------------------------------------------------------------------
diff --git a/fe/src/main/java/org/apache/impala/analysis/PrivilegeSpec.java b/fe/src/main/java/org/apache/impala/analysis/PrivilegeSpec.java
index fb75398..4ee5d49 100644
--- a/fe/src/main/java/org/apache/impala/analysis/PrivilegeSpec.java
+++ b/fe/src/main/java/org/apache/impala/analysis/PrivilegeSpec.java
@@ -23,7 +23,7 @@ import org.apache.impala.authorization.Privilege;
import org.apache.impala.catalog.FeDataSourceTable;
import org.apache.impala.catalog.FeTable;
import org.apache.impala.catalog.FeView;
-import org.apache.impala.catalog.RolePrivilege;
+import org.apache.impala.catalog.PrincipalPrivilege;
import org.apache.impala.catalog.TableLoadingException;
import org.apache.impala.common.AnalysisException;
import org.apache.impala.thrift.TPrivilege;
@@ -134,7 +134,7 @@ public class PrivilegeSpec implements ParseNode {
if (uri_ != null) privilege.setUri(uri_.toString());
if (columnName != null) privilege.setColumn_name(columnName);
privilege.setCreate_time_ms(-1);
- privilege.setPrivilege_name(RolePrivilege.buildRolePrivilegeName(privilege));
+ privilege.setPrivilege_name(PrincipalPrivilege.buildPrivilegeName(privilege));
return privilege;
}
http://git-wip-us.apache.org/repos/asf/impala/blob/a23e6f29/fe/src/main/java/org/apache/impala/analysis/ShowGrantRoleStmt.java
----------------------------------------------------------------------
diff --git a/fe/src/main/java/org/apache/impala/analysis/ShowGrantRoleStmt.java b/fe/src/main/java/org/apache/impala/analysis/ShowGrantRoleStmt.java
index 82c6ed0..749bcc2 100644
--- a/fe/src/main/java/org/apache/impala/analysis/ShowGrantRoleStmt.java
+++ b/fe/src/main/java/org/apache/impala/analysis/ShowGrantRoleStmt.java
@@ -49,7 +49,8 @@ public class ShowGrantRoleStmt extends AuthorizationStmt {
params.setRequesting_user(requestingUser_.getShortName());
if (privilegeSpec_ != null) {
params.setPrivilege(privilegeSpec_.toThrift().get(0));
- params.getPrivilege().setRole_id(role_.getId());
+ params.getPrivilege().setPrincipal_id(role_.getId());
+ params.getPrivilege().setPrincipal_type(role_.getPrincipalType());
}
return params;
}
http://git-wip-us.apache.org/repos/asf/impala/blob/a23e6f29/fe/src/main/java/org/apache/impala/catalog/AuthorizationPolicy.java
----------------------------------------------------------------------
diff --git a/fe/src/main/java/org/apache/impala/catalog/AuthorizationPolicy.java b/fe/src/main/java/org/apache/impala/catalog/AuthorizationPolicy.java
index 8c545fc..a151eb4 100644
--- a/fe/src/main/java/org/apache/impala/catalog/AuthorizationPolicy.java
+++ b/fe/src/main/java/org/apache/impala/catalog/AuthorizationPolicy.java
@@ -21,16 +21,18 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
+import com.google.common.base.Preconditions;
import org.apache.commons.net.ntp.TimeStamp;
-import org.apache.log4j.Logger;
-import org.apache.sentry.core.common.ActiveRoleSet;
-import org.apache.sentry.provider.cache.PrivilegeCache;
-
import org.apache.impala.thrift.TColumn;
+import org.apache.impala.thrift.TPrincipalType;
import org.apache.impala.thrift.TPrivilege;
import org.apache.impala.thrift.TResultRow;
import org.apache.impala.thrift.TResultSet;
import org.apache.impala.thrift.TResultSetMetadata;
+import org.apache.log4j.Logger;
+import org.apache.sentry.core.common.ActiveRoleSet;
+import org.apache.sentry.provider.cache.PrivilegeCache;
+
import org.apache.impala.util.TResultRowBuilder;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
@@ -39,17 +41,24 @@ import com.google.common.collect.Sets;
/**
* A thread safe authorization policy cache, consisting of roles, groups that are
- * members of that role, and the privileges associated with the role. The source data
- * this cache is backing is read from the Sentry Policy Service. Writing to the cache
- * will replace any matching items, but will not write back to the Sentry Policy Service.
- * A role can have 0 or more privileges and roles are stored in a map of role name
- * to role object. For example:
- * RoleName -> Role -> [RolePriv1, ..., RolePrivN]
+ * members of that role, the privileges associated with the role, and users and the
+ * privileges associated with the user. The source data this cache is backing is read from
+ * the Sentry Policy Service. Writing to the cache will replace any matching items, but
+ * will not write back to the Sentry Policy Service.
+ * The roleCache_ contains all roles defined in Sentry whereas userCache_ only contains
+ * users that have privileges defined in Sentry and does not represent all users in the
+ * system. A principal type can have 0 or more privileges and principal types are stored
+ * in a map of principal name to principal object. For example:
+ * RoleName -> Role -> [PrincipalPriv1, ..., PrincipalPrivN]
+ * UserName -> User -> [PrincipalPriv1, ..., PrincipalPrivN]
+ * There is a separate cache for users since we cannot guarantee uniqueness between
+ * user names and role names.
* To ensure we can efficiently retrieve the roles that a user is a member of, a map
* of user group name to role name is tracked as grantGroups_.
- * To reduce duplication of metadata, privileges are linked to roles using a "role ID"
- * rather than embedding the role name. When a privilege is added to a role, we do
- * a lookup to get the role ID to using the roleIds_ map.
+ * To reduce duplication of metadata, privileges are linked to roles/users using a
+ * "principal ID" rather than embedding the principal name. When a privilege is added to
+ * a principal type, we do a lookup to get the principal ID to probe the principalIds_
+ * map.
* Acts as the backing cache for the Sentry cached based provider (which is why
* PrivilegeCache is implemented).
* TODO: Instead of calling into Sentry to perform final authorization checks, we
@@ -58,11 +67,16 @@ import com.google.common.collect.Sets;
public class AuthorizationPolicy implements PrivilegeCache {
private static final Logger LOG = Logger.getLogger(AuthorizationPolicy.class);
+ // Need to keep separate caches of role names and user names since there is
+ // no uniqueness guarantee across roles and users
// Cache of role names (case-insensitive) to role objects.
- private final CatalogObjectCache<Role> roleCache_ = new CatalogObjectCache<Role>();
+ private final CatalogObjectCache<Role> roleCache_ = new CatalogObjectCache<>();
+
+ // Cache of user names (case-insensitive) to user objects.
+ private final CatalogObjectCache<User> userCache_ = new CatalogObjectCache<>();
- // Map of role ID -> role name. Used to match privileges to roles.
- Map<Integer, String> roleIds_ = Maps.newHashMap();
+ // Map of principal ID -> user/role name. Used to match privileges to users/roles.
+ private final Map<Integer, String> principalIds_ = Maps.newHashMap();
// Map of group name (case sensitive) to set of role names (case insensitive) that
// have been granted to this group. Kept in sync with roleCache_. Provides efficient
@@ -70,87 +84,100 @@ public class AuthorizationPolicy implements PrivilegeCache {
Map<String, Set<String>> groupsToRoles_ = Maps.newHashMap();
/**
- * Adds a new role to the policy. If a role with the same name already
- * exists and the role ID's are different, it will be overwritten by the new role.
- * If a role exists and the role IDs are the same, the privileges from the old
- * role will be copied to the new role.
+ * Adds a new principal to the policy. If a principal with the same name already
+ * exists and the principal ID's are different, it will be overwritten by the new
+ * principal. If a principal exists and the principal IDs are the same, the privileges
+ * from the old principal will be copied to the new principal.
*/
- public synchronized void addRole(Role role) {
- Role existingRole = roleCache_.get(role.getName());
- // There is already a newer version of this role in the catalog, ignore
+ public synchronized void addPrincipal(Principal principal) {
+ Principal existingPrincipal = getPrincipal(principal.getName(),
+ principal.getPrincipalType());
+ // There is already a newer version of this principal in the catalog, ignore
// just return.
- if (existingRole != null &&
- existingRole.getCatalogVersion() >= role.getCatalogVersion()) return;
-
- // If there was an existing role that was replaced we first need to remove it.
- if (existingRole != null) {
- // Remove the role. This will also clean up the grantGroup mappings.
- removeRole(existingRole.getName());
- CatalogObjectVersionSet.INSTANCE.removeAll(existingRole.getPrivileges());
- if (existingRole.getId() == role.getId()) {
- // Copy the privileges from the existing role.
- for (RolePrivilege p: existingRole.getPrivileges()) {
- role.addPrivilege(p);
+ if (existingPrincipal != null &&
+ existingPrincipal.getCatalogVersion() >= principal.getCatalogVersion()) return;
+
+ // If there was an existing principal that was replaced we first need to remove it.
+ if (existingPrincipal != null) {
+ // Remove the principal. This will also clean up the grantGroup mappings.
+ removePrincipal(existingPrincipal.getName(), existingPrincipal.getPrincipalType());
+ CatalogObjectVersionSet.INSTANCE.removeAll(existingPrincipal.getPrivileges());
+ if (existingPrincipal.getId() == principal.getId()) {
+ // Copy the privileges from the existing principal.
+ for (PrincipalPrivilege p: existingPrincipal.getPrivileges()) {
+ principal.addPrivilege(p);
}
}
}
- roleCache_.add(role);
+ if (principal.getPrincipalType() == TPrincipalType.USER) {
+ Preconditions.checkArgument(principal instanceof User);
+ userCache_.add((User) principal);
+ } else {
+ Preconditions.checkArgument(principal instanceof Role);
+ roleCache_.add((Role) principal);
+ }
// Add new grants
- for (String groupName: role.getGrantGroups()) {
+ for (String groupName: principal.getGrantGroups()) {
Set<String> grantedRoles = groupsToRoles_.get(groupName);
if (grantedRoles == null) {
grantedRoles = Sets.newHashSet();
groupsToRoles_.put(groupName, grantedRoles);
}
- grantedRoles.add(role.getName().toLowerCase());
+ grantedRoles.add(principal.getName().toLowerCase());
}
- // Add this role to the role ID mapping
- roleIds_.put(role.getId(), role.getName());
+ // Add this principal to the principal ID mapping
+ principalIds_.put(principal.getId(), principal.getName());
}
/**
- * Adds a new privilege to the policy mapping to the role specified by the
- * role ID in the privilege.
- * Throws a CatalogException no role with a corresponding ID existing in the catalog.
+ * Adds a new privilege to the policy mapping to the principal specified by the
+ * principal ID in the privilege. Throws a CatalogException no principal with a
+ * corresponding ID existing in the catalog.
*/
- public synchronized void addPrivilege(RolePrivilege privilege)
+ public synchronized void addPrivilege(PrincipalPrivilege privilege)
throws CatalogException {
if (LOG.isTraceEnabled()) {
- LOG.trace("Adding privilege: " + privilege.getName() +
- " role ID: " + privilege.getRoleId());
+ LOG.trace("Adding privilege: " + privilege.getName() + " " +
+ Principal.toString(privilege.getPrincipalType()).toLowerCase() +
+ " ID: " + privilege.getPrincipalId());
}
- Role role = getRole(privilege.getRoleId());
- if (role == null) {
- throw new CatalogException(String.format("Error adding privilege: %s. Role ID " +
- "'%d' does not exist.", privilege.getName(), privilege.getRoleId()));
+ Principal principal = getPrincipal(privilege.getPrincipalId(),
+ privilege.getPrincipalType());
+ if (principal == null) {
+ throw new CatalogException(String.format("Error adding privilege: %s. %s ID " +
+ "'%d' does not exist.", privilege.getName(),
+ Principal.toString(privilege.getPrincipalType()), privilege.getPrincipalId()));
}
if (LOG.isTraceEnabled()) {
- LOG.trace("Adding privilege: " + privilege.getName() + " to role: " +
- role.getName() + "ID: " + role.getId());
+ LOG.trace("Adding privilege: " + privilege.getName() + " to " +
+ Principal.toString(privilege.getPrincipalType()).toLowerCase() + ": " +
+ principal.getName() + " with ID: " + principal.getId());
}
- role.addPrivilege(privilege);
+ principal.addPrivilege(privilege);
}
/**
- * Removes a privilege from the policy mapping to the role specified by the
- * role ID in the privilege.
- * Throws a CatalogException if no role with a corresponding ID exists in the catalog.
- * Returns null if no matching privilege is found in this role.
+ * Removes a privilege from the policy mapping to the role specified by the principal ID
+ * in the privilege. Throws a CatalogException if no role with a corresponding ID exists
+ * in the catalog. Returns null if no matching privilege is found in this principal.
*/
- public synchronized RolePrivilege removePrivilege(RolePrivilege privilege)
+ public synchronized PrincipalPrivilege removePrivilege(PrincipalPrivilege privilege)
throws CatalogException {
- Role role = getRole(privilege.getRoleId());
- if (role == null) {
- throw new CatalogException(String.format("Error removing privilege: %s. Role ID " +
- "'%d' does not exist.", privilege.getName(), privilege.getRoleId()));
+ Principal principal = getPrincipal(privilege.getPrincipalId(),
+ privilege.getPrincipalType());
+ if (principal == null) {
+ throw new CatalogException(String.format("Error removing privilege: %s. %s ID " +
+ "'%d' does not exist.", privilege.getName(),
+ Principal.toString(privilege.getPrincipalType()), privilege.getPrincipalId()));
}
if (LOG.isTraceEnabled()) {
- LOG.trace("Removing privilege: '" + privilege.getName() + "' from Role ID: " +
- privilege.getRoleId() + " Role Name: " + role.getName());
+ LOG.trace("Removing privilege: " + privilege.getName() + " from " +
+ Principal.toString(privilege.getPrincipalType()).toLowerCase() + ": " +
+ principal.getName() + " with ID: " + principal.getId());
}
- return role.removePrivilege(privilege.getName());
+ return principal.removePrivilege(privilege.getName());
}
/**
@@ -161,6 +188,13 @@ public class AuthorizationPolicy implements PrivilegeCache {
}
/**
+ * Returns all users in the policy. Returns an empty list if no users exist.
+ */
+ public synchronized List<User> getAllUsers() {
+ return userCache_.getValues();
+ }
+
+ /**
* Returns all role names in the policy. Returns an empty set if no roles exist.
*/
public synchronized Set<String> getAllRoleNames() {
@@ -168,30 +202,62 @@ public class AuthorizationPolicy implements PrivilegeCache {
}
/**
- * Gets a role given a role name. Returns null if no roles exist with this name.
+ * Gets a role given a role name. Returns null if no role exist with this name.
*/
public synchronized Role getRole(String roleName) {
return roleCache_.get(roleName);
}
/**
- * Gets a role given a role ID. Returns null if no roles exist with this ID.
+ * Gets a role given a role ID. Returns null if no role exists with this ID.
*/
public synchronized Role getRole(int roleId) {
- String roleName = roleIds_.get(roleId);
+ String roleName = principalIds_.get(roleId);
if (roleName == null) return null;
return roleCache_.get(roleName);
}
/**
- * Gets a privilege from the given role ID. Returns null of there are no roles with a
- * matching ID or if no privilege with this name exists for the role.
+ * Returns all user names in the policy. Returns an empty set if no users exist.
*/
- public synchronized RolePrivilege getPrivilege(int roleId, String privilegeName) {
- String roleName = roleIds_.get(roleId);
- if (roleName == null) return null;
- Role role = roleCache_.get(roleName);
- return role.getPrivilege(privilegeName);
+ public synchronized Set<String> getAllUserNames() {
+ return Sets.newHashSet(userCache_.keySet());
+ }
+
+ /**
+ * Gets a user given a user name. Returns null if no user exist with this name.
+ */
+ public synchronized User getUser(String userName) {
+ return userCache_.get(userName);
+ }
+
+ /**
+ * Gets a user given a user ID. Returns null if no user exists with this ID.
+ */
+ public synchronized User getUser(int userId) {
+ String userName = principalIds_.get(userId);
+ if (userName == null) return null;
+ return userCache_.get(userName);
+ }
+
+
+ /**
+ * Gets a principal given a principal name and type. Returns null if no principal exists
+ * with this name and type.
+ */
+ public synchronized Principal getPrincipal(String principalName, TPrincipalType type) {
+ return type == TPrincipalType.ROLE ?
+ roleCache_.get(principalName) : userCache_.get(principalName);
+ }
+
+ /**
+ * Gets a principal given a principal ID and type. Returns null if no principal exists
+ * with this ID and type.
+ */
+ public synchronized Principal getPrincipal(int principalId, TPrincipalType type) {
+ String principalName = principalIds_.get(principalId);
+ if (principalName == null) return null;
+ return getPrincipal(principalName, type);
}
/**
@@ -203,7 +269,7 @@ public class AuthorizationPolicy implements PrivilegeCache {
if (roleNames != null) {
for (String roleName: roleNames) {
// TODO: verify they actually exist.
- Role role = roleCache_.get(roleName);
+ Principal role = roleCache_.get(roleName);
if (role != null) grantedRoles.add(roleCache_.get(roleName));
}
}
@@ -211,6 +277,16 @@ public class AuthorizationPolicy implements PrivilegeCache {
}
/**
+ * Removes a principal for a given principal name and type. Returns the removed
+ * principal or null if no principal with this name and type existed.
+ */
+ public synchronized Principal removePrincipal(String principalName,
+ TPrincipalType type) {
+ return type == TPrincipalType.ROLE ?
+ removeRole(principalName) : removeUser(principalName);
+ }
+
+ /**
* Removes a role. Returns the removed role or null if no role with
* this name existed.
*/
@@ -223,17 +299,29 @@ public class AuthorizationPolicy implements PrivilegeCache {
Set<String> roles = groupsToRoles_.get(grantGroup);
if (roles != null) roles.remove(roleName.toLowerCase());
}
- // Cleanup role id.
- roleIds_.remove(removedRole.getId());
+ // Cleanup role ID.
+ principalIds_.remove(removedRole.getId());
return removedRole;
}
/**
+ * Removes a user. Returns the removed user or null if no user with
+ * this name existed.
+ */
+ public synchronized User removeUser(String userName) {
+ User removedUser = userCache_.remove(userName);
+ if (removedUser == null) return null;
+ // Cleanup user ID.
+ principalIds_.remove(removedUser.getId());
+ return removedUser;
+ }
+
+ /**
* Adds a new grant group to the specified role. Returns the updated
- * Role, if a matching role was found. If the role does not exist a
+ * Principal, if a matching role was found. If the role does not exist a
* CatalogException is thrown.
*/
- public synchronized Role addGrantGroup(String roleName, String groupName)
+ public synchronized Role addRoleGrantGroup(String roleName, String groupName)
throws CatalogException {
Role role = roleCache_.get(roleName);
if (role == null) throw new CatalogException("Role does not exist: " + roleName);
@@ -249,10 +337,10 @@ public class AuthorizationPolicy implements PrivilegeCache {
/**
* Removes a grant group from the specified role. Returns the updated
- * Role, if a matching role was found. If the role does not exist a
+ * Principal, if a matching role was found. If the role does not exist a
* CatalogException is thrown.
*/
- public synchronized Role removeGrantGroup(String roleName, String groupName)
+ public synchronized Role removeRoleGrantGroup(String roleName, String groupName)
throws CatalogException {
Role role = roleCache_.get(roleName);
if (role == null) throw new CatalogException("Role does not exist: " + roleName);
@@ -268,8 +356,8 @@ public class AuthorizationPolicy implements PrivilegeCache {
* Returns a set of privilege strings in Sentry format.
*/
@Override
- public synchronized Set<String>
- listPrivileges(Set<String> groups, ActiveRoleSet roleSet) {
+ public synchronized Set<String> listPrivileges(Set<String> groups,
+ ActiveRoleSet roleSet) {
Set<String> privileges = Sets.newHashSet();
if (roleSet != ActiveRoleSet.ALL) {
throw new UnsupportedOperationException("Impala does not support role subsets.");
@@ -279,7 +367,7 @@ public class AuthorizationPolicy implements PrivilegeCache {
for (String groupName: groups) {
List<Role> grantedRoles = getGrantedRoles(groupName);
for (Role role: grantedRoles) {
- for (RolePrivilege privilege: role.getPrivileges()) {
+ for (PrincipalPrivilege privilege: role.getPrivileges()) {
String authorizeable = privilege.getName();
if (authorizeable == null) {
if (LOG.isTraceEnabled()) {
@@ -294,17 +382,29 @@ public class AuthorizationPolicy implements PrivilegeCache {
return privileges;
}
- /**
+ /**
* Returns a set of privilege strings in Sentry format.
*/
- // This is an override for Sentry 2.1, but not for Sentry 1.x; we
- // avoid annotation to support both.
- // @Override
+ @Override
public Set<String> listPrivileges(Set<String> groups, Set<String> users,
ActiveRoleSet roleSet) {
- /* User based roles and authorization hierarchy is not currently supported.
- Fallback to listing privileges using groups. */
- return listPrivileges(groups, roleSet);
+ Set<String> privileges = listPrivileges(groups, roleSet);
+ for (String userName: users) {
+ User user = getUser(userName);
+ if (user != null) {
+ for (PrincipalPrivilege privilege: user.getPrivileges()) {
+ String authorizeable = privilege.getName();
+ if (authorizeable == null) {
+ if (LOG.isTraceEnabled()) {
+ LOG.trace("Ignoring invalid privilege: " + privilege.getName());
+ }
+ continue;
+ }
+ privileges.add(authorizeable);
+ }
+ }
+ }
+ return privileges;
}
@Override
@@ -318,6 +418,25 @@ public class AuthorizationPolicy implements PrivilegeCache {
* granted to the role. Used by the SHOW GRANT ROLE statement.
*/
public synchronized TResultSet getRolePrivileges(String roleName, TPrivilege filter) {
+ return getPrincipalPrivileges(roleName, filter, TPrincipalType.ROLE);
+ }
+
+ /**
+ * Returns the privileges that have been granted to a user as a tabular result set.
+ * Allows for filtering based on a specific privilege spec or showing all privileges
+ * granted to the user. Used by the SHOW GRANT USER statement.
+ */
+ public synchronized TResultSet getUserPrivileges(String userName, TPrivilege filter) {
+ return getPrincipalPrivileges(userName, filter, TPrincipalType.USER);
+ }
+
+ /**
+ * Returns the privileges that have been granted to a principal as a tabular result set.
+ * Allows for filtering based on a specific privilege spec or showing all privileges
+ * granted to the principal.
+ */
+ private TResultSet getPrincipalPrivileges(String principalName, TPrivilege filter,
+ TPrincipalType type) {
TResultSet result = new TResultSet();
result.setSchema(new TResultSetMetadata());
result.getSchema().addToColumns(new TColumn("scope", Type.STRING.toThrift()));
@@ -331,14 +450,14 @@ public class AuthorizationPolicy implements PrivilegeCache {
result.getSchema().addToColumns(new TColumn("create_time", Type.STRING.toThrift()));
result.setRows(Lists.<TResultRow>newArrayList());
- Role role = getRole(roleName);
- if (role == null) return result;
- for (RolePrivilege p: role.getPrivileges()) {
+ Principal principal = getPrincipal(principalName, type);
+ if (principal == null) return result;
+ for (PrincipalPrivilege p: principal.getPrivileges()) {
TPrivilege privilege = p.toThrift();
if (filter != null) {
// Check if the privileges are targeting the same object.
filter.setPrivilege_level(privilege.getPrivilege_level());
- String privName = RolePrivilege.buildRolePrivilegeName(filter);
+ String privName = PrincipalPrivilege.buildPrivilegeName(filter);
if (!privName.equalsIgnoreCase(privilege.getPrivilege_name())) continue;
}
TResultRowBuilder rowBuilder = new TResultRowBuilder();
http://git-wip-us.apache.org/repos/asf/impala/blob/a23e6f29/fe/src/main/java/org/apache/impala/catalog/Catalog.java
----------------------------------------------------------------------
diff --git a/fe/src/main/java/org/apache/impala/catalog/Catalog.java b/fe/src/main/java/org/apache/impala/catalog/Catalog.java
index 7403bc2..a04d6d7 100644
--- a/fe/src/main/java/org/apache/impala/catalog/Catalog.java
+++ b/fe/src/main/java/org/apache/impala/catalog/Catalog.java
@@ -496,23 +496,28 @@ public abstract class Catalog {
result.setCache_pool(pool.toThrift());
break;
}
- case ROLE:
- Role role = authPolicy_.getRole(objectDesc.getRole().getRole_name());
- if (role == null) {
- throw new CatalogException("Role not found: " +
- objectDesc.getRole().getRole_name());
+ case PRINCIPAL:
+ Principal principal = authPolicy_.getPrincipal(
+ objectDesc.getPrincipal().getPrincipal_name(),
+ objectDesc.getPrincipal().getPrincipal_type());
+ if (principal == null) {
+ throw new CatalogException("Principal not found: " +
+ objectDesc.getPrincipal().getPrincipal_name());
}
- result.setType(role.getCatalogObjectType());
- result.setCatalog_version(role.getCatalogVersion());
- result.setRole(role.toThrift());
+ result.setType(principal.getCatalogObjectType());
+ result.setCatalog_version(principal.getCatalogVersion());
+ result.setPrincipal(principal.toThrift());
break;
case PRIVILEGE:
- Role tmpRole = authPolicy_.getRole(objectDesc.getPrivilege().getRole_id());
- if (tmpRole == null) {
- throw new CatalogException("No role associated with ID: " +
- objectDesc.getPrivilege().getRole_id());
+ Principal tmpPrincipal = authPolicy_.getPrincipal(
+ objectDesc.getPrincipal().getPrincipal_id(),
+ objectDesc.getPrincipal().getPrincipal_type());
+ if (tmpPrincipal == null) {
+ throw new CatalogException(String.format("No %s associated with ID: %d",
+ Principal.toString(objectDesc.getPrincipal().getPrincipal_type())
+ .toLowerCase(), objectDesc.getPrivilege().getPrincipal_id()));
}
- for (RolePrivilege p: tmpRole.getPrivileges()) {
+ for (PrincipalPrivilege p: tmpPrincipal.getPrivileges()) {
if (p.getName().equalsIgnoreCase(
objectDesc.getPrivilege().getPrivilege_name())) {
result.setType(p.getCatalogObjectType());
@@ -521,9 +526,9 @@ public abstract class Catalog {
return result;
}
}
- throw new CatalogException(String.format("Role '%s' does not contain " +
- "privilege: '%s'", tmpRole.getName(),
- objectDesc.getPrivilege().getPrivilege_name()));
+ throw new CatalogException(String.format("%s '%s' does not contain " +
+ "privilege: '%s'", Principal.toString(tmpPrincipal.getPrincipalType()),
+ tmpPrincipal.getName(), objectDesc.getPrivilege().getPrivilege_name()));
default: throw new IllegalStateException(
"Unexpected TCatalogObject type: " + objectDesc.getType());
}
@@ -550,12 +555,13 @@ public abstract class Catalog {
case FUNCTION:
return "FUNCTION:" + catalogObject.getFn().getName() + "(" +
catalogObject.getFn().getSignature() + ")";
- case ROLE:
- return "ROLE:" + catalogObject.getRole().getRole_name().toLowerCase();
+ case PRINCIPAL:
+ return "PRINCIPAL:" + catalogObject.getPrincipal().getPrincipal_name()
+ .toLowerCase();
case PRIVILEGE:
return "PRIVILEGE:" +
catalogObject.getPrivilege().getPrivilege_name().toLowerCase() + "." +
- Integer.toString(catalogObject.getPrivilege().getRole_id());
+ Integer.toString(catalogObject.getPrivilege().getPrincipal_id());
case HDFS_CACHE_POOL:
return "HDFS_CACHE_POOL:" +
catalogObject.getCache_pool().getPool_name().toLowerCase();
http://git-wip-us.apache.org/repos/asf/impala/blob/a23e6f29/fe/src/main/java/org/apache/impala/catalog/CatalogServiceCatalog.java
----------------------------------------------------------------------
diff --git a/fe/src/main/java/org/apache/impala/catalog/CatalogServiceCatalog.java b/fe/src/main/java/org/apache/impala/catalog/CatalogServiceCatalog.java
index a3f5a1e..252bfe1 100644
--- a/fe/src/main/java/org/apache/impala/catalog/CatalogServiceCatalog.java
+++ b/fe/src/main/java/org/apache/impala/catalog/CatalogServiceCatalog.java
@@ -31,7 +31,6 @@ import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.locks.ReentrantReadWriteLock;
-import org.apache.commons.codec.binary.Base64;
import org.apache.hadoop.fs.RemoteIterator;
import org.apache.hadoop.hdfs.DistributedFileSystem;
import org.apache.hadoop.hdfs.protocol.CachePoolEntry;
@@ -41,8 +40,6 @@ import org.apache.hadoop.hive.metastore.api.UnknownDBException;
import org.apache.impala.authorization.SentryConfig;
import org.apache.impala.catalog.MetaStoreClientPool.MetaStoreClient;
import org.apache.impala.common.FileSystemUtil;
-import org.apache.impala.common.ImpalaException;
-import org.apache.impala.common.JniUtil;
import org.apache.impala.common.Pair;
import org.apache.impala.common.Reference;
import org.apache.impala.service.BackendConfig;
@@ -51,9 +48,9 @@ import org.apache.impala.thrift.TCatalog;
import org.apache.impala.thrift.TCatalogObject;
import org.apache.impala.thrift.TCatalogObjectType;
import org.apache.impala.thrift.TCatalogUpdateResult;
-import org.apache.impala.thrift.TFunction;
import org.apache.impala.thrift.TGetCatalogUsageResponse;
import org.apache.impala.thrift.TPartitionKeyValue;
+import org.apache.impala.thrift.TPrincipalType;
import org.apache.impala.thrift.TPrivilege;
import org.apache.impala.thrift.TTable;
import org.apache.impala.thrift.TTableName;
@@ -66,7 +63,6 @@ import org.apache.log4j.Logger;
import org.apache.thrift.TException;
import org.apache.thrift.TSerializer;
import org.apache.thrift.protocol.TBinaryProtocol;
-import org.apache.thrift.protocol.TCompactProtocol;
import com.codahale.metrics.Timer;
import com.google.common.base.Preconditions;
@@ -444,7 +440,10 @@ public class CatalogServiceCatalog extends Catalog {
addHdfsCachePoolToCatalogDelta(cachePool, ctx);
}
for (Role role: getAllRoles()) {
- addRoleToCatalogDelta(role, ctx);
+ addPrincipalToCatalogDelta(role, ctx);
+ }
+ for (User user: getAllUsers()) {
+ addPrincipalToCatalogDelta(user, ctx);
}
// Identify the catalog objects that were removed from the catalog for which their
// versions are in range ('ctx.fromVersion', 'ctx.toVersion']. We need to make sure
@@ -539,6 +538,18 @@ public class CatalogServiceCatalog extends Catalog {
}
/**
+ * Get a snapshot view of all the users in the catalog.
+ */
+ private List<User> getAllUsers() {
+ versionLock_.readLock().lock();
+ try {
+ return ImmutableList.copyOf(authPolicy_.getAllUsers());
+ } finally {
+ versionLock_.readLock().unlock();
+ }
+ }
+
+ /**
* Adds a database in the topic update if its version is in the range
* ('ctx.fromVersion', 'ctx.toVersion']. It iterates through all the tables and
* functions of this database to determine if they can be included in the topic update.
@@ -702,42 +713,42 @@ public class CatalogServiceCatalog extends Catalog {
/**
- * Adds a role to the topic update if its version is in the range
+ * Adds a principal to the topic update if its version is in the range
* ('ctx.fromVersion', 'ctx.toVersion']. It iterates through all the privileges of
- * this role to determine if they can be inserted in the topic update.
+ * this principal to determine if they can be inserted in the topic update.
*/
- private void addRoleToCatalogDelta(Role role, GetCatalogDeltaContext ctx)
- throws TException {
- long roleVersion = role.getCatalogVersion();
- if (roleVersion > ctx.fromVersion && roleVersion <= ctx.toVersion) {
- TCatalogObject thriftRole =
- new TCatalogObject(TCatalogObjectType.ROLE, roleVersion);
- thriftRole.setRole(role.toThrift());
- ctx.addCatalogObject(thriftRole, false);
+ private void addPrincipalToCatalogDelta(Principal principal, GetCatalogDeltaContext ctx)
+ throws TException {
+ long principalVersion = principal.getCatalogVersion();
+ if (principalVersion > ctx.fromVersion && principalVersion <= ctx.toVersion) {
+ TCatalogObject thriftPrincipal =
+ new TCatalogObject(TCatalogObjectType.PRINCIPAL, principalVersion);
+ thriftPrincipal.setPrincipal(principal.toThrift());
+ ctx.addCatalogObject(thriftPrincipal, false);
}
- for (RolePrivilege p: getAllPrivileges(role)) {
- addRolePrivilegeToCatalogDelta(p, ctx);
+ for (PrincipalPrivilege p: getAllPrivileges(principal)) {
+ addPrincipalPrivilegeToCatalogDelta(p, ctx);
}
}
/**
- * Get a snapshot view of all the privileges in a role.
+ * Get a snapshot view of all the privileges in a principal.
*/
- private List<RolePrivilege> getAllPrivileges(Role role) {
- Preconditions.checkNotNull(role);
+ private List<PrincipalPrivilege> getAllPrivileges(Principal principal) {
+ Preconditions.checkNotNull(principal);
versionLock_.readLock().lock();
try {
- return ImmutableList.copyOf(role.getPrivileges());
+ return ImmutableList.copyOf(principal.getPrivileges());
} finally {
versionLock_.readLock().unlock();
}
}
/**
- * Adds a role privilege to the topic update if its version is in the range
+ * Adds a principal privilege to the topic update if its version is in the range
* ('ctx.fromVersion', 'ctx.toVersion'].
*/
- private void addRolePrivilegeToCatalogDelta(RolePrivilege priv,
+ private void addPrincipalPrivilegeToCatalogDelta(PrincipalPrivilege priv,
GetCatalogDeltaContext ctx) throws TException {
long privVersion = priv.getCatalogVersion();
if (privVersion <= ctx.fromVersion || privVersion > ctx.toVersion) return;
@@ -1465,12 +1476,30 @@ public class CatalogServiceCatalog extends Catalog {
* If a role with the same name already exists it will be overwritten.
*/
public Role addRole(String roleName, Set<String> grantGroups) {
+ Principal role = addPrincipal(roleName, grantGroups, TPrincipalType.ROLE);
+ Preconditions.checkState(role instanceof Role);
+ return (Role) role;
+ }
+
+ /**
+ * Adds a new user with the given name to the AuthorizationPolicy.
+ * If a user with the same name already exists it will be overwritten.
+ */
+ public User addUser(String userName) {
+ Principal user = addPrincipal(userName, Sets.<String>newHashSet(),
+ TPrincipalType.USER);
+ Preconditions.checkState(user instanceof User);
+ return (User) user;
+ }
+
+ private Principal addPrincipal(String principalName, Set<String> grantGroups,
+ TPrincipalType type) {
versionLock_.writeLock().lock();
try {
- Role role = new Role(roleName, grantGroups);
- role.setCatalogVersion(incrementAndGetCatalogVersion());
- authPolicy_.addRole(role);
- return role;
+ Principal principal = Principal.newInstance(principalName, type, grantGroups);
+ principal.setCatalogVersion(incrementAndGetCatalogVersion());
+ authPolicy_.addPrincipal(principal);
+ return principal;
} finally {
versionLock_.writeLock().unlock();
}
@@ -1482,17 +1511,36 @@ public class CatalogServiceCatalog extends Catalog {
* exists.
*/
public Role removeRole(String roleName) {
+ Principal role = removePrincipal(roleName, TPrincipalType.ROLE);
+ if (role == null) return null;
+ Preconditions.checkState(role instanceof Role);
+ return (Role) role;
+ }
+
+ /**
+ * Removes the user with the given name from the AuthorizationPolicy. Returns the
+ * removed user with an incremented catalog version, or null if no user with this name
+ * exists.
+ */
+ public User removeUser(String userName) {
+ Principal user = removePrincipal(userName, TPrincipalType.USER);
+ if (user == null) return null;
+ Preconditions.checkState(user instanceof User);
+ return (User) user;
+ }
+
+ private Principal removePrincipal(String principalName, TPrincipalType type) {
versionLock_.writeLock().lock();
try {
- Role role = authPolicy_.removeRole(roleName);
- if (role == null) return null;
- for (RolePrivilege priv: role.getPrivileges()) {
+ Principal principal = authPolicy_.removePrincipal(principalName, type);
+ if (principal == null) return null;
+ for (PrincipalPrivilege priv: principal.getPrivileges()) {
priv.setCatalogVersion(incrementAndGetCatalogVersion());
deleteLog_.addRemovedObject(priv.toTCatalogObject());
}
- role.setCatalogVersion(incrementAndGetCatalogVersion());
- deleteLog_.addRemovedObject(role.toTCatalogObject());
- return role;
+ principal.setCatalogVersion(incrementAndGetCatalogVersion());
+ deleteLog_.addRemovedObject(principal.toTCatalogObject());
+ return principal;
} finally {
versionLock_.writeLock().unlock();
}
@@ -1506,7 +1554,7 @@ public class CatalogServiceCatalog extends Catalog {
throws CatalogException {
versionLock_.writeLock().lock();
try {
- Role role = authPolicy_.addGrantGroup(roleName, groupName);
+ Role role = authPolicy_.addRoleGrantGroup(roleName, groupName);
Preconditions.checkNotNull(role);
role.setCatalogVersion(incrementAndGetCatalogVersion());
return role;
@@ -1523,7 +1571,7 @@ public class CatalogServiceCatalog extends Catalog {
throws CatalogException {
versionLock_.writeLock().lock();
try {
- Role role = authPolicy_.removeGrantGroup(roleName, groupName);
+ Role role = authPolicy_.removeRoleGrantGroup(roleName, groupName);
Preconditions.checkNotNull(role);
role.setCatalogVersion(incrementAndGetCatalogVersion());
return role;
@@ -1533,17 +1581,35 @@ public class CatalogServiceCatalog extends Catalog {
}
/**
- * Adds a privilege to the given role name. Returns the new RolePrivilege and
+ * Adds a privilege to the given role name. Returns the new PrincipalPrivilege and
* increments the catalog version. If the parent role does not exist a CatalogException
* is thrown.
*/
- public RolePrivilege addRolePrivilege(String roleName, TPrivilege thriftPriv)
+ public PrincipalPrivilege addRolePrivilege(String roleName, TPrivilege thriftPriv)
throws CatalogException {
+ return addPrincipalPrivilege(roleName, thriftPriv, TPrincipalType.ROLE);
+ }
+
+ /**
+ * Adds a privilege to the given user name. Returns the new PrincipalPrivilege and
+ * increments the catalog version. If the user does not exist a CatalogException is
+ * thrown.
+ */
+ public PrincipalPrivilege addUserPrivilege(String userName, TPrivilege thriftPriv)
+ throws CatalogException {
+ return addPrincipalPrivilege(userName, thriftPriv, TPrincipalType.USER);
+ }
+
+ private PrincipalPrivilege addPrincipalPrivilege(String principalName,
+ TPrivilege thriftPriv, TPrincipalType type) throws CatalogException {
versionLock_.writeLock().lock();
try {
- Role role = authPolicy_.getRole(roleName);
- if (role == null) throw new CatalogException("Role does not exist: " + roleName);
- RolePrivilege priv = RolePrivilege.fromThrift(thriftPriv);
+ Principal principal = authPolicy_.getPrincipal(principalName, type);
+ if (principal == null) {
+ throw new CatalogException(String.format("%s does not exist: %s",
+ Principal.toString(type), principalName));
+ }
+ PrincipalPrivilege priv = PrincipalPrivilege.fromThrift(thriftPriv);
priv.setCatalogVersion(incrementAndGetCatalogVersion());
authPolicy_.addPrivilege(priv);
return priv;
@@ -1553,39 +1619,51 @@ public class CatalogServiceCatalog extends Catalog {
}
/**
- * Removes a RolePrivilege from the given role name. Returns the removed
- * RolePrivilege with an incremented catalog version or null if no matching privilege
- * was found. Throws a CatalogException if no role exists with this name.
+ * Removes a PrincipalPrivilege from the given role name. Returns the removed
+ * PrincipalPrivilege with an incremented catalog version or null if no matching
+ * privilege was found. Throws a CatalogException if no role exists with this name.
*/
- public RolePrivilege removeRolePrivilege(String roleName, TPrivilege thriftPriv)
+ public PrincipalPrivilege removeRolePrivilege(String roleName, TPrivilege thriftPriv)
throws CatalogException {
+ return removePrincipalPrivilege(roleName, thriftPriv, TPrincipalType.ROLE);
+ }
+
+ private PrincipalPrivilege removePrincipalPrivilege(String principalName,
+ TPrivilege privilege, TPrincipalType type) throws CatalogException {
versionLock_.writeLock().lock();
try {
- Role role = authPolicy_.getRole(roleName);
- if (role == null) throw new CatalogException("Role does not exist: " + roleName);
- RolePrivilege rolePrivilege =
- role.removePrivilege(thriftPriv.getPrivilege_name());
- if (rolePrivilege == null) return null;
- rolePrivilege.setCatalogVersion(incrementAndGetCatalogVersion());
- deleteLog_.addRemovedObject(rolePrivilege.toTCatalogObject());
- return rolePrivilege;
+ Principal principal = authPolicy_.getPrincipal(principalName, type);
+ if (principal == null) {
+ throw new CatalogException(String.format("%s does not exist: %s",
+ Principal.toString(type), principalName));
+ }
+ PrincipalPrivilege principalPrivilege =
+ principal.removePrivilege(privilege.getPrivilege_name());
+ if (principalPrivilege == null) return null;
+ principalPrivilege.setCatalogVersion(incrementAndGetCatalogVersion());
+ deleteLog_.addRemovedObject(principalPrivilege.toTCatalogObject());
+ return principalPrivilege;
} finally {
versionLock_.writeLock().unlock();
}
}
/**
- * Gets a RolePrivilege from the given role name. Returns the privilege if it exists,
- * or null if no privilege matching the privilege spec exist.
- * Throws a CatalogException if the role does not exist.
+ * Gets a PrincipalPrivilege from the given principal name. Returns the privilege
+ * if it exists, or null if no privilege matching the privilege spec exist.
+ * Throws a CatalogException if the principal does not exist.
*/
- public RolePrivilege getRolePrivilege(String roleName, TPrivilege privSpec)
- throws CatalogException {
+ public PrincipalPrivilege getPrincipalPrivilege(String principalName,
+ TPrivilege privSpec) throws CatalogException {
versionLock_.readLock().lock();
try {
- Role role = authPolicy_.getRole(roleName);
- if (role == null) throw new CatalogException("Role does not exist: " + roleName);
- return role.getPrivilege(privSpec.getPrivilege_name());
+ Principal principal = authPolicy_.getPrincipal(principalName,
+ privSpec.getPrincipal_type());
+ if (principal == null) {
+ throw new CatalogException(Principal.toString(privSpec.getPrincipal_type()) +
+ " does not exist: " + principalName);
+ }
+ return principal.getPrivilege(privSpec.getPrivilege_name());
} finally {
versionLock_.readLock().unlock();
}
http://git-wip-us.apache.org/repos/asf/impala/blob/a23e6f29/fe/src/main/java/org/apache/impala/catalog/ImpaladCatalog.java
----------------------------------------------------------------------
diff --git a/fe/src/main/java/org/apache/impala/catalog/ImpaladCatalog.java b/fe/src/main/java/org/apache/impala/catalog/ImpaladCatalog.java
index 30c34ad..a259bf0 100644
--- a/fe/src/main/java/org/apache/impala/catalog/ImpaladCatalog.java
+++ b/fe/src/main/java/org/apache/impala/catalog/ImpaladCatalog.java
@@ -33,8 +33,8 @@ import org.apache.impala.thrift.TCatalogObjectType;
import org.apache.impala.thrift.TDataSource;
import org.apache.impala.thrift.TDatabase;
import org.apache.impala.thrift.TFunction;
+import org.apache.impala.thrift.TPrincipal;
import org.apache.impala.thrift.TPrivilege;
-import org.apache.impala.thrift.TRole;
import org.apache.impala.thrift.TTable;
import org.apache.impala.thrift.TUniqueId;
import org.apache.impala.thrift.TUpdateCatalogCacheRequest;
@@ -113,7 +113,7 @@ public class ImpaladCatalog extends Catalog implements FeCatalog {
return catalogObject.getType() == TCatalogObjectType.DATABASE ||
catalogObject.getType() == TCatalogObjectType.DATA_SOURCE ||
catalogObject.getType() == TCatalogObjectType.HDFS_CACHE_POOL ||
- catalogObject.getType() == TCatalogObjectType.ROLE;
+ catalogObject.getType() == TCatalogObjectType.PRINCIPAL;
}
/**
@@ -284,14 +284,14 @@ public class ImpaladCatalog extends Catalog implements FeCatalog {
case DATA_SOURCE:
addDataSource(catalogObject.getData_source(), catalogObject.getCatalog_version());
break;
- case ROLE:
- Role role = Role.fromThrift(catalogObject.getRole());
- role.setCatalogVersion(catalogObject.getCatalog_version());
- authPolicy_.addRole(role);
+ case PRINCIPAL:
+ Principal principal = Principal.fromThrift(catalogObject.getPrincipal());
+ principal.setCatalogVersion(catalogObject.getCatalog_version());
+ authPolicy_.addPrincipal(principal);
break;
case PRIVILEGE:
- RolePrivilege privilege =
- RolePrivilege.fromThrift(catalogObject.getPrivilege());
+ PrincipalPrivilege privilege =
+ PrincipalPrivilege.fromThrift(catalogObject.getPrivilege());
privilege.setCatalogVersion(catalogObject.getCatalog_version());
try {
authPolicy_.addPrivilege(privilege);
@@ -331,8 +331,8 @@ public class ImpaladCatalog extends Catalog implements FeCatalog {
case DATA_SOURCE:
removeDataSource(catalogObject.getData_source(), dropCatalogVersion);
break;
- case ROLE:
- removeRole(catalogObject.getRole(), dropCatalogVersion);
+ case PRINCIPAL:
+ removePrincipal(catalogObject.getPrincipal(), dropCatalogVersion);
break;
case PRIVILEGE:
removePrivilege(catalogObject.getPrivilege(), dropCatalogVersion);
@@ -467,24 +467,28 @@ public class ImpaladCatalog extends Catalog implements FeCatalog {
}
}
- private void removeRole(TRole thriftRole, long dropCatalogVersion) {
- Role existingRole = authPolicy_.getRole(thriftRole.getRole_name());
+ private void removePrincipal(TPrincipal thriftPrincipal, long dropCatalogVersion) {
+ Principal existingPrincipal = authPolicy_.getPrincipal(
+ thriftPrincipal.getPrincipal_name(), thriftPrincipal.getPrincipal_type());
// version of the drop, remove the function.
- if (existingRole != null && existingRole.getCatalogVersion() < dropCatalogVersion) {
- authPolicy_.removeRole(thriftRole.getRole_name());
- CatalogObjectVersionSet.INSTANCE.removeAll(existingRole.getPrivileges());
+ if (existingPrincipal != null &&
+ existingPrincipal.getCatalogVersion() < dropCatalogVersion) {
+ authPolicy_.removePrincipal(thriftPrincipal.getPrincipal_name(),
+ thriftPrincipal.getPrincipal_type());
+ CatalogObjectVersionSet.INSTANCE.removeAll(existingPrincipal.getPrivileges());
}
}
private void removePrivilege(TPrivilege thriftPrivilege, long dropCatalogVersion) {
- Role role = authPolicy_.getRole(thriftPrivilege.getRole_id());
- if (role == null) return;
- RolePrivilege existingPrivilege =
- role.getPrivilege(thriftPrivilege.getPrivilege_name());
+ Principal principal = authPolicy_.getPrincipal(thriftPrivilege.getPrincipal_id(),
+ thriftPrivilege.getPrincipal_type());
+ if (principal == null) return;
+ PrincipalPrivilege existingPrivilege =
+ principal.getPrivilege(thriftPrivilege.getPrivilege_name());
// version of the drop, remove the function.
if (existingPrivilege != null &&
existingPrivilege.getCatalogVersion() < dropCatalogVersion) {
- role.removePrivilege(thriftPrivilege.getPrivilege_name());
+ principal.removePrivilege(thriftPrivilege.getPrivilege_name());
}
}
http://git-wip-us.apache.org/repos/asf/impala/blob/a23e6f29/fe/src/main/java/org/apache/impala/catalog/Principal.java
----------------------------------------------------------------------
diff --git a/fe/src/main/java/org/apache/impala/catalog/Principal.java b/fe/src/main/java/org/apache/impala/catalog/Principal.java
new file mode 100644
index 0000000..d048d10
--- /dev/null
+++ b/fe/src/main/java/org/apache/impala/catalog/Principal.java
@@ -0,0 +1,181 @@
+// 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.impala.catalog;
+
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.apache.impala.thrift.TCatalogObject;
+import org.apache.impala.thrift.TCatalogObjectType;
+import org.apache.impala.thrift.TPrincipal;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+import org.apache.impala.thrift.TPrincipalType;
+
+/**
+ * A base class that represents a principal in an authorization policy.
+ * This class is thread safe.
+ */
+public abstract class Principal extends CatalogObjectImpl {
+ private final TPrincipal principal_;
+ // The last principal ID assigned, starts at 0.
+ private static AtomicInteger principalId_ = new AtomicInteger(0);
+
+ private final CatalogObjectCache<PrincipalPrivilege> principalPrivileges_ =
+ new CatalogObjectCache<>();
+
+ protected Principal(String principalName, TPrincipalType type,
+ Set<String> grantGroups) {
+ principal_ = new TPrincipal();
+ principal_.setPrincipal_name(principalName);
+ principal_.setPrincipal_type(type);
+ principal_.setPrincipal_id(principalId_.incrementAndGet());
+ principal_.setGrant_groups(Lists.newArrayList(grantGroups));
+ }
+
+ protected Principal(TPrincipal principal) {
+ principal_ = principal;
+ }
+
+ /**
+ * Adds a privilege to the principal. Returns true if the privilege was added
+ * successfully or false if there was a newer version of the privilege already added
+ * to the principal.
+ */
+ public boolean addPrivilege(PrincipalPrivilege privilege) {
+ return principalPrivileges_.add(privilege);
+ }
+
+ /**
+ * Returns all privileges for this principal. If no privileges have been added to the
+ * principal, an empty list is returned.
+ */
+ public List<PrincipalPrivilege> getPrivileges() {
+ return Lists.newArrayList(principalPrivileges_.getValues());
+ }
+
+ /**
+ * Returns all privilege names for this principal, or an empty set of no privileges are
+ * granted to the principal.
+ */
+ public Set<String> getPrivilegeNames() {
+ return Sets.newHashSet(principalPrivileges_.keySet());
+ }
+
+ /**
+ * Gets a privilege with the given name from this principal. If no privilege exists
+ * with this name null is returned.
+ */
+ public PrincipalPrivilege getPrivilege(String privilegeName) {
+ return principalPrivileges_.get(privilegeName);
+ }
+
+ /**
+ * Removes a privilege with the given name from the principal. Returns the removed
+ * privilege or null if no privilege exists with this name.
+ */
+ public PrincipalPrivilege removePrivilege(String privilegeName) {
+ return principalPrivileges_.remove(privilegeName);
+ }
+
+ /**
+ * Adds a new grant group to this principal.
+ */
+ public synchronized void addGrantGroup(String groupName) {
+ if (principal_.getGrant_groups().contains(groupName)) return;
+ principal_.addToGrant_groups(groupName);
+ }
+
+ /**
+ * Removes a grant group from this principal.
+ */
+ public synchronized void removeGrantGroup(String groupName) {
+ principal_.getGrant_groups().remove(groupName);
+ // Should never have duplicates in the list of groups.
+ Preconditions.checkState(!principal_.getGrant_groups().contains(groupName));
+ }
+
+ /**
+ * Returns the Thrift representation of the principal.
+ */
+ public TPrincipal toThrift() {
+ return principal_;
+ }
+
+ /**
+ * Creates a Principal from a TPrincipal thrift struct.
+ */
+ public static Principal fromThrift(TPrincipal thriftPrincipal) {
+ return thriftPrincipal.getPrincipal_type() == TPrincipalType.ROLE ?
+ new Role(thriftPrincipal) : new User(thriftPrincipal);
+ }
+
+ /**
+ * Creates a new instance of Principal.
+ */
+ public static Principal newInstance(String principalName, TPrincipalType type,
+ Set<String> grantGroups) {
+ return type == TPrincipalType.ROLE ?
+ new Role(principalName, grantGroups) : new User(principalName, grantGroups);
+ }
+
+ /**
+ * Gets the set of group names that have been granted to this principal or an empty
+ * set if no groups have been granted.
+ */
+ public Set<String> getGrantGroups() {
+ return Sets.newHashSet(principal_.getGrant_groups());
+ }
+
+ @Override
+ public TCatalogObjectType getCatalogObjectType() {
+ return TCatalogObjectType.PRINCIPAL;
+ }
+
+ @Override
+ public String getName() { return principal_.getPrincipal_name(); }
+
+ /**
+ * Returns the principal ID.
+ */
+ public int getId() { return principal_.getPrincipal_id(); }
+
+ @Override
+ public String getUniqueName() {
+ return this.getPrincipalType() == TPrincipalType.ROLE ? "ROLE:" : "USER:"
+ + getName().toLowerCase();
+ }
+
+ public TCatalogObject toTCatalogObject() {
+ TCatalogObject catalogObject =
+ new TCatalogObject(getCatalogObjectType(), getCatalogVersion());
+ catalogObject.setPrincipal(toThrift());
+ return catalogObject;
+ }
+
+ /**
+ * Returns the principal type.
+ */
+ public TPrincipalType getPrincipalType() { return principal_.getPrincipal_type(); }
+
+ public static String toString(TPrincipalType type) {
+ return type == TPrincipalType.ROLE ? "Role" : "User";
+ }
+}
http://git-wip-us.apache.org/repos/asf/impala/blob/a23e6f29/fe/src/main/java/org/apache/impala/catalog/PrincipalPrivilege.java
----------------------------------------------------------------------
diff --git a/fe/src/main/java/org/apache/impala/catalog/PrincipalPrivilege.java b/fe/src/main/java/org/apache/impala/catalog/PrincipalPrivilege.java
new file mode 100644
index 0000000..033b9c9
--- /dev/null
+++ b/fe/src/main/java/org/apache/impala/catalog/PrincipalPrivilege.java
@@ -0,0 +1,154 @@
+// 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.impala.catalog;
+
+import java.util.List;
+
+import org.apache.impala.thrift.TCatalogObject;
+import org.apache.impala.thrift.TCatalogObjectType;
+import org.apache.impala.thrift.TPrincipalType;
+import org.apache.impala.thrift.TPrivilege;
+import org.apache.impala.thrift.TPrivilegeLevel;
+import org.apache.impala.thrift.TPrivilegeScope;
+import org.apache.log4j.Logger;
+
+import com.google.common.base.Joiner;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Lists;
+
+/**
+ * Represents a privilege that has been granted to a principal in an authorization policy.
+ * This class is thread safe.
+ */
+public class PrincipalPrivilege extends CatalogObjectImpl {
+ private static final Logger LOG = Logger.getLogger(AuthorizationPolicy.class);
+ // These Joiners are used to build principal names. For simplicity, the principal name
+ // we use can also be sent to the Sentry library to perform authorization checks
+ // so we build them in the same format.
+ private static final Joiner AUTHORIZABLE_JOINER = Joiner.on("->");
+ private static final Joiner KV_JOINER = Joiner.on("=");
+ private final TPrivilege privilege_;
+
+ private PrincipalPrivilege(TPrivilege privilege) {
+ privilege_ = privilege;
+ }
+
+ public TPrivilege toThrift() { return privilege_; }
+ public static PrincipalPrivilege fromThrift(TPrivilege privilege) {
+ return new PrincipalPrivilege(privilege);
+ }
+
+ /**
+ * Builds a privilege name for the given TPrivilege object. For simplicity, this name is
+ * generated in a format that can be sent to the Sentry client to perform authorization
+ * checks.
+ */
+ public static String buildPrivilegeName(TPrivilege privilege) {
+ List<String> authorizable = Lists.newArrayListWithExpectedSize(4);
+ try {
+ Preconditions.checkNotNull(privilege);
+ TPrivilegeScope scope = privilege.getScope();
+ Preconditions.checkNotNull(scope);
+ switch (scope) {
+ case SERVER: {
+ authorizable.add(KV_JOINER.join("server", privilege.getServer_name().
+ toLowerCase()));
+ break;
+ }
+ case URI: {
+ authorizable.add(KV_JOINER.join("server", privilege.getServer_name().
+ toLowerCase()));
+ // (IMPALA-2695) URIs are case sensitive
+ authorizable.add(KV_JOINER.join("uri", privilege.getUri()));
+ break;
+ }
+ case DATABASE: {
+ authorizable.add(KV_JOINER.join("server", privilege.getServer_name().
+ toLowerCase()));
+ authorizable.add(KV_JOINER.join("db", privilege.getDb_name().
+ toLowerCase()));
+ break;
+ }
+ case TABLE: {
+ authorizable.add(KV_JOINER.join("server", privilege.getServer_name().
+ toLowerCase()));
+ authorizable.add(KV_JOINER.join("db", privilege.getDb_name().
+ toLowerCase()));
+ authorizable.add(KV_JOINER.join("table", privilege.getTable_name().
+ toLowerCase()));
+ break;
+ }
+ case COLUMN: {
+ authorizable.add(KV_JOINER.join("server", privilege.getServer_name().
+ toLowerCase()));
+ authorizable.add(KV_JOINER.join("db", privilege.getDb_name().
+ toLowerCase()));
+ authorizable.add(KV_JOINER.join("table", privilege.getTable_name().
+ toLowerCase()));
+ authorizable.add(KV_JOINER.join("column", privilege.getColumn_name().
+ toLowerCase()));
+ break;
+ }
+ default: {
+ throw new UnsupportedOperationException(
+ "Unknown privilege scope: " + scope.toString());
+ }
+ }
+
+ // The ALL privilege is always implied and does not need to be included as part
+ // of the name.
+ if (privilege.getPrivilege_level() != TPrivilegeLevel.ALL) {
+ authorizable.add(KV_JOINER.join("action",
+ privilege.getPrivilege_level().toString()));
+ }
+ return AUTHORIZABLE_JOINER.join(authorizable);
+ } catch (Exception e) {
+ // Should never make it here unless the privilege is malformed.
+ LOG.error("ERROR: ", e);
+ return null;
+ }
+ }
+
+ @Override
+ public TCatalogObjectType getCatalogObjectType() {
+ return TCatalogObjectType.PRIVILEGE;
+ }
+ @Override
+ public String getName() { return privilege_.getPrivilege_name(); }
+ public int getPrincipalId() { return privilege_.getPrincipal_id(); }
+ public TPrincipalType getPrincipalType() { return privilege_.getPrincipal_type(); }
+ @Override
+ public String getUniqueName() {
+ return "PRIVILEGE:" + getName().toLowerCase() + "." + Integer.toString(
+ getPrincipalId());
+ }
+
+ public TCatalogObject toTCatalogObject() {
+ TCatalogObject catalogObject =
+ new TCatalogObject(getCatalogObjectType(), getCatalogVersion());
+ catalogObject.setPrivilege(toThrift());
+ return catalogObject;
+ }
+
+ // The time this principal was created. Used to quickly check if the same privilege
+ // was dropped and re-created. Assumes a principal will not be created + dropped +
+ // created in less than 1ms. Returns -1 if create_time_ms was not set for the privilege.
+ public long getCreateTimeMs() {
+ return privilege_.isSetCreate_time_ms() ? privilege_.getCreate_time_ms() : -1L;
+ }
+}
http://git-wip-us.apache.org/repos/asf/impala/blob/a23e6f29/fe/src/main/java/org/apache/impala/catalog/Role.java
----------------------------------------------------------------------
diff --git a/fe/src/main/java/org/apache/impala/catalog/Role.java b/fe/src/main/java/org/apache/impala/catalog/Role.java
index b45ff22..9cee7d2 100644
--- a/fe/src/main/java/org/apache/impala/catalog/Role.java
+++ b/fe/src/main/java/org/apache/impala/catalog/Role.java
@@ -17,129 +17,23 @@
package org.apache.impala.catalog;
-import java.util.List;
-import java.util.Set;
-import java.util.concurrent.atomic.AtomicInteger;
-
-import org.apache.impala.thrift.TCatalogObject;
-import org.apache.impala.thrift.TCatalogObjectType;
-import org.apache.impala.thrift.TRole;
import com.google.common.base.Preconditions;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Sets;
+import org.apache.impala.thrift.TPrincipal;
+import org.apache.impala.thrift.TPrincipalType;
+
+import java.util.Set;
/**
- * Represents a role in an authorization policy. This class is thread safe.
+ * Represents a role in an authorization policy.
*/
-public class Role extends CatalogObjectImpl {
- private final TRole role_;
- // The last role ID assigned, starts at 0.
- private static AtomicInteger roleId_ = new AtomicInteger(0);
-
- private final CatalogObjectCache<RolePrivilege> rolePrivileges_ =
- new CatalogObjectCache<RolePrivilege>();
-
+public class Role extends Principal {
public Role(String roleName, Set<String> grantGroups) {
- role_ = new TRole();
- role_.setRole_name(roleName);
- role_.setRole_id(roleId_.incrementAndGet());
- role_.setGrant_groups(Lists.newArrayList(grantGroups));
- }
-
- private Role(TRole role) {
- role_ = role;
- }
-
- /**
- * Adds a privilege to the role. Returns true if the privilege was added successfully
- * or false if there was a newer version of the privilege already added to the role.
- */
- public boolean addPrivilege(RolePrivilege privilege) {
- return rolePrivileges_.add(privilege);
- }
-
- /**
- * Returns all privileges for this role. If no privileges have been added to the role
- * an empty list will be returned.
- */
- public List<RolePrivilege> getPrivileges() {
- return Lists.newArrayList(rolePrivileges_.getValues());
- }
-
- /**
- * Returns all privilege names for this role, or an empty set of no privileges are
- * granted to the role.
- */
- public Set<String> getPrivilegeNames() {
- return Sets.newHashSet(rolePrivileges_.keySet());
- }
-
- /**
- * Gets a privilege with the given name from this role. If no privilege exists
- * with this name null is returned.
- */
- public RolePrivilege getPrivilege(String privilegeName) {
- return rolePrivileges_.get(privilegeName);
- }
-
- /**
- * Removes a privilege with the given name from the role. Returns the removed
- * privilege or null if no privilege exists with this name.
- */
- public RolePrivilege removePrivilege(String privilegeName) {
- return rolePrivileges_.remove(privilegeName);
- }
-
- /**
- * Adds a new grant group to this role.
- */
- public synchronized void addGrantGroup(String groupName) {
- if (role_.getGrant_groups().contains(groupName)) return;
- role_.addToGrant_groups(groupName);
- }
-
- /**
- * Removes a grant group from this role.
- */
- public synchronized void removeGrantGroup(String groupName) {
- role_.getGrant_groups().remove(groupName);
- // Should never have duplicates in the list of groups.
- Preconditions.checkState(!role_.getGrant_groups().contains(groupName));
- }
-
- /**
- * Returns the Thrift representation of the role.
- */
- public TRole toThrift() {
- return role_;
- }
-
- /**
- * Creates a Role from a TRole thrift struct.
- */
- public static Role fromThrift(TRole thriftRole) {
- return new Role(thriftRole);
- }
-
- /**
- * Gets the set of group names that have been granted this role or an empty
- * Set if no groups have been granted the role.
- */
- public Set<String> getGrantGroups() {
- return Sets.newHashSet(role_.getGrant_groups());
+ super(roleName, TPrincipalType.ROLE, grantGroups);
}
- @Override
- public TCatalogObjectType getCatalogObjectType() { return TCatalogObjectType.ROLE; }
- @Override
- public String getName() { return role_.getRole_name(); }
- public int getId() { return role_.getRole_id(); }
- @Override
- public String getUniqueName() { return "ROLE:" + getName().toLowerCase(); }
- public TCatalogObject toTCatalogObject() {
- TCatalogObject catalogObject =
- new TCatalogObject(getCatalogObjectType(), getCatalogVersion());
- catalogObject.setRole(toThrift());
- return catalogObject;
+ public Role(TPrincipal thriftPrincipal) {
+ super(thriftPrincipal);
+ Preconditions.checkArgument(
+ thriftPrincipal.getPrincipal_type() == TPrincipalType.ROLE);
}
}
http://git-wip-us.apache.org/repos/asf/impala/blob/a23e6f29/fe/src/main/java/org/apache/impala/catalog/RolePrivilege.java
----------------------------------------------------------------------
diff --git a/fe/src/main/java/org/apache/impala/catalog/RolePrivilege.java b/fe/src/main/java/org/apache/impala/catalog/RolePrivilege.java
deleted file mode 100644
index ef3717c..0000000
--- a/fe/src/main/java/org/apache/impala/catalog/RolePrivilege.java
+++ /dev/null
@@ -1,151 +0,0 @@
-// 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.impala.catalog;
-
-import java.util.List;
-
-import org.apache.log4j.Logger;
-
-import org.apache.impala.thrift.TCatalogObject;
-import org.apache.impala.thrift.TCatalogObjectType;
-import org.apache.impala.thrift.TPrivilege;
-import org.apache.impala.thrift.TPrivilegeLevel;
-import org.apache.impala.thrift.TPrivilegeScope;
-import com.google.common.base.Joiner;
-import com.google.common.base.Preconditions;
-import com.google.common.collect.Lists;
-
-/**
- * Represents a privilege that has been granted to a role in an authorization policy.
- * This class is thread safe.
- */
-public class RolePrivilege extends CatalogObjectImpl {
- private static final Logger LOG = Logger.getLogger(AuthorizationPolicy.class);
- // These Joiners are used to build role names. For simplicity, the role name we
- // use can also be sent to the Sentry library to perform authorization checks
- // so we build them in the same format.
- private static final Joiner AUTHORIZABLE_JOINER = Joiner.on("->");
- private static final Joiner KV_JOINER = Joiner.on("=");
- private final TPrivilege privilege_;
-
- private RolePrivilege(TPrivilege privilege) {
- privilege_ = privilege;
- }
-
- public TPrivilege toThrift() { return privilege_; }
- public static RolePrivilege fromThrift(TPrivilege privilege) {
- return new RolePrivilege(privilege);
- }
-
- /**
- * Builds a privilege name for the given TPrivilege object. For simplicity, this name is
- * generated in a format that can be sent to the Sentry client to perform authorization
- * checks.
- */
- public static String buildRolePrivilegeName(TPrivilege privilege) {
- List<String> authorizable = Lists.newArrayListWithExpectedSize(4);
- try {
- Preconditions.checkNotNull(privilege);
- TPrivilegeScope scope = privilege.getScope();
- Preconditions.checkNotNull(scope);
- switch (scope) {
- case SERVER: {
- authorizable.add(KV_JOINER.join("server", privilege.getServer_name().
- toLowerCase()));
- break;
- }
- case URI: {
- authorizable.add(KV_JOINER.join("server", privilege.getServer_name().
- toLowerCase()));
- // (IMPALA-2695) URIs are case sensitive
- authorizable.add(KV_JOINER.join("uri", privilege.getUri()));
- break;
- }
- case DATABASE: {
- authorizable.add(KV_JOINER.join("server", privilege.getServer_name().
- toLowerCase()));
- authorizable.add(KV_JOINER.join("db", privilege.getDb_name().
- toLowerCase()));
- break;
- }
- case TABLE: {
- authorizable.add(KV_JOINER.join("server", privilege.getServer_name().
- toLowerCase()));
- authorizable.add(KV_JOINER.join("db", privilege.getDb_name().
- toLowerCase()));
- authorizable.add(KV_JOINER.join("table", privilege.getTable_name().
- toLowerCase()));
- break;
- }
- case COLUMN: {
- authorizable.add(KV_JOINER.join("server", privilege.getServer_name().
- toLowerCase()));
- authorizable.add(KV_JOINER.join("db", privilege.getDb_name().
- toLowerCase()));
- authorizable.add(KV_JOINER.join("table", privilege.getTable_name().
- toLowerCase()));
- authorizable.add(KV_JOINER.join("column", privilege.getColumn_name().
- toLowerCase()));
- break;
- }
- default: {
- throw new UnsupportedOperationException(
- "Unknown privilege scope: " + scope.toString());
- }
- }
-
- // The ALL privilege is always implied and does not need to be included as part
- // of the name.
- if (privilege.getPrivilege_level() != TPrivilegeLevel.ALL) {
- authorizable.add(KV_JOINER.join("action",
- privilege.getPrivilege_level().toString()));
- }
- return AUTHORIZABLE_JOINER.join(authorizable);
- } catch (Exception e) {
- // Should never make it here unless the privilege is malformed.
- LOG.error("ERROR: ", e);
- return null;
- }
- }
-
- @Override
- public TCatalogObjectType getCatalogObjectType() {
- return TCatalogObjectType.PRIVILEGE;
- }
- @Override
- public String getName() { return privilege_.getPrivilege_name(); }
- public int getRoleId() { return privilege_.getRole_id(); }
- @Override
- public String getUniqueName() {
- return "PRIVILEGE:" + getName().toLowerCase() + "." + Integer.toString(getRoleId());
- }
-
- public TCatalogObject toTCatalogObject() {
- TCatalogObject catalogObject =
- new TCatalogObject(getCatalogObjectType(), getCatalogVersion());
- catalogObject.setPrivilege(toThrift());
- return catalogObject;
- }
-
- // The time this role was created. Used to quickly check if the same privilege
- // was dropped and re-created. Assumes a role will not be created + dropped + created
- // in less than 1ms. Returns -1 if create_time_ms was not set for the privilege.
- public long getCreateTimeMs() {
- return privilege_.isSetCreate_time_ms() ? privilege_.getCreate_time_ms() : -1L;
- }
-}
http://git-wip-us.apache.org/repos/asf/impala/blob/a23e6f29/fe/src/main/java/org/apache/impala/catalog/User.java
----------------------------------------------------------------------
diff --git a/fe/src/main/java/org/apache/impala/catalog/User.java b/fe/src/main/java/org/apache/impala/catalog/User.java
new file mode 100644
index 0000000..2845670
--- /dev/null
+++ b/fe/src/main/java/org/apache/impala/catalog/User.java
@@ -0,0 +1,39 @@
+// 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.impala.catalog;
+
+import com.google.common.base.Preconditions;
+import org.apache.impala.thrift.TPrincipal;
+import org.apache.impala.thrift.TPrincipalType;
+
+import java.util.Set;
+
+/**
+ * Represents a role in an authorization policy.
+ */
+public class User extends Principal {
+ public User(String userName, Set<String> grantGroups) {
+ super(userName, TPrincipalType.USER, grantGroups);
+ }
+
+ public User(TPrincipal thriftPrincipal) {
+ super(thriftPrincipal);
+ Preconditions.checkArgument(
+ thriftPrincipal.getPrincipal_type() == TPrincipalType.USER);
+ }
+}