diff --git a/backend/src/main/java/io/metersphere/commons/utils/SessionUtils.java b/backend/src/main/java/io/metersphere/commons/utils/SessionUtils.java index 58911d4430..3b2b6c45cc 100644 --- a/backend/src/main/java/io/metersphere/commons/utils/SessionUtils.java +++ b/backend/src/main/java/io/metersphere/commons/utils/SessionUtils.java @@ -24,6 +24,9 @@ import static io.metersphere.commons.constants.SessionConstants.ATTR_USER; public class SessionUtils { + private static final ThreadLocal projectId = new ThreadLocal<>(); + private static final ThreadLocal workspaceId = new ThreadLocal<>(); + public static String getUserId() { SessionUser user = getUser(); return user == null ? null : user.getId(); @@ -90,7 +93,24 @@ public class SessionUtils { SecurityUtils.getSubject().getSession().setAttribute(FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME, sessionUser.getId()); } + /** + * 权限验证时从 controller 参数列表中找到 workspaceId 传入 + */ + public static void setCurrentWorkspaceId(String workspaceId) { + SessionUtils.workspaceId.set(workspaceId); + } + + /** + * 权限验证时从 controller 参数列表中找到 projectId 传入 + */ + public static void setCurrentProjectId(String projectId) { + SessionUtils.projectId.set(projectId); + } + public static String getCurrentWorkspaceId() { + if (StringUtils.isNotEmpty(workspaceId.get())) { + return workspaceId.get(); + } try { HttpServletRequest request = ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getRequest(); LogUtil.info("WORKSPACE: {}", request.getHeader("WORKSPACE")); @@ -104,6 +124,9 @@ public class SessionUtils { } public static String getCurrentProjectId() { + if (StringUtils.isNotEmpty(projectId.get())) { + return projectId.get(); + } try { HttpServletRequest request = ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getRequest(); LogUtil.info("PROJECT: {}", request.getHeader("PROJECT")); @@ -168,4 +191,12 @@ public class SessionUtils { .map(UserGroupPermission::getPermissionId) .collect(Collectors.toSet()); } + + public static void clearCurrentWorkspaceId() { + workspaceId.remove(); + } + + public static void clearCurrentProjectId() { + projectId.remove(); + } } diff --git a/backend/src/main/java/io/metersphere/config/ShiroConfig.java b/backend/src/main/java/io/metersphere/config/ShiroConfig.java index 4f09901923..7e70025d81 100644 --- a/backend/src/main/java/io/metersphere/config/ShiroConfig.java +++ b/backend/src/main/java/io/metersphere/config/ShiroConfig.java @@ -4,17 +4,22 @@ package io.metersphere.config; import io.metersphere.commons.utils.ShiroUtils; import io.metersphere.security.ApiKeyFilter; import io.metersphere.security.CsrfFilter; +import io.metersphere.security.MsPermissionAnnotationMethodInterceptor; import io.metersphere.security.UserModularRealmAuthenticator; import io.metersphere.security.realm.LdapRealm; import io.metersphere.security.realm.LocalRealm; import org.apache.commons.lang3.StringUtils; +import org.apache.shiro.aop.AnnotationResolver; import org.apache.shiro.authc.pam.FirstSuccessfulStrategy; import org.apache.shiro.authc.pam.ModularRealmAuthenticator; +import org.apache.shiro.authz.aop.*; import org.apache.shiro.cache.CacheManager; import org.apache.shiro.cache.MemoryConstrainedCacheManager; import org.apache.shiro.realm.Realm; import org.apache.shiro.session.mgt.SessionManager; import org.apache.shiro.spring.LifecycleBeanPostProcessor; +import org.apache.shiro.spring.aop.SpringAnnotationResolver; +import org.apache.shiro.spring.security.interceptor.AopAllianceAnnotationsAuthorizingMethodInterceptor; import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor; import org.apache.shiro.spring.web.ShiroFilterFactoryBean; import org.apache.shiro.web.mgt.DefaultWebSecurityManager; @@ -133,6 +138,17 @@ public class ShiroConfig implements EnvironmentAware { public AuthorizationAttributeSourceAdvisor getAuthorizationAttributeSourceAdvisor(DefaultWebSecurityManager sessionManager) { AuthorizationAttributeSourceAdvisor aasa = new AuthorizationAttributeSourceAdvisor(); aasa.setSecurityManager(sessionManager); + AopAllianceAnnotationsAuthorizingMethodInterceptor advice = new AopAllianceAnnotationsAuthorizingMethodInterceptor(); + List interceptors = new ArrayList<>(5); + + AnnotationResolver resolver = new SpringAnnotationResolver(); + interceptors.add(new RoleAnnotationMethodInterceptor(resolver)); + interceptors.add(new MsPermissionAnnotationMethodInterceptor(resolver)); + interceptors.add(new AuthenticatedAnnotationMethodInterceptor(resolver)); + interceptors.add(new UserAnnotationMethodInterceptor(resolver)); + interceptors.add(new GuestAnnotationMethodInterceptor(resolver)); + advice.setMethodInterceptors(interceptors); + aasa.setAdvice(advice); return aasa; } diff --git a/backend/src/main/java/io/metersphere/controller/ProjectController.java b/backend/src/main/java/io/metersphere/controller/ProjectController.java index 13d726ceb6..8fc8341c65 100644 --- a/backend/src/main/java/io/metersphere/controller/ProjectController.java +++ b/backend/src/main/java/io/metersphere/controller/ProjectController.java @@ -15,11 +15,9 @@ import io.metersphere.controller.request.AddProjectRequest; import io.metersphere.controller.request.ProjectRequest; import io.metersphere.dto.ProjectDTO; import io.metersphere.dto.WorkspaceMemberDTO; -import io.metersphere.i18n.Translator; import io.metersphere.log.annotation.MsAuditLog; import io.metersphere.service.CheckPermissionService; import io.metersphere.service.ProjectService; -import org.apache.shiro.authz.UnauthorizedException; import org.apache.shiro.authz.annotation.Logical; import org.apache.shiro.authz.annotation.RequiresPermissions; import org.springframework.web.bind.annotation.*; @@ -50,10 +48,8 @@ public class ProjectController { /*jenkins项目列表*/ @GetMapping("/listAll/{workspaceId}") + @RequiresPermissions(PermissionConstants.WORKSPACE_PROJECT_MANAGER_READ) public List listAll(@PathVariable String workspaceId) { - if (!SessionUtils.hasPermission(workspaceId, null, PermissionConstants.WORKSPACE_PROJECT_MANAGER_READ)) { - throw new UnauthorizedException(Translator.get("check_owner_workspace")); - } ProjectRequest request = new ProjectRequest(); request.setWorkspaceId(workspaceId); return projectService.getProjectList(request); @@ -73,7 +69,6 @@ public class ProjectController { public Project getProject(@PathVariable String id) { return projectService.getProjectById(id); } - @GetMapping("/member/size/{id}") public long getProjectMemberSize(@PathVariable String id) { return projectService.getProjectMemberSize(id); @@ -90,10 +85,8 @@ public class ProjectController { } @PostMapping("/list/{goPage}/{pageSize}") + @RequiresPermissions(PermissionConstants.WORKSPACE_PROJECT_MANAGER_READ) public Pager> getProjectList(@PathVariable int goPage, @PathVariable int pageSize, @RequestBody ProjectRequest request) { - if (!SessionUtils.hasPermission(request.getWorkspaceId(), null, PermissionConstants.WORKSPACE_PROJECT_MANAGER_READ)) { - throw new UnauthorizedException(Translator.get("check_owner_workspace")); - } Page page = PageHelper.startPage(goPage, pageSize, true); return PageUtils.setPageInfo(page, projectService.getProjectList(request)); } @@ -154,12 +147,12 @@ public class ProjectController { } @GetMapping("/getOwnerProjects") - public List getOwnerProjects() { + public List getOwnerProjects() { return checkPermissionService.getOwnerProjects(); } @GetMapping("/genTcpMockPort/{id}") - public String genTcpMockPort(@PathVariable String id) { + public String genTcpMockPort(@PathVariable String id){ return projectService.genTcpMockPort(id); } diff --git a/backend/src/main/java/io/metersphere/controller/UserController.java b/backend/src/main/java/io/metersphere/controller/UserController.java index 09ff5f6575..aea11292b8 100644 --- a/backend/src/main/java/io/metersphere/controller/UserController.java +++ b/backend/src/main/java/io/metersphere/controller/UserController.java @@ -19,7 +19,6 @@ import io.metersphere.i18n.Translator; import io.metersphere.log.annotation.MsAuditLog; import io.metersphere.service.UserService; import org.apache.commons.lang3.StringUtils; -import org.apache.shiro.authz.UnauthorizedException; import org.apache.shiro.authz.annotation.Logical; import org.apache.shiro.authz.annotation.RequiresPermissions; import org.springframework.web.bind.annotation.*; @@ -148,10 +147,8 @@ public class UserController { * 获取工作空间成员用户 */ @PostMapping("/ws/member/list/{goPage}/{pageSize}") + @RequiresPermissions(PermissionConstants.WORKSPACE_USER_READ) public Pager> getMemberList(@PathVariable int goPage, @PathVariable int pageSize, @RequestBody QueryMemberRequest request) { - if (!SessionUtils.hasPermission(request.getWorkspaceId(), null, PermissionConstants.WORKSPACE_USER_READ)) { - throw new UnauthorizedException(Translator.get("check_owner_workspace")); - } Page page = PageHelper.startPage(goPage, pageSize, true); return PageUtils.setPageInfo(page, userService.getMemberList(request)); } @@ -179,10 +176,8 @@ public class UserController { * 获取工作空间成员用户 不分页 */ @PostMapping("/ws/member/list/all") + @RequiresPermissions(PermissionConstants.WORKSPACE_PROJECT_MANAGER_READ) public List getMemberList(@RequestBody QueryMemberRequest request) { - if (!SessionUtils.hasPermission(request.getWorkspaceId(), null, PermissionConstants.WORKSPACE_USER_READ)) { - throw new UnauthorizedException(Translator.get("check_owner_workspace")); - } return userService.getMemberList(request); } diff --git a/backend/src/main/java/io/metersphere/security/MsPermissionAnnotationMethodInterceptor.java b/backend/src/main/java/io/metersphere/security/MsPermissionAnnotationMethodInterceptor.java new file mode 100644 index 0000000000..a4882db462 --- /dev/null +++ b/backend/src/main/java/io/metersphere/security/MsPermissionAnnotationMethodInterceptor.java @@ -0,0 +1,79 @@ +package io.metersphere.security; + +import io.metersphere.commons.utils.SessionUtils; +import org.apache.commons.lang3.ArrayUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.reflect.MethodUtils; +import org.apache.shiro.aop.AnnotationResolver; +import org.apache.shiro.aop.MethodInvocation; +import org.apache.shiro.authz.AuthorizationException; +import org.apache.shiro.authz.aop.PermissionAnnotationMethodInterceptor; + +import java.lang.reflect.Field; +import java.lang.reflect.Parameter; + +public class MsPermissionAnnotationMethodInterceptor extends PermissionAnnotationMethodInterceptor { + + + public MsPermissionAnnotationMethodInterceptor(AnnotationResolver resolver) { + super(resolver); + } + + @Override + public void assertAuthorized(MethodInvocation mi) throws AuthorizationException { + String projectId = null; + String workspaceId = null; + Object[] arguments = mi.getArguments(); + if (ArrayUtils.isNotEmpty(arguments)) { + Parameter[] parameters = mi.getMethod().getParameters(); + for (int i = 0; i < arguments.length; i++) { + Object argument = arguments[i]; + if (argument instanceof String) { + if (StringUtils.equals(parameters[i].getName(), "projectId")) { + projectId = (String) argument; + } + if (StringUtils.equals(parameters[i].getName(), "workspaceId")) { + workspaceId = (String) argument; + } + } else { + try { + if (isExistField(argument, "projectId")) { + projectId = (String) MethodUtils.invokeMethod(argument, "getProjectId"); + } + if (isExistField(argument, "workspaceId")) { + workspaceId = (String) MethodUtils.invokeMethod(argument, "getWorkspaceId"); + } + } catch (Exception e) { + } + } + } + } + try { + SessionUtils.setCurrentWorkspaceId(workspaceId); + SessionUtils.setCurrentProjectId(projectId); + super.assertAuthorized(mi); + } finally { + SessionUtils.clearCurrentWorkspaceId(); + SessionUtils.clearCurrentProjectId(); + } + } + + + public static boolean isExistField(Object obj, String fieldName) { + if (obj == null || StringUtils.isEmpty(fieldName)) { + return false; + } + //获取这个类的所有属性 + Field[] fields = obj.getClass().getDeclaredFields(); + boolean flag = false; + //循环遍历所有的fields + for (Field field : fields) { + if (field.getName().equals(fieldName)) { + flag = true; + break; + } + } + + return flag; + } +}