Added proxy configuration and check for absolute URL in link header
Change-Id: I1cdf9a9ec1365744a283a9174d5f4bd2137a14b4
Signed-off-by: Fauth Dirk <Dirk.Fauth@de.bosch.com>
diff --git a/manager/src/main/java/org/eclipse/app4mc/cloud/manager/App4McCloudManagerApplication.java b/manager/src/main/java/org/eclipse/app4mc/cloud/manager/App4McCloudManagerApplication.java
index bfe85c2..d4399b6 100644
--- a/manager/src/main/java/org/eclipse/app4mc/cloud/manager/App4McCloudManagerApplication.java
+++ b/manager/src/main/java/org/eclipse/app4mc/cloud/manager/App4McCloudManagerApplication.java
@@ -15,11 +15,27 @@
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.util.StringUtils;
+
+import kong.unirest.Unirest;
@SpringBootApplication
public class App4McCloudManagerApplication {
public static void main(String[] args) {
+ String proxyHost = System.getProperty("proxy.host");
+ String proxyPort = System.getProperty("proxy.port");
+ String proxyUser = System.getProperty("proxy.user");
+ String proxyPwd = System.getProperty("proxy.pwd");
+
+ if (!StringUtils.isEmpty(proxyHost) && !StringUtils.isEmpty(proxyPort)) {
+ if (!StringUtils.isEmpty(proxyUser) && !StringUtils.isEmpty(proxyPwd)) {
+ Unirest.config().proxy(proxyHost, Integer.valueOf(proxyPort), proxyUser, proxyPwd);
+ } else {
+ Unirest.config().proxy(proxyHost, Integer.valueOf(proxyPort));
+ }
+ }
+
SpringApplication.run(App4McCloudManagerApplication.class, args);
}
}
diff --git a/manager/src/main/java/org/eclipse/app4mc/cloud/manager/WorkflowController.java b/manager/src/main/java/org/eclipse/app4mc/cloud/manager/WorkflowController.java
index 7b21e2d..201c8ac 100644
--- a/manager/src/main/java/org/eclipse/app4mc/cloud/manager/WorkflowController.java
+++ b/manager/src/main/java/org/eclipse/app4mc/cloud/manager/WorkflowController.java
@@ -207,11 +207,14 @@
statusUrl = uploadResponse.getHeaders().getFirst("Location");
if (StringUtils.isEmpty(statusUrl)) {
// fallback check for Link header if Location header is not set
- statusUrl = getUrlFromLink(uploadResponse.getHeaders().get("Link"), "status");
+ statusUrl = getUrlFromLink(uploadResponse.getHeaders().get("Link"), "status", baseUrl);
+ } else if (!statusUrl.startsWith(baseUrl)) {
+ throw new ProcessingFailedException(
+ "The status URL from the Location header does not match with the service base URL '" + baseUrl + "': " + statusUrl);
}
} else if (uploadResponse.getStatus() == 200) {
// fallback if return code is 200, then follow up needs to be placed in Link header
- statusUrl = getUrlFromLink(uploadResponse.getHeaders().get("Link"), "status");
+ statusUrl = getUrlFromLink(uploadResponse.getHeaders().get("Link"), "status", baseUrl);
} else {
// error
workflowStatus.addError("Upload to " + serviceName + " failed! Error code: " + uploadResponse.getStatus() + " - Workflow stopped!");
@@ -250,7 +253,7 @@
}
// first check if there is a result link
- String downloadUrl = getUrlFromLink(linkHeaders, "result");
+ String downloadUrl = getUrlFromLink(linkHeaders, "result", baseUrl);
String deleteUrl = null;
if (downloadUrl != null) {
workflowStatus.addMessage(serviceName + " processing finished");
@@ -294,9 +297,9 @@
}
// extract delete
- deleteUrl = getUrlFromLink(downloadResponse.getHeaders().get("Link"), "delete");
+ deleteUrl = getUrlFromLink(downloadResponse.getHeaders().get("Link"), "delete", baseUrl);
} else {
- String errorUrl = getUrlFromLink(linkHeaders, "error");
+ String errorUrl = getUrlFromLink(linkHeaders, "error", baseUrl);
if (errorUrl != null) {
workflowStatus.addError(serviceName + " processing finished with error");
@@ -322,7 +325,7 @@
migrationError.getFileName().toString()).build().toUri().toString());
// extract delete
- deleteUrl = getUrlFromLink(errorResponse.getHeaders().get("Link"), "delete");
+ deleteUrl = getUrlFromLink(errorResponse.getHeaders().get("Link"), "delete", baseUrl);
}
}
@@ -371,10 +374,11 @@
* @param linkHeaders The link headers to parse.
* @param rel The value for the rel param for which the url is
* requested.
+ * @param baseUrl The base URL of the service.
* @return The url for the specified rel param or <code>null</code> if there is
* no link for the given rel.
*/
- public static String getUrlFromLink(List<String> linkHeaders, String rel) {
+ public static String getUrlFromLink(List<String> linkHeaders, String rel, String baseUrl) {
for (String linkHeader : linkHeaders) {
String[] links = linkHeader.split(LINK_DELIMITER);
@@ -404,6 +408,12 @@
}
if (rel.equals(relValue)) {
+ // SECURITY: ensure that host in link matches host in configured service
+ if (!url.startsWith(baseUrl)) {
+ throw new ProcessingFailedException(
+ "The link for rel '" + rel + "' does not match with the service base URL '" + baseUrl + "': " + url);
+ }
+
return url;
}
}
diff --git a/manager/src/main/java/org/eclipse/app4mc/cloud/manager/administration/AdminController.java b/manager/src/main/java/org/eclipse/app4mc/cloud/manager/administration/AdminController.java
index c86570c..908659d 100644
--- a/manager/src/main/java/org/eclipse/app4mc/cloud/manager/administration/AdminController.java
+++ b/manager/src/main/java/org/eclipse/app4mc/cloud/manager/administration/AdminController.java
@@ -24,6 +24,10 @@
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+
+import kong.unirest.Proxy;
+import kong.unirest.Unirest;
@Controller
public class AdminController {
@@ -38,11 +42,17 @@
model.addAttribute("dto", dto);
+ Proxy proxy = Unirest.config().getProxy();
+ model.addAttribute("proxy_host", proxy != null ? proxy.getHost() : "");
+ model.addAttribute("proxy_port", proxy != null ? proxy.getPort() : "");
+ model.addAttribute("proxy_user", proxy != null ? proxy.getUsername() : "");
+ model.addAttribute("proxy_pwd", proxy != null ? proxy.getPassword() : "");
+
return "admin";
}
@PostMapping("/admin/save")
- public String saveBooks(@ModelAttribute CloudServiceDefinitionDTO dto, Model model) {
+ public String saveServices(@ModelAttribute CloudServiceDefinitionDTO dto, Model model) {
// TODO save to DB
cloudServiceDefinitions.clear();
cloudServiceDefinitions.addAll(dto.getServices().stream()
@@ -53,6 +63,24 @@
return "redirect:/admin";
}
+ @PostMapping("/admin/saveProxy")
+ public String saveProxy(Model model,
+ @RequestParam(name = "proxy_host", required = false) String proxyHost,
+ @RequestParam(name = "proxy_port", required = false) String proxyPort,
+ @RequestParam(name = "proxy_user", required = false) String proxyUser,
+ @RequestParam(name = "proxy_pwd", required = false) String proxyPwd) {
+
+ // TODO save to DB and load from DB in App4McCloudManagerApplication
+ Unirest.config().reset();
+ if (!StringUtils.isEmpty(proxyHost) && !StringUtils.isEmpty(proxyPort)) {
+ Unirest.config().proxy(proxyHost, Integer.valueOf(proxyPort), proxyUser, proxyPwd);
+ } else {
+ Unirest.config().proxy(null);
+ }
+
+ return "redirect:/admin";
+ }
+
@ModelAttribute("cloudServiceDefinitions")
public List<CloudServiceDefinition> cloudServiceDefinitions() {
return cloudServiceDefinitions;
diff --git a/manager/src/main/java/org/eclipse/app4mc/cloud/manager/administration/ApplicationConfig.java b/manager/src/main/java/org/eclipse/app4mc/cloud/manager/administration/ApplicationConfig.java
index cd6cdee..a6ae0b8 100644
--- a/manager/src/main/java/org/eclipse/app4mc/cloud/manager/administration/ApplicationConfig.java
+++ b/manager/src/main/java/org/eclipse/app4mc/cloud/manager/administration/ApplicationConfig.java
@@ -1,3 +1,16 @@
+/*********************************************************************************
+ * Copyright (c) 2020 Robert Bosch GmbH and others.
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Robert Bosch GmbH - initial API and implementation
+ ********************************************************************************
+ */
package org.eclipse.app4mc.cloud.manager.administration;
import java.util.ArrayList;
@@ -5,11 +18,8 @@
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
-import org.springframework.util.StringUtils;
import org.springframework.web.context.annotation.ApplicationScope;
-import kong.unirest.Unirest;
-
@Configuration
public class ApplicationConfig {
@@ -20,20 +30,6 @@
definitions.add(new CloudServiceDefinition("Migration", "http://localhost:8080/app4mc/converter/", "Model Migration Service"));
definitions.add(new CloudServiceDefinition("Validation", "http://localhost:8181/app4mc/validation/", "Model Validation Service"));
- // TODO make this configurable via admin ui
- String proxyHost = System.getProperty("proxy.host");
- String proxyPort = System.getProperty("proxy.port");
- String proxyUser = System.getProperty("proxy.user");
- String proxyPwd = System.getProperty("proxy.pwd");
-
- if (!StringUtils.isEmpty(proxyHost) && !StringUtils.isEmpty(proxyPort)) {
- if (!StringUtils.isEmpty(proxyUser) && !StringUtils.isEmpty(proxyPwd)) {
- Unirest.config().proxy(proxyHost, Integer.valueOf(proxyPort), proxyUser, proxyPwd);
- } else {
- Unirest.config().proxy(proxyHost, Integer.valueOf(proxyPort));
- }
- }
-
return definitions;
}
}
diff --git a/manager/src/main/java/org/eclipse/app4mc/cloud/manager/administration/CloudServiceDefinition.java b/manager/src/main/java/org/eclipse/app4mc/cloud/manager/administration/CloudServiceDefinition.java
index f1069bc..ce77321 100644
--- a/manager/src/main/java/org/eclipse/app4mc/cloud/manager/administration/CloudServiceDefinition.java
+++ b/manager/src/main/java/org/eclipse/app4mc/cloud/manager/administration/CloudServiceDefinition.java
@@ -1,3 +1,16 @@
+/*********************************************************************************
+ * Copyright (c) 2020 Robert Bosch GmbH and others.
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Robert Bosch GmbH - initial API and implementation
+ ********************************************************************************
+ */
package org.eclipse.app4mc.cloud.manager.administration;
public class CloudServiceDefinition {
diff --git a/manager/src/main/java/org/eclipse/app4mc/cloud/manager/administration/CloudServiceDefinitionDTO.java b/manager/src/main/java/org/eclipse/app4mc/cloud/manager/administration/CloudServiceDefinitionDTO.java
index 5f71883..31ad030 100644
--- a/manager/src/main/java/org/eclipse/app4mc/cloud/manager/administration/CloudServiceDefinitionDTO.java
+++ b/manager/src/main/java/org/eclipse/app4mc/cloud/manager/administration/CloudServiceDefinitionDTO.java
@@ -1,3 +1,16 @@
+/*********************************************************************************
+ * Copyright (c) 2020 Robert Bosch GmbH and others.
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Robert Bosch GmbH - initial API and implementation
+ ********************************************************************************
+ */
package org.eclipse.app4mc.cloud.manager.administration;
import java.util.ArrayList;
diff --git a/manager/src/main/resources/templates/admin.html b/manager/src/main/resources/templates/admin.html
index 5807fae..e5a077c 100644
--- a/manager/src/main/resources/templates/admin.html
+++ b/manager/src/main/resources/templates/admin.html
@@ -11,8 +11,6 @@
<div>
<form action="#" th:action="@{/admin/save}" th:object="${dto}" method="POST">
<fieldset>
- <input type="submit" id="submitButton" th:value="Save">
- <input type="reset" id="resetButton" name="reset" th:value="Reset"/>
<table>
<thead>
<tr>
@@ -29,6 +27,37 @@
</tr>
</tbody>
</table>
+ <input type="submit" id="submitButton" th:value="Save">
+ <input type="reset" id="resetButton" name="reset" th:value="Reset"/>
+ </fieldset>
+ </form>
+ </div>
+ <div>
+ <h2>Configure Proxy</h2>
+ </div>
+ <div>
+ <form action="/admin/saveProxy" method="POST">
+ <fieldset>
+ <table>
+ <tr>
+ <td>Host:</td>
+ <td><input type="text" name="proxy_host" th:value="${proxy_host}"/></td>
+ </tr>
+ <tr>
+ <td>Port:</td>
+ <td><input type="text" name="proxy_port" th:value="${proxy_port}"/></td>
+ </tr>
+ <tr>
+ <td>User:</td>
+ <td><input type="text" name="proxy_user" th:value="${proxy_user}"/></td>
+ </tr>
+ <tr>
+ <td>Password:</td>
+ <td><input type="password" name="proxy_pwd" th:value="${proxy_pwd}"/></td>
+ </tr>
+ </table>
+ <input type="submit" id="submitButton" th:value="Save">
+ <input type="reset" id="resetButton" name="reset" th:value="Reset"/>
</fieldset>
</form>
</div>