Skip to content

Commit

Permalink
#3627 File permissions checked and applied
Browse files Browse the repository at this point in the history
  • Loading branch information
ymarcon committed May 21, 2021
1 parent 94e0fb9 commit 2165de9
Show file tree
Hide file tree
Showing 4 changed files with 109 additions and 43 deletions.
81 changes: 48 additions & 33 deletions opal-core-ws/src/main/java/org/obiba/opal/web/FilesResource.java
Original file line number Diff line number Diff line change
Expand Up @@ -385,6 +385,13 @@ public Response createFolder(@PathParam("path") String path, String folderName,
}
}

@POST
@Path("/{path:.*}")
@Consumes("application/json")
public Response processFile(@PathParam("path") String archivePath, @QueryParam("action") @DefaultValue("unzip") String action, @QueryParam("destination") String destinationPath, @QueryParam("key") String archiveKey, @Context UriInfo uriInfo) throws IOException {
return unzipArchive(archivePath, destinationPath, archiveKey, uriInfo);
}

@Nullable
private Response validateFolder(FileObject folder, String path) throws IOException {
if (folder == null || !folder.exists()) {
Expand Down Expand Up @@ -457,45 +464,53 @@ public Response getAvailableCharsets() {
return Response.ok(new JSONArray(names).toString()).build();
}

@POST
@Path("/_unzip/{path:.*}")
public Response unzipArchive(@PathParam("path") String archivePath, @QueryParam("destination") String destinationPath, @QueryParam("key") String archiveKey) throws IOException {
if (Strings.isNullOrEmpty(archivePath) || !archivePath.toLowerCase().endsWith(".zip") || Strings.isNullOrEmpty(destinationPath)) {
return Response.status(Status.BAD_REQUEST)
.entity("No destination path or valid archive file (ZIP) has been submitted. Please make sure that you are submitting them with your request.")
.build();
}
private Response unzipArchive(String archivePath, String destinationPath, String archiveKey, UriInfo uriInfo) throws IOException {
if (Strings.isNullOrEmpty(archivePath) || !archivePath.toLowerCase().endsWith(".zip"))
throw new BadRequestException("Missing or invalid archive file (.zip).");
if (Strings.isNullOrEmpty(destinationPath))
throw new BadRequestException("Destination path is missing.");

FileObject archive = resolveFileInFileSystem(archivePath);
FileObject destination = resolveFileInFileSystem(destinationPath);

if (destination.exists() && !destination.getType().equals(FileType.FOLDER)) {
return Response.status(Status.BAD_REQUEST).entity("Destination path is a regular file.").build();
} else if (!destination.exists()) {
destination.createFolder();
if (!destination.exists())
return Response.status(Status.INTERNAL_SERVER_ERROR).entity("cannotCreateFolderUnexpectedError").build();
}

if (archive.exists() && archive.getType().equals(FileType.FILE)) {
File archiveFile = opalRuntime.getFileSystem().getLocalFile(archive);
String archiveBasename = archiveFile.getName().replace(".zip", "");
File destinationFolder = new File(opalRuntime.getFileSystem().getLocalFile(destination), archiveBasename);
int inc = 1;
while (destinationFolder.exists()) {
destinationFolder = new File(destinationFolder.getParentFile(), archiveBasename + "-" + inc);
inc++;
if (!archive.exists())
throw new BadRequestException("Archive file is missing.");
else if (!archive.isReadable())
throw new ForbiddenException("Archive is not readable.");
else if (!archive.getType().equals(FileType.FILE))
throw new BadRequestException("Archive file is not a regular file.");

if (destination.exists()) {
if (!destination.getType().equals(FileType.FOLDER))
throw new BadRequestException("Destination is not a folder.");
} else if (!destination.exists() && destination.getParent().isWriteable()) {
try {
destination.createFolder();
} catch (FileSystemException e) {
throw new InternalServerErrorException("Destination folder cannot be created.");
}
if (Strings.isNullOrEmpty(archiveKey)) {
org.obiba.core.util.FileUtil.unzip(archiveFile, destinationFolder);
} else {
org.obiba.core.util.FileUtil.unzip(archiveFile, destinationFolder, archiveKey);
}
} else {
return Response.status(Status.NOT_FOUND).entity("No archive file found.").build();
}

return Response.ok(destinationPath).build();
if (!destination.isWriteable())
throw new ForbiddenException("Destination folder is not writable.");

File archiveFile = opalRuntime.getFileSystem().getLocalFile(archive);
String archiveBasename = archiveFile.getName().replace(".zip", "");
File destinationFolder = new File(opalRuntime.getFileSystem().getLocalFile(destination), archiveBasename);
int inc = 1;
while (destinationFolder.exists()) {
destinationFolder = new File(destinationFolder.getParentFile(), archiveBasename + "-" + inc);
inc++;
}
if (Strings.isNullOrEmpty(archiveKey))
org.obiba.core.util.FileUtil.unzip(archiveFile, destinationFolder);
else
org.obiba.core.util.FileUtil.unzip(archiveFile, destinationFolder, archiveKey);

Opal.FileDto dto = getBaseFolderBuilder(destination.getChild(destinationFolder.getName())).build();
URI folderUri = uriInfo.getBaseUriBuilder().path(FilesResource.class).path(destinationPath).path(destinationFolder.getName()).build();
return Response.created(folderUri)//
.header(AuthorizationInterceptor.ALT_PERMISSIONS, new OpalPermissions(folderUri, AclAction.FILES_ALL))//
.entity(dto).build();
}

//
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* Copyright (c) 2021 OBiBa. All rights reserved.
*
* This program and the accompanying materials
* are made available under the terms of the GNU Public License v3.0.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

package org.obiba.opal.web.provider;

import com.google.protobuf.GeneratedMessage;
import org.obiba.opal.web.magma.ClientErrorDtos;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.ws.rs.ForbiddenException;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.Provider;

import static javax.ws.rs.core.Response.Status.FORBIDDEN;

@Component
@Provider
public class ForbiddenExceptionMapper extends ErrorDtoExceptionMapper<ForbiddenException> {

private static final Logger log = LoggerFactory.getLogger(ForbiddenExceptionMapper.class);

@Override
protected Response.Status getStatus() {
return FORBIDDEN;
}

@Override
protected GeneratedMessage.ExtendableMessage<?> getErrorDto(ForbiddenException exception) {
log.warn("Forbidden exception", exception);
return ClientErrorDtos.getErrorMessage(getStatus(), "Forbidden", exception);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import org.obiba.opal.web.gwt.app.client.fs.event.FolderUpdatedEvent;
import org.obiba.opal.web.gwt.app.client.fs.event.UnzipRequestEvent;
import org.obiba.opal.web.gwt.app.client.i18n.TranslationMessages;
import org.obiba.opal.web.gwt.app.client.i18n.Translations;
import org.obiba.opal.web.gwt.app.client.presenter.ModalProvider;
import org.obiba.opal.web.gwt.app.client.presenter.SplitPaneWorkbenchPresenter;
import org.obiba.opal.web.gwt.rest.client.ResourceAuthorizationRequestBuilderFactory;
Expand Down Expand Up @@ -59,6 +60,8 @@ private enum FileAction {

private final TranslationMessages translationMessages;

private final Translations translations;

private final ModalProvider<FileUploadModalPresenter> fileUploadModalProvider;

private final ModalProvider<CreateFolderModalPresenter> createFolderModalProvider;
Expand All @@ -80,16 +83,17 @@ private enum FileAction {
@Inject
@SuppressWarnings("PMD.ExcessiveParameterList")
public FileExplorerPresenter(Display display, EventBus eventBus, FilePathPresenter filePathPresenter,
FilePlacesPresenter filePlacesPresenter, FolderDetailsPresenter folderDetailsPresenter,
ModalProvider<FileUploadModalPresenter> fileUploadModalProvider,
ModalProvider<CreateFolderModalPresenter> createFolderModalProvider, TranslationMessages translationMessages,
ModalProvider<EncryptDownloadModalPresenter> encryptDownloadModalProvider,
ModalProvider<RenameModalPresenter> renameModalPresenterModalProvider,
ModalProvider<UnzipModalPresenter> unzipModalPresenterModalProvider) {
FilePlacesPresenter filePlacesPresenter, FolderDetailsPresenter folderDetailsPresenter,
Translations translations, ModalProvider<FileUploadModalPresenter> fileUploadModalProvider,
ModalProvider<CreateFolderModalPresenter> createFolderModalProvider, TranslationMessages translationMessages,
ModalProvider<EncryptDownloadModalPresenter> encryptDownloadModalProvider,
ModalProvider<RenameModalPresenter> renameModalPresenterModalProvider,
ModalProvider<UnzipModalPresenter> unzipModalPresenterModalProvider) {
super(eventBus, display);
this.filePathPresenter = filePathPresenter;
this.filePlacesPresenter = filePlacesPresenter;
this.folderDetailsPresenter = folderDetailsPresenter;
this.translations = translations;
this.translationMessages = translationMessages;
this.fileUploadModalProvider = fileUploadModalProvider.setContainer(this);
this.createFolderModalProvider = createFolderModalProvider.setContainer(this);
Expand Down Expand Up @@ -211,9 +215,10 @@ public void onResponseCode(Request request, Response response) {
public void onUnzipRequest(UnzipRequestEvent event) {
final String password = event.getPassword();

String requestUrl = "/files/_unzip" + event.getArchive();
String requestUrl = "/files" + event.getArchive();

UriBuilder uriBuilder = UriBuilder.create().fromPath(requestUrl);
uriBuilder.query("action", "unzip");
uriBuilder.query("destination", event.getDestination());

if (password != null && password.trim().length() > 1) {
Expand All @@ -224,16 +229,19 @@ public void onUnzipRequest(UnzipRequestEvent event) {

@Override
public void onResponseCode(Request request, Response response) {
if(response.getStatusCode() != Response.SC_OK) {
if(response.getStatusCode() != Response.SC_CREATED) {
getEventBus().fireEvent(NotificationEvent.newBuilder().error(response.getText()).build());
} else {
FileDto created = FileDto.parse(response.getText());
getEventBus().fireEvent(NotificationEvent.newBuilder()
.success(translations.userMessageMap().get("FolderCreated").replace("{0}", created.getPath())).build());
getEventBus().fireEvent(new FolderRefreshEvent(getCurrentFolder()));
}
}
};

ResourceRequestBuilderFactory.newBuilder().forResource(uriBuilder.build()).post()
.withCallback(Response.SC_OK, responseCodeCallback)
.withCallback(Response.SC_CREATED, responseCodeCallback)
.send();
}
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -761,7 +761,8 @@ public interface Translations extends Constants {
"GHOrganizationIsRequired", "GitHub user or organization name is required",
"ResourceAssignSuccess", "Resource assignment in R was successful.",
"ResourceAssignFailed", "Resource assignment in R has failed: ",
"SQLError", "{0}"
"SQLError", "{0}",
"FolderCreated", "Folder created: {0}"
})
Map<String, String> userMessageMap();

Expand Down

0 comments on commit 2165de9

Please sign in to comment.