- Increase the security of "shutdownWorker" and "cancelShutdownWorker" endpoints, by only allowing the requests, which come from the same machine.

- Update the "UriBuilder.java" to be able to take the running port of the server, in case the port-number was initially set to "random" (0).
This commit is contained in:
Lampros Smyrnaios 2022-09-12 16:38:44 +03:00
parent 25070d7aba
commit d73a99b1c0
3 changed files with 56 additions and 34 deletions

View File

@ -13,6 +13,7 @@ import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext;
import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.core.env.Environment; import org.springframework.core.env.Environment;
@ -109,9 +110,9 @@ public class UrlsWorkerApplication {
} }
@Bean @Bean
public CommandLineRunner setServerBaseUrl(Environment environment) public CommandLineRunner setServerBaseUrl(Environment environment, ServletWebServerApplicationContext webServerAppCtxt)
{ {
return args -> new UriBuilder(environment); return args -> new UriBuilder(environment, webServerAppCtxt);
} }

View File

@ -1,6 +1,7 @@
package eu.openaire.urls_worker.controllers; package eu.openaire.urls_worker.controllers;
import eu.openaire.urls_worker.UrlsWorkerApplication; import eu.openaire.urls_worker.UrlsWorkerApplication;
import eu.openaire.urls_worker.util.UriBuilder;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
@ -10,6 +11,7 @@ import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -35,34 +37,32 @@ public class GeneralController {
public static boolean shouldShutdownWorker = false; public static boolean shouldShutdownWorker = false;
@GetMapping("shutdownWorker/{shutdownCode}") @GetMapping("shutdownWorker/{shutdownCode}")
public ResponseEntity<?> shutdownWorkerGracefully(@PathVariable String shutdownCode) public ResponseEntity<?> shutdownWorkerGracefully(@PathVariable String shutdownCode, HttpServletRequest request)
{ {
String initMsg = "Received a \"shutdownWorker\" request."; String initMsg = "Received a \"shutdownWorker\" request.";
if ( shutdownCode.equals(UrlsWorkerApplication.shutdownOrCancelCode) ) {
shouldShutdownWorker = true; ResponseEntity<?> responseEntity = passSecurityChecks(request, shutdownCode, initMsg);
logger.info(initMsg + " The worker will shutdown, after finishing current work."); if ( responseEntity != null )
return ResponseEntity.ok().build(); return responseEntity;
} else {
String errorMsg = initMsg + " But, it contains an invalid \"shutdownCode\": " + shutdownCode; shouldShutdownWorker = true;
logger.error(errorMsg); logger.info(initMsg + " The worker will shutdown, after finishing current work.");
return ResponseEntity.status(HttpStatus.FORBIDDEN).body(errorMsg); return ResponseEntity.ok().build();
}
} }
@GetMapping("cancelShutdownWorker/{cancelCode}") @GetMapping("cancelShutdownWorker/{cancelCode}")
public ResponseEntity<?> cancelShutdownWorkerGracefully(@PathVariable String cancelCode) public ResponseEntity<?> cancelShutdownWorkerGracefully(@PathVariable String cancelCode, HttpServletRequest request)
{ {
String initMsg = "Received a \"cancelShutdownWorker\" request."; String initMsg = "Received a \"cancelShutdownWorker\" request.";
if ( cancelCode.equals(UrlsWorkerApplication.shutdownOrCancelCode) ) {
shouldShutdownWorker = false; ResponseEntity<?> responseEntity = passSecurityChecks(request, cancelCode, initMsg);
logger.info(initMsg + " Any previous \"shutdownWorker\"-request is canceled. The \"maxAssignmentsBatchesToHandleBeforeShutdown\" will still be honored (if it's set)."); if ( responseEntity != null )
return ResponseEntity.ok().build(); return responseEntity;
} else {
String errorMsg = initMsg + " But, it contains an invalid \"cancelCode\": " + cancelCode; shouldShutdownWorker = false;
logger.error(errorMsg); logger.info(initMsg + " Any previous \"shutdownWorker\"-request is canceled. The \"maxAssignmentsBatchesToHandleBeforeShutdown\" will still be honored (if it's set).");
return ResponseEntity.status(HttpStatus.FORBIDDEN).body(errorMsg); return ResponseEntity.ok().build();
}
} }
@ -78,4 +78,29 @@ public class GeneralController {
return ResponseEntity.ok(handledAssignmentsCounts); return ResponseEntity.ok(handledAssignmentsCounts);
} }
public static ResponseEntity<?> passSecurityChecks(HttpServletRequest request, String code, String initMsg)
{
if ( request == null ) {
logger.error(initMsg + " The \"HttpServletRequest\" is null!");
return ResponseEntity.internalServerError().build();
}
String remoteAddr = request.getHeader("X-FORWARDED-FOR");
if ( remoteAddr == null || "".equals(remoteAddr) )
remoteAddr = request.getRemoteAddr();
if ( ! (remoteAddr.equals("127.0.0.1") || remoteAddr.equals(UriBuilder.ip)) ) {
logger.error(initMsg + " The request came from another IP: " + remoteAddr + " | while this worker has the IP: " + UriBuilder.ip);
return ResponseEntity.status(HttpStatus.FORBIDDEN).build();
}
if ( !code.equals(UrlsWorkerApplication.shutdownOrCancelCode) ) {
String errorMsg = initMsg + " But, it contains an invalid code: " + code;
logger.error(errorMsg);
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(errorMsg);
}
return null; // The checks are passing.
}
} }

View File

@ -3,6 +3,7 @@ package eu.openaire.urls_worker.util;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext;
import org.springframework.core.env.Environment; import org.springframework.core.env.Environment;
import java.io.BufferedReader; import java.io.BufferedReader;
@ -15,9 +16,11 @@ public class UriBuilder {
private static final Logger logger = LoggerFactory.getLogger(UriBuilder.class); private static final Logger logger = LoggerFactory.getLogger(UriBuilder.class);
public static String ip = null;
public static String baseUrl = null; public static String baseUrl = null;
public UriBuilder(Environment environment) { public UriBuilder(Environment environment, ServletWebServerApplicationContext webServerAppCtxt) {
baseUrl = "http"; baseUrl = "http";
String sslEnabled = environment.getProperty("server.ssl.enabled"); String sslEnabled = environment.getProperty("server.ssl.enabled");
@ -28,18 +31,11 @@ public class UriBuilder {
baseUrl += sslEnabled.equals("true") ? "s" : ""; baseUrl += sslEnabled.equals("true") ? "s" : "";
baseUrl += "://"; baseUrl += "://";
String hostName = getPublicIP(); ip = getPublicIP();
if ( hostName == null ) if ( ip == null )
hostName = InetAddress.getLoopbackAddress().getHostName(); // Non-null. ip = InetAddress.getLoopbackAddress().getHostAddress(); // Non-null.
baseUrl += hostName; baseUrl += ip + ":" + webServerAppCtxt.getWebServer().getPort();
String serverPort = environment.getProperty("server.port");
if (serverPort == null) { // This is unacceptable!
logger.error("No property \"server.port\" was found in \"application.properties\"!");
System.exit(-1); // Well, I guess the Spring Boot would not start in this case anyway.
}
baseUrl += ":" + serverPort;
String baseInternalPath = environment.getProperty("server.servlet.context-path"); String baseInternalPath = environment.getProperty("server.servlet.context-path");
if ( baseInternalPath != null ) { if ( baseInternalPath != null ) {