Skip to content

Commit

Permalink
YARN-10345 HsWebServices containerlogs does not honor ACLs for comple…
Browse files Browse the repository at this point in the history
…ted jobs (#7013)

- following rest apis did not have access control
- - /ws/v1/history/containerlogs/{containerid}/{filename}
- - /ws/v1/history/containers/{containerid}/logs

Change-Id: I434f6138966ab22583d356509e40b70d328d9e7c
  • Loading branch information
K0K0V0K authored Aug 27, 2024
1 parent 89e38f0 commit e4ee3d5
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@

import org.apache.hadoop.http.JettyUtils;
import org.apache.hadoop.mapreduce.JobACL;
import org.apache.hadoop.mapreduce.JobID;
import org.apache.hadoop.mapreduce.v2.api.protocolrecords.KillTaskAttemptRequest;
import org.apache.hadoop.mapreduce.v2.api.protocolrecords.KillTaskAttemptResponse;
import org.apache.hadoop.mapreduce.v2.api.protocolrecords.impl.pb.KillTaskAttemptRequestPBImpl;
Expand Down Expand Up @@ -113,9 +114,17 @@ private void init() {
response.setContentType(null);
}

/**
* convert a job id string to an actual job and handle all the error checking.
*/
public static Job getJobFromContainerIdString(String cid, AppContext appCtx)
throws NotFoundException {
//example container_e06_1724414851587_0004_01_000001
String[] parts = cid.split("_");
return getJobFromJobIdString(JobID.JOB + "_" + parts[2] + "_" + parts[3], appCtx);
}


/**
* convert a job id string to an actual job and handle all the error checking.
*/
public static Job getJobFromJobIdString(String jid, AppContext appCtx) throws NotFoundException {
JobId jobId;
Job job;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.http.JettyUtils;
import org.apache.hadoop.mapreduce.JobACL;
import org.apache.hadoop.mapreduce.MRConfig;
import org.apache.hadoop.mapreduce.v2.api.records.AMInfo;
import org.apache.hadoop.mapreduce.v2.api.records.JobState;
import org.apache.hadoop.mapreduce.v2.api.records.TaskId;
Expand Down Expand Up @@ -87,6 +88,7 @@ public class HsWebServices extends WebServices {
private final HistoryContext ctx;
private WebApp webapp;
private LogServlet logServlet;
private boolean mrAclsEnabled;

private @Context HttpServletResponse response;
@Context UriInfo uriInfo;
Expand All @@ -100,6 +102,7 @@ public HsWebServices(final HistoryContext ctx,
this.ctx = ctx;
this.webapp = webapp;
this.logServlet = new LogServlet(conf, this);
this.mrAclsEnabled = conf.getBoolean(MRConfig.MR_ACLS_ENABLED, false);
}

private boolean hasAccess(Job job, HttpServletRequest request) {
Expand All @@ -116,6 +119,11 @@ private void checkAccess(Job job, HttpServletRequest request) {
throw new WebApplicationException(Status.UNAUTHORIZED);
}
}
private void checkAccess(String containerIdStr, HttpServletRequest hsr) {
if (mrAclsEnabled) {
checkAccess(AMWebServices.getJobFromContainerIdString(containerIdStr, ctx), hsr);
}
}

private void init() {
//clear content type
Expand Down Expand Up @@ -500,7 +508,7 @@ public Response getContainerLogs(@Context HttpServletRequest hsr,
@QueryParam(YarnWebServiceParams.MANUAL_REDIRECTION)
@DefaultValue("false") boolean manualRedirection) {
init();

checkAccess(containerIdStr, hsr);
WrappedLogMetaRequest.Builder logMetaRequestBuilder =
LogServlet.createRequestFromContainerId(containerIdStr);

Expand All @@ -527,6 +535,7 @@ public Response getContainerLogFile(@Context HttpServletRequest req,
@QueryParam(YarnWebServiceParams.MANUAL_REDIRECTION)
@DefaultValue("false") boolean manualRedirection) {
init();
checkAccess(containerIdStr, req);
return logServlet.getLogFile(req, containerIdStr, filename, format, size,
nmId, redirectedFromNode, null, manualRedirection);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,23 +18,20 @@

package org.apache.hadoop.mapreduce.v2.hs.webapp;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Response.Status;

import org.junit.Before;
import org.junit.Test;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.CommonConfigurationKeys;
import org.apache.hadoop.fs.Path;
Expand All @@ -60,9 +57,19 @@
import org.apache.hadoop.security.UserGroupInformation;
import org.apache.hadoop.security.authorize.AccessControlList;
import org.apache.hadoop.yarn.api.records.Priority;
import org.apache.hadoop.yarn.server.webapp.LogServlet;
import org.apache.hadoop.yarn.webapp.WebApp;
import org.junit.Before;
import org.junit.Test;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyBoolean;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

public class TestHsWebServicesAcls {
private static String FRIENDLY_USER = "friendly";
Expand Down Expand Up @@ -253,6 +260,29 @@ public void testGetJobTaskAttemptIdCountersAcls() {
this.taskIdStr, this.taskAttemptIdStr);
}

@Test
public void testLogs() {
HttpServletRequest hsr = mock(HttpServletRequest.class);
when(hsr.getRemoteUser()).thenReturn(ENEMY_USER);
hsWebServices.setLogServlet(mock(LogServlet.class));
String cid = "container_e02_" + jobIdStr.substring(4) + "_01_000001";
try {
hsWebServices.getContainerLogFile(hsr, cid, "syslog",
null, null, null, false, false);
fail("enemy can access job");
} catch (WebApplicationException e) {
assertEquals(Status.UNAUTHORIZED,
Status.fromStatusCode(e.getResponse().getStatus()));
}

when(hsr.getRemoteUser()).thenReturn(FRIENDLY_USER);
hsWebServices.getContainerLogFile(hsr, cid, "syslog",
"format", "1024", "nmid", false, false);
verify(hsWebServices.getLogServlet(), times(1))
.getLogFile(any(), anyString(), anyString(),
anyString(), anyString(), anyString(), anyBoolean(), eq(null), anyBoolean());
}

private static HistoryContext buildHistoryContext(final Configuration conf)
throws IOException {
HistoryContext ctx = new MockHistoryContext(1, 1, 1);
Expand Down

0 comments on commit e4ee3d5

Please sign in to comment.