[Fix] Fixed updating sessions on changes of user or roles

This commit is contained in:
Robert von Burg 2024-03-05 10:16:32 +01:00
parent 76d38e9af0
commit d00b00d234
Signed by: eitch
GPG Key ID: 75DB9C85C74331F7
2 changed files with 54 additions and 31 deletions

View File

@ -30,7 +30,6 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.xml.sax.SAXParseException; import org.xml.sax.SAXParseException;
import javax.crypto.SecretKey;
import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamException;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
@ -292,14 +291,6 @@ public class DefaultPrivilegeHandler implements PrivilegeHandler {
() -> crudHandler.removeRole(certificate, roleName)); () -> crudHandler.removeRole(certificate, roleName));
} }
void invalidSessionsFor(User user) {
List<PrivilegeContext> contexts = new ArrayList<>(this.privilegeContextMap.values());
for (PrivilegeContext ctx : contexts) {
if (ctx.getUserRep().getUsername().equals(user.getUsername()))
invalidate(ctx.getCertificate());
}
}
@Override @Override
public void initiateChallengeFor(Usage usage, String username) { public void initiateChallengeFor(Usage usage, String username) {
initiateChallengeFor(usage, username, SOURCE_UNKNOWN); initiateChallengeFor(usage, username, SOURCE_UNKNOWN);
@ -355,8 +346,8 @@ public class DefaultPrivilegeHandler implements PrivilegeHandler {
false).getCertificate(); false).getCertificate();
if (!source.equals("unknown") && !source.equals(userChallenge.getSource())) { if (!source.equals("unknown") && !source.equals(userChallenge.getSource())) {
logger.warn("Challenge request and response source's are different: request: " + userChallenge.getSource() + logger.warn(format("Challenge request and response source''s are different: request: {0} to {1}",
" to " + source); userChallenge.getSource(), source));
} }
persistSessionsAsync(); persistSessionsAsync();
@ -444,9 +435,12 @@ public class DefaultPrivilegeHandler implements PrivilegeHandler {
* @return a stream of role names * @return a stream of role names
*/ */
public static Stream<String> streamAllRolesForUser(PersistenceHandler persistenceHandler, User user) { public static Stream<String> streamAllRolesForUser(PersistenceHandler persistenceHandler, User user) {
return Stream.concat(user.getRoles().stream(), return Stream.concat(user.getRoles().stream(), user
user.groups().stream().map(persistenceHandler::getGroup).filter(Objects::nonNull) .groups()
.flatMap(g -> g.roles().stream())); .stream()
.map(persistenceHandler::getGroup)
.filter(Objects::nonNull)
.flatMap(g -> g.roles().stream()));
} }
@Override @Override
@ -559,8 +553,11 @@ public class DefaultPrivilegeHandler implements PrivilegeHandler {
// get sessions reference // get sessions reference
AtomicReference<List<Certificate>> sessions = new AtomicReference<>(); AtomicReference<List<Certificate>> sessions = new AtomicReference<>();
this.lockingHandler.lockedExecute("persist-sessions", () -> sessions.set( this.lockingHandler.lockedExecute("persist-sessions", () -> sessions.set(
new ArrayList<>(this.privilegeContextMap.values()).stream().map(PrivilegeContext::getCertificate) new ArrayList<>(this.privilegeContextMap.values())
.filter(c -> !c.getUserState().isSystem()).collect(toList()))); .stream()
.map(PrivilegeContext::getCertificate)
.filter(c -> !c.getUserState().isSystem())
.collect(toList())));
// write the sessions // write the sessions
try (OutputStream out = Files.newOutputStream(this.persistSessionsPath.toPath()); try (OutputStream out = Files.newOutputStream(this.persistSessionsPath.toPath());
@ -573,8 +570,8 @@ public class DefaultPrivilegeHandler implements PrivilegeHandler {
} catch (Exception e) { } catch (Exception e) {
logger.error("Failed to persist sessions!", e); logger.error("Failed to persist sessions!", e);
if (this.persistSessionsPath.exists() && !this.persistSessionsPath.delete()) { if (this.persistSessionsPath.exists() && !this.persistSessionsPath.delete()) {
logger.error("Failed to delete sessions file after failing to write to it, at " + logger.error("Failed to delete sessions file after failing to write to it, at "
this.persistSessionsPath.getAbsolutePath()); + this.persistSessionsPath.getAbsolutePath());
} }
} }
}, 1, TimeUnit.SECONDS); }, 1, TimeUnit.SECONDS);
@ -694,8 +691,9 @@ public class DefaultPrivilegeHandler implements PrivilegeHandler {
PasswordCrypt requestPasswordCrypt; PasswordCrypt requestPasswordCrypt;
if (userPasswordCrypt.salt() == null) { if (userPasswordCrypt.salt() == null) {
requestPasswordCrypt = this.encryptionHandler.hashPasswordWithoutSalt(password); requestPasswordCrypt = this.encryptionHandler.hashPasswordWithoutSalt(password);
} else if (userPasswordCrypt.hashAlgorithm() == null || userPasswordCrypt.hashIterations() == -1 || } else if (userPasswordCrypt.hashAlgorithm() == null
userPasswordCrypt.hashKeyLength() == -1) { || userPasswordCrypt.hashIterations() == -1
|| userPasswordCrypt.hashKeyLength() == -1) {
requestPasswordCrypt = this.encryptionHandler.hashPassword(password, userPasswordCrypt.salt()); requestPasswordCrypt = this.encryptionHandler.hashPassword(password, userPasswordCrypt.salt());
} else { } else {
requestPasswordCrypt = this.encryptionHandler.hashPassword(password, userPasswordCrypt.salt(), requestPasswordCrypt = this.encryptionHandler.hashPassword(password, userPasswordCrypt.salt(),
@ -1075,12 +1073,27 @@ public class DefaultPrivilegeHandler implements PrivilegeHandler {
} }
} }
/**
* Invalidates all the sessions for the given user and persists the sessions async
*
* @param user the user for which to invalidate the sessions
*/
void invalidateSessionsFor(User user) {
List<PrivilegeContext> contexts = new ArrayList<>(this.privilegeContextMap.values());
for (PrivilegeContext ctx : contexts) {
if (ctx.getUserRep().getUsername().equals(user.getUsername()))
invalidate(ctx.getCertificate());
}
persistSessionsAsync();
}
/** /**
* Replaces any existing {@link PrivilegeContext} for the given user by updating with the new user object * Replaces any existing {@link PrivilegeContext} for the given user by updating with the new user object
* *
* @param newUser the new user to update with * @param newUser the new user to update with
*/ */
void updateExistingSessionsForUser(User newUser) { void updateExistingSessionsForUser(User newUser, boolean persistSessions) {
List<PrivilegeContext> contexts = new ArrayList<>(this.privilegeContextMap.values()); List<PrivilegeContext> contexts = new ArrayList<>(this.privilegeContextMap.values());
for (PrivilegeContext ctx : contexts) { for (PrivilegeContext ctx : contexts) {
if (!ctx.getUserRep().getUsername().equals(newUser.getUsername())) if (!ctx.getUserRep().getUsername().equals(newUser.getUsername()))
@ -1088,7 +1101,8 @@ public class DefaultPrivilegeHandler implements PrivilegeHandler {
replacePrivilegeContextForCert(newUser, ctx.getCertificate()); replacePrivilegeContextForCert(newUser, ctx.getCertificate());
} }
persistSessionsAsync(); if (persistSessions)
persistSessionsAsync();
} }
/** /**

View File

@ -172,8 +172,15 @@ public class PrivilegeCrudHandler {
// properties // properties
propertySelected = isSelectedByProperty(selPropertyMap, user.getProperties()); propertySelected = isSelectedByProperty(selPropertyMap, user.getProperties());
boolean selected = userIdSelected && usernameSelected && firstNameSelected && lastNameSelected && boolean selected = userIdSelected
userStateSelected && localeSelected && groupSelected && roleSelected && propertySelected; && usernameSelected
&& firstNameSelected
&& lastNameSelected
&& userStateSelected
&& localeSelected
&& groupSelected
&& roleSelected
&& propertySelected;
if (selected) if (selected)
result.add(user.asUserRep()); result.add(user.asUserRep());
@ -376,7 +383,10 @@ public class PrivilegeCrudHandler {
// delegate to persistence handler // delegate to persistence handler
toCreate.forEach(this.persistenceHandler::addUser); toCreate.forEach(this.persistenceHandler::addUser);
toUpdate.forEach(this.persistenceHandler::replaceUser); for (User user : toUpdate) {
this.persistenceHandler.replaceUser(user);
this.privilegeHandler.updateExistingSessionsForUser(user, false);
}
this.privilegeHandler.persistModelAsync(); this.privilegeHandler.persistModelAsync();
DefaultPrivilegeHandler.logger.info("Created " + toCreate.size() + " users"); DefaultPrivilegeHandler.logger.info("Created " + toCreate.size() + " users");
@ -530,7 +540,7 @@ public class PrivilegeCrudHandler {
// delegate to persistence handler // delegate to persistence handler
this.persistenceHandler.replaceUser(newUser); this.persistenceHandler.replaceUser(newUser);
this.privilegeHandler.persistModelAsync(); this.privilegeHandler.updateExistingSessionsForUser(newUser, true);
DefaultPrivilegeHandler.logger.info("Replaced user " + newUser.getUsername()); DefaultPrivilegeHandler.logger.info("Replaced user " + newUser.getUsername());
@ -559,9 +569,8 @@ public class PrivilegeCrudHandler {
new SimpleRestrictable(DefaultPrivilegeHandler.PRIVILEGE_REMOVE_USER, new Tuple(null, existingUser))); new SimpleRestrictable(DefaultPrivilegeHandler.PRIVILEGE_REMOVE_USER, new Tuple(null, existingUser)));
// delegate user removal to persistence handler // delegate user removal to persistence handler
this.privilegeHandler.invalidSessionsFor(existingUser); this.privilegeHandler.invalidateSessionsFor(existingUser);
this.persistenceHandler.removeUser(username); this.persistenceHandler.removeUser(username);
this.privilegeHandler.persistModelAsync();
DefaultPrivilegeHandler.logger.info("Removed user " + username); DefaultPrivilegeHandler.logger.info("Removed user " + username);
@ -715,7 +724,7 @@ public class PrivilegeCrudHandler {
// delegate user replacement to persistence handler // delegate user replacement to persistence handler
this.persistenceHandler.replaceUser(newUser); this.persistenceHandler.replaceUser(newUser);
this.privilegeHandler.persistModelAsync(); this.privilegeHandler.invalidateSessionsFor(newUser);
DefaultPrivilegeHandler.logger.info("Set state of user " + newUser.getUsername() + " to " + state); DefaultPrivilegeHandler.logger.info("Set state of user " + newUser.getUsername() + " to " + state);
@ -789,11 +798,11 @@ public class PrivilegeCrudHandler {
this.persistenceHandler.replaceRole(newRole); this.persistenceHandler.replaceRole(newRole);
this.privilegeHandler.persistModelAsync(); this.privilegeHandler.persistModelAsync();
DefaultPrivilegeHandler.logger.info("Replaced role " + newRole.getName());
// update any existing certificates with new role // update any existing certificates with new role
this.privilegeHandler.updateExistingSessionsWithNewRole(newRole); this.privilegeHandler.updateExistingSessionsWithNewRole(newRole);
DefaultPrivilegeHandler.logger.info("Replaced role " + newRole.getName());
return newRole.asRoleRep(); return newRole.asRoleRep();
} }