diff --git a/admin/src/main/scala/com/neu/api/Api.scala b/admin/src/main/scala/com/neu/api/Api.scala index 7ec495d7d..188df1bda 100644 --- a/admin/src/main/scala/com/neu/api/Api.scala +++ b/admin/src/main/scala/com/neu/api/Api.scala @@ -93,15 +93,17 @@ trait Api extends Directives with CoreActors with Core { private val workloadApi = new WorkloadApi(workloadService) val routes: Route = handleExceptions(exceptionHandler) { - authenticationApi.route ~ - dashboardApi.route ~ - clusterApi.route ~ - deviceApi.route ~ - groupApi.route ~ - notificationApi.route ~ - policyApi.route ~ - riskApi.route ~ - sigstoreApi.route ~ - workloadApi.route + rawPathPrefix(sys.env.get("PATH_PREFIX").map(r => Slash ~ r).getOrElse("")) { + authenticationApi.route ~ + dashboardApi.route ~ + clusterApi.route ~ + deviceApi.route ~ + groupApi.route ~ + notificationApi.route ~ + policyApi.route ~ + riskApi.route ~ + sigstoreApi.route ~ + workloadApi.route + } } } diff --git a/admin/src/main/scala/com/neu/core/Core.scala b/admin/src/main/scala/com/neu/core/Core.scala index 3b68c6bc8..39f6519c1 100644 --- a/admin/src/main/scala/com/neu/core/Core.scala +++ b/admin/src/main/scala/com/neu/core/Core.scala @@ -37,9 +37,10 @@ trait BootedCore CisNISTManager System.setProperty("net.sf.ehcache.enableShutdownHook", "true") - private val useSSL: String = sys.env.getOrElse("MANAGER_SSL", "on") - private val httpMaxHeaderLength: String = sys.env.getOrElse("HTTP_MAX_HEADER_LENGTH", "32k") - private val config: Config = + private val useSSL: String = sys.env.getOrElse("MANAGER_SSL", "on") + private val httpMaxHeaderLength: String = sys.env.getOrElse("HTTP_MAX_HEADER_LENGTH", "32k") + private val managerPathPrefix: Option[String] = sys.env.get("PATH_PREFIX") + private val config: Config = load .getConfig(if (useSSL == "off") "noneSsl" else "ssl") .withFallback(defaultReference(getClass.getClassLoader)) @@ -69,7 +70,9 @@ trait BootedCore private val bindingFuture: Future[Http.ServerBinding] = useSSL match { case "off" => - logger.info("Starting server in HTTP mode (MANAGER_SSL=off).") + logger.info( + s"Starting server in HTTP mode (MANAGER_SSL=off${managerPathPrefix.map(prefix => s",PATH_PREFIX=$prefix").getOrElse("")})" + ) NoOperationSSLContext.init() Http() .newServerAt("0.0.0.0", httpPort.toInt) @@ -78,7 +81,9 @@ trait BootedCore case _ => https match { case Some(httpsCtx) => - logger.info("Starting server in HTTPS mode (MANAGER_SSL=on).") + logger.info( + s"Starting server in HTTPS mode (MANAGER_SSL=on${managerPathPrefix.map(prefix => s",PATH_PREFIX=$prefix").getOrElse("")})" + ) Http() .newServerAt("0.0.0.0", httpPort.toInt) .enableHttps(httpsCtx) diff --git a/admin/src/main/scala/com/neu/web/StaticResources.scala b/admin/src/main/scala/com/neu/web/StaticResources.scala index f2a5ad60c..86aaa0429 100644 --- a/admin/src/main/scala/com/neu/web/StaticResources.scala +++ b/admin/src/main/scala/com/neu/web/StaticResources.scala @@ -20,6 +20,17 @@ trait StaticResources extends Directives with LazyLogging { private val isUsingSSL: Boolean = sys.env.getOrElse("MANAGER_SSL", "on") == "on" private val isDev: Boolean = sys.env.getOrElse("IS_DEV", "false") == "true" + private val _managerPathPrefixWithPrependedSlash: String = { + val rawPathOption: Option[String] = sys.env.get("PATH_PREFIX") + + rawPathOption match { + case Some(value) => "/" + value.trim + case None => "" + } + } + + private val managerPathPrefixWithPrependedSlash: String = _managerPathPrefixWithPrependedSlash + // # Rewrite redirect-implementation base on "spray/spray-routing/src/main/scala/spray/routing/RequestContext.scala, added strict transport security header" private def redirectMe(uri: Uri, redirectionType: StatusCodes.Redirection) = complete { @@ -42,60 +53,70 @@ trait StaticResources extends Directives with LazyLogging { } val staticResources: Route = get { - path("") { - redirectMe( - UrlEscapers - .urlFragmentEscaper() - .escape("/index.html?v=" + Md5.hash(managerVersion).take(shortPath)), - StatusCodes.MovedPermanently - ) - } ~ - path("index.html") { - parameters(Symbol("v").?) { v => - val hash = Md5.hash(managerVersion).take(shortPath) - if (v.isEmpty) { - redirectMe( - UrlEscapers.urlFragmentEscaper().escape("/index.html?v=" + hash), - StatusCodes.MovedPermanently - ) - } else { - if (v.get.equals(hash)) { - getFromResource("/index.html") - } else { - logger.info("Previous version hash: {}", v.get) - logger.info("Current version hash: {}", hash) + rawPathPrefix(sys.env.get("PATH_PREFIX").map(r => Slash ~ r).getOrElse("")) { + path("") { + redirectMe( + UrlEscapers + .urlFragmentEscaper() + .escape( + managerPathPrefixWithPrependedSlash + "/index.html?v=" + Md5 + .hash(managerVersion) + .take(shortPath) + ), + StatusCodes.MovedPermanently + ) + } ~ + path("index.html") { + parameters(Symbol("v").?) { v => + val hash = Md5.hash(managerVersion).take(shortPath) + if (v.isEmpty) { redirectMe( - UrlEscapers.urlFragmentEscaper().escape("/index.html?v=" + hash), + UrlEscapers + .urlFragmentEscaper() + .escape(managerPathPrefixWithPrependedSlash + "/index.html?v=" + hash), StatusCodes.MovedPermanently ) + } else { + if (v.get.equals(hash)) { + getFromResource("/index.html") + } else { + logger.info("Previous version hash: {}", v.get) + logger.info("Current version hash: {}", hash) + redirectMe( + UrlEscapers + .urlFragmentEscaper() + .escape(managerPathPrefixWithPrependedSlash + "/index.html?v=" + hash), + StatusCodes.MovedPermanently + ) + } } } - } - } ~ - path("favicon.ico") { - Utils.respondWithWebServerHeaders(isStaticResource = true) { - complete(StatusCodes.NotFound) - } - } ~ - path(Remaining) { path => - if (isDev) { + } ~ + path("favicon.ico") { Utils.respondWithWebServerHeaders(isStaticResource = true) { - getFromResource(UrlEscapers.urlFragmentEscaper().escape(s"root/$path")) + complete(StatusCodes.NotFound) } - } else { - if (path.endsWith(".js")) { + } ~ + path(Remaining) { path => + if (isDev) { Utils.respondWithWebServerHeaders(isStaticResource = true) { - respondWithHeader(RawHeader("Content-Type", "application/javascript")) { - encodeResponse { - getFromResource( - UrlEscapers.urlFragmentEscaper().escape(s"root/$path.gz") - ) - } - } + getFromResource(UrlEscapers.urlFragmentEscaper().escape(s"root/$path")) } } else { - Utils.respondWithWebServerHeaders(isStaticResource = true) { - getFromResource(UrlEscapers.urlFragmentEscaper().escape(s"root/$path")) + if (path.endsWith(".js")) { + Utils.respondWithWebServerHeaders(isStaticResource = true) { + respondWithHeader(RawHeader("Content-Type", "application/javascript")) { + encodeResponse { + getFromResource( + UrlEscapers.urlFragmentEscaper().escape(s"root/$path.gz") + ) + } + } + } + } else { + Utils.respondWithWebServerHeaders(isStaticResource = true) { + getFromResource(UrlEscapers.urlFragmentEscaper().escape(s"root/$path")) + } } } } diff --git a/admin/webapp/websrc/index.html b/admin/webapp/websrc/index.html index db022a143..3e1f36bc3 100644 --- a/admin/webapp/websrc/index.html +++ b/admin/webapp/websrc/index.html @@ -3,7 +3,6 @@