Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 25 additions & 24 deletions src/main/java/com/wipro/fhir/utils/JwtUtil.java
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
package com.wipro.fhir.utils;

import java.security.Key;
import java.util.Date;
import java.util.function.Function;
import javax.crypto.SecretKey;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.security.Keys;

@Component
Expand All @@ -18,36 +17,34 @@ public class JwtUtil {
@Value("${jwt.secret}")
private String SECRET_KEY;

private static final long EXPIRATION_TIME = 24L * 60 * 60 * 1000; // 1 day in milliseconds
@Autowired
private TokenDenylist tokenDenylist;

// Generate a key using the secret
private Key getSigningKey() {
private SecretKey getSigningKey() {
if (SECRET_KEY == null || SECRET_KEY.isEmpty()) {
throw new IllegalStateException("JWT secret key is not set in application.properties");
}
return Keys.hmacShaKeyFor(SECRET_KEY.getBytes());
}

// Generate JWT Token
public String generateToken(String username, String userId) {
Date now = new Date();
Date expiryDate = new Date(now.getTime() + EXPIRATION_TIME);

// Include the userId in the JWT claims
return Jwts.builder().setSubject(username).claim("userId", userId) // Add userId as a claim
.setIssuedAt(now).setExpiration(expiryDate).signWith(getSigningKey(), SignatureAlgorithm.HS256)
.compact();
}

// Validate and parse JWT Token
public Claims validateToken(String token) {
try {
// Use the JwtParserBuilder correctly in version 0.12.6
return Jwts.parser() // Correct method in 0.12.6 to get JwtParserBuilder
.setSigningKey(getSigningKey()) // Set the signing key
.build() // Build the JwtParser
.parseClaimsJws(token) // Parse and validate the token
.getBody();
Claims claims = Jwts.parser()
.verifyWith(getSigningKey())
.build()
.parseSignedClaims(token)
.getPayload();

String jti = claims.getId();

// Check if token is denylisted (only if jti exists)
if (jti != null && tokenDenylist.isTokenDenylisted(jti)) {
return null;
}

return claims;
} catch (Exception e) {
return null; // Handle token parsing/validation errors
}
Expand All @@ -59,10 +56,14 @@ public String extractUsername(String token) {

public <T> T extractClaim(String token, Function<Claims, T> claimsResolver) {
final Claims claims = extractAllClaims(token);
return claimsResolver.apply(claims);
return claims != null ? claimsResolver.apply(claims) : null;
}

private Claims extractAllClaims(String token) {
return Jwts.parser().setSigningKey(getSigningKey()).build().parseClaimsJws(token).getBody();
return Jwts.parser()
.verifyWith(getSigningKey())
.build()
.parseSignedClaims(token)
.getPayload();
}
}
55 changes: 55 additions & 0 deletions src/main/java/com/wipro/fhir/utils/TokenDenylist.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package com.wipro.fhir.utils;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;

@Component
public class TokenDenylist {
private final Logger logger = LoggerFactory.getLogger(this.getClass().getName());

private static final String PREFIX = "denied_";

@Autowired
private RedisTemplate<String, Object> redisTemplate;

private String getKey(String jti) {
return PREFIX + jti;
}

// Add a token's jti to the denylist with expiration time
public void addTokenToDenylist(String jti, Long expirationTime) {
if (jti == null || jti.trim().isEmpty()) {
return;
}
if (expirationTime == null || expirationTime <= 0) {
throw new IllegalArgumentException("Expiration time must be positive");
}

try {
String key = getKey(jti); // Use helper method to get the key
redisTemplate.opsForValue().set(key, " ", expirationTime, TimeUnit.MILLISECONDS);
} catch (Exception e) {
throw new RuntimeException("Failed to denylist token", e);
}
}

// Check if a token's jti is in the denylist
public boolean isTokenDenylisted(String jti) {
if (jti == null || jti.trim().isEmpty()) {
return false;
}
try {
String key = getKey(jti); // Use helper method to get the key
return Boolean.TRUE.equals(redisTemplate.hasKey(key));
} catch (Exception e) {
logger.error("Failed to check denylist status for jti: " + jti, e);
// In case of Redis failure, consider the token as not denylisted to avoid blocking all requests
return false;
}
}
}
Loading