Handled Download API by not passing sensitive info
This commit is contained in:
@@ -9,10 +9,7 @@ import com.skycrate.backend.skycrateBackend.entity.RefreshToken;
|
|||||||
import com.skycrate.backend.skycrateBackend.entity.User;
|
import com.skycrate.backend.skycrateBackend.entity.User;
|
||||||
import com.skycrate.backend.skycrateBackend.repository.UserRepository;
|
import com.skycrate.backend.skycrateBackend.repository.UserRepository;
|
||||||
import com.skycrate.backend.skycrateBackend.security.TokenBlacklistService;
|
import com.skycrate.backend.skycrateBackend.security.TokenBlacklistService;
|
||||||
import com.skycrate.backend.skycrateBackend.services.AuthenticationService;
|
import com.skycrate.backend.skycrateBackend.services.*;
|
||||||
import com.skycrate.backend.skycrateBackend.services.JwtService;
|
|
||||||
import com.skycrate.backend.skycrateBackend.services.RateLimiterService;
|
|
||||||
import com.skycrate.backend.skycrateBackend.services.RefreshTokenService;
|
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
@@ -25,6 +22,7 @@ import org.springframework.web.bind.annotation.*;
|
|||||||
@RequestMapping("/api/auth")
|
@RequestMapping("/api/auth")
|
||||||
public class AuthController {
|
public class AuthController {
|
||||||
|
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(FileService.class);
|
||||||
private final AuthenticationManager authManager;
|
private final AuthenticationManager authManager;
|
||||||
private final JwtService jwtService;
|
private final JwtService jwtService;
|
||||||
private final UserRepository userRepository;
|
private final UserRepository userRepository;
|
||||||
@@ -86,23 +84,6 @@ public class AuthController {
|
|||||||
return ResponseEntity.ok(new LoginResponse(accessToken, refreshToken.getToken()));
|
return ResponseEntity.ok(new LoginResponse(accessToken, refreshToken.getToken()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// @PostMapping("/logout")
|
|
||||||
// public ResponseEntity<?> logout(HttpServletRequest request) {
|
|
||||||
// String authHeader = request.getHeader("Authorization");
|
|
||||||
// if (authHeader == null || !authHeader.startsWith("Bearer ")) {
|
|
||||||
// return ResponseEntity.badRequest().body("Missing or invalid Authorization header");
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// String token = authHeader.substring(7);
|
|
||||||
//
|
|
||||||
// tokenBlacklistService.blacklistToken(token);
|
|
||||||
//
|
|
||||||
// String email = jwtService.extractUsername(token);
|
|
||||||
// userRepository.findByEmail(email).ifPresent(refreshTokenService::deleteByUser);
|
|
||||||
//
|
|
||||||
// return ResponseEntity.ok("Logged out successfully");
|
|
||||||
// }
|
|
||||||
|
|
||||||
@PostMapping("/logout")
|
@PostMapping("/logout")
|
||||||
public ResponseEntity<?> logout(HttpServletRequest request) {
|
public ResponseEntity<?> logout(HttpServletRequest request) {
|
||||||
String authHeader = request.getHeader("Authorization");
|
String authHeader = request.getHeader("Authorization");
|
||||||
@@ -126,30 +107,15 @@ public class AuthController {
|
|||||||
return ResponseEntity.ok("Logged out successfully");
|
return ResponseEntity.ok("Logged out successfully");
|
||||||
}
|
}
|
||||||
|
|
||||||
// @PostMapping("/refresh")
|
|
||||||
// public ResponseEntity<?> refresh(@RequestBody TokenRefreshRequest request) {
|
|
||||||
// String requestToken = request.getRefreshToken();
|
|
||||||
//
|
|
||||||
// return refreshTokenService.findByToken(requestToken)
|
|
||||||
// .map(token -> {
|
|
||||||
// if (refreshTokenService.isExpired(token)) {
|
|
||||||
// return ResponseEntity.status(403).body("Refresh token expired");
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// User user = token.getUser();
|
|
||||||
// String newAccessToken = jwtService.generateToken(user);
|
|
||||||
// return ResponseEntity.ok(new TokenRefreshResponse(newAccessToken, requestToken));
|
|
||||||
// })
|
|
||||||
// .orElseGet(() -> ResponseEntity.status(403).body("Invalid refresh token"));
|
|
||||||
// }
|
|
||||||
|
|
||||||
@PostMapping("/refresh")
|
@PostMapping("/refresh")
|
||||||
public ResponseEntity<?> refresh(@RequestBody TokenRefreshRequest request) {
|
public ResponseEntity<?> refresh(@RequestBody TokenRefreshRequest request) {
|
||||||
String requestToken = request.getRefreshToken();
|
String requestToken = request.getRefreshToken();
|
||||||
|
log.error("Received refresh token: " + requestToken);
|
||||||
|
|
||||||
return refreshTokenService.findByToken(requestToken)
|
return refreshTokenService.findByToken(requestToken)
|
||||||
.map(token -> {
|
.map(token -> {
|
||||||
if (refreshTokenService.isExpired(token)) {
|
if (refreshTokenService.isExpired(token)) {
|
||||||
|
log.error("Refresh token expired for user: " + token.getUser().getUsername());
|
||||||
// Clear the cached key on token expiry
|
// Clear the cached key on token expiry
|
||||||
authenticationService.clearDecryptedPrivateKeyCache(token.getUser().getId().toString());
|
authenticationService.clearDecryptedPrivateKeyCache(token.getUser().getId().toString());
|
||||||
return ResponseEntity.status(403).body("Refresh token expired");
|
return ResponseEntity.status(403).body("Refresh token expired");
|
||||||
@@ -157,8 +123,12 @@ public class AuthController {
|
|||||||
|
|
||||||
User user = token.getUser();
|
User user = token.getUser();
|
||||||
String newAccessToken = jwtService.generateToken(user);
|
String newAccessToken = jwtService.generateToken(user);
|
||||||
|
log.info("Generated new access token for user: " + user.getUsername());
|
||||||
return ResponseEntity.ok(new TokenRefreshResponse(newAccessToken, requestToken));
|
return ResponseEntity.ok(new TokenRefreshResponse(newAccessToken, requestToken));
|
||||||
})
|
})
|
||||||
.orElseGet(() -> ResponseEntity.status(403).body("Invalid refresh token"));
|
.orElseGet(() -> {
|
||||||
|
log.error("Invalid refresh token: " + requestToken);
|
||||||
|
return ResponseEntity.status(403).body("Invalid refresh token");
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
package com.skycrate.backend.skycrateBackend.controller;
|
package com.skycrate.backend.skycrateBackend.controller;
|
||||||
|
|
||||||
|
import com.skycrate.backend.skycrateBackend.dto.FileDownloadRequest;
|
||||||
import com.skycrate.backend.skycrateBackend.services.FileService;
|
import com.skycrate.backend.skycrateBackend.services.FileService;
|
||||||
import com.skycrate.backend.skycrateBackend.services.JwtService;
|
import com.skycrate.backend.skycrateBackend.services.JwtService;
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
@@ -39,20 +40,20 @@ public class FileController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/download/{filename}")
|
@GetMapping("/download")
|
||||||
public ResponseEntity<?> downloadFile(
|
public ResponseEntity<?> downloadFile(
|
||||||
@PathVariable String filename,
|
@RequestBody FileDownloadRequest fileDownloadRequest,
|
||||||
@RequestParam("password") String password,
|
|
||||||
HttpServletRequest request
|
HttpServletRequest request
|
||||||
) {
|
) {
|
||||||
try {
|
try {
|
||||||
String token = extractToken(request);
|
String token = extractToken(request);
|
||||||
String username = jwtService.extractUsername(token);
|
String username = jwtService.extractUsername(token);
|
||||||
|
|
||||||
byte[] decryptedData = fileService.downloadDecryptedFile(username, password, filename);
|
// Use the password and filename from the FileDownloadRequest DTO
|
||||||
|
byte[] decryptedData = fileService.downloadDecryptedFile(username, fileDownloadRequest.getPassword(), fileDownloadRequest.getFilename());
|
||||||
|
|
||||||
return ResponseEntity.ok()
|
return ResponseEntity.ok()
|
||||||
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + filename + "\"")
|
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + fileDownloadRequest.getFilename() + "\"")
|
||||||
.contentLength(decryptedData.length)
|
.contentLength(decryptedData.length)
|
||||||
.contentType(MediaType.APPLICATION_OCTET_STREAM)
|
.contentType(MediaType.APPLICATION_OCTET_STREAM)
|
||||||
.body(decryptedData);
|
.body(decryptedData);
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package com.skycrate.backend.skycrateBackend.dto;
|
||||||
|
|
||||||
|
public class FileDownloadRequest {
|
||||||
|
private String filename;
|
||||||
|
private String password;
|
||||||
|
|
||||||
|
// Getters and Setters
|
||||||
|
public String getFilename() {
|
||||||
|
return filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFilename(String filename) {
|
||||||
|
this.filename = filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPassword() {
|
||||||
|
return password;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPassword(String password) {
|
||||||
|
this.password = password;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -30,11 +30,6 @@ public class FileService {
|
|||||||
private final FileMetadataRepository fileMetadataRepository;
|
private final FileMetadataRepository fileMetadataRepository;
|
||||||
private final UserRepository userRepository;
|
private final UserRepository userRepository;
|
||||||
|
|
||||||
// public FileService(FileMetadataRepository fileMetadataRepository, UserRepository userRepository) {
|
|
||||||
// this.fileMetadataRepository = fileMetadataRepository;
|
|
||||||
// this.userRepository = userRepository;
|
|
||||||
// }
|
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public FileService(FileMetadataRepository fileMetadataRepository, UserRepository userRepository, AuthenticationService authenticationService) {
|
public FileService(FileMetadataRepository fileMetadataRepository, UserRepository userRepository, AuthenticationService authenticationService) {
|
||||||
this.fileMetadataRepository = fileMetadataRepository;
|
this.fileMetadataRepository = fileMetadataRepository;
|
||||||
@@ -91,37 +86,6 @@ public class FileService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// public byte[] downloadDecryptedFile(String username, String password, String filename) throws Exception {
|
|
||||||
// log.info("Download request: user={}, file={}", username, filename);
|
|
||||||
// try {
|
|
||||||
// User user = userRepository.findByUsername(username)
|
|
||||||
// .orElseThrow(() -> new RuntimeException("User not found: " + username));
|
|
||||||
//
|
|
||||||
// Path filePath = new Path("/" + username + "/" + filename);
|
|
||||||
// FileMetadata metadata = fileMetadataRepository.findByUsernameAndFilePath(username, filePath.toString())
|
|
||||||
// .orElseThrow(() -> new RuntimeException("File metadata not found for: " + filePath));
|
|
||||||
//
|
|
||||||
// SecretKey derivedKey = EncryptionUtil.deriveKey(password.toCharArray(), user.getPrivateKeySalt());
|
|
||||||
// byte[] decryptedPrivateKeyBytes = EncryptionUtil.decrypt(user.getPrivateKey(), derivedKey, user.getPrivateKeyIv());
|
|
||||||
// PrivateKey privateKey = RSAKeyUtil.decodePrivateKey(decryptedPrivateKeyBytes);
|
|
||||||
//
|
|
||||||
// byte[] aesKeyBytes = EncryptionUtil.decryptRSA(metadata.getEncryptedKey(), privateKey);
|
|
||||||
// SecretKey aesKey = EncryptionUtil.rebuildAESKey(aesKeyBytes);
|
|
||||||
//
|
|
||||||
// FileSystem fs = HDFSConfig.getHDFS();
|
|
||||||
// byte[] encryptedData;
|
|
||||||
// try (FSDataInputStream in = fs.open(filePath)) {
|
|
||||||
// encryptedData = in.readAllBytes();
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// return EncryptionUtil.decrypt(encryptedData, aesKey, metadata.getIv());
|
|
||||||
//
|
|
||||||
// } catch (Exception e) {
|
|
||||||
// log.error("Download failed for user={}, file={}: {}", username, filename, e.getMessage(), e);
|
|
||||||
// throw e;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
public byte[] downloadDecryptedFile(String username, String password, String filename) throws Exception {
|
public byte[] downloadDecryptedFile(String username, String password, String filename) throws Exception {
|
||||||
log.info("Download request: user={}, file={}", username, filename);
|
log.info("Download request: user={}, file={}", username, filename);
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -23,18 +23,6 @@ public class RefreshTokenService {
|
|||||||
this.refreshTokenRepo = refreshTokenRepo;
|
this.refreshTokenRepo = refreshTokenRepo;
|
||||||
}
|
}
|
||||||
|
|
||||||
// @Transactional
|
|
||||||
// public RefreshToken createRefreshToken(User user) {
|
|
||||||
// refreshTokenRepo.deleteByUser(user);
|
|
||||||
// refreshTokenRepo.flush();
|
|
||||||
//
|
|
||||||
// RefreshToken token = new RefreshToken();
|
|
||||||
// token.setUser(user);
|
|
||||||
// token.setExpiryDate(Instant.now().plusMillis(refreshTokenDurationMs));
|
|
||||||
// token.setToken(UUID.randomUUID().toString());
|
|
||||||
// return refreshTokenRepo.save(token);
|
|
||||||
// }
|
|
||||||
|
|
||||||
@Transactional
|
@Transactional
|
||||||
public RefreshToken createRefreshToken(User user) {
|
public RefreshToken createRefreshToken(User user) {
|
||||||
refreshTokenRepo.deleteByUser(user);
|
refreshTokenRepo.deleteByUser(user);
|
||||||
@@ -55,11 +43,6 @@ public class RefreshTokenService {
|
|||||||
public boolean isExpired(RefreshToken token) {
|
public boolean isExpired(RefreshToken token) {
|
||||||
return token.getExpiryDate().isBefore(Instant.now());
|
return token.getExpiryDate().isBefore(Instant.now());
|
||||||
}
|
}
|
||||||
//
|
|
||||||
// @Transactional
|
|
||||||
// public void deleteByUser(User user) {
|
|
||||||
// refreshTokenRepo.deleteByUser(user);
|
|
||||||
// }
|
|
||||||
|
|
||||||
@Transactional
|
@Transactional
|
||||||
public void deleteByUser(User user) {
|
public void deleteByUser(User user) {
|
||||||
|
|||||||
Reference in New Issue
Block a user