This is an automated email from the ASF dual-hosted git repository.

ruanwenjun pushed a commit to branch dev
in repository https://gitbox.apache.org/repos/asf/dolphinscheduler.git


The following commit(s) were added to refs/heads/dev by this push:
     new 25c6a87999 [Fix-18299][API] Enforce access token owner checks (#18300)
25c6a87999 is described below

commit 25c6a879991a69a29dc2148f276fa0a902252e57
Author: Wenjun Ruan <[email protected]>
AuthorDate: Thu May 28 14:32:57 2026 +0800

    [Fix-18299][API] Enforce access token owner checks (#18300)
---
 .../api/service/impl/AccessTokenServiceImpl.java   | 28 +++++-----
 .../api/service/AccessTokenServiceTest.java        | 64 ++++++++++++----------
 2 files changed, 50 insertions(+), 42 deletions(-)

diff --git 
a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/AccessTokenServiceImpl.java
 
b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/AccessTokenServiceImpl.java
index e9bba19af7..572f1cd148 100644
--- 
a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/AccessTokenServiceImpl.java
+++ 
b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/AccessTokenServiceImpl.java
@@ -17,9 +17,7 @@
 
 package org.apache.dolphinscheduler.api.service.impl;
 
-import static 
org.apache.dolphinscheduler.api.constants.ApiFuncIdentificationConstant.ACCESS_TOKEN_CREATE;
 import static 
org.apache.dolphinscheduler.api.constants.ApiFuncIdentificationConstant.ACCESS_TOKEN_DELETE;
-import static 
org.apache.dolphinscheduler.api.constants.ApiFuncIdentificationConstant.ACCESS_TOKEN_UPDATE;
 
 import org.apache.dolphinscheduler.api.enums.Status;
 import org.apache.dolphinscheduler.api.exceptions.ServiceException;
@@ -110,10 +108,7 @@ public class AccessTokenServiceImpl extends 
BaseServiceImpl implements AccessTok
     public AccessToken createToken(User loginUser, int userId, String 
expireTime, String token) {
 
         // 1. check permission
-        if (!(canOperatorPermissions(loginUser, null, 
AuthorizationType.ACCESS_TOKEN, ACCESS_TOKEN_CREATE)
-                || loginUser.getId() == userId)) {
-            throw new ServiceException(Status.USER_NO_OPERATION_PERM);
-        }
+        checkAccessTokenTargetUserIsLoginUserOrAdmin(loginUser, userId);
 
         // 2. check if user is existed
         if (userId <= 0) {
@@ -193,9 +188,7 @@ public class AccessTokenServiceImpl extends BaseServiceImpl 
implements AccessTok
     public AccessToken updateToken(User loginUser, int id, int userId, String 
expireTime, String token) {
 
         // 1. check permission
-        if (!canOperatorPermissions(loginUser, null, 
AuthorizationType.ACCESS_TOKEN, ACCESS_TOKEN_UPDATE)) {
-            throw new ServiceException(Status.USER_NO_OPERATION_PERM);
-        }
+        checkAccessTokenTargetUserIsLoginUserOrAdmin(loginUser, userId);
 
         // 2. check if token is existed
         AccessToken accessToken = accessTokenDao.queryById(id);
@@ -203,10 +196,7 @@ public class AccessTokenServiceImpl extends 
BaseServiceImpl implements AccessTok
             log.error("Access token does not exist, accessTokenId:{}.", id);
             throw new ServiceException(Status.ACCESS_TOKEN_NOT_EXIST, id);
         }
-        // admin can operate all, non-admin can operate their own
-        if (accessToken.getUserId() != loginUser.getId() && 
!loginUser.getUserType().equals(UserType.ADMIN_USER)) {
-            throw new ServiceException(Status.USER_NO_OPERATION_PERM);
-        }
+        checkAccessTokenOwnerIsLoginUserOrAdmin(loginUser, accessToken);
 
         // 3. generate access token if absent
         if (StringUtils.isBlank(token)) {
@@ -224,4 +214,16 @@ public class AccessTokenServiceImpl extends 
BaseServiceImpl implements AccessTok
         }
         return accessToken;
     }
+
+    private void checkAccessTokenTargetUserIsLoginUserOrAdmin(User loginUser, 
int userId) {
+        if (!isAdmin(loginUser) && loginUser.getId() != userId) {
+            throw new ServiceException(Status.USER_NO_OPERATION_PERM);
+        }
+    }
+
+    private void checkAccessTokenOwnerIsLoginUserOrAdmin(User loginUser, 
AccessToken accessToken) {
+        if (!isAdmin(loginUser) && accessToken.getUserId() != 
loginUser.getId()) {
+            throw new ServiceException(Status.USER_NO_OPERATION_PERM);
+        }
+    }
 }
diff --git 
a/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/service/AccessTokenServiceTest.java
 
b/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/service/AccessTokenServiceTest.java
index 9320c865ba..ba196f9643 100644
--- 
a/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/service/AccessTokenServiceTest.java
+++ 
b/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/service/AccessTokenServiceTest.java
@@ -20,7 +20,6 @@ package org.apache.dolphinscheduler.api.service;
 import static 
org.apache.dolphinscheduler.api.AssertionsHelper.assertDoesNotThrow;
 import static 
org.apache.dolphinscheduler.api.AssertionsHelper.assertThrowsServiceException;
 import static 
org.apache.dolphinscheduler.api.constants.ApiFuncIdentificationConstant.ACCESS_TOKEN_DELETE;
-import static 
org.apache.dolphinscheduler.api.constants.ApiFuncIdentificationConstant.ACCESS_TOKEN_UPDATE;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -40,7 +39,6 @@ import org.apache.dolphinscheduler.dao.entity.AccessToken;
 import org.apache.dolphinscheduler.dao.entity.User;
 import org.apache.dolphinscheduler.dao.repository.AccessTokenDao;
 
-import java.util.ArrayList;
 import java.util.Calendar;
 import java.util.Date;
 import java.util.List;
@@ -78,7 +76,7 @@ public class AccessTokenServiceTest {
     @SuppressWarnings("unchecked")
     public void testQueryAccessTokenList() {
         IPage<AccessToken> tokenPage = new Page<>();
-        tokenPage.setRecords(getList());
+        tokenPage.setRecords(Lists.newArrayList(getEntity()));
         User user = new User();
         user.setId(1);
         user.setUserType(UserType.ADMIN_USER);
@@ -109,10 +107,14 @@ public class AccessTokenServiceTest {
     public void testCreateToken() {
         User user = getLoginUser();
 
-        // Throw ServiceException when user has no permission
+        user.setUserType(UserType.GENERAL_USER);
+
+        // Throw ServiceException when general user creates token for another 
user
         assertThrowsServiceException(Status.USER_NO_OPERATION_PERM,
                 () -> accessTokenService.createToken(user, 2, getDate(), 
"AccessTokenServiceTest"));
+        Mockito.verify(accessTokenDao, 
Mockito.never()).insert(any(AccessToken.class));
 
+        user.setUserType(UserType.ADMIN_USER);
         user.setId(0);
 
         // Throw ServiceException when user is invalid
@@ -137,6 +139,16 @@ public class AccessTokenServiceTest {
                 () -> accessTokenService.createToken(user, 1, getDate(), 
"AccessTokenServiceTest"));
     }
 
+    @Test
+    public void testCreateTokenForOtherUserDeniedForGeneralUser() {
+        User user = getGeneralUser();
+        when(accessTokenDao.insert(any(AccessToken.class))).thenReturn(1);
+
+        assertThrowsServiceException(Status.USER_NO_OPERATION_PERM,
+                () -> accessTokenService.createToken(user, 2, getDate(), 
"AccessTokenServiceTest"));
+        Mockito.verify(accessTokenDao, 
Mockito.never()).insert(any(AccessToken.class));
+    }
+
     @Test
     public void testGenerateToken() {
         User user = new User();
@@ -184,16 +196,6 @@ public class AccessTokenServiceTest {
 
     @Test
     public void testUpdateToken() {
-        // operation perm check
-        
when(resourcePermissionCheckService.operationPermissionCheck(AuthorizationType.ACCESS_TOKEN,
 1,
-                ACCESS_TOKEN_UPDATE, baseServiceLogger)).thenReturn(false);
-        assertThrowsServiceException(Status.USER_NO_OPERATION_PERM,
-                () -> accessTokenService.updateToken(getLoginUser(), 1, 1, 
getDate(), "token"));
-
-        
when(resourcePermissionCheckService.operationPermissionCheck(AuthorizationType.ACCESS_TOKEN,
 1,
-                ACCESS_TOKEN_UPDATE, baseServiceLogger)).thenReturn(true);
-        
when(resourcePermissionCheckService.resourcePermissionCheck(AuthorizationType.ACCESS_TOKEN,
 null, 0,
-                baseServiceLogger)).thenReturn(true);
         // Given Token
         when(accessTokenDao.queryById(1)).thenReturn(getEntity());
         when(accessTokenDao.updateById(any())).thenReturn(true);
@@ -211,14 +213,10 @@ public class AccessTokenServiceTest {
         assertThrowsServiceException(Status.ACCESS_TOKEN_NOT_EXIST,
                 () -> accessTokenService.updateToken(getLoginUser(), 2, 
Integer.MAX_VALUE, getDate(), "token"));
 
-        // resource perm check
+        // old token owner check
         User user = getLoginUser();
         user.setUserType(UserType.GENERAL_USER);
         user.setId(2);
-        
when(resourcePermissionCheckService.operationPermissionCheck(AuthorizationType.ACCESS_TOKEN,
 2,
-                ACCESS_TOKEN_UPDATE, baseServiceLogger)).thenReturn(true);
-        
when(resourcePermissionCheckService.resourcePermissionCheck(AuthorizationType.ACCESS_TOKEN,
 null, 2,
-                baseServiceLogger)).thenReturn(true);
 
         assertThrowsServiceException(Status.USER_NO_OPERATION_PERM,
                 () -> accessTokenService.updateToken(user, 1, 
Integer.MAX_VALUE, getDate(), "token"));
@@ -229,6 +227,17 @@ public class AccessTokenServiceTest {
                 () -> accessTokenService.updateToken(getLoginUser(), 1, 
Integer.MAX_VALUE, getDate(), "token"));
     }
 
+    @Test
+    public void testUpdateTokenToOtherUserDeniedForGeneralUser() {
+        User user = getGeneralUser();
+        when(accessTokenDao.queryById(1)).thenReturn(getEntity());
+        
when(accessTokenDao.updateById(any(AccessToken.class))).thenReturn(true);
+
+        assertThrowsServiceException(Status.USER_NO_OPERATION_PERM,
+                () -> accessTokenService.updateToken(user, 1, 2, getDate(), 
"token"));
+        Mockito.verify(accessTokenDao, 
Mockito.never()).updateById(any(AccessToken.class));
+    }
+
     private User getLoginUser() {
         User loginUser = new User();
         loginUser.setId(1);
@@ -236,6 +245,13 @@ public class AccessTokenServiceTest {
         return loginUser;
     }
 
+    private User getGeneralUser() {
+        User loginUser = new User();
+        loginUser.setId(1);
+        loginUser.setUserType(UserType.GENERAL_USER);
+        return loginUser;
+    }
+
     /**
      * create entity
      */
@@ -249,16 +265,6 @@ public class AccessTokenServiceTest {
         return accessToken;
     }
 
-    /**
-     * entity list
-     */
-    private List<AccessToken> getList() {
-
-        List<AccessToken> list = new ArrayList<>();
-        list.add(getEntity());
-        return list;
-    }
-
     /**
      * get dateStr
      */

Reply via email to