【问题标题】:AbstractAuthenticationProcessingFilter is not firing before UsernamePasswordAuthenticationFilterAbstractAuthenticationProcessingFilter 在 UsernamePasswordAuthenticationFilter 之前未触发
【发布时间】:2017-06-03 03:49:15
【问题描述】:

向所有 Spring 专家致敬!

我有一个问题想解决一段时间,但我认为我已经走到了死胡同。

所以基本上我需要的是将我的 Spring-Security(在 Spring-Boot 中)配置为具有两种身份验证机制(一种用于 Legacy JSP 页面,一种用于 REST API)。所以我关注了以下帖子: multiple authentication mechanisms in a single app using java config

它与一个 LDAP 身份验证提供程序一起工作得很好。但后来我尝试扩展我的 LDAP 连接以从第三方服务获取票证(将用于未来与其他服务的连接),我遇到了问题。

所以我创建了一个新的身份验证令牌、过滤器和身份验证提供程序,但无论我做什么,都会首先触发默认的UsernamePasswordAuthenticationFilter

我尝试关注这个帖子How to configure a custom filter programatically in Spring Security?,发现问题可能在于我的过滤器正在扩展UsernamePasswordAuthenticationFilter。所以我删除了这个并尝试了一个简单的AbstractAuthenticationProcessingFilter,仍然 - 没有运气。

我认为问题出在我的 WebSecurity 配置中。目前,使用我要分享的以下代码,REST Api 身份验证返回 405 - 方法不允许 并且旧版登录卡在无限循环中并崩溃,甚至在我点击“登录”之前.

@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true) //Enables @PreAuthorize on methods
public class WebSecurityConfig  extends WebSecurityConfigurerAdapter {

    @Autowired
    private LDAPConfigurationBean ldapBean;

    @Autowired
    protected void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
//HERE GOES LDAP CONNECTION STUFF               
//      Add the custom LDAP + Token provider to the Authentication provider chain
        auth.authenticationProvider(new TicketAndLDAPAuthenticationProvider(authenticator,authoritiesPopulator));

//        Creating an LDAP provider using the authenticator and the populator.
        auth.authenticationProvider(new LdapAuthenticationProvider(authenticator,authoritiesPopulator));

    }


    @Configuration
    @Order(1)
    public static class ConfigureFilters extends WebSecurityConfigurerAdapter {
        protected void configure(HttpSecurity http) throws Exception {
            http.csrf().disable();
            http.addFilterBefore(new TicketAndLDAPAuthenticationFilter(),UsernamePasswordAuthenticationFilter.class);
        }
    }

    //Management Endpoints Authorization
    @Configuration
    @Order(2)
    public static class EndpointsWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {
        protected void configure(HttpSecurity http) throws Exception {
            http
                    .antMatcher("/manage/health")
                    .authorizeRequests()
                    .anyRequest().permitAll();
        }
    }

    //API Authentication+Authorization
    @Configuration
    @Order(3)
    public static class ApiWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {

        @Autowired
        private RestAuthenticationEntryPoint authenticationEntryPoint;
        @Autowired
        private RestAuthSuccessHandler authSuccessHandler;
        @Autowired
        private RestAuthFailureHandler authFailureHandler;
        @Autowired
        private RestLogoutSuccessHandler logoutSuccessHandler;

        private String LOGIN_PATH = "/api/authenticate";
        private String USERNAME = "username";
        private String PASSWORD = "password";

        protected void configure(HttpSecurity http) throws Exception {
            /*CSRF configuration*/
            http.csrf().disable();

            http
                    .antMatcher(LOGIN_PATH)
                    .authorizeRequests()
                    .anyRequest().permitAll();

            http
                    .antMatcher("/api/**")
                    //Stateless session creation - no session will be created or used by Spring Security
                    .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                    .and()
                    .exceptionHandling()
                        .authenticationEntryPoint(authenticationEntryPoint)
                    .and()
                    .formLogin().permitAll()
                        .loginProcessingUrl(LOGIN_PATH)
                        .usernameParameter(USERNAME)
                        .passwordParameter(PASSWORD)
                        .successHandler(authSuccessHandler)
                        .failureHandler(authFailureHandler)
                    .and()
                    .logout().permitAll()
                        .logoutSuccessHandler(logoutSuccessHandler);

            http
                    .authorizeRequests().anyRequest().authenticated();
        }
    }

    //JSP Authentication+Authorization
    @Configuration
    @Order(4)
    public static class FormLoginWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {

        @Override
        protected void configure(HttpSecurity http) throws Exception {
            /*CSRF configuration*/
            http.csrf().disable();

            /*Static content*/
            http
                    .authorizeRequests()
                    .antMatchers("/css*//**").permitAll()
                    .antMatchers("/images*//**").permitAll()
                    .antMatchers("/scripts*//**").permitAll()
                    .antMatchers("/fonts*//**").permitAll()
                    .antMatchers("/login*").anonymous();

        /*Login / Logout configuration*/
            http
                    .formLogin()
                        .loginPage("/login.htm").permitAll()
                        .defaultSuccessUrl("/index.htm?name=******")
                        .failureUrl("/login.htm?error=true")
                    .and()
                    .logout().permitAll()
                        .logoutSuccessUrl("/login.htm")
                        .invalidateHttpSession(true)
                        .deleteCookies("JSESSIONID");

        /*URL roles authorizations*/
            http
                    .authorizeRequests().anyRequest().authenticated();
        }
    }
}

如您所见,我正在尝试在“配置过滤器”方法中配置我的过滤器 - 但我也尝试在适配器内部配置它,带/不带 @Bean 注释 - 都没有运气。

过滤器:

public class TicketAndLDAPAuthenticationFilter  extends AbstractAuthenticationProcessingFilter {
    public TicketAndLDAPAuthenticationFilter() {
        super("/*");
    }

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
        //Save the password for later
        String username = request.getParameter("username");
        String password = request.getParameter("password");

        TicketAndLDAPAuthenticationToken token = new TicketAndLDAPAuthenticationToken(username,password,null);

        return token;
    }
}

编辑:忘记添加到过滤器:

if ( request.getParameter( "username" ) == null || request.getParameter( "password" ) == null ) == null ) {
            return null;
        }

现在我在两种登录机制中都得到 405。

代币:

public class TicketAndLDAPAuthenticationToken  extends UsernamePasswordAuthenticationToken {
    private AuthTicket otp;
    private String restoredPassword;


    public TicketAndLDAPAuthenticationToken( String username, String password, RestAuthLoginTicket otp ) {
        super( username, password );
        this.otp = otp;
    }

    public AuthTicket getOTP() {
        return otp;
    }

    public AuthTicket getOtp() {
        return otp;
    }

    public void setOtp(AuthTicket otp) {
        this.otp = otp;
    }
}

提供者:

public class TicketAndLDAPAuthenticationProvider extends LdapAuthenticationProvider {

    @Autowired
    TokenUtils tokenUtils;

    public TicketAndLDAPAuthenticationProvider(LdapAuthenticator authenticator, LdapAuthoritiesPopulator authoritiesPopulator) {
        super(authenticator, authoritiesPopulator);
    }

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
              TicketAndLDAPAuthenticationToken token =  (TicketAndLDAPAuthenticationToken) super.authenticate(authentication);
        token.setOtp(tokenUtils.getTicket(token));
        return token;
    }


    @Override
    public boolean supports(Class<?> authentication) {
        return TicketAndLDAPAuthenticationToken.class.isAssignableFrom(authentication);
    }
}

提前致谢!!

【问题讨论】:

    标签: java spring-mvc authentication spring-security


    【解决方案1】:

    所以我发现了问题。

    首先,配置身份验证管理器的正确方法不是我上面的配置,因为没有antMatcher,这导致我的资源和页面对所有人开放。

    其次,导致无限重定向和错误 405 的问题是我没有定义我的过滤器来接受帖子。

    修复该问题后,我的 JSP 登录表单和身份验证机制工作正常,但“/api”重定向到登录页面而不是资源。

    是什么让我想到了最后一点——http.formLogin() 正在创建一个UsernamePasswordAuthenticationFilter。我有两个 - 每个登录一个。所以我必须为每个登录添加http.addFilterBefore(),但使用不同的 URL。 “/api” url 再次使用 Spring 的默认重定向而不是我定义的重定向,所以我不得不覆盖它们。

    这些是对我有用的配置和过滤器:

    安全配置:

    @EnableWebSecurity
    @EnableGlobalMethodSecurity(prePostEnabled = true) //Enables @PreAuthorize on methods
    public class WebSecurityConfig  extends WebSecurityConfigurerAdapter {
    
        @Autowired
        private LDAPConfigurationBean ldapBean;
    
        @Autowired
        protected void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
    
            //LDAP Stuff
    
            TicketAndLDAPAuthenticationProvider ticketAndLDAPAuthenticationProvider = new TicketAndLDAPAuthenticationProvider(authenticator,authoritiesPopulator);
            auth.authenticationProvider(ticketAndLDAPAuthenticationProvider);
    
            LdapAuthenticationProvider ldapAuthenticationProvider = new LdapAuthenticationProvider(authenticator,authoritiesPopulator);
            auth.authenticationProvider(ldapAuthenticationProvider);    
        }
    
        //Management Endpoints Authorization
        @Configuration
        @Order(1)
        public static class EndpointsWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {
            protected void configure(HttpSecurity http) throws Exception {
                http
                        .antMatcher("/manage/health")
                        .authorizeRequests()
                        .anyRequest().permitAll();
            }
        }
    
        //API Authentication+Authorization
        @Configuration
        @Order(2)
        public static class ApiWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {
    
            @Autowired
            private RestAuthenticationEntryPoint authenticationEntryPoint;
            @Autowired
            private RestAuthSuccessHandler authSuccessHandler;
            @Autowired
            private RestAuthFailureHandler authFailureHandler;
            @Autowired
            private RestLogoutSuccessHandler logoutSuccessHandler;
    
            private String LOGIN_PATH = "/api/authenticate";
    
            protected void configure(HttpSecurity http) throws Exception {
                /*CSRF configuration*/
                http.csrf().disable();
    
                http.addFilterBefore(new TicketAndLDAPAuthenticationFilter(LOGIN_PATH,authSuccessHandler,authFailureHandler), UsernamePasswordAuthenticationFilter.class);
    
                http
                        .antMatcher("/api/**")
    //                    Stateless session creation - no session will be created or used by Spring Security
                        .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                        .and()
                        .exceptionHandling()
                            .authenticationEntryPoint(authenticationEntryPoint)
                        .and()
                        .logout().permitAll()
                            .logoutSuccessHandler(logoutSuccessHandler);
    
                http
                        .authorizeRequests().anyRequest().authenticated();
    
            }
        }
    
        //JSP Authentication+Authorization
        @Configuration
        @Order(3)
        public static class FormLoginWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
    
            private String LOGIN_PATH = "/login.htm";
    
            @Override
            protected void configure(HttpSecurity http) throws Exception {
                /*CSRF configuration*/
                http.csrf().disable();
    
                http.addFilterBefore(new TicketAndLDAPAuthenticationFilter(LOGIN_PATH), UsernamePasswordAuthenticationFilter.class);
    
                /*Static content*/
                http
                        .authorizeRequests()
                        .antMatchers("/css*//**").permitAll()
                        .antMatchers("/images*//**").permitAll()
                        .antMatchers("/scripts*//**").permitAll()
                        .antMatchers("/fonts*//**").permitAll()
                        .antMatchers("/login*").anonymous();
    
            /*Login / Logout configuration*/
                http
                        .formLogin()
                            .loginPage(LOGIN_PATH).permitAll()
                            .defaultSuccessUrl("/index.htm?name=******")
                            .failureUrl("/login.htm?error=true")
                        .and()
                        .logout().permitAll()
                            .logoutSuccessUrl("/login.htm")
                            .invalidateHttpSession(true)
                            .deleteCookies("JSESSIONID");
    
            /*URL roles authorizations*/
                http
                        .authorizeRequests().anyRequest().authenticated();
            }
        }
    }
    

    还有过滤器:

    public class TicketAndLDAPAuthenticationFilter  extends AbstractAuthenticationProcessingFilter {
    
        public TicketAndLDAPAuthenticationFilter(String defaultProcessUrl) {
            super(new AntPathRequestMatcher(defaultProcessUrl, "POST"));
        }
    
        public TicketAndLDAPAuthenticationFilter(String defaultProcessUrl, AuthenticationSuccessHandler authenticationSuccessHandler, AuthenticationFailureHandler authenticationFailureHandler) {
            super(new AntPathRequestMatcher(defaultProcessUrl, "POST"));
            setAuthenticationFailureHandler(authenticationFailureHandler);
            setAuthenticationSuccessHandler(authenticationSuccessHandler);
        }
    
        @Override
        public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
            //Save the password for later
            String username = request.getParameter("username");
            String password = request.getParameter("password");
    
            if ( username==null || password==null) {
                return null;
            }
    
            TicketAndLDAPAuthenticationToken token = new TicketAndLDAPAuthenticationToken(username,password,null);
    
            return token;
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-04-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多