Commit 825480fa authored by Piotr Gawron's avatar Piotr Gawron
Browse files

API does not allow to create plugin with wrong md5 hash

parent d98c5da3
Pipeline #47227 passed with stage
in 18 minutes and 43 seconds
......@@ -7,6 +7,7 @@ minerva (16.1.0~alpha.0) stable; urgency=medium
* Bug fix: anonymous user could upload file using API
* Bug fix: when passing JSON in patch/post methods contentType was not
checked
* Bug fix: API does not allow to create plugin with wrong md5 hash (#1074)
-- Piotr Gawron <piotr.gawron@uni.lu> Thu, 9 Sep 2021 13:00:00 +0200
......
package lcsb.mapviewer.common;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class Md5 {
private static Logger logger = LogManager.getLogger();
public static String compute(final String data) {
try {
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] mdbytes = md.digest(data.getBytes());
StringBuffer sb = new StringBuffer();
for (int i = 0; i < mdbytes.length; i++) {
// CHECKSTYLE:OFF
// this magic formula transforms integer into hex value
sb.append(Integer.toString((mdbytes[i] & 0xff) + 0x100, 16).substring(1));
// CHECKSTYLE:ON
}
return sb.toString();
} catch (final NoSuchAlgorithmException e) {
logger.fatal("Problem with instance of MD5 encoder", e);
}
return null;
}
}
package lcsb.mapviewer.api.plugins;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import org.apache.commons.validator.routines.UrlValidator;
import org.apache.logging.log4j.LogManager;
......@@ -21,7 +23,9 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import lcsb.mapviewer.annotation.cache.WebPageDownloader;
import lcsb.mapviewer.api.BaseController;
import lcsb.mapviewer.common.Md5;
import lcsb.mapviewer.model.plugin.Plugin;
import lcsb.mapviewer.model.plugin.PluginDataEntry;
import lcsb.mapviewer.model.user.User;
......@@ -76,6 +80,16 @@ public class PluginController extends BaseController {
}
if (!url.isEmpty()) {
plugin.addUrl(url);
if (!url.startsWith("http://localhost")) {
try {
String md5 = Md5.compute(new WebPageDownloader().getFromNetwork(url));
if (!Objects.equals(md5, hash)) {
throw new QueryException(String.format("Invalid hash. Expected %s, but %s found", md5, hash));
}
} catch (IOException e) {
throw new QueryException("Problem with fetching url", e);
}
}
}
pluginService.add(plugin);
}
......
......@@ -5,8 +5,6 @@ import java.io.File;
import java.io.IOException;
import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
......@@ -50,6 +48,7 @@ import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import lcsb.mapviewer.annotation.services.annotators.AnnotatorException;
import lcsb.mapviewer.api.BaseController;
import lcsb.mapviewer.api.OperationNotAllowedException;
import lcsb.mapviewer.common.Md5;
import lcsb.mapviewer.common.comparator.StringComparator;
import lcsb.mapviewer.common.exception.InvalidArgumentException;
import lcsb.mapviewer.converter.Converter;
......@@ -632,33 +631,7 @@ public class ProjectController extends BaseController {
protected String computePathForProject(final String projectId, final String path) {
long id = projectService.getNextId();
return path + "/../map_images/" + md5(projectId + "-" + id) + "/";
}
/**
* Method that computes md5 hash for a given {@link String}.
*
* @param data
* input string
* @return md5 hash for input string
*/
private String md5(final String data) {
try {
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] mdbytes = md.digest(data.getBytes());
StringBuffer sb = new StringBuffer();
for (int i = 0; i < mdbytes.length; i++) {
// CHECKSTYLE:OFF
// this magic formula transforms integer into hex value
sb.append(Integer.toString((mdbytes[i] & 0xff) + 0x100, 16).substring(1));
// CHECKSTYLE:ON
}
return sb.toString();
} catch (final NoSuchAlgorithmException e) {
logger.fatal("Problem with instance of MD5 encoder", e);
}
return null;
return path + "/../map_images/" + Md5.compute(projectId + "-" + id) + "/";
}
@PreAuthorize("hasAuthority('IS_ADMIN')"
......
......@@ -50,7 +50,9 @@ public class PluginControllerIntegrationTest extends ControllerIntegrationTest {
private static final String TEST_USER_PASSWORD = "test_pass";
private static final String TEST_USER_LOGIN = "test_user";
private static final String PLUGIN_HASH = "520e2c4c687047d78a7fd7355b9e215d";
private static final String PLUGIN_URL = "https://minerva-dev.lcsb.uni.lu/plugins/starter-kit/plugin.js";
private static final String PLUGIN_HASH = "b7a875a0536949d4d8a2f834dc54489e";
@Autowired
private PluginDao pluginDao;
......@@ -102,7 +104,7 @@ public class PluginControllerIntegrationTest extends ControllerIntegrationTest {
new BasicNameValuePair("name", "x"),
new BasicNameValuePair("version", "x"),
new BasicNameValuePair("isPublic", "true"),
new BasicNameValuePair("url", "https://minerva-dev.lcsb.uni.lu/plugins/starter-kit/plugin.js"))));
new BasicNameValuePair("url", PLUGIN_URL))));
RequestBuilder request = post("/api/plugins/")
.contentType(MediaType.APPLICATION_FORM_URLENCODED)
......@@ -122,7 +124,7 @@ public class PluginControllerIntegrationTest extends ControllerIntegrationTest {
new BasicNameValuePair("name", "x"),
new BasicNameValuePair("version", "x"),
new BasicNameValuePair("isPublic", "true"),
new BasicNameValuePair("url", "https://minerva-dev.lcsb.uni.lu/plugins/starter-kit/plugin.js"))));
new BasicNameValuePair("url", PLUGIN_URL))));
RequestBuilder request = post("/api/plugins/")
.contentType(MediaType.APPLICATION_FORM_URLENCODED)
......@@ -227,7 +229,7 @@ public class PluginControllerIntegrationTest extends ControllerIntegrationTest {
new BasicNameValuePair("name", "x"),
new BasicNameValuePair("version", "x"),
new BasicNameValuePair("isPublic", "false"),
new BasicNameValuePair("url", "https://minerva-dev.lcsb.uni.lu/plugins/starter-kit/plugin.js"))));
new BasicNameValuePair("url", PLUGIN_URL))));
RequestBuilder request = post("/api/plugins/")
.contentType(MediaType.APPLICATION_FORM_URLENCODED)
......@@ -395,7 +397,7 @@ public class PluginControllerIntegrationTest extends ControllerIntegrationTest {
plugin.setHash(PLUGIN_HASH);
plugin.setName("starter-kit");
plugin.setVersion("0.0.1");
plugin.addUrl("https://minerva-dev.lcsb.uni.lu/plugins/starter-kit/plugin.js");
plugin.addUrl(PLUGIN_URL);
pluginDao.add(plugin);
return plugin;
});
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment