Impala
Impalaistheopensource,nativeanalyticdatabaseforApacheHadoop.
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
AuthorizationTest.java
Go to the documentation of this file.
1 // Copyright 2013 Cloudera Inc.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 package com.cloudera.impala.analysis;
16 
17 import static org.junit.Assert.assertEquals;
18 import static org.junit.Assert.fail;
19 
20 import java.util.ArrayList;
21 import java.util.Arrays;
22 import java.util.Collection;
23 import java.util.List;
24 import java.util.UUID;
25 
26 import junit.framework.Assert;
27 
28 import org.apache.hive.service.cli.thrift.TGetColumnsReq;
29 import org.apache.hive.service.cli.thrift.TGetSchemasReq;
30 import org.apache.hive.service.cli.thrift.TGetTablesReq;
31 import org.apache.sentry.provider.common.ResourceAuthorizationProvider;
32 import org.apache.sentry.provider.file.LocalGroupResourceAuthorizationProvider;
33 import org.junit.After;
34 import org.junit.Test;
35 import org.junit.runner.RunWith;
36 import org.junit.runners.Parameterized;
37 import org.junit.runners.Parameterized.Parameters;
38 import org.slf4j.Logger;
39 import org.slf4j.LoggerFactory;
40 
56 import com.cloudera.impala.thrift.TMetadataOpRequest;
57 import com.cloudera.impala.thrift.TMetadataOpcode;
58 import com.cloudera.impala.thrift.TNetworkAddress;
59 import com.cloudera.impala.thrift.TPrivilege;
60 import com.cloudera.impala.thrift.TPrivilegeLevel;
61 import com.cloudera.impala.thrift.TPrivilegeScope;
62 import com.cloudera.impala.thrift.TQueryCtx;
63 import com.cloudera.impala.thrift.TResultSet;
64 import com.cloudera.impala.thrift.TSessionState;
66 import com.google.common.base.Preconditions;
67 import com.google.common.collect.Lists;
68 
69 @RunWith(Parameterized.class)
70 public class AuthorizationTest {
71  private final static Logger LOG =
72  LoggerFactory.getLogger(AuthorizationTest.class);
73 
74  // Policy file has defined current user and 'test_user' have:
75  // ALL permission on 'tpch' database and 'newdb' database
76  // ALL permission on 'functional_seq_snap' database
77  // SELECT permissions on all tables in 'tpcds' database
78  // SELECT permissions on 'functional.alltypesagg' (no INSERT permissions)
79  // SELECT permissions on 'functional.complex_view' (no INSERT permissions)
80  // SELECT permissions on 'functional.view_view' (no INSERT permissions)
81  // INSERT permissions on 'functional.alltypes' (no SELECT permissions)
82  // INSERT permissions on all tables in 'functional_parquet' database
83  // No permissions on database 'functional_rc'
84  private final static String AUTHZ_POLICY_FILE = "/test-warehouse/authz-policy.ini";
85  private final static User USER = new User(System.getProperty("user.name"));
86 
87  // The admin_user has ALL privileges on the server.
88  private final static User ADMIN_USER = new User("admin_user");
89 
91  private final ImpaladCatalog catalog_;
92  private final TQueryCtx queryCtx_;
94  private final Frontend fe_;
95  protected static final String SERVER_HOST = "localhost";
96  private static boolean isSetup_ = false;
97 
98  // Parameterize the test suite to run all tests using a file based
99  // authorization policy policy using metadata pulled from the Sentry Policy
100  // service.
101  @Parameters
102  public static Collection testVectors() {
103  return Arrays.asList(new Object[][] {{null}, {AUTHZ_POLICY_FILE}});
104  }
105 
106  public AuthorizationTest(String policyFile) throws Exception {
107  authzConfig_ = AuthorizationConfig.createHadoopGroupAuthConfig("server1", policyFile,
108  System.getenv("IMPALA_HOME") + "/fe/src/test/resources/sentry-site.xml");
109  authzConfig_.validateConfig();
110  if (!isSetup_ && policyFile == null) {
111  setup();
112  isSetup_ = true;
113  }
114  catalog_ = new ImpaladTestCatalog(authzConfig_);
115  queryCtx_ = TestUtils.createQueryContext(Catalog.DEFAULT_DB, USER.getName());
116  analysisContext_ = new AnalysisContext(catalog_, queryCtx_, authzConfig_);
117  fe_ = new Frontend(authzConfig_, catalog_);
118  }
119 
120  private void setup() throws Exception {
121  SentryPolicyService sentryService = new SentryPolicyService(
122  authzConfig_.getSentryConfig());
123  // Server admin. Don't grant to any groups, that is done within
124  // the test cases.
125  String roleName = "admin";
126  sentryService.createRole(USER, roleName, true);
127 
128  TPrivilege privilege = new TPrivilege("", TPrivilegeLevel.ALL,
129  TPrivilegeScope.SERVER, false);
130  privilege.setServer_name("server1");
131  sentryService.grantRolePrivilege(USER, roleName, privilege);
132  sentryService.revokeRoleFromGroup(USER, "admin", USER.getName());
133 
134  // insert functional alltypes
135  roleName = "insert_functional_alltypes";
136  roleName = roleName.toLowerCase();
137  sentryService.createRole(USER, roleName, true);
138  sentryService.grantRoleToGroup(USER, roleName, USER.getName());
139 
140  privilege = new TPrivilege("", TPrivilegeLevel.INSERT, TPrivilegeScope.TABLE,
141  false);
142  privilege.setServer_name("server1");
143  privilege.setDb_name("functional");
144  privilege.setTable_name("alltypes");
145  sentryService.grantRolePrivilege(USER, roleName, privilege);
146 
147  // insert_parquet
148  roleName = "insert_parquet";
149  sentryService.createRole(USER, roleName, true);
150  sentryService.grantRoleToGroup(USER, roleName, USER.getName());
151 
152  privilege = new TPrivilege("", TPrivilegeLevel.INSERT, TPrivilegeScope.TABLE,
153  false);
154  privilege.setServer_name("server1");
155  privilege.setDb_name("functional_parquet");
156  privilege.setTable_name(AuthorizeableTable.ANY_TABLE_NAME);
157  sentryService.grantRolePrivilege(USER, roleName, privilege);
158 
159  // all newdb w/ all on URI
160  roleName = "all_newdb";
161  sentryService.createRole(USER, roleName, true);
162  sentryService.grantRoleToGroup(USER, roleName, USER.getName());
163 
164  privilege = new TPrivilege("", TPrivilegeLevel.ALL, TPrivilegeScope.DATABASE,
165  false);
166  privilege.setServer_name("server1");
167  privilege.setDb_name("newdb");
168  sentryService.grantRolePrivilege(USER, roleName, privilege);
169 
170  privilege = new TPrivilege("", TPrivilegeLevel.ALL, TPrivilegeScope.URI,
171  false);
172  privilege.setServer_name("server1");
173  privilege.setUri("hdfs://localhost:20500/test-warehouse/new_table");
174  privilege.setTable_name(AuthorizeableTable.ANY_TABLE_NAME);
175  sentryService.grantRolePrivilege(USER, roleName, privilege);
176 
177  // all tpch
178  roleName = "all_tpch";
179  sentryService.createRole(USER, roleName, true);
180  sentryService.grantRoleToGroup(USER, roleName, USER.getName());
181  privilege = new TPrivilege("", TPrivilegeLevel.ALL, TPrivilegeScope.URI, false);
182  privilege.setServer_name("server1");
183  privilege.setUri("hdfs://localhost:20500/test-warehouse/tpch.lineitem");
184  sentryService.grantRolePrivilege(USER, roleName, privilege);
185 
186  privilege = new TPrivilege("", TPrivilegeLevel.ALL, TPrivilegeScope.DATABASE, false);
187  privilege.setServer_name("server1");
188  privilege.setDb_name("tpch");
189  sentryService.grantRolePrivilege(USER, roleName, privilege);
190 
191  // select tpcds
192  roleName = "select_tpcds";
193  sentryService.createRole(USER, roleName, true);
194  sentryService.grantRoleToGroup(USER, roleName, USER.getName());
195 
196  privilege = new TPrivilege("", TPrivilegeLevel.SELECT, TPrivilegeScope.TABLE, false);
197  privilege.setServer_name("server1");
198  privilege.setDb_name("tpcds");
199  privilege.setTable_name(AuthorizeableTable.ANY_TABLE_NAME);
200  sentryService.grantRolePrivilege(USER, roleName, privilege);
201 
202  // select_functional_alltypesagg
203  roleName = "select_functional_alltypesagg";
204  sentryService.createRole(USER, roleName, true);
205  sentryService.grantRoleToGroup(USER, roleName, USER.getName());
206 
207  privilege = new TPrivilege("", TPrivilegeLevel.SELECT, TPrivilegeScope.TABLE, false);
208  privilege.setServer_name("server1");
209  privilege.setDb_name("functional");
210  privilege.setTable_name("alltypesagg");
211  sentryService.grantRolePrivilege(USER, roleName, privilege);
212 
213  // select_functional_complex_view
214  roleName = "select_functional_complex_view";
215  sentryService.createRole(USER, roleName, true);
216  sentryService.grantRoleToGroup(USER, roleName, USER.getName());
217 
218  privilege = new TPrivilege("", TPrivilegeLevel.SELECT, TPrivilegeScope.TABLE, false);
219  privilege.setServer_name("server1");
220  privilege.setDb_name("functional");
221  privilege.setTable_name("complex_view");
222  sentryService.grantRolePrivilege(USER, roleName, privilege);
223 
224  // select_functional_view_view
225  roleName = "select_functional_view_view";
226  sentryService.createRole(USER, roleName, true);
227  sentryService.grantRoleToGroup(USER, roleName, USER.getName());
228 
229  privilege = new TPrivilege("", TPrivilegeLevel.SELECT, TPrivilegeScope.TABLE, false);
230  privilege.setServer_name("server1");
231  privilege.setDb_name("functional");
232  privilege.setTable_name("view_view");
233  sentryService.grantRolePrivilege(USER, roleName, privilege);
234 
235  // all_functional_seq_snap
236  roleName = "all_functional_seq_snap";
237  // Verify we are able to drop a role.
238  sentryService.dropRole(USER, roleName, true);
239  sentryService.createRole(USER, roleName, true);
240  sentryService.grantRoleToGroup(USER, roleName, USER.getName());
241 
242  privilege = new TPrivilege("", TPrivilegeLevel.ALL, TPrivilegeScope.DATABASE, false);
243  privilege.setServer_name("server1");
244  privilege.setDb_name("functional_seq_snap");
245  sentryService.grantRolePrivilege(USER, roleName, privilege);
246  }
247 
248  @Test
249  public void TestFix() throws AnalysisException {
250  AuthzError("select * from functional.complex_view_sub",
251  "User '%s' does not have privileges to execute 'SELECT' on: " +
252  "functional.complex_view_sub");
253  }
254 
255  @Test
256  public void TestSentryService() throws ImpalaException {
257  SentryPolicyService sentryService =
258  new SentryPolicyService(authzConfig_.getSentryConfig());
259  String roleName = "testRoleName";
260  roleName = roleName.toLowerCase();
261 
262  sentryService.createRole(USER, roleName, true);
263  String dbName = UUID.randomUUID().toString();
264  AuthorizeableDb db = new AuthorizeableDb(dbName);
265  TPrivilege privilege =
266  new TPrivilege("", TPrivilegeLevel.ALL, TPrivilegeScope.DATABASE, false);
267  privilege.setServer_name("server1");
268  privilege.setDb_name(dbName);
269  sentryService.grantRoleToGroup(USER, roleName, USER.getName());
270  sentryService.grantRolePrivilege(USER, roleName, privilege);
271 
272  for (int i = 0; i < 2; ++i) {
273  privilege = new TPrivilege("", TPrivilegeLevel.SELECT, TPrivilegeScope.TABLE,
274  false);
275  privilege.setServer_name("server1");
276  privilege.setDb_name(dbName);
277  privilege.setTable_name("test_tbl_" + String.valueOf(i));
278  sentryService.grantRolePrivilege(USER, roleName, privilege);
279  }
280  }
281 
282  @After
284  // Failure to cleanup TPCH can cause:
285  // TestDropDatabase(com.cloudera.impala.analysis.AuthorizationTest):
286  // Cannot drop non-empty database: tpch
287  if (catalog_.getDb("tpch").numFunctions() != 0) {
288  fail("Failed to clean up functions in tpch.");
289  }
290  }
291 
292  @Test
294  // Can select from table that user has privileges on.
295  AuthzOk("select * from functional.alltypesagg");
296 
297  AuthzOk("select * from functional_seq_snap.alltypes");
298 
299  // Can select from view that user has privileges on even though he/she doesn't
300  // have privileges on underlying tables.
301  AuthzOk("select * from functional.complex_view");
302 
303  // User has permission to select the view but not on the view (alltypes_view)
304  // referenced in its view definition.
305  AuthzOk("select * from functional.view_view");
306 
307  // User does not have SELECT privileges on this view.
308  AuthzError("select * from functional.complex_view_sub",
309  "User '%s' does not have privileges to execute 'SELECT' on: " +
310  "functional.complex_view_sub");
311 
312  // User has SELECT privileges on the view and the join table.
313  AuthzOk("select a.id from functional.view_view a "
314  + "join functional.alltypesagg b ON (a.id = b.id)");
315 
316  // User has SELECT privileges on the view, but does not have privileges
317  // to select join table.
318  AuthzError("select a.id from functional.view_view a "
319  + "join functional.alltypes b ON (a.id = b.id)",
320  "User '%s' does not have privileges to execute 'SELECT' on: " +
321  "functional.alltypes");
322 
323  // Constant select.
324  AuthzOk("select 1");
325 
326  // Unqualified table name.
327  AuthzError("select * from alltypes",
328  "User '%s' does not have privileges to execute 'SELECT' on: default.alltypes");
329 
330  // Select with no privileges on table.
331  AuthzError("select * from functional.alltypes",
332  "User '%s' does not have privileges to execute 'SELECT' on: " +
333  "functional.alltypes");
334 
335  // Select with no privileges on view.
336  AuthzError("select * from functional.complex_view_sub",
337  "User '%s' does not have privileges to execute 'SELECT' on: " +
338  "functional.complex_view_sub");
339 
340  // Select without referencing a column.
341  AuthzError("select 1 from functional.alltypes",
342  "User '%s' does not have privileges to execute 'SELECT' on: " +
343  "functional.alltypes");
344 
345  // Select from non-existent table.
346  AuthzError("select 1 from functional.notbl",
347  "User '%s' does not have privileges to execute 'SELECT' on: functional.notbl");
348 
349  // Select from non-existent db.
350  AuthzError("select 1 from nodb.alltypes",
351  "User '%s' does not have privileges to execute 'SELECT' on: nodb.alltypes");
352 
353  // Table within inline view is authorized properly.
354  AuthzError("select a.* from (select * from functional.alltypes) a",
355  "User '%s' does not have privileges to execute 'SELECT' on: " +
356  "functional.alltypes");
357  // Table within inline view is authorized properly (user has permission).
358  AuthzOk("select a.* from (select * from functional.alltypesagg) a");
359  }
360 
361  @Test
363  AuthzOk("select * from functional.alltypesagg union all " +
364  "select * from functional.alltypesagg");
365 
366  AuthzError("select * from functional.alltypesagg union all " +
367  "select * from functional.alltypes",
368  "User '%s' does not have privileges to execute 'SELECT' on: " +
369  "functional.alltypes");
370  }
371 
372  @Test
374  AuthzOk("insert into functional_parquet.alltypes " +
375  "partition(month,year) select * from functional_seq_snap.alltypes");
376 
377  // Insert + inline view (user has permissions).
378  AuthzOk("insert into functional.alltypes partition(month,year) " +
379  "select b.* from functional.alltypesagg a join (select * from " +
380  "functional_seq_snap.alltypes) b on (a.int_col = b.int_col)");
381 
382  // User doesn't have INSERT permissions in the target table.
383  AuthzError("insert into functional.alltypesagg select 1",
384  "User '%s' does not have privileges to execute 'INSERT' on: " +
385  "functional.alltypesagg");
386 
387  // User doesn't have INSERT permissions in the target view.
388  // Inserting into a view is not allowed.
389  AuthzError("insert into functional.alltypes_view select 1",
390  "User '%s' does not have privileges to execute 'INSERT' on: " +
391  "functional.alltypes_view");
392 
393  // User doesn't have SELECT permissions on source table.
394  AuthzError("insert into functional.alltypes " +
395  "select * from functional.alltypes",
396  "User '%s' does not have privileges to execute 'SELECT' on: " +
397  "functional.alltypes");
398 
399  // User doesn't have permissions on source table within inline view.
400  AuthzError("insert into functional.alltypes " +
401  "select * from functional.alltypesagg a join (select * from " +
402  "functional_seq.alltypes) b on (a.int_col = b.int_col)",
403  "User '%s' does not have privileges to execute 'SELECT' on: " +
404  "functional_seq.alltypes");
405  }
406 
407  @Test
409  // User has SELECT privileges on table in WITH-clause view.
410  AuthzOk("with t as (select * from functional.alltypesagg) select * from t");
411  // User doesn't have SELECT privileges on table in WITH-clause view.
412  AuthzError("with t as (select * from functional.alltypes) select * from t",
413  "User '%s' does not have privileges to execute 'SELECT' on: " +
414  "functional.alltypes");
415  // User has SELECT privileges on view in WITH-clause view.
416  AuthzOk("with t as (select * from functional.complex_view) select * from t");
417 
418  // User has SELECT privileges on table in WITH-clause view in INSERT.
419  AuthzOk("with t as (select * from functional_seq_snap.alltypes) " +
420  "insert into functional_parquet.alltypes partition(month,year) select * from t");
421  // User doesn't have SELECT privileges on table in WITH-clause view in INSERT.
422  AuthzError("with t as (select * from functional_parquet.alltypes) " +
423  "insert into functional_parquet.alltypes partition(month,year) select * from t",
424  "User '%s' does not have privileges to execute 'SELECT' on: " +
425  "functional_parquet.alltypes");
426  // User doesn't have SELECT privileges on view in WITH-clause view in INSERT.
427  AuthzError("with t as (select * from functional.alltypes_view) " +
428  "insert into functional_parquet.alltypes partition(month,year) select * from t",
429  "User '%s' does not have privileges to execute 'SELECT' on: " +
430  "functional.alltypes_view");
431  }
432 
433  @Test
435  AuthzOk("explain select * from functional.alltypesagg");
436  AuthzOk("explain insert into functional_parquet.alltypes " +
437  "partition(month,year) select * from functional_seq_snap.alltypes");
438 
439  // Select without permissions.
440  AuthzError("explain select * from functional.alltypes",
441  "User '%s' does not have privileges to execute 'SELECT' on: " +
442  "functional.alltypes");
443 
444  // Insert with no select permissions on source table.
445  AuthzError("explain insert into functional_parquet.alltypes " +
446  "partition(month,year) select * from functional.alltypes",
447  "User '%s' does not have privileges to execute 'SELECT' on: " +
448  "functional.alltypes");
449  // Insert, user doesn't have permissions on source table.
450  AuthzError("explain insert into functional.alltypes " +
451  "select * from functional.alltypes",
452  "User '%s' does not have privileges to execute 'SELECT' on: " +
453  "functional.alltypes");
454 
455  // Test explain on views. User has permissions on all the underlying tables.
456  AuthzOk("explain select * from functional_seq_snap.alltypes_view");
457  AuthzOk("explain insert into functional_parquet.alltypes " +
458  "partition(month,year) select * from functional_seq_snap.alltypes_view");
459 
460  // Select on view without permissions on view.
461  AuthzError("explain select * from functional.alltypes_view",
462  "User '%s' does not have privileges to execute 'SELECT' on: " +
463  "functional.alltypes_view");
464  // Insert into view without permissions on view.
465  AuthzError("explain insert into functional.alltypes_view " +
466  "select * from functional_seq_snap.alltypes ",
467  "User '%s' does not have privileges to execute 'INSERT' on: " +
468  "functional.alltypes_view");
469 
470  // User has permission on view, but not on underlying tables.
471  AuthzError("explain select * from functional.complex_view",
472  "User '%s' does not have privileges to EXPLAIN this statement.");
473  // User has permission on view in WITH clause, but not on underlying tables.
474  AuthzError("explain with t as (select * from functional.complex_view) " +
475  "select * from t",
476  "User '%s' does not have privileges to EXPLAIN this statement.");
477 
478  // User has permission on view in WITH clause, but not on underlying tables.
479  AuthzError("explain with t as (select * from functional.complex_view) " +
480  "select * from t",
481  "User '%s' does not have privileges to EXPLAIN this statement.");
482  // User has permission on view and on view inside view,
483  // but not on tables in view inside view.
484  AuthzError("explain select * from functional.view_view",
485  "User '%s' does not have privileges to EXPLAIN this statement.");
486  // User doesn't have permission on tables in view inside view.
487  AuthzError("explain insert into functional_seq_snap.alltypes " +
488  "partition(month,year) select * from functional.view_view",
489  "User '%s' does not have privileges to EXPLAIN this statement.");
490 
491  // User has SELECT privileges on the view, but does not have privileges
492  // to select join table. Should get standard auth message back.
493  AuthzError("explain select a.id from functional.view_view a "
494  + "join functional.alltypes b ON (a.id = b.id)",
495  "User '%s' does not have privileges to execute 'SELECT' on: " +
496  "functional.alltypes");
497 
498  // User has privileges on tables inside the first view, but not the second
499  // view. Should get masked auth error back.
500  AuthzError("explain select a.id from functional.view_view a "
501  + "join functional.complex_view b ON (a.id = b.id)",
502  "User '%s' does not have privileges to EXPLAIN this statement.");
503  }
504 
505  @Test
507  // Positive cases (user has privileges on these tables).
508  AuthzOk("use functional");
509  AuthzOk("use tpcds");
510  AuthzOk("use tpch");
511 
512  // Should always be able to use default, even if privilege was not explicitly
513  // granted.
514  AuthzOk("use default");
515 
516  AuthzError("use functional_seq",
517  "User '%s' does not have privileges to access: functional_seq.*");
518 
519  // Database does not exist, user does not have access.
520  AuthzError("use nodb",
521  "User '%s' does not have privileges to access: nodb.*");
522 
523  // Database does not exist, user has access:
524  try {
525  AuthzOk("use newdb");
526  fail("Expected AnalysisException");
527  } catch (AnalysisException e) {
528  Assert.assertEquals(e.getMessage(), "Database does not exist: newdb");
529  }
530 
531  // All users should be able to use the system db.
532  AuthzOk("use _impala_builtins");
533  }
534 
535  @Test
536  public void TestResetMetadata() throws ImpalaException {
537  // Positive cases (user has privileges on these tables/views).
538  AuthzOk("invalidate metadata functional.alltypesagg");
539  AuthzOk("refresh functional.alltypesagg");
540  AuthzOk("invalidate metadata functional.view_view");
541  AuthzOk("refresh functional.view_view");
542 
543  AuthzError("invalidate metadata unknown_db.alltypessmall",
544  "User '%s' does not have privileges to access: unknown_db.alltypessmall");
545  AuthzError("invalidate metadata functional_seq.alltypessmall",
546  "User '%s' does not have privileges to access: functional_seq.alltypessmall");
547  AuthzError("invalidate metadata functional.alltypes_view",
548  "User '%s' does not have privileges to access: functional.alltypes_view");
549  AuthzError("invalidate metadata functional.unknown_table",
550  "User '%s' does not have privileges to access: functional.unknown_table");
551  AuthzError("invalidate metadata functional.alltypessmall",
552  "User '%s' does not have privileges to access: functional.alltypessmall");
553  AuthzError("refresh functional.alltypessmall",
554  "User '%s' does not have privileges to access: functional.alltypessmall");
555  AuthzError("refresh functional.alltypes_view",
556  "User '%s' does not have privileges to access: functional.alltypes_view");
557 
558  AuthzError("invalidate metadata",
559  "User '%s' does not have privileges to access: server");
560 
561  // TODO: Add test support for dynamically changing privileges for
562  // file-based policy.
563  if (authzConfig_.isFileBasedPolicy()) return;
564  SentryPolicyService sentryService = createSentryService();
565 
566  try {
567  sentryService.grantRoleToGroup(USER, "admin", USER.getName());
568  ((ImpaladTestCatalog) catalog_).reset();
569  AuthzOk("invalidate metadata");
570  } finally {
571  sentryService.revokeRoleFromGroup(USER, "admin", USER.getName());
572  ((ImpaladTestCatalog) catalog_).reset();
573  }
574  }
575 
576  @Test
578  AuthzOk("create table tpch.new_table (i int)");
579  AuthzOk("create table tpch.new_lineitem like tpch.lineitem");
580  // Create table IF NOT EXISTS, user has permission and table exists.
581  AuthzOk("create table if not exists tpch.lineitem (i int)");
582  try {
583  AuthzOk("create table tpch.lineitem (i int)");
584  fail("Expected analysis error.");
585  } catch (AnalysisException e) {
586  Assert.assertEquals(e.getMessage(), "Table already exists: tpch.lineitem");
587  }
588 
589  // Create table AS SELECT positive and negative cases for SELECT privilege.
590  AuthzOk("create table tpch.new_table as select * from functional.alltypesagg");
591  AuthzError("create table tpch.new_table as select * from functional.alltypes",
592  "User '%s' does not have privileges to execute 'SELECT' on: " +
593  "functional.alltypes");
594 
595  AuthzError("create table functional.tbl tblproperties('a'='b')" +
596  " as select 1",
597  "User '%s' does not have privileges to execute 'CREATE' on: " +
598  "functional.tbl");
599 
600  // Create table IF NOT EXISTS, user does not have permission and table exists.
601  AuthzError("create table if not exists functional_seq.alltypes (i int)",
602  "User '%s' does not have privileges to execute 'CREATE' on: " +
603  "functional_seq.alltypes");
604 
605  // User has permission to create at given location.
606  AuthzOk("create table tpch.new_table (i int) location " +
607  "'hdfs://localhost:20500/test-warehouse/new_table'");
608 
609  // No permissions on source table.
610  AuthzError("create table tpch.new_lineitem like tpch_seq.lineitem",
611  "User '%s' does not have privileges to access: tpch_seq.lineitem");
612 
613  // No permissions on target table.
614  AuthzError("create table tpch_rc.new like tpch.lineitem",
615  "User '%s' does not have privileges to execute 'CREATE' on: tpch_rc.new");
616 
617  // Unqualified table name.
618  AuthzError("create table new_table (i int)",
619  "User '%s' does not have privileges to execute 'CREATE' on: default.new_table");
620 
621  // Table already exists (user does not have permission).
622  AuthzError("create table functional.alltypes (i int)",
623  "User '%s' does not have privileges to execute 'CREATE' on: " +
624  "functional.alltypes");
625 
626  // Database does not exist, user does not have access.
627  AuthzError("create table nodb.alltypes (i int)",
628  "User '%s' does not have privileges to execute 'CREATE' on: " +
629  "nodb.alltypes");
630 
631  // User does not have permission to create table at the specified location..
632  AuthzError("create table tpch.new_table (i int) location " +
633  "'hdfs://localhost:20500/test-warehouse/alltypes'",
634  "User '%s' does not have privileges to access: " +
635  "hdfs://localhost:20500/test-warehouse/alltypes");
636 
637  AuthzError("create table _impala_builtins.tbl(i int)",
638  "Cannot modify system database.");
639 
640  // Check that create like file follows authorization rules for HDFS files
641  AuthzError("create table tpch.table_DNE like parquet "
642  + "'hdfs://localhost:20500/test-warehouse/alltypes'",
643  "User '%s' does not have privileges to access: "
644  + "hdfs://localhost:20500/test-warehouse/alltypes");
645  }
646 
647  @Test
649  AuthzOk("create view tpch.new_view as select * from functional.alltypesagg");
650  AuthzOk("create view tpch.new_view (a, b, c) as " +
651  "select int_col, string_col, timestamp_col from functional.alltypesagg");
652  // Create view IF NOT EXISTS, user has permission and table exists.
653  AuthzOk("create view if not exists tpch.lineitem as " +
654  "select * from functional.alltypesagg");
655  // Create view IF NOT EXISTS, user has permission and table/view exists.
656  try {
657  AuthzOk("create view tpch.lineitem as select * from functional.alltypesagg");
658  fail("Expected analysis error.");
659  } catch (AnalysisException e) {
660  Assert.assertEquals(e.getMessage(), "Table already exists: tpch.lineitem");
661  }
662 
663  // Create view IF NOT EXISTS, user does not have permission and table/view exists.
664  AuthzError("create view if not exists functional_seq.alltypes as " +
665  "select * from functional.alltypesagg",
666  "User '%s' does not have privileges to execute 'CREATE' on: " +
667  "functional_seq.alltypes");
668 
669  // No permissions on source table.
670  AuthzError("create view tpch.new_view as select * from functional.alltypes",
671  "User '%s' does not have privileges to execute 'SELECT' on: " +
672  "functional.alltypes");
673 
674  // No permissions on target table.
675  AuthzError("create view tpch_rc.new as select * from functional.alltypesagg",
676  "User '%s' does not have privileges to execute 'CREATE' on: tpch_rc.new");
677 
678  // Unqualified view name.
679  AuthzError("create view new_view as select * from functional.alltypesagg",
680  "User '%s' does not have privileges to execute 'CREATE' on: default.new_view");
681 
682  // Table already exists (user does not have permission).
683  AuthzError("create view functional.alltypes_view as " +
684  "select * from functional.alltypesagg",
685  "User '%s' does not have privileges to execute 'CREATE' on: " +
686  "functional.alltypes_view");
687 
688  // Database does not exist, user does not have access.
689  AuthzError("create view nodb.alltypes as select * from functional.alltypesagg",
690  "User '%s' does not have privileges to execute 'CREATE' on: " +
691  "nodb.alltypes");
692 
693  AuthzError("create view _impala_builtins.new_view as "
694  + "select * from functional.alltypesagg",
695  "Cannot modify system database.");
696  }
697 
698  @Test
699  public void TestCreateDatabase() throws ImpalaException {
700  // Database already exists (no permissions).
701  AuthzError("create database functional",
702  "User '%s' does not have privileges to execute 'CREATE' on: functional");
703 
704  // Non existent db (no permissions).
705  AuthzError("create database nodb",
706  "User '%s' does not have privileges to execute 'CREATE' on: nodb");
707 
708  // Non existent db (no permissions).
709  AuthzError("create database if not exists _impala_builtins",
710  "Cannot modify system database.");
711 
712  // TODO: Add test support for dynamically changing privileges for
713  // file-based policy.
714  if (authzConfig_.isFileBasedPolicy()) return;
715 
716  SentryPolicyService sentryService =
717  new SentryPolicyService(authzConfig_.getSentryConfig());
718  try {
719  sentryService.grantRoleToGroup(USER, "admin", USER.getName());
720  ((ImpaladTestCatalog) catalog_).reset();
721 
722  // User has permissions to create database.
723  AuthzOk("create database newdb");
724 
725  // Create database with location specified explicitly (user has permission).
726  // Since create database requires server-level privileges there should never
727  // be a case where the user has privileges to create a database does not have
728  // privileges on the URI.
729  AuthzOk("create database newdb location " +
730  "'hdfs://localhost:20500/test-warehouse/new_table'");
731  } finally {
732  sentryService.revokeRoleFromGroup(USER, "admin", USER.getName());
733  ((ImpaladTestCatalog) catalog_).reset();
734  }
735  }
736 
737  @Test
739  // User has permissions.
740  AuthzOk("drop database tpch");
741  // User has permissions, database does not exists and IF EXISTS specified
742  AuthzOk("drop database if exists newdb");
743  // User has permission, database does not exists, IF EXISTS not specified.
744  try {
745  AuthzOk("drop database newdb");
746  fail("Expected analysis error");
747  } catch (AnalysisException e) {
748  Assert.assertEquals(e.getMessage(), "Database does not exist: newdb");
749  }
750 
751  // Database exists, user doesn't have permission to drop.
752  AuthzError("drop database functional",
753  "User '%s' does not have privileges to execute 'DROP' on: functional");
754  AuthzError("drop database if exists functional",
755  "User '%s' does not have privileges to execute 'DROP' on: functional");
756 
757  // Database does not exist, user doesn't have permission to drop.
758  AuthzError("drop database nodb",
759  "User '%s' does not have privileges to execute 'DROP' on: nodb");
760  AuthzError("drop database if exists nodb",
761  "User '%s' does not have privileges to execute 'DROP' on: nodb");
762 
763  AuthzError("drop database _impala_builtins",
764  "Cannot modify system database.");
765  }
766 
767  @Test
769  // Drop table (user has permission).
770  AuthzOk("drop table tpch.lineitem");
771  AuthzOk("drop table if exists tpch.lineitem");
772 
773  // Drop table (user does not have permission).
774  AuthzError("drop table functional.alltypes",
775  "User '%s' does not have privileges to execute 'DROP' on: functional.alltypes");
776  AuthzError("drop table if exists functional.alltypes",
777  "User '%s' does not have privileges to execute 'DROP' on: functional.alltypes");
778 
779  // Drop table with unqualified table name.
780  AuthzError("drop table alltypes",
781  "User '%s' does not have privileges to execute 'DROP' on: default.alltypes");
782 
783  // Drop table with non-existent database.
784  AuthzError("drop table nodb.alltypes",
785  "User '%s' does not have privileges to execute 'DROP' on: nodb.alltypes");
786 
787  // Drop table with non-existent table.
788  AuthzError("drop table functional.notbl",
789  "User '%s' does not have privileges to execute 'DROP' on: functional.notbl");
790 
791  // Using DROP TABLE on a view does not reveal privileged information.
792  AuthzError("drop table functional.view_view",
793  "User '%s' does not have privileges to execute 'DROP' on: functional.view_view");
794 
795  // Using DROP TABLE on a view does not reveal privileged information.
796  AuthzError("drop table if exists _impala_builtins.tbl",
797  "Cannot modify system database.");
798  }
799 
800  @Test
802  // Drop view (user has permission).
803  AuthzOk("drop view functional_seq_snap.alltypes_view");
804  AuthzOk("drop view if exists functional_seq_snap.alltypes_view");
805 
806  // Drop view (user does not have permission).
807  AuthzError("drop view functional.alltypes_view",
808  "User '%s' does not have privileges to execute 'DROP' on: functional.alltypes");
809  AuthzError("drop view if exists functional.alltypes_view",
810  "User '%s' does not have privileges to execute 'DROP' on: functional.alltypes");
811 
812  // Drop view with unqualified table name.
813  AuthzError("drop view alltypes",
814  "User '%s' does not have privileges to execute 'DROP' on: default.alltypes");
815 
816  // Drop view with non-existent database.
817  AuthzError("drop view nodb.alltypes",
818  "User '%s' does not have privileges to execute 'DROP' on: nodb.alltypes");
819 
820  // Drop view with non-existent table.
821  AuthzError("drop view functional.notbl",
822  "User '%s' does not have privileges to execute 'DROP' on: functional.notbl");
823 
824  // Using DROP VIEW on a table does not reveal privileged information.
825  AuthzError("drop view functional.alltypes",
826  "User '%s' does not have privileges to execute 'DROP' on: functional.alltypes");
827 
828  // Using DROP VIEW on a table does not reveal privileged information.
829  AuthzError("drop view _impala_builtins.my_view",
830  "Cannot modify system database.");
831  }
832 
833  @Test
835  // User has permissions to modify tables.
836  AuthzOk("ALTER TABLE functional_seq_snap.alltypes ADD COLUMNS (c1 int)");
837  AuthzOk("ALTER TABLE functional_seq_snap.alltypes REPLACE COLUMNS (c1 int)");
838  AuthzOk("ALTER TABLE functional_seq_snap.alltypes CHANGE int_col c1 int");
839  AuthzOk("ALTER TABLE functional_seq_snap.alltypes DROP int_col");
840  AuthzOk("ALTER TABLE functional_seq_snap.alltypes RENAME TO functional_seq_snap.t1");
841  AuthzOk("ALTER TABLE functional_seq_snap.alltypes SET FILEFORMAT PARQUET");
842  AuthzOk("ALTER TABLE functional_seq_snap.alltypes SET LOCATION " +
843  "'/test-warehouse/new_table'");
844  AuthzOk("ALTER TABLE functional_seq_snap.alltypes SET TBLPROPERTIES " +
845  "('a'='b', 'c'='d')");
846  AuthzOk("ALTER TABLE functional_seq_snap.alltypes SET LOCATION " +
847  "'hdfs://localhost:20500/test-warehouse/new_table'");
848  AuthzOk("ALTER TABLE functional_seq_snap.alltypes PARTITION(year=2009, month=1) " +
849  "SET LOCATION 'hdfs://localhost:20500/test-warehouse/new_table'");
850 
851  AuthzOk("ALTER TABLE functional_seq_snap.alltypes SET CACHED IN 'testPool'");
852 
853 
854  // Alter table and set location to a path the user does not have access to.
855  AuthzError("ALTER TABLE functional_seq_snap.alltypes SET LOCATION " +
856  "'hdfs://localhost:20500/test-warehouse/no_access'",
857  "User '%s' does not have privileges to access: " +
858  "hdfs://localhost:20500/test-warehouse/no_access");
859  AuthzError("ALTER TABLE functional_seq_snap.alltypes SET LOCATION " +
860  "'/test-warehouse/no_access'",
861  "User '%s' does not have privileges to access: " +
862  "hdfs://localhost:20500/test-warehouse/no_access");
863  AuthzError("ALTER TABLE functional_seq_snap.alltypes PARTITION(year=2009, month=1) " +
864  "SET LOCATION '/test-warehouse/no_access'",
865  "User '%s' does not have privileges to access: " +
866  "hdfs://localhost:20500/test-warehouse/no_access");
867 
868  // Different filesystem, user has permission to base path.
869  AuthzError("ALTER TABLE functional_seq_snap.alltypes SET LOCATION " +
870  "'hdfs://localhost:20510/test-warehouse/new_table'",
871  "User '%s' does not have privileges to access: " +
872  "hdfs://localhost:20510/test-warehouse/new_table");
873 
874  AuthzError("ALTER TABLE functional.alltypes SET FILEFORMAT PARQUET",
875  "User '%s' does not have privileges to execute 'ALTER' on: functional.alltypes");
876  AuthzError("ALTER TABLE functional.alltypes ADD COLUMNS (c1 int)",
877  "User '%s' does not have privileges to execute 'ALTER' on: functional.alltypes");
878  AuthzError("ALTER TABLE functional.alltypes REPLACE COLUMNS (c1 int)",
879  "User '%s' does not have privileges to execute 'ALTER' on: functional.alltypes");
880  AuthzError("ALTER TABLE functional.alltypes CHANGE int_col c1 int",
881  "User '%s' does not have privileges to execute 'ALTER' on: functional.alltypes");
882  AuthzError("ALTER TABLE functional.alltypes DROP int_col",
883  "User '%s' does not have privileges to execute 'ALTER' on: functional.alltypes");
884  AuthzError("ALTER TABLE functional.alltypes rename to functional_seq_snap.t1",
885  "User '%s' does not have privileges to execute 'ALTER' on: functional.alltypes");
886  AuthzError("ALTER TABLE functional.alltypes add partition (year=1, month=1)",
887  "User '%s' does not have privileges to execute 'ALTER' on: functional.alltypes");
888  AuthzError("ALTER TABLE functional.alltypes set cached in 'testPool'",
889  "User '%s' does not have privileges to execute 'ALTER' on: functional.alltypes");
890  AuthzError("ALTER TABLE functional.alltypes set uncached",
891  "User '%s' does not have privileges to execute 'ALTER' on: functional.alltypes");
892 
893  // Trying to ALTER TABLE a view does not reveal any privileged information.
894  AuthzError("ALTER TABLE functional.view_view SET FILEFORMAT PARQUET",
895  "User '%s' does not have privileges to execute 'ALTER' on: functional.view_view");
896  AuthzError("ALTER TABLE functional.view_view ADD COLUMNS (c1 int)",
897  "User '%s' does not have privileges to execute 'ALTER' on: functional.view_view");
898  AuthzError("ALTER TABLE functional.view_view REPLACE COLUMNS (c1 int)",
899  "User '%s' does not have privileges to execute 'ALTER' on: functional.view_view");
900  AuthzError("ALTER TABLE functional.view_view CHANGE int_col c1 int",
901  "User '%s' does not have privileges to execute 'ALTER' on: functional.view_view");
902  AuthzError("ALTER TABLE functional.view_view DROP int_col",
903  "User '%s' does not have privileges to execute 'ALTER' on: functional.view_view");
904  AuthzError("ALTER TABLE functional.view_views rename to functional_seq_snap.t1",
905  "User '%s' does not have privileges to execute 'ALTER' on: functional.view_view");
906 
907  // No privileges on target (existing table).
908  AuthzError("ALTER TABLE functional_seq_snap.alltypes rename to functional.alltypes",
909  "User '%s' does not have privileges to execute 'CREATE' on: " +
910  "functional.alltypes");
911 
912  // No privileges on target (existing view).
913  AuthzError("ALTER TABLE functional_seq_snap.alltypes rename to " +
914  "functional.alltypes_view",
915  "User '%s' does not have privileges to execute 'CREATE' on: " +
916  "functional.alltypes");
917 
918  // ALTER TABLE on a view does not reveal privileged information.
919  AuthzError("ALTER TABLE functional.alltypes_view rename to " +
920  "functional_seq_snap.new_view",
921  "User '%s' does not have privileges to execute 'ALTER' on: " +
922  "functional.alltypes_view");
923 
924  // Rename table that does not exist (no permissions).
925  AuthzError("ALTER TABLE functional.notbl rename to functional_seq_snap.newtbl",
926  "User '%s' does not have privileges to execute 'ALTER' on: functional.notbl");
927 
928  // Rename table in db that does not exist (no permissions).
929  AuthzError("ALTER TABLE nodb.alltypes rename to functional_seq_snap.newtbl",
930  "User '%s' does not have privileges to execute 'ALTER' on: nodb.alltypes");
931 
932  // Alter table that does not exist (no permissions).
933  AuthzError("ALTER TABLE functional.notbl ADD COLUMNS (c1 int)",
934  "User '%s' does not have privileges to execute 'ALTER' on: functional.notbl");
935 
936  // Alter table in db that does not exist (no permissions).
937  AuthzError("ALTER TABLE nodb.alltypes ADD COLUMNS (c1 int)",
938  "User '%s' does not have privileges to execute 'ALTER' on: nodb.alltypes");
939 
940  // Unqualified table name.
941  AuthzError("ALTER TABLE alltypes ADD COLUMNS (c1 int)",
942  "User '%s' does not have privileges to execute 'ALTER' on: default.alltypes");
943 
944  AuthzError("ALTER TABLE alltypes SET TBLPROPERTIES ('a'='b', 'c'='d')",
945  "User '%s' does not have privileges to execute 'ALTER' on: default.alltypes");
946  }
947 
948  @Test
950  AuthzOk("ALTER VIEW functional_seq_snap.alltypes_view rename to " +
951  "functional_seq_snap.v1");
952 
953  // No privileges on target (existing table).
954  AuthzError("ALTER VIEW functional_seq_snap.alltypes_view rename to " +
955  "functional.alltypes",
956  "User '%s' does not have privileges to execute 'CREATE' on: " +
957  "functional.alltypes");
958 
959  // No privileges on target (existing view).
960  AuthzError("ALTER VIEW functional_seq_snap.alltypes_view rename to " +
961  "functional.alltypes_view",
962  "User '%s' does not have privileges to execute 'CREATE' on: " +
963  "functional.alltypes_view");
964 
965  // ALTER VIEW on a table does not reveal privileged information.
966  AuthzError("ALTER VIEW functional.alltypes rename to " +
967  "functional_seq_snap.new_view",
968  "User '%s' does not have privileges to execute 'ALTER' on: " +
969  "functional.alltypes");
970 
971  // Rename view that does not exist (no permissions).
972  AuthzError("ALTER VIEW functional.notbl rename to functional_seq_snap.newtbl",
973  "User '%s' does not have privileges to execute 'ALTER' on: functional.notbl");
974 
975  // Rename view in db that does not exist (no permissions).
976  AuthzError("ALTER VIEW nodb.alltypes rename to functional_seq_snap.newtbl",
977  "User '%s' does not have privileges to execute 'ALTER' on: nodb.alltypes");
978 
979  // Alter view that does not exist (no permissions).
980  AuthzError("ALTER VIEW functional.notbl rename to functional_seq_snap.new_view",
981  "User '%s' does not have privileges to execute 'ALTER' on: functional.notbl");
982 
983  // Alter view in db that does not exist (no permissions).
984  AuthzError("ALTER VIEW nodb.alltypes rename to functional_seq_snap.new_view",
985  "User '%s' does not have privileges to execute 'ALTER' on: nodb.alltypes");
986 
987  // Unqualified view name.
988  AuthzError("ALTER VIEW alltypes rename to functional_seq_snap.new_view",
989  "User '%s' does not have privileges to execute 'ALTER' on: default.alltypes");
990 
991  // No permissions on target view.
992  AuthzError("alter view functional.alltypes_view as " +
993  "select * from functional.alltypesagg",
994  "User '%s' does not have privileges to execute 'ALTER' on: " +
995  "functional.alltypes_view");
996 
997  // No permissions on source view.
998  AuthzError("alter view functional_seq_snap.alltypes_view " +
999  "as select * from functional.alltypes_view",
1000  "User '%s' does not have privileges to execute 'SELECT' on: " +
1001  "functional.alltypes_view");
1002  }
1003 
1004  @Test
1006  AuthzOk("compute stats functional_seq_snap.alltypes");
1007 
1008  AuthzError("compute stats functional.alltypes",
1009  "User '%s' does not have privileges to execute 'ALTER' on: functional.alltypes");
1010  AuthzError("compute stats functional.alltypesagg",
1011  "User '%s' does not have privileges to execute 'ALTER' on: " +
1012  "functional.alltypesagg");
1013  }
1014 
1015  @Test
1017  AuthzOk("drop stats functional_seq_snap.alltypes");
1018 
1019  AuthzError("drop stats functional.alltypes",
1020  "User '%s' does not have privileges to execute 'ALTER' on: functional.alltypes");
1021  AuthzError("drop stats functional.alltypesagg",
1022  "User '%s' does not have privileges to execute 'ALTER' on: " +
1023  "functional.alltypesagg");
1024  }
1025 
1026  @Test
1028  AuthzOk("describe functional.alltypesagg");
1029  AuthzOk("describe functional.alltypes");
1030  AuthzOk("describe functional.complex_view");
1031 
1032  // Unqualified table name.
1033  AuthzError("describe alltypes",
1034  "User '%s' does not have privileges to access: default.alltypes");
1035  // Database doesn't exist.
1036  AuthzError("describe nodb.alltypes",
1037  "User '%s' does not have privileges to access: nodb.alltypes");
1038  // Insufficient privileges on table.
1039  AuthzError("describe functional.alltypestiny",
1040  "User '%s' does not have privileges to access: functional.alltypestiny");
1041  // Insufficient privileges on view.
1042  AuthzError("describe functional.alltypes_view",
1043  "User '%s' does not have privileges to access: functional.alltypes_view");
1044  // Insufficient privileges on db.
1045  AuthzError("describe functional_rc.alltypes",
1046  "User '%s' does not have privileges to access: functional_rc.alltypes");
1047  }
1048 
1049  @Test
1051  // User has permission on table and URI.
1052  AuthzOk("load data inpath 'hdfs://localhost:20500/test-warehouse/tpch.lineitem'" +
1053  " into table functional.alltypes partition(month=10, year=2009)");
1054 
1055  // User does not have permission on table.
1056  AuthzError("load data inpath 'hdfs://localhost:20500/test-warehouse/tpch.lineitem'" +
1057  " into table functional.alltypesagg",
1058  "User '%s' does not have privileges to execute 'INSERT' on: " +
1059  "functional.alltypes");
1060 
1061  // User does not have permission on URI.
1062  AuthzError("load data inpath 'hdfs://localhost:20500/test-warehouse/tpch.part'" +
1063  " into table functional.alltypes partition(month=10, year=2009)",
1064  "User '%s' does not have privileges to access: " +
1065  "hdfs://localhost:20500/test-warehouse/tpch.part");
1066 
1067  // URI does not exist and user does not have permission.
1068  AuthzError("load data inpath 'hdfs://localhost:20500/test-warehouse/nope'" +
1069  " into table functional.alltypes partition(month=10, year=2009)",
1070  "User '%s' does not have privileges to access: " +
1071  "hdfs://localhost:20500/test-warehouse/nope");
1072 
1073  // Table/Db does not exist, user does not have permission.
1074  AuthzError("load data inpath 'hdfs://localhost:20500/test-warehouse/tpch.lineitem'" +
1075  " into table functional.notable",
1076  "User '%s' does not have privileges to execute 'INSERT' on: " +
1077  "functional.notable");
1078  AuthzError("load data inpath 'hdfs://localhost:20500/test-warehouse/tpch.lineitem'" +
1079  " into table nodb.alltypes",
1080  "User '%s' does not have privileges to execute 'INSERT' on: " +
1081  "nodb.alltypes");
1082 
1083  // Trying to LOAD a view does not reveal privileged information.
1084  AuthzError("load data inpath 'hdfs://localhost:20500/test-warehouse/tpch.lineitem'" +
1085  " into table functional.alltypes_view",
1086  "User '%s' does not have privileges to execute 'INSERT' on: " +
1087  "functional.alltypes_view");
1088  }
1089 
1090  @Test
1092  AuthzOk("show tables in functional");
1093  AuthzOk("show databases");
1094  AuthzOk("show tables in _impala_builtins");
1095  AuthzOk("show functions in _impala_builtins");
1096 
1097  // Database exists, user does not have access.
1098  AuthzError("show tables in functional_rc",
1099  "User '%s' does not have privileges to access: functional_rc.*");
1100 
1101  // Database does not exist, user does not have access.
1102  AuthzError("show tables in nodb",
1103  "User '%s' does not have privileges to access: nodb.*");
1104 
1105  AuthzError("show tables",
1106  "User '%s' does not have privileges to access: default.*");
1107 
1108  // Database does not exist, user has access.
1109  try {
1110  AuthzOk("show tables in newdb");
1111  fail("Expected AnalysisException");
1112  } catch (AnalysisException e) {
1113  Assert.assertEquals(e.getMessage(), "Database does not exist: newdb");
1114  }
1115 
1116  // Show partitions and show table/column stats.
1117  String[] statsQuals = new String[] { "partitions", "table stats", "column stats" };
1118  for (String qual: statsQuals) {
1119  AuthzOk(String.format("show %s functional.alltypesagg", qual));
1120  AuthzOk(String.format("show %s functional.alltypes", qual));
1121  // User does not have access to db/table.
1122  AuthzError(String.format("show %s nodb.tbl", qual),
1123  "User '%s' does not have privileges to access: nodb.tbl");
1124  AuthzError(String.format("show %s functional.badtbl", qual),
1125  "User '%s' does not have privileges to access: functional.badtbl");
1126  AuthzError(String.format("show %s functional_rc.alltypes", qual),
1127  "User '%s' does not have privileges to access: functional_rc.alltypes");
1128  }
1129 
1130  // Show files
1131  String[] partitions = new String[] { "", "partition(month=10, year=2010)" };
1132  for (String partition: partitions) {
1133  AuthzOk(String.format("show files in functional.alltypes %s", partition));
1134  // User does not have access to db/table.
1135  AuthzError(String.format("show files in nodb.tbl %s", partition),
1136  "User '%s' does not have privileges to access: nodb.tbl");
1137  AuthzError(String.format("show files in functional.badtbl %s", partition),
1138  "User '%s' does not have privileges to access: functional.badtbl");
1139  AuthzError(String.format("show files in functional_rc.alltypes %s", partition),
1140  "User '%s' does not have privileges to access: functional_rc.alltypes");
1141  }
1142  }
1143 
1144  @Test
1146  // These are the only dbs that should show up because they are the only
1147  // dbs the user has any permissions on.
1148  List<String> expectedDbs = Lists.newArrayList("default", "functional",
1149  "functional_parquet", "functional_seq_snap", "tpcds", "tpch");
1150 
1151  List<String> dbs = fe_.getDbNames("*", USER);
1152  Assert.assertEquals(expectedDbs, dbs);
1153 
1154  dbs = fe_.getDbNames(null, USER);
1155  Assert.assertEquals(expectedDbs, dbs);
1156  }
1157 
1158  @Test
1160  // The user only has permission on these tables/views in the functional databases.
1161  List<String> expectedTbls =
1162  Lists.newArrayList("alltypes", "alltypesagg", "complex_view", "view_view");
1163 
1164  List<String> tables = fe_.getTableNames("functional", "*", USER);
1165  Assert.assertEquals(expectedTbls, tables);
1166 
1167  tables = fe_.getTableNames("functional", null, USER);
1168  Assert.assertEquals(expectedTbls, tables);
1169  }
1170 
1171  @Test
1172  public void TestShowCreateTable() throws ImpalaException {
1173  AuthzOk("show create table functional.alltypesagg");
1174  AuthzOk("show create table functional.alltypes");
1175 
1176  // Unqualified table name.
1177  AuthzError("show create table alltypes",
1178  "User '%s' does not have privileges to access: default.alltypes");
1179  // Database doesn't exist.
1180  AuthzError("show create table nodb.alltypes",
1181  "User '%s' does not have privileges to access: nodb.alltypes");
1182  // Insufficient privileges on table.
1183  AuthzError("show create table functional.alltypestiny",
1184  "User '%s' does not have privileges to access: functional.alltypestiny");
1185  // Insufficient privileges on db.
1186  AuthzError("show create table functional_rc.alltypes",
1187  "User '%s' does not have privileges to access: functional_rc.alltypes");
1188  }
1189 
1190  @Test
1191  public void TestHs2GetTables() throws ImpalaException {
1192  TMetadataOpRequest req = new TMetadataOpRequest();
1193  req.setSession(createSessionState("default", USER));
1194  req.opcode = TMetadataOpcode.GET_TABLES;
1195  req.get_tables_req = new TGetTablesReq();
1196  req.get_tables_req.setSchemaName("functional");
1197  // Get all tables
1198  req.get_tables_req.setTableName("%");
1199  TResultSet resp = fe_.execHiveServer2MetadataOp(req);
1200  assertEquals(4, resp.rows.size());
1201  assertEquals("alltypes",
1202  resp.rows.get(0).colVals.get(2).string_val.toLowerCase());
1203  assertEquals(
1204  "alltypesagg", resp.rows.get(1).colVals.get(2).string_val.toLowerCase());
1205  assertEquals(
1206  "complex_view", resp.rows.get(2).colVals.get(2).string_val.toLowerCase());
1207  assertEquals(
1208  "view_view", resp.rows.get(3).colVals.get(2).string_val.toLowerCase());
1209  }
1210 
1211  @Test
1212  public void TestHs2GetSchema() throws ImpalaException {
1213  TMetadataOpRequest req = new TMetadataOpRequest();
1214  req.setSession(createSessionState("default", USER));
1215  req.opcode = TMetadataOpcode.GET_SCHEMAS;
1216  req.get_schemas_req = new TGetSchemasReq();
1217  // Get all schema (databases).
1218  req.get_schemas_req.setSchemaName("%");
1219  TResultSet resp = fe_.execHiveServer2MetadataOp(req);
1220  List<String> expectedDbs = Lists.newArrayList("default", "functional",
1221  "functional_parquet", "functional_seq_snap", "tpcds", "tpch");
1222  assertEquals(expectedDbs.size(), resp.rows.size());
1223  for (int i = 0; i < resp.rows.size(); ++i) {
1224  assertEquals(expectedDbs.get(i),
1225  resp.rows.get(i).colVals.get(0).string_val.toLowerCase());
1226  }
1227  }
1228 
1229  @Test
1230  public void TestHs2GetColumns() throws ImpalaException {
1231  // It should return one column: alltypes.string_col.
1232  TMetadataOpRequest req = new TMetadataOpRequest();
1233  req.opcode = TMetadataOpcode.GET_COLUMNS;
1234  req.setSession(createSessionState("default", USER));
1235  req.get_columns_req = new TGetColumnsReq();
1236  req.get_columns_req.setSchemaName("functional");
1237  req.get_columns_req.setTableName("alltypes");
1238  req.get_columns_req.setColumnName("stri%");
1239  TResultSet resp = fe_.execHiveServer2MetadataOp(req);
1240  assertEquals(1, resp.rows.size());
1241 
1242  // User does not have permission to access the table, no results should be returned.
1243  req.get_columns_req.setTableName("alltypesnopart");
1244  resp = fe_.execHiveServer2MetadataOp(req);
1245  assertEquals(0, resp.rows.size());
1246 
1247  // User does not have permission to access db or table, no results should be
1248  // returned.
1249  req.get_columns_req.setSchemaName("functional_seq_gzip");
1250  req.get_columns_req.setTableName("alltypes");
1251  resp = fe_.execHiveServer2MetadataOp(req);
1252  assertEquals(0, resp.rows.size());
1253  }
1254 
1255  @Test
1258  // Different long variations of the same username.
1259  List<User> users = Lists.newArrayList(
1260  new User(USER.getName() + "/abc.host.com"),
1261  new User(USER.getName() + "/abc.host.com@REAL.COM"),
1262  new User(USER.getName() + "@REAL.COM"));
1263  for (User user: users) {
1264  AnalysisContext context = new AnalysisContext(catalog_,
1266  authzConfig_);
1267 
1268  // Can select from table that user has privileges on.
1269  AuthzOk(context, "select * from functional.alltypesagg");
1270 
1271  // Unqualified table name.
1272  AuthzError(context, "select * from alltypes",
1273  "User '%s' does not have privileges to execute 'SELECT' on: default.alltypes",
1274  user);
1275  }
1276  // If the first character is '/' or '@', the short username should be the same as
1277  // the full username.
1278  assertEquals("/" + USER.getName(), new User("/" + USER.getName()).getShortName());
1279  assertEquals("@" + USER.getName(), new User("@" + USER.getName()).getShortName());
1280  }
1281 
1282  @Test
1283  public void TestFunction() throws ImpalaException {
1284  // First try with the less privileged user.
1285  User currentUser = USER;
1286  AnalysisContext context = new AnalysisContext(catalog_,
1288  authzConfig_);
1289  AuthzError(context, "show functions",
1290  "User '%s' does not have privileges to access: default", currentUser);
1291  AuthzOk(context, "show functions in tpch");
1292 
1293  AuthzError(context, "create function f() returns int location " +
1294  "'/test-warehouse/libTestUdfs.so' symbol='NoArgs'",
1295  "User '%s' does not have privileges to CREATE/DROP functions.", currentUser);
1296 
1297  AuthzError(context, "create function tpch.f() returns int location " +
1298  "'/test-warehouse/libTestUdfs.so' symbol='NoArgs'",
1299  "User '%s' does not have privileges to CREATE/DROP functions.", currentUser);
1300 
1301  AuthzError(context, "create function notdb.f() returns int location " +
1302  "'/test-warehouse/libTestUdfs.so' symbol='NoArgs'",
1303  "User '%s' does not have privileges to CREATE/DROP functions.", currentUser);
1304 
1305  AuthzError(context, "drop function if exists f()",
1306  "User '%s' does not have privileges to CREATE/DROP functions.", currentUser);
1307 
1308  AuthzError(context, "drop function notdb.f()",
1309  "User '%s' does not have privileges to CREATE/DROP functions.", currentUser);
1310 
1311  // TODO: Add test support for dynamically changing privileges for
1312  // file-based policy.
1313  if (authzConfig_.isFileBasedPolicy()) return;
1314 
1315  // Admin should be able to do everything
1316  SentryPolicyService sentryService =
1317  new SentryPolicyService(authzConfig_.getSentryConfig());
1318  try {
1319  sentryService.grantRoleToGroup(USER, "admin", USER.getName());
1320  ((ImpaladTestCatalog) catalog_).reset();
1321 
1322  AuthzOk("show functions");
1323  AuthzOk("show functions in tpch");
1324 
1325  AuthzOk("create function f() returns int location " +
1326  "'/test-warehouse/libTestUdfs.so' symbol='NoArgs'");
1327  AuthzOk("create function tpch.f() returns int location " +
1328  "'/test-warehouse/libTestUdfs.so' symbol='NoArgs'");
1329  AuthzOk("drop function if exists f()");
1330 
1331  // Can't add function to system db
1332  AuthzError("create function _impala_builtins.f() returns int location " +
1333  "'/test-warehouse/libTestUdfs.so' symbol='NoArgs'",
1334  "Cannot modify system database.");
1335  AuthzError("drop function if exists pi()",
1336  "Cannot modify system database.");
1337 
1338  // Add default.f(), tpch.f()
1339  catalog_.addFunction(new ScalarFunction(new FunctionName("default", "f"),
1340  new ArrayList<Type>(), Type.INT, null, null, null, null));
1341  catalog_.addFunction(new ScalarFunction(new FunctionName("tpch", "f"),
1342  new ArrayList<Type>(), Type.INT, null, null, null, null));
1343 
1344  AuthzOk("drop function tpch.f()");
1345  } finally {
1346  sentryService.revokeRoleFromGroup(USER, "admin", USER.getName());
1347  ((ImpaladTestCatalog) catalog_).reset();
1348 
1349  AuthzError(context, "create function tpch.f() returns int location " +
1350  "'/test-warehouse/libTestUdfs.so' symbol='NoArgs'",
1351  "User '%s' does not have privileges to CREATE/DROP functions.", currentUser);
1352 
1353  // Couldn't create tpch.f() but can run it.
1354  AuthzOk("select tpch.f()");
1355 
1356  //Other tests don't expect tpch to contain functions
1357  //Specifically, if these functions are not cleaned up, TestDropDatabase() will fail
1358  catalog_.removeFunction(new ScalarFunction(new FunctionName("default", "f"),
1359  new ArrayList<Type>(), Type.INT, null, null, null, null));
1360  catalog_.removeFunction(new ScalarFunction(new FunctionName("tpch", "f"),
1361  new ArrayList<Type>(), Type.INT, null, null, null, null));
1362  }
1363  }
1364 
1365  @Test
1367  if (authzConfig_.isFileBasedPolicy()) {
1368  // Authorization config that has a different server name from policy file.
1369  TestWithIncorrectConfig(AuthorizationConfig.createHadoopGroupAuthConfig(
1370  "differentServerName", AUTHZ_POLICY_FILE, ""),
1371  new User(System.getProperty("user.name")));
1372  } // TODO: Test using policy server.
1373  }
1374 
1375  @Test
1377  // Test doesn't make sense except for file based policies.
1378  if (!authzConfig_.isFileBasedPolicy()) return;
1379 
1380  // Validate a non-existent policy file.
1381  // Use a HadoopGroupProvider in this case so the user -> group mappings can still be
1382  // resolved in the absence of the policy file.
1383  TestWithIncorrectConfig(AuthorizationConfig.createHadoopGroupAuthConfig("server1",
1384  AUTHZ_POLICY_FILE + "_does_not_exist", ""),
1385  new User(System.getProperty("user.name")));
1386  }
1387 
1388  @Test
1390  String sentryConfig = authzConfig_.getSentryConfig().getConfigFile();
1391  // Valid configs pass validation.
1392  AuthorizationConfig config = AuthorizationConfig.createHadoopGroupAuthConfig(
1393  "server1", AUTHZ_POLICY_FILE, sentryConfig);
1394  config.validateConfig();
1395  Assert.assertTrue(config.isEnabled());
1396  Assert.assertTrue(config.isFileBasedPolicy());
1397 
1398  config = AuthorizationConfig.createHadoopGroupAuthConfig("server1", null,
1399  sentryConfig);
1400  config.validateConfig();
1401  Assert.assertTrue(config.isEnabled());
1402  Assert.assertTrue(!config.isFileBasedPolicy());
1403 
1404  // Invalid configs
1405  // No sentry configuration file.
1406  config = AuthorizationConfig.createHadoopGroupAuthConfig(
1407  "server1", AUTHZ_POLICY_FILE, null);
1408  Assert.assertTrue(config.isEnabled());
1409  try {
1410  config.validateConfig();
1411  } catch (Exception e) {
1412  Assert.assertEquals(e.getMessage(), "A valid path to a sentry-site.xml config " +
1413  "file must be set using --sentry_config to enable authorization.");
1414  }
1415 
1416  // Empty / null server name.
1417  config = AuthorizationConfig.createHadoopGroupAuthConfig(
1418  "", AUTHZ_POLICY_FILE, sentryConfig);
1419  Assert.assertTrue(config.isEnabled());
1420  try {
1421  config.validateConfig();
1422  fail("Expected configuration to fail.");
1423  } catch (IllegalArgumentException e) {
1424  Assert.assertEquals(e.getMessage(),
1425  "Authorization is enabled but the server name is null or empty. Set the " +
1426  "server name using the impalad --server_name flag.");
1427  }
1428  config = AuthorizationConfig.createHadoopGroupAuthConfig(null, AUTHZ_POLICY_FILE,
1429  sentryConfig);
1430  Assert.assertTrue(config.isEnabled());
1431  try {
1432  config.validateConfig();
1433  fail("Expected configuration to fail.");
1434  } catch (IllegalArgumentException e) {
1435  Assert.assertEquals(e.getMessage(),
1436  "Authorization is enabled but the server name is null or empty. Set the " +
1437  "server name using the impalad --server_name flag.");
1438  }
1439 
1440  // Sentry config file does not exist.
1441  config = AuthorizationConfig.createHadoopGroupAuthConfig("server1", "",
1442  "/path/does/not/exist.xml");
1443  Assert.assertTrue(config.isEnabled());
1444  try {
1445  config.validateConfig();
1446  fail("Expected configuration to fail.");
1447  } catch (Exception e) {
1448  Assert.assertEquals(e.getMessage(),
1449  "Sentry configuration file does not exist: /path/does/not/exist.xml");
1450  }
1451 
1452  // Invalid ResourcePolicyProvider class name.
1453  config = new AuthorizationConfig("server1", AUTHZ_POLICY_FILE, "",
1454  "ClassDoesNotExist");
1455  Assert.assertTrue(config.isEnabled());
1456  try {
1457  config.validateConfig();
1458  fail("Expected configuration to fail.");
1459  } catch (IllegalArgumentException e) {
1460  Assert.assertEquals(e.getMessage(),
1461  "The authorization policy provider class 'ClassDoesNotExist' was not found.");
1462  }
1463 
1464  // Valid class name, but class is not derived from ResourcePolicyProvider
1465  config = new AuthorizationConfig("server1", AUTHZ_POLICY_FILE, "",
1466  this.getClass().getName());
1467  Assert.assertTrue(config.isEnabled());
1468  try {
1469  config.validateConfig();
1470  fail("Expected configuration to fail.");
1471  } catch (IllegalArgumentException e) {
1472  Assert.assertEquals(e.getMessage(), String.format("The authorization policy " +
1473  "provider class '%s' must be a subclass of '%s'.", this.getClass().getName(),
1474  ResourceAuthorizationProvider.class.getName()));
1475  }
1476 
1477  // Config validations skipped if authorization disabled
1478  config = new AuthorizationConfig("", "", "", "");
1479  Assert.assertFalse(config.isEnabled());
1480  config = new AuthorizationConfig(null, "", "", null);
1481  Assert.assertFalse(config.isEnabled());
1482  config = new AuthorizationConfig("", null, "", "");
1483  Assert.assertFalse(config.isEnabled());
1484  config = new AuthorizationConfig(null, null, null, null);
1485  Assert.assertFalse(config.isEnabled());
1486  }
1487 
1488  @Test
1491  if (!authzConfig_.isFileBasedPolicy()) return;
1492  // Use an authorization configuration that uses the
1493  // LocalGroupResourceAuthorizationProvider.
1494  AuthorizationConfig authzConfig = new AuthorizationConfig("server1",
1495  AUTHZ_POLICY_FILE, "",
1496  LocalGroupResourceAuthorizationProvider.class.getName());
1497  ImpaladCatalog catalog = new ImpaladTestCatalog(authzConfig);
1498 
1499  // Create an analysis context + FE with the test user (as defined in the policy file)
1500  User user = new User("test_user");
1501  AnalysisContext context = new AnalysisContext(catalog,
1502  TestUtils.createQueryContext(Catalog.DEFAULT_DB, user.getName()), authzConfig);
1503  Frontend fe = new Frontend(authzConfig, catalog);
1504 
1505  // Can select from table that user has privileges on.
1506  AuthzOk(fe, context, "select * from functional.alltypesagg");
1507  // Does not have privileges to execute a query
1508  AuthzError(fe, context, "select * from functional.alltypes",
1509  "User '%s' does not have privileges to execute 'SELECT' on: functional.alltypes",
1510  user);
1511 
1512  // Verify with the admin user
1513  user = new User("admin_user");
1514  context = new AnalysisContext(catalog,
1515  TestUtils.createQueryContext(Catalog.DEFAULT_DB, user.getName()), authzConfig);
1516  fe = new Frontend(authzConfig, catalog);
1517 
1518  // Admin user should have privileges to do anything
1519  AuthzOk(fe, context, "select * from functional.alltypesagg");
1520  AuthzOk(fe, context, "select * from functional.alltypes");
1521  AuthzOk(fe, context, "invalidate metadata");
1522  }
1523 
1524  private void TestWithIncorrectConfig(AuthorizationConfig authzConfig, User user)
1525  throws AnalysisException {
1526  Frontend fe = new Frontend(authzConfig, catalog_);
1528  TestUtils.createQueryContext(Catalog.DEFAULT_DB, user.getName()), authzConfig);
1529  AuthzError(fe, ac, "select * from functional.alltypesagg",
1530  "User '%s' does not have privileges to execute 'SELECT' on: " +
1531  "functional.alltypesagg", user);
1532  AuthzError(fe, ac, "ALTER TABLE functional_seq_snap.alltypes ADD COLUMNS (c1 int)",
1533  "User '%s' does not have privileges to execute 'ALTER' on: " +
1534  "functional_seq_snap.alltypes", user);
1535  AuthzError(fe, ac, "drop table tpch.lineitem",
1536  "User '%s' does not have privileges to execute 'DROP' on: tpch.lineitem",
1537  user);
1538  AuthzError(fe, ac, "show tables in functional",
1539  "User '%s' does not have privileges to access: functional.*", user);
1540  }
1541 
1542  private void AuthzOk(String stmt) throws AuthorizationException,
1544  AuthzOk(analysisContext_, stmt);
1545  }
1546 
1547  private void AuthzOk(AnalysisContext context, String stmt)
1548  throws AuthorizationException, AnalysisException {
1549  AuthzOk(fe_, context, stmt);
1550  }
1551 
1552  private static void AuthzOk(Frontend fe, AnalysisContext context, String stmt)
1553  throws AuthorizationException, AnalysisException {
1554  context.analyze(stmt);
1555  context.getAnalyzer().authorize(fe.getAuthzChecker());
1556  }
1557 
1562  private void AuthzError(String stmt, String expectedErrorString)
1563  throws AnalysisException {
1564  AuthzError(analysisContext_, stmt, expectedErrorString, USER);
1565  }
1566 
1567  private void AuthzError(AnalysisContext analysisContext,
1568  String stmt, String expectedErrorString, User user) throws AnalysisException {
1569  AuthzError(fe_, analysisContext, stmt, expectedErrorString, user);
1570  }
1571 
1572  private static void AuthzError(Frontend fe, AnalysisContext analysisContext,
1573  String stmt, String expectedErrorString, User user) throws AnalysisException {
1574  Preconditions.checkNotNull(expectedErrorString);
1575  try {
1576  try {
1577  analysisContext.analyze(stmt);
1578  } finally {
1579  analysisContext.getAnalyzer().authorize(fe.getAuthzChecker());
1580  }
1581  } catch (AuthorizationException e) {
1582  // Insert the username into the error.
1583  expectedErrorString = String.format(expectedErrorString, user.getName());
1584  String errorString = e.getMessage();
1585  Assert.assertTrue(
1586  "got error:\n" + errorString + "\nexpected:\n" + expectedErrorString,
1587  errorString.startsWith(expectedErrorString));
1588  return;
1589  }
1590  fail("Stmt didn't result in authorization error: " + stmt);
1591  }
1592 
1593  private static TSessionState createSessionState(String defaultDb, User user) {
1594  return new TSessionState(null, null,
1595  defaultDb, user.getName(), new TNetworkAddress("", 0));
1596  }
1597 
1599  return new SentryPolicyService(authzConfig_.getSentryConfig());
1600  }
1601 }
static AuthorizationConfig createHadoopGroupAuthConfig(String serverName, String policyFile, String sentryConfigFile)
static void AuthzError(Frontend fe, AnalysisContext analysisContext, String stmt, String expectedErrorString, User user)
static TSessionState createSessionState(String defaultDb, User user)
static void AuthzOk(Frontend fe, AnalysisContext context, String stmt)
static final ScalarType INT
Definition: Type.java:49
uint64_t Test(T *ht, const ProbeTuple *input, uint64_t num_tuples)
void AuthzError(AnalysisContext analysisContext, String stmt, String expectedErrorString, User user)
void AuthzOk(AnalysisContext context, String stmt)
static final String DEFAULT_DB
Definition: Catalog.java:58
void TestWithIncorrectConfig(AuthorizationConfig authzConfig, User user)
void AuthzError(String stmt, String expectedErrorString)