티스토리 뷰

Abstract
Spring Security 를 적용하고 컨트롤러 테스트를 했는데 에러가 발생했다.
403 에러였고, 찾아보니 클라이언트가 접근 권한이 없을 때 발생하는 forbidden 에러였다.

해결

 

먼저 Spring Security 적용 후에 컨트롤러 테스트를 하기 위해서는 테스트에서도 API 에 접근할 수 있어야 하므로 새로운 의존성을 추가해야 한다. 바로 spring-security-test 이다.

build.gradle 에 의존성을 추가해주었다.

추가한 후에는 컨트롤러 테스트에서 MockMvc 클래스의 가짜 객체에 서비스의 의존성을 주입해 사용하여 post 요청을 보낼 때 .with(csrf()) 를 붙여주어야 한다.

post 요청을 보낼 때 붙여준다.

Note
CSRF는 Cross-Site Request Forgery 의 줄임말로, 어떤 사이트에 로그인 된 유저들을 이용해서 사이트의 특정 요청을 보내도록 강제하는 공격을 말한다. CSRF 공격들은 웹 어플리케이션이 유저에게 갖고 있는 신뢰를 이용하는 것이다. (반대로 Cross-Site Scripting (XSS) 공격들은 웹 어플리케이션에 대한 유저의 신뢰를 이용한다.)
CSRF 공격은 웹 어플리케이션이 실제 사용자로부터 온 자발적인 요청과 사용자가 아닌 해커가 사용자의 인증 정보를 사용해 생성한 요청을 분간하지 못한다는 취약점을 이용한다.
Spring Security 는 CSRF 토큰을 이용해 CSRF 공격을 방어한다. 매 새션에 로그인된 사용자에게 임의의 난수로 된 토큰을 발급하고, 요청과 일치하는지 확인한 후에 응답하는 방식을 사용한다.
with(csrf()) 는 유효한 토큰을 가지고 테스트 중이니, API 에서 응답을 달라는 의미이다.

 

그리고 테스트를 실행해보니, 이번에는 401 unauthorized 에러가 발생했다. 유저 인증 과정을 거치지 않은 것이다.

이는 가짜로 인증 받은 유저로서 API 에 접근할 수 있도록 @WithMockUser 붙임으로서 해결할 수 있다.

메소드 레벨에 @WithMockUser 를 붙여주었다.

@WithMockUser

가짜 유저로서 테스트를 실행할 때 붙이는 어노테이션인 @WithMockUser 는 다양한 옵션을 붙여 사용할 수 있다.

 

1. 디폴트값

먼저 아무 옵션도 붙이지 않은 채 @WithMockUser 을 사용하면, 아래 정보로 로그인한다. 실제로 존재하지 않는 아이디와 비밀번호여도 상관 없다. 가짜 유저이기 때문이다.

  • username="user"
  • password="password"
  • roles="ROLE_USER"

Spring Security 는 이 세 개의 정보를 가지고 가짜 유저를 만든다.

  • Spring Security의 User 객체가 Authentication 에서 핵심적으로 사용된다. 그래서 테스트에 MockUser 가 필요하다.
  • Spring Security 에서 역할을 제한할 때 사용하는 GrantedAuthority 클래스의 객체 ROLE_USER 를 부여받는다.

2. 다양한 옵션들

위의 정보들을 옵션들을 통해 다양하게 바꾸어줄 수 있다. username 과 roles 를 아래와 같이 바꿀 수 있다.

@Test
@WithMockUser(username="customUsername",roles={"USER","ADMIN"})
public void getMessageWithMockUserCustomUser() {
	String message = messageService.getMessage();
	...
}

roles 에서 ROLE_USER 의 USER 는 Spring Security 에서 authorities 라고 하는 권한을 나타내는데, 변경 가능하다.

@Test
@WithMockUser(username = "customUsername", authorities = { "ADMIN", "USER" })
public void getMessageWithMockUserCustomAuthorities() {
	String message = messageService.getMessage();
	...
}

이렇게 하면 권한에 ADMIN 을 추가해 roles 는 ROLE_ADMIN 과 ROLE_USER 두 개가 된다. 

Tip
어노테이션을 클래스 레벨에 붙이면 매 메소드마다 어노테이션을 붙일 필요 없어 편리하게 사용할 수 있다.

인증받은 사용자에게만 요청을 허가하는 특정 API 의 테스트

post(url) 뒤에 .contentType() 외에도 .content() 를 하나 더 붙여 Authentication 을 매개변수로 주어야 한다. 왜냐하면 컨트롤러에서 API 구현 시 Authentication 객체를 매개변수로 받도록 했기 때문이다:

컨트롤러에서 매개변수로 Authentication 객체를 받고 있다.
뭔가 authentication 이라는 키워드가 들어가는 부분으로 설정이 필요해 보였다.

 

출처

https://docs.spring.io/spring-security/reference/servlet/test/mockmvc/csrf.html

 

Testing with CSRF Protection :: Spring Security

When testing any non-safe HTTP methods and using Spring Security’s CSRF protection, you must include a valid CSRF Token in the request. To specify a valid CSRF token as a request parameter use the CSRF RequestPostProcessor like so:

docs.spring.io

https://www.synopsys.com/glossary/what-is-csrf.html

 

What Is Cross-Site Request Forgery (CSRF) and How Does It Work? | Synopsys

Cross-Site Request Forgery (CSRF) is an attack that forces authenticated users to submit a request to a web application against which they are currently authenticated. Learn more at Synopsys.com.

www.synopsys.com

https://docs.spring.io/spring-security/site/docs/5.0.x/reference/html/test-method.html

 

11. Testing Method Security

This section demonstrates how to use Spring Security’s Test support to test method based security. We first introduce a MessageService that requires the user to be authenticated in order to access it. The result of getMessage is a String saying "Hello" t

docs.spring.io

 

 

11. Testing Method Security

This section demonstrates how to use Spring Security’s Test support to test method based security. We first introduce a MessageService that requires the user to be authenticated in order to access it. The result of getMessage is a String saying "Hello" t

docs.spring.io

 

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/02   »
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28
글 보관함