This is an automated email from the ASF dual-hosted git repository.
asf-gitbox-commits pushed a commit to branch atlas-2.6
in repository https://gitbox.apache.org/repos/asf/atlas.git
The following commit(s) were added to refs/heads/atlas-2.6 by this push:
new 205b53fca ATLAS-5326: Enforce Atlas authorization on AdminResource
REST endpoints (#675)
205b53fca is described below
commit 205b53fcae3d8a39583756e66976c74da0823a3b
Author: Radhika Kundam <[email protected]>
AuthorDate: Tue Jul 28 09:59:09 2026 -0700
ATLAS-5326: Enforce Atlas authorization on AdminResource REST endpoints
(#675)
* ATLAS-5326: Enforce Atlas authorization on AdminResource REST endpoints
(cherry picked from commit 53af3d8d7667ab17636aab8ecfd39f829724f2a9)
---
.../apache/atlas/web/resources/AdminResource.java | 30 ++-
.../atlas/web/resources/AdminResourceTest.java | 272 +++++++++++++++------
2 files changed, 231 insertions(+), 71 deletions(-)
diff --git
a/webapp/src/main/java/org/apache/atlas/web/resources/AdminResource.java
b/webapp/src/main/java/org/apache/atlas/web/resources/AdminResource.java
index da9967a1c..b0e3b04b8 100755
--- a/webapp/src/main/java/org/apache/atlas/web/resources/AdminResource.java
+++ b/webapp/src/main/java/org/apache/atlas/web/resources/AdminResource.java
@@ -268,9 +268,11 @@ public class AdminResource {
@GET
@Path("stack")
@Produces(MediaType.TEXT_PLAIN)
- public String getThreadDump() {
+ public String getThreadDump() throws AtlasBaseException {
LOG.debug("==> AdminResource.getThreadDump()");
+ AtlasAuthorizationUtils.verifyAccess(new
AtlasAdminAccessRequest(AtlasPrivilege.ADMIN_EXPORT), "thread dump");
+
ThreadGroup topThreadGroup = Thread.currentThread().getThreadGroup();
while (topThreadGroup.getParent() != null) {
@@ -735,6 +737,8 @@ public class AdminResource {
@Produces(Servlets.JSON_MEDIA_TYPE)
@Consumes(MediaType.APPLICATION_JSON)
public void abortAsyncImport(@PathParam("importId") String importId)
throws AtlasBaseException {
+ AtlasAuthorizationUtils.verifyAccess(new
AtlasAdminAccessRequest(AtlasPrivilege.ADMIN_IMPORT), "abort async import");
+
importService.abortAsyncImport(importId);
}
@@ -749,6 +753,8 @@ public class AdminResource {
perf = AtlasPerfTracer.getPerfTracer(PERF_LOG,
"AdminResource.getAsyncImportStatus()");
}
+ AtlasAuthorizationUtils.verifyAccess(new
AtlasAdminAccessRequest(AtlasPrivilege.ADMIN_IMPORT), "async import status");
+
return importService.getAsyncImportsStatus(offset, limit);
} finally {
AtlasPerfTracer.log(perf);
@@ -766,6 +772,8 @@ public class AdminResource {
perf = AtlasPerfTracer.getPerfTracer(PERF_LOG,
"AdminResource.getAsyncImportStatusById(importId=" + importId + ")");
}
+ AtlasAuthorizationUtils.verifyAccess(new
AtlasAdminAccessRequest(AtlasPrivilege.ADMIN_IMPORT), "async import status by
id");
+
return importService.getAsyncImportRequest(importId);
} finally {
AtlasPerfTracer.log(perf);
@@ -923,6 +931,8 @@ public class AdminResource {
perf = AtlasPerfTracer.getPerfTracer(PERF_LOG,
"cluster.getServer(" + serverName + ")");
}
+ AtlasAuthorizationUtils.verifyAccess(new
AtlasAdminAccessRequest(AtlasPrivilege.ADMIN_EXPORT), "get server");
+
AtlasServer cluster = new AtlasServer(serverName, serverName);
return atlasServerService.get(cluster);
@@ -946,6 +956,8 @@ public class AdminResource {
perf = AtlasPerfTracer.getPerfTracer(PERF_LOG,
"getExportImportAudit(" + serverName + ")");
}
+ AtlasAuthorizationUtils.verifyAccess(new
AtlasAdminAccessRequest(AtlasPrivilege.ADMIN_EXPORT), "export import audit");
+
return exportImportAuditService.get(userName, operation,
serverName, startTime, endTime, limit, offset);
} finally {
AtlasPerfTracer.log(perf);
@@ -1018,6 +1030,8 @@ public class AdminResource {
perf = AtlasPerfTracer.getPerfTracer(PERF_LOG,
"AdminResource.getAuditDetails(" + auditGuid + ", " + limit + ", " + offset +
")");
}
+ AtlasAuthorizationUtils.verifyAccess(new
AtlasAdminAccessRequest(AtlasPrivilege.ADMIN_AUDITS), "audit details");
+
List<AtlasEntityHeader> ret = new ArrayList<>();
AtlasAuditEntry auditEntry =
auditService.toAtlasAuditEntry(entityStore.getById(auditGuid, false, true));
@@ -1075,6 +1089,8 @@ public class AdminResource {
perf = AtlasPerfTracer.getPerfTracer(PERF_LOG, "checkState(" +
request + ")");
}
+ AtlasAuthorizationUtils.verifyAccess(new
AtlasEntityAccessRequest(typeRegistry, AtlasPrivilege.ENTITY_READ), "check
state");
+
return entityStore.checkState(request);
} finally {
AtlasPerfTracer.log(perf);
@@ -1084,9 +1100,11 @@ public class AdminResource {
@GET
@Path("patches")
@Produces(Servlets.JSON_MEDIA_TYPE)
- public AtlasPatches getAtlasPatches() {
+ public AtlasPatches getAtlasPatches() throws AtlasBaseException {
LOG.debug("==> AdminResource.getAtlasPatches()");
+ AtlasAuthorizationUtils.verifyAccess(new
AtlasAdminAccessRequest(AtlasPrivilege.ADMIN_IMPORT), "patches");
+
AtlasPatches ret = patchManager.getAllPatches();
LOG.debug("<== AdminResource.getAtlasPatches()");
@@ -1098,6 +1116,8 @@ public class AdminResource {
@Path("/tasks")
@Produces(Servlets.JSON_MEDIA_TYPE)
public List<AtlasTask> getTaskStatus(@QueryParam("guids") List<String>
guids) throws AtlasBaseException {
+ AtlasAuthorizationUtils.verifyAccess(new
AtlasAdminAccessRequest(AtlasPrivilege.ADMIN_PURGE), "tasks");
+
return CollectionUtils.isNotEmpty(guids) ?
taskManagement.getByGuids(guids) : taskManagement.getAll();
}
@@ -1105,6 +1125,8 @@ public class AdminResource {
@Path("/tasks")
@Produces(Servlets.JSON_MEDIA_TYPE)
public void deleteTask(@QueryParam("guids") List<String> guids) throws
AtlasBaseException {
+ AtlasAuthorizationUtils.verifyAccess(new
AtlasAdminAccessRequest(AtlasPrivilege.ADMIN_PURGE), "delete tasks");
+
if (CollectionUtils.isNotEmpty(guids)) {
taskManagement.deleteByGuids(guids);
}
@@ -1113,7 +1135,9 @@ public class AdminResource {
@GET
@Path("/debug/metrics")
@Produces(MediaType.APPLICATION_JSON)
- public Map<String, DebugMetrics> getDebugMetrics() {
+ public Map<String, DebugMetrics> getDebugMetrics() throws
AtlasBaseException {
+ AtlasAuthorizationUtils.verifyAccess(new
AtlasAdminAccessRequest(AtlasPrivilege.ADMIN_EXPORT), "debug metrics");
+
return debugMetricsRESTSink.getMetrics();
}
diff --git
a/webapp/src/test/java/org/apache/atlas/web/resources/AdminResourceTest.java
b/webapp/src/test/java/org/apache/atlas/web/resources/AdminResourceTest.java
index 7723ee75a..0402c333f 100644
--- a/webapp/src/test/java/org/apache/atlas/web/resources/AdminResourceTest.java
+++ b/webapp/src/test/java/org/apache/atlas/web/resources/AdminResourceTest.java
@@ -21,6 +21,7 @@ package org.apache.atlas.web.resources;
import com.fasterxml.jackson.databind.JsonNode;
import org.apache.atlas.AtlasErrorCode;
import org.apache.atlas.authorize.AtlasAuthorizationUtils;
+import org.apache.atlas.authorize.AtlasEntityAccessRequest;
import org.apache.atlas.discovery.SearchContext;
import org.apache.atlas.exception.AtlasBaseException;
import org.apache.atlas.model.PList;
@@ -96,6 +97,7 @@ import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.concurrent.Callable;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyBoolean;
@@ -232,6 +234,22 @@ public class AdminResourceTest {
debugMetricsRESTSink, auditReductionService, atlasMetricsUtil,
purgeService);
}
+ private void withAuthorizationBypass(Runnable runnable) {
+ try (MockedStatic<AtlasAuthorizationUtils> mockedUtils =
mockStatic(AtlasAuthorizationUtils.class)) {
+ mockedUtils.when(() ->
AtlasAuthorizationUtils.verifyAccess(any(org.apache.atlas.authorize.AtlasAdminAccessRequest.class),
any())).then(invocation -> null);
+ mockedUtils.when(() ->
AtlasAuthorizationUtils.verifyAccess(any(AtlasEntityAccessRequest.class),
any())).then(invocation -> null);
+ runnable.run();
+ }
+ }
+
+ private <T> T withAuthorizationBypassCallable(Callable<T> callable) throws
Exception {
+ try (MockedStatic<AtlasAuthorizationUtils> mockedUtils =
mockStatic(AtlasAuthorizationUtils.class)) {
+ mockedUtils.when(() ->
AtlasAuthorizationUtils.verifyAccess(any(org.apache.atlas.authorize.AtlasAdminAccessRequest.class),
any())).then(invocation -> null);
+ mockedUtils.when(() ->
AtlasAuthorizationUtils.verifyAccess(any(AtlasEntityAccessRequest.class),
any())).then(invocation -> null);
+ return callable.call();
+ }
+ }
+
// Helper method to inject HttpServletRequest via reflection
private void injectHttpServletRequest(AdminResource adminResource) throws
Exception {
Field requestField =
AdminResource.class.getDeclaredField("httpServletRequest");
@@ -249,11 +267,18 @@ public class AdminResourceTest {
@Test
public void testGetThreadDump() {
AdminResource adminResource = createAdminResource();
- String threadDump = adminResource.getThreadDump();
+ withAuthorizationBypass(() -> {
+ String threadDump = null;
+ try {
+ threadDump = adminResource.getThreadDump();
+ } catch (AtlasBaseException e) {
+ throw new RuntimeException(e);
+ }
- assertNotNull(threadDump);
- assertTrue(threadDump.length() > 0);
- assertTrue(threadDump.contains("State:"));
+ assertNotNull(threadDump);
+ assertTrue(threadDump.length() > 0);
+ assertTrue(threadDump.contains("State:"));
+ });
}
@Test
@@ -436,10 +461,16 @@ public class AdminResourceTest {
AdminResource adminResource = createAdminResource();
- AtlasCheckStateResult result = adminResource.checkState(request);
+ withAuthorizationBypass(() -> {
+ try {
+ AtlasCheckStateResult result =
adminResource.checkState(request);
- assertNotNull(result);
- verify(entityStore).checkState(request);
+ assertNotNull(result);
+ verify(entityStore).checkState(request);
+ } catch (AtlasBaseException e) {
+ throw new RuntimeException(e);
+ }
+ });
}
@Test
@@ -450,10 +481,16 @@ public class AdminResourceTest {
AdminResource adminResource = createAdminResource();
- AtlasPatches result = adminResource.getAtlasPatches();
+ withAuthorizationBypass(() -> {
+ try {
+ AtlasPatches result = adminResource.getAtlasPatches();
- assertNotNull(result);
- verify(patchManager).getAllPatches();
+ assertNotNull(result);
+ verify(patchManager).getAllPatches();
+ } catch (AtlasBaseException e) {
+ throw new RuntimeException(e);
+ }
+ });
}
@Test
@@ -470,11 +507,17 @@ public class AdminResourceTest {
AdminResource adminResource = createAdminResource();
- List<AtlasTask> result = adminResource.getTaskStatus(guids);
+ withAuthorizationBypass(() -> {
+ try {
+ List<AtlasTask> result = adminResource.getTaskStatus(guids);
- assertNotNull(result);
- assertFalse(result.isEmpty());
- verify(taskManagement).getByGuids(guids);
+ assertNotNull(result);
+ assertFalse(result.isEmpty());
+ verify(taskManagement).getByGuids(guids);
+ } catch (AtlasBaseException e) {
+ throw new RuntimeException(e);
+ }
+ });
}
@Test
@@ -487,10 +530,16 @@ public class AdminResourceTest {
AdminResource adminResource = createAdminResource();
- List<AtlasTask> result = adminResource.getTaskStatus(null);
+ withAuthorizationBypass(() -> {
+ try {
+ List<AtlasTask> result = adminResource.getTaskStatus(null);
- assertNotNull(result);
- verify(taskManagement).getAll();
+ assertNotNull(result);
+ verify(taskManagement).getAll();
+ } catch (AtlasBaseException e) {
+ throw new RuntimeException(e);
+ }
+ });
}
@Test
@@ -501,19 +550,31 @@ public class AdminResourceTest {
AdminResource adminResource = createAdminResource();
- adminResource.deleteTask(guids);
+ withAuthorizationBypass(() -> {
+ try {
+ adminResource.deleteTask(guids);
- verify(taskManagement).deleteByGuids(guids);
+ verify(taskManagement).deleteByGuids(guids);
+ } catch (AtlasBaseException e) {
+ throw new RuntimeException(e);
+ }
+ });
}
@Test
public void testDeleteTaskWithEmptyGuids() throws Exception {
AdminResource adminResource = createAdminResource();
- adminResource.deleteTask(null);
+ withAuthorizationBypass(() -> {
+ try {
+ adminResource.deleteTask(null);
- // Should not call deleteByGuids when guids is null or empty
- verify(taskManagement, never()).deleteByGuids(any());
+ // Should not call deleteByGuids when guids is null or empty
+ verify(taskManagement, never()).deleteByGuids(any());
+ } catch (AtlasBaseException e) {
+ throw new RuntimeException(e);
+ }
+ });
}
@Test
@@ -526,11 +587,17 @@ public class AdminResourceTest {
AdminResource adminResource = createAdminResource();
- Map<String, DebugMetrics> result = adminResource.getDebugMetrics();
+ withAuthorizationBypass(() -> {
+ try {
+ Map<String, DebugMetrics> result =
adminResource.getDebugMetrics();
- assertNotNull(result);
- assertFalse(result.isEmpty());
- verify(debugMetricsRESTSink).getMetrics();
+ assertNotNull(result);
+ assertFalse(result.isEmpty());
+ verify(debugMetricsRESTSink).getMetrics();
+ } catch (AtlasBaseException e) {
+ throw new RuntimeException(e);
+ }
+ });
}
@Test
@@ -661,7 +728,10 @@ public class AdminResourceTest {
AdminResource adminResource = createAdminResource();
- adminResource.checkState(request);
+ withAuthorizationBypassCallable(() -> {
+ adminResource.checkState(request);
+ return null;
+ });
}
@Test
@@ -812,9 +882,15 @@ public class AdminResourceTest {
AdminResource adminResource = createAdminResource();
- adminResource.abortAsyncImport(importId);
+ withAuthorizationBypass(() -> {
+ try {
+ adminResource.abortAsyncImport(importId);
- verify(importService).abortAsyncImport(importId);
+ verify(importService).abortAsyncImport(importId);
+ } catch (AtlasBaseException e) {
+ throw new RuntimeException(e);
+ }
+ });
}
@Test
@@ -828,10 +904,16 @@ public class AdminResourceTest {
AdminResource adminResource = createAdminResource();
- PList<AsyncImportStatus> result =
adminResource.getAsyncImportStatus(offset, limit);
+ withAuthorizationBypass(() -> {
+ try {
+ PList<AsyncImportStatus> result =
adminResource.getAsyncImportStatus(offset, limit);
- assertNotNull(result);
- verify(importService).getAsyncImportsStatus(offset, limit);
+ assertNotNull(result);
+ verify(importService).getAsyncImportsStatus(offset, limit);
+ } catch (AtlasBaseException e) {
+ throw new RuntimeException(e);
+ }
+ });
}
@Test
@@ -844,10 +926,16 @@ public class AdminResourceTest {
AdminResource adminResource = createAdminResource();
- AtlasAsyncImportRequest result =
adminResource.getAsyncImportStatusById(importId);
+ withAuthorizationBypass(() -> {
+ try {
+ AtlasAsyncImportRequest result =
adminResource.getAsyncImportStatusById(importId);
- assertNotNull(result);
- verify(importService).getAsyncImportRequest(importId);
+ assertNotNull(result);
+ verify(importService).getAsyncImportRequest(importId);
+ } catch (AtlasBaseException e) {
+ throw new RuntimeException(e);
+ }
+ });
}
@Test
@@ -860,10 +948,16 @@ public class AdminResourceTest {
AdminResource adminResource = createAdminResource();
- AtlasServer result = adminResource.getCluster(serverName);
+ withAuthorizationBypass(() -> {
+ try {
+ AtlasServer result = adminResource.getCluster(serverName);
- assertNotNull(result);
- verify(atlasServerService).get(any(AtlasServer.class));
+ assertNotNull(result);
+ verify(atlasServerService).get(any(AtlasServer.class));
+ } catch (AtlasBaseException e) {
+ throw new RuntimeException(e);
+ }
+ });
}
@Test
@@ -885,12 +979,18 @@ public class AdminResourceTest {
AdminResource adminResource = createAdminResource();
- List<ExportImportAuditEntry> result =
adminResource.getExportImportAudit(serverName, userName, operation,
- startTime, endTime, limit, offset);
+ withAuthorizationBypass(() -> {
+ try {
+ List<ExportImportAuditEntry> result =
adminResource.getExportImportAudit(serverName, userName, operation,
+ startTime, endTime, limit, offset);
- assertNotNull(result);
- assertFalse(result.isEmpty());
- verify(exportImportAuditService).get(userName, operation, serverName,
startTime, endTime, limit, offset);
+ assertNotNull(result);
+ assertFalse(result.isEmpty());
+ verify(exportImportAuditService).get(userName, operation,
serverName, startTime, endTime, limit, offset);
+ } catch (AtlasBaseException e) {
+ throw new RuntimeException(e);
+ }
+ });
}
@Test
@@ -904,11 +1004,17 @@ public class AdminResourceTest {
AdminResource adminResource = createAdminResource();
- List<AtlasTask> result = adminResource.ageoutAuditData(criteria, true);
+ withAuthorizationBypass(() -> {
+ try {
+ List<AtlasTask> result =
adminResource.ageoutAuditData(criteria, true);
- assertNotNull(result);
- assertFalse(result.isEmpty());
- verify(auditReductionService).startAuditAgingByConfig();
+ assertNotNull(result);
+ assertFalse(result.isEmpty());
+ verify(auditReductionService).startAuditAgingByConfig();
+ } catch (AtlasBaseException e) {
+ throw new RuntimeException(e);
+ }
+ });
}
@Test
@@ -931,12 +1037,18 @@ public class AdminResourceTest {
AdminResource adminResource = createAdminResource();
- List<AtlasTask> result = adminResource.ageoutAuditData(criteria,
false);
+ withAuthorizationBypass(() -> {
+ try {
+ List<AtlasTask> result =
adminResource.ageoutAuditData(criteria, false);
- assertNotNull(result);
- assertFalse(result.isEmpty());
-
verify(auditReductionService).buildAgeoutCriteriaForAllAgingTypes(criteria);
-
verify(auditReductionService).startAuditAgingByCriteria(mockCriteriaMap);
+ assertNotNull(result);
+ assertFalse(result.isEmpty());
+
verify(auditReductionService).buildAgeoutCriteriaForAllAgingTypes(criteria);
+
verify(auditReductionService).startAuditAgingByCriteria(mockCriteriaMap);
+ } catch (AtlasBaseException e) {
+ throw new RuntimeException(e);
+ }
+ });
}
@Test
@@ -946,10 +1058,16 @@ public class AdminResourceTest {
AdminResource adminResource = createAdminResource();
- List<AtlasTask> result = adminResource.ageoutAuditData(criteria,
false);
+ withAuthorizationBypass(() -> {
+ try {
+ List<AtlasTask> result =
adminResource.ageoutAuditData(criteria, false);
- assertNull(result);
- verify(auditReductionService,
never()).startAuditAgingByCriteria(any());
+ assertNull(result);
+ verify(auditReductionService,
never()).startAuditAgingByCriteria(any());
+ } catch (AtlasBaseException e) {
+ throw new RuntimeException(e);
+ }
+ });
}
@Test
@@ -963,11 +1081,17 @@ public class AdminResourceTest {
AdminResource adminResource = createAdminResource();
- List<AtlasAuditEntry> result =
adminResource.getAtlasAudits(searchParameters);
+ withAuthorizationBypass(() -> {
+ try {
+ List<AtlasAuditEntry> result =
adminResource.getAtlasAudits(searchParameters);
- assertNotNull(result);
- assertFalse(result.isEmpty());
- verify(auditService).get(searchParameters);
+ assertNotNull(result);
+ assertFalse(result.isEmpty());
+ verify(auditService).get(searchParameters);
+ } catch (AtlasBaseException e) {
+ throw new RuntimeException(e);
+ }
+ });
}
@Test
@@ -992,12 +1116,18 @@ public class AdminResourceTest {
AdminResource adminResource = createAdminResource();
- List<AtlasEntityHeader> result =
adminResource.getAuditDetails(auditGuid, limit, offset);
+ withAuthorizationBypass(() -> {
+ try {
+ List<AtlasEntityHeader> result =
adminResource.getAuditDetails(auditGuid, limit, offset);
- assertNotNull(result);
- assertFalse(result.isEmpty());
- verify(entityStore).getById(auditGuid, false, true);
- verify(auditService).toAtlasAuditEntry(any());
+ assertNotNull(result);
+ assertFalse(result.isEmpty());
+ verify(entityStore).getById(auditGuid, false, true);
+ verify(auditService).toAtlasAuditEntry(any());
+ } catch (AtlasBaseException e) {
+ throw new RuntimeException(e);
+ }
+ });
}
@Test
@@ -1012,11 +1142,17 @@ public class AdminResourceTest {
AdminResource adminResource = createAdminResource();
- List<AtlasEntityHeader> result =
adminResource.getAuditDetails(auditGuid, 10, 0);
+ withAuthorizationBypass(() -> {
+ try {
+ List<AtlasEntityHeader> result =
adminResource.getAuditDetails(auditGuid, 10, 0);
- assertNotNull(result);
- assertTrue(result.isEmpty());
- verify(entityStore).getById(auditGuid, false, true);
+ assertNotNull(result);
+ assertTrue(result.isEmpty());
+ verify(entityStore).getById(auditGuid, false, true);
+ } catch (AtlasBaseException e) {
+ throw new RuntimeException(e);
+ }
+ });
}
@Test