Spring Security для REST WebService: защита одной и той же конечной точки с помощью двух разных аутентификаций.пути - PullRequest
0 голосов
/ 05 марта 2019

У меня есть два метода аутентификации в моем REST WebService:

  • Внутренний единый вход
  • Сертификат (X.509)

Каждый изэтот метод защищает разные конечные точки, но теперь мне нужно, чтобы одна конечная точка отвечала за оба метода, если первый отказывает, он вызывает второй (и наоборот).Возможно ли это в Spring Security?

Вот мой код безопасности для обоих методов:

    @Configuration
    @Order(1)
    public static class X509WebSecurityConfig extends WebSecurityConfigurerAdapter {

        private SecurityUtil securityUtil;

        @Autowired
        public X509WebSecurityConfig(SecurityUtil securityUtil) {
            this.securityUtil = securityUtil;
        }

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

            http.antMatcher("/cert/**")
                    .authorizeRequests()
                    .anyRequest().hasRole("X509");
            http.x509().subjectPrincipalRegex("CN=(.*?)(?:,|$)").authenticationUserDetailsService(preAuthenticatedX509());
        }

        @Bean
        public AuthenticationUserDetailsService<PreAuthenticatedAuthenticationToken> preAuthenticatedX509() {
            return token -> {
                if ("MYCERTCN".equalsIgnoreCase(token.getName())) {
                    return securityUtil.createUserFromCertificate();
                }
                throw new UsernameNotFoundException("Could not validate CN provided for X.509 authentication. CN provided: " + token.getName());
            };
        }
    }

    @Configuration
    @Order(2)
    public static class GeneralWebSecurityConfig extends WebSecurityConfigurerAdapter {

        private CustomAccessDeniedHandler customAccessDeniedHandler;
        private UserServiceAuth userService;

        @Autowired
        public GeneralWebSecurityConfig(CustomAccessDeniedHandler customAccessDeniedHandler,
                                        UserServiceAuth userService) {
            this.customAccessDeniedHandler = customAccessDeniedHandler;
            this.userService = userService;
        }

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

            http.authorizeRequests().antMatchers("/api/**").hasAnyRole(ApplicationRole.REGULAR_USER.name());
            http.authorizeRequests().antMatchers("/error").permitAll();
            http.exceptionHandling().accessDeniedHandler(customAccessDeniedHandler);
            http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);

            http.jee()
                    .authenticatedUserDetailsService(userService)
                    .addObjectPostProcessor(new ObjectPostProcessor<J2eePreAuthenticatedProcessingFilter>() {
                        @Override
                        public J2eePreAuthenticatedProcessingFilter postProcess(J2eePreAuthenticatedProcessingFilter filter) {
                            return new MyUserFilter(http);
                        }
                    });

            http.csrf().disable();
        }
    }

private static class MyUserFilter extends J2eePreAuthenticatedProcessingFilter {

        MyUserFilter(HttpSecurity http) {
            setAuthenticationDetailsSource(createWebAuthenticationDetailsSource());
            setAuthenticationManager(http.getSharedObject(AuthenticationManager.class));
        }

        @Override
        protected Object getPreAuthenticatedPrincipal(HttpServletRequest request) {
            return request.getUserPrincipal();
        }

        private J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource createWebAuthenticationDetailsSource() {
            J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource detailsSource = new J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource();
            SimpleMappableAttributesRetriever rolesRetriever = new SimpleMappableAttributesRetriever();
            rolesRetriever.setMappableAttributes(Collections.emptySet());
            detailsSource.setMappableRolesRetriever(rolesRetriever);
            return detailsSource;
        }
    }

Это то, что у меня сегодня и отлично работает для префиксов отдельных конечных точек.

Но теперь я хотел бы что-то вроде этого:

@Configuration
    @Order(3)
    public static class BothWebSecurityConfig extends WebSecurityConfigurerAdapter {

        private CustomAccessDeniedHandler customAccessDeniedHandler;
        private UserServiceAuth userService;
        private SecurityUtil securityUtil;

        @Autowired
        public BothWebSecurityConfig(CustomAccessDeniedHandler customAccessDeniedHandler,
                                     UserServiceAuth userService,
                                     SecurityUtil securityUtil) {
            this.customAccessDeniedHandler = customAccessDeniedHandler;
            this.userService = userService;
            this.securityUtil = securityUtil;
        }

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

            http.antMatcher("/both/**")
                    .authorizeRequests()
                    .anyRequest().hasRole(ApplicationRole.X509.name());
            http.x509().subjectPrincipalRegex("CN=(.*?)(?:,|$)").authenticationUserDetailsService(preAuthenticatedX509Both());

            http.antMatcher("/both/**").authorizeRequests().anyRequest().hasAnyRole(ApplicationRole.REGULAR_USER.name());
            http.exceptionHandling().accessDeniedHandler(customAccessDeniedHandler);
            http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
            http.jee()
                    .authenticatedUserDetailsService(userService)
                    .addObjectPostProcessor(new ObjectPostProcessor<J2eePreAuthenticatedProcessingFilter>() {
                        @Override
                        public J2eePreAuthenticatedProcessingFilter postProcess(J2eePreAuthenticatedProcessingFilter filter) {
                            return new MyUserFilter(http);
                        }
                    });

            http.csrf().disable();
        }

        @Bean
        public AuthenticationUserDetailsService<PreAuthenticatedAuthenticationToken> preAuthenticatedX509Both() {
            return token -> {
                if ("MYCERTCN".equalsIgnoreCase(token.getName())) {
                    return securityUtil.createUserFromCertificate();
                }
                throw new UsernameNotFoundException("Could not validate CN provided for X.509 authentication. CN provided: " + token.getName());
            };
        }
    }

Но вышеупомянутое игнорирует безопасность X509 и всегда идет ко второму способу (JEE).

Можно защитить то же самоеконечная точка с двумя различными методами, X.509 и JEE (если один не удается перейти к другому и наоборот?).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...