java - CAS 过滤器在部署 war 时不拦截服务票据

标签 java spring-boot tomcat war cas

我有一个针对 CAS 服务器进行身份验证的 Spring Boot 应用程序。 当我执行“mvn spring-boot:run”时,登录正确完成:

  1. 调用 URL_1_APP

  2. 重定向到 cas/login

  3. 填写凭证并提交

  4. 重定向到 Service_id_path?ticket=ST-XX-...

  5. 重定向到请求的 URL URL_1_APP

但是当我执行“mvn package”并在 tomcat 服务器中部署 war 时,最后的重定向没有完成:

  1. 调用 URL_1_APP
  2. 重定向到 cas/login
  3. 填写凭证并提交
  4. 重定向到 Service_id_path?ticket=ST-XX-... -> 永远不会重定向到 URL_1_APP

我正在使用: Spring 引导 1.5.2。 汤姆猫 9.0.16 JDK 11

这是我的起始类(class):

package com.qim.ptp;

import com.qim.ptp.config.YmlPropertyFactory;
import org.jasig.cas.client.session.SingleSignOutFilter;
import org.jasig.cas.client.session.SingleSignOutHttpSessionListener;
import org.jasig.cas.client.validation.Cas30ServiceTicketValidator;
import org.jasig.cas.client.validation.TicketValidator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.boot.web.support.SpringBootServletInitializer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Primary;
import org.springframework.context.annotation.PropertySource;
import org.springframework.context.event.EventListener;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;

import org.springframework.security.cas.ServiceProperties;
import org.springframework.security.cas.authentication.CasAuthenticationProvider;
import org.springframework.security.cas.web.CasAuthenticationEntryPoint;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.authentication.logout.LogoutFilter;
import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;

import javax.servlet.http.HttpSessionEvent;

@ComponentScan(basePackages = {"com.qim"})
@ServletComponentScan
@SpringBootApplication
@EnableJpaRepositories(basePackages = {"com.qim.ptp.repository"})
@PropertySource(factory = YmlPropertyFactory.class, value = "file:${config.path}")
public class BackApplication extends SpringBootServletInitializer {

    private static final Logger log = LoggerFactory.getLogger(BackApplication.class);

    @Value("${qim.cas.service-id}")
    private String serviceId;

    @Value("${qim.cas.path.base}")
    private String casBasePath;

    @Value("${qim.cas.path.login}")
    private String casLoginPath;

    @Value("${qim.cas.path.logout}")
    private String casLogoutPath;

    @Value("${qim.cas.admin.username}")
    private String casUsername;

    @Value("${qim.cas.admin.password}")
    private String casPassword;

    @Value("${qim.cas.admin.role}")
    private String casRole;

    @Value("${qim.cas.admin.key}")
    private String casKey;

    @Value("${qim.paths.base.version.v1}")
    private String basePath;

    @Value("${qim.paths.logout}")
    private String logoutPath;

    @Value("${server.port}")
    private String serverPort;

    public static void main( String[] args ) {
        log.info("Init application");
        SpringApplication.run(BackApplication.class, args);
    }

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(BackApplication.class);
    }


    @Bean
    public ServiceProperties serviceProperties() {
        ServiceProperties serviceProperties = new ServiceProperties();
        serviceProperties.setService("http://localhost:"+serverPort+"/kaka");
        serviceProperties.setSendRenew(false);
        serviceProperties.setAuthenticateAllArtifacts(true);
        return serviceProperties;
    }

    @Bean
    @Primary
    public AuthenticationEntryPoint authenticationEntryPoint(
            ServiceProperties sP) {
        CasAuthenticationEntryPoint entryPoint = new CasAuthenticationEntryPoint();
        entryPoint.setLoginUrl(casBasePath+casLoginPath);
        entryPoint.setServiceProperties(sP);
        return entryPoint;
    }

    @Bean
    public TicketValidator ticketValidator() {
        return new Cas30ServiceTicketValidator(casBasePath);
    }

    @Bean
    public CasAuthenticationProvider casAuthenticationProvider() {

        CasAuthenticationProvider provider = new CasAuthenticationProvider();
        provider.setServiceProperties(serviceProperties());
        provider.setTicketValidator(ticketValidator());
        provider.setUserDetailsService(
                s -> new User(casUsername, casPassword, true, true, true, true,
                        AuthorityUtils.createAuthorityList(casRole)
                )
        );
        provider.setKey(casKey);
        return provider;
    }

    @Bean
    public SecurityContextLogoutHandler securityContextLogoutHandler() {
        return new SecurityContextLogoutHandler();
    }

    @Bean
    public LogoutFilter logoutFilter() {
        LogoutFilter logoutFilter = new LogoutFilter(
                casBasePath+casLogoutPath,
                securityContextLogoutHandler());
        logoutFilter.setFilterProcessesUrl(basePath+logoutPath);
        return logoutFilter;
    }

    @Bean
    public SingleSignOutFilter singleSignOutFilter() {
        SingleSignOutFilter singleSignOutFilter = new SingleSignOutFilter();
        singleSignOutFilter.setCasServerUrlPrefix(casBasePath);
        singleSignOutFilter.setIgnoreInitConfiguration(true);
        return singleSignOutFilter;
    }

    @EventListener
    public SingleSignOutHttpSessionListener singleSignOutHttpSessionListener(
            HttpSessionEvent event) {
        return new SingleSignOutHttpSessionListener();
    }

}

在这个类中,我配置了 Spring Security 过滤器:

package com.qim.ptp.config;

import org.jasig.cas.client.session.SingleSignOutFilter;
import org.jasig.cas.client.session.SingleSignOutHttpSessionListener;
import org.jasig.cas.client.validation.Cas30ServiceTicketValidator;
import org.jasig.cas.client.validation.TicketValidator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.context.event.EventListener;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.ProviderManager;
import org.springframework.security.cas.ServiceProperties;
import org.springframework.security.cas.authentication.CasAuthenticationProvider;
import org.springframework.security.cas.web.CasAuthenticationEntryPoint;
import org.springframework.security.cas.web.CasAuthenticationFilter;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
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.config.http.SessionCreationPolicy;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.authentication.logout.LogoutFilter;
import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;
import org.springframework.security.web.firewall.HttpFirewall;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;

import javax.servlet.http.HttpSessionEvent;
import java.util.Arrays;

@EnableWebSecurity
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    private AuthenticationProvider authenticationProvider;
    private AuthenticationEntryPoint authenticationEntryPoint;
    private SingleSignOutFilter singleSignOutFilter;
    private LogoutFilter logoutFilter;
    private CasAuthenticationFilter filter;

    @Value("${qim.paths.base.version.v1}")
    private String basePath;

    @Value("${qim.paths.logout}")
    private String logoutPath;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .csrf().disable()
                .addFilter(this.filter)
                .authorizeRequests()
                .regexMatchers("/.*")
                .authenticated()
                .and()
                .authorizeRequests()
                .regexMatchers("/")
                .permitAll()
                .and()
                .httpBasic()
                .authenticationEntryPoint(authenticationEntryPoint)
                .and()
                .logout().logoutSuccessUrl(basePath+logoutPath)
                .and()
                .addFilterBefore(singleSignOutFilter, CasAuthenticationFilter.class)
                .addFilterBefore(logoutFilter, LogoutFilter.class);
    }

    @Autowired
    public SecurityConfig(CasAuthenticationProvider casAuthenticationProvider, AuthenticationEntryPoint eP,
                          LogoutFilter lF
            , SingleSignOutFilter ssF
    ) {
        this.authenticationProvider = casAuthenticationProvider;
        this.authenticationEntryPoint = eP;

        this.logoutFilter = lF;
        this.singleSignOutFilter = ssF;

    }


    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(authenticationProvider);
    }

    @Override
    protected AuthenticationManager authenticationManager() throws Exception {
        return new ProviderManager(Arrays.asList(authenticationProvider));
    }

    @Bean
    public CasAuthenticationFilter casAuthenticationFilter(ServiceProperties sP) throws Exception {
        CasAuthenticationFilter filter = new CasAuthenticationFilter();
        filter.setServiceProperties(sP);
        filter.setFilterProcessesUrl("/kaka");
        filter.setAuthenticationManager(authenticationManager());
        this.filter = filter;
        return filter;
    }

}

提前谢谢你。

最佳答案

错误的产生是因为当在服务器上部署 war 时,包含了一个上下文路径来访问应用程序:资源http://localhost:9000/hello更改为 http://localhost:9000/application-version/hello

所以在服务属性方法中需要修改:

@Bean
public ServiceProperties serviceProperties() {
    ServiceProperties serviceProperties = new ServiceProperties();
    serviceProperties.setService("http://localhost:"+serverPort+"/application-version/kaka");
    serviceProperties.setSendRenew(false);
    serviceProperties.setAuthenticateAllArtifacts(true);
    return serviceProperties;
}

但是没有必要在cas filter方法中包含这个上下文路径:

@Bean
public CasAuthenticationFilter casAuthenticationFilter(ServiceProperties sP) throws Exception {
    CasAuthenticationFilter filter = new CasAuthenticationFilter();
    filter.setServiceProperties(sP);
    filter.setFilterProcessesUrl("/kaka");
    filter.setAuthenticationManager(authenticationManager());
    this.filter = filter;
    return filter;
}

关于java - CAS 过滤器在部署 war 时不拦截服务票据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55853210/

相关文章:

java - Android 应用程序在启动时崩溃 - SecurityException

tomcat - Spring 启动 war log4j2

Spring Boot Taglibs

hibernate - hibernate session 中的持久数据变得陈旧,有时 hibernate 会生成重复的 ID

java - eclipse /tomcat : deploy doesn't work any more (ClassNotFoundException)

java - 如何为索引准备 Unicode 字符串?

java - 比较两个时间在java中是更大还是更小

java - 如何修改JXL中的空单元格?

java - 如何在 Spring Boot 中使用 Log4J2 复合配置

apache - 使用表单例份验证 apache tomcat 在表单错误页面上显示用户名