Skip to content
Snippets Groups Projects
Commit 3f8e2f27 authored by 천 진강's avatar 천 진강
Browse files

feat: 프로젝트별 권한 검증 로직 추가

parent 585f5bb2
No related branches found
No related tags found
3 merge requests!15Feat/certificate,!12Feat/log,!11Feat/log 사용자 CUD 활동 로그 생성 및 조회
package com.aolda.itda.config; package com.aolda.itda.config;
import com.aolda.itda.dto.auth.ProjectIdAndNameDTO;
import com.aolda.itda.exception.CustomException; import com.aolda.itda.exception.CustomException;
import com.aolda.itda.exception.ErrorCode; import com.aolda.itda.exception.ErrorCode;
import com.aolda.itda.service.AuthService; import com.aolda.itda.service.AuthService;
import com.fasterxml.jackson.core.JsonProcessingException;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
...@@ -10,6 +12,10 @@ import lombok.extern.slf4j.Slf4j; ...@@ -10,6 +12,10 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.HandlerInterceptor;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@RequiredArgsConstructor @RequiredArgsConstructor
@Component @Component
@Slf4j @Slf4j
...@@ -20,18 +26,43 @@ public class AuthInterceptor implements HandlerInterceptor { ...@@ -20,18 +26,43 @@ public class AuthInterceptor implements HandlerInterceptor {
@Override @Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String token = request.getHeader("X-Subject-Token"); String token = request.getHeader("X-Subject-Token");
/* 토큰 헤더 검증 */
if (token == null || token.isEmpty()) { if (token == null || token.isEmpty()) {
throw new CustomException(ErrorCode.INVALID_TOKEN, request.getRequestURI()); throw new CustomException(ErrorCode.INVALID_TOKEN, request.getRequestURI());
} }
// 어드민과 일반 유저 구분 필요
/* 유효 토큰 검증 */
String userId = authService.validateTokenAndGetUserId(token);
if (userId == null) {
log.error("Token validation failed for URI {}: {}", request.getRequestURI(), request.getRemoteAddr());
throw new CustomException(ErrorCode.INVALID_TOKEN, request.getRequestURI());
}
/* 프로젝트 권한 검증 */
String projectId = request.getParameter("projectId");
if (projectId != null) {
try { try {
if (authService.validateTokenAndGetUserId(token) != null) { String role = authService.getBestRoleWithinProject(token, projectId).get("role");
return true; if (!role.equals("admin")) {
log.error("Unauthorized Token for URI {}: {}", request.getRequestURI(), request.getRemoteAddr());
throw new CustomException(ErrorCode.UNAUTHORIZED_USER, request.getRequestURI());
} }
} catch (Exception e) { } catch (Exception e) {
log.error("Token validation failed for URI {}: {}", request.getRequestURI(), e.getMessage(), e); throw new CustomException(ErrorCode.UNAUTHORIZED_USER, request.getRequestURI());
throw new CustomException(ErrorCode.INVALID_TOKEN, request.getRequestURI());
} }
throw new CustomException(ErrorCode.INVALID_TOKEN, request.getRequestURI());
}
/* 프로젝트 리스트 조회 */
List<String> projects = authService.getProjectsWithUser(Map.of("id", userId, "token", token))
.stream().map(ProjectIdAndNameDTO::getId)
.toList();
request.setAttribute("projects", projects);
return true;
} }
} }
...@@ -2,11 +2,14 @@ package com.aolda.itda.controller.forwarding; ...@@ -2,11 +2,14 @@ package com.aolda.itda.controller.forwarding;
import com.aolda.itda.dto.forwarding.ForwardingDTO; import com.aolda.itda.dto.forwarding.ForwardingDTO;
import com.aolda.itda.service.forwarding.ForwardingService; import com.aolda.itda.service.forwarding.ForwardingService;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.Valid; import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController @RestController
@RequestMapping("/api") @RequestMapping("/api")
@RequiredArgsConstructor @RequiredArgsConstructor
...@@ -22,8 +25,8 @@ public class ForwardingController { ...@@ -22,8 +25,8 @@ public class ForwardingController {
} }
@GetMapping("/forwarding") @GetMapping("/forwarding")
public ResponseEntity<Object> view(@RequestParam Long forwardingId) { public ResponseEntity<Object> view(@RequestParam Long forwardingId, HttpServletRequest request) {
return ResponseEntity.ok(forwardingService.getForwarding(forwardingId)); return ResponseEntity.ok(forwardingService.getForwarding(forwardingId, (List<String>) request.getAttribute("projects")));
} }
@GetMapping("/forwardings") @GetMapping("/forwardings")
...@@ -33,14 +36,16 @@ public class ForwardingController { ...@@ -33,14 +36,16 @@ public class ForwardingController {
@PatchMapping("/forwarding") @PatchMapping("/forwarding")
public ResponseEntity<Object> edit(@RequestParam Long forwardingId, public ResponseEntity<Object> edit(@RequestParam Long forwardingId,
@RequestBody ForwardingDTO dto) { @RequestBody ForwardingDTO dto,
forwardingService.editForwarding(forwardingId, dto); HttpServletRequest request) {
forwardingService.editForwarding(forwardingId, dto, (List<String>) request.getAttribute("projects") );
return ResponseEntity.ok().build(); return ResponseEntity.ok().build();
} }
@DeleteMapping("/forwarding") @DeleteMapping("/forwarding")
public ResponseEntity<Object> delete(@RequestParam Long forwardingId) { public ResponseEntity<Object> delete(@RequestParam Long forwardingId,
forwardingService.deleteForwarding(forwardingId); HttpServletRequest request) {
forwardingService.deleteForwarding(forwardingId, (List<String>) request.getAttribute("projects"));
return ResponseEntity.ok().build(); return ResponseEntity.ok().build();
} }
......
...@@ -3,10 +3,13 @@ package com.aolda.itda.controller.routing; ...@@ -3,10 +3,13 @@ package com.aolda.itda.controller.routing;
import com.aolda.itda.dto.forwarding.ForwardingDTO; import com.aolda.itda.dto.forwarding.ForwardingDTO;
import com.aolda.itda.dto.routing.RoutingDTO; import com.aolda.itda.dto.routing.RoutingDTO;
import com.aolda.itda.service.routing.RoutingService; import com.aolda.itda.service.routing.RoutingService;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController @RestController
@RequestMapping("/api") @RequestMapping("/api")
@RequiredArgsConstructor @RequiredArgsConstructor
...@@ -22,8 +25,9 @@ public class RoutingController { ...@@ -22,8 +25,9 @@ public class RoutingController {
} }
@GetMapping("/routing") @GetMapping("/routing")
public ResponseEntity<Object> view(@RequestParam Long routingId) { public ResponseEntity<Object> view(@RequestParam Long routingId,
return ResponseEntity.ok(routingService.getRouting(routingId)); HttpServletRequest request) {
return ResponseEntity.ok(routingService.getRouting(routingId, (List<String>) request.getAttribute("projects")));
} }
@GetMapping("/routings") @GetMapping("/routings")
...@@ -33,14 +37,16 @@ public class RoutingController { ...@@ -33,14 +37,16 @@ public class RoutingController {
@PatchMapping("/routing") @PatchMapping("/routing")
public ResponseEntity<Object> edit(@RequestParam Long routingId, public ResponseEntity<Object> edit(@RequestParam Long routingId,
@RequestBody RoutingDTO dto) { @RequestBody RoutingDTO dto,
routingService.editRouting(routingId, dto); HttpServletRequest request) {
routingService.editRouting(routingId, dto, (List<String>) request.getAttribute("projects"));
return ResponseEntity.ok().build(); return ResponseEntity.ok().build();
} }
@DeleteMapping("/routing") @DeleteMapping("/routing")
public ResponseEntity<Object> delete(@RequestParam Long routingId) { public ResponseEntity<Object> delete(@RequestParam Long routingId,
routingService.deleteRouting(routingId); HttpServletRequest request) {
routingService.deleteRouting(routingId, (List<String>) request.getAttribute("projects"));
return ResponseEntity.ok().build(); return ResponseEntity.ok().build();
} }
......
...@@ -10,6 +10,7 @@ public enum ErrorCode { ...@@ -10,6 +10,7 @@ public enum ErrorCode {
// User // User
INVALID_USER_INFO(HttpStatus.BAD_REQUEST, "잘못된 회원 정보입니다"), INVALID_USER_INFO(HttpStatus.BAD_REQUEST, "잘못된 회원 정보입니다"),
UNAUTHORIZED_USER(HttpStatus.BAD_REQUEST, "권한이 없는 사용자입니다"),
// Token // Token
INVALID_TOKEN(HttpStatus.BAD_REQUEST, "잘못된 토큰입니다"), INVALID_TOKEN(HttpStatus.BAD_REQUEST, "잘못된 토큰입니다"),
......
...@@ -239,7 +239,7 @@ public class AuthService { ...@@ -239,7 +239,7 @@ public class AuthService {
} }
// 특정 사용자의 참여 프로젝트 반환 // 특정 사용자의 참여 프로젝트 반환
private List<ProjectIdAndNameDTO> getProjectsWithUser(Map<String, String> user) throws JsonProcessingException { public List<ProjectIdAndNameDTO> getProjectsWithUser(Map<String, String> user) throws JsonProcessingException {
String userId = user.get("id"); String userId = user.get("id");
String token = user.get("token"); String token = user.get("token");
if (userId == null || token == null) { if (userId == null || token == null) {
...@@ -283,6 +283,12 @@ public class AuthService { ...@@ -283,6 +283,12 @@ public class AuthService {
} }
public void validateProjectAuth(List<String> projects, String projectId) {
if (!projects.contains(projectId)) {
throw new CustomException(ErrorCode.UNAUTHORIZED_USER);
}
}
private Boolean isAdmin(Map<String, String> user) throws JsonProcessingException { private Boolean isAdmin(Map<String, String> user) throws JsonProcessingException {
String url = keystone + "/role_assignments?user.id=" + user.get("id") + "&scope.system&include_names"; String url = keystone + "/role_assignments?user.id=" + user.get("id") + "&scope.system&include_names";
HttpHeaders headers = new HttpHeaders(); HttpHeaders headers = new HttpHeaders();
......
package com.aolda.itda.service.forwarding; package com.aolda.itda.service.forwarding;
import com.aolda.itda.dto.PageResp; import com.aolda.itda.dto.PageResp;
import com.aolda.itda.dto.auth.ProjectIdAndNameDTO;
import com.aolda.itda.dto.forwarding.ForwardingDTO; import com.aolda.itda.dto.forwarding.ForwardingDTO;
import com.aolda.itda.entity.forwarding.Forwarding; import com.aolda.itda.entity.forwarding.Forwarding;
import com.aolda.itda.exception.CustomException; import com.aolda.itda.exception.CustomException;
import com.aolda.itda.exception.ErrorCode; import com.aolda.itda.exception.ErrorCode;
import com.aolda.itda.repository.forwarding.ForwardingRepository; import com.aolda.itda.repository.forwarding.ForwardingRepository;
import com.aolda.itda.service.AuthService;
import com.aolda.itda.template.ForwardingTemplate; import com.aolda.itda.template.ForwardingTemplate;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.ConstraintViolation; import jakarta.validation.ConstraintViolation;
import jakarta.validation.Validation; import jakarta.validation.Validation;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
...@@ -30,6 +33,7 @@ import java.nio.file.Files; ...@@ -30,6 +33,7 @@ import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.nio.file.StandardCopyOption; import java.nio.file.StandardCopyOption;
import java.util.List;
import java.util.Map; import java.util.Map;
@Service @Service
...@@ -42,12 +46,17 @@ public class ForwardingService { ...@@ -42,12 +46,17 @@ public class ForwardingService {
private String serverBaseIp; private String serverBaseIp;
private final ForwardingTemplate forwardingTemplate; private final ForwardingTemplate forwardingTemplate;
private final ForwardingRepository forwardingRepository; private final ForwardingRepository forwardingRepository;
private final AuthService authService;
private final RestTemplate restTemplate = new RestTemplate(); private final RestTemplate restTemplate = new RestTemplate();
/* 포트포워딩 정보 조회 */ /* 포트포워딩 정보 조회 */
public ForwardingDTO getForwarding(Long forwardingId) { public ForwardingDTO getForwarding(Long forwardingId, List<String> projects) {
Forwarding forwarding = forwardingRepository.findByForwardingIdAndIsDeleted(forwardingId, false) Forwarding forwarding = forwardingRepository.findByForwardingIdAndIsDeleted(forwardingId, false)
.orElseThrow(() -> new CustomException(ErrorCode.NOT_FOUND_FORWARDING)); .orElseThrow(() -> new CustomException(ErrorCode.NOT_FOUND_FORWARDING));
/* 프로젝트 권한 검증 */
authService.validateProjectAuth(projects, forwarding.getProjectId());
return forwarding.toForwardingDTO(); return forwarding.toForwardingDTO();
} }
...@@ -158,10 +167,12 @@ public class ForwardingService { ...@@ -158,10 +167,12 @@ public class ForwardingService {
} }
/* 포트포워딩 정보 수정 */ /* 포트포워딩 정보 수정 */
public void editForwarding(Long forwardingId, ForwardingDTO dto) { public void editForwarding(Long forwardingId, ForwardingDTO dto, List<String> projects) {
Forwarding forwarding = forwardingRepository.findByForwardingIdAndIsDeleted(forwardingId, false) Forwarding forwarding = forwardingRepository.findByForwardingIdAndIsDeleted(forwardingId, false)
.orElseThrow(() -> new CustomException(ErrorCode.NOT_FOUND_FORWARDING)); .orElseThrow(() -> new CustomException(ErrorCode.NOT_FOUND_FORWARDING));
/* 프로젝트 권한 검증 */
authService.validateProjectAuth(projects, forwarding.getProjectId());
/* 중복 검증 */ /* 중복 검증 */
if (dto.getServerPort() != null && forwardingRepository.existsByServerPortAndIsDeleted(dto.getServerPort(), false)) { if (dto.getServerPort() != null && forwardingRepository.existsByServerPortAndIsDeleted(dto.getServerPort(), false)) {
...@@ -270,10 +281,13 @@ public class ForwardingService { ...@@ -270,10 +281,13 @@ public class ForwardingService {
} }
/* 포트포워딩 삭제 (소프트) */ /* 포트포워딩 삭제 (소프트) */
public void deleteForwarding(Long forwardingId) { public void deleteForwarding(Long forwardingId, List<String> projects) {
Forwarding forwarding = forwardingRepository.findByForwardingIdAndIsDeleted(forwardingId, false) Forwarding forwarding = forwardingRepository.findByForwardingIdAndIsDeleted(forwardingId, false)
.orElseThrow(() -> new CustomException(ErrorCode.NOT_FOUND_FORWARDING)); .orElseThrow(() -> new CustomException(ErrorCode.NOT_FOUND_FORWARDING));
/* 프로젝트 권한 검증 */
authService.validateProjectAuth(projects, forwarding.getProjectId());
/* 파일 삭제 */ /* 파일 삭제 */
String confPath = "/data/nginx/stream/" + forwarding.getForwardingId() + ".conf"; String confPath = "/data/nginx/stream/" + forwarding.getForwardingId() + ".conf";
String deletePath = confPath + ".deleted"; String deletePath = confPath + ".deleted";
......
...@@ -8,6 +8,7 @@ import com.aolda.itda.exception.CustomException; ...@@ -8,6 +8,7 @@ import com.aolda.itda.exception.CustomException;
import com.aolda.itda.exception.ErrorCode; import com.aolda.itda.exception.ErrorCode;
import com.aolda.itda.repository.certificate.CertificateRepository; import com.aolda.itda.repository.certificate.CertificateRepository;
import com.aolda.itda.repository.routing.RoutingRepository; import com.aolda.itda.repository.routing.RoutingRepository;
import com.aolda.itda.service.AuthService;
import com.aolda.itda.template.RoutingTemplate; import com.aolda.itda.template.RoutingTemplate;
import jakarta.validation.ConstraintViolation; import jakarta.validation.ConstraintViolation;
import jakarta.validation.Validation; import jakarta.validation.Validation;
...@@ -26,6 +27,7 @@ import java.nio.file.Files; ...@@ -26,6 +27,7 @@ import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.nio.file.StandardCopyOption; import java.nio.file.StandardCopyOption;
import java.util.List;
@Service @Service
@Transactional @Transactional
...@@ -35,14 +37,18 @@ public class RoutingService { ...@@ -35,14 +37,18 @@ public class RoutingService {
private final RoutingRepository routingRepository; private final RoutingRepository routingRepository;
private final CertificateRepository certificateRepository; private final CertificateRepository certificateRepository;
private final AuthService authService;
private final RoutingTemplate routingTemplate; private final RoutingTemplate routingTemplate;
private final RestTemplate restTemplate = new RestTemplate(); private final RestTemplate restTemplate = new RestTemplate();
/* Routing 조회 */ /* Routing 조회 */
public RoutingDTO getRouting(Long routingId) { public RoutingDTO getRouting(Long routingId, List<String> projects) {
// project id 확인 필요
Routing routing = routingRepository.findByRoutingIdAndIsDeleted(routingId, false) Routing routing = routingRepository.findByRoutingIdAndIsDeleted(routingId, false)
.orElseThrow(() -> new CustomException(ErrorCode.NOT_FOUND_ROUTING)); .orElseThrow(() -> new CustomException(ErrorCode.NOT_FOUND_ROUTING));
/* 프로젝트 권한 검증 */
authService.validateProjectAuth(projects, routing.getProjectId());
return routing.toRoutingDTO(); return routing.toRoutingDTO();
} }
...@@ -154,10 +160,13 @@ public class RoutingService { ...@@ -154,10 +160,13 @@ public class RoutingService {
} }
/* Routing 수정 */ /* Routing 수정 */
public void editRouting(Long routingId, RoutingDTO dto) { public void editRouting(Long routingId, RoutingDTO dto, List<String> projects) {
Routing routing = routingRepository.findByRoutingIdAndIsDeleted(routingId, false) Routing routing = routingRepository.findByRoutingIdAndIsDeleted(routingId, false)
.orElseThrow(() -> new CustomException(ErrorCode.NOT_FOUND_ROUTING)); .orElseThrow(() -> new CustomException(ErrorCode.NOT_FOUND_ROUTING));
/* 프로젝트 권한 검증 */
authService.validateProjectAuth(projects, routing.getProjectId());
/* 입력 DTO 검증 */ /* 입력 DTO 검증 */
validateDTO(dto); validateDTO(dto);
...@@ -253,10 +262,13 @@ public class RoutingService { ...@@ -253,10 +262,13 @@ public class RoutingService {
} }
/* Routing 삭제 */ /* Routing 삭제 */
public void deleteRouting(Long routingId) { public void deleteRouting(Long routingId, List<String> projects) {
Routing routing = routingRepository.findByRoutingIdAndIsDeleted(routingId, false) Routing routing = routingRepository.findByRoutingIdAndIsDeleted(routingId, false)
.orElseThrow(() -> new CustomException(ErrorCode.NOT_FOUND_ROUTING)); .orElseThrow(() -> new CustomException(ErrorCode.NOT_FOUND_ROUTING));
/* 프로젝트 권한 검증 */
authService.validateProjectAuth(projects, routing.getProjectId());
/* 파일 삭제 */ /* 파일 삭제 */
String confPath = "/data/nginx/proxy_host/" + routing.getRoutingId() + ".conf"; String confPath = "/data/nginx/proxy_host/" + routing.getRoutingId() + ".conf";
String deletePath = confPath + ".deleted"; String deletePath = confPath + ".deleted";
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment