App layout should not be rendered when login view is visible
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
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
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.
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
Your MainLayout is configured like so
@Layout
@AnonymousAllowed
so that's exactly what has happened here.
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
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?
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.
Or as an alternative we could just document autoLayout = false for use with LoginOverlay.
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.
Also what if app layout is wanted when login is shown.
Already documented here https://vaadin.com/docs/latest/building-apps/views/add-router-layout/flow#opting-out.
Could be a note in LoginOverlay component.
Should we mark
LoginOverlaywith@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.
Another scenario could be that the LoginOverlay is initially closed and the layout should be visible.