Redirect to keycloak login only for certain views

In my Vaadin 24.5 application with keycloak as oauth2 provider, most views should be visible without restriction, and only one view should be visible only to logged-in users of a certain role.

@Route("foo")
@AnonymousAllowed
public class FooView extends VerticalLayout
@Route("bar")
@RolesAllowed("ADMIN")
public class BarView extends VerticalLayout

Since the HTML link to BarView is not in a menu or similar where an AccessChecker checks, I could use the annotation @RolesAllowed. However, since Vaadin itself has no mechanism of its own for displaying the login page / keyclock only when required, I want to take the spring way via the requestMatcher.

However, the documentation recommends:

Vaadin strongly recommends not to mix Spring’s URL-pattern-based HTTP security and this view-based access control mechanism targeting the same views.

So I removed all the view access annotations and only use Spring’s own security mechanisms:

http.authorizeHttpRequests(auth -> auth
    .requestMatchers(antMatchers("/shoppingcart")).hasRole("USER")
    .requestMatchers(antMatchers("/*")).anonymous())

The application starts, the default route (‘/’) is displayed without login. But when I click on the link that points to ‘/shoppingcart’, I get the error page:

Access to 'shoppingcart' is denied by security rules.

here the logs

Checking access for view ShoppingCartView
00:25:49.679 | DEBUG | c.v.f.s.auth.RoutePathAccessChecker      | Access to view 'ShoppingCartView' with path 'shoppingcart' is denied
00:25:49.679 | DEBUG | f.s.a.DefaultAccessCheckDecisionResolver | Access to view 'ShoppingCartView' with path 'shoppingcart' denied by 1 out of 1 navigation checkers  (0 neutral).
00:25:49.679 | DEBUG | c.v.f.s.auth.NavigationAccessControl     | Decision against 1 checker results: Access decision: DENY. Access to 'shoppingcart' is denied by security rules.

Declaring an ExceptionHandling does not help either, although I am not sure if this is correct

.exceptionHandling(c -> c.authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/oauth2/authorization/keycloak")))

A SavedRequestAwareCache or something like that must surely be added here so that the originally requested route becomes available again after the login and can be called again.

What do I have to do to make some views in my Vaadin application accessible anonymously without login, and only show the keycloak login for some others when starting the corresponding route?

Kind regards
Dominik

I do not understand what’s wrong with the @RolesAllowed.

Can you explain why you don’t want to use annotations?

Hi Simon,

thank you, for your response.

The annotations are normally already checked when the navigation menu items are created. If this AccessCheck is negative, the menu item is not even displayed.
However, I would like to check whether the current user is logged in at all and has a certain role when try to starting the shoppingCart view. If not, the keycloak authorisation should be run and then the view should be displayed afterwards.

I have tried

a) to react to the AccessDeniedError according to the Vaadin way: ErrorHandler or via HasErrorParameter<AccessDenied|RouteNotFound>: but here you cannot simply redirect to the keycloak login page in case of an error. Interestingly, as the default Vaadin error page contains all available routes, if I manually click this respective route /shoppingcart then the redirect to keycloak happened. However, I then don’t know how to display the originally requested view again after logging in… hence the reference to SavedRequestAwareCache

b) react to the exception with Spring Security means: exceptionHandling and LoginAuthEntryPoint … but that doesn’t work either.

If the pure Vaadin way with the view access annotations would also work for the above scenario, I would like to stay with the view annotations…

Kind regards
Dominik

I’m not sure if I understood the problem correctly, but annotation should work fine.
You need to set the login view path to the identity provider entry point, then if you try to access a protected view, you will be redirected to the login page

VaadinWebSecurity has setOAuth2LoginPage() method for this.

This comes from your extending of VaadinWebSecurity - which in turn is “deny by default” to prevent “view leakage”. If you wanna go with Spring Security by antMatchers I would personally recommend to not extend from the mentioned above class. But keep in mind that this comes with the caveat that you need to reimplement some communication.

P.S. you still need to check roles in your views because not all navigations are done so that spring security can check it

I still don’t understand the problem.

I usually use the SideNav and the protected view is also in the navigation without AccessAnnotationChecker protection.

In this case, you might consider RoutePathAccessChecker, to be sure that Spring security rules are applied also during Flow navigation.

1 Like