Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support role management #7898

Closed
wants to merge 51 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
3be3e85
Introduce CREATE ROLE and DROP ROLE statements
Feb 8, 2017
9b868b3
Move PrincipalType to presto-spi
Feb 16, 2017
d6a7b2b
Expose Create/Drop/List roles methods in SPI
Feb 9, 2017
83fa644
Introduce <catalog>.information_schema.roles table
Feb 22, 2017
1a92680
Remove unused InMemoryHiveMetastore
Feb 9, 2017
4ecf5b0
Assign admin role to subset of users in FileHiveMetastore
Mar 2, 2017
698b266
Speedup TestHiveFileBasedSecurity
Mar 2, 2017
735b7a1
Implement Create/Drop/List roles in Hive connector
Feb 10, 2017
186d5f1
Introduce GRANT/REVOKE roles statements
Feb 21, 2017
9d4344b
Add Grant/Revoke/List roles authorization to the SPI
Feb 21, 2017
f211fc9
Introduce APPLICABLE_ROLES view
Feb 22, 2017
b3c3c95
Implement Grant/Revoke/ListApplicableRoles in Hive
Mar 2, 2017
71347fa
Refactor GRANT/REVOKE in Hive
Feb 23, 2017
90c3a2c
Introduce access control for GRANT/REVOKE ROLE
Feb 23, 2017
24eda47
Prepare metastore interface to accept ROLE for GRANT/REVOKE
Mar 2, 2017
826cdfe
Introduce SET ROLE statement
Feb 24, 2017
1643b0c
Introduce ConnectorIdentity
Mar 10, 2017
60a9f35
Implement SET ROLE
Feb 24, 2017
870067f
Store catalog selected roles in Identity
Mar 10, 2017
fcf5457
Introduce ENABLED_ROLES view
Feb 25, 2017
f4f7064
Implement SET ROLE in Hive Connector
Feb 25, 2017
5abb84b
Accept ROLE in GRANT/REVOKE Privileges statements
Jun 12, 2017
5a09900
Add SHOW ROLES to the parser
cawallin Mar 10, 2017
fb0f1da
Rewrite SHOW ROLES as a select query
cawallin Mar 10, 2017
a3f82ef
Add access control checks for SHOW ROLES
cawallin Mar 10, 2017
54f7cff
Add docs for SHOW ROLES
cawallin Mar 10, 2017
72bbff2
Product tests for SHOW ROLES
cawallin Mar 13, 2017
60d6487
Add SHOW CURRENT ROLES
cawallin Mar 13, 2017
e38826d
Add SHOW ROLE GRANTS syntax
cawallin Mar 13, 2017
8e74399
Add listRoleGrants to the SPI
cawallin Mar 14, 2017
1df6402
Implement listRoleGrants() in Hive
cawallin Mar 14, 2017
bef94cc
Implement SHOW ROLE GRANTS rewrite
cawallin Mar 14, 2017
f7829cd
Add docs for SHOW ROLE GRANTS
cawallin Mar 14, 2017
6127a23
Access control for SHOW ROLE GRANTS and SHOW CURRENT ROLES
cawallin Mar 15, 2017
3c59752
Remove redundant checkDatabasePermission methods
Mar 9, 2017
455a904
Reorder methods in SqlStandardAccessControl
Mar 9, 2017
e878ee5
Rename getGrantOptionForPrivilege to hasGrantOptionForPrivilege
Mar 9, 2017
3560f62
Remove hive privilege null check
Mar 9, 2017
ccc3c4e
Allow all for admin role
Mar 9, 2017
12bb097
Introduce isTableOwner method for readability
Mar 9, 2017
255925d
Simplify checkTablePermission
Mar 9, 2017
4df82ef
Refactor canCreateView security checks
Mar 9, 2017
6aeb17f
Consider enabled roles for permissions
Mar 10, 2017
ac6aa23
Refactor HivePrivilegeInfo
Mar 13, 2017
c6e28f9
Reorder methods in HivePrivilegeInfo
Mar 13, 2017
d693e0e
Move parsePrivilege to MetastoreUtil
Mar 13, 2017
6298f30
Add grantor to HivePrivilegeInfo
Mar 13, 2017
166e375
Add grantor_type and grantee_type columns to table_privileges
Mar 13, 2017
983c059
More product tests for SET ROLE
Mar 13, 2017
9a587bc
Document role management
Mar 27, 2017
8f09296
Catalog access control for roles
Apr 3, 2017
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions presto-cli/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@
<artifactId>presto-client</artifactId>
</dependency>

<dependency>
<groupId>com.facebook.presto</groupId>
<artifactId>presto-spi</artifactId>
</dependency>

<dependency>
<groupId>com.facebook.presto</groupId>
<artifactId>presto-parser</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

import com.facebook.presto.cli.ClientOptions.OutputFormat;
import com.facebook.presto.client.ClientSession;
import com.facebook.presto.spi.security.SelectedRole;
import com.facebook.presto.sql.parser.IdentifierSymbol;
import com.facebook.presto.sql.parser.ParsingException;
import com.facebook.presto.sql.parser.SqlParser;
Expand Down Expand Up @@ -56,6 +57,7 @@
import static com.facebook.presto.client.ClientSession.withCatalogAndSchema;
import static com.facebook.presto.client.ClientSession.withPreparedStatements;
import static com.facebook.presto.client.ClientSession.withProperties;
import static com.facebook.presto.client.ClientSession.withRoles;
import static com.facebook.presto.client.ClientSession.withTransactionId;
import static com.facebook.presto.sql.parser.StatementSplitter.Statement;
import static com.facebook.presto.sql.parser.StatementSplitter.isEmptyStatement;
Expand Down Expand Up @@ -346,6 +348,13 @@ private static void process(QueryRunner queryRunner, String sql, OutputFormat ou
session = withProperties(session, sessionProperties);
}

// update session roles
if (!query.getSetRoles().isEmpty()) {
Map<String, SelectedRole> roles = new HashMap<>(session.getRoles());
roles.putAll(query.getSetRoles());
session = withRoles(session, roles);
}

// update prepared statements if present
if (!query.getAddedPreparedStatements().isEmpty() || !query.getDeallocatedPreparedStatements().isEmpty()) {
Map<String, String> preparedStatements = new HashMap<>(session.getPreparedStatements());
Expand Down
6 changes: 6 additions & 0 deletions presto-cli/src/main/java/com/facebook/presto/cli/Query.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import com.facebook.presto.client.QueryError;
import com.facebook.presto.client.QueryResults;
import com.facebook.presto.client.StatementClient;
import com.facebook.presto.spi.security.SelectedRole;
import com.google.common.base.Splitter;
import com.google.common.base.Strings;
import com.google.common.base.Throwables;
Expand Down Expand Up @@ -72,6 +73,11 @@ public Set<String> getResetSessionProperties()
return client.getResetSessionProperties();
}

public Map<String, SelectedRole> getSetRoles()
{
return client.getSetRoles();
}

public Map<String, String> getAddedPreparedStatements()
{
return client.getAddedPreparedStatements();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
*/
package com.facebook.presto.client;

import com.facebook.presto.spi.security.SelectedRole;
import com.facebook.presto.spi.type.TimeZoneKey;
import com.google.common.collect.ImmutableMap;
import io.airlift.units.Duration;
Expand Down Expand Up @@ -41,6 +42,7 @@ public class ClientSession
private final Locale locale;
private final Map<String, String> properties;
private final Map<String, String> preparedStatements;
private final Map<String, SelectedRole> roles;
private final String transactionId;
private final boolean debug;
private final Duration clientRequestTimeout;
Expand All @@ -58,6 +60,7 @@ public static ClientSession withCatalogAndSchema(ClientSession session, String c
session.getLocale(),
session.getProperties(),
session.getPreparedStatements(),
session.getRoles(),
session.getTransactionId(),
session.isDebug(),
session.getClientRequestTimeout());
Expand All @@ -76,6 +79,26 @@ public static ClientSession withProperties(ClientSession session, Map<String, St
session.getLocale(),
properties,
session.getPreparedStatements(),
session.getRoles(),
session.getTransactionId(),
session.isDebug(),
session.getClientRequestTimeout());
}

public static ClientSession withRoles(ClientSession session, Map<String, SelectedRole> roles)
{
return new ClientSession(
session.getServer(),
session.getUser(),
session.getSource(),
session.getClientInfo(),
session.getCatalog(),
session.getSchema(),
session.getTimeZone().getId(),
session.getLocale(),
session.getProperties(),
session.getPreparedStatements(),
roles,
session.getTransactionId(),
session.isDebug(),
session.getClientRequestTimeout());
Expand All @@ -94,6 +117,7 @@ public static ClientSession withPreparedStatements(ClientSession session, Map<St
session.getLocale(),
session.getProperties(),
preparedStatements,
session.getRoles(),
session.getTransactionId(),
session.isDebug(),
session.getClientRequestTimeout());
Expand All @@ -112,6 +136,7 @@ public static ClientSession withTransactionId(ClientSession session, String tran
session.getLocale(),
session.getProperties(),
session.getPreparedStatements(),
session.getRoles(),
transactionId,
session.isDebug(),
session.getClientRequestTimeout());
Expand All @@ -130,6 +155,7 @@ public static ClientSession stripTransactionId(ClientSession session)
session.getLocale(),
session.getProperties(),
session.getPreparedStatements(),
session.getRoles(),
null,
session.isDebug(),
session.getClientRequestTimeout());
Expand Down Expand Up @@ -166,6 +192,25 @@ public ClientSession(
String transactionId,
boolean debug,
Duration clientRequestTimeout)
{
this(server, user, source, clientInfo, catalog, schema, timeZoneId, locale, properties, preparedStatements, emptyMap(), transactionId, debug, clientRequestTimeout);
}

public ClientSession(
URI server,
String user,
String source,
String clientInfo,
String catalog,
String schema,
String timeZoneId,
Locale locale,
Map<String, String> properties,
Map<String, String> preparedStatements,
Map<String, SelectedRole> roles,
String transactionId,
boolean debug,
Duration clientRequestTimeout)
{
this.server = requireNonNull(server, "server is null");
this.user = user;
Expand All @@ -179,6 +224,7 @@ public ClientSession(
this.debug = debug;
this.properties = ImmutableMap.copyOf(requireNonNull(properties, "properties is null"));
this.preparedStatements = ImmutableMap.copyOf(requireNonNull(preparedStatements, "preparedStatements is null"));
this.roles = ImmutableMap.copyOf(requireNonNull(roles, "roles is null"));
this.clientRequestTimeout = clientRequestTimeout;

// verify the properties are valid
Expand Down Expand Up @@ -241,6 +287,14 @@ public Map<String, String> getPreparedStatements()
return preparedStatements;
}

/**
* Returns the map of catalog name -> selected role
*/
public Map<String, SelectedRole> getRoles()
{
return roles;
}

public String getTransactionId()
{
return transactionId;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ public final class PrestoHeaders
public static final String PRESTO_SESSION = "X-Presto-Session";
public static final String PRESTO_SET_SESSION = "X-Presto-Set-Session";
public static final String PRESTO_CLEAR_SESSION = "X-Presto-Clear-Session";
public static final String PRESTO_SET_ROLE = "X-Presto-Set-Role";
public static final String PRESTO_ROLE = "X-Presto-Role";
public static final String PRESTO_PREPARED_STATEMENT = "X-Presto-Prepared-Statement";
public static final String PRESTO_ADDED_PREPARE = "X-Presto-Added-Prepare";
public static final String PRESTO_DEALLOCATED_PREPARE = "X-Presto-Deallocated-Prepare";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
package com.facebook.presto.client;

import com.facebook.presto.client.OkHttpUtil.NullCallback;
import com.facebook.presto.spi.security.SelectedRole;
import com.facebook.presto.spi.type.TimeZoneKey;
import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableMap;
Expand Down Expand Up @@ -53,6 +54,7 @@
import static com.facebook.presto.client.PrestoHeaders.PRESTO_PREPARED_STATEMENT;
import static com.facebook.presto.client.PrestoHeaders.PRESTO_SCHEMA;
import static com.facebook.presto.client.PrestoHeaders.PRESTO_SESSION;
import static com.facebook.presto.client.PrestoHeaders.PRESTO_SET_ROLE;
import static com.facebook.presto.client.PrestoHeaders.PRESTO_SET_SESSION;
import static com.facebook.presto.client.PrestoHeaders.PRESTO_SOURCE;
import static com.facebook.presto.client.PrestoHeaders.PRESTO_STARTED_TRANSACTION_ID;
Expand Down Expand Up @@ -89,6 +91,7 @@ public class StatementClient
private final AtomicReference<QueryResults> currentResults = new AtomicReference<>();
private final Map<String, String> setSessionProperties = new ConcurrentHashMap<>();
private final Set<String> resetSessionProperties = Sets.newConcurrentHashSet();
private final Map<String, SelectedRole> setRoles = new ConcurrentHashMap<>();
private final Map<String, String> addedPreparedStatements = new ConcurrentHashMap<>();
private final Set<String> deallocatedPreparedStatements = Sets.newConcurrentHashSet();
private final AtomicReference<String> startedtransactionId = new AtomicReference<>();
Expand Down Expand Up @@ -156,6 +159,11 @@ private Request buildQueryRequest(ClientSession session, String query)
builder.addHeader(PRESTO_SESSION, entry.getKey() + "=" + entry.getValue());
}

Map<String, SelectedRole> roles = session.getRoles();
for (Entry<String, SelectedRole> entry : roles.entrySet()) {
builder.addHeader(PrestoHeaders.PRESTO_ROLE, entry.getKey() + '=' + urlEncode(entry.getValue().toString()));
}

Map<String, String> statements = session.getPreparedStatements();
for (Entry<String, String> entry : statements.entrySet()) {
builder.addHeader(PRESTO_PREPARED_STATEMENT, urlEncode(entry.getKey()) + "=" + urlEncode(entry.getValue()));
Expand Down Expand Up @@ -223,6 +231,11 @@ public Set<String> getResetSessionProperties()
return ImmutableSet.copyOf(resetSessionProperties);
}

public Map<String, SelectedRole> getSetRoles()
{
return ImmutableMap.copyOf(setRoles);
}

public Map<String, String> getAddedPreparedStatements()
{
return ImmutableMap.copyOf(addedPreparedStatements);
Expand Down Expand Up @@ -325,6 +338,14 @@ private void processResponse(Headers headers, QueryResults results)
resetSessionProperties.add(clearSession);
}

for (String setRole : headers.values(PRESTO_SET_ROLE)) {
List<String> keyValue = SESSION_HEADER_SPLITTER.splitToList(setRole);
if (keyValue.size() != 2) {
continue;
}
setRoles.put(keyValue.get(0), SelectedRole.valueOf(urlDecode(keyValue.get(1))));
}

for (String entry : headers.values(PRESTO_ADDED_PREPARE)) {
List<String> keyValue = SESSION_HEADER_SPLITTER.splitToList(entry);
if (keyValue.size() != 2) {
Expand Down
22 changes: 22 additions & 0 deletions presto-docs/src/main/sphinx/connector/hive-security.rst
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,30 @@ Property Value Description
queries based on the privileges defined in Hive metastore.
To alter these privileges, use the :doc:`/sql/grant` and
:doc:`/sql/revoke` commands.
See :ref:`hive-sql-standard-based-authorization` for details.
================================================== ============================================================

.. _hive-sql-standard-based-authorization:

SQL Standard Based Authorization
--------------------------------

When ``sql-standard`` security is enabled, Presto enforces the same SQL
standard based authorization as Hive does.

Since Presto's ``ROLE`` syntax support matches the SQL standard, and
Hive does not exactly follow the SQL standard, there are the following
limitations and differences:

* ``CREATE ROLE role WITH ADMIN`` is not supported.
* The ``admin`` role must be enabled to execute ``CREATE ROLE`` or ``DROP ROLE``.
* ``GRANT role TO user GRANTED BY someone`` is not supported.
* ``REVOKE role FROM user GRANTED BY someone`` is not supported.
* By default, all a user's roles except ``admin`` are enabled in a new user session.
* One particular role can be selected by executing ``SET ROLE role``.
* ``SET ROLE ALL`` enables all of a user's roles except ``admin``.
* The ``admin`` role must be enabled explicitly by executing ``SET ROLE admin``.

Authentication
==============

Expand Down
2 changes: 2 additions & 0 deletions presto-docs/src/main/sphinx/connector/mysql.rst
Original file line number Diff line number Diff line change
Expand Up @@ -68,3 +68,5 @@ The following SQL statements are not yet supported:
* :doc:`/sql/grant`
* :doc:`/sql/revoke`
* :doc:`/sql/show-grants`
* :doc:`/sql/show-roles`
* :doc:`/sql/show-role-grants`
2 changes: 2 additions & 0 deletions presto-docs/src/main/sphinx/connector/postgresql.rst
Original file line number Diff line number Diff line change
Expand Up @@ -73,3 +73,5 @@ The following SQL statements are not yet supported:
* :doc:`/sql/grant`
* :doc:`/sql/revoke`
* :doc:`/sql/show-grants`
* :doc:`/sql/show-roles`
* :doc:`/sql/show-role-grants`
2 changes: 2 additions & 0 deletions presto-docs/src/main/sphinx/language/reserved.rst
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ Keyword SQL:2016 SQL-92
``CROSS`` reserved reserved
``CUBE`` reserved
``CURRENT_DATE`` reserved reserved
``CURRENT_ROLE`` reserved reserved
``CURRENT_USER`` reserved reserved
``CURRENT_TIME`` reserved reserved
``CURRENT_TIMESTAMP`` reserved reserved
``DEALLOCATE`` reserved reserved
Expand Down
7 changes: 7 additions & 0 deletions presto-docs/src/main/sphinx/sql.rst
Original file line number Diff line number Diff line change
Expand Up @@ -11,23 +11,28 @@ This chapter describes the SQL syntax used in Presto.
sql/alter-table
sql/call
sql/commit
sql/create-role
sql/create-schema
sql/create-table
sql/create-table-as
sql/create-view
sql/delete
sql/describe
sql/drop-role
sql/drop-schema
sql/drop-table
sql/drop-view
sql/explain
sql/explain-analyze
sql/grant
sql/grant-roles
sql/insert
sql/reset-session
sql/revoke
sql/revoke-roles
sql/rollback
sql/select
sql/set-role
sql/set-session
sql/show-catalogs
sql/show-columns
Expand All @@ -36,6 +41,8 @@ This chapter describes the SQL syntax used in Presto.
sql/show-functions
sql/show-grants
sql/show-partitions
sql/show-role-grants
sql/show-roles
sql/show-schemas
sql/show-session
sql/show-tables
Expand Down
49 changes: 49 additions & 0 deletions presto-docs/src/main/sphinx/sql/create-role.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
===========
CREATE ROLE
===========

Synopsis
--------

.. code-block:: none

CREATE ROLE role_name
[ WITH ADMIN ( user | USER user | ROLE role | CURRENT_USER | CURRENT_ROLE ) ]
[ IN catalog ]

Description
-----------

``CREATE ROLE`` creates the specified role in ``catalog`` or in the
current catalog if ``catalog`` is not specified.

The optional ``WITH ADMIN`` clause causes the role to be created with
the specified user as a role admin. A role admin has permission to drop
or grant a role. If the optional ``WITH ADMIN`` clause is not
specified, the role is created with current user as admin.

Examples
--------

Create role ``admin`` ::

CREATE ROLE admin;

Create role ``moderator`` with admin ``bob``::

CREATE ROLE moderator WITH ADMIN USER bob;

Create role ``foo`` in catalog ``bar``::

CREATE ROLE foo IN bar;

Limitations
-----------

Some connectors do not support role management.
See connector documentation for more details.

See Also
--------

:doc:`drop-role`, :doc:`set-role`, :doc:`grant-roles`, :doc:`revoke-roles`
Loading