행복하자!!
338
2022-03-06 22:47:31 작성 2022-03-06 22:48:16 수정됨
5
121

security filter 인 ExceptionTranslationFilter 가 인증예외 exception을 처리한다는 문서가 잘 못된거 같습니다.


ExceptionTranslationFilter doc에 보면 필터체인에서 던진 인증예외를 처리할 수 있다고 했는데

ExceptionTranslationFilter 필터 순서 상 무조건 뒤에 호출된  필터만 처리할 수 있다는걸 알았습니다.


ExceptionTranslationFilter 뒤에 위치한 UsernamePasswordAuthenticationFilter 입니다.

http.httpBasic().disable()
                .csrf().disable()
                .authorizeRequests()
                .antMatchers(matchers).anonymous()
                .and()
                .exceptionHandling().authenticationEntryPoint(new AuthenticationEntryPointImpl())
                .and()
                .logout()
                .logoutRequestMatcher(new AntPathRequestMatcher(Urls.logout))
                .invalidateHttpSession(true)    // 세션 초기화
                .and().formLogin().disable()
        .addFilterAfter(getUsernamePasswordAuthenticationFilterEx(), ExceptionTranslationFilter.class);

UsernamePasswordAuthenticationFilter 필터에서 인증예외 exception이 발생하면 authenticationEntryPoint 클래스에 commence 함수를 호출하게 되어 인증예외 처리가 됩니다.


필터 순서에 의해 인증예외를 처리할 수 있다면 doc가 잘 못 작성된게 아닌지 의구심이 들어 글 올려봅니다.

 


저와 동일한 의문을 품은 stackoverflow 질문이 있는데 아쉽게 그건 답변이 안달렸고 고심끝에 여기다가 저도 올려봅니다.

How Spring Security Filter Chain Works in case of `ExceptionTranslationFilter` - Stack Overflow

0
  • 답변 5

  • Dierslair
    5k
    2022-03-06 23:17:44 작성 2022-03-06 23:18:19 수정됨

    ExceptionTranslationFilter 바로 뒤에 FilterSecurityInterceptor 라는 필터가 있습니다. 그 안에서 발생하는 시큐리티 예외를 처리하기 위해 그 위치에 있으며, 의도된 것입니다.

    보통 AccessDecisionManager 또는 이번에 새롭게 도입된 AuthorizationFilter에서 발생한 AccessDeniedException, @PreAuthorize, @PostAuthorize 등으로 프록싱된 시큐리티 인터셉터의 시큐리티 오류를 처리합니다.

    ExceptionTranslationFilter 범위 밖의 시큐리티 필터는 예외를 던지면 안됩니다. 만약 그런 상황이 발생하는 경우, ErrorController에서 처리하는 것이 일반적입니다.

  • 행복하자!!
    338
    2022-03-07 01:02:29 작성 2022-03-07 01:18:48 수정됨

    답변 감사합니다.

    ExceptionTranslationFilter 필터가 FilterSecurityInterceptor 필터에서만 예외를 잡을 수 있다면 security filter 표준 체인에서 던지는 인증 예외는 무의미 하지 않나요?? 

    인증 예외를 던지는 표준 체인으로는 로그인 요청을 처리하는 UsernamePasswordAuthenticationFilter 필터가 있습니다.

    이 클래스는 표준적으로  AuthenticationManager class -> AuthenticationProvider class -> authenticate 함수를 호출하여 인증 예외를 반환하게 설계되어있습니다. 물론 ExceptionTranslationFilter 필터보다 앞에 위치하고 있습니다.


    제가 궁금한건 ExceptionTranslationFilter 필터가 FilterSecurityInterceptor 필터를 통해서만 던지는 예외를 잡을 수 있다면 다른 표준 필터들에서는 왜 인증 예외가 throw로 붙어 있냐는 겁니다.


    필터 자체에 예외가 표준으로 붙어있지는 않지만 필터 내부에서 호출하는 과정에서 인증 예외 exception이 충분히 발생할 수 있는 구조 입니다.

  • Dierslair
    5k
    2022-03-07 10:16:01 작성 2022-03-07 10:18:17 수정됨

    행복하자!! 

    다시 한 번 강조드리자면.. 시큐리티 필터는 인증 오류를 던지지 않습니다. 메서드를 혼동하신 것 같습니다. UsernamePasswordAuthenticationProcessingFilter.attemptAuthentication 에서는 AuthenticationException을 던지고 있으나, 이 메서드를 실행하는 AbstractAuthenticationProcessingFilter에서는 AuthenticationException을 처리하는 로직을 확인할 수 있습니다.

    	private void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
    			throws IOException, ServletException {
    		if (!requiresAuthentication(request, response)) {
    			chain.doFilter(request, response);
    			return;
    		}
    		try {
    			Authentication authenticationResult = attemptAuthentication(request, response);
    			if (authenticationResult == null) {
    				// return immediately as subclass has indicated that it hasn't completed
    				return;
    			}
    			this.sessionStrategy.onAuthentication(authenticationResult, request, response);
    			// Authentication success
    			if (this.continueChainBeforeSuccessfulAuthentication) {
    				chain.doFilter(request, response);
    			}
    			successfulAuthentication(request, response, chain, authenticationResult);
    		}
    		catch (InternalAuthenticationServiceException failed) {
    			this.logger.error("An internal error occurred while trying to authenticate the user.", failed);
    			unsuccessfulAuthentication(request, response, failed);
    		}
                    // 이 곳
    		catch (AuthenticationException ex) {
    			// Authentication failed
    			unsuccessfulAuthentication(request, response, ex);
    		}
    	}

    UsernamePasswordAuthenticationProcessingFilter를 대표적으로 예를 들었지만 다른 시큐리티 필터 모두 AuthenticationException이 발생하는 경우, handler를 통해 자체 핸들링합니다. 절대 ServletContainer로 노출시키는 일은 없습니다.

  • Mambo
    7k
    2022-03-07 13:20:16
    https://docs.spring.io/spring-security/reference/servlet/architecture.html

    스프링 시큐리티에서 기본적으로 제공하는 필터 체인 순서는 중요할 수 있습니다.

    일반적으로 ExceptionTranslationFilter가 호출하는 필터 체인은 FilterSecurityInterceptor 이므로 ExceptionTranslationFilter는 애플리케이션에서 인증이나 권한 체크를 수행하는 로직 이전에 위치한다는 것을 전제로 합니다. 해당 자바 도큐먼트 문서의 필터 체인 안에서라는 말은 ExceptionTranslationFilter에 의해 호출하는 필터라고 생각하셔야합니다. 정말로 오해의 소지가 있다고 판단한다면 PR 요청해보시는 것도...

  • 행복하자!!
    338
    2022-03-07 16:55:45

    두분 다 답변 감사드립니다.


    한 곳에서 모든 인증예외를 처리하려는 걸 찾다 보니 잘 못된 길로 빠진것 같습니다.


    일단 확인해보고 추가적인 질문 있으면 또 올려보도록 하겠습니다.


    감사합니다.

  • 로그인을 하시면 답변을 등록할 수 있습니다.