1
votes

After unsuccessfully searching for a solution I finally gave up. I am trying to deploy a test application which uses Spring Boot and Spring Security. When I run my application locally everything works perfectly fine - there are no errors or exceptions, and the application handles spring security well.

I use Gradle to build the project and then deploy it to Google App Engine. Before deploying I am trying to run my project locally by using the Google App Engine Gradle plugin, more specifically by using the appengineRun Gradle task.

After executing this particular task my application starts up normally, but when I try to access "/" on my localhost, the 403 error appears. I have no web.xml configuration file in my project, although I don't think that this is the crux of the matter. I do have an appengine-web.xml file, which is required by Google App Engine.

What would I to do to get my app working with this particular App Engine task? My main goals are to deploy the Spring Boot application on GAE and get Spring Security to work.

I include my java classes, build.gradle file and WEB-INF contents:

build.gradle:

buildscript {
    repositories {
        jcenter()
        mavenCentral()
    }
    dependencies {
        classpath 'com.google.cloud.tools:appengine-gradle-plugin:+'
        classpath("org.springframework.boot:spring-boot-gradle-plugin:2.0.0.RELEASE")

    }
}
repositories {

    maven {
        url 'https://oss.sonatype.org/content/repositories/snapshots'
        mavenCentral()
        jcenter()
    }

    apply plugin: 'java'
    apply plugin: 'war'
    apply plugin: 'com.google.cloud.tools.appengine'
    apply plugin: 'org.springframework.boot'
    apply plugin: 'io.spring.dependency-management'
    bootJar {
        baseName = 'gs-spring-boot'
        version = '0.1.0'
    }

    dependencies {
        compile group: 'com.google.appengine', name: 'appengine-api-1.0-sdk', version: '1.9.63'
        providedCompile 'javax.servlet:javax.servlet-api:3.1.0'
        compile 'jstl:jstl:1.2'
        compile("org.springframework.boot:spring-boot-starter-web")
        compile group: 'org.springframework.boot', name: 'spring-boot-starter-actuator', version: '2.0.0.RELEASE'
        compile group: 'org.springframework.boot', name: 'spring-boot-starter-security', version: '2.0.0.RELEASE'
        compile 'com.google.cloud:google-cloud:+'
        testCompile 'junit:junit:4.12'
        testCompile 'com.google.truth:truth:0.33'
        testCompile 'org.mockito:mockito-all:1.10.19'
        testCompile 'com.google.appengine:appengine-testing:+'
        testCompile 'com.google.appengine:appengine-api-stubs:+'
        testCompile 'com.google.appengine:appengine-tools-sdk:+'
    }

    appengineDeploy.dependsOn test
    appengineStage.dependsOn test

    appengine {
        run {
            port = 8090
        }

        deploy {   // deploy configuration
        }
    }

    test {

        useJUnit()
        testLogging.showStandardStreams = true
        beforeTest { descriptor ->
            logger.lifecycle("test: " + descriptor + "  Running")
        }

        onOutput { descriptor, event ->
            logger.lifecycle("test: " + descriptor + ": " + event.message)
        }
        afterTest { descriptor, result ->
            logger.lifecycle("test: " + descriptor + ": " + result)
        }
    }

    group = "com.example.appenginej8"
    version = "1.0.0-SNAPSHOT"

    sourceCompatibility = 1.8
    targetCompatibility = 1.8
}

appengine-web.xml:

<appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
    <version>1</version>
    <threadsafe>true</threadsafe>
    <runtime>java8</runtime>
</appengine-web-app>

Application.java:

@SpringBootApplication
@ComponentScan("packages")
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

MyController.java:

@RestController
public class MyController {


    @RequestMapping("/")
    public String hello() {
        return "test";
    }
}

SecurityConfig.java:

@EnableWebSecurity
public class SecurityConfig {

        @Bean
        public UserDetailsService userDetailsService() {
            InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
            manager.createUser(User.withDefaultPasswordEncoder().username("user").password("password").roles("ADMIN").roles("ACTUATOR").build());
            return manager;
        }
}
1
Someone help, please :)JacekDuszenko
I think this has nothing to do with Spring Boot Security. I completed removed the SecurityConfig class, and the local dev sever still returns 403.Chanseok Oh

1 Answers

7
votes

You need SpringBootServletInitializer to magically make Spring Boot function as a traditional Servlet WAR.

import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;

public class ServletInitializer extends SpringBootServletInitializer {

  @Override
  protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
    return application.sources(Application.class);
  }

}

This should make it work basically. I noticed you would still hit a different but minor issue after adding this class, but it should be trivial to fix.