vaadin / flow

Vaadin Flow is a Java framework binding Vaadin web components to Java. This is part of Vaadin 10+.
Apache License 2.0
603 stars 165 forks source link

VaadinWebSecurity - csrf protection on Login ignored for Webflow but active in Hilla? #17427

Open egloffmark opened 1 year ago

egloffmark commented 1 year ago

Description of the bug

While I am creating an own "Login" form with Vaadin flow I recognized that the "_csrf" token get not validated for Webflow Login Page.

I looked at the class VaadinWebSecurity and debugged its configuration art runtime it seems that it adds a request filter which excludes the login request from CSRF prtotection. Hence, the csrf protection seems to be disabled, but csrf tokens get generated and added into the pages.

I am wondering why the documentation mention this explicitly for the login component, See section "Technical" at the Login component documention. Also in the other method for Hilla setLoginView(hillaLoginViewPath) the login path get not excluded

I like to understand if I miss or oversee here something?

public abstract class VaadinWebSecurity {

 // Login Path for Webflow Excluded for CSRF
 protected void setLoginView(HttpSecurity http,
            Class<? extends Component> flowLoginView, String logoutSuccessUrl)
            throws Exception {
            ....
            http.csrf()
                .ignoringRequestMatchers(new AntPathRequestMatcher(loginPath));
            ...
 }

   // Login path for Hilla NOT Excluded for CSRF
   protected void setLoginView(HttpSecurity http, String hillaLoginViewPath,
            String logoutSuccessUrl) throws Exception {
        hillaLoginViewPath = applyUrlMapping(hillaLoginViewPath);
        FormLoginConfigurer<HttpSecurity> formLogin = http.formLogin();
        formLogin.loginPage(hillaLoginViewPath).permitAll();
        formLogin.successHandler(
                getVaadinSavedRequestAwareAuthenticationSuccessHandler(http));
        configureLogout(http, logoutSuccessUrl);
        http.exceptionHandling().defaultAuthenticationEntryPointFor(
                new LoginUrlAuthenticationEntryPoint(hillaLoginViewPath),
                AnyRequestMatcher.INSTANCE);
        viewAccessChecker.setLoginView(hillaLoginViewPath);
  }
...
}

I also added a break point on the org.springframework.security.web.server.csrf.CsrfWebFilter but the filter get not called in the Weblof Variant but for the Hilla Variant.

So I am here now a bit confused. Can you please clarify why you disable it at the LoginView configuration for Webflow?

The only explanation I have that you may use another Spring Security Filter for validating your csrf but I could not find it.

logged SecurityFilterChain:

org.springframework.security.web.session.DisableEncodeUrlFilter@66e3eb8c
org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@3c26b21
org.springframework.security.web.context.SecurityContextHolderFilter@2900213
org.springframework.security.web.header.HeaderWriterFilter@d5a59f4
org.springframework.security.web.csrf.CsrfFilter@16c2e85
org.springframework.security.web.authentication.logout.LogoutFilter@6be91f9a
org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter@45d53963
org.springframework.security.web.savedrequest.RequestCacheAwareFilter@62e80cc2
org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@362172f7
org.springframework.security.web.authentication.AnonymousAuthenticationFilter@269960
org.springframework.security.web.access.ExceptionTranslationFilter@5ea14797
org.springframework.security.web.access.intercept.AuthorizationFilter@74cee53c

Expected behavior

CSRF protection for login and other Forms should be activated and it should be transparent for which requests and where the validation is happening

Minimal reproducible example

  1. Take Example app from Start with Vaadin Weblow
  2. Configure the Spring Security by using VaadinWebSecurity
  3. Register an Own Login View
  4. Debug how the CSRF Token get validated e.g. breakpoint at CSRFWeb Filter

Versions

mshabarov commented 1 year ago

@egloffmark thank you for making an issue and asking! Do you have a project example? We are interested in point 2 and 3:

Configure the Spring Security by using VaadinWebSecurity
Register an Own Login View

(how you configure these).

egloffmark commented 1 year ago

I simple using the standard generated from Vaadin Application / Project initializer at https://start.vaadin.com. There you can setup a flow application with authentication. See below the generated Security configuration.

The problem is not the SecurityConfiguration it is more that the methods on VaadinWebSecurityclass for setLoginView for Flow and Hilla have different implementations regarding the CSRF. Personally I don't understand why you turn CSRF by default off for the Flow SetLoginView implementation

@EnableWebSecurity
@Configuration
public class SecurityConfiguration extends VaadinWebSecurity {

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

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

        http.authorizeHttpRequests().requestMatchers(new AntPathRequestMatcher("/images/*.png")).permitAll();

        // Icons from the line-awesome addon
        http.authorizeHttpRequests().requestMatchers(new AntPathRequestMatcher("/line-awesome/**/*.svg")).permitAll();
        super.configure(http);
        setLoginView(http, LoginView.class);
    }
}
mcollovati commented 9 months ago

Flow has its own CSRF mechanism for its internal request, so Flow views are protected in this way instead of using Spring. On the other hand, the login web component can also be used without Flow, so it offers a way to handle CSRF tokens that may be handled by the server.