Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision
  • dev
  • feat/auth
  • feat/certificate
  • feat/forwarding
  • feat/log
  • feat/routing
  • feat/ssl
  • main
8 results

Target

Select target project
  • aolda/proxy-manager-backend
1 result
Select Git revision
  • dev
  • feat/auth
  • feat/certificate
  • feat/forwarding
  • feat/log
  • feat/routing
  • feat/ssl
  • main
8 results
Show changes
Commits on Source (10)
Showing
with 284 additions and 137 deletions
......@@ -61,7 +61,7 @@ public class RoutingLogAspect {
+ "ip: " + routing.getInstanceIp() + "\n"
+ "port: " + routing.getInstancePort() + "\n"
+ (routing.getCertificate() != null ? ("certificateId: " + routing.getCertificate().getCertificateId() + "\n") : "")
+ "caching: " + routing.getCaching() + "\n";
+ "caching: " + routing.getCaching();
/* 로그 엔티티 저장 */
logRepository.save(Log.builder()
......@@ -97,7 +97,7 @@ public class RoutingLogAspect {
+ "ip: " + routing.getInstanceIp() + "\n"
+ "port: " + routing.getInstancePort() + "\n"
+ (routing.getCertificate() != null ? ("certificateId: " + routing.getCertificate().getCertificateId() + "\n") : "")
+ "caching: " + routing.getCaching() + "\n";
+ "caching: " + routing.getCaching();
/* 로그 엔티티 저장 */
logRepository.save(Log.builder()
......
package com.aolda.itda.config;
import com.aolda.itda.dto.auth.IdAndNameDTO;
import com.aolda.itda.exception.CustomException;
import com.aolda.itda.exception.ErrorCode;
import com.aolda.itda.service.AuthService;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import java.util.List;
import java.util.Map;
@RequiredArgsConstructor
@Component
@Slf4j
public class AuthInterceptor implements HandlerInterceptor {
private final AuthService authService;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String token = request.getHeader("X-Subject-Token");
/* 토큰 헤더 검증 */
if (token == null || token.isEmpty()) {
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 {
String role = authService.getBestRoleWithinProject(token, projectId).get("role");
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) {
throw new CustomException(ErrorCode.UNAUTHORIZED_USER, request.getRequestURI());
}
}
/* 프로젝트 리스트 조회 */
List<String> projects = authService.getProjectsWithUser(Map.of("id", userId, "token", token))
.stream().map(IdAndNameDTO::getId)
.toList();
request.setAttribute("projects", projects);
request.setAttribute("user", Map.of("id", userId, "token", token));
return true;
}
}
package com.aolda.itda.config;
import com.aolda.itda.dto.auth.IdAndNameDTO;
import com.aolda.itda.exception.CustomException;
import com.aolda.itda.exception.ErrorCode;
import com.aolda.itda.service.AuthService;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import java.io.IOException;
import java.util.List;
import java.util.Map;
@RequiredArgsConstructor
@Component
@Slf4j
public class AuthFilter extends OncePerRequestFilter {
private final AuthService authService;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
if (request.getRequestURI().contains("/api/auth")) {
filterChain.doFilter(request, response);
return;
}
String token = request.getHeader("X-Subject-Token");
// 토큰 헤더 검증
if (token == null || token.isEmpty()) {
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 {
authService.getBestRoleWithinProject(token, projectId).get("role");
if (!request.getMethod().equals("GET") && !authService.getBestRoleWithinProject(token, projectId).get("role").equals("admin")) {
throw new CustomException(ErrorCode.UNAUTHORIZED_USER, request.getRequestURI());
}
} catch (Exception e) {
throw new CustomException(ErrorCode.UNAUTHORIZED_USER, request.getRequestURI());
}
}
// 프로젝트 리스트 조회
List<String> projects;
if (authService.isAdmin(Map.of("id", userId, "token", token))) {
projects = authService.getAllProjects(token).stream().map(IdAndNameDTO::getId).toList();
} else {
projects = authService.getProjectsWithUser(Map.of("id", userId, "token", token)).stream().map(IdAndNameDTO::getId).toList();
}
request.setAttribute("projects", projects);
request.setAttribute("user", Map.of("id", userId, "token", token));
filterChain.doFilter(request, response);
}
}
\ No newline at end of file
package com.aolda.itda.config;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import org.springframework.web.util.ContentCachingRequestWrapper;
import java.io.IOException;
@Component
public class LoggingFilter extends OncePerRequestFilter {
private static final Logger logger = LoggerFactory.getLogger(LoggingFilter.class);
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
// Request Body를 읽을 수 있도록 래핑
ContentCachingRequestWrapper cachingRequest = new ContentCachingRequestWrapper(request);
System.out.println("필터 적용");
filterChain.doFilter(cachingRequest, response);
// 로그 기록
logRequest(cachingRequest);
System.out.println("왜 안돼ㅐ");
}
private void logRequest(ContentCachingRequestWrapper request) {
System.out.println("되는거 맞아?");
String ip = request.getRemoteAddr();
String method = request.getMethod();
String uri = request.getRequestURI();
String queryString = request.getQueryString();
String body = getRequestBody(request);
logger.info("IP: {}, Method: {}, URI: {}, Query Params: {}, Request Body: {}",
ip, method, uri, (queryString != null ? queryString : "None"),
(!body.isEmpty() ? body : "None"));
}
private String getRequestBody(ContentCachingRequestWrapper request) {
byte[] buf = request.getContentAsByteArray();
return (buf.length > 0) ? new String(buf) : "";
}
}
package com.aolda.itda.config;
import com.aolda.itda.exception.CustomException;
import com.aolda.itda.exception.ErrorCode;
import com.aolda.itda.service.AuthService;
import com.fasterxml.jackson.core.JsonProcessingException;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import org.springframework.web.util.ContentCachingRequestWrapper;
import java.io.IOException;
import java.util.Map;
@Component
@RequiredArgsConstructor
public class LoggingFilter extends OncePerRequestFilter {
private static final Logger logger = LoggerFactory.getLogger(LoggingFilter.class);
private final AuthService authService;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
// Request Body를 읽을 수 있도록 래핑
ContentCachingRequestWrapper cachingRequest = new ContentCachingRequestWrapper(request);
filterChain.doFilter(cachingRequest, response);
// 로그 기록
logRequest(cachingRequest);
}
private void logRequest(ContentCachingRequestWrapper request) throws JsonProcessingException {
String ip = request.getRemoteAddr();
String method = request.getMethod();
String uri = request.getRequestURI();
String queryString = request.getQueryString();
String body = getRequestBody(request);
Map<String, String> user = (Map<String, String>) request.getAttribute("user");
logger.info("IP: {}, Method: {}, URI: {}, Query Params: {}, User: {}, Request Body: {}",
ip, method, uri, (queryString != null ? queryString : "None"), (user != null ? user.get("id") : "None"),
(!body.isEmpty() ? body : "None"));
}
private String getRequestBody(ContentCachingRequestWrapper request) {
byte[] buf = request.getContentAsByteArray();
return (buf.length > 0) ? new String(buf) : "";
}
}
......@@ -3,17 +3,18 @@ package com.aolda.itda.config;
import com.querydsl.jpa.impl.JPAQueryFactory;
import jakarta.persistence.EntityManager;
import lombok.RequiredArgsConstructor;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
@RequiredArgsConstructor
public class WebConfig implements WebMvcConfigurer {
private final AuthInterceptor authInterceptor;
private final AuthFilter authFilter;
private final LoggingFilter loggingFilter;
@Override
public void addCorsMappings(CorsRegistry registry) { // 스프링단에서 cors 설정
......@@ -26,13 +27,23 @@ public class WebConfig implements WebMvcConfigurer {
;
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
String[] excludeAuth = {"/error", "/api/auth/*" };
registry.addInterceptor(authInterceptor)
.addPathPatterns("/**")
.excludePathPatterns(excludeAuth);
@Bean
public FilterRegistrationBean<AuthFilter> authFilterRegistration() {
FilterRegistrationBean<AuthFilter> registrationBean = new FilterRegistrationBean<>();
registrationBean.setFilter(authFilter);
registrationBean.setOrder(1); // AuthFilter의 순서를 1로 설정
registrationBean.addUrlPatterns("/*");
return registrationBean;
}
@Bean
public FilterRegistrationBean<LoggingFilter> loggingFilterRegistration() {
FilterRegistrationBean<LoggingFilter> registrationBean = new FilterRegistrationBean<>();
registrationBean.setFilter(loggingFilter);
registrationBean.setOrder(2); // LoggingFilter의 순서를 2로 설정
registrationBean.addUrlPatterns("/*");
return registrationBean;
}
@Bean
......
......@@ -30,8 +30,9 @@ public class ForwardingController {
}
@GetMapping("/forwardings")
public ResponseEntity<Object> lists(@RequestParam String projectId) {
return ResponseEntity.ok(forwardingService.getForwardings(projectId));
public ResponseEntity<Object> lists(@RequestParam String projectId,
@RequestParam(required = false) String query) {
return ResponseEntity.ok(forwardingService.getForwardingsWithSearch(projectId, query));
}
@PatchMapping("/forwarding")
......
package com.aolda.itda.controller.main;
import com.aolda.itda.service.main.MainService;
import com.fasterxml.jackson.core.JsonProcessingException;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
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 java.util.List;
import java.util.Map;
@RestController
@RequestMapping("/api")
@RequiredArgsConstructor
public class MainController {
private final MainService mainService;
@GetMapping("/projects")
public ResponseEntity<Object> projects(HttpServletRequest request) throws JsonProcessingException {
return ResponseEntity.ok(mainService.getAllProjects((Map<String, String>) request.getSession().getAttribute("user")));
}
@GetMapping("/main")
public ResponseEntity<Object> mainInfo(@RequestParam String projectId, HttpServletRequest request) {
return ResponseEntity.ok(mainService.getMainInfo(projectId, (List<String>) request.getAttribute("projects")));
}
}
......@@ -31,8 +31,9 @@ public class RoutingController {
}
@GetMapping("/routings")
public ResponseEntity<Object> lists(@RequestParam String projectId) {
return ResponseEntity.ok(routingService.getRoutings(projectId));
public ResponseEntity<Object> lists(@RequestParam String projectId,
@RequestParam(required = false) String query) {
return ResponseEntity.ok(routingService.getRoutingsWithSearch(projectId, query));
}
@PatchMapping("/routing")
......
package com.aolda.itda.dto.forwarding;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonInclude;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Pattern;
......@@ -40,6 +41,10 @@ public class ForwardingDTO {
@NotBlank(message = "name 값이 존재하지 않습니다")
private String name;
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Seoul")
private LocalDateTime createdAt;
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Seoul")
private LocalDateTime updatedAt;
}
......@@ -3,6 +3,7 @@ package com.aolda.itda.dto.log;
import com.aolda.itda.dto.auth.IdAndNameDTO;
import com.aolda.itda.entity.log.Action;
import com.aolda.itda.entity.log.ObjectType;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.querydsl.core.annotations.QueryProjection;
import lombok.AllArgsConstructor;
......@@ -22,7 +23,11 @@ public class LogDTO {
private Action action;
private ObjectType type;
private Long objectId;
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Seoul")
private String description;
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Seoul")
private LocalDateTime createdAt;
@QueryProjection
......
package com.aolda.itda.dto.main;
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
@JsonInclude(JsonInclude.Include.NON_NULL)
public class MainInfoDTO {
private Long routing;
private Long forwarding;
private Long certificate;
}
package com.aolda.itda.dto.routing;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonInclude;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
......@@ -28,8 +29,10 @@ public class RoutingDTO {
@NotNull
private Long certificateId;
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Seoul")
private LocalDateTime createdAt;
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Seoul")
private LocalDateTime updatedAt;
@NotNull
......
......@@ -17,12 +17,12 @@ import java.time.LocalDateTime;
public abstract class BaseTimeEntity {
@CreatedDate
@Column(updatable = false)
@Column(updatable = false, columnDefinition = "DATETIME")
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Seoul")
private LocalDateTime createdAt;
@LastModifiedDate
@Column(name = "updated_at")
@Column(name = "updated_at", columnDefinition = "DATETIME")
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Seoul")
private LocalDateTime updatedAt;
......
......@@ -27,10 +27,13 @@ public class Certificate extends BaseTimeEntity {
@JoinColumn(nullable = false, name = "user_id")
private User user;
@Column(length = 64)
private String projectId;
@Column(length = 64)
private String domain;
@Column(length = 64)
private String email;
private LocalDateTime expiredAt;
......@@ -40,6 +43,7 @@ public class Certificate extends BaseTimeEntity {
private Boolean isDeleted;
@Column(length = 256)
private String description;
public String formatDomain() {
......
package com.aolda.itda.entity.certificate;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonValue;
@JsonFormat(shape = JsonFormat.Shape.STRING)
public enum Challenge {
HTTP, DNS_CLOUDFLARE
HTTP, DNS_CLOUDFLARE;
@JsonValue
@Override
public String toString() {
return name().toLowerCase();
}
}
......@@ -20,18 +20,24 @@ public class Forwarding extends BaseTimeEntity {
@Column(nullable = false)
private Long forwardingId;
@Column(length = 64)
private String projectId;
@Column(length = 32)
private String serverIp;
@Column(length = 8)
private String serverPort;
@Column(length = 32)
private String instanceIp;
@Column(length = 8)
private String instancePort;
private Boolean isDeleted;
@Column(length = 256)
private String name;
public Forwarding(Forwarding forwarding) {
......
package com.aolda.itda.entity.log;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonValue;
@JsonFormat(shape = JsonFormat.Shape.STRING)
public enum Action {
CREATE, UPDATE, DELETE
CREATE, UPDATE, DELETE;
@JsonValue
@Override
public String toString() {
return name().toLowerCase();
}
}
......@@ -27,16 +27,20 @@ public class Log extends BaseTimeEntity {
@JoinColumn(name = "user_id", nullable = false)
private User user;
@Column(length = 64)
private String projectId;
@Enumerated(EnumType.STRING)
private ObjectType objectType;
@Column(length = 64)
private Long objectId;
@Enumerated(EnumType.STRING)
private Action action;
@Lob
@Column(length = 1024)
private String description;
public LogDTO toLogDTO() {
......
package com.aolda.itda.entity.log;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonValue;
@JsonFormat(shape = JsonFormat.Shape.STRING)
public enum ObjectType {
ROUTING, CERTIFICATE, FORWARDING
ROUTING, CERTIFICATE, FORWARDING;
@JsonValue
@Override
public String toString() {
return name().toLowerCase();
}
}
......@@ -28,18 +28,23 @@ public class Routing extends BaseTimeEntity {
@JoinColumn(name = "certificate_id")
private Certificate certificate;
@Column(length = 64)
private String projectId;
@Column(length = 64)
private String domain;
@Column(length = 32)
private String instanceIp;
@Column(length = 8)
private String instancePort;
private Boolean isDeleted;
private Boolean caching;
@Column(length = 256)
private String name;
public RoutingDTO toRoutingDTO() {
......
......@@ -2,6 +2,7 @@ package com.aolda.itda.repository.forwarding;
import com.aolda.itda.entity.forwarding.Forwarding;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import java.util.List;
import java.util.Optional;
......@@ -11,4 +12,7 @@ public interface ForwardingRepository extends JpaRepository<Forwarding, Long> {
Optional<Forwarding> findByForwardingIdAndIsDeleted(Long forwardingId, Boolean isDeleted);
Boolean existsByInstanceIpAndInstancePortAndIsDeleted(String instanceIp, String instancePort, Boolean isDeleted);
Boolean existsByServerPortAndIsDeleted(String serverPort, Boolean isDeleted);
@Query("SELECT f FROM Forwarding f WHERE f.projectId = ?1 AND f.isDeleted = ?3 AND (f.instanceIp LIKE %?2% OR f.serverPort LIKE %?2% OR f.name LIKE %?2%)")
List<Forwarding> findWithSearch(String projectId, String query, Boolean isDeleted);
}