Commit 9e7e3e62 authored by Piotr Gawron's avatar Piotr Gawron
Browse files

upload file separated properly between controller and service

parent 6d0b2e08
minerva (16.1.0~alpha.0) stable; urgency=medium
* Bug fix: api endpoints were exposed without 'api' prefix
* Bug fix: anonymous user could upload file using API
minerva (16.0.0~beta.1) stable; urgency=medium
* Backward incompatibility: layout parameter in minerva url is not supported
......
......@@ -9,9 +9,15 @@ import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.Authentication;
import org.springframework.web.bind.annotation.*;
import lcsb.mapviewer.api.*;
import lcsb.mapviewer.api.BaseController;
import lcsb.mapviewer.common.Configuration;
import lcsb.mapviewer.common.exception.InvalidStateException;
import lcsb.mapviewer.model.cache.UploadedFileEntry;
import lcsb.mapviewer.model.user.User;
import lcsb.mapviewer.persist.dao.cache.UploadedFileEntryDao;
import lcsb.mapviewer.services.ObjectNotFoundException;
import lcsb.mapviewer.services.QueryException;
import lcsb.mapviewer.services.interfaces.IFileService;
import lcsb.mapviewer.services.interfaces.IUserService;
@RestController
......@@ -20,19 +26,33 @@ public class FileController extends BaseController {
private FileRestImpl fileRest;
private IUserService userService;
private IFileService fileService;
@Autowired
public FileController(FileRestImpl fileRest, IUserService userService) {
public FileController(FileRestImpl fileRest, IUserService userService, IFileService fileService) {
this.fileRest = fileRest;
this.userService = userService;
this.fileService = fileService;
}
@PreAuthorize("isAuthenticated() and authentication.name != '" + Configuration.ANONYMOUS_LOGIN + "'")
@PostMapping(value = "/")
public Map<String, Object> createFile(
Authentication authentication,
@RequestParam(value = "filename") String filename,
@RequestParam(value = "length") String length) {
return fileRest.createFile(filename, length, userService.getUserByLogin(authentication.getName()));
User user = userService.getUserByLogin(authentication.getName());
UploadedFileEntry entry = new UploadedFileEntry();
entry.setOriginalFileName(filename);
entry.setFileContent(new byte[] {});
entry.setLength(Long.valueOf(length));
entry.setOwner(user);
fileService.add(entry);
try {
return getFile(entry.getId());
} catch (ObjectNotFoundException e) {
throw new InvalidStateException(e);
}
}
@PostAuthorize("hasAuthority('IS_ADMIN') or returnObject['owner'] == authentication.name")
......
......@@ -17,7 +17,6 @@ import lcsb.mapviewer.services.ObjectNotFoundException;
import lcsb.mapviewer.services.QueryException;
import lcsb.mapviewer.services.interfaces.IFileService;
@Transactional
@Service
public class FileRestImpl extends BaseRestImpl {
......@@ -31,20 +30,6 @@ public class FileRestImpl extends BaseRestImpl {
this.fileService = fileService;
}
public Map<String, Object> createFile(String filename, String length, User user) {
UploadedFileEntry entry = new UploadedFileEntry();
entry.setOriginalFileName(filename);
entry.setFileContent(new byte[] {});
entry.setLength(Long.valueOf(length));
entry.setOwner(user);
uploadedFileEntryDao.add(entry);
try {
return getFile(entry.getId());
} catch (ObjectNotFoundException e) {
throw new InvalidStateException(e);
}
}
public Map<String, Object> getFile(Integer id) throws ObjectNotFoundException {
UploadedFileEntry fileEntry = fileService.getById(id);
if (fileEntry == null) {
......
......@@ -4,7 +4,6 @@ import org.junit.runner.RunWith;
import org.junit.runners.Suite;
import org.junit.runners.Suite.SuiteClasses;
import lcsb.mapviewer.api.files.AllFileTests;
import lcsb.mapviewer.api.genomics.AllGenomicsTests;
import lcsb.mapviewer.api.mesh.AllMeshTests;
import lcsb.mapviewer.api.projects.AllProjectTests;
......@@ -12,7 +11,6 @@ import lcsb.mapviewer.api.users.AllUserTests;
@RunWith(Suite.class)
@SuiteClasses({
AllFileTests.class,
AllGenomicsTests.class,
AllMeshTests.class,
AllProjectTests.class,
......
package lcsb.mapviewer.api.files;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
import org.junit.runners.Suite.SuiteClasses;
@RunWith(Suite.class)
@SuiteClasses({ FileRestImplTest.class })
public class AllFileTests {
}
package lcsb.mapviewer.api.files;
import static org.junit.Assert.*;
import java.util.Map;
import org.apache.commons.lang3.ArrayUtils;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import lcsb.mapviewer.api.RestTestFunctions;
import lcsb.mapviewer.model.cache.UploadedFileEntry;
import lcsb.mapviewer.model.user.User;
import lcsb.mapviewer.persist.dao.cache.UploadedFileEntryDao;
import lcsb.mapviewer.services.interfaces.IUserService;
public class FileRestImplTest extends RestTestFunctions {
@Autowired
UploadedFileEntryDao uploadedFileEntryDao;
@Autowired
FileRestImpl fileRestImpl;
@Autowired
IUserService userService;
@Test
public void testCreateFile() throws Exception {
User user = userService.getUserByLogin("admin");
Map<String, Object> result = fileRestImpl.createFile("test.txt", "100", user);
assertNotNull(result);
int id = (Integer) result.get("id");
UploadedFileEntry file = uploadedFileEntryDao.getById(id);
assertNotNull(file);
assertEquals(100, file.getLength());
assertEquals(0, file.getFileContent().length);
uploadedFileEntryDao.delete(file);
}
@Test
public void testUploadContent() throws Exception {
User user = userService.getUserByLogin("admin");
byte[] dataChunk = new byte[] { 105, 103 };
byte[] dataChunk2 = new byte[] { 32, 73 };
byte[] dataChunkMerged = ArrayUtils.addAll(dataChunk, dataChunk2);
Map<String, Object> result = fileRestImpl.createFile("test.txt", "100", user);
int id = (Integer) result.get("id");
fileRestImpl.uploadContent(id, dataChunk);
UploadedFileEntry file = uploadedFileEntryDao.getById(id);
assertEquals(100, file.getLength());
assertEquals(2, file.getFileContent().length);
assertArrayEquals(dataChunk, file.getFileContent());
fileRestImpl.uploadContent(id, dataChunk2);
assertEquals(100, file.getLength());
assertEquals(4, file.getFileContent().length);
assertArrayEquals(dataChunkMerged, file.getFileContent());
uploadedFileEntryDao.delete(file);
}
@Test
public void testUploadInvalidContent() throws Exception {
User user = userService.getUserByLogin("admin");
byte[] dataChunk = new byte[100];
Map<String, Object> result = fileRestImpl.createFile("test.txt", "100", user);
int id = (Integer) result.get("id");
try {
fileRestImpl.uploadContent(id, dataChunk);
} finally {
uploadedFileEntryDao.getById(id);
UploadedFileEntry file = uploadedFileEntryDao.getById(id);
uploadedFileEntryDao.delete(file);
}
}
}
......@@ -39,4 +39,9 @@ public class FileService implements IFileService {
}
@Override
public void add(UploadedFileEntry entry) {
uploadedFileEntryDao.add(entry);
}
}
......@@ -9,4 +9,6 @@ public interface IFileService {
User getOwnerByFileId(Integer id);
void add(UploadedFileEntry entry);
}
package lcsb.mapviewer.web;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document;
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get;
......@@ -9,8 +10,7 @@ import static org.springframework.restdocs.payload.PayloadDocumentation.response
import static org.springframework.restdocs.request.RequestDocumentation.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import java.util.Arrays;
import java.util.List;
import java.util.*;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.message.BasicNameValuePair;
......@@ -25,6 +25,8 @@ import org.springframework.restdocs.payload.FieldDescriptor;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.web.servlet.RequestBuilder;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.gson.JsonParser;
import lcsb.mapviewer.model.cache.UploadedFileEntry;
......@@ -40,10 +42,13 @@ public class FileControllerIntegrationTest extends ControllerIntegrationTest {
@Autowired
private IUserService userService;
@Autowired
private IFileService fileService;
@Autowired
private ObjectMapper objectMapper;
@Before
public void setup() {
}
......@@ -205,7 +210,17 @@ public class FileControllerIntegrationTest extends ControllerIntegrationTest {
String response = mockMvc.perform(request)
.andExpect(status().is2xxSuccessful()).andReturn().getResponse().getContentAsString();
int id = new JsonParser().parse(response).getAsJsonObject().get("id").getAsInt();
Map<String, Object> data = objectMapper.readValue(response,
new TypeReference<Map<String, Object>>() {
});
assertEquals("unknown.txt", data.get("filename"));
assertEquals(29, data.get("length"));
assertEquals(BUILT_IN_TEST_ADMIN_LOGIN, data.get("owner"));
assertEquals(0, data.get("uploadedDataLength"));
int id = (int) data.get("id");
String fileContent = "elementIdentifier\tvalue\nxx\t-1";
......@@ -217,4 +232,18 @@ public class FileControllerIntegrationTest extends ControllerIntegrationTest {
.andExpect(status().is2xxSuccessful());
}
@Test
public void createFileWithoutPrivileges() throws Exception {
String body = EntityUtils.toString(new UrlEncodedFormEntity(Arrays.asList(
new BasicNameValuePair("filename", "unknown.txt"),
new BasicNameValuePair("length", "29"))));
RequestBuilder request = post("/api/files/")
.contentType(MediaType.APPLICATION_FORM_URLENCODED)
.content(body);
mockMvc.perform(request)
.andExpect(status().isForbidden());
}
}
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