[Major] Added persisting and reloading of sessions
This commit is contained in:
parent
60300ab21d
commit
c37fd20efb
|
@ -1 +1 @@
|
||||||
Subproject commit 6a62864331d93d180d4382706e9b30b8ed6cab6a
|
Subproject commit 5dc94514e13d142de8e2532b3bec18b28c7855dd
|
|
@ -1 +1 @@
|
||||||
Subproject commit f59f4c5c0fd4201e9e5a81ed26f853e99226725c
|
Subproject commit 46c3db2913efaf4dd287c4feeb2548d85a6ac1d4
|
|
@ -20,11 +20,33 @@ import java.io.InputStream;
|
||||||
import java.text.MessageFormat;
|
import java.text.MessageFormat;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
|
||||||
import li.strolch.runtime.configuration.ComponentConfiguration;
|
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import ch.eitchnet.privilege.base.PrivilegeException;
|
||||||
|
import ch.eitchnet.privilege.handler.SystemUserAction;
|
||||||
|
import li.strolch.runtime.StrolchConstants;
|
||||||
|
import li.strolch.runtime.configuration.ComponentConfiguration;
|
||||||
|
import li.strolch.runtime.privilege.RunRunnable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* A {@link StrolchComponent} is a configurable extension to Strolch. Every major feature should be implemented as a
|
||||||
|
* {@link StrolchComponent} so that they can be easily added or removed from a Strolch runtime.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* A {@link StrolchComponent} has access to the container and can perform different operations. They can be passive or
|
||||||
|
* active and their life cycle is bound to the container's life cycle
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* A {@link StrolchComponent} is registered in the Strolch configuration file and can have different configuration
|
||||||
|
* depending on the container's runtime environment
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*/
|
||||||
public class StrolchComponent {
|
public class StrolchComponent {
|
||||||
|
|
||||||
public static final String COMPONENT_VERSION_PROPERTIES = "/componentVersion.properties"; //$NON-NLS-1$
|
public static final String COMPONENT_VERSION_PROPERTIES = "/componentVersion.properties"; //$NON-NLS-1$
|
||||||
|
@ -35,6 +57,15 @@ public class StrolchComponent {
|
||||||
private ComponentVersion version;
|
private ComponentVersion version;
|
||||||
private ComponentConfiguration configuration;
|
private ComponentConfiguration configuration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor which takes a reference to the container and the component's name under which it can be retrieved at
|
||||||
|
* runtime (although one mostly retrieves the component by interface class for automatic casting)
|
||||||
|
*
|
||||||
|
* @param container
|
||||||
|
* the container
|
||||||
|
* @param componentName
|
||||||
|
* the component name
|
||||||
|
*/
|
||||||
public StrolchComponent(ComponentContainer container, String componentName) {
|
public StrolchComponent(ComponentContainer container, String componentName) {
|
||||||
this.container = container;
|
this.container = container;
|
||||||
this.componentName = componentName;
|
this.componentName = componentName;
|
||||||
|
@ -48,18 +79,37 @@ public class StrolchComponent {
|
||||||
return this.componentName;
|
return this.componentName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the current component's state
|
||||||
|
*
|
||||||
|
* @return the component's current state
|
||||||
|
*/
|
||||||
public ComponentState getState() {
|
public ComponentState getState() {
|
||||||
return this.state;
|
return this.state;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the reference to the container for sub classes
|
||||||
|
*
|
||||||
|
* @return the reference to the container
|
||||||
|
*/
|
||||||
protected ComponentContainer getContainer() {
|
protected ComponentContainer getContainer() {
|
||||||
return this.container;
|
return this.container;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The components current configuration dependent on the environment which is loaded
|
||||||
|
*
|
||||||
|
* @return the component's configuration
|
||||||
|
*/
|
||||||
protected ComponentConfiguration getConfiguration() {
|
protected ComponentConfiguration getConfiguration() {
|
||||||
return this.configuration;
|
return this.configuration;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Can be used by sub classes to assert that the component is started and thus ready to use, before any component
|
||||||
|
* methods are used
|
||||||
|
*/
|
||||||
protected void assertStarted() {
|
protected void assertStarted() {
|
||||||
if (getState() != ComponentState.STARTED) {
|
if (getState() != ComponentState.STARTED) {
|
||||||
String msg = "Component {0} is not yet started!"; //$NON-NLS-1$
|
String msg = "Component {0} is not yet started!"; //$NON-NLS-1$
|
||||||
|
@ -67,6 +117,10 @@ public class StrolchComponent {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Can be used by sub classes to assert that the entire container is started and thus ready to use, before any
|
||||||
|
* component methods are used
|
||||||
|
*/
|
||||||
protected void assertContainerStarted() {
|
protected void assertContainerStarted() {
|
||||||
if (this.container.getState() != ComponentState.STARTED) {
|
if (this.container.getState() != ComponentState.STARTED) {
|
||||||
String msg = "Container is not yet started!"; //$NON-NLS-1$
|
String msg = "Container is not yet started!"; //$NON-NLS-1$
|
||||||
|
@ -74,27 +128,109 @@ public class StrolchComponent {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Life cycle step setup. This is a very early step in the container's startup phase.
|
||||||
|
*
|
||||||
|
* @param configuration
|
||||||
|
*/
|
||||||
public void setup(ComponentConfiguration configuration) {
|
public void setup(ComponentConfiguration configuration) {
|
||||||
this.state = this.state.validateStateChange(ComponentState.SETUP);
|
this.state = this.state.validateStateChange(ComponentState.SETUP);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Life cycle step initialize. Here you would typically read configuration values
|
||||||
|
*
|
||||||
|
* @param configuration
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
public void initialize(ComponentConfiguration configuration) throws Exception {
|
public void initialize(ComponentConfiguration configuration) throws Exception {
|
||||||
this.configuration = configuration;
|
this.configuration = configuration;
|
||||||
this.state = this.state.validateStateChange(ComponentState.INITIALIZED);
|
this.state = this.state.validateStateChange(ComponentState.INITIALIZED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Life cycle step start. This is the last step of startup and is where threads and connections etc. would be
|
||||||
|
* prepared. Can also be called after stop, to restart the component.
|
||||||
|
*
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
public void start() throws Exception {
|
public void start() throws Exception {
|
||||||
this.state = this.state.validateStateChange(ComponentState.STARTED);
|
this.state = this.state.validateStateChange(ComponentState.STARTED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Life cycle step stop. This is the first step in the tearing down of the container. Stop all active threads and
|
||||||
|
* connections here. After stop is called, another start might also be called to restart the component.
|
||||||
|
*
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
public void stop() throws Exception {
|
public void stop() throws Exception {
|
||||||
this.state = this.state.validateStateChange(ComponentState.STOPPED);
|
this.state = this.state.validateStateChange(ComponentState.STOPPED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Life cycle step destroy. This is the last step in the tearing down of the container. Here you would release
|
||||||
|
* remaining resources and the component can not be started anymore afterwards
|
||||||
|
*
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
public void destroy() throws Exception {
|
public void destroy() throws Exception {
|
||||||
this.state = this.state.validateStateChange(ComponentState.DESTROYED);
|
this.state = this.state.validateStateChange(ComponentState.DESTROYED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs the given {@link SystemUserAction} as a system user with the given username. Returns the action for
|
||||||
|
* chaining calls
|
||||||
|
*
|
||||||
|
* @param username
|
||||||
|
* the name of the system user to perform the action as
|
||||||
|
* @param action
|
||||||
|
* the action to perform
|
||||||
|
*
|
||||||
|
* @return the action performed for chaining calls
|
||||||
|
*
|
||||||
|
* @throws PrivilegeException
|
||||||
|
*/
|
||||||
|
protected <V extends SystemUserAction> V runAs(String username, V action) throws PrivilegeException {
|
||||||
|
return this.container.getPrivilegeHandler().runAsSystem(username, action);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs the given {@link SystemUserAction} as the privileged system user
|
||||||
|
* {@link StrolchConstants#PRIVILEGED_SYSTEM_USER}. Returns the action for chaining calls
|
||||||
|
*
|
||||||
|
* @param action
|
||||||
|
* the action to perform
|
||||||
|
*
|
||||||
|
* @return the action performed for chaining calls
|
||||||
|
*
|
||||||
|
* @throws PrivilegeException
|
||||||
|
*/
|
||||||
|
protected <V extends SystemUserAction> V runPrivileged(V action) throws PrivilegeException {
|
||||||
|
return this.container.getPrivilegeHandler().runAsSystem(StrolchConstants.PRIVILEGED_SYSTEM_USER, action);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs the given {@link SystemUserAction} as the privileged system user
|
||||||
|
* {@link StrolchConstants#PRIVILEGED_SYSTEM_USER}. Returns the action for chaining calls
|
||||||
|
*
|
||||||
|
* @param action
|
||||||
|
* the action to perform
|
||||||
|
*
|
||||||
|
* @throws PrivilegeException
|
||||||
|
*/
|
||||||
|
protected <T> T runPrivileged(RunRunnable.Runnable<T> action) throws PrivilegeException {
|
||||||
|
return this.container.getPrivilegeHandler()
|
||||||
|
.runAsSystem(StrolchConstants.PRIVILEGED_SYSTEM_USER, new RunRunnable<>(action)).getResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the version of this component. The version should be stored in the file
|
||||||
|
* {@link #COMPONENT_VERSION_PROPERTIES}. See {@link ComponentVersion} for more information
|
||||||
|
*
|
||||||
|
* @return the component's version.
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
public ComponentVersion getVersion() throws IOException {
|
public ComponentVersion getVersion() throws IOException {
|
||||||
if (this.version == null) {
|
if (this.version == null) {
|
||||||
try (InputStream stream = getClass().getResourceAsStream(COMPONENT_VERSION_PROPERTIES)) {
|
try (InputStream stream = getClass().getResourceAsStream(COMPONENT_VERSION_PROPERTIES)) {
|
||||||
|
|
|
@ -95,6 +95,17 @@ public class DefaultStrolchPrivilegeHandler extends StrolchComponent implements
|
||||||
try (FileInputStream inputStream = new FileInputStream(privilegeXmlFile)) {
|
try (FileInputStream inputStream = new FileInputStream(privilegeXmlFile)) {
|
||||||
XmlHelper.parseDocument(inputStream, xmlHandler);
|
XmlHelper.parseDocument(inputStream, xmlHandler);
|
||||||
|
|
||||||
|
Map<String, String> parameterMap = containerModel.getParameterMap();
|
||||||
|
|
||||||
|
// set sessions data path
|
||||||
|
if (Boolean.valueOf(
|
||||||
|
parameterMap.get(ch.eitchnet.privilege.handler.PrivilegeHandler.PARAM_PERSIST_SESSIONS))) {
|
||||||
|
String sessionsPath = new File(configuration.getRuntimeConfiguration().getDataPath(),
|
||||||
|
"sessions.dat").getAbsolutePath();
|
||||||
|
parameterMap.put(ch.eitchnet.privilege.handler.PrivilegeHandler.PARAM_PERSIST_SESSIONS_PATH,
|
||||||
|
sessionsPath);
|
||||||
|
}
|
||||||
|
|
||||||
// set base path
|
// set base path
|
||||||
if (containerModel.getPersistenceHandlerClassName().equals(XmlPersistenceHandler.class.getName())) {
|
if (containerModel.getPersistenceHandlerClassName().equals(XmlPersistenceHandler.class.getName())) {
|
||||||
Map<String, String> xmlParams = containerModel.getPersistenceHandlerParameterMap();
|
Map<String, String> xmlParams = containerModel.getPersistenceHandlerParameterMap();
|
||||||
|
@ -144,7 +155,6 @@ public class DefaultStrolchPrivilegeHandler extends StrolchComponent implements
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean invalidateSession(Certificate certificate) {
|
public boolean invalidateSession(Certificate certificate) {
|
||||||
assertContainerStarted();
|
|
||||||
boolean invalidateSession = this.privilegeHandler.invalidateSession(certificate);
|
boolean invalidateSession = this.privilegeHandler.invalidateSession(certificate);
|
||||||
StrolchRealm realm = getContainer().getRealm(certificate);
|
StrolchRealm realm = getContainer().getRealm(certificate);
|
||||||
try (StrolchTransaction tx = realm.openTx(certificate, StrolchPrivilegeConstants.LOGOUT)) {
|
try (StrolchTransaction tx = realm.openTx(certificate, StrolchPrivilegeConstants.LOGOUT)) {
|
||||||
|
@ -185,7 +195,6 @@ public class DefaultStrolchPrivilegeHandler extends StrolchComponent implements
|
||||||
@Override
|
@Override
|
||||||
public ch.eitchnet.privilege.handler.PrivilegeHandler getPrivilegeHandler(Certificate certificate)
|
public ch.eitchnet.privilege.handler.PrivilegeHandler getPrivilegeHandler(Certificate certificate)
|
||||||
throws PrivilegeException {
|
throws PrivilegeException {
|
||||||
assertContainerStarted();
|
|
||||||
return this.privilegeHandler;
|
return this.privilegeHandler;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,10 +3,19 @@ package li.strolch.runtime.privilege;
|
||||||
import ch.eitchnet.privilege.handler.SystemUserAction;
|
import ch.eitchnet.privilege.handler.SystemUserAction;
|
||||||
import ch.eitchnet.privilege.model.PrivilegeContext;
|
import ch.eitchnet.privilege.model.PrivilegeContext;
|
||||||
import li.strolch.service.api.AbstractService;
|
import li.strolch.service.api.AbstractService;
|
||||||
|
import li.strolch.service.api.Service;
|
||||||
import li.strolch.service.api.ServiceArgument;
|
import li.strolch.service.api.ServiceArgument;
|
||||||
import li.strolch.service.api.ServiceHandler;
|
import li.strolch.service.api.ServiceHandler;
|
||||||
import li.strolch.service.api.ServiceResult;
|
import li.strolch.service.api.ServiceResult;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link SystemUserAction} to run a {@link Service} as a system user
|
||||||
|
*
|
||||||
|
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*
|
||||||
|
* @param <T>
|
||||||
|
* @param <U>
|
||||||
|
*/
|
||||||
public class RunAsAgent<T extends ServiceArgument, U extends ServiceResult> extends SystemUserAction {
|
public class RunAsAgent<T extends ServiceArgument, U extends ServiceResult> extends SystemUserAction {
|
||||||
|
|
||||||
private ServiceHandler svcHandler;
|
private ServiceHandler svcHandler;
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
package li.strolch.runtime.privilege;
|
||||||
|
|
||||||
|
import ch.eitchnet.privilege.handler.SystemUserAction;
|
||||||
|
import ch.eitchnet.privilege.model.PrivilegeContext;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link SystemUserAction} to run {@link Runnable} as a system user
|
||||||
|
*
|
||||||
|
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*
|
||||||
|
* @param <T>
|
||||||
|
* @param <U>
|
||||||
|
*/
|
||||||
|
public class RunRunnable<T> extends SystemUserAction {
|
||||||
|
|
||||||
|
private Runnable<T> runnable;
|
||||||
|
private T result;
|
||||||
|
|
||||||
|
public RunRunnable(Runnable<T> runnable) {
|
||||||
|
this.runnable = runnable;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(PrivilegeContext privilegeContext) {
|
||||||
|
this.result = runnable.run(privilegeContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
public T getResult() {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface Runnable<T> {
|
||||||
|
|
||||||
|
public T run(PrivilegeContext ctx);
|
||||||
|
}
|
||||||
|
}
|
|
@ -33,13 +33,7 @@ import java.util.Map;
|
||||||
import java.util.Timer;
|
import java.util.Timer;
|
||||||
import java.util.TimerTask;
|
import java.util.TimerTask;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
import li.strolch.agent.api.ComponentContainer;
|
|
||||||
import li.strolch.agent.api.StrolchComponent;
|
|
||||||
import li.strolch.exception.StrolchException;
|
|
||||||
import li.strolch.rest.model.UserSession;
|
|
||||||
import li.strolch.runtime.configuration.ComponentConfiguration;
|
|
||||||
import li.strolch.runtime.privilege.PrivilegeHandler;
|
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
@ -50,6 +44,12 @@ import ch.eitchnet.privilege.model.Certificate;
|
||||||
import ch.eitchnet.privilege.model.PrivilegeContext;
|
import ch.eitchnet.privilege.model.PrivilegeContext;
|
||||||
import ch.eitchnet.privilege.model.SimpleRestrictable;
|
import ch.eitchnet.privilege.model.SimpleRestrictable;
|
||||||
import ch.eitchnet.utils.dbc.DBC;
|
import ch.eitchnet.utils.dbc.DBC;
|
||||||
|
import li.strolch.agent.api.ComponentContainer;
|
||||||
|
import li.strolch.agent.api.StrolchComponent;
|
||||||
|
import li.strolch.exception.StrolchException;
|
||||||
|
import li.strolch.rest.model.UserSession;
|
||||||
|
import li.strolch.runtime.configuration.ComponentConfiguration;
|
||||||
|
import li.strolch.runtime.privilege.PrivilegeHandler;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Robert von Burg <eitch@eitchnet.ch>
|
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
@ -57,17 +57,15 @@ import ch.eitchnet.utils.dbc.DBC;
|
||||||
public class DefaultStrolchSessionHandler extends StrolchComponent implements StrolchSessionHandler {
|
public class DefaultStrolchSessionHandler extends StrolchComponent implements StrolchSessionHandler {
|
||||||
|
|
||||||
public static final String PARAM_SESSION_TTL_MINUTES = "session.ttl.minutes"; //$NON-NLS-1$
|
public static final String PARAM_SESSION_TTL_MINUTES = "session.ttl.minutes"; //$NON-NLS-1$
|
||||||
|
public static final String PARAM_SESSION_RELOAD_SESSIONS = "session.reload"; //$NON-NLS-1$
|
||||||
|
|
||||||
private static final Logger logger = LoggerFactory.getLogger(DefaultStrolchSessionHandler.class);
|
private static final Logger logger = LoggerFactory.getLogger(DefaultStrolchSessionHandler.class);
|
||||||
private PrivilegeHandler privilegeHandler;
|
private PrivilegeHandler privilegeHandler;
|
||||||
private Map<String, Certificate> certificateMap;
|
private Map<String, Certificate> certificateMap;
|
||||||
|
private boolean reloadSessions;
|
||||||
private long sessionTtl;
|
private long sessionTtl;
|
||||||
private Timer sessionTimeoutTimer;
|
private Timer sessionTimeoutTimer;
|
||||||
|
|
||||||
/**
|
|
||||||
* @param container
|
|
||||||
* @param componentName
|
|
||||||
*/
|
|
||||||
public DefaultStrolchSessionHandler(ComponentContainer container, String componentName) {
|
public DefaultStrolchSessionHandler(ComponentContainer container, String componentName) {
|
||||||
super(container, componentName);
|
super(container, componentName);
|
||||||
}
|
}
|
||||||
|
@ -75,6 +73,7 @@ public class DefaultStrolchSessionHandler extends StrolchComponent implements St
|
||||||
@Override
|
@Override
|
||||||
public void initialize(ComponentConfiguration configuration) throws Exception {
|
public void initialize(ComponentConfiguration configuration) throws Exception {
|
||||||
this.sessionTtl = TimeUnit.MINUTES.toMillis(configuration.getInt(PARAM_SESSION_TTL_MINUTES, 30));
|
this.sessionTtl = TimeUnit.MINUTES.toMillis(configuration.getInt(PARAM_SESSION_TTL_MINUTES, 30));
|
||||||
|
this.reloadSessions = configuration.getBoolean(PARAM_SESSION_RELOAD_SESSIONS, false);
|
||||||
super.initialize(configuration);
|
super.initialize(configuration);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,6 +82,21 @@ public class DefaultStrolchSessionHandler extends StrolchComponent implements St
|
||||||
this.privilegeHandler = getContainer().getComponent(PrivilegeHandler.class);
|
this.privilegeHandler = getContainer().getComponent(PrivilegeHandler.class);
|
||||||
this.certificateMap = Collections.synchronizedMap(new HashMap<>());
|
this.certificateMap = Collections.synchronizedMap(new HashMap<>());
|
||||||
|
|
||||||
|
if (this.reloadSessions) {
|
||||||
|
List<Certificate> certificates = runPrivileged(ctx -> {
|
||||||
|
Certificate cert = ctx.getCertificate();
|
||||||
|
return this.privilegeHandler.getPrivilegeHandler(cert).getCertificates(cert).stream()
|
||||||
|
.filter(c -> !c.getUserState().isSystem()).collect(Collectors.toList());
|
||||||
|
});
|
||||||
|
for (Certificate certificate : certificates) {
|
||||||
|
this.certificateMap.put(certificate.getAuthToken(), certificate);
|
||||||
|
}
|
||||||
|
|
||||||
|
checkSessionsForTimeout();
|
||||||
|
logger.info("Restored " + certificates.size() + " sessions of which "
|
||||||
|
+ (certificates.size() - this.certificateMap.size()) + " had timed out and were removed.");
|
||||||
|
}
|
||||||
|
|
||||||
this.sessionTimeoutTimer = new Timer("SessionTimeoutTimer", true); //$NON-NLS-1$
|
this.sessionTimeoutTimer = new Timer("SessionTimeoutTimer", true); //$NON-NLS-1$
|
||||||
long checkInterval = TimeUnit.MINUTES.toMillis(1);
|
long checkInterval = TimeUnit.MINUTES.toMillis(1);
|
||||||
this.sessionTimeoutTimer.schedule(new SessionTimeoutTask(), checkInterval, checkInterval);
|
this.sessionTimeoutTimer.schedule(new SessionTimeoutTask(), checkInterval, checkInterval);
|
||||||
|
@ -92,7 +106,12 @@ public class DefaultStrolchSessionHandler extends StrolchComponent implements St
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void stop() throws Exception {
|
public void stop() throws Exception {
|
||||||
if (this.certificateMap != null) {
|
if (this.reloadSessions) {
|
||||||
|
|
||||||
|
runPrivileged(ctx -> getContainer().getPrivilegeHandler().getPrivilegeHandler(ctx.getCertificate())
|
||||||
|
.persistSessions(ctx.getCertificate()));
|
||||||
|
|
||||||
|
} else if (this.certificateMap != null) {
|
||||||
synchronized (this.certificateMap) {
|
synchronized (this.certificateMap) {
|
||||||
for (Certificate certificate : this.certificateMap.values()) {
|
for (Certificate certificate : this.certificateMap.values()) {
|
||||||
this.privilegeHandler.invalidateSession(certificate);
|
this.privilegeHandler.invalidateSession(certificate);
|
||||||
|
@ -198,23 +217,26 @@ public class DefaultStrolchSessionHandler extends StrolchComponent implements St
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
|
checkSessionsForTimeout();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Map<String, Certificate> map = getCertificateMap();
|
private void checkSessionsForTimeout() {
|
||||||
Map<String, Certificate> certificateMap;
|
Map<String, Certificate> map = getCertificateMap();
|
||||||
synchronized (map) {
|
Map<String, Certificate> certificateMap;
|
||||||
certificateMap = new HashMap<>(map);
|
synchronized (map) {
|
||||||
}
|
certificateMap = new HashMap<>(map);
|
||||||
|
}
|
||||||
|
|
||||||
LocalDateTime timeOutTime = LocalDateTime.now().minus(sessionTtl, ChronoUnit.MILLIS);
|
LocalDateTime timeOutTime = LocalDateTime.now().minus(sessionTtl, ChronoUnit.MILLIS);
|
||||||
ZoneId systemDefault = ZoneId.systemDefault();
|
ZoneId systemDefault = ZoneId.systemDefault();
|
||||||
|
|
||||||
for (Certificate certificate : certificateMap.values()) {
|
for (Certificate certificate : certificateMap.values()) {
|
||||||
Instant lastAccess = certificate.getLastAccess().toInstant();
|
Instant lastAccess = certificate.getLastAccess().toInstant();
|
||||||
if (timeOutTime.isAfter(LocalDateTime.ofInstant(lastAccess, systemDefault))) {
|
if (timeOutTime.isAfter(LocalDateTime.ofInstant(lastAccess, systemDefault))) {
|
||||||
String msg = "Session {0} for user {1} has expired, invalidating session..."; //$NON-NLS-1$
|
String msg = "Session {0} for user {1} has expired, invalidating session..."; //$NON-NLS-1$
|
||||||
logger.info(MessageFormat.format(msg, certificate.getAuthToken(), certificate.getUsername()));
|
logger.info(MessageFormat.format(msg, certificate.getSessionId(), certificate.getUsername()));
|
||||||
sessionTimeout(certificate);
|
sessionTimeout(certificate);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,8 @@ import java.util.Map;
|
||||||
import java.util.concurrent.BlockingQueue;
|
import java.util.concurrent.BlockingQueue;
|
||||||
import java.util.concurrent.LinkedBlockingQueue;
|
import java.util.concurrent.LinkedBlockingQueue;
|
||||||
|
|
||||||
|
import ch.eitchnet.privilege.model.Certificate;
|
||||||
|
import ch.eitchnet.utils.helper.ExceptionHelper;
|
||||||
import li.strolch.agent.api.ComponentContainer;
|
import li.strolch.agent.api.ComponentContainer;
|
||||||
import li.strolch.agent.api.StrolchComponent;
|
import li.strolch.agent.api.StrolchComponent;
|
||||||
import li.strolch.exception.StrolchException;
|
import li.strolch.exception.StrolchException;
|
||||||
|
@ -29,7 +31,6 @@ import li.strolch.service.api.Service;
|
||||||
import li.strolch.service.api.ServiceArgument;
|
import li.strolch.service.api.ServiceArgument;
|
||||||
import li.strolch.service.api.ServiceHandler;
|
import li.strolch.service.api.ServiceHandler;
|
||||||
import li.strolch.service.api.ServiceResult;
|
import li.strolch.service.api.ServiceResult;
|
||||||
import ch.eitchnet.privilege.model.Certificate;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The {@link ServiceExecutionHandler} is used to perform long running services so that no singletons etc. are required.
|
* The {@link ServiceExecutionHandler} is used to perform long running services so that no singletons etc. are required.
|
||||||
|
@ -62,7 +63,7 @@ public class ServiceExecutionHandler extends StrolchComponent {
|
||||||
doService(queue.take());
|
doService(queue.take());
|
||||||
}
|
}
|
||||||
} catch (InterruptedException ex) {
|
} catch (InterruptedException ex) {
|
||||||
logger.error(ex.getLocalizedMessage());
|
logger.error(ExceptionHelper.formatExceptionMessage(ex));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, "ServiceExecutor");
|
}, "ServiceExecutor");
|
||||||
|
|
|
@ -23,12 +23,6 @@ import static org.junit.Assert.assertThat;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
|
||||||
import li.strolch.service.api.ServiceResult;
|
|
||||||
import li.strolch.service.test.model.GreetingResult;
|
|
||||||
import li.strolch.service.test.model.GreetingService;
|
|
||||||
import li.strolch.service.test.model.GreetingService.GreetingArgument;
|
|
||||||
import li.strolch.service.test.model.TestService;
|
|
||||||
|
|
||||||
import org.junit.Rule;
|
import org.junit.Rule;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.rules.ExpectedException;
|
import org.junit.rules.ExpectedException;
|
||||||
|
@ -36,6 +30,12 @@ import org.junit.rules.ExpectedException;
|
||||||
import ch.eitchnet.privilege.base.AccessDeniedException;
|
import ch.eitchnet.privilege.base.AccessDeniedException;
|
||||||
import ch.eitchnet.privilege.base.PrivilegeException;
|
import ch.eitchnet.privilege.base.PrivilegeException;
|
||||||
import ch.eitchnet.privilege.model.Certificate;
|
import ch.eitchnet.privilege.model.Certificate;
|
||||||
|
import ch.eitchnet.privilege.model.UserState;
|
||||||
|
import li.strolch.service.api.ServiceResult;
|
||||||
|
import li.strolch.service.test.model.GreetingResult;
|
||||||
|
import li.strolch.service.test.model.GreetingService;
|
||||||
|
import li.strolch.service.test.model.GreetingService.GreetingArgument;
|
||||||
|
import li.strolch.service.test.model.TestService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Robert von Burg <eitch@eitchnet.ch>
|
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
@ -57,15 +57,15 @@ public class ServiceTest extends AbstractServiceTest {
|
||||||
this.thrown.expect(PrivilegeException.class);
|
this.thrown.expect(PrivilegeException.class);
|
||||||
TestService testService = new TestService();
|
TestService testService = new TestService();
|
||||||
getServiceHandler().doService(
|
getServiceHandler().doService(
|
||||||
new Certificate(null, new Date(), null, null, null, null, null, new HashSet<String>(), null),
|
new Certificate(null, null, null, null, null, null, new Date(), null, new HashSet<String>(), null),
|
||||||
testService);
|
testService);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void shouldFailInvalidCertificate2() {
|
public void shouldFailInvalidCertificate2() {
|
||||||
TestService testService = new TestService();
|
TestService testService = new TestService();
|
||||||
Certificate badCert = new Certificate(
|
Certificate badCert = new Certificate("1", "bob", "Bob", "Brown", UserState.ENABLED, "dsdf", new Date(), null, //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$
|
||||||
"1", new Date(), "bob", "Bob", "Brown", "dsdf", null, new HashSet<String>(), null); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
|
new HashSet<String>(), null);
|
||||||
ServiceResult svcResult = getServiceHandler().doService(badCert, testService);
|
ServiceResult svcResult = getServiceHandler().doService(badCert, testService);
|
||||||
assertThat(svcResult.getThrowable(), instanceOf(AccessDeniedException.class));
|
assertThat(svcResult.getThrowable(), instanceOf(AccessDeniedException.class));
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue