Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions .github/workflows/ec2-deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -72,13 +72,12 @@ jobs:
ORG_LOWER="team-senifit"
REPO_LOWER=$(echo "${{ github.repository }}" | tr '[:upper:]' '[:lower:]')
SPRING_BOOT_IMAGE="ghcr.io/${REPO_LOWER}:${{ github.sha }}"
ADMIN_BOOT_IMAGE="ghcr.io/${ORG_LOWER}/senifit-admin:${{ github.sha }}"
ENV_B64=$(printf '%s' "${{ secrets.ENV_FILE }}" | base64 -w 0)
COMMAND_ID=$(aws ssm send-command \
--instance-ids "${{ secrets.SSM_INSTANCE_ID }}" \
--document-name "AWS-RunShellScript" \
--parameters "{\"commands\":[\"cd /apps/senifit\",\"echo ${ENV_B64} | base64 -d > /apps/senifit/.env\",\"export SPRING_BOOT_IMAGE=${SPRING_BOOT_IMAGE}\",\"export ADMIN_BOOT_IMAGE=${ADMIN_BOOT_IMAGE}\",\"docker compose pull\",\"docker compose up -d\"]}" \
--comment "Deploy spring-boot image ${SPRING_BOOT_IMAGE}" \
--parameters "{\"commands\":[\"cd /apps/senifit && echo ${ENV_B64} | base64 -d > /apps/senifit/.env && export SPRING_BOOT_IMAGE=${SPRING_BOOT_IMAGE} && sudo /apps/senifit/restart_if_infra_down.sh\"]}" \
--comment "Deploy was image ${SPRING_BOOT_IMAGE}" \
--output text \
--query "Command.CommandId")
echo "command_id=$COMMAND_ID" >> $GITHUB_OUTPUT
Expand Down
62 changes: 62 additions & 0 deletions was/src/main/resources/application-dev-local-only.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# 로컬 Docker 개발 환경 설정
# 사용법: ./gradlew bootRun --args='--spring.profiles.active=dev-local'
# 사전 조건: cd src/dev && docker compose up -d

server:
port: 8443
ssl:
enabled: true
key-store: classpath:cert/localhost.p12
key-store-type: PKCS12
key-store-password: '!senifit0527@'
key-alias: localhost

spring:
datasource:
url: jdbc:mysql://localhost:3306/dev?rewriteBatchedStatements=true
driver-class-name: com.mysql.cj.jdbc.Driver
username: senifit
password: '!senifiT2025'
pbkdf2_pepper: 8ZvnK2f7CYVU/UEXT55uE1VeVdbzqGm7okaUwmOZaUIc6Sb/Cv310TI3GFRz+CqB7GbgCzM/EPskIqoP+OwK7A==

jpa:
database: mysql
hibernate:
ddl-auto: none
show-sql: true
properties:
hibernate:
format_sql: true
dialect: org.hibernate.dialect.MySQL8Dialect
jdbc:
batch_size: 20
order_inserts: true
order_updates: true

data:
redis:
host: localhost
port: 6379
password: '!senifiT2025'

session:
store-type: redis
timeout: 5400s

app:
s3:
region: ap-northeast-2
bucket: senifit-program-bk
video-prefix: video/
thumb-prefix: thumb/
presign:
expiry-seconds: 7200
content-disposition: inline
force-content-type: false

logging:
level:
root: info
com.senifit: debug
org.hibernate.SQL: debug
org.hibernate.type.descriptor.sql.BasicBinder: trace
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package com.senifit.was.security;

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.mock.web.MockHttpSession;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;

import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestBuilders.formLogin;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

/**
* 세션 기반 인증 테스트
*
* 이 테스트는 백엔드의 세션 관리가 정상 동작하는지 검증합니다.
* - 로그인 후 세션 쿠키가 유지되는지
* - 세션을 통한 인증된 요청이 정상 처리되는지
* - 세션 없이 요청하면 401/403이 반환되는지
*/
@SpringBootTest
@AutoConfigureMockMvc
class SessionAuthenticationTest {

@Autowired
private MockMvc mockMvc;

@Test
@DisplayName("인증 없이 보호된 API 호출 시 403 반환")
void unauthenticatedRequest_shouldReturn403() throws Exception {
mockMvc.perform(get("/center"))
.andExpect(status().isForbidden());
}

@Test
@DisplayName("로그인 후 세션으로 인증된 API 호출 성공")
void authenticatedRequest_withSession_shouldSucceed() throws Exception {
// 1. 로그인 수행 (테스트용 계정 필요)
// 실제 테스트 시에는 테스트용 계정 정보로 변경 필요
MvcResult loginResult = mockMvc.perform(
formLogin("/auth/signin")
.user("id", "test_account") // 실제 테스트 계정으로 변경
.password("password", "test_password") // 실제 비밀번호로 변경
).andReturn();

// 2. 로그인 응답에서 세션 추출
MockHttpSession session = (MockHttpSession) loginResult.getRequest().getSession();

// 3. 세션을 포함하여 보호된 API 호출
if (loginResult.getResponse().getStatus() == 200) {
mockMvc.perform(get("/center").session(session))
.andExpect(status().isOk());
}
}

@Test
@DisplayName("세션 없이 요청 → 새 세션으로 요청: 403 반환")
void requestWithoutSessionCookie_shouldReturn403() throws Exception {
// 첫 번째 요청 (세션 없음)
MvcResult result1 = mockMvc.perform(get("/center"))
.andExpect(status().isForbidden())
.andReturn();

// 두 번째 요청 (다른 세션)
mockMvc.perform(get("/center"))
.andExpect(status().isForbidden());
}

@Test
@DisplayName("로그인 엔드포인트는 인증 없이 접근 가능")
void loginEndpoint_shouldBeAccessible() throws Exception {
mockMvc.perform(get("/health"))
.andExpect(status().isOk());
}
}