mirror of
https://github.com/Stirling-Tools/Stirling-PDF.git
synced 2025-08-22 04:09:22 +00:00
Removing frontend code
This commit is contained in:
parent
5c809269d2
commit
ddac966485
@ -1,59 +1,14 @@
|
|||||||
// JWT Management Utility
|
// Authentication utility for cookie-based JWT
|
||||||
window.JWTManager = {
|
window.JWTManager = {
|
||||||
JWT_STORAGE_KEY: 'stirling_jwt',
|
// Check if user is authenticated (simplified for cookie-based auth)
|
||||||
|
|
||||||
// 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)
|
|
||||||
isAuthenticated: function() {
|
isAuthenticated: function() {
|
||||||
const token = this.getToken();
|
// With cookie-based JWT, we rely on server-side validation
|
||||||
if (!token) return false;
|
// This is a simplified check - actual authentication status is determined server-side
|
||||||
|
return document.cookie.includes('stirling_jwt=');
|
||||||
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;
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
// Logout - remove token and redirect to login
|
// Logout - clear cookies and redirect to login
|
||||||
logout: function() {
|
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)
|
// 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';
|
||||||
@ -101,20 +56,12 @@ window.fetchWithCsrf = async function(url, options = {}) {
|
|||||||
fetchOptions.headers['X-XSRF-TOKEN'] = csrfToken;
|
fetchOptions.headers['X-XSRF-TOKEN'] = csrfToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add JWT token to Authorization header if available
|
// Always include credentials to send JWT cookies
|
||||||
const jwtToken = window.JWTManager.getToken();
|
fetchOptions.credentials = 'include';
|
||||||
if (jwtToken) {
|
|
||||||
fetchOptions.headers['Authorization'] = `Bearer ${jwtToken}`;
|
|
||||||
// Include credentials when JWT is enabled
|
|
||||||
fetchOptions.credentials = 'include';
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make the request
|
// Make the request
|
||||||
const response = await fetch(url, fetchOptions);
|
const response = await fetch(url, fetchOptions);
|
||||||
|
|
||||||
// Extract JWT from response if present
|
|
||||||
window.JWTManager.extractTokenFromResponse(response);
|
|
||||||
|
|
||||||
// Handle 401 responses (unauthorized)
|
// Handle 401 responses (unauthorized)
|
||||||
if (response.status === 401) {
|
if (response.status === 401) {
|
||||||
console.warn('Authentication failed, redirecting to login');
|
console.warn('Authentication failed, redirecting to login');
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
// JWT Initialization Script
|
// JWT Authentication Management Script
|
||||||
// This script handles JWT token extraction during OAuth/Login flows and initializes the JWT manager
|
// This script handles cookie-based JWT authentication and page access control
|
||||||
|
|
||||||
(function() {
|
(function() {
|
||||||
// Extract JWT token from URL parameters (for OAuth redirects)
|
// Clean up JWT token from URL parameters after OAuth/Login flows
|
||||||
function extractTokenFromUrl() {
|
function cleanupTokenFromUrl() {
|
||||||
const urlParams = new URLSearchParams(window.location.search);
|
const urlParams = new URLSearchParams(window.location.search);
|
||||||
const token = urlParams.get('jwt') || urlParams.get('token');
|
const hasToken = urlParams.get('jwt') || urlParams.get('token');
|
||||||
if (token) {
|
if (hasToken) {
|
||||||
window.JWTManager.storeToken(token);
|
|
||||||
// Clean up URL by removing token parameter
|
// Clean up URL by removing token parameter
|
||||||
|
// Token should now be set as cookie by server
|
||||||
urlParams.delete('jwt');
|
urlParams.delete('jwt');
|
||||||
urlParams.delete('token');
|
urlParams.delete('token');
|
||||||
const newUrl = window.location.pathname + (urlParams.toString() ? '?' + urlParams.toString() : '');
|
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
|
// Initialize JWT handling when page loads
|
||||||
function initializeJWT() {
|
function initializeJWT() {
|
||||||
// Try to extract token from URL first (OAuth flow)
|
// Clean up any JWT tokens from URL (OAuth flow)
|
||||||
extractTokenFromUrl();
|
cleanupTokenFromUrl();
|
||||||
|
|
||||||
// If no token in URL, try cookie (login flow)
|
// Check if user is authenticated via cookie
|
||||||
if (!window.JWTManager.getToken()) {
|
|
||||||
extractTokenFromCookie();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if user is authenticated
|
|
||||||
if (window.JWTManager.isAuthenticated()) {
|
if (window.JWTManager.isAuthenticated()) {
|
||||||
console.log('User is authenticated with JWT');
|
console.log('User is authenticated with JWT cookie');
|
||||||
} else {
|
} 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
|
// Only redirect to login if we're not already on login/register pages
|
||||||
const currentPath = window.location.pathname;
|
const currentPath = window.location.pathname;
|
||||||
const currentSearch = window.location.search;
|
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() {
|
function enhanceFormSubmissions() {
|
||||||
// Override form submit for login forms
|
// Cookie-based JWT is automatically included in form submissions
|
||||||
document.addEventListener('submit', function(event) {
|
// No additional processing needed
|
||||||
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);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add logout functionality to logout buttons
|
// Add logout functionality to logout buttons
|
||||||
@ -99,12 +68,10 @@
|
|||||||
if (document.readyState === 'loading') {
|
if (document.readyState === 'loading') {
|
||||||
document.addEventListener('DOMContentLoaded', function() {
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
initializeJWT();
|
initializeJWT();
|
||||||
enhanceFormSubmissions();
|
|
||||||
enhanceLogoutButtons();
|
enhanceLogoutButtons();
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
initializeJWT();
|
initializeJWT();
|
||||||
enhanceFormSubmissions();
|
|
||||||
enhanceLogoutButtons();
|
enhanceLogoutButtons();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,10 +8,8 @@ import org.springframework.context.annotation.Bean;
|
|||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.context.annotation.DependsOn;
|
import org.springframework.context.annotation.DependsOn;
|
||||||
import org.springframework.context.annotation.Lazy;
|
import org.springframework.context.annotation.Lazy;
|
||||||
import org.springframework.security.authentication.AuthenticationManager;
|
|
||||||
import org.springframework.security.authentication.ProviderManager;
|
import org.springframework.security.authentication.ProviderManager;
|
||||||
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
|
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.method.configuration.EnableMethodSecurity;
|
||||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||||
@ -183,7 +181,6 @@ public class SecurityConfiguration {
|
|||||||
.csrfTokenRequestHandler(requestHandler));
|
.csrfTokenRequestHandler(requestHandler));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Configure session management based on JWT setting
|
|
||||||
http.sessionManagement(
|
http.sessionManagement(
|
||||||
sessionManagement -> {
|
sessionManagement -> {
|
||||||
if (v2Enabled) {
|
if (v2Enabled) {
|
||||||
@ -346,12 +343,6 @@ public class SecurityConfiguration {
|
|||||||
return http.build();
|
return http.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
|
||||||
public AuthenticationManager authenticationManager(AuthenticationConfiguration configuration)
|
|
||||||
throws Exception {
|
|
||||||
return configuration.getAuthenticationManager();
|
|
||||||
}
|
|
||||||
|
|
||||||
public DaoAuthenticationProvider daoAuthenticationProvider() {
|
public DaoAuthenticationProvider daoAuthenticationProvider() {
|
||||||
DaoAuthenticationProvider provider = new DaoAuthenticationProvider(userDetailsService);
|
DaoAuthenticationProvider provider = new DaoAuthenticationProvider(userDetailsService);
|
||||||
provider.setPasswordEncoder(passwordEncoder());
|
provider.setPasswordEncoder(passwordEncoder());
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package stirling.software.proprietary.security.service;
|
package stirling.software.proprietary.security.service;
|
||||||
|
|
||||||
|
import jakarta.annotation.PostConstruct;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
@ -19,7 +20,7 @@ import java.util.Base64;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.cache.Cache;
|
import org.springframework.cache.Cache;
|
||||||
import org.springframework.cache.CacheManager;
|
import org.springframework.cache.CacheManager;
|
||||||
@ -27,11 +28,6 @@ import org.springframework.cache.annotation.CacheEvict;
|
|||||||
import org.springframework.cache.caffeine.CaffeineCache;
|
import org.springframework.cache.caffeine.CaffeineCache;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
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.configuration.InstallationPathConfig;
|
||||||
import stirling.software.common.model.ApplicationProperties;
|
import stirling.software.common.model.ApplicationProperties;
|
||||||
import stirling.software.proprietary.security.model.JwtVerificationKey;
|
import stirling.software.proprietary.security.model.JwtVerificationKey;
|
||||||
@ -240,29 +236,4 @@ public class KeyPersistenceService implements KeyPersistenceServiceInterface {
|
|||||||
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
|
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
|
||||||
return keyFactory.generatePublic(keySpec);
|
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -2,13 +2,11 @@ package stirling.software.proprietary.security.service;
|
|||||||
|
|
||||||
import java.security.KeyPair;
|
import java.security.KeyPair;
|
||||||
import java.security.NoSuchAlgorithmException;
|
import java.security.NoSuchAlgorithmException;
|
||||||
import java.security.PrivateKey;
|
|
||||||
import java.security.PublicKey;
|
import java.security.PublicKey;
|
||||||
import java.security.spec.InvalidKeySpecException;
|
import java.security.spec.InvalidKeySpecException;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
import stirling.software.proprietary.security.model.JwtVerificationKey;
|
import stirling.software.proprietary.security.model.JwtVerificationKey;
|
||||||
|
|
||||||
public interface KeyPersistenceServiceInterface {
|
public interface KeyPersistenceServiceInterface {
|
||||||
@ -27,8 +25,4 @@ public interface KeyPersistenceServiceInterface {
|
|||||||
|
|
||||||
PublicKey decodePublicKey(String encodedKey)
|
PublicKey decodePublicKey(String encodedKey)
|
||||||
throws NoSuchAlgorithmException, InvalidKeySpecException;
|
throws NoSuchAlgorithmException, InvalidKeySpecException;
|
||||||
|
|
||||||
PublicKey getPublicKey(String keyId);
|
|
||||||
|
|
||||||
PrivateKey getPrivateKey(String keyId);
|
|
||||||
}
|
}
|
||||||
|
@ -198,45 +198,4 @@ class KeyPersistenceServiceInterfaceTest {
|
|||||||
assertNotNull(result.getVerifyingKey());
|
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());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user