diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-timelineservice/src/main/java/org/apache/hadoop/yarn/server/timelineservice/reader/TimelineReaderWebServices.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-timelineservice/src/main/java/org/apache/hadoop/yarn/server/timelineservice/reader/TimelineReaderWebServices.java index 7bf66b0bd76..8c0d8082dcf 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-timelineservice/src/main/java/org/apache/hadoop/yarn/server/timelineservice/reader/TimelineReaderWebServices.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-timelineservice/src/main/java/org/apache/hadoop/yarn/server/timelineservice/reader/TimelineReaderWebServices.java @@ -55,6 +55,7 @@ import org.apache.hadoop.yarn.server.timelineservice.storage.TimelineReader.Field; import org.apache.hadoop.yarn.util.timeline.TimelineUtils; import org.apache.hadoop.yarn.webapp.BadRequestException; +import org.apache.hadoop.yarn.webapp.ForbiddenException; import org.apache.hadoop.yarn.webapp.NotFoundException; import com.google.common.annotations.VisibleForTesting; @@ -188,6 +189,8 @@ private static void handleException(Exception e, String url, long startTime, "Filter Parsing failed." : e.getMessage()); } else if (e instanceof BadRequestException) { throw (BadRequestException)e; + } else if (e instanceof ForbiddenException) { + throw (ForbiddenException) e; } else { LOG.error("Error while processing REST request", e); throw new WebApplicationException(e, @@ -329,6 +332,9 @@ public TimelineAbout about( if (context == null) { throw new BadRequestException("Incorrect UID " + uId); } + // TODO to be removed or modified once ACL story is played + checkAccess(timelineReaderManager, callerUGI, context.getUserId()); + context.setEntityType( TimelineReaderWebServicesUtils.parseStr(entityType)); entities = timelineReaderManager.getEntities(context, @@ -602,18 +608,43 @@ public TimelineAbout about( init(res); TimelineReaderManager timelineReaderManager = getTimelineReaderManager(); Set entities = null; + boolean checkAccess = false; try { TimelineReaderContext context = TimelineReaderWebServicesUtils .createTimelineReaderContext(clusterId, userId, flowName, flowRunId, appId, entityType, null, null); + if (context.getUserId() != null) { + // TODO to be removed or modified once ACL story is played + checkAccess(timelineReaderManager, callerUGI, context.getUserId()); + checkAccess = true; + } + entities = timelineReaderManager.getEntities(context, - TimelineReaderWebServicesUtils.createTimelineEntityFilters( - limit, createdTimeStart, createdTimeEnd, relatesTo, isRelatedTo, - infofilters, conffilters, metricfilters, eventfilters, - fromId), - TimelineReaderWebServicesUtils.createTimelineDataToRetrieve( - confsToRetrieve, metricsToRetrieve, fields, metricsLimit, - metricsTimeStart, metricsTimeEnd)); + TimelineReaderWebServicesUtils + .createTimelineEntityFilters(limit, createdTimeStart, + createdTimeEnd, relatesTo, isRelatedTo, infofilters, + conffilters, metricfilters, eventfilters, fromId), + TimelineReaderWebServicesUtils + .createTimelineDataToRetrieve(confsToRetrieve, metricsToRetrieve, + fields, metricsLimit, metricsTimeStart, metricsTimeEnd)); + + if (entities != null && entities.size() > 0 && !checkAccess) { + TimelineReaderContext timelineReaderContext = null; + TimelineEntity entity = entities.iterator().next(); + if (TimelineEntityType.YARN_APPLICATION.matches(entityType)) { + String uid = + (String) entity.getInfo().get(TimelineReaderUtils.UID_KEY); + timelineReaderContext = + TimelineUIDConverter.APPLICATION_UID.decodeUID(uid); + } else { + String uid = + (String) entity.getInfo().get(TimelineReaderUtils.UID_KEY); + timelineReaderContext = + TimelineUIDConverter.GENERIC_ENTITY_UID.decodeUID(uid); + } + checkAccess(timelineReaderManager, callerUGI, + timelineReaderContext.getUserId()); + } } catch (Exception e) { handleException(e, url, startTime, "createdTime start/end or limit or flowrunid"); @@ -700,6 +731,9 @@ public TimelineEntity getEntity( if (context == null) { throw new BadRequestException("Incorrect UID " + uId); } + // TODO to be removed or modified once ACL story is played + checkAccess(timelineReaderManager, callerUGI, context.getUserId()); + entity = timelineReaderManager.getEntity(context, TimelineReaderWebServicesUtils.createTimelineDataToRetrieve( confsToRetrieve, metricsToRetrieve, fields, metricsLimit, @@ -893,6 +927,14 @@ public TimelineEntity getEntity( TimelineReaderWebServicesUtils.createTimelineDataToRetrieve( confsToRetrieve, metricsToRetrieve, fields, metricsLimit, metricsTimeStart, metricsTimeEnd)); + + if (entity != null) { + String uid = (String) entity.getInfo().get(TimelineReaderUtils.UID_KEY); + TimelineReaderContext timelineReaderContext = + TimelineUIDConverter.GENERIC_ENTITY_UID.decodeUID(uid); + checkAccess(timelineReaderManager, callerUGI, + timelineReaderContext.getUserId()); + } } catch (Exception e) { handleException(e, url, startTime, "flowrunid"); } @@ -956,6 +998,9 @@ public TimelineEntity getFlowRun( if (context == null) { throw new BadRequestException("Incorrect UID " + uId); } + // TODO to be removed or modified once ACL story is played + checkAccess(timelineReaderManager, callerUGI, context.getUserId()); + context.setEntityType(TimelineEntityType.YARN_FLOW_RUN.toString()); entity = timelineReaderManager.getEntity(context, TimelineReaderWebServicesUtils.createTimelineDataToRetrieve( @@ -1069,6 +1114,13 @@ public TimelineEntity getFlowRun( TimelineEntityType.YARN_FLOW_RUN.toString(), null, null), TimelineReaderWebServicesUtils.createTimelineDataToRetrieve( null, metricsToRetrieve, null, null, null, null)); + if (entity != null) { + String uid = (String) entity.getInfo().get(TimelineReaderUtils.UID_KEY); + TimelineReaderContext timelineReaderContext = + TimelineUIDConverter.FLOWRUN_UID.decodeUID(uid); + checkAccess(timelineReaderManager, callerUGI, + timelineReaderContext.getUserId()); + } } catch (Exception e) { handleException(e, url, startTime, "flowrunid"); } @@ -1156,6 +1208,9 @@ public TimelineEntity getFlowRun( if (context == null) { throw new BadRequestException("Incorrect UID " + uId); } + // TODO to be removed or modified once ACL story is played + checkAccess(timelineReaderManager, callerUGI, context.getUserId()); + context.setEntityType(TimelineEntityType.YARN_FLOW_RUN.toString()); entities = timelineReaderManager.getEntities(context, TimelineReaderWebServicesUtils.createTimelineEntityFilters( @@ -1304,15 +1359,22 @@ public TimelineEntity getFlowRun( TimelineReaderManager timelineReaderManager = getTimelineReaderManager(); Set entities = null; try { - entities = timelineReaderManager.getEntities( - TimelineReaderWebServicesUtils.createTimelineReaderContext( - clusterId, userId, flowName, null, null, - TimelineEntityType.YARN_FLOW_RUN.toString(), null, null), - TimelineReaderWebServicesUtils.createTimelineEntityFilters( - limit, createdTimeStart, createdTimeEnd, null, null, null, - null, null, null, fromId), - TimelineReaderWebServicesUtils.createTimelineDataToRetrieve( - null, metricsToRetrieve, fields, null, null, null)); + + TimelineReaderContext timelineReaderContext = TimelineReaderWebServicesUtils + .createTimelineReaderContext(clusterId, userId, flowName, null, + null, TimelineEntityType.YARN_FLOW_RUN.toString(), null, + null); + // TODO to be removed or modified once ACL story is played + checkAccess(timelineReaderManager, callerUGI, + timelineReaderContext.getUserId()); + + entities = timelineReaderManager.getEntities(timelineReaderContext, + TimelineReaderWebServicesUtils + .createTimelineEntityFilters(limit, createdTimeStart, + createdTimeEnd, null, null, null, null, null, null, fromId), + TimelineReaderWebServicesUtils + .createTimelineDataToRetrieve(null, metricsToRetrieve, fields, + null, null, null)); } catch (Exception e) { handleException(e, url, startTime, "createdTime start/end or limit or fromId"); @@ -1435,7 +1497,6 @@ public TimelineEntity getFlowRun( long startTime = Time.monotonicNow(); init(res); TimelineReaderManager timelineReaderManager = getTimelineReaderManager(); - Configuration config = timelineReaderManager.getConfig(); Set entities = null; try { DateRange range = parseDateRange(dateRange); @@ -1455,19 +1516,9 @@ public TimelineEntity getFlowRun( long endTime = Time.monotonicNow(); if (entities == null) { entities = Collections.emptySet(); - } else if (isDisplayEntityPerUserFilterEnabled(config)) { - Set userEntities = new LinkedHashSet<>(); - userEntities.addAll(entities); - for (TimelineEntity entity : userEntities) { - if (entity.getInfo() != null) { - String userId = - (String) entity.getInfo().get(FlowActivityEntity.USER_INFO_KEY); - if (!validateAuthUserWithEntityUser(timelineReaderManager, callerUGI, - userId)) { - entities.remove(entity); - } - } - } + } else { + checkAccess(timelineReaderManager, callerUGI, entities, + FlowActivityEntity.USER_INFO_KEY, true); } LOG.info("Processed URL " + url + " (Took " + (endTime - startTime) + " ms.)"); @@ -1547,6 +1598,9 @@ public TimelineEntity getApp( if (context == null) { throw new BadRequestException("Incorrect UID " + uId); } + // TODO to be removed or modified once ACL story is played + checkAccess(timelineReaderManager, callerUGI, context.getUserId()); + context.setEntityType(TimelineEntityType.YARN_APPLICATION.toString()); entity = timelineReaderManager.getEntity(context, TimelineReaderWebServicesUtils.createTimelineDataToRetrieve( @@ -1722,6 +1776,13 @@ public TimelineEntity getApp( TimelineReaderWebServicesUtils.createTimelineDataToRetrieve( confsToRetrieve, metricsToRetrieve, fields, metricsLimit, metricsTimeStart, metricsTimeEnd)); + if (entity != null) { + String uid = (String) entity.getInfo().get(TimelineReaderUtils.UID_KEY); + TimelineReaderContext timelineReaderContext = + TimelineUIDConverter.APPLICATION_UID.decodeUID(uid); + checkAccess(timelineReaderManager, callerUGI, + timelineReaderContext.getUserId()); + } } catch (Exception e) { handleException(e, url, startTime, "flowrunid"); } @@ -1852,6 +1913,9 @@ public TimelineEntity getApp( if (context == null) { throw new BadRequestException("Incorrect UID " + uId); } + // TODO to be removed or modified once ACL story is played + checkAccess(timelineReaderManager, callerUGI, context.getUserId()); + context.setEntityType(TimelineEntityType.YARN_APPLICATION.toString()); entities = timelineReaderManager.getEntities(context, TimelineReaderWebServicesUtils.createTimelineEntityFilters( @@ -3335,6 +3399,9 @@ public TimelineEntity getContainer(@Context HttpServletRequest req, TimelineReaderContext context = TimelineReaderWebServicesUtils.createTimelineReaderContext(clusterId, null, null, null, null, entityType, null, null, userId); + // TODO to be removed or modified once ACL story is played + checkAccess(timelineReaderManager, callerUGI, context.getDoAsUser()); + entities = timelineReaderManager.getEntities(context, TimelineReaderWebServicesUtils.createTimelineEntityFilters( limit, createdTimeStart, createdTimeEnd, relatesTo, isRelatedTo, @@ -3405,6 +3472,9 @@ public TimelineEntity getContainer(@Context HttpServletRequest req, TimelineReaderContext context = TimelineReaderWebServicesUtils .createTimelineReaderContext(clusterId, null, null, null, null, entityType, entityIdPrefix, entityId, userId); + // TODO to be removed or modified once ACL story is played + checkAccess(timelineReaderManager, callerUGI, context.getDoAsUser()); + entities = timelineReaderManager.getEntities(context, new TimelineEntityFilters.Builder().build(), TimelineReaderWebServicesUtils.createTimelineDataToRetrieve( @@ -3442,4 +3512,39 @@ private boolean validateAuthUserWithEntityUser( } return (readerManager.checkAccess(ugi) || authUser.equals(requestedUser)); } + + // TODO to be removed/modified once ACL story has played + private void checkAccess(TimelineReaderManager readerManager, + UserGroupInformation ugi, String entityUser) { + if (isDisplayEntityPerUserFilterEnabled(readerManager.getConfig())) { + if (!validateAuthUserWithEntityUser(readerManager, ugi, entityUser)) { + String userName = ugi.getShortUserName(); + String msg = "User " + userName + + " is not allowed to read TimelineService V2 data."; + throw new ForbiddenException(msg); + } + } + } + + private void checkAccess(TimelineReaderManager readerManager, + UserGroupInformation callerUGI, Set entities, + String entityUserKey, boolean verifyForAllEntity) { + if (entities.size() > 0 && isDisplayEntityPerUserFilterEnabled( + readerManager.getConfig())) { + Set userEntities = new LinkedHashSet<>(); + userEntities.addAll(entities); + for (TimelineEntity entity : userEntities) { + if (entity.getInfo() != null) { + String userId = (String) entity.getInfo().get(entityUserKey); + if (!validateAuthUserWithEntityUser(readerManager, callerUGI, + userId)) { + entities.remove(entity); + if (!verifyForAllEntity) { + break; + } + } + } + } + } + } }