Skip to content

Commit

Permalink
Merge branch 'develop' into release/2.1
Browse files Browse the repository at this point in the history
  • Loading branch information
eitch committed Oct 30, 2023
2 parents 41304e1 + 8e7ee23 commit 42ee3de
Show file tree
Hide file tree
Showing 143 changed files with 4,834 additions and 5,710 deletions.
12 changes: 10 additions & 2 deletions agent/src/main/java/li/strolch/policy/StrolchPolicy.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@
*/
package li.strolch.policy;

import static li.strolch.model.StrolchModelConstants.PolicyConstants.PARAM_ORDER;

import li.strolch.agent.api.ComponentContainer;
import li.strolch.agent.api.StrolchAgent;
import li.strolch.agent.api.StrolchComponent;
Expand All @@ -27,6 +25,8 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import static li.strolch.model.StrolchModelConstants.PolicyConstants.PARAM_ORDER;

/**
* Interface for all Strolch policies, which are instantiated by the {@link PolicyHandler}
*
Expand Down Expand Up @@ -103,6 +103,14 @@ protected StrolchTransaction tx() {
return this.tx;
}

/**
* Returns true if this TX is still open, or committing, and thus can still be used
* @return true if this TX is still open, or committing, and thus can still be used
*/
protected boolean isTxOpen() {
return this.tx.isOpen() || this.tx.isCommitting();
}

protected Order getOrder(IActivityElement element) {
return tx().getOrderByRelation(element.getRootElement(), PARAM_ORDER, true);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
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.XML_PARAM_BASE_PATH;
import static li.strolch.privilege.helper.XmlConstants.PARAM_BASE_PATH;
import static li.strolch.runtime.StrolchConstants.StrolchPrivilegeConstants.*;

import java.io.File;
Expand Down Expand Up @@ -126,7 +126,7 @@ private li.strolch.privilege.handler.PrivilegeHandler initializeFromXml(Componen
if (containerModel.getPersistenceHandlerClassName().equals(XmlPersistenceHandler.class.getName())) {
Map<String, String> xmlParams = containerModel.getPersistenceHandlerParameterMap();
File configPath = runtimeConfig.getConfigPath();
xmlParams.put(XML_PARAM_BASE_PATH, configPath.getPath());
xmlParams.put(PARAM_BASE_PATH, configPath.getPath());
}

return new PrivilegeInitializer(getScheduledExecutor(getName())).initializeFromXml(containerModel);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import li.strolch.privilege.base.AccessDeniedException;
import li.strolch.privilege.base.PrivilegeException;
import li.strolch.privilege.i18n.PrivilegeMessages;
import li.strolch.privilege.model.IPrivilege;
import li.strolch.privilege.model.Privilege;
import li.strolch.privilege.model.PrivilegeContext;
import li.strolch.privilege.model.Restrictable;
import li.strolch.privilege.model.internal.Role;
Expand All @@ -20,26 +20,26 @@ public class ModelPrivilege implements PrivilegePolicy {
/**
* The value of {@link Restrictable#getPrivilegeValue()} is used to check if the {@link Role} has this privilege
*
* @see li.strolch.privilege.policy.PrivilegePolicy#validateAction(PrivilegeContext, IPrivilege, Restrictable)
* @see li.strolch.privilege.policy.PrivilegePolicy#validateAction(PrivilegeContext, Privilege, Restrictable)
*/
@Override
public void validateAction(PrivilegeContext ctx, IPrivilege privilege, Restrictable restrictable)
public void validateAction(PrivilegeContext ctx, Privilege privilege, Restrictable restrictable)
throws AccessDeniedException {
validateAction(ctx, privilege, restrictable, true);
}

/**
* The value of {@link Restrictable#getPrivilegeValue()} is used to check if the {@link Role} has this privilege
*
* @see li.strolch.privilege.policy.PrivilegePolicy#validateAction(PrivilegeContext, IPrivilege, Restrictable)
* @see li.strolch.privilege.policy.PrivilegePolicy#validateAction(PrivilegeContext, Privilege, Restrictable)
*/
@Override
public boolean hasPrivilege(PrivilegeContext ctx, IPrivilege privilege, Restrictable restrictable)
public boolean hasPrivilege(PrivilegeContext ctx, Privilege privilege, Restrictable restrictable)
throws PrivilegeException {
return validateAction(ctx, privilege, restrictable, false);
}

protected boolean validateAction(PrivilegeContext ctx, IPrivilege privilege, Restrictable restrictable,
protected boolean validateAction(PrivilegeContext ctx, Privilege privilege, Restrictable restrictable,
boolean assertHasPrivilege) throws AccessDeniedException {

preValidate(privilege, restrictable);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,21 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package li.strolch.rest;

import static java.util.function.Function.identity;
import static li.strolch.runtime.StrolchConstants.StrolchPrivilegeConstants.PRIVILEGE_GET_SESSION;
import static li.strolch.runtime.StrolchConstants.StrolchPrivilegeConstants.PRIVILEGE_INVALIDATE_SESSION;

import java.text.MessageFormat;
import java.time.ZonedDateTime;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
package li.strolch.runtime.sessions;

import li.strolch.agent.api.ComponentContainer;
import li.strolch.agent.api.StrolchComponent;
Expand All @@ -38,26 +24,36 @@
import li.strolch.privilege.model.PrivilegeContext;
import li.strolch.privilege.model.SimpleRestrictable;
import li.strolch.privilege.model.Usage;
import li.strolch.rest.model.UserSession;
import li.strolch.runtime.configuration.ComponentConfiguration;
import li.strolch.runtime.privilege.PrivilegeHandler;
import li.strolch.utils.dbc.DBC;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.text.MessageFormat;
import java.time.ZonedDateTime;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static java.util.function.Function.identity;
import static li.strolch.runtime.StrolchConstants.StrolchPrivilegeConstants.PRIVILEGE_GET_SESSION;
import static li.strolch.runtime.StrolchConstants.StrolchPrivilegeConstants.PRIVILEGE_INVALIDATE_SESSION;

/**
* @author Robert von Burg <[email protected]>
*/
public class DefaultStrolchSessionHandler extends StrolchComponent implements StrolchSessionHandler {

public static final String PARAM_SESSION_TTL_MINUTES = "session.ttl.minutes";
public static final String PARAM_SESSION_MAX_KEEP_ALIVE_MINUTES = "session.maxKeepAlive.minutes";
public static final String PARAM_SESSION_RELOAD_SESSIONS = "session.reload";

private static final Logger logger = LoggerFactory.getLogger(DefaultStrolchSessionHandler.class);
private PrivilegeHandler privilegeHandler;
private final Map<String, Certificate> certificateMap;
private boolean reloadSessions;
private int sessionTtlMinutes;
private int maxKeepAliveMinutes;

Expand All @@ -74,6 +70,29 @@ public int getSessionTtlMinutes() {
return this.sessionTtlMinutes;
}

@Override
public void refreshSessions() {
Map<String, Certificate> certificates;
try {
certificates = runAsAgentWithResult(ctx -> {
Certificate cert = ctx.getCertificate();
return this.privilegeHandler.getPrivilegeHandler().getCertificates(cert).stream()
.filter(c -> !c.getUserState().isSystem())
.collect(Collectors.toMap(Certificate::getAuthToken, identity()));
});
} catch (Exception e) {
throw new IllegalStateException("Failed to refresh sessions!", e);
}

synchronized (this.certificateMap) {
this.certificateMap.clear();
this.certificateMap.putAll(certificates);
}
checkSessionsForTimeout();
logger.info("Restored " + certificates.size() + " sessions of which " +
(certificates.size() - this.certificateMap.size()) + " had timed out and were removed.");
}

@Override
public int getSessionMaxKeepAliveMinutes() {
return this.maxKeepAliveMinutes;
Expand All @@ -89,30 +108,14 @@ public void initialize(ComponentConfiguration configuration) throws Exception {
this.sessionTtlMinutes = configuration.getInt(PARAM_SESSION_TTL_MINUTES, 30);
this.maxKeepAliveMinutes = configuration.getInt(PARAM_SESSION_MAX_KEEP_ALIVE_MINUTES,
Math.max(this.sessionTtlMinutes, 30));
this.reloadSessions = configuration.getBoolean(PARAM_SESSION_RELOAD_SESSIONS, false);
super.initialize(configuration);
}

@Override
public void start() throws Exception {
this.privilegeHandler = getContainer().getComponent(PrivilegeHandler.class);
this.certificateMap.clear();

if (this.reloadSessions) {
Map<String, Certificate> certificates = runAsAgentWithResult(ctx -> {
Certificate cert = ctx.getCertificate();
return this.privilegeHandler.getPrivilegeHandler()
.getCertificates(cert)
.stream()
.filter(c -> !c.getUserState().isSystem())
.collect(Collectors.toMap(Certificate::getAuthToken, identity()));
});
this.certificateMap.putAll(certificates);

checkSessionsForTimeout();
logger.info("Restored " + certificates.size() + " sessions of which " + (certificates.size()
- this.certificateMap.size()) + " had timed out and were removed.");
}
refreshSessions();

this.validateSessionsTask = getScheduledExecutor("SessionHandler").scheduleWithFixedDelay(
this::checkSessionsForTimeout, 5, 1, TimeUnit.MINUTES);
Expand All @@ -126,27 +129,6 @@ public void stop() throws Exception {
if (this.validateSessionsTask != null)
this.validateSessionsTask.cancel(true);

if (this.reloadSessions) {

if (this.privilegeHandler != null)
persistSessions();

} else {
Map<String, Certificate> certificateMap;
synchronized (this.certificateMap) {
certificateMap = new HashMap<>(this.certificateMap);
this.certificateMap.clear();
}
for (Certificate certificate : certificateMap.values()) {
try {
this.privilegeHandler.invalidate(certificate);
} catch (Exception e) {
logger.error("Failed to invalidate certificate " + certificate, e);
}
}

}

this.privilegeHandler = null;
super.stop();
}
Expand Down Expand Up @@ -321,8 +303,8 @@ public Certificate validateChallenge(String username, String challenge, String s
}

private void checkSessionsForTimeout() {
ZonedDateTime maxKeepAliveTime = ZonedDateTime.now().minus(this.maxKeepAliveMinutes, ChronoUnit.MINUTES);
ZonedDateTime timeOutTime = ZonedDateTime.now().minus(this.sessionTtlMinutes, ChronoUnit.MINUTES);
ZonedDateTime maxKeepAliveTime = ZonedDateTime.now().minusMinutes(this.maxKeepAliveMinutes);
ZonedDateTime timeOutTime = ZonedDateTime.now().minusMinutes(this.sessionTtlMinutes);

Map<String, Certificate> certificateMap = getCertificateMapCopy();
for (Certificate certificate : certificateMap.values()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package li.strolch.rest;
package li.strolch.runtime.sessions;

import java.util.List;
import java.util.Locale;
Expand All @@ -24,7 +24,6 @@
import li.strolch.privilege.model.Certificate;
import li.strolch.privilege.model.PrivilegeContext;
import li.strolch.privilege.model.Usage;
import li.strolch.rest.model.UserSession;

/**
* The {@link StrolchSessionHandler} implements session management. It authenticates, validates and invalidates session
Expand All @@ -34,6 +33,11 @@
*/
public interface StrolchSessionHandler {

/**
* Refreshes the sessions from the {@link li.strolch.runtime.privilege.PrivilegeHandler}
*/
void refreshSessions();

/**
* Returns the time to live for a session in minutes
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package li.strolch.rest.model;
package li.strolch.runtime.sessions;

import java.time.ZonedDateTime;
import java.util.Locale;
Expand Down
28 changes: 4 additions & 24 deletions agent/src/test/resources/emptytest/config/PrivilegeConfig.xml
Original file line number Diff line number Diff line change
@@ -1,46 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<Privilege>

<Container>

<Parameters>
<!-- parameters for the container itself -->
<Parameter name="secretKey" value="58d27145-5d1a-48ea-9e1c-f5a522f6a19f"/>
<Parameter name="secretSalt" value="25bd8911-0008-464f-82b8-4c5200db8dd7"/>
<Parameter name="secretKey" value="CHANGE-ME"/>
<Parameter name="secretSalt" value="CHANGE-ME"/>
<Parameter name="autoPersistOnUserChangesData" value="true" />
<Parameter name="privilegeConflictResolution" value="MERGE"/>
</Parameters>

<EncryptionHandler class="li.strolch.privilege.handler.DefaultEncryptionHandler">
<Parameters>
<!-- WARNING: If you change iterations or keyLength, then all passwords are invalid -->
<!-- default algorithm is: PBKDF2WithHmacSHA512 -->
<Parameter name="hashAlgorithm" value="PBKDF2WithHmacSHA512" />
<!-- default iterations: 200000 -->
<Parameter name="hashIterations" value="10000" />
<!-- default key length: 256 -->
<Parameter name="hashKeyLength" value="256" />
</Parameters>
</EncryptionHandler>

<PersistenceHandler class="li.strolch.privilege.handler.XmlPersistenceHandler">
<Parameters>
<Parameter name="usersXmlFile" value="PrivilegeUsers.xml" />
<Parameter name="rolesXmlFile" value="PrivilegeRoles.xml" />
</Parameters>
</PersistenceHandler>

<UserChallengeHandler class="li.strolch.privilege.handler.ConsoleUserChallengeHandler">
</UserChallengeHandler>

<PersistenceHandler class="li.strolch.privilege.handler.XmlPersistenceHandler"/>
<UserChallengeHandler class="li.strolch.privilege.handler.ConsoleUserChallengeHandler"/>
</Container>

<Policies>
<Policy name="DefaultPrivilege" class="li.strolch.privilege.policy.DefaultPrivilege" />
<Policy name="ModelPrivilege" class="li.strolch.runtime.privilege.ModelPrivilege" />
<Policy name="RoleAccessPrivilege" class="li.strolch.privilege.policy.RoleAccessPrivilege" />
<Policy name="UserAccessPrivilege" class="li.strolch.privilege.policy.UserAccessPrivilege" />
<Policy name="UserSessionAccessPrivilege" class="li.strolch.privilege.policy.UsernameFromCertificatePrivilege"/>
</Policies>

</Privilege>
28 changes: 4 additions & 24 deletions agent/src/test/resources/minimaltest/config/PrivilegeConfig.xml
Original file line number Diff line number Diff line change
@@ -1,46 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<Privilege>

<Container>

<Parameters>
<!-- parameters for the container itself -->
<Parameter name="secretKey" value="58d27145-5d1a-48ea-9e1c-f5a522f6a19f"/>
<Parameter name="secretSalt" value="25bd8911-0008-464f-82b8-4c5200db8dd7"/>
<Parameter name="secretKey" value="CHANGE-ME"/>
<Parameter name="secretSalt" value="CHANGE-ME"/>
<Parameter name="autoPersistOnUserChangesData" value="true" />
<Parameter name="privilegeConflictResolution" value="MERGE"/>
</Parameters>

<EncryptionHandler class="li.strolch.privilege.handler.DefaultEncryptionHandler">
<Parameters>
<!-- WARNING: If you change iterations or keyLength, then all passwords are invalid -->
<!-- default algorithm is: PBKDF2WithHmacSHA512 -->
<Parameter name="hashAlgorithm" value="PBKDF2WithHmacSHA512" />
<!-- default iterations: 200000 -->
<Parameter name="hashIterations" value="10000" />
<!-- default key length: 256 -->
<Parameter name="hashKeyLength" value="256" />
</Parameters>
</EncryptionHandler>

<PersistenceHandler class="li.strolch.privilege.handler.XmlPersistenceHandler">
<Parameters>
<Parameter name="usersXmlFile" value="PrivilegeUsers.xml" />
<Parameter name="rolesXmlFile" value="PrivilegeRoles.xml" />
</Parameters>
</PersistenceHandler>

<UserChallengeHandler class="li.strolch.privilege.handler.ConsoleUserChallengeHandler">
</UserChallengeHandler>

<PersistenceHandler class="li.strolch.privilege.handler.XmlPersistenceHandler"/>
<UserChallengeHandler class="li.strolch.privilege.handler.ConsoleUserChallengeHandler"/>
</Container>

<Policies>
<Policy name="DefaultPrivilege" class="li.strolch.privilege.policy.DefaultPrivilege" />
<Policy name="ModelPrivilege" class="li.strolch.runtime.privilege.ModelPrivilege" />
<Policy name="RoleAccessPrivilege" class="li.strolch.privilege.policy.RoleAccessPrivilege" />
<Policy name="UserAccessPrivilege" class="li.strolch.privilege.policy.UserAccessPrivilege" />
<Policy name="UserSessionAccessPrivilege" class="li.strolch.privilege.policy.UsernameFromCertificatePrivilege"/>
</Policies>

</Privilege>
Loading

0 comments on commit 42ee3de

Please sign in to comment.