Search code examples
spring-bootspring-securityvaadin

Vaadin 24 + Spring Boot 3 + Spring Security - How to Authenticate via a SOAP Endpoint


I'm a total newbie to both Vaadin and Java - so I apologize in advance if I'm asking a question that is totally LAME - or has been answered elsewhere (I have done extensive Google and Stackoverflow searches - and have not been able to find what I need).

SO - I need to authenticate a Vaadin 24 application with Spring 3 using Spring Security against a SOAP endpont.

The rest endpoint takes a username and password - and will return a SOAP response like:

<?xml version="1.0" encoding="UTF-8"?>
<SSOAPI version="2.0">
    <Response>
        <RequestStatusCode>0</RequestStatusCode>
        <RequestStatusMessage>OK</RequestStatusMessage>
        <SSOTokenStr></SSOTokenStr>
        <uid>jdoe</uid>
        <FullName>Doe_John</FullName>
        <IdType>AD</IdType>
        <eMail>[email protected]</eMail>
        <UserGroup>Group 1</UserGroup>
        <UserGroup>Group 2</UserGroup>
        <UserGroup>Group 3</UserGroup>
    </Response>
</SSOAPI>

A FAILED response would be:

<?xml version="1.0" encoding="UTF-8"?>
<SSOAPI version="2.0">
    <Response>
        <RequestStatusCode>1326</RequestStatusCode>
        <RequestStatusMessage>Failed : Invalid Credentials</RequestStatusMessage>
        <SSOTokenStr></SSOTokenStr>
        <uid>rcusickk</uid>
        <FullName></FullName>
        <MednetUserGroup></MednetUserGroup>
    </Response>
</SSOAPI>

I have a basic Vaadin login view that looks like this:

@Route("login")
public class LoginView extends Composite<LoginOverlay>{

    
    public LoginView(){
        LoginOverlay loginOverlay = getContent();
        loginOverlay.setTitle("My App");
        loginOverlay.setDescription("Log in requires an account");
        loginOverlay.setOpened(true);
        
        loginOverlay.addLoginListener(event -> {
            try{
                
                authService.authenticate(event.getUsername(), event.getPassword());
                UI.getCurrent().navigate("home");
                
            } catch (Exception e) {
                
                
            }
            
        });
    }
}

I would like to just setup a service ("authService" above) that will allow me to connect to a URL, pass in URL params with userName and password (via POST) and then get back a response that I can then just parse and and if there is Request Status Code > 0 - to return the Request Status code.

There are 1,000,000 examples of using a database to authenticate - but I need to authenticate via a SOAP endpoint URL.

Any hints to the Yellow Brick Road would be appreciated!

I've tried to create an "Auth Service" - so I can just make sure it passed in the username and password:

class AuthService {
    
    public class AuthException extends Exception {
        
    }
    
    public AuthService(){
        
    }
    
    public void authenticate(String username, String password) {
        
        System.out.println("User: " + username + ", pass: " + password);
    }
}

and I also tried to reference the service via the login view:

@Route("login")
public class LoginView extends Composite<LoginOverlay>{

    
    public LoginView(AuthService authService){
        LoginOverlay loginOverlay = getContent();
        loginOverlay.setTitle("My App");
        loginOverlay.setDescription("Log in requires an account");
        loginOverlay.setOpened(true);
        
        loginOverlay.addLoginListener(event -> {
            try{
                
                authService.authenticate(event.getUsername(), event.getPassword());
                UI.getCurrent().navigate("home");
                
            } catch (Exception e) {
                
                
            }
            
        });
    }
}

RESULT ERROR when displaying the LoginView:

There was an exception while trying to navigate to 'login' with the root cause 'org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.example.application.views.login.AuthService' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}'
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'com.example.application.views.login.LoginView': Unsatisfied dependency expressed through constructor parameter 0: No qualifying bean of type 'com.example.application.views.login.AuthService' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}

Solution

  • Route and referenced router layouts are automatically instantiated by Vaadin and if you are using the Vaadin Spring support that will delegate the task to the regular Spring dependency injection.

    The error you are seeing is Spring not being able to instantiate AuthService, which you have not configured to take part in DI. Add a @Service annotation to your AuthService and make sure Spring can see it (e.g. put it in a package beside or below your Application class).

    This said: if you want to go against the grain of Spring security, I'd suggest to not use it at all. Otherwise consider making your AuthService a UserDetailService and call your SOAP endpoints there. The mentioned 1.000.000 DB tutorials also have pointers on how to query the DB yourself and this is the place where you would put your own authn code.