Aggiornate componenti per gestione token.
All checks were successful
IntegryManagementSystem_Multi/pipeline/head This commit looks good

This commit is contained in:
2025-02-12 16:27:53 +01:00
parent ddd5cbaf77
commit 7265f32b3d
9 changed files with 139 additions and 110 deletions

View File

@@ -2,14 +2,15 @@ package it.integry.ems.license;
import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.core.type.TypeReference;
import it.integry.annotations.PostContextAutowired;
import it.integry.annotations.PostContextConstruct; import it.integry.annotations.PostContextConstruct;
import it.integry.ems.json.ResponseJSONObjectMapper; import it.integry.ems.json.ResponseJSONObjectMapper;
import it.integry.ems.looper.service.LooperService;
import it.integry.ems.response.EsitoType; import it.integry.ems.response.EsitoType;
import it.integry.ems.response.ServiceRestResponse; import it.integry.ems.response.ServiceRestResponse;
import it.integry.ems.service.HttpRestWrapper; import it.integry.ems.service.HttpRestWrapper;
import it.integry.ems.settings.Model.AvailableConnectionsModel; import it.integry.ems.settings.Model.AvailableConnectionsModel;
import it.integry.ems.settings.Model.SettingsModel; import it.integry.ems.settings.Model.SettingsModel;
import it.integry.ems.sync.MultiDBTransaction.AdvancedDataSource;
import it.integry.ems.sync.MultiDBTransaction.MultiDBTransactionManager; import it.integry.ems.sync.MultiDBTransaction.MultiDBTransactionManager;
import it.integry.ems.utility.UtilityDebug; import it.integry.ems.utility.UtilityDebug;
import it.integry.ems_model.config.EmsRestConstants; import it.integry.ems_model.config.EmsRestConstants;
@@ -19,10 +20,12 @@ import org.apache.http.entity.ContentType;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.concurrent.TimeUnit;
@Component @Component
public class LicenseComponent { public class LicenseComponent {
@@ -32,27 +35,46 @@ public class LicenseComponent {
@Autowired @Autowired
private SettingsModel settingsModel; private SettingsModel settingsModel;
@Autowired
private LooperService looperService;
@Autowired @Autowired
private ResponseJSONObjectMapper jsonObjectMapper; private ResponseJSONObjectMapper jsonObjectMapper;
@PostContextAutowired
private MultiDBTransactionManager multiDBTransactionManager;
private final HashMap<String, LicenseStatusDTO> cachedLicenseStatus = new HashMap<>(); private final HashMap<String, LicenseStatusDTO> cachedLicenseStatus = new HashMap<>();
boolean canStart = false;
@PostContextConstruct(priority = 10) @PostContextConstruct(priority = 10)
public void init() { public void init() {
logger.info("Initializing license checker service"); if(UtilityDebug.isDebugExecution() || UtilityDebug.isIntegryServer())
return;
logger.debug("isDebug: " + (UtilityDebug.isDebugExecution() ? "yes" : "no")); canStart = true;
logger.debug("isIntegryServer: " + (UtilityDebug.isIntegryServer() ? "yes" : "no")); this.syncLicense(multiDBTransactionManager);
if (!UtilityDebug.isDebugExecution() && !UtilityDebug.isIntegryServer())
looperService.add(this::syncLicense, 60 * 60 * 1000, LicenseComponent.class.getName());
// else
// looperService.add(this::syncLicense, 15 * 1000, LicenseComponent.class.getName());
} }
private void syncLicense() { @Scheduled(fixedDelay = 1, timeUnit = TimeUnit.HOURS)
private void syncLicenseScheduled() {
if (!canStart)
return;
List<AvailableConnectionsModel> availableConnectionsModels = settingsModel.getAvailableConnections(true);
try (MultiDBTransactionManager multiDBTransactionManager = new MultiDBTransactionManager()) {
for (AvailableConnectionsModel model : availableConnectionsModels) {
multiDBTransactionManager.addConnection(model);
}
syncLicense(multiDBTransactionManager);
} catch (Exception ex) {
logger.error(ex.getMessage(), ex);
}
}
private void syncLicense(MultiDBTransactionManager multiDBTransactionManager) {
try { try {
String url = "https://services.studioml.it/ems-api" + EmsRestConstants.PATH_GET_LICENSE_STATUS; String url = "https://services.studioml.it/ems-api" + EmsRestConstants.PATH_GET_LICENSE_STATUS;
@@ -60,14 +82,12 @@ public class LicenseComponent {
final HashMap<String, String> listAziende = new HashMap<>(); final HashMap<String, String> listAziende = new HashMap<>();
for (AvailableConnectionsModel model : settingsModel.getAvailableConnections(true)) { for (AdvancedDataSource model : multiDBTransactionManager.getActiveConnections()) {
try (MultiDBTransactionManager multiDBTransactionManager = new MultiDBTransactionManager(model)) { String sql = "SELECT part_iva FROM azienda WHERE part_iva is not null";
String sql = "SELECT part_iva FROM azienda WHERE part_iva is not null"; String partIva = UtilityDB.executeSimpleQueryOnlyFirstRowFirstColumn(model.getConnection(), sql);
String partIva = UtilityDB.executeSimpleQueryOnlyFirstRowFirstColumn(multiDBTransactionManager.getPrimaryConnection(), sql);
if (!UtilityString.isNullOrEmpty(partIva)) if (!UtilityString.isNullOrEmpty(partIva))
listAziende.put(model.getProfileName(), partIva); listAziende.put(model.getProfileName(), partIva);
}
} }
String jsonBody = jsonObjectMapper.writeValueAsString(listAziende.values()); String jsonBody = jsonObjectMapper.writeValueAsString(listAziende.values());

View File

@@ -61,7 +61,7 @@ public class ConfigActivityRules extends QueryRules {
} }
} }
if (blocca) if (blocca)
throw new Exception("Impossibile modificare\\inserire un'attività in un periodo fatturato."); throw new Exception("Impossibile modificare/inserire un'attività in un periodo fatturato.");
return false; return false;
} }

View File

@@ -11,6 +11,7 @@ import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope; import org.springframework.context.annotation.Scope;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
@@ -55,9 +56,10 @@ public class UserController {
} }
@PreAuthorize("isAnonymous()")
@RequestMapping(value = "availableProfiles", method = RequestMethod.GET) @RequestMapping(value = "availableProfiles", method = RequestMethod.GET)
public ServiceRestResponse changePassword(@RequestParam String username) throws Exception { public ServiceRestResponse availableProfiles(@RequestParam String username, @RequestParam String password) {
return ServiceRestResponse.createPositiveResponse(userService.retrieveAvailableProfiles(username)); return ServiceRestResponse.createPositiveResponse(userService.retrieveAvailableProfiles(username, password));
} }
} }

View File

@@ -87,7 +87,7 @@ public class UserCacheService {
users.add(user); users.add(user);
} }
public List<String> retrieveProfilesOfUserByUsername(String username) { public List<String> retrieveProfilesOfUser(String username, String password) {
ArrayList<String> profiles = new ArrayList<>(); ArrayList<String> profiles = new ArrayList<>();
for (Map.Entry<String, List<UserDTO>> users : cachedUsers.entrySet()) { for (Map.Entry<String, List<UserDTO>> users : cachedUsers.entrySet()) {

View File

@@ -104,16 +104,16 @@ public class UserService {
return UtilityDB.executeSimpleQueryOnlyFirstRowFirstColumn(multiDBTransactionManager.getPrimaryConnection(), sql); return UtilityDB.executeSimpleQueryOnlyFirstRowFirstColumn(multiDBTransactionManager.getPrimaryConnection(), sql);
} }
public List<String> retrieveAvailableProfiles(String username) { public List<String> retrieveAvailableProfiles(String username, String password) {
List<String> profiles; List<String> profiles;
profiles = userCacheService.retrieveProfilesOfUserByUsername(username); profiles = userCacheService.retrieveProfilesOfUser(username, password);
if (profiles.isEmpty()) { if (profiles.isEmpty()) {
// SELEZIONE CICLICA IN TUTTI I DB SPECIFICATI // SELEZIONE CICLICA IN TUTTI I DB SPECIFICATI
userCacheService.invalidateCache(); userCacheService.invalidateCache();
profiles = userCacheService.retrieveProfilesOfUserByUsername(username); profiles = userCacheService.retrieveProfilesOfUser(username, password);
} }
return profiles; return profiles;

View File

@@ -1,10 +1,9 @@
package it.integry.security.cache; package it.integry.security.cache;
import it.integry.annotations.PostContextAutowired;
import it.integry.annotations.PostContextConstruct; import it.integry.annotations.PostContextConstruct;
import it.integry.ems.looper.service.LooperService;
import it.integry.ems.settings.Model.AvailableConnectionsModel; import it.integry.ems.settings.Model.AvailableConnectionsModel;
import it.integry.ems.settings.Model.SettingsModel; import it.integry.ems.settings.Model.SettingsModel;
import it.integry.ems.settings.SettingsController;
import it.integry.ems.sync.MultiDBTransaction.AdvancedDataSource; import it.integry.ems.sync.MultiDBTransaction.AdvancedDataSource;
import it.integry.ems.sync.MultiDBTransaction.MultiDBTransactionManager; import it.integry.ems.sync.MultiDBTransaction.MultiDBTransactionManager;
import it.integry.ems_model.entity.StbAuthToken; import it.integry.ems_model.entity.StbAuthToken;
@@ -15,7 +14,6 @@ import it.integry.ems_model.utility.UtilityLocalDate;
import it.integry.security.event.InvalidateTokenCacheEvent; import it.integry.security.event.InvalidateTokenCacheEvent;
import it.integry.security.event.TokenCreateEvent; import it.integry.security.event.TokenCreateEvent;
import it.integry.security.event.TokenExpireEvent; import it.integry.security.event.TokenExpireEvent;
import it.integry.security.jwt.AccessTokenProvider;
import net.jodah.expiringmap.ExpiringMap; import net.jodah.expiringmap.ExpiringMap;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
@@ -23,6 +21,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEvent; import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationEventPublisher; import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationListener; import org.springframework.context.ApplicationListener;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.time.Instant; import java.time.Instant;
@@ -34,40 +33,44 @@ import java.util.concurrent.TimeUnit;
public class JwtTokenCacheComponent implements ApplicationListener { public class JwtTokenCacheComponent implements ApplicationListener {
Logger logger = LogManager.getLogger(); Logger logger = LogManager.getLogger();
@Autowired
private AccessTokenProvider accessTokenProvider;
@Autowired
private SecretKeyCacheComponent secretKeyCacheComponent;
@Autowired @Autowired
private SettingsModel settingsModel; private SettingsModel settingsModel;
@Autowired @Autowired
private ApplicationEventPublisher applicationEventPublisher; private ApplicationEventPublisher applicationEventPublisher;
@Autowired @PostContextAutowired
private LooperService looperService; private MultiDBTransactionManager multiDBTransactionManager;
@Autowired
private SettingsController settingsController;
private final HashMap<String, ExpiringMap<String, StbAuthToken>> tokenEventMap = new HashMap<>(); private final HashMap<String, ExpiringMap<String, StbAuthToken>> tokenEventMap = new HashMap<>();
boolean canStart = false;
@PostContextConstruct(priority = 20) @PostContextConstruct(priority = 20)
public void init() throws Exception { public void init() throws Exception {
updateCache(multiDBTransactionManager);
if (!settingsModel.isEnableTokenCaching()) return; canStart = true;
looperService.add(() -> {
try {
refreshCache();
} catch (Exception e) {
//throw new RuntimeException(e);
logger.error("Caching JWTSessions", e);
}
}, 5 * 60 * 1000, JwtTokenCacheComponent.class.getName());
} }
@Scheduled(fixedDelay = 5, timeUnit = TimeUnit.MINUTES)
private void updateCacheScheduled() {
if (!settingsModel.isEnableTokenCaching()) return;
List<AvailableConnectionsModel> availableConnectionsModels = settingsModel.getAvailableConnections(true);
try (MultiDBTransactionManager multiDBTransactionManager = new MultiDBTransactionManager()) {
for (AvailableConnectionsModel model : availableConnectionsModels) {
multiDBTransactionManager.addConnection(model);
}
updateCache(multiDBTransactionManager);
} catch (Exception ex) {
logger.error(ex.getMessage(), ex);
}
}
@Override @Override
public void onApplicationEvent(ApplicationEvent applicationEvent) { public void onApplicationEvent(ApplicationEvent applicationEvent) {
@@ -90,7 +93,7 @@ public class JwtTokenCacheComponent implements ApplicationListener {
} }
} else if (applicationEvent instanceof InvalidateTokenCacheEvent) { } else if (applicationEvent instanceof InvalidateTokenCacheEvent) {
try { try {
refreshCache(); updateCacheScheduled();
} catch (Exception e) { } catch (Exception e) {
logger.error("Errore durante il refresh della cache dei token", e); logger.error("Errore durante il refresh della cache dei token", e);
} }
@@ -98,7 +101,7 @@ public class JwtTokenCacheComponent implements ApplicationListener {
} }
private void refreshCache() throws Exception { private void updateCache(MultiDBTransactionManager multiDBTransactionManager) throws Exception {
if(!settingsModel.isEnableTokenCaching()) return; if(!settingsModel.isEnableTokenCaching()) return;
tokenEventMap.clear(); tokenEventMap.clear();
@@ -106,20 +109,6 @@ public class JwtTokenCacheComponent implements ApplicationListener {
String sql = "SELECT * " + String sql = "SELECT * " +
"FROM " + StbAuthToken.ENTITY; "FROM " + StbAuthToken.ENTITY;
MultiDBTransactionManager multiDBTransactionManager = new MultiDBTransactionManager();
for (AvailableConnectionsModel availableConnectionsModel : settingsModel.getAvailableConnections()) {
if (!availableConnectionsModel.getInternalDb())
continue;
try {
multiDBTransactionManager.addConnection(
availableConnectionsModel.getProfileName());
} catch (Exception ex) {
logger.error("Database connection error", ex);
}
}
boolean shouldCloseConnections = true; boolean shouldCloseConnections = true;
for (AdvancedDataSource advancedDataSource : multiDBTransactionManager.getActiveConnections()) { for (AdvancedDataSource advancedDataSource : multiDBTransactionManager.getActiveConnections()) {

View File

@@ -2,65 +2,79 @@ package it.integry.security.cache;
import io.jsonwebtoken.io.Decoders; import io.jsonwebtoken.io.Decoders;
import io.jsonwebtoken.security.Keys; import io.jsonwebtoken.security.Keys;
import it.integry.annotations.PostContextConstruct;
import it.integry.ems.looper.service.LooperService;
import it.integry.ems.settings.Model.AvailableConnectionsModel;
import it.integry.ems.settings.Model.SettingsModel;
import it.integry.ems.sync.MultiDBTransaction.MultiDBTransactionManager;
import it.integry.ems.utility.UtilityDebug;
import it.integry.ems_model.entity.Azienda;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import javax.crypto.SecretKey; import javax.crypto.SecretKey;
import java.util.HashMap;
import java.util.List;
@Component @Component
public class SecretKeyCacheComponent { public class SecretKeyCacheComponent {
private final Logger logger = LogManager.getLogger(); private final String SIGNING_KEY = "gICy3bjD56i/YFnBZZKe5ibiz3Snsp08nybGGziCV4ZcvyXBbyqWUnJ2wTrRXhOuf/xdljPXX0yBaqdAgvKthQ==";
// private final Logger logger = LogManager.getLogger();
@Autowired
private LooperService looperService;
@Autowired
private SettingsModel settingsModel;
private final HashMap<String, SecretKey> internalCache = new HashMap<>();
@PostContextConstruct(priority = 10) // @Autowired
public void init() throws Exception { // private SettingsModel settingsModel;
if (!UtilityDebug.isDebugExecution()) // @PostContextAutowired
looperService.add(this::updateInternalCache, 5 * 60 * 1000, SecretKeyCacheComponent.class.getName()); //Ogni 5 minuti // private MultiDBTransactionManager multiDBTransactionManager;
else this.updateInternalCache();
}
private void updateInternalCache() {
List<AvailableConnectionsModel> availableConnectionsModels = settingsModel.getAvailableConnections(true);
for (AvailableConnectionsModel model : availableConnectionsModels) { // private final HashMap<String, SecretKey> internalCache = new HashMap<>();
try (MultiDBTransactionManager multiDBTransactionManager = new MultiDBTransactionManager(model)) {
Azienda azienda = Azienda.getDefaultAzienda(multiDBTransactionManager.getPrimaryConnection()); // boolean canStart = false;
internalCache.put(model.getDbName().toLowerCase(), Keys.hmacShaKeyFor(Decoders.BASE64.decode(azienda.getJwtSecretKey())));
} catch (Exception ex) { // @PostContextConstruct(priority = 10)
logger.info(String.format("Cannot find %s database", model.getDbName()), ex); // public void init() throws SQLException {
} // canStart = true;
} // this.updateCache(multiDBTransactionManager);
} // }
// @Scheduled(fixedDelay = 5, timeUnit = TimeUnit.MINUTES)
// private void updateCacheScheduled() {
// if (!canStart || UtilityDebug.isDebugExecution())
// return;
//
// List<AvailableConnectionsModel> availableConnectionsModels = settingsModel.getAvailableConnections(true);
//
// try (MultiDBTransactionManager multiDBTransactionManager = new MultiDBTransactionManager()) {
//
// for (AvailableConnectionsModel model : availableConnectionsModels) {
// multiDBTransactionManager.addConnection(model);
// }
//
// updateCache(multiDBTransactionManager);
//
// } catch (Exception ex) {
// logger.error(ex.getMessage(), ex);
// }
//
// }
//
//
// private void updateCache(MultiDBTransactionManager multiDBTransactionManager) throws SQLException {
//
// for (AdvancedDataSource dataSource : multiDBTransactionManager.getActiveConnections()) {
// try {
// Azienda azienda = Azienda.getDefaultAzienda(dataSource.getConnection());
// internalCache.put(dataSource.getDataSource().getDbName().toLowerCase(), Keys.hmacShaKeyFor(Decoders.BASE64.decode(azienda.getJwtSecretKey())));
// } catch (Exception ex) {
// logger.error(String.format("Cannot find %s database", dataSource.getDataSource().getDbName()), ex);
// }
// }
// }
// public SecretKey getKey(String dbName) {
// if (internalCache.containsKey(dbName.toLowerCase()))
// return internalCache.get(dbName.toLowerCase());
//
// return null;
// }
public SecretKey getKey(String dbName) { public SecretKey getKey(String dbName) {
if(internalCache.containsKey(dbName.toLowerCase())) return Keys.hmacShaKeyFor(Decoders.BASE64.decode(SIGNING_KEY));
return internalCache.get(dbName.toLowerCase());
return null;
} }
} }

View File

@@ -60,6 +60,10 @@ public class AuthService {
@Autowired @Autowired
private RequestDataDTO requestDataDTO; private RequestDataDTO requestDataDTO;
public JwtResponse login(String profileDb, LoginRequestDTO loginRequestDTO) throws Exception { public JwtResponse login(String profileDb, LoginRequestDTO loginRequestDTO) throws Exception {
if (UtilityString.isNullOrEmpty(loginRequestDTO.getUsername())) { if (UtilityString.isNullOrEmpty(loginRequestDTO.getUsername())) {
throw new Exception("Username mancante."); throw new Exception("Username mancante.");
@@ -130,7 +134,7 @@ public class AuthService {
.setExpireIn(ChronoUnit.SECONDS.between(UtilityLocalDate.getNowTime(), stbAuthToken.getExpiryDate())); .setExpireIn(ChronoUnit.SECONDS.between(UtilityLocalDate.getNowTime(), stbAuthToken.getExpiryDate()));
} }
public void logout(String profileDb, LogoutRequestDTO logoutRequestDTO) throws Exception { public void logout(String profileDb, LogoutRequestDTO logoutRequestDTO) {
TokenExpireEvent tokenExpireEvent = new TokenExpireEvent(profileDb, logoutRequestDTO.getToken()); TokenExpireEvent tokenExpireEvent = new TokenExpireEvent(profileDb, logoutRequestDTO.getToken());
applicationEventPublisher.publishEvent(tokenExpireEvent); applicationEventPublisher.publishEvent(tokenExpireEvent);

View File

@@ -316,7 +316,7 @@ public class SystemService {
List<String> profiles = null; List<String> profiles = null;
profiles = userCacheService.retrieveProfilesOfUserByUsername(username); profiles = userCacheService.retrieveProfilesOfUser(username, password);
if (profiles.isEmpty()) { if (profiles.isEmpty()) {
// SELEZIONE CICLICA IN TUTTI I DB SPECIFICATI // SELEZIONE CICLICA IN TUTTI I DB SPECIFICATI