Removing frontend code

This commit is contained in:
Dario Ghunney Ware 2025-08-05 18:00:29 +01:00
parent 2591a3070d
commit 51dfade4bc
6 changed files with 26 additions and 197 deletions

View File

@ -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');

View File

@ -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();
}

View File

@ -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());

View File

@ -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;
}
}
}

View File

@ -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);
}

View File

@ -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<InstallationPathConfig> 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<InstallationPathConfig> 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());
}
}
}