/* * This file is part of vospace-file-service * Copyright (C) 2021 Istituto Nazionale di Astrofisica * SPDX-License-Identifier: GPL-3.0-or-later */ package it.inaf.ia2.transfer.controller; import it.inaf.ia2.transfer.auth.GmsClient; import it.inaf.ia2.transfer.auth.TokenPrincipal; import it.inaf.ia2.transfer.persistence.FileDAO; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.UncheckedIOException; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; import java.util.Optional; import javax.servlet.http.HttpServletResponse; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import static org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR; import static org.springframework.http.HttpStatus.NOT_FOUND; import static org.springframework.http.HttpStatus.UNAUTHORIZED; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class GetFileController extends FileController { private static final Logger LOG = LoggerFactory.getLogger(GetFileController.class); @Autowired private FileDAO fileDAO; @Autowired private GmsClient gmsClient; @Autowired private HttpServletResponse response; @GetMapping("/**") public ResponseEntity getFile() { String path = getPath(); LOG.debug("getFile called for path {}", path); Optional optFileInfo = fileDAO.getFileInfo(path); if (optFileInfo.isPresent()) { FileInfo fileInfo = optFileInfo.get(); if (!fileInfo.isIsPublic() && !privateButDownloadable(fileInfo)) { return new ResponseEntity<>("Unauthorized", UNAUTHORIZED); } return getFileResponse(fileInfo); } else { return new ResponseEntity<>("File " + path + " not found", NOT_FOUND); } } private boolean privateButDownloadable(FileInfo fileInfo) { TokenPrincipal principal = (TokenPrincipal) request.getUserPrincipal(); String token = principal.getToken(); if (token == null) { return false; } if (principal.getName().equals(fileInfo.getOwnerId())) { return true; } // TODO: configure cache if (fileInfo.getGroupRead() == null) { return false; } for (String group : fileInfo.getGroupRead()) { if (gmsClient.isMemberOf(token, group)) { return true; } } return false; } private ResponseEntity getFileResponse(FileInfo fileInfo) { File file = new File(fileInfo.getOsPath()); if (!file.exists()) { LOG.error("File not found: " + file.getAbsolutePath()); return new ResponseEntity<>("File " + file.getName() + " not found", NOT_FOUND); } if (!file.canRead()) { LOG.error("File not readable: " + file.getAbsolutePath()); return new ResponseEntity<>("File " + file.getName() + " is not readable", INTERNAL_SERVER_ERROR); } String vosName = fileInfo.getVirtualPath().substring(fileInfo.getVirtualPath().lastIndexOf("/") + 1); response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(vosName, StandardCharsets.UTF_8)); response.setHeader("Content-Length", String.valueOf(file.length())); response.setCharacterEncoding("UTF-8"); byte[] bytes = new byte[1024]; try (OutputStream out = response.getOutputStream(); InputStream is = new FileInputStream(file)) { int read; while ((read = is.read(bytes)) != -1) { out.write(bytes, 0, read); } } catch (IOException ex) { throw new UncheckedIOException(ex); } return null; } }