0

Right now I'm preparing my Vaadin 23.2.5 application for production and very often after redeploy the application unable to fully reload itself and hangs with fat blue progress bar at the top.

The only issue I may see, is the following JS issue in the browser console:

FireFox

enter image description here

Chrome

enter image description here

Also, based on my previous questions on this subject - I completely removed the Grid component from the application, but as you may see - the issue still exists. How to solve this issue?

UPDATED

My configs:

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true)
public class SecurityConfiguration extends VaadinWebSecurityConfigurerAdapter {

    private final ClientRegistrationRepository clientRegistrationRepository;
    private final GrantedAuthoritiesMapper authoritiesMapper;
    private final ProfileService profileService;

    SecurityConfiguration(ClientRegistrationRepository clientRegistrationRepository,
                          GrantedAuthoritiesMapper authoritiesMapper, ProfileService profileService) {
        this.clientRegistrationRepository = clientRegistrationRepository;
        this.authoritiesMapper = authoritiesMapper;
        this.profileService = profileService;
        SecurityContextHolder.setStrategyName(VaadinAwareSecurityContextHolderStrategy.class.getName());
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        super.configure(http);
        http
                // Enable OAuth2 login
                .oauth2Login(oauth2Login ->
                        oauth2Login
                                .clientRegistrationRepository(clientRegistrationRepository)
                                .userInfoEndpoint(userInfoEndpoint ->
                                        userInfoEndpoint
                                                // Use a custom authorities mapper to get the roles from the identity provider into the Authentication token
                                                .userAuthoritiesMapper(authoritiesMapper)
                                )
                                // Use a Vaadin aware authentication success handler
                                .successHandler(new KeycloakVaadinAuthenticationSuccessHandler(profileService))
                )
                // Configure logout
                .logout(logout ->
                        logout
                                // Enable OIDC logout (requires that we use the 'openid' scope when authenticating)
                                .logoutSuccessHandler(logoutSuccessHandler())
                                // When CSRF is enabled, the logout URL normally requires a POST request with the CSRF
                                // token attached. This makes it difficult to perform a logout from within a Vaadin
                                // application (since Vaadin uses its own CSRF tokens). By changing the logout endpoint
                                // to accept GET requests, we can redirect to the logout URL from within Vaadin.
                                .logoutRequestMatcher(new AntPathRequestMatcher("/logout", "GET"))
                );
    }

    @Bean
    @Primary
    public SpringViewAccessChecker springViewAccessChecker(AccessAnnotationChecker accessAnnotationChecker) {
        return new KeycloakSpringViewAccessChecker(accessAnnotationChecker, "/oauth2/authorization/keycloak");
    }

    private OidcClientInitiatedLogoutSuccessHandler logoutSuccessHandler() {
        var logoutSuccessHandler = new OidcClientInitiatedLogoutSuccessHandler(clientRegistrationRepository);
        logoutSuccessHandler.setPostLogoutRedirectUri("{baseUrl}");
        return logoutSuccessHandler;
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        super.configure(web);
        // Don't apply security rules on our static pages
        web.ignoring().antMatchers("/session-expired", "/images/*");
    }

    @Bean
    public PolicyFactory htmlSanitizer() {
        // This is the policy we will be using to sanitize HTML input
        return Sanitizers.FORMATTING.and(Sanitizers.BLOCKS).and(Sanitizers.STYLES).and(Sanitizers.LINKS);
    }

}


@Component
class VaadinSessionConfiguration implements VaadinServiceInitListener, SystemMessagesProvider, SessionDestroyListener {

    private final String relativeSessionExpiredUrl;

    VaadinSessionConfiguration(ServerProperties serverProperties) {
        relativeSessionExpiredUrl = UriComponentsBuilder.fromPath(serverProperties.getServlet().getContextPath()).path("logout").build().toUriString();
    }

    @Override
    public SystemMessages getSystemMessages(SystemMessagesInfo systemMessagesInfo) {
        var messages = new CustomizedSystemMessages();
        // Redirect to a specific screen when the session expires. In this particular case we don't want to logout
        // just yet. If you would like the user to be completely logged out when the session expires, this URL
        // should the logout URL.
        messages.setSessionExpiredURL(relativeSessionExpiredUrl);
        return messages;
    }

    @Override
    public void sessionDestroy(SessionDestroyEvent event) {
        // We also want to destroy the underlying HTTP session since it is the one that contains the authentication
        // token.
        try {
            event.getSession().getSession().invalidate();
        } catch (Exception ignore) {
            // Session was probably already invalidated.
        }
    }

    @Override
    public void serviceInit(ServiceInitEvent event) {
        event.getSource().setSystemMessagesProvider(this);
        event.getSource().addSessionDestroyListener(this);
    }

}

public final class VaadinAwareSecurityContextHolderStrategy implements SecurityContextHolderStrategy {

    private final ThreadLocal<SecurityContext> contextHolder = new ThreadLocal<>();

    @Override
    public void clearContext() {
        contextHolder.remove();
    }

    @Override
    @NonNull
    public SecurityContext getContext() {
        var context = contextHolder.get();
        if (context == null) {
            context = getFromVaadinSession().orElseGet(() -> {
                var newCtx = createEmptyContext();
                // This copies the behaviour of ThreadLocalSecurityContextHolder.
                contextHolder.set(newCtx);
                return newCtx;
            });
        }
        return context;
    }

    @NonNull
    private Optional<SecurityContext> getFromVaadinSession() {
        // Don't store this security context in the ThreadLocal as that may lead to the context leaking
        // into other sessions as threads may be reused.
        var session = VaadinSession.getCurrent();
        if (session == null) {
            return Optional.empty();
        }
        var securityContext = session.getSession().getAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY);
        if (securityContext instanceof SecurityContext) {
            return Optional.of((SecurityContext) securityContext);
        } else {
            return Optional.empty();
        }
    }

    @Override
    public void setContext(@NonNull SecurityContext securityContext) {
        contextHolder.set(requireNonNull(securityContext));
    }

    @Override
    @NonNull
    public SecurityContext createEmptyContext() {
        return new SecurityContextImpl();
    }
}

UPDATED 1

enter image description here

alexanoid
  • 24,051
  • 54
  • 210
  • 410
  • What does "very often" mean? What is fixing it? – cfrick Oct 21 '22 at 08:33
  • Looks like after every redeploy of the application jar file. Web application correctly detects that has to reload and fails to do that with the mentioned errors. I also updated my question, and added the Google Chrome console error – alexanoid Oct 21 '22 at 09:25
  • Is this a _running_ client and you replace the server-side? Or is this after a CTRL-F5-Reload with Cache disabled in the dev-tools? So what _does_ fix it? "Very often" means, you do something (maybe many times) and then it works again. – cfrick Oct 21 '22 at 10:17
  • This is a running application in the production mode. I have the application opened in the two different browsers - FF and Chrome. I redeploy the jar file in the production server environment. After a few seconds, the application in the browser window detects restart and tries to reload the page. And hangs with the issue mentioned in the question. Right after that I have two choices - reload the page in the browser manually, and it solves the reload issue,, or to wait a few mins and after a number of retries the application becomes working also. During this issue I see resync error in console – alexanoid Oct 21 '22 at 10:46
  • Do you persiste the sessions over restarts? – cfrick Oct 21 '22 at 10:47
  • Honestly, I don't know how to control that. Could you please instruct me? – alexanoid Oct 21 '22 at 10:51
  • I added my Spring Security and session configs to the question – alexanoid Oct 21 '22 at 11:01
  • added one more resync issue screenshot – alexanoid Oct 24 '22 at 23:48
  • I reimplemented my Vaadin app to support stateless approach with JWT in Cookie. Everything works perfect, except this really disruptive issue with resync on redeploy. Is there a chance it will be fixed? – alexanoid Oct 31 '22 at 14:33

0 Answers0