'springboot war working with embedded tomcat but not with external tomcat
I have been working on a springboot 2.3.4 application with spring security. It's working with embedded tomcat. We want to make it work with external application servers like tomcat and jboss. I have tried to deploy the war file in external tomcat server. when hitting the endpoints I receive 404 error code. Here is my pom file:
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.4.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.teradata</groupId>
<artifactId>modelstudio</artifactId>
<version>1</version>
<name>modelstudio</name>
<packaging>war</packaging>
<description>ModelStudio Application</description>
<properties>
<java.version>13</java.version>
<start-class>
com.teradata.modelstudio.ModelStudioApplication
</start-class>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
<exclusion>
<groupId>org.skyscreamer</groupId>
<artifactId>jsonassert</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.teradata.jdbc</groupId>
<artifactId>terajdbc4</artifactId>
<version>17</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20200518</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<exclusions>
<exclusion>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<finalName>modelstudio</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
<includes>
<include>static/**</include>
</includes>
</resource>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
<excludes>
<exclude>ModelStudioUI/**</exclude>
<exclude>static/**</exclude>
</excludes>
</resource>
</resources>
</build>
</project>
My JWT Entry point is:
package com.teradata.modelstudio.filter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import com.teradata.modelstudio.service.CustomAuthenticationProviderService;
import com.teradata.modelstudio.utils.JwtUtil;
import com.teradata.modelstudio.utils.Logger;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.regex.Pattern;
@Component
public class JwtFilter extends OncePerRequestFilter {
@Autowired
private JwtUtil jwtUtil;
@Autowired
private CustomAuthenticationProviderService service;
@Autowired JwtUserDetailsService jwtUserDetailsService;
@Override
protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {
String requestURI = httpServletRequest.getRequestURI();
Logger.info("==================="+requestURI);
Pattern mega = Pattern.compile(
"\\/*.css|\\/*.js|\\/*.png|\\/*.jpg|\\/assets\\/*.*|\\/*.woff2|\\/*.woff|\\/*.ttf|\\/swagger-resources\\/*|/servicemanagement/configuration/*|/servicemanagement/etlframework/*|/servicemanagement/refreshCache/*");
// System.out.println(requestURI);
if (httpServletRequest.getMethod().equals("OPTIONS")// || requestURI.equalsIgnoreCase("/index.html")
|| requestURI.equalsIgnoreCase("/favicon.ico") || mega.matcher(requestURI).find() || requestURI.equalsIgnoreCase("/")) {
filterChain.doFilter(httpServletRequest, httpServletResponse);
return;
}
// TODO Auto-generated method stub
String url = httpServletRequest.getRequestURL().toString();
// System.out.println("+++URL in jwt request filter:"+url);
if (url.contains("auth") || url.contains("dbcontent") || url.contains("favico")) {
filterChain.doFilter(httpServletRequest, httpServletResponse);
return;
}
String requestTokenHeader = httpServletRequest.getHeader("Authorization");
String username = null;
String password = null;
String serverUrl = null;
String dbName = null;
String authType = null;
String jwtToken = null;
if (requestTokenHeader != null && requestTokenHeader.startsWith("Bearer ")) {
jwtToken = requestTokenHeader.substring(7);
try {
username = jwtUtil.getUsernameFromJWT(jwtToken);
password = jwtUtil.getPasswordFromJWT(jwtToken);
serverUrl = jwtUtil.getServerUrlFromJWT(jwtToken);
dbName = jwtUtil.getDbNameFromJWT(jwtToken);
authType = jwtUtil.getAuthTypeFromJWT(jwtToken);
jwtUtil.validateToken(jwtToken, username);
} catch (Exception e) {
throw e;
}
} else {
throw new IOException("Invalid Authorization");
}
SecurityContextHolder.getContext().setAuthentication(null);
if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
UserDetails userDetails = jwtUserDetailsService.loadUserByUsername(username);
if (jwtUtil.validateToken(jwtToken, username)) {
CustomUserPrincipal customUserPrincipal = new CustomUserPrincipal(username, password, serverUrl, dbName, authType);
UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken =
new UsernamePasswordAuthenticationToken(customUserPrincipal, null, userDetails.getAuthorities());
usernamePasswordAuthenticationToken
.setDetails(new WebAuthenticationDetailsSource().buildDetails(httpServletRequest));
SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
}
}
filterChain.doFilter(httpServletRequest, httpServletResponse);
}
}
My Security config file:
package com.teradata.modelstudio.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.BeanIds;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import com.teradata.modelstudio.filter.JwtFilter;
import com.teradata.modelstudio.payload.JwtAuthenticationResponse;
import com.teradata.modelstudio.security.JwtAuthenticationEntryPoint;
import com.teradata.modelstudio.service.CustomAuthenticationProviderService;
@EnableWebSecurity
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private CustomAuthenticationProviderService authenticationProviderService;
@Autowired
private JwtFilter jwtFilter;
@Autowired
JwtAuthenticationEntryPoint unauthorizedHandler;
@Autowired
private com.teradata.modelstudio.filter.SimpleCORSFilter simpleCORSFilter;
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable().authorizeRequests()
.antMatchers(
HttpMethod.GET,
"/",
"/*.html",
"/*.svg",
"/*.png",
"/*.woff",
"/*.woff2",
"/*.svg",
"/*.jpg",
"/*.json",
"/favicon.ico",
"/**/*.html",
"/**/*.css",
"/**/*.js",
"/**/*.svg",
"/**/*.png",
"/**/*.jpg",
"/**/*.ico",
"/**/*.icons",
"/resources/**",
"/assets/",
"/static/**",
"/h2-console/**"
).permitAll()
.antMatchers("/auth/**", "/dbcontent/**")
.permitAll()
.anyRequest().authenticated()
.and().exceptionHandling().and().sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
http.addFilterBefore(simpleCORSFilter, UsernamePasswordAuthenticationFilter.class);
http.addFilterBefore(jwtFilter, UsernamePasswordAuthenticationFilter.class);
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(authenticationProviderService);
}
@Bean(name = BeanIds.AUTHENTICATION_MANAGER)
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
}
One of my controller classes are:
package com.teradata.modelstudio.controllers;
import java.io.File;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.teradata.modelstudio.exception.ModelStudioException;
import com.teradata.modelstudio.utils.Logger;
import org.apache.commons.io.FileUtils;
import org.json.JSONObject;
@RestController
@RequestMapping("dbcontent")
public class DBContentController {
@GetMapping(path="servers", produces = "application/json")
public ResponseEntity<?> getServers() {
try {
String dbConFilePath = System.getProperty("user.dir")+File.separator+"db-con";
File file = new File(dbConFilePath);
String content = FileUtils.readFileToString(file, "utf-8");
// Convert JSON string to JSONObject
JSONObject fileContents = new JSONObject(content);
return ResponseEntity.ok(fileContents.toString());
} catch(Exception e) {
Logger.error("Unable to get servers: "+e.getMessage());
throw new ModelStudioException(e.getMessage());
}
}
}
Here is my main class
package com.teradata.modelstudio;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
import org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration;
import org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
@SpringBootApplication(
exclude = { DataSourceAutoConfiguration.class,
HibernateJpaAutoConfiguration.class,
DataSourceTransactionManagerAutoConfiguration.class,
})
public class ModelstudioApplication extends SpringBootServletInitializer{
public static void main(String[] args) {
SpringApplication.run(ModelstudioApplication.class, args);
}
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
return builder.sources(ModelstudioApplication.class);
}
}
With embedded tomcat serever, I hit:
localhost:8080/dbcontent/servers
and I get the results while on external I do the following:
localhost:8080/modelstudio/dbcontent/servers
and I get 404.
Can anyone please help and advise me how to resolve this issue with external server like tomcat.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|
