Skip to content

Commit 150527d

Browse files
authored
Merge pull request #300 from DevKor-github/codexd/request-validation-hardening
[codex] Add request validation hardening
2 parents e1c3885 + 587946a commit 150527d

51 files changed

Lines changed: 1042 additions & 77 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

ontime-back/build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ dependencies {
2929
implementation 'org.springframework.boot:spring-boot-starter-security'
3030
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
3131
implementation 'org.springframework.boot:spring-boot-starter-web'
32+
implementation 'org.springframework.boot:spring-boot-starter-validation'
3233
implementation 'org.thymeleaf.extras:thymeleaf-extras-springsecurity6'
3334
implementation 'org.springframework.boot:spring-boot-starter-actuator'
3435
compileOnly 'org.projectlombok:lombok'

ontime-back/src/main/java/devkor/ontime_back/config/SecurityConfig.java

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import devkor.ontime_back.global.oauth.google.GoogleLoginFilter;
1818
import devkor.ontime_back.repository.UserAlarmSettingRepository;
1919
import devkor.ontime_back.repository.UserRepository;
20+
import jakarta.validation.Validator;
2021
import lombok.RequiredArgsConstructor;
2122
import org.springframework.beans.factory.annotation.Value;
2223
import org.springframework.context.annotation.Bean;
@@ -54,6 +55,7 @@ public class SecurityConfig {
5455
private final UserRepository userRepository;
5556
private final UserAlarmSettingRepository userAlarmSettingRepository;
5657
private final ObjectMapper objectMapper;
58+
private final Validator validator;
5759
private final AppleLoginService appleLoginService;
5860
private final GoogleLoginService googleLoginService;
5961

@@ -77,11 +79,11 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
7779
.requestMatchers("/health").permitAll() // 로드밸런서 연결 확인용 url
7880
.anyRequest().authenticated()
7981
)
80-
.addFilterBefore(new KakaoLoginFilter("/oauth2/kakao/login", jwtTokenProvider, userRepository, userAlarmSettingRepository),
82+
.addFilterBefore(new KakaoLoginFilter("/oauth2/kakao/login", objectMapper, validator, jwtTokenProvider, userRepository, userAlarmSettingRepository),
8183
UsernamePasswordAuthenticationFilter.class)
82-
.addFilterBefore(new GoogleLoginFilter("/oauth2/google/login", googleLoginService, userRepository),
84+
.addFilterBefore(new GoogleLoginFilter("/oauth2/google/login", objectMapper, validator, googleLoginService, userRepository),
8385
UsernamePasswordAuthenticationFilter.class)
84-
.addFilterBefore(new AppleLoginFilter("/oauth2/apple/login", appleLoginService, userRepository),
86+
.addFilterBefore(new AppleLoginFilter("/oauth2/apple/login", objectMapper, validator, appleLoginService, userRepository),
8587
UsernamePasswordAuthenticationFilter.class)
8688
.addFilterAfter(customJsonUsernamePasswordAuthenticationFilter(), LogoutFilter.class)
8789
.addFilterBefore(jwtAuthenticationProcessingFilter(), CustomJsonUsernamePasswordAuthenticationFilter.class);
@@ -121,7 +123,7 @@ public LoginFailureHandler loginFailureHandler() {
121123
@Bean
122124
public CustomJsonUsernamePasswordAuthenticationFilter customJsonUsernamePasswordAuthenticationFilter() {
123125
CustomJsonUsernamePasswordAuthenticationFilter customJsonUsernamePasswordLoginFilter
124-
= new CustomJsonUsernamePasswordAuthenticationFilter(objectMapper);
126+
= new CustomJsonUsernamePasswordAuthenticationFilter(objectMapper, validator);
125127
customJsonUsernamePasswordLoginFilter.setAuthenticationManager(authenticationManager());
126128
customJsonUsernamePasswordLoginFilter.setAuthenticationSuccessHandler(loginSuccessHandler());
127129
customJsonUsernamePasswordLoginFilter.setAuthenticationFailureHandler(loginFailureHandler());

ontime-back/src/main/java/devkor/ontime_back/controller/AlarmController.java

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,12 @@
1010
import io.swagger.v3.oas.annotations.responses.ApiResponse;
1111
import io.swagger.v3.oas.annotations.responses.ApiResponses;
1212
import jakarta.servlet.http.HttpServletRequest;
13+
import jakarta.validation.Valid;
1314
import lombok.RequiredArgsConstructor;
1415
import org.springframework.http.HttpStatus;
1516
import org.springframework.http.ResponseEntity;
1617
import org.springframework.web.bind.annotation.*;
1718

18-
import java.util.Map;
19-
2019
@RestController
2120
@RequiredArgsConstructor
2221
public class AlarmController {
@@ -60,7 +59,7 @@ public ResponseEntity<ApiResponseForm<AlarmSettingsResponseDto>> getAlarmSetting
6059
@PatchMapping("/users/me/alarm-settings")
6160
public ResponseEntity<ApiResponseForm<AlarmSettingsResponseDto>> patchAlarmSettings(
6261
HttpServletRequest request,
63-
@RequestBody Map<String, Object> requestBody) {
62+
@Valid @RequestBody AlarmSettingsPatchDto requestBody) {
6463
Long userId = userAuthService.getUserIdFromToken(request);
6564
return ResponseEntity.status(HttpStatus.OK)
6665
.body(ApiResponseForm.success(alarmService.patchAlarmSettings(userId, requestBody)));
@@ -87,7 +86,7 @@ public ResponseEntity<ApiResponseForm<AlarmSettingsResponseDto>> patchAlarmSetti
8786
@PutMapping("/users/me/devices/current")
8887
public ResponseEntity<ApiResponseForm<AlarmDeviceCurrentResponseDto>> registerCurrentDevice(
8988
HttpServletRequest request,
90-
@RequestBody AlarmDeviceCurrentRequestDto requestDto) {
89+
@Valid @RequestBody AlarmDeviceCurrentRequestDto requestDto) {
9190
Long userId = userAuthService.getUserIdFromToken(request);
9291
return ResponseEntity.status(HttpStatus.OK)
9392
.body(ApiResponseForm.success(alarmService.registerCurrentDevice(
@@ -117,7 +116,7 @@ public ResponseEntity<ApiResponseForm<AlarmDeviceCurrentResponseDto>> registerCu
117116
@DeleteMapping("/users/me/devices/current")
118117
public ResponseEntity<ApiResponseForm<AlarmDeviceUnregisterResponseDto>> unregisterCurrentDevice(
119118
HttpServletRequest request,
120-
@RequestBody(required = false) AlarmDeviceUnregisterRequestDto requestDto) {
119+
@Valid @RequestBody(required = false) AlarmDeviceUnregisterRequestDto requestDto) {
121120
Long userId = userAuthService.getUserIdFromToken(request);
122121
return ResponseEntity.status(HttpStatus.OK)
123122
.body(ApiResponseForm.success(alarmService.unregisterCurrentDevice(
@@ -147,7 +146,7 @@ public ResponseEntity<ApiResponseForm<AlarmDeviceUnregisterResponseDto>> unregis
147146
@PostMapping("/users/me/alarm-status")
148147
public ResponseEntity<ApiResponseForm<AlarmStatusReportResponseDto>> reportAlarmStatus(
149148
HttpServletRequest request,
150-
@RequestBody AlarmStatusReportRequestDto requestDto) {
149+
@Valid @RequestBody AlarmStatusReportRequestDto requestDto) {
151150
Long userId = userAuthService.getUserIdFromToken(request);
152151
return ResponseEntity.status(HttpStatus.OK)
153152
.body(ApiResponseForm.success(alarmService.reportAlarmStatus(

ontime-back/src/main/java/devkor/ontime_back/controller/FeedbackController.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import io.swagger.v3.oas.annotations.responses.ApiResponse;
1111
import io.swagger.v3.oas.annotations.responses.ApiResponses;
1212
import jakarta.servlet.http.HttpServletRequest;
13+
import jakarta.validation.Valid;
1314
import lombok.RequiredArgsConstructor;
1415
import org.springframework.http.ResponseEntity;
1516
import org.springframework.web.bind.annotation.PostMapping;
@@ -47,12 +48,12 @@ public class FeedbackController {
4748
@ApiResponse(responseCode = "4XX", description = "피드백 저장 실패", content = @Content(mediaType = "application/json", schema = @Schema(example = "실패 메세지(정확히 어떤 메세지인지는 모름)")))
4849
})
4950
@PostMapping("")
50-
public ResponseEntity<ApiResponseForm<?>> saveFeedback(HttpServletRequest request, @RequestBody FeedbackAddDto feedbackAddDto) {
51+
public ResponseEntity<ApiResponseForm<?>> saveFeedback(HttpServletRequest request, @Valid @RequestBody FeedbackAddDto feedbackAddDto) {
5152
Long userId = userAuthService.getUserIdFromToken(request);
5253

5354
feedbackService.saveFeedback(userId, feedbackAddDto);
5455

5556
String message = "피드백이 성공적으로 저장되었습니다!";
5657
return ResponseEntity.ok(ApiResponseForm.success(null, message));
5758
}
58-
}
59+
}

ontime-back/src/main/java/devkor/ontime_back/controller/FirebaseTokenController.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import io.swagger.v3.oas.annotations.responses.ApiResponse;
1111
import io.swagger.v3.oas.annotations.responses.ApiResponses;
1212
import jakarta.servlet.http.HttpServletRequest;
13+
import jakarta.validation.Valid;
1314
import lombok.RequiredArgsConstructor;
1415
import org.springframework.http.ResponseEntity;
1516
import org.springframework.web.bind.annotation.PostMapping;
@@ -47,7 +48,7 @@ public class FirebaseTokenController {
4748
@ApiResponse(responseCode = "4XX", description = "FCM 토큰 저장 실패", content = @Content(mediaType = "application/json", schema = @Schema(example = "실패 메세지(정확히 어떤 메세지인지는 모름)")))
4849
})
4950
@PostMapping("")
50-
public ResponseEntity<ApiResponseForm<String>> registerFirebaseToken(HttpServletRequest request, @RequestBody FirebaseTokenAddDto firebaseTokenAddDto) {
51+
public ResponseEntity<ApiResponseForm<String>> registerFirebaseToken(HttpServletRequest request, @Valid @RequestBody FirebaseTokenAddDto firebaseTokenAddDto) {
5152
Long userId = userAuthService.getUserIdFromToken(request);
5253

5354
firebaseTokenService.registerFirebaseToken(

ontime-back/src/main/java/devkor/ontime_back/controller/FriendShipController.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import io.swagger.v3.oas.annotations.responses.ApiResponse;
1313
import io.swagger.v3.oas.annotations.responses.ApiResponses;
1414
import jakarta.servlet.http.HttpServletRequest;
15+
import jakarta.validation.Valid;
1516
import lombok.RequiredArgsConstructor;
1617
import org.springframework.http.ResponseEntity;
1718
import org.springframework.web.bind.annotation.*;
@@ -85,10 +86,10 @@ public ResponseEntity<ApiResponseForm<CreateFriendshipLinkResponse>> createFrien
8586
@ApiResponse(responseCode = "4XX", description = "친구추가 요청자 조회 실패", content = @Content(mediaType = "application/json", schema = @Schema(example = "실패 메세지(정확히 어떤 메세지인지는 모름)")))
8687
})
8788
@GetMapping("/{uuid}/requests") // 친구 추가 요청자 조회
88-
public ResponseEntity<ApiResponseForm<GetFriendshipRequesterResponse>> getFriendShipRequester(HttpServletRequest request, @PathVariable String uuid) {
89+
public ResponseEntity<ApiResponseForm<GetFriendshipRequesterResponse>> getFriendShipRequester(HttpServletRequest request, @PathVariable UUID uuid) {
8990
Long userId = userAuthService.getUserIdFromToken(request);
9091

91-
User requester = friendShipService.getFriendShipRequester(userId, UUID.fromString(uuid));
92+
User requester = friendShipService.getFriendShipRequester(userId, uuid);
9293
GetFriendshipRequesterResponse getFriendshipRequesterResponse = GetFriendshipRequesterResponse.builder()
9394
.requesterId(requester.getId())
9495
.requesterName(requester.getName())
@@ -122,10 +123,10 @@ public ResponseEntity<ApiResponseForm<GetFriendshipRequesterResponse>> getFriend
122123
@ApiResponse(responseCode = "4XX", description = "친구추가 수락상태 업데이트 실패", content = @Content(mediaType = "application/json", schema = @Schema(example = "실패 메세지(정확히 어떤 메세지인지는 모름)")))
123124
})
124125
@PostMapping("/{uuid}/approve") // 친구 추가 요청 수락
125-
public ResponseEntity<ApiResponseForm<String>> updateAcceptStatus(HttpServletRequest request, @PathVariable String uuid, @RequestBody UpdateAcceptStatusDto updateAcceptStatusDto) {
126+
public ResponseEntity<ApiResponseForm<String>> updateAcceptStatus(HttpServletRequest request, @PathVariable UUID uuid, @Valid @RequestBody UpdateAcceptStatusDto updateAcceptStatusDto) {
126127
Long userId = userAuthService.getUserIdFromToken(request);
127128

128-
friendShipService.updateAcceptStatus(userId, UUID.fromString(uuid), updateAcceptStatusDto.getAcceptStatus());
129+
friendShipService.updateAcceptStatus(userId, uuid, updateAcceptStatusDto.getAcceptStatus());
129130

130131
String status = updateAcceptStatusDto.getAcceptStatus().equals("ACCEPTED") ? "수락" : "거절";
131132
String message = "친구추가 요청 " + status + " 성공";

ontime-back/src/main/java/devkor/ontime_back/controller/PreparationScheduleController.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,12 @@
1111
import io.swagger.v3.oas.annotations.responses.ApiResponse;
1212
import io.swagger.v3.oas.annotations.responses.ApiResponses;
1313
import jakarta.servlet.http.HttpServletRequest;
14+
import jakarta.validation.Valid;
15+
import jakarta.validation.constraints.NotEmpty;
1416
import lombok.RequiredArgsConstructor;
1517
import org.springframework.http.HttpStatus;
1618
import org.springframework.http.ResponseEntity;
19+
import org.springframework.validation.annotation.Validated;
1720
import org.springframework.web.bind.annotation.*;
1821

1922
import java.util.List;
@@ -22,6 +25,7 @@
2225
@RestController
2326
@RequestMapping("/schedules")
2427
@RequiredArgsConstructor
28+
@Validated
2529
public class PreparationScheduleController {
2630

2731
private final PreparationScheduleService preparationScheduleService;
@@ -45,7 +49,7 @@ public class PreparationScheduleController {
4549
@ApiResponse(responseCode = "4XX", description = "잘못된 요청", content = @Content(mediaType = "application/json", schema = @Schema(example = "실패 메세지(정확히 어떤 메세지인지는 모름)")))
4650
})
4751
@PostMapping("/{scheduleId}/preparations")
48-
public ResponseEntity<ApiResponseForm<Void>> createPreparationSchedule(HttpServletRequest request, @Parameter(description = "스케줄 ID (UUID 형식)", required = true, example = "3fa85f64-5717-4562-b3fc-2c963f66afe5") @PathVariable UUID scheduleId, @RequestBody List<PreparationDto> preparationDtoList) {
52+
public ResponseEntity<ApiResponseForm<Void>> createPreparationSchedule(HttpServletRequest request, @Parameter(description = "스케줄 ID (UUID 형식)", required = true, example = "3fa85f64-5717-4562-b3fc-2c963f66afe5") @PathVariable UUID scheduleId, @NotEmpty(message = "준비과정은 하나 이상 필요합니다.") @RequestBody List<@Valid PreparationDto> preparationDtoList) {
4953
Long userId = userAuthService.getUserIdFromToken(request);
5054

5155
preparationScheduleService.makePreparationSchedules(userId, scheduleId, preparationDtoList);
@@ -70,7 +74,7 @@ public ResponseEntity<ApiResponseForm<Void>> createPreparationSchedule(HttpServl
7074
@ApiResponse(responseCode = "4XX", description = "잘못된 요청", content = @Content(mediaType = "application/json", schema = @Schema(example = "실패 메세지(정확히 어떤 메세지인지는 모름)")))
7175
})
7276
@PutMapping("/{scheduleId}/preparations")
73-
public ResponseEntity<ApiResponseForm<Void>> modifyPreparationSchedule(HttpServletRequest request, @Parameter(description = "스케줄 ID (UUID 형식)", required = true, example = "3fa85f64-5717-4562-b3fc-2c963f66afe5") @PathVariable UUID scheduleId, @RequestBody List<PreparationDto> preparationDtoList) {
77+
public ResponseEntity<ApiResponseForm<Void>> modifyPreparationSchedule(HttpServletRequest request, @Parameter(description = "스케줄 ID (UUID 형식)", required = true, example = "3fa85f64-5717-4562-b3fc-2c963f66afe5") @PathVariable UUID scheduleId, @NotEmpty(message = "준비과정은 하나 이상 필요합니다.") @RequestBody List<@Valid PreparationDto> preparationDtoList) {
7478
Long userId = userAuthService.getUserIdFromToken(request);
7579

7680
preparationScheduleService.updatePreparationSchedules(userId, scheduleId, preparationDtoList);

ontime-back/src/main/java/devkor/ontime_back/controller/PreparationUserController.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,20 @@
1010
import io.swagger.v3.oas.annotations.responses.ApiResponse;
1111
import io.swagger.v3.oas.annotations.responses.ApiResponses;
1212
import jakarta.servlet.http.HttpServletRequest;
13+
import jakarta.validation.Valid;
14+
import jakarta.validation.constraints.NotEmpty;
1315
import lombok.RequiredArgsConstructor;
1416
import org.springframework.http.HttpStatus;
1517
import org.springframework.http.ResponseEntity;
18+
import org.springframework.validation.annotation.Validated;
1619
import org.springframework.web.bind.annotation.*;
1720

1821
import java.util.List;
1922

2023
@RestController
2124
@RequestMapping("/users")
2225
@RequiredArgsConstructor
26+
@Validated
2327
public class PreparationUserController {
2428

2529

@@ -44,7 +48,7 @@ public class PreparationUserController {
4448
@ApiResponse(responseCode = "4XX", description = "잘못된 요청", content = @Content(mediaType = "application/json", schema = @Schema(example = "실패 메세지(정확히 어떤 메세지인지는 모름)")))
4549
})
4650
@PutMapping("/preparations")
47-
public ResponseEntity<ApiResponseForm<Void>> modifyPreparationUser(HttpServletRequest request, @RequestBody List<PreparationDto> preparationDtoList) {
51+
public ResponseEntity<ApiResponseForm<Void>> modifyPreparationUser(HttpServletRequest request, @NotEmpty(message = "준비과정은 하나 이상 필요합니다.") @RequestBody List<@Valid PreparationDto> preparationDtoList) {
4852
Long userId = userAuthService.getUserIdFromToken(request);
4953

5054
preparationUserService.updatePreparationUsers(userId, preparationDtoList);

ontime-back/src/main/java/devkor/ontime_back/controller/ScheduleController.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import io.swagger.v3.oas.annotations.responses.ApiResponse;
1313
import io.swagger.v3.oas.annotations.responses.ApiResponses;
1414
import jakarta.servlet.http.HttpServletRequest;
15+
import jakarta.validation.Valid;
1516
import lombok.RequiredArgsConstructor;
1617
import org.springframework.format.annotation.DateTimeFormat;
1718
import org.springframework.http.HttpStatus;
@@ -185,7 +186,7 @@ public ResponseEntity<ApiResponseForm<Void>> deleteSchedule(HttpServletRequest r
185186
@ApiResponse(responseCode = "4XX", description = "잘못된 요청", content = @Content(mediaType = "application/json", schema = @Schema(example = "실패 메세지(정확히 어떤 메세지인지는 모름)")))
186187
})
187188
@PutMapping("/{scheduleId}")
188-
public ResponseEntity<ApiResponseForm<Void>> modifySchedule(HttpServletRequest request, @PathVariable UUID scheduleId, @RequestBody ScheduleModDto scheduleModDto) {
189+
public ResponseEntity<ApiResponseForm<Void>> modifySchedule(HttpServletRequest request, @PathVariable UUID scheduleId, @Valid @RequestBody ScheduleModDto scheduleModDto) {
189190
Long userId = userAuthService.getUserIdFromToken(request);
190191
scheduleService.modifySchedule(userId, scheduleId, scheduleModDto);
191192
return ResponseEntity.status(HttpStatus.OK).body(ApiResponseForm.success(null));
@@ -210,7 +211,7 @@ public ResponseEntity<ApiResponseForm<Void>> modifySchedule(HttpServletRequest r
210211
@ApiResponse(responseCode = "4XX", description = "잘못된 요청", content = @Content(mediaType = "application/json", schema = @Schema(example = "실패 메세지(정확히 어떤 메세지인지는 모름)")))
211212
})
212213
@PostMapping("")
213-
public ResponseEntity<ApiResponseForm<Void>> addSchedule(HttpServletRequest request, @RequestBody ScheduleAddDto scheduleAddDto) {
214+
public ResponseEntity<ApiResponseForm<Void>> addSchedule(HttpServletRequest request, @Valid @RequestBody ScheduleAddDto scheduleAddDto) {
214215
Long userId = userAuthService.getUserIdFromToken(request);
215216
scheduleService.addSchedule(scheduleAddDto, userId);
216217
return ResponseEntity.status(HttpStatus.OK).body(ApiResponseForm.success(null));
@@ -300,7 +301,7 @@ public ResponseEntity<ApiResponseForm<List<PreparationDto>>> getPreparation(Http
300301
public ResponseEntity<ApiResponseForm<?>> finishSchedule(
301302
HttpServletRequest request,
302303
@PathVariable UUID scheduleId,
303-
@RequestBody FinishPreparationDto finishPreparationDto) {
304+
@Valid @RequestBody FinishPreparationDto finishPreparationDto) {
304305

305306
Long userId = userAuthService.getUserIdFromToken(request);
306307
scheduleService.finishSchedule(userId, scheduleId, finishPreparationDto);

0 commit comments

Comments
 (0)