Skip to content

Commit 63c0ce0

Browse files
fangyuraoImpala Public Jenkins
authored andcommitted
IMPALA-11382: Produce log for unauthorized SELECT on non-existing table
This patch revised the logic of Ranger audit log generation such that unauthorized SELECT operation on non-existing tables would be produced as well. Note that after this change, in the case of an unauthorized SELECT operation on an existing table, Impala will produce a table event instead of the first failing column event because we do not filter out the table event for an unauthorized SELECT operation like what we did before. In addition, this patch fixed a subtle bug where an authorized table event could be produced even though the authorization failed due to a deny policy on a column in the same table. The code comment in RangerAuthorizationChecker#authorizeTableAccess() was also updated to reflect Impala's current behavior with respect to Ranger audit log generation. Testing: - Added a test case to verify the log corresponding to an unauthorized SELECT operation on a non-existing table is produced. - Manually verified that an authorized table event won't be produced when the requesting user is granted the SELECT privilege on a table but is denied access to a column in the same table. Change-Id: I92b2a6acc920de1d2d14b991c374a4550e742f7b Reviewed-on: http://gerrit.cloudera.org:8080/18656 Reviewed-by: Impala Public Jenkins <impala-public-jenkins@cloudera.com> Tested-by: Impala Public Jenkins <impala-public-jenkins@cloudera.com>
1 parent 00db9a2 commit 63c0ce0

2 files changed

Lines changed: 43 additions & 21 deletions

File tree

fe/src/main/java/org/apache/impala/authorization/ranger/RangerAuthorizationChecker.java

Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -255,34 +255,49 @@ protected void authorizeTableAccess(AuthorizationContext authzCtx,
255255
throws AuthorizationException, InternalException {
256256
RangerAuthorizationContext originalCtx = (RangerAuthorizationContext) authzCtx;
257257
RangerBufferAuditHandler originalAuditHandler = originalCtx.getAuditHandler();
258-
// case 1: table (select) OK --> add the table event
258+
// case 1: table (select) OK, columns (select) OK --> add the table event,
259+
// add the column events
259260
// case 2: table (non-select) ERROR --> add the table event
260261
// case 3: table (select) ERROR, columns (select) OK -> only add the column events
261-
// case 4: table (select) ERROR, columns (select) ERROR --> only add the first column
262-
// event
262+
// case 4: table (select) ERROR, columns (select) ERROR --> add the table event
263+
// case 5: table (select) ERROR --> add the table event
264+
// This could happen when the select request for a non-existing table fails
265+
// the authorization.
266+
// case 6: table (select) OK, columns (select) ERROR --> add the first column event
267+
// This could happen when the requesting user is granted the select privilege
268+
// on the table but is denied access to a column in the same table in Ranger.
263269
RangerAuthorizationContext tmpCtx = new RangerAuthorizationContext(
264270
originalCtx.getSessionState(), originalCtx.getTimeline());
265271
tmpCtx.setAuditHandler(new RangerBufferAuditHandler(originalAuditHandler));
272+
AuthorizationException authorizationException = null;
266273
try {
267274
super.authorizeTableAccess(tmpCtx, analysisResult, catalog, requests);
268275
} catch (AuthorizationException e) {
276+
authorizationException = e;
269277
tmpCtx.getAuditHandler().getAuthzEvents().stream()
270278
.filter(evt ->
271279
// case 2: get the first failing non-select table
272280
(!"select".equalsIgnoreCase(evt.getAccessType()) &&
273281
"@table".equals(evt.getResourceType())) ||
274-
// case 4: get the first failing column
275-
("@column".equals(evt.getResourceType()) && evt.getAccessResult() == 0))
282+
// case 4 & 5 & 6: get the table or a column event
283+
(("@table".equals(evt.getResourceType()) ||
284+
"@column".equals(evt.getResourceType())) &&
285+
evt.getAccessResult() == 0))
276286
.findFirst()
277287
.ifPresent(evt -> originalCtx.getAuditHandler().getAuthzEvents().add(evt));
278288
throw e;
279289
} finally {
280-
// case 1 & 4: we only add the successful events. The first table-level access
281-
// check is only for the short-circuit, we don't want to add an event for that.
282-
List<AuthzAuditEvent> events = tmpCtx.getAuditHandler().getAuthzEvents().stream()
283-
.filter(evt -> evt.getAccessResult() != 0)
284-
.collect(Collectors.toList());
285-
originalCtx.getAuditHandler().getAuthzEvents().addAll(events);
290+
// We should not add successful events when there was an AuthorizationException.
291+
// Specifically, we should not add the successful table event in case 6.
292+
if (authorizationException == null) {
293+
// case 1 & 3: we only add the successful events.
294+
// TODO(IMPALA-11381): Consider whether we should keep the table-level event which
295+
// corresponds to a check only for short-circuiting authorization.
296+
List<AuthzAuditEvent> events = tmpCtx.getAuditHandler().getAuthzEvents().stream()
297+
.filter(evt -> evt.getAccessResult() != 0)
298+
.collect(Collectors.toList());
299+
originalCtx.getAuditHandler().getAuthzEvents().addAll(events);
300+
}
286301
}
287302
}
288303

fe/src/test/java/org/apache/impala/authorization/ranger/RangerAuditLogTest.java

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -317,14 +317,22 @@ public void testAuditLogFailure() throws ImpalaException {
317317
onDatabase("functional", TPrivilegeLevel.CREATE));
318318

319319
authzError(events -> {
320-
// Only log the first column event. We do not log the table access used for
321-
// short-circuiting.
320+
// Only log the table event.
322321
assertEquals(1, events.size());
323-
assertEventEquals("@column", "select", "functional/alltypes/id", 0, events.get(0));
322+
assertEventEquals("@table", "select", "functional/alltypes", 0, events.get(0));
324323
assertEquals("select id, string_col from functional.alltypes",
325324
events.get(0).getRequestData());
326325
}, "select id, string_col from functional.alltypes");
327326

327+
authzError(events -> {
328+
// Log the table event even when the table does not exist.
329+
assertEquals(1, events.size());
330+
assertEventEquals("@table", "select", "functional/non_existing_tbl", 0,
331+
events.get(0));
332+
assertEquals("select * from functional.non_existing_tbl",
333+
events.get(0).getRequestData());
334+
}, "select * from functional.non_existing_tbl");
335+
328336
authzError(events -> {
329337
// Show the actual view_metadata audit log.
330338
assertEquals(1, events.size());
@@ -496,15 +504,14 @@ public void testAuditsForColumnMasking() throws ImpalaException {
496504
// When the requesting user is not granted the necessary privileges, the audit log
497505
// entries corresponding to column masking are not generated. Notice that in the
498506
// case when the requesting user is not granted the necessary privileges, only the
499-
// event of the first column that failed the authorization will be logged, i.e.,
500-
// 'id'. Refer to RangerAuthorizationChecker#authorizeTableAccess() for further
501-
// details.
507+
// event of the table that failed the authorization will be logged. Refer to
508+
// RangerAuthorizationChecker#authorizeTableAccess() for further details.
502509
authzError(events -> {
503510
assertEquals(1, events.size());
504511
assertEquals("with iv as (select id, bool_col, string_col from " +
505512
"functional.alltypestiny) select * from iv",
506513
events.get(0).getRequestData());
507-
assertEventEquals("@column", "select", "functional/alltypestiny/id", 0,
514+
assertEventEquals("@table", "select", "functional/alltypestiny", 0,
508515
events.get(0));
509516
},"with iv as (select id, bool_col, string_col from functional.alltypestiny) " +
510517
"select * from iv", onTable("functional", "alltypestiny"));
@@ -714,13 +721,13 @@ public void testAuditsForRowFiltering() throws ImpalaException {
714721
TPrivilegeLevel.SELECT));
715722

716723
// When fails with not enough privileges, no audit logs for row filtering is
717-
// generated. Only the event of the first column (i.e. id) that failed the
718-
// authorization will be logged.
724+
// generated. Only the event of the table that failed the authorization will be
725+
// logged.
719726
authzError(events -> {
720727
assertEquals(1, events.size());
721728
assertEquals("select * from functional.alltypestiny",
722729
events.get(0).getRequestData());
723-
assertEventEquals("@column", "select", "functional/alltypestiny/id", 0,
730+
assertEventEquals("@table", "select", "functional/alltypestiny", 0,
724731
events.get(0));
725732
},"select * from functional.alltypestiny", onTable("functional", "alltypestiny"));
726733

0 commit comments

Comments
 (0)