W15D5

Onni·2021년 11월 15일
0

1. Spring Security Architectrue

사용자의 인증처리를 담당하는 Authentication Manager
사용ㅇ자가 적절한 권한을 가지고 있는지 확인하는지 Acess Decision Manager
로 구성되어 있다. 사용자가 요청을 보냈을떄 사용자를 인증하고 인증된 사용자가 리소스에 접근하는데 적절한 권한이 있는지 확인한 후 적절한 권한이 없었다면 Acess Decision Manager 에서 403 과 같은 응답을 한다. 사용자가 적절한 권한을 가지고 있었으면 정상적으로 요청한 리소스에 대해 응담이 내려가게 됨
스프링시큐리티는 결국 서블릿필터의 목록이다.
서블릿 필터를 구현하고 있는 필터구현체들의 집합
사용자의 웹 요청은 스프링시큐리티의 서블릿 필터 목록으로 전달이 되고 처리가 이러우지게 됨
서블릿필터목록을 필터체인 프록시라고 부름

사용자의 웹요청은 필터체인 프록시에 들어오게되고 필터들을 순차적으로 통과

-delegatingFilterProxy :뭔가르 위임하기 위한 필터
요청을 받아 그 요청을 delegate로 전달
스프링큐리티의 필터체인 목록을 delegate로 지정하는 delegateFilterProxy를 만들고 있음

사용자의 웹요청은 delegatingFilterProxy에 의해서 filterchainProxy에 전달이 됐고, filterchainProxy에서 스프링 니큐리티 필터목록을 가지고와 사용자의 웹요청을 필터목록에 의해 처리하게 댐


  • Conceptual Architecture
    • 거시적인 관점에서 Spring Security는 웹 요청을 가로챈 후 사용자를 인증하고, 인증된 사용자가 적절한 권한을 지니고 있는 확인함
      • AuthenticationManager 사용자 인증 관련 처리
      • AccessDecisionManager 사용자가 보호받는 리소스에 접근할 수 있는 적절한 권한이 있는지 확인

  • FilterChainProxy (Spring Security 필터 체인) 소개
    • Spring Security의 실제적인 구현은 서블릿 필터 (javax.servlet.Filter 인터페이스 구현체) 를 통해 이루어짐
      • 서블릿 필터는 웹 요청을 가로챈 후 전처리 또는 후처리를 수행하거나, 요청 자체를 리다이렉트 하기도 함
    • FilterChainProxy 세부 내용은 WebSecurityConfigurerAdapter 추상 클래스를 상속하는 구현체에서 설정함 (보통 @EnableWebSecurity 어노테이션도 함께 사용)
      • 웹 요청은 이러한 필터 체인을 차례로 통과하게 됨
        • 웹 요청은 모든 필터를 통과하게 되지만, 모든 필터가 동작하는 것은 아님
        • 각 필터는 웹 요청에 따라 동작 여부를 결정할 수 있고, 동작할 필요가 없다면 다음 필터로 웹 요청을 즉시 넘김
      • 요청을 처리하고 응답을 반환하면 필터 체인 호출 스택은 모든 필터에 대해 역순으로 진행
      • 보통 springSecurityFilterChain 이라는 이름으로 Bean 등록됨
    • 웹 요청은 어떻게 FilterChainProxy로 전달될까?
      • 웹 요청을 수신한 서블릿 컨테이너는 해당 요청을 DelegatingFilterProxy (javax.servlet.Filter 인터페이스 구현체) 로 전달함
        • DelegatingFilterProxy Bean은 ****SecurityFilterAutoConfiguration 클래스에서 자동으로 등록됨
                @Bean
                @ConditionalOnBean(name = DEFAULT_FILTER_NAME)
                public DelegatingFilterProxyRegistrationBean securityFilterChainRegistration(SecurityProperties securityProperties) {
                	DelegatingFilterProxyRegistrationBean registration = new DelegatingFilterProxyRegistrationBean(DEFAULT_FILTER_NAME);
                	registration.setOrder(securityProperties.getFilter().getOrder());
                	registration.setDispatcherTypes(getDispatcherTypes(securityProperties));
                	return registration;
}
  • DelegatingFilterProxy는 실제적으로 웹 요청을 처리할 Target Filter Bean을 지정해야함
  • Target Filter Bean은 바로 앞에서 알아본 FilterChainProxy
                @Override
                public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws ServletException, IOException {
                	// Lazily initialize the delegate if necessary.
                	Filter delegateToUse = this.delegate;
                	if (delegateToUse == null) {
                		synchronized (this.delegateMonitor) {
                			delegateToUse = this.delegate;
                			if (delegateToUse == null) {
                				WebApplicationContext wac = findWebApplicationContext();
                				if (wac == null) {
                					throw new IllegalStateException("No WebApplicationContext found: " +
                							"no ContextLoaderListener or DispatcherServlet registered?");
                				}
                				delegateToUse = initDelegate(wac);
                			}
                			this.delegate = delegateToUse;
                		}
                	}
                	// Let the delegate perform the actual doFilter operation.
                	invokeDelegate(delegateToUse, request, response, filterChain);
                }
                
                protected Filter initDelegate(WebApplicationContext wac) throws ServletException {
                	String targetBeanName = getTargetBeanName();
                	Assert.state(targetBeanName != null, "No target bean name set");
                	Filter delegate = wac.getBean(targetBeanName, Filter.class);
                	if (isTargetFilterLifecycle()) {
                		delegate.init(getFilterConfig());
                	}
                	return delegate;
                }
                
                protected void invokeDelegate(Filter delegate, ServletRequest request, ServletResponse response, FilterChain filterChain)
                		throws ServletException, IOException {
                	delegate.doFilter(request, response, filterChain);
                }
  • FilterChainProxy를 구성하는 Filter 목록
    • 정말 다양한 필터 구현을 제공함
    • 결국 Spring Security를 잘 이해하고 활용한다는 것은 이들 Filter 를 이해하고, 적절하게 사용한다는 것을 의미함

2. RequestCacheAwareFiter

FilterSecurityInterceptor 에서 접근거부가 되어 예외가 발생 하고 ExceptionTranslationFilter가 그 예외를 catch한다.

실제로 ExceptionTranslationFilter가 예외를 발생하는지 보기위해 breakPoint를 두고 권한이 필요한 /me 페이지에 접속한다.

예상대로 아직 로그인 하기 전이기 때문에 권한이 없어 AccessDeniedException이 발생하는 것을 볼 수 있다. 이 ExceptionTranslationFilterd을 더 자세하게 살펴 보도록 하자

예외 타입에 따라 처리하는 방식이 나누어져 있고 아까 발생한 AccessDeniedException을 다루는 handleAccessDeniedException을 들어가본다.


handleAccessDeniedException에서는 먼저 익명인지 확인하고 그 여부에 따라 다르게 동작한다. 주의해서 봐야할 부분은 sendStartAuthenticationdl 인데 , 우리가 실제로 /me 페이지에 접속하면 권한이 없기때문에 로그인 페이지로 리다이렉션 되는것을 확인 할 수 있다. 즉 sendStartAuthentication 는 사용자를 로그인 페이지로 리다이렉션하는 역할을 하는 것이다.


sendStartAuthentication에서는 원래 접속할랐던 me 페이지를 savedRequset라는 객체를 만들어서 저장 후 리다이랙션하는 것을 확인 할 수 있다.

3. ChannelProcessingFilter

https 의 default 포트인 443으로 변경
ssl 생성시 만들었던 alias

maven을 reload하고 프로젝트를 실행시키면 443포트로 뜨는 것과 링크 접속시 인증서에 대한 정보를 확인할 수 있다.

현재요청을 hppt와 https 중에서 어떤걸로 처리하는지 결정하는 부분인
channelDecisionManager를 더 자세히 살펴보도록 하자


먼저, WebSecurityConfigure에 설정 정보를 추가해주고
channelDecisionManager 에 breakPoint를 걸고 디버깅을 해보면

reauestMap에 우리가 설정파일에 적어놨던 any request 정보가 담겨 있는것을 확인할 수 있다.

설정정보를 변경후에 다시 디버깅 해보면 마찬가지로 변경한 정보가 담겨 있는것을 확인 할 수 있다.

channelProcessingFilter에 있는 channelDecisionManager을 마찬가지로 디버깅해보면 channelProcessors에 InsecureChannelProcessor과 SecureChannelProcessor에 대한 정보가 담겨 있는 것을 확인 할 수 있다.

SecureChannelProcessor는 현재 요청이 secure(https인지 아닌지) 여부에 따라 아닐경우 if문이 실행되어 리다이렉션이 발생 했을 것이다.
우리는 이미 ssl을 이용해 secure 되기때문에 if문이 실행되지는 않았다.

profile
꿈꿈

0개의 댓글

관련 채용 정보