flow icon indicating copy to clipboard operation
flow copied to clipboard

App layout should not be rendered when login view is visible

Open abdullahtellioglu opened this issue 2 months ago • 12 comments

Description of the bug

In a flow application following view is used to render a LoginView, which is fine

@Route(value = "login")
public class LoginView extends LoginOverlay implements BeforeEnterObserver {

    private final AuthenticationContext authenticationContext;

    public LoginView(AuthenticationContext authenticationContext) {
        this.authenticationContext = authenticationContext;
        setAction(RouteUtil.getRoutePath(VaadinService.getCurrent().getContext(), getClass()));

        LoginI18n i18n = LoginI18n.createDefault();
        i18n.setHeader(new LoginI18n.Header());
        i18n.getHeader().setTitle("My App");
        i18n.getHeader().setDescription("Login using user/user or admin/admin");
        i18n.setAdditionalInformation(null);
        setI18n(i18n);

        setForgotPasswordButtonVisible(false);
        setOpened(true);
    }

    @Override
    public void beforeEnter(BeforeEnterEvent event) {
        if (authenticationContext.isAuthenticated()) {
            setOpened(false);
            event.forwardTo("");
        }

        setError(event.getLocation().getQueryParameters().getParameters().containsKey("error"));
    }
}

But when you open the login view in the browser you can see that it is a child of the app layout. When you remove the login overlay from the DOM, you can have access to application routes, which looks wrong and may leak unwanted data to anonymous users

https://github.com/user-attachments/assets/df1e04e0-a3af-449f-ae7c-3580c3b56c03

Expected behavior

I would expect login view present in the UI as a standalone view. App layout should not be present in the DOM.

Minimal reproducible example

Download Flow project from start, enable spring security using Copilot then enter /login page or use the attached project

app 7.zip

Versions

Hilla: 24.9.3 Flow: 24.9.3 Vaadin: 24.9.3 Spring Boot: 3.5.6 Spring: 6.2.11 Spring Security: Spring Data JPA: Copilot: 24.9.3 Frontend Hotswap: Disabled ⋅ Pre-built Bundle OS: aarch64 Mac OS X 14.7.1 Java: JetBrains s.r.o. 21.0.5 Browser: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Java Hotswap: Java Hotswap is enabled IDE Plugin: 1.0-SNAPSHOT IntelliJ

abdullahtellioglu avatar Oct 29 '25 09:10 abdullahtellioglu

That's by design if you use @Layout so that all views automatically get the default layout. You might wanna add @Route(value = "login", autoLayout = false) to your login view.

knoobie avatar Oct 29 '25 11:10 knoobie

LoginView does not have @Layout annotation in the example.

Additionally, I would expect autoLayout feature to be disabled by default if not explicitly set true for view marked as Login view in security configuration

abdullahtellioglu avatar Oct 29 '25 11:10 abdullahtellioglu

Your MainLayout is configured like so

@Layout
@AnonymousAllowed

so that's exactly what has happened here.

knoobie avatar Oct 29 '25 11:10 knoobie

I see. I still think that this should be reversed in a way that Login view should not be rendered as a child of Layout if not explicitly set autoLayout to true

abdullahtellioglu avatar Oct 29 '25 11:10 abdullahtellioglu

When you use @Layout, you want your regular views to be automatically rendered inside the app layout, e.g.

@Route(value = "patients")
public class PatientView extends VerticalLayout implements BeforeEnterObserver {

What information can the framework use to know that this view should be handled in a different way?

@Route(value = "login")
public class LoginView extends LoginOverlay implements BeforeEnterObserver {

It doesn't seem reasonable that the framework would have a hardcoded special case for views that inherit specifically from LoginOverlay?

Legioth avatar Nov 03 '25 11:11 Legioth

What we could consider doing is to add a marker interface or annotation to the framework that works for any component to tell that it should break out of any router layout. And then we'd make LoginOverlay use that interface/annotation. In that way, it would work for any view and not only the login view, and it would also also be possible for other components to use if it they have that particular generic escape requirement without requiring explicit configuration in @Route.

Legioth avatar Nov 03 '25 12:11 Legioth

Or as an alternative we could just document autoLayout = false for use with LoginOverlay.

mshabarov avatar Nov 04 '25 11:11 mshabarov

Should we mark LoginOverlay with @Layout? My assumption is that it would then match itself a as a layout whenever it is used as a route, therefore discarding other layouts by default for such a route.

platosha avatar Nov 04 '25 11:11 platosha

Also what if app layout is wanted when login is shown.

mshabarov avatar Nov 04 '25 11:11 mshabarov

Already documented here https://vaadin.com/docs/latest/building-apps/views/add-router-layout/flow#opting-out. Could be a note in LoginOverlay component.

mshabarov avatar Nov 04 '25 11:11 mshabarov

Should we mark LoginOverlay with @Layout?

That would also make regular views render inside LoginOverlay which might be relatively surprising.

Also what if app layout is wanted when login is shown.

Then you use LoginForm instead of LoginOverlay. The overlay variant will always render on top of the entire application - there's no way to make it only cover the content area of an AppLayout without also covering the sidebar.

Legioth avatar Nov 04 '25 12:11 Legioth

Another scenario could be that the LoginOverlay is initially closed and the layout should be visible.

mcollovati avatar Nov 04 '25 12:11 mcollovati