0

I have set up a Rest Controller in a simple vaadin application, it has a very basic request mapping of type Post, when hitting the endoint it should print to the log some text. However when hitting the endpoint from postman I receive a 200 ok and in the body an automated html page.

I have set up Rest Controllers in other projects and never had this problem before. I know that I have missed something simple (I hope!) but I just cant find what the problem is.

The complete source code is here: https://github.com/nonWhistle/tkhmm-home.git

Any advice on this would be much appreciated.

Below is the Restcontroller and POM files, The entry point to the application is annotated with @SpringBootApplication and I think the RestController is being picked up in the component scan because the constructor prints "Created".

Im suspicous this could be a problem with how my security is configured and so I have included below my SecurityConfiguration class.

RestController

package com.tkhmm.application.rest;

import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;

import java.util.logging.Logger;

@RestController
@RequestMapping(value = "/tkhmm/cv")
public class CvViewController {

private static final Logger log = Logger.getLogger(CvViewController.class.getSimpleName());

protected static final String API_KEY_HEADER_NAME = "api-key";

public CvViewController() {
    log.info("Created");
}

@PostMapping("/labeltext/{message}")
@ResponseStatus(HttpStatus.OK)
public void updateLabelTextInCvView(@PathVariable("message") String message,
                                    @RequestHeader(name = API_KEY_HEADER_NAME) String apiKey) {
    log.info("HERE -> " + message);
    log.info("HERE -> " + apiKey);
}

@PostMapping("/test")
public void test() {
    log.info("HERE");
}
}

POM.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<!-- Project from https://start.vaadin.com/project/5da11fe1-c5a6-48ba-b4e2-dd8ab29c346d -->
<groupId>com.tkhmm.application</groupId>
<artifactId>tkhmm</artifactId>
<name>tkhmm</name>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>

<properties>
    <java.version>11</java.version>
    <vaadin.version>23.3.2</vaadin.version>
    <!-- this parameter is needed as spring-boot bom overwrites it -->
    <selenium.version>4.5.3</selenium.version>
</properties>

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.7.5</version>
</parent>

<repositories>
    <!-- The order of definitions matters. Explicitly defining central here to make sure it has the highest priority. -->

    <!-- Main Maven repository -->
    <repository>
        <id>central</id>
        <url>https://repo.maven.apache.org/maven2</url>
        <snapshots>
            <enabled>false</enabled>
        </snapshots>
    </repository>
    <repository>
        <id>vaadin-prereleases</id>
        <url>
            https://maven.vaadin.com/vaadin-prereleases/
        </url>
    </repository>
    <!-- Repository used by many Vaadin add-ons -->
    <repository>
        <id>Vaadin Directory</id>
        <url>https://maven.vaadin.com/vaadin-addons</url>
        <snapshots>
            <enabled>false</enabled>
        </snapshots>
    </repository>
</repositories>

<pluginRepositories>
    <!-- The order of definitions matters. Explicitly defining central here to make sure it has the highest priority. -->
    <pluginRepository>
        <id>central</id>
        <url>https://repo.maven.apache.org/maven2</url>
        <snapshots>
            <enabled>false</enabled>
        </snapshots>
    </pluginRepository>
    <pluginRepository>
        <id>vaadin-prereleases</id>
        <url>
            https://maven.vaadin.com/vaadin-prereleases/
        </url>
    </pluginRepository>
</pluginRepositories>

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>com.vaadin</groupId>
            <artifactId>vaadin-bom</artifactId>
            <version>${vaadin.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

<dependencies>
    <dependency>
        <groupId>com.vaadin</groupId>
        <!-- Replace artifactId with vaadin-core to use only free components -->
        <artifactId>vaadin</artifactId>
    </dependency>
    <dependency>
        <groupId>com.vaadin</groupId>
        <artifactId>vaadin-spring-boot-starter</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-security</artifactId>
    </dependency>

    <dependency>
        <groupId>com.h2database</groupId>
        <artifactId>h2</artifactId>
        <scope>runtime</scope>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-validation</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
        <optional>true</optional>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>com.vaadin</groupId>
        <artifactId>vaadin-testbench</artifactId>
        <scope>test</scope>
    </dependency>
    <!-- Include JUnit 4 support for TestBench and others -->
    <dependency>
        <groupId>org.junit.vintage</groupId>
        <artifactId>junit-vintage-engine</artifactId>
        <scope>test</scope>
        <exclusions>
            <exclusion>
                <groupId>org.hamcrest</groupId>
                <artifactId>hamcrest-core</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
    <dependency>
        <groupId>io.github.bonigarcia</groupId>
        <artifactId>webdrivermanager</artifactId>
        <version>5.1.1</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.postgresql</groupId>
        <artifactId>postgresql</artifactId>
        <version>42.3.7</version>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.18.20</version>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>com.mashape.unirest</groupId>
        <artifactId>unirest-java</artifactId>
        <version>1.4.9</version>
    </dependency>

</dependencies>

<build>
    <defaultGoal>spring-boot:run</defaultGoal>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <!-- Clean build and startup time for Vaadin apps sometimes may exceed
                 the default Spring Boot's 30sec timeout.  -->
            <configuration>
                <jvmArguments>-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=5122</jvmArguments>
                <wait>500</wait>
                <maxAttempts>240</maxAttempts>
            </configuration>
        </plugin>

        <!--
            Take care of synchronizing java dependencies and imports in
            package.json and main.js files.
            It also creates webpack.config.js if not exists yet.
        -->
        <plugin>
            <groupId>com.vaadin</groupId>
            <artifactId>vaadin-maven-plugin</artifactId>
            <version>${vaadin.version}</version>
            <executions>
                <execution>
                    <goals>
                        <goal>prepare-frontend</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
    <finalName>tkhmm-home</finalName>
</build>

<profiles>
    <profile>
        <!-- Production mode is activated using -Pproduction -->
        <id>production</id>
        <build>
            <plugins>
                <plugin>
                    <groupId>com.vaadin</groupId>
                    <artifactId>vaadin-maven-plugin</artifactId>
                    <version>${vaadin.version}</version>
                    <executions>
                        <execution>
                            <goals>
                                <goal>build-frontend</goal>
                            </goals>
                            <phase>compile</phase>
                        </execution>
                    </executions>
                    <configuration>
                        <productionMode>true</productionMode>
                    </configuration>
                </plugin>
            </plugins>
        </build>
    </profile>

    <profile>
        <id>it</id>
        <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                    <executions>
                        <execution>
                            <id>start-spring-boot</id>
                            <phase>pre-integration-test</phase>
                            <goals>
                                <goal>start</goal>
                            </goals>
                        </execution>
                        <execution>
                            <id>stop-spring-boot</id>
                            <phase>post-integration-test</phase>
                            <goals>
                                <goal>stop</goal>
                            </goals>
                        </execution>
                    </executions>
                </plugin>

                <!-- Runs the integration tests (*IT) after the server is started -->
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-failsafe-plugin</artifactId>
                    <executions>
                        <execution>
                            <goals>
                                <goal>integration-test</goal>
                                <goal>verify</goal>
                            </goals>
                        </execution>
                    </executions>
                    <configuration>
                        <trimStackTrace>false</trimStackTrace>
                        <enableAssertions>true</enableAssertions>
                    </configuration>
                </plugin>
            </plugins>
        </build>
    </profile>

</profiles>

Security Configuration

package com.tkhmm.application.security;

import com.tkhmm.application.views.login.LoginView;
import com.vaadin.flow.spring.security.VaadinWebSecurity;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

@EnableWebSecurity
@Configuration
public class SecurityConfiguration extends VaadinWebSecurity {

@Bean
public PasswordEncoder passwordEncoder() {
    return new BCryptPasswordEncoder();
}

@Override
protected void configure(HttpSecurity http) throws Exception {

    http.authorizeRequests().requestMatchers(new AntPathRequestMatcher("/images/*.png")).permitAll();
    super.configure(http);
    setLoginView(http, LoginView.class);
}

}

1 Answers1

2

If VaadinServelt is mapped to the root maping (default) , you have to tell it to ignore your controller path, by setting vaadin.exclude-urls in the application.properties file, e.g.

vaadin.exclude-urls=/tkhmm/**

Here's a link to the documentation page https://vaadin.com/docs/latest/integrations/spring/configuration/#prevent-handling-of-specific-urls

In addition, you should probably disable CSRF for the controller and authorize it in the security configuration

protected void configure(HttpSecurity http) throws Exception {
    ...
    http.authorizeRequests(auth -> auth.mvcMatchers("/tkhmm/**").permitAll());
    http.csrf().ignoringAntMatchers("/tkhmm/**");
    ...
    super.configure(http);
    ...
}

To debug what is happening, you can also set the spring security logger to DEBUG level in application.properties

logging.level.org.springframework.security=DEBUG
Marco C
  • 706
  • 4
  • 6
  • Thanks for the responce, I was very hopeful that this was the solution for my problem, however I have added the param to app.props in different arrangements (/tkhmm/**) (tkhmm/**) (/tkhmm/cv/**) (/tkhmm/cv/test) and I still get the vaadin default page. Iv also tried removing the RouteAlias("") annotation from my view with no success. Is there anything else that may be causing this I could try? – Tom Milton Apr 25 '23 at 15:06
  • Its also worth mentioning that I double checked the value from app.props was being brought into the application by printing it out on application start up. – Tom Milton Apr 25 '23 at 15:07
  • You should also disable CSRF for your controller and configure authorization in security config class. I'll update the answer with the details – Marco C Apr 25 '23 at 15:46
  • Thank you for taking the time to look into this for me, thats worked! :D – Tom Milton Apr 25 '23 at 19:58