content: package com.ctrip.framework.apollo.portal.spi.configuration;
  
  import com.google.common.collect.Maps;
  
  import com.ctrip.framework.apollo.common.condition.ConditionalOnMissingProfile;
  import com.ctrip.framework.apollo.portal.component.config.PortalConfig;
  import com.ctrip.framework.apollo.portal.spi.LogoutHandler;
  import com.ctrip.framework.apollo.portal.spi.SsoHeartbeatHandler;
  import com.ctrip.framework.apollo.portal.spi.UserInfoHolder;
  import com.ctrip.framework.apollo.portal.spi.UserService;
  import com.ctrip.framework.apollo.portal.spi.ctrip.CtripLogoutHandler;
  import com.ctrip.framework.apollo.portal.spi.ctrip.CtripSsoHeartbeatHandler;
  import com.ctrip.framework.apollo.portal.spi.ctrip.CtripUserInfoHolder;
  import com.ctrip.framework.apollo.portal.spi.ctrip.CtripUserService;
  import com.ctrip.framework.apollo.portal.spi.defaultimpl.DefaultLogoutHandler;
  import com.ctrip.framework.apollo.portal.spi.defaultimpl.DefaultSsoHeartbeatHandler;
  import com.ctrip.framework.apollo.portal.spi.defaultimpl.DefaultUserInfoHolder;
  import com.ctrip.framework.apollo.portal.spi.defaultimpl.DefaultUserService;
  import com.ctrip.framework.apollo.portal.spi.springsecurity.SpringSecurityUserInfoHolder;
  import com.ctrip.framework.apollo.portal.spi.springsecurity.SpringSecurityUserService;
  
  import org.apache.tomcat.jdbc.pool.DataSource;
  import org.springframework.beans.factory.annotation.Autowired;
  import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
  import org.springframework.boot.context.embedded.FilterRegistrationBean;
  import org.springframework.boot.context.embedded.ServletListenerRegistrationBean;
  import org.springframework.context.annotation.Bean;
  import org.springframework.context.annotation.Configuration;
  import org.springframework.context.annotation.Profile;
  import org.springframework.core.annotation.Order;
  import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
  import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
  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.configuration.WebSecurityConfigurerAdapter;
  import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
  import org.springframework.security.provisioning.JdbcUserDetailsManager;
  import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;
  
  import javax.servlet.Filter;
  import java.util.EventListener;
  import java.util.Map;
  
  
  @Configuration
  public class AuthConfiguration {
  
    /**
     * spring.profiles.active = ctrip
     */
    @Configuration
    @Profile("ctrip")
    static class CtripAuthAutoConfiguration {
  
      @Autowired
      private PortalConfig portalConfig;
  
      @Bean
      public ServletListenerRegistrationBean redisAppSettingListner() {
        ServletListenerRegistrationBean redisAppSettingListener = new ServletListenerRegistrationBean();
        redisAppSettingListener.setListener(listener("org.jasig.cas.client.credis.CRedisAppSettingListner"));
        return redisAppSettingListener;
      }
  
      @Bean
      public ServletListenerRegistrationBean singleSignOutHttpSessionListener() {
        ServletListenerRegistrationBean singleSignOutHttpSessionListener = new ServletListenerRegistrationBean();
        singleSignOutHttpSessionListener
            .setListener(listener("org.jasig.cas.client.session.SingleSignOutHttpSessionListener"));
        return singleSignOutHttpSessionListener;
      }
  
      @Bean
      public FilterRegistrationBean casFilter() {
        FilterRegistrationBean singleSignOutFilter = new FilterRegistrationBean();
        singleSignOutFilter.setFilter(filter("org.jasig.cas.client.session.SingleSignOutFilter"));
        singleSignOutFilter.addUrlPatterns("/*");
        singleSignOutFilter.setOrder(1);
        return singleSignOutFilter;
      }
  
      @Bean
      public FilterRegistrationBean authenticationFilter() {
        FilterRegistrationBean casFilter = new FilterRegistrationBean();
  
        Map<String, String> filterInitParam = Maps.newHashMap();
        filterInitParam.put("redisClusterName", "casClientPrincipal");
        filterInitParam.put("serverName", portalConfig.portalServerName());
        filterInitParam.put("casServerLoginUrl", portalConfig.casServerLoginUrl());
        //we don't want to use session to store login information, since we will be deployed to a cluster, not a single instance
        filterInitParam.put("useSession", "false");
        filterInitParam.put("/openapi.*", "exclude");
  
        casFilter.setInitParameters(filterInitParam);
        casFilter.setFilter(filter("com.ctrip.framework.apollo.sso.filter.ApolloAuthenticationFilter"));
        casFilter.addUrlPatterns("/*");
        casFilter.setOrder(2);
  
        return casFilter;
      }
  
      @Bean
      public FilterRegistrationBean casValidationFilter() {
        FilterRegistrationBean casValidationFilter = new FilterRegistrationBean();
        Map<String, String> filterInitParam = Maps.newHashMap();
        filterInitParam.put("casServerUrlPrefix", portalConfig.casServerUrlPrefix());
        filterInitParam.put("serverName", portalConfig.portalServerName());
        filterInitParam.put("encoding", "UTF-8");
        //we don't want to use session to store login information, since we will be deployed to a cluster, not a single instance
        filterInitParam.put("useSession", "false");
        filterInitParam.put("useRedis", "true");
        filterInitParam.put("redisClusterName", "casClientPrincipal");
  
        casValidationFilter
            .setFilter(filter("org.jasig.cas.client.validation.Cas20ProxyReceivingTicketValidationFilter"));
        casValidationFilter.setInitParameters(filterInitParam);
        casValidationFilter.addUrlPatterns("/*");
        casValidationFilter.setOrder(3);
  
        return casValidationFilter;
  
      }
  
  
      @Bean
      public FilterRegistrationBean assertionHolder() {
        FilterRegistrationBean assertionHolderFilter = new FilterRegistrationBean();
  
        Map<String, String> filterInitParam = Maps.newHashMap();
        filterInitParam.put("/openapi.*", "exclude");
  
        assertionHolderFilter.setInitParameters(filterInitParam);
  
        assertionHolderFilter.setFilter(filter("com.ctrip.framework.apollo.sso.filter.ApolloAssertionThreadLocalFilter"));
        assertionHolderFilter.addUrlPatterns("/*");
        assertionHolderFilter.setOrder(4);
  
        return assertionHolderFilter;
      }
  
      @Bean
      public CtripUserInfoHolder ctripUserInfoHolder() {
        return new CtripUserInfoHolder();
      }
  
      @Bean
      public CtripLogoutHandler logoutHandler() {
        return new CtripLogoutHandler();
      }
  
      private Filter filter(String className) {
        Class clazz = null;
        try {
          clazz = Class.forName(className);
          Object obj = clazz.newInstance();
          return (Filter) obj;
        } catch (Exception e) {
          throw new RuntimeException("instance filter fail", e);
        }
  
      }
  
      private EventListener listener(String className) {
        Class clazz = null;
        try {
          clazz = Class.forName(className);
          Object obj = clazz.newInstance();
          return (EventListener) obj;
        } catch (Exception e) {
          throw new RuntimeException("instance listener fail", e);
        }
      }
  
      @Bean
      public UserService ctripUserService(PortalConfig portalConfig) {
        return new CtripUserService(portalConfig);
      }
  
      @Bean
      public SsoHeartbeatHandler ctripSsoHeartbeatHandler() {
        return new CtripSsoHeartbeatHandler();
      }
  
    }
  
  
    /**
     * spring.profiles.active = auth
     */
    @Configuration
    @Profile("auth")
    static class SpringSecurityAuthAutoConfiguration {
  
      @Bean
      @ConditionalOnMissingBean(SsoHeartbeatHandler.class)
      public SsoHeartbeatHandler defaultSsoHeartbeatHandler() {
        return new DefaultSsoHeartbeatHandler();
      }
  
      @Bean
      @ConditionalOnMissingBean(UserInfoHolder.class)
      public UserInfoHolder springSecurityUserInfoHolder() {
        return new SpringSecurityUserInfoHolder();
      }
  
      @Bean
      @ConditionalOnMissingBean(LogoutHandler.class)
      public LogoutHandler logoutHandler() {
        return new DefaultLogoutHandler();
      }
  
      @Bean
      public JdbcUserDetailsManager jdbcUserDetailsManager(AuthenticationManagerBuilder auth, DataSource datasource) throws Exception {
        JdbcUserDetailsManager jdbcUserDetailsManager = auth.jdbcAuthentication().passwordEncoder(new BCryptPasswordEncoder()).dataSource(datasource)
            .usersByUsernameQuery("select Username,Password,Enabled from `Users` where Username = ?")
            .authoritiesByUsernameQuery("select Username,Authority from `Authorities` where Username = ?")
            .getUserDetailsService();
  
        jdbcUserDetailsManager.setUserExistsSql("select Username from `Users` where Username = ?");
        jdbcUserDetailsManager.setCreateUserSql("insert into `Users` (Username, Password, Enabled) values (?,?,?)");
        jdbcUserDetailsManager.setUpdateUserSql("update `Users` set Password = ?, Enabled = ? where Username = ?");
        jdbcUserDetailsManager.setDeleteUserSql("delete from `Users` where Username = ?");
        jdbcUserDetailsManager.setCreateAuthoritySql("insert into `Authorities` (Username, Authority) values (?,?)");
        jdbcUserDetailsManager.setDeleteUserAuthoritiesSql("delete from `Authorities` where Username = ?");
        jdbcUserDetailsManager.setChangePasswordSql("update `Users` set Password = ? where Username = ?");
  
        return jdbcUserDetailsManager;
      }
  
      @Bean
      @ConditionalOnMissingBean(UserService.class)
      public UserService springSecurityUserService() {
        return new SpringSecurityUserService();
      }
  
    }
  
    @Order(99)
    @Profile("auth")
    @Configuration
    @EnableWebSecurity
    @EnableGlobalMethodSecurity(prePostEnabled = true)
    static class SpringSecurityConfigurer extends WebSecurityConfigurerAdapter {
  
      public static final String USER_ROLE = "user";
  
      @Override
      protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable();
        http.headers().frameOptions().disable();
        http.authorizeRequests().antMatchers("/openapi/**", "/vendor/**", "/styles/**", "/scripts/**", "/views/**", "/img/**","/**").permitAll()
        .antMatchers("/**").hasAnyRole(USER_ROLE);
        http.formLogin().loginPage("/signin").permitAll().failureUrl("/signin?#/error").and().httpBasic();
        http.logout().invalidateHttpSession(true).clearAuthentication(true).logoutSuccessUrl("/signin?#/logout");
        http.exceptionHandling().authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/signin"));
      }
  
    }
  
    /**
     * default profile
     */
    @Configuration
    @ConditionalOnMissingProfile({"ctrip", "auth"})
    static class DefaultAuthAutoConfiguration {
  
      @Bean
      @ConditionalOnMissingBean(SsoHeartbeatHandler.class)
      public SsoHeartbeatHandler defaultSsoHeartbeatHandler() {
        return new DefaultSsoHeartbeatHandler();
      }
  
      @Bean
      @ConditionalOnMissingBean(UserInfoHolder.class)
      public DefaultUserInfoHolder defaultUserInfoHolder() {
        return new DefaultUserInfoHolder();
      }
  
      @Bean
      @ConditionalOnMissingBean(LogoutHandler.class)
      public DefaultLogoutHandler logoutHandler() {
        return new DefaultLogoutHandler();
      }
  
      @Bean
      @ConditionalOnMissingBean(UserService.class)
      public UserService defaultUserService() {
        return new DefaultUserService();
      }
    }
  
    @ConditionalOnMissingProfile("auth")
    @Configuration
    @EnableWebSecurity
    @EnableGlobalMethodSecurity(prePostEnabled = true)
    static class DefaultWebSecurityConfig extends WebSecurityConfigurerAdapter {
  
      @Override
      protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable();
        http.headers().frameOptions().disable();
      }
    }
  }
  