YARN-8091. Revisit checkUserAccessToQueue RM REST API. (wangda)
Change-Id: I5fab3fe229c34e967487b7327c7b3c8ddf7cb795
This commit is contained in:
parent
54a81211ea
commit
c78cb18c61
|
@ -53,6 +53,7 @@ import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.NodeLabelsInfo;
|
|||
import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.NodeToLabelsEntryList;
|
||||
import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.NodeToLabelsInfo;
|
||||
import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.NodesInfo;
|
||||
import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.RMQueueAclInfo;
|
||||
import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ReservationDeleteRequestInfo;
|
||||
import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ReservationSubmissionRequestInfo;
|
||||
import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ReservationUpdateRequestInfo;
|
||||
|
@ -673,7 +674,7 @@ public interface RMWebServiceProtocol {
|
|||
* @throws AuthorizationException if the user is not authorized to invoke this
|
||||
* method.
|
||||
*/
|
||||
Response checkUserAccessToQueue(String queue, String username,
|
||||
RMQueueAclInfo checkUserAccessToQueue(String queue, String username,
|
||||
String queueAclType, HttpServletRequest hsr)
|
||||
throws AuthorizationException;
|
||||
}
|
||||
|
|
|
@ -173,6 +173,7 @@ import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.NodeToLabelsEntr
|
|||
import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.NodeToLabelsEntryList;
|
||||
import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.NodeToLabelsInfo;
|
||||
import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.NodesInfo;
|
||||
import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.RMQueueAclInfo;
|
||||
import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ReservationDefinitionInfo;
|
||||
import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ReservationDeleteRequestInfo;
|
||||
import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ReservationDeleteResponseInfo;
|
||||
|
@ -2523,7 +2524,7 @@ public class RMWebServices extends WebServices implements RMWebServiceProtocol {
|
|||
@Path(RMWSConsts.CHECK_USER_ACCESS_TO_QUEUE)
|
||||
@Produces({ MediaType.APPLICATION_JSON + "; " + JettyUtils.UTF_8,
|
||||
MediaType.APPLICATION_XML + "; " + JettyUtils.UTF_8 })
|
||||
public Response checkUserAccessToQueue(
|
||||
public RMQueueAclInfo checkUserAccessToQueue(
|
||||
@PathParam(RMWSConsts.QUEUE) String queue,
|
||||
@QueryParam(RMWSConsts.USER) String username,
|
||||
@QueryParam(RMWSConsts.QUEUE_ACL_TYPE)
|
||||
|
@ -2531,42 +2532,39 @@ public class RMWebServices extends WebServices implements RMWebServiceProtocol {
|
|||
@Context HttpServletRequest hsr) throws AuthorizationException {
|
||||
init();
|
||||
|
||||
// Check if the specified queue acl is valid.
|
||||
QueueACL queueACL;
|
||||
try {
|
||||
queueACL = QueueACL.valueOf(queueAclType);
|
||||
} catch (IllegalArgumentException e) {
|
||||
return Response.status(Status.BAD_REQUEST).entity(
|
||||
"Specified queueAclType=" + queueAclType
|
||||
+ " is not a valid type, valid queue acl types={"
|
||||
+ "SUBMIT_APPLICATIONS/ADMINISTER_QUEUE}").build();
|
||||
}
|
||||
|
||||
// For the user who invokes this REST call, he/she should have admin access
|
||||
// to the queue. Otherwise we will reject the call.
|
||||
UserGroupInformation callerUGI = getCallerUserGroupInformation(hsr, true);
|
||||
if (callerUGI != null && !this.rm.getResourceScheduler().checkAccess(
|
||||
callerUGI, QueueACL.ADMINISTER_QUEUE, queue)) {
|
||||
return Response.status(Status.FORBIDDEN).entity(
|
||||
throw new ForbiddenException(
|
||||
"User=" + callerUGI.getUserName() + " doesn't haven access to queue="
|
||||
+ queue + " so it cannot check ACLs for other users.")
|
||||
.build();
|
||||
+ queue + " so it cannot check ACLs for other users.");
|
||||
}
|
||||
|
||||
// Create UGI for the to-be-checked user.
|
||||
UserGroupInformation user = UserGroupInformation.createRemoteUser(username);
|
||||
if (user == null) {
|
||||
return Response.status(Status.FORBIDDEN).entity(
|
||||
"Failed to retrieve UserGroupInformation for user=" + username)
|
||||
.build();
|
||||
throw new ForbiddenException(
|
||||
"Failed to retrieve UserGroupInformation for user=" + username);
|
||||
}
|
||||
|
||||
// Check if the specified queue acl is valid.
|
||||
QueueACL queueACL;
|
||||
try {
|
||||
queueACL = QueueACL.valueOf(queueAclType);
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new BadRequestException("Specified queueAclType=" + queueAclType
|
||||
+ " is not a valid type, valid queue acl types={"
|
||||
+ "SUBMIT_APPLICATIONS/ADMINISTER_QUEUE}");
|
||||
}
|
||||
|
||||
if (!this.rm.getResourceScheduler().checkAccess(user, queueACL, queue)) {
|
||||
return Response.status(Status.FORBIDDEN).entity(
|
||||
return new RMQueueAclInfo(false, user.getUserName(),
|
||||
"User=" + username + " doesn't have access to queue=" + queue
|
||||
+ " with acl-type=" + queueAclType).build();
|
||||
+ " with acl-type=" + queueAclType);
|
||||
}
|
||||
|
||||
return Response.status(Status.OK).build();
|
||||
return new RMQueueAclInfo(true, user.getUserName(), "");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.hadoop.yarn.server.resourcemanager.webapp.dao;
|
||||
|
||||
import javax.xml.bind.annotation.XmlAccessType;
|
||||
import javax.xml.bind.annotation.XmlAccessorType;
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
|
||||
@XmlRootElement
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
public class RMQueueAclInfo {
|
||||
protected boolean allowed;
|
||||
protected String user;
|
||||
protected String diagnostics;
|
||||
|
||||
public RMQueueAclInfo() {
|
||||
|
||||
}
|
||||
|
||||
public RMQueueAclInfo(boolean allowed, String user, String diagnostics) {
|
||||
this.allowed = allowed;
|
||||
this.user = user;
|
||||
this.diagnostics = diagnostics;
|
||||
}
|
||||
|
||||
public boolean isAllowed() {
|
||||
return allowed;
|
||||
}
|
||||
|
||||
public void setAllowed(boolean allowed) {
|
||||
this.allowed = allowed;
|
||||
}
|
||||
|
||||
public String getUser() {
|
||||
return user;
|
||||
}
|
||||
|
||||
public void setUser(String user) {
|
||||
this.user = user;
|
||||
}
|
||||
|
||||
public String getDiagnostics() {
|
||||
return diagnostics;
|
||||
}
|
||||
|
||||
public void setDiagnostics(String diagnostics) {
|
||||
this.diagnostics = diagnostics;
|
||||
}
|
||||
}
|
|
@ -68,6 +68,7 @@ import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.AppsInfo;
|
|||
import org.apache.hadoop.yarn.server.security.ApplicationACLsManager;
|
||||
import org.apache.hadoop.yarn.util.AdHocLogDumper;
|
||||
import org.apache.hadoop.yarn.util.YarnVersionInfo;
|
||||
import org.apache.hadoop.yarn.webapp.BadRequestException;
|
||||
import org.apache.hadoop.yarn.webapp.ForbiddenException;
|
||||
import org.apache.hadoop.yarn.webapp.GenericExceptionHandler;
|
||||
import org.apache.hadoop.yarn.webapp.GuiceServletConfig;
|
||||
|
@ -798,42 +799,47 @@ public class TestRMWebServices extends JerseyTestBase {
|
|||
RMWebServices webSvc =
|
||||
new RMWebServices(mockRM, conf, mock(HttpServletResponse.class));
|
||||
|
||||
boolean caughtException = false;
|
||||
|
||||
// Case 1: Only queue admin user can access other user's information
|
||||
HttpServletRequest mockHsr = mockHttpServletRequestByUserName("non-admin");
|
||||
Assert.assertEquals(webSvc.checkUserAccessToQueue("queue", "jack",
|
||||
QueueACL.SUBMIT_APPLICATIONS.name(), mockHsr).getStatus(),
|
||||
Response.SC_FORBIDDEN);
|
||||
try {
|
||||
webSvc.checkUserAccessToQueue("queue", "jack",
|
||||
QueueACL.SUBMIT_APPLICATIONS.name(), mockHsr);
|
||||
} catch (ForbiddenException e) {
|
||||
caughtException = true;
|
||||
}
|
||||
Assert.assertTrue(caughtException);
|
||||
|
||||
// Case 2: request an unknown ACL causes BAD_REQUEST
|
||||
mockHsr = mockHttpServletRequestByUserName("admin");
|
||||
Assert.assertEquals(webSvc.checkUserAccessToQueue("queue", "jack",
|
||||
"XYZ_ACL", mockHsr).getStatus(), Response.SC_BAD_REQUEST);
|
||||
caughtException = false;
|
||||
try {
|
||||
webSvc.checkUserAccessToQueue("queue", "jack", "XYZ_ACL", mockHsr);
|
||||
} catch (BadRequestException e) {
|
||||
caughtException = true;
|
||||
}
|
||||
Assert.assertTrue(caughtException);
|
||||
|
||||
// Case 3: get FORBIDDEN for rejected ACL
|
||||
mockHsr = mockHttpServletRequestByUserName("admin");
|
||||
Assert.assertEquals(webSvc.checkUserAccessToQueue("queue", "jack",
|
||||
QueueACL.SUBMIT_APPLICATIONS.name(), mockHsr).getStatus(),
|
||||
Response.SC_FORBIDDEN);
|
||||
Assert.assertEquals(webSvc.checkUserAccessToQueue("queue", "jack",
|
||||
QueueACL.ADMINISTER_QUEUE.name(), mockHsr).getStatus(),
|
||||
Response.SC_FORBIDDEN);
|
||||
Assert.assertFalse(webSvc.checkUserAccessToQueue("queue", "jack",
|
||||
QueueACL.SUBMIT_APPLICATIONS.name(), mockHsr).isAllowed());
|
||||
Assert.assertFalse(webSvc.checkUserAccessToQueue("queue", "jack",
|
||||
QueueACL.ADMINISTER_QUEUE.name(), mockHsr).isAllowed());
|
||||
|
||||
// Case 4: get OK for listed ACLs
|
||||
mockHsr = mockHttpServletRequestByUserName("admin");
|
||||
Assert.assertEquals(webSvc.checkUserAccessToQueue("queue", "admin",
|
||||
QueueACL.SUBMIT_APPLICATIONS.name(), mockHsr).getStatus(),
|
||||
Response.SC_OK);
|
||||
Assert.assertEquals(webSvc.checkUserAccessToQueue("queue", "admin",
|
||||
QueueACL.ADMINISTER_QUEUE.name(), mockHsr).getStatus(),
|
||||
Response.SC_OK);
|
||||
Assert.assertTrue(webSvc.checkUserAccessToQueue("queue", "admin",
|
||||
QueueACL.SUBMIT_APPLICATIONS.name(), mockHsr).isAllowed());
|
||||
Assert.assertTrue(webSvc.checkUserAccessToQueue("queue", "admin",
|
||||
QueueACL.ADMINISTER_QUEUE.name(), mockHsr).isAllowed());
|
||||
|
||||
// Case 5: get OK only for SUBMIT_APP acl for "yarn" user
|
||||
mockHsr = mockHttpServletRequestByUserName("admin");
|
||||
Assert.assertEquals(webSvc.checkUserAccessToQueue("queue", "yarn",
|
||||
QueueACL.SUBMIT_APPLICATIONS.name(), mockHsr).getStatus(),
|
||||
Response.SC_OK);
|
||||
Assert.assertEquals(webSvc.checkUserAccessToQueue("queue", "yarn",
|
||||
QueueACL.ADMINISTER_QUEUE.name(), mockHsr).getStatus(),
|
||||
Response.SC_FORBIDDEN);
|
||||
Assert.assertTrue(webSvc.checkUserAccessToQueue("queue", "yarn",
|
||||
QueueACL.SUBMIT_APPLICATIONS.name(), mockHsr).isAllowed());
|
||||
Assert.assertFalse(webSvc.checkUserAccessToQueue("queue", "yarn",
|
||||
QueueACL.ADMINISTER_QUEUE.name(), mockHsr).isAllowed());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -53,6 +53,7 @@ import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.NodeLabelsInfo;
|
|||
import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.NodeToLabelsEntryList;
|
||||
import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.NodeToLabelsInfo;
|
||||
import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.NodesInfo;
|
||||
import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.RMQueueAclInfo;
|
||||
import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ReservationDeleteRequestInfo;
|
||||
import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ReservationSubmissionRequestInfo;
|
||||
import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ReservationUpdateRequestInfo;
|
||||
|
@ -471,10 +472,10 @@ public class DefaultRequestInterceptorREST
|
|||
}
|
||||
|
||||
@Override
|
||||
public Response checkUserAccessToQueue(String queue, String username,
|
||||
public RMQueueAclInfo checkUserAccessToQueue(String queue, String username,
|
||||
String queueAclType, HttpServletRequest hsr) {
|
||||
return RouterWebServiceUtil.genericForward(webAppAddress, hsr,
|
||||
Response.class, HTTPMethods.GET,
|
||||
RMQueueAclInfo.class, HTTPMethods.GET,
|
||||
RMWSConsts.RM_WEB_SERVICE_PATH + RMWSConsts.QUEUES + "/" + queue
|
||||
+ "/access", null, null);
|
||||
}
|
||||
|
|
|
@ -79,6 +79,7 @@ import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.NodeLabelsInfo;
|
|||
import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.NodeToLabelsEntryList;
|
||||
import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.NodeToLabelsInfo;
|
||||
import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.NodesInfo;
|
||||
import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.RMQueueAclInfo;
|
||||
import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ReservationDeleteRequestInfo;
|
||||
import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ReservationSubmissionRequestInfo;
|
||||
import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ReservationUpdateRequestInfo;
|
||||
|
@ -1184,7 +1185,7 @@ public class FederationInterceptorREST extends AbstractRESTRequestInterceptor {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Response checkUserAccessToQueue(String queue, String username,
|
||||
public RMQueueAclInfo checkUserAccessToQueue(String queue, String username,
|
||||
String queueAclType, HttpServletRequest hsr) {
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
|
|
@ -75,6 +75,7 @@ import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.NodeLabelsInfo;
|
|||
import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.NodeToLabelsEntryList;
|
||||
import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.NodeToLabelsInfo;
|
||||
import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.NodesInfo;
|
||||
import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.RMQueueAclInfo;
|
||||
import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ReservationDeleteRequestInfo;
|
||||
import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ReservationSubmissionRequestInfo;
|
||||
import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ReservationUpdateRequestInfo;
|
||||
|
@ -837,7 +838,7 @@ public class RouterWebServices implements RMWebServiceProtocol {
|
|||
@Produces({ MediaType.APPLICATION_JSON + "; " + JettyUtils.UTF_8,
|
||||
MediaType.APPLICATION_XML + "; " + JettyUtils.UTF_8 })
|
||||
@Override
|
||||
public Response checkUserAccessToQueue(
|
||||
public RMQueueAclInfo checkUserAccessToQueue(
|
||||
@PathParam(RMWSConsts.QUEUE) String queue,
|
||||
@QueryParam(RMWSConsts.USER) String username,
|
||||
@QueryParam(RMWSConsts.QUEUE_ACL_TYPE)
|
||||
|
|
|
@ -50,6 +50,7 @@ import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.NodeLabelsInfo;
|
|||
import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.NodeToLabelsEntryList;
|
||||
import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.NodeToLabelsInfo;
|
||||
import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.NodesInfo;
|
||||
import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.RMQueueAclInfo;
|
||||
import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ReservationDeleteRequestInfo;
|
||||
import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ReservationSubmissionRequestInfo;
|
||||
import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ReservationUpdateRequestInfo;
|
||||
|
@ -319,9 +320,9 @@ public class MockRESTRequestInterceptor extends AbstractRESTRequestInterceptor {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Response checkUserAccessToQueue(String queue, String username,
|
||||
public RMQueueAclInfo checkUserAccessToQueue(String queue, String username,
|
||||
String queueAclType, HttpServletRequest hsr) {
|
||||
return Response.status(Status.OK).build();
|
||||
return new RMQueueAclInfo(true, username, "");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -48,6 +48,7 @@ import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.NodeLabelsInfo;
|
|||
import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.NodeToLabelsEntryList;
|
||||
import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.NodeToLabelsInfo;
|
||||
import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.NodesInfo;
|
||||
import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.RMQueueAclInfo;
|
||||
import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ReservationDeleteRequestInfo;
|
||||
import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ReservationSubmissionRequestInfo;
|
||||
import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ReservationUpdateRequestInfo;
|
||||
|
@ -69,7 +70,7 @@ public class PassThroughRESTRequestInterceptor
|
|||
}
|
||||
|
||||
@Override
|
||||
public Response checkUserAccessToQueue(String queue, String username,
|
||||
public RMQueueAclInfo checkUserAccessToQueue(String queue, String username,
|
||||
String queueAclType, HttpServletRequest hsr)
|
||||
throws AuthorizationException {
|
||||
return getNextInterceptor().checkUserAccessToQueue(queue, username,
|
||||
|
|
Loading…
Reference in New Issue