单个Spring安全配置中的Kerberos,X509和Oauth2

时间:2018-08-09 04:00:16

标签: java spring-boot spring-security oauth-2.0 kerberos

我想在单个spring安全配置中配置所有三种(Kerberos,X509和OAuth2)身份验证机制。

情况1 :所有功能都应同时正常运行。

情况2 :如果第一个身份验证提供程序返回任何异常或未经授权,则其他身份验证提供程序会自动触发。

示例 :如果请求被kerberos未经授权,则应尝试进行X509身份验证。

问题1: Oauth 2和Kerberos无法一起使用。协商请求由 SpnegoAuthenticationProcessingFilter 发起,但协商响应由 OAuth2AuthenticationEntryPoint.commence 方法获取,并引发以下异常

“访问此资源需要完整身份验证”

如果我在安全配置中注释掉OAuth依赖项和相关配置,则其工作正常。

问题2::如果Kerbeors身份验证失败,我该如何处理响应并调用其他身份验证配置?

在下面检查我当前的工作代码:

@EnableWebSecurity
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Configuration
    @Order(2)
    public static class PermitUnsecuredEndpoints extends WebSecurityConfigurerAdapter {
        protected void configure(HttpSecurity http) throws Exception {
            http
                    .csrf().disable()
                    .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.NEVER).and()
                    .requestMatchers()
                    .antMatchers(
                            "/info",
                           ...
                           ...
                            "/api-docs/**",
                    )
                    .and()
                    .authorizeRequests()
                    .anyRequest().permitAll();
        }
    }

    @Configuration
    @Order(4)
    public static class Kerberos extends WebSecurityConfigurerAdapter {

        @Value("${app.service-principal}")
        private String servicePrincipal;

        @Value("${app.keytab-location}")
        private String keytabLocation;

        @Value("${app.kerberos-conf}")
        private String krb5Location;

        @Override
        protected void configure(HttpSecurity httpSecurity) throws Exception {

            httpSecurity
                    .exceptionHandling()
                    .authenticationEntryPoint(spnegoEntryPoint())
                    .and().authorizeRequests().anyRequest().authenticated()
                    .and().formLogin()
                    .and().addFilterBefore(spnegoAuthenticationProcessingFilter(authenticationManagerBean()),
                    BasicAuthenticationFilter.class);
        }

        @Override
        protected void configure(AuthenticationManagerBuilder auth) throws Exception {
            auth

                    .authenticationProvider(kerberosAuthenticationProvider())
                    .authenticationProvider(kerberosServiceAuthenticationProvider());
        }

        @Bean(name = BeanIds.AUTHENTICATION_MANAGER)
        @Override
        public AuthenticationManager authenticationManagerBean() throws Exception {
            return super.authenticationManagerBean();
        }

        @Bean
        public KerberosAuthenticationProvider kerberosAuthenticationProvider() {
            KerberosAuthenticationProvider provider =
                    new KerberosAuthenticationProvider();
            SunJaasKerberosClient client = new SunJaasKerberosClient();
            client.setDebug(true);
            provider.setKerberosClient(client);
            provider.setUserDetailsService(dummyUserDetailsService());
            return provider;
        }

        @Bean
        public SpnegoEntryPoint spnegoEntryPoint() {
            return new SpnegoEntryPoint();
        }


        @Bean
        public SpnegoAuthenticationProcessingFilter spnegoAuthenticationProcessingFilter(
                AuthenticationManager authenticationManager) {
            SpnegoAuthenticationProcessingFilter filter = new SpnegoAuthenticationProcessingFilter();
            filter.setFailureHandler(new AuthenticationFailureHandler() {
                                         @Override
                                         public void onAuthenticationFailure(
                                                 HttpServletRequest request,
                                                 HttpServletResponse response,
                                                 AuthenticationException ae) throws IOException, ServletException {
                                             response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
                                         }
                                     }
            );
            filter.setAuthenticationManager(authenticationManager);
            return filter;
        }


        @Bean
        public KerberosServiceAuthenticationProvider kerberosServiceAuthenticationProvider() throws Exception {
            KerberosServiceAuthenticationProvider provider = new KerberosServiceAuthenticationProvider();
            provider.setTicketValidator(sunJaasKerberosTicketValidator());
            provider.setUserDetailsService(dummyUserDetailsService());
            return provider;
        }

        @Bean
        public SunJaasKerberosTicketValidator sunJaasKerberosTicketValidator() throws Exception {
            SunJaasKerberosTicketValidator ticketValidator = new SunJaasKerberosTicketValidator();
            final GlobalSunJaasKerberosConfig krb5Config = new GlobalSunJaasKerberosConfig();
            krb5Config.setKrbConfLocation(krb5Location);
            krb5Config.afterPropertiesSet();
            ticketValidator.setServicePrincipal(servicePrincipal);
            ticketValidator.setKeyTabLocation(new FileSystemResource(keytabLocation));
            ticketValidator.setDebug(true);
            ticketValidator.afterPropertiesSet();
            return ticketValidator;
        }


        @Bean
        public SunJaasKrb5LoginConfig loginConfig() {
            SunJaasKrb5LoginConfig loginConfig = new SunJaasKrb5LoginConfig();

            loginConfig.setKeyTabLocation(new FileSystemResource(keytabLocation));
            loginConfig.setServicePrincipal(servicePrincipal);
            loginConfig.setDebug(true);
            loginConfig.setIsInitiator(true);
            loginConfig.setUseTicketCache(true);
            return loginConfig;
        }

        @Bean
        public DummyUserDetailsService dummyUserDetailsService() {
            return new DummyUserDetailsService();
        }
    }

    @Configuration
    @Order(5)
    public static class X509Endpoints extends WebSecurityConfigurerAdapter {

        private static final String CN_PATTERN = "CN=(.*?)(?:,|$)";

        protected void configure(HttpSecurity http) throws Exception {
            http
                    .csrf().disable()
                    .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.NEVER).and()
                    .authorizeRequests().anyRequest().authenticated().and()
                    .x509().subjectPrincipalRegex(CN_PATTERN)
                    .authenticationUserDetailsService(new X509AuthenticatedUserDetailsService());
        }

        protected static class X509AuthenticatedUserDetailsService implements AuthenticationUserDetailsService<PreAuthenticatedAuthenticationToken> {
            @Override
            public UserDetails loadUserDetails(PreAuthenticatedAuthenticationToken token) throws UsernameNotFoundException {
                X509Certificate certificate = (X509Certificate) token.getCredentials();
                return new User(certificate.getSubjectX500Principal().getName(), "", Lists.newArrayList());
            }
        }
    }

/*    *
     * Configuration for authenticating JWT tokens.
     *
     * Default order is 3.  Can possibly be changed with:
     * security:
     *   oauth2:
     *     resource:
     *       filter-order: 3*/
    @Configuration
    @EnableResourceServer
    public static class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {

        private final static String EMAIL_KEY = "email";

        private final ResourceServerProperties resourceServerProperties;

        public ResourceServerConfiguration(ResourceServerProperties resourceServerProperties) {
            this.resourceServerProperties = resourceServerProperties;
        }

        @Bean
        public TokenStore jwkTokenStore() {

            DefaultAccessTokenConverter accessTokenConverter = new DefaultAccessTokenConverter();
            accessTokenConverter.setUserTokenConverter(new DefaultUserAuthenticationConverter() {
                @Override
                public Map<String, ?> convertUserAuthentication(Authentication userAuthentication) {
                    Map<String, ?> stringMap = super.convertUserAuthentication(userAuthentication);
                    return stringMap;
                }

                @Override
                public Authentication extractAuthentication(Map<String, ?> map) {
                    if (map.containsKey(EMAIL_KEY)) {
                        String email = map.get(EMAIL_KEY).toString();
                        User user = new User(email, "N/A", Collections.emptySet());
                        return new UsernamePasswordAuthenticationToken(user, "N/A", null);
                    }
                    return null;
                }

                @Override
                public String toString() {
                    return "DefaultUserAuthenticationConverter";
                }
            });
            return new JwkTokenStore(this.resourceServerProperties.getJwk().getKeySetUri(), accessTokenConverter);
        }

        @Override
        public void configure(HttpSecurity http) throws Exception {
            http
                    .csrf().disable()
                    .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.NEVER).and()
                    .requestMatcher(new RequestHeaderRequestMatcher("Authorization"))
                    .authorizeRequests()
                    .anyRequest().authenticated();
        }

        @Override
        public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
            resources.resourceId(resourceServerProperties.getId());
        }
    }
}
  • 订单2用于不安全的端点
  • 订单3 OAuth2
  • 4号Kerberos
  • 订购5 X509

0 个答案:

没有答案