/* * Copyright 2020-2022 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.wb.domainserver.security.config; import com.wb.domainserver.domain.sopmal.oauth.service.CustomOAuth2UserService; import com.wb.domainserver.exception.response.CustomOauthFailureException; import com.wb.domainserver.realm.RealmResolver; import com.wb.domainserver.realm.filter.RealmFilter; import com.wb.domainserver.response.CustomAuthenticationSuccessHandler; import com.wb.domainserver.security.authentication.CustomAccessDeniedEntryPoint; import com.wb.domainserver.security.authentication.CustomAuthenticationEntryPoint; import com.wb.domainserver.security.authorization.WnbtAuthorizationManager; import com.wb.domainserver.security.filter.CustomXssFilter; import com.wb.domainserver.security.filter.JwtAuthenticationFilter; import com.wb.domainserver.security.handler.CustomLogoutSuccessHandler; import com.wb.domainserver.security.user.SecurityUserDetailService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.aop.Advisor; import org.springframework.aop.support.JdkRegexpMethodPointcut; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Role; import org.springframework.core.annotation.Order; import org.springframework.security.authorization.method.AuthorizationManagerBeforeMethodInterceptor; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer; import org.springframework.security.config.annotation.web.configurers.HeadersConfigurer; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.authentication.logout.LogoutFilter; import org.springframework.security.web.header.HeaderWriterFilter; import org.springframework.security.web.savedrequest.RequestCacheAwareFilter; import org.springframework.security.web.util.matcher.AntPathRequestMatcher; import org.springframework.security.web.util.matcher.OrRequestMatcher; import org.springframework.security.web.util.matcher.RequestMatcher; import java.util.List; import java.util.stream.Collectors; import static org.springframework.beans.factory.config.BeanDefinition.ROLE_INFRASTRUCTURE; @EnableWebSecurity(debug = false) @Configuration //@EnableMethodSecurity public class ResourceServerConfig { private static final Logger logger = LoggerFactory.getLogger(ResourceServerConfig.class); @Autowired private RealmResolver realmResolver; @Autowired private SecurityUserDetailService userDetailService; @Autowired private CustomAuthenticationEntryPoint authenticationEntryPoint; @Autowired private CustomAccessDeniedEntryPoint accessDeniedEntryPoint; @Autowired private CustomAuthenticationSuccessHandler customAuthenticationSuccessHandler; @Autowired private CustomOAuth2UserService customOAuth2UserService; @Bean @Role(ROLE_INFRASTRUCTURE) public Advisor authorizationManagerBeforeMethodInterception(WnbtAuthorizationManager authorizationManager) { JdkRegexpMethodPointcut pattern = new JdkRegexpMethodPointcut(); pattern.setPattern("com.wb.domainserver.*.controller.*"); return new AuthorizationManagerBeforeMethodInterceptor(pattern, authorizationManager); } @Bean @Order(1) SecurityFilterChain sopmalSecurityFilterChain(HttpSecurity http, SecurityPathProperties securityProperties) throws Exception { RequestMatcher logoutRequestMatcher = new OrRequestMatcher( new AntPathRequestMatcher("/sopmal/logout") ); //사용자 권한 List anonymousPath = securityProperties.getSolmal().getAnonmymous().stream() .map(AntPathRequestMatcher::new) .collect(Collectors.toList()); List authPath = securityProperties.getSolmal().getAuthenticated().stream() .map(AntPathRequestMatcher::new) .collect(Collectors.toList()); List resourcePath = securityProperties.getCommon().getResources().stream() .map(AntPathRequestMatcher::new) .collect(Collectors.toList()); OrRequestMatcher anonymoushMatchers = new OrRequestMatcher(anonymousPath); OrRequestMatcher authMatchers = new OrRequestMatcher(authPath); OrRequestMatcher resourceMatchers = new OrRequestMatcher(resourcePath); return http .securityMatcher("/sopmal/**", "/oauth2/**", "/login/oauth2/**","/file/*") .headers((headers)->headers.frameOptions(HeadersConfigurer.FrameOptionsConfig::sameOrigin)) .csrf(AbstractHttpConfigurer::disable) .authorizeHttpRequests(authorize -> authorize .requestMatchers(authMatchers).authenticated() .requestMatchers(anonymoushMatchers).anonymous() .requestMatchers(resourceMatchers).permitAll() .requestMatchers( new AntPathRequestMatcher("/oauth2/**"), new AntPathRequestMatcher("/login/oauth2/**") ).permitAll() .anyRequest().permitAll() ) .oauth2Login(oauth2 -> oauth2 //sns oauth .loginPage("/sopmal/login") .successHandler(customAuthenticationSuccessHandler) //인증성공시 로그인 혹은 연동처리 .userInfoEndpoint(userInfo -> userInfo //인증처리 .userService(customOAuth2UserService) ) .failureHandler(new CustomOauthFailureException()) //인증 실패시 ) .addFilterAfter(new CustomXssFilter(), RequestCacheAwareFilter.class) .addFilterBefore(new JwtAuthenticationFilter(userDetailService), LogoutFilter.class) .addFilterAfter(new RealmFilter(realmResolver), HeaderWriterFilter.class) .exceptionHandling(exceptions -> exceptions .authenticationEntryPoint(authenticationEntryPoint) .accessDeniedHandler(accessDeniedEntryPoint) ).logout(logout -> logout.logoutRequestMatcher(logoutRequestMatcher) .deleteCookies("JSESSIONID") .logoutSuccessHandler(new CustomLogoutSuccessHandler()) ) .build(); } @Bean @Order(2) SecurityFilterChain adminSecurityFilterChain(HttpSecurity http, SecurityPathProperties securityProperties) throws Exception { // 설정된 로그아웃 URL RequestMatcher logoutRequestMatcher = new OrRequestMatcher( new AntPathRequestMatcher("/mngr/logout"), new AntPathRequestMatcher("/admin/logout"), new AntPathRequestMatcher("/crm/logout") ); List anonmyPath = securityProperties.getAdmin().getAnonmymous().stream() .map(AntPathRequestMatcher::new) .collect(Collectors.toList()); List authPath = securityProperties.getAdmin().getAuthenticated().stream() .map(AntPathRequestMatcher::new) .collect(Collectors.toList()); List resourcePath = securityProperties.getCommon().getResources().stream() .map(AntPathRequestMatcher::new) .collect(Collectors.toList()); OrRequestMatcher authMatchers = new OrRequestMatcher(authPath); OrRequestMatcher resourceMatchers = new OrRequestMatcher(resourcePath); return http .csrf(AbstractHttpConfigurer::disable) .securityMatcher("/mngr/**","/mngr","/admin/**","/admin","/admin/**","/crm/**","/itrnt/**", logoutRequestMatcher.toString()) //"/*/mq/**", "/api/batch/schedulerloader/**", 제외 .authorizeHttpRequests(authorize -> authorize // .requestMatchers(AntPathRequestMatcher.antMatcher("/*/mq/**")).anonymous() //ERP 호출 허용을 위해 // .requestMatchers(AntPathRequestMatcher.antMatcher("/api/batch/schedulerloader/**")).anonymous() //batch 스케줄 동적기동 .requestMatchers(AntPathRequestMatcher.antMatcher("/admin")).permitAll() .requestMatchers(AntPathRequestMatcher.antMatcher("/mngr")).permitAll() .requestMatchers(AntPathRequestMatcher.antMatcher("/mngr/login/**")).permitAll() .requestMatchers(AntPathRequestMatcher.antMatcher("/admin/login/**")).permitAll() .requestMatchers(AntPathRequestMatcher.antMatcher("/mngr/tokens/**")).anonymous() .requestMatchers(AntPathRequestMatcher.antMatcher("/admin/tokens/**")).anonymous() .requestMatchers(resourceMatchers).permitAll() .requestMatchers(authMatchers).authenticated() .anyRequest().permitAll() ) .addFilterBefore(new JwtAuthenticationFilter(userDetailService), LogoutFilter.class) .addFilterAfter(new RealmFilter(realmResolver), HeaderWriterFilter.class) .exceptionHandling(exceptions -> exceptions .authenticationEntryPoint(authenticationEntryPoint) .accessDeniedHandler(accessDeniedEntryPoint) ).logout(logout -> logout.logoutRequestMatcher(logoutRequestMatcher) .deleteCookies("JSESSIONID") .logoutSuccessHandler(new CustomLogoutSuccessHandler()) ) .build(); } // // private String customBearerTokenResolver(HttpServletRequest request) { // String authorization = request.getHeader("Authorization"); // if (StringUtils.hasText(authorization) && authorization.startsWith("Bearer ")) { // return authorization.substring(7); // } // return null; // } // // private String determineIssuerUri(String token) { // return String.format(issuerUri+"/%s", RealmContextHolder.getRealm()); // } @Bean public BCryptPasswordEncoder bCryptPasswordEncoder() { return new BCryptPasswordEncoder(); } }