【修复】"CVE-2024-42681" 子任务越权漏洞修复;

2.4.2
xuxueli 2 weeks ago
parent 5d71149c87
commit a2dc901131

@ -2368,6 +2368,8 @@ public void execute() {
### 7.35 版本 v2.4.2 Release Notes[规划中]
- 1、【升级】多个项目依赖升级至较新稳定版本涉及netty、groovy、gson、springboot、mybatis等
- 2、【修复】"CVE-2024-42681" 子任务越权漏洞修复;
- 2、[规划中]登陆态Token声称逻辑优化混淆登陆时间属性降低token泄漏风险。
### TODO LIST

@ -1,7 +1,7 @@
package com.xxl.job.admin.controller;
import com.xxl.job.admin.controller.annotation.PermissionLimit;
import com.xxl.job.admin.service.LoginService;
import com.xxl.job.admin.service.impl.LoginService;
import com.xxl.job.admin.service.XxlJobService;
import com.xxl.job.core.biz.model.ReturnT;
import org.springframework.beans.propertyeditors.CustomDateEditor;

@ -1,5 +1,6 @@
package com.xxl.job.admin.controller;
import com.xxl.job.admin.controller.interceptor.PermissionInterceptor;
import com.xxl.job.admin.core.model.XxlJobInfo;
import com.xxl.job.admin.core.model.XxlJobLogGlue;
import com.xxl.job.admin.core.util.I18nUtil;
@ -43,7 +44,7 @@ public class JobCodeController {
}
// valid permission
JobInfoController.validPermission(request, jobInfo.getJobGroup());
PermissionInterceptor.validJobGroupPermission(request, jobInfo.getJobGroup());
// Glue类型-字典
model.addAttribute("GlueTypeEnum", GlueTypeEnum.values());

@ -1,5 +1,6 @@
package com.xxl.job.admin.controller;
import com.xxl.job.admin.controller.interceptor.PermissionInterceptor;
import com.xxl.job.admin.core.exception.XxlJobException;
import com.xxl.job.admin.core.model.XxlJobGroup;
import com.xxl.job.admin.core.model.XxlJobInfo;
@ -10,7 +11,6 @@ import com.xxl.job.admin.core.scheduler.ScheduleTypeEnum;
import com.xxl.job.admin.core.thread.JobScheduleHelper;
import com.xxl.job.admin.core.util.I18nUtil;
import com.xxl.job.admin.dao.XxlJobGroupDao;
import com.xxl.job.admin.service.LoginService;
import com.xxl.job.admin.service.XxlJobService;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.enums.ExecutorBlockStrategyEnum;
@ -56,7 +56,7 @@ public class JobInfoController {
List<XxlJobGroup> jobGroupList_all = xxlJobGroupDao.findAll();
// filter group
List<XxlJobGroup> jobGroupList = filterJobGroupByRole(request, jobGroupList_all);
List<XxlJobGroup> jobGroupList = PermissionInterceptor.filterJobGroupByRole(request, jobGroupList_all);
if (jobGroupList==null || jobGroupList.size()==0) {
throw new XxlJobException(I18nUtil.getString("jobgroup_empty"));
}
@ -67,33 +67,6 @@ public class JobInfoController {
return "jobinfo/jobinfo.index";
}
public static List<XxlJobGroup> filterJobGroupByRole(HttpServletRequest request, List<XxlJobGroup> jobGroupList_all){
List<XxlJobGroup> jobGroupList = new ArrayList<>();
if (jobGroupList_all!=null && jobGroupList_all.size()>0) {
XxlJobUser loginUser = (XxlJobUser) request.getAttribute(LoginService.LOGIN_IDENTITY_KEY);
if (loginUser.getRole() == 1) {
jobGroupList = jobGroupList_all;
} else {
List<String> groupIdStrs = new ArrayList<>();
if (loginUser.getPermission()!=null && loginUser.getPermission().trim().length()>0) {
groupIdStrs = Arrays.asList(loginUser.getPermission().trim().split(","));
}
for (XxlJobGroup groupItem:jobGroupList_all) {
if (groupIdStrs.contains(String.valueOf(groupItem.getId()))) {
jobGroupList.add(groupItem);
}
}
}
}
return jobGroupList;
}
public static void validPermission(HttpServletRequest request, int jobGroup) {
XxlJobUser loginUser = (XxlJobUser) request.getAttribute(LoginService.LOGIN_IDENTITY_KEY);
if (!loginUser.validPermission(jobGroup)) {
throw new RuntimeException(I18nUtil.getString("system_permission_limit") + "[username="+ loginUser.getUsername() +"]");
}
}
@RequestMapping("/pageList")
@ResponseBody
public Map<String, Object> pageList(@RequestParam(required = false, defaultValue = "0") int start,
@ -105,14 +78,16 @@ public class JobInfoController {
@RequestMapping("/add")
@ResponseBody
public ReturnT<String> add(XxlJobInfo jobInfo) {
return xxlJobService.add(jobInfo);
public ReturnT<String> add(HttpServletRequest request, XxlJobInfo jobInfo) {
XxlJobUser loginUser = PermissionInterceptor.getLoginUser(request);
return xxlJobService.add(jobInfo, loginUser);
}
@RequestMapping("/update")
@ResponseBody
public ReturnT<String> update(XxlJobInfo jobInfo) {
return xxlJobService.update(jobInfo);
public ReturnT<String> update(HttpServletRequest request, XxlJobInfo jobInfo) {
XxlJobUser loginUser = PermissionInterceptor.getLoginUser(request);
return xxlJobService.update(jobInfo, loginUser);
}
@RequestMapping("/remove")
@ -137,7 +112,7 @@ public class JobInfoController {
@ResponseBody
public ReturnT<String> triggerJob(HttpServletRequest request, int id, String executorParam, String addressList) {
// login user
XxlJobUser loginUser = (XxlJobUser) request.getAttribute(LoginService.LOGIN_IDENTITY_KEY);
XxlJobUser loginUser = PermissionInterceptor.getLoginUser(request);
// trigger
return xxlJobService.trigger(loginUser, id, executorParam, addressList);
}

@ -1,5 +1,6 @@
package com.xxl.job.admin.controller;
import com.xxl.job.admin.controller.interceptor.PermissionInterceptor;
import com.xxl.job.admin.core.complete.XxlJobCompleter;
import com.xxl.job.admin.core.exception.XxlJobException;
import com.xxl.job.admin.core.model.XxlJobGroup;
@ -56,7 +57,7 @@ public class JobLogController {
List<XxlJobGroup> jobGroupList_all = xxlJobGroupDao.findAll();
// filter group
List<XxlJobGroup> jobGroupList = JobInfoController.filterJobGroupByRole(request, jobGroupList_all);
List<XxlJobGroup> jobGroupList = PermissionInterceptor.filterJobGroupByRole(request, jobGroupList_all);
if (jobGroupList==null || jobGroupList.size()==0) {
throw new XxlJobException(I18nUtil.getString("jobgroup_empty"));
}
@ -73,7 +74,7 @@ public class JobLogController {
model.addAttribute("jobInfo", jobInfo);
// valid permission
JobInfoController.validPermission(request, jobInfo.getJobGroup());
PermissionInterceptor.validJobGroupPermission(request, jobInfo.getJobGroup());
}
return "joblog/joblog.index";
@ -94,7 +95,7 @@ public class JobLogController {
int jobGroup, int jobId, int logStatus, String filterTime) {
// valid permission
JobInfoController.validPermission(request, jobGroup); // 仅管理员支持查询全部;普通用户仅支持查询有权限的 jobGroup
PermissionInterceptor.validJobGroupPermission(request, jobGroup); // 仅管理员支持查询全部;普通用户仅支持查询有权限的 jobGroup
// parse param
Date triggerTimeStart = null;

@ -1,12 +1,12 @@
package com.xxl.job.admin.controller;
import com.xxl.job.admin.controller.annotation.PermissionLimit;
import com.xxl.job.admin.controller.interceptor.PermissionInterceptor;
import com.xxl.job.admin.core.model.XxlJobGroup;
import com.xxl.job.admin.core.model.XxlJobUser;
import com.xxl.job.admin.core.util.I18nUtil;
import com.xxl.job.admin.dao.XxlJobGroupDao;
import com.xxl.job.admin.dao.XxlJobUserDao;
import com.xxl.job.admin.service.LoginService;
import com.xxl.job.core.biz.model.ReturnT;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
@ -112,7 +112,7 @@ public class UserController {
public ReturnT<String> update(HttpServletRequest request, XxlJobUser xxlJobUser) {
// avoid opt login seft
XxlJobUser loginUser = (XxlJobUser) request.getAttribute(LoginService.LOGIN_IDENTITY_KEY);
XxlJobUser loginUser = PermissionInterceptor.getLoginUser(request);
if (loginUser.getUsername().equals(xxlJobUser.getUsername())) {
return new ReturnT<String>(ReturnT.FAIL.getCode(), I18nUtil.getString("user_update_loginuser_limit"));
}
@ -140,7 +140,7 @@ public class UserController {
public ReturnT<String> remove(HttpServletRequest request, int id) {
// avoid opt login seft
XxlJobUser loginUser = (XxlJobUser) request.getAttribute(LoginService.LOGIN_IDENTITY_KEY);
XxlJobUser loginUser = PermissionInterceptor.getLoginUser(request);
if (loginUser.getId() == id) {
return new ReturnT<String>(ReturnT.FAIL.getCode(), I18nUtil.getString("user_update_loginuser_limit"));
}
@ -166,7 +166,7 @@ public class UserController {
String md5Password = DigestUtils.md5DigestAsHex(password.getBytes());
// update pwd
XxlJobUser loginUser = (XxlJobUser) request.getAttribute(LoginService.LOGIN_IDENTITY_KEY);
XxlJobUser loginUser = PermissionInterceptor.getLoginUser(request);
// do write
XxlJobUser existUser = xxlJobUserDao.loadByUserName(loginUser.getUsername());

@ -1,9 +1,10 @@
package com.xxl.job.admin.controller.interceptor;
import com.xxl.job.admin.controller.annotation.PermissionLimit;
import com.xxl.job.admin.core.model.XxlJobGroup;
import com.xxl.job.admin.core.model.XxlJobUser;
import com.xxl.job.admin.core.util.I18nUtil;
import com.xxl.job.admin.service.LoginService;
import com.xxl.job.admin.service.impl.LoginService;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.AsyncHandlerInterceptor;
@ -11,6 +12,9 @@ import org.springframework.web.servlet.AsyncHandlerInterceptor;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
*
@ -50,10 +54,66 @@ public class PermissionInterceptor implements AsyncHandlerInterceptor {
if (needAdminuser && loginUser.getRole()!=1) {
throw new RuntimeException(I18nUtil.getString("system_permission_limit"));
}
request.setAttribute(LoginService.LOGIN_IDENTITY_KEY, loginUser);
request.setAttribute(LoginService.LOGIN_IDENTITY_KEY, loginUser); // set loginUser, with request
}
return true; // proceed with the next interceptor
}
// -------------------- permission tool --------------------
/**
* get loginUser
*
* @param request
* @return
*/
public static XxlJobUser getLoginUser(HttpServletRequest request){
XxlJobUser loginUser = (XxlJobUser) request.getAttribute(LoginService.LOGIN_IDENTITY_KEY); // get loginUser, with request
return loginUser;
}
/**
* valid permission by JobGroup
*
* @param request
* @param jobGroup
*/
public static void validJobGroupPermission(HttpServletRequest request, int jobGroup) {
XxlJobUser loginUser = getLoginUser(request);
if (!loginUser.validPermission(jobGroup)) {
throw new RuntimeException(I18nUtil.getString("system_permission_limit") + "[username="+ loginUser.getUsername() +"]");
}
}
/**
* filter XxlJobGroup by role
*
* @param request
* @param jobGroupList_all
* @return
*/
public static List<XxlJobGroup> filterJobGroupByRole(HttpServletRequest request, List<XxlJobGroup> jobGroupList_all){
List<XxlJobGroup> jobGroupList = new ArrayList<>();
if (jobGroupList_all!=null && jobGroupList_all.size()>0) {
XxlJobUser loginUser = PermissionInterceptor.getLoginUser(request);
if (loginUser.getRole() == 1) {
jobGroupList = jobGroupList_all;
} else {
List<String> groupIdStrs = new ArrayList<>();
if (loginUser.getPermission()!=null && loginUser.getPermission().trim().length()>0) {
groupIdStrs = Arrays.asList(loginUser.getPermission().trim().split(","));
}
for (XxlJobGroup groupItem:jobGroupList_all) {
if (groupIdStrs.contains(String.valueOf(groupItem.getId()))) {
jobGroupList.add(groupItem);
}
}
}
}
return jobGroupList;
}
}

@ -34,7 +34,7 @@ public interface XxlJobService {
* @param jobInfo
* @return
*/
public ReturnT<String> add(XxlJobInfo jobInfo);
public ReturnT<String> add(XxlJobInfo jobInfo, XxlJobUser loginUser);
/**
* update job
@ -42,7 +42,7 @@ public interface XxlJobService {
* @param jobInfo
* @return
*/
public ReturnT<String> update(XxlJobInfo jobInfo);
public ReturnT<String> update(XxlJobInfo jobInfo, XxlJobUser loginUser);
/**
* remove job

@ -1,4 +1,4 @@
package com.xxl.job.admin.service;
package com.xxl.job.admin.service.impl;
import com.xxl.job.admin.core.model.XxlJobUser;
import com.xxl.job.admin.core.util.CookieUtil;
@ -6,7 +6,7 @@ import com.xxl.job.admin.core.util.I18nUtil;
import com.xxl.job.admin.core.util.JacksonUtil;
import com.xxl.job.admin.dao.XxlJobUserDao;
import com.xxl.job.core.biz.model.ReturnT;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;
import javax.annotation.Resource;
@ -17,7 +17,7 @@ import java.math.BigInteger;
/**
* @author xuxueli 2019-05-04 22:13:264
*/
@Configuration
@Service
public class LoginService {
public static final String LOGIN_IDENTITY_KEY = "XXL_JOB_LOGIN_IDENTITY";
@ -26,6 +26,8 @@ public class LoginService {
private XxlJobUserDao xxlJobUserDao;
// ---------------------- token tool ----------------------
private String makeToken(XxlJobUser xxlJobUser){
String tokenJson = JacksonUtil.writeValueAsString(xxlJobUser);
String tokenHex = new BigInteger(tokenJson.getBytes()).toString(16);
@ -41,6 +43,8 @@ public class LoginService {
}
// ---------------------- login tool, with cookie and db ----------------------
public ReturnT<String> login(HttpServletRequest request, HttpServletResponse response, String username, String password, boolean ifRemember){
// param

@ -61,7 +61,7 @@ public class XxlJobServiceImpl implements XxlJobService {
}
@Override
public ReturnT<String> add(XxlJobInfo jobInfo) {
public ReturnT<String> add(XxlJobInfo jobInfo, XxlJobUser loginUser) {
// valid base
XxlJobGroup group = xxlJobGroupDao.load(jobInfo.getJobGroup());
@ -131,6 +131,10 @@ public class XxlJobServiceImpl implements XxlJobService {
return new ReturnT<String>(ReturnT.FAIL_CODE,
MessageFormat.format((I18nUtil.getString("jobinfo_field_childJobId")+"({0})"+I18nUtil.getString("system_not_found")), childJobIdItem));
}
if (!loginUser.validPermission(childJobInfo.getJobGroup())) {
return new ReturnT<String>(ReturnT.FAIL_CODE,
MessageFormat.format((I18nUtil.getString("jobinfo_field_childJobId")+"({0})"+I18nUtil.getString("system_permission_limit")), childJobIdItem));
}
} else {
return new ReturnT<String>(ReturnT.FAIL_CODE,
MessageFormat.format((I18nUtil.getString("jobinfo_field_childJobId")+"({0})"+I18nUtil.getString("system_unvalid")), childJobIdItem));
@ -169,7 +173,7 @@ public class XxlJobServiceImpl implements XxlJobService {
}
@Override
public ReturnT<String> update(XxlJobInfo jobInfo) {
public ReturnT<String> update(XxlJobInfo jobInfo, XxlJobUser loginUser) {
// valid base
if (jobInfo.getJobDesc()==null || jobInfo.getJobDesc().trim().length()==0) {
@ -223,6 +227,10 @@ public class XxlJobServiceImpl implements XxlJobService {
return new ReturnT<String>(ReturnT.FAIL_CODE,
MessageFormat.format((I18nUtil.getString("jobinfo_field_childJobId")+"({0})"+I18nUtil.getString("system_not_found")), childJobIdItem));
}
if (!loginUser.validPermission(childJobInfo.getJobGroup())) {
return new ReturnT<String>(ReturnT.FAIL_CODE,
MessageFormat.format((I18nUtil.getString("jobinfo_field_childJobId")+"({0})"+I18nUtil.getString("system_permission_limit")), childJobIdItem));
}
} else {
return new ReturnT<String>(ReturnT.FAIL_CODE,
MessageFormat.format((I18nUtil.getString("jobinfo_field_childJobId")+"({0})"+I18nUtil.getString("system_unvalid")), childJobIdItem));

@ -1,6 +1,6 @@
package com.xxl.job.admin.controller;
import com.xxl.job.admin.service.LoginService;
import com.xxl.job.admin.service.impl.LoginService;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.slf4j.Logger;

Loading…
Cancel
Save