LoginForm - Simulate setAction("login")

Hi,
I have a question for Vaadin Flow23 with SpringBoot and SpringSecurity.
Due to necessary enhancements in the LoginForm, I cannot use anymore the login.setAction(“login”), which posts automatically the form data to SpringSecurity.
Instead I have a login event listener which authorizes the user using SpringSecurity directly.

What I need now is that after successful authentication, the ServiceInitEvents are sent like with the original setAction(“login”).
How can I achieve this?

`private void login(LoginEvent e) {
String username = e.getUsername();
String password = e.getPassword();
String mandant = cbMandanten.getValue();
PakAuthenticationToken authenticationToken = new PakAuthenticationToken(username, password, mandant);
authenticationToken.setDetails(new WebAuthenticationDetails(VaadinServletRequest.getCurrent()
.getHttpServletRequest()));

try {
  Authentication authentication = authenticationManager.authenticate(authenticationToken);
  if (authentication.isAuthenticated()) {
    SecurityContextHolder.getContext()
                         .setAuthentication(authentication);

    // Here I need to have the same thing as with setAction("login") instead of navigation
    getUI().ifPresent(ui -> ui.navigate(PakView.class));
  }
} catch (BadCredentialsException | UsernameNotFoundException ex) {
  e.getSource()
   .setError(true);
  e.getSource()
   .setEnabled(true);
}

}`

Best regards,
Erik

Hard to grasp what you’ve done and missing. Your explanation sounds like the usage of a spring Security Filter that handles login, but the code tells other things

ok, the login event listener is new.
The original code contains the setAction(“login”) call just like described in the docs.

Now we need additional information for authentication which cannot be sent because the login form does not support them.
So we enhanced the form with a Combobox, removed the setAction(…) and added a manual login with authentication.
All of it does work as expected, but now the VaadinServiceInitListener does not get called anymore.

My question is, if and how this can be achieved?

I have a feeling that both aren’t really meant to be used together / without the dedicated spring filters. Meaning… you probably have to replace the whole form with a custom form that contains 3 fields and a button… because the setAction is always creating a post request that is handled by spring Security and does not reach your code… you could try to setAction (null) and see if that bypasses springs filters - but I’m not sure

Maybe I did not get the question correctly, but VaadinServiceInitListener is not invoked after login, but at server startup, when Vaadin is initialized

Good catch… could be a total different question :sweat_smile: overlooked that / read LoginEvent again

I’ve checked this by reverting my changes. After calling the spring authentication via LoginForm.submit(), the ServiceInitEvent is called. Everytime after login. And that’s what I want to with manual authentication.
It is this what I mean:

@Override public void serviceInit(ServiceInitEvent serviceInitEvent) { serviceInitEvent .getSource() .addUIInitListener( uiInitEvent -> { ... }); }

As far as I understand it, this is called on UI initialization which happens (again) after login

:thinking: and the code above works / the login event is thrown and you just want to have a new UI once you authenticated the user?

UI.getCurrent().getPage().reload();

Could do that

Even tho… I have a feeling something is “weirdly” designed in the application.

Nothing of the code above is made by us! The LoginForm was nearly exactly like described in the docs when using SpringSecurity. Do you think it is a wrong behaviour that the UiInitListener gets called after login?

Do you mean the UIInitListener?

Yes, the UiInitListener is part of VaadinServiceInitListener, isn’t it?

Ok. They have two different lifecycles.
VaadinServiceInitListener is invoked only at server startup, the UiInitListener every time a new UI is created

yes, and within the UIInitListener some of our session handling takes place, so we have to get it called, just like it happens with the setAction(“login”) behaviour

With the login action a new UI is created after the login is processed. With your solution you continue to use the same UI that was created for the Login view
If you want a new UI you should do a page reload as @quirky-zebra suggested

ok, I’ll give it a try - Thank you both

You can also take a look here Securing Plain Java Applications | Advanced Security Topics | Security | Vaadin Docs for an example
On successfull login, it redirects to a different page with UI.getPage().setLocation(....)

it works :+1: