반응형
스프링 부트 테스트가 웹 보안 구성을 존중하지 않음
Rest API 컨트롤러 테스트를 작성하고 있습니다.이 끝점은 권한 없이 액세스할 수 있습니다.
@EnableWebSecurity
@Configuration
@Import(AppConfig.class)
class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsRepository accountRepository;
@Autowired
private CustomUserDetailsService customUserDetailsService;
@Autowired
private JWTAuthenticationFilter jwtAuthenticationFilter;
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class)
.authorizeRequests()
.anyRequest().authenticated().and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
/*
* Apparently, permitAll() doesn't work for custom filters, therefore we ignore the signup and login endpoints
* here
*/
@Override
public void configure(WebSecurity web)
throws Exception {
web.ignoring()
.antMatchers(HttpMethod.POST, "/login")
.antMatchers(HttpMethod.POST, "/signup");
}
/*
* set user details services and password encoder
*/
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsServiceBean()).passwordEncoder(passwordEncoder());
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
/* Stopping spring from adding filter by default */
@Bean
public FilterRegistrationBean rolesAuthenticationFilterRegistrationDisable(JWTAuthenticationFilter filter) {
FilterRegistrationBean registration = new FilterRegistrationBean(filter);
registration.setEnabled(false);
return registration;
}
}
그JWTAuthenticationFilter클래스:
@Component
public class JWTAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
@Autowired
private UserDetailsService customUserDetailsService;
private static Logger logger = LoggerFactory.getLogger(JWTAuthenticationFilter.class);
private final static UrlPathHelper urlPathHelper = new UrlPathHelper();
final static String defaultFilterProcessesUrl = "/**";
public JWTAuthenticationFilter() {
super(defaultFilterProcessesUrl);
super.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher(defaultFilterProcessesUrl)); //Authentication will only be initiated for the request url matching this pattern
setAuthenticationManager(new NoOpAuthenticationManager());
}
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException {
Authentication authentication = AuthenticationService.getAuthentication(request, customUserDetailsService);
return getAuthenticationManager().authenticate(authentication);
}
@Override
protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException, ServletException {
logger.debug("failed authentication while attempting to access "+ urlPathHelper.getPathWithinApplication((HttpServletRequest) request));
response.sendError(HttpServletResponse.SC_UNAUTHORIZED,"Authentication Failed");
}
@Override
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {
SecurityContextHolder.getContext().setAuthentication(authResult);
chain.doFilter(request, response);
}
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
super.doFilter(req, res, chain);
}
}
엔드포인트를 '가입'하기 위해 (포스트맨 사용) 요청을 하면 잘 작동합니다.하지만 테스트를 실행해보면,doFilter인증되지 않기 때문에 실패합니다.
@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc
public class AuthenticationControllerFTest {
@Autowired
private MockMvc mockMvc;
@MockBean
private AuthenticationManager authenticationManager;
@Test
public void testCreate() throws Exception {
Authentication authentication = Mockito.mock(Authentication.class);
Mockito.when(authentication.getName()).thenReturn("DUMMY_USERNAME");
Mockito.when(
authenticationManager.authenticate(Mockito
.any(UsernamePasswordAuthenticationToken.class)))
.thenReturn(authentication);
String exampleUserInfo = "{\"name\":\"Test1234\",\"username\":\"test@test.com\",\"password\":\"Salam12345\"}";
RequestBuilder requestBuilder = MockMvcRequestBuilders
.post("/signup")
.accept(MediaType.APPLICATION_JSON).content(exampleUserInfo)
.contentType(MediaType.APPLICATION_JSON);
MvcResult result = mockMvc.perform(requestBuilder).andReturn();
MockHttpServletResponse response = result.getResponse();
int status = response.getStatus();
String content = response.getContentAsString();
System.out.println(content);
Assert.assertEquals("http response status is wrong", 200, status);
}
}
이 문제를 어떻게 해결할 것인지에 대한 아이디어가 있습니까?
이 문제는 테스트 클래스에 다음 코드를 추가하여 해결되었습니다.
@Autowired
private WebApplicationContext context;
@Autowired
private Filter springSecurityFilterChain;
@Before
public void setup() {
mockMvc = MockMvcBuilders.webAppContextSetup(context)
.addFilters(springSecurityFilterChain).build();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable().authorizeRequests()
.antMatchers("/**").permitAll()
.anyRequest().authenticated();
}
언급URL : https://stackoverflow.com/questions/45230620/spring-boot-test-does-not-respect-web-security-configuration
반응형
'programing' 카테고리의 다른 글
| Python/psycopg2 WHERE IN 문 (0) | 2023.08.10 |
|---|---|
| 현재 지점이 아닌 지점에 'git pull'하는 방법은 무엇입니까? (0) | 2023.08.10 |
| localdb를 따로 설치하는 방법은 무엇입니까? (0) | 2023.08.10 |
| A4 용지 크기 페이지에서 HTML 페이지를 만드는 방법은 무엇입니까? (0) | 2023.08.10 |
| 보안 웹 소켓 서버(tomcat)를 통해 각 소켓(HTTPS)이 있는 스프링 웹 소켓(WSS) (0) | 2023.08.10 |