[Minor] Persist user model async

This commit is contained in:
Robert von Burg 2023-09-12 16:03:43 +02:00
parent da0f8a0516
commit e5cd14ac17
Signed by: eitch
GPG Key ID: 75DB9C85C74331F7
2 changed files with 86 additions and 79 deletions

View File

@ -147,6 +147,7 @@ public class DefaultPrivilegeHandler implements PrivilegeHandler {
private ElementLockingHandler<String> lockingHandler;
private ScheduledExecutorService executorService;
private Future<?> persistSessionsTask;
private Future<?> persistModelTask;
@Override
public SingleSignOnHandler getSsoHandler() {
@ -395,10 +396,8 @@ public class DefaultPrivilegeHandler implements PrivilegeHandler {
prvCtx.assertHasPrivilege(PRIVILEGE_ADD_USER);
// make sure userId is not set
if (isNotEmpty(userRepParam.getUserId())) {
String msg = "UserId can not be set when adding a new user!";
throw new PrivilegeModelException(format(msg, userRepParam.getUsername()));
}
if (isNotEmpty(userRepParam.getUserId()))
throw new PrivilegeModelException("UserId can not be set when adding a new user!");
UserRep userRep = userRepParam.getCopy();
@ -443,6 +442,7 @@ public class DefaultPrivilegeHandler implements PrivilegeHandler {
// delegate to persistence handler
this.persistenceHandler.addUser(newUser);
persistModelAsync();
logger.info("Created new user " + newUser.getUsername());
@ -527,6 +527,7 @@ public class DefaultPrivilegeHandler implements PrivilegeHandler {
// delegate to persistence handler
toCreate.forEach(user -> this.persistenceHandler.addUser(user));
toUpdate.forEach(user -> this.persistenceHandler.replaceUser(user));
persistModelAsync();
logger.info("Created " + toCreate.size() + " users");
logger.info("Updated " + toUpdate.size() + " users");
@ -590,6 +591,7 @@ public class DefaultPrivilegeHandler implements PrivilegeHandler {
// delegate to persistence handler
this.persistenceHandler.replaceUser(newUser);
persistModelAsync();
logger.info("Replaced user " + newUser.getUsername());
@ -686,6 +688,7 @@ public class DefaultPrivilegeHandler implements PrivilegeHandler {
// delegate to persistence handler
this.persistenceHandler.replaceUser(newUser);
persistModelAsync();
logger.info("Updated user " + newUser.getUsername());
@ -719,6 +722,7 @@ public class DefaultPrivilegeHandler implements PrivilegeHandler {
// delegate user removal to persistence handler
invalidSessionsFor(existingUser);
this.persistenceHandler.removeUser(username);
persistModelAsync();
logger.info("Removed user " + username);
@ -772,6 +776,7 @@ public class DefaultPrivilegeHandler implements PrivilegeHandler {
// delegate user replacement to persistence handler
this.persistenceHandler.replaceUser(newUser);
persistModelAsync();
logger.info("Added role " + roleName + " to " + newUser.getUsername());
@ -819,6 +824,7 @@ public class DefaultPrivilegeHandler implements PrivilegeHandler {
// delegate user replacement to persistence handler
this.persistenceHandler.replaceUser(newUser);
persistModelAsync();
logger.info("Removed role " + roleName + " from " + newUser.getUsername());
@ -858,11 +864,7 @@ public class DefaultPrivilegeHandler implements PrivilegeHandler {
// delegate user replacement to persistence handler
this.persistenceHandler.replaceUser(newUser);
// perform automatic persisting, if enabled
if (this.autoPersistOnUserChangesData) {
this.persistenceHandler.persist();
}
persistModelAsync();
logger.info("Set locale to " + locale + " for " + newUser.getUsername());
@ -896,11 +898,7 @@ public class DefaultPrivilegeHandler implements PrivilegeHandler {
// delegate user replacement to persistence handler
this.persistenceHandler.replaceUser(newUser);
// perform automatic persisting, if enabled
if (this.autoPersistOnUserChangesData) {
this.persistenceHandler.persist();
}
persistModelAsync();
logger.info("Requiring user " + newUser.getUsername() + " to change their password on next login.");
}
@ -956,15 +954,10 @@ public class DefaultPrivilegeHandler implements PrivilegeHandler {
// delegate user replacement to persistence handler
this.persistenceHandler.replaceUser(newUser);
persistModelAsync();
// perform automatic persisting, if enabled
if (this.autoPersistOnUserChangesData) {
this.persistenceHandler.persist();
}
if (certificate.getUsage() == Usage.SET_PASSWORD) {
if (certificate.getUsage() == Usage.SET_PASSWORD)
invalidate(certificate);
}
if (password == null)
logger.info("Cleared password for " + newUser.getUsername());
@ -1004,6 +997,7 @@ public class DefaultPrivilegeHandler implements PrivilegeHandler {
// delegate user replacement to persistence handler
this.persistenceHandler.replaceUser(newUser);
persistModelAsync();
logger.info("Set state of user " + newUser.getUsername() + " to " + state);
@ -1042,6 +1036,7 @@ public class DefaultPrivilegeHandler implements PrivilegeHandler {
// delegate to persistence handler
this.persistenceHandler.addRole(newRole);
persistModelAsync();
logger.info("Added new role " + newRole.getName());
@ -1084,6 +1079,7 @@ public class DefaultPrivilegeHandler implements PrivilegeHandler {
// delegate to persistence handler
this.persistenceHandler.replaceRole(newRole);
persistModelAsync();
logger.info("Replaced role " + newRole.getName());
@ -1127,6 +1123,7 @@ public class DefaultPrivilegeHandler implements PrivilegeHandler {
// delegate role removal to persistence handler
this.persistenceHandler.removeRole(roleName);
persistModelAsync();
logger.info("Removed role " + roleName);
@ -1189,6 +1186,7 @@ public class DefaultPrivilegeHandler implements PrivilegeHandler {
// delegate role replacement to persistence handler
this.persistenceHandler.replaceRole(newRole);
persistModelAsync();
logger.info("Added/replaced privilege " + privilegeRep.getName() + " to " + roleName);
@ -1239,6 +1237,7 @@ public class DefaultPrivilegeHandler implements PrivilegeHandler {
// delegate user replacement to persistence handler
this.persistenceHandler.replaceRole(newRole);
persistModelAsync();
logger.info("Removed privilege " + privilegeName + " from " + roleName);
@ -1264,6 +1263,8 @@ public class DefaultPrivilegeHandler implements PrivilegeHandler {
this.privilegeContextMap.put(cert.getSessionId(), privilegeContext);
}
}
persistSessionsAsync();
}
/**
@ -1286,6 +1287,8 @@ public class DefaultPrivilegeHandler implements PrivilegeHandler {
this.privilegeContextMap.put(cert.getSessionId(), privilegeContext);
}
}
persistSessionsAsync();
}
private void invalidSessionsFor(User user) {
@ -1360,7 +1363,7 @@ public class DefaultPrivilegeHandler implements PrivilegeHandler {
" to " + source);
}
persistSessions();
persistSessionsAsync();
logger.info(format("Challenge validated for user {0} with usage {1}", username, usage));
return certificate;
@ -1418,15 +1421,14 @@ public class DefaultPrivilegeHandler implements PrivilegeHandler {
PrivilegeContext privilegeContext = buildPrivilegeContext(certificate, user);
this.privilegeContextMap.put(sessionId, privilegeContext);
persistSessions();
persistSessionsAsync();
// save last login
if (user.getHistory().isFirstLoginEmpty())
user.getHistory().setFirstLogin(ZonedDateTime.now());
user.getHistory().setLastLogin(ZonedDateTime.now());
this.persistenceHandler.replaceUser(user);
if (this.autoPersistOnUserChangesData)
this.persistenceHandler.persist();
persistModelAsync();
// log
logger.info(format("User {0} authenticated: {1}", username, certificate));
@ -1478,9 +1480,7 @@ public class DefaultPrivilegeHandler implements PrivilegeHandler {
user.getHistory().setFirstLogin(internalUser.getHistory().getFirstLogin());
this.persistenceHandler.replaceUser(user);
}
if (this.autoPersistOnUserChangesData)
this.persistenceHandler.persist();
persistModelAsync();
// get 2 auth tokens
String authToken = this.encryptionHandler.nextToken();
@ -1495,7 +1495,7 @@ public class DefaultPrivilegeHandler implements PrivilegeHandler {
PrivilegeContext privilegeContext = buildPrivilegeContext(certificate, user);
this.privilegeContextMap.put(sessionId, privilegeContext);
persistSessions();
persistSessionsAsync();
// log
logger.info(format("User {0} authenticated: {1}", user.getUsername(), certificate));
@ -1546,8 +1546,6 @@ public class DefaultPrivilegeHandler implements PrivilegeHandler {
// invalidate the previous session
invalidate(certificate);
persistSessions();
// log
logger.info(format("User {0} refreshed session: {1}", user.getUsername(), refreshedCert));
@ -1573,7 +1571,24 @@ public class DefaultPrivilegeHandler implements PrivilegeHandler {
user.getLocale(), userRoles, new HashMap<>(user.getProperties()));
}
private boolean persistSessions() {
private synchronized void persistModelAsync() {
if (!this.autoPersistOnUserChangesData)
return;
// async execution, max. once per second
if (this.persistModelTask != null)
this.persistModelTask.cancel(true);
this.persistModelTask = this.executorService.schedule(
() -> this.lockingHandler.lockedExecute("persist-model", () -> {
try {
this.persistenceHandler.persist();
} catch (Exception e) {
logger.error("Failed to persist model!", e);
}
}), 1, TimeUnit.SECONDS);
}
private synchronized boolean persistSessionsAsync() {
if (!this.persistSessions)
return false;
@ -1759,8 +1774,8 @@ public class DefaultPrivilegeHandler implements PrivilegeHandler {
user.isPasswordChangeRequested(), user.getHistory().getClone());
// delegate user replacement to persistence handler
this.persistenceHandler.replaceUser(newUser);
this.persistenceHandler.replaceUser(user);
persistModelAsync();
logger.info("Updated password for " + user.getUsername());
}
@ -1854,7 +1869,7 @@ public class DefaultPrivilegeHandler implements PrivilegeHandler {
// persist sessions
if (privilegeContext != null)
persistSessions();
persistSessionsAsync();
// return true if object was really removed
boolean loggedOut = privilegeContext != null;
@ -1970,6 +1985,7 @@ public class DefaultPrivilegeHandler implements PrivilegeHandler {
PrivilegeContext prvCtx = validate(certificate);
prvCtx.validateAction(new SimpleRestrictable(PRIVILEGE_ACTION, PRIVILEGE_ACTION_PERSIST));
// persist non async
return this.persistenceHandler.persist();
}
@ -1980,7 +1996,7 @@ public class DefaultPrivilegeHandler implements PrivilegeHandler {
PrivilegeContext prvCtx = validate(certificate);
prvCtx.validateAction(new SimpleRestrictable(PRIVILEGE_ACTION, PRIVILEGE_ACTION_PERSIST_SESSIONS));
return persistSessions();
return persistSessionsAsync();
}
@Override

View File

@ -15,17 +15,6 @@
*/
package li.strolch.privilege.handler;
import static java.text.MessageFormat.format;
import static li.strolch.privilege.handler.PrivilegeHandler.PARAM_CASE_INSENSITIVE_USERNAME;
import static li.strolch.privilege.helper.XmlConstants.*;
import static li.strolch.utils.helper.StringHelper.formatNanoDuration;
import java.io.File;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import li.strolch.privilege.base.PrivilegeException;
import li.strolch.privilege.helper.XmlConstants;
import li.strolch.privilege.model.internal.Role;
@ -34,11 +23,22 @@ import li.strolch.privilege.xml.PrivilegeRolesDomWriter;
import li.strolch.privilege.xml.PrivilegeRolesSaxReader;
import li.strolch.privilege.xml.PrivilegeUsersDomWriter;
import li.strolch.privilege.xml.PrivilegeUsersSaxReader;
import li.strolch.utils.helper.StringHelper;
import li.strolch.utils.helper.XmlHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import static java.text.MessageFormat.format;
import static li.strolch.privilege.handler.PrivilegeHandler.PARAM_CASE_INSENSITIVE_USERNAME;
import static li.strolch.privilege.helper.XmlConstants.*;
import static li.strolch.utils.helper.StringHelper.formatNanoDuration;
import static li.strolch.utils.helper.StringHelper.isEmpty;
/**
* {@link PersistenceHandler} implementation which reads the configuration from XML files. These configuration is passed
* in {@link #initialize(Map)}
@ -167,39 +167,11 @@ public class XmlPersistenceHandler implements PersistenceHandler {
throw new PrivilegeException(msg);
}
// get users file name
String usersFileName = this.parameterMap.get(XML_PARAM_USERS_FILE);
if (StringHelper.isEmpty(usersFileName)) {
String msg = "[{0}] Defined parameter {1} is not valid as it is empty!";
msg = format(msg, PersistenceHandler.class.getName(), XML_PARAM_USERS_FILE);
throw new PrivilegeException(msg);
}
// get users file path
File usersPath = getFile(basePath, XML_PARAM_USERS_FILE);
// get roles file name
String rolesFileName = this.parameterMap.get(XML_PARAM_ROLES_FILE);
if (StringHelper.isEmpty(rolesFileName)) {
String msg = "[{0}] Defined parameter {1} is not valid as it is empty!";
msg = format(msg, PersistenceHandler.class.getName(), XML_PARAM_ROLES_FILE);
throw new PrivilegeException(msg);
}
// validate users file exists
String usersPathS = basePath + "/" + usersFileName;
File usersPath = new File(usersPathS);
if (!usersPath.exists()) {
String msg = "[{0}] Defined parameter {1} is invalid as users file does not exist at path {2}";
msg = format(msg, PersistenceHandler.class.getName(), XML_PARAM_USERS_FILE, usersPath.getAbsolutePath());
throw new PrivilegeException(msg);
}
// validate roles file exists
String rolesPathS = basePath + "/" + rolesFileName;
File rolesPath = new File(rolesPathS);
if (!rolesPath.exists()) {
String msg = "[{0}] Defined parameter {1} is invalid as roles file does not exist at path {2}";
msg = format(msg, PersistenceHandler.class.getName(), XML_PARAM_ROLES_FILE, rolesPath.getAbsolutePath());
throw new PrivilegeException(msg);
}
// get roles file path
File rolesPath = getFile(basePath, XML_PARAM_ROLES_FILE);
// save path to model
this.usersPath = usersPath;
@ -211,6 +183,25 @@ public class XmlPersistenceHandler implements PersistenceHandler {
logger.info("Privilege Data loaded.");
}
private File getFile(String basePath, String param) {
String fileName = this.parameterMap.get(param);
if (isEmpty(fileName)) {
String msg = "[{0}] Defined parameter {1} is not valid as it is empty!";
msg = format(msg, PersistenceHandler.class.getName(), param);
throw new PrivilegeException(msg);
}
String path = basePath + "/" + fileName;
File file = new File(path);
if (!file.exists()) {
String msg = "[{0}] Defined parameter {1} is invalid as file does not exist at path {2}";
msg = format(msg, PersistenceHandler.class.getName(), param, file.getAbsolutePath());
throw new PrivilegeException(msg);
}
return file;
}
/**
* Reads the XML configuration files which contain the model. Which configuration files are parsed was defined in
* the while calling {@link #initialize(Map)}