10 Commits

Author SHA1 Message Date
Kshitij 490578cfe2 Added readme file. 2025-08-03 20:52:58 +05:30
Kshitij c45bc27c81 Fixed version for backend. It's not 1.5, it's still on 0.0.2. Dockerfile is at 1.5. 2025-08-03 20:42:39 +05:30
Kshitij 95d77fb3fe Added application.properties.bak to gitignore. 2025-08-03 20:35:54 +05:30
Kshitij 92b335410b Now passing in application.properties instead of hard coded values. 2025-08-03 20:35:31 +05:30
Kshitij b7ce85a5ec Lotta changes to Dockerfile.
- Bumped version to 1.5.
- Copying only the jar file now.
- No longer creating temp directory for downloading files. Fixed that in this version 0.0.2 of backend.
- Changed port to 8080.
- Updated CMD accn to new jar file.
2025-08-03 20:32:39 +05:30
Kshitij 7ae2eca31b Added instructions to create .p12 file using keytool (part of JDK) 2025-08-03 20:28:13 +05:30
Kshitij 0aba0e7911 Removed keystore.p12 2025-08-03 20:25:51 +05:30
Kshitij 7411f8b4fa Bumped version to 1.5 in pom.xml 2025-08-03 20:13:07 +05:30
SonaliChaudhari b2147537ca Handled Download API by not passing sensitive info 2025-07-27 15:05:33 +05:30
SonaliChaudhari 063bfa794a Implemented Cache for decrypted private key and handled refresh token 2025-07-25 13:36:15 +05:30
17 changed files with 248 additions and 94 deletions
+1
View File
@@ -1,3 +1,4 @@
src/main/resources/application.properties.bak
wiki/ wiki/
HELP.md HELP.md
target/ target/
+5 -8
View File
@@ -5,7 +5,7 @@ FROM debian:12-slim
# Metadata # Metadata
LABEL maintainer="kshitijka" LABEL maintainer="kshitijka"
LABEL version=1.0 LABEL version=1.5
LABEL description="Skycrate is a web based file management system that uses Hadoop as filesystem." LABEL description="Skycrate is a web based file management system that uses Hadoop as filesystem."
# Update & upgrade & install & rm # Update & upgrade & install & rm
@@ -19,16 +19,13 @@ RUN useradd -s /bin/bash skycrateBack
# Create work dir # Create work dir
RUN mkdir /app RUN mkdir /app
RUN chown -R skycrateBack:skycrateBack /app RUN chown -R skycrateBack:skycrateBack /app
COPY ./target/ /app COPY ./target/skycrateBackend-0.0.2.jar /app
WORKDIR /app WORKDIR /app
# Create temp download directory
RUN mkdir -p /Skycrate/downloaded/
RUN chown -R skycrateBack:skycrateBack /Skycrate /Skycrate/downloaded/
# Switch user # Switch user
USER skycrateBack USER skycrateBack
EXPOSE 8081 # Expose port for backend
EXPOSE 8080
CMD ["java", "-jar", "/app/skycrateBackend-0.0.1-SNAPSHOT.jar"] CMD ["java", "-jar", "skycrateBackend-0.0.2.jar"]
+7
View File
@@ -0,0 +1,7 @@
# Skycrate-Backend
---
This repository holds code for [Skycrate](https://git.kska.io/notkshitij/Skycrate) backend.
---
+12 -1
View File
@@ -13,7 +13,7 @@
<groupId>com.skycrate.backend</groupId> <groupId>com.skycrate.backend</groupId>
<artifactId>skycrateBackend</artifactId> <artifactId>skycrateBackend</artifactId>
<version>0.0.1-SNAPSHOT</version> <version>0.0.2</version>
<name>skycrateBackend</name> <name>skycrateBackend</name>
<description>Cloud Storage App using HDFS</description> <description>Cloud Storage App using HDFS</description>
@@ -121,6 +121,17 @@
<artifactId>spring-boot-starter-test</artifactId> <artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<!-- Caching -->
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
<version>3.0.5</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
</dependencies> </dependencies>
<build> <build>
@@ -0,0 +1,24 @@
package com.skycrate.backend.skycrateBackend.config;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.github.benmanes.caffeine.cache.Caffeine;
import org.springframework.cache.caffeine.CaffeineCacheManager;
import java.util.concurrent.TimeUnit;
@Configuration
@EnableCaching
public class CacheConfig {
@Bean
public CaffeineCacheManager cacheManager() {
CaffeineCacheManager cacheManager = new CaffeineCacheManager();
cacheManager.setCaffeine(Caffeine.newBuilder()
.expireAfterWrite(30, TimeUnit.MINUTES) // Cache expiry time
.maximumSize(100)); // Maximum cache size
return cacheManager;
}
}
@@ -29,7 +29,7 @@ public class SecurityConfig {
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.authenticationProvider(authenticationProvider) .authenticationProvider(authenticationProvider)
.authorizeHttpRequests(auth -> auth .authorizeHttpRequests(auth -> auth
.requestMatchers("/api/auth/login", "/api/auth/register", "/actuator/**").permitAll() .requestMatchers("/api/auth/logout","/api/auth/login", "/api/auth/register", "/actuator/**").permitAll()
.requestMatchers(HttpMethod.GET, "/public/**").permitAll() .requestMatchers(HttpMethod.GET, "/public/**").permitAll()
.anyRequest().authenticated() .anyRequest().authenticated()
) )
@@ -9,11 +9,10 @@ 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.LoggerFactory;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
@@ -23,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;
@@ -92,29 +92,43 @@ public class AuthController {
} }
String token = authHeader.substring(7); String token = authHeader.substring(7);
String username = jwtService.extractUsername(token);
userRepository.findByUsername(username).ifPresent(user -> {
// Clear the cached decrypted private key for the user
authenticationService.clearDecryptedPrivateKeyCache(user.getId().toString());
// Delete the refresh token associated with the user
refreshTokenService.logout(user); // This should delete the token
});
tokenBlacklistService.blacklistToken(token); tokenBlacklistService.blacklistToken(token);
String email = jwtService.extractUsername(token);
userRepository.findByEmail(email).ifPresent(refreshTokenService::deleteByUser);
return ResponseEntity.ok("Logged out successfully"); return ResponseEntity.ok("Logged out successfully");
} }
@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
authenticationService.clearDecryptedPrivateKeyCache(token.getUser().getId().toString());
return ResponseEntity.status(403).body("Refresh token expired"); return ResponseEntity.status(403).body("Refresh token expired");
} }
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;
}
}
@@ -15,4 +15,5 @@ public interface RefreshTokenRepository extends JpaRepository<RefreshToken, Long
@Modifying @Modifying
@Query("DELETE FROM RefreshToken t WHERE t.user = :user") @Query("DELETE FROM RefreshToken t WHERE t.user = :user")
void deleteByUser(User user); void deleteByUser(User user);
}
}
@@ -9,6 +9,8 @@ import com.skycrate.backend.skycrateBackend.utils.EncryptionUtil;
import com.skycrate.backend.skycrateBackend.utils.RSAKeyUtil; import com.skycrate.backend.skycrateBackend.utils.RSAKeyUtil;
import org.apache.hadoop.fs.FileSystem; import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path; import org.apache.hadoop.fs.Path;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder;
@@ -17,6 +19,8 @@ import org.springframework.stereotype.Service;
import javax.crypto.SecretKey; import javax.crypto.SecretKey;
import java.security.KeyPair; import java.security.KeyPair;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@Service @Service
public class AuthenticationService { public class AuthenticationService {
@@ -24,13 +28,18 @@ public class AuthenticationService {
private final UserRepository userRepository; private final UserRepository userRepository;
private final PasswordEncoder passwordEncoder; private final PasswordEncoder passwordEncoder;
private final AuthenticationManager authenticationManager; private final AuthenticationManager authenticationManager;
private final KeyCacheService keyCacheService;
private static final Logger log = LoggerFactory.getLogger(AuthenticationService.class);
public AuthenticationService(UserRepository userRepository, public AuthenticationService(UserRepository userRepository,
AuthenticationManager authenticationManager, AuthenticationManager authenticationManager,
PasswordEncoder passwordEncoder) { PasswordEncoder passwordEncoder,
KeyCacheService keyCacheService) {
this.userRepository = userRepository; this.userRepository = userRepository;
this.passwordEncoder = passwordEncoder; this.passwordEncoder = passwordEncoder;
this.authenticationManager = authenticationManager; this.authenticationManager = authenticationManager;
this.keyCacheService = keyCacheService;
} }
public User signUp(RegisterUserDto inputUser) { public User signUp(RegisterUserDto inputUser) {
@@ -90,4 +99,23 @@ public class AuthenticationService {
return userRepository.findByEmail(inputUser.getEmail()) return userRepository.findByEmail(inputUser.getEmail())
.orElseThrow(() -> new RuntimeException("User not found")); .orElseThrow(() -> new RuntimeException("User not found"));
} }
@Cacheable(value = "decryptedPrivateKeys", key = "#userId")
public byte[] getDecryptedPrivateKey(String userId, String password) throws Exception {
User user = userRepository.findById(Integer.valueOf(userId))
.orElseThrow(() -> new RuntimeException("User not found: " + userId));
log.info("Caching decrypted private key for userId: {}", userId);
SecretKey derivedKey = EncryptionUtil.deriveKey(password.toCharArray(), user.getPrivateKeySalt());
byte[] decryptedPrivateKeyBytes = EncryptionUtil.decrypt(user.getPrivateKey(), derivedKey, user.getPrivateKeyIv());
return decryptedPrivateKeyBytes;
}
@CacheEvict(value = "decryptedPrivateKeys", key = "#userId")
public void clearDecryptedPrivateKeyCache(String userId) {
// This method will clear the cached decrypted private key for the given userId
log.info("Clearing Caching decrypted private key for userId: {}", userId);
keyCacheService.clearKey(Long.valueOf(userId));
}
} }
@@ -17,63 +17,63 @@ public class EncryptionUtil {
private static final int IV_LENGTH = 16; // for AES CBC private static final int IV_LENGTH = 16; // for AES CBC
private static final int ITERATIONS = 65536; private static final int ITERATIONS = 65536;
private static final int KEY_LENGTH = 256; // bits private static final int KEY_LENGTH = 256; // bits
//
// // --- AES key derivation using PBKDF2 --- // --- AES key derivation using PBKDF2 ---
// public static SecretKey deriveAESKey(char[] password, byte[] salt) public static SecretKey deriveAESKey(char[] password, byte[] salt)
// throws NoSuchAlgorithmException, InvalidKeySpecException { throws NoSuchAlgorithmException, InvalidKeySpecException {
//
// SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256"); SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
//
// KeySpec spec = new PBEKeySpec(password, salt, ITERATIONS, KEY_LENGTH); KeySpec spec = new PBEKeySpec(password, salt, ITERATIONS, KEY_LENGTH);
// byte[] keyBytes = factory.generateSecret(spec).getEncoded(); byte[] keyBytes = factory.generateSecret(spec).getEncoded();
//
// return new SecretKeySpec(keyBytes, "AES"); return new SecretKeySpec(keyBytes, "AES");
// } }
//
// // --- Encrypt data using AES-CBC --- // --- Encrypt data using AES-CBC ---
// public static byte[] encrypt(byte[] data, SecretKey key, byte[] iv) public static byte[] encrypt(byte[] data, SecretKey key, byte[] iv)
// throws GeneralSecurityException { throws GeneralSecurityException {
//
// Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
//
// IvParameterSpec ivSpec = new IvParameterSpec(iv); IvParameterSpec ivSpec = new IvParameterSpec(iv);
// cipher.init(Cipher.ENCRYPT_MODE, key, ivSpec); cipher.init(Cipher.ENCRYPT_MODE, key, ivSpec);
//
// return cipher.doFinal(data); return cipher.doFinal(data);
// } }
// --- Decrypt data using AES-CBC --- // --- Decrypt data using AES-CBC ---
// public static byte[] decrypt(byte[] encryptedData, SecretKey key, byte[] iv) public static byte[] decrypt(byte[] encryptedData, SecretKey key, byte[] iv)
// throws GeneralSecurityException { throws GeneralSecurityException {
//
// Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
//
// IvParameterSpec ivSpec = new IvParameterSpec(iv);
// cipher.init(Cipher.DECRYPT_MODE, key, ivSpec);
//
// return cipher.doFinal(encryptedData);
// }
//
// // --- Generate random salt ---
// public static byte[] generateSalt() {
// byte[] salt = new byte[SALT_LENGTH];
// new SecureRandom().nextBytes(salt);
// return salt;
// }
// // --- Generate random IV --- Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
// public static byte[] generateIV() {
// byte[] iv = new byte[IV_LENGTH]; IvParameterSpec ivSpec = new IvParameterSpec(iv);
// new SecureRandom().nextBytes(iv); cipher.init(Cipher.DECRYPT_MODE, key, ivSpec);
// return iv;
// } return cipher.doFinal(encryptedData);
// }
// // --- Optional: Utility to base64 encode data ---
// public static String encodeBase64(byte[] data) { // --- Generate random salt ---
// return Base64.getEncoder().encodeToString(data); public static byte[] generateSalt() {
// } byte[] salt = new byte[SALT_LENGTH];
// new SecureRandom().nextBytes(salt);
// public static byte[] decodeBase64(String base64) { return salt;
// return Base64.getDecoder().decode(base64); }
// }
// --- Generate random IV ---
public static byte[] generateIV() {
byte[] iv = new byte[IV_LENGTH];
new SecureRandom().nextBytes(iv);
return iv;
}
// --- Optional: Utility to base64 encode data ---
public static String encodeBase64(byte[] data) {
return Base64.getEncoder().encodeToString(data);
}
public static byte[] decodeBase64(String base64) {
return Base64.getDecoder().decode(base64);
}
} }
@@ -13,7 +13,9 @@ import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path; import org.apache.hadoop.fs.Path;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.crypto.SecretKey; import javax.crypto.SecretKey;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
@@ -24,15 +26,18 @@ import java.security.PublicKey;
public class FileService { public class FileService {
private static final Logger log = LoggerFactory.getLogger(FileService.class); private static final Logger log = LoggerFactory.getLogger(FileService.class);
private final AuthenticationService authenticationService;
private final FileMetadataRepository fileMetadataRepository; private final FileMetadataRepository fileMetadataRepository;
private final UserRepository userRepository; private final UserRepository userRepository;
public FileService(FileMetadataRepository fileMetadataRepository, UserRepository userRepository) { @Autowired
public FileService(FileMetadataRepository fileMetadataRepository, UserRepository userRepository, AuthenticationService authenticationService) {
this.fileMetadataRepository = fileMetadataRepository; this.fileMetadataRepository = fileMetadataRepository;
this.userRepository = userRepository; this.userRepository = userRepository;
this.authenticationService = authenticationService;
} }
@Transactional
public void uploadEncryptedFile(String username, byte[] fileContent, String filename) throws Exception { public void uploadEncryptedFile(String username, byte[] fileContent, String filename) throws Exception {
log.info("Starting upload for user={}, file={}", username, filename); log.info("Starting upload for user={}, file={}", username, filename);
try { try {
@@ -91,8 +96,8 @@ public class FileService {
FileMetadata metadata = fileMetadataRepository.findByUsernameAndFilePath(username, filePath.toString()) FileMetadata metadata = fileMetadataRepository.findByUsernameAndFilePath(username, filePath.toString())
.orElseThrow(() -> new RuntimeException("File metadata not found for: " + filePath)); .orElseThrow(() -> new RuntimeException("File metadata not found for: " + filePath));
SecretKey derivedKey = EncryptionUtil.deriveKey(password.toCharArray(), user.getPrivateKeySalt()); // Use the cached decrypted private key
byte[] decryptedPrivateKeyBytes = EncryptionUtil.decrypt(user.getPrivateKey(), derivedKey, user.getPrivateKeyIv()); byte[] decryptedPrivateKeyBytes = authenticationService.getDecryptedPrivateKey(String.valueOf(user.getId()), password);
PrivateKey privateKey = RSAKeyUtil.decodePrivateKey(decryptedPrivateKeyBytes); PrivateKey privateKey = RSAKeyUtil.decodePrivateKey(decryptedPrivateKeyBytes);
byte[] aesKeyBytes = EncryptionUtil.decryptRSA(metadata.getEncryptedKey(), privateKey); byte[] aesKeyBytes = EncryptionUtil.decryptRSA(metadata.getEncryptedKey(), privateKey);
@@ -0,0 +1,28 @@
package com.skycrate.backend.skycrateBackend.services;
import org.springframework.stereotype.Service;
import java.util.concurrent.ConcurrentHashMap;
@Service
public class KeyCacheService {
private final ConcurrentHashMap<Long, String> keyCache = new ConcurrentHashMap<>();
public void cacheKey(Long userId, String decryptedKey) {
keyCache.put(userId, decryptedKey);
}
public String getKey(Long userId) {
return keyCache.get(userId);
}
public void clearKey(Long userId) {
keyCache.remove(userId);
}
public void clearAllKeys() {
keyCache.clear();
}
}
@@ -16,7 +16,7 @@ public class RefreshTokenService {
private final RefreshTokenRepository refreshTokenRepo; private final RefreshTokenRepository refreshTokenRepo;
@Value("${security.jwt.refresh-expiry-ms:604800000}") // 7 days default @Value("${security.jwt.refresh-expiry-ms:86400000}") //1 day in milliseconds
private Long refreshTokenDurationMs; private Long refreshTokenDurationMs;
public RefreshTokenService(RefreshTokenRepository refreshTokenRepo) { public RefreshTokenService(RefreshTokenRepository refreshTokenRepo) {
@@ -35,6 +35,7 @@ public class RefreshTokenService {
return refreshTokenRepo.save(token); return refreshTokenRepo.save(token);
} }
public Optional<RefreshToken> findByToken(String token) { public Optional<RefreshToken> findByToken(String token) {
return refreshTokenRepo.findByToken(token); return refreshTokenRepo.findByToken(token);
} }
@@ -45,6 +46,20 @@ public class RefreshTokenService {
@Transactional @Transactional
public void deleteByUser(User user) { public void deleteByUser(User user) {
refreshTokenRepo.deleteByUser(user); try {
refreshTokenRepo.deleteByUser(user);
System.out.println("Successfully deleted refresh tokens for user: " + user.getId());
} catch (Exception e) {
System.err.println("Error deleting refresh tokens for user: " + user.getId() + " - " + e.getMessage());
}
}
@Transactional
public void logout(User user) {
deleteByUser(user); // This should call the repository method to delete the token
}
public Optional<RefreshToken> refreshAccessToken(String refreshToken) {
return findByToken(refreshToken).filter(token -> !isExpired(token));
} }
} }
+6 -7
View File
@@ -5,13 +5,13 @@ spring.servlet.multipart.max-request-size=1000MB
spring.servlet.multipart.enabled=true spring.servlet.multipart.enabled=true
security.jwt.secret-key=PPp27xSTfBwOpRn4/AV6gPzQSnQg+Oi80KdWfCcuAHs= security.jwt.secret-key=${JWT_SECRET}
security.jwt.expiration-time=3600000 security.jwt.expiration-time=3600000
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQLDialect spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQLDialect
spring.datasource.username=skycrateDB spring.datasource.username=${DB_USERNAME}
spring.datasource.password=loa_dngLLA8729 spring.datasource.password=${DB_PASSWORD}
spring.datasource.url=jdbc:mysql://192.168.29.36:3306/skycrate spring.datasource.url=jdbc:mysql://${DB_URI}/${DB_NAME}
spring.jpa.hibernate.ddl-auto=update spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true spring.jpa.show-sql=true
@@ -23,15 +23,14 @@ server.port=8080
server.ssl.enabled=true server.ssl.enabled=true
server.ssl.key-store=classpath:keystore.p12 server.ssl.key-store=classpath:keystore.p12
server.ssl.key-store-password=changeit server.ssl.key-store-password=${SSL_PASSWORD}
server.ssl.key-store-type=PKCS12 server.ssl.key-store-type=PKCS12
server.ssl.key-alias=mykey server.ssl.key-alias=skycrateSSL
management.endpoints.web.exposure.include=* management.endpoints.web.exposure.include=*
management.endpoint.health.show-details=always management.endpoint.health.show-details=always
management.endpoints.enabled-by-default=true management.endpoints.enabled-by-default=true
# Allow unauthenticated access # Allow unauthenticated access
#management.server.port=8080 #management.server.port=8080
#management.server.ssl.enabled=false #management.server.ssl.enabled=false
Binary file not shown.