diff --git a/src/main/java/com/easysoftware/adapter/query/CoAdminAdapter.java b/src/main/java/com/easysoftware/adapter/query/CoAdminAdapter.java new file mode 100644 index 0000000000000000000000000000000000000000..2b7aca56110431100844f14be4d6a041db3c3b2e --- /dev/null +++ b/src/main/java/com/easysoftware/adapter/query/CoAdminAdapter.java @@ -0,0 +1,89 @@ +/* Copyright (c) 2024 openEuler Community + EasySoftware is licensed under the Mulan PSL v2. + You can use this software according to the terms and conditions of the Mulan PSL v2. + You may obtain a copy of Mulan PSL v2 at: + http://license.coscl.org.cn/MulanPSL2 + THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + See the Mulan PSL v2 for more details. +*/ + +package com.easysoftware.adapter.query; + +import java.util.HashMap; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import com.easysoftware.common.account.UerPermissionDef; +import com.easysoftware.common.account.UserPermission; +import com.easysoftware.common.annotation.PreUserPermission; +import com.easysoftware.common.aop.RequestLimitRedis; +import com.easysoftware.common.entity.MessageCode; +import com.easysoftware.common.utils.ResultUtil; + +@RestController +@RequestMapping("/collaboration/admin") +public class CoAdminAdapter { + /** + * Logger for ApplicationVersionQueryAdapter. + */ + private static final Logger LOGGER = LoggerFactory.getLogger(CoAdminAdapter.class); + + /** + * Define current functional permissions. + */ + private static final String[] REQUIRE_PERMISSIONS = {UerPermissionDef.COLLABORATION_PERMISSION_ADMIN}; + + /** + * Autowired UserPermission for check user permission. + */ + @Autowired + private UserPermission userPermission; + + /** + * Endpoint to search for repos based on the provided search + * condition. + * + * @param repo The search condition for querying repos. + * @return ResponseEntity. + */ + @GetMapping() + @RequestLimitRedis() + @PreUserPermission(UerPermissionDef.COLLABORATION_PERMISSION_ADMIN) + public ResponseEntity queryRepos(@RequestParam(value = "repo") String repo) { + return ResultUtil.success(HttpStatus.OK, "success"); + } + + /** + * Check if the user has permission to access. + * + * @return ResponseEntity. + */ + @GetMapping("/permission") + @RequestLimitRedis() + public ResponseEntity checkPermission() { + HashMap result = new HashMap<>(); + try { + boolean permissionFlag = userPermission.checkUserPermission(REQUIRE_PERMISSIONS); + + if (permissionFlag) { + result.put("allow_access", Boolean.TRUE); + } else { + result.put("allow_access", Boolean.FALSE); + } + return ResultUtil.success(HttpStatus.OK, result); + } catch (Exception e) { + LOGGER.error("Authentication exception - {}", e.getMessage()); + return ResultUtil.fail(HttpStatus.UNAUTHORIZED, MessageCode.EC00020); + } + } +} diff --git a/src/main/java/com/easysoftware/adapter/query/CoMaintainerAdapter.java b/src/main/java/com/easysoftware/adapter/query/CoMaintainerAdapter.java new file mode 100644 index 0000000000000000000000000000000000000000..0e5287fe4485791e0b62f0d7407026f54b4cb248 --- /dev/null +++ b/src/main/java/com/easysoftware/adapter/query/CoMaintainerAdapter.java @@ -0,0 +1,85 @@ +/* Copyright (c) 2024 openEuler Community + EasySoftware is licensed under the Mulan PSL v2. + You can use this software according to the terms and conditions of the Mulan PSL v2. + You may obtain a copy of Mulan PSL v2 at: + http://license.coscl.org.cn/MulanPSL2 + THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + See the Mulan PSL v2 for more details. +*/ + +package com.easysoftware.adapter.query; + +import java.util.HashMap; +import java.util.HashSet; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import com.easysoftware.common.account.UserPermission; +import com.easysoftware.common.annotation.CoMaintainerPermission; +import com.easysoftware.common.aop.RequestLimitRedis; +import com.easysoftware.common.entity.MessageCode; +import com.easysoftware.common.utils.ResultUtil; + +@RestController +@RequestMapping("/collaboration/maintainer") +public class CoMaintainerAdapter { + + /** + * Logger for CoMaintainerAdapter. + */ + private static final Logger LOGGER = LoggerFactory.getLogger(CoMaintainerAdapter.class); + + /** + * Autowired UserPermission for check user permission. + */ + @Autowired + private UserPermission userPermission; + + /** + * Endpoint to search for repos based on the provided search + * condition. + * + * @param repo repo name. + * @return ResponseEntity. + */ + @GetMapping() + @RequestLimitRedis() + @CoMaintainerPermission() + public ResponseEntity queryRepos(@RequestParam(value = "repo") String repo) { + return ResultUtil.success(HttpStatus.OK, "success"); + } + + /** + * Check if the user has permission to access. + * + * @return ResponseEntity. + */ + @GetMapping("/permission") + @RequestLimitRedis() + public ResponseEntity checkPermission() { + HashMap result = new HashMap<>(); + try { + HashSet permissionRepos = userPermission.getUserRepoList(); + + if (permissionRepos.size() > 0) { + result.put("allow_access", Boolean.TRUE); + } else { + result.put("allow_access", Boolean.FALSE); + } + return ResultUtil.success(HttpStatus.OK, result); + } catch (Exception e) { + LOGGER.error("Authentication exception - {}", e.getMessage()); + return ResultUtil.fail(HttpStatus.UNAUTHORIZED, MessageCode.EC00020); + } + } +} diff --git a/src/main/java/com/easysoftware/common/account/UerPermissionDef.java b/src/main/java/com/easysoftware/common/account/UerPermissionDef.java index db81a11a8a5f97756d5a47090da036a1741f60d5..a0d3aecbf71d149c30066b913a3dad88e8019d28 100644 --- a/src/main/java/com/easysoftware/common/account/UerPermissionDef.java +++ b/src/main/java/com/easysoftware/common/account/UerPermissionDef.java @@ -6,6 +6,11 @@ public final class UerPermissionDef { */ public static final String USER_PERMISSION_READ = "easysoftwareread"; + /** + * user permission - easysoftwareadmin. + */ + public static final String COLLABORATION_PERMISSION_ADMIN = "easysoftwareadmin"; + private UerPermissionDef() { throw new RuntimeException("Not supported for instantiation"); } diff --git a/src/main/java/com/easysoftware/common/account/UserPermission.java b/src/main/java/com/easysoftware/common/account/UserPermission.java index 051f025866ac95da9b4069ec2a16096374e77860..ae0330e33bf767c85742f31419ea32ff39de3122 100644 --- a/src/main/java/com/easysoftware/common/account/UserPermission.java +++ b/src/main/java/com/easysoftware/common/account/UserPermission.java @@ -46,6 +46,18 @@ public class UserPermission { @Value("${oneid.permissionApi}") private String permissionApi; + /** + * Value injected for the user info API. + */ + @Value("${oneid.userInfoApi}") + private String userInfoApi; + + /** + * Value injected for the user repos API. + */ + @Value("${oneid.userReposApi}") + private String userReposApi; + /** * Value injected for the cookie token name. */ @@ -73,6 +85,76 @@ public class UserPermission { return Arrays.stream(requirePermissions).anyMatch(permissionSet::contains); } + /** + * Check if user has repo permission. + * @param repo repo required user permission. + * @return Permission matching results. + */ + public boolean checkUserRepoPermission(String repo) { + HashSet repoSet = this.getUserRepoList(); + if (Objects.isNull(repoSet) || repoSet.isEmpty()) { + return false; + } + + /* Check if user has repo permission */ + return repoSet.contains(repo); + } + + /** + * Get user login name by user token and manage token. + * @return login name. + */ + public String getUserLogin() { + String userToken = getUserToken(); + String manageToken = getManageToken(); + + // 使用userToken、manageToken查询用户信息 + Cookie cookie = getCookie(cookieTokenName); + String response = HttpClientUtil.getHttpClient(userInfoApi, manageToken, userToken, cookie.getValue()); + JsonNode resJson = ObjectMapperUtil.toJsonNode(response); + + String resCode = resJson.get("code").asText(); + if (!"200".equals(resCode)) { + LOGGER.error("query user login name failed"); + throw new HttpRequestException("query user login name failed"); + } + String loginName = null; + JsonNode identities = resJson.get("data").get("identities"); + for (JsonNode identity : identities) { + if (identity.has("identity") && identity.get("identity").asText().equalsIgnoreCase("gitee")) { + loginName = identity.get("login_name").asText(); + } + } + return loginName; + } + + /** + * Get user repos. + * @return Collection of repos. + */ + public HashSet getUserRepoList() { + String login = getUserLogin(); + if (login == null) { + throw new HttpRequestException("user login name is null"); + } + String response = HttpClientUtil.getHttpClient(String.format(userReposApi, login), null, null, null); + JsonNode resJson = ObjectMapperUtil.toJsonNode(response); + + String resCode = resJson.get("code").asText(); + + if (!"200".equals(resCode)) { + LOGGER.error("query user repos failed"); + throw new HttpRequestException("query user repos failed"); + } + HashSet repoSet = new HashSet<>(); + JsonNode repos = resJson.get("data"); + for (JsonNode repo : repos) { + repoSet.add(repo.asText()); + } + + return repoSet; + } + /** * Get user permission by user token and manage token. * @return Collection of user permissions. diff --git a/src/main/java/com/easysoftware/common/annotation/CoMaintainerPermission.java b/src/main/java/com/easysoftware/common/annotation/CoMaintainerPermission.java new file mode 100644 index 0000000000000000000000000000000000000000..51b0c624a7cc5ca1ead1a0d4314a3a7964b6afab --- /dev/null +++ b/src/main/java/com/easysoftware/common/annotation/CoMaintainerPermission.java @@ -0,0 +1,33 @@ +/* Copyright (c) 2024 openEuler Community + EasySoftware is licensed under the Mulan PSL v2. + You can use this software according to the terms and conditions of the Mulan PSL v2. + You may obtain a copy of Mulan PSL v2 at: + http://license.coscl.org.cn/MulanPSL2 + THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + See the Mulan PSL v2 for more details. +*/ + +package com.easysoftware.common.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.lang.annotation.Retention; +import java.lang.annotation.Inherited; +import java.lang.annotation.Documented; + +@Target({ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@Inherited +@Documented +public @interface CoMaintainerPermission { + + /** + * Specifies the number of allowed requests (default value: 5). + * + * @return Default to empty. + */ + String[] value() default {}; +} diff --git a/src/main/java/com/easysoftware/common/aop/CoMaintainerAspect.java b/src/main/java/com/easysoftware/common/aop/CoMaintainerAspect.java new file mode 100644 index 0000000000000000000000000000000000000000..e12d7c217f4c2e71cee1faea735c47478687ae06 --- /dev/null +++ b/src/main/java/com/easysoftware/common/aop/CoMaintainerAspect.java @@ -0,0 +1,75 @@ +/* Copyright (c) 2024 openEuler Community + EasySoftware is licensed under the Mulan PSL v2. + You can use this software according to the terms and conditions of the Mulan PSL v2. + You may obtain a copy of Mulan PSL v2 at: + http://license.coscl.org.cn/MulanPSL2 + THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + See the Mulan PSL v2 for more details. +*/ + +package com.easysoftware.common.aop; + +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.stereotype.Component; + +import com.easysoftware.common.account.UserPermission; +import com.easysoftware.common.entity.MessageCode; +import com.easysoftware.common.utils.ResultUtil; + +import jakarta.servlet.http.HttpServletRequest; + +@Aspect +@Component +public class CoMaintainerAspect { + /** + * Logger for CoMaintainerAspect. + */ + private static final Logger LOGGER = LoggerFactory.getLogger(CoMaintainerAspect.class); + + /** + * Autowired UserPermission for get user permission. + */ + @Autowired + private UserPermission userPermission; + + /** + * Autowired HttpServletRequest for handling HTTP request information. + */ + @Autowired + private HttpServletRequest request; + + /** + * Advice method called before a method with CoMaintainerPermission, and authentication. + * @param joinPoint The JoinPoint representing the intercepted method. + * @throws Throwable if an error occurs during method execution, or authentication fail. + * @return Business processing results. + */ + @Around("@annotation(com.easysoftware.common.annotation.CoMaintainerPermission)") + public Object around(final ProceedingJoinPoint joinPoint) throws Throwable { + try { + String repo = request.getParameter("repo"); + + /* Check if the user has repo permission */ + boolean permissionFlag = userPermission.checkUserRepoPermission(repo); + + if (!permissionFlag) { + LOGGER.error("Insufficient permissions"); + return ResultUtil.fail(HttpStatus.FORBIDDEN, MessageCode.EC00019); + } + } catch (Exception e) { + LOGGER.error("Authentication exception - {}", e.getMessage()); + return ResultUtil.fail(HttpStatus.UNAUTHORIZED, MessageCode.EC00020); + } + + /* 业务处理 */ + return joinPoint.proceed(); + } +}