Compare commits
6 Commits
76d38e9af0
...
2914889172
Author | SHA1 | Date |
---|---|---|
Robert von Burg | 2914889172 | |
Robert von Burg | d3c261b750 | |
Robert von Burg | de8d35480d | |
Robert von Burg | 1158acfd90 | |
Robert von Burg | faf05126b4 | |
Robert von Burg | d00b00d234 |
|
@ -1167,14 +1167,14 @@ public abstract class AbstractTransaction implements StrolchTransaction {
|
|||
@Override
|
||||
public Stream<Resource> streamCachedResources(String... types) {
|
||||
if (types.length == 0)
|
||||
return this.resourceCache.streamValues();
|
||||
return this.resourceCache.values().stream();
|
||||
if (types.length == 1) {
|
||||
String type = types[0];
|
||||
if (!this.resourceCache.containsMap(type))
|
||||
return Stream.empty();
|
||||
return this.resourceCache.getMap(type).values().stream();
|
||||
return new ArrayList<>(this.resourceCache.getMap(type).values()).stream();
|
||||
}
|
||||
return this.resourceCache.streamValues().filter(element -> {
|
||||
return this.resourceCache.values().stream().filter(element -> {
|
||||
String resType = element.getType();
|
||||
for (String type : types) {
|
||||
if (resType.equals(type))
|
||||
|
@ -1187,14 +1187,14 @@ public abstract class AbstractTransaction implements StrolchTransaction {
|
|||
@Override
|
||||
public Stream<Order> streamCachedOrders(String... types) {
|
||||
if (types.length == 0)
|
||||
return this.orderCache.streamValues();
|
||||
return this.orderCache.values().stream();
|
||||
if (types.length == 1) {
|
||||
String type = types[0];
|
||||
if (!this.orderCache.containsMap(type))
|
||||
return Stream.empty();
|
||||
return this.orderCache.getMap(type).values().stream();
|
||||
return new ArrayList<>(this.orderCache.getMap(type).values()).stream();
|
||||
}
|
||||
return this.orderCache.streamValues().filter(element -> {
|
||||
return this.orderCache.values().stream().filter(element -> {
|
||||
String resType = element.getType();
|
||||
for (String type : types) {
|
||||
if (resType.equals(type))
|
||||
|
@ -1207,14 +1207,14 @@ public abstract class AbstractTransaction implements StrolchTransaction {
|
|||
@Override
|
||||
public Stream<Activity> streamCachedActivities(String... types) {
|
||||
if (types.length == 0)
|
||||
return this.activityCache.streamValues();
|
||||
return this.activityCache.values().stream();
|
||||
if (types.length == 1) {
|
||||
String type = types[0];
|
||||
if (!this.activityCache.containsMap(type))
|
||||
return Stream.empty();
|
||||
return this.activityCache.getMap(type).values().stream();
|
||||
return new ArrayList<>(this.activityCache.getMap(type).values()).stream();
|
||||
}
|
||||
return this.activityCache.streamValues().filter(element -> {
|
||||
return this.activityCache.values().stream().filter(element -> {
|
||||
String resType = element.getType();
|
||||
for (String type : types) {
|
||||
if (resType.equals(type))
|
||||
|
|
|
@ -15,19 +15,6 @@
|
|||
*/
|
||||
package li.strolch.runtime.privilege;
|
||||
|
||||
import static java.lang.Boolean.parseBoolean;
|
||||
import static java.util.concurrent.TimeUnit.NANOSECONDS;
|
||||
import static li.strolch.privilege.handler.PrivilegeHandler.PARAM_PERSIST_SESSIONS;
|
||||
import static li.strolch.privilege.handler.PrivilegeHandler.PARAM_PERSIST_SESSIONS_PATH;
|
||||
import static li.strolch.privilege.helper.XmlConstants.PARAM_BASE_PATH;
|
||||
import static li.strolch.runtime.StrolchConstants.StrolchPrivilegeConstants.*;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.Files;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.Map;
|
||||
|
||||
import li.strolch.agent.api.ComponentContainer;
|
||||
import li.strolch.agent.api.StrolchComponent;
|
||||
import li.strolch.agent.api.StrolchRealm;
|
||||
|
@ -48,6 +35,21 @@ import li.strolch.runtime.configuration.ComponentConfiguration;
|
|||
import li.strolch.runtime.configuration.RuntimeConfiguration;
|
||||
import li.strolch.utils.helper.XmlHelper;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.Files;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.Map;
|
||||
|
||||
import static java.lang.Boolean.parseBoolean;
|
||||
import static java.util.concurrent.TimeUnit.NANOSECONDS;
|
||||
import static li.strolch.persistence.api.TransactionThreadLocal.getTx;
|
||||
import static li.strolch.persistence.api.TransactionThreadLocal.hasTx;
|
||||
import static li.strolch.privilege.handler.PrivilegeHandler.PARAM_PERSIST_SESSIONS;
|
||||
import static li.strolch.privilege.handler.PrivilegeHandler.PARAM_PERSIST_SESSIONS_PATH;
|
||||
import static li.strolch.privilege.helper.XmlConstants.PARAM_BASE_PATH;
|
||||
import static li.strolch.runtime.StrolchConstants.StrolchPrivilegeConstants.*;
|
||||
|
||||
public class DefaultStrolchPrivilegeHandler extends StrolchComponent implements PrivilegeHandler {
|
||||
|
||||
public static final String PROP_PRIVILEGE_CONFIG_FILE = "privilegeConfigFile";
|
||||
|
@ -89,8 +91,7 @@ public class DefaultStrolchPrivilegeHandler extends StrolchComponent implements
|
|||
/**
|
||||
* Initializes the {@link DefaultPrivilegeHandler} from the configuration file
|
||||
*
|
||||
* @param privilegeXmlFile
|
||||
* a {@link File} reference to the XML file containing the configuration for Privilege
|
||||
* @param privilegeXmlFile a {@link File} reference to the XML file containing the configuration for Privilege
|
||||
*
|
||||
* @return the initialized {@link PrivilegeHandler} where the {@link EncryptionHandler} and
|
||||
* {@link PersistenceHandler} are set and initialized as well
|
||||
|
@ -185,13 +186,17 @@ public class DefaultStrolchPrivilegeHandler extends StrolchComponent implements
|
|||
|
||||
private void writeAudit(Certificate certificate, String login, AccessType accessType, String username) {
|
||||
StrolchRealm realm = getContainer().getRealm(certificate);
|
||||
try (StrolchTransaction tx = realm.openTx(certificate, login, false).silentThreshold(1, NANOSECONDS)) {
|
||||
try (StrolchTransaction tx = hasTx() ? getTx() : openTx(certificate, login, realm)) {
|
||||
tx.setSuppressAudits(true);
|
||||
Audit audit = tx.auditFrom(accessType, PRIVILEGE, CERTIFICATE, username);
|
||||
tx.getAuditTrail().add(tx, audit);
|
||||
}
|
||||
}
|
||||
|
||||
private static StrolchTransaction openTx(Certificate certificate, String login, StrolchRealm realm) {
|
||||
return realm.openTx(certificate, login, false).silentThreshold(1, NANOSECONDS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PrivilegeContext validate(Certificate certificate) throws PrivilegeException {
|
||||
return this.privilegeHandler.validate(certificate);
|
||||
|
|
|
@ -30,7 +30,6 @@ import org.slf4j.Logger;
|
|||
import org.slf4j.LoggerFactory;
|
||||
import org.xml.sax.SAXParseException;
|
||||
|
||||
import javax.crypto.SecretKey;
|
||||
import javax.xml.stream.XMLStreamException;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
@ -292,14 +291,6 @@ public class DefaultPrivilegeHandler implements PrivilegeHandler {
|
|||
() -> 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
|
||||
public void initiateChallengeFor(Usage usage, String username) {
|
||||
initiateChallengeFor(usage, username, SOURCE_UNKNOWN);
|
||||
|
@ -355,8 +346,8 @@ public class DefaultPrivilegeHandler implements PrivilegeHandler {
|
|||
false).getCertificate();
|
||||
|
||||
if (!source.equals("unknown") && !source.equals(userChallenge.getSource())) {
|
||||
logger.warn("Challenge request and response source's are different: request: " + userChallenge.getSource() +
|
||||
" to " + source);
|
||||
logger.warn(format("Challenge request and response source''s are different: request: {0} to {1}",
|
||||
userChallenge.getSource(), source));
|
||||
}
|
||||
|
||||
persistSessionsAsync();
|
||||
|
@ -444,9 +435,12 @@ public class DefaultPrivilegeHandler implements PrivilegeHandler {
|
|||
* @return a stream of role names
|
||||
*/
|
||||
public static Stream<String> streamAllRolesForUser(PersistenceHandler persistenceHandler, User user) {
|
||||
return Stream.concat(user.getRoles().stream(),
|
||||
user.groups().stream().map(persistenceHandler::getGroup).filter(Objects::nonNull)
|
||||
.flatMap(g -> g.roles().stream()));
|
||||
return Stream.concat(user.getRoles().stream(), user
|
||||
.groups()
|
||||
.stream()
|
||||
.map(persistenceHandler::getGroup)
|
||||
.filter(Objects::nonNull)
|
||||
.flatMap(g -> g.roles().stream()));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -554,34 +548,37 @@ public class DefaultPrivilegeHandler implements PrivilegeHandler {
|
|||
// async execution, max. once per second
|
||||
if (this.persistSessionsTask != null)
|
||||
this.persistSessionsTask.cancel(true);
|
||||
this.persistSessionsTask = this.executorService.schedule(() -> {
|
||||
|
||||
// get sessions reference
|
||||
AtomicReference<List<Certificate>> sessions = new AtomicReference<>();
|
||||
this.lockingHandler.lockedExecute("persist-sessions", () -> sessions.set(
|
||||
new ArrayList<>(this.privilegeContextMap.values()).stream().map(PrivilegeContext::getCertificate)
|
||||
.filter(c -> !c.getUserState().isSystem()).collect(toList())));
|
||||
|
||||
// write the sessions
|
||||
try (OutputStream out = Files.newOutputStream(this.persistSessionsPath.toPath());
|
||||
OutputStream outputStream = AesCryptoHelper.wrapEncrypt(this.secretKey, out)) {
|
||||
|
||||
CertificateStubsSaxWriter writer = new CertificateStubsSaxWriter(sessions.get(), outputStream);
|
||||
writer.write();
|
||||
outputStream.flush();
|
||||
|
||||
} catch (Exception e) {
|
||||
logger.error("Failed to persist sessions!", e);
|
||||
if (this.persistSessionsPath.exists() && !this.persistSessionsPath.delete()) {
|
||||
logger.error("Failed to delete sessions file after failing to write to it, at " +
|
||||
this.persistSessionsPath.getAbsolutePath());
|
||||
}
|
||||
}
|
||||
}, 1, TimeUnit.SECONDS);
|
||||
|
||||
this.persistSessionsTask = this.executorService.schedule(this::internalPersistSessions, 1, TimeUnit.SECONDS);
|
||||
return true;
|
||||
}
|
||||
|
||||
private void internalPersistSessions() {
|
||||
// get sessions reference
|
||||
AtomicReference<List<Certificate>> sessions = new AtomicReference<>();
|
||||
this.lockingHandler.lockedExecute("persist-sessions", () -> sessions.set(
|
||||
new ArrayList<>(this.privilegeContextMap.values())
|
||||
.stream()
|
||||
.map(PrivilegeContext::getCertificate)
|
||||
.filter(c -> !c.getUserState().isSystem())
|
||||
.collect(toList())));
|
||||
|
||||
// write the sessions
|
||||
try (OutputStream out = Files.newOutputStream(this.persistSessionsPath.toPath());
|
||||
OutputStream outputStream = AesCryptoHelper.wrapEncrypt(this.secretKey, out)) {
|
||||
|
||||
CertificateStubsSaxWriter writer = new CertificateStubsSaxWriter(sessions.get(), outputStream);
|
||||
writer.write();
|
||||
outputStream.flush();
|
||||
|
||||
} catch (Exception e) {
|
||||
logger.error("Failed to persist sessions!", e);
|
||||
if (this.persistSessionsPath.exists() && !this.persistSessionsPath.delete()) {
|
||||
logger.error("Failed to delete sessions file after failing to write to it, at "
|
||||
+ this.persistSessionsPath.getAbsolutePath());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void loadSessions() {
|
||||
if (!this.persistSessions) {
|
||||
logger.info("Persisting of sessions not enabled, so not loading!.");
|
||||
|
@ -694,8 +691,9 @@ public class DefaultPrivilegeHandler implements PrivilegeHandler {
|
|||
PasswordCrypt requestPasswordCrypt;
|
||||
if (userPasswordCrypt.salt() == null) {
|
||||
requestPasswordCrypt = this.encryptionHandler.hashPasswordWithoutSalt(password);
|
||||
} else if (userPasswordCrypt.hashAlgorithm() == null || userPasswordCrypt.hashIterations() == -1 ||
|
||||
userPasswordCrypt.hashKeyLength() == -1) {
|
||||
} else if (userPasswordCrypt.hashAlgorithm() == null
|
||||
|| userPasswordCrypt.hashIterations() == -1
|
||||
|| userPasswordCrypt.hashKeyLength() == -1) {
|
||||
requestPasswordCrypt = this.encryptionHandler.hashPassword(password, userPasswordCrypt.salt());
|
||||
} else {
|
||||
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
|
||||
*
|
||||
* @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());
|
||||
for (PrivilegeContext ctx : contexts) {
|
||||
if (!ctx.getUserRep().getUsername().equals(newUser.getUsername()))
|
||||
|
@ -1088,7 +1101,8 @@ public class DefaultPrivilegeHandler implements PrivilegeHandler {
|
|||
replacePrivilegeContextForCert(newUser, ctx.getCertificate());
|
||||
}
|
||||
|
||||
persistSessionsAsync();
|
||||
if (persistSessions)
|
||||
persistSessionsAsync();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -172,8 +172,15 @@ public class PrivilegeCrudHandler {
|
|||
// properties
|
||||
propertySelected = isSelectedByProperty(selPropertyMap, user.getProperties());
|
||||
|
||||
boolean selected = userIdSelected && usernameSelected && firstNameSelected && lastNameSelected &&
|
||||
userStateSelected && localeSelected && groupSelected && roleSelected && propertySelected;
|
||||
boolean selected = userIdSelected
|
||||
&& usernameSelected
|
||||
&& firstNameSelected
|
||||
&& lastNameSelected
|
||||
&& userStateSelected
|
||||
&& localeSelected
|
||||
&& groupSelected
|
||||
&& roleSelected
|
||||
&& propertySelected;
|
||||
|
||||
if (selected)
|
||||
result.add(user.asUserRep());
|
||||
|
@ -376,7 +383,10 @@ public class PrivilegeCrudHandler {
|
|||
|
||||
// delegate to persistence handler
|
||||
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();
|
||||
|
||||
DefaultPrivilegeHandler.logger.info("Created " + toCreate.size() + " users");
|
||||
|
@ -530,7 +540,7 @@ public class PrivilegeCrudHandler {
|
|||
|
||||
// delegate to persistence handler
|
||||
this.persistenceHandler.replaceUser(newUser);
|
||||
this.privilegeHandler.persistModelAsync();
|
||||
this.privilegeHandler.updateExistingSessionsForUser(newUser, true);
|
||||
|
||||
DefaultPrivilegeHandler.logger.info("Replaced user " + newUser.getUsername());
|
||||
|
||||
|
@ -559,9 +569,8 @@ public class PrivilegeCrudHandler {
|
|||
new SimpleRestrictable(DefaultPrivilegeHandler.PRIVILEGE_REMOVE_USER, new Tuple(null, existingUser)));
|
||||
|
||||
// delegate user removal to persistence handler
|
||||
this.privilegeHandler.invalidSessionsFor(existingUser);
|
||||
this.privilegeHandler.invalidateSessionsFor(existingUser);
|
||||
this.persistenceHandler.removeUser(username);
|
||||
this.privilegeHandler.persistModelAsync();
|
||||
|
||||
DefaultPrivilegeHandler.logger.info("Removed user " + username);
|
||||
|
||||
|
@ -715,7 +724,7 @@ public class PrivilegeCrudHandler {
|
|||
|
||||
// delegate user replacement to persistence handler
|
||||
this.persistenceHandler.replaceUser(newUser);
|
||||
this.privilegeHandler.persistModelAsync();
|
||||
this.privilegeHandler.invalidateSessionsFor(newUser);
|
||||
|
||||
DefaultPrivilegeHandler.logger.info("Set state of user " + newUser.getUsername() + " to " + state);
|
||||
|
||||
|
@ -789,11 +798,11 @@ public class PrivilegeCrudHandler {
|
|||
this.persistenceHandler.replaceRole(newRole);
|
||||
this.privilegeHandler.persistModelAsync();
|
||||
|
||||
DefaultPrivilegeHandler.logger.info("Replaced role " + newRole.getName());
|
||||
|
||||
// update any existing certificates with new role
|
||||
this.privilegeHandler.updateExistingSessionsWithNewRole(newRole);
|
||||
|
||||
DefaultPrivilegeHandler.logger.info("Replaced role " + newRole.getName());
|
||||
|
||||
return newRole.asRoleRep();
|
||||
}
|
||||
|
||||
|
|
|
@ -33,7 +33,6 @@ import li.strolch.persistence.api.StrolchTransaction;
|
|||
import li.strolch.policy.notifications.NotificationsPolicy;
|
||||
import li.strolch.privilege.model.Certificate;
|
||||
import li.strolch.rest.RestfulStrolchComponent;
|
||||
import li.strolch.rest.helper.ResponseUtil;
|
||||
import li.strolch.service.JsonServiceArgument;
|
||||
import li.strolch.service.StringArgument;
|
||||
import li.strolch.service.api.ServiceHandler;
|
||||
|
@ -50,14 +49,13 @@ import java.util.List;
|
|||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static java.util.Optional.ofNullable;
|
||||
import static li.strolch.model.StrolchModelConstants.*;
|
||||
import static li.strolch.rest.RestfulStrolchComponent.getInstance;
|
||||
import static li.strolch.rest.StrolchRestfulConstants.DATA;
|
||||
import static li.strolch.rest.StrolchRestfulConstants.STROLCH_CERTIFICATE;
|
||||
import static li.strolch.rest.helper.ResponseUtil.*;
|
||||
import static li.strolch.rest.helper.ResponseUtil.toResponse;
|
||||
import static li.strolch.runtime.StrolchConstants.DEFAULT_REALM;
|
||||
import static li.strolch.runtime.StrolchConstants.StrolchPrivilegeConstants.*;
|
||||
import static li.strolch.utils.helper.ExceptionHelper.getCallerMethod;
|
||||
|
@ -75,7 +73,7 @@ public class NotificationResource {
|
|||
String realm = certificate.getRealm();
|
||||
if (StringHelper.isEmpty(realm))
|
||||
realm = DEFAULT_REALM;
|
||||
return RestfulStrolchComponent.getInstance().openTx(certificate, realm, getCallerMethod());
|
||||
return RestfulStrolchComponent.getInstance().openTx(certificate, realm, getCallerMethod(2));
|
||||
}
|
||||
|
||||
private static Certificate validateCertificate(HttpServletRequest request, String privilege) {
|
||||
|
|
Loading…
Reference in New Issue