Sending token with requests to server

This commit is contained in:
Dario Ghunney Ware 2025-07-21 12:58:52 +01:00
parent f5756944ed
commit 57b72c2d4f
4 changed files with 9 additions and 49 deletions

View File

@ -56,7 +56,7 @@ window.JWTManager = {
sessionStorage.removeItem(this.JWT_STORAGE_KEY); sessionStorage.removeItem(this.JWT_STORAGE_KEY);
// Clear JWT cookie manually (fallback) // Clear JWT cookie manually (fallback)
document.cookie = 'STIRLING_JWT=; Path=/; Expires=Thu, 01 Jan 1970 00:00:01 GMT; SameSite=None; Secure'; document.cookie = 'stirling_jwt=; Path=/; Expires=Thu, 01 Jan 1970 00:00:01 GMT; SameSite=None; Secure';
// Perform logout request to clear server-side session // Perform logout request to clear server-side session
fetch('/logout', { fetch('/logout', {

View File

@ -20,13 +20,13 @@
function extractTokenFromCookie() { function extractTokenFromCookie() {
const cookieValue = document.cookie const cookieValue = document.cookie
.split('; ') .split('; ')
.find(row => row.startsWith('STIRLING_JWT=')) .find(row => row.startsWith('stirling_jwt='))
?.split('=')[1]; ?.split('=')[1];
if (cookieValue) { if (cookieValue) {
window.JWTManager.storeToken(cookieValue); window.JWTManager.storeToken(cookieValue);
// Clear the cookie since we're using localStorage with consistent SameSite policy // Clear the cookie since we're using localStorage with consistent SameSite policy
document.cookie = 'STIRLING_JWT=; Path=/; Expires=Thu, 01 Jan 1970 00:00:01 GMT; SameSite=None; Secure'; document.cookie = 'stirling_jwt=; Path=/; Expires=Thu, 01 Jan 1970 00:00:01 GMT; SameSite=None; Secure';
} }
} }

View File

@ -67,7 +67,7 @@ class JwtServiceTest {
String token = jwtService.generateToken(authentication, Collections.emptyMap()); String token = jwtService.generateToken(authentication, Collections.emptyMap());
assertNotNull(token); assertNotNull(token);
assertTrue(!token.isEmpty()); assertFalse(token.isEmpty());
assertEquals(username, jwtService.extractUsername(token)); assertEquals(username, jwtService.extractUsername(token));
} }
@ -106,25 +106,6 @@ class JwtServiceTest {
}); });
} }
// fixme
// @Test
// void testValidateTokenWithExpiredToken() {
// // Create a token that expires immediately
// JWTService shortLivedJwtService = new JWTService(true);
// String token = shortLivedJwtService.generateToken("testuser", new HashMap<>());
//
// // Wait a bit to ensure expiration
// try {
// Thread.sleep(10);
// } catch (InterruptedException e) {
// Thread.currentThread().interrupt();
// }
//
// assertThrows(AuthenticationFailureException.class, () -> {
// shortLivedJwtService.validateToken(token);
// });
// }
@Test @Test
void testValidateTokenWithMalformedToken() { void testValidateTokenWithMalformedToken() {
AuthenticationFailureException exception = assertThrows(AuthenticationFailureException.class, () -> { AuthenticationFailureException exception = assertThrows(AuthenticationFailureException.class, () -> {
@ -184,24 +165,6 @@ class JwtServiceTest {
assertThrows(AuthenticationFailureException.class, () -> jwtService.extractAllClaims("invalid-token")); assertThrows(AuthenticationFailureException.class, () -> jwtService.extractAllClaims("invalid-token"));
} }
// fixme
// @Test
// void testIsTokenExpired() {
// String token = jwtService.generateToken("testuser", new HashMap<>());
// assertFalse(jwtService.isTokenExpired(token));
//
// JWTService shortLivedJwtService = new JWTService();
// String expiredToken = shortLivedJwtService.generateToken("testuser", new HashMap<>());
//
// try {
// Thread.sleep(10);
// } catch (InterruptedException e) {
// Thread.currentThread().interrupt();
// }
//
// assertThrows(AuthenticationFailureException.class, () -> shortLivedJwtService.isTokenExpired(expiredToken));
// }
@Test @Test
void testExtractTokenFromRequestWithAuthorizationHeader() { void testExtractTokenFromRequestWithAuthorizationHeader() {
String token = "test-token"; String token = "test-token";
@ -213,7 +176,7 @@ class JwtServiceTest {
@Test @Test
void testExtractTokenFromRequestWithCookie() { void testExtractTokenFromRequestWithCookie() {
String token = "test-token"; String token = "test-token";
Cookie[] cookies = { new Cookie("STIRLING_JWT", token) }; Cookie[] cookies = { new Cookie("stirling_jwt", token) };
when(request.getHeader("Authorization")).thenReturn(null); when(request.getHeader("Authorization")).thenReturn(null);
when(request.getCookies()).thenReturn(cookies); when(request.getCookies()).thenReturn(cookies);
@ -252,18 +215,17 @@ class JwtServiceTest {
jwtService.addTokenToResponse(response, token); jwtService.addTokenToResponse(response, token);
verify(response).setHeader("Authorization", "Bearer " + token); verify(response).setHeader("Authorization", "Bearer " + token);
verify(response).addHeader(eq("Set-Cookie"), contains("STIRLING_JWT=" + token)); verify(response).addHeader(eq("Set-Cookie"), contains("stirling_jwt=" + token));
verify(response).addHeader(eq("Set-Cookie"), contains("HttpOnly")); verify(response).addHeader(eq("Set-Cookie"), contains("HttpOnly"));
verify(response).addHeader(eq("Set-Cookie"), contains("Secure")); verify(response).addHeader(eq("Set-Cookie"), contains("Secure"));
// verify(response).addHeader(eq("Set-Cookie"), contains("SameSite=Strict"));
} }
@Test @Test
void testClearTokenFromResponse() { void testClearTokenFromResponse() {
jwtService.clearTokenFromResponse(response); jwtService.clearTokenFromResponse(response);
verify(response).setHeader("Authorization", ""); verify(response).setHeader("Authorization", null);
verify(response).addHeader(eq("Set-Cookie"), contains("STIRLING_JWT=")); verify(response).addHeader(eq("Set-Cookie"), contains("stirling_jwt="));
verify(response).addHeader(eq("Set-Cookie"), contains("Max-Age=0")); verify(response).addHeader(eq("Set-Cookie"), contains("Max-Age=0"));
} }
} }

View File

@ -34,7 +34,7 @@ import stirling.software.proprietary.security.saml2.CustomSaml2AuthenticatedPrin
@Service @Service
public class JwtService implements JwtServiceInterface { public class JwtService implements JwtServiceInterface {
private static final String JWT_COOKIE_NAME = "STIRLING_JWT"; private static final String JWT_COOKIE_NAME = "stirling_jwt";
private static final String AUTHORIZATION_HEADER = "Authorization"; private static final String AUTHORIZATION_HEADER = "Authorization";
private static final String BEARER_PREFIX = "Bearer "; private static final String BEARER_PREFIX = "Bearer ";
private static final String ISSUER = "Stirling PDF"; private static final String ISSUER = "Stirling PDF";
@ -80,7 +80,6 @@ public class JwtService implements JwtServiceInterface {
public void validateToken(String token) throws AuthenticationFailureException { public void validateToken(String token) throws AuthenticationFailureException {
extractAllClaimsFromToken(token); extractAllClaimsFromToken(token);
// todo: test
if (isTokenExpired(token)) { if (isTokenExpired(token)) {
throw new AuthenticationFailureException("The token has expired"); throw new AuthenticationFailureException("The token has expired");
} }
@ -174,7 +173,6 @@ public class JwtService implements JwtServiceInterface {
@Override @Override
public void clearTokenFromResponse(HttpServletResponse response) { public void clearTokenFromResponse(HttpServletResponse response) {
// Remove Authorization header instead of setting empty string
response.setHeader(AUTHORIZATION_HEADER, null); response.setHeader(AUTHORIZATION_HEADER, null);
ResponseCookie cookie = ResponseCookie cookie =