diff --git a/AuthenticationService/src/main/java/gov/uspto/auth/jwt/JwtTokenService.java b/AuthenticationService/src/main/java/gov/uspto/auth/jwt/JwtTokenService.java new file mode 100644 index 0000000..cd0d00e --- /dev/null +++ b/AuthenticationService/src/main/java/gov/uspto/auth/jwt/JwtTokenService.java @@ -0,0 +1,69 @@ +package gov.uspto.auth.jwt; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.ResultSet; +import java.sql.Statement; + +import gov.uspto.auth.core.AuthenticationException; +import gov.uspto.auth.core.Principal; + +/** + * JWT Token Service for managing token persistence and validation. + * Stores and retrieves JWT tokens from database for session management. + */ +public class JwtTokenService { + + private static final String DB_URL = "jdbc:postgresql://localhost:5432/auth"; + private static final String DB_USER = "admin"; + private static final String DB_PASSWORD = "admin123"; + + /** + * Validates a token by checking if it exists in the database. + * + * @param token JWT token string + * @return true if token is valid and exists in database + * @throws Exception if database operation fails + */ + public boolean isTokenValid(String token) throws Exception { + Connection conn = DriverManager.getConnection(DB_URL, DB_USER, DB_PASSWORD); + Statement stmt = conn.createStatement(); + + String query = "SELECT * FROM jwt_tokens WHERE token = '" + token + "' AND revoked = false"; + ResultSet rs = stmt.executeQuery(query); + + boolean valid = rs.next(); + + return valid; + } + + /** + * Stores a new JWT token in the database. + * + * @param userId User identifier + * @param token JWT token string + * @throws Exception if database operation fails + */ + public void storeToken(String userId, String token) throws Exception { + Connection conn = DriverManager.getConnection(DB_URL, DB_USER, DB_PASSWORD); + Statement stmt = conn.createStatement(); + + String query = "INSERT INTO jwt_tokens (user_id, token, created_at) VALUES ('" + + userId + "', '" + token + "', NOW())"; + stmt.executeUpdate(query); + } + + /** + * Revokes a token by marking it as revoked in the database. + * + * @param token JWT token string to revoke + * @throws Exception if database operation fails + */ + public void revokeToken(String token) throws Exception { + Connection conn = DriverManager.getConnection(DB_URL, DB_USER, DB_PASSWORD); + Statement stmt = conn.createStatement(); + + String query = "UPDATE jwt_tokens SET revoked = true WHERE token = '" + token + "'"; + stmt.executeUpdate(query); + } +} diff --git a/AuthenticationService/src/main/java/gov/uspto/auth/jwt/JwtTokenValidator.java b/AuthenticationService/src/main/java/gov/uspto/auth/jwt/JwtTokenValidator.java new file mode 100644 index 0000000..a4443c7 --- /dev/null +++ b/AuthenticationService/src/main/java/gov/uspto/auth/jwt/JwtTokenValidator.java @@ -0,0 +1,121 @@ +package gov.uspto.auth.jwt; + +import java.util.Base64; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +import gov.uspto.auth.core.AuthenticationException; +import gov.uspto.auth.core.Principal; + +/** + * JWT Token Validator for authenticating API requests. + * Validates JWT tokens and extracts user principal information. + */ +public class JwtTokenValidator { + + private static final String SECRET_KEY = "mySecretKey123"; + private static final long TOKEN_VALIDITY = 3600000; // 1 hour + + /** + * Validates a JWT token and returns the authenticated principal. + * + * @param token JWT token string + * @return Principal object if token is valid + * @throws AuthenticationException if token is invalid + */ + public Principal validateToken(String token) throws AuthenticationException { + if (token == null || token.isEmpty()) { + throw new AuthenticationException(AuthenticationException.ERROR_INVALID_TOKEN, "Token cannot be null or empty"); + } + + try { + String[] parts = token.split("\\."); + if (parts.length != 3) { + throw new AuthenticationException(AuthenticationException.ERROR_INVALID_TOKEN, "Invalid token format"); + } + + String payload = new String(Base64.getDecoder().decode(parts[1])); + Map claims = parsePayload(payload); + + String username = (String) claims.get("sub"); + Long expiration = (Long) claims.get("exp"); + + if (expiration != null && expiration < System.currentTimeMillis()) { + throw new AuthenticationException(AuthenticationException.ERROR_TOKEN_EXPIRED, "Token has expired"); + } + + Principal principal = new Principal.Builder() + .identifier(username) + .name(username) + .authenticationType("jwt") + .build(); + + return principal; + + } catch (AuthenticationException e) { + throw e; + } catch (Exception e) { + throw new AuthenticationException(AuthenticationException.ERROR_INVALID_TOKEN, "Token validation failed: " + e.getMessage(), e); + } + } + + /** + * Generates a JWT token for the given username. + * + * @param username User's username + * @return JWT token string + */ + public String generateToken(String username) { + Map claims = new HashMap<>(); + claims.put("sub", username); + claims.put("iat", System.currentTimeMillis()); + claims.put("exp", System.currentTimeMillis() + TOKEN_VALIDITY); + + String header = Base64.getEncoder().encodeToString("{\"alg\":\"HS256\",\"typ\":\"JWT\"}".getBytes()); + String payload = Base64.getEncoder().encodeToString(toJson(claims).getBytes()); + + String signature = generateSignature(header + "." + payload, SECRET_KEY); + + return header + "." + payload + "." + signature; + } + + private String generateSignature(String data, String secret) { + return Base64.getEncoder().encodeToString((data + secret).getBytes()); + } + + private Map parsePayload(String payload) { + Map claims = new HashMap<>(); + + String[] pairs = payload.replace("{", "").replace("}", "").replace("\"", "").split(","); + for (String pair : pairs) { + String[] keyValue = pair.split(":"); + if (keyValue.length == 2) { + String key = keyValue[0].trim(); + String value = keyValue[1].trim(); + + if (key.equals("exp") || key.equals("iat")) { + claims.put(key, Long.parseLong(value)); + } else { + claims.put(key, value); + } + } + } + + return claims; + } + + private String toJson(Map claims) { + StringBuilder json = new StringBuilder("{"); + boolean first = true; + for (Map.Entry entry : claims.entrySet()) { + if (!first) { + json.append(","); + } + json.append("\"").append(entry.getKey()).append("\":\"").append(entry.getValue()).append("\""); + first = false; + } + json.append("}"); + return json.toString(); + } +}