From ddac966485cedaf0ad62396733f173e9857a1c91 Mon Sep 17 00:00:00 2001 From: Dario Ghunney Ware Date: Tue, 5 Aug 2025 18:00:29 +0100 Subject: [PATCH] Removing frontend code --- .../main/resources/static/js/fetch-utils.js | 69 +++---------------- .../src/main/resources/static/js/jwt-init.js | 65 +++++------------ .../configuration/SecurityConfiguration.java | 9 --- .../service/KeyPersistenceService.java | 33 +-------- .../KeyPersistenceServiceInterface.java | 6 -- .../KeyPersistenceServiceInterfaceTest.java | 41 ----------- 6 files changed, 26 insertions(+), 197 deletions(-) diff --git a/app/core/src/main/resources/static/js/fetch-utils.js b/app/core/src/main/resources/static/js/fetch-utils.js index 73c26ffb3..764a94ce1 100644 --- a/app/core/src/main/resources/static/js/fetch-utils.js +++ b/app/core/src/main/resources/static/js/fetch-utils.js @@ -1,59 +1,14 @@ -// JWT Management Utility +// Authentication utility for cookie-based JWT window.JWTManager = { - JWT_STORAGE_KEY: 'stirling_jwt', - - // Store JWT token in localStorage - storeToken: function(token) { - if (token) { - localStorage.setItem(this.JWT_STORAGE_KEY, token); - } - }, - - // Get JWT token from localStorage - getToken: function() { - return localStorage.getItem(this.JWT_STORAGE_KEY); - }, - - // Remove JWT token from localStorage - removeToken: function() { - localStorage.removeItem(this.JWT_STORAGE_KEY); - }, - - // Extract JWT from Authorization header in response - extractTokenFromResponse: function(response) { - const authHeader = response.headers.get('Authorization'); - if (authHeader && authHeader.startsWith('Bearer ')) { - const token = authHeader.substring(7); // Remove 'Bearer ' prefix - this.storeToken(token); - return token; - } - return null; - }, - - // Check if user is authenticated (has valid JWT) + // Check if user is authenticated (simplified for cookie-based auth) isAuthenticated: function() { - const token = this.getToken(); - if (!token) return false; - - try { - // Basic JWT expiration check (decode payload) - const payload = JSON.parse(atob(token.split('.')[1])); - const now = Date.now() / 1000; - return payload.exp > now; - } catch (error) { - console.warn('Invalid JWT token:', error); - this.removeToken(); - return false; - } + // With cookie-based JWT, we rely on server-side validation + // This is a simplified check - actual authentication status is determined server-side + return document.cookie.includes('stirling_jwt='); }, - // Logout - remove token and redirect to login + // Logout - clear cookies and redirect to login logout: function() { - this.removeToken(); - - // Clear all possible token storage locations - localStorage.removeItem(this.JWT_STORAGE_KEY); - sessionStorage.removeItem(this.JWT_STORAGE_KEY); // Clear JWT cookie manually (fallback) document.cookie = 'stirling_jwt=; Path=/; Expires=Thu, 01 Jan 1970 00:00:01 GMT; SameSite=None; Secure'; @@ -101,20 +56,12 @@ window.fetchWithCsrf = async function(url, options = {}) { fetchOptions.headers['X-XSRF-TOKEN'] = csrfToken; } - // Add JWT token to Authorization header if available - const jwtToken = window.JWTManager.getToken(); - if (jwtToken) { - fetchOptions.headers['Authorization'] = `Bearer ${jwtToken}`; - // Include credentials when JWT is enabled - fetchOptions.credentials = 'include'; - } + // Always include credentials to send JWT cookies + fetchOptions.credentials = 'include'; // Make the request const response = await fetch(url, fetchOptions); - // Extract JWT from response if present - window.JWTManager.extractTokenFromResponse(response); - // Handle 401 responses (unauthorized) if (response.status === 401) { console.warn('Authentication failed, redirecting to login'); diff --git a/app/core/src/main/resources/static/js/jwt-init.js b/app/core/src/main/resources/static/js/jwt-init.js index a2733bf35..b101e666f 100644 --- a/app/core/src/main/resources/static/js/jwt-init.js +++ b/app/core/src/main/resources/static/js/jwt-init.js @@ -1,14 +1,14 @@ -// JWT Initialization Script -// This script handles JWT token extraction during OAuth/Login flows and initializes the JWT manager +// JWT Authentication Management Script +// This script handles cookie-based JWT authentication and page access control (function() { - // Extract JWT token from URL parameters (for OAuth redirects) - function extractTokenFromUrl() { + // Clean up JWT token from URL parameters after OAuth/Login flows + function cleanupTokenFromUrl() { const urlParams = new URLSearchParams(window.location.search); - const token = urlParams.get('jwt') || urlParams.get('token'); - if (token) { - window.JWTManager.storeToken(token); + const hasToken = urlParams.get('jwt') || urlParams.get('token'); + if (hasToken) { // Clean up URL by removing token parameter + // Token should now be set as cookie by server urlParams.delete('jwt'); urlParams.delete('token'); const newUrl = window.location.pathname + (urlParams.toString() ? '?' + urlParams.toString() : ''); @@ -16,35 +16,16 @@ } } - // Extract JWT token from cookie on page load (fallback) - function extractTokenFromCookie() { - const cookieValue = document.cookie - .split('; ') - .find(row => row.startsWith('stirling_jwt=')) - ?.split('=')[1]; - - if (cookieValue) { - window.JWTManager.storeToken(cookieValue); - // 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'; - } - } - // Initialize JWT handling when page loads function initializeJWT() { - // Try to extract token from URL first (OAuth flow) - extractTokenFromUrl(); + // Clean up any JWT tokens from URL (OAuth flow) + cleanupTokenFromUrl(); - // If no token in URL, try cookie (login flow) - if (!window.JWTManager.getToken()) { - extractTokenFromCookie(); - } - - // Check if user is authenticated + // Check if user is authenticated via cookie if (window.JWTManager.isAuthenticated()) { - console.log('User is authenticated with JWT'); + console.log('User is authenticated with JWT cookie'); } else { - console.log('User is not authenticated or token expired'); + console.log('User is not authenticated'); // Only redirect to login if we're not already on login/register pages const currentPath = window.location.pathname; const currentSearch = window.location.search; @@ -63,23 +44,11 @@ } } - // Override form submissions to include JWT + // No form enhancement needed for cookie-based JWT + // Cookies are automatically sent with form submissions function enhanceFormSubmissions() { - // Override form submit for login forms - document.addEventListener('submit', function(event) { - const form = event.target; - - // Add JWT to form data if available - const jwtToken = window.JWTManager.getToken(); - if (jwtToken && form.method && form.method.toLowerCase() !== 'get') { - // Create a hidden input for JWT - const jwtInput = document.createElement('input'); - jwtInput.type = 'hidden'; - jwtInput.name = 'jwt'; - jwtInput.value = jwtToken; - form.appendChild(jwtInput); - } - }); + // Cookie-based JWT is automatically included in form submissions + // No additional processing needed } // Add logout functionality to logout buttons @@ -99,12 +68,10 @@ if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', function() { initializeJWT(); - enhanceFormSubmissions(); enhanceLogoutButtons(); }); } else { initializeJWT(); - enhanceFormSubmissions(); enhanceLogoutButtons(); } diff --git a/app/proprietary/src/main/java/stirling/software/proprietary/security/configuration/SecurityConfiguration.java b/app/proprietary/src/main/java/stirling/software/proprietary/security/configuration/SecurityConfiguration.java index 7f2afc735..aceb3b712 100644 --- a/app/proprietary/src/main/java/stirling/software/proprietary/security/configuration/SecurityConfiguration.java +++ b/app/proprietary/src/main/java/stirling/software/proprietary/security/configuration/SecurityConfiguration.java @@ -8,10 +8,8 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.DependsOn; import org.springframework.context.annotation.Lazy; -import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.ProviderManager; import org.springframework.security.authentication.dao.DaoAuthenticationProvider; -import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration; import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; @@ -183,7 +181,6 @@ public class SecurityConfiguration { .csrfTokenRequestHandler(requestHandler)); } - // Configure session management based on JWT setting http.sessionManagement( sessionManagement -> { if (v2Enabled) { @@ -346,12 +343,6 @@ public class SecurityConfiguration { return http.build(); } - @Bean - public AuthenticationManager authenticationManager(AuthenticationConfiguration configuration) - throws Exception { - return configuration.getAuthenticationManager(); - } - public DaoAuthenticationProvider daoAuthenticationProvider() { DaoAuthenticationProvider provider = new DaoAuthenticationProvider(userDetailsService); provider.setPasswordEncoder(passwordEncoder()); diff --git a/app/proprietary/src/main/java/stirling/software/proprietary/security/service/KeyPersistenceService.java b/app/proprietary/src/main/java/stirling/software/proprietary/security/service/KeyPersistenceService.java index 4470c085d..e820f6d37 100644 --- a/app/proprietary/src/main/java/stirling/software/proprietary/security/service/KeyPersistenceService.java +++ b/app/proprietary/src/main/java/stirling/software/proprietary/security/service/KeyPersistenceService.java @@ -1,5 +1,6 @@ package stirling.software.proprietary.security.service; +import jakarta.annotation.PostConstruct; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; @@ -19,7 +20,7 @@ import java.util.Base64; import java.util.List; import java.util.Optional; import java.util.stream.Collectors; - +import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cache.Cache; import org.springframework.cache.CacheManager; @@ -27,11 +28,6 @@ import org.springframework.cache.annotation.CacheEvict; import org.springframework.cache.caffeine.CaffeineCache; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; - -import jakarta.annotation.PostConstruct; - -import lombok.extern.slf4j.Slf4j; - import stirling.software.common.configuration.InstallationPathConfig; import stirling.software.common.model.ApplicationProperties; import stirling.software.proprietary.security.model.JwtVerificationKey; @@ -240,29 +236,4 @@ public class KeyPersistenceService implements KeyPersistenceServiceInterface { KeyFactory keyFactory = KeyFactory.getInstance("RSA"); return keyFactory.generatePublic(keySpec); } - - @Override - public PublicKey getPublicKey(String keyId) { - try { - JwtVerificationKey verifyingKey = - verifyingKeyCache.get(keyId, JwtVerificationKey.class); - if (verifyingKey == null) { - return null; - } - return decodePublicKey(verifyingKey.getVerifyingKey()); - } catch (Exception e) { - log.error("Failed to get public key for keyId: {}", keyId, e); - return null; - } - } - - @Override - public PrivateKey getPrivateKey(String keyId) { - try { - return loadPrivateKey(keyId); - } catch (Exception e) { - log.error("Failed to get private key for keyId: {}", keyId, e); - return null; - } - } } diff --git a/app/proprietary/src/main/java/stirling/software/proprietary/security/service/KeyPersistenceServiceInterface.java b/app/proprietary/src/main/java/stirling/software/proprietary/security/service/KeyPersistenceServiceInterface.java index cd9c4bcff..43aa9c7c7 100644 --- a/app/proprietary/src/main/java/stirling/software/proprietary/security/service/KeyPersistenceServiceInterface.java +++ b/app/proprietary/src/main/java/stirling/software/proprietary/security/service/KeyPersistenceServiceInterface.java @@ -2,13 +2,11 @@ package stirling.software.proprietary.security.service; import java.security.KeyPair; import java.security.NoSuchAlgorithmException; -import java.security.PrivateKey; import java.security.PublicKey; import java.security.spec.InvalidKeySpecException; import java.time.LocalDateTime; import java.util.List; import java.util.Optional; - import stirling.software.proprietary.security.model.JwtVerificationKey; public interface KeyPersistenceServiceInterface { @@ -27,8 +25,4 @@ public interface KeyPersistenceServiceInterface { PublicKey decodePublicKey(String encodedKey) throws NoSuchAlgorithmException, InvalidKeySpecException; - - PublicKey getPublicKey(String keyId); - - PrivateKey getPrivateKey(String keyId); } diff --git a/app/proprietary/src/test/java/stirling/software/proprietary/security/service/KeyPersistenceServiceInterfaceTest.java b/app/proprietary/src/test/java/stirling/software/proprietary/security/service/KeyPersistenceServiceInterfaceTest.java index 71df48dd8..04632d0ea 100644 --- a/app/proprietary/src/test/java/stirling/software/proprietary/security/service/KeyPersistenceServiceInterfaceTest.java +++ b/app/proprietary/src/test/java/stirling/software/proprietary/security/service/KeyPersistenceServiceInterfaceTest.java @@ -198,45 +198,4 @@ class KeyPersistenceServiceInterfaceTest { assertNotNull(result.getVerifyingKey()); } } - - @Test - void testGetPublicKey() throws Exception { - String keyId = "test-key-public"; - String publicKeyBase64 = Base64.getEncoder().encodeToString(testKeyPair.getPublic().getEncoded()); - - JwtVerificationKey signingKey = new JwtVerificationKey(keyId, publicKeyBase64); - - try (MockedStatic mockedStatic = mockStatic(InstallationPathConfig.class)) { - mockedStatic.when(InstallationPathConfig::getPrivateKeyPath).thenReturn(tempDir.toString()); - keyPersistenceService = new KeyPersistenceService(applicationProperties, cacheManager); - - // Add the key to cache for testing - var cache = cacheManager.getCache("verifyingKeys"); - cache.put(keyId, signingKey); - - var result = keyPersistenceService.getPublicKey(keyId); - - assertNotNull(result); - assertEquals(testKeyPair.getPublic().getAlgorithm(), result.getAlgorithm()); - } - } - - @Test - void testGetPrivateKey() throws Exception { - String keyId = "test-key-private"; - String privateKeyBase64 = Base64.getEncoder().encodeToString(testKeyPair.getPrivate().getEncoded()); - - Path keyFile = tempDir.resolve(keyId + ".key"); - Files.writeString(keyFile, privateKeyBase64); - - try (MockedStatic mockedStatic = mockStatic(InstallationPathConfig.class)) { - mockedStatic.when(InstallationPathConfig::getPrivateKeyPath).thenReturn(tempDir.toString()); - keyPersistenceService = new KeyPersistenceService(applicationProperties, cacheManager); - - var result = keyPersistenceService.getPrivateKey(keyId); - - assertNotNull(result); - assertEquals(testKeyPair.getPrivate().getAlgorithm(), result.getAlgorithm()); - } - } }