SSO 처리를 위해 AbstractAuthenticationProcessingFilter를 사용하여 사전에 사용자 정보를 가져와 로그인 처리를 하려 하는데 분명 로그인을 했는데 자꾸 AnonymousUser라고 로그인 안 된거 처럼 되는 현상으로 하루 죙일 구글링 시작...

찾은 결과

SecurityContext는 인증 성공후에 기본적으로 저장하지 않는다. 
UsernamePasswordAuthenticationFilter는 form-login 기반으로 SSO 처리시에는 호출 되지 않기 때문에
SessionManagementFilter에 인증정보를 감지할 수 없다.
그렇기 때문에 인증 성공후에 인정된 객체를 SecurityContext에 저장해야 한다.
SecurityContext에 저장하기 위하여는 AbstractAuthenticationProcessingFilter의 successfulAuthentication를 재정의하여야 한다.

@Override
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {

        SecurityContext context = SecurityContextHolder.createEmptyContext();
        context.setAuthentication(authResult);
        //SecurityContextHolder.setContext(context);
        HttpSessionSecurityContextRepository secRepo = new HttpSessionSecurityContextRepository();
        secRepo.saveContext(context, request, response);

        super.successfulAuthentication(request, response, chain, authResult);
}

이걸 찾는데 너무 오랜 시간을 사용했다...ㅜㅜ

SecurityConfig에서 해당 부분만 발췌한 내용은 아래와 같다.

@Configuration
@EnableWebSecurity
public class SpringSecurityConfig {

    ...
    
    @Autowired
    private UrlBasedAuthorizationManager urlBasedAuthorizationManager;

    @Bean
    public PasswordEncoder encoder() {
    return new BCryptPasswordEncoder();
    }

    @Bean
    protected SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    	http
			.csrf((csrf) ->
				csrf.disable()
			)
            .authorizeHttpRequests(
					(requests) ->
							requests
								.requestMatchers("/", "/loginionvalid.html").permitAll()
								.anyRequest().authenticated()
			)
			.formLogin((form) ->
							form
								.loginPage("/login.html")
								.usernameParameter("userId")
								.passwordParameter("pass")
								.loginProcessingUrl("/login/proc.html")
								.defaultSuccessUrl("/")
								.successHandler(customAuthenticationSuccessHandler)
								.failureHandler(customAuthenticationFailureHandler)
								.permitAll()
			)
			.logout((logout) ->
						logout
							.logoutUrl("/logout.html")
							//.logoutSuccessHandler(null)
							.logoutSuccessUrl("/")
							.permitAll()
			)
			.addFilterBefore(requestProcessingFilter(http), UsernamePasswordAuthenticationFilter.class)
			.addFilterBefore(urlBaseAuthorizationFilter(), AuthorizationFilter.class)
		;

        return http.build();
    }
    
    /**
     * SSO 처리를 위한 처리
     * @param http
     * @return
     * @throws Exception
     */
    @Bean
    public RequestProcessingFilter requestProcessingFilter(HttpSecurity http) throws Exception {

        AuthenticationManager authenticationManager = http.getSharedObject(AuthenticationManagerBuilder.class).build();

        RequestProcessingFilter rpf = new RequestProcessingFilter("/ssoLogin.html");
        rpf.setAuthenticationManager(authenticationManager);
        rpf.setAuthenticationFailureHandler(ssoAuthenticationFailureHandler);
        rpf.setAuthenticationSuccessHandler(customAuthenticationSuccessHandler);
        return rpf;
    }
    
    ...
}


RequestProcessingFilter.java

public class RequestProcessingFilter extends AbstractAuthenticationProcessingFilter {

	private String usernameParameter = "userInfo";

	public RequestProcessingFilter(String defaultFilterProcessesUrl) {
		super(defaultFilterProcessesUrl);
	}

	@Override
	public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
			throws AuthenticationException, IOException, ServletException {

		String requestInfo = obtainUsername(request);
		if( !StringUtils.hasText(requestInfo) ) {
			logger.error("사용자 정보 연계시 사용자 정보 미전송");
			throw new BadCredentialsException("사용자 정보가 올바르게 전송되지 않았습니다. 관리자에게 문의하여 주시기 바랍니다.");
		}

		...
		String userNo = ...;

		UsernamePasswordAuthenticationToken authRequest = UsernamePasswordAuthenticationToken.unauthenticated(userNo,
				"user1");

		// Allow subclasses to set the "details" property
		setDetails(request, authRequest);
		return this.getAuthenticationManager().authenticate(authRequest);
	}

	protected void setDetails(HttpServletRequest request, UsernamePasswordAuthenticationToken authRequest) {
		authRequest.setDetails(this.authenticationDetailsSource.buildDetails(request));
	}

	public String obtainUsername(HttpServletRequest request){
		return request.getParameter(usernameParameter);
	}

	@Override
	protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {

	        SecurityContext context = SecurityContextHolder.createEmptyContext();
	        context.setAuthentication(authResult);
	        //SecurityContextHolder.setContext(context);
	        HttpSessionSecurityContextRepository secRepo = new HttpSessionSecurityContextRepository();
	        secRepo.saveContext(context, request, response);

	        super.successfulAuthentication(request, response, chain, authResult);
	}

}

Spring Security 설정 파일에서 다음과 같이 설정한다.


@Configuration

@Import({SecurityBeanConfig.class})

@EnableWebSecurity

public class SecurityConfig extends WebSecurityConfigurerAdapter {


  ...


@Autowired

private FilterSecurityInterceptor filterSecurityInterceptor;


  ...


@Override

public void configure(WebSecurity web) throws Exception {

web

.ignoring()

.antMatchers("/resources/**")

.and()

.privilegeEvaluator(webInvocationPrivilegeEvaluator());

}  


   ...


/**

* Cusome Tag를 사용하여 Web 페이지에서 권한을 체크하고 싶을 때 사용함.

*

* <code>

* <sec:authorize url="/admin/stats/index.jsp">

* <a href="<spring:url value="/admin/stats/index.jsp"/>">link</a>

* </sec:authorize>

* </code>

*

* @return

*/

@Bean

public WebInvocationPrivilegeEvaluator webInvocationPrivilegeEvaluator(){

return new DefaultWebInvocationPrivilegeEvaluator(filterSecurityInterceptor);

}

}


사용은 위의  주석과 같이


체크하고자 하는 경로를 넣어 주면 접근이 가능한지 여부를 판단하여 준다.


<sec:authorize url="/admin/stats/index.jsp">

<a href="<spring:url value="/admin/stats/index.jsp"/>">link</a>

</sec:authorize>


+ Recent posts