Skip to content

Commit

Permalink
feat: PasswordEncoder 변경 및 DirtiesContext 삭제 (#429)
Browse files Browse the repository at this point in the history
* feat: PasswordEncoder 인터페이스 분리

* test: DirtiesContext 삭제

* refactor: 테스트용 데이터베이스 초기화 객체 추출

* refactor: 남아있는 DirtContext 삭제

* remove: 사용하지 않는 클래스 삭제

---------

Co-authored-by: songusika <sws981202@gmail.com>
  • Loading branch information
thdwoqor and Songusika authored Nov 17, 2023
1 parent c2cc7c6 commit b6b5a4d
Show file tree
Hide file tree
Showing 21 changed files with 143 additions and 137 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,8 @@ private Member(final String username, final Password password, final Provider pr
this.nickname = nickname;
}

public static Member self(final String username, final String password) {
return new Member(username, new Password(password), Provider.SELF, Nickname.random());
public static Member self(final String username, final Password password) {
return new Member(username, password, Provider.SELF, Nickname.random());
}

public static Member social(final String username, final Provider provider, final String nickname) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.digginroom.digginroom.domain.member;

import com.digginroom.digginroom.util.DigginRoomPasswordEncoder;
import com.digginroom.digginroom.util.PasswordEncoder;
import jakarta.persistence.Embeddable;
import lombok.AccessLevel;
import lombok.Getter;
Expand All @@ -17,15 +17,15 @@ public class Password {

private String password = EMPTY_PASSWORD;

public Password(final String password) {
this.password = DigginRoomPasswordEncoder.encode(password);
public Password(final String password, final PasswordEncoder passwordEncoder) {
this.password = passwordEncoder.encode(password);
}

public boolean doesNotMatch(final String password) {
public boolean doesNotMatch(final String password, final PasswordEncoder passwordEncoder) {
if (this.isEmpty()) {
return false;
}
return !DigginRoomPasswordEncoder.matches(password, this.password);
return !passwordEncoder.matches(password, this.password);
}

public boolean isEmpty() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,22 @@
package com.digginroom.digginroom.service;

import com.digginroom.digginroom.service.dto.FavoriteGenresRequest;
import com.digginroom.digginroom.service.dto.MemberDetailsResponse;
import com.digginroom.digginroom.service.dto.MemberDuplicationResponse;
import com.digginroom.digginroom.service.dto.MemberLoginRequest;
import com.digginroom.digginroom.service.dto.MemberLoginResponse;
import com.digginroom.digginroom.service.dto.MemberSaveRequest;
import com.digginroom.digginroom.domain.Genre;
import com.digginroom.digginroom.domain.member.Member;
import com.digginroom.digginroom.domain.member.Password;
import com.digginroom.digginroom.domain.member.Provider;
import com.digginroom.digginroom.exception.MemberException.DuplicationException;
import com.digginroom.digginroom.exception.MemberException.NotFoundException;
import com.digginroom.digginroom.exception.MemberException.WrongProviderException;
import com.digginroom.digginroom.oauth.IdTokenResolver;
import com.digginroom.digginroom.oauth.payload.IdTokenPayload;
import com.digginroom.digginroom.repository.MemberRepository;
import com.digginroom.digginroom.service.dto.FavoriteGenresRequest;
import com.digginroom.digginroom.service.dto.MemberDetailsResponse;
import com.digginroom.digginroom.service.dto.MemberDuplicationResponse;
import com.digginroom.digginroom.service.dto.MemberLoginRequest;
import com.digginroom.digginroom.service.dto.MemberLoginResponse;
import com.digginroom.digginroom.service.dto.MemberSaveRequest;
import com.digginroom.digginroom.util.PasswordEncoder;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
Expand All @@ -27,13 +29,15 @@ public class MemberService {

private final MemberRepository memberRepository;
private final IdTokenResolver idTokenResolver;
private final PasswordEncoder passwordEncoder;


public void save(final MemberSaveRequest request) {
if (isDuplicated(request.username())) {
throw new DuplicationException();
}
memberRepository.save(request.toMember());
Password password = new Password(request.password(), passwordEncoder);
memberRepository.save(Member.self(request.username(), password));
}

private boolean isDuplicated(final String username) {
Expand Down Expand Up @@ -73,7 +77,7 @@ public MemberLoginResponse loginMember(final MemberLoginRequest request) {
throw new WrongProviderException();
}

if (member.getPassword().doesNotMatch(request.password())) {
if (member.getPassword().doesNotMatch(request.password(), passwordEncoder)) {
throw new NotFoundException();
}
return MemberLoginResponse.of(member);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.digginroom.digginroom.service.dto;

import com.digginroom.digginroom.domain.member.Member;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Pattern;
import jakarta.validation.constraints.Size;
Expand All @@ -21,8 +20,4 @@ public record MemberSaveRequest(
)
String password
) {

public Member toMember() {
return Member.self(username, password);
}
}
Original file line number Diff line number Diff line change
@@ -1,19 +1,23 @@
package com.digginroom.digginroom.util;

import java.util.UUID;
import org.springframework.stereotype.Component;

public class DigginRoomPasswordEncoder {
@Component
public class DigginRoomPasswordEncoder implements PasswordEncoder {

private static final int SALT_LENGTH = 36;
private static final int SALT_START_INDEX = 0;

public static String encode(final String plainText) {
@Override
public String encode(final String plainText) {
UUID salt = UUID.randomUUID();
String hashed = HashAlgorithm.encrypt(salt + plainText);
return salt + hashed;
}

public static boolean matches(final String plainText, final String encoded) {
@Override
public boolean matches(final String plainText, final String encoded) {
String salt = encoded.substring(SALT_START_INDEX, SALT_LENGTH);
String hashed = HashAlgorithm.encrypt(salt + plainText);
return (salt + hashed).equals(encoded);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.digginroom.digginroom.util;

public interface PasswordEncoder {

String encode(final String plainText);

boolean matches(final String plainText, final String encoded);
}
16 changes: 10 additions & 6 deletions backend/src/test/java/com/digginroom/digginroom/TestFixture.java
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
package com.digginroom.digginroom;

import com.digginroom.digginroom.service.dto.CommentRequest;
import com.digginroom.digginroom.service.dto.MemberLoginRequest;
import com.digginroom.digginroom.service.dto.MemberSaveRequest;
import com.digginroom.digginroom.domain.Genre;
import com.digginroom.digginroom.domain.member.Member;
import com.digginroom.digginroom.domain.member.Password;
import com.digginroom.digginroom.domain.member.Provider;
import com.digginroom.digginroom.domain.room.Room;
import com.digginroom.digginroom.domain.track.Track;
Expand All @@ -13,7 +11,10 @@
import com.digginroom.digginroom.oauth.jwk.KakaoJwkProvider;
import com.digginroom.digginroom.oauth.jwk.ThirdPartyJwkProviders;
import com.digginroom.digginroom.oauth.payload.IdTokenPayload;

import com.digginroom.digginroom.service.dto.CommentRequest;
import com.digginroom.digginroom.service.dto.MemberLoginRequest;
import com.digginroom.digginroom.service.dto.MemberSaveRequest;
import com.digginroom.digginroom.util.DigginRoomPasswordEncoder;
import java.util.List;

//TODO: 픽스쳐 분리
Expand All @@ -30,12 +31,15 @@ public class TestFixture {
public static final MemberLoginRequest MEMBER2_LOGIN_REQUEST = new MemberLoginRequest(MEMBER2_USERNAME,
MEMBER2_PASSWORD);

public static Password PASSWORD = new Password(MEMBER_PASSWORD, new DigginRoomPasswordEncoder());
public static Password PASSWORD2 = new Password(MEMBER2_PASSWORD, new DigginRoomPasswordEncoder());

public static Member 파워() {
return Member.self(MEMBER_USERNAME, MEMBER_PASSWORD);
return Member.self(MEMBER_USERNAME, PASSWORD);
}

public static Member 블랙캣() {
return Member.self(MEMBER2_USERNAME, MEMBER2_PASSWORD);
return Member.self(MEMBER2_USERNAME, PASSWORD2);
}

public static final CommentRequest COMMENT_REQUEST = new CommentRequest("베리는 REST API 고수");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,8 @@
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.test.annotation.DirtiesContext;

@SuppressWarnings("NonAsciiCharacters")
@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD)
class CommentControllerTest extends ControllerTest {

@Autowired
Expand All @@ -42,6 +40,7 @@ class CommentControllerTest extends ControllerTest {
private RoomRepository roomRepository;
@Autowired
private CommentRepository commentRepository;

private Room 나무;
private Room 차이;
private Member 파워;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
package com.digginroom.digginroom.controller;


import com.digginroom.digginroom.util.DatabaseCleanerExtension;
import io.restassured.RestAssured;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayNameGeneration;
import org.junit.jupiter.api.DisplayNameGenerator.ReplaceUnderscores;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.test.web.server.LocalServerPort;

@ExtendWith(DatabaseCleanerExtension.class)
@DisplayNameGeneration(ReplaceUnderscores.class)
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
public abstract class ControllerTest {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,8 @@
import org.hamcrest.Matchers;
import org.junit.jupiter.api.Test;
import org.springframework.http.HttpStatus;
import org.springframework.test.annotation.DirtiesContext;

@SuppressWarnings("NonAsciiCharacters")
@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD)
class MemberArgumentResolverTest extends ControllerTest {

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,8 @@
import io.restassured.http.ContentType;
import org.junit.jupiter.api.Test;
import org.springframework.http.HttpStatus;
import org.springframework.test.annotation.DirtiesContext;

@SuppressWarnings("NonAsciiCharacters")
@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD)
class MemberJoinControllerTest extends ControllerTest {

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,12 @@
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.test.annotation.DirtiesContext;

import static com.digginroom.digginroom.TestFixture.MEMBER_LOGIN_REQUEST;
import static com.digginroom.digginroom.TestFixture.파워;
import static org.hamcrest.Matchers.*;

@SuppressWarnings("NonAsciiCharacters")
@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD)
class MemberLoginControllerTest extends ControllerTest {

@Autowired
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,8 @@
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.http.HttpStatus;
import org.springframework.test.annotation.DirtiesContext;

@SuppressWarnings("NonAsciiCharacters")
@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD)
class MemberOperationControllerTest extends ControllerTest {

private String cookie;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,8 @@
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.test.annotation.DirtiesContext;

@SuppressWarnings("NonAsciiCharacters")
@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD)
class RoomControllerTest extends ControllerTest {

@Autowired
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import static org.assertj.core.api.Assertions.assertThat;

import com.digginroom.digginroom.domain.member.Password;
import com.digginroom.digginroom.util.DigginRoomPasswordEncoder;
import com.digginroom.digginroom.util.PasswordEncoder;
import org.junit.jupiter.api.DisplayNameGeneration;
import org.junit.jupiter.api.DisplayNameGenerator;
import org.junit.jupiter.api.Test;
Expand All @@ -11,37 +13,38 @@
@DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class)
class PasswordTest {

private static final PasswordEncoder passwordEncoder = new DigginRoomPasswordEncoder();
private static final String PLAIN_TEXT = "konghanapassword";

@Test
void 패스워드를_직접_생성하면_암호화된_패스워드가_생성된다() {
Password password = new Password(PLAIN_TEXT);
Password password = new Password(PLAIN_TEXT, passwordEncoder);

assertThat(password.getPassword()).isNotEqualTo(PLAIN_TEXT);
}

@Test
void 빈_패스워드인지_확인할_수_있다() {
assertThat(new Password(PLAIN_TEXT).isEmpty()).isFalse();
assertThat(new Password(PLAIN_TEXT, passwordEncoder).isEmpty()).isFalse();
assertThat(Password.EMPTY.isEmpty()).isTrue();
}

@Test
void 패스워드가_일치하는지_확인할_수_있다() {
Password password = new Password(PLAIN_TEXT);
Password password = new Password(PLAIN_TEXT, passwordEncoder);

assertThat(password.doesNotMatch(PLAIN_TEXT)).isFalse();
assertThat(password.doesNotMatch(PLAIN_TEXT, passwordEncoder)).isFalse();
}

@Test
void 패스워드가_일치하지_않는지_확인할_수_있다() {
Password password = new Password(PLAIN_TEXT);
Password password = new Password(PLAIN_TEXT, passwordEncoder);

assertThat(password.doesNotMatch("anotherpassword")).isTrue();
assertThat(password.doesNotMatch("anotherpassword", passwordEncoder)).isTrue();
}

@Test
void 빈_패스워드는_어떤_문자열과도_일치하지_않는다() {
assertThat(Password.EMPTY.doesNotMatch("")).isFalse();
assertThat(Password.EMPTY.doesNotMatch("", passwordEncoder)).isFalse();
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
package com.digginroom.digginroom.feedback.controller;

import static com.digginroom.digginroom.TestFixture.MEMBER_LOGIN_REQUEST;
import static com.digginroom.digginroom.TestFixture.파워;
import static org.assertj.core.api.Assertions.assertThat;

import com.digginroom.digginroom.TestFixture;
import com.digginroom.digginroom.controller.ControllerTest;
import com.digginroom.digginroom.feedback.domain.Feedback;
Expand All @@ -17,15 +21,9 @@
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.test.annotation.DirtiesContext;

import static com.digginroom.digginroom.TestFixture.MEMBER_LOGIN_REQUEST;
import static com.digginroom.digginroom.TestFixture.파워;
import static org.assertj.core.api.Assertions.assertThat;

@SuppressWarnings("NonAsciiCharacters")
@DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class)
@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD)
class FeedbackControllerTest extends ControllerTest {

@Autowired
Expand Down
Loading

0 comments on commit b6b5a4d

Please sign in to comment.