Vaadin application with additional endpoints

Hello all,

I have a vaadin application and want to create additional endpoints. Therefore, I tried many many things, but unfortunatley I’m not able to write my own web security config (without destorying my vaadin application).

My goals are:

  • run vaadin application without any security on “/myvaadinapp”
  • add additional endpoint “/endpoint1” without any security checks
  • add additional endpoint “/endpoint2” with security (basic auth)

Does anyone have an example? This would help me a lot :slight_smile:

Regards
Thomas

1 Like

Assuming you are using Spring Boot, if you want to secure only one endpoint and not the Vaadin application, write your own security configuration class not extending VaadinWebSecurity (Authorize HttpServletRequests :: Spring Security) and tell Vaadin to prevent handling endpoint urls (Configuration | Spring | Integrations | Flow | Vaadin Docs)

Thans for your information

@Configuration
@EnableWebSecurity
public class WebSecurityConfig {

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
	http.authorizeHttpRequests((requests) -> {

		requests.requestMatchers(antMatcher("/endpoint1/**")).permitAll();
		requests.requestMatchers(antMatcher("/endpoint2/**")).hasAuthority("superuser");
		requests.requestMatchers(antMatcher("/myvaadinapp/**")).permitAll();
		requests.requestMatchers(antMatcher("/swagger-ui/**")).permitAll();
		
		requests.anyRequest().denyAll();
	});

	http.httpBasic(Customizer.withDefaults());
	http.csrf((customizer) -> customizer.ignoringRequestMatchers("/myvaadinapp/**"));

	return http.build();
}

@Bean
public InMemoryUserDetailsManager userDetailsService() {
	UserDetails user = User.withDefaultPasswordEncoder()
			.username("user")
			.password("pass")
			.roles("superuser")
			.build();
    return new InMemoryUserDetailsManager(user);
}

}

I also tried this, but maybe no Vaadin issue. Unfortunatley I receive in Swagger for every test the window to enter user and password (I only wanted to have it for “entpoint2”. Second, the user and password will not be accepted in Swagger. Also I receive the window to add the credentials by opening the Vaadin application (“myvaadinapp”).

Did you try with a securityMatcher, as in the example in the linked page from Spring Security docs?

Also, looking at the question again, I suppose you defined a custom url mapping for Vaadin, so the exclude-urls does not have any effect in this case.

I tried, but I do not understand how to integrate the securityMatcher, because in the example (Spring Security Docs) it matches to “api” and the requestMatchers on “user” and “admin”. I is not clear for me how to adapt it in the above example.

Lookin at your config I would say something like

http
    .securityMatcher("/endpoint2/**")                            
    .authorizeHttpRequests(authorize ->
        authorize.anyRequest().hasAuthority("superuser");                  
    )

But I am not able to test it right now

Great, now I have it. But one problem. I added an additional SecurityChain to block all other endpoints. Now Vaadin app is not reachable anymore without allow specific endpoints in an additional security chain (“/vaadin/", "/VAADIN/”, “/frontend/", "/webjars/”). Are more needed?

@Bean
@Order(50)
public SecurityFilterChain defaultSecurityChain(HttpSecurity http) throws Exception {
	http
		.authorizeHttpRequests((requests) -> requests.anyRequest().denyAll())
		.csrf((customizer) -> customizer.disable());
	return http.build();
}

To protect a Vaadin application with Spring Security the preferred way is to extend VaadinWebSecurity

I do not want to protect the vaadin page. I only want to extend with additional endpoints. To extend the VaadinWebSecurity I have to set the setLoginView() and given each views @AnonymousAllowed annotations, etc.

Nevertheless by opening the web page I receive a white page with an red error text

Invalid JSON response from server: body, #outlet { height: 100vh; width: 100%; margin: 0; } .v-reconnect-dialog,.v-system-error {position: absolute;color: black;background: white;top: 1em;right: 1em;border: 1px solid black;padding: 1em;z-index: 10000;max-width: calc(100vw - 4em);max-height: calc(100vh - 4em);overflow: auto;} .v-system-error {color: indianred;pointer-events: auto;} .v-system-error h3, .v-system-error b {color: red;}[hidden] { display: none !important; }

If you don’t want to protect pages, why are you setting a deny all rule on every request?

Anyway, did you set up Vaadin with a custom url mapping ‘/myvaadinapp/**’? If so grant access to that path and to /VAADIN/**

You can also use VaadinWebSecurity without setting the login page and disabling access control

I thought it would by a good idea to protect everything and allow only endpoints which are allowed? Maybe my thinking is wrong?

it is a good idea.
But in this case to allow Vaadin requests the best way is to use VaadinWebSecurity. Otherwise you may have to replicate all configurations on your configuration class

Okay, thanks for the information. I added the two endpoints, but now the basic auth is not used anymore:

@Override
protected void configure(HttpSecurity http) throws Exception {
	http.securityMatcher("/endpoint1/**")
		.authorizeHttpRequests((requests) -> requests.requestMatchers("/endpoint1/**")
		.hasAuthority("superuser"))
		.httpBasic(withDefaults())
		.csrf((customizer) -> customizer.disable());
	
	http.securityMatcher("/endpoint2/**")
		.authorizeHttpRequests((requests) -> requests.requestMatchers("/endpoint2/**").permitAll())
		.csrf((customizer) -> customizer.disable());
	
    super.configure(http); 
}

For “endpoint1” I would expect using basic auth. Are all other endpoints now automatically protected?

You have to build separated security filter chains.
The one provided by VaadinWebSecurity requires user to be authenticated if no other rules are defined

By adding one additional method (SecurityFilterChain) my vaadin application is blocked and it is required to allow explicit this endpoint in another SecurityFilterChain. Sorry for my questions… ;-)

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends VaadinWebSecurity {

@Bean
public SecurityFilterChain basicAuth(HttpSecurity http) throws Exception {
	http.securityMatcher("endpoint1/**")
		.authorizeHttpRequests((requests) -> requests.anyRequest().hasAuthority("superuser"))
		.httpBasic(withDefaults())
		.csrf((customizer) -> customizer.disable());
	return http.build();
}
 
@Override
protected boolean enableNavigationAccessControl() {
	return false;
}


}

You are probably missing an order annotation.
Please take a look at this example configuration by @Matti
vaadin-with-rest-end-points-and-spring-security/src/main/java/in/virit/sb/example/security/SecurityConfig.java at main · mstahv/vaadin-with-rest-end-points-and-spring-security · GitHub

1 Like

Ah, okay… understand… :slight_smile: But I think it is still a bit random, because the SecurityFilterChain in VaadinWebSecurity has no Order annotation?

You can override the annotated method from VaadinWebSecurity and apply order annotation. Just remember to also duplicate the bean annotation