-
Notifications
You must be signed in to change notification settings - Fork 4.8k
Spark client can create/alter/drop a view #1391
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
Changes from all commits
4010958
bcc17a0
76490a4
eb79970
1b971f7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -24,6 +24,10 @@ | |
| import java.util.Set; | ||
| import java.util.Map.Entry; | ||
|
|
||
| import org.apache.hadoop.conf.Configuration; | ||
| import org.apache.hadoop.hive.conf.HiveConf; | ||
| import org.apache.hadoop.hive.metastore.HiveMetaStore; | ||
| import org.apache.hadoop.hive.metastore.TableType; | ||
| import org.apache.hadoop.hive.metastore.api.Database; | ||
| import org.apache.hadoop.hive.ql.exec.FunctionInfo; | ||
| import org.apache.hadoop.hive.ql.exec.FunctionUtils; | ||
|
|
@@ -104,8 +108,25 @@ private static List<HivePrivilegeObject> getHivePrivObjects(List<? extends Entit | |
| continue; | ||
| } | ||
| if (privObject instanceof ReadEntity && !((ReadEntity)privObject).isDirect()) { | ||
| // This ReadEntity represents one of the underlying tables/views of a view, so skip it. | ||
| continue; | ||
| // This ReadEntity represents one of the underlying tables/views of a view, skip it if | ||
| // it's not inside a deferred authorized view. | ||
| ReadEntity reTable = (ReadEntity)privObject; | ||
| Boolean isDeferred = false; | ||
| if( reTable.getParents() != null && reTable.getParents().size() > 0){ | ||
| for( ReadEntity re: reTable.getParents()){ | ||
| if (re.getTyp() == Type.TABLE && re.getTable() != null ) { | ||
| Table t = re.getTable(); | ||
| if(!isDeferredAuthView(t)){ | ||
| continue; | ||
| }else{ | ||
| isDeferred = true; | ||
| } | ||
| } | ||
| } | ||
| } | ||
| if(!isDeferred){ | ||
| continue; | ||
| } | ||
| } | ||
| if (privObject instanceof WriteEntity && ((WriteEntity)privObject).isTempURI()) { | ||
| // do not authorize temporary uris | ||
|
|
@@ -121,6 +142,32 @@ private static List<HivePrivilegeObject> getHivePrivObjects(List<? extends Entit | |
| return hivePrivobjs; | ||
| } | ||
|
|
||
| /** | ||
| * A deferred authorization view is view created by non-super user like spark-user. This view contains a parameter "Authorized" | ||
| * set to false, so ranger will not authorize it during view creation. When a select statement is issued, then the ranger authorizes | ||
| * the under lying tables. | ||
| * @param Table t | ||
| * @return boolean value | ||
| */ | ||
| private static boolean isDeferredAuthView(Table t){ | ||
| String tableType = t.getTTable().getTableType(); | ||
| String authorizedKeyword = "Authorized"; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What I meant was having a constant defined in HiveMetastoreAuthorizer.java like below. Once you do that you can use the key DEFERRED_AUTHORIZED_KEY everywhere whereever you are directly looking for "Authorized" key. The advantage of doing this way is that code is less error-prone and maintainable.
|
||
| boolean isView = false; | ||
| if (TableType.MATERIALIZED_VIEW.name().equals(tableType) || TableType.VIRTUAL_VIEW.name().equals(tableType)) { | ||
| isView = true; | ||
| } | ||
| if(isView){ | ||
| Map<String, String> params = t.getParameters(); | ||
| if (params != null && params.containsKey(authorizedKeyword)) { | ||
| String authorizedValue = params.get(authorizedKeyword); | ||
| if ("false".equalsIgnoreCase(authorizedValue)) { | ||
| return true; | ||
| } | ||
| } | ||
| } | ||
| return false; | ||
| } | ||
|
|
||
| private static void addHivePrivObject(Entity privObject, Map<String, List<String>> tableName2Cols, | ||
| List<HivePrivilegeObject> hivePrivObjs) { | ||
| HivePrivilegeObjectType privObjType = AuthorizationUtils.getHivePrivilegeObjectType(privObject.getType()); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -36,10 +36,12 @@ | |
| import org.junit.runners.MethodSorters; | ||
| import org.junit.Before; | ||
| import org.junit.Test; | ||
| import java.util.Map; | ||
|
|
||
| import java.io.File; | ||
|
|
||
| import static org.junit.Assert.assertEquals; | ||
| import static org.junit.Assert.assertTrue; | ||
|
|
||
| /* | ||
| Test whether HiveAuthorizer for MetaStore operation is trigger and HiveMetaStoreAuthzInfo is created by HiveMetaStoreAuthorizer | ||
|
|
@@ -138,10 +140,37 @@ public void testC_CreateView_anyUser() throws Exception { | |
| .setOwner(authorizedUser) | ||
| .build(conf); | ||
| hmsHandler.create_table(viewObj); | ||
| Map<String, String> params = viewObj.getParameters(); | ||
| assertTrue(params.containsKey("Authorized")); | ||
| assertTrue("false".equalsIgnoreCase(params.get("Authorized"))); | ||
| } catch (Exception e) { | ||
| String err = e.getMessage(); | ||
| String expected = "Operation type CREATE_VIEW not allowed for user:" + authorizedUser; | ||
| assertEquals(expected, err); | ||
| // no Exceptions for user same as normal user is now allowed CREATE_VIEW operation | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The catch all exception here is not good, since the test will pass in case there is a MetaException thrown on line 142. The test added will pass without code modifications in the HiveMetastoreAuthorizer as well and hence I feel is not really a good regression test. Also, looks like there are other tests in this class which do a catch all exception blocks which can give false positive (eg. testD_CreateView_SuperUser). Would be good to fix them up as well. |
||
| } | ||
| } | ||
|
|
||
| @Test | ||
| public void testC2_AlterView_anyUser() throws Exception{ | ||
| UserGroupInformation.setLoginUser(UserGroupInformation.createRemoteUser(authorizedUser)); | ||
| try { | ||
| Table viewObj = new TableBuilder() | ||
| .setTableName(viewName) | ||
| .setType(TableType.VIRTUAL_VIEW.name()) | ||
| .addCol("name", ColumnType.STRING_TYPE_NAME) | ||
| .setOwner(authorizedUser) | ||
| .build(conf); | ||
| hmsHandler.create_table(viewObj); | ||
| viewObj = new TableBuilder() | ||
| .setTableName(viewName) | ||
| .setType(TableType.VIRTUAL_VIEW.name()) | ||
| .addCol("dep", ColumnType.STRING_TYPE_NAME) | ||
| .setOwner(authorizedUser) | ||
| .build(conf); | ||
| hmsHandler.alter_table("default", viewName, viewObj); | ||
| Map<String, String> params = viewObj.getParameters(); | ||
| assertTrue(params.containsKey("Authorized")); | ||
| assertTrue("false".equalsIgnoreCase(params.get("Authorized"))); | ||
| } catch (Exception e) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. same comment as above related to exception handling. |
||
| // no Exceptions for user same as normal user is now allowed Alter_VIEW operation | ||
| } | ||
| } | ||
|
|
||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.