package net.gepafin.tendermanagement.config.jwt; import io.jsonwebtoken.Claims; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.SignatureAlgorithm; import io.jsonwebtoken.security.Keys; import jakarta.annotation.PostConstruct; import jakarta.servlet.http.HttpServletRequest; import net.gepafin.tendermanagement.entities.UserEntity; import net.gepafin.tendermanagement.util.Utils; import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.time.DateUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.stereotype.Component; import org.springframework.util.StringUtils; import javax.crypto.SecretKey; import java.nio.charset.StandardCharsets; import java.util.*; import java.util.stream.Collectors; import com.google.gson.Gson; import static io.micrometer.common.util.StringUtils.isEmpty; @Component public class TokenProvider { private final Logger log = LoggerFactory.getLogger(TokenProvider.class); @Value("${security.authentication.jwt.secret}") private String secretKey; @Value("${security.authentication.jwt.token-validity-in-seconds}") private long tokenValidityInSeconds; private SecretKey key; private static final String AUTHORITIES_KEY = "auth"; private static final String MERCHANTID="merchantId"; public static final String INVALID_USER = "invalid_user"; static final String AUTH_SECRET = "X-Api-Secret"; @PostConstruct public void init() { this.key = Keys.hmacShaKeyFor(secretKey.getBytes(StandardCharsets.UTF_8)); log.info("JWT Secret Key initialized."); } public String createToken(Authentication authentication, Boolean rememberMe, UserEntity user) { String authorities = authentication.getAuthorities().stream() .map(GrantedAuthority::getAuthority) .collect(Collectors.joining(",")); Long now; Date validity; if (Boolean.TRUE.equals(rememberMe)) { now = DateUtils.addMonths(new Date(), 2).getTime(); validity = new Date(now); log.info("Creating token with extended validity for 2 months."); } else { now = (new Date()).getTime(); validity = new Date(now + (this.tokenValidityInSeconds * 1000)); log.info("Creating token with standard validity of {} seconds.", this.tokenValidityInSeconds); } String payload = authentication.getName(); if(user != null) { payload += ":"+user.getId(); } String token = Jwts.builder() .setSubject(payload) .claim("auth", authorities) .signWith(key, SignatureAlgorithm.HS512) .setExpiration(validity) .compact(); log.debug("Generated token: {}", token); return token; } public Authentication getAuthentication(String token) { Claims claims = Jwts.parserBuilder() .setSigningKey(key) .build() .parseClaimsJws(token) .getBody(); UserDetails principal = new User(claims.getSubject(), "", Collections.emptyList()); log.info("Authenticated user: {}", claims.getSubject()); return new UsernamePasswordAuthenticationToken(principal, token, ClaimsToAuthorities(claims.get("auth"))); } private Collection ClaimsToAuthorities(Object authClaim) { Collection authorities = authClaim == null || ((String) authClaim).isEmpty() ? Collections.emptyList() : Arrays.stream(((String) authClaim).split(",")) .map(SimpleGrantedAuthority::new) .collect(Collectors.toList()); log.debug("Converted authorities from claims: {}", authorities); return authorities; } public boolean validateToken(String authToken) { try { Jwts.parserBuilder() .setSigningKey(key) .build() .parseClaimsJws(authToken); log.info("Token is valid."); return true; } catch (Exception e) { log.error("Token validation failed: {}", e.getMessage()); return false; } } public Map getUserInfoAndUserIdFromToken(HttpServletRequest request) { Map userInfo = new HashMap<>(); String authSecretHeader=request.getHeader(AUTH_SECRET); // userInfo.put(MERCHANTID, null); String bearerToken = request.getHeader("Authorization"); String token = ""; if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) { token = bearerToken.substring(7, bearerToken.length()); } extractDetailsFromTheToken(userInfo, authSecretHeader, token); return userInfo; } public Map extractDetailsFromTheToken(Map userInfo, String authSecretHeader, String token) { String payload = null; Boolean isSuperAdmin = false; // if (StringUtils.hasText(token) && token.endsWith("_superKey" + getSuperUserToken())) { // Map payloadMap = getUserDetailsForSuperUser(token); // payload = payloadMap.get("sub").toString(); // isSuperAdmin = true; // // } else if (!isEmpty(authSecretHeader)) { String secret = Utils.decodeBase64String(authSecretHeader); String[] tokenArr = secret.split("\\.", 2); String[] merchant = tokenArr[0].split("-"); if (ArrayUtils.isNotEmpty(merchant) && 2 <= merchant.length) { userInfo.put(MERCHANTID, merchant[1]); return userInfo; } } else { payload = getUserDetails(token); } if (payload != null && !isSuperAdmin) { String[] payloadString = payload.split(":");{ if (payloadString.length > 1) { // userInfo.put(MERCHANTID, payloadString[1]); // userInfo.put("associatedTags", payloadString[2]); userInfo.put("userId", payloadString[1]); } } if (payloadString.length > 1) { // userInfo.put(MERCHANTID, payloadString[1]); // userInfo.put("associatedTags", payloadString[2]); userInfo.put("userId", payloadString[1]); } } else { String[] payloadString = payload.split(":"); if (payloadString.length > 1) { userInfo.put("userId", payloadString[1]); } } return userInfo; } public Map getUserDetailsForSuperUser(String token) { Base64.Decoder decoder = Base64.getUrlDecoder(); String[] parts = token.split("\\."); // Splitting header, payload and signature Gson g = new Gson(); return g.fromJson(new String(decoder.decode(parts[1])), Map.class); } // public String getSuperUserToken() { // return superUserToken; // } public String getUserDetails(String token) { Claims claims = Jwts.parser().setSigningKey(key).parseClaimsJws(token).getBody(); return claims.getSubject(); } }